Redis积累
一、Redis简介
Redis是一个开源的内存中的数据结构存储系统,它可以用作:数据库、缓存和消息中间件。
书籍:《redis设计与实现》
1.1 Redis数据类型:
- 字符串(String)
- 散列(Hash)
- 列表(List)
- 集合(Set)
- 有序集合(SortedSet或ZSet)
- Bitmaps
- Hyperloglogs
- 地理空间(Geospatial)
它支持多种类型的数据结构,如字符串(String),散列(Hash),列表(List),集合(Set),有序集合(Sorted Set或者是ZSet)与范围查询,Bitmaps,Hyperloglogs 和地理空间(Geospatial)索引半径查询。其中常见的数据结构类型有:String、List、Set、Hash、ZSet这5种。
1.2 Redis的命令
String
String类型是redis中最简单数据类型,String类型实质是一个String映射到另一个String,同时它也是复杂类型的基类型。String类型的value不得超过512M,可以被使用在很多场合。如果String类型的值是数字类型,则可以使用加法和减法操作,在使用算术运算的时候,其实redis将其String类型解析成Integer类型进行运算的。
- SET mystring “mystring0” 设置值
- GET mystring 获取key的值
- EXISTS mystring 判断这个key是否存在
- DEL mystring 删除key
- EXPIRE mystring 10000 设置存活时间
- TTL mystring 查询还有多久的存活时间
- SET mystring12 100 设置一个数字
- INCR mystring12 自增1
- DECR mystring12 自减1
- INCRBY mystring12 35 自增35
List
- LPUSH mylist0 name age address phoneNo 从list的左边插入四个元素
- LRANGE mylist0 0 -1 获取list中某些元素(-1表示最后一位)
- RPOP mylist1 从右边移除一个元素
- BRPOP mylist 10000 如果没有元素,则客户端阻塞等待,10000表示超时时间
Set
- SADD myset 0 0 1 2 6 6 6 向set中插入元素,相同则覆盖
- SISMEMBER myset 0 判断元素是否在set中
- SMEMBERS myset 获取set中所有元素
- SINTER myset myset1 myset2 取多个set的交集
Sorted Set
- ZADD mysortset 1 “BACD” 向sortset中添加元素,1表示元素的score
- ZADD mysortset 2 "BCDE”
- ZRANGE mysortset 0 -1 zrange获取Sorted Set中的元素,ZREVRANGE获取Sorted Set中元素并方向输出。
- ZRANGEBYSCORE mysortset -inf 4 withscores zrangbyscore根据score获取输出元素, -inf参数表明获取小于指定score的元素
Hash
- HMSET usr:1000 username lxy birth 1991 verified 1 插入元素
- HMGET usr:1000 username birth verified 获取元素,可以获取多个key
- HGET usr:1000 username hget只能获取一个
核心:dict
typedef struct dictEntry {
void *key;
union {
void *val;
uint64_t u64;
int64_t s64;
double d;
} v;
struct dictEntry *next;
} dictEntry;
typedef struct dictht {
dictEntry **table;
unsigned long size;
unsigned long sizemask; /*hash表的掩码,总是size-1,用于计算hash表的索引值*/
unsigned long used;
} dictht;
typedef struct dict {
dictType *type;
void *privdata;
dictht ht[2];
long rehashidx; /* rehashing not in progress if rehashidx == -1 */
int iterators; /* number of iterators currently running */
} dict;
二、Redis的功能
- 复制(Replication)
- LUA脚本(Lua scripting)
- LRU驱动事件(LRU eviction)
- 事务(Transactions)
- 磁盘持久化(Persistence)
- Redis哨兵(Sentinel)
- 自动分区(Cluster)
Redis 内置了复制(Replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(Transactions) 和不同级别的磁盘持久化(Persistence),并通过 Redis哨兵(Sentinel)和自动分区(Cluster)提供高可用性(High Availability)。
2.1 复制
A Redis可以配置slaveof <B Redis host> <B Redis port>来复制B Redis,A是从节点,B是主节点
- 1.从Redis向主Redis发送SYNC命令
- 2.主Redis收到SYNC命令后执行BGSAVE命令,即fork一个子进程生成RDB文件,在开始生成RDB文件之时并使用一个缓冲区,记录客户端的写操作命令
- 3.主Redis的BGSAVE命令执行完成,主Redis将生成好的RDB文件发送给从Redis,从Redis接收到RDB文件,将自己原有的数据(如果有的话)全部清除干净,将RDB文件加载到内存中,在RDB文件的加载期间,从Redis是阻塞无法处理客户端请求的
- 4.主Redis将记录在缓冲区的写命令发送给从Redis,从Redis执行主Redis发过来的写操作命令,这样,从Redis的数据库状态就可以跟。主Redis当前的数据库状态达成一致
- 5.接着主、从Redis就使用命令传播操作来同步数据
2.2 LUA脚本
Redis内置了对LUA脚本的支持,并且在计算过程中保证了脚本中执行的原子性。
对cas的支持
2.3 LRU驱动事件
redis使用LRU机制删除过期时间但是还没过期的key
2.4 事务
Redis中的事务(transaction)是一组命令的集合。事务同命令一样都是Redis最小的执行单位,一个事务中的命令要么都执行,要么都不执行。Redis事务的实现需要用到 MULTI 和 EXEC 两个命令,事务开始的时候先向Redis服务器发送 MULTI 命令,然后依次发送需要在本次事务中处理的命令,最后再发送 EXEC 命令表示事务命令结束。
Redis中的事务并没有关系型数据库中的事务回滚(rollback)功能
WATCH命令
WATCH命令可以监控一个或多个键,一旦其中有一个键被修改(或删除),之后的事务就不会执行,监控一直持续到EXEC命令(事务中的命令是在EXEC之后才执行的,EXEC命令执行完之后被监控的键会自动被UNWATCH)
PipeLine
redis支持通过PipeLine将一组Redis命令进行组装,通过一次RTT传输给Redis,再将这组Redis命令按照顺序执行并装填结果返回给客户端
2.5 磁盘持久化
快照方式和AOF方式
快照方式是在指定的时间间隔内生成数据集的时间点快照
AOF 持久化记录服务器执行的所有写操作命令,并在服务器启动时,通过重新执行这些命令来还原数据集。 AOF 文件中的命令全部以 Redis 协议的格式来保存,新命令会被追加到文件的末尾。 Redis 还可以在后台对 AOF 文件进行重写(rewrite),使得 AOF 文件的体积不会超出保存数据集状态所需的实际大小。
2.6 Redis哨兵
由一个或多个Sentinel实例组成Sentinel系统可以监视一个或多个主Redis服务器,以及主Redis属下的从Redis,当被监视的主Redis进入下线状态时,Sentinel会将它的其中一个从Redis升级为主Redis,其他从Redis复制新的主Redis,当旧的主Redis重新上线时,会以从Redis的角色来复制新的主Redis。
2.7 分区Cluster
Redis Cluster本身提供了自动将数据分散到Redis Cluster不同节点的能力,分区实现的关键点问题包括:如何将数据自动地打散到不同的节点,使得不同节点的存储数据相对均匀。
Redis Cluster中有一个16384长度的槽的概念,他们的编号为0、1、2、3……16382、16383。这个槽是一个虚拟的槽,并不是真正存在的。正常工作的时候,Redis Cluster中的每个Master节点都会负责一部分的槽,当有某个key被映射到某个Master负责的槽,那么这个Master负责为这个key提供服务。
redis的发布订阅
redis实现mq可以用发布订阅和阻塞List实现
Redis也提供了持久化的选项,这些选项可以让用户将自己的数据保存到磁盘上面进行存储。根据实际情况,可以每隔一定时间将数据集导出到磁盘(快照),或者追加到命令日志中(AOF只追加文件),他会在执行写命令时,将被执行的写命令复制到硬盘里面。您也可以关闭持久化功能,将Redis作为一个高效的网络的缓存数据功能使用。
Redis不使用表,他的数据库不会预定义或者强制去要求用户对Redis存储的不同数据进行关联。
数据库的工作模式按存储方式可分为:硬盘数据库和内存数据库。Redis 将数据储存在内存里面,读写数据的时候都不会受到硬盘 I/O 速度的限制,所以速度极快。
Redis采用的是基于内存的采用的是单进程单线程模型的 KV 数据库,由C语言编写,官方提供的数据是可以达到100000+的QPS(每秒内查询次数)。三、Redis为什么这么快
1、完全基于内存,绝大部分请求是纯粹的内存操作,非常快速。数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1);
2、数据结构简单,对数据操作也简单,Redis中的数据结构是专门进行设计的;
3、采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗 CPU,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗;
4、使用多路I/O复用模型,非阻塞IO;
5、使用底层模型不同,它们之间底层实现方式以及与客户端之间通信的应用协议不一样,Redis直接自己构建了VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求。