极客时间已完结课程限时免费阅读

48 | 再谈开源项目:如何选择、使用以及二次开发?

48 | 再谈开源项目:如何选择、使用以及二次开发?-极客时间

48 | 再谈开源项目:如何选择、使用以及二次开发?

讲述:黄洲君

时长14:08大小6.47M

我在专栏特别放送第 3 期谈了如何高效地学习开源项目,主要聊了我在学习开源项目的一些看法和步骤。今天我们再聊开源项目,谈谈如何选择、使用以及二次开发
软件开发领域有一个流行的原则:DRY,Don’t repeat yourself。翻译过来更通俗易懂:不要重复造轮子。开源项目的主要目的是共享,其实就是为了让大家不要重复造轮子,尤其是在互联网这样一个快速发展的领域,速度就是生命,引入开源项目可以节省大量的人力和时间,大大加快业务的发展速度,何乐而不为呢?
然而现实往往没有那么美好,开源项目虽然节省了大量的人力和时间,但带来的问题也不少,相信绝大部分技术人员都踩过开源软件的坑,小的影响可能是宕机半小时,大的问题可能是丢失几十万条数据,甚至灾难性的事故是全部数据都丢失。
除此以外,虽然 DRY 原则摆在那里,但实际上开源项目反而是最不遵守 DRY 原则的,重复的轮子好多,你有 MySQL,我有 PostgreSQL;你有 MongoDB,我有 Cassandra;你有 Memcached,我有 Redis;你有 Gson,我有 Jackson;你有 Angular,我有 React……总之放眼望去,其实相似的轮子很多!相似轮子太多,如何选择就成了让人头疼的问题了。
怎么办?完全不用开源项目几乎是不可能的,架构师需要更加聪明地选择和使用开源项目。形象点说:不要重复发明轮子,但要找到合适的轮子!但别忘了,如果你开的是保时捷,可别找个拖拉机的轮子。

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

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 等)都是这样做的,否则我们也就没有那么多好用的开源项目了。

小结

今天我从如何选、如何用和如何改三个方面,为你讲了如何才能用好开源项目,希望对你有所帮助。
这就是今天的全部内容,留一道思考题给你吧,目前的云计算厂商很多都提供了和开源项目类似的系统(例如阿里云的云数据库 HBase),你倾向于购买云厂商提供的系统,还是只是将开源系统部署在云服务器上?理由是什么?
欢迎你把答案写到留言区,和我一起讨论。相信经过深度思考的回答,也会让你对知识的理解更加深刻。(编辑乱入:精彩的留言有机会获得丰厚福利哦!)
分享给需要的人,Ta购买本课程,你将得20
生成海报并分享

赞 20

提建议

上一篇
47 | 架构重构内功心法第三式:运筹帷幄
下一篇
49 | 谈谈App架构的演进
unpreview
 写留言

精选留言(36)

  • 何磊
    2018-08-16
    如果公司规模小建议可以直接使用云厂商的产品,因为运维方便。但是如果业务大,很多个性化的配置以及有自己的整套监控系统等,不适合用云厂商产品,无法进行系统整合。

    作者回复: 点赞👍

    55
  • 文竹
    2018-08-26
    依据情况做出选择。比如:我们公司有些组件,mysql,redis都是使用阿里云上的。数据平台则是自己搭建的。 使用云上的mysql,redis省去了很多运维成本和一些复杂性问题,不如高可用,高性能。总的来说成本较低。 自己搭建数据平台有如下原因: 1、集团下面有很多子公司,如果每个公司都要自己专门处理大量数据的话,总合计成本很高。 2、技术更容易沉淀,能更有效地为集团产业链提供服务。
    展开

    作者回复: 你们的思路挺好,大数据确实要统一维护

    26
  • 问题究竟系边度
    2018-08-20
    业务初期,云平台本身提供的服务性能已经满足需求了,同时提供可视化运维,极大降低运维和部署成本,同时有熟悉的专家团队帮忙特殊问题。 业务发展后,在考虑根据业务特性做定制开发

    作者回复: 正解,参考架构设计的合适原则

    16
  • William
    2018-08-16
    个人认为: 用云产品的好处是,1.方便快捷,既然是产品那肯定经过包装,对很多bug进行了处理,因此上手快和使用方便;2.云产品自带维护功能,专业性比自建强,不用自己投入大量人力到维护的事情上; 缺点也有两个:1.羊毛出在羊身上,自带维护功能,意味着费用也会贵一些;2.维护交给第三方,意味着依赖第三方,出现影响业务的紧急情况可能出现支撑不到位,响应缓慢,解决问题需要时间长等问题; 自己用云服务器搭建的话,自己还是得亲力亲为,坑要自己踩,出现问题自己解决,但是也相应的灵活,有些问题可以结合业务情况来回避。
    展开

    作者回复: 正确👍👍👍

    11
  • SeeSharp
    2018-08-16
    我身边很多人有个坏习惯,开源库版本喜欢用最新稳定版–0.1,以为遇到坑可以在网上获得别人的解决方案,真遇到坑的时候自己又没有能力改或者已经被最新稳定版fix了要么手动把这单个bug fix搬过去要么被迫升版本,怎么劝都劝不动

    作者回复: 哈哈,确实如此,其实我建议用最新的稳定版就可以了

    8
  • 2019-09-04
    课后思考及问题 目前的云计算厂商很多都提供了和开源项目类似的系统(例如阿里云的云数据库 HBase),你倾向于购买云厂商提供的系统,还是只是将开源系统部署在云服务器上?理由是什么? 我会倾向于购买云厂商提供的系统 理由:如果实力够(不差钱,不差人),最好自己弄,既然购买了云服务器,应该有人钱的短板,既然如此何不再多花一下买下对于的服务,应该更加的省心省事,运维应该也更加方便。当然,视公司发展情况而定,后面自己研究或整个都用自己的都行。 1:本文核心观点 1-1:不要重复发明轮子,但要找到合适的轮子! 1-2:如何找到合适的轮子? 聚焦于是否满足业务,而不需要过于关注开源项目是否优秀 聚焦是否成熟,尽量选择成熟的开源项目,降低风险 运维能力是必不可少的一环 1-3:如何用好轮子? 深入研究,仔细测试 小心应用,灰度发布 做好应急,以防万一 1-4:如何仿造轮子? 保持纯洁,加以包装 发明你要的轮子
    展开
    6
  • pding
    2020-05-23
    团队、业务从小到大,对于开源项目的应用也是不同的方式,从不用,拿来就用,附加功能开发到最后的自己造轮子。在这个过程,BUG都是无法避免,要做的是备份、容灾,做好运维,管理好风险!

    作者回复: 总结到位

    5
  • Jun
    2019-12-22
    我倾向于直接用服务。第一,运维压力小。云厂商会提供大部分基础架构的运维和调优。客户集中精力在业务运维。第二,上线扩容方便快速。客户可以自己申请新实例。但安装和配置都是问题,也无法利用云厂商已有的经验。这些经验都是其他客户血泪基础上得到的,非常宝贵。第三,软件升级有保障。新版本不一定兼容,也许有bug。自己升级需要大量人力物力确认。第四,出了问题有人背锅。

    作者回复: 云服务是大趋势了

    共 3 条评论
    5
  • 小喵喵
    2018-08-20
    为了存储高可用,比如在 mongdb写一份,然后在MySQL也写一份,具体怎么写呢?是写找到mongdb,然后由mongdb同步到MySQL吗?还是有其他更好的方法?

    作者回复: 1. 代码写两次,简单粗暴,但可能数据不一致 2. 脚本同步,但可能出现同步延迟导致数据丢失一部分

    共 2 条评论
    4
  • 呵呵
    2018-08-18
    DRY,不是说的是不要随意复制、粘贴代码么

    作者回复: 代码层面不要拷贝粘贴,设计层面不要重复发明轮子

    5
  • 李培
    2020-10-04
    小公司还是建议用云厂商的,有以下原因: 1、运维成本低,买来即用。 2、弹性伸缩方便。 3、可以做到运维可视化,并且方便权限管理。

    作者回复: 是的,现在小公司优先云厂商的产品

    2
  • caohuan
    2018-11-12
    先回答华仔的问题,觉得 根据 业务需求 来选择 云平台 还是 开源软件,如果是 常规性的需求 云平台 就可以满足,如果 有特殊一点的需求,可能需要 自己开发新的模块 满足需求,云平台 一般不提供 你一家 公司 需要的技术。 本篇专栏 所得,1.不要重复造轮子 2.寻找满足自己所需业务的开源软件 3.选择 成熟的开源 ,关注运维能力,然后仔细测试、小心应用,从非功能性慢慢切换到功能性上应用,最后做好应急方案 4.造适合自己所需求的轮子,应用开源软件的绝好模板。
    展开
    2
  • 波波安
    2018-09-05
    根据团队的开发实力来决定吧。前期团队小,业务量不大,可以购买成熟方案。

    作者回复: 正解

    3
  • 谭方敏
    2020-03-16
    不要重复发明轮子,但要找到合适的轮子 选:如何选择一个开源项目 聚焦是否满足业务 聚焦于是否满足业务,而不是需要过于关注开源项目是否优秀。 聚焦是否成熟 尽量选择成熟的开源项目,降低风险。 判断开源项目是否成熟: 1)版本号,除非特殊情况,否则不要选择0.x版本的,至少选1.x版本的,版本号越高越好。 2)使用的公司数量:一般开源项目都会把采用了自己项目的公司列在主页上,公司越大越好,数据越多越好。 3)社区活跃度:看看社区是否活跃,发帖数,回复数,问题处理速度等。 聚焦运维能力 考察运维能力的指标: 开源项目日志是否齐全:有的开源项目日志只有廖廖启动停止几行,出了问题根本无法排查。 开源项目是否有命令行,管理控制台等维护工具,能够看到系统运行时的情况。 开源项目是否有故障检测和恢复的能力,例如告警,切换等。 用:如何使用开源项目 1深入研究,仔细测试 通读开源项目的设计文档或者白皮书,了解其设计原理。 核对每个配置项的作用和影响,识别出关键配置项。 进行多种场景的性能测试。 进行压力测试,连续跑几天,观察cpu,内存,磁盘l/o等指标波动。 进行故障测试:kill,断电,拔网线,重启100次以上,切换等。 2 小心应用,灰度发布 即使你的研究再深入,测试再仔细,还是要小心为妙,因为再怎么深入地研究,再怎么仔细测试,都只能降低风险,但不可能完全覆盖所有线上场景。 3 做好应急,以防万一 对于重要的业务或者数据,使用开源项目时,最好有另外一个比较成熟的方案做备份,尤其是数据存储。 改:如何基于开源项目做二次开发 1 保持纯洁,加以包装 不要改动原系统,而是要开发辅助系统:监控,报警,负载均衡,管理等,如果要增加集群功能,不要去改动redis本身实现,而是增加一个proxy层,比如Twitter 的twemproxy就是这样的,而redis到3.0后本身提供了集群功能,原有的方案简单切换至redis3.0即可。 如果实在想改到原有系统,怎么办?我们得建议是直接给开源项目提需求或者bug,但弊端就是响应比较慢,这个要看业务紧急程度了,如果实在太急那就只能自己修改了,如果不是太急,建议做好备份或者应急手段即可。 2 发明你要的轮子 没有完全适合你的轮子 我们现在的做法是讲开源系统部署在云服务器上,原因有二,1)方便我们自己用,我们有绝对的掌控权,如果出现云厂商提供的系统问题,担心会找不到人协助,这样耽误进度。2)从成本的角度来说,有利于节约成本,特别在用户规模没那么大的初创公司中,这笔开销还不少,至少要等业务到百万级以上,才有使用云厂商的可能性。
    展开
    共 1 条评论
    1
  • Xg huang
    2018-08-16
    如果在业务的初始期,项目规模不大的时候,可以考虑直接购买云平台提供的开源服务,因为使用方便,运维成本相对更低。 随着项目规模变大,如果需要对开源服务做更定制化的开发,就可以考虑自己搭建。这样做不仅开发效率高,而且保持以后云平台迁移的灵活性

    作者回复: 正确👍

    2
  • 右左
    2018-08-16
    讲开源项目部署到云服务,这样更灵活,后期还可以自己封装,写辅助系统等

    作者回复: 看看其他人的回答😄

    1
  • 初见
    2022-06-30
    看技术和运维团队的技术水平,如果资源不够或者水平不够,直接买云厂商的产品,成熟,稳定,出问题有人支持解决,有完善的监控运维工具,比自己建设成本低非常多。

    作者回复: 现在除非大公司,基本上用云厂商的没错

    1
  • 小康
    2021-09-01
    Zookeeper项目ZAB我确实不精,老师有没有那个开源项目比较好阅读并且贡献代码,我想贡献代码逆袭,证明自己的能力,我学历比较低,大专自考的,很多公司卡学历,但是我没有放弃学习,不断的学习中.

    作者回复: 贡献代码并不是一条好走和好的路,你找一些国产的开源项目试试看,比如TiDB、APISIX这些,复杂度不会太高,也容易交流沟通

  • 小康
    2021-08-31
    老师,就是那个zookeeper ,看了一年多源码,都没看懂思路,就是搞懂了里面的分布式原理选举机制leases, 代码看完了,改造或者优化代码没思路,想贡献代码,不知道怎么下手?

    作者回复: 这个项目你还是别想着贡献代码了,算法的实现细节太多了,你对ZAB算法本身不精的话,算法逻辑都理不清楚,更谈不上贡献代码了 :)

  • 小康
    2021-08-29
    老师,你好,我研究了一个开源项目一年多了,主要是代码量太大了,也想给这个项目贡献代码,结果写代码思路不清晰,不知道怎么下手,

    作者回复: 你至少要告诉我你研究的是哪个项目呀

    共 2 条评论