题目如下:
在面试后请候选人用GoLang完成编程作业:
* 问题描述:
新游戏在开服后往往会有瞬时大量用户登录涌入的高峰流量,对服务器产生压力。
* 解决方案:
开发开服排队系统,对到达服务器的大量用户进行队列缓冲,名为QueueService,根据服务器压力情况,逐步让队列中的用户拿到登录服务器的令牌(token),代表该用户请求可以被处理了,从而缓解登录高峰,排队中用户要能够“实时”知道自己在队伍中的位置变更。
* 开发要求:
线下,无时间限制
* 交付:
* 服务器QueueService:要求使用GoLang编写, 使用channel, 使用tcp长连接通信. 要求按照工业级代码标准开发, 比如高并发下吞吐瓶颈是否合理, 各种边界处理是否完备, 在系统发生错误时进程是否健壮
* 客户端:对QueueService发起请求, 并对队列进行实时监控。要求使用GoLang编写, 使用tcp长连接通信
* 文档:说明怎样部署和运行, 如何进行压测, 最好有完整压测数据(QPS, RTT, CPU, Mem等)
我花费了三天的时间,完成了这个项目,这中间还一度失眠没睡好
发给他们后一直没反馈,我主动问了才给了反馈
看到这个结果对我还是有点受打击和气愤的
- golang不熟悉:之前工作中主要是用C++,但对golang深入学习过(源代码层),用golang只写过小项目,面试的时候我透露了这一点,目前这个小项目上能体现出好不好,我也不好判断
- 代码库选的不对:这个.. 我无法接受,选用的gnet开源库是经过测试验证的,接口易使用易理解,且内置了ants协程池,官方甚至还附带了使用gnet作为底层网络服务的公司(腾讯、小米、百度、360)
- 整体行文没有做到分层和结构化:这个就抽象了,怎么说都有理,项目中功能基本都封装成模块了(msg,sequence,queue,conn,client),相互耦合度的并不高,不知道这样一个小的项目还能做出什么高度的分层和结构化
- 那个tcp连接要求自己管理:在题目要求中,我是真心的没找到这么一条
##技术选型
- gnet
- 基于 Event-Loop 事件驱动的高性能和轻量级网络库,解决大量socket高并发问题
per socket per goroutine
- 融合了ants协程池,解决大量协程问题
per msg per goroutine
- 基于 Event-Loop 事件驱动的高性能和轻量级网络库,解决大量socket高并发问题
- zerolog
- 高性能,支持日志等级,钩子的结构化日志库
- 输出格式多样化,支持json格式,便于读取分析
- protobuf
- 协议数据交换格式工具,易于使用且销量高
-
utils
- utils.go 生成随机令牌、生成随机用户ID、统一的panic处理
- sequence.go 协成池任务队列,保证任务顺序执行,解决消息的顺序和数据安全问题
- msg.go 消息头、消息注册和解析消息接口
- gnetconn.go 封装的gnet连接对象,服务器中客户端的连接对象,方便消息数据解析和发送,消息注册分发功能,使用sequence,保证每个conn对象处理消息是顺序
- conn.go 封装的net.TCPConn连接对象,客户端使用,同上
-
msg
- 【源文件】目录中放置消息定义文件和消息导出命令
-
server
- app.go 表示程序对象,通过实例 theApp 来表示全局的程序对象,记录
- conf.go 表示配置对象,通过实例 theConf 来访问
- server.go 表示服务器对象,通过实例 theServer 来访问
- 开启监听,处理客户端的连接和断开,记录连接对象
- 记录在线人数和最近1秒登录的人数,控制用户是否要排队
- client.go 表示连接的客户端
- 内部注册消息,处理客户端发来的消息
- 内部和conn使用同一个sequence,来保证数据的安全性,client内部所有的变量和函数都通过sequence来访问
- 记录用户的登录状态
- queue.go 排队模块,通过实例 theQueue 来访问
- 变量clientPos(map)、clientList(list) 来表示用户排队列表,使用读写锁保护
- changeChann 新增和删除用户写入此channel中,把数据保存到 changeList 中
- 内部运行了一个gorutine来把 changeList 数据更新到排队列表中
- 同时开启另一个gorutine,检查可以登录的用户
-
client 测试客户端
- app、client、conf,主要通能同server服务器,client对象是通过配置来创建个数
- client登录成功后,会触发一定概率的下线重连(app.UpdateClient),模拟用户掉线,给其他排队用户让位置
-
边界检查问题基本上在开发的过程中都考虑
-
【服务器.bat】 启动服务器程序,会读取server.json中的配置,配置参数如下:
- "pprof":1 // 开启性能监控
- "maxonlinenum":50000 // 最大在线人数
- "loginnumpresec":500 // 每秒允许最大的登录人数
- "color":1 // 终端日志输出是否带颜色信息 windows自动终端好像不支持 可以使用Cmder终端
-
【客户端.bat】 启动服务器程序,会读取client.json中的配置,配置参数如下:
- "clientnum":5000 // 最大在线人数
- "showqueue":0 // 是否显示
- "color":1 // 终端日志输出是否带颜色信息 windows自动终端好像不支持 可以使用Cmder终端
-
【查看排队位置的客户端.bat】 客户端程序读取watchconf下的配置,只启动一个客户端,并打印当前客户端排队信息
测试服务器配置成最多支持5万用户在线,新增用户都需要进入登录排队列表
开启11个客户端,每个客户端配饰5000用户,每5秒启动一个客户端
最终会保持5000人在排队中
因为客户端会模拟掉线,查看自己的排队位置会不断的向前变化中
【目前只制作了一个测试中的截图数据,详细的数据变化流程没有,不过从下面的截图数据可以看出,服务器在面对5万个链接时没有表现出压力来】