- 博客(197)
- 资源 (1)
- 收藏
- 关注
原创 流式计算-low watermark机制
前言最近在学习流式计算相关的知识,在阅读了MillWheel论文以及DStream相关实现后,在这里对low watermark机制做一个总结与介绍。Window实时数据流是永不停歇的,我们无法获取所有的数据并产出一个最终的结果。很多情况下我们更关心的是最近的状态,而不是从实时数据流启动至今的统计数据。因此需要将数据流切分为一个个片段,这些片段形象的称为Window。总而言之,Wi...
2018-06-24 20:54:27 4577
原创 nginx源码阅读(十五).事件模块小结(从解析配置到事件的处理)
前言配置项结构体的创建及赋值初始化工作处理事件小结前言本小节主要是整理一下前几节分析的nginx的核心模块的ngx_events_module以及事件模块,关于事件模块什么时候初始化以及事件的处理等,因此不会涉及到太多具体的代码,主要是把握事件模块的整体。配置项结构体的创建及赋值在使用一个模块的功能之前,我们需要先根据配置文件来定制该模块的功能,对于事件模块来说,有选取哪种事件模型,以及单
2017-11-13 09:10:23 940
原创 nginx源码阅读(十四).惊群问题的解决
前言accept导致的惊群问题epoll导致的惊群问题多个进程共用一个epfd多个进程有自己的epfd小结前言本小节将看到nginx中解决惊群现象的方法。所谓惊群现象,简单的来说就是当多个进程或线程在同时阻塞等待同一个事件时,如果该事件发生,会唤醒在等待的所有的进程/线程,但最终只可能有一个进程/线程对该事件进行处理,其他进程/线程会在失败后重新休眠,唤醒多个进程/线程这种不必要的行为会造
2017-11-11 22:31:41 2420 1
原创 nginx源码阅读(十三).新建连接并处理就绪事件
前言如何建立新连接建立新连接的回调函数处理事件小结前言本小节主要讨论事件模块中如何接受新连接,其中涉及到了惊群以及负载均衡的处理。如何建立新连接之前在分析ngx_event_process_init函数时,将所有空闲连接形成链表之后,它会遍历所有监听端口并将其读事件的回调函数设置为ngx_event_accept接着会把监听连接的读事件添加到ngx_epoll_module模块中。当执行ng
2017-11-09 22:12:01 1003
原创 nginx源码阅读(十二).定时器及超时事件的管理
前言时间缓存缓存时间的精度定时器的实现小结前言本小节将分析nginx定时器以及时间管理部分的知识,当事件超时时,会触发nginx中的超时机制进行处理。nginx的定时器的底层实现是使用的红黑树,这里就不去讲解红黑树了,网上有很多资料。时间缓存nginx为了性能方面的考虑,并不是每次需要获取时间时都调用gettimeofday函数,而是将时间缓存下来存在全局变量中(core/ngx_times
2017-11-08 16:15:25 1474
原创 nginx源码阅读(十一).ngx_epoll_module模块(上)
前言模块的通用接口感兴趣的配置项存储配置项的结构体事件模块的通用接口小结前言事件模块中有封装了多种I/O多路复用机制的模块,这里只分析epoll对应的ngx_epoll_module模块,如果你对其他的感兴趣,可以参照本小节分析的源码及步骤,因为其他驱动模块的实现与ngx_epoll_module都是大同小异的。 首先我们还是从通用接口ngx_module_t下手。模块的通用接口ngx
2017-11-07 21:55:57 1088
原创 nginx源码阅读(十).ngx_event_core_module模块
前言所有模块的通用接口ngx_module_t感兴趣的配置项ngx_event_core_commands存储配置项的结构体ngx_event_conf_t事件模块的通用性接口ngx_event_module_t小结前言本小节将进入到ngx_event_core_module模块,它是所有事件模块中排第一位的模块,因为要负责创建连接池,还要选择I/O多路复用机制等工作。接下来我们就来看看它
2017-11-06 21:31:45 1188
原创 nginx源码阅读(九).事件及连接的定义、连接池
前言事件的定义连接的定义关于连接池小结前言本小节将分析事件模块中事件的定义以及连接池等相关定义,方便我们后面对事件模块中的模块进行分析。事件的定义每个事件由ngx_event_s表示:struct ngx_event_s { /* 跟事件相关的对象。通常指向ngx_connection_t连接 * 当开启了文件异步I/O之后,它可能会指向ngx_event_aio_t结构体
2017-11-06 08:52:47 1160
原创 nginx源码阅读(八).ngx_events_module模块
前言在上一小节中我们对模块的整体有了一定的把握,本小节将进入到事件模块的分析中,了解nginx是如何收集、管理、分发事件的。nginx将网络事件以及定时事件集成到一起进行管理,由于各平台的I/O多路复用机制不同,但是nginx支持多个操作系统,因此在事件模块中也实现了多种针对不同平台下封装I/O多路复用机制的模块。由于我所用的环境主要关注的是linux,因此后面主要分析ngx_epoll_modul
2017-11-04 22:01:25 1068
原创 nginx源码阅读(七).nginx的模块化设计
前言高度模块化是nginx的一个特点,在正式进入到具体的模块之前,有必要从整体把握各模块之间联系与nginx对模块的控制。在前面的分析中其实已经使用了模块中提供的方法,比如worker进程的工作循环中调用的ngx_process_events_and_timers()函数,用于处理事件。模块之间的联系官方提供了5个类型的模块:核心模块、配置模块、事件模块、http模块、mail模块
2017-11-03 21:43:53 1345
原创 nginx源码阅读(六).内存池
前言本小节中,我们将看到内存池的实现。由于nginx是由c语言实现,并没有垃圾回收机制,比较容易导致memory leak,因此nginx实现了自己的内存池,将内存的管理和释放交给内存池,而需要申请内存的地方直接使用内存池来申请内存即可,每个连接/请求都会新建一个内存池。既然释放内存是由内存池来释放,那么何时释放也是一个问题,nginx中的做法是在内存池销毁的时候也将内存释放了,这样可行是因为ngi
2017-11-02 22:05:21 1047
原创 nginx源码阅读(五).worker进程的工作循环
前言在上一小节中,我们看到了nginx是如何使用master进程创建子进程,以及存储子进程的状态,也知道了进程间通信采用的是socketpair机制。接下来我们将重点分析ngx_spawn_process调用的proc函数,即worker进程的工作循环。ngx_worker_process_cycleproc是一个函数指针,worker进程对应的是ngx_worker_process_cycle函数
2017-11-01 21:27:43 1056
原创 nginx源码阅读(四).创建子进程(worker和cache)
前言在上一小节中,我们主要分析了master进程的工作循环。本小结中,我们将看到nginx是如何创建worker进程的。在上一小节中分析master进程的工作循环时,调用了ngx_start_worker_processes函数,但是其内部调用的创建子进程的代码在ngx_spawn_process中。ngx_spawn_process创建进程自然想到的就是调用fork函数。ngx_
2017-10-31 19:50:31 1790 2
原创 nginx源码阅读(三).master进程的工作循环
前言在上一个小节中,我们分析了一下nginx的初始化工作,在最后部分nginx进入多进程工作模式/单进程模式。单进程模式一般用于调试,实用性不高。本小节将分析master和worker进程所做的一些工作,比如master如何控制worker进程以及worker进程执行的流程。首先需要知道nginx由一个master进程管理多个worker进程,worker进程负责处理请求,而master负责做管理工
2017-10-30 21:59:46 1512
原创 nginx源码阅读(二).初始化:main函数及ngx_init_cycle函数
前言在分析源码时,我们可以先把握主干,然后其他部分再挨个分析就行了。接下来我们先看看nginx的main函数干了些什么。main函数这里先介绍一些下面会遇到的变量类型:ngx_int_t: typedef intptr_t ngx_int_t; 64位机器上,intptr_t为long int, 即typedef long int intptr_t;在32位机器上,intptr_t为int,即t
2017-10-29 21:45:49 1980
原创 nginx源码阅读(一).综述
前言nginx作为一款开源的轻量级高性能web服务器,是非常值得立志从事服务端开发方向的人学习的。现今nginx的最新版本是nginx-1.13.6,代码量也日渐庞大,但是由于其核心思想并没改变,为了降低阅读难度,我选择的是nginx-1.0.15版本,并且由于时间和水平有限,重点关注的是nginx的启动以及进程模型、事件模块中的epoll模块、负载均衡以及整体的框架等方面。 这里先推荐两本
2017-10-28 09:33:43 11081
原创 (零)阅读源码的工具及参考资料
工具分析源码,首先对工具的准备很重要,在windows有阅读源码的利器source insight,但是由于我的日常系统是centos,并且不想在虚拟机下进行分析,所以找了一些linux阅读源码的工具。 我使用的主要工具是:ctags+cscope 接下来我简单介绍一下这些工具的使用ctags的使用在源码根目录执行ctags -R命令,递归的为源码建立tags,在根目录会生成一个Tags的文件,
2017-09-04 09:49:32 1766
原创 (十九)对libevent源码分析的总结
前言在写对libevent源码分析之前,其实已经阅读过几遍libevent源码,结果在分析的时候,还是遇到了一些障碍,不过还好都解决了。由于在真正意义上,这是我第一次分析超过万行的源码,所以可能在分析的过程中,有些遗漏难免发生,后面发现的时候再补上,如果有错误的地方,希望大家指出。总结libevent将定时事件、信号事件、I/O事件都集成到一起,并且可以支持多种多路I/O处理方法,采用了事件驱动机制
2017-09-04 09:36:00 1057
原创 (十八)bufferevent的读写回调函数及对外接口
前言在上一节中,我们介绍了bufferevent实现自动管理的基本思想(水位线机制),在本小节中,我们将介绍bufferevent_readcb、bufferevent_writecb等函数,了解它工作的全过程。bufferevent_readcbstatic voidbufferevent_readcb(int fd, short event, void *arg) { struct
2017-09-03 17:02:53 5839 1
原创 (十七)bufferevent的管理
前言在上节中,我们将evbuffers剩余的内容,比如读/写操作进行了剖析。接下来,我们将对bufferevent进行分析,它主要实现了对缓冲区的自动管理。 在本节中,我们先介绍相关结构体以及一些管理操作,相关代码在evbuffer.c以及event.h文件中。struct bufferevent该结构体用于管理bufferevent。定义如下:struct bufferevent { s
2017-09-03 15:21:28 1037
原创 (十六)evbuffers缓冲区(下)
前言在上节中,我们介绍了evbuffers的部分知识,在本小节中,我们将对剩余的部分一起分析总结。evbuffer_drain在上节中分析的evbuffer_add_buffer中,如果添加源缓冲区到目的缓冲区结尾成功,则会调用evbuffer_drain清除源缓冲区,但是它的功能除了清除整个有效缓冲区以外,还可以清除一部分,接下来我们来看看它的源码:voidevbuffer_drain(stru
2017-09-02 15:05:57 1814
原创 (十五)evbuffers缓冲区(上)
前言evbuffer是libevent的缓冲区部分,它主要是负责缓冲区的构建等操作,而bufferevent主要负责管理输入输出缓冲区,相当于是对evbuffer做的一层抽象,缓冲区对于一个网络库几乎是必需的。我们来介绍关于evbuffer部分,部分主要集中在event.h和buffer.c。evbuffer结构体首先,先了解缓冲区的数据结构:struct evbuffer { u_
2017-09-01 19:44:58 1389
原创 (十四)支持多种IO多路复用的技术
前言众所周知,libevent支持多种I/O多路复用,如select、poll、epoll、kqueue等。那么其中是如何实现的呢? 主要就是结构体eventop,它内部成员有几个函数指针,统一了每种I/O多路复用的接口,也就是说,要想libevent支持某种I/O多路复用,就必须实现这几种接口。结构体eventop位于event-internal.h中。eventopstruct eventop
2017-08-31 22:03:41 824
原创 (十三)时间管理
前言在上一小节,我们主要介绍了定时事件相关的函数。在本小节中,为了加强这部分的理解,我们将探讨libevent有关时间管理的部分,比如我们之前在event_base_loop中看到的时间缓存,时间校正这些。初始化在event_base_new函数中有这样一段代码:detect_monotonic();gettime(base, &base->event_tv);min_
2017-08-31 22:00:37 696
原创 (十二)定时事件集成到多路IO机制
前言在本小节中,我们将展开对定时事件的研究。首先还是和研究信号事件部分一样,先看看它是如何集成到多路I/O中的(或者说是如何与event_base联系起来的)。如何将定时事件集成到主循环中由于seletc、poll、epoll这类多路I/O机制支持定时,所以将定时事件集成到主循环中比起信号事件容易的多。我们只需要将定时事件注册到小根堆上,然后根据堆顶(最短超时事件)来计算多路I/O机制需要等待的最大
2017-08-31 17:28:41 703
原创 (十一)信号事件的管理
前言在上一小节中我们主要讲解了信号事件是如何合并到多路I/O复用机制中的以及信号事件的初始化。在本小节中,我们将看到有关信号事件的主要操作。信号事件的注册前面我们看到了信号事件是在何时何地如何被初始化的,一个事件无非就是初始化、注册、激活、回调、注销这几个重要的操作。接下来我们看看信号事件注册相关的,即evsignal_add函数,它在signal.c文件中定义。intevsignal_add(s
2017-08-30 22:12:24 664
原创 (十)信号事件集成到多路I/O机制
前言之前剖析代码的时候我们知道事件没激活前,都有自己的数据结构来管理,但是在激活之后都是放在激活链表中的。本小节我们将介绍libevent中关于信号事件如何管理,如何将信号事件统一到多路I/O复用事件中一起管理的。如何将信号集成到主循环中libevent采用的是socket pair的方法。分为读socket和写socket,读socket会在event_base上注册一个读事件,而当信号发生时,记
2017-08-29 22:13:24 892 1
原创 (九)事件的激活与调度
前言我们在上一个小节中分析了事件主循环的整个过程以及event_base_once函数。可能信息量有点大,这一小节,我们把event.c剩下的一部分重要的函数分析分析。event_dispatch我们再回到讨论主循环这个话题来,在第1小节给的例子里面最后调用了event_dispatch,它其实干的就是事件主循环的事,只是做了几层封装而已。 下面我们来看一看。event_dispatchinte
2017-08-28 20:03:53 1020 1
原创 (八)事件主循环
前言上一小节我们介绍了事件是如何注册/注销的,在本小节中,我们将进一步探讨事件从未注册到处理的整个过程,即事件的主循环。事件主循环事件的主循环主要是通过event_base_loop完成的。我们下面先来看看这个函数,再进行总结。event_base_loopintevent_base_loop(struct event_base *base, int flags){ const stru
2017-08-28 20:01:35 1212 1
原创 (七)注册/注销event事件
前言在本小节中,我们将看到event是如何注册到event_base上的,以及如何注销,如何激活等操作,最后还会梳理一下事件的状态是如何变化的。event_addintevent_add(struct event *ev, const struct timeval *tv){ struct event_base *base = ev->ev_base; const struct
2017-08-27 22:03:51 1617
原创 (六)初始化并设置event
## 前言 在这一小节里我们将接触到event.c源文件里面的一些关于设置event接口函数。这对我们了解event以及它和event_base之间的联系很有帮助。event_set首先我们看一看初始化event的操作:voidevent_set(struct event *ev, int fd, short events, void (*callback)(int, short,
2017-08-27 18:34:29 1057
原创 (五)struct event结构体
前言之前说到过libevent是基于事件驱动模型的网络库,其中的事件,就是event,它的确算是libevent中最核心的部分,而上一节说到的event_base其实算是驱动部分,负责事件的各种处理。它们之间的关系是,一个event_base对应多个event。 下面主要讲解的是struct event结构体,位于event.h。struct eventstruct event { /*
2017-08-26 20:41:47 2517
原创 (三)libevent源文件结构
前言在正式阅读源码之前,我们先对libevent的整体结构有大致的了解。这对我们在大体上了解libevent很有好处。源文件结构进入到libevent库目录里面一看,好像还挺多的,不过除去脚本还有.lo与.la这些用libtool编译出来的目标文件以及库文件,也没剩多少了。主要分为事件头文件、内部头文件、事件主框架、对多种多路I/O复用的机制的封装、信号管理方面、定时事件管理方面、缓冲区管理方面、日
2017-08-26 14:08:28 932
原创 (四)初探反应器(event_base)
前言在本节中,我们将初次接触struct event_base,并介绍下event_init函数。由于event_base属于整个libevent中中心的部位,所以我们没办法一下就完全弄懂它,需要结合后面的各部分知识才能有一个很好的认识。struct event_base还记得我们之前写的那个小例子吗,一开始调用了event_init()函数。它到底有什么作用?对应函数原型在libevent库中的e
2017-08-25 19:56:42 1181
原创 (二)什么是Reactor模式
Reactor模式(反应堆模式):这便是libevent的中心思想。在常规的I/O多路复用中采用select和poll、epoll等来实现,而将这些机制封装而成的就是I/O多路复用模式,Reactor就是其中之一。通俗的来讲,它就是通过回调机制实现的。我们只需将事件的接口注册到Reactor上,当事件发生之后,会回调注册的接口。比如你订闹钟明早六点半起床,那么在六点半之前你就可以安心睡觉,到了六点半
2017-08-25 19:49:01 2340
原创 (一)libevent安装及简单的使用
前言首先我阅读的版本是libevent-1.4.14b-stable版本。1.4系列虽然比较古老,但是它的源码相对简单,便于学习,并且主要的思想与2.0系列是一致的。 附上官网链接:http://libevent.org/安装及简单使用libevent接下来我们直接进入正题,安装libevent-1.4。 1. 在官网上下载对应版本的包 2. tar -zxvf /your path/libe
2017-08-25 19:46:54 15156 10
原创 谨防fork与锁之间的深坑
fork之后应当谨慎使用锁:这是因为fork有一个特点,那就是子进程只会保留调用fork的那个线程,父进程中其他的线程在子进程中都会消失。但是fork之后,除了文件锁以外,其他的锁都会被继承。这就导致了,如果在子进程中,对某个已经在父进程中加了锁的锁继续加锁,就会导致死锁发生。并且我们无法对该锁进行解锁,因为在子进程中,该锁的持有者并不存在。 下面给一个例子:#include <stdio.h>
2017-06-21 12:27:29 2917 3
原创 宏函数为什么使用do{...}while{0}包起来
在我们看内核源码或者库以及一些优秀的源码时,都会发现他们的宏函数是包括在do{…}while(0)内。具体的原因其实想想就能明白。考虑下面一个特殊的例子。 宏函数的定义如下:#define test(x) \ a(x); \ b(x);如果在调用时是这样调用的:if (judge) test(x);那么展开之后就是:if (judge): a(x);b(x);这时产生的效果可能就
2017-06-20 09:18:46 3280 3
原创 解析变长结构体的用法和优点
变长结构体:在接触变长结构体之前,以为会是一个很难理解的东西,但是这其实算是C里面的一种技巧吧,优点是:分配了一段连续的内存,防止内存碎片化以及方便内存的管理。使用变长结构体的格式如下:struct Test{ .... int a; .... char b[0];};重点是结构体的最后一个成员char b[0],是个空数组。在我们不知道结构体内的某个成员大小是多少的时候,我们
2017-05-14 10:08:06 6223
原创 unix/linux下几种常见的IO模型
unix/linux下几种常见的I/O模型:(以下图片均引用自UNP一书)阻塞式I/O:顾名思义就是当进行I/O时,数据还没有准备好,就会阻塞在I/O上。 下面配合代码进行讲解:#include <string.h>#include <stdio.h>#include <unistd.h>#include <arpa/inet.h>#define SERV_PORT 8000int ma
2017-05-12 17:01:05 1359
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人