系统性能优化-10 分布式系统

发布于:2025-07-06 ⋅ 阅读:(20) ⋅ 点赞:(0)

系统性能优化-10 分布式系统

如何牺牲系统的一致性来提高性能

在 CAP 理论中,CA 只能强调一个,当然 C 不是说非 0 即 1 的,大多数场景下都是在可接受的不一致范围内保证最大的可用性。一般在牺牲 C 的情况下可以提升性能,提升的方向分为纵向和横向:

  • 纵向是请求的处理路径,即用户发送请求到服务,期间如果可以在离客户端更近的位置使用处理速度更快的物理介质,就可以作为缓存来降低请求时延
  • 横向是同类服务之间的数据同步路径,如果能增加服务的副本数,并互相同步数据,就可以同时对客户端提供服务,提高了系统的并发性

image-20250703141115667

如果这个服务不是无状态的,例如数据库,不同节点是需要同步数据的,当然也可以读写分离,其他节点只能读,只有主节点可写。所以缓存、有状态服务都是存在一致性的问题。一般有两种方案,一种在更新数据库的时候同时更新缓存,都更新成功再返回,这可以保持较好的的一致性,相应的会影响性能,即 write through;另一种方案则是更新完数据库就返回,异步更新缓存,优点是性能较好,但如果异步更新缓存失败,会出现数据一致性的问题,即 write back。

这个方案是按照缓存来说的,但不同副本间同步数据也是这个逻辑,例如一些主从集群的方案。如果副本间网络较好或系统对一致性要求较高,采用 write through 方案,反之可以采用 write back 方案。

AKF 拓展立方体对分布式系统性能优化的启发

我们日常见到的各种系统扩展方案,都可以归结到 AKF 立方体的这三个维度上。

image-20250703142115549

  • X 轴:直接水平复制应用进程来扩展系统。
  • Y 轴:将功能拆分出来扩展系统。
  • Z 轴:基于用户信息扩展系统。

X轴拓展:当单个服务性能达到上限,可以通过运行多个同样的服务,使用反向代理统一进行转发来提高服务整体的处理能力。这种方式的改动是最少的,原有的事务也不会被影响,缺点是这种只能针对无状态服务,而有状态服务例如数据库,新增节点就需要考虑数据库的集群方案,如何保持数据库整体的数据一致性,另外当性能不是由于服务本身,而是由于服务依赖的后台(数据库等)读写性能到达上限后,再水平拓展服务本身对性能的提升微乎其微。

Y轴拓展:此时就可以考虑依照功能对系统进行拆分,像微服务那样,每个服务有自己的数据库,负责一部分相对独立的业务处理。这种方式的改动是很大的,需要重构一些代码,重新设计表,数据迁移,数据库进行读写分离也属于 Y 轴拆分功能拓展。在单机服务性能到达上限后,可以结合 X 轴拓展提高更好的性能。

Z轴拓展:随着时间累积,数据库中的记录数量达到千万级以上后,X 轴 和 Y 轴拓展(Y 轴更像是表的垂直拆分,但行数依然不变,只是每个表的字段少了)已经不起作用了,这时候就可以考虑基于用户的一些信息进行拓展。例如进行分库分表,例如按照用户的所属省划分为 M 个库,再根据用户的所在市划分为 N 个表,利用 hash 函数进行对应。这种方式的改动也很大,尤其是分库分表后跨库的事务很难实现,优点是可以解决数据增长带来的性能瓶颈,也可以基于数据的空间位置提升系统性能,例如选择离用户 ip 最近的 IDC 提供服务。

降低扩缩容带来的迁移成本 一致性哈希

如果反向代理基于简单的 hash,那么在节点数量增加或减少时,原有的对应关系也会发生很大变化,采用一致性哈希 可以缓解扩缩容带来的影响。

  • 首先,将关键字经由通用的哈希函数映射为 32 位整型哈希值。这些哈希值会形成 1 个环,最大的数字 2^32 相当于 0。
  • 其次,设集群节点数为 N,将哈希环由小至大分成 N 段,每个主机节点处理哈希值落在该段内的数据。

image-20250703145700937

如果需要某个节点承担更大的权重,就在哈希环上分配的更大的弧长。不过这会带来两个问题:

  • 如果选择的 key 与哈希算法不好,容易导致节点承受数据量不均匀,压力集中到其中部分节点上。
  • 发生扩缩容时对相邻的节点不友好,尤其是缩容时直接把该节点的内容分给相邻节点,可能会导致相邻节点崩溃,进而产生连锁反应。

为了解决这个问题,可以在真实的数据节点与哈希环之间引入一个虚拟节点层,假如有 4 个节点,并不需要每个节点负责相连的 1/4 的内容,而是可以把环分为 32 个虚拟节点,虚拟节点再通过哈希函数到 4 个真实节点。

image-20250703150511541

这样当其中一个节点下机后,它的内容在分给相邻的节点时就不会完全分给一个节点,由其他节点共同承担压力。例如节点0下机后,它的部分会分给蓝色的节点2、橙色的节点1和粉色的节点3(从右上角开始分析),同理新增节点也可以分担所有节点的压力。

这样的方案提升了一致性哈希算法的均衡性,但需要消耗更多的内存和服务器算力。

通过修改读写模型来提高性能 NWR 算法

NWR 算法是从 鸽巢原理 得出的,简单来说就是 n+1 个物品放入 n 个抽屉,一定有一个抽屉有两个物品,在分布式集群中可以这么理解,例如有 10 个数据库节点,每次写操作都要写入 6 个节点,每次读操作都要读 5 个节点,那么其实是可以保证数据的一致性的,因为每次读的数据中一定能读到刚刚写的数据,根据时间戳进行比对,很容易找到最新数据。

N 总节点 W 写节点 R 读节点

当鸽子的数量超过了鸽巢后,就要注定某一个鸽巢内一定含有两只以上的鸽子,同样的道理,只要读、写操作涉及的节点超过半数,就注定读写操作总包含一个含有正确数据的节点。NWR 算法将这一原理一般化为:只要读节点数 R + 写节点数 W > 存储节点数 N,特别是 W > N/2 时,就能使去中心的分布式系统获得强一致性。

Cassandra 的一致性模型就将 NWR 算法作为基础,我之前用过 mysql lgalera 方案,也是如此~

通过配置 W 和 R 的个数,可以调整系统对于性能和一致性方向的追求~