Notify

article/2025/11/6 2:27:56

1 有什么用

作用 : 解耦,异步,并行

举个栗子

假设我们有这么一个应用场景,为了完成一个用户注册淘宝的操作,可能需要将用户信息写入到用户库中,然后通知给红包中心给用户发新手红包,然后还需要通知支付宝给用户准备对应的支付宝账号,进行合法性验证,告知sns系统导入新的用户等10步操作。
那么针对这个场景,一个最简单的设计方法就是串行的执行整个流程,如图1所示:
在这里插入图片描述
图1 : 用户注册流程 - 串行流程
这种方式的最大问题是,随着后端流程越来越多,每步流程都需要额外的耗费很多时间,从而会导致用户更长的等待延迟。自然的,我们可以采用并行的方式来完成业务,能够极大的减少延迟,如图2所示。
![image.png](https://img-blog.csdnimg.cn/img_convert/c35b77ac5a3257aa77beb70637747de5.png#clientId=ue811b460-
图2 :用户注册流程 - 并行流程
但并行以后又会有一个新的问题出现了,在用户注册这一步,系统并行的发起了4个请求,那么这四个请求中,如果通知SNS这一步需要的时间很长,比如需要10秒钟的话,那么就算是发新手包,准备支付宝账号,进行合法性验证这几个步骤的速度再快,用户也仍然需要等待10秒以后才能完成用户注册过程。因为只有当所有的后续操作全部完成的时候,用户的注册过程才算真正的“完成”了。用户的信息状态才是完整的。而如果这时候发生了更严重的事故,比如发新手红包的所有服务器因为业务逻辑bug导致down机,那么因为用户的注册过程还没有完全完成,业务流程也就是失败的了。这样明显是不符合实际的需要的,随着下游步骤的逐渐增多,那么用户等待的时间就会越来越长,并且更加严重的是,随着下游系统越来越多,整个系统出错的概率也就越来越大
通过业务分析我们能够得知,用户的实际的核心流程其实只有一个,就是用户注册。而后续的准备支付宝,通知sns等操作虽然必须要完成,但却是不需要让用户等待的。 这种模式有个专业的名词,就叫最终一致。为了达到最终一致,我们引入了MQ系统。业务流程如下:
在这里插入图片描述

图3 :主流程
在这里插入图片描述

图4 : 异步流程
在这里插入图片描述

整体流程
解耦 : 消息发送方和消息消费方解耦
异步&并行 : 消息消费之间异步&并行

2 是什么

核心原理

Notify的设计理念和传统的MQ有些不同,Notify的核心理念是

  1. 为了消息堆积而设计系统
  • 为了消息堆积而设计系统在市面上的大部分MQ产品,大部分的核心场景就是点对点的消息传输通道,然后非常激进的使用内存来提升整体的系统性能,这样做虽然标称的tps都能达到很高,但这种设计的思路是很难符合大规模分布式场景的实际需要的。
  • 在实际的分布式场景中,这样的系统会存在着较大的应用场景瓶颈,在后端有大量消费者的前提下,消费者出现问题是个非常常见的情况,而消息系统则必须能够在后端消费不稳定的情况下,仍然能够保证用户写入的正常并且TPS不降,是个非常考验消息系统能力的实际场景。
  • 也因为如此,在Notify的整体设计中,我们最优先考虑的就是消息堆积问题,在目前的设计中我们使用了持久化磁盘的方式,在每次用户发消息到Notify的时候都将消息先落盘,然后再异步的进行消息投递,而没有采用激进的使用内存的方案来加快投递速度。
  • 这种方式,虽然系统性能在峰值时比目前市面的MQ效率要差一些,但是作为整个业务逻辑的核心单元,稳定,安全可靠是系统的核心诉求。
  1. 无单点,可自由扩展点设计

Notify领域模型

notify消息领域对象的设计如下图所示,每条消息记录包含messageId(这个就是key)、topic、body(二进制)、header(用户自定义kv集合)、commited(事务状态,是否提交)、Fail target(记录失败的消费者id,消息重试要用到)。
在这里插入图片描述

Notify启动流程

  1. Notify Server服务器设置一个固定的订阅关系(终端或客户端),例如 A : B
  2. 消息消费 Server初始化中设置参数为B,那么消息消费 Server启动时,会携带服务器信息发送到Notify Server上,在Notify Server中,B就关联了当前消费服务器
  3. 消息发送Server初始化时设置参数A,那么消息发送Server初始化时在Notify Server上通过A可以获得对应B关联到服务器
  4. 消息发送服务器发送消息到Notify Server,Notify根据订阅关系将当前消息分发到不同的消息消费服务器

Notify普通消息处理流程

  1. 当notify收到消息后,先进行持久化,在kv存储增加一条记录,然后ack给生产者;
  2. 持久化后执行exchange,这一步会对消费者Subscription的属性过滤规则进行计算,得到目标消费者id集合,找到消费者channel直接push。push完后,内存中维护callback等待消费者ack(成功或者失败),如果没有ack,callback默认等待5秒,作为消费超时处理。最多等待5秒后,callback收集到所有ack,如果全部成功,那么直接删除消息记录;如果部分失败,对消息记录进行修改,主要是修改fail target字段,记录失败消费者id。
  3. notify会有后台任务扫描未删除记录,重新投递给失败的消费者id,再次执行4、5、6步骤。

在这里插入图片描述

Notify事务消息处理流程

** 对于事务消息,区别之处在于消息生产环节**。生产者先发送half消息,当notify收到half消息后,先进行持久化,在kv存储增加一条half(即commited字段为false)记录,然后ack给生产者,此时并不会触发推送消费者事件。生产者half发送成功后,执行本地事务,事务执行成功后,发送异步commit请求。notify收到commit请求后,将消息的commited字段更新为true,然后就立马执行推送消费者的流程,消费相关逻辑和普通消息无异。
在这里插入图片描述

注意点 : notify事务消息,第5步commit是异步的吗? commit之后第6步 notify才写KV,如果写失败了,生产者的本地事务还是会提交的。这样的话怎么保证消息会发出去呢?是因为会定期扫描没有commit的数据,然后回调生产者的接口询问数据是否需要comit吗?
1 第5步commit是异步的
2 会扫描未commit的消息回查生产者,达到最终一致

存储服务选择

从07年到现在,notify采用的kv存储模块经历过多次改造。最早notify的消息存储是采用本地文件存储的,参考了ActiveMQ的kaha实现了单机kv存储引擎,在07年12月上线,支撑直冲业务,日均500w消息。然而考虑到交易消息重要性,消息要保证不能丢失,第一个版本的单机存储引擎没有经过多年生产环境的验证,不够成熟,另外也没有多副本机制,无法满足交易对消息可靠性的严苛需求。到了第二个版本,notify开始采用当时最稳定的关系型数据库oracle来做消息存储,在08年3月份发布,支撑核心交易链路,日均1000w消息。随后集团开始启动去O战略,数据库存储需要全面从oracle迁到mysql,为了弥补mysql和oracle的性能和稳定性差异,notify实现了多点高可用mysql存储集群,全部迁移到mysql存储,10年4月完成。由于多点mysql在存储层具备了无状态横向扩容的能力,在稳定性和性能方面许久未遇到瓶颈,所以一直使用了很多年。
在这里插入图片描述
图5 : Notify系统组成结构

  • 消息发送集群:主要是业务方的机器,这些机器上是没有任何状态信息的,可以随着用户的请求量增加而增加或减少业务发送方的机器数量,从而扩大或缩小集群能力
  • 配置服务集群(Config Server) : 这个集群的主要目的是动态感知应用集群,消息集群机器上线与下线,并且及时广播给其他集群。如当前业务接受消息的机器下线时,config server会感知到机器下线,从而将该机器从目标用户组踢出,并通知notify server,notify server在获取到通知之后,就可以将已经下线的机器从自己的投递目标列表中删除,这样就可以实现机器的自动上下线扩容
  • 消息服务器集群(Notify Server) : 也就是真正承载消息发送和消息接受的服务器,也是一个集群,应用发送消息时可以随机选择一台机器进行消息发送,任意一台server挂掉,系统都可以正常运行。当需要增加出林能力时,只需要增加notify Server就可以了
  • 存储(Storage) : Notify存储集群有多种不同的实现方式,以满足不同的应用的实际需求。针对消息安全性要求高的应用,我们会选择使用多份落盘的方式存储消息数据,而对于要求吞吐量而不要求消息安全的场景,我们则可以使用内存存储模型的存储。所以,所有的存储也被设计为随机无状态写入存储模型以保障可以自由扩展。
  • 消息接收集群 : 业务方用于处理消息的服务器集群,上下线机器时也能动态的被config server感知,从而实现机器的自动扩展。

http://chatgpt.dhexx.cn/article/KUqNJq5m.shtml

相关文章

NotifyICon使用

2010-04-11 15:47 by Ju2ender, 1438 visits, 网摘, 收藏, 编辑 最常见使用NotifyIcon的程序就是QQ了,当初我很好奇这通知区域的小企鹅是如何随着QQ的运行放上去的,这的确是个有趣的技巧。 要是用到自己的程序上的确显得很专业!我们来为自己的…

notifyIcon 用法

BalloonTipIcon —— 气泡提示的类型,有None(无)、Info(蓝色感叹号)、Warnning(黄色感叹号)、Error(小红叉) BalloonTipText —— 气泡提示的内容,如上图的N…

C#如何使用NotifyIcon实现任务栏托盘菜单及气泡提示

以软件【银行业会计人员技能训练系统】为例,如何使用NotifyIcon实现任务栏托盘菜单及气泡提示? 实现系统托盘方法如下: 1、向窗体中添加NotifyIcon控件和ContextMenuStrip控件; 2、为ContextMenuStrip控件添加子项; 3…

C#——NotifyICON的使用

1、作用(给程序增加下方提示图标) 2、实现方式 1)添加NotifyIcon控件,属性中Visible设为true 2)选择要显示的图标(icon格式),此时已经可以显示小图标,但右击不会显示小菜单栏. 3、添加ContextMenuStrip控…

【学习笔记】C# 动态系统托盘图标的实现 - NotifyIcon控件

操作步骤: 1、创建一个C# Windows窗体应用项目,命名为“IconTwinkle”: 2、双击解决方案中的“Resources.resx”,点击“添加资源”,选择图标并导入: 3、可见选定的图标已导入项目中: 4、双击右…

Android开发之PreferenceActivity和PreferenceFragment

在PreferenceActivity中,给我们提供了四个选项集成控件:ListPreference,EditTextPreference,CheckBoxPreference和RingtonePreference。 注意: 通过PreferenceActivity生成的XML文件,命名方式是定死了的&…

设置PreferenceFragment主题

整个项目主题颜色暗色,在使用PreferenceFragmentCompat文字也是黑色的导致看不清楚,采取更改PreferenceFragmentCompat主题实现,效果如下: 查看PreferenceFragmentCompat源码看到onCreate开始设置Theme,先获取preferen…

PreferenceFragment和PreferenceActivity

提要:PreferenceFragment展示中设置的值可以通过PreferenceManager.getDefaultSharedPreferences(context).来实现 【正文】 一、PreferenceFragment的引入: PreferenceActivity是一个非常有用的基类,当我们开发Android项目时避免不了选项设置…

彻底变换PreferenceFragment样式和全局设置字体样式的解决方案

一、PreferenceFragment样式修改 新样式 直接上图,原样式为白色样式,即为PreferenceFragment的默认样式: ① 白底黑字;② SwitchPreference开关默认为蓝色; ③ ListPreference列表默认为白色,选中状…

Android之PreferenceFragment详解

【正文】 一、PreferenceFragment的引入: PreferenceActivity是一个非常有用的基类,当我们开发Android项目时避免不了选项设置,这些设置习惯用Preference来保存。Android专门为这种Activity提供了便捷的基类PreferenceActivity。如果继承自Pr…

PreferenceActivity和PreferenceFragment实现设置界面

在进行Android开发的过程中,有时需要实现一个设置界面,就像下面的系统的显示设置。这样的界面自己实现起来略显繁琐,好在Android中已经实现了这样的设置界面,那就是PreferenceActivity。并且PreferenceActivity还有一个莫大的好处…

PreferenceFragment设置界面的编写

效果图&#xff1a; 布局文件&#xff1a; <PreferenceScreenxmlns:android"http://schemas.android.com/apk/res/android"xmlns:app"http://schemas.android.com/apk/res-auto"><PreferenceCategoryandroid:title"string/basic_setting…

Android PreferenceFragment

PreferenceFragment用来显示首选项的设置&#xff0c;效果图如下&#xff1a; 主布局文件&#xff1a; <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:tools"http://schemas.android.com/tools"android:layout_widt…

PreferenceFragment使用

PreferenceFragment 在Android3.0之前&#xff0c;设置界面使用PreferenceActivity&#xff0c;在Android3.0之后&#xff0c;官方推荐使用PreferenceFragment&#xff0c;对应于碎片化技术。 使用 新建Fragment 新建GeneralPreferenceFragment 继承PreferenceFragment&…

Android设置页面之PreferenceFragment的简单使用示例

1.PreferenceFragment介绍 a.PreferenceFragment实际为Fragment的一个子类 b.创建一个PreferenceFragment需要绑定一个xml来显示视图 c.绑定后没就可以当作普通Fragment使用&#xff0c;只是每new一个实例就会创建一个SharePreference,把之前绑定的xml中的值写入保存&#x…

Personal preference

Personal preference 相关文章Algorithm&#xff1a;Algorithm的进阶之路 目录 程序猿成长之路 Personal 历史问题记录 程序猿成长之路 Personal 1、C:\Users\99386\AppData\Local\kingsoft\WPS Cloud Files\userdata\qing\filecache\jazve的云文档\knowledge 历史问题记录…

PreferenceFragment详解

在上篇文章中我们讲述了Android 5.1 Settings的源码解析Android 5.1 Settings模块源码分析_Flying snow-CSDN博客&#xff0c; 其中在介绍到Android的Sub Setting时&#xff0c;我们说到基本上都是使用的PreferenceFragment技术&#xff0c;今天我们就来了解一下关于Preferenc…

Android进阶——Preference详解之Preference系的基本应用和管理(二)

引言 前面一篇文章Android进阶——Preference详解之初识Preference及Preference系&#xff08;一&#xff09;简单描述下了Preference的家族构成和基本知识&#xff0c;相信对于Preference早已不会陌生&#xff0c;肯定也跃跃欲试了吧&#xff0c;这篇文章就给大家总结下Prefe…

Android自定义PreferenceScreen的Layout布局,并获取控件

先说一下需求&#xff0c;要在<PreferenceScreen>里添加一个自定义的Layout&#xff0c;实现如下效果&#xff1a; 操作步骤&#xff1a; 1、在res/layout目录创建一个xml文件&#xff0c;名为my_preference_layout.xml&#xff0c;代码如下&#xff1a; <?xml ver…

PreferenceScreen的使用(非常有用)

在res下建个xml文件夹,建立2个xml文件: preferencescreentest_one.xml <?xml version="1.0" encoding="utf-8"?> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"android:key="using_categor…