聊聊工程端的效率提升

想起了自己毕竟是技术Leader,天天水管理也不是个事,所以还是聊下工程端的一些工作吧。工程的问题最终全部会体现在业务上,一个系统一直优化不好,因为每个系统都可能旁枝错节:

管理侧的解题思路前面很多文章已经介绍,今天主要介绍工程侧的解决办法。

Case:优化不好的系统

背景

研发研发团队去年年初60人左右,由于业务急速增长,6月启动招聘扩大研发团队规模,至今团队接近200人,新人占比超过60%;

与此同时,需求井喷,产研团队应接不暇,作为最终执行侧的研发团队暴露的问题尤为凸显,常常成为被吐槽对象,业务压力大,历史包袱重成为团队常态;

具体表现

工作台是平台重要的工具,从上线以来BUG不断:

1、用户量大后,进入工作台空白/使用系统卡顿;

2、工作台新消息不置顶(有BUG);

3、工作台用户列表区头像裂开;

4、以及难复现的各种各种偶发性问题等等…

为解决这个问题,小规模优化10多次;大型优化2次,结果依旧不理想。

抽象问题

这个简单的Case体现了三个问题:

组织建设问题:

1)管理单点凸显。上下锁死,一米五九问题严重,关键人凋零,组织执行力跟不上……

2)质效问题。产品质量低下并且研发质量意识不足;项目流程混乱,文档基无沉淀;业务单点问题严重,整体业务意识偏低……

3)工程问题。历史包袱过重,工程建设停留在两年前;现有数量级一定会有性能问题,更不能满足10倍增长;业务效率一定会跟不上……

去年刚到新公司就面临这一棘手环境,除了业务方还经常有运维或者开发同学吐槽,问题大致下面几点:

1)服务依赖复杂,部署管理难(如果涉及到大版本迭代发布,经常都是通宵发版本,并且很难顺利发成功);

2)新老逻辑交叉很难做技术迭代升级(技术负债太多,很难做好规范,翻新老逻辑困难)。技术语言不统一,一部分php一部分golang,涉及到紧急项目人员协调困难;

3)由于代码很少翻新,了解之前的历史业务的同学比较少,新同学很难快速熟悉老业务,非常担心业务熟悉的老同学离职,技术团队的稳定性差;

基于上面的原因我们打算使用新的成熟的微服务框架,来重构公司所有的项目,解决以上问题,并且通过工程化和devops一些系统,让整个技术团队的工作轻松,不需要花太多时间在框架和环境上,更多时间放在业务上。

先说说什么是微服务

微服务(Microservices)就是一些协同工作小而自治的服务。

2014年,Martin Fowler 与 James Lewis 共同提出了微服务的概念,定义了微服务是由以单一应用程序构成的小服务,自己拥有自己的行程与轻量化处理,服务依业务功能设计,以全自动的方式部署,与其他服务使用 HTTP API 通信。同时服务会使用最小的规模的集中管理 (例如 Docker) 能力,服务可以用不同的编程语言与数据库等组件实现 。「维基百科」

我们的目的也是将我们现在复杂混乱的额项目变的边界清楚,并且每个项目做自己独立的事情,系统与系统之间能够方便快速调用,并且入手成本很低。

我们也在网上了解一些微服务框架最终使用,最终基于B站开源的 discovery(//github.com/bilibili/discovery)、kratos (//github.com/go-kratos/kratos)两个项目进行我们服务的搭建,kratos是使用的1.x版本,选择这个项目的原因是该项目微服务治理方面比较完善,有完整的监控大盘、链路追踪、限流、统一配置、告警 以及一些常用的中间件,我们也是使用的大仓的模式来组织代码,能够极大的提高开发效率。

简单的脚手架

1、首先我们需要一个快速创建工程的脚手架,如下图,直接通过medcreate就会在golang对应的目录中创建一个完整的新工程,我们整体工程分了3类 服务类、BFF网关类、Job定时任务类

图片

工程创建之后,在开发中,我们使用的grpc来进行接口,参考kratos也知道我们也是基于proto文件来定义http接口和grpc接口,所以我们开发一个工程中使用的工具medgen包含以下功能

1)、定义proto文件之后,可以根据命令生成对应的grpc或者http的一些golang的模版形式的初始化代码,直接写上逻辑代码就可以正常运行

2)、我们使用的文档有多种,我们可以直接根据命令生成swagger、markdown、yapi等,并且直接上传到对应的服务器上,非常方便。

3)、还能生成一些redis、db操作的一些模版代码供参考。

4)、也可以生成grpc的client代码,等等。

有了以上的工具,单个项目开发就会变的比较简单,并且大家统一工具,一些生成的代码都是可以整个工程快速变更的,并且非常方便。

服务发现

这部分需要参考discovery,我们也是直接使用discovery来作为注册中心进行服务发现,并且部署了3个节点(现在discovery多个节点数据同步会有小问题,需要修改代码)图片

配置中心

kratos提供了统一的配置,我们使用的携程的apollo作为配置中心,kratos也是支持,但是唯一不好的事apollo不支持toml结构的配置,我们之前的所有服务都是使用的toml,我们最终使用了apollo txt的private的namespace 存放toml格式的配置,勉强可以用。我们也可以根据不同环境来配置apollo支持我们后面所说到的泳道(有多个开发或者测试环境,每个环境的配置管理)。

测试环境调试

我们使用kratos的环境区分也是用的染色的方式来进行区分的,一般来说我们的服务可能有几百个,不会本地全部启动,我们本地可能会链接到不同的测试环境中进行测试,所以提供了grpcDebug通过json编码调用grpc的服务,如果需要测试环境能够调用到我们本机的服务,需要测试环境和公司的网络互通,我们现在办公网络事互通的,不同环境的调试是非常方便的。

图片

图片

图片

大仓如果出现代码泄漏是非常不安全的,所以我们比较重要的项目也做成了单独的私有仓库,只是支持快速的方便调用,使用方式和上面所说的一样。

发布系统

接踵而至的是团队越来越大,服务越来越多,仅仅靠运维团队是不行的,是不是要把服务的维护“成本”分摊到不同的单元化开发小组分而治之,这样每个小组并不需要承担太多的维护成本,而且能够减少运维的时间成本,让整个复杂的事情变的短小可控。

于是我们准备搭建一套系统来解决以上提到的问题,并且能够支持业务和团队的持续扩张。

图片

下面就用一些例子来说一下我们现在做成的系统能解决的问题

例子1:  

开发:新来了一个需求,左顾右盼,这是一个新的业务线,我们需要新建一个新的微服务,还要为该服务新建一套测试环境、预发环境、线上环境。

之前运维:需求提过来我在各个环境的jenkins创建对应的项目,20分钟给你弄好。

开发:来吧,我们这个需求比较大,我们需要有10个新的应用需要创建30套环境。

如果你有一个系统

现在运维:你有10个系统,你们自己去我们的系统上创建环境就可以了,资源自己配置,我给你审核

图片

图片

图片

创建多个环境,并且每个环境1个节点

图片

这样原本需要运维解决多次创建不同环境的事项分担到多个研发,不会阻塞到某一个同学身上,这个事情变的更顺了。

场景2:

研发1: 我有用户服务的需求紧急我需要一个调试环境。

研发2: 我和楼上一样,我也有个紧急需求更改了用户服务需要一个调试环境。

研发3: 同上

一个服务需要并行开发并行测试,来看我们怎么支持这种场景我们可以让开发同学随意创建自己的环境(但我们测试的k8s集群资源是有限的),并且环境里包含你需要更改的服务,依赖的项目无更改流量调度都是调用的QA基准环境,相当于虚拟了人手一个调试环境,想怎么改就怎么改,每个人环境都是隔离的不会项目影响,满足正常迭代。

图片

场景3:

研发: 我要发线上,我需要先滚动一台上线,看下监控,看下这次上线的业务日志是否正常,正常了再灰度线上全量,或者流量大的时候,我需要一台一台灰度,避免流量不均匀。

图片

场景4:

研发:突然我的用户服务好像流量涨了之前的资源不满足了,我需要扩资源或者今天晚上有一波活动用户量会触达200个W的人,我需要扩资源扩到10台,每一台4C8G,需要紧急扩容,我们可以直接更改每个服务的实例数,每个实例CPU核数和内存,直接灰度重启生效,可能就2-3分钟就弄完了。

图片

图片

场景5:

研发:我们需要设置环境变量区分环境,当然也是可以在我们系统中进行配置的。

经历大概1年的时间以上很多问题都得到了友好的解决,关于发版本的这个事情上,基本上都是研发团队自己能解决的事情,并且单元化之后,每个团队负责的服务都不是太多,只要服务拆分的合理整体复杂度得到有效控制,再也不见当初研发团队发版本的吐槽了。

抛开语言层面不说,整体的建设方向大概是这样,只是看如何建设的符合大家的大环境。