最近研发了公司的rtmfp服务器,参考http://blog.csdn.net/win_lin/article/details/38779151,原因是cumulus性能还是不满意。
对比的rtmfp服务器包括:
- cumulus:这个是老牌的rtmfp服务器,还不错,目前我们线上在跑。
- rtmplite:这个更老,比cumulus还老,python做的。我们主要参考它来研发我们自己的服务器。
- bravo-rtmfpd:这个是参考rtmplite,以及一些博客,rtmfp标准协议,我们自己研发的服务器,参考http://blog.csdn.net/win_lin/article/details/38779151。
先测试下其他两个服务器的性能,我们的服务器还没有经过性能优化,所以会测试多次。
工具是我们自己写的,基于st的一个工具,类似于st-load,能模拟10k并发。并且能统计出丢包率,断开率和超时次数,对于分析服务器的服务质量有极大的帮助。
另外,只测量握手和ping包。peer和peer之间打洞不测量,其实这个就是多了两个包而已,没有什么特别的性能开销。
RtmpLite性能测试
测试rtmplite的性能。启动rtmplite的命令是:
python rtmfp.py --no-rtmp
以下是性能数据:
备注:SSp,随机启动休眠时间(秒)。启动时随机休眠,模拟客户端并发。
备注:带宽kbps,内存MB,CPU为top显示的值,丢包率和断开率为百分比。
备注:时长为测试的时间(秒)。
备注:测试为lo网卡,本机127.0.0.1地址
比较有理由相信,rtmplite的并发在500左右。
Cumulus性能测试
测试cumulus性能。启动cumulus的命令是:
cd ~/git/Cumulus/CumulusServer && ./CumulusSer
以下是性能数据:
备注:SSp,随机启动休眠时间(秒)。启动时随机休眠,模拟客户端并发。
备注:带宽kbps,内存MB,CPU为top显示的值,丢包率和断开率为百分比。
备注:时长为测试的时间(秒)。
备注:测试为lo网卡,本机127.0.0.1地址
貌似cumulus是10000并发时开始出现丢包和断开,10k左右是比较合理的数据。CPU因为是ping包,所以占用不多,实际上会有很多p2p握手包,比较费cpu。
BravoRtmfpd在CC后的性能对比
对性能进行对比测试,在没有优化性能之前,先对比一下。CC即代码完成。
以下是性能数据:
备注:SSp,随机启动休眠时间(秒)。启动时随机休眠,模拟客户端并发。
备注:带宽kbps,内存MB,CPU为top显示的值,丢包率和断开率为百分比。
备注:时长为测试的时间(秒)。
备注:测试为lo网卡,本机127.0.0.1地址
可以看到我们支持20k+是没有问题的。
加解密集群性能分析
gprof测试性能,发现时间都被加解密(key计算)占用了。数据如下:
% cumulative self self total
time seconds seconds calls ms/call ms/call name
69.89 45.44 45.44 bn_sqr4x_mont
15.86 55.75 10.31 bn_mul4x_mont_gather5
具体参考http://blog.csdn.net/win_lin/article/details/38779151。
去掉加解密之后,性能数据变为:
% cumulative self self total
time seconds seconds calls s/call s/call name
14.20 2.44 2.44 heap_delete
7.76 3.77 1.33 16640538 0.00 0.00 std::less<unsigned int>::operator() const
5.86 4.77 1.01 heap_insert
可见频繁释放内存有提升的空间,map的比较less已经最优了。
结论就是几点:
1. 加解密集群那块是大头,占80%性能瓶颈。这个可以和rtmfp集群互补。
2. 频繁释放内存是小头,占10%。tcmalloc试了作用不大,可能需要自己管理内存分配,需要用缓存。
3. 可以用rtmfp集群,master管理共享数据,worker去查询。可以和加解密集群配合。
客户端模拟工具最重要,不然无法度量改进效果。
快速Cookie查找
rtmfp在rhello时服务器发送给客户端64字节的cookie,用来标识临时会话,等rikeying之后变成session_id。握手时,cumulus很老实的比较64字节,而我们实际上保证前面8字节是唯一的,也就是u_int64_t整型和64字节cookie对应。
也就是说,cumulus在收到iikeying包时,查找cookie是O(n*n)复杂度的,而我们是O(lg(n)),换句话来说,对于一个4000000个节点时,cumulus每次都要查询4000000次,而我们只需查询32次就可以找到cookie。
class Handshake : public ServerSession {
struct CompareCookies {
bool operator()(const Poco::UInt8* a,const Poco::UInt8* b) const {
return std::memcmp(a,b,COOKIE_SIZE)<0;
}
};
std::map<const Poco::UInt8*,Cookie*,CompareCookies> _cookies; // Cookie, in waiting of creation session
我们的数据结构:
class RtmfpHandshake : public IRtmfpPacketHandler
{
private:
// key: cookie fast id,
// value: the cookie object.
std::map<u_int64_t, RtmfpCookie*> cookies;