Linux高性能服务器处理框架

发布时间:2022-08-09 23:00:03 作者:樵子 阅读量:4600

终于开始学习epoll了,虽然不明白的地方还是很多,但从理论到实践,相信自己动手去写一个具体的框架后,一切会清晰很多。

  终于开始学习epoll了,虽然不明白的地方还是很多,但从理论到实践,相信自己动手去写一个具体的框架后,一切会清晰很多。

  1、首先需要一个内存池,目的在于:

  ·减少频繁的分配和释放,提高性能的同时,还能避免内存碎片的问题;

  ·能够存储变长的数据,不要很傻瓜地只能预分配一个最大长度;

  ·基于SLAB算法实现内存池是一个好的思路:分配不同大小的多个块,请求时返回大于请求长度的最小块即可,对于容器而言,处理固定块的分配和回收,相当容易实现。当然,还要记得需要设计成线程安全的,自旋锁比较好,使用读写自旋锁就更好了。

  ·分配内容的增长管理是一个问题,比如第一次需要1KB空间,随着数据源源不断的写入,第二次就需要4KB空间了。扩充空间容易实现,可是扩充的时候必然 涉及数据拷贝。甚至,扩充的需求很大,上百兆的数据,这样就不好办了。暂时没更好的想法,可以像STL一样,指数级增长的分配策略,拷贝数据虽不可避免, 但是起码重分配的几率越来越小了。

  ·上面提到的,如果是上百兆的数据扩展需要,采用内存映射文件来管理是一个好的办法:映射文件后,虽然占了很大的虚拟内存,但是物理内存仅在写入的时候才会被分配,加上madvice()来加上顺序写的优化建议后,物理内存的消耗也会变小。

  ·用string或者vector去管理内存并不明智,虽然很简单,但服务器软件开发中不适合使用STL,特别是对稳定性和性能要求很高的情况下。

  2、第二个需要考虑的是对象池,与内存池类似:

  ·减少对象的分配和释放。其实C++对象也就是struct,把构造和析构脱离出来手动初始化和清理,保持对同一个缓冲区的循环利用,也就不难了。

  ·可以设计为一个对象池只能存放一种对象,则对象池的实现实际就是固定内存块的池化管理,非常简单。毕竟,对象的数量非常有限。

  3、第三个需要的是队列:

  ·如果可以预料到极限的处理能力,采用固定大小的环形队列来作为缓冲区是比较不错的。一个生产者一个消费者是常见的应用场景,环形队列有其经典的“锁无关”算法,在一个线程读一个线程写的场景下,实现简单,性能还高,还不涉及资源的分配和释放。好啊,实在是好!

  ·涉及多个生产者消费者的时候,tbb::concurent_queue是不错的选择,线程安全,并发性也好,就是不知道资源的分配释放是否也管理得足够好。

  4、第四个需要的是映射表,或者说hash表:

  ·因为epoll是事件触发的,而一系列的流程可能是分散在多个事件中的,因此,必须保留下中间状态,使得下一个事件触发的时候,能够接着上次处理的位置继续处理。要简单的话,STL的hash_map还行,不过得自己处理锁的问题,多线程环境下使用起来很麻烦。

  ·多线程环境下的hash表,最好的还是tbb::concurent_hash_map。

  5、核心的线程是事件线程:

  ·事件线程是调用epoll_wait()等待事件的线程。例子代码里面,一个线程干了所有的事情,而需要开发一个高性能的服务器的时候,事件线程应该专注于事件本身的处理,将触发事件的socket句柄放到对应的处理队列中去,由具体的处理线程负责具体的工作。

  6、accept()单独一个线程:

  ·服务端的socket句柄(就是调用bind()和listen()的这个)最好在单独的一个线程里面做accept(),阻塞还是非阻塞都无所谓,相比整个服务器的通讯,用户接入的动作只是很小一部分。而且,accept()不放在事件线程的循环里面,减少了判断。

  7、接收线程单独一个:

  ·接收线程从发生EPOLLIN事件的队列中取出socket句柄,然后在这个句柄上调用recv接收数据,直到缓冲区没有数据为止。接收到的数据写入以socket为键的hash表中,hash表中有一个自增长的缓冲区,保存了客户端发过来的数据。

  ·这样的处理方式适合于客户端发来的数据很小的应用,比如HTTP服务器之类;假设是文件上传的服务器,则接受线程会一直处理某个连接的海量数据,其他客户端的数据处理产生了饥饿。所以,如果是文件上传服务器一类的场景,就不能这样设计。

  8、发送线程单独一个:

  ·发送线程从发送队列获取需要发送数据的SOCKET句柄,在这些句柄上调用send()将数据发到客户端。队列中指保存了SOCKET句柄,具体的信息 还需要通过socket句柄在hash表中查找,定位到具体的对象。如同上面所讲,客户端信息的对象不但有一个变长的接收数据缓冲区,还有一个变长的发送 数据缓冲区。具体的工作线程发送数据的时候并不直接调用send()函数,而是将数据写到发送数据缓冲区,然后把SOCKET句柄放到发送线程队列。

  ·SOCKET句柄放到发送线程队列的另一种情况是:事件线程中发生了EPOLLOUT事件,说明TCP的发送缓冲区又有了可用的空间,这个时候可以把SOCKET句柄放到发送线程队列,一边触发send()的调用;

  ·需要注意的是:发送线程发送大量数据的时候,当频繁调用send()直到TCP的发送缓冲区满后,便无法再发送了。这个时候如果循环等待,则其他用户的 发送工作受到影响;如果不继续发送,则EPOLL的ET模式可能不会再产生事件。解决这个问题的办法是在发送线程内再建立队列,或者在用户信息对象上设置 标志,等到线程空闲的时候,再去继续发送这些未发送完成的数据。

  9、需要一个定时器线程:

  ·一位将epoll使用的高手说道:“单纯靠epoll来管理描述符不泄露几乎是不可能的。完全解决方案很简单,就是对每个fd设置超时时间,如果超过timeout的时间,这个fd没有活跃过,就close掉”。

  ·所以,定时器线程定期轮训整个hash表,检查socket是否在规定的时间内未活动。未活动的SOCKET认为是超时,然后服务器主动关闭句柄,回收资源。

  10、多个工作线程:

  ·工作线程由接收线程去触发:每次接收线程收到数据后,将有数据的SOCKET句柄放入一个工作队列中;工作线程再从工作队列获取SOCKET句柄,查询hash表,定位到用户信息对象,处理业务逻辑。

  ·工作线程如果需要发送数据,先把数据写入用户信息对象的发送缓冲区,然后把SOCKET句柄放到发送线程队列中去。

  ·对于任务队列,接收线程是生产者,多个工作线程是消费者;对于发送线程队列,多个工作线程是生产者,发送线程是消费者。在这里需要注意锁的问题,如果采用tbb::concurrent_queue,会轻松很多。

  11、仅仅只用scoket句柄作为hash表的键,并不够:

  ·假设这样一种情况:事件线程刚把某SOCKET因发生EPOLLIN事件放入了接收队列,可是随即客户端异常断开了,事件线程又因为EPOLLERR事 件删除了hash表中的这一项。假设接收队列很长,发生异常的SOCKET还在队列中,等到接收线程处理到这个SOCKET的时候,并不能通过 SOCKET句柄索引到hash表中的对象。

  ·索引不到的情况也好处理,难点就在于,这个SOCKET句柄立即被另一个客户端使用了,接入线程为这个SCOKET建立了hash表中的某个对象。此时,句柄相同的两个SOCKET,其实已经是不同的两个客户端了。极端情况下,这种情况是可能发生的。

  ·解决的办法是,使用socket fd + sequence为hash表的键,sequence由接入线程在每次accept()后将一个整型值累加而得到。这样,就算SOCKET句柄被重用,也不会发生问题了。

  12、监控,需要考虑:

  ·框架中最容易出问题的是工作线程:工作线程的处理速度太慢,就会使得各个队列暴涨,最终导致服务器崩溃。因此必须要限制每个队列允许的最大大小,且需要监视每个工作线程的处理时间,超过这个时间就应该采用某个办法结束掉工作线程。

  

***本网站图片,文字之类版权申明,因为网站可以由注册用户自行上传图片或文字,本网站无法鉴别所上传图片或文字的知识版权,如果侵犯,请及时通知我们,本网站将在第一时间及时删除。

我要评论

网友评论


评论时间:2023-01-14 00:30:02

nas服务器安装教程 5、如果没有网络连接,则可以选择不启动电服务器租用价格贵吗 脑或者关机等待计算机开机


评论时间:2022-10-17 14:30:01

最后再按下鼠标左键选择“确定”选项即可完成对服务器的安装与配置竹云主机跑路 工作戴尔服务器安装 对服务器的安装与配置工作


评论时间:2022-10-04 10:30:03

因为在过去的十几年中,随着互联网技术的飞速发展服务器导轨如何拆下来 和应用范围的不断拓展,人们对计算机性能要求也越来越高,而传电脑上的虚拟主机在哪 不断拓展,人们对计算机性能要求也越来越高,而传统的集中式架构已经无法满足需求了,于是出现了以分布式计算为基础的新型IT系统——云计算

最新文章

 2023-04-21 20:28:29   admin

活动发布区版规

 2023-04-11 19:07:00   沐浴阳光

2020年Kubernetes即...

 2023-04-11 18:35:03   门吉木易

云计算:为什么金融市场的未来在云...

 2023-04-11 16:01:08   兵棕

为什么AIOps工具最终可以为云...

热门阅读

 2022-02-26 05:23:03   冷雨点枫

DNS服务器配置之添加正向查找区...

 2022-02-11 05:23:03   chense

Windows下Apache安装

 2022-07-27 18:23:02   sy_901

微软开发ARM版WindowsS...

 2021-08-09 01:35:43   瑟琳娜

企业网站建设根本是向客户营销运营...

 2021-10-26 05:30:02   jiess

跑分订单匹配互助抢单系统开发

随机文章

 2021-08-18 05:30:03   xxm830

纵观整个营销网站建设

 2021-08-25 05:30:02   shinosuke

知己知彼,掌握网站现状 营销建站...

 2022-01-22 05:30:04   9999999999999

如何让备份服务器的性能达到最佳?

 2022-02-05 05:30:04   zerokong

Linux下基于PAM机制的US...

 2022-02-07 05:30:04   yangjun520

Nginx服务器配置优化

 2022-03-09 05:23:03   sakot

JBoss Web应用程序配置

热评文章

 2022-02-19 05:23:03   ghh

根域名服务器配置

 2022-07-31 06:23:02   randywong

浪潮服务器“全面接盘”IBM中国...

 2021-11-01 05:30:02   fdfjdlkfjslkj

全球看点系统APP模式开发

 2022-07-19 06:46:01   yuhaonan

服务器CPU市场上的“斗士”

  热门标签

小快云 - 更小更快-打造便捷的企业快网站
Catfish(鲶鱼) Blog V 4.7.3