上篇我们讲了非关系型数据库的简介,有兴趣的朋友可以点击链接:
这篇我们就详细说说redis是什么。
一、Redis数据结构
REmote DIctionary Server(Redis) 是一个由 Salvatore Sanfilippo 写的 key-value 存储系统,是跨平台的非关系型数据库。Redis 是一个开源的使用 ANSI C 语言编写、遵守 BSD 协议、支持网络、可基于内存、分布式、可选持久性的键值对(Key-Value)存储数据库,并提供多种语言的 API。
Redis 通常被称为数据结构服务器,因为值(value)可以是字符串(String)、哈希(Hash)、列表(list)、集合(sets)和有序集合(sorted sets)等类型。
String(字符串)
redis的string 是 与 Memcached 一样的最基本的类型,一个 key 对应一个 value,string 类型的值最大能存储 512MB,包含任何数据。比如jpg图片或者序列化的对象。
//SET/GET命令:
redis 127.0.0.1:6379> SET keyName "value"
OK
redis 127.0.0.1:6379> GET keyName
"value"
//将给定 key 的值设为 value ,并返回 key 的旧值(old value)。
GETSET key value
//只有在 key 不存在时设置 key 的值。存在就返回0
SETNX key value
//将值 value 关联到 key ,并将 key 的过期时间设为 seconds (以秒为单位)。
SETEX key seconds value
//将 key 中储存的数字值增一。
INCR key
//将 key 中储存的数字值减一。
DECR key
Hash(哈希)
Redis hash 是一个键值(key=>value)对集合,也是string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象,每个 hash 可以存储 -1 键值对(40多亿)。
//SET命令
redis 127.0.0.1:6379> HMSET keyName field1 "Hello" field2 "World"
"OK"
//GET field1
redis 127.0.0.1:6379> HGET keyName field1
"Hello"
//GET field2
redis 127.0.0.1:6379> HGET keyName field2
"World"
//删除
redis 127.0.0.1:6379> DEL keyName
List(列表)
Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边),列表最多可存储 - 1 元素
redis 127.0.0.1:6379> lpush keyName redis
(integer) 1
redis 127.0.0.1:6379> lpush keyName mongodb
(integer) 2
redis 127.0.0.1:6379> lpush keyName rabbitmq
(integer) 3
redis 127.0.0.1:6379> lrange keyName 0 10
1) "rabbitmq"
2) "mongodb"
3) "redis"
SET(集合)
Redis 的 Set 是 string 类型的无序集合。集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1),集合中最大的成员数为 - 1
//添加一个 string 元素到 key 对应的 set 集合中,成功返回 1,如果元素已经在集合中返回 0。
sadd key member
示例:
redis 127.0.0.1:6379> sadd keyName redis
(integer) 1
redis 127.0.0.1:6379> sadd keyName mongodb
(integer) 1
redis 127.0.0.1:6379> sadd keyName rabbitmq
(integer) 1
redis 127.0.0.1:6379> sadd keyName rabbitmq
(integer) 0
redis 127.0.0.1:6379> smembers keyName
1) "redis"
2) "rabbitmq"
3) "mongodb"
//获取集合的成员数
SCARD key
zset(sorted set:有序集合)
Redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。zset的成员是唯一的,但分数(score)却可以重复。
redis 127.0.0.1:6379> zadd keyName 1 redis
(integer) 1
redis 127.0.0.1:6379> zadd keyName 0 mongodb
(integer) 1
redis 127.0.0.1:6379> zadd keyName 2 rabbitmq
(integer) 1
redis 127.0.0.1:6379> zadd keyName 0 rabbitmq
(integer) 0
redis 127.0.0.1:6379> ZRANGEBYSCORE keyName 0 1000
1) "mongodb"
2) "rabbitmq"
3) "redis"
Stream
Redis Stream 是 Redis 5.0 版本新增加的数据结构。Redis Stream 主要用于消息队列(MQ,Message Queue),Redis 本身是有一个 Redis 发布订阅 (pub/sub) 来实现消息队列的功能,但它有个缺点就是消息无法持久化,如果出现网络断开、Redis 宕机等,消息就会被丢弃。
Stream结构:
- Consumer Group :消费组,使用 XGROUP CREATE 命令创建,一个消费组有多个消费者(Consumer)。
- last_delivered_id :游标,每个消费组会有个游标 last_delivered_id,任意一个消费者读取了消息都会使游标 last_delivered_id 往前移动。
- pending_ids :消费者(Consumer)的状态变量,作用是维护消费者的未确认的 id。 pending_ids 记录了当前已经被客户端读取的消息,但是还没有 ack (Acknowledge character:确认字符)。
//追加消息
XADD key ID field string [field string ...]
//ID,最常使用*,表示由Redis生成消息ID,这也是强烈建议的方案。
// field string [field string], 就是当前消息内容,由1个或多个key-value构成。
//示例:
127.0.0.1:6379> XADD memberMessage * user kang msg Hello
"1553439850328-0"
127.0.0.1:6379> XADD memberMessage * user zhong msg nihao
"1553439858868-0"
//获取消息 XREAD
127.0.0.1:6379> XREAD streams memberMessage 0
1) 1) "memberMessage"
2) 1) 1) "1553439850328-0"
2) 1) "user"
2) "kang"
3) "msg"
4) "Hello"
2) 1) "1553439858868-0"
2) 1) "user"
2) "zhong"
3) "msg"
4) "nihao"
还有三种高级数据结构,简略介绍一下:
Bitmap 位图
以bit位来管理的string类型数据,基于string定义了一组bit位操作,存储成本低,1属性~1bit
GEO 地理位置
GeoHash 利用 Z阶曲线,将二维点转换为一阶曲线,地球二维经纬度坐标转化为一维52bit整数编码,整数编码(score)反向解码获得经纬度
HyperLogLog
HyperLogLog是Redis的高级数据结构,是统计基数的利器。每个 HyperLogLog 键只需要花费 12 KB 内存,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定 的、并且是很小的。 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能像集合那样,返回输入的各个元素。
主要的命令有三个:
//添加指定元素到 HyperLogLog 中。
PFADD key element [element ...]
//返回给定 HyperLogLog 的基数估算值。
PFCOUNT key [key ...]
//将多个 HyperLogLog 合并为一个 HyperLogLog
PFMERGE destkey sourcekey [sourcekey ...]
基于Reids的消息队列实现有很多种,例如:PUB/SUB(订阅/发布模式)、基于List的 LPUSH+BRPOP 的实现、基于Sorted-Set的实现。Stream类型的出现,几乎满足了消息队列的全部内容,包括:消息ID的序列化生成、消息遍历、消息的阻塞和非阻塞读取、消息的分组消费、未完成消息的处理、消息队列监控等。上面的示例只是两个基础功能,对redis用作消息队列的方案,感兴趣的朋友可以看看下面的文章,本文不过多赘述。
注意,Redis支持多个数据库,并且每个数据库的数据是隔离的不能共享,并且基于单机才有,如果是集群就没有数据库的概念。每个数据库对外都是一个从0开始的递增数字命名,Redis默认支持16个数据库(可以通过配置文件支持更多,无上限),可以通过配置databases来修改这一数字。
二、Redis命令
我们上面演示了基础数据类型的使用命令,下面演示其他的几种redis命令Redis 发布订阅
Redis 发布订阅 (pub/sub) 是一种消息通信模式:发送者 (pub) 发送消息,订阅者 (sub) 接收消息。例如:你订阅了一份报纸,每天有新的新闻登载在报纸上,你就能接收到报纸并且读取消息。
//订阅一个或多个符合给定模式的频道。
PSUBSCRIBE pattern [pattern ...]
//查看订阅与发布系统状态。
PUBSUB subcommand [argument [argument ...]]
//将信息发送到指定的频道
PUBLISH channel message
//退订所有给定模式的频道。
PUNSUBSCRIBE [pattern [pattern ...]]
//订阅给定的一个或多个频道的信息
SUBSCRIBE channel [channel ...]
//退订给定的频道。
UNSUBSCRIBE [channel [channel ...]]
事务
Redis 事务可以一次执行多个命令, 以下三个阶段:
- 开始事务。批量操作在发送 EXEC 命令前被放入队列缓存
- 命令入队。收到 EXEC 命令后进入事务执行,事务中任意命令执行失败,其余的命令依然被执行
- 执行事务。在事务执行时,其他客户端提交的命令请求不会插入到事务执行命令序列中。
//标记一个事务块的开始。
MULTI
//取消事务,放弃执行事务块内的所有命令。
DISCARD
//执行所有事务块内的命令。
EXEC
//取消 WATCH 命令对所有 key 的监视。
UNWATCH
//监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。
WATCH key [key ...]
三、Redis 协议
RESP Redis Serialization Protocol (Redis序列化协议) RESP 二进制安全,供redis 或 其他Client-Server使用 Redis内部。
请求响应模型
- Ping-Pong 模式 几乎所有命令响应模式
- Pipeline 模式 一次发送多个请求,然后等待多个响应
- Pub/Sub 模式 client订阅channel,push协议响应
四、redis可视化工具
类似于mysql数据库的可视化工具Navicat,redis也有可视化工具。
我们常用的主要有
Redis Desktop Manager
Another Redis Desktop Manager
当然,redis的用法远不止这些,我们下期继续探讨redis。