Redis
Redis
一.基本指令
|
|
二.Redis的五大数据类型
1.String(使用最多)
|
|
2.List
单键多值
底层是双向链表 对两端的操作性高,通过索引操作中间节点性能较差
|
|
3.Set
与list功能类似 但是value不能重复
String类型的无序集合
底层是value为空的hash表
删除查找的复杂度都是O(1)
|
|
4.Hash
是键值对集合
适合存储对象
类似java中的 Map<String,String>
|
|
5.ZSet
在Set的基础上加上评分
|
|
使用zset实现文章访问量的排行
|
|
三.Redis的相关配置
- ip地址绑定
- 默认 “bind 127.0.0.1”只接受本机访问
- 使其他机器访问解决方法
- 注释“bind 127.0.0.1” 取消绑定id
- “protected-mode yes” yes改为no 关闭保护模式
- tcp-backlog
- 默认“tcp-backlog 511”
- 可以理解为请求到达后至进程处理前的队列
- timeout
- 一个空闲的客户端维持多长时间(秒)会关闭,0代表永不关闭,默认0
- tcp-keepalive
- 对客户端的心跳检测 官方推荐60s
- daemonize
- 是否为后台进程
- pidfile
- 存放pid文件的位置
- loglevel
- 默认 loglevel notice
- 日志级别 四个等级
- database
- 设定库的数量 默认16
- maxclient
- 最大客户端链接数
- maxmemory
- 设置内存量
- 超过后 会根据maxmemory-policy指定移除
- maxmemory-policy
- volatile-lru 使用LRU(最近最少使用)算法移除key,只对设置了过期时间的键
- allkeys-lru 使用LRU算法移除key
- volatile-random 在过期集合中移除key,只对设置了过期时间的键
- allkeys-random 随机移除
- volatile-ttl(即将过期) 移除ttl最小的key
- noeviction 不移除(头铁 等着报错)
- maxmemory-samples
- 设置样本大小
- 3-7 一般3或5
四.连接java(SSM)
-
jar:
- jedis-xxx.jar
-
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
package com.jsh; import redis.clients.jedis.Jedis; public class Test { public static void main(String[] args) { Jedis jedis = new Jedis("127.0.0.1",6379); String result = jedis.ping(); System.out.println(result); // jedis.set("a","a"); jedis.get("a"); System.out.println("a"); jedis.close(); } }
手机短信验证例子
- 前端
|
|
-
controller
-
模拟接收短信验证码并缓存
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
@WebServlet("/CodeSenderServlet") public class CodeSenderServlet extends HttpServlet { private static final long serialVersionUID = 1L; /** * @see HttpServlet#HttpServlet() */ public CodeSenderServlet() { super(); // TODO Auto-generated constructor stub } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //获取手机号 String phone_no = request.getParameter("phone_no"); //模拟获取验证码 String code = getCode(6); //拼接key String codeKey = "Verify_code:" + phone_no + ":code";//Verify_code:12345:code String countKey = "Verify_code:" + phone_no + ":count"; Jedis jedis = new Jedis("127.0.0.1", 6379); //判断发送验证码的次数 String count = jedis.get(countKey); if(count == null) { //代表第一次 jedis.setex(countKey, 24*60*60, "1"); }else if(Integer.parseInt(count) <= 2) { jedis.incr(countKey); }else if(Integer.parseInt(count) > 2) { response.getWriter().print("limit"); jedis.close(); return ; } //向redis中进行存储,以手机号为键,以验证码为值 jedis.setex(codeKey, 120, code); jedis.close(); response.getWriter().print(true); } //模拟短信 private String getCode(int length) { String code = ""; Random random = new Random(); for(int i = 0; i < length; i++) { int rand = random.nextInt(10); code += rand; } return code; } }
-
从缓存中取出返回到前端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
package com.atguigu.servlet; @WebServlet("/CodeVerifyServlet") public class CodeVerifyServlet extends HttpServlet { private static final long serialVersionUID = 1L; /** * @see HttpServlet#HttpServlet() */ public CodeVerifyServlet() { super(); // TODO Auto-generated constructor stub } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //获取验证码和手机号 String phone_no = request.getParameter("phone_no"); String verify_code = request.getParameter("verify_code"); //拼接key String codeKey = "Verify_code:" + phone_no + ":code"; //从redis中获取手机号所对应的验证码 Jedis jedis = new Jedis("127.0.0.1", 6379); String code = jedis.get(codeKey); if(code.equals(verify_code)) { response.getWriter().print(true); } jedis.close(); } }
-
五.Redis事务
- 编译出错会直接取消 例如:单词拼写错误
- 某一步如果在运行时出错 只会取消那一步的操作
|
|
演示
|
|
监视
|
|
三特性
- 单独的隔离操作:事务中的所有命令都会序列化,按顺序的执行。事务在等待执行的时候,不会被其他客户端发送来的米命令请求打断
- 没有隔离级别的概念:队列中的所有命令没有提交exec之前都是不会被执行的
- 不保证原子性:redis中如果一条命令执行失败,其后的命令仍然会被执行,没有回滚
六.持久化
RDB
在指定的时间间隔内生成内存中整个数据集的持久化快照。快照文件默认被存储在当前文件夹中,名称为
dump.rdb
,可以通过dir和dbfilename参数来修改默认值。恢复数据特别快,节省空间,存储的是数据
Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。 整个过程中,主进程是不进行任何的IO操作的,这就确保了极高的性能。
缺点:最后一次持久化后数据可能丢失
配置文件
|
|
触发条件
-
通过配制文件中的save条件(可自己配置)
1 2 3
save 900 1 save 300 10 save 60 10000
-
手动通过save和bgsave命令
- save:save时只管保存,其他不管,全部阻塞
- bgsave:redis会在后台异步的进行快照操作,同时还可以响应客户端请求。可以通过lastsave命令获取最后一次成功执行快照的事件
如何恢复
- 关闭Redis
- 把备份的文件拷贝到工作目录下
- 启动Redis,会自动加载
AOF
以日志的形式来记录每个写操作,将Redis执行过的所有写指令记录下来(读操作补不可记录),只许追加文件但不可以改写文件,redis启动之初会读取改文件重新构建数据。保存的是appendonly.aof文件
aof机制默认关闭,可以通过
appendonly = yes
参数开启aof机制,通过appendfilename = myaoffile.aof
指定aof文件名称。
|
|
对于触发aof重写机制也可以通过配置文件来进行设置:
|
|
|
|
如何恢复
正常恢复
将文件放到dir指定的文件夹下,当redis启动的时候会自动加载数据,注意:aof文件的优先级比dump大
。
异常恢复
-
有些操作可以直接到appendonly.aof文件里去修改。
eg:使用了flushall这个命令,此刻持久化文件中就会有这么一条命令记录,把它删掉就可以了
-
写坏的文件可以通过
redis-check-aof --fix
进行修复
优势
- 根据不同的策略,可以实现每秒,每一次修改操作的同步持久化,就算在最恶劣的情况下只会丢失不会超过两秒数据。
- 当文件太大时,会触发重写机制,确保文件不会太大。
- 文件可以简单的读懂
劣势
- aof文件的大小太大,就算有重写机制,但重写所造成的阻塞问题是不可避免的
- aof文件恢复速度慢。
总结
-
如果你只希望你的数据在服务器运行的时候存在,可以不使用任何的持久化方式
-
一般建议同时开启两种持久化方式。AOF进行数据的持久化,确保数据不会丢失太多,而RDB更适合用于备份数据库,留着一个做万一的手段。
-
性能建议:
因为RDB文件只用做后备用途,建议只在slave上持久化RDB文件,而且只要在15分钟备份一次就够了,只保留900 1这条规则。
如果Enalbe AOF,好处是在最恶劣情况下也只会丢失不超过两秒数据,启动脚本较简单只load自己的AOF文件就可以了。代价:1、带来了持续的IO;2、AOF rewrite的最后将rewrite过程中产生的新数据写到新文件造成的阻塞几乎是不可避免的。只要硬盘许可,应该尽量减少AOF rewrite的频率,AOF重写的基础大小默认值64M太小了,可以设到5G以上。默认超过原大小100%大小时重写可以改到适当的数值。
如果不Enable AOF,仅靠Master-Slave Replication 实现高可用性也可以。能省掉一大笔IO也减少了rewrite时带来的系统波动。代价是如果Master/Slave同时宕掉,会丢失10几分钟的数据,启动脚本也要比较两个Master/Slave中的RDB文件,载入较新的那个。新浪微博就选用了这种架构。
七.复制(master/slaver)
就是我们常说的主从复制,主机数据更新后根据配置和策略,自动同步到备机的master/slaver机制,Master以写为主,Slave以读为主
读写分离
容灾恢复
主服务器用来写
从服务器用来读
不管何时 从机都和主机数据相同
主机shutdown后,从机等待
配置(配置从服务器,不配置主服务器)
- 拷贝多个redis文件include
- 开启daemonize yes
- Pid文件名字pidfile
- 指定端口port
- Log文件名字
- Dump.rdb名字dbfilename
- Appendonly关掉或者换名字
- 如果要永久 在配置文件中 配置 slaveof
命令
|
|
薪火相传
含义:就是上一个Slave可以是下一个slave的Master,Slave同样可以接收其他slaves的连接和同步请求,那么该slave作为了链条中下一个的master,可以有效减轻master的写压力。
哨兵模式
反客为主的自动版,能够后台监控Master库是否故障,如果故障了根据投票数自动将slave库转换为主库。一组sentinel能同时监控多个Master。
使用步骤:
-
在Master对应redis.conf同目录下新建sentinel.conf文件,名字绝对不能错;
-
配置哨兵,在sentinel.conf文件中填入内容(可以配置多个):
1 2
#说明:最后一个数字1,表示主机挂掉后slave投票看让谁接替成为主机,得票数多少后成为主机。 sentinel monitor 被监控数据库名字(自己起名字) ip port 1
-
启动哨兵模式(路径按照自己的需求进行配置):
1
redis-sentinel /myredis/sentinel.conf
注意:
- 当master挂掉后,会通过选票进行选出下一个master。而且只有使用了sentinel.conf启动的才能开启选票
- 当原来的master后来后,很不幸变成了slave。
八.Redis集群(以后再学)
实现了水平扩容,启动N个节点,将整个数据库储存分布在N个节点中,每个节点存储数据的1/N