Redis入门笔记
NoSQL概述
NoSQL表示not only sql,泛指非关系型数据库
NoSQL作用
- High performance - 高并发读写
- Huge Storage - 海量数据的高效率存储和访问
- High Scalability && High Availability - 高可扩展性和高可用性
NoSQL数据库的四大分类
分类 | 相关产品 | 典型应用 | 数据模型 | 优点 | 缺点 |
---|---|---|---|---|---|
键值(Key-Value) | Redis | 内容缓存.主要用户处理大量数据的高访问负载 | 一系列键值对 | 快速查询 | 存储数据缺少结构化 |
列存储 | HBase | 分布式的文件系统 | 以列式存储,将同一列数据存在一起 | 查找速度块,扩展性强,更容易进行分布式扩展 | 功能相对局限 |
文档 | MongoDB | Web应用(与Key-Value类似,Value时结构化的) | 一系列键值对 | 数据结构要求不严格 | 查询性能不高,缺少统一查询语法 |
图形 | InfoGraphic | 社交网络,推荐系统等,专注于构建关系图谱 | 图结构 | 图结构相关算法 | 对图做计算做出结果,不容易做分布式集群方案 |
NoSQL特点
- 易扩展(无关系型数据库结构关系)
- 灵活的数据模型(无需事先对存储数据建立字段)
- 大数据量,高性能存储(具有非常高的读写性能)
- 高可用(不太影响性能的情况下实现高可用框架)
Redis概述
Redis是使用C语言开发的一个开源的高性能的键值对数据库,通过提供多种键值数据类型来适应不同场景下的存储需求
支持的键值数据类型
- 字符串类型string
- 列表类型list
- 有序集合类型sorted set
- 散列类型hash
- 集合类型set
应用场景
- 缓存
- 任务队列
- 网站访问统计
- 数据过期处理
- 应用排行榜
- 分布式集群架构中session分离
Redis安装配置
https://blog.csdn.net/lj402159806/article/details/81910942
Jedis入门
Jedis介绍
Jedis是Redis官方首选的Java客户端开发包
jedis github https://github.com/xetorthio/jedis
Jedis连接
单连接
// 1.设置ip地址和端口
Jedis jedis = new Jedis("192.168.1.110", 6379);
jedis.auth("123456");
// 2.保存数据
jedis.set("name", "gavinandre");
// 3.获取数据
String value = jedis.get("name");
连接池连接
//获取连接池的配置对象
JedisPoolConfig config = new JedisPoolConfig();
//设置最大连接数
config.setMaxTotal(30);
//设置最大空闲连接数
config.setMaxIdle(10);
//获得连接池
JedisPool jedisPool = new JedisPool(config, "192.168.1.110", 6379);
//获得核心对象
Jedis jedis = null;
try {
//通过连接池获得连接
jedis = jedisPool.getResource();
jedis.auth("123456");
//设置数据
jedis.set("name", "tixialu");
//获取数据
String name = jedis.get("name");
} catch (Exception e) {
e.printStackTrace();
} finally {
//释放资源
if (jedis != null) {
jedis.close();
}
if (jedisPool != null) {
jedisPool.close();
}
}
Redis数据结构
Key定义的注意点:
- 不要过长(不超过1024字节)
- 不要过短(影响可读性)
- 统一命名规范(使用前缀区分命名)
类型 | 简介 | 特性 | 场景 |
---|---|---|---|
String(字符串) | 二进制安全 | 可以包含任何数据,比如jpg图片或者序列化的对象,一个键最大能存储512M | |
Hash(字典) | 键值对集合,即编程语言中的Map类型 | 适合存储对象,并且可以像数据库中update一个属性一样只修改某一项属性值(Memcached中需要取出整个字符串反序列化成对象修改完再序列化存回去) | 存储、读取、修改用户属性 |
List(列表) | 链表(双向链表) | 增删快,提供了操作某一段元素的API | 1,最新消息排行等功能(比如朋友圈的时间线) 2,消息队列 |
Set(集合) | 哈希表实现,元素不重复 | 1、添加、删除,查找的复杂度都是O(1) 2、为集合提供了求交集、并集、差集等操作 | 1、共同好友 2、利用唯一性,统计访问网站的所有独立ip 3、好友推荐时,根据tag求交集,大于某个阈值就可以推荐 |
Sorted Set(有序集合) | 将Set中的元素增加一个权重参数score,元素按score有序排列 | 数据插入集合时,已经进行天然排序 | 1、排行榜 2、带权重的消息队列 |
String
Redis中最为基础的数据存储类型
以二进制方式来进行操作,意味着存储和获取的数据时相同的
Value最多可以容纳的数据长度是512M
常用命令:
赋值
set “key” “value”
getset “key” “value” (先获取后设置)
取值
get “key”
删除
del “key”
数值增减
incr “key” (加1)
incrby “key” “value” (增加值)
decr “key” (减1)
decrby “key” “value” (减少值)
扩展
append “key” “value” (末尾追加值)
Hash
String Key和String Value的map容器
每一个Hash可以存储4294967295个键值对
常用命令:
赋值
hset “hash” “key” “value” (在一个hash中插入一个键值对)
hset “hash” “key1” “value1” “key2” “value2” (在一个hash中插入多个键值对)
取值
hget “hash” “key” (通过key取出该hash中value)
hmget “hash” “key1” “key2” (通过多个key取出该hash中多个value)
hgetall “hash” (取出该hash中所有键值对)
删除
hdel “hash” “key” (通过key删除该hash中的键值对)
del “hash” (删除该hash)
增加数字
hincrby “hash” “key” “value” (hash中指定key的value增加值)
自学命令
hexists “hash” “key” (判断该hash中指定的键值对是否存在)
hlen “hash” (获取该hash中键值对的数量)
hkeys “hash” (获取该哈希表中的所有key)
hvals “hash” (获取该哈希表中的所有value)
List
按照插入顺序排列的字符串链表
在头部与尾部添加新的元素效率较高,在中间插入效率较低
List中最大元素数量为4294967295
List存储数据方式:
ArrayList 数组方式,检索快
LinkedList 双向链表方式,插入快
常用命令:
两端添加
lpush “list” “value1” [“value2”] (将一个或多个值插入到列表头部)
lpushx “list” “value1” [“value2”] (将一个或多个值插入到已存在的列表头部)
rpush “list” “value1” [“value2”] (将一个或多个值插入到列表尾部)
rpushx “list” “value1” [“value2”] (将一个或多个值插入到已存在的列表尾部)
查看列表
lrange “list” start end (获取列表指定范围内的元素,偏移量以start和end指定,0表示列表的第一个元素,1表示列表的第二个元素,以此类推,负数以-1表示最后一个元素,-2表示倒数第二个元素以此类推)
两端弹出
lpop “list” (移出并获取列表的第一个元素)
rpop “list” (移除并获取列表最后一个元素)
获取列表元素个数
llen “list”
扩展命令
lrem “list” count “value” (移除列表中与value相等的元素;count>0表示从表头开始的数量;count<0表尾从表尾开始的数量;count=0,表示所有)
lset “list” “index” “value” (通过index索引设置列表元素的值)
linsert “list” before|after “pivot” “value” (在列表的老元素pivot前或者后插入新元素value)
rpoplpush “list1” “list2” (移除list1列表的最后一个元素,并将该元素添加到list2列表的顶部并返回该元素)
Set
没有排序的字符集合,且不允许重复数据
set中最大元素数量为4294967295
常用命令:
添加/删除元素
sadd “set” “value1” [“value2”] (向集合添加一个或多个元素)
srem “set” “value1” [“value2”] (移除集合中一个或多个元素)
获得集合中的元素
smembers “set” (返回集合中的所有元素)
sismember “set” “value” (判断value元素是否在集合中)
集合中的差集运算
sdiff “set1” [“set2”] (返回给定所有集合的差集)
sdiffstore “set” “set1” [“set2”] (将给定所有集合之间的差集存储在set中)
集合中的交集运算
sinter “set1” [“set2”] (返回给定所有集合的交集)
sinterstore “set” “set1” [“set2”] (将给定所有集合之间的交集存储在set中)
集合中的并集运算
sunion “set1” [“set2”] (返回给定所有集合的并集)
sunionstore “set” “set1” [“set2”] (将给定所有集合之间的并集存储在set中)
扩展命令
scard “set” (获取集合的元素数)
srandmember “set” [count] (返回集合中一个或多个随机数)
Sorted Set
类似Set,每个元素都会关联一个double类型的分数,redis正是通过分数来为集合中的元素进行从小到大的排序
集合中的元素是唯一的,但分数(score)却可以重复
常用命令:
添加元素
zadd “sort” score1 “value1” [score2 “value2”] (向有序集合添加一个或多个元素,或者更新已存在元素的分数)
删除元素
zrem “sort” “value1” [“value2”] (移除有序集合中的一个或多个元素)
zremrangebyrank “sort” start end (移除有序集合中给定的排名区间的所有元素)
zrangebyscore “sort” min max (移除有序集合中给定的分数区间的所有元素)
范围查询
zrange “sort” start end [withscores] (通过索引区间返回有序集合的指定区间内的元素,按分数值递增排序)
zrevrange “sort” start end [withscores] (通过索引区间返回有序集合的指定区间内的元素,按分数值递减排序)
zrangebyscore “sort” min max [withscores] [limit offset count] (通过分数返回有序集合指定区间内的元素,按分数值递增排序)
扩展命令
zscore “sort” “value” (返回有序集中,元素的分数值)
zcard “sort” (获取有序集合的元素数)
zincrby “sort” increment “value” (有序集合中对指定元素的分数加上增量increment)
zcount “sort” min max (计算在有序集合中指定区间分数的元素数)
Keys操作
keys * 查询所有key
keys name* 查询所有以name开头的key
keys name? 查询以name开头?作为占位符的key(name1/name2)
del “key1” [“key2”] 删除一个或多个key
exists “key1” [“key2”] 查询一个或多个key是否存在
rename “key” “newkey” 重命名key名
expire “key” time 设置过期时间,time单位为秒
ttl “key” 查看超时时间
type “key” 获取key的数据类型
flushall 清空数据库
Redis特性
多数据库
一个Redis实例最多可包含16个数据库,客户端可指定连接某个数据库,下标0-15,默认为0,可通过select来选择连接指定数据库
select 0-15 连接指定数据库
move “key” 0-15 移动key到指定数据库
Redis事务
事务中所有命令都会被串行化顺序执行,事务执行期间redis不会再为其他客户端提供任何服务,保证事务中所有命令都被原子化执行,redis事务中某个命令执行失败,之后的命令还会继续执行
multi 开启事务,该语句之后的命令都被存到命令的队列中
exec 提交事务
discard 回滚事务
Redis持久化
持久化方式:
- RDB 在指定时间间隔内将内存中的数据集快照写入到磁盘(30秒写入一次)
- AOF 将以日志的形式记录服务器所处理的每一个操作,在redis启动时,读取该文件重新构建数据库
- AOF + RDB 当redis重启时,它会有限使用AOF文件来还原数据集,因为AOF文件保存的数据集通常比RDB文件所保存的数据集更加完
RDB
优点
RDB是一个非常紧凑(compact)的文件,它保存了Redis在某个时间点上的数据集,这种文件非常适合用于进行备份:比如说,你可以在最近的24小时内,每小时备份一次RDB文件,并且在每个月的每一天,也备份一个RDB文件,这样的话,即使遇上问题,也可以随时将数据集还原到不同的版本
RDB非常适用于灾难恢复(disaster recovery):它只有一个文件,并且内容都非常紧凑,可以(在加密后)将它传送到别的数据中心,或者亚马逊S3中
RDB可以最大化Redis的性能:父进程在保存RDB文件时唯一要做的就是fork出一个子进程,然后这个子进程就会处理接下来的所有保存工作,父进程无须执行任何磁盘I/O操作
RDB在恢复大数据集时的速度比AOF的恢复速度要快
缺点
如果你需要尽量避免在服务器故障时丢失数据,那么RDB不适合你,虽然Redis允许你设置不同的保存点(savepoint)来控制保存RDB文件的频率,但是,因为RDB文件需要保存整个数据集的状态,所以它并不是一个轻松的操作,因此你可能会至少5分钟才保存一次RDB文件,在这种情况下,一旦发生故障停机,你就可能会丢失好几分钟的数据
每次保存RDB的时候,Redis都要fork()出一个子进程,并由子进程来进行实际的持久化工作,在数据集比较庞大时,fork()可能会非常耗时,造成服务器在某某毫秒内停止处理客户端;如果数据集非常巨大,并且CPU时间非常紧张的话,那么这种停止时间甚至可能会长达整整一秒,虽然AOF重写也需要进行fork(),但无论AOF重写的执行间隔有多长,数据的耐久性都不会有任何损失
AOF
优点
使用AOF持久化会让Redis变得非常耐久(muchmoredurable):你可以设置不同的fsync策略,比如无fsync,每秒钟一次fsync,或者每次执行写入命令时fsync,AOF的默认策略为每秒钟fsync一次,在这种配置下,Redis仍然可以保持良好的性能,并且就算发生故障停机,也最多只会丢失一秒钟的数据(fsync会在后台线程执行,所以主线程可以继续努力地处理命令请求)
AOF文件是一个只进行追加操作的日志文件(appendonlylog),因此对AOF文件的写入不需要进行seek,即使日志因为某些原因而包含了未写入完整的命令(比如写入时磁盘已满,写入中途停机,等等),redis-check-aof工具也可以轻易地修复这种问题
Redis可以在AOF文件体积变得过大时,自动地在后台对AOF进行重写:重写后的新AOF文件包含了恢复当前数据集所需的最小命令集合,整个重写操作是绝对安全的,因为Redis在创建新AOF文件的过程中,会继续将命令追加到现有的AOF文件里面,即使重写过程中发生停机,现有的AOF文件也不会丢失,而一旦新AOF文件创建完毕,Redis就会从旧AOF文件切换到新AOF文件,并开始对新AOF文件进行追加操作
AOF文件有序地保存了对数据库执行的所有写入操作,这些写入操作以Redis协议的格式保存,因此AOF文件的内容非常容易被人读懂,对文件进行分析(parse)也很轻松,导出(export)AOF文件也非常简单:举个例子,如果你不小心执行了FLUSHALL命令,但只要AOF文件未被重写,那么只要停止服务器,移除AOF文件末尾的FLUSHALL命令,并重启Redis,就可以将数据集恢复到FLUSHALL执行之前的状态
缺点
对于相同的数据集来说,AOF文件的体积通常要大于RDB文件的体积
根据所使用的fsync策略,AOF的速度可能会慢于RDB,在一般情况下,每秒fsync的性能依然非常高,而关闭fsync可以让AOF的速度和RDB一样快,即使在高负荷之下也是如此,不过在处理巨大的写入载入时,RDB可以提供更有保证的最大延迟时间(latency)
AOF在过去曾经发生过这样的bug:因为个别命令的原因,导致AOF文件在重新载入时,无法将数据集恢复成保存时的原样,(举个例子,阻塞命令BRPOPLPUSH就曾经引起过这样的bug,)测试套件里为这种情况添加了测试:它们会自动生成随机的、复杂的数据集,并通过重新载入这些数据来确保一切正常,虽然这种bug在AOF文件中并不常见,但是对比来说,RDB几乎是不可能出现这种bug的