[Go back to REDIS]
Overview
- 内存中的数据结构存储系统,可以用作数据库、缓存和消息中间件。
- redis底层数据结构:跳跃表 [为什么选skiplist而不是red-black tree]
- 支持多种数据结构:String, hash, list, set, sorted set...
- 内置: Replication, lua scripting, LRU eviction, transaction, persistence, Sentinel, Cluster. [具体往下看,分别有具体介绍~]
单线程效率
完全基于内存
数据结构简单,对数据操作也简单
多路IO复用模型 (参考link.)
不要考虑各种锁
不存在多线程上下文切换而消耗CPU
事务
- 事务是一个单独的隔离操作,事务中所有命令都会序列化、按顺序地执行,执行过程中不被其它客户端发来的命令请求打断。
- 不支持rollback (redis认为失败的命令是由编程错误造成,不应出现在生产环境中;使redis内部保持简单且快速。)
- 若事务中某些命令在执行时产生了错误,事务中的其他命令仍然会继续执行。
- redis中关于事务的命令:MULTI、EXEC、DISCARD、WATCH
CAS乐观锁
- watch命令可以为redis事务提供CAS(check-and-set)行为。
- 典型的例子如下:
val = GET mykey
val = val + 1
SET mykey $val上述代码在多个client争用时会产生不正确的结果。可以通过watch来解决:
WATCH mykey
val = GET mykey
val = val + 1
MULTI
SET mykey $val
EXEC上述代码会在exec执行之前监视mykey,如果有其他client修改了mykey的值,那么当前client的事务就会失败。程序要做的就是不断重试该操作,直到没有发生碰撞为止。
watch命令从其被调用开始生效,一直到调用EXEC为止。 实际上这就是乐观锁。(通常情况下不会产生大量的重试。)
ACID
以上,redis事务
不满足原子性:redis事务在执行过程遇到错误,不会回滚,而是继续执行后续命令。
?持久性:redis没有在事务层面有额外的持久性保证,所以仍然由redis提供的持久化模式决定。 [所以redis事务是不能保证持久性的,除非底层是aof always的持久化模式。]
隔离性:redis事务执行过程中,不会处理其他命令。
一致性:能保证。
Persistence
bgsave做全量持久化:耗时长,不够实时,宕机时存在大量数据丢失。
bgsave的原理是什么?你给出两个词汇就可以了,fork和cow。
fork是指redis通过创建子进程来进行bgsave操作。
cow指的是copy on write,子进程创建后,父子进程共享数据段,父进程继续提供读写服务,写脏的页面数据会逐渐和子进程分离开来。 [使用单独子进程来进行持久化,主进程不进行任何IO操作,保证了redis的高性能。 ]
- 由于os的写时复制(copy on write)机制,父子进程会共享当前的物理页面,当父进程处理写请求时,os会为父进程要修改的页面创建副本,而不是写共享的页面。所以子进程的地址空间内的数据是fork时刻整个数据库的一个快照。
- [注意:每次快照持久化都是将内存数据完整地写入到磁盘一次,并不是增量的。因而,在数据量比较大的时候必然会引起大量的磁盘IO。]
aof(Append-only file)做增量持久化: 将“操作+数据”以格式化指令的方式追加到操作日志文件的尾部。在append操作返回后才进行实际的数据变更。
—> 二者结合,在redis实例重启时,会使用bgsave持久化文件重新构建内存,再使用aof重放近期的操作指令来实现完整恢复重启之前的状态。
突然断电的情况? —> 取决于aof的配置:如果不要求性能,在每条写指令时都sync一下磁盘,就不会丢失数据。但是在高性能的要求下每次都sync是不现实的,一般都使用定时sync,比如1s1次,这个时候最多就会丢失1s的数据。 [linux文件操作的“延迟写入”:并非每次write都会出发实际磁盘操作,而是进入buffer] aof记录同步选项如下
always:每一条aof记录都立即同步到文件,最安全的方式,但带来更多的磁盘操作和更大的阻塞延迟。
erverysec:每秒同步一次。如果遇到物理server故障,可能导致最近1s内aof记录丢失。
no:redis并不直接调用文件同步(并不是说不采用aof),而是交给os来处理 --> os可以根据buffer填充/通道空闲时间等择机触发同步。性能比较好,数据丢失量会与OS配置有关。
以上,可以看出来redis并不十分适合“所有数据都需要机器可靠”的场景(may be relational db for ur choice)
- RDB: 在某个时间点将数据写入一个临时文件,持久化结束后,用这个临时文件替换上次持久化的文件,达到数据恢复。
- 默认的持久化方式
- 优点:
- 使用单独子进程来进行持久化,主进程不进行任何IO操作,保证了redis的高性能。
- 恢复速度快。
- 缺点:
- 间隔一段时间进行持久化,容易发生数据丢失。
- 每次保存RDB时,redis都要fork出一个子进程,在数据集比较大时,fork可能会十分耗时,造成server在一段时间内停止处理client请求。
Partition
- 按key分区
- 作用:
- 增大内存
- 通过增加计算机来提高redis计算能力、网络带宽
- 分区方式:
- range:需要一张表存储数据到redis实例的映射关系。
- hash:key必须是object_name:<id>的形式。
- 分区实现方式:
- 客户端分区:在client端就已经决定数据会被存储到哪个redis节点或从哪个redis节点读取。
- 代理分区:client将请求发给代理,然后代理决定。redis和memcached的一种代理实现就是Twemproxy。
- 查询路由(Querying routing):client随即地请求任意一个redis实例,然后由redis将请求转发给正确的redis节点。
Redis Cluster实现了一种混合形式的查询路由,但并不是直接将请求转发给正确的redis节点,而是在client端的帮助下直接redirected到正确的redis节点。
- 缺点:
- 涉及多个key的操作不被支持
- 同时操作多个key,不能使用redis事务
- 分区粒度是key,so it is not possible to shard a dataset with a single huge key like a very big sorted set
- 分区时的动态扩容或缩容可能非常复杂。
Redis集群
Sentinel
redis sentinel着眼于高可用,在master宕机时会自动提升slave
Sentinel本身也是集群,避免SPOF。redis的客户端可以随意地连接任意一个sentinel来获得关于redis集群中的信息。 (sentinel集群自身也需要多数机制,也就是2个sentinel进程时,挂掉一个另一个就不可用了。)
sentinel的failover过程对client 是透明的。
Set sentinels = new HashSet();
sentinels.add(new HostAndPort("172.30.37.73", 26379).toString());
sentinels.add(new HostAndPort("172.30.37.73", 26380).toString());
sentinels.add(new HostAndPort("172.30.37.73", 26381).toString());
JedisSentinelPool sentinelPool = new JedisSentinelPool("myredis", sentinels);
System.out.println("Current master: " + sentinelPool.getCurrentHostMaster().toString()); Jedis master = sentinelPool.getResource();
master.set("username","tom");
sentinelPool.returnResource(master);
Redis Cluster
redis cluster着眼于扩展性,在单个redis内存不足时,使用Cluster进行分片存储。 [Sharding]
Redis采取了P2P而非Proxy方式、异步复制、客户端重定向等设计,而牺牲了部分的一致性。
可用性:在Cluster推出之前,可用性要靠Sentinel保证。有了集群之后也自动具有了Sentinel的监控和自动Failover能力。
有了Cluster功能后,Redis从一个单纯的NoSQL内存数据库变成了分布式NoSQL数据库,CAP模型也从CP变成了AP。
redis cluster VS codis
redis cluster基于smart client和无中心的设计,client必须按key的哈希将请求直接发送到对应的节点。 [转发] —> client不能直接像单机一样使用pipeline来提高效率,想同时执行多个请求来提速必须在client端自行实现异步逻辑。
而codis因其有中心节点、基于proxy的设计,对client来说可以像对单机redis一样去操作proxy(除了一些命令不支持),还可以继续使用pipeline并且如果后台redis有多个的话速度会显著快于单redis的pipeline。
codis是一整套解决方案,还提供了auto-rebalance(迁移对上层业务透明)等。
redis pipelining
Redis is a TCP server using the client-server model and what is called a Request/Response protocol.
The client sends a query to the server, and reads from the socket, usually in a blocking way, for the server response.
Operations
keys VS scan
keys阻塞 [redis单线程]
scan非阻塞,但有一定重复概率
FYI
[Go back to REDIS]的更多相关文章
- 使用redis构建可靠分布式锁
关于分布式锁的概念,具体实现方式,直接参阅下面两个帖子,这里就不多介绍了. 分布式锁的多种实现方式 分布式锁总结 对于分布式锁的几种实现方式的优劣,这里再列举下 1. 数据库实现方式 优点:易理解 缺 ...
- Ignite性能测试以及对redis的对比
测试方法 为了对Ignite做一个基本了解,做了一个性能测试,测试方法也比较简单主要是针对client模式,因为这种方法和使用redis的方式特别像.测试方法很简单主要是下面几点: 不作参数优化,默认 ...
- mac osx 安装redis扩展
1 php -v查看php版本 2 brew search php|grep redis 搜索对应的redis ps:如果没有brew 就根据http://brew.sh安装 3 brew ins ...
- Redis/HBase/Tair比较
KV系统对比表 对比维度 Redis Redis Cluster Medis Hbase Tair 访问模式 支持Value大小 理论上不超过1GB(建议不超过1MB) 理论上可配置(默认配置1 ...
- Redis数据库
Redis是k-v型数据库的典范,设计思想及数据结构实现都值得学习. 1.数据类型 value支持五种数据类型:1.字符串(strings)2.字符串列表(lists)3.字符串集合(sets)4.有 ...
- redis 学习笔记(2)
redis-cluster 简介 redis-cluster是一个分布式.容错的redis实现,redis-cluster通过将各个单独的redis实例通过特定的协议连接到一起实现了分布式.集群化的目 ...
- redis 学习笔记(1)
redis持久化 snapshot数据快照(rdb) 这是一种定时将redis内存中的数据写入磁盘文件的一种方案,这样保留这一时刻redis中的数据镜像,用于意外回滚.redis的snapshot的格 ...
- python+uwsgi导致redis无法长链接引起性能下降问题记录
今天在部署python代码到预生产环境时,web站老是出现redis链接未初始化,无法连接到服务的提示,比对了一下开发环境与测试环境代码,完全一致,然后就是查看各种日志,排查了半天也没有查明是什么原因 ...
- nginx+iis+redis+Task.MainForm构建分布式架构 之 (redis存储分布式共享的session及共享session运作流程)
本次要分享的是利用windows+nginx+iis+redis+Task.MainForm组建分布式架构,上一篇分享文章制作是在windows上使用的nginx,一般正式发布的时候是在linux来配 ...
- windows+nginx+iis+redis+Task.MainForm构建分布式架构 之 (nginx+iis构建服务集群)
本次要分享的是利用windows+nginx+iis+redis+Task.MainForm组建分布式架构,由标题就能看出此内容不是一篇分享文章能说完的,所以我打算分几篇分享文章来讲解,一步一步实现分 ...
随机推荐
- oracle导出导入指定表
从源数据库导出: exp user1/pwd@server1/orcl file=c:\temp\exp.dmp tables=(table1, table2) 导入到目标数据库: imp user2 ...
- C#计算两个时间年份月份差
C#计算两个时间年份月份差 https://blog.csdn.net/u011127019/article/details/79142612
- 51Nod 1058 N的阶乘的长度
输入N求N的阶乘的10进制表示的长度.例如6! = 720,长度为3. Input 输入N(1 <= N <= 10^6) Output 输出N的阶乘的长度 Input示例 6 Out ...
- button theme
children:[ButtonTheme.bar( child:ButtonBar( children:[ FlatButton... ], ),), ]
- Html img 标签
Html img 标签 <html> <body> <!-- img 标签用于显示图片.src="xxx.jpg" 指定图片路径名称--> &l ...
- --save 与--save-dev的区别
一.模式 运行webpack命令时,一定要指定模式. webpack --mode developmentwebpack --mode production二.--save -dev --save:将 ...
- git 管理和存储二进制大文件
git 管理二进制文件 本文档将逐步带你体验 git 的大文件管理方式. 环境: windows10 64位 cmd git版本: git version 2.18.0.windows.1 创建到推送 ...
- android to hide the keybord
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); imm.hi ...
- 《温故而知新》JAVA基础五
定义:是类和类之间的关系"is a" 弗父类(基类)->子类(派生类) 是一直单继承的关系 好处:子类拥有父类的属性方法(private除外) 语法 class Son ex ...
- variable 'o' used without having been completely initialized Compiling Vertex program
variable 'o' used without having been completely initialized Compiling Vertex program v2f vert (ap ...