美文网首页
看不见的“性能损耗”

看不见的“性能损耗”

作者: fooboo | 来源:发表于2018-09-21 22:42 被阅读54次

迫不及待的想记录下这一篇,虽然比较累,但今天发现的问题比较有趣。

先总结下这一周的工作,其实还是非常忙的,时间节点卡在那里,不能再延期,周日、中秋和国庆节都要加班(周六本来就加班)。

这周按照腾讯那边要求重构了下日志模块,需要过TDR1/TDR2/TDR3评审;然后关注线上报错并定位,这次由腾讯那边导了几千量测试;然后有个可能造成数据回档的严重bug已经定位并复现,登陆和切场景比较复杂,容易造成bug;准备添加弱网络模块;然后又优化了因最近新加的类似一个脏词过滤系统检查上报的功能代码,上层由我们这边写。

之前日志系统大概是每记录一条日志(同时在线四五千人的话,预估峰值每秒能产生至少十万条日志),需要做些额外的操作,因为要尝试是否滚动日志文件等,lua有些函数实现还是比较耗时的,我这里会定时tick检查是否要滚动,且缓存了当前日志文件的大小等优化。

这周看了Effective Modern C++的第一章节,类型推导,改天有时间总结下。

下面是重要内容。

因为导了少些量测试,当时没多少玩家,后来有账号登陆,导致进不了游戏,后台的认证日志返回的没问题,然后已经在游戏中的玩家没受影响,查看了网络也没问题。这些之前测试过几次,级别在五千人左右,也没出现类似的问题。后来想到,可能是最近加入的新模块影响的。

底层C++模块主要是作些上报检查功能(脏词过滤系统),由其他同事负责,代码量在四百行左右,对一些功能中的输入做检查等工作,由另一个线程负责(非skynet框架中的线程)。然后添加了debug日志,发现某个接口调用的特别频繁,后来发现是上层的定时器,每10ms检查一次,后来降低10倍为100ms检查一次,这是可以接受的,然后问题还没解决。

为什么先想到这个,因为通过lua调用C++实现的update接口,里面有mutex互斥锁。为什么会使用这种锁?如果看过之前的博客读过skynet源码,会知道它的框架是多线程的,而其实现中就只有spinlock自旋锁和原子操作,而不是互斥锁,也没有会造成睡眠的操作,除了没有消息会阻塞在epoll上。它假定工作线程会立即获取CPU执行权。然后由于其工作方式,不能立即处理消息的时候造成时间过长或者把线程切出去睡眠,否则会影响到其他服务的调度,进而造成消息的积压和可能的雪崩。

由于是多线程,且涉及到skynet的某个工作线程和新加入的线程竞争,但有多个接口有互斥锁保护临界区,原来实现类似这种:

std::vector<CInputData*> vecMaster;
void update()   //skynet thread
{
    std::vector<CInputData*> vecSlave;
    pthread_mutex_lock(&lock);
    vecMaster.swap(vecSlave);
    pthread_mutex_unlock(&lock);
    //...code
}

void input()  //thread
{
    CInputData* pdata = new (std::nothrow) CInputData(...);
    if (!pdata) //...
    pthread_mutex_lock(&lock);
    vecMaster.push_back(data);
    pthread_mutex_unlock(&lock);
    //...code
}

大致是这样的,thread把数据塞到vecMaster里,skynet工作线程定时处理。
因为vector的实现原理,在扩容时会以两倍的方式(可能有些厂商是1.5倍的样子)重新开辟内存空间,那么需要把原来的东西拷贝过去,且释放原来的内存等操作,所以看似用mutex保护起来的一条语句,可能临界区很大,执行时间过久,造成skynet工作线程获取锁时,被睡眠一会,进而造成该服务队列长期被这个睡眠的skynet工作线程占有得不到调度,进而造成这个服务的消息队列过长和占用更多的内存等一系列的严重问题,很可能严重影响玩家体验如上面那种情况。

后来做的优化是预先定义vecMaster和vecSlave,不会再程序运行中释放和可能的重新分配,且预先reserve一定的空间,这极大程度降低上面出现的情况;不再使用mutex,根据mutex的实现原理知道,当锁被其他线程占用时,lock的时候会造成该线程的睡眠,改用自旋,这里的场景也适应,因为只是简单的push指针和swap,很快的。就不会出现让skynet的工作线程切出去,除非要压入元素时,vector的size已经满了。再者,skynet工作线程只是定时更新而已,实时性并不高,上层并不需要处理数据,所以这里用try lock即可,获取不到锁就返回,更新则进入下一次。

本以为能顺利解决这个问题,可能是想多了。后来今天凌晨五点开服时,有同事说进不去游戏,但仔细询问了下一些情况,发现还不太好断定。后来老大打电话过来赶紧回公司,后来一起排查。因为进程还在,且数据库的链接是establish状态,且认证能进行(这里进行了一次db过程),也有几个同事能正常游戏。这里先查看了下这个进程打开的文件描述符,然后找到相关的socket 链接,因为是service连接db,且查看socket状态时,发现send队列有120多kb的字节未发送,然后状态是fin_wait1,表示这边发了fin包,估计在发送缓冲区中,那边当然没回ack,具体情况未知,后来基本判断是这个问题了。后来跟腾讯那边的同学反馈这个问题,由于有个代理进程,后面是分布式的,然后代理进程那边出了些问题,后来那边修复后,这个问题就完美解决。

当然我一开始想到的,可能跟解决这个问题没有多大关系,但分析的情况,确实存在,且会影响。

相关文章

  • 看不见的“性能损耗”

    迫不及待的想记录下这一篇,虽然比较累,但今天发现的问题比较有趣。 先总结下这一周的工作,其实还是非常忙的,时间节点...

  • 油介质损耗测试仪的使用要点

    全自动绝缘油介电损耗测试仪的特性和性能 用于现场抗干扰介质损耗测量或实验室精密介质损耗测量。该仪器是一个集成结构,...

  • recyclerView缓存分析

    mAttachedScrap:onlayout可能执行多次,remove add view性能损耗过大,因而在其中...

  • Java 8 Stream的性能到底如何?

    那么,Stream API的性能到底如何呢,代码整洁的背后是否意味着性能的损耗呢?本文我们对Stream API的...

  • Java注解

    利用运行时注解,然后通过Java的反射机制实现功能,所以难免会在性能上带来损耗(损耗的根源我还不特别清楚,这是我接...

  • 关于控制损耗的思考之一

    关于损耗的:个人观点,损失加消耗就是所谓的损耗。包括看见的还有看不见的,无论是损还是耗都是店铺的成本,成本就是利润...

  • 电脑性能速度秒升级,没想到NVMe M.2硬盘安装使用那么简单

    电脑用着用着,总免不了会碰上配置跟不上、性能损耗这类问题。这对电脑性能要求高的人,特别是像我生活、工作都要求高效的...

  • HTTPS性能优化

    分析性能损耗 产⽣性能消耗的两个环节: 1.第⼀个环节,TLS协议握⼿过程; 2.第⼆个环节,握⼿后的对称加密报⽂...

  • 用它,就能测出iPhone电池寿命

    市面上的锂离子电池,随着使用时间的增长,会出现不可逆的损耗,而无法再达到出厂时的良好性能。出现损耗的电池,往往达不...

  • c++性能优化(cpu篇)

    背景 1.做性能优化时,其实也是存在二八定律的,基本上80% 的性能损耗是由20%的代码引起的,而且这20%的代码...

网友评论

      本文标题:看不见的“性能损耗”

      本文链接:https://www.haomeiwen.com/subject/bymonftx.html