Redis基本类型和操作

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 # 查询在某个范围内的人的个数

    1. “chongqing”
    2. “341.9374”
    1. “xian”
    2. “483.8340”

127.0.0.1:6379> GEORADIUS china 110 30 500 km withdist withcoord count 2 #可以排序并且可以确定人数

    1. “chongqing”
    2. “341.9374”
      1. “106.49999767541885376”
      2. “29.52999957900659211”
    1. “xian”
    2. “483.8340”
      1. “108.96000176668167114”
      2. “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

优点

  1. 适合大规模的数据恢复

  2. 对数据的完整性要求不高

缺点

  1. 需要一定的时间间隔进程操作 如果Redis意外宕机,这个最后一次修改数据就没有了
  2. fork进程的时候,会占用一定的内容空间

AOF持久化

  • 将我们所有的命令记录下来,恢复的时候就把这个文件全执行一遍

  • 以日志的形式记录每个写操作

默认是不开启

  • 开启之后设置

    • always 每一次写操作都写入

    • everysec 每秒写入一次

    • no 不写入

如果AOF配置文件有错误Redis启动不起来,通过Redis提供的工具来修复AOF文件–redis-check-aof

优点

  1. 每一次修改都同步,文件的完整性更加好

  2. 每秒同步一次,可能会丢失一秒的数据

  3. 从不同步,效率最高

缺点

  1. 相对于数据文件,aof远远大于rdb文件,修复速度也rdb慢

  2. AOF运行效率也要比rdb慢,所以我们redis默认是RDB持久化

RDB和AOF的选择之感

  • 对数据非常敏感,建议使用默认的AOF持久化方案
    AOF持久化策略使用erverysecond,每秒钟fsync一次。该策略redis任然可以保持很好的处理性能,当出现问题时,最多丢失0-1秒中的数据。
    注意:由于AOF文件存储体积较大,且恢复数据较慢
  • 数据呈现阶段有效性,建议使用RDB持久化方案
    数据可以良好的做到阶段内无丢失(该阶段是开发者或运维人工手工维护的),且恢复速度较快,阶段点数据恢复通常采用RDB方案
    注意:利用RDB实现紧凑的数据持久化会使Redis降得很低
  • 综合对比
    1. RDB与AOF得选择实际上是在做一种权衡,每种都有利弊
    2. 如不能承受数分钟以内得数据丢失,对业务数据非常敏感,选用AOF
    3. 如能承受数分钟以内数据丢失,且追求大数据集得恢复速度,选用RDB
      灾难恢复选用RDB
    4. 双保险策略,同时开启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

使用场景:

  1. 实时消息系统!
  2. 实时聊天
  3. 订阅,关注系统都是可以的

主从复制

  • 主从复制,进行读写分离! 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

优点

  1. 哨兵几圈,基于主从复制模式,所有的主从配置优点他都有
  2. 主从可以切换,故障可以转移,系统的可用性就很好
  3. 主从模式升级,自动配置更加强壮

缺点:

  1. Redis不好在线扩容,集群容量一旦到达上限,在线扩容就十分麻烦
  2. 实现哨兵模式的配置非常麻烦

Redis缓存穿透和雪崩

  • 服务器高可用问题
缓存穿透
  • 用户要查询一个数据,但是在缓存中没有,于是向数据库中去查,于是本次查询失败。当用户很多的时候,缓存都没有命中,缓存就没有意义 就出现了缓存穿透

解决办法

  • 布隆过滤器:是一种数据结构,在控制层进行校验,不符合直接丢弃,从而避免了对底层存储系统的查询压力
  • 缓存空对象: 在缓存中不命中,将返回的空对象也缓存起来,同时设置过期时间。
    • 存在问题:
      • 空值被缓存起来需要更多的空间去存储更多的键。
      • 即使设置了过期时间,还是会存在缓存层和存储层的数据会有一段时间窗口的不一致
缓存击穿

概述: 某个热点数据突然过期导致大量的请求落到了数据库上面导致崩溃

解决方案

  1. 不去设置过期时间
  2. 分布式锁: 保证对于每个key同时只有一个线程去查询后端服务,其他线程没有获取分布式锁的权限,等待就可以。这种方式将高并发的压力转移到了分布式锁,因此对分布式锁的考验很大
缓存雪崩

概述: 大部分缓存过期,导致很多的请求发送到了数据库上 或者服务器宕机或者断网

解决

数据预热: 在正式部署之前,先把可能的数据先预先访问一遍,这样部分可能大量访问的数据就会加载到缓存当中。在即将发生大并发访问前手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间尽量均匀

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值