此文已由作者杨凯明授权网易云社区发布。

欢迎访问网易云社区,了解更多网易技术产品运营经验。

背景

为什么要做事务消息中心

原有kqueue的方式缺点:

  • 降低业务库性能

  • 占用业务库磁盘

  • 历史数据管理成本高

  • 技术运维工作量很大

事务消息中心的优点:

  • 去除上述kqueue的缺点

  • 易运维

  • 易扩展

事务消息中心的缺点:

  • 接入适当改造

  • 增加网络开销

TMC基本概念

事务消息中心主要是提供两阶段提交的方案,对业务方消息提供保证投递的支持。

  • 支持RabbitMQ及Kafka

  • 支持多数据源、多类型

  • 服务端水平扩展

  • 不同业务拆库拆表

名词解释

Application:应用,对应CMDB上的应用名。

TableName:表名,一类消息可以存在一个消息表中,一个消息表可以对应多个exchange或者topic,一个TableName会创建一个Retry Thread及一个CallBack Thread。

TaskItem:任务项,代表一个topic或者一个exchange,一个TaskItem会创建6个Send Thread。

Send Thread:发送线程,每个TaskItem会有创建指定数量的发送线程,可以是Kafka的发送线程,也可以说RabbitMQ的发送线程。。

State Thread:状态线程,是处理消息队列comfirm的线程,包括Kafka、RabbitMQ。。

Retry Thread:重试线程,是处理投递失败消息的线程,重试次数默认是3次。如果发送线程内存队列积满,会导致消息只落库,不投递,也需要重试线程来发送。。

CallBack Thread:回查线程,是处理prepare状态的消息,默认取前3分钟,状态还是prepare状态的消息调用客户端回查接口进行确认。

消息中心平台架构图

  • 哨兵监控,引入哨兵监控图表展示

  • 应用同步自CMDB

  • 应用绑定数据源

  • 应用按业务划分TableName

  • TableName支持一种消息实例多个TaskItem

  • 环境按TableName或者TaskItem分离

  • 数据源管理

消息中心服务端架构图

  • API层,TMC对外暴露Dubbo接口,提供Kafka API以及RabbitMQ API。

  • 引擎层,主要分为4个模块

    • 发送模块:初始化时会根据配置的TaskItem创建Send Thread和State Thread,默认是各6个Thread,

    • 重试模块:初始化时会根据TableName维度创建Retry Thread,每个TableName全局一个重试线程。

    • 回查模块:初始化时会根据TableName维度创建CallBack Thread,每个TableName全局一个回查线程,回查接口通过泛化调用客户端DUBBO接口。

    • 哨兵模块:哨兵会定时收集内存队列大小、发送线程数、状态线程数、重试线程数、回查线程数等

  • 存储层,根据消息系统的类型以及数据库的类型,创建出对应的MessageStore,用以支持Kafka、RabbiMQ以及Mysql、DDB、ORACLE。

  • 基础层,可以是Mysql,DDB或者ORACLE,并部署了一个zookeeper来支持重试线程以及回查线程的选主及配置刷新。

业务方-服务端的投递时序图

  • 除了prepare接口外,其他接口可异步

接入准备

申请消息中心配置创建(待规范)

1.环境说明

2.appName: 应用名称,同CMDB

3.tableName: 在事务消息中心DB表,表名可以自己定义,也可以由我定义后给你

4.topic: kafka的topic  或者 exchange: RabbitMQ的exchange

  • 队列的创建按照原有方式,kafka目前在kafkamanager上建,RabbitMQ走mq申请邮件

  • 前期优化及功能更新较为频繁,具体信息可以popo沟通,手把手支持:hzyangkaiming@corp.netease.com

  • 区分测试的各个环境 以及pre、beta、online可以通过tableName 或者 topic及exchange来做,具体情况具体分析。

中心配置简图如下:  

客户端接入(java+dubbo)

引入pom依赖

<dependency>
   <groupId>com.netease.kaola</groupId>
   <artifactId>transfer-center-api</artifactId>
   <version>0.0.2</version></dependency>

实现callback接口

a.先继承jar包中的接口

package com.netease.kaola.message.client;import com.netease.kaola.message.api.CallBackFacede;public interface CallBackService extends CallBackFacede{

}

b.实现自己的回查接口实现

package com.netease.kaola.message.client;import java.util.List;import com.netease.kaola.message.api.meta.CallBackResult;@Service("callBackService")public class CallBackServiceImpl implements CallBackService{    @Override
    public CallBackResult callback(List<String> primaryKyes) {
        CallBackResult result = new CallBackResult();        // 这里会搜到主键Keys列表,业务进行一一确认后返回
        for(int i = 0;i < primaryKyes.size() ; i++){            if(primaryKyes.size() > 1 && i == (primaryKyes.size() -1) ){
                result.addRollBack(primaryKyes.get(i));
            }else{
                result.addCommit(primaryKyes.get(i));
            }
        }        return result;
    } }

配置callback的dubbo provider

<dubbo:service interface="com.netease.kaola.message.client.CallBackService" ref="callBackServiceImpl" />
配置两阶段提交接口dubbo consumer
<dubbo:reference id="kafkaMesageApi" interface="com.netease.kaola.message.api.KafkaMessageApiService" /><dubbo:reference id="rabbitmqMesageApi" interface="com.netease.kaola.message.api.RabbitmqMessageApiService" />

业务中投递消息

    String msgId = kafkaMesageApi.prepare(message);    try{
        xxxService.doSomeThing();
        message.setMsgId(msgId);     }catch(Exception e){
        kafkaMesageApi.rollback(message); 
    }
kafkaMesageApi.commit(message);

注意事项

  • a.对RT较敏感的服务,可以配置commit及rollback接口异步调用。

    <dubbo:reference id="kafkaMesageApi" interface="com.netease.kaola.message.api.KafkaMessageApiService">
     <dubbo:method name="commit" async="true" />
     <dubbo:method name="rollback" async="true" /></dubbo:reference>

消息体解释

公共参数:

  • msgId:消息id,服务端生成,commit时需要传

  • primaryKey:业务主键字段,由业务方自己填入,回查时的业务主键

  • serverName:业务应用的服务器名称

  • appName:应用名称,同CMDB

  • tableName:在事务消息中心DB表

  • payload:消息内容

KFMessageDTO:

  • topic:kafka的topic

RBMessageDTO:

  • exchange:RabbitMQ的exchange

  • routingKey:RabbitMQ的routingKey

哨兵采集器TransferCollector

实现了哨兵采集器,用来监控TMC事务消息中心的各项指标

网易云免费体验馆,0成本体验20+款云产品!

更多网易技术、产品、运营经验分享请点击

相关文章:
【推荐】 一个体验好的Windows 任务栏缩略图开发心得
【推荐】 kudu存储引擎简析

事务消息中心-TMC的更多相关文章

  1. Apache RocketMQ 正式开源分布式事务消息

    近日,Apache RocketMQ 社区正式发布4.3版本.此次发布不仅包括提升性能,减少内存使用等原有特性增强,还修复了部分社区提出的若干问题,更重要的是该版本开源了社区最为关心的分布式事务消息, ...

  2. 关于 RocketMQ 事务消息的正确打开方式 → 你学废了吗

    开心一刻 昨晚和一哥们一起吃夜宵,点了几瓶啤酒 不一会天空下起了小雨,哥们突然道:糟了 我:怎么了 哥们:外面下雨了,我老婆还在等着我去接她 他给了自己一巴掌,说道:真他妈不是个东西 我心想:哥们真是 ...

  3. RocketMQ 事务消息示例分析

    @ 目录 1 示例模式 2 安装与配置 RocketMQ 3 运行服务 3.1 启动 NameServer 3.2 启动 broker 4 生产者 4.1 事务监听器 4.2 事务消息生产者 5 消费 ...

  4. RocketMQ源码 — 十一、 RocketMQ事务消息

    分布式事务是一个复杂的问题,rmq实现了事务的最终一致性,rmq保证本地事务成功消息一定会发送成功并被成功消费,如果本地事务失败了,消息不会被发送. rmq事务消息的实现过程为: producer发送 ...

  5. RocketMQ源码分析之RocketMQ事务消息实现原理上篇(二阶段提交)

    在阅读本文前,若您对RocketMQ技术感兴趣,请加入 RocketMQ技术交流群 根据上文的描述,发送事务消息的入口为: TransactionMQProducer#sendMessageInTra ...

  6. RocketMQ事务消息实现分析

    这周RocketMQ发布了4.3.0版本,New Feature中最受关注的一点就是支持了事务消息: 今天花了点时间看了下具体的实现内容,下面是简单的总结. RocketMQ事务消息概要 通过冯嘉发布 ...

  7. RocketMQ实现事务消息

    在RocketMQ4.3.0版本后,开放了事务消息这一特性,对于分布式事务而言,最常说的还是二阶段提交协议,那么RocketMQ的事务消息又是怎么一回事呢,这里主要带着以下几个问题来探究一下Rocke ...

  8. RocketMQ事务消息回查设计方案

    用户U1从A银行系统转账给B银行系统的用户U2的处理过程如下:第一步:A银行系统生成一条转账消息,以事务消息的方式写入RocketMQ,此时B银行系统不可见这条消息(Prepare阶段) 第二步:写入 ...

  9. 基于 SOA 概念 RPC 框架 的 消息中心 云部署 设计 漫谈

    一.背景 假设有一个系统的最大并发量有2000TPS左右.同时该系统有闲时和忙时,希望可以随时进行拓展和削减服务能力,以节省服务器费用开销. 该系统能提供站内消息.短信.app消息.邮箱的一个消息系统 ...

随机推荐

  1. linux下时间同步的两种方法分享(转)

    与一个已知的时间服务器同步 代码如下: ntpdate time.nist.gov 其中 time.nist.gov 是一个时间服务器. 删除本地时间并设置时区为上海 复制代码 代码如下: rm -r ...

  2. 【[SDOI2014]旅行】

    听说这是动态开点主席树的板子题,但是发现我还不会,于是就来写一写 其实跟主席树一个样子的 这里就是存个板子吧 #include<cstdio> #include<cstring> ...

  3. 【luogu P1801 黑匣子_NOI导刊2010提高(06)】 题解

    题目链接:https://www.luogu.org/problemnew/show/P1801 替罪羊树吼啊! #include <cstdio> #include <cstrin ...

  4. js操作json方法总结

    相对于前端的老铁来说JSon并不陌生,JSON JavaScript Object Notation 是一种轻量级的数据交换格式,采用完全独立于语言的文本格式,是一种理想的数据交换格式. json可以 ...

  5. [Oracle]分区索引

    上一节学习了分区表,接着学习分区索引. (一)什么时候对索引进行分区 · 为了避免移动数据时重建整个索引,可对索引分区,在重建索引时,只需重建与数据分区相关的索引: · 在对分区表进行维护时,为了避免 ...

  6. chsh 设置用户禁止登陆

    chsh username -s /sbin/nologin ##禁止登陆 chsh username -s /bin/bash ##允许登陆

  7. SpringBoot学习17:springboot热部署配置

    spring为开发者提供了一个名为spring-boot-devtools的模块来使Spring Boot应用支持热部署,提高开发者的开发效率,无需手动重启Spring Boot应用. devtool ...

  8. 关于 NSData 的数据类型(2进制,16进制之间)及深入剖析(转)

    . NSData 与 NSString NSData-> NSString NSString *aString = [[NSString alloc initWithData:adataenco ...

  9. C/C++远程开机

    // 2C:4D:54:ED:08:F0 #include <stdio.h> #include <Windows.h> #include <winsock.h> ...

  10. Windows获取物理内存的2种方式 - 随笔记录

    typedef enum _SYSTEM_INFORMATION_CLASS { SystemBasicInformation, SystemProcessorInformation, // obso ...