Erlang 全局 PID - 如何将其保存在 MySQL

Erlang global PID - how to save it in MySQL

问题:我有多个 Erlang 服务,每个服务都由它们的 Erlang PID 标识。我想将 {PID, ServiceName} 保存在我的数据库 (MySQL) 中,这样我的集群中任何需要访问任何服务的 Erlang 进程都只需要 SELECT 来访问该服务名称以获取其 PID,然后对其进行 gen_server 调用。

  1. PID 在我使用 term_to_binary(self()) 将其转换为 "global" PID 后应该保存 - 基本上,假设 Node1 上的 Erlang 进程 A 将自身保存为 <0.45.0>在数据库中:这意味着节点 2 上的进程 B 试图访问由 <0.45.0> 表示的服务将不会成功,因为“<0.45.0>”仅在节点 1 上有效;将其保存为 PID = term_to_binary(self()) 如果我们从 db
  2. MySQL 查询的格式为 "INSERT INTO ServiceTable ... " ++ io_lib:format("ServicePID = '~p', " [binary_to_list(term_to_binary(self()) )]) ++
  3. 当我从数据库中读回 PID 时,我得到类似 <<"[131,103,100,0,23,115"...>> 的信息,这就是我的问题所在:我可以将这个二进制文件转换回某些东西吗像 <<131、103、100 等 ... >> ???

(我知道我可以通过例如注册我的服务等来解决这个问题 - 但我有理由不这样做)。

谢谢。

最简单的方法是使用 pid_to_list/1 and list_to_pid/1 函数。

根据您展示的内容,我猜您可以避免从二进制文件到列表的转换,因此 io_lib:format 会将二进制文件转换为它的字符串表示形式。

稍后您可以使用 erl_parse 和 erl_eval 模块检索 pid:

1> Pid = self(). 
<0.32.0>
2> 
2> String = lists:flatten(io_lib:format("~p.~n",[term_to_binary(Pid)])).
"<<131,103,100,0,13,110,111,110,111,100,101,64,110,111,104,111,115,116,0,0,0,32,\n  0,0,0,0,0>>.\n"
3> %% to get an equivalent form of what you get from sql.
3> {done,{ok,T,_},[]} = erl_scan:tokens([],String,1).
{done,{ok,[{'<<',1},
           {integer,1,131},
           {',',1},
           {integer,1,103},
           {',',1},
           {integer,1,100},
           {',',1},
           {integer,1,0},
           {',',1},
           {integer,1,13},
           {',',1},
           {integer,1,110},
           {',',1},
           {integer,1,111},
           {',',1},
           {integer,1,110},
           {',',1},
           {integer,1,111},
           {',',1},
           {integer,1,100},
           {',',1},
           {integer,1,101},
           {',',1},
           {integer,...},
           {...}|...],
          3},
      []}
4> {ok,Tree} = erl_parse:parse_exprs(T).
{ok,[{bin,1,
          [{bin_element,1,{integer,1,131},default,default},
           {bin_element,1,{integer,1,103},default,default},
           {bin_element,1,{integer,1,100},default,default},
           {bin_element,1,{integer,1,0},default,default},
           {bin_element,1,{integer,1,13},default,default},
           {bin_element,1,{integer,1,110},default,default},
           {bin_element,1,{integer,1,111},default,default},
           {bin_element,1,{integer,1,110},default,default},
           {bin_element,1,{integer,1,111},default,default},
           {bin_element,1,{integer,1,100},default,default},
           {bin_element,1,{integer,1,101},default,default},
           {bin_element,1,{integer,1,64},default,default},
           {bin_element,1,{integer,1,110},default,default},
           {bin_element,1,{integer,1,111},default,default},
           {bin_element,1,{integer,1,104},default,default},
           {bin_element,1,{integer,1,111},default,default},
           {bin_element,1,{integer,1,115},default,default},
           {bin_element,1,{integer,1,...},default,default},
           {bin_element,1,{integer,...},default,...},
           {bin_element,1,{...},...},
           {bin_element,1,...},
           {bin_element,...},
           {...}|...]}]}
5> {value,Res,[]} = erl_eval:exprs(Tree,[]).
{value,<<131,103,100,0,13,110,111,110,111,100,101,64,110,
         111,104,111,115,116,0,0,0,32,0,0,0,0,0>>,
       []}
6> Pid =  binary_to_term(Res).  %% that's it :o)
<0.32.0>

您应该使用预先存在的解决方案,例如 gproc(由 Ulf Wiger 提供)。

我最近在 ErlangFactory 2015 上看到了一个类似的解决方案,由 martinsk 提出,他说可能很快就会发布,称为 "Industry"。它比 gproc 做得更多,包括像 raft 共识协议支持这样的功能,以确定带头的最佳服务器……我想更多的是与他的用例相关。

Gproc 可能是您最好的第一步。如果您使用 MySQL 不仅仅是全球注册的知识库,那么配置和缓存选项可能会为您提供物理存储数据所需的支持。

但是,为了回答你的具体问题,如果你真的想自己做,也许 atom_to_list(node()) ++ pid_to_list(self()). 可以。

例如:

(foo@lankhmar)6> atom_to_list(node()) ++ pid_to_list(self()). "foo@lankhmar<0.43.0>"