目录
Redis 简介
Redis 简单介绍
Redis 是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库。
Redis 与其他 key - value 缓存产品有以下三个特点:
- Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
- Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。
Redis 优势
- 性能极高 – Redis能读的速度是110000次/s,写的速度是81000次/s 。 内存, C语言实现,单线程
- 丰富的数据类型 – Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。
- 原子 – Redis的所有操作都是原子性的,意思就是要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务,即原子性,通过MULTI和EXEC指令包起来。
- 丰富的特性 – Redis还支持 publish/subscribe, 通知, key 过期等等特性。
Redis与其他key-value存储有什么不同?
- Redis有着更为复杂的数据结构并且提供对他们的原子性操作,这是一个不同于其他数据库的进化路径。Redis的数据类型都是基于基本数据结构的同时对程序员透明,无需进行额外的抽象。
- Redis运行在内存中但是可以持久化到磁盘,所以在对不同数据集进行高速读写时需要权衡内存,因为数据量不能大于硬件内存。在内存数据库方面的另一个优点是,相比在磁盘上相同的复杂的数据结构,在内存中操作起来非常简单,这样Redis可以做很多内部复杂性很强的事情。同时,在磁盘格式方面他们是紧凑的以追加的方式产生的,因为他们并不需要进行随机访问。
Redis的应用场景
- 缓存系统 (Http ——redis——storage)
- 任务队列,消息队列(kafka,rabbitMQ)
- 应用排行榜
- 网站访问统计(转发,评论)
- 数据过期处理
- 分布式集群架构中的session
一、Redis 的通用命令和数据结构
1.1 通用命令
通用命令 | 解释 |
keys | 查看key,正则匹配也可以 |
dbsize | 数据库的大小,时间复杂度O(1) |
exists key | 判断key 是否存在,O(1) |
del key | 删除key |
expire key seconds | 设置过期时间 ttl, persist |
type | 数据类型 |
启动 Redis(Window)
进入客户端窗口
keys * 的使用
- 热备从节点
- scan
1.2 数据结构和内部编码
1.3 单线程架构
串行的执行 ,就好比 过独木桥, 某个 时间只会执行一条命令。
单线程为什么这么快
- 纯内存
- 非阻塞 IO
- 避免线程切换和竟态消耗
使用 单线程要注意什么
- 一次只运行一条命令
- 拒绝长命令 keys ,flushall, flushdb , slow lua script , mutil/exec, operate big value (collection)
- 其实不是单线程
二、五种数据类型
2.1 字符串
value的 大小: 限制 为 512 M value的类型可以是 数字,字符串,二进制数
使用场景: 缓存、计算器、分布式锁
字符串API:get 、set 、setnx, del,incr,decr, mset, mget
获取多个 value
实现如下功能:
记录网站每个人的主页访问量:incr userid:pageview(单线程 : 无竞争)
缓存视频的基本信息(数据源在MySQL中) 伪代码
通过一个 vid 获取视频信息,如果Redis 中存在 ,直接返回给 App Server ,不需要访问后端的服务器。如果Redis中没有取到则访问 MySQL,并将 数据会写到 Redis ,以便下次访问直接 到 Redis 中获取。
伪代码 实现:
public VideoInfo get (long id) {
String redisKey = redisPrefis + id;
VideoInfo videoInfo = redis.get(redisKey);
if(videoInfo == null) {
videoInfo = mysql.get(id);
if(videoInfo != null) {
// 序列化
redis.set(redisKey, serialize(videoInfo));
}
}
return videoInfo;
}
分布式的 id 生成器
2.2 哈希
Redis hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象。
Redis 中每个 hash 可以存储 232 - 1 键值对(40多亿)。
哈希值结构
数据 存储 逻辑图如下
其实 学过 Hbase的 同胞们 看了就感觉 颇深, Hbase 也是 非关系型的数据库包含Rowkey, ColumnFamily , column等 schema信息,Hbase 本身存储数据也是 KeyValue ,只不过 Hbase 的数据放在 HDFS中 , Redis放在内存中。
哈希API:hget , hset , hdel , hexists , hlen , hmget , hmset (O(n)), hgetall (O(n)), hvals , hkeys ,hincreby(hash key 对应的field 的value自增)
判断 name, age 是否存在(其实 这些命令都差不多)
多个 key ,value
key , value 分别获取
实现如下功能:
- 记录网站每个用户个人主页的访问量?
hincrby user:1:info pageview count
- 缓存视频基本信息
public VideoInfo get(long id) {
String redisKey = redisPrefix + id; // key
Map<String, String> hashMap = redis.hgetAll(redisKey); // 获取 key 的所有 hash 值
VideoInfo videoInfo = transferMapToVideo(hashMap); // 将 hashMap 转为 vdieo
if( videoInfo == null ) {
videoInfo = mySql.get(id); // 从 MySQL中 获取
if ( videoInfo != null ) {
redis.hmset(redisKey, transferVideoToMap(videoInfo)); // 写回 Redis
}
}
return videoInfo;
}
2.3 列表
Redis列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)
一个列表最多可以包含 232 - 1 个元素 (4294967295, 每个列表超过40亿个元素)。
特点
有序,可重复, 左右两边可以弹出, 和Java的 List 相似,对 元素 可以的插入、删除可以做到精确的控制
列表API:rpush (右边) , lpush , lpop , rpop , lrem , lrange(范围), lindex(索引)、lset(改)
lrem 的使用 剖析
ltrim
简单示例
2.4 Set
Redis 的 Set 是 String 类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。
Redis 中集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。
集合中最大的成员数为 232 - 1 (4294967295, 每个集合可存储40多亿个成员)。
特点:无序、不重复
集合内API:sadd , srem , scard(计算) , sismember(判断) , srandmember (随机取), smembers(取所有)
2.5 有序集合
Redis 有序集合和集合一样也是string类型元素的集合,且不允许重复的成员。
不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。
有序集合的成员是唯一的,但分数(score)却可以重复。
集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。 集合中最大的成员数为 232 - 1 (4294967295, 每个集合可存储40多亿个成员)。 菜鸟教程 摘取
有序集合结构:
有序集合API:zadd, zrem , zcard(个数O(1)), zrange (索引范围 升序 O(log(n))) , zcount , zremrangebyrank , zrevrank , zrevrange , zrevrangebyscore
有序集合总结
操作类型 | 命令 |
基本操作 | zadd zrem zcard zincrby zscore |
范围操作 |
zrange zrangebyscore zcount zremrangebyrank |
集合操作 |
zunionstore zinterstore |