一般早期架构是一体化架构(Monolithic Architecture)
,简单来说就是所有的业务都在一个后台服务来承载。
例如,一个Java web应用运行在Tomcat之类web容器上,仅包含单个WAR文件;一个Rails应用使用Phusion Passenger部署在Apache/Nginx上,或者使用JRuby部署在Tomcat上,它们都仅包含单个目录结构。为了伸缩和提高可用性,你可以在一个负载均衡器下面运行该应用的多份实例。
1. 一体化架构痛点
1.1 技术层面,数据库可能成为系统瓶颈
一体化应用是可以快速复制,但是数据库一般没法横向扩展(除非做分库分表拆分)。
数据库比如MYSQL的客户端连接数是有限制的,一般可在服务器端配置,比如2w。假设一个应用100数据库连接,最多100*200=2w,实际不能扩展到这么多,因为还有运维、监控相关也会使用一定的连接数。
1.2 增加沟通成本,抑制研发效率提升
《人月神话》中曾经提到:一个团队内部沟通成本,和人员数量 n 有关,约等于 n(n-1)/2,也就是说随着团队人员的增加,沟通的成本呈指数级增长,一个 100 人的团队,需要沟通的渠道大概是 100(100-1)/2 = 4950。
同时针对一体化项目,大多代码比较多,这会导致开发维护效率变低。之前在一个客户端项目,一个apk的代码量在150w,30+团队一起开发,合代码做需求非常刺激,有时候专门需要1整天来解决需求提交的代码冲突。
1.3 运维复杂度增加
系统编译、构建、启动等随着代码量的增多变得越来越复杂
1.4 一体化架构优点
一体化架构也是有着一些优点的,如果针对访问量不大、并发不高的系统,一体化架构可以节约机器、精简架构、提高研发效率有着自身的优势。
可以参考2023年的这篇文章:从微服务转为单体架构、成本降低 90%,亚马逊内部案例引发轰动!CTO:莫慌,要持开放心态
针对单体架构还是微服务化架构,针对项目不同阶段、人员储备等情况按需进行选择
2. 如何进行服务化拆分
2.1 做到单一服务内部功能的高内聚,和低耦合
每个服务只完成自己职责之内的任务,对于不是自己职责的功能,交给其它服务来完成。
2.2 服务拆分的粒度,先粗略拆分,再逐渐细化
拆分初期可以把服务粒度拆的粗一些,后面随着团队对于业务和微服务理解的加深,再考虑把服务粒度细化。
2.3 尽量避免影响产品的日常功能迭代,也就是说,要一边做产品功能迭代,一边完成服务化拆分
优先剥离比较独立的边界服务(比如短信服务、地理位置服务),从非核心的服务出发,减少拆分对现有业务的影响
当两个服务存在依赖关系时,优先拆分被依赖的服务。
2.4 服务接口的定义要具备可扩展性
为保证接口扩展性,接口入参和返回值采用对象而不是直接使用参数做入参
比如下面test1要增加一个参数处理新增加一个方法外没有其他处理方式了,test2直接在入参加一个字段即可
java
void test1(int a, int b);
void test2(Test1Req req)
3. 微服务化带来的问题和解决思路
3.1 服务接口的调用,不再是同一进程内的方法调用,而是跨进程的网络调用,这会增加接口响应时间的增加
选择何时微服务框架,比如Dubbo
3.2 多个服务之间有着错综复杂的依赖关系
引入服务治理体系:熔断降级限流超时控制
3.3 服务拆分到多个进程后,一条请求的调用链路上,涉及多个服务,那么一旦这个请求的响应时间增长,或者是出现错误,我们就很难知道,是哪一个服务出现的问题
分布式追踪服务
监控报表 APM工具,如PINPOINT
4. 其他
4.1 康威定律
设计系统的组织,其产生的设计等同于组织间的沟通结构。通俗一点说,就是你的团队组织结构是什么样的,你的架构就会长成什么样。
4.2 贝索斯的两个披萨理论
按照亚马逊 CEO,贝佐斯的"两个披萨"的理论,如果两个披萨不够你的团队吃,那么你的团队就太大了,需要拆分,所以一个小团队包括开发、运维、测试以 6~8 个人为最佳
4.3 微服务化成本高,先采用工程拆分方式
参考:
什么是一体化架构(Monolithic Architecture)
从微服务转为单体架构、成本降低 90%,亚马逊内部案例引发轰动!CTO:莫慌,要持开放心态