【分布式技术专题】「架构实践于案例分析」盘点高并发场景的技术设计方案和规划

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
简介: 【分布式技术专题】「架构实践于案例分析」盘点高并发场景的技术设计方案和规划

高并发是什么?


⾼并发(High Concurrency)是互联⽹分布式系统架构设计中必须考虑的因素之⼀,它通常是指通过设计保证系统能够同时并⾏处理很多请求。



高并发属性和因素


⾼并发相关常⽤的⼀些指标有响应时间(Response Time),吞吐量(Throughput,eg. RPS),每 秒查询率 QPS(Query Per Second),并发⽤户数等。


  • 响应时间(RT)系统对请求做出响应的时间。例如系统处理⼀个 HTTP 请求需要 200ms,这个200ms是系统的响应时间。
  • 吞吐量单位时间内处理的请求数量。
  • QPS每秒响应请求数。在互联⽹领域,这个指标和吞吐量区分的没有这么明显。
  • 并发⽤户数同时承载正常使⽤系统功能的⽤户数量。例如即时通讯系统,同时在线量就****代表了系统的并发⽤户数。



高并发容错技术


高并发容错技术主要是指在高并发场景下的技术实现和解决如何在发生错误的场景下,仍然可以保证系统可以正常运行的技术手段和设计实现方案。


雪崩效应

image.png

如何容错


  • 超时
  • 限流
  • 舱壁模式

断路器


断路器转换示意图

image.png


断路器
组件名称 Hystrix Sentinel Resilience4J
超时机制 线程池模式有timeout 暂时支持的不好 通过限时器实现,此外也有线程池模式
限流 采用线程池和信号量限流 采用信号量机制限流 采用线程池和信号量限流
仓壁模式 采用线程池模式实现隔离 暂时支持的不好 采用线程池模式实现隔离
断路器 采用了开关进行模式 暂时支持的不好 采用了开关进行模式



异步化


本地调⽤异步化


  1. 创建⼀个线程,将耗时操作放到独⽴的线程中执⾏【不建议使⽤】
  2. 使⽤线程池创建线程
  3. @Async注解(尽量把@Async注解标注的⽅法,独⽴到⼀个类⾥⾯去,防⽌this调⽤导致⽆效)



线程池要⾃⼰指定⼀下⼤⼩,防⽌⾼并发场景下内存溢出



远程操作异步化


  • 采用-AsyncRestTemplate



不阻塞当前的业务线程执行,不会造成阻塞和雪崩。

ListenableFuture<ResponseEntity<String>> future = 
    asyncRestTemplate.getForEntity("http://www.baidu.com", String.class);
    future.addCallback(new ListenableFutureCallback<ResponseEntity<String>>() {
        //调⽤失败
        @Override
        public void onFailure(Throwable ex) {
          System.out.println("失败");
        }
        //调⽤成功
        @Override
        public void onSuccess(ResponseEntity<String> result) {
          System.out.println(result.getBody());
        }
  });
  ResponseEntity<String> entity = future.get();
  String body = entity.getBody();
  System.out.println(body);
复制代码


  • 采用-WebClient
  • maven依赖
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-webflux</artifactId>
</dependency>
<dependency>
  <groupId>io.projectreactor.netty</groupId>
  <artifactId>reactor-netty</artifactId>
</dependency>
复制代码
  • 代码实现
Mono<String> mono = this.webClient.get().uri("http://www.baidu.com").retrieve()
                         .bodyToMono(String.class);
HashMap<Object, Object> map = new HashMap<>();
map.put("addressId","demoData");
map.put("userId","demoData");
map.put("receiver","demoData");
map.put("mobile","15151816012");
map.put("province","demoData");
map.put("city","demoData");
map.put("district","demoData");
map.put("detail","demoData");
Mono<String> mono = this.webClient.post().uri("http://localhost:8088/address/update")
    .contentType(MediaType.APPLICATION_JSON_UTF8)
    .body(BodyInserters.fromObject(map))
    .retrieve().bodyToMono(String.class);
return mono.block();
复制代码



其他异步实现机制介绍


  • 基于MQ实现异步化
  • ⽆阻塞编程
  • Reactive Stream编程模型
  • RxJava2/RxJava3编程模型
  • 无锁编程Disruptor编程模型



池化技术改善资源


  • 对象池:享元模式
  • 线程池:生产者/消费者模式
  • 连接池:资源复用模式



缓存提升应用性能




缓存优化问题-如何提升命中率


  • 缓存场景要⽤对——读多写少使⽤缓存才有意义



  • 合理的粒度


  • key:userId value:user对象
  • key:users value:[user1,user2,user3]
  • 前者,当且仅当该user发⽣变化缓存更新;后者任意⼀个user发⽣变化缓存都要更新,命中率往往相对较低



  • 缓存容量


  • ⼀旦缓存存储达到⼀定阈值,就会淘汰数据,缓存算法:LRU/LFU/FIFO等等。
  • 为你的缓存集群做好容量规划。
  • 故障问题



  • 例如:某个缓存实例挂了,此时也会影响命中率
  • 故障转移、⾼可⽤很重要



  • 迁移/扩容缩
  • 不管是⼀致性hash,还是hash槽算法,都有⼀定的数据需要搬迁。



缓存错误问题-缓存雪崩


缓存雪崩是当Redis等缓存服务器挂了,客户端直接请求到数据库⾥⾯。数据库负载⾮常⾼。甚⾄数据库拖挂了。

image.png

  • 优化⽅法:保持缓存层服务器的⾼可⽤。 监控、集群、哨兵。当集群⾥有服务器有问题,让哨兵****踢出去。


  • 依赖隔离组件为后端限流并降级。 ⽐如推荐服务中,如果个性化推荐服务不可⽤,可以降级为热****点数据。


提前演练。演练缓存层crash后,应⽤以及后端的负载情况以及可能出现的问题。 对此做⼀些预案设定。


  • ⽆底洞问题


2010年,Facebook有了3000个Memcached节点,他们发现加机器性能没能提升反⽽下降。

例如:要想对Redis执⾏mget操作,或者在Cluster上实现mget的效果,在集群上执⾏的性能⽐单机 差,⽽且随着节点的增加,性能会越来越差(如果⽤并⾏IO的⽅案,那么⽹络时间复杂度就会从O(1) 变成O(node)

image.png分析总结


  • 更多的机器 != 更⾼的性能
  • 批量接⼝需求(mget/mset)等,机器越多可能性能越差
  • 数据增⻓和⽔平扩展的需求,随着业务量增⼤,就是要⽔平扩容



优化IO的⼏种⽅法:


  • 命令本身的优化:例如慢查询keys、hgetall bigkey等等,性能本身就差,要慎⽤
  • 减少⽹络通信次数
  • 降低接⼊成本:例如客户端⻓连接/连接池、NIO等

  • 热点key的重建优化


问题描述:热点key + 较⻓的重建时间


新浪微博有个⼤V发了⼀条微博,很多⼈去访问,但是可能缓存的设置(或重建)过程是⽐较慢 的,那么就可能导致⼤量的线程都会查询数据源,对数据源压⼒很⼤,⽽且响应⾮常慢

image.png

  • 减少缓存重建的次数
  • 数据尽可能⼀致
  • 互斥锁(读写锁)
  • 永远不过期

  • 分布式锁方案

image.png

  • 可能会有⼤量的线程阻塞住
  • 可能存在死锁问题
  • 永远不过期
  • 缓存层⾯:不设置过期时间(不设置expire)
  • 功能层⾯:为每个value添加逻辑过期时间,⼀但发现超过逻辑过期时间后,就使⽤单独的线程构建缓存。

image.png

  • 可能存在的问题
  • 数据可能会不⼀致
  • 额外的编码⼯作
方案 优点 缺点
互斥锁 思路简单、保证一致性 容易死锁、性能较差
永不过期 基本可以杜绝热点key问题 无法保证一致性、需要独立功能维护缓存



缓存错误问题-缓存穿透


缓存穿透是指查询⼀个⼀定不存在的数据,由于缓存是不命中时需要从数据库查询,查不到数据则不写⼊缓存,这将导致这个不存在的数据每次请求都要到数据库去查询,造成缓存穿透。


如图,如果⽤户通过某个条件,查询缓存没有查到数据,然后查询数据库也没有查到结果,于是数据库直接返回。下⼀次,⽤户继续通过这个条件再去查询,缓存中依然不会有结果,⼜会查询到数据库。如果有⼤量的请求⽆法命中,就可能打穿数据库。

image.png

  • 业务代码⾃身问题


  • 例如调⽤别⼈的接⼝,别⼈的接⼝有问题,那我这边拿到的就是个异常或者null,此时我这边没办法对别⼈接⼝的存储层进⾏缓存恶意hinting、爬⾍等等,例如前端随机⽤⼀个uuid去查询⽂章内容。
  • 观察业务响应时间


  • 响应时间突然过慢,那么可能出现了穿透问题


  • 业务本身出现了问题


相关指标:总调⽤数、缓存层命中数、存储层命中数


  • 解决⽅案
  • 缓存空对象

image.png

  • 存在的问题:


  • 需要更多的key
  • ⼀般会设置过期时间
  • 缓存层和存储层数据“短期”不⼀致


例如调⽤的是⼀个接⼝,接⼝开始挂了,返回null,redis将null给缓存起来了。后来接⼝恢复了正常,存储层也是有数据的,但在缓存过期之前,客户端依然只会接收到null,⽽并⾮接⼝返回的数据。 可以在接⼝正常时,刷新⼀下缓存。(可以考虑在更新或者新增操作的时候删除缓存)。



  • 布隆过滤器


  • 对所有可能查询的参数以hash形式存储,在控制层先进⾏校验,不符合则丢弃。还有最常⻅的则是采⽤布隆过滤器,将所有可能存在的数据哈希到⼀个⾜够⼤的bitmap中,⼀个⼀定不存在的数据会被这个bitmap拦截掉,从⽽避免了对底层存储系统的查询压⼒。


  • 存在问题


  • 对于频繁更新的数据,很难实时构建布隆过滤器。⼀般都是对不太容易变化的数据集使⽤布隆过滤器。



⽔平扩容与垂直扩容


  • 垂直扩容


  • ⽔平扩容




相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
打赏
0
0
0
0
379
分享
相关文章
融合AMD与NVIDIA GPU集群的MLOps:异构计算环境中的分布式训练架构实践
本文探讨了如何通过技术手段混合使用AMD与NVIDIA GPU集群以支持PyTorch分布式训练。面对CUDA与ROCm框架互操作性不足的问题,文章提出利用UCC和UCX等统一通信框架实现高效数据传输,并在异构Kubernetes集群中部署任务。通过解决轻度与强度异构环境下的挑战,如计算能力不平衡、内存容量差异及通信性能优化,文章展示了如何无需重构代码即可充分利用异构硬件资源。尽管存在RDMA验证不足、通信性能次优等局限性,但该方案为最大化GPU资源利用率、降低供应商锁定提供了可行路径。源代码已公开,供读者参考实践。
36 3
融合AMD与NVIDIA GPU集群的MLOps:异构计算环境中的分布式训练架构实践
领先AI企业经验谈:探究AI分布式推理网络架构实践
当前,AI行业正处于快速发展的关键时期。继DeepSeek大放异彩之后,又一款备受瞩目的AI智能体产品Manus横空出世。Manus具备独立思考、规划和执行复杂任务的能力,其多智能体架构能够自主调用工具。在GAIA基准测试中,Manus的性能超越了OpenAI同层次的大模型,展现出卓越的技术实力。
MaxFrame:链接大数据与AI的高效分布式计算框架深度评测与实践!
阿里云推出的MaxFrame是链接大数据与AI的分布式Python计算框架,提供类似Pandas的操作接口和分布式处理能力。本文从部署、功能验证到实际场景全面评测MaxFrame,涵盖分布式Pandas操作、大语言模型数据预处理及企业级应用。结果显示,MaxFrame在处理大规模数据时性能显著提升,代码兼容性强,适合从数据清洗到训练数据生成的全链路场景...
127 5
MaxFrame:链接大数据与AI的高效分布式计算框架深度评测与实践!
盘古分布式存储系统的稳定性实践
本文介绍了阿里云飞天盘古分布式存储系统的稳定性实践。盘古作为阿里云的核心组件,支撑了阿里巴巴集团的众多业务,确保数据高可靠性、系统高可用性和安全生产运维是其关键目标。文章详细探讨了数据不丢不错、系统高可用性的实现方法,以及通过故障演练、自动化发布和健康检查等手段保障生产安全。总结指出,稳定性是一项系统工程,需要持续迭代演进,盘古经过十年以上的线上锤炼,积累了丰富的实践经验。
128 7
云端问道21期方案教学-应对高并发,利用云数据库 Tair(兼容 Redis®*)缓存实现极速响应
云端问道21期方案教学-应对高并发,利用云数据库 Tair(兼容 Redis®*)缓存实现极速响应
本地消息表事务:10Wqps 高并发分布式事务的 终极方案,大厂架构师的 必备方案
45岁资深架构师尼恩分享了一篇关于分布式事务的文章,详细解析了如何在10Wqps高并发场景下实现分布式事务。文章从传统单体架构到微服务架构下分布式事务的需求背景出发,介绍了Seata这一开源分布式事务解决方案及其AT和TCC两种模式。随后,文章深入探讨了经典ebay本地消息表方案,以及如何使用RocketMQ消息队列替代数据库表来提高性能和可靠性。尼恩还分享了如何结合延迟消息进行事务数据的定时对账,确保最终一致性。最后,尼恩强调了高端面试中需要准备“高大上”的答案,并提供了多个技术领域的深度学习资料,帮助读者提升技术水平,顺利通过面试。
本地消息表事务:10Wqps 高并发分布式事务的 终极方案,大厂架构师的 必备方案
阿里云容器服务 ACK One 分布式云容器企业落地实践
阿里云容器服务ACK提供强大的产品能力,支持弹性、调度、可观测、成本治理和安全合规。针对拥有IDC或三方资源的企业,ACK One分布式云容器平台能够有效解决资源管理、多云多集群管理及边缘计算等挑战,实现云上云下统一管理,提升业务效率与稳定性。
大厂都在用的分布式事务方案,Seata+RocketMQ带你打破10万QPS瓶颈
分布式事务涉及跨多个数据库或服务的操作,确保数据一致性。本地事务通过数据库直接支持ACID特性,而分布式事务则需解决跨服务协调难、高并发压力及性能与一致性权衡等问题。常见的解决方案包括两阶段提交(2PC)、Seata提供的AT和TCC模式、以及基于消息队列的最终一致性方案。这些方法各有优劣,适用于不同业务场景,选择合适的方案需综合考虑业务需求、系统规模和技术团队能力。
683 7
分布式爬虫框架Scrapy-Redis实战指南
本文介绍如何使用Scrapy-Redis构建分布式爬虫系统,采集携程平台上热门城市的酒店价格与评价信息。通过代理IP、Cookie和User-Agent设置规避反爬策略,实现高效数据抓取。结合价格动态趋势分析,助力酒店业优化市场策略、提升服务质量。技术架构涵盖Scrapy-Redis核心调度、代理中间件及数据解析存储,提供完整的技术路线图与代码示例。
分布式爬虫框架Scrapy-Redis实战指南
【📕分布式锁通关指南 02】基于Redis实现的分布式锁
本文介绍了从单机锁到分布式锁的演变,重点探讨了使用Redis实现分布式锁的方法。分布式锁用于控制分布式系统中多个实例对共享资源的同步访问,需满足互斥性、可重入性、锁超时防死锁和锁释放正确防误删等特性。文章通过具体示例展示了如何利用Redis的`setnx`命令实现加锁,并分析了简化版分布式锁存在的问题,如锁超时和误删。为了解决这些问题,文中提出了设置锁过期时间和在解锁前验证持有锁的线程身份的优化方案。最后指出,尽管当前设计已解决部分问题,但仍存在进一步优化的空间,将在后续章节继续探讨。
489 131
【📕分布式锁通关指南 02】基于Redis实现的分布式锁

热门文章

最新文章