2014-12-03 97 views
0

riak在2台服务器上运行集群。在server1上Server1上RIAK获取http:// host/riak/people/key“找不到”

for i in {1..1000}; do 
curl -i -XPOST 'http://server1.local:8098/riak/people/'$i'' -H 'Content-Type:application/json' -d '{"name":"aaron_'$i'"}' 
done 

关机了Riak

riak-admin status | grep ring_members 
ring_members : ['[email protected]','[email protected]', 

写入数据:/etc/init.d/riak停止

,并与服务器2

for i in {1..1000}; do 
curl -v -i http://server2.local:8098/riak/people/$i 
done 

10-获取数据30%的数据没有通过第一遍读取。数据在第二遍读取。

第一遍

curl -i http://server2.local:8098/riak/people/196 

About to connect() to server2.local port 8098 (#0) 
* Trying 2.2.2.2... connected 
* Connected to server2.local (2.2.2.2) port 8098 (#0) 
> GET /riak/people/196 HTTP/1.1 
> Host: server2.local:8098 
> Accept: */* 
< HTTP/1.1 404 Object Not Found 
< Server: MochiWeb/1.1 WebMachine/1.10.0 (never breaks eye contact) 
< Date: Thu, 27 Nov 2014 11:22:25 GMT 
< Content-Type: text/plain 
< Content-Length: 10 

server2.local left intact 

* Closing connection #0 

    not found 

第二次

curl -i http://server2.local:8098/riak/people/196 

* About to connect() to server2.local port 8098 (#0) 
* Trying 2.2.2.2... connected 
* Connected to server2.local (2.2.2.2) port 8098 (#0) 
> GET /riak/people/196 HTTP/1.1 
> Host: server2.local:8098 
> Accept: */* 
< HTTP/1.1 200 OK 
< X-Riak-Vclock: a85hYGBgzGDKBVIcypz/foYkbmfKYEpkzGNlCGh9fZYvCwA= 
< Vary: Accept-Encoding 
< Server: MochiWeb/1.1 WebMachine/1.10.0 (never breaks eye contact) 
< Link: </riak/people>; rel="up" 
< Last-Modified: Thu, 27 Nov 2014 11:21:52 GMT 
< ETag: "2C4oPFcSctzBX1mwHjjfQ1" 
< Date: Thu, 27 Nov 2014 11:25:47 GMT 
< Content-Type: application/json 
< Content-Length: 20 

* Closing connection #0 

{"name":"aaron_196"} 

为什么会出现这种情况?

回答

1

这是由最终一致性,分区容限和小簇大小的组合引起的。

Preflists

当存储的关键,在了Riak 3个不同的虚拟节点(虚拟节点)存储副本,统称为重点的“preflist`。

vnodes数量的缺省值是64.因此,每个节点都有32个vnode。创建群集时,将vnodes分配给物理节点的算法会尝试在同一物理节点上不会有超过1个vnode驻留在同一物理节点上 - 这是当只有2个节点存在时不可能完成的任务。

所以当你存储你的值时,2个副本被写入一个节点,而另一个节点写入另一个节点。

失败国家

当一个节点发生故障,关机或以其他方式变得不可用,余下的节点开始,以接受会被丢失的节点的虚拟节点处理操作需要备用虚拟节点。当原始节点再次可用时,会触发一个提示性切换过程,导致备用vnode将其所有数据发送到原始位置的主要vnode。

仲裁

请求在了Riak受到的vnode法定人数。一些常用的法定人数是:

  • 阅读r - 虚拟节点的最小数目必须回复读请求,才可以返回一个值给客户端。
  • w - 必须返回成功写入虚拟节点的最小数目之前,客户端可以告知这是成功的
  • 小学读pr - 同样的,除了备用虚拟节点r可能不被视为
  • 主写pw - 的相同,除了回退的vnode w可以不被认为

rw法定人数的默认值是(n_val/2) + 1,2在默认0123的情况下。

发生了什么事

当你写你的价值观到2节点集群,每个值的2个拷贝写入到一个节点和1个其他。在预闪现之间哪个节点收到2份副本。我认为这个部门大概是你写的两个关键字中的一半写入节点1和一次写入节点2,反之亦然。

然后,当您停止节点1时,其所有虚拟节点都变为同时不可用。您对节点2的第一个读取请求会导致它启动1个或2个回退vnode,以替换预填表中缺少的一个或多个。这些回退在完成启动之前无法响应,因此get过程的第一个回复将来自节点2上的主vnode,该节点具有该值。然后,获取过程将等待另一个答复(以满足默认的r = 2个法定人数),这可能是新开始的(并且非常空的)后备vnode未发现的,之后它会将该值返回给客户端。

回复后,get过程不会立即退出。它等待来自所有vnode的响应,如果它们不匹配,则它会比较返回的值,根据它们的vclock选择最新的电流,并将解析后的值发送回vnode。该过程被称为read repair,并且是恢复一致性的关键。

随着每次连续读取,以前的读取所需的回退变得更有可能,因此已经开始。

假设您在Bitcask中保留了默认后端,那些没有该值的回退vnode将扫描in-RAM密钥目录,发现请求的密钥不存在,并返回notfound。具有数据的vnode将扫描keydir,通过引用和偏移量为包含数据的磁盘文件找到请求的键的条目,执行磁盘读取以获取数据,然后将其发送到get过程。由此可以推断,由于不涉及磁盘访问,因此可以比使用数据的响应更快地生成未发现的响应。

因此,如果满足以下所有条件都为真:正在运行

  • 钥匙没有要求,因为在回退中开始

    • 你读请求所需的所有虚拟节点
    • 关键是写两次以节点1,并且一旦到节点2
    • 默认n_val = 3,且r = 2用于

    然后,获得亲cess将首先收到2 notfound响应,该响应满足r=2法定人数,并向客户端回复notfound。它会在适当的时候收到数据的第三个响应,并将该值写入回退节点。

    接下来的读取请求会找到填充的所有3个vnodes并返回值。

    如何防止这种情况

    为了防止这种情况发生或者:

    • 使用需要在preflist所有虚拟节点响应(r=all
    • 使用需要的法定人数法定人数来自主vnode的回答(pr=1
    • 将节点添加到集群,直到没有预制列表在同一节点上有2个成员。

    当加入节点集群,在​​阶段,你应该看到的效果的警告“不是所有的副本将是不同的节点,”如果任何一个节点将包含preflist的2名成员。

    向节点分配vnode的算法使用target_n_val设置(通常高于n_val),以确保如果某个节点发生故障,则回退vnode的第一个选择不是已经拥有预填充列表的另一个成员的节点。 target_n_val的默认值为4,通常建议群集中存在target_n_val + 1节点,以确保可以在不重叠的情况下完成vnode分配。