2013-09-18

构建C1000K的服务器(2) – 实现百万连接的comet服务器

Views: 53899 | 39 Comments

这是关于 C1000K 序列文章的第二篇, 在前一篇文章 构建C1000K的服务器(1) – 基础 中, 介绍了支持 C1000K 的 Linux 系统的内核参数调整和系统设置. 在本篇文章中, 将对一个真正的应用服务器做 C1000K 测试.

Comet 服务器是一类逻辑相对简单, 需要高并发连接的服务器. Comet 在网站系统中的应用非常广泛, 可以见这篇日志的介绍: http://www.ideawu.net/blog/archives/737.html.

HTTP 协议处理

要开发一个支持百万并发连接的 Comet 服务器, 我选择 C/C++ 语言, 当然还有其它的选择如 Erlang, Java 等. 对于一个只支持 long-polling Comet 服务器, 首先要具备解析 HTTP 协议的能力, 我选择 libevent 来处理 HTTP 协议.

通道和订阅者管理

服务器在启动的时候, 就预先分配了 100 万个通道对象的空间, 但订阅者对象是按需分配的, 通过内存池方式. 100 万个通道对象和程序的其它数据占用了 24MB 的内存.

Benchmark

启动 icomet 服务器:

./icomet

服务器监听了 100 个端口, 是为了测试方便, 原因见前一篇文章的分析: 构建C1000K的服务器(1) – 基础.

然后启动 benchmark 客户端:

./tools/benchmark 127.0.0.1 8100

benchmark 程序每创建十万个连接, 就会暂停, 按回车后继续. 通过 top/ps 查看 icomet 进程的内存占用. 最终, 得出如下数据.

连接数 进程VIRT 进程RES
0 39m 24m
100000 302m 288m
200000 579m 565m
500000 1441m 1427m
1000000 2734m 2720m

可以看到, 每一个 Comet 连接大约占用了 2.7KB 的内存. 此时, 服务器空闲, 进程占用 CPU 为 0%.

项目的代码在: https://github.com/ideawu/icomet, 欢迎大家试用, 并反馈你的测试数据.

Related posts:

  1. 构建C1000K的服务器(1) – 基础
  2. HTTP 长连接技术 Comet
  3. 轻量级 COMET 服务器 icomet 支持 EventSource(SSE)
  4. iComet 的一个应用场景
Posted by ideawu at 2013-09-18 22:06:31 Tags: , ,

39 Responses to "构建C1000K的服务器(2) – 实现百万连接的comet服务器"

  • server端编译完运行,10万个连接数差不多消耗2G内存,跟博主测试的差距好大 Reply
  • 我今天在实测试的时候,遇到问题,cpu占用率超高
    [root@localhost icomet]# ps aux | grep comet
    root 11196 95.4 0.0 40728 17904 ? Rs 17:23 1:51 ./comet-server comet.conf -d

    我的配置如下:
    pidfile = ./comet.pid

    logger:
    level: debug
    #output: stdout
    output: ./logs/log.txt
    rotate:
    size: 100000000000

    admin:
    #listen: 127.0.0.1:8000
    listen: 0.0.0.0:8101
    # allowed ip prefix, one ip each line
    allow: 127.0.0.1
    allow: 192.168
    #deny: all
    #allow: all
    max_channels: 100000

    front:
    listen: 0.0.0.0:8100
    # none|token
    auth: none
    max_channels: 100000
    max_subscribers_per_channel: 16
    # number of messages buffered
    channel_buffer_size: 0
    # in seconds
    channel_timeout: 30
    # in seconds
    polling_timeout: 30

    启动一会,用户就连不进来了,如果发送信息,会有漏消息的情况。 Reply
    @david: 你好, 请问你是如何测试的? 当时的 log.txt 显示有多少个 channels 和 subs? Reply
    @ideawu: 请问一下,内存使用上去了以后,为什么不会降下来?目前我32G的内容全部使用完了,comet-server使用了29G Reply
    @david: 请问你用的是哪个版本的代码? 客户端全部关闭后, 内存使用也不降下来吗? Reply
    @ideawu: 客户端一定是一部分关闭,而不是部分关闭。 Reply
    @david: 写错,是部分关闭,不是全部关闭
    @ideawu: 我使用的是0.1.0版本的,我从启动以来,就没有降低过。 Reply
    @david: 可否分享一下你的网站?
    @ideawu:好的,謝謝。我已經在線上使用了。
    @david: 你可以升级到最新的 0.2.2 版本(在主干上), 新版本会立即释放内存给回操作.
    @david: icomet 采用了内存池的内存管理方案, 不会主动释放内存. 你是在测试还是实际使用? 我考虑采用新的内存管理方案.
    @ideawu: 我按你的另一篇文章将服务器的参数加大以后,就没有占用率99%的问题了,目前正常在查看中。谢谢。 Reply
  • 请问一下,是否可以通过icomet查询哪些用户在线,哪些不在线?即不在线的有一个通知。 Reply
    @david: Hi, 你可以请求 8100 端口的 /psub 接口, 订阅通道的状态变化信息, 如创建通道(第一个订阅者连接时), 关闭通道时, 通过 endless chunk 返回. Reply
    @ideawu: 我要如何确认一个用户是否在线? Reply
    @david: 使用管理端口(8100)的 /check 接口. Reply
  • 在2个不同的服务器上尝试推送信息,发现一台必须把"\"编码成%5c 另一台却不能编码
    请问博主是设置的问题么,如何解决? Reply
  • 博主好,请问icomet有没有手册之类的?
    不知道都有哪些方法和参数; Reply
    @xmxoxo: Hi, icomet 目前还没有完备的手册和文档, 后续会补充. Reply
    @ideawu: 请问close 频道用什么方法? Reply
    @xmxoxo: curl -v “http://127.0.0.1:8100/close?cname=12″ Reply
  • # make


    cd util; make
    make[1]: Entering directory `/root/icomet-master/util’
    make[1]: Nothing to be done for `all’.
    make[1]: Leaving directory `/root/icomet-master/util’
    cd comet; make
    make[1]: Entering directory `/root/icomet-master/comet’
    g++ -o ../comet-server -g -O2 -Wall -Wno-sign-compare -D__STDC_FORMAT_MACROS -I "/root/icomet-master/deps/libevent-2.0.21-stable" -I "/root/icomet-master/deps/libevent-2.0.21-stable/include" -I "/root/icomet-master/deps/libevent-2.0.21-stable/compact" -I "/root/icomet-master/deps/jemalloc-3.4.0/include" -I ../ \
    comet-server.cpp channel.o server.o \
    ../util/*.o \
    /root/icomet-master/deps/libevent-2.0.21-stable/.libs/libevent.a \
    -lrt -pthread "/root/icomet-master/deps/jemalloc-3.4.0/lib/libjemalloc.a"
    comet-server.cpp: In function ¡®int main(int, char**)¡¯:
    comet-server.cpp:138: 警告:当转换到 ‘int'(从‘double’)时
    make[1]: Leaving directory `/root/icomet-master/comet’ Reply
    @xmxoxo: 先忽略这个警告吧. 以后的版本我再把它消除. Reply
  • icomet有没有清除某个频道消息的方法?

    在一个频道里消息很多,有没有方法可以 一次性把这些消息全部清除? Reply
    @xmxoxo: Hi, 可以的. close 那个频道即可. Reply
  • 博主好,我在测试comet服务的时候发现个问题,我在一台上部署成功,在另一台部署时出现以下现象: 服务部署成功,通过命令行测试也正常;我将WEB目录复制到另一个地方,配置成为一个WEB站点,然后登录聊天室,到这里都正常,但发送消息后,每个消息前面都在转圈,消息没发去去,另一个窗口相同频道也没收到消息,我打开浏览器跟踪发现sub和pub都是正常的。 Reply
    @xmxoxo: Hi, 你可以用浏览器调试抓包工具看一下, 例如 firefox + firebug, chrome, 看是哪个请求出现问题. Reply
    @ideawu: 登录进入聊天室,开firebug,发一个消息,看到pub.php有返回:
    jQuery19108672550765331835_1387285654444({type: "ok"});
    sub.php过一会才有返回:
    icomet_cb_0({type: "noop", cname: "public", seq: "0"});
    icomet_cb_0({type: "noop", cname: "public", seq: "1"});

    就是消息在其它聊天窗口没有出现; Reply
    @xmxoxo: 还有, 你还可以看看 icomet 的 log.txt, 反正查找问题方法很简单, 自己多琢磨琢磨就能立即发现解决. Reply
    @xmxoxo: 还有, 需要看看 pub.php 的请求url和参数是什么. Reply
    @xmxoxo: Hi, 你需要修改一下 pub.php, 修改里面的 url 改为正确的地址. Reply
  • ==================================================
    server: ubuntu12.04 4GB RAM
    /etc/sysctl.conf:
    # For connector server
    net.ipv4.tcp_rmem = 128 4096 102400
    net.ipv4.tcp_wmem = 1024 4096 102400
    ## The unit is memory page(4KB), so this means: 512M 1G 3G, for the case of 4GB RAM server
    net.ipv4.tcp_mem = 131072 262144 786432

    ## For fast connect
    ### Default: 1000
    net.core.netdev_max_backlog = 1024
    ### Default: 128
    net.core.somaxconn = 1024
    ### Default: 2048
    net.ipv4.tcp_max_syn_backlog = 2048

    ## For fast half-open connection detection
    ### Default: 75
    net.ipv4.tcp_keepalive_intvl = 30
    ### Default: 9
    net.ipv4.tcp_keepalive_probes = 3

    fs.file-max = 999999


    # for connector server’s test client
    net.ipv4.tcp_tw_reuse = 1
    net.ipv4.tcp_tw_recycle = 1
    net.ipv4.tcp_max_tw_buckets = 5000

    net.ipv4.ip_local_port_range = 1024 65535
    =========================================================
    client: ubuntu 12.04 2GB RAM
    ===========================================================
    result:
    before/after 100k connection
    free -m 170M/1132M
    icomet(RSS) 13M/190M
    =============================================================
    Any idea why the OS consume so much memory? Which type of OS are you using?
    Thanks. Reply
    @inetfuture: Hi, 你方便用这篇文章中的代码测试一下吗? 这个代码只测试内核占用的内存大小. http://www.ideawu.net/blog/archives/740.html Reply
    @ideawu:
    result:
    before/after 100k connection
    free -m 170M/460M Reply
    @ideawu: 刚放假,现在没有测试环境了,放假回来我试一下
    可以说下你用的操作系统和tcp配置参数吗? Reply
  • 操作系统占用的内存是多少呢? Reply
    @inetfuture: 约 2K 每连接. Reply

Leave a Comment