文章 John Pan · 15 分鐘 前 4m read

IRIS 嵌入式 Python 与 Azure Service Bus (ASB) 的用例

概述

三年前,我们开始将 Azure Service Bus(ASB)作为企业消息传递解决方案投入使用。它目前被用于在组织内的众多应用程序之间发布和消费数据。 由于数据流较为复杂,且一个应用程序的数据通常需要被多个应用程序使用,因此“发布者”→“多个订阅者”的模式非常适合。本组织中ASB的日消息量达数千万条,而IRIS平台的日消息量则约为200万至300万条。

ASB 存在的问题

在开始进行 ASB 集成时,我们发现 AMQP 协议并非 IRIS 部署的“开箱即用”选项,因此我们一直在寻找一种替代方案,以便与 ASB 进行通信。

解决方案

我们开发了一个本地 Windows 服务(基于 .NET 和 Swagger),由其负责与 ASB 进行实际通信。该服务安装在与 IRIS 相同的机器上。我们将消息发送到 ASB 时,会先发送给这个本地 Windows 服务(通过 localhost 并调用 REST API),随后由该服务完成后续处理。 该方案运行了几年,效果良好,但监控流量、调试“丢失”的消息以及衡量整体性能却非常困难。事实上,将这个本地 Windows 服务作为“中间人”始终不是最佳架构。

IRIS 嵌入式 Python 早期访问计划 (EAP)

我受邀(或者是我自告奋勇的,记不清了)参与了嵌入式 Python 的早期发布计划(ERP)。这让我非常兴奋,能够测试新功能并向开发团队提供反馈。能够积极参与并影响该产品的开发,这种感觉也特别好。 在此阶段,我们开始测试嵌入式 Python 的 ERP 版本,并决定验证是否能利用嵌入式 Python 来解决“实际”问题。为此选择“IRIS 与 ASB 的直接连接”作为测试案例,是再自然不过的选择。

概念验证(POC)

我们开始编写解决方案的代码,并发现使用 Microsoft ASB 的 Python 库能让我们的工作(和编码)变得轻松许多。 最初阶段是开发一个能够连接到 ASB 中特定主题并接收消息的函数。这一部分完成得相当快(仅用 1 天开发时间),随后我们进入了“发布”(向 ASB 发送)阶段。

又花了几天时间,我们为这些发送和接收函数构建了完整的“封装”:我们实现了以下内容:

  • 用于控制消息进出流的规范化“暂存区”
  • 一个中央机制,用于存储 ASB 的进出流量,以便进行准确的统计和性能测量
  • 一个 CSP 监控页面,用于启用/禁用服务、显示统计数据以及在出现任何问题时发出警报

实现过程

初步配置

在使用 Microsoft ASB Python 库之前,需要将其安装到 ..\python 专用文件夹中。
我们选择使用 ../mge/python/,但您也可以使用任何其他喜欢的文件夹(最初这是一个空文件夹)
这些命令需在以管理员身份运行的 CMD(Windows 系统)中执行,或使用具有管理员权限的用户(Linux 系统):

..\bin\irispip install --target ..\mgr\python asyncio

..\bin\irispip install --target ..\mgr\python azure.servicebus

接收发往 ASB 的消息(消费)

我们有一个带参数的类方法:

  • topiId - ASB 被划分为多个主题,您可以从中消费消息
  • subscriptionName - Azure 订阅名称
  • connectionString - 用于连接您已订阅的主题

请注意,我们使用 [ Language = python ] 来表示此类方法是用 Python 编写的 (!)

ClassMethod retrieveASB(topicId As %Integer = 1, topicName As %String = "", subscriptionName As %String = "", connectionString As %String = "", debug As %Integer = 1, deadLetter As %Integer = 0) 作为 %Integer [ 语言 = python ]

要使用 ASB 库,我们首先需要导入 ServiceBusClient 和 ServiceBusSubQueue 库:

from azure.servicebus import ServiceBusClient, ServiceBusSubQueue

为了能够与 IRIS 进行交互(例如运行代码),我们还需要:

import iris

此时,我们就可以使用 ASB 库了:

with ServiceBusClient.from_connection_string(connectionString) as client:

with client.get_subscription_receiver(topicName, subscriptionName, max_wait_time=1, sub_queue=subQueue) as receiver:

for msg in receiver:

此时,我们已获得一个 Python 对象“msg”(流),可以将其(当然是以流的形式)传递给 IRIS,并直接存储到数据库中:

result = iris.cls("anyIRIS.Class").StoreFrom Python(stream)

向 ASB 发送消息(发布)

我们有一个带参数的类方法:

  • topicName - 我们要发布到的主题(此处需传入名称而非 ID)
  • connectionString - 用于连接您已订阅的主题
  • JSONmessage - 我们要发送(发布)的消息

请注意,我们使用 [ Language = python ] 来表示该类方法是用 Python 编写的 (!)

ClassMethod publishASB(topicName As %String = "", connectionString As %String = "", JSONmessage As %String = "") As %Status [ Language = python ]

要使用 ASB 库,我们首先需要导入 ServiceBusClient 和 ServiceBusMessage 库:

from azure.servicebus import ServiceBusClient, ServiceBusMessage

随后使用 ASB 库就非常简单了:

try:

result=1

with ServiceBusClient.from_connection_string(connectionString) as client:

with client.get_queue_sender(topicName) as sender:

single_message = ServiceBusMessage(JSONmessage)

sender.send_messages(single_message)

except Exception as e:

print(e)

result=0

return result

使用直接 ASB 连接的优势

  • 比使用“Windows 本地服务”这种“旧方案”快得多
  • 便于监控、收集统计数据及排查问题
  • 淘汰“中间人”(Windows 本地服务)可减少潜在的“单点故障”
  • 能够自动管理任何主题的“死信”,并让 ASB 将这些消息重新发送至订阅者的主题

鸣谢

我要感谢 @David.Satorres6134 (我们的 IRIS 高级开发人员),感谢他在 设计、编码和测试方面 做出的巨大 贡献。 没有他的帮助,这个项目就无法实现。