关于Redis
Redis官网
Redis百度百科
REmote DIctionary Server(Redis) 是一个由 Salvatore Sanfilippo 写的 key-value 存储系统,是跨平台的非关系型数据库。
Redis 是一个开源的使用 ANSI C 语言编写、遵守 BSD 协议、支持网络、可基于内存、分布式、可选持久性的键值对(Key-Value)存储数据库,并提供多种语言的 API。
Redis 通常被称为数据结构服务器,因为值(value)可以是字符串(String)、哈希(Hash)、列表(list)、集合(sets)和有序集合(sorted sets)等类型。
使用Redis是为了解决多次读写数据库引发的性能问题。因为Redis是基于内存的数据库,所以它的性能十分优越,读的速度是110000次/s,写的速度是81000次/s。JavaWeb通常使用它存储缓存用的数据,以及需要高速读/写的场合,以减少对基于硬盘的数据库的访问次数。
Redis中的数据结构及操作命令
Redis中的数据结构
数据类型 | 格式 | 例子 |
---|---|---|
string(字符串) | 单key:单value | name:zhangsan |
list(列表,按插入顺序) | 单key:多有序value | contacts:13952900000,xxx,xxx |
set(集合,无序且不重复,string类型) | 单key:多无序value | city:beijing shanghai shenzhen |
hash(哈希,适合存储对象) | 单key:对象(属性:值) | student:id:1,name:zhangsan,age:20 |
zset(有序集合,通过double类型分数排序) | 单key:多有序value | city:1000 beijing,1500 shanghai,2000 shenzhen |
关于键(key)的操作命令
- 查看redis中的key: keys pattern(查找符合给定模式pattern的key)
- keys *: 查看redis中所有的key(*匹配零或多个字符)
- keys h?o: 查看redis中以h开头,o结尾且中间只有一个字符的key(?匹配一个字符)
- keys h[abc]llo: 查看redis中以h开头,llo结尾,且中间为abc中一个的key([]匹配[]中的一个字符)
- 判断key在redis中是否存在
- exists key(存在返回1,不存在返回0)
- exists key [key key key] (返回值为存在key的数量)
- 移动指定key到指定的redis实例: move key index
- move k1 1
- 查看指定key的剩余生存时间: ttl key(key未设置生存时间,返回-1;key不存在,返回-2)
- ttl k1
- 设置key最大生命时间: expire key seconds(单位秒)
- expire k2 20
- 查看指定key的数据类型: type key
- type k1
- 重命名key: rename key newkey
- rename k1 k2
- 删除指定key: del key [key key key](返回值是实际删除key的数量)
- del k1 k2
关于string类型数据的操作命令
- 将string类型数据设置到redis中: set key value
- set name zhangsan
- set age 20
- 从redis中获取string类型数据: get key
- get name
- > zhangsan
- get age
- > 20
- 追加字符串: append key value(返回值为追加后字符串长度;如果key不存在,则创建并赋值)
- set phone 2333333
- append phone 8888
- > 23333338888
- 获取字符串长度: strlen key
- strlen phone
- > 5
- 将字符串数值进行加1运算: incr key
(返回加1运算后的数据;key不存在,设置一个初始值为0的key,在进行incr运算;key的value不为数值,报错) - 将字符串数值进行减1运算: decr key
(返回减1运算后的数据;key不存在,设置一个初始值为0的key,在进行decr运算;key的value不为数值,报错) - 将字符串数值进行加offset运算: incrby key offset
(返回加offset运算后的数据;key不存在,设置一个初始值为0的key,在进行incrby运算;key的value不为数值,报错) - 将字符串数值进行减offset运算: decrby key offset
(返回减offset运算后的数据;key不存在,设置一个初始值为0的key,在进行decrby运算;key的value不为数值,报错) - 获取字符串key中从startIndex到endIndex的子串: getrange key startIndex endIndex(闭区间,下标也可为负数)
- set k1 zhangsan
- getrange k1 2 5
- > angs
- getrange k1 0 -1
- > zhangsan
- 用value覆盖从startIndex开始的字符串: setrange key startIndex value
- set k1 zhangsan
- setrange k1 5 233
- > zhang233
- setrange k1 5 a
- > zhanga33
- 设置string数据同时,设置它的最大生命周期: setex key seconds value
- setex k1 20 zhangsan
- 设置string数据到redis中,不存在则设置;存在则放弃: setnx key value
- setnx k1 20
- 批量设置string数据到redis中: mset key1 value1 key2 value2 …
- 批量获取string数据: mget key1 key2 …
关于list类型数据的操作命令
单key-多有序value
多个value之间有顺序(插入顺序),最左侧是表头,最右侧表尾。
每个元素都有下标,表头元素下标是0。下标可以为负数
- 将一个或多个值依次插入列表的表头: lpush key value [value value …]
- lpush list1 1 2 3
- 获取指定列表中指定下标区间的元素: lrange key startIndex endIndex
- lrange list1 0 2
- >3
- >2
- >1
- 将一个或多个值依次插入列表的表尾: rpush key value [value value …]
- rpush list2 1 2 3
- lrange list2 0 2
- >1
- >2
- >3
- 从指定列表移除并返回表头: lpop key
- 从指定列表移除并返回表尾: rpop key
- 获取指定列表中指定下标的元素: lindex key index
- lindex list1 1
- >2
- 获取指定列表的长度: llen key
- llen list1
- >3
- 根据count值移除指定列表中跟value相等的数据: lrem key count value
count>0:从列表的左侧移除count个跟value相等的数据;
count<0:从列表的右侧移除count个跟value相等的数据;
count=0:从列表移除所有跟value相等的数据。 - 截取指定列表指定区间组成新的列表,并赋值给key: ltrim key startIndex endIndex
- 将指定列表指定下标元素设置为指定值: lset key index value
- 将value插入到指定列表中位于pivot元素之前/之后的位置: linsert key before/after pivot value
关于set类型数据的操作命令
单key-多无序value
无序且不重复,所以元素没有下标,直接操作数据。
- 将一个或多个元素添加到指定集合: sadd key value [value value …]
如果元素已经存在,则会忽略。返回成功加入的元素个数。- sadd set1 a b c a
- 获取指定集合中的所有元素: smembers key
- smembers set1
- >a
- >c
- >b
- 判断指定元素在指定集合中是否存在: sismember key member
存在返回1,不存在返回0。 - 获取指定集合的长度: scard key
- 移除指定集合中的一个或多个元素: srem key member [member member …]
不存在的元素会被忽略
返回成功移除的元素个数 - 随机获取指定集合中的一个或多个元素: srandmember key [count]
count>0 随机获取的多个元素不能重复
count<0 随机获取的多个元素之间可能重复 - 从指定集合中随机移除一个或多个元素: spop key [count]
- 将指定集合中指定元素移动到另一个集合: smove source dest member
- smove set1 set2 a
- 获取第一个集合中有,但其他集合中没有的元素组成新的集合(差集): sdiff key key [key key …]
- 获取所有指定集合中都有的元素组成新的集合(交集): sinter key key [key key …]
- 获取所有指定集合中所有的元素组成新的集合(并集): sunion key key [key key …]
关于hash类型数据的操作命令
单key:field-value field-value …
hash是string类型的key和value的映射表,value是一系列的键值对,适合存储对象
- 将一个或多个field-value对设置到哈希表中: hset key field1 value1 [field2 value2 …]
- hset stu1 id 0001
- hset stu2 id 0002 name zhangsan
- 获取指定哈希表中指定的field的值: hget key field
- hget stu1 id
- >0001
批量将多个field-value对设置到哈希表中: hmset key field1 value1 [field2 value2 …]- 批量获取指定哈希表在的field值: hmget key field1 [field2 field3 …]
- 获取指定哈希表中所有的field和value: hgetall key
- 从指定哈希表中删除一个或多个field: hdel key field1 [field1 field2 …]
- 获取指定哈希表中所有的field个数: hlen key
- 判断指定哈希表中是否存在某个field: hexists key field
- 获取指定哈希表中所有的field列表: hkeys key
- 获取指定哈希表中所有的value列表: hvals key
- 对指定哈希表中指定的field值进行整数加法运算: hincrby key field int
- 对指定哈希表中指定的field值进行浮点数加法运算: hincrbyfloat key field float
- 将一个field-value对设置到指定哈希表中: hsetnx stu1 age 30
当key-field已经存在,则放弃设置
关于zset类型数据的操作命令
有序集合,不允许重复元素。
但zset集合中,每个元素会关联一个分数,redis根据分数对元素进行排序,分数可以重复。
zset中每个元素都有顺序,所有每个元素也有下标。。
- 将一个或多个member及其score值加入有序集合: zadd key score member [score member …]
如果元素已经存在,则会覆盖其分数- zadd zset1 1 a
- 获取指定有序集合中指定下标区间的元素: zrange key startIndex endIndex [withscores]
withscores 是否显示分数 - 获取指定有序集合中指定分数区间(闭区间)的元素: zrangebysorce key min max [withscores]
- 删除指定有序集合中的一个或多个元素: zrem key member [member …]
- 获取指定有序集合中所有元素的个数: zcard key
- 获取指定有序集合中分数在指定区间内的元素个数: zcount key min max
- 获取指定有序集合中指定元素的排名(从0开始): zrank key member
- 获取指定有序集合中指定元素的分数: zscore key member
- 获取指定有序集合中指定元素的排名(按分数从小到大的排名): zrevrank key member
命令小结
上面的命令是部分常用的命令,写到这里感觉不如去看文档,不过写一遍也算是加深印象。
菜鸟教程Redis
Redis的配置文件
redis根目录下提供redis.conf配置文件
如果不使用配置文件,redis按默认参数运行。如果使用配置文件,在启动redis服务时,必须指定所使用的配置文件。
关于网络的配置
- port:指定redis服务所使用的端口号,默认使用6379
- bind:配置客户端连接redis服务时,所能使用的ip地址,默认可以使用redis服务所在主机上任意一个ip都可以;一般情况会配置一个真实ip。
- 如果配置了port和bind,则客户端连接redis服务时,必须指定端口和ip:
redis-cli -h 192.268.11.128 -p 6380
redis-cli -h 192.268.11.128 -p 6380 shutdown
- 如果配置了port和bind,则客户端连接redis服务时,必须指定端口和ip:
- tcp-keepalive:TCP连接保活策略。单位秒,每过多少秒向连接空闲的客户端发送一个ACK请求,以检查客户端是否挂掉,对于无响应的客户端会关闭连接。如果设置为0,则不会进行保活检测。
常规配置
- loglevel:配置日志级别,开发阶段可以设置成debug,生产阶段通常设置为notice或waring。
- logfile:指定日志文件。redis运行过程中会输出日志信息;默认会输出到控制台。
- databases:配置redis服务创建的数据库实例个数,默认16个。
安全配置
- requirepass:配置redis的访问密码。默认不配置密码。此参数必须在protected-mode=yes(安全模式)是才起作用。
RDB配置
- save
:配置复合的快照触发条件,即redis在seconds秒内key改变了changes次,会将快照内数据保存到磁盘一次。默认策略是: - 1分钟内改变1万次
- 或5分钟内改变10次
- 或15分钟内改变1次
- 如果要禁用redis的持久化功能,吧所有的save配置注释即可。
- stop-writes-on-bgsave-erroe:在bgsave快照操作出错时停止写入磁盘,以保证数据一致性。如果出错时要继续写入,配置为no。
- rdbcompression:设置对存储到磁盘的快照是否压缩。yes会采用LZF算法进行压缩,no关闭此功能,可减少CPU消耗。
- rdbchecksum:快照存储后,可使用CRC64算法进行数据校验,会消耗一定性能,no关闭此功能。
- sdbfilename:持久化数据生成的文件名。默认为dump.rdb
- dir:持久化数据生成文件的保存目录。默认./即redis启动目录
AOF配置
- appendonly:配置是否开启AOF,yes表示开启,no表示关闭。默认no
- appendfilename:AOF保存的文件名
- appendfsync:AOF异步持久化策略
- always:同步持久化,每次发生数据变化立刻写入磁盘。性能差但数据安全。
- everysec:每秒异步记录一次。默认。
- no:不及时同步,由操作系统决定何时同步。
- no-appendfysnc-on-rewrite:重写时是否可以运用appendsync,默认no,可以保证数据安全性。
- auto-aof-rewrite-percentage:设置重写的基准百分比。
- auto-aof-rewrite-min-size:设置重写的基准值。
Redis的持久化
redis是内存数据库,数据存储在内存中,虽然加快了读取速度,但也对数据安全性产生新的问题。当服务器宕机后,redis数据库中所有数据会全部丢失,所以redis提供了持久化功能——RDB和AOF。
RDB策略
在指定时间间隔内,redis服务执行指定次数的写操作,会自动触发一次持久化操作。
RDB策略是redis默认的持久化策略,在redis服务开启时,这种持久化策略默认开启。
AOF策略
采用操作日志来记录进行的每一次操作,每次redis启动时,都会重新执行一遍日志中的命令。
效率低下,redis默认不开启。作为RDB策略的补充。
持久化策略小结
根据数据的特点来决定使用哪种策略,一般RDB足够。redis主要做缓存,数据在关系型数据库中有备份。
Redis的事务
事务:把一组数据库放在一起执行,保证操作的原子性,要么同时成功,要么同时失败。
Redis的事务:允许把一组redis命令放在一起执行,把命令序列化,然后一起执行,保证部分原子性。
- multi:用来标记一个事务的开始。
- 压入事务队列
- multi
- set k1 v1
- set k2 v2
- …
- exec:用来执行事务队列中的所有命令。
- exec
- redis的事务只能保证部分原子性:
- 如果一组命令中,在压入事务队列过程中发生错误,则本事务中所有命令都不执行,保证事务原子性。
- 如果一组命令中,艾压入队列过程正常,但在执行事务队列命令时发生错误,则只会影响发生错误的命令,不会影响其他命令,不能保证事务的原子性。
- discard:清除所有已经压入队列中的命令,并且结束整个事务。
- multi
- set k1 v1
- set k2 v2
- discard
- watch:监控某一个键,当事务在执行过程中,此键代码的值发生变化,则本事务放弃执行;否则,正常执行。
- unwatch:放弃监控某一键
事务小结:
1.单独的隔离操作:事务中的所有命令会序列化、顺序地执行。执行过程中不会被其他客户端的命令请求打断,除非是用watch进行监视。
2.不保证事务的原子性:同一事务如果某一命令执行失败,其他命令仍可能被继续执行,redis事务没有回滚。
Redis消息的发布与订阅(了解)
redis客户端订阅频道,消息的发布者往频道上发布消息,所有订阅此频道的客户端都能够接收到消息。
- subscribe:订阅一个或多个频道的消息。
- subscribe ch1 ch2 ch3
- publish:将消息发布到指定频道
- publish ch1 hello
- psubscribe:订阅一个或多个频道的消息,频道名支持通配符。
Redis的主从复制
主少从多,主写从读,读写分离,主写同步复制到从。
搭建一主二从的redis集群:
- 搭建三台redis服务:使用一台机器,三个不同端口模拟
- 修改配置文件(bind、port等),以redis6379.conf为例
- bind 127.0.0.1
- port 6379
- pidfile /var/run/redis_6379.pid
- logfile “6379.log”
- dbfilename dump6379.rdb
- 启动服务
- redis-server redis6379.cond &
- redis-server redis6380.cond &
- redis-server redis6381.cond &
- 连接到redis服务
- redis-cli -h 127.0.0.1 -p 6379
- redis-cli -h 127.0.0.1 -p 6380
- redis-cli -h 127.0.0.1 -p 6381
- 查看三台redis服务在集群中的主从角色:
- info replication
- 默认情况下,所有的redis服务都是主机,既能读也能写,但都没有从机。
- 设置主从关系:设从不设主
- 在6380上执行:slaveof 127.0.0.1 6379
- 在6381上执行:slaveof 127.0.0.1 6379
- 全量复制:一旦主从关系确定,会自动把主机上已有的数据同步复制到从库
- 增量复制:主库写数据会自动同步到从库
- 主写从读,读写分离:
- 在从机上进行写操作会报错
- 主机宕机、从机原地待命:
- 从机可以继续读,但数据不会再更新。
- 主机恢复、一切恢复正常
- 从机宕机、主机少一个从机,其他从机不变。
- 从机恢复、需重新设置主从关系。
- 从机上位:
- 主机宕机、从机原地待命
- 从机断开原来的主从关系
- 在6380上执行:slaveof no one
- 重新设置主从关系
- 在6381上执行:slaveof 127.0.0.1 6380
- 原主机恢复
- 在6379上执行:slaveof 127.0.0.1 6379
- 让6379变为6380的从机
- 或者在6379上执行:slaveof 127.0.0.1 6381
- 让6379成为6381的从机,此时6381既是主机又是从机,但他不能读。
小结:
一台主机配置多台从机,一台从机也可以配置多台从机,从而形成一个庞大的集群。减轻一台主机的压力,但是增加了服务间的延迟。
Redis的哨兵模式
主机宕机、从机上位的自动版
- 搭建一主二从的redis集群(见上文)
- 提供哨兵的配置文件:
- 在redis安装目录下下创建配置文件:redis_sentinel.conf
- 写入 sentinel monitor dc-redis 127.0.0.1 6379 1
- 启动哨兵服务:redis-sentinel redis_sentinel.conf
- 主机宕机,哨兵自动选择从机上位
- 原主机恢复,自动从属于新主机
哨兵小结
可以设置多个哨兵。即每个redis服务都可以设置一个哨兵。
哨兵模式三大任务:监控、提醒、自动故障迁移
Jedis操作Redis
使用Redis官方推荐的Jedis,在Java应用中操作Redis。操作Redis的命令在jedis中以方法形式出现。
Jedis文档
maven配置
1 | <dependency> |
示例java程序
1 | package org.example; |
输出:[]
Jedis中连接池的使用
工具类
1 | package org.example; |
测试类
1 | package org.example; |
输出:[]
Redis客户端工具——Redis Desktop Manager
使用命令行还行,就不用客户端了。贴个官网链接
总结
Redis的学习告一段落,其中用的最多的应该还是对数据的操作。