系统的分层架构有一个迭代演进的过程。早期系统的两层架构如下:(1)上游是业务应用;(2)下游是数据库;随着架构的演进,可能需要抽取微服务,系统的三层架构如下:(1)上游仍然是业务应用;(2)中间是微服务层,提供RPC接口;(3)下游是数据库;众所周知,数据库是可以读写分离的,为了让职责更加明确,在架构设计上,服务能不能和读写分离?如上图所示,服务化读写分离后:(1)业务方通过RPC分别调用读服务和写服务;(2)服务层分为读服务和写服务;(3)底层是高可用的数据库集群;当然也有可能读服务和写服务读写不同的数据库,如上图所示:(1)写服务访问写数据库;(2)读服务访问读数据库;写库和读库是一个主从同步集群。那么,问题来了:(1)你遇到过这种读服务+写服务分离的架构设计吗?(2)这个架构设计好不好,为什么?宿主机是否支持这种读写服务分离的架构设计?先说结论吧。我明确反对服务之间的读写分离。你为什么反对?有五个原因,或大或小。第一点:对于调用者来说,很容易混淆是调用读服务还是写服务来访问同一个基础服务来访问它的RPC接口。第二点:同一个基础服务,服务数量翻倍,运维更加复杂。画外音:总的来说,以上两点是可以忍受的。第三点:一般来说,服务拆分是按照“子业务”维度拆分,而不是“读写”维度。这就是模块化设计的基本原理。画外音:这一点是原则性的问题。第四点:完全打破了微服务“私有服务化数据库”的初衷。画外音:数据访问,你该闭嘴了。由于访问相同的数据库资源,这两个服务耦合在一起。当数据库资源发生变化时(例如:ip变化、域名变化、表结构变化、水平拆分变化等),有两个依赖点需要修改。而一个好的设计,当有变化时,只需要修改一个(低耦合,高内聚)。第五点:没有办法很好的添加缓存。画外音:这是致命的。大多数互联网服务都是读多写少的业务。数据库读取最有可能成为瓶颈。提高读取性能的常用方法是增加缓存。如上图所示,在读服务的下游添加了一个缓存。当有读请求访问时:(1)先访问缓存,命中直接返回;(2)如果缓存未命中,则访问数据库,然后将数据放入缓存中,以便下次命中;那么,在这个架构下,这个方案是不可行的。因为,当写服务修改数据库时,缓存中的数据是无法清除的!!!OK,有朋友说在写数据库之前,可以通过写服务来消除缓存:即读服务和写服务都可以操作缓存。嗯,这样的设计违背了“面向服务的缓存私有”的微服务初衷。由于访问相同的缓存资源,两个服务耦合在一起。当缓存资源发生变化时,有两个依赖点需要修改。画外音:缓存访问,应该闭嘴。此外,如果两个服务访问同一个数据库和缓存,为什么不将它们合并为一个服务呢?如果硬要拆分成两个服务,你自己玩不玩吗?OK,另一个朋友说写服务可以发送消息消除缓存:如上图:(1)缓存是私有的,只有读服务操作缓存;(2)当数据库发生写请求时,写服务向MQ发送消息,读服务清除缓存;本次设计:(1)read服务是用来消除缓存的,本质上是一个写请求,这不奇怪吗?(2)引入了MQ组件,引入了较大的一致性风险;(3)如果读服务和写服务是一个进程岂不是更好那么,为什么非要跨进程通信呢?因此,一个服务更好:(1)来电者不迷茫纠结;(2)易于维护;(3)数据库,私有缓存,无耦合;总的来说,我个人的看法是:互联网微服务架构,建议按照“子服务”拆分微服务,而不是按照“读写”拆分微服务,避免过度设计。以上只是我个人的架构经验,希望逻辑清晰,供大家参考,欢迎一起讨论。【本文为专栏作者《58神剑》原创稿件,转载请联系原作者】点此阅读更多该作者好文
