有一些感悟,但觉得积累还浅薄,希望大家多多批评。
我对java的服务器开发非常有好感,以前用C++写通讯和软件功能
,由于C++依赖操作系统,而当时用的是VC++,windows的API又是出名的混乱。java由于纯面向对象(不和ruby比较)缺点是类更多,代码量更多, 但是开发越久,积累的代码越多,做新项目的效率越快。
第二点就是哲学思想统一,分工明确,像管理制度严格的工厂,不像C++那么难以入手。当然有些写法让人很郁闷,比如java的监听使用接口伪实例化 ,以及三目运算的无限迭代。
看了淘宝架构师的总结,我也思考了下说说服务器架构的优化。
1.适当放弃一致性
首先说架构清晰度的优化,这一点,其实在于接口的使用。我看过很多项目代码,有些项目会使用非常多的接口,而且这些接口只是一个标识作用(只被一个类继承),以便更换组件。 比如有的人写通讯,喜欢写很多接口,以便从neety换到mina。其实这些项目基本没有可能 也没有必要去更换代码。因为mina没有比netty多出一点优势。
为了让架构更清晰容易维护,有必要去除多余的接口。
其次是维护的优化,不一定要用java开发所有功能,一些常变动的功能可以使用脚本(比如)做热更新。
2.备份和隔离解决稳定性问题
备份,则是定时保存信息,防止服务器宕机时丢失信息,有几种方法,一种是保存文本文档在硬盘,一种是保存在备份数据库。
保存文本文档在硬盘的好处是比经常操作数据库更节约性能和时间。
隔离这一点,则是将风险分化。比如登陆服务器,逻辑服务器分别隔离,则某些因素导致登陆服务器挂掉后,逻辑服务器不受影响,已经登陆的用户使用逻辑服务器自然也不会受影响。
3.分割和异步解决性能问题。
异步在于传输。同步的传输速度在网络带宽大并且稳定时,当然比异步传输更多更快。但是每个用户的网络并不相同,而且性能不能单纯寄希望于网络稳定。使用异步则可以在网络良好的情况下多传输消息,网络不良的情况下少传输。
分割在于功能的划分和业务的划分。
功能的划分(垂直划分)比如将处理I/O的部分划分出来处理,密集运算的功能划分出来处理,而不是分散在各个线程,有利于服务器的性能发挥最大化。
有人说java基于虚拟机,这样分割后,能对实际的服务器产生优化吗。 当然能,多线程并发,当功能分散到不同线程后,抢占服务器资源(I/O,cpu等)时,服务器对资源的分配消耗时间和性能,而同一线程顺序执行同样的功能则不需要CPU调度资源分配。
业务的划分(水平划分),则是比如战场与野外的进程/线程分离,以达到性能伸缩,和功能扩展。
这样当战场火爆的时候,可以通过对战场的服务器扩展,而达到性能优化的效果。而不用扩展所有服务器。
而且当对战场功能进行扩展的时候,其他功能不受影响。
4.自动化降低人力成本
我要说的不只是项目完成后的人力成本。在开发阶段各种底层的封装,工具类,都属于开发自动化,对后续开发效率有很大提高。而比如游戏服务器的GM工具,一些功能的自动化,则能降低运营成本。
5. 产品化管理
svn的代码管理,maven的包管理,禅道的项目管理,这些都有助于项目的严谨。
6.约定优先配置
很多时候,需要强行配置,但是时刻牢记约定优先配置,使得命名更规范清晰,会让重构时开发成本更低。
7.使用缓存来降低DB负载和服务器负载
一般来说缓存根据与应用程序的远近程度不同可以分为:local cache 和 remote cache。
local cache和remote cache应该分开使用,两者混合使用的话,对数据一致性处理会比较麻烦。
loacl cache,也就是服务器缓存,一般用来存储数据库的信息,比如游戏开发中,map的初始化信息,怪物的初始化信息等等,都可以放入缓存中,在重复使用时无需读取数据库。
除了读缓存,缓存还有另外一个类型:写缓存.
对于一些读写比不高,同时对数据安全性需求不高的数据,我们可以将其缓存起来从而减少对底层数据库的访问,比如玩家的签到/上线时间/在游戏中活动的喜好(供运营分析)等等,可以采用先写内存缓存然后延迟持久化到数据库(比如玩家下线时才保存),这样可以大大减少对数据库的写压力。
还有一个典型例子是玩家操作先用log4j保存在文本文档,再延迟持久化。
remote cache,则是客户端缓存,一个是服务器端传输过去的一些信息,一个是运行期间产生的信息,可以在客户端做缓存,不用频繁请求服务器。
8.最后提一点,框架的选择
其实框架选择不只在于性能/扩展性/移植性,还在于排错是否容易。
最近一个例子就是我使用mybatis,出错只会给一个大概的错误原因,有时很难找到具体出错。而hibernate在这方面做得更好。