现象:
项目后端服务器几乎全部以c++完成,svr的基础建立在一个比较简陋的多路复用socket框架上面,
整个大的项目架构是一年多前建立的,随着:
1) 产品需求变化反复,代码为应付需求改来改去,夹杂了非常多的临时的业务逻辑,几乎没有任何
文档(有些需求确实太小太临时了,根本不会去维护一份文档,也没有地方去维护,基本上文档
只是用来说明svr大体架构的);
2) 开发人员的来来去去,有些代码多次易手,开发人员素质能力的良莠不齐导致代码风格迥异,有些
陈年svr已经很难去阅读维护,腐化的不行;
3) 因为只有一个简陋的socket框架,用起来不怎么方便,开发人员会根据自己的喜好在此基础上
进行一些自己的包装,于是产生了很多库,这些库代码风格各异,质量层次不齐,有些就完全只是
开发人员自己用,自然库的接口乱七八糟,随着业务需求变化库的接口随意变化是经常的事情;
时间一长,人员调整,最后发现:这些库根本没有带来好处,没有产生技术积累积淀应该带来的
好处,反而成了非常称重的一份累赘,不维护不行,维护代价也非常大;
反思:
记得06年刚刚从学校毕业,进入迅雷,做的第一个产品是迅雷博客,这个产品虽然最后失败了,但
失败的是产品定位,从架构上从技术上来说应该都可以说是成功的;这个产品经历了两年多,需求自然
也经常改了改,但整个架构和代码没有像现在的项目这样腐化的不行;现在想来,这个项目技术上能
成功缘由两个字“简单”,简单的 mysql+apache+fcgi+动静互配cache,甚至没有写一个像样的svr;
kiss 原则,keep it simple stupid,最简单的就是最好的;
那过去我们为什么要采用这些“复杂高级”技术呢?工作了多年,有很多感受:
1) 为了性能
cgi,fcg -> 简单的多进程阻塞svr -> 非常粗陋的异步多路复用svr -> 精致的异步多路
复用svr -> 多线程异步多路复用svr(seda)
上面就是工作中用到的主要开发框架,随着时间的推移,一步一步前进,一步一步高级,
一切都为了追求高性能,高并发...从最初的鄙视cgi,fcg,鄙视php,时间一长甚至都忘了
cgi,fcg,php的存在;每碰到什么需求,条件反射的会思考,怎么搭svr满足这个需求;
反思:过早的优化是万恶之源
一问:性能真的这么重要么?
产品都还没出来,甚至产品方向都还确定的时候,开发高并发高吞吐量的svr有什么屁用?
产品最最重要的是能用,能提供稳定的服务;而不是开发了n久才出来,看起来高并发高服务
能力,却到处暗藏bug,动不动就core的服务;快速的搭建出一个能用的原型,然后迅速推向
市场,推到用户面前,然后不断的改进用户体验,满足用户需求才是最重要的;
在一个用户都没有的时候想着用户千万,pv过亿,不切实际;系统架构是要预估,但预估
最多10倍,而不是幻想中的100,1000倍;
二问:cgi,fcg,php 很菜吗?
现在的项目组开发人员碰到需求,想都不用就是怎么自己搭svr去实现,因为在很长一段
时间内,cgi,fcg 成了性能低下的代表,php成了菜鸟采用的工具;其实想想facebook,
每天pv几十亿,php用的非常广泛...
对,cgi,fcg,php是阻塞的,如果一个工作进程阻塞住,是没法做其他工作的;但其实
仔细算算,假设起100个php工作,每个请求话费50ms,全力工作,一天按16个有效工作时间
每天服务请求=100*20*3600*16=115200000,是1.1亿请求,这么大的一个请求,这个产品已经
非常成功了...
三问:如果cgi,fcg,php真顶不住了,是不是要自己写svr解决?
恭喜啊,产品非常成功,在这个100产品,99个失败的环境下,很不容易;
站着什么都不做是最好的解决方案,机器是廉价的,宁肯浪费机器一个小时,绝不浪费人一
分钟;加机器能解决的问题不是问题...
其实:不带状态,不需要在内存中一直维护的业务,php+mysql+nginx+memcache之类的架构足矣
阻塞就阻塞吧,够用就好,异步非阻塞,何必呢????
项目:比如下载验证,常用的svr agent等模块,完全可以拿上面或其他类似的架构实现
2) 成熟的架构,开源的技术用的过少
或者是视野不开阔,对业界已有的成熟架构和技术不熟悉;或者是满足现状,习惯了问题习惯
了bug,即使知道有成熟的架构和技术,也视而不见;或者是有畏惧心理,一是担心开源的东西
不牢靠,另外担心掌握这些开源的东西学习成本高,所以干脆埋头苦干...
成熟的架构和开源的架构确实是有学习成本的,另外很多东西不是直接拿过来就可以用的,需
要用一些手段和技术整合到现有的业务大框架中的;
于是现在项目中开发人员还经常要去写一些早已经被写过n次的东西,比如lru数据结构;于是
还经常写dbp就为了在db前面挡层cache...
就感觉一群人还处在刀耕火种的原始社会,什么都自己发明,什么都自己创造,结果千奇百怪
良莠不齐的轮子满项目都是,看似什么都有,却什么都不能放心的用;svr中到处是看起来差不多
的代码,似重复又还真有一两处不一样...一个简单的svr动不动就是几十个文件,看进去发现
其实就为了实现一个非常的代理分发功能...查个问题,要一头扎进那些是是非非的代码中去,
改处简单的不能再简单的地方,都要反反复复上上下下检查一遍,然后自测,提测...
其实:开源项目的质量远比我们想像的高多了,开源的东西有时好用的用了会上瘾,开源项目
对于我们的帮助是非常大的...业界早已经有好多开源的东西,视野开阔点!!!
项目:去年年初写了大量代码,非常复杂的业务逻辑,异常复杂的异步调用,状态机貌似都
不够用了...自定义二进制协议,编解码手工完成,svr的client要写出来都不是一件简单
的事情用c++去写client生不如死,感觉恶心到快不行了;
后来用上了 thrift 做编解码,然后狠狠的包装了下,包装到后面,用起来根本感觉不到
他的存在,但他又实实在在的帮了大忙;这个玩意貌似倒成了我们开发的一个好帮手了。
前段时间改一个非常旧的svr,里面还是用的二进制自定义协议,完全没了改的动力。
于是干脆重写,重写都比直接在旧的上面还省力...
为什么那么多种代码风格?为什么那么多不通用的东西?为什么那些代码那么容易就腐化了?
基础技术积淀太浅导致了这些问题,因为没有一些固有的东西,要实现一些东西,只能自己随意
造,而开发人员的素质良莠不齐,造出来的东西可能bug问题重重,就不用说沉淀了;不能沉淀
的后果是:后面的人抛弃前面的人的代码,自起炉灶,然后引出了新的问题;再后面的人又抛弃
前人的代码...就这样循环,不停的写,不停的抛弃...
代码越写的精炼,越写的简洁,越写的有技术含量,自然系统就越稳固;于是系统的质量就
完全依赖于开发人员的素质高低;然而一个项目组里面肯定有些人代码写的比较烂,于是项目很
容易在那里开始烂...
一个过于依赖开发人员的素质的项目是很难的,一来不可能保证所有的开发人员能力都那么
牛逼,二来项目很容易被开发人员所左右,离职对于开发人员来说是很正常的;
拿对面的腾讯来说,他们有大量的基础固件,经常搭一个svr对于任何一个开发人员来说
都是非常容易的,而且生成的svr就包括了大量的功能(比如监控,统计,流量控制,防雪崩,
防过载等等),这样就不再需要开发人员做这些对他们有难度的工作,他们只需要关心比较简单
的业务逻辑了;如果一个开发人员连这个工作都不能胜任的话,那直接可以开掉了...
纯业务的代码本身还是比较容易理解,改来改去,也就是那个地方,腐化也仅仅是那一处的
腐化,而不是像现在有的项目,从上到下都腐化了...
架构在大量基础固件上的代码,代码行数文件数就要少好多好多,而代码行数其实和代码质量
是有极大关系的,越复杂的代码越容易产生bug,也越容易腐化;
代码越少越好,直至最后无代码境地...当然无代码不可能,但如果能在完成需求的基础
上保证代码越少越好,绝对是有利而无弊的;
可能大量的基础固件会束缚某些人的创造性,但其实很多开发人员创造出来的东西的价值
远比他造成的问题要低的多...
那为什么腾讯有,而迅雷没有呢,一:不重视,二:没有好的产品驱动;好的基础固件是从
业务研发中诞生的,绝对不是凭空想象出来的,脱离业务的基础固件是虚幻的毫无用处的(
以前公司貌似有人是专门来做这个技术支撑的,但后面没戏了,完全脱离业务的玩意没人用);好
的产品推动基础固件升级,好的固件支持产品更加优秀,两者是相辅相成,互相推动的;陷入到
先有蛋还是先有鸡的问题上去了;好在迅雷还是有些蛋的....
说说自动化的问题,有个观点:能让机器完成的绝不让开发人员去完成,一是因为能让机器
完成,没必要让开发人员去完成,人都是会犯错的,再优秀的开发人员也无法避免;二是确实很
多开发人员其实没能力去完成或者说完成不了...
其实:代码越少越好,能自动化的绝对自动化,尽量减少对开发人员的依赖...
项目:在原来的socket框架上保证了一层,终于写一个svr文件数目只需要几个了,降到了原来
的20%左右,看起来就要清晰不少;基础固件的作用是非常明显的;