【2019-11-07】twemproxy事件--by 闫昌

epoll简介:

函数:epoll_create;、epoll_ctl;、epoll_wait;

epoll_create(size);//size 低版本生效,高版本不生效

epoll 的LT模式

水平触发模式,epoll_wait的处理流程为:遍历就绪的链表,把fd的buf中有数据的fd返回给用户,并在链表中保留该节点,buf中没数据的则从链表中剔除,放回红黑树中,这么做的好处是,只要fd中海油未处理的数据,都会通过epoll_wait读取到,缺点是,每次需遍历,性能差。

epoll的EL模式
边缘触发模式,epoll_wait就非常简单,返回链表中所有的fd给用户,并情况就绪列表,放回红黑树中,等待新事件到来。好处就是性能高,缺点是,用户拿到fd后读取其数据时每次没读取完,造成事件的丢失。

twemproxy对事件的使用

twemproxy对epoll/kqueue/evport进行了统一封装,一般linux使用epoll, mac使用kqueue,Sun Solaris使用evport,为了统一底层api调用,对上面的三种事件处理api进行了接口的统一: event/nc_event.h

相关结构体

struct event_base {
     int   ep;  /* epoll descriptor */
     struct epoll_event *event; /* event[] - events that were triggered */
     int    nevent; /* # event */
     event_cb_t   cb; /* 回调函数event callback */
     };

事件处理核心api参考:

  • event_base_create()    创建事件循环管理fd
event_base_create(int nevent, event_cb_t cb)
{
   ep = epoll_create(nevent);
   event = nc_calloc(nevent, sizeof(*event));
   evb = nc_alloc(sizeof(*evb));
   evb->ep = ep;
   evb->event = event;
   evb->nevent = nevent;
   evb->cb = cb;
}
  • event_add_in()             将一个fd的读事件纳入事件管理器的管理中
event_add_in(struct event_base *evb, struct conn *c)
{
  struct epoll_event event;
  int ep = evb->ep;
  event.events = (uint32_t)(EPOLLIN | EPOLLET);//ET模式
  status = epoll_ctl(ep, EPOLL_CTL_MOD, c->sd, &event);
}
  • event_add_out()           将一个fd的读写事件纳入事件管理器的管理中
event_add_out(struct event_base *evb, struct conn *c)
{
  struct epoll_event event;
  int ep = ev->ep;
  event.events = (uint32_t)(EPOLLIN | EPOLLOUT | EPOLLET);
  status = epoll_ctl(ep, EPOLL_CTL_MOD, c->sd, &event);
}
  • event_add_conn()        将一个fd的读写事件纳入事件管理器的管理中
event_add_conn(struct event_base *evb, struct conn *c)
{
   struct epoll_event event;
   int ep = evb->ep;
   event.events = (uint32_t)(EPOLLIN | EPOLLOUT | EPOLLET);
   event.data.ptr = c;
   status = epoll_ctl(ep, EPOLL_CTL_ADD, c->sd, &event);
}
  • event_wait()                  从事件管理器中获取准备好读/写的fd列表,并调用cb进行处理
event_wait(struct event_base *evb,int timeout)//自己封装的epoll_wait
{
 struct epoll_event event;
 int nevent = evb->nevent;
 for(;;) {
   int i, nsd;
   nsd = epoll_wait(ep, event, nevent, timeout);
   for(i =0; i < nsd; i++) {
    struct epoll_event *ev = &evb->event[i];
    uint32_t events =0;
    if(ev->events & (EPOLLIN | EPOLLHUP))    {
        events |= EVENT_READ;
    }
    if(ev->events & EPOLLOUT) {
        events |= EVENT_WRITE;
    }
    if(evb->cb != NULL) {
        evb->cb(ev->data.ptr, events);//执行回调函数 cb是在 event_base_create添加 
    }
   }
  }
}

怎么用:

todo

负载均衡算法

redis协议的解析

多个redis命令在一起怎么处理,粘包问题


Nginx源码分析
研读nginx源码

一群热爱代码的人 研究Nginx PHP Redis Memcache Beanstalk 等源码 以及一群热爱前端的人

7.1k 声望
12.7k 粉丝
0 条评论
推荐阅读
【转发】来自西红柿(李乐)的《深入理解Go语言
作者:李乐 原文地址:[链接]第一章 Go语言快速入门&emsp;&emsp;第一篇 基本语法&emsp;&emsp;第二讲 数组与切片&emsp;&emsp;第三讲 字符串&emsp;&emsp;第四讲 哈希表MAP&emsp;&emsp;第五讲 结构体与接口&emsp;&em...

LNMPRG源码研究1阅读 1.1k

Redis的线程模型和事务
我原本只是想学习Redis的事务,但后来发现,Redis和传统关系型数据库的事务在ACID的表现上差异很大。而要想详细了解其中的缘由,就离不开Redis独特的单线程模型,因此本文将二者联系在一起讲解。

KerryWu6阅读 5.9k评论 2

Redis分布式锁的实现
很多新手将 分布式锁 和 分布式事务 混淆,个人理解:锁 是用于解决多程序并发争夺某一共享资源;事务 是用于保障一系列操作执行的一致性。我前面有几篇文章讲解了分布式事务,关于2PC、TCC和异步确保方案的实现...

KerryWu4阅读 6.8k评论 2

又一款内存数据库横空出世,比 Redis 更强,性能直接飙升一倍!杀疯了
KeyDB是Redis的高性能分支,专注于多线程,内存效率和高吞吐量。除了多线程之外,KeyDB还具有仅在Redis Enterprise中可用的功能,例如Active Replication,FLASH存储支持以及一些根本不可用的功能,例如直接备份...

民工哥4阅读 899评论 1

封面图
详解Redisson分布式限流的实现原理
&emsp;&emsp;我们目前在工作中遇到一个性能问题,我们有个定时任务需要处理大量的数据,为了提升吞吐量,所以部署了很多台机器,但这个任务在运行前需要从别的服务那拉取大量的数据,随着数据量的增大,如果同时...

xindoo3阅读 894

封面图
redis 学习笔记
一 搭建 {代码...} 二 数据类型,常用操作命令 {代码...} {代码...} 三 redis常用命令 {代码...} 四 Redis高级应用 {代码...} 五 PHP-REDIS使用 {代码...} 六 BitMap 教程 {代码...}

hufeng2阅读 2.2k

1.5万字总结 Redis 常见面试题&知识点
Redis 是一个基于 C 语言开发的开源数据库(BSD 许可),与传统数据库不同的是 Redis 的数据是存在内存中的(内存数据库),读写速度非常快,被广泛应用于缓存方向。并且,Redis 存储的是 KV 键值对数据。

JavaGuide3阅读 1.1k

封面图

一群热爱代码的人 研究Nginx PHP Redis Memcache Beanstalk 等源码 以及一群热爱前端的人

7.1k 声望
12.7k 粉丝
宣传栏