忍不住先吐槽一下,Libev里面的宏真T*D难看而且很多不必要的宏,好吧,其实他是为了性能。
估计介绍Libev的文章挺多的,这里只是个人记录一下,随便写点东西,libev代码还算简洁,虽然宏多了点,还有各种预定义变量等,今天花了几个小时下载了代码看看,简单记录一下。
之前没有用过libev,一般直接裸写的epoll,总结的话,libev的功能是: 支持将SOCKET,管道, 信号,以及定时器统一为通用的变成逻辑,给开发人员提供了一个简单高效的异步网络编程库。
阅读全文...
Mosquitto是一个IBM 开源pub/sub订阅发布协议MQTT的一个单机版实现(目前也只有单机版),MQTT主打轻便,比较适用于移动设备等上面,花费流量少,解析代价低。相对于XMPP等来说,简单许多。
MQTT采用二进制协议,而不是XMPP的XML协议,所以一般消息甚至只需要花费2个字节的大小就可以交换信息了,对于移动开发比较有优势。
IBM虽然开源了其MQTT消息协议,但是却没有开源其RSMB服务端程序,不过还好目前有比较稳定的实现可用,本文的Mosquitto是其中比较活跃的实现之一,具体在这里有目前的实现列表可供选择。
趁着大脑还没有进入睡眠状态记录一下刚才看代码学到的东西。我下载的版本是1.2.2版,在这里可以找到下载链接。 阅读全文...
今天在看MQTT协议文档,到处关于QoS(Quality of Service)的介绍,文档说如果没有收到对方的PUBREL等确认包,超时后server需要'delivery retry", 一开始觉得理所当然的,重发嘛,丢包,正常。
然后就看到消息重发(Message delivery retry)这一章:
4.2. Message delivery retry
Although TCP normally guarantees delivery of packets, there are certain scenarios where an MQTT message may not be received. In the case of MQTT messages that expect a response (QoS >0 PUBLISH, PUBREL, SUBSCRIBE, UNSUBSCRIBE), if the response is not received within a certain time period, the sender may retry delivery. The sender should set the DUP flag on the message.
阅读全文...
前面的2篇文章分别介绍了Redis主从同步源码浅析-Master端 以及 Redis主从同步源码浅析-Slave端 相关的代码实现,从中我们可以看出redis主从同步的一个最大的缺点,也是阻碍大数据应用的地方便是其每次连接端开都需要重连master进行全量数据的重新同步,这个代价是可想而知的。
长连接断开在线上环境中出现得很频繁,如果需要重新同步所有RDB文件,几十G的文件,从建立RDB快照,发送文件内容到slave,然后slave执行命令一一加载进内存中,这个时间开销估计也得好几个小时,更别说树形结构的master->slave->slave, 对网卡的压力,对服务器的压力都是很恐怖的。从这方面来说,动辄几个小时甚至一天的修复时间,没人敢用Redis主从同步在生产环境中使用。
但是福音来了:即将(2013年第三季度)发布的2.8版本会解决这个问题,通过:Replication partial resynchronization 的方式,也就是部分重新同步,这里就说部分同步吧,注意不是常规情况下的新写入指令同步。 阅读全文...
前一篇文章写了下redis主从同步的server端代码,这里补一下slave端的。
简单来讲,看了master端就知道slave端的代码大概流程了:
- 中断跟本slave的下一级slave的连接,强迫其重连SYNC;
- 给master发送PING确认其状态是否OK;
- 发送SYNC要求master做RDB快照(2.8版本以上会有PSYNC的指令,也就是部分同步,下回介绍。);
- 接收RDB文件大小;
- 接收RDB文件;
- emptyDb()清空当前数据库,rdbLoad()重新加载新的RDB文件;
- 按需startAppendOnly,然后接收master过来的累积和实时更新数据;
下面分别介绍这些步骤。 阅读全文...
关于Redis的主从同步的基本介绍这里有:Replication, 不多介绍了。本文只涉及到主库的代码,从库的相关代码改天补上。
这里主要介绍redis 2.6.13版本代码,目前2.8新增了一些功能,比如增量同步功能等,不过到目前2013-10-05还没有正式上线。总结一下几点跟下面相关的:
- 同步采用类似mysql的操作日志重放方式,将写操作分发到从库重放。
- 每次从库启动必须从主库重新同步一份全量RDB数据文件,因此不能随便停止从库;
- 数据同步采用异步将写操作指令发送给从库的方式进行。
总体来说,redis的同步原理是:slave启动时下载所有数据快照,下载快照过程中产生的新写操作日志会不断累积记录起来,发送完快照后就发送这部分增量日志,日志在slave端进行重放。下面分步讲。 阅读全文...
spawn-fcgi是一个小程序,作用是管理fast-cgi进程,功能和php-fpm类似,简单小巧,原先是属于lighttpd的一部分,后来由于使用比较广泛,所以就迁移出来作为独立项目了,本文介绍的是这个版本“spawn-fcgi-1.6.3”。不过从发布新版本到目前已经4年了,代码一直没有变动,需求少,基本满足了。另外php有php-fpm后,码农们再也不担心跑不起FCGI了。
很久之前看的spawn-fcgi的代码,当时因为需要改一下里面的环境变量。今天翻代码看到了就顺手记录一下,就当沉淀.备忘吧。 阅读全文...
HTTP 的Content-Range支持对于一般的网页处理没啥重要的作用,但是对于大文件的下载,CDN回源,点续传功能的作用是非常重要的。
Content-Range允许一次只下载一个文件的一部分,后面再分批次下载文件的其他部分,或者并发下载,提高下载速度,这样如果在下载一个文件的过程中,网络断开了,恢复后不需要重新下载。
nginx 对Content-Range的支持包括header处理和body处理,分别用来解析客户端发送过来的Range header 和裁剪返回给客户端的请求数据Body。其实现分别由2个filter过滤模块完成,分别是ngx_http_range_header_filter_module和ngx_http_range_body_filter_module。下面分别介绍。 阅读全文...
回顾一下之前看的redis代码,脑子内存比较小,一会就忘了,所以备忘一下。
redis主体流程比较简单,init,listen, accept, read, write,基本就是这几步。下面简单介绍一下,当做备忘。 阅读全文...
字典和hash表的实现都大同小异,所以简单说一下不同点。
0.概要
redis的字典是使用hash表实现的,相同hash值的key保存在list中,也就是index= hash(key), index代表了key所在的数组下标,也就是槽位。查找操作找到槽位后,需要遍历下面的链表的元素去查找对应的key。插入操作将新key插入到链表的头部。 阅读全文...
继上面一篇文章“Redis源码学习-AOF数据持久化原理分析(0)”,介绍了Redis是如何将不断从客户端发送过来的数据持久化到AOF文件中的。这里介绍一下AOF rewrite是如何工作的,也就是redis是如何将AOF文件初始化,并后台自动AOF rewrite的。 阅读全文...
Redis作为一个使用广泛的KV内存存储,其也支持一定的数据持久化,这里试着介绍一下Redis在源码层面对持久化的实现机制。
总的来说,Redis支持的将其数据库里面的KV数据存储到磁盘,但可能会有短时间的丢失。官网关于持久化的介绍可以参考这里“Redis Persistence”,这篇文章介绍一下其在代码层面的实现。
其支持2中不同的持久化机制:
- 第一种RDB数据快照持久化。RDB持久化实际上就是对数据库内容做快照,然后将快照存储到磁盘上面,这样就要去我们进行周期性的做快照,但是这种方式无法做到实时的存储,出现故障时只能恢复上一次做快照时的状态,因此比较有限。不过redis的主从同步也是利用RDB实现的,这个我们后续文章分析;
- 第二种AOF日志实时持久化。AOF=Append Only File,也就是不断追加写的文件。在这种情况下,Redis首先将数据库做个快照,将数据还原为跟客户端的协议格式的文本数据,然后将其存储到一个临时文件中,然后将其覆盖成正常的aof文件,并把这个过程中新增的命令追加到aof文件后面,从此之后,后续的从客户端过来的命令都会不断根据不同的安全级别写到磁盘里面去。这样就支持了实时的持久化,只是可能会有短时间内的数据丢失,对一般系统还是可以容忍的。
下面一步步介绍其实现的原理。 阅读全文...
上篇文章“Nginx upstream原理分析【1】给后端FastCGI发送数据”讲到了给PHP等FCGI程序发送数据了,也就是ngx_http_upstream_send_request函数,下面接着写。
ngx_http_upstream_send_request调用输出的过滤器,发送数据到后端,前面已经介绍过,ngx_http_proxy_create_request函数会将客户端发送过来的HEADER,以及body部分的数据组成一块块的FCGI协议的buffer,放到u->request_bufs成员上面,因此在发送数据的时候,就需要吧这块数据发送给后端的PHP或者其他模块。send_request函数完成的任务有如下几个:
- 连接状态诊断,调用ngx_http_upstream_test_connect();
- 调用ngx_output_chain函数将需要发送的数据发送出去(不一定真的发送出了,可能留在缓冲链表里面);
- 设置定时器send_timeout,ngx_tcp_push标志位等;
- 如果连接可读,则调用ngx_http_upstream_process_header()尝试读取FCGI的返回数据。
下面分2部分介绍这个函数: 阅读全文...
在前一篇文章“Nginx upstream原理分析【1】新连接的处理过程”中我们介绍了一个连接从accept到ngx_http_core_run_phases过程处理所发生的事情,后面剩下的就是FCGI的相关处理了,留在这里进行介绍。
0、写在前面的话
ngx_http_core_run_phases函数会不断调用cmcf->phase_engine.handlers上面的checker,从而调用rewrite模块,find_config模块等的函数进行相应的处理,对于我们今天要介绍的FCGI模块的处理,其checker调用的是ngx_http_core_content_phase,后者调用了ngx_http_fastcgi_handler进行相关的处理。 阅读全文...
在上一篇“Nginx upstream原理分析【0】指令解析”中介绍了nginx对于upstream的指令解析,初始化的逻辑。这里介绍一个请求从一开始到后面是怎么处理的。
0、Accept接收新连接:
首先,nginx在ngx_init_cycle解析完配置后,就已经打开了所有的监听端口,然后会调用各个进程初始化函数,这样event模块的进程初始化函数为ngx_event_process_init,这个函数会将所有的listening端口结构跟ngx_connection_t结构进行关联,互相指向,并且为这个连接注册了读写监控事件,这个事件的句柄正式:ngx_event_accept函数,这样,当listen端口有新连接到来的时候会调用ngx_event_accept函数。
下面来简单看一下ngx_event_accept函数的逻辑,函数首先循环最多5次调用accept()系统函数去接收这个连接,并计算一下本进程的负载,来进行简单的负载均衡: 阅读全文...
熟悉nginx的同学都知道upstream的重要作用,当nginx接收到一个连接后,读取完客户端发送出来的Header,然后就会进行各个处理过程的调用。
之后就是upstream发挥作用的时候了,upstream在客户端跟后端比如FCGI/PHP之间,接收客户端的HTTP body,发送给FCGI,然后接收FCGI的结果,发送给客户端。作为一个桥梁的作用。同时,upstream为了充分显示其灵活性,至于后端具体是什么协议,什么系统他都不care,我只实现主体的框架,具体到FCGI协议的发送,接收,解析,这些都交给后面的插件来处理,比如有fastcgi,memcached,proxy等插件,我之前也做过一个简单的跟公司内部系统的module,其实他们都是一种回调形式的模块,跟upstream模块配合从而完成整个请求。如无特殊说明,后面都已FCGI作为后端模块为例说明。 阅读全文...
之前介绍过Nginx的FCGI模块,upstream模块的解析,今晚扫了一下mecached模块的代码,下面记录一下。
总的来说,mecached 模块是继proxy模块外的一个很简单的content模块了,非常简单,就500多行代码,也没有处理一次发送多个KEY给mecached的情况,也没有像FCGI那样做buffering处理,这样mecached返回一点点数据,nginx就发送一点数据给客户端,比较简单。
阅读全文...
上一篇Nginx upstream原理分析【2】-带buffering读取upstream数据 我们介绍了nginx在带buffering的情况下是如何读取FCGI数据的,这里我们介绍他是怎么给客户端返回数据的。
从上篇文章我们知道ngx_event_pipe这个函数一句参数不同,既可以读取upstream数据,也可以给客户端返回数据。其调用的功能函数分别为:ngx_event_pipe_read_upstream 和ngx_event_pipe_write_to_downstream。nginx读取upstream的数据后,会把数据放在p->in链表里面,当然如果缓存不够等原因,写入了磁盘的话,nginx总是将p->in的前面部分写入磁盘,因此会记录在p->out链表上面。在发送时就围绕这2个成员进行了。
发送数据时,客户端的连接结构存放在p->downstream。先来看一下缓存结构:
阅读全文...
上篇文章Nginx upstream原理分析【1】-无缓冲模式发送数据 讲到了nginx upstream在不带buffer的情况下,是如何接收upstream数据然后把它们发送给客户端的。这里讲一下带缓存的情况下nginx是怎么巧妙的完成这一任务的。
回到ngx_http_upstream_send_response函数,这个函数发送请求数据给客户端。里面会分别发送header,body,这个在上篇文章已经介绍过了,对于FCGI这种带buffering的数据处理,这里nginx是用所谓的event_pipe方式处理的,pipe为管子的意思,顾名思义就是读写事件的管道。
其所有的处理都集中在ngx_event_pipe_s这个结构体上,结构体包含指向upstream连接,指向客户端的连接的指针,以及尽心各个缓冲区管理的指针,还有input_filter、output_filter等函数回调,以及一堆标志位。这里先看一下这个结构的内容:
阅读全文...
前阵子学习了一下nginx 关于接收upstream的数据,然后发送给客户端的过程,总结一下。
下面的许多注释等是在upstream后面是FCGI协议而介绍的,比如nginx连接后端php-fpm的情况下。nginx接收到客户端的header数据后会调用各个处理过程,也就是ngx_http_core_content_phase,该过程会不断调用各个阶段(phrase)的回调函数,依次进行配置解析,重定向,访问控制,内容处理等过程。
在内容处理的回调ngx_http_core_content_phase()中,会调用ngx_http_fastcgi_handler,请求由后者接管。
nginx中关于upstream经常围绕在ngx_http_upstream_s上面,这上面包括各种缓冲区数据,回调等,所以先看一下ngx_http_upstream_s结构的内容,具体含义注释下面了。
阅读全文...
近期评论