|
最近在开发中遇到了并发过多导致服务器负载过高的问题,结合实际情况优化了一下,特此记录。以下内容已隐去业务细节。
业务逻辑
该问题涉及到的接口主要处理第三方发出的回调,主要是由回调数据给数据库中的数据条目打标签(可视为更新Stamp字段)。应用程序调用一次第三方接口后,至多会收到1000次回调,造成数据库压力过大。该任务对实时性要求不高,适合作为后台任务处理。使用Redis队列与Hangfire优化了数据库并发以改善性能。主要思路如下:
请求到达时,将打标签所用参数序列化后加入Redis队列,再由Hangfire定时任务每分钟处理队列中的任务。
简要实现
以下是代码只展示关键逻辑,其中使用了StackExchange.Redis。ConvertHelper.Serialize<T>(object item)及ConvertHelper.Deserialize<T>(byte[] objBytes)为通用的序列化方法,读者可实现为适当的序列化形式,如JSON,Protobuf等。IScoped接口是一个空接口,表示将该类加入依赖注入容器中。
StampQueueHelper.cs
public class StampQueueHelper : IScoped
{
private readonly IDataBase _database;
public StampQueueHelper(IDatabase database)
{
_database = database
}
private string QueueName = &#34;StampQueue&#34;;
public async Task Enqueue(StampModel model)
{
await _dataBase.ListRightPushAsync(QueueName, ConvertHelper.Serialize(model));
}
private async Task<StampModel> Dequeue()
{
return await _database.ListLeftPush(QueueName)
}
}
StampHelper.cs
public class StampHelper : IScoped
{
private readonly StampQueueHelper _stampQueueHelper;
public StampHelper(StampQueueHelper stampQueueHelper)
{
_stampQueueHelper = stampQueueHelper;
}
public async Task ProcessStamp()
{
var random = new Random();
while(true)
{
var model = await _stampQueueHelper.Dequeue();
if (model == null)
break;
await AddStamp(model) // 执行业务的函数
// 随机等待,进一步减小数据库压力
await Task.Delay(random.next(100, 200));
}
}
}
HTTP接口
[HttpPost]
public async Task StampCallBack(StampModel model)
{
await _stampQueueHelper.Enqueue(model);
}
Hangfire配置
RecurringJob.AddOrUpdate<StampHelper>(c => c.ProcessStamp(), Cron.Minutely, TimeZoneInfo.Local);
本文采用 CC BY-NC-ND 4.0 协议 ,转载请注明出处。 |
|