• 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. 高德AR & 车道级导航技术演进与实践

    2020云栖大会于9月17日-18日在线上举行,阿里巴巴高德地图携手合作伙伴精心组织了"智慧出行"专场,为大家分享高德地图在打造基于DT+AI和全面上云架构下的新一代出行生活服务平 ...

  2. Quartz.NET集成UI版

    Quartz.NET Quartz.NET是NET的开源作业调度系统. Quartz.NET是一个功能齐全的开源作业调度系统,可用于从最小的应用程序到大型企业系统. Quartz.NET目前支持NET ...

  3. eureka源码--服务的注册、服务续约、服务发现、服务下线、服务剔除、定时任务以及自定义注册中心的思路

    微服务注册后,在注册中心的注册表结构是一个map: ConcurrentHashMap<String, Map<String, Lease<InstanceInfo>>& ...

  4. SpringBoot整合SpringDataJPA,今天没啥事情就看了一下springboot整合springdataJPA,实在是香啊,SQL语句都不用写了

    SpringBoot整合SpringDataJPA 1.JPA概念 JPA是Java Persistence API的简称,中文名Java持久层API,是JDK 5.0注解或XML描述对象-关系表的映 ...

  5. Arduino 串口库函数

    库函数目录 if (Serial) available() availableForWrite() begin() end() find() findUntil() flush() parseFloa ...

  6. Android高级控件(下)

    计时器(Chronometer) getBase() 基准时间 setFormat() 设置显示格式 start() 开始计时 stop() 停止计时 setOnChronometerListener ...

  7. 深入理解golang:Context

    一.背景 在golang中,最主要的一个概念就是并发协程 goroutine,它只需用一个关键字 go 就可以开起一个协程,并运行. 一个单独的 goroutine运行,倒也没什么问题.如果是一个go ...

  8. try-finally的时候try里面带return

    最近学习的JVM小册中老师提了个问题: 最开始我觉得是1,结果程序跑出来是0,感到很疑惑,于是查看了下字节码: 从字节码可以看出: 0:定义变量0 1:将0存入本地变量表slot-0 2:加载slot ...

  9. ubuntu20 使用命令安装 nginx

    安装 nginx sudo apt-get install nginx -y 配置文件 nginx 服务管理 # 启动 nginx 服务 service nginx start # 关闭 nginx ...

  10. Apache Hudi与Apache Flink集成

    感谢王祥虎@wangxianghu 投稿 Apache Hudi是由Uber开发并开源的数据湖框架,它于2019年1月进入Apache孵化器孵化,次年5月份顺利毕业晋升为Apache顶级项目.是当前最 ...