消息队列延时聚合通知的重要性

(未完待续)浅谈微服务以及 常用中间件( zookeeper redis rabbitmq) 传统的单体框架,已经不满足目前公司战略规划要求,近几年“微服务“ 这个字眼,出现的越来越频繁,虽然有过一年多微服务项目经验,也很难把微服务解释清楚,到底何为微服务? 哈哈哈,好正经的开头,Martin Fowler曾在其blog上发表了”Microservices“的文章,正式提出了微服务架构,对于微服务的解释,他的定义为:微服务架构是一种架构模式,他 提倡将单一应用程序,划分为一个个独立的服务,服务之间相互协调,相互配合,为用户提供最终价值。 来一张图,感受一下微服务的魅力~ 将传统一个独... 阅读详情

前言

从第一次使用消息队列开始,业务背景是报名系统通知到我们的系统。正常流量下数据都能正常通知过来,但遇到导入报名人时,采用了Task异步通知,数据量一大,队列就死了。当时是尽量采用同步方式,减少并发量。

后来业务上有了专门的营销系统,各种数据的增删改都要进营销系统,我采用的方式在仓储层对需要通知的表的任何更新都通知到队列,这样的方式几乎对其他业务无侵犯。

好处有,坏处也有。很多批量任务的更新如果采用同步方式频繁通知是十分浪费速度的,既影响数据的更新速度,也对队列带来了挑战。我曾经专门拉了个分支来优化批量任务,但由于需要涉及很多批量任务最后不了了之。

更合理的推送模型应该是这样,更新消息先到内存队列,积累一段时间(5秒或30秒)后,聚合到一起推送到消息队列,如下图:

挑战过去

其实也说不上是问题,原因知道,解决方法也知道。只是现状还能支撑,就没有去解决,但这些事情总要面对的。挑战过去的糟糕代码,优化提升性能,本身就是一个技术成长的过程。

迈出第一步

第一步当然是Demo,先列出代码。先贴上一个基于Rabbitmq.Client的客户端帮助代码,用于推送单条数据和多条数据。

<pre style="box-sizing: border-box; font-family: monospace; font-size: 18px; margin: 20px 0px; padding: 15px; border: 0px; background-color: rgb(244, 245, 246); white-space: pre-wrap; word-break: break-all; color: rgb(34, 34, 34); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: justify; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">public class RabbitProvider
 {
 public const string RABBITMQURL = "amqp://test:test@rabbitmq.login1.com:5672/test";
 private static IConnection conn;
 /// <summary>
 /// 获取连接。
 /// </summary>
 /// <param name="url"></param>
 /// <returns></returns>
 public static IConnection CreateConnection(string url)
 {
 ConnectionFactory factory = new ConnectionFactory();
 factory.Uri = new Uri(url);
 factory.AutomaticRecoveryEnabled = true;
 IConnection conn = factory.CreateConnection();
 return conn;
 }
 /// <summary>
 /// 单个
 /// </summary>
 /// <param name="data"></param>
 public static void Publish<T>(string exchange, string queue, string route, T data)
 {
 if (conn == null || !conn.IsOpen)
 {
 conn = CreateConnection(RABBITMQURL);
 }
 using (IModel model = conn.CreateModel())
 {
 model.ExchangeDeclare(exchange, ExchangeType.Direct);
 model.QueueDeclare(queue, false, false, false, null);
 model.QueueBind(queue, exchange, route, null);
 //IBasicProperties props = ch.CreateBasicProperties();
 //FillInHeaders(props); // or similar
 // byte[] body = ComputeBody(props); // or similar 
 model.BasicPublish(exchange, route, null, System.Text.Encoding.Default.GetBytes(data.ToString()));
 }
 }
 /// <summary>
 /// 多条数据
 /// </summary>
 /// <param name="data"></param>
 public static void Publish<T>(string exchange, string queue, string route, List<T> data)
 {
 if (conn == null || !conn.IsOpen)
 {
 conn = CreateConnection(RABBITMQURL);
 }
 using (IModel model = conn.CreateModel())
 {
 model.ExchangeDeclare(exchange, ExchangeType.Direct);
 model.QueueDeclare(queue, false, false, false, null);
 model.QueueBind(queue, exchange, route, null);
 //IBasicProperties props = ch.CreateBasicProperties();
 //FillInHeaders(props); // or similar
 // byte[] body = ComputeBody(props); // or similar
 foreach (var item in data)
 {
 model.BasicPublish(exchange, route, null, System.Text.Encoding.Default.GetBytes(item.ToString()));
 }
 }
 }
 }

也许在部分人眼里能提供支持单条和多条推送的方式已经能解决绝大多数问题,看起来确实如此。但单纯的推送批量数据是有业务方发起,是对每个批量任务都有较大侵入的,虽然它很好,但不够好。接下来我们贴上基于BlockingCollection<T>提供的线程安全集合来完成的队列代码。

<pre style="box-sizing: border-box; font-family: monospace; font-size: 18px; margin: 20px 0px; padding: 15px; border: 0px; background-color: rgb(244, 245, 246); white-space: pre-wrap; word-break: break-all; color: rgb(34, 34, 34); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: justify; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">public class DANQueue<T> : IDANQueue<T>
 {
 private static BlockingCollection<DANMessage<T>> GlobalCollection;
 static DANQueue()
 {
 GlobalCollection = new BlockingCollection<DANMessage<T>>();
 }
 /// <summary>
 /// 添加
 /// </summary>
 /// <param name="item"></param>
 /// <returns></returns>
 public static bool TryAdd(DANMessage<T> item)
 {
 return GlobalCollection.TryAdd(item);
 }
 /// <summary>
 /// 获取一个
 /// </summary>
 /// <param name="item"></param>
 public static DANMessage<T> TryTake()
 {
 var msg = new DANMessage<T>();
 if (GlobalCollection.TryTake(out msg))
 {
 return msg;
 }
 return null;
 }
 /// <summary>
 /// 获取所有
 /// </summary>
 /// <returns></returns>
 public static List<DANMessage<T>> TryTakeAll()
 {
 var list = new List<DANMessage<T>>();
 while (true)
 {
 var q = TryTake();
 if (q == null)
 {
 return list;
 }
 list.Add(q);
 }
 }
 /// <summary>
 /// 统计
 /// </summary>
 public static int Count()
 {
 return GlobalCollection.Count;
 }
 }

测试业务Demo

<pre style="box-sizing: border-box; font-family: monospace; font-size: 18px; margin: 20px 0px; padding: 15px; border: 0px; background-color: rgb(244, 245, 246); white-space: pre-wrap; word-break: break-all; color: rgb(34, 34, 34); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: justify; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">/// <summary>
 /// 用户
 /// </summary>
 public class User
 {
 public string Mobile { get; set; }
 public long CompanyId { get; set; }
 }
 /// <summary>
 /// 仓储
 /// </summary>
 public class Repository<TDocument> : IRepository<TDocument>
 {
 public bool Update(User user)
 {
 DANQueue<User>.TryAdd(new DANMessage<User>() { Body = user, Key = user.CompanyId + user.Mobile, Type = typeof(User).Name, TimeStamp = DateTime.Now.Ticks });
 return true;
 }
 }

分别测试批量更新数据下循环通知和只通知一次耗时,代码如下:

<pre style="box-sizing: border-box; font-family: monospace; font-size: 18px; margin: 20px 0px; padding: 15px; border: 0px; background-color: rgb(244, 245, 246); white-space: pre-wrap; word-break: break-all; color: rgb(34, 34, 34); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: justify; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">public const string ExchangeStr = "fanTest";
 public const string QueueStr = "fanQueueTest";
 private static string TypeUserName = typeof(User).Name;
 static void Main(string[] args)
 {
 //这里就不引入依赖注入了。
 Repository<User> repository = new Repository<User>();
 Stopwatch stopwatch = new Stopwatch();
 stopwatch.Start();
 for (var i = 0; i <= 1000; i++)
 {
 var user = new User()
 {
 CompanyId = 13232,
 Mobile = "11111" + i
 };
 repository.Update(user);
 RabbitProvider.Publish(ExchangeStr, QueueStr, TypeUserName, DANQueue<User>.TryTake());
 }
 stopwatch.Stop();
 Console.WriteLine($"100000UpdateWithPush-Time:" + stopwatch.ElapsedMilliseconds);
 //批量测试。
 stopwatch.Restart();
 for (var i = 0; i <= 1000; i++)
 {
 var user = new User()
 {
 CompanyId = 13232,
 Mobile = "11111" + i
 };
 repository.Update(user);
 }
 RabbitProvider.Publish(ExchangeStr, QueueStr, TypeUserName, DANQueue<User>.TryTakeAll());
 stopwatch.Stop();
 Console.WriteLine($"100000UpdateDelayPush-Time:" + stopwatch.ElapsedMilliseconds);
 Console.ReadLine();
 }
 }

结果如下:

<pre style="box-sizing: border-box; font-family: monospace; font-size: 18px; margin: 20px 0px; padding: 15px; border: 0px; background-color: rgb(244, 245, 246); white-space: pre-wrap; word-break: break-all; color: rgb(34, 34, 34); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: justify; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">UpdateWithPush-Time:4103
UpdateDelayPush-Time:73

这里列举的只是1000条,当我改成1万条的时候,队列挂了!这充分说明了延时聚合通知的重要性。相同的环境下,循环通知支撑不了1万,但聚合后只通知一次的情况下,10万数据也花了9秒。双方性能对比结果是指数级的。

<pre style="box-sizing: border-box; font-family: monospace; font-size: 18px; margin: 20px 0px; padding: 15px; border: 0px; background-color: rgb(244, 245, 246); white-space: pre-wrap; word-break: break-all; color: rgb(34, 34, 34); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: justify; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">UpdateDelayPush-Time:9671

引入定时机制

上面已经对比了循环通知和聚合通知的性能,但普通的聚合十分侵入业务。每种类型的业务都需要引入代码,使用不方便,而且维护起来也麻烦。这时候可以考虑引入定时任务来处理聚合通知。先来个1百万的更新。

<pre style="box-sizing: border-box; font-family: monospace; font-size: 18px; margin: 20px 0px; padding: 15px; border: 0px; background-color: rgb(244, 245, 246); white-space: pre-wrap; word-break: break-all; color: rgb(34, 34, 34); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: justify; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">System.Timers.Timer timer = new System.Timers.Timer(5000);
 timer.Elapsed += Timer_Elapsed;
 timer.Start();
 //批量测试大量数据
 for (var i = 0; i <= 1000000; i++)
 {
 var user = new User()
 {
 CompanyId = 13232,
 Mobile = "11111" + i
 };
 repository.Update(user);

 }

定时触发的方法如下:

<pre style="box-sizing: border-box; font-family: monospace; font-size: 18px; margin: 20px 0px; padding: 15px; border: 0px; background-color: rgb(244, 245, 246); white-space: pre-wrap; word-break: break-all; color: rgb(34, 34, 34); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: justify; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">private static void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
 {
 var list = DANQueue<User>.TryTakeAll();
 if (list.Count > 0)
 {
 RabbitProvider.Publish(ExchangeStr, QueueStr, TypeUserName, list);
 }
 }

运行Debug测试,为方便显示,我减少了一些列,只显示queue名和发布速度,能达到每秒1万左右的量。

<pre style="box-sizing: border-box; font-family: monospace; font-size: 18px; margin: 20px 0px; padding: 15px; border: 0px; background-color: rgb(244, 245, 246); white-space: pre-wrap; word-break: break-all; color: rgb(34, 34, 34); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: justify; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">| test | [fanQueueTest](/#/queues/test/fanQueueTest) | 10,569/s |
| test | [fanQueueTest](/#/queues/test/fanQueueTest) | 12,336/s |

谈到此时的推送速度,再来回顾下刚开始循环通知的速度,每秒250左右,可见速度提升了50倍!

<pre style="box-sizing: border-box; font-family: monospace; font-size: 18px; margin: 20px 0px; padding: 15px; border: 0px; background-color: rgb(244, 245, 246); white-space: pre-wrap; word-break: break-all; color: rgb(34, 34, 34); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: justify; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">| test | [fanQueueTest](/#/queues/test/fanQueueTest) | 249/s |

源码

DAN : DelayAggregationNotice 延时聚合通知组件

总结

经过以上对比,性能从几千就挂到支撑到每秒上万的推送量,并且支撑百万(更高级别没测试)以上级更新依然健壮运行。

结果如此明显,如果还没有动力改变,那还有什么能拯救你呢?

这里的Timer以后可以替换成hangfire,因为hangfire有UI监控,可以查看状态。hangfire貌似不推荐大数据量的参数,这些细节问题以后可以根据测试情况去取舍。

以上仅为了测试,如果要变成通用可复用,还有更长的路需要走,但比起分布式追踪简单多了,一步一步来,用目标约束自己慢慢实现。

播放量、广告曝光与收益如何实时同步?广告数据联动看板实践 在内容变现类应用中,播放量、广告曝光与收益是运营最关注的三个指标,但它们分属内容、广告触发和结算三个不同链路,实时性要求也完全不同。理解事件上报、服务端聚合与平台对账的基本原理,是构建数据看板的基础。广告数据通过客户端SDK回调采集,叠加服务端定时拉取联盟结算数据,形成两套口径并存的体系,既能满足实时趋势观察,又能保证最终收益准确。借助消息队列削峰、Redis原子计数、trace_id去重等工程手段,可将播放与曝光提升到秒级同步。此类联动能力可广泛应用于信息流、短视频等广告变现场景,帮助运营将内容表现与广告 阅读详情

相关推荐

消息处理架构设计:解析、去重与防抖的三层过滤实战

在分布式系统和微服务架构中,消息队列和事件驱动是构建高可靠、可扩展应用的核心技术。其原理在于通过异步通信解耦服务组件,确保系统在部分故障时仍能保持整体可用性。这一技术的核心价值在于提升系统的弹性、吞吐量和可维护性。它广泛应用于实时通知、数据同步、流处理等场景,例如在线协作工具、物联网平台和金融交易系统。本文聚焦于消息处理入口的关键环节,通过构建一个具备解析、去重和防抖能力的“收件箱”模式,解决高并发下的消息乱序、重复和洪峰问题,其中涉及LRU缓存和Redis的混合去重策略,以及针对业务逻辑的防抖优化,为处理

weixin_30500473的博客 429

【任务通知】消息队列

任务通知试水

ystbr的博客 518

Wireshark抓包实战:5个CTF比赛中高频出现的流量分析技巧(附真实案例)

本文分享了Wireshark在CTF比赛和实战渗透中的五个核心流量分析技巧。内容涵盖从宏观统计概览锁定可疑目标、深度解析ICMP与HTTP等协议、追踪重组完整会话流,到利用字符串搜索和命令行工具进行自动化分析。掌握这些高阶技巧能显著提升分析海量网络流量的效率与精准度。

rrr55的博客 260

同步异步通讯和消息队列

一篇文章理解通讯方式

weixin_51980608的博客 1363

单片机OTA升级:Bootloader如何多重校验保障APP完整性?

本文详细介绍了单片机OTA升级中Bootloader如何通过CRC校验、数字签名、版本比对和存储位置检查等多重校验机制保障APP完整性。CRC校验作为快速检测数据完整性的核心手段,结合其他安全措施有效防止设备变砖和安全漏洞,确保远程升级的可靠性。

l3m4n的博客 981

网络工程系统CAD图:从设计到落地的关键技能与实战指南

网络工程并不只是配置路由器和交换机,真正的核心在于将设计方案转化为可施工的物理图纸。网络工程系统CAD图正是连接逻辑设计与物理世界的桥梁,它涵盖综合布线、信息点布置、桥架路由、弱电间规划等关键内容。理解并掌握这套图纸体系,是网络工程师从基础设备调试走向项目主导者、弱电总工乃至网络架构师的重要分水岭。在园区网、数据中心、智能楼宇等真实场景中,一套规范的系统CAD图直接决定了施工质量、验收效率与后期运维的可靠性。本文从基础概念出发,拆解图纸的组成层次、绘制流程和软件工作流,并结合学习路线与就业方向,帮助初学者建

weixin_33860553的博客 389

消息队列之RabbitMQ的五种消息模型,及如何保证可靠消息最终一致性

消息队列(Message Queue,简称MQ):是在消息的传输过程中保存消息的容器,用于分布式系统之间进行通信。MQ的选型和对比在讲RabbitMQ之前先说一下AMQP,即 Advanced Message Queuing Protocol(高级消息队列协议),是一个网络协议,是应用层协议的一个开放标准,为面向消息的中间件设计。基于此协议的客户端与消息中间件可传递消息,并不受客户端/中间件不同产品,不同的开发语言等条件的限制。2006年,AMQP规范发布。类比HTTP。

Tobenumerator的博客 1万+

MediaCreationToolW11:Windows11系统升级与修复利器

在日常使用Windows11系统的过程中,我们可能会遇到一些棘手的问题,比如系统更新时出现异常导致无法成功更新,或者系统本身出现异常需要进行无损修复。此外,当我们的电脑尚未升级到Windows11,而我们又希望进行升级时,一款高效且可靠的工具就显得尤为重要。接下来,MediaCreationToolW11将开始下载Windows11的安装文件,并创建Windows11介质。在“选择你要执行的操作”界面中,选择“ISO文件”。此时,你可以使用你的账户登录系统,并开始使用全新的Windows11系统了。

nntxthml的博客 2404

【消息队列】RabbitMQ五种消息模式

Spring AMQP是基于AMQP协议定义的一套API规范,提供了模板来发送和接收消息,包含两部分,其中Spring-amqp是基础抽象,spring-rabbit是底层的默认实现。这是为了防止消息队列中的队列不存在,在进行消息队列初始化的时候不知道是先建立消费者,还是先建立生产者,所以都执行创建函数,但是创建的队列只有一个不会重复。发布者发送消息时,指定消息的RoutingKey,Exchange将消息路由到BindingKey与消息RoutingKey一致的队列。Work queue,工作队列。

weixin_62513677的博客 3505

Kaggle赛题总结:Enefit - Predict Energy Behavior of Prosumers

竞赛旨在解决能源不平衡的问题,即预计使用的能源与实际使用或产生的能源不符。自发自用者是既消耗又产生能源的个体,他们在造成能源不平衡方面起到了重要作用。尽管他们只占所有能源消费者的一小部分,但他们不可预测的能源使用行为给能源公司带来了物流和财务问题。如果不加以解决,可能会导致运营成本增加、电网不稳定以及能源资源的低效利用。如果这个问题得到有效解决,将显著降低不平衡成本,提高电网的可靠性,并使自发自用者更高效和可持续地融入能源系统中。

猫敷雪 741

Linux 4.19、Linux 5.10、Linux 6.1 三个版本详细分析

Linux 4.19发布日期:2018年10月22日LTS 状态:是长期支持版本,官方支持到2024年12月。Linux 5.10发布日期:2020年12月13日LTS 状态:LTS 版本,官方支持到2026年12月。Linux 6.1发布日期:2022年12月11日LTS 状态:不是官方的LTS版本,但通常社区会为新的版本提供一定时间的支持。定位:稳定性和长期支持,广泛应用于多种平台,尤其是嵌入式系统和服务器。主要优势:稳定性高,广泛的硬件支持,核心功能可靠。

小灰灰的博客 5949

性能提升五十倍:消息队列延时聚合通知的重要性

前言这个话题对我而言,是影响很久的事情。从第一次使用消息队列开始,业务背景是报名系统通知到我们的系统。正常流量下数据都能正常通知过来,但遇到导入报名人时,采用了Task异步通知,数据量一大,队列就死了。当时是尽量采用同步方式,减少并发量。 后来业务上有了专门的营销系统,各种数据的增删改都要进营销系统,我采用的方式在仓储层对需要通知的表的任何更新都通知到队列,这样的方式几乎对其他业务无侵犯。 好处有...

weixin_34290096的博客 147

深度学习论文: Cultivated Land Extraction from High-Resolution Remote Sensing Image

深度学习论文: Cultivated Land Extraction from High-Resolution Remote Sensing Image The Winning Solution to the iFLYTEK Challenge 2021 Cultivated Land Extraction from High-Resolution Remote Sensing Image PDF: https://arxiv.org/pdf/2202.10974.pdf PyTorch代码: https:

mingo_敏 3479

延时消息_性能提升五十倍:消息队列延时聚合通知的重要性

前言这个话题对我而言,是影响很久的事情。从第一次使用消息队列开始,业务背景是报名系统通知到我们的系统。正常流量下数据都能正常通知过来,但遇到导入报名人时,采用了Task异步通知,数据量一大,队列就死了。当时是尽量采用同步方式,减少并发量。后来业务上有了专门的营销系统,各种数据的增删改都要进营销系统,我采用的方式在仓储层对需要通知的表的任何更新都通知到队列,这样的方式几乎对其他业务无侵犯。好处有,坏...

weixin_39540271的博客 203

ICC2如何写出floorplan信息

不用-exclude 的话rows_tracks / vias /blockages / routing_rules信息都会写出去,即便用了-include {macro ports}也不行,所以不介意这些东西的话可以用以下两种种def方式去写floorplan。write_floorplan用法和write_def一样,因为写出来的文件夹里就包含def,用write_floorplan的好处和innovus saveFPlan一样,都能写出voltage area和bound信息。

m0_61544122的博客 1069

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

聚合或其他 set 操作消除了 null 值_性能提升五十倍:消息队列延时聚合通知的重要性...

前言这个话题对我而言,是影响很久的事情。从第一次使用消息队列开始,业务背景是报名系统通知到我们的系统。正常流量下数据都能正常通知过来,但遇到导入报名人时,采用了Task异步通知,数据量一大,队列就死了。当时是尽量采用同步方式,减少并发量。后来业务上有了专门的营销系统,各种数据的增删改都要进营销系统,我采用的方式在仓储层对需要通知的表的任何更新都通知到队列,这样的方式几乎对其他业务无侵犯。好处有,坏...

weixin_39564755的博客 579

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

消息队列选型:Kafka vs RabbitMQ vs RocketMQ 终极对决

摘要:本文从软件测试视角对比分析Kafka、RabbitMQ和RocketMQ三大消息队列,重点考察其性能、可靠性和易测试性。Kafka擅长高吞吐流处理,RabbitMQ侧重灵活路由,RocketMQ强于事务消息。测试团队应基于业务场景(如日志分析、订单处理)设计针对性测试策略,包括性能基准、故障注入和端到端追踪,确保技术选型匹配系统需求。建议通过POC验证关键指标,平衡吞吐量、延迟和容错能力,为分布式系统提供可靠的消息中间件解决方案。(149字)

2501_94438416的博客 470

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

RabbitMQ与Kafka消息队列技术选型指南

消息队列作为分布式系统解耦的核心组件,通过异步通信机制实现生产者和消费者的松耦合。其技术原理主要基于发布/订阅和点对点模式,在保证消息可靠传递的同时提升系统扩展性。从技术价值看,优秀的消息中间件能显著降低系统复杂度,实现流量削峰和故障隔离。典型应用场景包括金融交易、电商订单、日志采集等对消息顺序性、可靠性和吞吐量要求各异的领域。RabbitMQ凭借灵活的Exchange路由机制,在需要复杂消息路由的金融支付场景表现突出;而Kafka的分布式日志架构则更适合处理用户行为分析等海量数据场景。理解两者的设计哲学差

weixin_28224217的博客 148

kafka应用场景

活动跟踪:Kafka 可以用来跟踪用户行为,比如我们经常回去淘宝购物,你打开淘宝的那一刻,你的登陆信息,登陆次数都会作为消息传输到Kafka ,当你浏览购物的时候,你的浏览信息,你的搜索指数,你的购物爱好都会作为一个个消息传递给 Kafka,这样就可以生成报告,可以做智能推荐,购买喜好等。传递消息:Kafka另外一个基本用途是传递消息,应用程序向用户发送通知就是通过传递消息来实现的,这些应用组件可以生成消息,而不需要关心消息的格式,也不需要关心消息是如何发送的。

randou_的博客 1168

云智学院 | 十分钟看懂时序数据库⑵-预处理

物联网领域近期如火如荼,互联网和传统公司争相布局物联网。作为物联网领域数据存储的首选时序数据库也越来越多进入人们的视野,早在2016年7月,百度云在其天工物联网平台上发布了国内首个多租户...

百度智能云 150

从TDengine的开源说起技术选型

如果一艘快艇足够承载下你的所有货物到达彼岸,那么你不需要使用一艘轮船出行。产品设计和技术选型也是一样,我们经常会说:“我需要一个能够处理百万规模并发读写操作的,低延时,高可用的系统。” 如果按照这样的需求去设计系统,你可能得到的是一个设计复杂,代价昂贵的通用方案。但是如果仔细分析一下需求,你可能省略了需求背后的一些前提条件,比如真实的需求可能是这样的:“我需要一个能够处理百万规模的并发(只是理论峰...

曲奇泡芙 1万+

使用 AMQP 和 Vert.x 实现微服务间的异步通信

微服务是大多数新型现代软件解决方案中的首选架构。它们(大多数)被设计成去做一件事,它们必须相互协作去完成业务用例。微服务之间的所有通信都是通过网络呼叫进行的;这种模式避免了服务之间的紧耦合而且提供了更好的模块分离。 这里基本上有两种通信方式:同步和异步。正确应用这两个方式是请求-回复和事件驱动模式的基础。在请求-回复模式中,客户端初始化一个请求,并且通常同步等待回复。然而,有些情况下,客户端可以不...

Tybyqi的博客 492

微服务架构组成以及注意事项

(一)、架构分解 网关集群:数据的聚合、实现对接入客户端的身份认证、防报文重放与防数据篡改、功能调用的业务鉴权、响应数据的脱敏、流量与并发控制等 业务集群:一般情况下移动端访问和浏览器访问的网关需要隔离,防止业务耦合 Local Cache:由于客户端访问业务可能需要调用多个服务聚合,所以本地缓存有效的降低了服务调用的频次,同时也提示了访问速度。本地缓存一般使用自动过期方式,业务场景中允...

weixin_30437481的博客 444

RocketMQ之Topic主题详解

RocketMQ中消息传输和存储的顶层容器,用于标识同类业务中逻辑的消息,可理解为消息的分类,主题消息的分类取决于业务,要发送的业务消息最好单独是一个Topic主题,以保证互相不被干扰

FlyingFish868的博客 1699

Zephyr RTOS线程机制详解:从内核调度到同步通信实践

在嵌入式实时操作系统(RTOS)中,线程作为核心的并发执行单元,是实现多任务处理的基础。其原理基于内核调度器对多个独立执行流的快速切换,模拟并行处理能力。这一机制的技术价值在于提升系统响应效率与资源利用率,尤其适用于需要同时处理传感器数据、网络通信和外设驱动的物联网设备等场景。通过优先级调度与可抢占机制,结合信号量、互斥锁等同步原语,开发者能够构建稳定可靠的多线程应用。本文聚焦于Zephyr RTOS的线程实现,深入解析其生命周期管理、栈内存规划及线程间通信的最佳实践,帮助开发者规避数据竞争和栈溢出等常见问

weixin_34242331的博客 488
上一篇: 高效巧用这19条MySQL优化
下一篇: Redis存储——这些数据结构原理你都懂吗?
Java_ttcd
博客等级 码龄4年 198粉丝 190原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值