一、重构中的外部准备工作
技改在任何时候都是个敏感的事情。大量的问题需要摆平,天时地利人和,缺一不可。
1. 天时
即选择合适时机进行技术改造工作。在时机的选择上,我们经历了三个阶段。
(1)空闲时段
在开发企业应用时,技术改进也是常见的工作。企业应用开发的特点是有忙有闲。在版本发布前都紧锣密鼓进行开发工作;在老版本发布之后,新版本刚刚启动开发时,有相对空闲时间,可以进行技术改进。 而当这一套方法搬到互联网应用开发上时,却发现基本行不通。互联网应用开发是两种情况:很忙和非常忙。预留大片的时间进行技术改进,几乎是不现实的。如果有业务可以有空闲时间做技改,那基本上也就没必要改了,因为这也意味着这个业务进入稳定和衰退期。
(2)随需改进
既然找不到空闲时段,另一个选择是随需进行,也就是在项目开发过程中,对涉及到的模块进行改进。而在实践中,我们也发现这种做法难度很大。
- 遗留系统的模块依赖关系往往令人匪夷所思,改进过程中,经常会发现需要对所依赖的底层模块进行大调整,导致改进工作无法进行。
- 就算是所依赖的模块没有问题,改进工作也会导致更多的时间开销,2~3倍都是正常的。这个延迟不是所有项目都能够承受的。
(3)优化团队
比较适合互联网应用开发的做法,是组建专门团对进行技术改进。预留大约30%的开发能力来进行技改。这些人可以是专门负责架构改进的,也可以从项目组中抽调轮岗。
- 改进前,制定改进计划,循序将近进行。涉及到具体模块改进时,抽调负责该模块的技术人员来参与。
- 如果模块改进和业务开发工作同时开展,则可以考虑将这两个工作合并进行。
技改不能一哄而上,也不能蜻蜓点水的做。他是一个持续的过程,循序将近,不要中断。项目紧的时候挑选风险小的任务来执行,少安排几个重构点。项目松的时候重构下核心接口,多安排些重构。但是不要中断。 一旦中断,往往结果是没有人会愿意继续。重构往往是个前人栽树 后人乘凉的事,风险又大,短期看不到效果,大家做着做着,往往就放弃了。所以持续改进是必须的,避免半途而废。
还有一个大家容易忽略的地方,对于特别看重绩效的团队,按照产出来度量工作成果,那必须果断避开绩效考评的这段敏感时期。
2. 地利
所谓地利,从软件角度,主要是基础设施的建设。在针对现有系统进行改进,推动微服务架构前,需要评估下当前的基础设施建设是否能够满足要求。 服务所需要的基础设施包括:
(1)虚机环境或者docker
不同服务的线上压力和运行环境需求不同,内存,CPU,磁盘需求也不一样。按照服务需要自动弹性创建所需要的环境,是微服务部署的前置条件。
(2)版本控制软件
版本控制不仅仅是协调人和人之间的协作,同时也是保证线上运行的系统必须是最终正式的版本。一旦出现问题,开发人员可以从版本控制服务器上下载到一致的代码。现在一般用git来实现。为什么不用SVN,网上有很多对比文章,不是本文重点。
(3)代码评审软件
每个微服务作为独立的项目来开发,统一编码规范,审核代码逻辑等,在这场景下犹为重要。和git相配合,gitlab是优先考虑的codereview软件。
(4)集成发布
集群对微服务是必不可少的基础环境,将一个服务部署到几十,甚至上千台机器上是必要的。这种情况下,人工部署是不现实的,依赖于集成发布环境,实现获取版本,集成编译,备份老版本,发布新版本,启动服务,暂停服务和重启服务。推荐使用jenkins。
(5)系统监控
监控自动化也是必要的基础设施。对出问题的服务报警,在高峰期对核心服务进行监控,都必须借助监控系统来处理。推荐使用zabbix。
(6)日志分析
排查错误和对系统进行审查,日志处理是不可避免的。想跟踪某个ID用户的行为,在几百台机器上逐个查看日志也是不现实的。使用工具,如ELK,将日志收集到一个存储中,提供检索功能来查看日志,甚至对日志做统计分析,也是必须的设施。
(7)办公环境
不用说,新老系统开发人员得在一起办公,随时交流。如果条件无法满足,那至少必须建立顺畅的沟通方式,比如QQ群,微信群等。邮件并不是一个好的选择,电话会议也是不错的。
3. 人和
最重要的因素。总体上包括三个方面内容,上级领导的支持,团队成员的认可,合作部门的理解。
(1)上级的支持
毫无疑问,上级领导支持是前提条件。重构是高风险的工作,往往不容易立即出新成果,而且还需要额外的投入。几个月内,没有新东西,出货速度变慢,没有其他因素,不是重构就是在怠工。从公司层面,更高层的人越能知道什么时机适合开展重构工作。公司马上要架构调整了,系统快下架了,近期有重大活动需要支持,有人需要尽快出成果来晋升….都需要慎重评估是否可以进行重构,而这些事情,越高层的人掌握的信息越多,所以得到他们的支持是必须的。
(2)团队成员的认可
其次是团队成员们认可。特别是老系统的开发人员,他们认可和毫无保留的支持是必要的条件。他们最清楚系统有哪些坑,哪些是必须改动的,哪些是没有用的功能,哪些只是临时的解决方案。这样才可以在功能迁移时,有目的地进行调整。
二、重构中的内部准备工作
随着系统改进工作的进行,一些架构性的问题也越来越突出。在开发中,一个遗留接口是否要迁移到微服务架构上,哪些接口应该放到同一个项目上,项目应该如何组织,日志、监控等基础性的工作应该怎么统一规划,都需要从架构的层面来进行设计。
1. 确定目标
公司每一年都会有一个明确的战略目标,这个目标最终会被分解到每个业务上去实施。 对于支付业务,我们的目标是:
(1)持续提升支付成功率
支付成功率是支付业务的***衡量指标。提升成功率的首要措施是提升系统的稳定性,在此基础上,通过简化支付流程、优化支付路由等措施,提升转化率。
(2)持续降低支付成本
在保证支付的稳定的前提下,引入更多底成本的渠道,通过支持渠道优惠活动等措施,来降低支付成本。
(3)支持进入新市场
配合公司的市场拓展需求,为新市场提供支付支持。
2. 原则
为了和目标保持一致,我们制定了一些微服务的架构规则。当然,这些规则也是随着团队的进步、业务的变更做调整。 我们的原则是参考Heroku的12 Factor而制定的。
以下原则是在刚启动微服务架构改进的时候制定的。
(1)虚机开发
所有开发工作必须在虚机上进行,不得使用个人物理机开发。这使得开发人员能够随时在任何地方调起开发环境,避免由于环境配置问题而影响问题修复。
(2)版本控制
使用Git做版本控制。 每个项目都有一个基准代码库,部署时从主干获取代码。上线时对主干打Tag,每个Tag对应一个线上可执行代码。 测试环境、预部署环境和线上环境都使用相同的基准代码。
(3)代码审核
为了保证代码质量,所有代码必须通过至少两位工程师的审核才可以签入到主干版本中。执行日常代码审核,避免在部署前进行突击式审核。
(4)自动部署
开发人员不得直接将开发机上的构件推送到测试、线上环境。 build, release和run必须分离。 自动部署系统(Jenkins)将从版本控制服务器上下载代码,编译并发布到各个stage server上。
(5)横向扩展
所有系统必须可以通过多进程部署的方式进行扩展。 这就要求:
- 所有系统可以运行在一个或多个进程中。 但所有进程必须是无状态的,进程之间是无共享的。 对于Web来说,特别注意避免依赖session。如有需要,session需保存在membcached或者redis等内存缓存中。
- 所有进程运行时动态绑定到端口来提供服务。
- 避免使用守护进程或者PID文件。
(6)同构环境
确保开发、测试和线上环境的同构。这包括如下内容:
- 各stage下所使用的操作系统环境是一致的。
- 各stage下所使用的容器是一致的,包括JVM版本、容器版本;
- 各stage下所使用的数据库及其版本是一致的。
- 测试和线上环境可以在部署实例数量上不同,但在测试环境中,对于每个系统,至少部署2个实例。
- 各个stage下的唯一差异是通过配置参数来控制的。
随着基础设施的完善,我们补充了如下原则:
(7)配置参数
与环境相关的配置信息,必须与代码严格分离,包括数据库、第三方证书、域名、和性能有关的配置(线程数、重试间隔等)。配置信息统一使用环境变量来存储。
(8)幂等原则
所有的接口必须实现为幂等的,这包括:
- 该接口在同一个server上可以多次调用;
- 如果某一个server上调用出现网络问题,客户端可以进行重试并将请求转发到另一个server上执行。
(9)启动关闭
每个系统需提供启动、关闭和验证脚本。
- 系统在启动时执行必要的环境检查,包括不得使用root账户来启动应用、端口是否被占用等。
- 启动成功后,可以通过验证脚本来确认运行状态。
- 关闭脚本必须能够优雅终止进程,这包括回退所有的连接、停止接收消息,完成所有待处理的消息,必要时执行回滚等操作。
(10)收集日志
所有日志信息都必须通过终端收集到日志服务器上。
(11)监控报警
所有线上运行的系统,必须配置监控和报警,并落实报警处理人员。
3. 制定规范
在原有的Java编码规范的基础上,针对本次技改,我们又制定如下规范:
- 支付系统监控报警规范。在支付系统的监控与报警 一文中有介绍。
- 支付系统Restful 接口设计规范。
- 支付系统RPC接口设计规范。 在微服务与RPC一文中有介绍。
这些规范在执行过程中也会不断地进行补充和调整。除了在code review中确保这些规范被落地执行外,每周周会也会对异常执行情况进行分析,确保规范制定是符合实际需求的,并能够与时俱进地进行调整。 当然,最重要的规范,是软件过程的规范:支付系统开发的软件过程规范。在微服务开发的软件过程一文中有详细介绍。
4. 团队建设
微服务架构是否能够顺利实施,离不开团队成员的支持,以及团队能力的提升。团队建设一直是整个技改过程的重中之重。 团队建设本身是一个大话题。这里重点介绍我们在团队分工上的工作。
团队的分工和整个架构设计需保持一致(又是康威定律)。在架构设计上,我们采取的整体策略,是参考原有的SSH架构,将业务逻辑和接口实现分离,将进程内调用改造成进程外调用,并在此基础上做切分。 这样,在团队划分上,前期,是按照层来分工,分为如下三个小团队:
- 接口服务团队,开发对外的接口,对接业务系统以及Android,IOS,PCWeb等各端。随着业务的发展在,这个团队也会逐步按照端来进一步分解。
- 基础服务团队,为对外接口提供业务逻辑服务。这也是***的一个团队,随着业务的发展,这个团队也会逐步按照业务进行拆分,分裂成账户、支付、交易等小团队。
- 基础设施团队,负责支持上述工作的各种规范的制定,以及支持这些规范实现的基础设施。
【本文为51CTO专栏作者“凤凰牌老熊”的原创稿件,转载请通过微信公众号“凤凰牌老熊”联系作者本人】