后端处理高并发状态的多次重复请求
2018-01-12 20:04
274 查看
相信做Web的,都有可能遇到有多次重复请求发送到后端的情况。而这些重复请求,可能大都是由于在网络较差的情况下,用户多次连续点击。最后导致后端面临处理大量重复请求的境地。阻止这些情况发生的方法有很多。
比如在前端,可以设置当用户点击按钮之后,禁用按钮直到有结果返回。如果是用ajax发送请求,那么在发送请求之前,可以调用XMLHttpRequest的abort()函数,abort 函数是清除上一个XMLHttpRequest 重置为 readyState 为 0 的状态,并且取消所有未决的网络活动,等等。
在后端,可以用消息队列,或者缓存,过滤掉相同的请求,也可以设置请求时间间隔。在一个请求执行完一段时间之后才可以执行下一个相同的请求,就当于不休息不给干活。也可以每次都执行你发送的最后一个请求,多次请求只执行最后一次。
以上是比较常见的一些方法。然后我遇到的问题,用这些方法却不能很好的解决。
问题: 目前在做一个基于Lucene的搜索系统,在用户第一次点击搜索的时候,会先调用建索引的接口,把用户相关的信息写到索引里。然后再根据查询条件去查找索引并返回结果。但是由于键索引消耗的时间和资源有点多(包括调用获取数据的API接口),经常会建1分钟的索引。用户在这段时间,会多次点击搜索。于是在后台,就会发现7,8个重复的建索引的请求。同时多个用户如此点击,导致获取数据的API接口的cpu直接爆满,建索引的速度也相当的慢。都是由于7,8个相当于并行处理的请求。然后我希望这些重复的请求只执行一个,并且以最快的速度返回给前端。
解决:我只想用后端的方式解决,那么很显然,只执行第一个请求,后面的都忽略。一开始设置了一层缓存:
第一个请求进来,会为它建立缓存,后面的请求进来会先查找缓存中是否有相同的请求。如果有,那就不执行,那么问题来了,后面的请求不执行检索,那它应该立即返回吗?如果立即返回的话,那么前端会认为索引已经建好了,就开始调用搜索的接口,最后搜索的结果自然是空的。也不能不返回,那样就会报超时的错误。
后来看到网上的一句话: 对于高并发或者分布式的场景 重复的请求最好是不要阻塞 通过判断锁状态直接返回处理状态就好
意思就是,后面请求应该是去看它要执行的代码是否正在被执行,如果正在被执行,就返回索引正在维护,如果执行完了就返回索引已经建好,它本身不回去执行。所以我设计了一下,让后面的请求都搁置,知道索引建完,然后再返回。当然这里最好的办法应该是:返回索引正在维护,并且对维护索引的代码上锁。
修改之后的代码:
我用了一个无限循环,暴力等待索引建好。这样很多请求过来,只有一个请求在执行,并且等第一个请求执行完之后,全部返回同样的结果。这样,这种并发的情况就可以处理好了。
cpu也没有报警。
比如在前端,可以设置当用户点击按钮之后,禁用按钮直到有结果返回。如果是用ajax发送请求,那么在发送请求之前,可以调用XMLHttpRequest的abort()函数,abort 函数是清除上一个XMLHttpRequest 重置为 readyState 为 0 的状态,并且取消所有未决的网络活动,等等。
在后端,可以用消息队列,或者缓存,过滤掉相同的请求,也可以设置请求时间间隔。在一个请求执行完一段时间之后才可以执行下一个相同的请求,就当于不休息不给干活。也可以每次都执行你发送的最后一个请求,多次请求只执行最后一次。
以上是比较常见的一些方法。然后我遇到的问题,用这些方法却不能很好的解决。
问题: 目前在做一个基于Lucene的搜索系统,在用户第一次点击搜索的时候,会先调用建索引的接口,把用户相关的信息写到索引里。然后再根据查询条件去查找索引并返回结果。但是由于键索引消耗的时间和资源有点多(包括调用获取数据的API接口),经常会建1分钟的索引。用户在这段时间,会多次点击搜索。于是在后台,就会发现7,8个重复的建索引的请求。同时多个用户如此点击,导致获取数据的API接口的cpu直接爆满,建索引的速度也相当的慢。都是由于7,8个相当于并行处理的请求。然后我希望这些重复的请求只执行一个,并且以最快的速度返回给前端。
解决:我只想用后端的方式解决,那么很显然,只执行第一个请求,后面的都忽略。一开始设置了一层缓存:
//设置一层缓存,来阻止大量的相同的访问。 string cachekey = GetMemoryKey(appName, authorId); DateTime result; if(!_memoryCache.TryGetValue(cachekey,out result)) { result = DateTime.Now; _memoryCache.Set(cachekey, result,new MemoryCacheEntryOptions() .SetAbsoluteExpiration(TimeSpan.FromMinutes(7)) .SetSlidingExpiration(TimeSpan.FromMinutes(6)) .RegisterPostEvictionCallback((key, value, reason, state) => { Console.WriteLine("缓存失效"); })); //执行建索引的代码 }
第一个请求进来,会为它建立缓存,后面的请求进来会先查找缓存中是否有相同的请求。如果有,那就不执行,那么问题来了,后面的请求不执行检索,那它应该立即返回吗?如果立即返回的话,那么前端会认为索引已经建好了,就开始调用搜索的接口,最后搜索的结果自然是空的。也不能不返回,那样就会报超时的错误。
后来看到网上的一句话: 对于高并发或者分布式的场景 重复的请求最好是不要阻塞 通过判断锁状态直接返回处理状态就好
意思就是,后面请求应该是去看它要执行的代码是否正在被执行,如果正在被执行,就返回索引正在维护,如果执行完了就返回索引已经建好,它本身不回去执行。所以我设计了一下,让后面的请求都搁置,知道索引建完,然后再返回。当然这里最好的办法应该是:返回索引正在维护,并且对维护索引的代码上锁。
修改之后的代码:
//设置一层缓存,来阻止大量的相同的访问。 string cachekey = GetMemoryKey(appName, authorId); DateTime result; if(!_memoryCache.TryGetValue(cachekey,out result)) { result = DateTime.Now; _memoryCache.Set(cachekey, result,new MemoryCacheEntryOptions() .SetAbsoluteExpiration(TimeSpan.FromMinutes(7)) .SetSlidingExpiration(TimeSpan.FromMinutes(6)) .RegisterPostEvictionCallback((key, value, reason, state) => { Console.WriteLine("缓存失效"); })); //建索引代码 Console.WriteLine("索引建好了"); //如果索引成功建完 string buildKey = GetMemoryKey2(appName, authorId); _memoryCache.Set(buildKey, "ok", new MemoryCacheEntryOptions() .SetAbsoluteExpiration(TimeSpan.FromDays(0.8)) .SetSlidingExpiration(TimeSpan.FromDays(0.8)) .RegisterPostEvictionCallback((key, value, reason, state) => { Console.WriteLine("建索引缓存失效"); })); } else { var result2 = "ok"; string buildKey = GetMemoryKey2(appName, authorId); Console.WriteLine(buildKey); while(true) { if(_memoryCache.TryGetValue(buildKey,out result2)) { Console.WriteLine("索引建好了"); break; } } }
我用了一个无限循环,暴力等待索引建好。这样很多请求过来,只有一个请求在执行,并且等第一个请求执行完之后,全部返回同样的结果。这样,这种并发的情况就可以处理好了。
cpu也没有报警。
相关文章推荐
- 控制服务器处理请求的数量(高并发)-防止用户重复点击导致多次请求
- 利用redis缓存解决高并发下后端重复请求措施
- 高并发重复请求的去重处理
- 利用redis缓存解决高并发下后端重复请求措施
- 高并发重复请求的去重处理(转)
- ASP.NET一个页面请求被重复处理多次的原因记录。
- 查看Apache并发请求数及其TCP连接状态
- TCP编程:多进程(fork)并发处理客户端请求
- Linux并发(子进程退出状态的处理)
- IOS-如何处理多个网络请求的并发的情况
- 【微信小程序】下拉加载多次请求的解决方案,避免用户多次发起请求降低业务处理。
- 并发请求在实际应用的处理探讨
- 查看 Apache并发请求数及其TCP连接状态
- 避免Ajax多次发送重复请求
- php处理抢购类功能的高并发请求
- ASIHTTPRequest多次重复请求的问题
- Volley高并发处理网络请求(No2)
- Linux并发(子进程退出状态的处理)
- PageRequestManagerServerErrorException: 在服务器上处理 请求时出现未知错误。服务器返回的状态码为: 500
- 防重复请求处理的实践与总结