随记(9)分布式开发流程

作者:

文章目录
  • 进程可以相互连接,假设两个普通进程AB,A进程出于某种原因终止,就会向进程B发送一个错误信号,由于AB创建了连接,B又是普通进程,所以最后两个进程一起挂掉 spawn创建的是普通进程,普通进程通过执行process_flag(trap_exit, true)变成系统进程,意思就是可以接受和处理错误信号的进程,而不会随与之相连接的进程退出 监视与连接相比,是单向的,A监视B,B进程挂了,会发送“宕机”消息给A, A不是系统进程也可以处理消息,不会随之退出
  • 当前数据库有wuxia_login(登录服务器)、wuxia_s1(一服)、wuxia_s2*(二服)、wuxia_db(模板数据)、wuxia_dt(数据库后台管理网站的结构) 当前有数据库的服务器: login服务器player_token表(所有玩家的uid、token、nickname,一般涉及所有玩家的数据操作rpc此节点) logic服务器(存着不同服的玩家的数据player_id、uid、nickname)、 logger服务器(日志信息) 当前分布式数据库结构都相同,但是数据有所不同,例如: login服务器的数据库player_token表中有所有玩家的nickname数据 logic1服务器中的player表中有该区所有玩家的nickname数据 登录流程 gate服务器|启动连接:客户端向网关服务器(gate)发送一个tcp连接请求,就启动了一个玩家进程,这个进程中保存了state状态字 web(login)服务器|请求token:向web服务器发送http请求,拿到token,wuxia_login数据库中的player_token表中存下了玩家的uid、token login服务器|检验token:向login服务器发送检验token请求,没问题返回srv_id,存在玩家进程的state中,然后数据库置空玩家的token、time logic1服务器|登录(创建账号):根据玩家进程中状态字state存储的srv_id,向分配的服务器发送login请求,检验token是否超时.接着wuxia_s1数据库中player表是否有该uid对应的记录,有就返回该记录,没有就创建一条记录(获取当前player自增长的值作为player_id,并保存在状态字中),最后返回格式为{PlayerId, Nickname, IsMale},客户端通过nickname是否为空来判断是否创建角色 logic1服务器|创建角色:根据玩家id判断所在服务器,对该节点进行rpc请求(mod_player:api_init(PlayerId, Nickname, IsMale)),无异常,就增加该player_id的nickname、male等. 客户端向gate网关服务器发送一个tcp连接请求,就启动了一个玩家进程,这个进程中保存了state状态字(结构如下),接着向web(login)服务器获取token,向login服务器检测token,完成后向状态字中保存的服务器sid发送登录请求(也把自己的玩家进程号发送给服务器节点) %%—–客户端状态-record(client_state,{player_id, %%—–玩家idip = "0.0.0.0", %%—–玩家ipsid = 0, %%—–主逻辑服务器idcheck_token = false, %%—–是否确认过tokenis_login = false, %%—–是否登陆成功last_error_time = 0 %%—–最后错误时间}). 服务器:一个大型的监督树,管理多个进程,处理大型服务,绑定数据库,分布式则绑定不同数据库?? 签名流程 请求token:127.0.0.1/login?uid=xxx&sign=md5(uid=xxx&key=xxx) 检测token: player:check_token(Uid, Token) 登录: player:login(Uid, Time, md5(uid=xxx&time=xxx&key=xxx)) key = 8ebe40da1fac1b1efefcb0bde484568a, 示例如下: uid=www&key=8ebe40da1fac1b1efefcb0bde484568a http://127.0.0.1:8001/login?uid=www&sign=8ceb216edd15703d61915cb40473170ftoken=b2f2e025ec450e1btest_player:check_token("www","b2f2e025ec450e1b");uid=www&time=1546856674&key=8ebe40da1fac1b1efefcb0bde484568atest_player:login("www",1546856674,"2a0e7b1ccbfabebfcc4c621b7cfcfa8c"); 报错看logger服务器,打印的,处在哪个服务器就查看哪个 read查找单条记录,一般是返回列表或者空列表,这边架构有返回记录,没有返回null 优化:一些异常判断最好在函数开头做好判断处理,有问题就抛异常,不要多层嵌套在if里面,如下: api_init (PlayerId, NickName, IsMale) ->%%—–账号是否存在(是否有这条记录)Player = get_player(PlayerId),ifPlayer =/= null ->ok;true ->exit(player_id_error)end,%%—–是否初始化(nickname是否为空)ifPlayer #player.nickname == "" ->ok;true ->exit(already_init)end,%%—–检测名字长度%%—–检测重复%%—–检测屏蔽字 player_1、player_2、player_3(mod_uets下,服务器初始化,遍历player表加载进ets) player_1:uid(账号)—–player_id—–uid转玩家id player_2:nickname—–player_id—–昵称转玩家id player_3:nickname—–uid(账号)—–昵称转uid 远程调用节点(rp)返回格式{badrpc, Reason} [error:reason] case ?PLAYER_ID_TRACE_CALL(State, PlayerId, mod_test_player, api_init, [PlayerId, NickName, IsMale]) of{badrpc, {_,nickname_length_error}} ->{?C_NICKNAME_LENGTH_ERROR};{badrpc, {_,nickname_repeat}} ->{?C_NICKNAME_REPEAT};{badrpc, {_,nickname_shielding_words}} ->{?C_NICKNAME_SHIELDING_WORDS};{badrpc, _} ->{?C_UNKNOW_ERROR};_ ->{?C_success} 先开发功能,再去考虑由哪个服务器或者进程调用(取决于哪个数据库合适,因为分布式下) 比如考虑到取所有玩家昵称就要选择login服务器,因为wuxia_login数据库下的player_token表中有所有的玩家nickname 比如考虑到取某个服务器区所有玩家昵称就要选择logic1或者logicN服务器,因为wuxia_s1/sN数据库下的player表中有当前服的所有玩家的nickname 当前服务器架构下的所有路由接口返回都是二元组
    • 一、杂记
    • 二、分布式开发流程(针对当前服务器架构)

    1. 进程可以相互连接,假设两个普通进程AB,A进程出于某种原因终止,就会向进程B发送一个错误信号,由于AB创建了连接,B又是普通进程,所以最后两个进程一起挂掉
    2. spawn创建的是普通进程,普通进程通过执行process_flag(trap_exit, true)变成系统进程,意思就是可以接受和处理错误信号的进程,而不会随与之相连接的进程退出
    3. 监视与连接相比,是单向的,A监视B,B进程挂了,会发送“宕机”消息给A, A不是系统进程也可以处理消息,不会随之退出

    1. 当前数据库有wuxia_login(登录服务器)、wuxia_s1(一服)、wuxia_s2*(二服)、wuxia_db(模板数据)、wuxia_dt(数据库后台管理网站的结构)
    2. 当前有数据库的服务器:
    • login服务器player_token表(所有玩家的uid、token、nickname,一般涉及所有玩家的数据操作rpc此节点)
    • logic服务器(存着不同服的玩家的数据player_id、uid、nickname)、
    • logger服务器(日志信息)
    1. 当前分布式数据库结构都相同,但是数据有所不同,例如:
    • login服务器的数据库player_token表中有所有玩家的nickname数据
    • logic1服务器中的player表中有该区所有玩家的nickname数据
    1. 登录流程
    • gate服务器|启动连接:客户端向网关服务器(gate)发送一个tcp连接请求,就启动了一个玩家进程,这个进程中保存了state状态字
    • web(login)服务器|请求token:向web服务器发送http请求,拿到token,wuxia_login数据库中的player_token表中存下了玩家的uid、token
    • login服务器|检验token:向login服务器发送检验token请求,没问题返回srv_id,存在玩家进程的state中,然后数据库置空玩家的token、time
    • logic1服务器|登录(创建账号):根据玩家进程中状态字state存储的srv_id,向分配的服务器发送login请求,检验token是否超时.接着wuxia_s1数据库player表是否有该uid对应的记录,有就返回该记录,没有就创建一条记录(获取当前player自增长的值作为player_id,并保存在状态字中),最后返回格式为{PlayerId, Nickname, IsMale},客户端通过nickname是否为空来判断是否创建角色
    • logic1服务器|创建角色:根据玩家id判断所在服务器,对该节点进行rpc请求(mod_player:api_init(PlayerId, Nickname, IsMale)),无异常,就增加该player_id的nickname、male等.
    1. 客户端向gate网关服务器发送一个tcp连接请求,就启动了一个玩家进程,这个进程中保存了state状态字(结构如下),接着向web(login)服务器获取token,向login服务器检测token,完成后向状态字中保存的服务器sid发送登录请求(也把自己的玩家进程号发送给服务器节点)
        %%-----客户端状态-record(client_state,{player_id,      						%%-----玩家idip				 = "0.0.0.0", 			%%-----玩家ipsid				 = 0, 					%%-----主逻辑服务器idcheck_token		 = false, 				%%-----是否确认过tokenis_login		 = false, 				%%-----是否登陆成功last_error_time	 = 0    				%%-----最后错误时间}).
    
    1. 服务器:一个大型的监督树,管理多个进程,处理大型服务,绑定数据库,分布式则绑定不同数据库??
    2. 签名流程
    • 请求token:127.0.0.1/login?uid=xxx&sign=md5(uid=xxx&key=xxx)
    • 检测token: player:check_token(Uid, Token)
    • 登录: player:login(Uid, Time, md5(uid=xxx&time=xxx&key=xxx))
    • key = 8ebe40da1fac1b1efefcb0bde484568a, 示例如下:
        uid=www&key=8ebe40da1fac1b1efefcb0bde484568a http://127.0.0.1:8001/login?uid=www&sign=8ceb216edd15703d61915cb40473170ftoken=b2f2e025ec450e1btest_player:check_token("www","b2f2e025ec450e1b");uid=www&time=1546856674&key=8ebe40da1fac1b1efefcb0bde484568atest_player:login("www",1546856674,"2a0e7b1ccbfabebfcc4c621b7cfcfa8c");
    
    1. 报错看logger服务器,打印的,处在哪个服务器就查看哪个
    2. read查找单条记录,一般是返回列表或者空列表,这边架构有返回记录,没有返回null
    3. 优化:一些异常判断最好在函数开头做好判断处理,有问题就抛异常,不要多层嵌套在if里面,如下:
    api_init (PlayerId, NickName, IsMale) ->%%-----账号是否存在(是否有这条记录)Player = get_player(PlayerId),ifPlayer =/= null ->ok;true ->exit(player_id_error)end,%%-----是否初始化(nickname是否为空)ifPlayer #player.nickname == "" ->ok;true ->exit(already_init)end,%%-----检测名字长度%%-----检测重复%%-----检测屏蔽字
    1. player_1、player_2、player_3(mod_uets下,服务器初始化,遍历player表加载进ets)
    • player_1:uid(账号)—–player_id—–uid转玩家id
    • player_2:nickname—–player_id—–昵称转玩家id
    • player_3:nickname—–uid(账号)—–昵称转uid
    1. 远程调用节点(rp)返回格式{badrpc, Reason} [error:reason]
    case ?PLAYER_ID_TRACE_CALL(State, PlayerId, mod_test_player, api_init, [PlayerId, NickName, IsMale]) of{badrpc, {_,nickname_length_error}} ->{?C_NICKNAME_LENGTH_ERROR};{badrpc, {_,nickname_repeat}} ->{?C_NICKNAME_REPEAT};{badrpc, {_,nickname_shielding_words}} ->{?C_NICKNAME_SHIELDING_WORDS};{badrpc, _} ->{?C_UNKNOW_ERROR};_ ->{?C_success}
    
    1. 先开发功能,再去考虑由哪个服务器或者进程调用(取决于哪个数据库合适,因为分布式下)
    • 比如考虑到取所有玩家昵称就要选择login服务器,因为wuxia_login数据库下的player_token表中有所有的玩家nickname
    • 比如考虑到取某个服务器区所有玩家昵称就要选择logic1或者logicN服务器,因为wuxia_s1/sN数据库下的player表中有当前服的所有玩家的nickname
    1. 当前服务器架构下的所有路由接口返回都是二元组

    评论

    发表回复

    您的邮箱地址不会被公开。 必填项已用 * 标注

    站内搜索