软件开发领域有一个流行的原则:DRY,Don’t repeat yourself。翻译过来更通俗易懂:不要重复造轮子。开源项目的主要目的是共享,其实就是为了让你们不要重复造轮子,尤为是在互联网这样一个快速发展的领域,速度就是生命,引入开源项目能够节省大量的人力和时间,大大加快业务的发展速度,何乐而不为呢?html
然而现实每每没有那么美好,开源项目虽然节省了大量的人力和时间,但带来的问题也很多,相信绝大部分技术人员都踩过开源软件的坑,小的影响多是宕机半小时,大的问题多是丢失几十万条数据,甚至灾难性的事故是所有数据都丢失。mysql
除此之外,虽然 DRY 原则摆在那里,但实际上开源项目反而是最不遵照 DRY 原则的,重复的轮子好多,你有 MySQL,我有 PostgreSQL;你有 MongoDB,我有 Cassandra;你有 Memcached,我有 Redis;你有 Gson,我有 Jackson;你有 Angular,我有 React……总之放眼望去,其实类似的轮子不少!类似轮子太多,如何选择就成了让人头疼的问题了。程序员
怎么办?彻底不用开源项目几乎是不可能的,架构师须要更加聪明地选择和使用开源项目。形象点说:不要重复发明轮子,但要找到合适的轮子!但别忘了,若是你开的是保时捷,可别找个拖拉机的轮子。sql
1. 聚焦是否知足业务缓存
架构师在选择开源项目时,一个头疼的问题就是类似的开源项目较多,并且后面的老是要宣称比前面的更加优秀。有的架构师在选择时有点无所适从,老是会担忧选择了 A 项目而错过了 B 项目。这个问题的解决方式是聚焦因而否知足业务,而不须要过于关注开源项目是否优秀。网络
Tokyo Tyrant 的教训
在开发一个社交类业务时,咱们使用了 TT(Tokyo Tyrant)开源项目,以为既可以作缓存取代 Memcached,又有持久化存储功能,还能够取代 MySQL,以为很强大,因而就在业务里面大量使用了。但后来的使用过程让人很郁闷,主要表现为:架构
不能彻底取代 MySQL,所以有两份存储,设计时每次都要讨论和决策究竟什么数据放 MySQL,什么数据放 TT。负载均衡
功能上看起来很高大上,但相应的 bug 也很多,并且有的 bug 是致命的。例如全部数据不可读,后来是本身研究源码写了一个工具才恢复了部分数据。框架
功能确实强大,但须要花费较长时间熟悉各类细节,不熟悉随便用很容易踩坑。运维
后来咱们反思和总结,其实当时的业务 Memcached + MySQL 彻底可以知足,并且你们都熟悉,其实彻底不须要引入 TT。
简单来讲:若是你的业务要求 1000 TPS,那么一个 20000 TPS 和 50000 TPS 的项目是没有区别的。有的架构师可能会担忧 TPS 不断上涨怎么办?其实不用过于担忧,架构是能够不断演进的,等到真的须要这么高的时候再来架构重构,这里的设计决策遵循架构设计原则中的“合适原则”和”演化原则”。
2. 聚焦是否成熟
不少新的开源项目每每都会声称本身比之前的项目更加优秀:性能更高、功能更强、引入更多新概念……看起来都很诱人,但实际上都有意无心地隐藏了一个负面的问题:更加不成熟!无论多优秀的程序员写出来的项目都会有 bug,千万不要觉得做者历害就没有 bug,Windows、Linux、MySQL 的开发者都是顶级的开发者,系统同样有不少 bug。
不成熟的开源项目应用到生产环境,风险极大:轻则宕机,重则宕机后重启都恢复不了,更严重的是数据丢失都找不回来。仍是以我上面提到的 TT 为例:咱们真的遇到异常断电后,文件被损坏,重启也恢复不了的故障。还好当时天天作了备份,因而只能用 1 天前的数据进行恢复,但当天的数据所有丢失了。后来咱们花费了大量的时间和人力去看源码,本身写工具恢复了部分数据,还好这些数据不是金融相关的数据,丢失一部分问题也不大,不然就有大麻烦了。
因此在选择开源项目时,尽可能选择成熟的开源项目,下降风险。
你能够从这几个方面考察开源项目是否成熟:
版本号:除非特殊状况,不然不要选 0.X 版本的,至少选 1.X 版本的,版本号越高越好。
使用的公司数量:通常开源项目都会把采用了本身项目的公司列在主页上,公司越大越好,数量越多越好。
社区活跃度:看看社区是否活跃,发帖数、回复数、问题处理速度等。
3. 聚焦运维能力
大部分架构师在选择开源项目时,基本上都是聚焦于技术指标,例如性能、可用性、功能这些评估点,而几乎不会去关注运维方面的能力。但若是要将项目应用到线上生产环境,则运维能力是必不可少的一环,不然一旦出问题,运维、研发、测试都只能干瞪眼,求菩萨保佑了!
你能够从这几个方面去考察运维能力:
开源项目日志是否齐全:有的开源项目日志只有寥寥启动中止几行,出了问题根本没法排查。
开源项目是否有命令行、管理控制台等维护工具,可以看到系统运行时的状况。
开源项目是否有故障检测和恢复的能力,例如告警、切换等。
若是是开源库,例如 Netty 这种网络库,自己是不具有运维能力的,那么就须要在使用库的时候将一些关键信息经过日志记录下来,例如在 Netty 的 Handler 里面打印一些关键日志。
1. 深刻研究,仔细测试
不少人用开源项目,实际上是完彻底全的“拿来主义”,看了几个 Demo,把程序跑起来就开始部署到线上应用了。这就好像看了一下开车指南,知道了方向盘是转向、油门是加速、刹车是减速,而后就开车上路了,实际上是很是危险的。
Elasticsearch 的案例
咱们有团队使用了 Elasticsearch,基本上是拿来就用,倒排索引是什么都不太清楚,配置都是用默认值,跑起来就上线了,结果就遇到节点 ping 时间太长,剔除异常节点太慢,致使整站访问挂掉。
MySQL 的案例
不少团队最初使用 MySQL 时,也没有怎么研究过,常常有业务部门抱怨 MySQL 太慢了。但通过定位,发现最关键的几个参数(例如,innodb_buffer_pool_size、sync_binlog、innodb_log_file_size 等)都没有配置或者配置错误,性能固然会慢。
你能够从这几方面进行研究和测试,更详细的完整方法能够参考专栏特别放送《如何高效的学习开源项目》:
通读开源项目的设计文档或者白皮书,了解其设计原理。
核对每一个配置项的做用和影响,识别出关键配置项。
进行多种场景的性能测试。
进行压力测试,连续跑几天,观察 CPU、内存、磁盘 I/O 等指标波动。
进行故障测试:kill、断电、拔网线、重启 100 次以上、切换等。
2. 当心应用,灰度发布
假如咱们作了上面的“深刻研究、仔细测试”,发现没什么问题,是否就能够放心大胆地应用到线上了呢?别高兴太早,即便你的研究再深刻,测试再仔细,仍是要当心为妙,由于再怎么深刻地研究,再怎么仔细地测试,都只能下降风险,但不可能彻底覆盖全部线上场景。
Tokyo Tyrant 的教训
仍是以 TT 为例,其实咱们在应用以前专门安排一个高手看源码、作测试,作了大约 1 个月,但最后上线仍是遇到各类问题。线上生产环境的复杂度,真的不是测试可以覆盖的,必须当心谨慎。
因此,无论研究多深刻、测试多仔细、自信心多爆棚,时刻对线上环境和风险要有敬畏之心,当心驶得万年船。咱们的经验就是先在非核心的业务上用,而后有经验后慢慢扩展。
3. 作好应急,以防万一
即便咱们前面的工做作得很是完善和充分,也不能认为万事大吉,尤为是刚开始使用一个开源项目,运气很差可能遇到一个以前全世界的使用者历来没遇到的 bug,致使业务都没法恢复,尤为是存储方面,一旦出现问题没法恢复,可能就是致命的打击。
MongoDB 丢失数据
某个业务使用了 MongoDB,结果宕机后部分数据丢失,没法恢复,也没有其余备份,人工恢复都没办法,只能接一个用户投诉处理一个,致使 DBA 和运维今后之后都反对咱们用 MongoDB,即便是尝试性的。
虽然由于一次故障就彻底反对尝试是有点反应过分了,但确实故障也给咱们提了一个醒:对于重要的业务或者数据,使用开源项目时,最好有另一个比较成熟的方案作备份,尤为是数据存储。例如,若是要用 MongoDB 或者 Redis,能够用 MySQL 作备份存储。这样作虽然复杂度和成本高一些,但关键时刻可以救命!
1. 保持纯洁,加以包装
当咱们发现开源项目有的地方不知足咱们的需求时,天然会有一种去改改的冲动,可是怎么改是个大学问。一种方式是投入几我的从内到外所有改一遍,将其改形成彻底符合咱们业务需求。但这样作有几个比较严重的问题:
投入太大,通常来讲,Redis 这种级别的开源项目,真要本身改,至少要投入 2 我的,搞 1 个月以上。
失去了跟随原项目演进的能力:改的太多,即便原有开源项目继续演进,也没法合并了,由于差别太大。
因此个人建议是不要改动原系统,而是要开发辅助系统:监控、报警、负载均衡、管理等。以 Redis 为例,若是咱们想增长集群功能,则不要去改动 Redis 自己的实现,而是增长一个 proxy 层来实现。Twitter 的 Twemproxy 就是这样作的,而 Redis 到了 3.0 后自己提供了集群功能,原有的方案简单切换到 Redis 3.0 便可(详细可参考这里)。
若是实在想改到原有系统,怎么办呢?咱们的建议是直接给开源项目提需求或者 bug,但弊端就是响应比较缓慢,这个就要看业务紧急程度了,若是实在太急那就只能本身改了;若是不是太急,建议作好备份或者应急手段便可。
2. 发明你要的轮子
这一点估计让你大跌眼镜,怎么讲了半天,最后又回到了“重复发明你要的轮子”呢?
其实选与不选开源项目,核心仍是一个成本和收益的问题,并非说选择开源项目就必定是最优的项目,最主要的问题是:没有彻底适合你的轮子!
软件领域和硬件领域最大的不一样就是软件领域没有绝对的工业标准,你们都很尽兴,想怎么玩就怎么玩。不像硬件领域,你造一个尺寸不同凡响的轮子,其余车都用不上,你的轮子工艺再高,质量再好也是白费;软件领域能够造不少类似的轮子,基本上能处处用。例如,把缓存从 Memcached 换成 Redis,不会有太大的问题。
除此之外,开源项目为了可以大规模应用,考虑的是通用的处理方案,而不一样的业务其实差别较大,通用方案并不必定完美适合具体的某个业务。好比说 Memcached,经过一致性 Hash 提供集群功能,可是咱们的一些业务,缓存若是有一台宕机,整个业务可能就被拖慢了,这就要求咱们提供缓存备份的功能。但 Memcached 又没有,而 Redis 当时又没有集群功能,因而咱们投入 2~4 我的花了大约 2 个月时间基于 LevelDB 的原理,本身作了一套缓存框架支持存储、备份、集群的功能,后来又在这个框架的基础上增长了跨机房同步的功能,很大程度上提高了业务的可用性水平。若是彻底采用开源项目,等开源项目来实现,是不可能这么快速的,甚至开源项目彻底就不支持咱们的需求。
因此,若是你有钱有人有时间,投入人力去重复发明完美符合本身业务特色的轮子也是很好的选择!毕竟,不少财大气粗的公司(BAT 等)都是这样作的,不然咱们也就没有那么多好用的开源项目了。