elasticsearch 最终一致性-如何避免幻影,elasticsearch,cassandra,hazelcast,ignite,high-availability,elasticsearch,Cassandra,Hazelcast,Ignite,High Availability" /> elasticsearch 最终一致性-如何避免幻影,elasticsearch,cassandra,hazelcast,ignite,high-availability,elasticsearch,Cassandra,Hazelcast,Ignite,High Availability" />

elasticsearch 最终一致性-如何避免幻影

elasticsearch 最终一致性-如何避免幻影,elasticsearch,cassandra,hazelcast,ignite,high-availability,elasticsearch,Cassandra,Hazelcast,Ignite,High Availability,我不熟悉这个话题。读了几篇关于它的文章,问了几个人,我仍然不明白你们在一个问题上做了什么 有一些UI客户端向几个后端实例发出请求(目前,会话是否具有粘性无关紧要),这些实例连接到一些高可用的DB集群(可能是Cassandra或其他甚至Elasticsearch)。假设后端实例没有专门绑定到一台或多台集群的机器,相反,它对DB的每个请求都可能由不同的机器提供服务。 一个客户端创建一些记录,它同步或异步地存储到集群的一台机器上,然后最终复制到其余的DB机器上。然后,另一个客户机请求列表或记录,该请求

我不熟悉这个话题。读了几篇关于它的文章,问了几个人,我仍然不明白你们在一个问题上做了什么

有一些UI客户端向几个后端实例发出请求(目前,会话是否具有粘性无关紧要),这些实例连接到一些高可用的DB集群(可能是Cassandra或其他甚至Elasticsearch)。假设后端实例没有专门绑定到一台或多台集群的机器,相反,它对DB的每个请求都可能由不同的机器提供服务。 一个客户端创建一些记录,它同步或异步地存储到集群的一台机器上,然后最终复制到其余的DB机器上。然后,另一个客户机请求列表或记录,该请求最终由一台尚未接收到复制更改的远程计算机提供,因此客户机看不到该记录。嗯,那很糟糕,但还不难看

但是,请考虑第二个客户端命中具有记录的计算机,将其显示在列表中,然后刷新列表,这一次命中远程计算机,并且再次看不到记录。这是很奇怪的行为,不是吗?它甚至可能变得更糟:客户端成功地请求记录,开始对其进行一些编辑,然后尝试将更新存储到DB,这一次,远程机器会显示“我对您尝试更新的记录一无所知”。这是用户在做完全合法的事情时会看到的错误

那么,预防这种情况的常见做法是什么? 到目前为止,我只看到三种解决方案

1) 实际上,这不是一个解决方案,而是一个策略:忽略问题,而是提高集群速度,以保证99.999%的更改将在整个集群上复制,比如说,0.5秒(很难想象一些用户会在这段时间内尝试对一条记录发出几个连续的请求;他当然可以发出几个读取请求,但在这种情况下,他可能不会注意到结果之间的不一致)。即使有时出现问题,用户面临问题,我们也会接受。如果失败者不高兴并向我们投诉(可能每周或每小时发生一次),我们会道歉,然后继续

2) 在用户会话和特定DB机器之间引入关联。这会有所帮助,但需要DB的明确支持,也会影响负载平衡,并且在DB机器停机并且会话需要重新绑定到另一台机器时会带来复杂性(然而,在DB的适当支持下,我认为这是可能的;比如Elasticsearch可以接受路由密钥,我相信如果目标碎片掉了,它只会将关联链接切换到另一个碎片——虽然我不完全确定;但即使发生重新绑定,另一台机器也可能包含旧数据:))

3) 依赖于单调一致性,即某种方法,以确保来自客户端的下一个请求将得到不早于前一个请求的结果。但是,据我所知,这种方法还需要DB的显式支持,比如能够将一些“全局版本时间戳”传递给集群的平衡器,它将与所有机器的时间戳上的最新数据进行比较,以确定哪些机器可以为请求提供服务

还有其他好的选择吗?还是认为这三种方法足够好用


另外,我现在的具体问题是Elasticsearch;抱歉,这里不支持单调读取,不过看起来选项2可能可用。

ApacheIgnite有一个密钥的主分区和备份分区。除非您设置了
readFromBackup
选项,否则您将始终从其内容可靠的主分区进行读取

如果一个节点消失,事务(或操作)应该由剩余的节点传播或回滚


请注意,ApacheIgnite不会实现最终一致性,而是实现强一致性。这意味着您可以在节点丢失期间观察延迟,但不会观察到不一致的数据。

在Cassandra中,如果对读写操作使用至少仲裁一致性,您将获得单调的读取。这不是1.0之前的情况,但那是很久以前的事了。如果使用服务器时间戳,会有一些问题,但这不是默认情况,所以如果使用C*2.1+,可能不会有问题


有趣的是,C*使用的时间戳是在“同一时间”发生的事情。因为卡桑德拉是最后一个写赢的人,所以时间和时钟漂移确实很重要。但对记录的并发更新总是有竞争条件,因此,如果您需要强的先读后写保证,您可以使用轻量级事务(基本上是使用paxos的CAS操作),以确保在从读取到更新之间没有其他人进行更新,这些都很慢,所以除非很重要,否则我会避免它。

在真正的分布式系统中,只要您的客户端连接到远程集群,您的记录存储在远程集群中的什么位置都无关紧要。在Hazelcast中,一条记录总是存储在一个分区中,一个分区由集群中的一个服务器拥有。集群中可能有X个分区(默认情况下为271个),所有这些分区在集群中分布均匀。因此,一个由3个成员组成的集群将具有类似91-90-90的分区分布

现在,当客户机发送一条记录到Hazelcast集群中存储时,它已经通过使用一致性哈希算法知道该记录属于哪个分区。这样,它还可以知道哪个服务器是该分区的所有者。因此,客户机将其操作直接发送到该服务器。这种方法适用于所有客户端操作——put或get。因此,在您的情况下,您可能有多个UI客户端连接到集群,但特定用户的记录存储在集群中的一台服务器上,并且所有用户的记录都存储在集群中