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

以下部分内容仅针对当前所使用的分布式服务器架构,记录这些来巩固自己的理解,方便以后查阅

  • 一、杂记
  • 二、分布式开发流程(针对当前服务器架构)

一、杂记

  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. 当前服务器架构下的所有路由接口返回都是二元组

Published by

风君子

独自遨游何稽首 揭天掀地慰生平

发表回复

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