区服节点互连
(金庆的专栏)
【上海龙图招聘】所有Erlang服务器节点加入同一集群,使用相同的cookie。
使用BIF erlang:set_cookie(node(), C)把本地节点的cookie设置为原子C。
1个或多个节点配置为主节点(主服务器)。
主节点不必全部启动,但要求至少启动1个。
主节点配置可热更新即时生效。
主节点启动后,主动连接所有未连接的主节点,每隔5s尝试连接。
其他节点,如新开区服,仅需连接主节点。
所有主节点和其他节点最终全互连。
仅需配置主服务器内网地址,利用net_adm:world_list([Host])连接所有节点。
客户端仅需配置数个主服务器的地址,连上某个主服后即可查询所有服务器的地址与负载。
客户端一般会记录后最连接的服务器,用于角色重登,同样也可查询服务器列表。
ping_main_hosts() ->
MainHosts = config_main_hosts:get(),
Nodes = net_adm:world_list(MainHosts),
lager:debug("Ping main hosts: ~p. Result nodes: ~p", [MainHosts, Nodes]),
ok.
18:34:45.023 [debug] Ping main hosts: ['127.0.0.1']. Result nodes: []
18:34:50.029 [debug] Ping main hosts: ['127.0.0.1']. Result nodes: []
Reloading config_main_hosts ... ok.
18:34:55.272 [debug] Ping main hosts: ['192.168.8.9','127.0.0.1']. Result nodes: ['s3@192.168.8.9']
18:35:00.057 [debug] Ping main hosts: ['192.168.8.9','127.0.0.1']. Result nodes: ['s3@192.168.8.9']
cluster_svr 处理集群互连。
%%%-------------------------------------------------------------------
%%% @author jinqing
%%% @copyright (C) 2015, <COMPANY>
%%% @doc 集群互连服务器。
%%% 处理集群互连。广播自身节点状态,接收其他节点状态。
%%% @end
%%% Created : 23. 四月 2015 12:12
%%%-------------------------------------------------------------------
-module(cluster_svr).
-author("jinqing").
-behaviour(gen_server).
...
-type state() :: #{nodes => [node()]}.
-type server_info() :: #{host_cfg => config_gateway:host_cfg(),
current_load => integer()}.
-export_type([server_info/0]).
...
init([]) ->
init_ets(),
init_timer(),
{ok, #{}}.
...
handle_info(timer_ping, State) ->
NewState = timer_ping(State),
{noreply, NewState};
handle_info(timer_bcast_info, State) ->
timer_bcast_info(),
{noreply, State};
handle_info({server_info, ServerId, ServerInfo}, State)
when is_integer(ServerId), is_map(ServerInfo) ->
lager:debug("~p Server~p info: ~p", [self(), ServerId, ServerInfo]),
ets:insert(ets_server, {ServerId, ServerInfo}),
{noreply, State};
...
init_timer() ->
% 启动时短时间内Ping多次,接着每隔10s定时Ping.
{ok, _} = timer:send_after(200, self(), timer_ping),
{ok, _} = timer:send_after(1000, self(), timer_ping),
{ok, _} = timer:send_interval(10000, self(), timer_ping),
{ok, _} = timer:send_after(2000, self(), timer_bcast_info),
{ok, _} = timer:send_after(5000, self(), timer_bcast_info),
{ok, _} = timer:send_interval(31000, self(), timer_bcast_info),
ok.
init_ets() ->
ets:new(ets_server, [named_table]), % 区服列表
ok.
-spec timer_ping(State :: state()) -> state().
timer_ping(State) ->
% lager:debug("timer_ping"),
spawn(cluster_ping, ping_main_hosts, []),
PrevNodes = maps:get(nodes, State, []),
Nodes = nodes(),
case (Nodes =:= PrevNodes) of
true -> State;
_ ->
% 如果有节点更新,就打印节点列表。
AllNodes = [node() | Nodes],
lager:info("All nodes: ~p", [AllNodes]),
State#{nodes => Nodes}
end.
timer_bcast_info() ->
% lager:debug("timer_bcast_info"),
ServerId = six_util:get_server_id(),
ServerInfo = cluster_server_info:get(ServerId),
rpc:abcast(nodes(), ?MODULE, {server_info, ServerId, ServerInfo}),
ok.
【上海龙图招聘】