Redis常规操作
- 默认16个数据库
- 安装完后,在/usr/local/redis/bin下有几个可执行文件
- redis-benchmark ----性能测试工具
- redis-check-aof ----AOF文件修复工具
- redis-check-dump ----RDB文件检查工具(快照持久化文件)
- redis-cli ----命令行客户端
- redis-server ----redis服务器启动命令
Redis启动
- 前端模式直接运行bin/redis-server将以前端模式启动,前端模式启动的缺点是启动完成后,不能再进行其他操作,如果要操作必须使用ctrl+c,同时redis-server程序结束,不推荐使用此方法。
- 后端模式修改redis.conf配置文件, daemonize yes 以后端模式启动。
- 启动时,
cd /usr/local/redis/ //进入指定文件夹 ./bin/redis-server ./redis.conf //使用指定配置过的配置文件启动
- Redis默认端口6379,通过当前服务进行查看
ps -ef | grep -i redis
- 连接客户端
- 在redis的安装目录中有redis的客户端,即redis-cli(Redis Command Line Interface),它是Redis自带的基于命令行的Redis客户端。
redis-cli -h ip地址 -p 端口
Redis停止
- 强制结束程序。强行终止Redis进程可能会导致redis持久化数据丢失。
kill -9 31475 #pid需要通过“ps aux | grep -i redis”进行查询
- 正确停止Redis的方式应该是向Redis发送SHUTDOWN
cd /usr/local/redis
./bin/redis-cli shutdown
数据类型
- STRING 字符串
- 可以是字符串,整数或者浮点数;
- 可以对字符串的部分或整体进行操作;对整数和浮点数进行自增自减的操作;
- HASH 散列(类似于Map)
- 包括键值对的无需列表;
- 添加、获取、移除单个元素;获取所有键值对;
- LIST 有序链表
- 一个链表,链表上的节点包含了一个字符串;
- 从链表两端推入或弹出元素;根据偏移量对链表进行裁剪;读取单个或多个元素;根据值查找或移除元素;
- SET 字符串集合
- 去重,无需的字符串集合
- 添加、获取、移除单个元素;检查一个元素是否存在于集合中;计算交集、并集、差集;从集合里面随机获取元素;
- ZSET 有序字符串集合
- 字符串成员与浮点数分值之间的有序映射,元素的排列顺序由分值的大小决定 ;
- 添加、获取、删除单个元素;根据分值范围或成员来获取元素;
每个数据类型的增查改删
String类型的增查改删
- 必须:
- 增: set 键 值
- 查: get 键
- 改: set 旧键 新值
- 删: del 键
- 其他:
- getset 键 值 //先设置再获取
- incr 键 //相当于 Java的自增,自增的键对应的值必须是数字,键不存在设置默认值为 0,自增后为1
- decr 键 //相当于 Java 的自减
- 扩展命令
- incrby 键 增量 //指定键自增指定增量,增量必须是数字
- decrby 键 减量 //指定键自减指定减量,减量必须是数字
- append 键 值 //将值拼接在指定键的值后面后,注意是拼接字符串!!
hash类型的增查改删
//相当于 Java 的 HashMap
- 必须:
- 增:
- hset 集合名称 field value //设置单个键值对
- hmset 集合名称 field1 value1 field2 value2 ... //设置多个键值对
- 查:
- hget 集合名称 field //获取集合中一个字段对应的值
- hmget 集合名称 field1 field2 .... //获取集合中指定多个字段对应的值
- hgetall 集合名称 //直接获取集合所有键值对
- 改: hset 集合名称 旧field 新value
- 删:
- hdel 集合名称 field //删除集合中指定字段
- del 集合名称 //删除集合
- 增:
- 扩展命令
- hincrby 集合 字段 增量 //集合中指定字段对应数字,自增
- hexists 集合 字段 //判断集合中指定字段是否存在
- hlen 集合 //集合中储存的字段数量
- hkeys 集合 //获得所有的字段
- hvals 集合 //获取所有字段对应的值
list类型的增查改删
- //相当于 Java 的 LinkedList,特点:可执行两端操作
- 增:
- lpush 集合 元素1 元素2 元素3 ... // ... 元素3 元素2 元素1 存储和添加反序
- rpush 集合 元素1 元素2 元素3 ... // 元素1 元素2 元素3 ... 存储和添加一致
- 查:
- lrange 集合 开始索引 结束索引 // 结束索引可以使用负数 -n 代表倒数第n个
- llen 集合 //获取集合中元素的个数
- 改: lset 集合 索引 新值
- 删:
- lpop 集合 //删除并返回第一个元素
- rpop 集合 //删除并返回最后一个元素
- 扩展命令
- lpushx 集合 元素 //当集合存在时,向头部添加,一次只能添加一个
- rpushx 集合 元素 //当集合存在时,向尾部添加,一次只能添加一个
- lrem 集合 count 元素//如果count是正数,从头开始删除count个指定元素;如果count是负的,从尾部开始;如果count是0,删除所有的指定元素
- lset 集合 脚标 新元素 //修改集合中指定脚标的元素
- linsert 集合 before|after 指定元素 元素 //在第一个指定元素之前或之后添加元素
- rpoplpush resource destination //将链表中的尾部元素跳出并添加到头部
- rpoplpush的使用场景:
- Redis链表经常会被用于消息队列的服务,以完成多程序之间的消息交换。假设一个应用程序正在执行LPUSH操作向链表中添加新的元素,我们通常将这样的程序称之为"生产者(Producer)",而另外一个应用程序正在执行RPOP操作从链表中取出元素,我们称这样的程序为"消费者(Consumer)"。如果此时,消费者程序在取出消息元素后立刻崩溃,由于该消息已经被取出且没有被正常处理,那么我们就可以认为该消息已经丢失,由此可能会导致业务数据丢失,或业务状态的不一致等现象的发生。然而通过使用RPOPLPUSH命令,消费者程序在从主消息队列中取出消息之后再将其插入到备份队列中,直到消费者程序完成正常的处理逻辑后再将该消息从备份队列中删除。同时我们还可以提供一个守护进程,当发现备份队列中的消息过期时,可以重新将其再放回到主消息队列中,以便其它的消费者程序继续处理。
set类型的增查改删
- //相当于 Java 的 HashSet,无序不能存储重复元素
- 增: sadd 集合 元素1 元素2 .... //无序 不能重复
- 查:
- smembers 集合 //获取所有元素
- sismember 集合 值 //查询某个值是否是集合元素 0 为 false 1 为 true
- 改: 无
删: srem 集合 元素
- 集合运算(特有):
- 交集: sinter 集合A 集合B
- 并集: sunion 集合A 集合B
- 差集: sdiff 集合A 集合B
- 扩展命令
- scard key:获取set中成员的数量
- srandmember key:随机返回set中的一个成员
- sdiffstore destination key1 key2…:将key1、key2相差的成员存储在destination上
- sinterstore destination key[key…]:将返回的交集存储在destination上
- sunionstore destination key[key…]:将返回的并集存储在destination上
- 使用场景
-
- 可以使用Redis的Set数据类型跟踪一些唯一性数据,比如访问某一博客的唯一IP地址信息。对于此场景,我们仅需在每次访问该博客时将访问者的IP存入Redis中,Set数据类型会自动保证IP地址的唯一性。
- 2.充分利用Set类型的服务端聚合操作方便、高效的特性,可以用于维护数据对象之间的关联关系。比如所有购买某一电子设备的客户ID被存储在一个指定的Set中,而购买另外一种电子产品的客户ID被存储在另外一个Set中,如果此时我们想获取有哪些客户同时购买了这两种商品时,Set的intersections命令就可以充分发挥它的方便和效率的优势了。
-
zSet类型的增查改删
- //相当于 Java 的 TreeSet,特点:排序
- 增: zadd 集合 分数1 元素1 分数2 元素2 .... //按照分数排序
- 查:
- zscore 集合 元素 //元素分数查询
- zrank 集合 元素 //元素的排名
- zcard 集合 //查询元素个数
- zrange 集合 开始索引 结束索引 [withscores] //查询指定区间的元素 [带分数查询],升序
- zrevrange集合 开始索引 结束索引 [withscores] //查询指定区间的元素 [带分数查询],降序
- 改: zadd 集合 新分数 旧元素 //修改指定元素的分数
- 删: zrem 集合 元素
- 扩展命令
- zrangebyscore key min max [withscores] [limit offset count]:返回分数在[min,max]的成员并按照分数从低到高排序。[withscores]:显示分数;[limit offset count]:offset,表明从脚标为offset的元素开始并返回count个成员。
- zincrby key increment member:设置指定成员的增加的分数。返回值是更改后的分数。
- zcount key min max:获取分数在[min,max]之间的成员
- zrank key member:返回成员在集合中的排名。(从小到大)
- zrevrank key member:返回成员在集合中的排名。(从大到小)
key操作
- 增: 上述五种数据类型增的操作
- 查:
- keys 正则表达式
- type 键 //获取键对应的值的数据类型
- exists 键 //判断某个键是否存在 0 为 false 1 为 true
- expire 键 秒数 //设置键的存活时间
- ttl 键 //获取键的剩余存活时间 -1 没有时间限制, -2 已经超时被销毁
- 改: rename 旧键名 新键名
- 删: del 键
Jedis
类似JDBC
- 导入相关jar包
- 在Java程序与Redis之间创建一个连接
- Jedis conn = new Jedis("192.168.18.136", 6379);
- 连接之上通过Jedis的API操作Redis
- conn.set("china","北京");
- String value = conn.get("china");
- System.out.println(value);
- 释放Jedis连接
conn.close();
当Java程序与外部交互时,交互完毕必须释放资源
==Jedis的方法与Redis的操作语句一一对应==
Jedis连接池
- 创建连接池
JedisPoolConfig poolConfig = new JedisPoolConfig();//创建JeidsPoolConfig()对象
- 设置连接池的相关信息
poolConfig.setMaxTotal(100);//最大连接数
poolConfig.setMaxIdle(30);//最大空闲连接数
poolConfig.setMinIdle(20);//最小空闲连接数
- 根据配置信息创建连接池对象
JedisPool jedisPool = new JedisPool(poolConfig, "192.168.18.136",6379);//new JedisPool(连接池配置,路径,端口号)
- 使用Jedis时从连接池获取Jedis连接,然后使用
jedis = jedisPool.getResource();//获取jedis对象
- 使用完毕,将Jedis放回连接池
jedisPool.returnResource(jedis)
jedis.close();//在3.0以后,使用这个方法
Redis特性
多数据库
- Redis默认帮我们创建==16==个数据库
- 选择数据库----- select 数据库编号
移动数据库-----
服务器命令
消息订阅与发布
相关命令:
- subscribe 频道名 //订阅给定的一个或多个频道
- unsubscribe 频道名 //退订频道,如果没有指定频道名,退订所有频道
- publish 频道名 信息 //给指定频道发信息
- psubscribe 模式的正则表达式 //订阅与给定模式相匹配的所有频道
- punsubscribe 模式的正则表达式 //退订给定的模式,如果没有给定模式,退订所有模式
相对其他消息队列,redis的功能并不是很强,jedis相关命令不仔细看了
Redis 事务
命令
- MULTI 开启事务
- EXEC 执行命令
- DISCARD 取消事务,放弃执行事务块内的所有命令
- WATCH key... 监视一个或多个key,如果在食物执行之前这些key被其他命令改动,事务将被打断
- UNWATCH 取消WATCH命令对key的监视
基本事务
Redis基本事务会在MULTI执行后开启事务,将接下来的命令加入队列,在接收到EXEC命令之后按顺序执行所有队列中的
单个 Redis 命令的执行是原子性的,但 Redis 没有在事务上增加任何维持原子性的机制,所以 Redis 事务的执行并不是原子性的。
事务可以理解为一个打包的批量执行脚本,但批量指令并非原子化的操作,中间某条指令的失败不会导致前面已做指令的回滚,也不会造成后续的指令不做
WATCH、UNWATCH、DISCARD命令
WATCH命令可以监控一个或多个键,一旦其中有一个键被修改(或删除),之后的事务就不会执行,监控一直持续到EXEC命令(事务中的命令是在EXEC之后才执行的,EXEC命令执行完之后被监控的键会自动被UNWATCH)
如果在使用WATCH命令监视key的时候使用DISCARD,不仅会取消事务,同事也会UNWATCH取消所有WATCH
Redis事务错误处理
语法错误:就像上面的例子一样,语法错误表示命令不存在或者参数错误,这种情况需要区分Redis的版本,Redis 2.6.5之前的版本会忽略错误的命令,执行其他正确的命令,2.6.5之后的版本会忽略这个事务中的所有命令,都不执行,就比如上面的例子(使用的Redis版本是2.8的)
运行错误 运行错误表示命令在执行过程中出现错误,比如用GET命令获取一个散列表类型的键值。这种错误在命令执行之前Redis是无法发现的,所以在事务里这样的命令会被Redis接受并执行。如果食物里有一条命令执行错误,其他命令依旧会执行(包括出错之后的命令)
键的过期时间
- PERSIST key-name //移除键的过期时间
- TTL key-name //查看给定键距离过期还有多少秒
- EXPIRE key-name seconds //指定键在多少秒后过期
- EXPIREAT key-name timestamp //指定键在给定的UNIX时间戳的时候过期
- PTTL key-name //查看给定键距离过期还有多少毫秒(2.6版本之后可用)
- PEXPIRE key-name milliseconds //指定键在多少毫秒之后过期(2.6版本之后可用)
- PEXPIREAT key-name timestamp-milliseconds //将一个毫秒级精度的UNIX时间戳设置为给定键的过期时间(2.6版本之后可用)
Ridis持久化
- Reids数据和MySQL不同,都是储存在==内存==中,服务器关闭时,内存数据释放,数据全部丢失
- 持久化方案:
- RDB 快照:隔某个时间间隔,将Redis数据序列化到磁盘上
- AOF(append-only file) 只追加文件:检测Redis的数据改变,一旦发生修改,立即写数据到磁盘上
- RDB数据安全性低,AOF效率低
官方推荐使用RDB因为AOF效率太低,且Redis存储的数据一般安全性要求不高,因此Redis默认序列化机制是RDB
RDB储存机制
配置文件:
- save 时间 次数 //当指定时间内,进行了指定次数的写入操作,那么就使用BGSAVE命令进行一次RDB快照备份
- 数据序列化后保存的磁盘文件 dbfilename--------->dump.rdb
配置策略: - 个人开发:尽量减低快照带来的资源消耗,但是个人的数据量很小,处理很快,所以不怎么用考虑带来的资源消耗
- 可以采用 save 900 1 //15分钟内如果有写入,进行备份
- 日志聚合运算:考虑如果Redis因为崩溃而未能成功创建新的快照,我们能承受丢失多长时间以内产生的新数据
- 如果丢失一个小时之内产生的数据是可以接受的,可以采用 save 3600 1
- 在处理日志的程序中需要记录快照产生时,日志处理的进度和偏移量,用以恢复时定位工作位置
- 大数据: 当数据量非常大的时候,特别实在虚拟机中,快照生成会消耗极大地虚拟内存,从而导致Redis性能降低到无法使用的程度
- 为了防止Redis因为创建子线程而出现停顿,我们可以考虑关闭自动保存,转而通过手动发送BGSAVE或SAVE命令来进行持久化,从而手动控制卡顿的时间(这种情况下尽量使用SAVE,因为用时更短)
AOF储存机制
AOF因为消耗资源较多,默认不启动;
配置:
- appendonly yes //开启AOF持久化
- appendfsync [同步频率] //设置同步频率
- always 每个命令都同步写入硬盘,会严重降低Redis的速度
- everysec 每秒执行一次同步,显式地将多个命令同步到硬盘
- no 让操作系统来决定应该何时进行同步
- auto-aof-rewrite-percentage 自动重写相关配置,比上次重写体积增加百分之多少以上时重写
- auto-aof-rewrite-min-size 自动重写相关配置,AOF备份文件体积大于多少M以上时重写
固态硬盘一定不要用appendfsync always 会极大地降低硬盘使用寿命
AOF最大的问题是随着运行时间的增加备份的AOF文件体积会越来越大,每次还原数据的时间也会无限延长,我们可以使用命令来重写AOF文件
命令:
- BGREWRITEAOF 创建子线程重写AOF文件,去除冗余的命令,和快照的原理相似
复制
主从拓扑
配置:
- 配置方式一、新增redis6380.conf, 加入 slaveof 192.168.152.128 6379, 在6379启动完后再启6380,完成配置;
- 配置方式二、在从节点启动时加上参数 redis-server --slaveof 192.168.152.128 6379 临时生效
- 配置方式三、子节点输入命令:6380:> slaveof 192.168.152.128 6379
命令: - 查看状态:info replication
- 断开主从复制:在slave节点,执行6380:>slaveof no one
底层步骤
- 从服务器连接或者重新连接主服务器,发送SYNC命令
- 主服务器执行BGSAVE,并使用缓冲区记录BGSAVE之后执行的所有写命令; 从服务器根据配置选项来决定继续使用现有的数据(如果有的话)来处理客户端的命令请求,还是向发送请求的客户端返回错误
- 主服务器BGSAVE执行完毕,向从服务器发送快照文件,并在发送期间继续使用缓冲区记录被执行的写命令; 从服务器丢弃所有旧的数据(如果有的话),开始载入主服务器发来的快照文件
- 主服务器快照文件发送完毕,开始向从服务器发送储存在缓冲区里面的写命令; 从服务器完成对快照文件的解释操作,像往常一样开始接受命令请求
- 主服务器缓冲区储存的写命令发送完毕; 从现在开始每执行一个写命令,就向从服务器发送相同的写命令; 从服务器执行主服务器发送来的所有储存在缓冲区里面的写命令;并从现在开始,接受并执行主服务器传来的每个写命令
一主一从(写操作较多,需要同步备份)
主节点写的命令并发高并且需要持久化,而持久化带来的性能影响太大;
所以可以将数据同步到从节点,让从节点进行持久化
一主多从(高读取场景)或者树形结构
主节点处理写的命令,同步给从节点,从节点分担主节点的读的命令,但是节点出现故障之后需要人工更改配置进行处理,无法实现高可用;
树形结构可以减少主节点直接复制的从节点,从而减轻主节点压力。
主从的缺点
- 主从复制,若主节点出现问题,则不能提供服务,需要人工修改配置将从变主
- 主从复制主节点的写能力单机,能力有限
- 单机节点的存储能力也有限
主从故障如何转移
- 主节点(master)故障,从节点slave-1端执行 slaveof no one后变成新主节点;
- 其它的节点成为新主节点的从节点,并从新节点复制数据;
- 需要人工干预,无法实现高可用。
如何更换故障主服务器
例如,A是主服务器,B是A的从服务器;A服务器挂了,暂时无法修复,我们决定用C暂时替代A的位置,成为新的主服务器
- B执行SAVE,进行快照备份
- 将快照文件发送到C服务器
- 启动C服务器上的Redis
- B执行SLAVOF ip 端口 的命令,将C作为新的主服务器
验证快照文件和AOF文件
redis自带了验证修复工具redis-check-aof
和redis-check-dump
,就在redis根目录
修复方法是找到第一个出错的命令,把后面的记录全删了
- $redis-check-aof [--fix] <file.aof> //--fix参数可选,如果加上就是修复,不加就是查看 后面跟的是备份的文件名
- $redis-checkdump <dump.rdb> //后面跟的是备份的快照文件名