游戏终于上线啦,加班结束,来总结一下前一段时间的所学吧。先从上线前的压力测试说起。
1 网络相关优化
1.1 背景
单位的网络库使用的时候,网络和逻辑处理是两个线程。
网络线程负责:接收数据, 解析出protobuf结构,放入网络队列。
逻辑线程负责:从网络队列取出protobuf,处理。
1.2 思考:网络线程是否有意义?
如果网络线程处理完直接处理,其实也是可以的。但是分离网络线程会避免当逻辑线程处理过慢,导致socket接收缓冲区满了,客户端发送数据失败。不过逻辑线程处理太慢也会导致客户端发出请求没有回应。
1.3 优化:逻辑线程,每次处理网络队列的数量应该有个上限
逻辑线程的主循环伪代码如下:
while(1)
{
// 处理网络队列里的请求
while(!pack.empty())
{
Msg *p = pack.pop();
process(p);
}
// 一些其他的循环,例如发送ping包,每隔5分钟发送体力,libevent库的循环。。。
check_ping();
check_present_energy();
}
压力测试时,因为逻辑线程处理的速度比网络线程慢,所以逻辑线程会一直卡在处理网路请求的循环中,因为pack永远不为空,修改方案是在while循环的条件加上一个每次处理包的个数上限,这样其他循环也会有机会执行。
发现这个问题是因为测试时,服务器的状态数据是用libevent库写的一个http接口获取的,但是测试时发现调用这个接口一直超时,后来发现时因为libevent的循环一直没有执行。
2 mysql数据库相关优化
每个玩家在数据库的角色表是一行数据,每次玩家下线时的保存数据的sql语句是这个样子的:
updata role_table set val1=xxx,val2=xxx,val3=xxx ….. where roleid=yyy;
会更新所有字段无论是否有修改,有时玩家仅仅修改了几个字段却需要更新几十个字段。
然后做了优化,把玩家的信息在上线时保存了一个备份,下线保存时会比较只把修改的字段拼到update语句中,因为使用的protobuf支持反射,所以可以写一个通用接口,不必担心字段变化。
3 redis相关优化
游戏中使用了redis存储了一些数据,因为用的时redis的同步api,每次使用相当于向redis server发送一个请求,然后“原地”等候redis的返回,这里开销还是很大的。
优化时时采取了redis支持的lua脚本,将一些简单逻辑让redis server来执行,来减少和redis server的网路交互次数。