Erlang 性能优化总结
Posted ITPUB技术小栈
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Erlang 性能优化总结相关的知识,希望对你有一定的参考价值。
本人主要从事游戏后端开发,所以本文只从游戏开发角度分析Erlang使用中应注意的问题和优化点。
1.单节点还是多节点
Erlang节点之间的通信是透明的,节点内部和外部之间的调用一致。基于这样的特性,很多人会选用多节点,把各子系统(登陆节点,玩家节点,地图节点,全局节点等)分配到不同的节点中,以支持更多的在线玩家。这样做的出发点是好点是好的,但会引起一列表的问题:登陆、转场逻辑复杂,节点间的消息广播频繁,玩家数据同步、一致问题,内存消耗,运维复杂化等。相比之下,单节点就简单多了,不用考虑节点通信,玩家数据保证一致,运维方便,一机多服。在开启SMP的情间下,单节点的性能已经很好。对页游的业务,同时在线达到5000人已经非常少见,即使达到也是首服当天才会出现,单节点完全可以应付这样的情况,所以没必要用多节点,增加系统复杂性。
2. 消息广播
消息广播是游戏中的性能消耗大头,主要包括地图的行走、PK广播,世界聊天广播。世界聊天广播可以通过CD等策划手段限制,行走和PK包的广播实时性高,只能通过技术手段解决。地图中的广播包,只需发给视野内的玩家就可以,不用全地图广播。视野内的玩家可以通过九宫格划分,以 X,Y为主键,映射到对应的玩家数据。以九宫格方式查找玩家非常高效,我第一个游戏,地图中的玩家起初是保存在一个列表中,每次广播时都要遍历列表,找出同屏玩家,消息广播非常低效,特别是在PK时,CPU占用高。用九宫格优化后,一切问题都解决了。还有一个优化广播问题的方法是数据包缓存。
3. 缓存-数据库,网络
缓存是用空间换时间,它是性能优化中常用的方法。数据库缓存,开服时把玩家的必要数据加载到内存中,可以减少玩家的登陆延时,应对玩家并发登陆,刷新也很有效。同时玩家数据没必要实现存库,对于坐标,经验,金钱等变化频繁的值,如果实时存在,会很容易压跨数据库或对存库进程造成消息阻塞。玩家改变的数据可以缓在内存中,定时存库,或下线时再存库。网络中的消息包也可以在应用层给缓存起来,达到一定长度或延时一定时间后再发出去。虽然虚拟机和TCP层会做缓存,最好还是在应用层做一次缓存。
4. 进程-每玩家应该有几个进程
其实每玩家一个进程已经足够,代码简单,方便维护,性能开销小。没必要为每个玩家开启了网络,物品、任务等进程,多个进程不但造成进程间通信开销,还不好维护。
5. 善用进程字典
Erlang中是不建议用进程字典的,但进程字典是数据存取最快的方式,对于游戏这种高性能要求的应用,进程字典是不二的选择。使用进程字典时要切记在对应的进程中操作,最好按功能把put,get操作封装到模块接口中,避免误用。
6. 代码规范
a. 代码应该简单,逻辑清晰,把功能细分到函数中。函数一般不多于30行,每个模块不多于1000行。
b. 写尾递归函数一定要有清淅的退出条件,不要在函数中改变退出条件。一个退出条件不明确的尾递归,是造成消息阻塞,内存耗尽的主要原因之一。
%% 一个明确的尾递归函数:
loop([H |T]) ->
do_something,
loop(T);
loop([]) ->
ok.
%% 存在错误风险的写法
%% NewLiist不可预期,存在死循环风险
loop([H | T]) ->
NewList = do_something(H,T),
loop(NewList);
loop([]) ->
ok.
c. 不要相信客户端,上行的数据都需要验证,前端的请求都要做合法性判断,防止出现外挂、刷钱刷物品、刷金币的情况。
d 不要写过多的case ,if嵌套,最好不要大于3个嵌套,通过 try catch 方法写扁平化的代码。
7. 自动化工具
自动化工具可以避免出错,还把开发人员解放出来,提高生产效率。对于重复性,有规律的代码(如数据存取,通信协议),可以分离出来,让工具自动生成。有了生成工具后,修改协议,新加字段等操作,简单方便,不用为增加数据表中一个字段,而改十多个函数接口的修改;也不用担心前后端协议不一致的问题。
8. 监控系统
通过erlang:system_monitor/2,监控系统long_gc,large_heap等情况。
9. 性能分析工具
准备好top memory,top message_queue等查看系统属性的工具,出问题时可以随时查看。
以上是关于Erlang 性能优化总结的主要内容,如果未能解决你的问题,请参考以下文章