求助 C#有办法在自己程序内部实现一个跨线程的简易消息队列吗?现在这种轮询数据库的实现 CPU 占用率很高, 4C8G 阿 里 云占用一直在 100%

2023-11-22 12:58:21 +08:00
 drymonfidelia

需求是几百个客户端不断给我们上报一些数据(加起来每分钟 2000 条左右)我们分类后上报给不同上游。上游的接口设计非常差劲(按照同一份文档),一次只能接受一条数据,有的上游一个请求 3 分钟才响应。上游的程序不是我们能控制的,我们也没权利要求他们修改。

目前我的设计是一个独立 ASP.Net Core 程序接受数据存入数据库(因为有在线率要求,处理任务的程序需要经常重启更新,有的时候会更新坏掉),另一个程序每 2 秒查询一次数据库的新数据,按需要上报的上游分类好进入 5 个不同队列(不能接受数据的时候就分类,因为分类的逻辑也要经常改),另外启动的时候开 5 个线程在数据库里扫描这些队列,发现新的任务就开一个异步 Task 上报。不同上游能接受的并发不一样,Task 外面有个 semaphoreSlim.WaitAsync();防止把上游服务弄炸。这种实现 CPU 占用率很高,4C8G 阿 里 云占用一直在 100%,有没有人知道最佳实现是什么?

2972 次点击
所在节点    .NET
27 条回复
gitdoit
2023-11-22 22:02:26 +08:00
看你这描述,为啥 CPU 会 100%啊?另外,你说的是跨进程消息队列吗
liuhan907
2023-11-22 23:08:10 +08:00
@drymonfidelia
你不应该用数据库做这个工作,这种事情很适合用本地 Log 存储。例如说微软自家的 https://github.com/microsoft/FASTER 。每次收到消息就写入提交,然后你本地多开几组 Task 去处理本地日志就行了。
jiangzm
2023-11-22 23:37:04 +08:00
用数据库做统计干嘛, 单机直接用线程安全队列即可,同时把队列也持久化到数据库,启动的时候扫一下数据库运行的时候只做更新
多台机器/多服务,就用分布式缓存 redis 做队列+分布式锁即可,redis 自带持久化甚至数据库都不用
night98
2023-11-22 23:39:39 +08:00
这不纯纯典型的:生产-》消费场景吗,不过你这个是不是得聚合数据后去上报?不是的话就很简单,直接弄个 mq 或者 redis 消息,生产端拿到客户端数据后塞 db ,然后你收到消息后去处理 db 里对应的数据。

你要是聚合数据后去上报,就稍微麻烦一点,不过也都差不多,既可以用批量消息的功能去进行批量消费,也可以记一个 lastid 然后按区间进行消费,再稍微改进一下就是你接受到消息之后根据业务类型放到不同的线程池里面,根据上游的消费能力去调整不同线程池的大小来控制流速。
lesismal
2023-11-23 00:32:33 +08:00
目测队列不适合解决你的问题:
1. 队列适合解耦、削峰,适合不需要响应队列处理后的结果的请求
2. 队列不能减少处理数量,如果请求需要响应、积压后响应延迟更高甚至超时

要提高性能又不至于让大量请求超时:
1. 数据库前面加缓存
2. 操作缓存和数据库的前面,加 singleflight 、合并同类请求、减少不必要的数据层操作
3. 如果真的量大,仍然需要软、硬件扩容

缺少业务的实际细节,先列这几条吧
yicong135
2023-11-24 09:44:16 +08:00
数据存一份到数据库,一份存消息队列;
你读消息队列数据发送,发送成功后更新数据库
qx4235
353 天前
简单点的你用 Channel 就可以.net3 以上,进程内消息队列。
如果框架不支持,简单点的用 redis stream 来做,redis 版本低了就用 pub/sub,list
复杂或者足够成熟的用 rabbitmq 这些,一般小功能我都用 redis stream 来做

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/994142

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX