高并发相关技巧(待完善)

1.系统的稳定性

高并发业务中首先要考虑的是:系统的稳定性。是首先要保证的问题点。

就好比我一卖早点的,突然一千人冲过来了,咋办,为了保证我店面的安全,要么让排队,然后限制供应。要是油条半天做不出来,等的人等了很久了,咱就给它熔断掉,不卖了,大家也别等了,告辞了您嘞。还有就是卖豆浆的师傅扛不住了,太累了就休息休息,不干主力了。就好比我一卖早点的,突然一千人冲过来了,咋办,为了保证我店面的安全,要么让排队,然后限制供应。要是油条半天做不出来,等的人等了很久了,咱就给它熔断掉,不卖了,大家也别等了,告辞了您嘞。还有就是卖豆浆的师傅扛不住了,太累了就休息休息,不干主力了。

限流(Rate Limiting)

限流是指通过限制系统的请求速率,防止系统因流量过大而崩溃。其核心思想是控制流量,确保系统在可承受的范围内运行。

目的:防止系统资源被耗尽,避免系统因过载而崩溃。

  • 常见算法:

令牌桶算法:系统以固定速率生成令牌,请求需要消耗令牌才能通过。当令牌不足时,请求被拒绝。这种模式可以保证请求在一段时间内不会超过预设的阈值,但是突发请求可能会超过限制。

漏桶算法:请求像水一样流入漏桶,以固定速率流出。当桶满时,新请求被丢弃。这种模式严格平滑流量,无突发流量。

计数器算法:在固定时间窗口内限制请求数量。

滑动窗口算法:在动态时间窗口内限制请求数量,支持动态调整限流策略,适合复杂场景。

  • 适用场景:

API接口限流,防止恶意刷量。
秒杀系统限流,控制秒杀活动的请求速率。
消息队列限流,限制消息的生产和消费速率。
微服务调用限流,防止某个服务的故障导致整个系统崩溃。
数据库访问限流,防止数据库因高并发而宕机。

熔断(Circuit Breaker)

熔断机制是一种保护机制,当服务异常或不可用时,自动切换到备用逻辑或停止访问,避免大量请求堆积导致系统崩溃。其核心思想是快速失败,防止系统雪崩。

  • 状态:

关闭状态(Closed):正常调用服务。此时,断路器观察到请求失败比例没有达到阈值,认为被代理服务状态良好。

打开状态(Open):切断服务调用,直接返回错误。此时,断路器观察到请求失败比例已经达到阈值,认为被代理服务故障,于是打开开关,请求不再到达被代理的服务。

半开状态(Half-Open):尝试恢复服务调用,根据结果决定是否切换到关闭状态。为了能自动恢复对被代理服务的访问,断路器会切换到半开放状态,去尝试请求被代理服务以查看服务是否已经故障恢复。如果成功,会转成关闭状态;否则转到打开状态。

  • 实现原理

服务熔断是指调用方访问服务时通过断路器做代理进行访问。断路器会持续观察服务返回的成功、失败状态,当失败超过设置的阈值时,断路器打开,请求就不能真正地访问到服务了。

  • 适用场景

主要用于微服务架构中,防止某个服务的故障扩散到整个系统。例如,当某个远程服务调用失败率达到一定阈值时,可以熔断对该服务的调用,避免继续请求已经故障的服务,从而保护系统的稳定性。

降级策略

某个功能扛不住时,可以先让它 “休息” 一下,比如返回缓存数据或者提示用户功能暂时不可用。

2.资源争抢与锁竞争

高并发场景下,资源争抢问题尤其严重。

就好比几个顾客一起冲到摊位上抢油条,咱到底该先卖给谁?如果不加以控制,可能还会发生顾客互相抢油条的情况,最后弄得大家都不高兴。钱付了,最后油条不够,这就尴尬了。

数据库并发控制

用乐观锁或者悲观锁来防止数据被同时修改出问题。比如,用版本号或者时间戳来确保数据更新的正确性。

分布式锁

在分布式系统中,避免多个节点同时操作同一资源。可以用 Redis 或 Zookeeper 实现分布式锁。

3.缓存的优化设计

缓存就像是摊位上的 “预制油条”,顾客来了不需要每次都现做,直接从缓存里取现成的,速度快得多。但如果处理不好,缓存也会有自己的麻烦,比如 “缓存穿透”、“缓存击穿” 和 “缓存雪崩”。

缓存穿透、击穿和雪崩

缓存不命中、大量请求涌入数据库时,系统压力会很大。可以用布隆过滤器(Bloom Filter)避免无效查询,用多级缓存架构(比如 Redis 加本地缓存)来分担压力。

缓存更新策略

比如用双写策略或者异步更新,甚至是基于消息队列的延迟双删策略来保证缓存和数据库的数据一致性。

穿透是指缓存中没有,全跑到表里去查询了。击穿是指一个热点数据失效了,突然大量的请求到库里了。而雪崩是指,大量数据到过期时间了,全部失效,这时候大量数据打到库里了。穿透的解决方案上边说了,布隆过滤器。击穿就需要用正确的过期回填策略,雪崩最容易避免,别把大量数据的过期时间设置的相同就好了。

4.数据库压力和优化

数据库就像是摊位背后仓库的库存登记表,如果顾客太多、需求太高,这个表很容易被搞得乱七八糟,甚至崩溃。为了解决这个问题,我们需要做一些优化,就像给摊主配上更多的仓库和店员,一起分担工作。

分库分表

当一张表的数据太多时,可以水平分表或者垂直拆分,同时要注意分片键的选择。

读写分离

将读请求和写请求分散到不同的数据库实例上,以减轻主库的压力。

索引和查询优化

创建合适的索引,避免全表扫描和大范围查询,提升查询效率。

5.队列和异步处理

如果所有任务都要求立刻处理,系统就像一口气涌入了太多顾客的摊位,摊主根本忙不过来。这时候就需要用到消息队列和异步处理来分担工作量,就像安排顾客有序地排队,先登记一下需求,再慢慢满足。

消息队列

使用消息队列(如 Kafka、RabbitMQ)将瞬时的大量请求缓冲起来,再让消费者慢慢处理,这样可以平衡系统的负载。

异步任务处理

将一些不需要实时处理的任务放到后台,让主业务流程更流畅。

6.前端优化和静态资源处理

前端和静态资源的优化就像是提前把油条摊位前的各种调料、筷子、餐巾纸等都准备好,避免顾客反复问摊主要这些小东西,从而减少摊主的工作量,让整个摊位的运转更高效。

前端静态资源优化

用 CDN 和缓存技术减少服务器请求量。合理配置浏览器缓存策略(如 ETag、Cache-Control、 max-age),降低服务器负担。

前后端分离

前端和后端完全分离,减少后端资源消耗,提高系统的整体性能。

7.应用服务扩展与容器化

当摊位(系统)越来越火爆时,摊主一个人显然忙不过来了,这时候就需要考虑如何扩展摊位、增加人手(服务扩展),甚至把整个业务划分成多个摊位,每个摊位各管各的(微服务拆分),这样才能高效运转,满足越来越多的顾客需求。

服务扩展

通过增加实例数量来提升系统处理能力,可以使用 Kubernetes 等容器化平台实现自动扩展。

微服务拆分

将一个大的应用拆分成多个微服务,每个微服务专注于自己的一块业务,这样可以减少资源竞争和锁问题。

8.日志和监控

做高并发系统就像经营一个大型连锁摊位,如果没有及时的信息反馈和监控手段,就像摊主完全不知道店里发生了什么,顾客堵门了都没察觉,等出问题了再处理已经晚了。因此,实时的日志和监控就像摊主的眼睛和耳朵,可以帮助他随时掌握店铺的运营状况,及时发现问题并迅速处理。

全链路监控

通过 APM 工具(如 SkyWalking、Zipkin)进行全链路监控,及时发现和定位性能瓶颈。

日志分析

利用 ELK 等日志分析系统,实时监控系统状态,帮助分析故障原因。

9.连接池和线程池管理

高并发系统中,就像一个繁忙的摊位,摊主得合理分配资源和人手(线程和连接),才能确保摊位高效运行,不然摊主忙不过来就容易出现问题。连接池和线程池的管理就像安排摊位前的排队和后厨的工作分配,让各个环节都有条不紊地运作,避免出现忙成一团的混乱场面。

数据库连接池

合理配置数据库连接池的大小,避免连接数耗尽导致系统崩溃。

线程池管理

用合适的线程池(如 JDK 自带的 ThreadPoolExecutor),合理配置核心线程数、最大线程数和队列长度,避免线程耗尽或任务丢失。

10.安全性与防护

在一个繁忙的摊位,安全和防护同样重要。如果不加以防范,就可能遭遇恶意顾客的攻击,造成损失。安全性和防护策略就像摊主在店门口设置的守卫和监控,确保摊位的正常运营不被打扰。

流量防刷

通过验证码、IP 黑白名单、行为分析等手段,防止恶意流量攻击。

数据防篡改

对关键数据进行签名校验或一致性校验,防止并发下数据被非法篡改。