• 1:连接池
  • 2:发送命令
  • 3:解析结果
1:连接池
连接池结构体如下:
type Pool struct {
// Dial is an application supplied function for creating and configuring a
// connection.
//
// The connection returned from Dial must not be in a special state
// (subscribed to pubsub channel, transaction started, ...).
Dial func() (Conn, error) //生成网络连接对象 // TestOnBorrow is an optional application supplied function for checking
// the health of an idle connection before the connection is used again by
// the application. Argument t is the time that the connection was returned
// to the pool. If the function returns an error, then the connection is
// closed.
TestOnBorrow func(c Conn, t time.Time) error //测试连接是否通畅 // Maximum number of idle connections in the pool.
MaxIdle int //最大空闲连接数 // Maximum number of connections allocated by the pool at a given time.
// When zero, there is no limit on the number of connections in the pool.
MaxActive int //最大活动(正在执行任务)连接数 // Close connections after remaining idle for this duration. If the value
// is zero, then idle connections are not closed. Applications should set
// the timeout to a value less than the server's timeout.
IdleTimeout time.Duration //空闲连接超时时间,超时会释放 // If Wait is true and the pool is at the MaxActive limit, then Get() waits
// for a connection to be returned to the pool before returning.
Wait bool //当到达最大活动连接时,是否阻塞 chInitialized uint32 // set to 1 when field ch is initialized 初始化标记 mu sync.Mutex // mu protects the following fields 锁
closed bool // set to true when the pool is closed. 连接池关闭标记
active int // the number of open connections in the pool 连接总数
ch chan struct{} // limits open connections when p.Wait is true 用于实现阻塞逻辑
idle idleList // idle connections 双向链表,存放空闲连接
} type idleList struct { //空闲连接链表
count int //空闲连接数
front, back *idleConn //空闲连接信息
} type idleConn struct { //空闲连接信息
c Conn //连接接口
t time.Time //加入空闲队列的时间,用于判断空闲超时
next, prev *idleConn //双向链表指针
}
1:空闲连接池实现
空闲连接池存在一个双向链表中,一个连接用完后回收,就会从表头插入这个链表,当需要一个连接时也是从链表的表头取,从表头插入的时候会写入当前时间,所以链表是一个按时间倒序的链表,判断一个连接有没有空闲超时,就从链表表尾开始判断,如果空闲超时,就从表尾移除并关闭连接。从表头插入一个元素后,如果空闲数量超过阈值,会从表尾移除一个元素,保证空闲的连接数不超过指定的值,防止空闲的连接过多浪费系统资源
 
获取可用连接过程
对应方法:Pool.Get
1:删除超时空闲连接。从链表的表尾开始往表头判断,如果到达空闲超时时间,从链表中移除并释放连接
2:从空闲链表中获取可用连接。从链表表头往表尾查找可用的连接,如果连接能ping通,将当前连接从链表中移除,返回当前连接
3:建立一个新的连接。如果空闲连接为空,或者空闲链表中的所有连接都不可用,则从新建立一个新的连接并返回
在获取连接的时候删除超时空闲连接,这是一种惰性删除的方式
 
以上实现方式同时解决了断开重连的问题。
如在某一时刻redis server重启了,那么空闲链表中的连接都会变得不可用,由于在获取可用连接前会先ping一下,但是所有连接都ping不通,最后只能重新建立,而空闲连接会在空闲时间超时后自动释放,于是很好的解决了断开重连的问题,同时也做了一些牺牲,不ping一下怎么知道连接是否可用,每次获取可用连接的时候都ping了一下,但是大部分时候连接都是可用的。
 
回收可用连接:
对应方法:pooledConnection.Close  -> Pool.put
1:终止相关操作,如果是事务/监听/订阅,停止相关操作
2:将连接放入空闲链表。将连接存入链表表头,如果空闲连接数量超过阈值,就将表尾元素移除并关闭连接
 
 
2:发送命令&接收回复并解析
func (c *conn) Do(cmd string, args ...interface{}) (interface{}, error) {
return c.DoWithTimeout(c.readTimeout, cmd, args...)
} func (c *conn) DoWithTimeout(readTimeout time.Duration, cmd string, args ...interface{}) (interface{}, error) {
c.mu.Lock()
pending := c.pending
c.pending = 0
c.mu.Unlock() if cmd == "" && pending == 0 {
return nil, nil
} //设置写超时时间
if c.writeTimeout != 0 {
c.conn.SetWriteDeadline(time.Now().Add(c.writeTimeout))
}
//发送命令内容
if cmd != "" {
if err := c.writeCommand(cmd, args); err != nil {
return nil, c.fatal(err)
}
} if err := c.bw.Flush(); err != nil {
return nil, c.fatal(err)
} var deadline time.Time
if readTimeout != 0 {
deadline = time.Now().Add(readTimeout)
}
//设置读超时时间
c.conn.SetReadDeadline(deadline) if cmd == "” {
//获取server回复信息并解析
reply := make([]interface{}, pending)
for i := range reply {
r, e := c.readReply()
if e != nil {
return nil, c.fatal(e)
}
reply[i] = r
}
return reply, nil
} var err error
var reply interface{}
for i := 0; i <= pending; i++ {
var e error
if reply, e = c.readReply(); e != nil {
return nil, c.fatal(e)
}
if e, ok := reply.(Error); ok && err == nil {
err = e
}
}
return reply, err
}

redis请求协议格式

set命令消息格式:
*3\r\n$3\r\nSET\r\n$4\r\nhlxs\r\n$28\r\nhttps://www.cnblogs.com/hlxs\r\n 注释如下:
*3 //参数个数是*开头,3个参数
$3 //参数长度是$开头,命令长度
SET //命令名称SET
$5 //参数长度是$开头,key长度
mykey //key的内容
$28 //参数长度是$开头,value长度
https://www.cnblogs.com/hlxs //value内容
参数个数是*开头,参数长度是$开头,每个参数通过\r\n隔开
redis协议格式特点:1易于实现,2可以高效地被计算机分析,3可以很容易地被人类读懂
发送命令其实就是构造请求协议格式,以二进制的方式发送出去
 
redis回复协议格式
* 状态回复(status reply)的第一个字节是 “+”,如:+ok\r\n
* 错误回复(error reply)的第一个字节是 “-“,如:-ERR unknown command xxx\r\n
在 "-" 之后,直到遇到第一个空格或新行为止,这中间的内容表示所返回错误的类型
* 整数回复(integer reply)的第一个字节是 “:”,如::1000\r\n
* 批量回复(bulk reply)的第一个字节是 “$”,如:$6\r\nfoobar\r\n,也是长度加内容的风格
* 多条批量回复(multi bulk reply)的第一个字节是 “*”,如:*5\r\n:1\r\n:2\r\n:3\r\n:4\r\n$6\r\nfoobar\r\n,前面多了数量

接收命令其实就是解析以上格式

redis client原理分析的更多相关文章

  1. Redis事务原理分析

    Redis事务原理分析 基本应用 在Redis的事务里面,采用的是乐观锁,主要是为了提高性能,减少客户端的等待.由几个命令构成:WATCH, UNWATCH, MULTI, EXEC, DISCARD ...

  2. 一、Redis事务原理分析

    一.Redis事务原理分析 在Redis的事务里面,采用的是乐观锁,主要是为了提高性能,减少客户端的等待.由几个命令构成:WATCH, UNWATCH, MULTI, EXEC, DISCARD.通过 ...

  3. Redis Pipeline原理分析

    转载请注明出处:http://www.cnblogs.com/jabnih/ 1. 基本原理 1.1 为什么会出现Pipeline Redis本身是基于Request/Response协议的,正常情况 ...

  4. Redis数据持久化机制AOF原理分析一---转

    http://blog.csdn.net/acceptedxukai/article/details/18136903 http://blog.csdn.net/acceptedxukai/artic ...

  5. Redis核心原理与实践--事务实践与源码分析

    Redis支持事务机制,但Redis的事务机制与传统关系型数据库的事务机制并不相同. Redis事务的本质是一组命令的集合(命令队列).事务可以一次执行多个命令,并提供以下保证: (1)事务中的所有命 ...

  6. redis原理分析

    基本全是参考http://blog.csdn.net/a600423444/article/details/8944601     redis的使用大家都很熟悉,可能除了watch 锁,pipelin ...

  7. Redis有序集内部实现原理分析(二)

    Redis技术交流群481804090 Redis:https://github.com/zwjlpeng/Redis_Deep_Read 本篇博文紧随上篇Redis有序集内部实现原理分析,在这篇博文 ...

  8. 【Redis】跳跃表原理分析与基本代码实现(java)

    最近开始看Redis设计原理,碰到一个从未遇见的数据结构:跳跃表(skiplist).于是花时间学习了跳表的原理,并用java对其实现. 主要参考以下两本书: <Redis设计与实现>跳表 ...

  9. Redis核心原理与实践--Redis启动过程源码分析

    Redis服务器负责接收处理用户请求,为用户提供服务. Redis服务器的启动命令格式如下: redis-server [ configfile ] [ options ] configfile参数指 ...

随机推荐

  1. Oracle学习(一)SQL基础

    一.认识SQL SQL是什么? SQL,结构化查询语言,全称是 Structured Query Language. SQL 是一门 ANSI(American National Standards ...

  2. OSI和TCP/IP参考模型

    分层思想: 分层模型是一种开发网络协议的设计方法. 把节点之间的通讯这个复杂的问题,分成了若干个简单的小问题逐一解决. 把网络相邻节点之间通过接口进行通信,下层为上层提供服务.当网络发生故障,很容易确 ...

  3. MySQL手注之盲注(布尔)

    布尔注入: 当我们在注入的过程中输入的语句在页面没有数据返回点,这就需要利用布尔型盲注一步步来猜取想要的数据.(盲注分为布尔盲注和时间盲注) 盲注常用函数: length()  返回字符串的长度, 可 ...

  4. Spring Cloud实战 | 最终篇:Spring Cloud Gateway+Spring Security OAuth2集成统一认证授权平台下实现注销使JWT失效方案

    一. 前言 在上一篇文章介绍 youlai-mall 项目中,通过整合Spring Cloud Gateway.Spring Security OAuth2.JWT等技术实现了微服务下统一认证授权平台 ...

  5. sping ioc 源码分析(一)-- register(componentClasses) 方法

    一.测试环境的搭建: public class Apple { } @Component public class MyComponet { } public class MyCondition im ...

  6. unittest培训后总结记录

    今天在给同学们上了自动化测试单元框架unittest之后,突发奇想,要总结下自己今天上的课程内容.于是有了下面的一幕: 首先,今天上课的目标是要学会关于unittest框架的基本使用及断言.批量执行. ...

  7. Pyinstaller打包通用流程

    Pyinstaller打包通用流程 前言 什么是Pyinstaller Pyinstaller是用于打包python项目的一个工具, 可以将项目代码打包成可执行文件, 在其他机器上使用. 通俗的说, ...

  8. 记录一下第一次写 50行 SQL代码

    这 是一个电商项目,做的是报表的展示,我还以为要请求几次,结果,用一个SQL全部查完了 下面是目标效果图 这是我的SQL代码 SELECT product.NAME, product.price, p ...

  9. c++模板中set(date st):t(st)中的:符号

    转载:https://zhidao.baidu.com/question/618119741512344012.html 半角冒号是构造函数里的初bai始化列表 开始du的标识. 如楼上所述: set ...

  10. 伺服电机的Arduino库函数

    servo.attach(pin)  //连接伺服电机的信号线于控制板的引脚,9或10号引脚servo.attach(pin, min, max) servo: a variable of type ...