高性能服务器编程,网络库

网络编程

伪共享问题

两线程分别需要处理两个内存邻近的变量,看起来是互不干涉,但是即使两线程分别在两个不同的cpu核上执行,两个变量分别放到两个核的cacheL1的一行cache line上,mesi协议更新任意一个都会invalidate所有cpu自己的cacheL1这一行的数据,cache失效导致频繁需要从内存重新加载,性能很差。

sendfile

零拷贝技术,内核中实现了两个文件描述符的缓冲区拷贝。

mmap共享内存

splice

也是两个文件描述符直接的零拷贝,但是必须有一个是管道文件描述符。

tee

两个管道之间的零拷贝技术。

epoll,reactor和proactor

epoll:epoll_create,epoll_ctl,epoll_wait,et边缘模式只通知一次,需要循环读取缓冲区直到全部读完,lt水平模式,没读完会一直通知。在内核当中是以红黑树的方式组织监听的事件,查询开销是O(logn)。采用回调的方式检测就绪事件,时间复杂的位O(1),有一个就绪列表,直接从就绪列表读取事件就行。注意所有fd设置为非阻塞模式。

reactor:主线程负责监听文件描述符事件,有事件就通知工作线程,工作线程处理读写数据和处理。需要注意工作线程在处理的fd事件需要先关闭可读事件,等处理玩了再重新开启,否则可能会有条件竞争问题。

proactor:主线程和内核处理好数据的接收,通知应用程序数据可用,应用程序事先定义了回调函数选择一个工作线程处理这个回调。工作线程处理写入缓冲后调用aio_write函数向内核注册写完成事件,并告诉内核缓冲区位置和写完成通知应用程序的回调。

半同步/半异步模式

缺点:主线程和工作线程共享一个请求队列,都需要加锁操作,消耗cpu;每个工作线程同时只能处理一个请求,工作线程太多,线程切换也会消耗cpu。

高效解决方案:主线程只监听socket,连接由工作线程管理,连接的socket分散固定到每一个工作线程上。这样就不需要锁了。

领导者/追随者模式

工作线程轮流当领导者,有事件就指定下一个领导者然后自己处理这个事件。领导者推选新领导和追随者等待成为领导这两个操作仍然存在竞态条件,需要一个同步者来同步这两个操作。每个fd的事件可能对应多个线程处理。
在这里插入图片描述

EPOLLONESHOT

每个fd同时只会有一个线程处理,可以避免很多可能的竞态条件。

epoll循环的定时器

可以通过epoll_wait带超时参数,周期检查超时的事件。或者通过周期信号或者fd从外部定时周期发送来实现。

高性能定时器实现

时间轮:多个槽,每个槽一个链表,槽可分为不同档次,低档次走一圈高档次走一格。
最小堆:事件比较少时性能不错。

libevent分析

基于reactor实现,需要处理三种事件,I/O事件,信号,定时器。

流程

1.event_init或者event_base_new创建event_base对象。
2.创建具体的事件处理器。evsignal_new信号事件处理器,evtimer_new定时事件处理器,最终都是调用event_new。事件类型可具体分为:定时事件,可读事件,可写事件,信号事件,永久事件,边沿触发,每个事件独立一位,可位与。
3.event_add添加注册事件。
4.event_base_dispatch执行事件循环。
5.event_free释放具体事件,event_base释放事件处理器。
总体流程和libuv类似。

event_add

调用了event_add_internal,内部调用了几个重要函数:
evmap_io_add,将事件加入到epll或者其他多路分发器,将对应事件处理器加入到I/O事件队列中,建立映射关系,内部数据结构一般用哈希表。
evmap_signal_add类似,处理的是信号。
event_queue_insert加事件插入到各种事件队列中,要添加定时器直接加入不需要映射,处理定时器会将定时器插入到时间轮或最小堆实现的定时器容器中。

event_top

封装了I/O复用机制必要的操作,如注册事件,等待事件等。为event_base支持的所有后端I/O复用机制提供统一接口,默认选择epoll,windows就是iocp了。

event_base_loop

事件循环。

socketpair

libuv使用管道生成的fd来触发事件,可实现自定义事件;libevent使用socketpair实现类似的功能,信号通知要让事件处理器知道需要一个fd,信号处理函数就会向socketpair发送消息触发事件。

进程池,线程池,连接池,内存池

进程池一般需要消息队列配合,既然用到进程级别,那就可以直接考虑分布式方案了。

其他

1.跳转最大文件描述符数量
2.调整内核参数
/proc/sys/fs : file_max系统文件描述符限制。epoll/max_user_watches,所有epoll注册的事件总量。64位系统一个事件消耗160字节内存。

/proc/sys/net:core/somaxconn能够建立连接到ESTABLISHED的socket最大数量。
ipv4/tcp_max_syn_backlog指定listen监听队列能够转移至ESTABLISHED或者SYN_RCVD的socket最大数量。
ipv4/tcp_wmem指定tcp写缓冲区的最小最大默认值。
ipv4/tcp_syncookies指定是否打开tcp同步标签,可防止syn泛洪攻击。

epoll内核通知基本原理

epoll_ctl会将事件回调加入到fd对应的对象的等待队列中,当fd对应对象发生变化会执行等待队列的回调,然后回调到epoll注册的函数,接着切换到用户态执行回调。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值