如何避免单点风险:基于实践经验分享服务拆分原则的一些思考原创
- 背景:系统崩了
- 具体情况:1%的请求影响了剩余90%的请求
- 架构演进:拆分热点服务【进程级隔离】
- 复盘
- 总结
- 拆服务的经典实践
背景
系统崩溃了?别惊慌!这里有快速恢复的方法!
分析发现崩时服务X被几个慢接口拖垮继而踩踏,且X的QPS过高,是业务gateway的2倍
具体情况:1%的请求影响了剩余90%的请求
相同时段之前崩掉服务的情况:
当前流量流转概览
业务gateway的流量远小于服务x的流量???
业务服务与基础数据服务耦合在一块是不是合理的?
接口响应时长, 从毫秒级, 快速退化到秒级
请求等待了7707ms
org.springframework.web.servlet.FrameworkServlet.doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response)
解决方案:拆分热点服务【进程级隔离】+水平扩容+k8s HPA
https://www.processon.com/view/6447cd7e8e188d4a087d3d1e
复盘
这是谁的问题?
这是服务的稳定性的问题。
有什么问题?
一个服务崩了,导致整个业务系统崩了。
解决的思路是什么?
把整个业务系统依赖的基础拆出来。
一个基础服务不可用,导致整个业务系统不可用。
然后,通过把这个基础服务拆成一个单独的服务,来解决这个问题。
思考
拆服务的原则是什么?
在分享对拆分的思考之前,先聊几个概念热热场。
什么是架构?
什么是微服务架构?
微服务架构是一种架构模式,它提倡将单一应用程序划分成一组小的服务,服务之间互相协调、互相配合,为用户提供最终价值。微服务架构的本质是分布式系统。
来看看Martin Fowler大佬的理解:
上述英文的三个关键词分别是:small、lightweight、automated,这基本上浓缩了微服务的精华,也是微服务和SOA的本质区别所在。
微服务拆分的原则:化大而复杂为小而简单。
微服务到底有多微,是个仁者见仁,智者见智的问题,最重要的是团队觉得合适。但注意,要达成“团队觉得合适”的结论,至少还应该遵循以下两个基本前提:
-
业务独立性
-
团队自主性
微服务拆分过程中的坑
-
微服务拆过细,过分强调“small” -
微服务基础设施不健全,忽略了“automated” -
微服务并不轻量级,规模大了后,“lightweight”不再适应
如何拆分?
对拆分依据的思考,实际上是在问:“服务的粒度如何界定”。
针对微服务拆分过细导致的问题,建议基于团队规模进行拆分,类似贝索斯在定义团队规模时提出的“两个披萨”理论(每个团队的人数不能多到两个Pizza都不够吃的地步)。
那么,以“三个火枪手”的微服务拆分粒度原则,即一个微服务三个人负责开发。当我们在实施微服务架构时,根据团队的规模来划分微服务数量,如果业务规模继续发展,团队规模扩大,我们再将已有的微服务按这个原则拆分。
“三个火枪手”的原则主要应用于微服务设计和开发阶段,如果微服务经过一段时间发展后已经比较稳定,处于稳定期了,无须太多的开发,那么1个人维护1个微服务甚至几个微服务都可以。
拆分的思路
基于“三个火枪手”的理论,我们可以计算出拆分后合适的服务数量,但具体怎么拆分也是有技巧的,并不是快刀斩乱麻随便拆分成指定的数量就可以了。常见的拆分方式有如下几种,接下来我们一一介绍。
(1)基于业务逻辑拆分
将系统中的业务模块按照职责范围识别出来,每个单独的业务模块拆分为一个独立的服务。
(2)基于可扩展拆分
将系统中的业务模块按照稳定性进行排序,将已经成熟和改动不大的服务拆分为稳定服务,将经常变化和迭代的服务拆分为变动服务。刚开始,稳定的服务粒度可以粗一些,即使逻辑上没有强关联的服务,也可以放在同一个子系统中。例如,将“消息推送服务”和“升级服务”放在同一个子系统中。
这样拆分主要是为了提升项目快速迭代的效率,避免在开发的时候,不小心影响已有的成熟功能导致线上问题。
(3)基于可靠性拆分
将系统中的业务模块按照优化级排序,将可靠性要求高的核心服务和可靠性要求低的非核心服务拆分开来,然后重点保证核心服务的高可用。具体拆分的时候,核心服务可以是一个,也可以是多个,只要最终的服务数据满足“三个火枪手”的原则就可以。
这样拆分可以带来如下几个好处:
-
避免非核心服务故障影响核心服务
-
核心服务高可用方案可以更简单
核心服务的功能逻辑更加简单,存储的数据可能更少,用到的组件也会更少,设计高可用方案在大部分情况下要比不分要简单得多。
-
能够降低高可用成本
将核心服务拆分出来后,核心服务占用的机器、带宽等资源比不拆分要少得多。因此只针对核心服务做高可用方案,机器、带宽等成本比不拆分要节省较多。
(4)基于性能拆分
基于性能拆分和基于性能拆分类似,将性能要求高或性能压力大的模块拆分出来,避免性能压力大的服务影响其它服务。常见的拆分方式和具体的性能瓶颈有关,可以拆分Web服务、数据库、Cache等。例如,电商的抢购,性能压力最大的入口的排队功能,可以将排队功能独立为一个服务。
以上几种拆分方式不是多选一,而是可以根据实际情况自由排列组合。
拆分是为了 化大而复杂为小而简单。
拆分是为了系统稳定性和研发的效能提升。
如果没有达到上面两条目标,就要重新考虑下拆分是否必要了。
另外要
引用
https://martinfowler.com/articles/microservices.html
https://time.geekbang.org/column/intro/100006601?code=SWmCO2yChZKMsxvoZphPgPyr8SX0c6wLhHZBcxyOZFs%3D&source=app_share
《从零开始学架构 照着做,你也能成为架构师》
《微服务 架构与实践》
《聊聊“架构”》