Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typo3/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
<img src="//i.stack.imgur.com/RUiNP.png" height="16" width="18" alt="" class="sponsor tag img">elasticsearch 排队机制与Elasticsearch 1.4.0_<img Src="//i.stack.imgur.com/RUiNP.png" Height="16" Width="18" Alt="" Class="sponsor Tag Img">elasticsearch_Rabbitmq_Spring Integration_Spring Amqp - Fatal编程技术网 elasticsearch 排队机制与Elasticsearch 1.4.0,elasticsearch,rabbitmq,spring-integration,spring-amqp,elasticsearch,Rabbitmq,Spring Integration,Spring Amqp" /> elasticsearch 排队机制与Elasticsearch 1.4.0,elasticsearch,rabbitmq,spring-integration,spring-amqp,elasticsearch,Rabbitmq,Spring Integration,Spring Amqp" />

elasticsearch 排队机制与Elasticsearch 1.4.0

elasticsearch 排队机制与Elasticsearch 1.4.0,elasticsearch,rabbitmq,spring-integration,spring-amqp,elasticsearch,Rabbitmq,Spring Integration,Spring Amqp,我有一个RabbitMQ代理,我在上面发布不同的消息,这些消息最终将作为Elasticsearch中的文档。代理中有多个使用者,它们实际上是分配给amqp入站网关的任务执行器中的不同线程(此处使用spring integration和spring amqp) 请考虑以下场景:我已在ES中使用该结构创建了一个文档 { "field1" : "value1", "field2" : "value2" } 之后,我发送了两个更新请求,都更新了相同的字段,比如说field1。如果我一个接一

我有一个RabbitMQ代理,我在上面发布不同的消息,这些消息最终将作为Elasticsearch中的文档。代理中有多个使用者,它们实际上是分配给amqp入站网关的任务执行器中的不同线程(此处使用spring integration和spring amqp)

请考虑以下场景:我已在ES中使用该结构创建了一个文档

{
   "field1" : "value1",
   "field2" : "value2"
}
之后,我发送了两个更新请求,都更新了相同的字段,比如说
field1
。如果我一个接一个地发送此消息(生产中的常见用例),我的使用者线程将以正确的顺序获取消息(amqp允许这样做),但是处理可能以错误的顺序发生,并且稍后更新的值可能会被第一个值覆盖。我最终会把数据写出来

如何确保我的数据不会损坏?=>只有一个消费者线程是不够的,因为如果我想通过在我的消费应用程序中添加更多的机器来扩展,我最终还是会有多个消费者。我可能需要对消息进行排序,但是由于有多台机器,我可能需要创建某种集群感知组件,我使用的是SI,所以在我看来这似乎很难做到


在1.2版本之前的ES中,我们使用了一个外部版本,比如时间戳,在我的场景中ES会抛出
VersionConflictException
:第一次更新的版本是10000,比如说,第二次更新的版本是10001,如果第一次更新是先处理的,ES将拒绝版本为10000的请求,因为它低于现有版本。但是从最新的版本来看,更新操作需要更多的人。

一个解决方案可能是使用多个队列,每个队列上只有一个使用者;使用哈希函数始终将对同一文档的更新路由到同一队列。有关各种选项,请参阅

您可以通过添加更多队列(并更改哈希函数)进行扩展

对于弹性,考虑你的消费者。您可以拥有每个rabbit源的单个实例(对于每个队列),如果发生故障,XD将负责将其故障转移到另一个容器节点

否则,您可以使用配置有
auto startup=“false”
的热备用入站适配器,并使用某个监视器和
启动新实例(如果活动实例出现故障)

编辑:

针对以下第四条评论

正如我上面所说的,要向外扩展,必须更改哈希函数。因此,在运行时自动添加消费者将是一件棘手的事情

您不必在jar中硬编码队列名称,您可以使用属性占位符并从属性、系统属性或环境变量填充它

此解决方案是最简单的,但有这些限制

但是,您可以构建一个管理应用程序来扩展它—停止生产商,等待所有队列停止,重新配置消费者并重新启动生产商—Spring集成提供了启动/停止适配器的
;您也可以通过JMX来实现


替代解决方案是可能的,但通常需要在集群中维护一些共享状态(可能使用zookeeper等),因此要复杂得多;您仍然必须处理竞争条件(第二次更新可能在第一次更新之前到达某个消费者)。

您可以使用默认机制进行一致性检查。基本上,您希望验证您是否拥有所更新内容的最新版本

因此,您需要使用对象获取_版本。在查询中,可以通过在顶层设置version=true来实现这一点。这将导致_版本与查询结果一起返回。然后在执行更新时,只需将url中的version参数设置为您拥有的值,如果不匹配,它将生成版本冲突


更好的方法是使用闭包处理更新。基本上,它的工作原理如下:有一个更新方法,该方法通过id获取对象,应用一个闭包(更新函数的参数),该闭包封装您想要进行的修改,然后存储修改后的对象。如果捕获到仍然可能存在的版本冲突,只需再次获取对象并将闭包重新应用于对象即可。我们这样做,并在重试之前添加了一个随机睡眠,这大大减少了多次更新失败的机会,这是一个很好的设计模式。将读写操作保持在一起可以最大限度地减少冲突的可能性,然后在冲突发生之前进行睡眠重试可以进一步降低冲突的可能性。您可以添加多次重试以进一步降低风险

如何使用spring amqp注入此哈希函数?你能给我一个简单的例子吗?只需以某种方式计算文档中的哈希值,例如,
customerNumber%3
(如果有3个队列),然后使用它在
rabbitmplate.send…(…)
方法中构建
routingKey
。假设我发布到3个不同的队列,并为每个队列注册1个消费者。如果我有3台机器部署了我的应用程序,如何确保只有一个线程从队列中获取消息?默认情况下,每个侦听器容器(入站通道适配器)一个线程;它由
并发性
属性控制。但是,您不能在容器线程上转移到另一个线程进程;不要使用任何
QueueChannel
s或
ExecutorChannel
s等。我的问题不同:假设我有3个队列:q1、q2、q3和3个代表消费者的可运行jar。在每个可运行jar中,我将定义一个入站通道适配器或入站网关,这里我必须指定我正在侦听的队列。我必须硬编码队列名称并输入第一个消费者q1、第二个q2,依此类推。这个假设正确吗?我如何能自动扩展?我想我必须这么做