7

使用开源项目的正确姿势,都是血和泪的总结!

 3 years ago
source link: http://www.androidchina.net/8548.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
使用开源项目的正确姿势,都是血和泪的总结! – Android开发中文站
你的位置:Android开发中文站 > 热点资讯 > 使用开源项目的正确姿势,都是血和泪的总结!

640?wx_fmt=jpeg&wxfrom=5&wx_lazy=1

阿里妹导读:开源精神是技术发展的源动力之一,受到工程师们的热烈欢迎。但是开源项目如此之多,哪一个最适合自己?如何更好利用开源项目,甚至做二次开发?今天,阿里资深无线开发专家李运华,总结多年与开源项目打交道的经验,讲述如何正确利用开源项目,希望对大家有所启发。

软件开发领域有一个流行的原则:DRY,Don’t repeat yourself,我们翻译过来更形象通俗:不要重复造轮子。开源项目主要目的是共享,其实就是为了让大家不要重复造轮子,尤其是在互联网这样一个快速发展的领域,速度就是生命,引入开源项目,可以节省大量的人力和时间,大大加快业务的发展速度,何乐而不为呢?

然而现实往往没有那么美好,开源项目虽然节省了大量的人力和时间,但带来的问题也不少,相信绝大部分同学都踩过开源软件的坑,小的影响可能是宕机半小时,大的问题可能是丢失几十万数据,甚至灾难性的事故是全部数据都丢失。

除此以外,虽然DRY原则摆在那里,但实际上开源项目反而是最不遵守DRY原则的,重复的轮子好多,尤其是歪果仁,一看哪个开源方案不爽,自己就吭哧吭哧搞一个差不多的:你有MySQL,我有PostgreSQL;你有MongoDB,我有Cassandra;你有memcached,我有redis;你有Gson,我有Jackson;你有Angular,我有React。总之放眼望去,其实相似的轮子很多!相似轮子太多,选择就是让人头疼的问题了。

怎么办?完全不用开源项目几乎是不可能的,我们需要更加聪明的去选择和使用开源项目。形象点说:不要重复发明轮子,但要找到合适的轮子!你开的是保时捷,可别找个拖拉机的轮子。

接下来我将根据加入UC,5年与开源项目有关的经历,总结出一些“如何正确使用开源项目”的经验和教训。有的项目是我亲身经历,有的是我接触到的,有的是我观察的,其中部分描述细节可能并不完全准确,大家可以结合自己的经历一起探讨。

以下内容主要分3个部分进行描述,分别是“选”、“用”、“改”。


选:如何选择一个开源项目?

聚焦是否满足业务?

640?wx_fmt=gif

我们在选择开源项目的时候,一个头疼的问题就是相似的开源方案较多,而且后面的总是要宣称比前面的更加牛逼。我们在选择的时候有点无所适从,总是会担心选择了A方案而错过了B方案,或者反过来。这里我们的经验是聚焦于是否满足业务,而不需要过于关注开源方案是否牛逼。

案例:当时尝试一个社交类业务时,我们发现了TT(Tokyo Tyrant)这个开源方案,觉得既能够做缓存取代Memcached,又有持久化存储功能,可以取代MySQL,很牛逼,很高大上,于是就在业务里面大量使用了。但后来的使用过程让人很蛋疼,主要表现为:

1、不能完全取代MySQL,因此有两份存储,设计的时候每次都要讨论和决策

2、功能上看起来很高大上,但相应的bug也不少,而且有的bug是致命的,例如所有数据不可读,后来是自己研究源码写了一个工具才恢复了部分数据。

3、功能确实牛逼,但需要花费较长时间熟悉各种细节

后来我们反思和总结,其实当时的业务Memcached + MySQL完全能够满足,且大家都熟悉,当时的业务完全不需要引入TT。

简单来说:如果你的业务要求1000 TPS,那么一个20000 TPS 和50000 TPS的方案是没有区别的。有的人可能会担心我TPS不断上涨怎么办?其实不用担心,我们的架构会不断演进的,等到真的需要这么高的时候我们再来架构重构,记住:不要过早优化,过早优化是万恶之源 —— 《UNIX编程哲学》

聚焦是否成熟

很多新的开源项目往往都会声称自己比以前的项目更加牛逼:性能更高、功能更强、引入更多新概念。看起来都很诱人,但实际上都有意无意的隐藏了一个负面的问题:都更加不成熟!不管多牛逼的程序员写出来的项目都会有bug,千万不要以为作者牛逼就没有bug,Windows、Linux、MySQL的开发者都是顶级的开发者吧,一样很多bug。

不成熟的开源项目应用到生产环境,风险极大。轻则宕机,重则宕机后重启都恢复不了,更严重的是数据丢失都找不回了。还是以上面提到的TT为例:我们真的遇到异常断电后,文件被损坏,重启也恢复不了的故障,还好当时每天做了备份,于是只能用1天前的数据进行恢复,但当天的数据全部丢失了。后来我们花费了大量的时间和人力去看源码,自己写工具恢复了部分数据,还好这些数据不是金融相关的数据,丢失一部分问题也不大,否则就有大麻烦了。

所以在选择开源项目的时候,尽量选择成熟的开源项目,降低风险。

可以从以下几个方面考察是否成熟:

1)版本号:一般建议除非特殊情况,否则不要选0.X版本的,至少选1.X版本的,版本号越高越好。

2)使用的公司数量:一般开源项目都会把采用了自己项目的公司列在主页上,公司越大越好,数量越多越好

3)社区活跃度:看看社区是否活跃,发帖数、回复数、问题处理速度等

聚焦运维能力

我们在选择开源项目的时候,基本上都是聚焦于技术指标,例如性能、可靠性、功能这些方案,而几乎不会去关注运维方面的能力。但如果要将方案应用到线上生产环境,运维能力是必不可少的一环,否则一旦出问题,运维、研发、测试都只能干瞪眼,求菩萨保佑了!

可以从以下几个方案去考察运维能力:

1)开源方案日志是否齐全:有的开源方案日志只有寥寥启动停止几行,出了问题根本无法排查

2)开源方案是否有命令行、管理控制台等维护工具,能够看到系统运行时的情况

3)开源方案是否有故障检测和恢复的能力,例如告警、倒换等

用:如何使用开源方案?

深入研究,仔细测试

640?wx_fmt=jpeg

很多人用开源项目,其实是完完全全的“拿来主义”,看了几个Demo,把程序跑起来就开始部署到线上应用了。就好像看了一下开车指南,知道了方向盘是转向、油门是加速、刹车是减速,然后就开车上路了,其实是非常危险的。

案例:我们有团队使用了elasticsearch,基本上是拿来就用,倒排索引是什么不太清楚,配置都是用默认值,跑起来就上线了,结果就遇到节点ping时间太长,剔除异常节点太慢,导致整站访问挂掉。

案例2:很多团队最初使用MySQL的时候,也没有怎么研究过,经常有业务部门抱怨MySQL太慢了,其实经过定位,发现最关键的几个参数(例如innodb_buffer_pool_size, sync_binlog,innodb_log_file_size等)都没有配置或者配置错误,性能当然会慢。

可以从如下几方面进行研究和测试:

1)通读开源项目的设计文档或者白皮书,了解其设计原理

2)核对每个配置项的作用和影响,识别出关键配置项

3)进行多种场景的性能测试

4)进行压力测试,连续跑几天,观察cpu、内存、磁盘io等指标波动

5)进行故障测试:kill,断电、拔网线、重启100次以上、倒换等

‌小心应用,灰度发布

假如我们做了上面的“深入研究、仔细测试”,发现没什么问题,是否就可以放心大胆的应用到线上了呢?别高兴太早,即使你的研究再深入,测试再仔细,也还是要小心为妙,因为再怎么深入的研究,再怎么仔细的测试,都只能降低风险,但不可能完全覆盖所有线上场景。

案例:还是以TT为例吧,其实我们在应用之前专门安排一个大牛看源码、做测试,做了大约1个月,但最后上线还是遇到各种问题。线上生产环境的复杂度,真的不是测试能够覆盖的,必须小心谨慎。

所以,不管研究多深入、测试多仔细、自信心多爆棚,时刻对线上要有敬畏之心,小心驶的万年船。我们的经验就是先在非核心的业务上用,然后有经验后慢慢扩展。

做好应急,以防万一

640?wx_fmt=jpeg

即使我们前面的工作做得非常完善和充分,也不能认为就万事大吉了,尤其是刚开始使用一个开源项目,运气不好的话就可能遇到一个之前全世界的使用者从来没遇到的bug,导致业务都无法恢复,尤其是存储方面,一旦出现问题无法恢复可能就是致命的打击。

案例(此案例是听说的):某个业务使用了MongoDB,结果宕机后部分数据丢失,无法恢复,也没有其它备份,人工恢复都没办法,只能接一个用户投诉处理一个,导致DBA和运维从此以后都反对我们用MongoDB,即使是尝试性的。

虽然因为一次故障就完全反对尝试是有点反应过度了,但确实故障也给我们提了一个醒:对于重要的业务或者数据,使用开源项目时,最好有另外一个比较成熟的方案做备份,尤其是数据存储。例如:如果要用MongoDB或者Redis,可以用MySQL做备份存储。这样做虽然复杂度和成本高一些,但关键时刻能够救命!

改:如何基于开源项目做二次开发?

‌保持纯洁,加以包装

当我们发现开源项目有的地方不满足我们的需求的时候,自然会有一种去改改的冲动,但是怎么改是个大学问。一种方式是投入几个人从内到外全部改一遍,将其改造成完全符合我们业务需求。但这样做有几个比较严重的问题:

1)投入太大,一般来说,redis这种级别的开源方案,真要自己改,至少要投入2个人,搞个1个月以上

2)失去了跟随原方案演进的能力:改的太多的话,即使原有开源项目继续演进,我们也无法合并了,因为差异太大。

所以我们的建议是不要改动原系统,而是要开发辅助系统: 监控,报警,负载均衡,管理等。以Redis为例,如果我们想增加集群功能,不要去改动Redis本身的实现,而是增加一个proxy层来实现,Twitter的Twemproxy就是这样做的,而Redis到了3.0后本身提供了集群功能,原有的方案简单切换到Redis 3.0即可。详细可参考(http://www.cnblogs.com/gomysql/p/4413922.html )

如果实在想改到原有系统,怎么办呢?我们的建议是直接给开源项目提需求或者bug,但弊端就是响应比较缓慢,这个就要看业务紧急程度了,如果实在太急那就只能自己改了,不过不是太急,建议做好备份或者应急手段即可。

发明你要的轮子

640?wx_fmt=jpeg

这点估计让很多人大跌眼镜,怎么讲了半天,最后又回到了“重复发明你要的轮子”呢?

其实选与不选开源项目,核心还是一个成本和收益的问题,并不是说选择开源项目就一定是最优的方案,最主要的问题是:没有完全适合你的轮子!

软件领域和硬件领域最大的不同就是软件领域没有绝对的工业标准,大家都很尽兴,想怎么玩怎么玩,不像硬件领域,你造一个尺寸与众不同的轮子,其它车都用不上,你的轮子工艺再高,质量再好也是白费;软件领域可以造很多相似的轮子,也基本上能到处用,例如你把缓存从Memcached换成Redis,不会有太大的问题。

除此以外,开源项目为了能够大规模应用,考虑的是通用的处理方案,而不同的业务其实差异较大,通用方案并不一定完美适合具体的某个业务。比如说Memcached,通过一致性hash提供集群功能,但是我们的一些业务,缓存如果有一台宕机,整个业务可能就被拖慢了,这就要求我们提供缓存备份的功能,但Memcached又没有,而Redis当时又没有集群功能,于是我们投入2~4个人花了大约2个月时间基于LevelDB的原理,自己做了一套缓存框架支持存储、备份、集群的功能,后来又在这个框架的基础上增加了跨机房同步的功能,很大程度上提升了业务的可用性水平。如果完全采用开源方案,等开源方案来实现,是不可能这么快速的,甚至都有可能开源项目完全就不支持我们的需求。

所以,如果你有钱有人有时间,投入人力去重复发明完美符合自己业务特点的轮子也是很好的选择!毕竟,土豪们(BAT、Facebook、Google……等)很多都是这样做的,否则我们也就没有那么多好用的开源项目了 :)

转载请注明:Android开发中文站 » 使用开源项目的正确姿势,都是血和泪的总结!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK