三、I/O模型

数据结构

[include/types/fd.h]
/* info about one given fd */
struct fdtab {
	struct {
		int (*f)(int fd);          /* read/write function */
		struct buffer *b;         /* read/write buffer */
	} cb[DIR_SIZE];
	void *owner;               /* the session (or proxy) associated with this fd */
	struct {                    /* used by pollers which support speculative polling */
		unsigned char e;        /* read and write events status. 4 bits*/
		unsigned int s1;         /* Position in spec list+1. 0=not in list. */
	} spec;
	unsigned short flags;         /* various flags precising the exact status of this fd */
	unsigned char state;          /* the state of this fd */
	unsigned char ev;            /* event seen in return of poll() : FD_POLL_* */
};

struct poller {
	void   *private;                 /* any private data for the poller */
	int REGPRM2 (*is_set)(const int fd, int dir); /* check if <fd> is being polled for dir <dir> */
	int  REGPRM2    (*set)(const int fd, int dir);    /* set   polling on <fd> for <dir> */
	int  REGPRM2    (*clr)(const int fd, int dir);       /* clear polling on <fd> for <dir> */
	int  REGPRM2 (*cond_s)(const int fd, int dir); * set   polling on <fd> for <dir> if unset */
	int  REGPRM2 (*cond_c)(const int fd, int dir); /* clear polling on <fd> for <dir> if set */
	void REGPRM1    (*rem)(const int fd);      /* remove any polling on <fd> */
	void REGPRM1    (*clo)(const int fd);      /* mark <fd> as closed */
    	void REGPRM2   (*poll)(struct poller *p, int exp);   /* the poller itself */
	int  REGPRM1   (*init)(struct poller *p);            /* poller initialization */
	void REGPRM1   (*term)(struct poller *p);            /* termination of this poller */
	int  REGPRM1   (*test)(struct poller *p);            /* pre-init check of the poller */
	int  REGPRM1   (*fork)(struct poller *p);            /* post-fork re-opening */
	const char   *name;                                  /* poller name */
	int    pref;                           /* try pollers with higher preference first */
};

[src/fd.c]
struct fdtab *fdtab = NULL;     /* array of all the file descriptors */
struct fdinfo *fdinfo = NULL;   /* less-often used infos for file descriptors */
int maxfd;                      /* # of the highest fd + 1 */
int totalconn;                  /* total # of terminated sessions */
int actconn;                    /* # of active sessions */

struct poller pollers[MAX_POLLERS];
struct poller cur_poller;
int nbpollers = 0;

在看到fdtabpoller的结构体时,然后查看ev_epoll.c的时候可能会奇怪为什么会设置成这样。但是如果先查看ev_sepoll.c的话可能很多疑惑都没有了。

sepoll

Haproxy中,作者在epoll上将模型推进至sepoll(我不知道是否在此之前就有人提出或者使用这种方法),从理论上来说,这种模型的总体效率应该比epoll更好,虽然说它是基于epoll的,因为它能够减少较多与epoll相关的昂贵的系统调用。

sepoll,作者在代码注释中称为speculative I/O。Sepoll的原理就是,对于刚accept完的套接字描述符,一般都是直接能够读取导数据的;对于connect完的描述符,一般都是可写的;即使是对于在传输数据的链接,它也是能提升效率的,因为假设对于某一条链接的某端已经处于epoll的等待队列中,那么另一端也是需要做出反应的,要么发送数据,要么接收数据,这依赖于(读/写)缓冲区的水位。

当然,作者也描述了sepoll的缺点,那就是这可能会导致在epoll队列中的可用事件缺少而变得饥饿(starve the polled events)(我对此处饥饿的理解是,有足够资源的时候不给予需要的人;poll本来就是用于处理多个描述符专用,假设只处理几个描述符,那么poll根本就提升不了多少性能,因为它本身也是系统调用,因此需要保持poll队列含有一定数量的fd,否则就是出现饥饿情况),作者说实验证明,当epoll队列出现饥饿的情况时,压力会转到spec I/O上面,此时由于每次去读取或者写入,但是都失败,陷入恶性循环,会严重的降低系统性能(spec list描述符较多,一直轮询肯定会导致性能问题)。用于解决此问题的方法,可以通过减少epoll一次处理的事件来解决这个问题(对spec list的不能使用这个方法,因为实验显示,spec list中2/3的fd是新的,只有1/3的fd是老的)。作者说这是基于以下两点事实,第一,对于位于spec listfd,不能也将它们注册在epoll中等待;第二是,即使在系统压力非常大的时候,我们基本上也不会同时对同一个fd进行读

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值