首页 文章详情

.NET 分布式缓存中的发布和订阅模式

DotNet NB | 33 2022-08-08 23:52 0 0 0
UniSMS (合一短信)

  发布和订阅模式(Pub/Sub)是构建企业级 .NET 应用程序不可或缺的工具。Pub/Sub 是一种消息传递范式,消息的发送方(发布者)不知道目标接收方(订阅者)的任何信息。此外,发布者和订阅者之间不直接发生交互,而是依赖一种叫作主题的公共媒介。因此,这是一个松散耦合的消息模型。

  现在,我们假设在同一个架构中部署了多个不同的应用程序,它们需要一种机制来向彼此发送事件通知。这些事件可能是短暂的(因运行时发生变更引起的),也可能是数据库事件(因数据库发生变更引起的)。发布和订阅模式可以帮你实现这种分布式事件通知。

  实现分布式事件通知的方案

  为了设计一种分布式事件驱动的架构,开发人员通常会使用以下几种方案中的一种。

  RDBMS 提供的数据通知

  如果数据存储仅限于关系数据库,那么使用数据库的通知功能似乎是最好的选择。你可以向数据库服务器注册你感兴趣的内容,当数据库的数据集由于更新、添加或删除操作而发生变更时,你的应用程序会收到通知。

  但 RDBMS 本质上是不可伸缩的,很容易成为应用程序的性能瓶颈。所以,你也不希望给数据库增加不必要的负载。此外,数据库通知功能本身就很慢,而且也不支持运行时数据共享。

  现在你应该能理解为什么使用数据库作为消息传递媒介并不是应用程序的最佳选择。

  消息队列

  另一种选择是在架构中引入消息队列。虽然消息队列可以帮你在应用程序之间传输消息,但它们并不是以数据为中心的,也就是说,它们不会监控数据库或其他数据源的数据变更情况。此外,消息队列无法随应用程序一起伸缩。

  自己实现

  留给你的最后一个选择是构建满足自己需求的消息平台。虽然这个空沙盒一开始很吸引人,让你可以随心所欲地开发自己的东西,但从时间和资源方面来看,它太复杂了。尽管存在可能性,但构建和管理一个健壮且可伸缩的消息平台是一项非常艰巨的任务。

  问题在于哪种解决方案更容易集成,具有可伸缩性、高可用性和可靠性。

  将分布式缓存作为消息传递平台

  别担心,这里有一个简单的解决方案。集成健壮的消息平台的一种更现代的方法是使用内存分布式缓存。NCache 是目前市场上唯一可用的真正原生的 .NET/.NET Core 分布式缓存。它是一种内存分布式缓存,速度极快,可伸缩。它让你的应用程序能够处理极端的事务负载,并且不会让数据库成为瓶颈。你也可以用 NCache 来实时处理数据流。

  NCache 通常部署在多层架构的中间位置。为了更好地说明这一点,请看下面这张图。

图 1 多层架构中的 NCache

  NCache 是一个缓存服务器集群,它将频繁使用的数据保存在内存中,避免了大多数数据库访问,为 .NET 应用程序和 Java 应用程序提供每秒处理数万个请求的能力。

  我们先来看看如何将 NCache 作为事件驱动架构的消息传递总线。

  NCache 的事件驱动消息传递

  下图显示了 NCache 如何作为 .NET 和 Java 应用程序的消息总线。

图 2 将 NCache 作为消息平台

  在这里,NCache 使用快速紧凑的序列化将 .NET 或 Java 对象转换成二进制文件,再将它们传递到缓存集群中,实现了跨平台通信。NCache 允许 .NET 应用程序与 Java 应用程序之间发生交互。

  NCache 通过事件来实现发布和订阅模式,并为你提供了不同的方法将消息传递给其他监听应用程序。我们来看一下这两种消息类型,并看看分布式缓存如何传递它们。

  首先,我们需要明确应用程序需要监听的数据变更。NCache 本身是一个 .NET 键值存储系统,提供了一些可以在缓存中的数据发生变更时更新应用程序的能力。因为这些变更都是在内存中发生的,所以不存在性能瓶颈。这些变更可以是:

  • 缓存级的数据项变更,无论是更新还是删除。

  • 整个缓存级的数据变更。

  • 持续查询。你注册了一个类似 SQL 的查询,观察缓存中的结果集是否发生了变更。如果是,你的应用程序将收到通知。

  • 集群变更(针对管理员来说),在添加或删除新节点或者节点发生崩溃时发生。NCache 还允许你注册依赖数据库,包括 SQL、Oracle 和 OleDb。这有助于缓存、数据库和应用程序之间保持同步。点击查看受支持的依赖数据库类型的完整清单。这些是注册在不同数据存储系统上的数据变更通知,只是 NCache 帮你处理掉了。你还可以将数据库通知与 NCache 数据通知结合起来,满足特定的应用需求。

  另一方面,如果你只想将简单的消息传播到复杂的 .NET 或 Java 对象,那么你应该使用自定义消息传递特性。应用程序可以生成数据并触发事件,感兴趣的监听器几乎可以立即接收到事件。

  NCache 的 Pub/Sub API

  NCache 提供了一个基于内存的发布和订阅特性和一个专门的发布和订阅消息存储,为在 .NET Web 应用程序中实现实时信息共享提供支持。我们将看到 NCache 与发布和订阅模式的结合如何解决上述的挑战,并实现更好的应用程序间通信。

  发布和订阅模型提供了一个通道,发布者在其中发布消息,感兴趣的用户订阅消息,从而将发布者和订阅者解耦。现在,我们将 NCache 作为消息总线,发布和订阅模型将受益于 NCache 底层的分布式架构和许多方便的特性。

  基本架构

  话不多说,我们先来了解一下 NCache Pub/Sub 的基本组件及其工作原理。NCache 一般的发布和订阅流程是这样的:发布者使用 ITopic 接口向主题发布消息,订阅者创建订阅一个或多个主题并接收相关消息。消息被成功传递时,NCache 将接收到确认。否则,NCache 会在消息过期之前继续重试(如果设置了过期时间)。未传递的消息将驻留在缓存中,直到被驱逐或过期。

图 3 NCache 的 Pub/Sub 架构

  订阅类型

  NCache 提供了两种不同的订阅类型,即非持久订阅和持久订阅。此外,NCache 也支持独占和共享订阅策略。

  • 非持久订阅:默认情况下,在主题上创建的所有订阅都是非持久订阅。它只向订阅者传递预期的消息,直到连接断开。如果用户因任何原因断开连接,在重新连线时不会收到旧消息。这种类型的订阅是排他性的,也就是一个订阅只属于一个订阅者。 

  • 持久订阅:它考虑到订阅者在断开连接时会发生消息丢失的情况。NCache 在连接丢失时将保留订阅服务器的订阅。因此,订阅者可以在重新连线时收到已发布的消息。持久订阅也提供了两种策略:1)独占,一个订阅只属于一个活动的订阅者;2)共享,一个订阅可以有多个订阅者,消息是共享的。 

  开始使用 NCache Pub/Sub

  我们假设有一个网店,不同的供应商会定期向商店中添加新商品。同时,还需要提供商品的销量和售价信息。对商品感兴趣的商店经理和客户需要了解新商品、正在销售的商品和最新的折扣情况。NCache 的发布和订阅特性可以在这个场景中提供分布式通知机制。为此,我们可以先创建 NCache 专用的发布和订阅消息存储。

  我们将使用 NCache Pub/Sub API 来逐步实现上述场景的分布式消息传递过程。

  创建主题

  第一步是创建一个主题,不同供应商可以向这个主题发布关于新商品的更新消息。我们可以使用 NCache ITopic 接口创建具有唯一名称的主题。在下面的代码中,发布者应用程序使用 CreateTopic 方法创建了一个叫作 newProducts 的主题。

// 前提条件:已经连上 NCache// 指定主题名string topicName = “newProducts”// 创建主题ITopic topic = cache.MessagingService.CreateTopic (topicName);

  如果已经存在相同名称的主题,则返回主题的实例,类型为 ITopic。

  NCache 允许在创建主题时设置主题优先级。如果某些事件需要以比其他事件更高的优先级处理时,这个特性就很有用。例如,商品已售罄就是紧急信息。同样,由于折扣或销售而导致商品价格变动对于卖方或买方来说都是很重要的信息。在这种情况下,我们可以在创建主题时将其设置为高优先级,这样客户端就可以毫不延迟地接收到相关通知。

  发布消息

  在创建了主题后,发布者应用程序就可以使用 Publish 方法向主题发布消息。为此,我们需要先通过指定主题名获得主题实例。NCache 为发布消息提供了以下两种传递模式:

  • All(默认):将消息传递给所有的订阅者。当需要广播信息时,这个就很有用。

  • Any:将消息传递给任意一个订阅者。此外,为了有效管理发布和订阅缓存的存储空间,你还可以设置消息的过期时间。

  在下面的代码中,发布者向主题 newProducts 广播有关新商品的消息。

// 前提条件:已经连上 NCache// 已创建"newProducts"主题string topicName = "newProducts"// 获取主题实例ITopic productTopic = cache.MessagingService.GetTopic (topicName);// 创建要放在消息中传递的对象Product product = FetchProductFromDB (10248);// 用对象创建新消息var productMessage = new Message (product);// 发布消息,将选项设置为 AllorderTopic.Publish (productMessage, DeliveryOption.All, true);

  订阅主题

  在创建了主题后,订阅者应用程序就可以通过获取订阅来接收发布到主题的消息。由于可以支持不同类型的订阅,如果要进行非持久订阅,可以使用 CreateSubscription 方法。如果要进行持久订阅,可以使用 CreateDurableSubscription 方法。

  下面的代码展示了订阅者应用程序如何订阅 newProducts 主题。MessageReceived 回调将在收到通知时执行预期操作。例如,订阅者可以在收到销售通知时在 MessageReceived 回调中更新产品价格。

// 前提条件:已经连上 NCache// 已创建"newProducts"主题string topicName = "newProducts"// 获取主题实例ITopic productTopic = cache.MessagingService.GetTopic (topicName);// 订阅 newProducts 主题// 指定 MessageReceived 回调ITopicSubscription orderSubscriber = orderTopic.CreateSubscription (MessageReceived);

  在上面的示例中,我们创建了一个非持久订阅。此外,如果需要在重新连接时从订阅的主题接收旧消息,可以创建持久订阅。

  NCache 还提供了一种基于模式的订阅方法,支持通过多个通配符来订阅与模式匹配的单个或多个主题。

  注册通知

  NCache 可以让发布者知道消息的状态和主题的可用性。发布者应用程序可以注册下面的通知:

  • MessageDeliveryFailure:如果由于任何问题而无法传递消息,则通知发布者。

  • OnTopicDeleted:当主题被删除时通知发布者。以下是发布者注册这两种类型的通知的代码。

// 你有一个主题实例 productTopic// 注册消息传递失败通知productTopic.MessageDeliveryFailure += OnFailureMessageReceived;//注册主题删除通知productTopic.OnTopicDeleted = TopicDeleted;

  遵循以上这些步骤,一个基本的发布和订阅消息架构就可以被集成到任何 ASP.NET/.NET Core 应用程序中。

  结论   

  到目前为止,我们已经了解了 NCache 的发布和订阅特性。我们来总结一下 Ncache Pub/Sub 在处理现有解决方案的局限性方面提供了哪些好处。

  • 由于具有线性可伸缩性,NCache Pub/Sub 可以通过添加缓存服务器和负载均衡来处理不断增加的订阅请求。伸缩对用户是透明的,不会影响通信过程。因此,你可以很容易地使用 NCache Pub/Sub 来扩展系统的通信性能。

  • NCache Pub/Sub 提供了持久订阅、消息传递重试和传递失败通知,以避免消息丢失。此外,NCache 的分布式和复制架构确保了 NCache 的高可用性。所有这些功能确保了可靠的通信。

  • 由于 NCache 是基于内存的分布式缓存,因此驻留在缓存中的消息存储速度非常快。此外,NCache 允许缓存中的数据过期并将其回收,从而智能地管理好存储空间。NCache 的可扩展性、可靠性和存储效率,以及发布和订阅的松耦合和异步消息传递模式,使得 NCache 的发布和订阅特性在未来的 .NET/.NET Core 应用程序的分布式消息传递方面具有很大的应用前景。

  原文链接:

  https://dzone.com/articles/pubsub-design-pattern-in-net-distributed-cache


推荐阅读:
  API 工程化分享
  我的微软 MVP 之路
【译】ASP.NET Core 6 中的性能改进
【译】.NET 7 预览版 1 中的 ASP.NET Core 更新
【译】C# 11 特性的早期预览

点击下方卡片关注DotNet NB

一起交流学习

▲ 点击上方卡片关注DotNet NB,一起交流学习

请在公众号后台

回复 【路线图】获取.NET 2021开发者路线图
回复 【原创内容】获取公众号原创内容
回复 【峰会视频】获取.NET Conf开发者大会视频
回复 【个人简介】获取作者个人简介
回复 【年终总结】获取作者年终总结
回复 加群加入DotNet NB 交流学习群

长按识别下方二维码,或点击阅读原文。和我一起,交流学习,分享心得。


good-icon 0
favorite-icon 0
收藏
回复数量: 0
    暂无评论~~
    Ctrl+Enter