erlang refs在节点/ VM重启之间是唯一的吗?

时间:2012-04-05 13:04:06

标签: erlang uuid ref

文档说

make_ref() -> ref()  
     

返回一个几乎唯一的引用。

     

返回的引用将在大约2次 82 调用后重新发生;   因此它具有足够的实用性。

但我的眼睛告诉我,在VM重启之间,我可以很容易地获得相同的参考:

[~] erl
Erlang R14B04 (erts-5.8.5)
1> make_ref().
#Ref<0.0.0.33>
2> make_ref().
#Ref<0.0.0.37>
^C

[~] erl
Erlang R14B04 (erts-5.8.5)
1> make_ref().
#Ref<0.0.0.33>

那么,Erlang的Refs有多独特?当标记在mq或db中持久化并且可能由不同的VM会话生成时,它们是否适合用作唯一的“标记”生成器。

我知道UUID可以用于此。众所周知,pids()是可重复的,可重用的,如果是序列化的,则绝不是唯一的,然后从持久存储中加载。

问题是,什么是refs() - 更像是UUID还是更像pids()?节点之间的refs()是否唯一?重启之间?有关于这个主题的官方信息吗?

2 个答案:

答案 0 :(得分:6)

与节点名称相关的引用并不意味着随机性,只是唯一性。 正如您已经注意到的那样,它们是以循环方式创建的。 此外,您对事实引用的正确性仅在节点的生命周期中是唯一的。一旦重启VM,就可以重复引用。

与PID的情况一样,打印的引用#Ref<W.X.Y.Z>包含 - 作为第一个元素(W) - 有关节点编号的信息:

erl -sname right
Erlang R15B (erts-5.9) [source] [64-bit] [smp:4:4] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.9  (abort with ^G)
(right@mars)1> register(right, self()).
true
(right@mars)2> receive M -> M end.
#Ref<6793.0.0.41>
(right@mars)3> 

erl -sname left
Erlang R15B (erts-5.9) [source] [64-bit] [smp:4:4] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.9  (abort with ^G)
(left@mars)1> {right, 'right@mars'} ! make_ref().
#Ref<0.0.0.41>
(left@mars)2> 

请注意,在这种情况下,参考的W在本地节点0中是6793,在远程节点中是{{1}}。

答案 1 :(得分:5)

在任何分布式系统中,为了能够生成唯一标识符,您必须依赖具有持久存储的中央原子ID生成器,或者确保在任何时间点正确配置集群。以下是第二种情况的一个例子。

在分布式Erlang集群中,{node(), now()}可视为唯一。如果您可以确保合理配置时钟并且不会启动具有相同名称的两个节点,则可以尝试使用{node(), now(), make_ref()},这会使碰撞的可能性忽略不计。