看了这篇文章

http://blog.nosqlfan.com/html/4153.html

本文所述内容基于 Redis2.6 及以上版本。

注:在客户端通过 info 命令可以查看服务器版本信息,以及很多其他信息。

> info
# Server
redis_version:3.2.3

主要介绍了 Redis 处理客户端连接的一些内部实现机制,包括连接处理、超时、缓冲区等一系列内容。

连接的建立

Redis 通过监听一个 TCP 端口或者 Unix socket 的方式来接收来自客户端的连接,当一个连接建立后,Redis 内部会进行以下一些操作:

首先,客户端 socket 会被设置为非阻塞模式,因为 Redis 在网络事件处理上采用的是非阻塞多路复用模型。
然后为这个socket 设置 TCP_NODELAY 属性,禁用 Nagle 算法
然后创建一个 readable 的文件事件用于监听这个客户端 socket 的数据发送

上面提到了Nagle算法,看这里基本就可以了 (http://baike.baidu.com/view/2468335.htm)

Nagle算法就是为了尽可能发送大块数据,避免网络中充斥着许多小数据块。

Nagle算法的基本定义是任意时刻,最多只能有一个未被确认的小段。 所谓“小段”,指的是小于MSS尺寸的数据块,
所谓“未被确认”,是指一个数据块发送出去后,没有收到对方发送的ACK确认该数据已收到。 Nagle算法只允许一个未被ACK的包存在于网络,它并不管包的大小,因此它事实上就是一个扩展的停-等协议,只不过它是基于包停-等的,而不是基于字节停-等的。 TCP_NODELAY 选项
默认情况下,发送数据采用Nagle 算法。这样虽然提高了网络吞吐量,但是实时性却降低了,在一些交互性很强的应用程序来说是不允许的,
使用TCP_NODELAY选项可以禁止Nagle 算法。 因为Nagle有时候会很慢:
因为TCP/IP中不仅仅有nagle算法,还有一个TCP确认延迟机制 。当Server端收到数据之后,它并不会马上向client端发送ACK,
而是会将ACK的发送延迟一段时间(假设为t),它希望在t时间内server端会向client端发送应答数据,这样ACK就能够和应答数据一起发送,
就像是应答数据捎带着ACK过去。 TCP_CORK 选项
所谓的CORK就是塞子的意思,形象地理解就是用CORK将连接塞住,使得数据先不发出去,等到拔去塞子后再发出去。
设置该选项后,内核会尽力把小数据包拼接成一个大的数据包(一个MTU)再发送出去,当然若一定时间后(一般为200ms,该值尚待确认),
内核仍然没有组合成一个MTU时也必须发送现有的数据。 Nagle算法与CORK算法区别 Nagle算法关心的是网络拥塞问题,只要所有的ACK回来则发包。避免网络因为太多的小包(协议头的比例非常大)而拥塞(其实就是避免太多包,它不关注包的大小)。 而CORK算法则是为了提高网络的利用率,使得总体上协议头占用的比例尽可能的小(它关注包的大小,希望把小包凑成大的包)。 它们的着眼点不一样。 在用户控制的层面上,Nagle算法完全不受用户socket的控制,你只能简单的设置TCP_NODELAY而禁用它,
CORK算法同样也是通过设置或者清除TCP_CORK使能或者禁用之。

然后检查最大连接数:

当客户端连接被初始化后,Redis会查看目前的连接数,然后对比配置好的 maxclients 值,如果目前连接数已经达到最大连接数 maxclients 了,
那么说明这个连接不能再接收,Redis 会直接返回客户端一个连接错误,并马上关闭掉这个连接。 注:先建立连接,后检查,然后再断开。提高了并发量。

服务端处理顺序

如果有多个客户端连接上 Redis,并且都向 Redis 发送命令,那么 Redis 服务端会先处理哪个客户端的请求呢?

答案其实并不确定,主要与两个因素有关,
一是客户端对应的 socket 对应的数字的大小,
二是 kernal 报告各个客户端事件的先后顺序。

Redis 处理一个客户端传来数据的步骤如下:

它对触发事件的 socket 调用一次 read(),只读一次(而不是把这个 socket 上的消息读完为止),是为了防止由于某个别客户端持续发送太多命令,
导致其它客户端的请求长时间得不到处理的情况。

当然,当这一次 read()调用完成后,它里面无论包含多少个命令,都会被一次性顺序地执行。这样就保证了对各个客户端命令的公平对待。

关于最大连接数 maxclients

在 Redis2. 中,最大连接数是被直接硬编码在代码里面的,
而在2.6版本中这个值变成可配置的。
maxclients 的默认值是 ,你也可以在 redis.conf 中对这个值进行修改。

Redis 还会照顾到系统本身对进程使用的文件描述符数量的限制。在启动时 Redis 会检查系统的 soft limit,以查看打开文件描述符的个数上限。

如果系统设置的数字,小于咱们希望的最大连接数加32,那么这个 maxclients 的设置将不起作用,Redis 会按系统要求的来设置这个值。
(加32是因为 Redis 内部会使用最多32个文件描述符,所以连接能使用的相当于所有能用的描述符号减32)。

当上面说的这种情况发生时(maxclients 设置后不起作用的情况),Redis 的启动过程中将会有相应的日志记录。

--maxclients  []  Jan ::33.179 # Unable to set the max number of files limit to  (Invalid argument), 
setting the max clients configuration to .

修改soft limit

ulimit -Sn  # This will only work if hard limit is big enough.
sysctl -w fs.file-max=

输出缓冲区大小限制

可能是一个简单的命令,能够产生体积庞大的返回数据。

另外也有可能因为执行命令太多,产生的返回数据的速率超过了往客户端发送的速率,这时也会产生消息堆积,
从而造成输出缓冲区越来越大,占用过多内存,甚至导致系统崩溃。

所以 Redis 设置了一些保护机制来避免这种情况的出现,这些机制作用于不同种类的客户端,有不同的输出缓冲区大小限制,限制方式有两种:

一种是大小限制,当某一个客户端的缓冲区超过某一大小时,直接关闭掉这个客户端连接
另一种是当某一个客户端的缓冲区持续一段时间占用空间过大时,也直接关闭掉客户端连接

对于不同客户端的策略如下:

对普通客户端来说,限制为0,也就是不限制,因为普通客户端通常采用阻塞式的消息应答模式,如:发送请求,等待返回,再发请求,再等待返回。
这种模式通常不会导致输出缓冲区的堆积膨胀。
对于 Pub/Sub 客户端来说,大小限制是32m,当输出缓冲区超过32m时,会关闭连接。持续性限制是,当客户端缓冲区大小持续60秒超过8m,也会导致连接关闭。
而对于 Slave 客户端来说,大小限制是256m,持续性限制是当客户端缓冲区大小持续60秒超过64m时,关闭连接。

这样也学习到了,Redis的客户端分为三种:普通客户端、Pub/Sub客户端、Slave客户端。

输入缓冲区大小限制

比较暴力,当客户端传输的请求大小超过1G时,服务端会直接关闭连接。

这种方式可以有效防止一些客户端或服务端 bug 导致的输入缓冲区过大的问题。

Client 超时

对当前的 Redis 版本来说,服务端默认是不会关闭长期空闲的客户端的。但是你可以修改默认配置来设置你希望的超时时间。
比如客户端超过多长时间无交互,就直接关闭。同理,这也可以通过 CONFIG SET 命令或者修改 redis.conf 文件来配置。
值得注意的是,超时时间的设置,只对普通客户端起作用,对 Pub/Sub 客户端来说,长期空闲状态是正常的。
另外,实际的超时时间可能不会像设定的那样精确,这是因为 Redis 并不会采用计时器或者轮训遍历的方法来检测客户端超时,而是通过一种渐近式的方式来完成,
每次检查一部分。所以导致的结果就是,可能你设置的超时时间是10s,但是真实执行的时间是超时12s后客户端才被关闭。

CLIENT 命令

其实说的是和CLIENT连接相关的命令。Redis 的 CLIENT 命令能够实现三种功能:检查连接的状态,杀掉某个连接以及为连接设置名字。

比如下面这条命令(实际实验):

> client list
id= addr=10.117.146.21: fd= name= age= idle= flags=S db= sub= psub= multi=- qbuf= qbuf-free= obl= oll= omem= events=r cmd=replconf
id= addr=10.117.146.21: fd= name= age= idle= flags=N db= sub= psub= multi=- qbuf= qbuf-free= obl= oll= omem= events=r cmd=client

如上面命令的输出可知,目前此 Redis 有两个客户端连接,每一行表示一个连接的各项信息:

addr: 客户端的TCP地址,包括IP和端口
fd: 客户端连接 socket 对应的文件描述符句柄号
name: 连接的名字,默认为空,可以通过 CLIENT SETNAME 设置
age: 客户端存活的秒数
idle: 客户端空闲的秒数
flags: 客户端的类型 (N 表示普通客户端,更多类型见 http://redis.io/commands/client-list)
omem: 输出缓冲区的大小
cmd: 最后执行的命令名称

当你通过上面命令获取到客户端列表后,就可以通过 CLIENT KILL 命令来杀死指定的连接了。CLIENT KILL 的参数就是上面的 addr 值。

如上面提到的 CLIENT SETNAME 和 CLIENT GETNAME 可以用来为一个连接设置一个名字。

完。

Redis 网络通信及连接机制学习的更多相关文章

  1. 【Redis数据库】命令学习笔记——发布订阅、事务、脚本、连接等命令汇总

    本篇基于redis 4.0.11版本,学习发布订阅.事务.脚本.连接的相关命令. Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息. 序号 ...

  2. Redis 教程 Java工程师学习知识点

    1. Redis简介及安装 1.1 Redis 简介 Redis 是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库. Redis 与其他 key - value 缓存产品有以下 ...

  3. SpringMVC + Spring + Mybatis+ Redis +shiro以及MyBatis学习

    SpringMVC + Spring + Mybatis+ Redis +shiro http://www.sojson.com/shiro MyBatis简介与配置MyBatis+Spring+My ...

  4. Redis的安装及学习

    最近因为做Chatbot项目需要对于NoSQL数据库进行研究,调研范围包括MongoDB和Redis.本文将介绍Redis在Windows环境的安装及如何利用python来操作Redis数据库. Re ...

  5. [redis] 与redis cluster有关的学习笔记

    主要是以下三个官方文档,只略读了前两个,第三个还没有读. <redis cluster tutorial> <redis sentinel> <redis cluster ...

  6. Redis 3.0中文版学习(二)

    网址:http://wiki.jikexueyuan.com/project/redis-guide/entry-to-master-middle.html 1.Redis的列表: 采用链表的实现方法 ...

  7. Redis 3.0中文版学习(一)

    网址:http://wiki.jikexueyuan.com/project/redis-guide/entry-to-master-a.html http://www.yiibai.com/redi ...

  8. redis集群的学习(一)

    redis配置文件详解 redis默认是不作为守护进程来运行的,你可以把这个设置为yes,让它作为守护进程来运行 注意,当作为守护进程的时候,redis 会把进程ID 写到/var/run/redis ...

  9. 入门大数据---Redis集群分布式学习

    Redis是什么? 官方介绍: Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库.缓存和消息中间件. 它支持多种类型的数据结构,如 字符串(strings), 散列( ...

随机推荐

  1. linux下安装vsftp

    1. yum安装vsftp # yum install vsftpd 2. 配置Vsftpd 安装完之后我们要对它进行配置,才能正常使用.编辑vsftpd的配置文件vi /etc/vsftpd/vsf ...

  2. PE文件之资源讲解

    资源是PE文件中非常重要的部分,几乎所有的PE文件中都包含资源,与导入表与导出表相比,资源的组织方式要复杂得多,要了解资源的话,重点在于了解资源整体上的组织结构. 我们知道,PE文件资源中的内容包括: ...

  3. rm删除命令

    linux中删除文件和目录的命令: rm命令.rm是常用的命令,该命令的功能为删除一个目录中的一个或多个文件或目录,它也可以将某个目录及其下的所有文件及子目录均删除.对于链接文件,只是删除了链接,原有 ...

  4. PHP 中 Date 函数与实际时间相差8小时的解决方法

    PHP 中的 date() 函数显示的时间是格林威治时间,和北京时间正好相差8个小时,其他时间相关的函数,如 strtotime() 也有相同的问题,同样可以通过下面的方法来解决: 1. 修改php. ...

  5. Raphaël 是一个小型的 JavaScript 库,用来简化在页面上显示向量图的工作。你可以用它在页面上绘制各种图表、并进行图片的剪切、旋转等操作。

    点这里 在线效果演示:http://raphaeljs.com/pie.html http://raphaeljs.com github: https://github.com/DmitryBaran ...

  6. POJ 1419

    #include <iostream> #define MAXN 105 #define max _max using namespace std; int j; bool _m[MAXN ...

  7. hdu 4061 A Card Game

    思路: 分析:假设取的牌顺序是一个序列,那么这种序列在末尾为1时是和取牌序列一一对应的,且是符合“游戏结束时牌恰好被取完”的一种情况. 简证:1.在序列中,任一数 i 的后一个数 j 是必然要放在第 ...

  8. UVA 11481 - Arrange the Numbers 数学

    Consider this sequence {1, 2, 3, . . . , N}, as a initial sequence of first N natural numbers. You ca ...

  9. Codeforces Round #336 (Div. 2) D. Zuma 区间dp

    D. Zuma   Genos recently installed the game Zuma on his phone. In Zuma there exists a line of n gems ...

  10. MyEclipse — Maven+Spring+Struts+Hibernate 整合 [学习笔记-5]

    测试项目 目录结构