热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

粘性会话负载均衡MQTTBroker集群详解(二)

在上一篇文章《MQTTBroker集群详解(一):负载均衡》中,我们简单介绍了MQTT负载均衡:负载均衡既可以

在上一篇文章《MQTT Broker 集群详解(一):负载均衡》中,我们简单介绍了 MQTT 负载均衡:负载均衡既可以应用于传输层,也可以用于应用层。在本文中,我们将详细介绍应用层负载均衡,其中最有趣的部分:粘性会话(sticky-session)。

本文由两部分组成,第一部分将介绍 MQTT 会话,以及在分布式 MQTT Broker 集群中处理会话面临的挑战;第二部分是通过在 EMQ X 4.3 集群前面配置 HAProxy 2.4 负载均衡器,带读者亲自体验如何充分利用粘性会话实现负载均衡。

MQTT 会话

为了持续接收消息,MQTT 客户端通常会连接至 MQTT Broker 进行订阅并保持长期连接。由于网络问题或客户端软件维护等原因,连接可能会中断一段时间,这并不罕见,但客户端通常希望在重新连接成功后仍然能接收到中断期间漏收的消息。

因此,为客户端提供服务的 MQTT Broker 应该为客户端保持会话(根据客户端的请求,将「Clean-Session」标志设置为 false)。此时,即使客户端断开连接,订阅者当前订阅的主题以及传递给这些主题的消息(QoS1 和 2)等也会由消息服务器(broker)保留。

当具有持久会话的客户端重新连接时,它不需要重新订阅主题,消息服务器应该将所有未发送的消息发送给该客户端。

我们之前写过一篇关于 MQTT 会话的文章,如果您对 MQTT 会话的技术细节感兴趣,可以通过阅读这篇文章做进一步了解。

会话接管

当 MQTT Brokers 形成集群时,事情会变得更加复杂。从客户端的角度来看,要连接的服务器不止一个,很难知道哪个服务器最适合连接。我们需要网络中的另一个关键组件:负载均衡器。负载均衡器成为整个集群的接入点,并将客户端的连接路由到集群中的某一个服务器。

如果客户端通过负载均衡器连接到服务器(例如,node1),然后断开连接并稍后重新连接,则新连接可能会路由到集群中的不同服务器(例如,node3)。在这种情况下,node3 应该在客户端断开连接时开始向客户端发送未发送的消息。

实现集群范围的持久会话有很多不同的策略。例如,整个集群可以共享一个全局存储来保存客户端的会话。

然而,更具可扩展性的解决方案通常以分布式方式解决这个问题,即数据从一个节点迁移到另一个节点。这种迁移称为会话接管。会话接管应该对客户端完全透明,但它是有代价的,尤其是当有很多消息需要处理时。

会话接管

粘性会话解决方案

这里的「粘性」一词指的是负载均衡器能够在重新连接时将客户端路由到之前服务器的能力,这可以避免会话接管。当有许多客户端在同一时间重新连接时,或者在一个有问题的客户端反复断开连接并再次连接的情况下,这是一个特别有用的功能。

为了让负载均衡器以「粘性」方式分派连接,服务器需要知道连接请求中的客户端标识符(有时是用户名)——这需要负载均衡器检查 MQTT 数据包以查找此类信息。

一旦获得客户端标识符(或用户名),对于静态集群,服务器可以将客户端标识符(或用户名)散列到服务器 ID。或者为了更好的灵活性,负载均衡器可以选择维护一个从客户端标识符(或用户名)到目标节点 ID 的映射表。

在下一节中,我们将演示 HAProxy 2.4 中的粘性表策略。

使用 HAProxy 2.4 实现粘性会话

为了尽量减少先决条件,在这个演示集群中,我们将在 docker 容器中启动两个 EMQ X 节点和一个 HAProxy 2.4。

创建 docker 网络

为了使容器彼此连接,我们为它们创建了一个 docker 网络。

docker network create test.net

启动两个 EMQ X 4.3 节点

为了使节点彼此连接,应该在网络名称空间(test.net)中分配容器名称和 EMQX 节点名称。

启动 node1

docker run -d \--name n1.test.net \--net test.net \-e EMQX_NODE_NAME=emqx@n1.test.net \-e EMQX_LISTENER__TCP__EXTERNAL__PROXY_PROTOCOL=on \emqx/emqx:4.3.7

启动 node2

docker run -d \--name n2.test.net \--net test.net \-e EMQX_NODE_NAME=emqx@n2.test.net \-e EMQX_LISTENER__TCP__EXTERNAL__PROXY_PROTOCOL=on \emqx/emqx:4.3.7

注意环境变量

EMQX_LISTENER__TCP__EXTERNAL__PROXY_PROTOCOL. 该变量是为TCP监听器启用二进制代理协议,以便服务器可以获得客户端的真实 IP 地址信息,而不是负载均衡器的 IP 地址。


使 EMQ X 节点加入集群

docker exec -it n2.test.net emqx_ctl cluster join emqx@n1.test.net

如果一切按预期进行,应该打印输出这样的日志:

[EMQ X] emqx shutdown for join
Join the cluster successfully.
Cluster status: #{running_nodes => ['emqx@n1.test.net','emqx@n2.test.net'], stopped_nodes => []}

启动 HAProxy 2.4

创建文件 /tmp/haproxy.config,内容如下:

globallog stdout format raw daemon debugnbproc 1nbthread 2cpu-map auto:1/1-2 0-1# Enable the HAProxy Runtime API# e.g. echo "show table emqx_tcp_back" | sudo socat stdio tcp4-connect:172.100.239.4:9999stats socket :9999 level admin expose-fd listenersdefaultslog globalmode tcpoption tcplogmaxconn 1024000timeout connect 30000timeout client 600stimeout server 600sfrontend emqx_tcpmode tcpoption tcplogbind *:1883default_backend emqx_tcp_backbackend emqx_tcp_backmode tcp# Create a stick table for session persistencestick-table type string len 32 size 100k expire 30m# Use ClientID / client_identifier as persistence keystick on req.payload(0,0),mqtt_field_value(connect,client_identifier)# send proxy-protocol v2 headersserver emqx1 n1.test.net:1883 check-send-proxy send-proxy-v2server emqx2 n2.test.net:1883 check-send-proxy send-proxy-v2

在测试 docker 网络中启动 haproxy:

docker run -d \--net test.net \--name proxy.test.net \-p 9999:9999 \-v /tmp/haproxy.cfg:/haproxy.cfg \haproxy:2.4 haproxy -f /haproxy.cfg

测试

现在我们使用流行的 mosquitto MQTT 客户端(也在 docker 中)对其进行测试。

我们启动一个订阅者(名为 subscriber1)订阅 t/# 主题

docker run --rm -it --net test.net eclipse-mosquitto \mosquitto_sub -h proxy.test.net -t 't/#' -I subscriber1

然后从另一个客户端向 t/xyz 发布一条 hello 消息

docker run --rm -it --net test.net eclipse-mosquitto \mosquitto_pub -h proxy.test.net -t 't/xyz' -m 'hello'

如果一切都按预期进行,订阅者应该打印出 hello 消息。

检查 HAProxy 中的粘性表

我们还可以使用如下命令检查在 HAProxy 中创建的粘性表。这需要 socat 命令,所以我们从 docker 主机运行它。

show table emqx_tcp_back" | sudo socat stdio tcp4-connect:127.0.0.1:9999

该命令应该打印当前连接,如下所示:

# table: emqx_external_tcp_listners, type: string, size:102400, used:1
0x7f930c033d90: key=subscriber1 use=0 exp=1793903 server_id=2 server_key=emqx2

在这个例子中,客户端 subscriber1 被固定连接到服务器 emqx2

结语

至此,我们可以了解到从客户端的角度看,EMQ X 集群是如何通过负载均衡器对外部提供服务的。

在本系列文章的后续内容中,我们将跟踪一个 MQTT 消息从发布者到订阅者的全过程,以便大家了解 EMQ X 如何将它在集群中复制和转发。敬请期待。

本系列中的其它文章


  • MQTT Broker 集群详解(一):负载均衡

版权声明: 本文为 EMQ 原创,转载请注明出处。

原文链接:https://www.emqx.com/zh/blog/mqtt-broker-clustering-part-2-sticky-session-load-balancing

技术支持:如对本文或 EMQ 相关产品有疑问,可访问 EMQ 问答社区 https://askemq.com 提问,我们将会及时回复支持。

更多技术干货,欢迎关注我们公众号【EMQ 中文社区】。


推荐阅读
  • 秒建一个后台管理系统?用这5个开源免费的Java项目就够了
    秒建一个后台管理系统?用这5个开源免费的Java项目就够了 ... [详细]
  • 在使用SSH框架进行项目开发时,经常会遇到一些常见的问题。例如,在Spring配置文件中配置AOP事务声明后,进行单元测试时可能会出现“No Hibernate Session bound to thread”的错误。本文将详细探讨这一问题的原因,并提供有效的解决方案,帮助开发者顺利解决此类问题。 ... [详细]
  • 第十九天 - 类的约束、异常处理与日志记录
    本文介绍了如何通过类的约束来确保代码的一致性,以及如何使用异常处理和日志记录来提高代码的健壮性和可维护性。具体包括抛出异常、使用抽象类和方法,以及异常处理和日志记录的详细示例。 ... [详细]
  • Hadoop的文件操作位于包org.apache.hadoop.fs里面,能够进行新建、删除、修改等操作。比较重要的几个类:(1)Configurati ... [详细]
  • 本文详细介绍了如何在Linux系统(以CentOS为例)上彻底卸载Zimbra邮件系统,包括停止服务、删除文件和用户等步骤。 ... [详细]
  • Linux CentOS 7 安装PostgreSQL 9.5.17 (源码编译)
    近日需要将PostgreSQL数据库从Windows中迁移到Linux中,LinuxCentOS7安装PostgreSQL9.5.17安装过程特此记录。安装环境&#x ... [详细]
  • 如何使用 `org.opencb.opencga.core.results.VariantQueryResult.getSource()` 方法及其代码示例详解 ... [详细]
  • 在《Cocos2d-x学习笔记:基础概念解析与内存管理机制深入探讨》中,详细介绍了Cocos2d-x的基础概念,并深入分析了其内存管理机制。特别是针对Boost库引入的智能指针管理方法进行了详细的讲解,例如在处理鱼的运动过程中,可以通过编写自定义函数来动态计算角度变化,利用CallFunc回调机制实现高效的游戏逻辑控制。此外,文章还探讨了如何通过智能指针优化资源管理和避免内存泄漏,为开发者提供了实用的编程技巧和最佳实践。 ... [详细]
  • 您的数据库配置是否安全?DBSAT工具助您一臂之力!
    本文探讨了Oracle提供的免费工具DBSAT,该工具能够有效协助用户检测和优化数据库配置的安全性。通过全面的分析和报告,DBSAT帮助用户识别潜在的安全漏洞,并提供针对性的改进建议,确保数据库系统的稳定性和安全性。 ... [详细]
  • 基于Net Core 3.0与Web API的前后端分离开发:Vue.js在前端的应用
    本文介绍了如何使用Net Core 3.0和Web API进行前后端分离开发,并重点探讨了Vue.js在前端的应用。后端采用MySQL数据库和EF Core框架进行数据操作,开发环境为Windows 10和Visual Studio 2019,MySQL服务器版本为8.0.16。文章详细描述了API项目的创建过程、启动步骤以及必要的插件安装,为开发者提供了一套完整的开发指南。 ... [详细]
  • 服务器部署中的安全策略实践与优化
    服务器部署中的安全策略实践与优化 ... [详细]
  • 本文介绍了如何利用Shell脚本高效地部署MHA(MySQL High Availability)高可用集群。通过详细的脚本编写和配置示例,展示了自动化部署过程中的关键步骤和注意事项。该方法不仅简化了集群的部署流程,还提高了系统的稳定性和可用性。 ... [详细]
  • 体积小巧的vsftpd与pureftpd Docker镜像在Unraid系统中的详细配置指南:支持TLS加密及IPv6协议
    本文详细介绍了如何在Unraid系统中配置体积小巧的vsftpd和Pure-FTPd Docker镜像,以支持TLS加密和IPv6协议。通过这些配置,用户可以实现安全、高效的文件传输服务,适用于各种网络环境。配置过程包括镜像的选择、环境变量的设置以及必要的安全措施,确保了系统的稳定性和数据的安全性。 ... [详细]
  • 在开发过程中,我最初也依赖于功能全面但操作繁琐的集成开发环境(IDE),如Borland Delphi 和 Microsoft Visual Studio。然而,随着对高效开发的追求,我逐渐转向了更加轻量级和灵活的工具组合。通过 CLIfe,我构建了一个高度定制化的开发环境,不仅提高了代码编写效率,还简化了项目管理流程。这一配置结合了多种强大的命令行工具和插件,使我在日常开发中能够更加得心应手。 ... [详细]
  • 提升 Kubernetes 集群管理效率的七大专业工具
    Kubernetes 在云原生环境中的应用日益广泛,然而集群管理的复杂性也随之增加。为了提高管理效率,本文推荐了七款专业工具,这些工具不仅能够简化日常操作,还能提升系统的稳定性和安全性。从自动化部署到监控和故障排查,这些工具覆盖了集群管理的各个方面,帮助管理员更好地应对挑战。 ... [详细]
author-avatar
jac
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有