Redis常用命令
select 2 //切换到2号数据库
keys * //查看所有key值
set name zhangs //设置kv
get name //查看V
move name //删除
EXPIRE name 10 //设置过期时间为10秒
ttl name //查看过期时间
EXISTS name //判断key是否存在
type name //查看key数据类型
Redis五大数据类型
String
String类型
- 基本命令
127.0.0.1:6379> set name haha
OK
127.0.0.1:6379> get name
"haha"
127.0.0.1:6379> append name heihei #在字符串后面添加
(integer) 10
127.0.0.1:6379> get name
"hahaheihei"
127.0.0.1:6379> Exists name # 查看Key是否存在
(integer) 1
127.0.0.1:6379> strlen
(error) ERR wrong number of arguments for 'strlen' command
127.0.0.1:6379> strlen name #查看key长度
(integer) 10
127.0.0.1:6379>
127.0.0.1:6379> set age 10
OK
127.0.0.1:6379> get age
"10"
127.0.0.1:6379> incr age # ++操作
(integer) 11
127.0.0.1:6379> incr age
(integer) 12
127.0.0.1:6379> decr age # --操作
(integer) 11
127.0.0.1:6379> INCRBY age 5 # 加多个值
(integer) 16
127.0.0.1:6379> INCRBY age 5
(integer) 21
127.0.0.1:6379> DECRBY age 10 # 减多个值
(integer) 11
127.0.0.1:6379> DECRBY age 10
(integer) 1
127.0.0.1:6379> FLUSHdb #清空所有key
OK
127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379> set key1 hellohahah
OK
127.0.0.1:6379> GETRANGE key1 0 4 #截取字符串 左右都是闭
"hello"
127.0.0.1:6379> get key1
"hellohahah"
127.0.0.1:6379> GETRANGE key1 0 3
"hell"
127.0.0.1:6379>
127.0.0.1:6379> set key2 zhangsan123
OK
127.0.0.1:6379> get key2
"zhangsan123"
127.0.0.1:6379> SETRANGE key2 1 lisi #替换指定位置中的值
(integer) 11
127.0.0.1:6379> get key2
"zlisisan123"
127.0.0.1:6379>
127.0.0.1:6379> setex key3 10 "wangwu" #设置过期时间
OK
127.0.0.1:6379> get key3
"wangw"
127.0.0.1:6379> get key3
(nil)
127.0.0.1:6379>
127.0.0.1:6379> setnx mykey "haha" #设置一个字符如果不存在返回1并设置成功
(integer) 1
127.0.0.1:6379> setnx mykey "haha"
(integer) 0
127.0.0.1:6379> get mykey
"haha"
127.0.0.1:6379>
127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3 # 批量设置key值
OK
127.0.0.1:6379> keys *
1) "k3"
2) "k2"
3) "k1"
127.0.0.1:6379>
127.0.0.1:6379> mget k1 k2 k3 k4 #批量获取key值
1) "v1"
2) "v2"
3) "v3"
4) (nil)
127.0.0.1:6379>
127.0.0.1:6379> msetnx k1 v1 k4 v4 #同时设置多个值,是一个原子性操作如果一个失败全部失败
(integer) 0
127.0.0.1:6379> keys *
1) "k3"
2) "k2"
3) "k1"
127.0.0.1:6379>
127.0.0.1:6379> getset key 123 #如果不存在会get 进去 并且返回之前的值
(nil)
127.0.0.1:6379> getset key 321
"123"
127.0.0.1:6379> get key
"321"
127.0.0.1:6379>
List
List类型使用
-
基本命令
-
可以吧list玩成、栈、队列、阻塞队列
127.0.0.1:6379> lpush list 1 2 3 # 添加操作
(integer) 3
127.0.0.1:6379> lrange list 0 -1 # 查询所有操作
1) "3"
2) "2"
3) "1"
127.0.0.1:6379> lrange list 0 1 # 查询部分操作
1) "3"
2) "2"
127.0.0.1:6379>
127.0.0.1:6379> Rpush list 1 # 放到队列的最后面
(integer) 4
127.0.0.1:6379> lrange list 0 -1
1) "3"
2) "2"
3) "1"
4) "1"
127.0.0.1:6379>
127.0.0.1:6379> lrange list 0 -1
1) "3"
2) "2"
3) "1"
4) "1"
127.0.0.1:6379> lpop list #移除最左边的值
"3"
127.0.0.1:6379> rpop list # 移除最右边的值
"1"
127.0.0.1:6379> lrange list 0 -1
1) "2"
2) "1"
127.0.0.1:6379> lrange list 0 -1
1) "2"
2) "1"
127.0.0.1:6379> lindex list 1 # 通过下标获得第几个值
"1"
127.0.0.1:6379> lindex list 0
"2"
127.0.0.1:6379> lindex list 9
127.0.0.1:6379> llen list # 获取列表的长度
(integer) 2
127.0.0.1:6379>
127.0.0.1:6379> lrem list 1 1 # 移除 1个1
(integer) 1
127.0.0.1:6379> lrange list 0 -1
1) "2"
2) "2"
3) "2"
4) "2"
5) "1"
127.0.0.1:6379> lrem list 3 2 # 移除3个2
(integer) 3
127.0.0.1:6379> lrange list 0 -1
1) "2"
2) "1"
127.0.0.1:6379>
127.0.0.1:6379> lrange list 0 -1
1) "6"
2) "5"
3) "4"
4) "3"
5) "2"
6) "1"
7) "1"
127.0.0.1:6379> ltrim list 0 4 #截取数组
OK
127.0.0.1:6379> lrange list 0 -1
1) "6"
2) "5"
3) "4"
4) "3"
5) "2"
127.0.0.1:6379>
127.0.0.1:6379> lrange list 0 -1
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
6) "6"
127.0.0.1:6379> rpoplpush list list1 #把其中一个数组中的位置放到另一个数组里面
"6"
127.0.0.1:6379> lrange list 0 -1
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
127.0.0.1:6379> lrange list1 0 -1
1) "6"
127.0.0.1:6379> lrange list1 0 -1
1) "6"
127.0.0.1:6379> lset list1 0 0 #将指定下标的值替换成另一个值
OK
127.0.0.1:6379> lrange list1 0 -1
1) "0"
127.0.0.1:6379>
127.0.0.1:6379> Linsert list1 before 0 -1 # 在某个值前面插入
(integer) 2
127.0.0.1:6379> lrange list1 0 -1
1) "-1"
2) "0"
127.0.0.1:6379> Linsert list1 after 0 1 # 在某个值后面插入
(integer) 3
127.0.0.1:6379> lrange list1 0 -1
1) "-1"
2) "0"
3) "1"
127.0.0.1:6379>
-
list实际上是一个链表
-
如果移除了所有的值就会变成一个空链表 ,也就不存在了
Set(集合)
- set中的值不能重复
127.0.0.1:6379> sadd set zhangsan #添加
(integer) 1
127.0.0.1:6379> sadd set list
(integer) 1
127.0.0.1:6379> sadd set list
(integer) 0
127.0.0.1:6379> smembers set # 查看
1) "zhangsan"
2) "list"
127.0.0.1:6379> sismember set zhangsan # 判断是否存在
(integer) 1
127.0.0.1:6379> sismember set zhangsa1
(integer) 0
127.0.0.1:6379> scard set # 查看set中值的个数
(integer) 2
127.0.0.1:6379> srem set zhangsan # 移除set中的值
(integer) 1
127.0.0.1:6379> SRANDMEMBER set 1 # 随机抽取指定的元素个数
1) "list"
127.0.0.1:6379> SRANDMEMBER set # 随机抽取一个元素
"list"
127.0.0.1:6379> spop set #随机删除一些set集合
"2"
127.0.0.1:6379> spop set
"1"
127.0.0.1:6379> SMEMBERS set
1) "3"
2) "list"
127.0.0.1:6379> SMOVE set myset list #将set中指定的值放到myset中
(integer) 1
127.0.0.1:6379> SMEMBERS myset
1) "list"
127.0.0.1:6379> SMEMBERS set
1) "3"
127.0.0.1:6379>
127.0.0.1:6379> SMEMBERS myset
1) "a"
2) "d"
3) "list"
4) "b"
127.0.0.1:6379> SMEMBERS set
1) "c"
2) "a"
3) "3"
4) "b"
127.0.0.1:6379> sdiff set myset # 差集
1) "3"
2) "c"
127.0.0.1:6379> sdiff myset set
1) "list"
2) "d"
127.0.0.1:6379> SINTER set myset # 交集
1) "a"
2) "b"
127.0.0.1:6379> sunion set myset #并集
1) "3"
2) "d"
3) "b"
4) "c"
5) "a"
6) "list"
- 可以做共同关注、共同爱好、二度好友、推荐好友等
Hash(哈希)
- hash和String差不多 本质和String类型没有太大的区别
127.0.0.1:6379> hset hash 1 zhangsan # 添加一个值
(integer) 1
127.0.0.1:6379> hset hash 2 list
(integer) 1
127.0.0.1:6379> hmset hash 3 wangwu 4 haha # 批量添加
OK
127.0.0.1:6379> HGETALL hash # 查看所有值
1) "1"
2) "zhangsan"
3) "2"
4) "list"
5) "3"
6) "wangwu"
7) "4"
8) "haha"
127.0.0.1:6379> hget hash 3 #根据key查看某个值
"wangwu"
127.0.0.1:6379> hdel hash 1 # 删除其中某个值
(integer) 1
127.0.0.1:6379> HGETALL hash
1) "2"
2) "list"
3) "3"
4) "wangwu"
5) "4"
6) "haha"
127.0.0.1:6379> hlen hash #获取hash的长度
(integer) 3
127.0.0.1:6379> hkeys hash #获取所有的key值
1) "2"
2) "3"
3) "4"
127.0.0.1:6379> hvals hash # 获取所有的value值
1) "list"
2) "wangwu"
3) "haha"
- hash适合于对象的存储,string更适合字符串存储
Zset(有序集合)
- 在set的基础上加了一个值
127.0.0.1:6379> zadd zset 1 1 #zset 是有权值的添加 根据权值排序
(integer) 1
127.0.0.1:6379> zadd zset 2 3
(integer) 1
127.0.0.1:6379> zadd zset 3 2
(integer) 1
127.0.0.1:6379> ZRANGE zset 0 -1 # 查看所有
1) "1"
2) "3"
3) "2"
127.0.0.1:6379> ZRANGEBYSCORE zset -inf +inf # 排序从低到高
1) "9"
2) "1"
3) "3"
4) "2"
127.0.0.1:6379> ZREVRANGE zset 0 -1 # 排序从高到低
1) "2"
2) "3"
3) "1"
127.0.0.1:6379> zrem zset 9 # 移除元素
(integer) 1
127.0.0.1:6379> ZRANGE zset 0 -1
1) "1"
2) "3"
3) "2"
127.0.0.1:6379> ZCARD zset # 查看个数
(integer) 3
127.0.0.1:6379> ZCOUNT zset 0 2 # 获得区间里面的数量
(integer) 2
127.0.0.1:6379> ZCOUNT zset 0 4
(integer) 3
127.0.0.1:6379> ZCOUNT zset 0 8
(integer) 3
- zset是有序的
三种特殊类型
geospatial 地理位置
Redis在3.2版本推出 可以推算地理位置信息,两地之间的距离等
127.0.0.1:6379> geoadd china 116.40 39.90 beijing 121.47 31.23 shanghai 106.50 29.53 chongqing 114.05 22.52 shenzhen 120.16 30.24 hangzhou 108.96 34.26 xian
(integer) 6 # 添加地理位置
127.0.0.1:6379> GEOPOS china beijing #获取指定精度和纬度
1) 1) "116.39999896287918091"
2) "39.90000009167092543"
127.0.0.1:6379> GEOPOS china beijing chongqing
1) 1) "116.39999896287918091"
2) "39.90000009167092543"
2) 1) "106.49999767541885376"
2) "29.52999957900659211"
127.0.0.1:6379>
获取两个人之间的距离
127.0.0.1:6379> GEODIST china shanghai beijing #单位为米
“1067378.7564”
127.0.0.1:6379> GEODIST china shanghai beijing km # 单位为千米
“1067.3788”
附近的人
127.0.0.1:6379> GEORADIUS china 110 30 500 km withdist # 查询在某个范围内的人的个数
- “chongqing”
- “341.9374”
- “xian”
- “483.8340”
127.0.0.1:6379> GEORADIUS china 110 30 500 km withdist withcoord count 2 #可以排序并且可以确定人数
- “chongqing”
- “341.9374”
- “106.49999767541885376”
- “29.52999957900659211”
- “xian”
- “483.8340”
- “108.96000176668167114”
- “34.25999964418929977”
以某一个地点为中心查询周围的地点
127.0.0.1:6379> GEORADIUSBYMEMBER china beijing 1000 km
1) "beijing"
2) "xian"
127.0.0.1:6379> GEORADIUSBYMEMBER china shanghai 4000 km
1) "chongqing"
2) "xian"
3) "shenzhen"
4) "hangzhou"
5) "shanghai"
6) "beijing"
127.0.0.1:6379> GEORADIUSBYMEMBER china shanghai 400 km
1) "hangzhou"
2) "shanghai"
Hyperloglog
用于基数统计 占用资源小
127.0.0.1:6379> pfadd key 1 2 3 4 5 6 7 # 放入key
(integer) 1
127.0.0.1:6379> PFCOUNT key # 统计数量
(integer) 7
127.0.0.1:6379> pfadd key2 8 9 0 2 3
(integer) 1
127.0.0.1:6379> PFMERGE key3 key key2 # 合并两组 为并集
OK
127.0.0.1:6379> PFCOUNT key3
(integer) 10
允许容错可以使用Hyperloglog
Bigmaps
按位去运算
位图,都是操作二进制位来进行记录,只有0和1两个状态
127.0.0.1:6379> setbit long 0 1 #添加
(integer) 0
127.0.0.1:6379> setbit long 1 0
(integer) 0
127.0.0.1:6379> setbit long 2 1
(integer) 0
127.0.0.1:6379> BITCOUNT long #查看1的个数
(integer) 2
事务
-
Redis单条命令保持原子性的,但是事务不保证原子性
-
Redis事务本质: 一组命令的集合,一个事务中的所有命令都会被序列化,在事物执行过程中,会按照顺序执行!一次性、排他性!执行一系列命令
Redis事务过程
-
开启事务(multi)
-
命令入队(。。。各种命令)
-
执行事物(exec)
127.0.0.1:6379> MULTI #开启事务
OK
127.0.0.1:6379> set k1 v2
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> get k1
QUEUED
127.0.0.1:6379> exec # 结束事务
1) OK
2) OK
3) OK
4) "v2"
- 如何放弃事物 (discard)
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set k5 v5
QUEUED
127.0.0.1:6379> DISCARD # 结束事务 队列中的操作都不会被执行
OK
127.0.0.1:6379> get k5
(nil)
- 如果事务队列中有代码执行错误,不会影响其他命令
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> get k1
QUEUED
127.0.0.1:6379> get k4
QUEUED
127.0.0.1:6379> incr k5
QUEUED
127.0.0.1:6379> exec
1) "v2"
2) (nil)
3) (integer) 1
- 如果代码写错(编译错误) 队列中的所有命令都不会执行
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set k4 k4
QUEUED
127.0.0.1:6379> getset k3 # 代码写错
(error) ERR wrong number of arguments for 'getset' command
127.0.0.1:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0
Redis 加锁
127.0.0.1:6379> set money 100
OK
127.0.0.1:6379> set out 20
OK
127.0.0.1:6379> watch money out # watch 起一个监事作用类似于乐观锁 当有其他的任务修改了监事的对象时执行会报错
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> DECRby money 20
QUEUED
127.0.0.1:6379> INCRby out 20
QUEUED
127.0.0.1:6379> exec
1) (integer) 80
2) (integer) 40
127.0.0.1:6379> get money
"80"
127.0.0.1:6379> UNWATCH # 解除监控 执行结束之后也会自动解锁
OK
Jedis
- Jedis是Redis官方推荐的java开发工具!使用java操作Redis的中间件
导入依赖就可以使用
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.3.0</version>
</dependency>
SpringBoot 整合
SpringData里有redis的整合
jedis:采用直连,多个线程操作的话,是不安全的,如果想要
lettuce:采用netty,实例可以在多个线程中进行共享,不存在现线程不安全的情况,可以减少线程数据
Redis.conf
Redis对大小写不敏感
# Note on units: when memory size is needed, it is possible to specify
# it in the usual form of 1k 5GB 4M and so forth:
#
# 1k => 1000 bytes
# 1kb => 1024 bytes
# 1m => 1000000 bytes
# 1mb => 1024*1024 bytes
# 1g => 1000000000 bytes
# 1gb => 1024*1024*1024 bytes
#
# units are case insensitive so 1GB 1Gb 1gB are all the same.
配置文件
################################## INCLUDES ###################################
# Include one or more other config files here. This is useful if you
# have a standard template that goes to all Redis servers but also need
# to customize a few per-server settings. Include files can include
# other files, so use this wisely.
#
# Notice option "include" won't be rewritten by command "CONFIG REWRITE"
# from admin or Redis Sentinel. Since Redis always uses the last processed
# line as value of a configuration directive, you'd better put includes
# at the beginning of this file to avoid overwriting config change at runtime.
#
# If instead you are interested in using includes to override configuration
# options, it is better to use include as the last line.
#
# include /path/to/local.conf
# include /path/to/other.conf
网络
################################## NETWORK #####################################
# By default, if no "bind" configuration directive is specified, Redis listens
# for connections from all the network interfaces available on the server.
# It is possible to listen to just one or multiple selected interfaces using
# the "bind" configuration directive, followed by one or more IP addresses.
#
# Examples:
#
# bind 192.168.1.100 10.0.0.1
# bind 127.0.0.1 ::1
#
# ~~~ WARNING ~~~ If the computer running Redis is directly exposed to the
# internet, binding to all the interfaces is dangerous and will expose the
# instance to everybody on the internet. So by default we uncomment the
# following bind directive, that will force Redis to listen only into
# the IPv4 loopback interface address (this means Redis will be able to
# accept connections only from clients running into the same computer it
# is running).
#
# IF YOU ARE SURE YOU WANT YOUR INSTANCE TO LISTEN TO ALL THE INTERFACES
# JUST COMMENT THE FOLLOWING LINE.
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bind 127.0.0.1 #可以设置ip
# are explicitly listed using the "bind" directive.
protected-mode yes # 是否受保护
# Accept connections on the specified port, default is 6379 (IANA #815344).
# If port 0 is specified Redis will not listen on a TCP socket.
port 6379 # 端口号
通用配置GENERAL
daemonize yes # 是否以守护(后台)进程开启
pidfile /var/run/redis_6379.pid # 如果以后台的方式运行,我们就需要指定一个pid
# Specify the server verbosity level.
# This can be one of:
# debug (a lot of information, useful for development/testing)
# verbose (many rarely useful info, but not a mess like the debug level)
# notice (moderately verbose, what you want in production probably)
# warning (only very important / critical messages are logged)
loglevel notice # 日志级别
logfile "" # 日志文件位置名
# Set the number of databases. The default database is DB 0, you can select
# a different one on a per-connection basis using SELECT <dbid> where
# dbid is a number between 0 and 'databases'-1
databases 16 #数据库数量 默认是16
always-show-logo yes # 是否显示log
快照SNAPSHOTTING
持久化,在规定时间执行了多少次操作
# 900秒内 如果有1个key进行修改,就进行持久化操作
save 900 1
# 300秒内 有10个key进行修改,就进行持久化操作
save 300 10
# 60秒内有10000个key进行修改,就进行持久化操作
save 60 10000#
# 可以设置自己的持久化规则
stop-writes-on-bgsave-error yes # 如果持久化错误是否还要继续工作
rdbcompression yes # 是否压缩rdb文件 需要消耗CPU资源
rdbchecksum yes # 保存RDB文件的时候是否进行错误校验
dir ./ # RDB文件保存目录
安全SECURITY
#设置密码
congif set requirepass 123456
auth 123456 #登录
限制CLIENTS
# maxclients 10000 默认最大连接客户端数量
# maxmemory <bytes> 最大内存容量设置
# maxmemory-policy noeviction 到达最大内存的处理策略
-
volatile-lru(推荐):使用LRU算法进行数据淘汰(淘汰上次使用时间最早的,且使用次数最少的key),只淘汰设定了有效期的key
-
allkeys-lru:使用LRU算法进行数据淘汰,所有的key都可以被淘汰
-
volatile-random:随机淘汰数据,只淘汰设定了有效期的key
-
allkeys-random:随机淘汰数据,所有的key都可以被淘汰
-
volatile-ttl:淘汰剩余有效期最短的key
AOF配置APPEND ONLY MODE
appendonly no # 默认不开启aof持久化模式
appendfilename "appendonly.aof" # 持久化文件名字
# appendfsync always # 每次修改都会同步
appendfsync everysec # 每秒执行一次,可能会丢失1s的数据
# appendfsync no # 不执行
Redis持久化
RDB持久化
-
在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是Snapshot快照,需要恢复时是将快照文件直接读到内存里。
-
Redis会单独创建(fork)一个子进程来进行持久化操作,会先将数据写入到一个临时文件当中,待持久化过程都结束,再用这个临时文件替换上次持久化好的文件。整个过程主进程不进行任何IO操作,保证了性能。如果进行大规模的数据恢复,并且对于数据恢复的完整性不是非常敏感,RDB会比AOF更加高效 默认是RDB快照快照文件是dump.rdb
优点:
-
适合大规模的数据恢复
-
对数据的完整性要求不高
缺点:
- 需要一定的时间间隔进程操作 如果Redis意外宕机,这个最后一次修改数据就没有了
- fork进程的时候,会占用一定的内容空间
AOF持久化
-
将我们所有的命令记录下来,恢复的时候就把这个文件全执行一遍
-
以日志的形式记录每个写操作
默认是不开启
-
开启之后设置
-
always 每一次写操作都写入
-
everysec 每秒写入一次
-
no 不写入
-
如果AOF配置文件有错误Redis启动不起来,通过Redis提供的工具来修复AOF文件–redis-check-aof
优点:
-
每一次修改都同步,文件的完整性更加好
-
每秒同步一次,可能会丢失一秒的数据
-
从不同步,效率最高
缺点:
-
相对于数据文件,aof远远大于rdb文件,修复速度也rdb慢
-
AOF运行效率也要比rdb慢,所以我们redis默认是RDB持久化
RDB和AOF的选择之感
- 对数据非常敏感,建议使用默认的AOF持久化方案
AOF持久化策略使用erverysecond,每秒钟fsync一次。该策略redis任然可以保持很好的处理性能,当出现问题时,最多丢失0-1秒中的数据。
注意:由于AOF文件存储体积较大,且恢复数据较慢 - 数据呈现阶段有效性,建议使用RDB持久化方案
数据可以良好的做到阶段内无丢失(该阶段是开发者或运维人工手工维护的),且恢复速度较快,阶段点数据恢复通常采用RDB方案
注意:利用RDB实现紧凑的数据持久化会使Redis降得很低 - 综合对比
- RDB与AOF得选择实际上是在做一种权衡,每种都有利弊
- 如不能承受数分钟以内得数据丢失,对业务数据非常敏感,选用AOF
- 如能承受数分钟以内数据丢失,且追求大数据集得恢复速度,选用RDB
灾难恢复选用RDB - 双保险策略,同时开启RDB和AOF,重启后,Redis优先使用AOF来恢复数据,降低丢失数据的量
Redis发布订阅
- 基于Redis实现一个网络聊天室
监听端
127.0.0.1:6379> SUBSCRIBE zhangsan lisi #监听zhangsan和lisi
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "zhangsan"
3) (integer) 1
1) "subscribe"
2) "lisi"
3) (integer) 2
1) "message"
2) "zhangsan"
3) "nihaoya"
1) "message"
2) "lisi"
3) "nihaolisi"
发送端
[root@VM-8-13-centos ~]# redis
127.0.0.1:6379> PUBLISH zhangsan nihaoya #向zhangsan发送信息
(integer) 1
127.0.0.1:6379> PUBLISH lisi nihaolisi # 向lisi发送信息
(integer) 1
使用场景:
- 实时消息系统!
- 实时聊天
- 订阅,关注系统都是可以的
主从复制
-
主从复制,进行读写分离! 80%的情况都是读操作! 可以减缓服务器压力,在架构中经常使用
查看主从信息
127.0.0.1:6379> info replication # 查看当前库的信息
# Replication
role:master # 角色
connected_slaves:0
master_replid:ca6cacde55c09ec6a9e71c723095825c09ea49d6
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
认老大
SLAVEOF 端口号
主从特点
- 主机可以设置值,从机不可以,从机只能读取
全量复制:
哨兵机制
- 配置哨兵文件 sentinel.conf
#sentinel monitor 名称 host post 主机挂了
sentinel monitor myredis 127.0.0.1 6379 1
优点:
- 哨兵几圈,基于主从复制模式,所有的主从配置优点他都有
- 主从可以切换,故障可以转移,系统的可用性就很好
- 主从模式升级,自动配置更加强壮
缺点:
- Redis不好在线扩容,集群容量一旦到达上限,在线扩容就十分麻烦
- 实现哨兵模式的配置非常麻烦
Redis缓存穿透和雪崩
- 服务器高可用问题
缓存穿透
- 用户要查询一个数据,但是在缓存中没有,于是向数据库中去查,于是本次查询失败。当用户很多的时候,缓存都没有命中,缓存就没有意义 就出现了缓存穿透
解决办法
- 布隆过滤器:是一种数据结构,在控制层进行校验,不符合直接丢弃,从而避免了对底层存储系统的查询压力
- 缓存空对象: 在缓存中不命中,将返回的空对象也缓存起来,同时设置过期时间。
- 存在问题:
- 空值被缓存起来需要更多的空间去存储更多的键。
- 即使设置了过期时间,还是会存在缓存层和存储层的数据会有一段时间窗口的不一致
- 存在问题:
缓存击穿
概述: 某个热点数据突然过期导致大量的请求落到了数据库上面导致崩溃
解决方案:
- 不去设置过期时间
- 加分布式锁: 保证对于每个key同时只有一个线程去查询后端服务,其他线程没有获取分布式锁的权限,等待就可以。这种方式将高并发的压力转移到了分布式锁,因此对分布式锁的考验很大
缓存雪崩
概述: 大部分缓存过期,导致很多的请求发送到了数据库上 或者服务器宕机或者断网
解决:
数据预热: 在正式部署之前,先把可能的数据先预先访问一遍,这样部分可能大量访问的数据就会加载到缓存当中。在即将发生大并发访问前手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间尽量均匀