服务的雪崩以及解决方案


一、什么是服务的雪崩

服务的雪崩效应是一种因服务提供者不可用导致服务调用者不可用,并将不可用逐渐放大的过程。
在这里插入图片描述

二、服务雪崩形成的原因

1.服务提供者不可用
2.重试加大流量

  • 在服务提供者不可用后,用户由于忍受不了界面上的长时间等待,而不断刷新页面,甚至提交表单。
  • 服务的调用端存在大量服务异常后的重试逻辑。

3.服务调用者不可用(服务雪崩效应的每个阶段都可能由不同的原因造成)造成服务不可能的原因如下:

  • 硬件故障可能为硬件损坏造成的服务器主机死机,网络硬件故障造成的服务提供者的不可访问。
  • 缓存击穿一般发生在缓存应用重启,所有缓存被清空时,以及短时间内大量的缓存失效时。大量的缓存不命中,使请求直接访问后端,造成服务提供者超负荷运行,引起服务不可用。
  • 在秒杀和大促开始前,如果准备不充分,使用户发起大量的请求,也会造成服务的不可用。

服务调用者不可用的主要原因是当服务调用者使用同步调用时,会产大量的线程等待占用系统资源。一旦线程资源被耗尽,服务调用者提供的服务也将处于不可用状态,于是服务雪崩效应就产生了。

三、雪崩解决方案

3.1 设置超时时间

超时处理:设定超时时间,请求超过一定时间没有响应就返回错误信息,不会无休止等待。
在这里插入图片描述

3.2 线程隔离(舱壁模式)

舱壁模式来源于船舱的设计:
在这里插入图片描述
船舱都会被隔板分离为多个独立空间,当船体破损时,只会导致部分空间进入,将故障控制在一定范围内,避免整个船体都被淹没。

于此类似,我们可以限定每个业务能使用的线程数,避免耗尽整个tomcat的资源,因此也叫线程隔离。
在这里插入图片描述

设置每个业务线程上限,不会导致一个业务把所有的资源都耗尽

3.3 熔断器(断路器)

断路器模式:由 断路器 统计业务执行的异常比例,如果超出阈值则会 熔断 该业务,拦截访问该业务的一切请求。

断路器会统计访问某个服务的请求数量,异常比例:
在这里插入图片描述
当发现访问服务C的请求异常比例过高时,认为服务C有导致雪崩的风险,会拦截访问服务C的一切请求,形成熔断:
在这里插入图片描述
设置异常/失败/慢调用上限,当达到上限就断开调用,再来的请求都不让调用,隔断时间之后再尝试调用,如果服务还能运行再放行,否则继续拒绝。

3.4 限流

流量控制:限制业务访问的QPS,避免服务因流量的突增而故障。
在这里插入图片描述

四、总结

1.什么是雪崩问题?

微服务之间相互调用,因为调用链中的一个服务故障,引起整个链路都无法访问的情况。

2.限流 是对服务的保护,避免因瞬间高并发流量而导致服务故障,进而避免雪崩。是一种 预防 措施。

3.超时处理、线程隔离、降级熔断 是在部分服务故障时,将故障控制在一定范围,避免雪崩。是一种 补救 措施。

### 解决缓存雪崩问题的有效方法 缓存雪崩是指大量缓存在同一时刻过期,导致请求直接打到数据库,造成数据库负载过高甚至崩溃的情况。为了避免这种情况的发生,可以从以下几个方面入手: #### 1. **设置合理的缓存过期时间** 通过为不同类型的缓存设置随机的过期时间,可以避免所有缓存在同一时间失效。例如,在实际开发中,可以通过在基础过期时间的基础上增加一个随机数来实现这一目标[^3]。 ```python import random base_time = 60 * 60 # 基础过期时间为1小时 random_offset = random.randint(0, 60) # 随机偏移量为0~60秒 expire_time = base_time + random_offset ``` #### 2. **引入多级缓存机制** 采用多级缓存设计,能够有效降低单一缓存层的压力。通常情况下,可以结合本地缓存(如 Caffeine 或 Ehcache)和分布式缓存(如 Redis),形成多层次的缓存体系。当一级缓存失效时,可以尝试从二级缓存中获取数据,进一步减少对数据库的直接访问次数。 #### 3. **实施缓存预热策略** 缓存预热是一种主动加载缓存的方式,能够在业务高峰期之前提前将热点数据加载至缓存中,从而避免因冷启动而导致的大规模缓存缺失现象。具体做法是在低峰时段批量查询并填充缓存,确保高峰期间大部分请求可以直接命中缓存[^1]。 #### 4. **使用分布式锁保护热点数据** 对于某些高频访问的热点数据,即使设置了较长的过期时间,仍然可能面临高并发场景下的竞争问题。此时可以通过引入分布式锁(如基于 Redis 的分布式锁)来控制这些热点数据的更新过程,防止多个线程同时刷新缓存而引发连锁反应[^4]。 #### 5. **启用限流降级措施** 针对突发流量或异常情况,应考虑加入熔断器和限流组件,及时拦截超出预期范围的请求,保障核心服务稳定运行。常见的工具包括 Sentinel 和 Hystrix 等框架,它们可以帮助开发者快速构建具备自我防护能力的应用程序。 --- ### 示例代码:Redis 实现缓存预热与分布式锁 以下是利用 Python 结合 `redis-py` 库演示如何实现缓存预热以及加锁逻辑的一个简单例子: ```python import redis from threading import Thread import time # 初始化 Redis 客户端 r = redis.Redis(host='localhost', port=6379, decode_responses=True) def load_data_to_cache(key): """模拟从数据库加载数据""" data = f"Value_for_{key}" r.setex(key, 3600, data) # 设置键值对及其有效期 print(f"{key} loaded into cache.") def preheat_cache(keys_list): """缓存预热函数""" threads = [] for key in keys_list: t = Thread(target=load_data_to_cache, args=(key,)) threads.append(t) t.start() for t in threads: t.join() def acquire_lock(lock_name, timeout=10): """获取分布式锁""" lock_key = f"lock:{lock_name}" end_time = time.time() + timeout while True: if r.setnx(lock_key, "locked"): r.expire(lock_key, 5) # 锁定超时时间设为5秒 return True if time.time() >= end_time: break time.sleep(0.1) return False def release_lock(lock_name): """释放分布式锁""" lock_key = f"lock:{lock_name}" r.delete(lock_key) if __name__ == "__main__": hot_keys = ["hot_item_1", "hot_item_2", "hot_item_3"] preheat_cache(hot_keys) # 执行缓存预热操作 locked = acquire_lock("update_hot_items") if locked: try: update_database_logic() # 更新数据库或其他耗时任务 finally: release_lock("update_hot_items") # 不管成功与否都需解锁 ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值