前景回顾

【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. volatile 修饰符的有过什么实践?

    一种实践是用 volatile 修饰 long 和 double 变量,使其能按原子类型来读写. double 和 long 都是 64 位宽,因此对这两种类型的读是分为两部分的,第一次 读取第一个  ...

  2. 常见算法的时间复杂度(大O计数法)

    定义 ​ 对于不同的机器环境而言,确切的单位时间是不同的,但是对于算法进行多少个基本操作(即花费多少时间单位)在规模数量级上却是相同的,由此可以忽略机器环境的影响而客观的反应算法的时间效率. 对于算法 ...

  3. Numpy怎样给数组增加一个维度

    Numpy怎样给数组增加一个维度 背景:很多数据计算都是二维或三维的,对于一维的数据输入为了形状匹配,经常需升维变成二维 需要:在不改变数据的情况下,添加数组维度:(注意观察这个例子,维度变了,但数据 ...

  4. 二十二、导入DXF文件

    x

  5. JavaScript の 内容属性(HTML属性attribute)和 DOM 属性(property)

    [博文]内容属性(HTML属性)和 DOM 属性 标签: 博文 JavaScript 粗略解读(与jQuery做对比) 内容属性(HTML属性) : attribute DOM 属性(Element属 ...

  6. 小程序完整对接 pingpp支付

    小程序完整对接 pingpp支付 有几个先要条件: 小程序需要企业认证且开通支付功能,个人认证是无法使用支付功能的(小程序微信支付官网) pingpp 本身接入的企业服务器(即商户服务器)并不强制要求 ...

  7. Codepen 每日精选(2018-3-24)

    按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以打开原始页面. 纯 css 画的抽象小鸟https://codepen.io/gregoryb/f... 纯 css 制作 ...

  8. python-计算素数和

    本题要求计算输入两个正整数x,y(x<=y,包括x,y)素数和.函数isPrime用以判断一个数是否素数,primeSum函数返回素数和. 输入格式: 输入两个整数. 输出格式: [m-n]间的 ...

  9. Javascript中数组的判断方法

    摘要: 1.数组检测的方法: 1) typeof . 2) instanceof . 3) constructor . 4) Object.prototype.toString. 5) Array.i ...

  10. 生成swap分区之利用磁盘分区

    生成swap 分区方式很多,有利用磁盘分区来生成swap,这种效率比较高,他并不是文件系统, 另外我们还可以拿出磁盘一些空间,做成swap分区还有通过lvm逻辑卷的方式创建swap分区(这种分区就可以 ...