关于系统4个9可靠性的思考

公司定义了所有软件系统需要有4个9的可靠性,姑且不论这是外行还是伪内行提出的,在国企领导的话就是规章。(虽然现在运行的系统达到2个9的都很少)。这个先抛开不论,
本人是去IOE的严重支持者。本文基于X86平台和开源软件为基础,虽然这样的架构在国企不受待见,原因大家都应该明白。不想在系统建设中担责任的人员请绕行。本文就自己的理解写写如果要建设一个接近4个9的系统该做些什么。

硬件可靠性:
服务器:在X86体系中,现在普遍使用的双路服务器,由于主板和raid卡是单点,加上CPU是CISC结构,双路的又较少RAS特性,单机的可靠性最多也就3个9。
交换机:交换机单机可以做到5个9的运营商级别,可以使用VRRP/HSRP实现主备,这部分不在本文讨论范围。
负载均衡设备:F5,A10都可以支持主备,但是和IOE一样,贵的离谱。本文考虑用LVS,nginx等方案,个人认为和LVS比起来,F5,A10的性价比为零。

整体考虑:
现代的软件系统一般都至少有负载均衡,应用和数据库三层,要保证4个9,每层都需要在4个9以上,系统至少不能有单点失效(SPOF)。由于企业应用还是已JAVAEE为主,这里的应用层只关注JAVA的,至于是否java就是企业应用最适合的语言,另外写文章讨论(见 JAVA是否最适合企业应用开发)。
下图是个整体方案,mysql使用DRDB方式




相关硬件软件:
服务器:双路带管理的IBM,HP,DELL服务器,如果使用ISCSI,选取带TOE的网卡
ISCSI:带TOE网卡的存储服务器,如dell R720XD,这里不讨论FC SAN和DAS。
交换机:CISCO/H3C带网管交换机
---------------------------------
操作系统:CentOS6,TCMALLOC
负载均衡:LVS,KeepAlived,Nginx
应用服务器:Tomcat,APR,Nginx
数据库服务器:mariaDB,HeartBeat,DRBD
缓存/KV:redis,redis sentinel
JOB:quartz数据库集群
运维:cacti,nagios
代码检查:CheckStyle,PMD,findbug


下面分层讨论:
LVS
LVS可以工作在3层或4层,通常使用三层的DR(Direct Routing),这需要ARP转发,故交换机上不能禁。另外需要VIP和RIP在一个网段,公网IP不在时可以使用内网IP转发,但实测内网转发nginx时,反向代理没问题,fcgi有问题。
LVS使用VRRP的keepalived进行报活和故障转移
LVS性能优秀,因为只在内核中处理,不会调用fd。在i3-2100,broadcom 5709实测可以达到20w/s的转发速率。但CPU的1个核会被网卡软中断压到99%。在使用支持RSS的网卡(intel 82576)和e3-1230下,系统性能和稳定性都很好。

nginx
虽然在使用java的环境里,部署nginx还是有很大必要的。
1、nginx做反向代理:这样可以使得tomcat部署更具灵活性(如虚拟机部署,多端口部署)
2、静态资源的处理:一般情况下,如果有比较大并发压力时,静态资源需要web服务器分开域名部署,nginx是十分可靠,性能十分强(epoll)的web服务 器,而且有强大的插件体系。
3、文件上传下载:JVM处理上传下载极易导致频繁的fullgc。这时比较理想的做法是使用nginx+fcgi/php来完成,系统互通可以使用性能接近变态的thrift。

Tomcat+APR
本人一直认为java应用的可靠性是比较难做上去的,主要是JVM的共享HEAP和stop world的 fullgc机制,另外java语言的exception特性也导致很多问题(本人更喜欢C/C++的fail fast)。
由于现代的很多javaee框架还是以thread local为根本,Tomcat只能按照thread pool的方式来部署,添加APR(apache portable runtime)后,线程调度和IO有明显改善。
另外一个要注意的是JVM的调优,因为JVM并不能有效管理太大内存(8G以下),另外垃圾回收算法也是一个影响性能和稳定性的因素。一般情况会使用类似如下的JVM参数。
-server -Xmx3500m -Xms3500m -Xss256k -XX:+UseConcMarkSweepGC -XX:+UseCMSCompactAtFullCollection

数据库
开源关系数据库主要是mysql和postgresql。mysql是线程连接,postgresql是进程连接,对于JAVA使用连接池来说,可能postgresql更好些。但是从多方面对比,还是倾向于mysql。参考 http://www.wikivs.com/wiki/MySQL_vs_PostgreSQL
由于oracle手下的mysql已经不是个东西了,选择了创始者创建的mariadb5.5分支,另外percona也不错。关于mariadb,会单独写文章讨论。
DRBD:通过TCP协议实现的块设备复制的应用,原理图如下(来自官方)

mariadb的HA使用DRBD和Heartbeat实现,这种方案要注意心跳线的问题,防止脑裂产生,建议使用2-3条心跳线,如串口Null Modem Cable,交叉网线,fence(Drac/IPMI,iLO,RSA-II)。

其它考虑:
操作系统和malloc
操作系统使用基于RHEL源码的CentOS6,在国内,由于红帽的技术支持十分单薄,有没有技术支持差别不大。centos6是基于2.6.32的内核,支持RSS,FUSE等。
TCmalloc:是google使用C++实现的malloc,对多线程支持相当好,内存使用的稳定性远好于libc的malloc,另外基于BSD的jemalloc也是可以考虑的。本人在mariaDB,nginx,redis的使用中都使用了TCmalloc,但拒绝使用LD_PRELOAD方式。

集中式session
为了增强系统的可扩展性,可以考虑share nothing的架构,将session用redis集中管理,tomcat的redis session插件可参照 https://github.com/jcoleman/tomcat-redis-session-manager
同样也可实用session wrapper的方式将httpsession转换为redis数据
这样可以避免传统集群session复制的低效,session sticky的用户体验差等问题。
redis是高效动态分配内存的KV内存数据库,比之memacached没有命中问题,并且有多种实用数据结构
redis的可以使用原作者redis sentinel的HA方案,具体见 http://redis.io/topics/sentinel

代码检查
java是最流行的企业应用开发语言,有大量的开发着,但是水平是参差不齐的。尤其是一些过度设计的框架,如hibernate,struts2(webwork时尚好)。使用不到位都会使JVM变得不稳定,性能出现波动,乃至假死。使用findbug/PMD来检查代码隐含的漏洞,这是一个较简单的提升代码质量的方法,能解决一部分问题。就我的经验,即便是IBM的开发人员(其实也是外包),检查一下也是大批的BUG。更多信息见 类国企的软件开发过程和工具集

运维监控
系统的可靠性依赖好的运维策略,对于上述的架构,计算了以下整体可靠性在99.7左右,离4个9还有不少差距。主要是数据库的问题,用ISCSI块共享存储要好很多。这个另外讨论。
那么自动化的运维监控就是解决问题的一个补充。(我们公司在这方面做的有点 ,而且还发明了好多新词,如巡检,呵呵,虽然我不是专注运维的)
使用cacti+nagios实现图形化的监控网络流量,主机资源,服务健壮性等。从而实现实时的故障通知,运维人员可以第一时间查找和处理问题。加上系统架构设计的是可以优雅的重启,所以会快速恢复普通故障。
细节不写了,上两张监控图做纪念。
mysql的

nagios的


乱七八糟的写了一些,作为告别IT行当前回顾这10年的工作的第一篇文章。
另外建议女ITer趁早离开技术行当,别像我一样傻傻的坚持了10年。

猜你喜欢

转载自hanxuebo.iteye.com/blog/1844972