在很多微服务化的文章中,很少会把持续集成放在第一篇,因为大多数的文章都会将如何拆的问题,例如拆的粒度,拆的时机,拆的方式。
为什么需要拆呢?因为这是人类处理问题的本质方式:将一个大的复杂问题,变成很多个小问题解决。
所以当一个系统复杂到一定程度,当维护一个系统的人数多到一定程度,解决问题的难度和沟通成本大大提高,因而需要拆成很多个工程,拆成很多个团队,分而治之。
然而当每个子团队将子问题解决了,整个系统的问题就解决了么?你可以想象你将一辆整车拆成零件,然后再组装起来的过程,你就可以想象拆虽然不容易,合则更难,需要各种标准,各种流水线,才能将零件组装称为车。
我们先来回顾一下拆的过程。
最初的应用大多数是一个单体应用:
单体应用一个Java后端,后面跟一个数据库,基本上就搞定了。
随着系统复杂度的增加,首先Java程序需要做的是纵向的拆分。
纵向拆分首先最外面是一个负载均衡,接着是接入的Nginx,做不同服务的路由。
不同的服务拆成独立的进程,独立部署,每个服务使用自己的数据库和缓存,解决数据库和缓存的单点瓶颈。
数据库使用一主多从的模式,进行读写分离,主要针对读多写少的场景。
为了承载更多的请求,设置缓存层,将数据缓存到Memcached或者Redis中,增加命中率。
当然还有些跨服务的查询,或者非结构化数据的查询,引入搜索引擎,比关系型数据库的查询速度快很多。
服务化架构
在高并发情况下,仅仅纵向拆分还不够,因而需要做真正的服务化。
一个服务化的架构如图所示。
首先是接入层,这一层主要实现API网关和动态资源和静态资源的分离及缓存,并且可以在这一层做整个系统的限流。
接下来是Web层,也就是controller,提供最外层的API,是对外提供服务的一层。
下面是组合服务层,有时候被称为编排层,compose层,是实现复杂逻辑的一层。
下面是基础服务层,是提供原子性的基本的逻辑的一层,他下面是缓存,数据库。
服务之间需要治理,需要相互发现,所以一般会有dubbo或者springcloud一样的框架。
对所有的服务,都应该有监控告警,及时发现异常,并自动修复或者告警运维手动修复。
对于所有的服务的日志,应该有相同的格式,收集到一起,称为日志中心,方便发现错误的时候,在统一的一个地方可以debug。
对于所有的服务的配置,有统一的管理的地方,称为配置中心,可以通过修改配置中心,下发配置,对于整个集群进行配置的修改,例如打开熔断或者降级开关等。
通过简单的描述,大家可以发现,从一个简单的单体应用,变成如此复杂的微服务架构,除了关心怎么拆的问题,还必须关注:
如何控制拆的风险
如何保证代码质量
如何保证功能不变,不引入新的Bug
答案当然就是集成,从一开始就集成,并且不断的集成,反复的将拆分的模块重新组合,看看是否能够顺利组合起来,并且保证功能的不变。
要是不没事儿就组合一下,天知道几个月以后还能不能合的起来。
别忘了程序是人写的,你和你媳妇长时间不沟通都对不上默契,别说两个程序员了。
二、持续集成就是不断的尝试在一起
集成就是在一起。
集成的逻辑
为什么需要一个统一的代码仓库Git来做代码管理呢?是为了代码集成在一起。
为什么需要进行构建build呢?就是代码逻辑需要集成在一起,编译不出错。
为什么要单元测试呢?一个模块的功能集成在一起能够正确工作。