第一次听见单元化架构的小伙伴可能一时有点懵,听说过微服务架构、网格架构等但是单元化架构是什么鬼?
其实在我们手机里面很多常用APP都是单元化架构,类似高德导航、金融银行类APP都是将单元化架构进行了很多年,我们都知道导航类APP对于请求RT和请求稳定性都是十分严格的,如果RT延迟很高,等你已经路过某个路口了,导航突然告诉你需要拐弯....这个时候的你是不是心里一万个草泥马涌出来了,那么这个导航APP你到家肯定立刻就卸载了
何为单元化架构?
所谓单元,是指一个能完成所有业务操作的自包含集合,在这个集合中包含了所有业务所需的所有服务,以及分配给这个单元的数据。
假如一个业务有30亿数据,采用单元化架构部署的话,我们可以把数据拆解为3份,每份10亿数据,建立3个单元,这三个单元,业务服务一模一样,但是数据库存储的数据不同,分别是10亿数据。
这里根据数据进行单元的拆分,数据需要具备可拆分的属性,比如用户ID等全局唯一标识信息,否则无法拆分单元。
传统分层架构如下图:
- 每一层的服务都有多个节点,上层调用下层都是流量均匀的
- 每一层服务都可以单独扩容或者缩容
单元化架构如下图:
- 也是分为了多层结构,但是每层架构的不同服务节点个数固定,调用链也是固定的
- 一个单元化内部形成了闭环
单元化架构的优势:
不管是传统的分布式架构还是单元化架构都不存在完美的设计,任何架构设计都需要根据使用场景的变化而进行相应的选择
传统分布式架构(SOA服务化)优势很明显,不同分层的服务都可以进行独立的伸缩部署,不过这种架构有个问题就是服务水平拆分了,数据库必须进行分库分表,不然日益增长的流量会导致数据库出现问题,可是数据库分库分表并不能解决服务带来的连接数问题,最终会导致数据库连接爆炸,那么如果数据库进行水平拆分那么对于代码的改造和入侵也是巨大的
随着计算机硬件越来越牛,成本越来越低的时代,其实垂直扩容也是一种新的思路,单元化架构就属于一种垂直扩展,不过这种垂直扩展和传统的垂直扩展不一样,属于全集逻辑+数据切片
就和一个个卡片一样,如果某个机房压力很大无法继续扩展了,那么就将其中一个卡片放到另一个机房部署,并且如果某个单元化出现DOWN机的时候,影响面也很小,这种方式的非常灵活无论是水平扩展还是异地多活的部署都可以立刻完成
流程对比:
在常规的分布式架构中,当遇到银行的存取款这种需要强一致要求时,通常请求会在一个专门操作用户账户的服务中完成对数据库主DB的操作,然后主DB在同步到副本节点中,因为这种场景对于数据一致要求很高,所以后续的取款也会操作到主DB而不是到副本DB,虽然数据安全保障符合了,但是性能太低下了,由于都是对数据库的一条数据进行强操作,势必会被阻塞体验会降低
而如果是单元化架构的话,就会变成下面的流程
- 这是一种最简单的单元化交互结构,各个单元的数据通过MQ同步,不过在真实场景中不单单只会使用这种方式,通常我们还会使用更加快速的小批量数据同步方式那就是内存中间件的同步,不过这个方式虽然速度很快但是不适合同步数据量较大的场景
request确保用户ID一段时间内对应的路由单元不变,就算用户相关纬度的属性发生了变更也能在一段时间内路由单元不变(导航类型APP单元化会有更细致的逻辑),那么这流程和上面的流程就有了本质的区别,A用户不关心B用户的账户是否操作成功,只要A账户操作成功那么A账户立刻完成扣款, 该单元利用同步机制告诉其他单元,这个时候如果B来取款,B所在的单元如果还没同步到最新数据那么B无法看到新的钱,这也就是为什么银行转账会有个等待时间
核心要素:
- 就近路由
- 数据副本增量同步
这2个核心要素完成的话那么异地多活的单元化架构就可以基本跑起来了,单元内部闭环+请求路由就近分配,这2个机制就确保了性能上是高于传统分布式部署方式的,不过带来的问题是复杂度和原始架构(代码)整改成本比较高
就近路由方案:
要满足RT要求,那么单元内的服务要尽可能的完成闭环减少对其他单元的交互,所以路由的策略就必须考虑这个
- 用户取模路由
- 用户常用地点路由
- 设备路由
常规采取的还是常用入口分组路由策略,路由表的映射关系为用户 -- 组关系,组 -- 单元关系
在存储结构确定后,我们还需要确定存储方案,因为整个用户-组分析是依赖大量的调用日志分析得到的,当用户量也很客观的时候我们不得不考虑存储成本,常用的我们可能立即想到:bitmap、db、布隆过滤器
路由场景下就算跨单元路由了,对用户本次请求的影响也只是RT升高,所以只要概率很小那么业务上基本都是可以接受的,所以选用布隆过滤器比较合适,可以支持用户ID、设备ID等多种方式路由,存储成本和计算性能都还不错,路由错误的概率也还能接受
当然还存在一种情况,就是经过用户分组计算后,没有找到用户应该在哪个组,这个时候我们需要一个兜底路由策略,那就是取模策略