前景回顾

【mq】从零开始实现 mq-01-生产者、消费者启动

【mq】从零开始实现 mq-02-如何实现生产者调用消费者?

【mq】从零开始实现 mq-03-引入 broker 中间人

【mq】从零开始实现 mq-04-启动检测与实现优化

【mq】从零开始实现 mq-05-实现优雅停机

【mq】从零开始实现 mq-06-消费者心跳检测 heartbeat

为什么需要心跳?

心跳(heartbeat ),顾名思义就是心脏的跳动。

医学上一般通过心跳是否跳动,来判断一个人是否活着。

那么,分布式服务中如何判断一个服务是否还活着呢?

实现思路

比如 mq 中,broker 需要把消息实时推送给在线的消费者。

那么如何判断一个消费者是否活着呢?

我们可以让消费者定时,比如每 5 秒钟给 broker 发送一个心跳包,考虑到网络延迟等,如果连续 1min 都没有收到心跳,我们则移除这个消费者,认为服务已经挂了。

消费者实现

上代码!

心跳实现

心跳可以是一个很简单的消息体。

@Override
public void heartbeat() {
final MqHeartBeatReq req = new MqHeartBeatReq();
final String traceId = IdHelper.uuid32();
req.setTraceId(traceId);
req.setMethodType(MethodType.C_HEARTBEAT);
req.setAddress(NetUtil.getLocalHost());
req.setPort(0);
req.setTime(System.currentTimeMillis()); log.debug("[HEARTBEAT] 往服务端发送心跳包 {}", JSON.toJSON(req)); // 通知全部
for(RpcChannelFuture channelFuture : channelFutureList) {
try {
Channel channel = channelFuture.getChannelFuture().channel();
callServer(channel, req, null);
} catch (Exception exception) {
log.error("[HEARTBEAT] 往服务端处理异常", exception);
}
}
}

消费者把心跳通知所有的 broker.

心跳的定时执行

我们启动一个定时任务,5S 钟执行一次。

/**
* 初始化心跳
* @since 0.0.6
*/
private void initHeartbeat() {
//5S 发一次心跳
scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
heartbeat();
}
}, 5, 5, TimeUnit.SECONDS);
}

心跳是在连接到 broker 之后就开始启动:

@Override
public void initChannelFutureList(ConsumerBrokerConfig config) {
//1. 配置初始化
//... //2. 初始化
this.channelFutureList = ChannelFutureUtils.initChannelFutureList(brokerAddress,
initChannelHandler(), check); //3. 初始化心跳
this.initHeartbeat();
}

Broker 实现

消费者定时发送消息,生产者肯定是需要接受的。

接收心跳

为了简单,我们让心跳是 ONE-WAY 的。

// 消费者心跳
if(MethodType.C_HEARTBEAT.equals(methodType)) {
MqHeartBeatReq req = JSON.parseObject(json, MqHeartBeatReq.class);
registerConsumerService.heartbeat(req, channel);
return null;
}

hearbeat 处理

每次收到消息,我们把请求的 channelId 记录下来,并保存最新的访问时间

@Override
public void heartbeat(MqHeartBeatReq mqHeartBeatReq, Channel channel) {
final String channelId = ChannelUtil.getChannelId(channel);
log.info("[HEARTBEAT] 接收消费者心跳 {}, channelId: {}",
JSON.toJSON(mqHeartBeatReq), channelId); ServiceEntry serviceEntry = new ServiceEntry();
serviceEntry.setAddress(mqHeartBeatReq.getAddress());
serviceEntry.setPort(mqHeartBeatReq.getPort()); BrokerServiceEntryChannel entryChannel = InnerChannelUtils.buildEntryChannel(serviceEntry, channel);
entryChannel.setLastAccessTime(mqHeartBeatReq.getTime());
heartbeatMap.put(channelId, entryChannel);
}

移除消费者

如果一些消费者长时间没有心跳,我们就认为服务已经挂了。

LocalBrokerConsumerService 服务启动的时候,同时启用一个定时清理任务。

public LocalBrokerConsumerService() {
//120S 扫描一次
final long limitMills = 2 * 60 * 1000; scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
for(Map.Entry<String, BrokerServiceEntryChannel> entry : heartbeatMap.entrySet()) {
String key = entry.getKey();
long lastAccessTime = entry.getValue().getLastAccessTime();
long currentTime = System.currentTimeMillis();
if(currentTime - lastAccessTime > limitMills) {
removeByChannelId(key);
}
}
}
}, 2 * 60, 2 * 60, TimeUnit.SECONDS);
}

这个任务 2min 执行一次,如果 2min 都没有心跳,这移除对应的消费者。

小结

心跳,是网络传输中验证服务可用性非常简单,但是有效的方式。

希望本文对你有所帮助,如果喜欢,欢迎点赞收藏转发一波。

我是老马,期待与你的下次重逢。

开源地址

The message queue in java.(java 简易版本 mq 实现) https://github.com/houbb/mq

拓展阅读

rpc-从零开始实现 rpc https://github.com/houbb/rpc

【mq】从零开始实现 mq-06-消费者心跳检测 heartbeat的更多相关文章

  1. 四大MQ比较及MQ详解

    消息队列已经逐渐成为企业IT系统内部通信的核心手段.它具有低耦合.可靠投递.广播.流量控制.最终一致性等一系列功能,成为异步RPC的主要手段之 一.当今市面上有很多主流的消息中间件,如老牌的Activ ...

  2. 1、微服务--为什么有consul,consul注册,心跳检测,服务发现

    一.为什么有consul? 在微服务,每1个服务都是集群式的,订单服务在10台服务器上都有,那么用户的请求到达,获取哪台服务器的订单服务呢?如果10台中的有的订单服务挂了怎么办?10台服务器扛不住了, ...

  3. EF架构~通过EF6的DbCommand拦截器来实现数据库读写分离~再续~添加对各只读服务器的心跳检测

    回到目录 上一讲中基本实现了对数据库的读写分离,而在选择只读数据库上只是随机选择,并没有去检测数据库服务器是否有效,如服务器挂了,SQL服务停了,端口被封了等等,而本讲主要对以上功能进行一个实现,并对 ...

  4. 介绍开源的.net通信框架NetworkComms框架之五 心跳检测

    原文网址: http://www.cnblogs.com/csdev Networkcomms 是一款C# 语言编写的TCP/UDP通信框架  作者是英国人  以前是收费的 目前作者已经开源  许可是 ...

  5. web双机热备添加心跳检测ip的时候填了网关导致外网ip不能上网

    web双机热备添加心跳检测ip的时候填了网关导致外网ip不能上网 1 连接 机器其他机器, 通过机房做的服务器的局域网,ssh到这台的局域网ip,删除网卡配置文件的网关哪一行,重启网卡. 2 如果没有 ...

  6. AndroidPN中的心跳检测

    在AndroidPN客户端里存在着心跳检测功能.就是每隔一段时间客户端向服务器端发送一个消息,以检测连接是否正常,发送的消息内容为: <presence id="h09Ke-13&qu ...

  7. Netty实现服务端客户端长连接通讯及心跳检测

    通过netty实现服务端与客户端的长连接通讯,及心跳检测.        基本思路:netty服务端通过一个Map保存所有连接上来的客户端SocketChannel,客户端的Id作为Map的key.每 ...

  8. 通过netty实现服务端与客户端的长连接通讯,及心跳检测。

    基本思路:netty服务端通过一个Map保存所有连接上来的客户端SocketChannel,客户端的Id作为Map的key.每次服务器端如果要向某个客户端发送消息,只需根据ClientId取出对应的S ...

  9. Netty之心跳检测技术(四)

    Netty之心跳检测技术(四) 一.简介 "心跳"听起来感觉很牛X的样子,其实只是一种检测端到端连接状态的技术.举个简单的"栗子",现有A.B两端已经互相连接, ...

随机推荐

  1. 启动Tomcat,Idea控制台输出乱码 淇℃伅

      解决:修改 tomcat 下的conf目录下 logging.properties这个文件ava.util.logging.ConsoleHandler.encoding修改为 为 GBK 就好了 ...

  2. MariaDB InnoDB基本介绍

    InnoDB锁定模式 事务获取锁,以防止并发事务修改甚至读取某些行或行范围.这样做是为了确保并发写入操作不会冲突. 共享锁(S)和排他锁(X) 两种标准的行级锁是共享锁(S)和排他锁(X) 获取共享锁 ...

  3. SQLyog创建用户并授权的过程

    点击你要授权的数据库然后点击用户管理器 然后输入用户名和密码主机选localhost 然后点击创建,然后选择你创建的数据库全选 最后保存就可以了

  4. CEPH-3:cephfs功能详解

    ceph集群cephfs使用详解 一个完整的ceph集群,可以提供块存储.文件系统和对象存储. 本节主要介绍文件系统cephfs功能如何灵活的使用,集群背景: [cephadmin@yq01-aip- ...

  5. Unsafe Rust 能做什么

    在不安全的 Rust 中唯一不同的是,你可以: 对原始指针进行解引用 调用"不安全"的函数(包括 C 函数.编译器的内建指令和原始分配器. 实现"不安全"的特性 ...

  6. Numpy中数组的乘法

    Numpy中数组的乘法 按照两个相乘数组A和B的维度不同,分为以下乘法: 数字与一维/二维数组相乘: 一维数组与一维数组相乘: 二维数组与一维数组相乘: 二维数组与二维数组相乘: numpy有以下乘法 ...

  7. task0002(四)- 练习:数据处理、轮播及交互

    转载自我的个人博客 欢迎大家批评指正 包括5部分: 小练习1-处理用户输入 小练习2-日期对象的使用 小练习3:轮播图 小练习4:输入提示框 小练习5:界面拖拽交互 源码地址task0002 在线De ...

  8. 在微信小程序中绘制图表(part2)

    本期大纲 1.确定纵坐标的范围并绘制 2.根据真实数据绘制折线 相关阅读:在微信小程序中绘制图表(part1)在微信小程序中绘制图表(part3) 关注我的 github 项目 查看完整代码. 确定纵 ...

  9. Python窗口学习之使窗口变得更高清

    初学tkinter发现窗口并不像成熟软件那么清楚 在实例化window后加这一行代码 #使窗口更加高清 # 告诉操作系统使用程序自身的dpi适配 ctypes.windll.shcore.SetPro ...

  10. 【Android开发】【数据库】LitePal 数据库的使用

    一,导包 dependencies { ...... // LitePal的包 compile 'org.litepal.android:core:1.3.1' ...... } 二,创建bean类 ...