问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

高性能高并发高可用三高系统架构设计看这篇绝对够了

创作时间:
作者:
@小白创作中心

高性能高并发高可用三高系统架构设计看这篇绝对够了

引用
1
来源
1.
https://itindex.net/detail/62966-%E6%80%A7%E8%83%BD-%E5%B9%B6%E5%8F%91-%E4%B8%89%E9%AB%98

保证系统的可用性是系统建设中的重中之重,如果没有可用性,高性能和高并发也无从谈起。高可用的建设通常是通过保护系统和冗余的方法来进行容错,以保证系统的可用性。本文主要从三个维度:应用层、存储层、部署层,详细介绍了可用性的建设方法。

方法论

应用层

限流

限流一般是从服务提供者(Provider)的视角提供的针对自我保护的能力。对于流量负载超过系统处理能力的情况,限流策略可以防止系统被激增的流量打垮。京东内部无论是同步交互的JSF,还是异步交互的JMQ都提供了限流的能力,可以根据系统情况设置。常见的限流算法包括计数器算法、滑动时间窗口算法、漏桶算法、令牌桶算法。以下是这些算法的优缺点对比:

算法
优点
缺点
流量计数器算法
简单好理解
单位时间很难把控,不平滑
滑动时间窗口算法
时间好把控
1. 超过窗口时间的流量就丢弃或降级 2. 没有办法削峰填谷
漏桶算法
削峰填谷
1. 漏桶大小的控制,太大给服务端造成压力,太小大量请求被丢弃 2. 漏桶给下游发送请求的速率固定
令牌桶算法
1. 削峰填谷 2. 动态控制令牌桶的大小,从而控制向下游发送请求的速率
1. 实现相对复杂 2. 只能预先设计不适配突发
熔断降级

熔断和降级是两件事情,但通常结合使用。熔断是为了防止系统被下游系统拖垮。当下游系统接口性能严重变差或挂掉时,会导致大量线程堆积,占用CPU和内存等资源,影响其他接口性能,严重时会将系统拖垮,造成雪崩效应。通过打开熔断器,流量不再请求到有问题的系统,可以保护系统不被拖垮。降级是一种有损操作,需要将损失降到最低,可以返回友好的提示或可接受的降级数据。降级可分为人工降级和自动降级。

  • 人工降级:一般采用降级开关控制,公司内部通常采用配置中心Ducc进行开关降级,开关修改支持线上操作,需要做好监控。
  • 自动降级:采用自动化中间件如Hystrix或公司的小盾龙。使用自动降级时,必须明确降级条件,如失败调用次数等。
超时设置

分布式系统中,不可靠的网络是一个难点。京东物流现有的微服务架构下,服务之间通过JSF网络交互进行同步通信。探测下游依赖服务是否可用的最快捷方式是设置超时时间。超时设置可以让系统快速失败,进行自我保护,避免无限等待下游依赖系统,耗尽系统线程。超时时间的设置需要遵循漏斗原则,从上游系统到下游系统设置的超时时间要逐渐减少。如果不满足漏斗原则,比如服务A调取服务B的超时时间设置成500ms,而服务B调取服务C的超时时间设置成800ms,会导致服务A调取服务B大量超时,而服务B自身却认为是可用的。

重试

分布式系统中,性能的影响主要来自于通信。在一次请求交互中,系统希望尽最大努力得到想要的结果。但在不可靠网络的情况下,需要配置超时重试次数。重试不是无限的,通常会配置重试次数限制。偶尔的抖动重试可以提高系统可用率,但如果下游服务故障挂掉,重试反而会增加下游系统负载,加重故障。对于API的重试,需要区分读接口和写接口。读接口重试一般影响不大,但写接口重试需要做好接口的幂等性。

隔离

隔离是将故障爆炸半径最小化的有效手段,通过不同层面的隔离来控制影响范围,保证系统高可用。

  • 系统建设层面隔离:系统可分为在线系统、离线系统(批处理系统)和近实时系统(流处理系统)。在线系统需要快速响应,离线系统注重吞吐量,近实时系统介于两者之间。例如,可以将在线系统单独部署为一个服务,离线系统和近实时系统单独部署为另一个服务。
  • 环境的隔离:从研发到上线阶段,通常会使用开发、测试、预发和线上环境。部署时要遵循从应用层到中间件层再到存储层,都要在一个环境,严禁跨环境调用。
  • 数据隔离:随着业务发展,需要支撑多业务、多租户。可以通过租户ID字段区分数据,或按库粒度区分。数据隔离还包括按环境隔离、按访问频次隔离等。
  • 核心/非核心流程隔离:应用有分级,业务流程也有黄金流程和非黄金流程之分。例如,在交易业务中,订单系统和支付系统是核心系统,而通知系统可以采用异步方式解耦隔离。
  • 读写隔离:应用层面通过CQRS实现读写隔离,存储层面通过一主多从架构实现读写分离。
  • 线程池隔离:为了避免多个API接口复用同一个线程,需要做好线程池的隔离。
兼容

在对老系统、老功能进行重构迭代时,一定要做好兼容,否则上线后可能出现重大线上问题。兼容分为向前兼容性和向后兼容性。

  • 向前兼容性:旧版本软件或硬件能够与新版本兼容的特性,即旧版本软件或系统兼容新的数据和流量。
  • 向后兼容性:新版本软件或硬件能够与旧版本系统或组件兼容的特性,即新版本软件或系统兼容老的数据和流量。

根据新老系统和新老数据,可以将系统划分为四个象限:

  • 第一象限:新系统和新数据,是系统改造上线后的状态。
  • 第三象限:老系统和老数据,是系统改造上线前的状态。
  • 第二象限:新数据与老系统,如果上线过程中发现问题进行代码回滚,但上线过程中产生了新数据,回滚后的老系统不能处理这些新数据,可能导致线上故障。
  • 第四象限:老数据与新系统,上线后新系统可能影响老流程。

针对第二象限的问题,可以通过构造新数据验证老系统;针对第四象限的问题,可以通过流量录制回放解决。

存储层

存储层主要通过复制和分片来保证高可用。复制是通过副本(主从节点、主从副本)保证高可用,分片是将数据分散到不同节点上保证高可用。复制和分片的思想在MySQL、Redis、ElasticSearch、Kafka中都有采用。

复制

复制技术是一份数据的完整拷贝,通过冗余保证高可用。复制可分为主从复制、多主复制、无主复制。

  • 主从复制:客户端将所有写入操作发送到单个节点(主库),该节点将数据更改事件流发送到其他副本(从库)。读取可以在任何副本上执行,但从库的读取结果可能是陈旧的。
  • 多主复制:客户端将每个写入发送到几个主库节点之一,其中任何一个主库都可以接受写入。主库将数据更改事件流发送给彼此以及任何从库节点。
  • 无主复制:客户端将每个写入发送到几个节点,并从多个节点并行读取,以检测和纠正具有陈旧数据的节点。
分区

分区也称为分片,对于非常大的数据集在单节点存储时,可用性较低且存在存储和性能瓶颈。需要将大数据集通过负载均衡分片到不同节点上,每条数据属于且仅属于一个分区,每个分区都是小型数据库。分区可分为键范围分区和散列分区。

  • 键范围分区:键是有序的,分区拥有从某个最小值到某个最大值的所有键。排序的优势在于可以进行有效的范围查询,但如果应用程序经常访问相邻的键,则存在热点风险。在这种方法中,当分区变得太大时,通常将分区分成两个子分区来动态地重新平衡分区。
  • 散列分区:散列函数应用于每个键,分区拥有一定范围的散列。这种方法破坏了键的排序,使得范围查询效率低下,但可以更均匀地分配负载。通过散列进行分区时,通常先提前创建固定数量的分区,为每个节点分配多个分区,并在添加或删除节点时将整个分区从一个节点移动到另一个节点。也可以使用动态分区。
Redis 的复制和分片

Redis Cluster集群中,会划分16384个槽,key通过散列哈希算法映射到相应的槽中,这些槽分配到不同的分片上,每个分片有主节点和从节点,主节点对外提供读写服务,从节点对外提供读服务。当某个分片的主节点挂掉,其他分片的主节点会从挂掉分片的从节点选择一个作为主节点继续对外提供服务。整体架构如下图所示。

ES索引的复制和分片

创建ES索引时,需要指定分片数量和副本数量。分片数量确定后不允许修改,副本数量允许修改。分片数量一般和数据节点数量保持一致,每个数据节点存储索引的部分数据。Primary分片可以对外提供读写服务,Replica分片对外提供读服务的同时作为备份节点保证可用性。ES索引的不同分片在不同数据节点的分布如下图所示。

Kafka topic的复制和分区

Kafka的topic为了提高可用性和高吞吐,引入了topic的分区。每个分区为了提高可用性,分为Leader partition和Follower partition。Leader partition对外提供读写服务,Follower partition作为灾备提高可用性。整体架构如下图。

部署层

部署层是通过不断突破单机器、单机房、单地域,做到机器级别、机房级别、地域级别的容灾来保证系统的高可用。核心思想是通过冗余以及负载均衡进行容灾保证高可用。

目前的部署架构现状是:应用采用多机房多分组Docker容器化部署,会根据业务方的重要程度及流量大小设置不同的别名,隔离到不同的分组中对外提供服务。具体包括:

  • 应用容器机房:中云信、有孚、廊坊、宿迁等
  • 数据库Mysql双机房部署:中云信、有孚
  • 缓存Redis双机房部署:中云信、有孚
  • ES单机房部署:有孚

整体部署架构如下图所示。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号