一个视角下服务的3种模式

当下的各业务系统,通常会有这样的几种特征:

  1. 完全化的存储计算分离
  2. 部分分离,部分未分离
  3. 完全不分离

对于大多数业务公司,都喜欢用第一种模式,这是一种典型的业务应用 “无状态” 模式,所有的状态管理完全交给数据库,典型的例子是: 关系数据存mysql、缓存放 redis、灵活的数据放 mongodb,服务前面加一个 nginx 做负载均衡。

这种模式的最大优点是 开发简单,绝大多数时候仅需要关心业务逻辑即可。 弊端在于 数据库压力较大,如果数据量增加迅速,或者有高频操作的场景,性能和体量就会受到限制。

当然,这个限制不一定很低,通过钞能力能让这个限制保持在一个很高的位置,高到大多数企业够不到(例如,在阿里云购买很牛逼性能的中间件,或者使用 polarx、mongodb-cluster、redis-cluster 等分布式中间件)。

第二种模式,适用于一些 “操作很重” 的应用中,最好能大量命中缓存,就会采用 部分分离(eg: 数据库操作)、部分未分离(eg: 游戏中的实时数据) 的模式。

当出现数据存储与内存中时,就需要考虑 “数据丢失” 和 “数据不一致” 的问题了,其中 数据不一致 的问题,在分布式系统中比较常见。源于现在大家已经习惯性地写无状态应用了,协议用的是 http 这类无状态协议,负载均衡用的是 轮询 反状态策略,因此,容易出现 “请求节点漂移” 的问题。这部分问题和第三种模式相同,详见第三种模式。

第三种模式,适用于操作频率高,数据关联性十分密切的场景,大多数中间件都属于这类。

这种模式的特点就是 “性能非常高”,他们能够自行管理数据、缓存等等,因此绝大多数操作都在内存中完成。

缺点主要有两方面,其一,需要保证非常强的可用性、可恢复性;其二,分布式场景下的处理比较复杂。

在第二种模式中,说到过 数据一致性 的问题,其中一种方案就是 负载均衡,让对的请求达到对的节点,即可得到对的数据。

解决这个问题,可以有两个方案: 1. Client 需要关心连接的问题 (例如 指定ip、指定路由、重连等等) 2. Client 不关心,由内部模块自行转发。

这两种方案十分常见,例如,nginx 的 xxx hash 的负载均衡策略,就是方案 1,redis client 连接 redis-cluster 时也是方案 1,而 mongodb client 连接 mongodb-cluster 时,则是由 mongos 做转发处理,可以认为是 方案 2。

从 redis 的方案 和 mongodb 的方案中,在负载均衡的方法中,很常用的一种就是 hash slot 方案,对不同节点进行 hash slot 的分配。

另一种方案是 节点注册,这种模式适用于需要精确控制负载的场景。

在分布式场景中,上面这种处理数据一致性的方案是主库模式,数据一致性的问题还存在于 主从同步、元数据变更 等场景中。主从同步,一般采用版本控制的方式和 check sum 的方式。元数据变更,一般采用共识算法保证,例如 poxos 或者 raft ,也有 gossip 这类弱一致性算法。


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!