C# --- 本地缓存失效形成缓存击穿触发限流

C# --- 本地缓存失效形成缓存击穿触发限流

问题描述

  • 某一接口前端会偶发返回400.
  • 通过检查日志发现是后端服务调用外部Api时,因为缓存失效导致并发请求数量过多 (QPS接近300), 外部Api返回429导致的.
  • 代码大致如下
csharp 复制代码
private readonly MemoryCache _timeZoneCache = new(new MemoryCacheOptions())
	private MemeoryCacheEntryOptions EntryOption => new MemeoryCacheEntryOption().SetAbsoluteExpiraton(DataTimeOffset.Utc.Now.AddMinutes(1))

public async Task Process()
{
	var elements = await GetAllElementsAsync();
	//如果elements数量过多,这里会并发发送大量请求
 	var tasks = elements.Select(element -> GetTimeZoneAsync(element)).ToList();
  
 	if (tasks.Any())
	{
		await Task.WhenAll(tasks)
 	}
 }
 
 private async Task<string> GetTimeZoneAsync(Element element)
 {
  	if (_timeZoneCache.TryGetValue(element.QueryParameter, out string timeZone)
  	{
  		return timeZone
  	}
	
	//send reuqets to external Api
	var reponse = await SendTimeZoneRequestAsync(element)
	//parse http response
    var result = ParseHttpResponse(response)
    //set cache
	_timeZoneCache.Add(element.QueryParameter, result)
 }
  • 当缓存失效时,如果elements的数量过多(比如300个),那么上面的代码会并发发送300个请求. 导致触发外部服务的限流,返回429

解决方案

缓存Request Task

  • 经过调查发现,被发送出去的大量请求其实很多是重复的请求
  • 那么可以利用C#的Task机制,加入一个新的缓存,这个缓存用来缓存发送出去的Request Task,避免重复发送请求
csharp 复制代码
private readonly MemoryCache _timeZoneCache = new(new MemoryCacheOptions())
	private MemeoryCacheEntryOptions EntryOption => new MemeoryCacheEntryOption().SetAbsoluteExpiraton(DataTimeOffset.Utc.Now.AddMinutes(1))

public async Task Process()
{
	var elements = await GetAllElementsAsync();
	//如果elements数量过多,这里会并发发送大量请求
 	var tasks = elements.Select(element -> GetTimeZoneAsync(element)).ToList();
  
 	if (tasks.Any())
	{
		await Task.WhenAll(tasks)
 	}
 }
 
 private async Task<string> GetTimeZoneAsync(Element element)
 {
  	if (_timeZoneCache.TryGetValue(element.QueryParameter, out string timeZone)
  	{
  		return timeZone
  	}
	
   var response = await GetTimeZoneRequestTaskAsync(element);
   
   //parse http response
    var result = ParseHttpResponse(response)
   //set cache
	_timeZoneCache.Add(element.QueryParameter, result)
 }
 
 private async Task<HttpResponse> GetTimeZoneRequestTaskAsync(Element element)
 {
  	if (_timeZoneRequestCache.TryGetValue(element.QueryParameter, out string timeZoneRequest)
  	{
  		return timeZoneRequest
  	}

   //do not await here
   var request = SendTimeZoneRequestAsync(element)
   
   //cache the request
   _timeZoneRequestCache(element.QueryParameter, request);
   return request;
 }
 

加入信号量限制请求数量

相关推荐
死磕音视频4 小时前
让小模型做选择题:限定候选项并读取 logits 概率的入门实践(附 Python 代码)
开发语言·python·大模型·文本分类·transformers
silvamux_5 小时前
curl 测试 OpenAI 兼容 API 的完整流程
java·人工智能·缓存·ai·oneapi
顽疲6 小时前
Java vue 养老系统源码详解:月账单 care_month_bill 与 Quartz 扣费 Job 实践
java·开发语言·vue.js·vue养老·springboot养老·java养老
Wang's Blog6 小时前
Java 项目实战: 交友项目 - 安装开发工具与环境准备
java·开发语言·交友
曹牧7 小时前
C#:输入的字符串格式不正确
c#
程序喵大人8 小时前
【C++入门】编译链接模型 - 07 链接器怎样把符号对上号
开发语言·c++·编译器·编译链接·链接器
微三云 - 廖会灵 (私域系统开发)8 小时前
供应链系统实战:多渠道订单聚合与分布式库存一致性方案总结
开发语言·分布式·php
学逆向的9 小时前
C 数据溢出与精度丢失
c语言·开发语言·网络安全
霸道流氓气质9 小时前
AgentFlow 入门与实战:Task-Based 并发、EWMA 动态调度与四道门禁的 Java 生产级编排
java·开发语言
释厄62310 小时前
错误无误公理——错误正确本同源都迭代定律——逆转有价值
android·开发语言·kotlin