Jedis源代码探索
1.Redis的通信协议
Redis采用自定义的二进制通信协议。有一个基本规范
发送命令规范:
<参数个数>\r\n
$<参数1字节数>\r\n
<参数1>\r\n
...
$<参数n字节数>\r\n
<参数n>\r\n
响应规范
响应类型有返回数据的第一个字节决定的
+代表一个状态信息,+ok
-代表错误
:返回的是一个整数
$返回一个块数据,跟发送命令的规范一样。$<长度>\r\n<数据>\r\n
*返回多个数据块。同上,后面跟着参数的个数和每个参数的数据。
2.jedis的整体架构(核心解决方案)
解剖jedis架构之前,先自己尝试设计一个客户端。如果用最简单的方式,你会如何设计?
用最简单的Socket就可以实现了,socket跟服务端通信后,就可以按上面的格式发命令了。然后阻塞获得服务端返回的数据。听起来很简单吧。
实际上jedis也是这样实现的。客户端连接数很大,怎么办?每次新建一个socket,开销会成线性增长。我们想到了连接池方案。先新建一批连接,使用时从连接池取一个,用完再回收。连接池实现起来有多复杂?用 apache 的连接池接口,可以简化开发成本。
一台机容量有限,想将数据存储到多个节点。有很多种方案。在业务层面,我们可以将不同的业务数据存储在不同的节点(水平分割)。根据用户容量分割到不同的节点(纵向分割)。有没有通用一点的,我们想到的"一致性hash”方案。根据key,定位到目标节点,存储相关的数据。
吹了那么多,其实上面就是jedis的核心了。其他的只是处理各种的命令返回值而已了
3.源代码剖析
连接redis,非常简单,跟传统的socket通信一样。new一个socket,设置相关的参数,connect获取相关的输入输出流进行通信。它的特别之处在于,封装了这些流,方便操作。
发送命令,就是按照上面的所说的通信协议发送相关的命令
要注意的是要将字符串转成二进制流
处理服务端返回。Redis本身是单线程阻塞的。所以你可以从socket的InputStream中直接读取数据。
获得二进制流,根据不同的命令,将它(解析)转成相应的数据类型即可。
连接池的实现。现在要实现连接池,一般都是用apache的pool接口来实现了。只需要两个步骤。
1.实现Config 就是连接池的配置参数,包括最大连接数,初始连接数,空闲时间.
2.实现 BasePoolableObjectFactory,提供新建连接,废弃连接,测试连接方法
一致性hash的实现。关键是如何使得key均匀散列。jedis使用了murmurhash 2.0
4.经验教训
这里谈谈实践中遇到的几个问题,都是血和泪的教训啊。
1.jedis的连接池获得的连接,进行通信时候出错了,一定要记得销毁该连接。因为它的inputstream里面可能还残留数据。下次从连接池获得的时候都是dirty data了。一般采用以下的方案:
2.使用一致性hash的时候,使用批量查询命令mget的时候,ShardedJedis本身不支持的,只能用一个个key去取数据,性能低下。有一个 比较土的办法。先将key对应的节点分类合并,然后单独用mget去获取数据,再将返回值合并给用户。可以显著减少网络连接。
5.总结
jedis简单,高效,本身代码也可以当做一个网络客户端的典型实现范例。
Jedis源代码探索的更多相关文章
- Jedis 源代码阅读一 —— Jedis
这是jedis 源代码文件夹,我们接下来选择性阅读重要的接口以及实现. └─redis └─clients ├─jedis │ │ BinaryClient.java │ │ BinaryJedis. ...
- netty5源代码探索(一)----ByteBuf初探
Netty的各种简单介绍,总体架构就不介绍了,假设大家感觉的确须要,给我留言我再追加. 这里再推广一个自己做得netty+spring的集成方案,优化netty配置启动,并提供基础server搭建的配 ...
- jedis提纲
A01 - jedis库介绍 A01 - 在多线程下使用Jedis A01 - Jedis的八种调用方式 A02 - API使用文档 A02 - Jedis代码编程使用(简单的使用) A03 ...
- Parrot源代码分析之海贼王
我们的目的是找到speedup-example在使用Parrot加速的原因,假设仅仅说它源于Context Switch的降低,有点简单了,它究竟为什么降低了?除了Context Switch外是否还 ...
- Android源代码学习之六——ActivityManager框架解析
ActivityManager在操作系统中有关键的数据,本文利用操作系统源代码,逐步理清ActivityManager的框架,并从静态类结构图和动态序列图两个角度分别进行剖析,从而帮助开发者加强对系统 ...
- Redis c/c++, java client连接
Redis 介绍 redis这个想必大家都了解,关于redis的安装參考这里,redis使用文档參见这里,英文文档. Redis Cclient的用法 Redis的cclient Hiredis使用比 ...
- Android SDK上手指南:示例项目
Android SDK上手指南:示例项目 2013-12-26 15:40 核子可乐译 51CTO 字号:T | T Android SDK示例项目中的应用能够执行种种功能,例如各类用户界面元素.数据 ...
- 【redis】pipeline - 管道模型
redis-pipeline 2020-02-10: 因为我把github相关的wiki删了,所以导致破图...待解决.(讲真github-wiki跟project是2个url,真的不好用) 因为用的 ...
- Jedis的JedisSentinelPool源代码分析
概述 Jedis是Redis官方推荐的Java客户端,更多Redis的客户端可以参考Redis官网客户端列表.Redis-Sentinel作为官方推荐的HA解决方案,Jedis也在客户端角度实现了对S ...
随机推荐
- python实现复制整个目录的方法
import shutil #复制文件 shutil.copyfile('listfile.py', 'd:/test.py') #复制目录 shutil.copytree('d:/temp', 'c ...
- ERROR 1396 (HY000): Operation CREATE USER failed for 'root'@'localhost'
安装ranger时MySQL报错,查看MySQL数据库,发现host=localhost这一列被删除了,插入这一列就好了,具体操作如下: 解决办法: 进入MySQL数据库 use mysql: &qu ...
- 深入理解MVC架构
MVC MVC是一种设计模式(Design pattern),也就是一种解决问题的方法和思路, 是上世纪80年代提出的,到现在已经颇有历史了. MVC的意义在于指导开发者将数据与表现解耦,提高代码,特 ...
- 爬虫四 selenium模块
一.介绍 selenium最初是一个自动化测试工具,而爬虫中使用它主要是为了解决requests无法直接执行JavaScript代码的问题 selenium本质是通过驱动浏览器,完全模拟浏览器的操作, ...
- 剑指offer 面试25题
面试25题:题目:合并两个排序的链表 题:输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则. 解题思路:递归,并需注意对空链表单独处理. 解题代码: # -* ...
- LeetCode:螺旋矩阵||【59】
LeetCode:螺旋矩阵||[59] 题目描述 给定一个正整数 n,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵. 示例: 输入: 3 输出: [ [ 1, 2, 3 ...
- Android:日常学习笔记(8)———探究UI开发(2)
Android:日常学习笔记(8)———探究UI开发(2) 对话框 说明: 对话框是提示用户作出决定或输入额外信息的小窗口. 对话框不会填充屏幕,通常用于需要用户采取行动才能继续执行的模式事件. 提示 ...
- iOS 视图控制器转场动画/页面切换效果/跳转动画 学习
一 学习 在 UINavigationController 中 push 和 pop 的转场效果 (基于iOS7 以上的转场方式) 经过学习了解到,重点分三块: (1)pushAnimation: ...
- flex 实现图片播放 方案二 把临时3张图片预加载放入内存
该方案,是预加载:前一张,当前,下一张图片,一共3张图片放入内存中.这样对内存的消耗可以非常小,加载之后的图片就释放内存. 下面示例一个是类ImagePlayers,一个是index.mxml pac ...
- 2017最全的php面试题目及答案总结
最近在网上看到很多的小伙伴们都在询问如何应对php面试,这个对于有工作经验和实战项目的小伙伴来说是没什么问题的,但是对于刚刚学习完php的小伙伴们.php面试却是一个很重要的一步,那么今天php中文网 ...