共计 8480 个字符,预计需要花费 22 分钟才能阅读完成。
作者|一啸
起源|尔达 Erda 公众号
任何大型工程项目的研发都会波及到两个十分共通的难题:
- 第一个是稳定性问题,越大的我的项目越难做稳固,“魔鬼在细节里”;
- 第二个是工程研发效率。
本文咱们先聊聊第二个问题,前面再谈谈 Erda 的稳定性建设。具体议论如何打造大型的工程研发效率之前,先回顾一下我之前在阿里的 8 年研发经验,心愿借此造成一个有带入感的比照。
我在阿里的经验
DataX
我刚毕业退出淘宝后,第一次真正接触的研发工作就是参加 DataX 的开发。
datax 的工作原理就是全量将某个数据库或存储中的数据读出,而后再全量写入到另一个数据库或存储中,总结起来,就是为了将数据从一个中央传输到另一个中央。过后在淘宝的外围场景是将 MySQL 的表数据传输到 hdfs 中进行 mapreduce 的大数据计算,除了 hadoop 计算场景外,还有将 MySQL 数据导入 Oracle RAC 集群进行剖析的场景。
datax 的设计其实很简洁:1 个外围框架 + N 个数据库或存储插件。过后整个研发团队也就不过 4、5 集体,我次要负责 Oracle 数据库的插件开发,很多时候都是在写插件,因为插件的运行自身也就是单机程序,所以整个研发工作根本都是本人一个人实现。除了最初联调的时候,过程中也不须要过多的简单合作,研发的效率是十分高效的。
Logserver
起初,我开始接触 logserver 的开发,logserver 就是接管从淘宝每一个页面发送过去的埋点申请,生成上游可能生产的日志数据。
除了上下游的需要团队外,这个服务的开发只有我一个人全权负责,我的次要工作就是将 logserver 从 apache httpd 的架构迁徙到 Nginx 架构上,外围工作就是在 Nginx 上开发一个模块。logserver 过后在很长时间内都是整个淘宝 qps 量最大的服务,没有之一(明天就不分明了)。
当初回忆一下,大都是当初一个人在缓缓倒腾这个 Nginx 模块的场景。logserver 和 datax 一样,都是单机版程序,同样不须要太多的合作开发。
dbsync
接着,我又投向 dbsync 的开发。dbsync 和 datax 要做的事件实质上差不多,就是想从全量同步数据降级到实时的增量同步。过后次要做的是从 MySQL 实时同步到 HDFS 上,印象中只有 3 集体参加开发,而我负责的工作就是写一个 C 程序从 MySQL 中实时地将 binlog 日志订阅进去。
Timetunnel
写到这里忽然发现:在淘宝的前几年,我始终在做数据传输相干的中间件。
TT 实质也是用来传输数据的,并且它自身也是一个消息中间件,相似 kafka。整个 TT 的开发团队大略 5、6 人的样子,我的次要工作就是基于 hbase 来实现音讯的存储引擎。
这也是我在阿里惟一一个用 java 开发的我的项目,其余大部分都是写 C 和 Go。
tengine & cdn
后续我转岗去了 tengine 团队,这里乏味度超高。团队大略有十多人,根本都是各做各的事件(模块),同时也乐在其中。整个团队颇受外界猎头喜爱,甚至一度流传“要挖就挖 tengine 团队”。
最初,整个 tengine 团队一起去做 cdn 了。在 cdn,我被安顿带着 3、4 集体去优化 dns 服务器和调度零碎,大略状况就是老牌的 bind 性能不行了,于是齐全重写一个 dns 服务器。其实,写一个 dns 服务器也不难,大多时候都是一个人在看 RFC,把规范撸到丝毫不差就完事。最终,我重写的 dns 服务器性能大幅度超过 bind,胜利上线节俭了很多机器。后续筹备再用 dpdk 干一版的,还没来得及干,阴差阳错就跑去做容器了。
容器
在我去容器团队前,只有一个小伙伴天天和 docker 做奋斗,我去之后变成了两个人,他也不再是孤军奋战了。
而后,咱们两个人把 docker 里里外外魔改了一通,将其称之为 alidocker。改到最初,老板们感觉始终还是 docker,索性就决定做一个本人的容器引擎,也就是当初的 pouch。就这样,我也算是成了 pouch 的第一个作者,惋惜做了第一个版本就跑路了,当初的 pouch 也挺遗憾的。
补一句题外话(小声吐槽):容器团队抉择做 Swarm 而不是 K8s 这件事件也挺遗憾的。
总结一下
我在阿里的 8 年,始终做零碎级的根底软件,这些软件有着独特的特点:
- 很根底
- 没有业务需要
- 迭代速度较慢
- 短少大型团队的合作开发
- 代码级简单,但服务架构简略
- 行业内十分地通用且规范
- 对稳定性性能要求很高
- 很容易拿进去吹牛逼(是不是值得吹,又是另外一个话题了~)
总结而言:我在阿里 8 年待过的所有团队,如同没有一个用过我的项目合作工具、继续集成 CI/CD、全链路调用追踪等研发效力相干的工具。这可能就是根底软件的研发现状:团队小、单兵作战、强调集体能力;甚至,线上 debug、fix bug 这种事件都是做过的。
有幸,明天我还能持续从事根底软件的研发工作。不同的是团队规模更大了,近百人的团队共同开发一个根底软件,一起往前疾速迭代是一件十分具备工程挑战的事件。如果明天持续采纳我过来在阿里这种粗放、散养式的研发形式必定是行不通的。
Erda 工程实际
接下来聊一聊:来到阿里后,我当初所处的 Erda 团队是如何实际大规模工程研发的?
里程碑
(里程碑治理)
里程碑是宏观层面比拟重要的一个工具,咱们次要靠它来设定方向、框定产品大图。如果没有里程碑设计的话,咱们很容易忽然迷失方向,陷入各种日常需要和问题中。
咱们个别会把里程碑做得很大,或者说设计得很远。比方,将来两年一个比拟粗的工夫点要实现的事件都放入里程碑治理。
咱们 Erda 设计的里程碑,大略就是这个样子:
里程碑的设计和治理毕竟太 high level,有点相似顶层设计,所以它并不能成为日常研发工作内容的安顿。这有点相似于 OKR,但没有 OKR 那么简单,咱们只是将将来的产品大图打散到一个比拟冀望的工夫节奏下来,而后让日常的工作内容尽可能沿着这条工夫线往前推动。
里程碑治理好的话,其实能起到承前启后的作用:向上,可能给公司层面跨团队单干造成很好的同步和信任感;向下,能领导方向,拿到研发后果,不至于一年到头碌碌无为。
需要治理
后面咱们提到了里程碑工具,要想撑持里程碑的实现,还得靠日常的具体需要和问题,这里先一起聊聊需要。理论察看下来,很多开发同学其实不懂什么是真正的需要,也不懂如何接需要。
上面举个例子。
需求方 :Erda 能不能反对从 Excel 中导入数据?
(初一听,这的确是个需要,就是要反对从 Excel 这种很常见的文件里导入数据。略微思考多一点的同学,就能够持续诘问。)
开发 :为什么要从 Excel 导入数据,具体的场景是什么?
需求方:Excel 表格上填写这些数据很方,我习惯先在表格上把这些工作做好,再导入进 Erda。
诘问到这里,其实曾经可能发现。需求方的真正的痛点是 Erda 这个性能不如 Excel 不便好用,导致用户绕了一个弯路。所以,咱们真正要做的需要是优先解决这个不好用的痛点。(至于有些人就是要这个性能,那是咱们另外要探讨的事件了。)
最常见的需要就是,能不能加个 XX 性能。(这里大家能够细品一下。)
综上,咱们要求产品和开发同学对于任何需要都要一直思考,多诘问几个为什么,拿到用户最原始的需要。始终要记住,用户给你的极有可能是他认为的计划,而不是原始需要。
需要治理对了,前面的开发才会少走弯路,需要是终点、是基本。
迭代队列
一个商业化的大规模工程团队,肯定有 PD 这个角色。PD 是做什么的呢?除了下面提到的需要治理外,PD 最根本的工作就是设计产品逻辑,这里就不开展形容了。
在 Erda 团队里,PD 最须要外围设计的是迭代队列,留神:这里提到的是队列,这个队列里须要长期装满 3 个迭代,其中的 1 个迭代里寄存着最优先要解决的需要和问题。为什么这里是 3 个迭代的队列,而不是 1 个迭代呢?能够思考一下,咱们在零碎架构中,引入音讯队列中间件的作用。PD 和开发之间齐全能够通过这种形式来解耦的,开发只须要从队列中取设计好的产品工作解决问题就好,PD 只须要一直地从需要池里取内容通过设计后再正当排入到迭代队列中即可,两边的角色都能够实现自我驱动,不须要严格同步工作,所以这里的外围是为了异步工作。
(迭代治理)
那么,这个队列为什么是迭代队列,而不间接设计成需要队列,开发间接取需要而不是取迭代呢?
需要队列会存在两个很大的问题:
- 第一,迭代是用来严格定义一个版本的工夫周期,如果没有迭代,版本的工夫周期节奏会变得很乱,会进入一种比拟随便的状态。
- 第二,以后理论开发中的需要如果要延期解决的话,这个延期的需要从新排到哪里去?难道从新放到需要队列的开端吗?放到开端显然不适合。如果是迭代,就能够严格规定放到下一个迭代或者下下一个迭代。
开发过程
开发过程中,对咱们而言十分重要的一个要害指标就是:咱们可能正当承受单个需要的延期,但不能承受整个版本的延期(个别的非凡状况不在探讨中)。
很多人可能对于这个指标的了解仅停留在放弃发版节奏上,甚至会感觉这只是一种外表工作,版本进去了,需要没有做完有何用,为什么不延期版本把需要全副一起做完?
其实,这个要害指标齐全不是一个治理后果,而是技术后果。很多我的项目在做架构设计、代码设计的时候,是没有思考后续小步快跑的,不能小步快跑地增加新性能、解决新需要的话,就会经常性导致局部需要做了一半要延期的时候,基本停不下来,这个版本根本无法长期放弃需要而持续发版;更重大的是,需要和需要之间还是强耦合的,一个需要做不完,其余需要也不能失常发版。这都是实实在在的技术问题、代码问题,而不是治理问题。
(需要工作治理)
除了要害指标以外,开发过程的治理,次要是基于工作来协同的,每个需要在开发前都曾经被拆分成了正当的工作,也就是说一个需要会关联实现这个需要的所有工作,开发同学只须要每天依照优先级实现,并及时更新反馈工作的状况和进度即可。(这里提到了及时反馈,反馈又是一个异步工作的要害机制。)
很多研发主管都喜爱有事没事在钉钉、微信里询问一下具体的工作进度,或者拉个会议对一下进度,所以“已读 + ding 一下“对他们来说是一个很好的性能。咱们十分不激励这种依赖即时通信工具或会议的形式来沟通、理解开发进度,这种形式十分同步,就和同步调用一样。正确的做法,应该是开发同学每天依据本人的状况及时在项目管理工具对本人的工作进行进度更新和总结反馈,研发主管本人按需关注工作的研发进度和状况,彼此没事不要互相打搅。
CI 流程
在今年年初咱们决定将 Erda 开源后,就把整个团队的日常迭代开发全副转移到 GitHub 上执行了,因而 CI 次要是基于 GitHub 的 Action 来做的,会把常规性的查看工作全副放到 CI 中来实现,比方:单元测试、代码质量检查、标准等。这个局部比拟惯例,没有什么特地的。但 GitHub Action 太慢了,咱们后续计要把 GitHub Action 迁徙到 Erda 的 CI,这样咱们能够实现 CI 并发更高、跑得更快、效率更高。
本地 + 云端
一个很大的产品就是一个很大的软件工程,这样大的工程要齐全放到集体笔记本电脑上进行本地调试开发,是一件难度不小的事件。就像一个中间件、一个框架、一个 webserver 等,都能够很轻松地放到本地电脑上开发调试,但要把整个淘宝装到本地电脑就有点尴尬了,当然咱们也正在向这个方向致力。
在不能齐全将整个 Erda 轻装到本地电脑前,咱们采纳了本地 + 云端联结的形式来进行开发调试。云端自身是一个曾经部署好的 Erda 全平台开发环境,蕴含所有可能失常工作的组件;而后应用 telepresence 买通本地和云端 K8s 之间的网络:
- 本地能够间接应用 K8s 容器网络内的 DNS,同时反对短域名的 search 机制。
- 本地启动一个服务,劫持(intercept)云端 K8s 集群内的 Pod,当 K8s 集群内其余服务拜访该 Pod 时,流量会转发到本地。
- 实现将云端 K8s 集群 Pod 中的环境变量全副主动导出到本地。
- 实现将云端 K8s 集群 Pod 中挂载的 volume 通过 sshfs 映射到本地的文件系统。
简而言之,本地起一个服务,能够随便拜访 K8s 集群内的任意 service;同时,本地的服务也能被 K8s 集群里的其余服务拜访到。这样一来,的确能够大幅度提高开发调试效率,开发人员不必在简单环境上来来回回的折腾。
集成环境
尽管 Erda 给下层的业务利用提供了很弱小的继续集成、部署和运维监控等能力,但 Erda 在很长一段时间内却不能通过本人部署本人,也就是不能实现 Erda On Erda,所以那段时间始终没有真正的自动化集成环境,研发品质和效率也不太高。
因为 Erda 整个工程项目比拟宏大,代码从构建到部署更新,再加上所有的自动化测试跑一遍,整个流程须要数小时,消耗工夫长。所以,咱们的集成环境次要采纳每天夜间定时运行自动化集成 + 测试,次日下班就能够看到集成后果。集成进去的谬误后果,当天内必须 fix 掉,这是继续保障集成成果的要害。
(基于流水线的自动化集成)
自动化集成次要针对的是 Master 骨干分支,咱们没法做到任何一个 PR 触发自动化集成,外围问题还是我的项目太、开发人员多、自动化用例太多,基于 PR 集成的工夫老本承受不了。
能够看进去,咱们的日常开发测试和自动化集成两条线路也不是串行的,而是异步关系。咱们一直地谋求、设计整个工程流程的异步化,只有异步能力高效撑持大型工程的研发。即便你的整个工程流程执行速度十分快,没有工夫耗费的老本,同步也会有额定问题产生的;同步的最大问题就是会被异常情况打断、烦扰,哪怕是一些能够提早解决的异常情况,也会烦扰你的工作,你必须花工夫先解决异样,这种打断和烦扰对研发团队的效率影响是致命的。
API 设计和自动化测试
集成环境可能无效工作的要害是什么呢?很显然,必然是自动化测试了。
自动化测试分为自动化的单元测试、接口测试、性能测试、平安测试、UI 测试等等。日常开发过程中,效率影响最大,最频繁的显然是单元测试、接口测试、UI 测试。
- 单元测试比较简单,咱们放到了 CI 流程中,每一个 PR 就驱动实现了单元测试。
- 接口测试十分要害,咱们须要笼罩那些全链路场景的接口,从最顶层的接口登程实现整个零碎的性能自动化测试,所以接口的自动化测试就放到了整个集成环境中实现,因为集成环境有最新、最稳固的代码,以及异步执行等劣势。
- UI 的自动化测试老本绝对比拟高,咱们目前还在尝试阶段,没有齐全达到成熟。我始终心愿从智能测试的角度,用 AI 算法的思路去解决 UI 的自动化测试。
这里先介绍一下接口测试。接口就是 API,要想编写出好的接口测试用例,必须得先有 API 的设计。API 的设计从哪里来呢?咱们当然不心愿从开发工程师的口中来,所以自研了 API 治理平台,从 API 的设计到测试进行全笼罩。开发工程师在实现需要前,首先在平台上实现 API 的设计工作;而后将 API 的设计和需要关联上,这样一来,测试工程师就自主从需要里获取到具体的 API 信息,实现接口测试用例的编写。
(API 设计治理)
除了异步协同外,买通整个工程流程,也是咱们至关重要的一环,这也是咱们为什么不必 jira,jenkins 等的一个起因。
另外,咱们的自动化测试用例是由测试工程师编写、开发工程师一起保护,对测试工程师的 OKR 设定就是任何一个版本的回归 + 新功能测试必须管制在一个十分小的人 / 天内。明天 Erda 有着近百人的研发团队,而测试只有 5 集体。
(基于场景的自动化自动化测试流程)
手工测试
有了自动化测试,为什么还须要手工测试?手工测试显得仿佛没有那么高级了。
对于没有前端 UI 的零碎,自动化掉所有的测试实践上是可行的;一个有着简单前端 UI 的零碎,自动化起来还是会有很多难点,大多数做 UI 自动化的,根本也都是集中在几个外围的流程上,很难笼罩边边角角的全副场景。
在业余测试工程师眼里,手工测试也是很重要的一部分,须要有工具、有办法来撑持的。每一个版本,手工测试用例也是要可能被回归的,因而这些手工用例也要被记录下来。
(手工测试用例治理)
这部分咱们就讲到这里,不再过多探讨。
答疑和问题解决
Erda 作为根底平台性产品,用户会比拟多,零零碎碎的答疑和服务反对间接打到产研团队的话,会耗费十分多的研发精力,因而咱们建设了专门的“SRE 团队 + 轮值的产品研发答疑同学”来面对客户,针对客户和用户的各种问题进行答疑。除了配置业余的服务以外,另外一个更重要的事件就是须要将服务反对过程中的问题记录到 Erda 我的项目的工单(tickets)中,这里说的 Erda 我的项目工单就是等同于 GitHub 的 Issues,它并不是一个面向客户服务的工单零碎。
(答疑问题治理)
我的项目的工单列表在每周五须要进行 Review,将那些比较简单、可能疾速解决的工单问题梳理进去,而后一键复制到迭代队列中。这里有两个很要害的点:
- Review 先筛选的是那些简略的、能疾速解决的问题。
- 放入到迭代队列,而不是需要池。
软件系统的 bug 总是解决一个少一个,越跑越稳固,所以简略的问题要疾速解决、0 容忍看待。难的问题须要专项看待、专项解决,不对的工夫节点或者资源无限的状况去死磕难题,大概率不是一个好想法。
筛选进去的工单问题千万不要放到需要池中,肯定要间接进迭代布局。进了需要池,就不晓得什么工夫才能够排上号了,明确放入迭代、明确好解决工夫,疾速收敛问题最重要。
发版经理
咱们在一个迭代周期内,会轮值一个“发版经理”的角色,发版经理要做的事件外围就是协调 + 跟踪。当然,发版经理不是去协调团队内的你我他的事件,也不是去跟踪某个人有没有划水。而是和 PD 一起确定迭代要做的需要内容,参加需要是否延期到下一个迭代的决策,确认新版本周期内几个要害工夫节点的产物并做好验收,以及对立负责解冻代码分支等事件。总之,“发版经理”须要为新版本的效率和品质负责。
工具优先给谁用
最初,这里再聊聊工具的推广应用问题。我集体在做整个研发治理过程中,有一个深切体会:工具的推广个别来自于下级,下级推广这个工具的出发点当然是为了效率;然而,你常常会发现很多研发主管在关注工具的时候,个别都是从本人的治理视觉登程,而不是真正从一线员工应用工具的视角登程。
比方,项目管理类工具的第一外围到底应该是定位给 PM 或研发主管用,还是应该定位成工程师间的协同应用?如果你要将团队打造成更高效的异步协同团队,那么这类管理工具肯定是先给一线员工应用的,真正做到让团队内的每个人在工具上协同起来,通过工具平台来连贯你我他。
架构设计
这里谈架构设计,不是想聊 Erda 的架构,咱们还是聊一下工程效率这件事件:从架构层面如何做一些效率上的保障,让大规模研发团队能够更加从容迭代。
微服务化
晚期版本,Erda 也是一个大的单体利用,团队规模就几号人,和我之前在阿里团队经验的差不多,协同起来十分高效,增加性能和解决问题也很快。但随着人数的逐步增多,过程中出确实现了很多合作问题、效率问题,反正最初就是拆分成了微服务。当然,微服务也有微服务的问题。
讲微服务设计方法论的分享有很多,能够自行搜寻参考。
组件化协定
Erda 团队的前后端比例,在最高时能达到 1:7,也就是一个前端要对接多个团队的多个后端,产品开发迭代的瓶颈被前端资源限制住了。
为了解决这个问题,咱们思考并摸索出了一套组件化协定框架,前端提供组件库和交互定义,专一于丰盛组件的性能和改善交互体验,如何拼装组件和提供数据来实现业务性能,就交给后端来做,因为前端能够不关注业务逻辑和对接沟通 API 定义,两头能节俭掉许多沟通老本,从而进步了整体的产品开发效率。
db migration
对于 Erda 来说,疾速迭代产生的泛滥版本必须保障可能顺利降级。对咱们来说,降级最难的其实是数据库的 migration,针对这样的一个状况,咱们本人开发了一个 dbmigration 的治理框架,而后基于第一个产品版本定义好数据库的基线,后续的每个版本都在前一个版本的根底上开发 migration 逻辑放入到框架集中管理。Erda 的降级必须是从公布的版本按程序一个一进行 migration 降级。
开发一个软件可能比拟容易,开发一个可能继续降级的软件绝对来讲艰难度就比拟高了。针对 migration 和降级,咱们在测试阶段也会重复验证这件事件。
写在最初
研发治理这件事件自身治理的是技术,而不是人。我所接触到的很多人,还是会感觉研发治理是安顿一个 PM 去盯着整个研发过程,甚至拿着“鞭子”去抽那些走得慢的人。这个意识和认知必定是不对的,只有把治理动作拉回到技术自身这件事件上,能力真正激发团队的激情。
另外,任何人设计的任何一个工程流程和治理,在理论落地执行的时候,都不要去谋求完满、100% 的准确,这是一件不事实的事件,有误差才是合乎自然规律的,咱们要做的事件就是将误差管制在足够小的范畴即可。可能承受不完满,是研发 TL 的自我涵养。
对于 Erda 如果你有更多想要理解的内容,欢送增加小助手微信(Erda202106)进入交换群探讨,或者间接点击下方链接理解更多!
- Erda Github 地址:https://github.com/erda-proje…
- Erda Cloud 官网:https://www.erda.cloud/