上虞网站建设,WordPress交互式网站,我要自学网官网免费,网站建设与维护中职目录
1. Redis 基本概念
2. Redis 的优势
3. Redis 适用场景
4. Redis-3.2.6 安装(未整理)与测试
5. 使用 Redis 的 Java API 客户端——Jedis
6. 数据结构
6.1 String -- 字符串
6.1.1 String 使用概述
6.1.2 String 常用操作
6.1.3 String 使用案例
6.2 List -- 列…目录
1. Redis 基本概念
2. Redis 的优势
3. Redis 适用场景
4. Redis-3.2.6 安装(未整理)与测试
5. 使用 Redis 的 Java API 客户端——Jedis
6. 数据结构
6.1 String -- 字符串
6.1.1 String 使用概述
6.1.2 String 常用操作
6.1.3 String 使用案例
6.2 List -- 列表
6.2.1 List 使用概述
6.2.2 List 应用案例
6.3 Set -- 集合
6.3.1 Set 使用概述
6.3.2 Set 使用案例
6.4 ZSet -- 有序集合
6.4.1 ZSet 使用概述
6.4.2 ZSet 使用案例
6.5 Hash -- 哈希表
6.5.1 Hash 使用概述
6.5.2 Hash 案例
6.6 键值相关的命令
6.7 服务器相关命令
6.8 Redis 事务
7. Redis 的高可用
8. Redis 的持久化
8.1 RDB 持久化
8.2 AOF 持久化
8.3 总结 1. Redis 基本概念
Remote Dictionary Server(Redis) 是一个由 Salvatore Sanfilippo 写的开源的、高性能的、使用 ANSI C 语言编写的、遵守 BSD 协议、支持网络、可基于内存亦可持久化的日志型、Key-Value 存储系统并提供多种语言的 API。
和 memcached 类似Redis 常被称作是一款 Key-Value 内存存储系统或者内存数据库同时由于它支持丰富的数据结构又被称为一种数据结构服务器Data Structure Server因为其值Value可以是字符串String、哈希Map、列表List、集合Set和有序集合Sorted Set等类型。 Redis 与其他 Key-Value 缓存产品有如下三个特点
1. Redis 支持数据的持久化可以将内存中的数据保持在磁盘中重启的时候可以再次加载进行使用
2. Redis 不仅仅支持简单的 Key-Value 类型的数据同时还提供 List, Set, ZSet, Hash 等数据结构的存储
3. Redis 支持数据的备份即 Master-Slave 模式的数据备份 2. Redis 的优势
1. 性能极高Redis 读的速度可达 110000 次/s写的速度可达 81000 次/s
2. 丰富的数据类型Redis 支持二进制案例的 String, List, Hash, Set 以及 Sorted Set 数据类型的操作
3. 原子操作Redis 的所有操作都是原子性的同时 Redis 还支持对几个操作合并后的原子性执行
4. 丰富的特性Redis 还支持 Publish/Subscribe通知 Key 过期支持高可用集群等特性
5. 数据持久化机制持久化机制有两种1RDB 方式定期将内存数据 dump 到磁盘 2AOF(Append Only File) 持久化机制用记日志的方式记录每一条数据更新操作一旦出现灾难事件可以通过日志重放来恢复整个数据库 3. Redis 适用场景
1. TopN 需求取最新的 N 个数据如读取作家博客最新的 50 篇文章通过 List 实现对按时间排序的数据的高效读取
2. 排行榜应用以特定条件为排序标准将其设成 Sorted Set 的 score进而实现高效获取
3. 需要精准设定过期时间的应用把 Sorted Set 的 score 值设置成过期时间的时间戳那么就可以简单地通过过期时间排序定时清除过期数据了
4. 计数器应用Redis 的命令都是原子性的可以轻松地利用 INCR, DECR 命令来构建计数器系统
5. 去除大量数据中的重复数据将数据放入 Set 中就能实现对重复数据的排除
6. 构建队列系统使用 List 可以构建队列系统使用 Sorted Set 甚至可以构建有优先级的队列系统
7. 实时系统、反垃圾系统通过上面说到的 Set 功能可以知道有一个终端用户是否进行了某个操作可以找到其操作的集合并进行分析统计对比等
8. Publish/Subscribe 构建实时消息系统
9. 缓存会话、商品列表、评论列表、经常查询的数据等 以一个某技术社区为例 记录帖子的点赞数、评论数和点击数(Hash) 记录用户的帖子 ID 列表 (排序)便于快速显示用户的帖子列表(ZSet) 记录帖子的标题、摘要、作者和封面信息用于列表页展示(Hash) 记录帖子的点赞用户 ID 列表评论 ID 列表用于显示和去重计数(ZSet) 缓存近期热帖内容 (帖子内容空间占用比较大)减少数据库压力 (Hash) 记录帖子的相关文章 ID根据内容推荐相关帖子(List) 如果帖子 ID 是整数自增的可以使用 Redis 来分配帖子 ID(计数器) 收藏集和帖子之间的关系(ZSet) 记录热榜帖子 ID 列表总热榜和分类热榜(ZSet) 缓存用户行为历史进行恶意行为过滤(ZSet,Hash) 4. Redis-3.2.6 安装(未整理)与测试
官网https://redis.io/ 下载安装包
假设安装已完成
启动 Redis Server
redis-server
后台启动
nohup redis-server 1~/data/redis/redis_std.log 2~/data/redis/redis_err.log
启动客户端执行命令
redis-cli
检测 Redis 是否正常工作
PING 5. 使用 Redis 的 Java API 客户端——Jedis
1. 新建一个 Maven 工程导入如下依赖
dependency groupIdredis.clients/groupId artiFactIdjedis/artiFactId version2.9.0/version
/dependency
2. 编写一个测试类用来测试客户端是否可以访问服务器
package cn.gldwolf.jedis import redis.clients.jedis.Jedis; \public class JedisClientDriver { public static void main(String[] args) { // 创建一个 Jedis 客户端对象 Jedis client new Jedis(hdp01, 6379); // 测试服务器是否连通 String response client.ping(); Sytstme.out.println(response); // 若能 ping 通则会返回一个 PONG }
} 6. 数据结构
6.1 String -- 字符串
6.1.1 String 使用概述
String 是 Redis 最基本的类型可以理解成与 Memcached 一模一样的类型一个 Key 对应一个 Value.
String 类型是二进制安全的。意思是 Redis 的 String 可以包含任何数据比如 jpg 图片或者序列化的对象。
String 类型是 Redis 最基本的数据类型一个键最大能存储 512MB. 命令 介绍 SET key value 设置值 SETNX key value 如果 Key 存在返回 0 且修改不生效 SETEX key seconds value 指定有效期为 seconds 秒 SETRANGE key offset value 将 Key 对应的 Value 第 n 位后面的字符替换成 value MSET key value [key value ...] 一次设置多个值 MSETNX key value [key value ...] 类似 SETNX设置多个值如果 Key 存在则返回 0 且修改不生效 GET key 获取 Key 对应的值 GETSET key value 设置 Key 的值并返回 Key 的旧值 GETRANGE key start end 获取索引位置从 start 到 end 的 Key 对应值的字符串 MGET key [key ...] 一次获取多个 Key 对应的值如果不存在则返回 nil INCR key 对 Key 的值作 1 操作如果 INCR 一个不存在的值则对 Key 赋值为 1如果 Key 对应值不是 Int 类型则返回错误-ERR value is not an integer or out of range INCRBY key increment 加指定值 incrementKey 不存在的时候会设置 Key并认为原来的 Value 为 0 DECR key 对 Key 的值作 -1 操作DECR 一个不存在的 Key则设置 Key 为 -1 DECRBY key decrement 减指定值 APPEND key value 将 value 追加到 Key 对应的值的末尾返回新字符串的长度 STRLEN key 读取 Key 对应的 value 的长度 6.1.2 String 常用操作
1. 插入和读取一条 String 类型的数据 2. 对 String 类型数据进行增减前提是这条数据的 Value 可以看作数字 3. 一次性插入或者获取多条数据 4. 在插入一条 String 类型的数据的同时为它指定一个存活期限
如下所示test 只有 7 秒的存活期7 秒之后会自动删除 6.1.3 String 使用案例
1. 将对象序列化成 byte 数组
package cn.gldwolf.jedis;import redis.clients.jedis.Jedis;import java.io.*;/*** author: Gldwolf* email: ZengqiangZhaosina.com* date: 2019/6/16 22:47*/class Student implements Serializable { // 必须要实现序列化private String name;private String sex;private int age;public Student() {}public Student(String name, int age, String sex) {this.name name;this.age age;this.sex sex;}Overridepublic String toString() {return Student name: name , age: age , sex: sex;}
}public class TestJedisObject {public static void main(String[] args) throws IOException, ClassNotFoundException {// 创建一个 Jedis 连接对象Jedis jedis new Jedis(hdp01, 6379);Student student new Student(唐伯虎, 23, 男);// 将对象序列化成字节数组ByteArrayOutputStream baos new ByteArrayOutputStream();ObjectOutputStream oos new ObjectOutputStream(baos);// 用对象序列化流来将 student 对象序列化然后把序列化之后的二进制数据写到 baos 流中oos.writeObject(student);// 将 baos 转换成字节数组byte[] sBytes baos.toByteArray();// 将对象序列化之后的 byte 数组存到 Redis 的 String 数据结构中jedis.set(student_Tang.getBytes(), sBytes);// 根据 Key 从 Redis 中取出对象的 byte 数据byte[] response jedis.get(student_Tang.getBytes());// 将字节数据反序列化出对象ByteArrayInputStream bais new ByteArrayInputStream(response);ObjectInputStream ois new ObjectInputStream(bais);// 从对象读取流中读取出 responseStudent 对象Student responseStudent (Student)ois.readObject();System.out.println(responseStudent);}
}
2. 将对象转换成 JSON 字符串进行存储
package cn.gldwolf.jedis;import com.google.gson.Gson;
import redis.clients.jedis.Jedis;import java.io.*;/*** author: Gldwolf* email: ZengqiangZhaosina.com* date: 2019/6/16 23:00*/class Student { // 这种方式就不需要实现序列化private String name;private String sex;private int age;public Student() {}public Student(String name, int age, String sex) {this.name name;this.age age;this.sex sex;}Overridepublic String toString() {return Student name: name , age: age , sex: sex;}
}public class JedisClientDriver {public static void main(String[] args) throws IOException, ClassNotFoundException {// 创建一个 Jedis 连接对象Jedis jedis new Jedis(hdp01, 6379);Student student new Student(唐伯虎, 23, 男);// 利用 gson 将对象转成 json 串Gson gson new Gson();String pJson gson.toJson(student);// 将 json 串存入 Redisjedis.set(student_Tang, pJson);// 从 Redis 中取出对象的 json 串String responseJson jedis.get(student_Tang);// 将返回的 json 串解析成 Student 对象Student responseStudent gson.fromJson(responseJson, Student.class);System.out.println(responseStudent);}
}6.2 List -- 列表
6.2.1 List 使用概述
Redis 列表是简单的字符串列表按照插入顺序排序。我们可以添加一个元素到列表的头部左边或者尾部右边。 命令 介绍 LPUSH/RPUSH key value [value ...] 从头/尾部向 list 添加值返回 list 长度 LRANGE key start stop 返回 list 对应索引区间的值 LINSERT/RINSERT key BEFORE|AFTER pivot value 在 list 的 pivot 的前面/后面插入 value LSET key index value 将特定索引的值设置为 value, 注意如果 index 为负值则从 list 尾部开始算起 LREM key count value 从 list 中删除 count 个和 value 相同的值若 count 0则从链头算起若 count 0则从链尾算起若 count 0则删除全部 LTRIM key start stop 仅保留 list 中索引从 start 到 end 的值 LPOP/RPOP key 从头部/尾部删除元素同时返回该元素 RPOPLPUSH source destination 从 source 的尾部移除元素并添加到 destination 的头部最后返回被移除的元素值整个操作是原子性的如果 source 是空或者不存在则返回 nil LINDEX key index 返回 list 中 index 索引位置的元素 LLEN key 返回 list 的长度 6.2.2 List 应用案例
1. 需求描述
任务调度系统生产者不断产生任务放入 task-queue 排队消费者不断拿出任务来进行处理同时放入一个 temp-queue 队列暂存如果任务处理成功则清除 temp-queue否则将任务弹回 task-queue 2. 架构思路图解 3. 代码实现
TaskProducer.class
package cn.gldwolf.jedis;import redis.clients.jedis.Jedis;import java.util.Random;
import java.util.UUID;/*** author: Gldwolf* email: ZengqiangZhaosina.com* date: 2019/6/17 15:44*/public class TaskProducer {public static void main(String[] args) {Jedis jedis new Jedis(hdp01, 6379);Random random new Random();// 生成任务while (true) {try {// 生成任务的速度有一定的随机性在 1-2 秒之间Thread.sleep(random.nextInt(1000) 1000);// 生成一个 taskIdString taskId UUID.randomUUID().toString();// 往任务队列 task-queue 中插入第一次插入时task-queue 还不存在// 但是 lpush 方法会在 Redis 库中创建一个新的 list 数据jedis.lpush(task-queue, taskId);System.out.println(在任务队列中加入一个新的任务 taskId);} catch (InterruptedException e) {e.printStackTrace();}}}
}
TaskConsumer.class
package cn.gldwolf.jedis;import redis.clients.jedis.Jedis;import java.util.Random;
import java.util.UUID;/*** author: Gldwolf* email: ZengqiangZhaosina.com* date: 2019/6/17 11:31*/public class TaskConsumerForRedisList {public static void main(String[] args) {Jedis jedis new Jedis(hdp01, 6379);Random random new Random();while (true) {try {// 获取 taskId将 taskId 从 task-queue 中弹出并放到 temp-queue 队列中String taskId jedis.rpoplpush(task-queue, temp-queue);// 模拟处理任务的耗时Thread.sleep(1000);// 模拟有成功有失败的情况int nextInt random.nextInt(10);// 如果任务队列中没有任务则等待 0.5 秒if (jedis.llen(task-queue) 0) {Thread.sleep(500);} else {// 模拟失败的情况当 taskId 为 8 时设置任务处理失败if (nextInt 8) {// 失败的情况下需要将任务从 temp-queue 中弹回 task-ququejedis.rpoplpush(temp-queue, task-queue);System.out.println( 任务处理失败失败的任务 ID 为 taskId );} else {// 成功的情况下将任务从 temp-queue 中删除jedis.rpop(temp-queue);System.out.println(***** 任务处理成功任务 ID 为 taskId *****);}}} catch (InterruptedException e) {e.printStackTrace();}}}
}
6.3 Set -- 集合
6.3.1 Set 使用概述
Redis 的 Set 是 String 类型的无序集合。
集合是通过哈希表实现的所以添加、删除、查找的时间复杂度都是 O(1)。 命令 介绍 SMEMBERS key 查看 Set 中的元素 SADD key member [member ...] 向 Set 中插入 value成功插入则返回 1如果 Set 中已有这个 Value 则失败并返回 0 SREM key member [member ...] 删除 Set 中对应的 Value删除成功则返回 1若不存在则返回 0 SPOP key [count] 随机删除 Set 中的 count 个元素并返回其值 SDIFF key [key ...] 返回 Set1 中在 Set2 里不存在的元素 SDIFFSTORE destination key [key ...] 例SDIFFSTORE set3 set1 set2 将 Set1 中不在 Set2 中的元素保存在 Set3 中 SINTER key [key ...] 返回 Set1 和 Set2 中的共有元素 SINTERSTORE destination key [key ...] 将 Set1 和 Set2 中的共有元素保存到 Set3 中 SUNION key [key ...] 返回 Set1 和 Set2 的并集 SUNIONSTORE destination key [key ...] 将 Set1 和 Set2 的并集保存到 Set3 中 SMOVE source destination member 将 Set1 的 Value 移动到 Set2 中若 Value 存在于 Set1那么无论 Set2 是否已存在这个 Value都返回 1成功若 Value 不存在于 Set1则返回 0 失败 SCARD key 返回 Set 中的 Value 的个数 SISMEMBER key member 判断 member 是否存在于 Set 中存在则返回 1不存在则返回 0 SRANDMEMBER key [count] 随机返回 Set 中的 count 个元素 6.3.2 Set 使用案例
package cn.gldwolf.jedis;import redis.clients.jedis.Jedis;import java.util.Set;/*** author: Gldwolf* email: ZengqiangZhaosina.com* date: 2019/6/17 16:52*/public class SetTest {public static void main(String[] args) {Jedis jedis new Jedis(hdp01, 6379);jedis.sadd(Hadoop, HDFS, MapReduce, YARN, Zookeeper);jedis.sadd(Spark, Flume, Kafka, Redis, Zookeeper);// 判断一个元素是否属于指定的集合System.out.println(----------- 判断一个集合中是否存在某个值——sismember ----------);Boolean isExist jedis.sismember(Hadoop, HDFS);System.out.println(Are there HDFS in the Hadoop: isExist);// 求两个集合的差集System.out.println(----------- 两个集合的差集——sdiff ----------);SetString diff jedis.sdiff(Hadoop,Spark);for (String di : diff){System.out.println(di);}// 求两个集合的并集System.out.println(----------- 两个集合的并集——sunion ----------);SetString union jedis.sunion(Hadoop,Spark);for(String un : union){System.out.println(un);}// 求两个集合的交集System.out.println(----------- 两个集合的交集——sinter ----------);SetString intersect jedis.sinter(Hadoop,Spark);for(String inter : intersect){System.out.println(inter);}}
} 6.4 ZSet -- 有序集合
6.4.1 ZSet 使用概述
ZSet 和 Set 一样也是 String 类型元素的集合且不允许存在重复的元素。
不同的是每个元素都会关联一个 double 类型的分数scoreRedis 正是通过分数来为集合中的成员进行从小到大的排序。
ZSet 的成员是唯一的但分数score却可以重复。 命令 介绍 ZADD key [NX|XX] [CH] [INCR] score member [score member ...] 如果 Zset 中不存在这个元素则向 ZSet 中添加一个或多个元素同时返回 1。或者对一个已经存在的元素更新其 score 同时返回 0 ZRANGE key start stop [WITHSCORES] 根据 index 返回给定范围内的元素WITHSCORES 为可选表示是否同时显示元素对应的 score ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count] 根据 score 返回给定范围内的元素WITHSCORES 为可选表示是否同时返回元素对应的 score ZREM key member [member ...] 删除 ZSet 中的一个或多个元素 ZINCRBY key increment member 如果 ZSet 中存在这个元素则对这个元素的 score 作 increment 的操作否则添加这个元素并设置其 score 为 increment ZRANK key member 返回这个元素在 ZSet 中根据 score 的排名排名按 score 从小到大 ZREVRANK key member 返回这个元素在 ZSet 中根据 score 的排名排名按 score 从大到小 ZCOUNT key min max 根据给定的 score 范围返回元素的个数 ZCARD key 返回 ZSet 中的元素的个数 ZSCORE key member 获取元素对应的 score ZREMRANGEBYRANK key start stop 删除给定的索引范围内的所有元素索引按 score 从小到大排序生成 ZREMRANGEBYSCORE key min max 删除给定的 score 范围内的所有元素 6.4.2 ZSet 使用案例
1. 案例需求KPL 中英雄使用率排行榜 1在 Redis 中需要一个榜单所对应的 sorted set 数据 2玩家每选择一个英雄打一场游戏就对 sorted set 数据对应的英雄分数 1 3在查看榜单时就调用 ZRANGE 来看榜单中的排序结果 2. 代码实现
模拟游戏玩家的选择
package cn.gldwolf.jedis;import redis.clients.jedis.Jedis;import java.util.Random;/*** author: Gldwolf* email: ZengqiangZhaosina.com* date: 2019/6/17 21:29*/public class KPLPlayer {public static void main(String[] args) throws InterruptedException {Jedis jedis new Jedis(hdp01, 6379);Random random new Random();String[] heros {李白, 孙悟空, 韩信, 赵云, 后羿, 鲁班, 妲己};while (true) {int index random.nextInt(heros.length);// 选择一个英雄String hero heros[index];// 开始玩游戏Thread.sleep(100);// 给集合中的该英雄的出场次数 1// 第一次添加的时候集合不存在此时使用 zincrby 方法会创建jedis.zincrby(Heros_rank, 1, hero);System.out.println(*** hero 出场了***);}}
}
查看排行榜
package cn.gldwolf.jedis;import redis.clients.jedis.Jedis;
import redis.clients.jedis.Tuple;import java.util.Set;/*** author: Gldwolf* email: ZengqiangZhaosina.com* date: 2019/6/17 21:56*/public class KPLViewer {public static void main(String[] args) throws InterruptedException {Jedis jedis new Jedis(hdp01, 6379);for (int i 0; ; i){// 每隔两秒查看一次榜单Thread.sleep(2000);System.out.println( 第 i 次查看榜单 );// 查看榜单的SetTuple herosRankWithScore jedis.zrevrangeWithScores(Heros_rank, 0, 5);for (Tuple hero : herosRankWithScore) {System.out.println(hero.getElement() : hero.getScore());}}}
} 6.5 Hash -- 哈希表
6.5.1 Hash 使用概述
Redis Hash 是一个键值对集合。
Redis Hash 类型可以看成是具有 String Key 和 String Value 的 Map 容器。
Redis Hash 是一个 String 类型的 field 和 value 的映射表Hash 特别用于存储对象. 命令 介绍 HSET key field value 给 object 对象添加属性和值 HSETNX key field value 类似 HSET如果 field 已存在则返回 0 且修改不生效 HMSET key field value [field value ...] 同时设置多个属性及其值 HGET key field 获取对象的属性的值 HMGET key field [field ...] 获取对象的多个属性的值 HINCRBY key field increment 给对象的属性的值增加 increment HEXISTS key field 判断对象指定的 field 是否存在存在则返回 1不存在则返回 0 HLEN key 返回对象 fields 的数量 HDEL key field [field ...] 删除对象的一个或多个 field HKEYS key 返回对象所有的 field HVALS key 返回对象所有的 field 对应的 value HGETALL key 返回对象所有的 field 和 value 6.5.2 Hash 案例
1. 案例需求实现购物车
需求分析1加入购物车 2查询购物车 3修改购物车 4清空购物车
2. 代码实现
package cn.gldwolf.jedis;import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import redis.clients.jedis.Jedis;import java.util.Map;
import java.util.Set;/*** author: Gldwolf* email: ZengqiangZhaosina.com* date: 2019/6/18 10:12*/public class CartServiceByRedis {private Jedis jedis null;Beforepublic void init() {jedis new Jedis(hdp01, 6379);}/*** 添加商品到购物车*/Testpublic void addItemsToCart() {jedis.hset(ZZQ, AirDots, 3);jedis.hset(Gldwolf, AirPods, 10);jedis.hset(JJ, Honor 20Pro, 1);}/*** 查询购物车的商品信息*/Testpublic void getCartInfo() {MapString, String goodsInfo jedis.hgetAll(JJ);SetMap.EntryString, String entrySet goodsInfo.entrySet();for (Map.EntryString, String entry : entrySet) {System.out.println(JJ: entry.getKey() -- entry.getValue());}}/*** 更改购物车信息*/Testpublic void modifyCart() {// 把 Gldwolf 选购的 AirPods 的数量增加 5jedis.hincrBy(Gldwolf, AirPods, 5);}/*** 从购物车中删除商品*/Testpublic void deleteGoods() {jedis.hdel(ZZQ, AirDots);}Afterpublic void closeRedis() {jedis.close();}
}
6.6 键值相关的命令 命令 介绍 返回值 KEYS pattern 查询满足 pattern 的键 返回满足条件的 Key EXISTS key [key ...] 判断一个 Key 是否存在 存在返回 1不存在返回 0 DEL key [key ...] 删除一个或多个 Key 返回删除的 Key 的数量 EXPIRE key seconds 设置一个 Key 的到期时间以秒为单位 设置成功返回 1Key 不存在或不能被设置返回 0 EXPIREAT key timestamp 设置一个 Key 在指定时间戳之时到期 设置成功返回 1Key 不存在或不能被设置返回 0 TTL key 查询 Key 的有效时长 返回时长如果该键不存在或没有超时设置则返回 -1 MOVE key db 将当前数据库中的 Key 移动到其他数据库中 成功返回 1否则返回 0 PERSIST key 移除给定 Key 的到期时间 成功返回 1如果该 Key 不存在或没有设置过期时间则返回 0 RANDOMKEY - 随机获取一个 Key 返回一个随机获取的 Key RENAME key newkey 重命名 Key如果 newKey 已经存在则覆盖 如果 Key 不存在则返回错误信息否则返回 OK RENAMENX key newkey 如果 newKey 存在则失败且返回 0否则 重命名 Key 成功返回 1否则返回 0 TYPE key 查询 Key 的类型 返回 Key 的类型 6.7 服务器相关命令 命令 介绍 SELECT index 选择数据库Redis 数据库编号为 0-15 QUIT - 退出 ECHO message 打印 message DBSIZE - 返回当前数据库中 Key 的数量 INFO [section] 获取服务器的信息和统计 FLUSHDB - 删除当前选择数据库中的所有 Key FLUSHALL - 删除所有数据库中的所有的 Key跑路 6.8 Redis 事务
可以一次执行多个命令本质是一组命令的集合。一个事务中的所有命令都会序列化按照顺序串行化执行而不会被其它命令插入不允许加塞。 命令
discard: 取消事务放弃执行事务块内的所有命令
exec: 执行事务块内的命令
multi: 标记一个事务块的开始
unwatch: 取消 watch 对所有 Key 的监视
watch: 监视一个或多个 Key如果在事务执行之前被其他命令所改动那么事务被打断 不保证原子性Redis 同一个事务中如果有一条命令执行失败其后的命令仍然会被执行没有回滚
Note: 1如果中间一条命令语法写错了则全部撤销 2运行时报出异常只撤销异常的语句 7. Redis 的高可用
在 Web 服务器中高可用是指服务器可以正常访问的时间衡量的标准是在多长时间内可以提供正常服务99.9%, 99.99% 等。但是在 Redis 语境中高可用的含义不仅仅是能提供正常的服务如主从分离快速容灾技术还要保证数据的安全性以及数据容量的可扩展性。
在 Redis 中实现高可用的技术主要包括持久化、复制、哨兵和集群。解释说明如下
1. 持久化
持久化是最简单的高可用方法有时甚至不被归为高可用的手段主要作用是数据备份即将数据存储到硬盘保证数据不会因进程的退出而丢失。
2. 主从复制
复制是高可用 Redis 的基础哨兵和集群都是在复制的基础上实现高可用的。复制主要实现了数据的多机备份以及对于读操作的负载均衡和简单的故障恢复。缺陷故障恢复无法自动化写操作无法负载均衡存储能力受到单机的限制。
3. 哨兵
哨兵在复制的基础上哨兵实现了自动化的故障恢复。缺陷写操作无法负载存储能力受到单机的限制。
4. 集群
通过集群Redis 解决了写操作无法负载均衡以及存储能力受到单机限制的问题实现了较为完善的高可用方案。 8. Redis 的持久化
持久化功能Redis 是内存数据库数据都是存储在内存中为了避免进程退出导致数据的永久丢失需要定期将 Redis 中的数据以某种形式数据或命令从内存中持久化到磁盘。当下次重启 Redis 时利用持久化的文件实现数据恢复。除此之外为了进行灾难备份可以将持久化文件拷贝到一个远程位置。
Redis 的持久化分为
RDB 持久化
AOP 持久化
RDB 持久化原理将 Redis 在内存中的数据库记录定时 dump 到磁盘上的 RDB 持久化
AOF 持久化原理将 Redis 的操作日志依次以追加的方式写入磁盘文件类似于 MySQL 的 binlog
由于 AOF 持久化的实时性更好即当进程意外退出时丢失的数据更少因此 AOF 是目前主流的持久化方式不过 RDB 持久化仍然有其用武之地。 8.1 RDB 持久化
RDB 持久化是批在指定时间间隔内将内存中的数据集快照写入磁盘因此也称作快照持久化实际操作过程是 fork 一个子进程先将数据集写入临时文件保存的文件后缀是 .rdb写入成功后再替换之前的文件用二进制压缩存储。当 Redis 重新启动时可以读取快照文件恢复数据。
有两个触发条件
1. 手动方式
save 命令和 bgsave 命令都可以生成 RDB 文件。
save 命令会阻塞 Redis 服务器进程直到 RDB 文件创建完毕为止在 Redis 服务器阻塞期间服务器不能处理任何命令请求。
而 bgsave 命令会创建一个子进程由子进程来负责创建 RDB 文件父进程即 Redis 主进程则继续响应处理请求。
bgsave 命令执行过程中只有 fork 子进程时会阻塞服务器而对于 save 命令整个过程都会阻塞服务器因此 save 已基本废弃线上环境要杜绝 save 的使用。此外在自动触发 RDB 持久化时Redis 也会选择 bgsave 而不是 save 来进行持久化。
2. 自动触发
save m n
自动触发最常见的情况是在配置文件中通过 save m n指定当 m 秒内发生 n 次变化时会触发 bgsave。 save 900 1 -- 在 900 秒内如果超过 1 个 Key 被修改就发起快照保存
save 300 10 -- 在 300 秒内如果超过 10 个 Key 被修改就发起快照保存
save 60 10000 -- 在 60 秒内如果超过 10000 个 Key 被修改就发起快照保存 8.2 AOF 持久化
AOF 比快照方式有更好的持久化性是由于在使用 AOF 持久化方式时Redis 会将每一个收到的写命令都通过 write 函数追加到文件中默认是 appendonly.aof。当 Redis 重启时会通过重新执行文件中保存的命令来在内存中重建整个数据库的内容。
当然由于 os 会在内核中缓存 write 做的修改所以可能不是立即写到磁盘上这样 AOF 方式的持久化也还是有可能会丢失部分修改。不过我们可以通过配置文件告诉 Redis 我们想要通过 fsync 函数强制 os 写入到磁盘的时机。有如下三种方式默认是每秒 fsync 一次
appendonly yes # 启用 AOF 持久化方式 # appendfsync always # 每次收到写命令就立即强制写入磁盘最慢的但是保证完全的持久化不推荐使用 appendfsync everysec # 每秒种强制写入磁盘一次在性能和持久化方面做了很好的折衷推荐 # appendfsync no # 完全依赖 os, 性能最好但是持久化没有保证 8.3 总结
相同数据集的数据 AOF 文件要远大于 RDB 文件恢复速度慢于 RDB
AOF 运行效率要慢于 RDB每秒同步策略效率较好不同步效率和 RDB 相同
Redis 还能对 AOF 文件进行后台重写使得 AOF 文件的体积不至于过大
总结
RDB 持久化方式能够在指定的时间间隔内对数据进行快照存储
AOF 持久化方式记录每次对服务器写的操作当服务器重启的时候会重新执行这些命令来恢复原始的数据AOF 命令以 Redis 协议追加保存每次写的操作到文件末尾