目前很多互联网公司都采用微服务架构,微服务的优点和缺点被反复说到,这里不在重复赘述,只结合工作中的一些实践,说说要用微服务要注意的点,厚颜写做编程范式,其实就是一些具体实践而已。

原则(道)

原则是比较抽象的一个概念,简单说是一些指导意见,在不同的组之间可以共享,是为了实现一个共同的目的,必须准守的一些规则,或者叫做规矩。

这些规则(或规矩)对我们开发过程中有一定的约束作用,不容置疑,必须遵守。如果发现有那个团队或者个人没有准守,一定要及时纠正,否则,原则就没有任何存在的意义。

现在用的很广的一个原则是Heroku的 12-Factor 原则。具体内容如下:

I. 基准代码
一份基准代码,多份部署
II. 依赖
显式声明依赖关系
III. 配置
在环境中存储配置
IV. 后端服务
把后端服务当作附加资源
V. 构建,发布,运行
严格分离构建和运行
VI. 进程
以一个或多个无状态进程运行应用
VII. 端口绑定
通过端口绑定提供服务
VIII. 并发
通过进程模型进行扩展
IX. 易处理
快速启动和优雅终止可最大化健壮性
X. 开发环境与线上环境等价
尽可能的保持开发,预发布,线上环境相同
XI. 日志
把日志当作事件流
XII. 管理进程
后台管理任务当作一次性进程运行

在我们团队中有一些原则可以和大家分享:

  1. 不要为了用而用,程序猿(或者叫攻城狮)是最喜欢尝鲜的人,有了新技术出来,就想用。这无疑是优点,但是在工作中这样,就有可能给系统带来灾难。所以如果想用某项技术,必须充分调研之后,经过一系列的验证,才能引入。
  2. 战略目标明确,业务部门愿景清晰。作为开发团队,可能很少关心业务团队的想法,这是很致命的。我们开发的东西,不是业务部门想要的,顾客想要一个吃饭的勺子,你给做了一个铁铲,铁铲做的再好又有什么用。
  3. 服务之间调用必须使用HTTP/RESTful方案,不能引入其他方案。不是说其他方案不好,而是最好协议一致,一致的协议能够减少系统的复杂性和沟通成本。

标准(术)

标准的定义会比原则更加具体,有点类似于道和术、战略和战术的关系,不同的技术栈、不同的团队可能会制定不同的标准。

  1. 我们团队都是使用的是Java技术栈,所以标准大体上采用的是《阿里巴巴Java开发手册》,有一部分内容作了修改,这里对孤尽表示感谢。这个手册脱胎于《Effective Java》和《代码简洁之道》,其中加入了孤尽在阿里的一些实践,所以对于Java栈的同学是比较适用的。
  2. 我们使用的是Spring Cloud,服务之间的调用,必须使用Feign Client形式,指定这个标准是为了以后使用K8s时改动最小。
  3. 页面与服务之间的调用,HTTP返回状态码都是200,在返回的数据中,定义具体的状态码,这个状态码参照HTTP状态码,同时定义一个子级状态码,用来具体定义业务情况。比如,状态码等于500标识服务异常,子级状态码等于5001,表示操作数据库异常等。
  4. 监控系统、日志系统、任务调度等,如果需要,也要指定明确是标准。比如打印日志时,日志开头必须以6位数字开头,因为我们的日志系统与监控系统对接,6位数字能够定位到不同的系统、模块、业务,直接定位问题位置。
  5. 不一而足(每个团队有每个团队具体的标准,这里就不一一列举了)。。。

这些标准,最好形成文档,放在知识库中。这样,团队的成员可以随时查看,有新人加入时,也能避免老员工口口相传,传错了指令。

有些架构师认为,原则和标准就是一个东西。就我来看,这两个粒度不同,对于大的团队,最好分开。因为大的团队,技术栈更加多样化,标准没有办法做到一致,但是原则可以做到不会脱离大框。对于小的团队,因为技术栈比较单一,有可能就是一个技术栈(就像我现在的团队),因为标准只有一个,就是对原则的细化,所以两者就是一个东西。

标准的另外一个作用,就是告诉团队成员怎么做是对的,怎么做是更好的方案,更加直白的表述是,按照标准进行开发,bug更少。

有了开发标准之后,就需要将标准推广到所有人,但是每个人的理解力和执行力是有偏差的,所以需要一些手段来快速推广。具体的方法有:DEMO(示例)、代码模板(脚手架)。

DEMO(示例)

软件开发是一个比较有技术壁垒的行业,一个新人(没有经验或者有经验刚加入新团队的人)想要快速了解老系统所使用的标准,是比较困难的,毕竟每家团队采用的标准都不是百分之百一致。比较简单的做法就是,提供新人DEMO示例,然后告诉他,“就照着这个做”。

对于有经验的新人,一定是先接受,然后在了解清楚之后,才会提出自己的一些看法,而不是一上来,就搬出自己以前的经验,全盘否定团队指定的标准。

代码模板(脚手架)

代码模板的作用实现一个服务的集成方案,经过有效可靠的裁剪和定制。在需要新建服务时,就使用这个方案,直接进行业务代码开发即可,所以也被称为脚手架,比如SpringBoot的Starter和AutoConfiguration。

前面说过,我们团队使用的是Java技术栈,基于SpringCloud开发,所以我们对SpringCloud进行封装,定义了几根通用的组件,比如定义了一个web-misc组件,引入这个组件,就能够实现,引入实现WebMvc,并且提供了统一的获取Metric信息的接口,统一的异常处理的ExceptionHandler等。

及时清理技术债务

虽然我们都是代码洁癖,但是有时候迫于时间压力、业务压力,我们不得不背负一些技术债务。

比如我们知道硬编码会破坏系统灵活性,但是明天就要上线,根本没有时间做配置型服务,所以只能硬编码到系统中,这就是技术债务。第二天系统上线,正常运行,如果这个时候把硬编码事情抛之脑后,这个债务就会产生利息,不知道哪天就会变成炸弹。

对于技术债务,我们团队的做法是做一个技术债务清单,设置超时提醒功能,限期修复。这个清单是公开的,每一项都注明了,是谁,因为什么,于什么时间,产生的技术债务,需要在什么时候修复。如果是临时特性或功能产生的债务,也需要注明特性或功能过期时间,由专人检查债务是否已经没有了。


个人主页: http://www.howardliu.cn
个人博文: 微服务编程范式
CSDN主页: http://blog.csdn.net/liuxinghao
CSDN博文: 微服务编程范式