前景回顾

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

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

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

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

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

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

【mq】从零开始实现 mq-07-负载均衡 load balance

为什么需要负载均衡

大家好,我是老马。

这一节让我们看一下如何实现 MQ 的负载均衡。

为什么需要负载均衡呢?

作用

负载均衡最核心的作用:

(1)可以避免单点故障

(2)可以让请求均分的分散到每一个节点

实现思路

负载均衡实现的方式比较多,最简单的就是随机选择一个。

拓展阅读:

从零手写实现负载均衡 http://houbb.github.io/2020/06/19/load-balance-03-hand-write

MQ 中用到负载均衡的地方

生产者发送

生产者发送消息时,可以发送给任一 broker。

broker 推送给消费者

broker 接收到消息以后,在推送给消费者时,也可以任一选择一个。

消费者的消费 ACK

消费者消费完,状态回执给 broker,可以选择任一一个。

消息黏连

有些消息比较特殊,比如需要保证消费的有序性,可以通过 shardingKey 的方式,在负载的时候固定到指定的片区。

代码实现

生产者发送

统一调整获取 channel 的方法。

@Override
public Channel getChannel(String key) {
// 等待启动完成
while (!statusManager.status()) {
log.debug("等待初始化完成...");
DateUtil.sleep(100);
}
RpcChannelFuture rpcChannelFuture = RandomUtils.loadBalance(this.loadBalance,
channelFutureList, key);
return rpcChannelFuture.getChannelFuture().channel();
}

工具类实现为核心实现:

/**
* 负载均衡
*
* @param list 列表
* @param key 分片键
* @return 结果
* @since 0.0.7
*/
public static <T extends IServer> T loadBalance(final ILoadBalance<T> loadBalance,
final List<T> list, String key) {
if(CollectionUtil.isEmpty(list)) {
return null;
} if(StringUtil.isEmpty(key)) {
LoadBalanceContext<T> loadBalanceContext = LoadBalanceContext.<T>newInstance()
.servers(list);
return loadBalance.select(loadBalanceContext);
} // 获取 code
int hashCode = Objects.hash(key);
int index = hashCode % list.size();
return list.get(index);
}

如果指定了 shardingKey,那么根据 shadringKey 进行 hash 判断。

如果没有,则进行默认的负载均衡策略。

Broker 消息推送给消费者

消费者订阅列表的获取:

@Override
public List<Channel> getSubscribeList(MqMessage mqMessage) {
final String topicName = mqMessage.getTopic();
Set<ConsumerSubscribeBo> set = subscribeMap.get(topicName);
if(CollectionUtil.isEmpty(set)) {
return Collections.emptyList();
} //2. 获取匹配的 tag 列表
final List<String> tagNameList = mqMessage.getTags();
Map<String, List<ConsumerSubscribeBo>> groupMap = new HashMap<>();
for(ConsumerSubscribeBo bo : set) {
String tagRegex = bo.getTagRegex();
if(hasMatch(tagNameList, tagRegex)) {
//TODO: 这种设置模式,统一添加处理 haven
String groupName = bo.getGroupName();
List<ConsumerSubscribeBo> list = groupMap.get(groupName);
if(list == null) {
list = new ArrayList<>();
}
list.add(bo);
groupMap.put(groupName, list);
}
} //3. 按照 groupName 分组之后,每一组只随机返回一个。最好应该调整为以 shardingkey 选择
final String shardingKey = mqMessage.getShardingKey();
List<Channel> channelList = new ArrayList<>();
for(Map.Entry<String, List<ConsumerSubscribeBo>> entry : groupMap.entrySet()) {
List<ConsumerSubscribeBo> list = entry.getValue();
ConsumerSubscribeBo bo = RandomUtils.loadBalance(loadBalance, list, shardingKey);
final String channelId = bo.getChannelId();
BrokerServiceEntryChannel entryChannel = registerMap.get(channelId);
if(entryChannel == null) {
log.warn("channelId: {} 对应的通道信息为空", channelId);
continue;
}
channelList.add(entryChannel.getChannel());
}
return channelList;
}

核心逻辑:RandomUtils.loadBalance(loadBalance, list, shardingKey); 获取,其他的保持不变。

消费者 ACK

消费者也是类似的,获取 channel 的方式调整如下:

public Channel getChannel(String key) {
// 等待启动完成
while (!statusManager.status()) {
log.debug("等待初始化完成...");
DateUtil.sleep(100);
} RpcChannelFuture rpcChannelFuture = RandomUtils.loadBalance(loadBalance,
channelFutureList, key);
return rpcChannelFuture.getChannelFuture().channel();
}

小结

负载均衡在分布式服务中,是必备的特性之一。实现的原理并不算复杂。

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

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

开源地址

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

拓展阅读

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

【mq】从零开始实现 mq-07-负载均衡 load balance的更多相关文章

  1. Oracle RAC 服务器端连接负载均衡(Load Balance)

    Oracle RAC服务器端的负载均衡是根据RAC中各节点的连接负荷数情况,将新的连接请求分配到负荷最小的节点上去.当数据库处于运行时,RAC中各节点的PMON进程每3秒会将各自节点的连接负荷数更新到 ...

  2. Oracle RAC 客户端连接负载均衡(Load Balance)

    实现负载均衡(Load Balance)是Oracle RAC最重要的特性之一,主要是把负载平均分配到集群中的各个节点,以提高系统的整体吞吐能力.通常情况下有两种方式来实现负载均衡,一个是基于客户端连 ...

  3. &quot;高可用方案工具包&quot; high availability toolkit 1.2 公布了。version 1.2 新增了 负载均衡 load balance 的技术实现

    "高可用方案工具包"  high availability toolkit 1.2 公布了. version 1.2 新增了 负载均衡 load balance 的技术实现. 项目 ...

  4. 【高可用HA】Nginx (1) —— Mac下配置Nginx Http负载均衡(Load Balancer)之101实例

    [高可用HA]Nginx (1) -- Mac下配置Nginx Http负载均衡(Load Balancer)之101实例 nginx版本: nginx-1.9.8 参考来源: nginx.org [ ...

  5. 【高可用HA】Apache (4) —— Mac下配置Apache Httpd负载均衡(Load Balancer)之mod_jk

    Mac下配置Apache Httpd负载均衡(Load Balancer)之mod_jk httpd版本: httpd-2.4.17 jk版本: tomcat-connectors-1.2.41 参考 ...

  6. 【高可用HA】Apache (3) —— Mac下配置Apache Httpd负载均衡(Load Balancer)之mod_proxy

    Mac下配置Apache Httpd负载均衡(Load Balancer)之mod_proxy httpd版本: httpd-2.4.17 参考来源: Apache (1) -- Mac下安装Apac ...

  7. 章文嵩博士和他背后的负载均衡(LOAD BANLANCER)帝国

    案首语: 阿里集团技术大牛,@正明,淘宝基础核心软件研发负责人.LVS创始人.阿里云首席科学家章文嵩博士从阿里离职,去追求技术人生另一段历程,让阿里像我一样的很多热爱技术的工程师都有一丝牵动和感触. ...

  8. 【消息队列MQ】各类MQ比较

    目录(?)[-] RabbitMQ Redis ZeroMQ ActiveMQ JafkaKafka 目前业界有很多MQ产品,我们作如下对比: RabbitMQ 是使用Erlang编写的一个开源的消息 ...

  9. 消息队列MQ】各类MQ比较

    目前业界有很多MQ产品,我们作如下对比:RabbitMQ 是使用Erlang编写的一个开源的消息队列,本身支持很多的协议:AMQP,XMPP, SMTP, STOMP,也正是如此,使的它变的非常重量级 ...

随机推荐

  1. Axure在Chrome浏览解决方案

    AXURE RP EXTENSION FOR CHROME Google Chrome浏览器需要扩展程序才能查看本地存储的项目.或者,将您的RP文件上传到Axure Cloud或使用其他浏览器.您也可 ...

  2. Java中如何声明方法?JavaScript中如何声明函数?

    public void method(){ } //实例方法 Function Declaration 可以定义命名的函数变量,而无需给变量赋值.Function Declaration 是一种独立的 ...

  3. 使用kindeditor

    首先在http://kindeditor.net/demo.php下载样式 点击右上角的下载按钮 点击官方下载下载之后解压出来 然后在桌面创建一个文件夹 然后回到刚才的http://kindedito ...

  4. C语言break,return

    C语言break,continue,return的相似与区别 相同点: 都改变了程序的执行流程 区别是:break    用于循环和switch分支,跳出它所在分支或循环体到它所在的模块的      ...

  5. 饿了么组件库element-ui正则表达式验证表单,后端验证表单。

    前言 老是遇到一些朋友问一些element-ui组件使用相关的基础问题,因为官方文档上并没有提供所有琐碎的功能代码demo.从这里开始我会根据我实际遇到的问题记录一些常见的官方文档没有详述的功能代码, ...

  6. java中程序,进程和线程的区别

    2.程序,进程和线程的区别 马克-to-win:程序,进程和线程的区别是什么?这个问题比较抽象难理解,但又非常重要.我并不想给出一大堆抽象的学术解释,那样只能误国误民.所以我先给大家举一个例子.马克- ...

  7. 第一阶段:Java基础之异常和处理

    文章目录 Java中异常处理机制的简单和应用 一.异常的体系结构&分类 二.问题扩展 三.应用场景 Java中异常处理机制的简单和应用 异常也是一种对象,Java中有很多异常类,并且定义了基类 ...

  8. Shiro+springboot+mybatis+EhCache(md5+salt+散列)认证与授权-03

    从上文:Shiro+springboot+mybatis(md5+salt+散列)认证与授权-02 当每次进行刷新时,都会从数据库重新查询数据进行授权操作,这样无疑给数据库造成很大的压力,所以需要引入 ...

  9. 自己写一个简单的LinkedList

    单链表 推荐阅读:https://www.cnblogs.com/zwtblog/tag/源码/ 哨兵节点: 哨兵节点在树和链表中被广泛用作伪头.伪尾等,通常不保存任何数据. 我们将使用伪头来简化我们 ...

  10. What is ACPI

    What is ACPI, OnNow, and PCI Power Management? Microsoft began an initiative called OnNow to shorten ...