探索skynet(五):随笔


最近准备在组内做一个有关skynet的分享,所以对skynet产生了一些“形而上”的思考。这篇文章将不涉及具体的代码细节,就是就着skynet这个框架“扯扯淡”,随便写写。

skynet的核心是什么

skynet从Erlang借鉴而来,主要借鉴它的Actor模型,用以充分利用多核实现并行计算。所以skynet可以说是一个C语言+lua语言实现的Actor模型框架。

skynet中的每一个Actor,原则上,都是一个so库。每个Actor,对应于一个自己的消息队列。所有消息队列又串成了一个消息队列的大队列。多个工作线程,不断的从大队列中拿出消息队列,取出消息,找到对应的Actor(也就是so库),将消息扔给so库去处理。从这个角度来说,Actor(so库),不过是一个消息处理器

如何做好一次优化与重构


上周周版本更新后的三天,我基本上都在不断的做hotfix,原因是之前我对一个跨服战场老系统里的部分代码逻辑进行重构和优化,本意是可以大幅降低服务器的单点负载,均衡服务器压力;但是不成想却引出几个比较难追查的问题。到昨天新的周版本上线,目前这一波阵痛期才算已经过去。

首先是自我检讨的部分

对运行了好几年的代码进行重构,很大的风险在于不能彻底理解这段代码的主人当时的想法:他为什么要这么做?这段看似“愚蠢”的代码,是不是在避开什么陷阱?尤其是在这个程序员已经离开项目组的时候。对于这次优化,我想当然的以为,当时是因为底层没有提供相关的支持(确实没有),所以才遗留下这样一段低效的逻辑。所以当我给底层架构添加上相关支持以后,就大刀阔斧的直接进行改动了。其实,这段代码还隐含的避免了其他问题,这个问题在这次的风波中也是爆发的最集中的一个。

解忧杂货店


搬家之后,上下班花在地铁上的时间,单程就从10分钟大涨至45分钟,正好适合读书。三四天的时间,差不多正好每天一两个小节,一直想读而没时间读的《解忧杂货店》,就在哐啷哐啷的轨道声中读完了。

给shell脚本加锁


在内部测试服务器上,有一个shell脚本用于将csv数据表格转换成Python数据文件。在执行过程中的某一步,由于需要对一些文件进行写操作,所以如果同时有两个人运行了导表程序,则第二个人运行到此步骤时,就会失败并退出,这既拖慢了第一个人的导表速度,而且对第二人的体验也不好(运行了五分钟然后告诉我失败了?黑人问号……)。所以我就想给这个shell脚本加个锁,保证同一时刻只能有一个实例在运行,并及早给出其他用户提示信息。

如何估算一个Python对象的内存占用


需求

最近接到一个需求:制作一个工具,可以即时查看线上服务器的内存使用状况,不要求精确,但是如果存在爆内存的情况,要能查到有嫌疑的Entity是哪个。

pytracemalloc神器无用武之地

在网上一番搜索,对GuppyPySizerpytracemalloc进行比较之后,貌似大家对pytracemalloc的评价较好。按照官方文档,需要对Python2.7.8源码打个patch,虽然我们项目使用的是2.7.11,不过也问题不大,打Patch时obmalloc.c里面有2个reject,手动将其merge到源码中即可。编译通过,写个小程序进行实现,可行,而且可以定位到源代码的行号,确实神器。于是将情况报告给领导,正以为将大功告成之时,领导说,tracemalloc这个库我们已经集成到引擎中,但是对服务器性能有影响,所以一般就在测试环境用用,不满足即时查看线上服务器内存使用状况的要求。根据我了解的情况,确实有这样的问题,pytracemalloc其实是修改了Python虚拟机分配内存时的代码,所以:

踩坑记——覆写Python中的__cmp__


最近做一个简单的排行榜功能时,不小心踩到一个Python语言上的坑,花费掉我不少时间才找出具体原因,值得记录一下。


具体功能需求是这样的,制作一个500人的积分排行榜(TOP 500),每个人的积分只增不减,分数相同时比较上榜的时间戳,先达到积分的用户排名靠前。

这种排行榜之前已经做过无数个,一般的,会先抽象出一个TopItem对象,保存用户的积分,以及姓名、UUID等相关信息。然后用一个list对象tops保存有序的500元素,并用一个dict对象cache保存一个uuid到TopItem的映射。由于Python对象的引用特性,多增加一个dict对象,并没有增加TopItem对象的副本,而是均指向同一个TopItem对象,所以内存方面也不会有什么太大的问题。

2017年上半年书单


非技术类

  • 长恨歌 王安忆
    • 一部上海百年画卷,从细节纹理描绘城市的巨变。王琦瑶的一生,和我们大多数人一样,有高光,但大部分时间是平淡和挣扎,个人的努力最终还是要屈服于历史的进程O-O

日本之行感悟


上周参加公司的旅行福利,去了一趟日本,主要行程是大阪-奈良-京都-东京。这是我第二次去日本了,上一次是去参加Tokyo Game Show(TGS),主要是在东京都内,而且自己活动的时间比较少。这次纯粹是旅行,看的更多,体会也更深一些。

探索skynet(四):服务之间的通信


《探索skynet(三):消息队列》中已经提到,skynet中每个服务都有自己的地址和消息队列。有了这个基础,理解服务之间的消息通信,就比较简单了。

skynet.call

以最常用到的skynet.call为例,它通过调用skynet.core.send(也即,lua-skynet.c中的lsend函数)–> skynet_send函数 –> skynet_context_push函数,向目标服务的消息队列中插入了一条消息。

Python内存管理模块的一个奇技淫巧


最近在读Python源码中有关内存管理的部分。Python在分配小块内存(小于256字节)时,采用了内存池,以降低对内核内存分配程序的调用频次。在内存池的设计上,采用了一个分层的设计,由上到下依次是arena、pool、block。这次我看到的这个比较费解的结构,就来自于分配内存时,对于pool的处理。