Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sql-server-2005/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用SQL Server数据事件进行消息传递_C#_Sql Server 2005_Rabbitmq - Fatal编程技术网

C# 使用SQL Server数据事件进行消息传递

C# 使用SQL Server数据事件进行消息传递,c#,sql-server-2005,rabbitmq,C#,Sql Server 2005,Rabbitmq,在我们的组织中,我们有一个SQLServer2005数据库和大量的数据库客户端:网站(php、zope、asp.net)、富客户端(legacy fox pro)。现在我们需要将核心数据库中的某些事件传递给其他系统(MongoDb、LDAP和其他系统)。消息传递范式似乎很有能力解决这类问题。因此,我们决定使用RabbitMQ代理作为中间件 起初,从数据库中消费事件的问题似乎只有两种可能的解决方案: 轮询数据库中传出的消息,并将它们传递给消息代理 在某些表上使用触发器将消息传递给同一台机器上的代理

在我们的组织中,我们有一个SQLServer2005数据库和大量的数据库客户端:网站(php、zope、asp.net)、富客户端(legacy fox pro)。现在我们需要将核心数据库中的某些事件传递给其他系统(MongoDb、LDAP和其他系统)。消息传递范式似乎很有能力解决这类问题。因此,我们决定使用RabbitMQ代理作为中间件

起初,从数据库中消费事件的问题似乎只有两种可能的解决方案:

  • 轮询数据库中传出的消息,并将它们传递给消息代理
  • 在某些表上使用触发器将消息传递给同一台机器上的代理
  • 我不喜欢第一个想法,因为当涉及定期执行sql时会出现延迟问题

    但基于事件的触发方法有一个问题,目前我似乎无法解决。考虑这种情况:

  • 将一行插入到表中
  • 触发器触发并发送消息(使用C#编写的CLR存储过程)
  • 除非写数据的事务回滚,否则一切都正常。在这种情况下,数据是一致的,但消息已经发送,无法回滚,因为触发器是在写入数据库日志时触发的,而不是在事务提交时触发的(这是RDBMS的正确行为)

    我现在意识到我对触发器的要求太多了,它们不适合处理数据以外的任务

    因此,我的问题是:

  • 是否有人设法使用触发器提取数据事件
  • 您还可以建议其他哪些使用数据事件的方法
  • 查询通知(构建在ServiceBroker之上)适合我的情况吗

  • 提前谢谢

    以免首先从等式中剔除明显的不匹配:查询通知技术不适合这种情况,因为它旨在解决相对稳定数据的缓存失效问题。使用QN,您只能知道表已更改,但无法知道更改了什么

    感谢您找出了调用SQLCRL的触发器不起作用的原因:回滚时一致性被破坏

    那么什么有效呢?想想看:换句话说,整个业务都围绕着这个问题空间展开,而解决方案绝不是微不足道的(否则没有人会购买这样的产品)

    通过遵循以下几个原则,您可以走得更远:

    • 解耦。基于事件的触发器可以,但不从触发器发送消息。除了回滚时的一致性问题外,您还存在让每个DML操作现在等待外部API调用(RabbitMQ发送)的延迟问题,以及外部API调用失败的可用性问题(如果RabbitMQ不可用,则您的DB不可用)。解决方案是让触发器使用普通触发器,触发器将消息排入本地db队列(即插入此表),外部进程将通过将消息移出队列(即从表中删除)并将其转发到RabbitMQ来服务此队列。这将事务与RabbitMQ操作分离(只有在原始xact提交时,外部进程才能看到消息),但代价是明显增加了延迟(涉及额外的跃点,本地表充当队列)
    • 幂等性。由于RabbitMQ无法注册数据库的分布式事务,因此无法保证DB操作(从本地表中作为队列出列)和RabbitMQ操作(发送)的原子性。当另一个失败时,任何一个都可以成功,没有显式的分布式事务注册支持,根本没有办法解决。这意味着应用程序每隔一段时间就会发送重复的消息(通常是在某些原因导致情况恶化时)。快速提醒:加入明确的“确认”消息和发送序列号的行为是一场失败的战斗,因为你很快就会发现,你正在消息的基础上重新发明TCP,这条路是由身体铺就的
    • 公差。出于与上述项目相同的原因,有时您认为发送的消息永远不会成功。同样,这造成的损害完全取决于业务。问题不是如何防止这种情况(几乎不可能…),而是如何检测这种情况,以及如何处理。恐怕没有银弹
    您确实在传递ServiceBroker时提到过(事实上,支持查询通知是它最不有趣的方面…)。作为内置于SQL Server中的消息传递平台,它提供了一次到位的交付保证,并且能够完全进行事务处理,因此可以解决上述所有痛点(您可以从触发器中进行操作,而不会受到惩罚,您可以用它来解决延迟问题,您永远不会看到重复或丢失的消息,有明确的错误语义)还有一些我以前没有提到的痛点(由于数据和消息位于同一存储单元(数据库)上,所以备份/恢复的一致性;由于SSB同时支持数据库镜像和群集,所以HA/DR故障切换的一致性等等)。但缺点是SSB只能与另一个SSB服务通信,换句话说,它只能用于在两个(或更多)SQL Server实例之间交换消息。任何其他用途都要求双方使用SQL Server来交换消息。但是如果你的端点都是SQL Server,那就考虑一下还有一些。请注意,像php或asp.net这样的端点可以被视为SQL Server端点,它们只是在DB API上的编程层,不同的端点可能需要将消息从手持设备(电话)直接发送到数据库(99%的时间都是通过web服务完成的,这意味着他们最终可以访问SQL Server)