微服务系统架构设计:基本原则与理论分析

@[TOC]

一、从不同维度对微服务进行拆分

1、DDD

提起微服务拆分,很多小伙伴立马想起非常火爆的一个概念:DDD,但是互联网应用没有"银弹",除了DDD,还有其他微服务拆分的方式。

本文暂不讨论DDD微服务拆分,后续有时间单独成篇讨论DDD。

2、压力模型

有以下几种服务器压力的模型:

  • 高频高并发流量:用户点击的频次高、并发高。比如说电商项目中的商品详情页
  • 低频突发流量:访问频次不高,但是突发流量高。比如说电商项目中的秒杀商品
  • CPU密集型:占用大量CPU计算资源,比如说一些复杂的计算。
  • IO密集型:占用大量的磁盘IO与网络IO,比如说文件传输。

在这些,对服务器性能和代码的健壮性要求很高的业务模块中,经常需要实现服务隔离而将这些模块单独部署,为了防止突发流量服务器压力过大造成崩溃,导致服务不可用而牵连其他应用。因此,我们通过服务隔离,可以很好地保护其他服务。

再者,将这些模块隔离出来,可以很好地做一些流控措施,比如说一些削峰填谷以及流控的手段。

对于热点数据,通常仅仅隔离服务还远远不够,有时候还需要隔离底层的热点数据。比如说秒杀商品,可以将这些商品使用缓存等单独处理。

还有一些热点新闻等,一般可以通过API调用策略,后台触发这些热点数据的探测,进行动态热点数据的隔离

3、主链路规划

对于用户行为的主链路,一定要将每一个模块单独拆分出来,不用完全的顾及领域模型,这完全是根据业务的角度进行规划的主链路

比如说电商项目,用户搜索->详情->购物车->下单->支付,这一整个主链路,完全可以单独拆分出来。这样做的好处就是,可以做到与边缘业务服务隔离,如果服务器压力过大,可以将这些服务进行弹性伸缩、流控、容错等等更加精细的控制。与边缘业务隔离开之后,也可以避免边缘业务影响到主链路的正常使用。

4、用户群体

比如说很多电商中的用户群体,有商家用户、消费者用户、运营用户、采购用户等等,可以将这些用户进行单独拆分。

还有很多教育平台,分教师、学生等等用户。

其实很多网站,不单单是只有一个APP入口,通常来说不同的用户角色都会对应着不同的系统入口,比如说滴滴就分乘客APP和司机APP。为了使系统更加清晰,可以对不同的用户进行独立拆分,各自维护。

二、设计微服务的无状态化

1、什么是无状态

无状态(stateLess),也就是上下文并没有依赖。

比如说用户登录状态Session,单机环境下,Session存在服务器本地,用户每次登录需要获取到当前登录的用户信息,这就叫有状态。这样的话,该服务就无法做到横向扩容,增加一个服务节点之后无法做到服务节点之间的Session共享。解决方案也很简单,将Session存储到一个公共存储空间即可比如redis。

再比如本地缓存。单机环境下,如果数据库响应过慢,通常会将部分热点数据保存在服务的内存中,但是增加服务节点之后同样会导致多个节点中的内存数据不一致。同样也可以使用一个公共存储空间来解决这个问题。

2、为什么要追求无状态化

无状态化完全是为了实现服务的横向扩缩容。如果服务设计为有状态,这会限制该服务的横向扩缩容。

3、如何设计无状态化

为了保证服务的无状态,需要实现数据的分发、处理、存储,任意节点的可达性

也就是一个用户请求,不论是落在服务器集群中的任意节点上,都可以完成该请求的处理。

通常来说,实现服务的无状态,就需要在其他方面做到有状态,比如说存储、配置等等。

三、接口的版本控制:向后兼容

1、为什么要做接口的向后兼容

当一个新功能迭代较快时,接口的功能会不断完善和优化,但是下游系统有时候并不会同步进行升级。所以为了兼顾老系统,需要同一个接口功能需要进行老旧功能兼顾,做到向后兼容。

2、兼容方式:if-else

很简单的代码逻辑,通过加一个参数,表示我想调用该接口的哪一个版本,通过if-else的方式进行向后兼容。

有的小伙伴可能编码能力很强,使用策略模式等等一系列的手段,对代码进行更细粒度的拆分。

但是这样的情况会导致,该接口的代码会越来越臃肿难以维护。一个小小的改动通常会牵一发而动全身,而且需要保证测试用例要把历史的情况全覆盖。

3、兼容方式:API Version

通过API的版本将不同的访问请求,路由到不同的接口中。

这样做的好处是,可以兼容老业务,并且实现接口的隔离。

如果使用rpc框架的话,通常很多rpc框架都实现了自动根据接口的版本来查找接口,比如说dubbo:

xml 复制代码
<dubbo:reference id="production" version="1.0.1" interface="IProductionService"/>

对于http接口,可以通过path实现:app/v1app/v2app/v3,通过接口的版本进行接口的隔离。 还可以通过使用header的方式,在header中指定一个版本号,通过业务网关根据header,进行接口的路由。

四、可用性保障:限流

1、限流的维度

通常来说,会考虑根据以下几个维度进行流量的限制:访问频率、IP连接数、黑白名单、传输速率

网关层限流资源消耗最小,业务层限流更加精细。通常来说网关层并不会涉及过多的业务逻辑,如果达到限流策略,直接触发快速失败策略。业务层限流可以实现更加精细、自定义的限流处理。

2、网关层限流

网关层限流是资源消耗最小的,通常会实现一些访问频率、IP连接数、黑白名单、传输速率的限流手段。

使用Nginx+Lua组合可以实现非常靠谱的Nginx层限流。并不会牵扯过多的业务逻辑

3、业务层限流

业务层限流,可以实现一些流量更加精细的限制。

业务层网关限流,比如说Gateway,也算是业务层限流,可以做到一些很精密的限制,不光是限流,还有降级、熔断以及复杂的谓词判断。

还可以借助很多限流组件,比如说Sentinel、Redis+Lua、单机的Guava包等等。

五、BASE理论

Base 是三个短语的简写,即基本可用(Basically Available)、软状态(Soft State)和最终一致性(Eventually Consistent)。

Base 理论的核心思想是最终一致性,即使无法做到强一致性(Strong Consistency),但每个应用都可以根据自身的业务特点,采用适当的方式来使系统达到最终一致性(Eventual Consistency)。

六、幂等性处理

接口的幂等性------详细谈谈接口的幂等即解决方案

相关推荐
杜杜的man38 分钟前
【go从零单排】go中的结构体struct和method
开发语言·后端·golang
幼儿园老大*39 分钟前
走进 Go 语言基础语法
开发语言·后端·学习·golang·go
llllinuuu41 分钟前
Go语言结构体、方法与接口
开发语言·后端·golang
cookies_s_s42 分钟前
Golang--协程和管道
开发语言·后端·golang
为什么这亚子44 分钟前
九、Go语言快速入门之map
运维·开发语言·后端·算法·云原生·golang·云计算
想进大厂的小王1 小时前
项目架构介绍以及Spring cloud、redis、mq 等组件的基本认识
redis·分布式·后端·spring cloud·微服务·架构
customer081 小时前
【开源免费】基于SpringBoot+Vue.JS医院管理系统(JAVA毕业设计)
java·vue.js·spring boot·后端·spring cloud·开源·intellij-idea
2402_857589362 小时前
SpringBoot框架:作业管理技术新解
java·spring boot·后端
一只爱打拳的程序猿2 小时前
【Spring】更加简单的将对象存入Spring中并使用
java·后端·spring