某些产品是面向全球用户的, 所以会在全球多个机房部署业务进程(Service)和数据库(Database). 这带来了所谓的数据一致性问题. 以用户加好友功能作为例子:
用户 A 在中, 在 App 中向用户 B 发送了好友申请. 用户 B 在美国, 打开 App 刷新, 没有看到有任何未处理的好友申请…
这是一个非常典型的例子. 我们仔细分析一下问题出在哪.
Continue reading »
某些产品是面向全球用户的, 所以会在全球多个机房部署业务进程(Service)和数据库(Database). 这带来了所谓的数据一致性问题. 以用户加好友功能作为例子:
用户 A 在中, 在 App 中向用户 B 发送了好友申请. 用户 B 在美国, 打开 App 刷新, 没有看到有任何未处理的好友申请…
这是一个非常典型的例子. 我们仔细分析一下问题出在哪.
Continue reading »
做一下记录。
做了一个可靠传输层,优点是层次分明,缺点是当丢包时价格更新不及时。可以优化成只重传不排序,Aggregator 区分是否是最新包,不是最新包则不更新最新价。
对外提供推和拉接口,两种都有适用场景,不能只提供一种。Query Server 采用 HTTP 协议,Push Server 可以用 WebSocket 协议。
把图改成 stack 形式。
这个版本主要是修复了内存泄露的 BUG, 让 icomet 的内存占用更少了,
在之前这篇博客里介绍. 对于一个 1 万并发连接的应用, 只需要占用不到 20M 的内存.
支持百万并发连接的 comet 推送服务器 icomet 刚刚修复了一个内存泄露的 bug, 这个 bug 是因为不正确地使用 libevent 导致的, 无法用 valgrind 等工具检查出来.
这个 bug 的原因是这样的, 当客户端请求到来时, 服务器端调用了
evhttp_send_reply_start();
表示开始向客户端推送数据(使用 HTTP chunked), 最后当 long-polling 结束时, 应该调用
evhttp_send_reply_end();
来关闭连接, 释放 libevent 的内存. 不过, 如果客户端提前终止了请求, 会导致什么呢? 会导致连接关闭的回调函数 evhttp_connection_set_closecb() 被调用, 但是, 在这个回调函数里, 我没有调用 evhttp_send_reply_end()
, 所以导致了内存泄露.
在使用 libevent 的过程中, 发现 libevent 的坑确实不少, 而且它的文档根本没有对类似的地方做特别说明, 没有说明哪些函数必须配对使用, 如何释放内存等.
iComet 是我做的另一个开源项目, 已经有不少朋友将 iComet 应用到了 Web IM, 移动 App 等应用的线上生产环境, 前几天还有一位朋友帮忙开发并开源了 iComet 的 Java/Android SDK.
最近在做一个手机端 App 与桌面 PC 程序联动的项目, 简单来说, 这个软件就是要在手机上进行操作, 并立即根据操作的结果更新 PC 上的程序的响应. 例如在手机上点击了一个按钮, 就要在 PC 上自动打开某个窗口. 其中一个重要的步骤便是从服务器下发指令给 PC 上的应用程序.
IO 多路复用技术, 就是常说的 select/epoll/kqueue 等处理文件描述符相关的函数. 在高性能高并发网络服务器的实现时, IO 多路复用技术可以用来处理多个 socket 连接的读写 IO 操作, 避免了传统的每一个 socket 连接分配一个单独的线程的低效的多线程技术.
虽然多线程在处理高并发网络 IO 方面是低效的, 但是, 多线程在处理业务相关的逻辑方面是有优势的, 而且多线程能利用多核 CPU.
所以, 一个高性能高并发的网络服务器, 应该是结合了 IO 多路复用技术和多线程技术的.
IO 多路复用技术用于处理网络 IO, 而多线程用于处理业务逻辑. 那么, 这两种技术是如何结合的呢?
整个服务器的流程是这样的: IO 多路复用接口层从客户端 socket 中读取了完整的请求报文之后, 便将请求报文转交给线程池, 线程处理完业务逻辑, 生成响应报文, 转交给 IO 多路复用接口层, 发送给客户端. 示意图如下:
bytes packet Client ------- IO Multiplexing Layer -------- Thread Pool
这样, 一个重要的问题就来了. 线程池和 IO 多路复用层之间的交互是报文(其实就是内存操作), 但是, IO 多路复用层只能处理文件描述符, 也就是 read()/write() 系统调用. 因此, 两者的交互必须从报文传递转换成文件描述符的操作. 所以, 我们需要一个可以 select/epoll/kqueue 的队列.
为此, 我用管道(pipe)封装了一个 SelectableQueue 类, 可以和 IO 多路复用层无缝结合. 这个技术已经在 SSDB 数据库服务器中使用了, 感兴趣的朋友可以获取 SSDB 的源码看看.
唯一的不足是, 管道通信在 10us 左右的延时, 所以会影响单个请求的处理时间, 但是, 对于高并发的网络服务器来说, 单个请求的处理时间的微小增加, 并不会对整个服务器的吞吐量有明显影响, 所以整个服务器的处理能力仍然非常高.