看了这篇文章

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. map初始化定时器

    init_timer(); //各种定时器的初始化 void Map::init_timer() { //auto tf = GetPlug(TimerFactory); auto tf = m_sp ...

  2. Xamarin 中开发Android实现全屏或者不显示标题栏的方法-宋兴柱

    using System; using Android.App; using Android.Content; using Android.Runtime; using Android.Views; ...

  3. 数位DP之小小结

    资料链接:http://wenku.baidu.com/view/9de41d51168884868662d623.html http://wenku.baidu.com/view/d2414ffe0 ...

  4. javascript实现数据结构与算法系列:循环链表与双向链表

    循环链表(circular linked list) 是另一种形式的链式存储结构.它的特点是表中最后一个结点的指针域指向头结点,整个表形成一个环. 循环链表的操作和线性链表基本一致,仅有细微差别. w ...

  5. Tomcat server分端口部署web项目

    <?xml version='1.0' encoding='utf-8'?> <Server port="8006" shutdown="SHUTDOW ...

  6. sql注入分类

    Sql注入根据数据提取通道的类型,从服务器接收到的响应等可以分为不同的类型. 基于从服务器接收到的响应 ▲基于错误的SQL注入 ▲联合查询的类型 ▲堆查询注射 ▲SQL盲注 •基于布尔SQL盲注 •基 ...

  7. Google NACL 简介

    Back to README Getting Started This page tells you how to install Native Client and run demos, both ...

  8. tomcat 跨域

    http://www.360doc.com/content/14/0920/14/7909375_411017244.shtml http://www.tuicool.com/articles/Znq ...

  9. ExtJs布局之accordion,fit,auto

    <!DOCTYPE html> <html> <head> <title>ExtJs</title> <meta http-equiv ...

  10. (转)Android之ListView原理学习与优化总结

    转自: http://jishu.zol.com.cn/12893.html 在整理前几篇文章的时候有朋友提出写一下ListView的性能优化方面的东西,这个问题也是小马在面试过程中被别人问到的….. ...