(六)Redis数据类型之Set

(六)Redis数据类型之Set

sadd

sadd key member [member1 …]

给集合内新增成员,若集合不存在则创建集合并新增成员。

1
2
3
4
5
6
7
8
9
10
11
12
13
sadd set one
sadd set two
sadd set three
sadd set four
sadd set five


Docker:0>smembers set
1) "four"
2) "two"
3) "one"
4) "three"
5) "five"

srem

srem key member [member1 …]

移除元素

smove

smove source destination member

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Docker:0>sadd set1 dick joe nick joe
"3"

Docker:0>sadd set2 helen steve frank
"3"

Docker:0>smove set1 set2 joe
"1"

Docker:0>smembers set2
1) "steve"
2) "joe"
3) "frank"
4) "helen"

Docker:0>smembers set1
1) "nick"
2) "dick"

smembers

smembers key

查看成员

1
2
3
4
5
Docker:0>smembers set2
1) "steve"
2) "joe"
3) "frank"
4) "helen"

scard

scard key

返回集合中成员的个数

1
2
3
4
5
 Docker:0>scard set2
"4"

Docker:0>scard set1
"2"

srandmember

srandmember key [count]

从集合中随机返回指定个数的成员

1
2
3
Docker:0>srandmember set2 2
1) "helen"
2) "frank"

sismember

sismember key member

判断是否存在于指定key的集合中

1
2
3
4
5
 Docker:0>smembers set1
1) "nick"
2) "dick"
Docker:0>sismember set1 dick
"1"

spop

spop key

从集合中随机弹出一个成员,返回该成员并从集合中删除该成员

1
2
3
4
5
6
7
8
9
10
11
Docker:0>smembers set2
1) "steve"
2) "joe"
3) "frank"
4) "helen"
Docker:0>spop set2
"joe"
Docker:0>smembers set2
1) "steve"
2) "frank"
3) "helen"

sinter

sinter key [key2 key3 …]

取多个集合的交集,返回这些集合中共同拥有的成员

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Docker:0>smembers setA
1) "C"
2) "A"
3) "F"
4) "B"
5) "D"
6) "E"
Docker:0>smembers setB
1) "E"
2) "D"
3) "B"
4) "C"
5) "F"
Docker:0>smembers setC
1) "D"
2) "C"

Docker:0>sinter setA setB setC
1) "D"
2) "C"

sinterstore

sinterstore destination key [key1 key2 …]

取多个集合的交集∩, 结果存于新的set

1
2
3
4
5
6
Docker:0>sinterstore rest_A_B_C setA setB setC
"2"

Docker:0>smembers rest_A_B_C
1) "D"
2) "C"

sunion

sunion key [key1 key2 …]

求并集∪,相同的成员会被去重

1
2
3
4
5
6
7
Docker:0>sunion setA setB setC
1) "F"
2) "B"
3) "D"
4) "A"
5) "C"
6) "E"

sunionstore

sunionstore destination key [key …]

将多个集合的并集的结果保存为一个新的集合destination ,返回新集合的成员个数。

1
2
3
4
5
6
7
8
9
10
Docker:0>sunionstore union_A_B_C setA setB setC
"6"

Docker:0>smembers union_A_B_C
1) "F"
2) "B"
3) "D"
4) "A"
5) "C"
6) "E"

sdiff

sdiff key [key1 key2 …]

取多个集合的差集,以最左边的为主集合,返回左集合中有而其他集合没有的成员

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Docker:0>smembers setA
1) "C"
2) "A"
3) "F"
4) "B"
5) "D"
6) "E"
Docker:0>smembers setB
1) "E"
2) "D"
3) "B"
4) "C"
5) "F"
Docker:0>smembers setC
1) "D"
2) "C"
※ 集合A 比集合B和集合C多了A这个元素
Docker:0>sdiff setA setB setC
1) "A"

sdiffstore

sdiffstore destination key [key1 key2 …]

将多个集合的差集的结果保存为一个新的集合destination,返回新集合的成员个数

1
2
3
4
5
6

Docker:0>sdiffstore diff_A_B_C setA setB setC
"1"

Docker:0>smembers diff_A_B_C
1) "A"

set 集合结合具体业务场景:

应用场景

  • 抽奖:随机返回指定个数成员
  • 共同好友:取交集
  • 好友推荐:根据标签取交集,交集的成员个数大于某个阈值触发推荐动作

(一) Redis 数据类型之字符串String

(一) Redis 数据类型之字符串String

判断key是否存在,返回true / false, 1/0

1
exists key

查看剩余存活时间

※ 获取不存在的key,返回-1

1
ttl key

查看过期key情况

※ redis作为一个内存型的数据库,我们需要对过期key保持关注,从info keyspace中可以看出有多少key没有设置过期时间

1
2
3
info keyspace

eg: db0:keys=10000,expires=3,avg_ttl=583699

set

set key value [ex seconds] [px milliseconds] [nx|xx]

  • ex : 过期 (s)
  • px: 过期 (ms)
  • nx: 不存在则创建
  • xx: 存在则覆盖创建
1
2
3
4
5
6
7
8
9
10
11
12
set key value

set key value ex 10
或者写法为: setex key 10 value

set key value px 1000
或者写法为: psetex key 1000 value

set key value nx
或者写法为: setnx key value

set key value xx

mset

mset, msetnx 批量创建

mset key1 value1 [key2 value2…] #批量创建kv,已存在的会被更新

msetnx key1 value1 [key2 value2…] #批量创建kv,所有key不存在才会创建

1
2
3
4
5
6
127.0.0.1:6379> mset k1 a k2 b k3 c
OK
127.0.0.1:6379> mget k1 k2 k3
1) "a"
2) "b"
3) "c"

del

del key1 [key2 key3…]

1
2
3
4
5
6
7
8
9
10
127.0.0.1:6379> del k1 k2 k3
(integer) 3
127.0.0.1:6379> del name_xx
(integer) 1
127.0.0.1:6379> mget k1 k2 k3 name_xx name_nx
1) (nil)
2) (nil)
3) (nil)
4) (nil)
5) "dick"

getset

getset key new_value

等同于get+set,执行此命令返回get的结果,然后将该key更新为新的value,下次再get的时候查到的就是新的value。

setrange

setrange key offeset value

对指定下标的字符串进行更新,下标从0开始算起。

keys

keys *

查看所有key

get

get key

使用get获得指定key的value

mget

mget key1 [key2 key3…]

使用mget批量获得指定keys的values

getrange

getrange key start end

从字符串的指定开始结束下标截取字符串返回,下标从0开始算起。

incr

incr key

对指定的key的value值 + 1, 若不存在,初始值为0,incr后为1。字符串无法转换会报错。

decr

decr key

对指定的key的value值 - 1, 若不存在,初始值为0,incr后为-1。字符串无法转换会报错。

incrby

incrby key

增加指定步长,如果key不存在,初始值为0,incrby后为步长。不能转换会报错。

decrby

decrby key 3

增加指定步长,如果key不存在,初始值为0,incrby后为步长的负数。不能转换会报错。

append

append key valu

追加字符串

strlen

strlen key

返回字符串的长度

incrbyfloat

incrbyfloat key 2.5

支持浮点传参

Redis使用Lua脚本的注意点

Redis使用Lua脚本的注意点

  1. Lua脚本的bug特别可怕,由于Redis的单线程特点,一旦Lua脚本出现不会返回(不是返回值)得问题,那么这个脚本就会阻塞整个redis实例。

  2. Lua脚本应该尽量短小实现关键步骤即可。(原因同上)

  3. Lua脚本中不应该出现常量Key,这样会导致每次执行时都会在脚本字典中新建一个条目,应该使用全局变量数组KEYS和ARGV, KEYS和ARGV的索引都从1开始

  4. 传递给lua脚本的的键和参数:传递给lua脚本的键列表应该包括可能会读取或者写入的所有键。传入全部的键使得在使用各种分片或者集群技术时,其他软件可以在应用层检查所有的数据是不是都在同一个分片里面。另外集群版redis也会对将要访问的key进行检查,如果不在同一个服务器里面,那么redis将会返回一个错误。(决定使用集群版之前应该考虑业务拆分),参数列表无所谓。

  5. Lua脚本跟单个redis命令和事务段一样都是原子的已经进行了数据写入的lua脚本将无法中断,只能使用SHUTDOWN NOSAVE杀死Redis服务器,所以lua脚本一定要测试好。

(九)Redis服务器相关命令

(九)Redis服务器相关命令

验证密码是否正确

使用auth命令验证密码是否正确,如果当前未登陆进行验证通过后会转为登陆状态,如果当前已登陆,会返回验证结果成功或失败:

1
auth password

查看服务器信息

1
2
3
4
5
6
7
8
9
INFO [section]

info cpu

# CPU
used_cpu_sys:5495.206247
used_cpu_user:5338.722012
used_cpu_sys_children:0.627837
used_cpu_user_children:0.214709

统计当前库下key的数量

1
dbsize

查看配置信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
config get patten

config get port

config get max*

config get *


Docker:0>config get port
1) "port"
2) "6379"

Docker:0>config get max*
1) "maxmemory"
2) "0"
3) "maxmemory-samples"
4) "5"
5) "maxclients"
6) "10000"
7) "maxmemory-policy"
8) "noeviction"

修改当前配置信息(动态修改)

Config Set 命令可以动态地调整 Redis 服务器的配置(configuration)而无须重启,但此时配置文件中仍是修改前的配置,可搭配config rewrite命令一起使用:

1
config set parameter value

重写配置文件

Config rewrite 命令对启动 Redis 服务器时所指定的 redis.conf 配置文件进行改写。与config
set不同,set之后会将配置信息修改而无需重启服务,但此时redis.conf配置文件里记录的参数仍是set之前的值,如果将redis服务重启后会读取conf文件中的配置,这时候读到的还是set之前的配置,因此我们可以在set配置之后使用rewrite命令将当前的配置回写至配置文件内,这样就能不停机修改配置信息了,因此config set和config rewrite是配合使用的:

1
2
3
4
5
6
7
8
9
10
11
12
config rewrite

config set slowlog-max-len 256

config get slowlog-max-len

config rewrite

config rewrite 命令对启动 Redis 服务器时所指定的 redis.conf 配置文件进行改写写回配置文件


cat /opt/redis6/

config resetstat

使用Config Resetstat 命令重置 INFO 命令中的某些统计数据,包括:

  • Keyspace hits (键空间命中次数)
  • Keyspace misses (键空间不命中次数)
  • Number of commands processed (执行命令的次数)
  • Number of connections received (连接服务器的次数)
  • Number of expired keys (过期key的数量)
  • Number of rejected connections (被拒绝的连接数量)
  • Latest fork(2) time(最后执行 fork(2) 的时间)
  • The aof_delayed_fsync counter(aof_delayed_fsync 计数器的值)

切换数据库

redis共有16个db,从db0~db15,使用select index命令在数据库之间进行切换:

1
select index

time

Time 命令用于返回当前服务器时间,返回一个包含两个字符串的列表: 第一个字符串是当前时间(以 UNIX 时间戳格式表示),而第二个字符串是当前这一秒钟已经逝去的微秒数。

1
2
3
4
5
time

Docker:0>time
1) "1597122706"
2) "914251"

DEBUG

debug object key获取 key 的调试信息,当key不存在时返回错误信息。

debug segfault 命令执行一个非法的内存访问从而让 Redis 崩溃,仅在开发时用于 BUG 调试,执行后需要重启服务。

1
2
3
debug object key

debug segfault bengku崩溃,需要重启服务

清空库

flushdb清空当前数据库下的所有数据。
flushall清空所有库下的所有数据。

1
2
flushdb
flushall

监控

monitor命令用于监听redis服务器接收到的所有命令:

1
monitor

关闭

1
SHUTDOWN [NOSAVE|SAVE]

command

查看当前Redis中所有可用命令,使用Command 命令用于返回所有的Redis命令的详细信息,以数组形式展示:

1
command

使用command count命令查看当前Redis中命令的数量:

1
command count

使用command info命令查看当前Redis中指定的命令的详细信息:

1
COMMAND INFO command-name [command-name ...]

(十一)Redis的“事务”及Lua脚本操作

(十一)Redis的“事务”及Lua脚本操作

“事务”

redis提供简单的事务命令,由multi和exec组成,实际上相当于将多个命令添加到一个执行的集合内,multi为begin,exec为commit,discard相当于rollback,watch相当于锁,对象若在事务执行前被修改则事务被打断。

因此redis的事务机制为乐观锁,如果在高并发场景下,如果多个客户端同时对一个key进行了watch,只要有一个客户端提交成功,其他客户端的操作都是无效的,因此redis事务不适合在高并发场景下使用,使用lua脚本可以更好的解决事务解决不了的场景。

Redis 事务可以一次执行多个命令, 并且带有以下三个重要的保证:

  • 批量操作在发送 EXEC 命令前被放入队列缓存。
  • 收到 EXEC 命令后进入事务执行,事务中任意命令执行失败,其余的命令依然被执行。
  • 在事务执行过程,其他客户端提交的命令请求不会插入到事务执行命令序列中。

一个事务从开始到执行会经历以下三个阶段:

  • 开始事务。
  • 命令入队。
  • 执行事务。

如果事务中出现错误:

  1. 还未exec就报错:如果事务中出现语法错误,则事务会成功回滚,整个事务中的命令都不会提交;
  2. 成功执行exec后才报错:如果事务中出现的不是语法错误,而是执行错误,不会触发回滚,该事务中仅有该错误命令不会提交,其他命令依旧会继续提交,因此这里的”事务”打了个引号,和我们通常理解的数据库事务完全不一样。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#begin 开启一个redis事务
multi

#commit 提交事务里的命令队列
exec

#rollback 回滚
discard

#锁,监视一个或多个key,被监视的key若在提交事务前被修改,则事务被打断
watch key [key ...

#取消监视
unwatch

LUA脚本

介绍

Redis2.6之后新增的功能,我们可以在redis中通过lua脚本操作redis。与事务不同的是事务是将多个命令添加到一个执行的集合,执行的时候仍然是多个命令,会受到其他客户端的影响,而脚本会将多个命令和操作当成一个命令在redis中执行,也就是说该脚本在执行的过程中,不会被任何其他脚本或命令打断干扰。正是因此这种原子性,lua脚本才可以代替multi和exec的事务功能。同时也是因此,在lua脚本中不宜进行过大的开销操作,避免影响后续的其他请求的正常执行。

使用lua脚本的好处

  • lua脚本是作为一个整体执行的.所以中间不会被其他命令插入;
  • 可以把多条命令一次性打包,所以可以有效减少网络开销;
  • lua脚本可以常驻在redis内存中,所以在使用的时候,可以直接拿来复用,也减少了代码。

应用

redis脚本使用eval命令执行lua脚本,其中numkeys表示lua script里有多少个key参数,redis脚本根据该数字从后面的key和arg中取前n个作为key参数,之后的都作为arg参数:

1
eval script numkeys key [key ...] arg [arg ...]

场景1:记录IP登录次数

利用hash记录所有登录的IP次数

key参数的数量必须和numkey一致,使用key或者argv可以实现一样的效果。

如下面第一个命令里用了三个key,代表后面的三个参数分别对应脚本里的key1 key2 key3.

第二个命令里用了一个key,代表了后面第一个参数对应脚本里的key1,后面第二和第三个参数对应脚本里的argv1和argv2

1
2
3
4
5
6
eval "return redis.call('hincrby', KEYS[1], KEYS[2], KEYS[3])" 3 h_host host_192.168.145.1 1

※ 可以看到存在3key
eval "return redis.call('hincrby', KEYS[1], ARGV[1], ARGV[2])" 1 h_host host_192.168.145.1 1

※ 配置了1key, 2个argv参数

场景2:当10秒内请求3次后拒绝访问

  1. 给访问ip的key递增
  2. 判断该访问次数若为首次登录则设置过期时间10秒
  3. 若不是首次登录则判断是否大于3次,若大于则返回0,否则返回1。
    1
    2
    3
    eval "local request_times = redis.call('incr',KEYS[1]);
    if request_times == 1 then redis.call('expire',KEYS[1], ARGV[1]) end;
    if request_times > tonumber(ARGV[2]) then return 0 end return 1;" 1 test_127.0.0.1 10 3

通过上面的例子也可以看出,我们可以在redis里使用eval命令调用lua脚本,且该脚本在redis里作为单条命令去执行不会受到其余命令的影响,非常适用于高并发场景下的事务处理。同样我们可以在lua脚本里实现任何想要实现的功能,迭代,循环,判断,赋值 都是可以的。

lua脚本缓存

redis脚本也支持将脚本进行持久化,这样的话,下次再使用就不用输入那么长的lua脚本了。事实上使用eval执行的时候也会缓存,eval与load不同的是eval会将lua脚本执行并缓存,而load只会将脚本缓存。相同点是它们都使用sha算法进行缓存,因此只要lua脚本内容相同,eval与load缓存的sha码就是一样的。而缓存后的脚本,我们可以使用evalsha命令直接调用,极大的简化了我们的代码量,不用重复的将lua脚本写出来。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#eval 执行脚本并缓存
eval script numkeys key [key ...] arg [arg ...]

#load 缓存lua脚本
script load script

#使用缓存的脚本sha码调用脚本
evalsha sha1 numkeys key [key ...] arg [arg ...]

#使用sha码判断脚本是否已缓存
script exist sha1 [sha1 ...]

#清空所有缓存的脚本
script flush

#杀死当前正在执行的所有lua脚本
script kill

Redis的过期策略和内存淘汰机制

Redis的过期策略和内存淘汰机制

一、背景
线上你写代码的时候,想当然的认为写进 redis 的数据就一定会存在,后面导致系统各种 bug,谁来负责?
常见的有两个问题:
往 redis 写入的数据怎么没了?
可能有同学会遇到,在生产环境的 redis 经常会丢掉一些数据,写进去了,过一会儿可能就没了。我的天,同学,你问这个问题就说明 redis 你就没用对啊。redis 是缓存,你给当存储了是吧?
啥叫缓存?用内存当缓存。内存是无限的吗,内存是很宝贵而且是有限的,磁盘是廉价而且是大量的。可能一台机器就几十个 G 的内存,但是可以有几个 T 的硬盘空间。redis 主要是基于内存来进行高性能、高并发的读写操作的。
那既然内存是有限的,比如 redis 就只能用 10G,你要是往里面写了 20G 的数据,会咋办?当然会干掉 10G 的数据,然后就保留 10G 的数据了。那干掉哪些数据?保留哪些数据?当然是干掉不常用的数据,保留常用的数据了。
数据明明过期了,怎么还占用着内存?
这是由 redis 的过期策略来决定。

3种过期策略

定时删除

含义:

在设置key的过期时间的同时,为该key创建一个定时器,让定时器在key的过期时间来临时,对key进行删除

优点:

保证内存被尽快释放

缺点:

  1. 若过期key很多,删除这些key会占用很多的CPU时间,在CPU时间紧张的情况下,CPU不能把所有的时间用来做要紧的事儿,还需要去花时间删除这些key
  2. 定时器的创建耗时,若为每一个设置过期时间的key创建一个定时器(将会有大量的定时器产生),性能影响严重
  3. 没人用

惰性删除

含义:

key过期的时候不删除,每次从数据库获取key的时候去检查是否过期,若过期,则删除,返回null。

优点:

删除操作只发生在从数据库取出key的时候发生,而且只删除当前key,所以对CPU时间的占用是比较少的,而且此时的删除是已经到了非做不可的地步(如果此时还不删除的话,我们就会获取到了已经过期的key了)

缺点:

若大量的key在超出超时时间后,很久一段时间内,都没有被获取过,那么可能发生内存泄露(无用的垃圾占用了大量的内存)

定期删除

含义:

每隔一段时间执行一次删除(在redis.conf配置文件设置hz,1s刷新的频率)过期key操作

优点:

通过限制删除操作的时长和频率,来减少删除操作对CPU时间的占用–处理”定时删除”的缺点
定期删除过期key–处理”惰性删除”的缺点

缺点:

在内存友好方面,不如”定时删除”
在CPU时间友好方面,不如”惰性删除”

难点:

合理设置删除操作的执行时长(每次删除执行多长时间)和执行频率(每隔多长时间做一次删除)(这个要根据服务器运行情况来定了)

redis的过期策略和内存淘汰机制

1、定期删除+惰性删除

定期删除:指的是redis默认是每隔100ms就随机抽取一些设置了过期时间的key,检查其是否过期,如果过期就删除

惰性删除:在你获取某个key的时候,redis会检查一下 ,这个key如果设置了过期时间那么是否过期了,如果过期了此时就会删除,不会给你返回任何东西

2、如果大量过期key堆积在内存里,导致redis内存块耗尽了,怎么办?

内存淘汰机制:

redis.conf中配置:

1
# maxmemory-policy noeviction

  • noeviction:当内存使用达到阈值的时候,所有引起申请内存的命令会报错。

  • allkeys-lru:在主键空间中,优先移除最近未使用的key。

  • volatile-lru:在设置了过期时间的键空间中,优先移除最近未使用的key。

  • allkeys-random:在主键空间中,随机移除某个key。

  • volatile-random:在设置了过期时间的键空间中,随机移除某个key。

  • volatile-ttl:在设置了过期时间的键空间中,具有更早过期时间的key优先移除。

(七)Redis数据类型之ZSet(sorted_set)

(七)Redis数据类型之ZSet(sorted_set)

zadd

zadd key [NX|XX] [CH] [INCR] score member [score member …]

往有序集合中新增成员,需要指定该成员的分数,分数可以是整形或浮点型,当分数相同时候,索引下标按照字典排序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
zadd zset 1 value1 2 value2 3 value3 4 value4

1,2,3,4 表示的是各个元素的分数

Docker:0>zrange zset 0 -1
1) "value1"
2) "value2"
3) "value3"
4) "value4"

Docker:0>zrange zset 0 -1 withscores
1) "value1"
2) "1"
3) "value2"
4) "2"
5) "value3"
6) "3"
7) "value4"
8) "4"

zrange

zrange key start stop [WITHSCORES]

根据下标查看集合内所有成员(及分数),[start,stop]
[0 -1] 表示全部元素

zcard

zcard key

获取有序集合的成员数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Docker:0>zrange zset 0 -1 
1) "value1"
2) "value2"
3) "value3"
4) "value4"
Docker:0>zrange zset 0 -1 withscores
1) "value1"
2) "1"
3) "value2"
4) "2"
5) "value3"
6) "3"
7) "value4"
8) "4"
Docker:0>zcard zset
"4"

zcount

ZCOUNT key min max

从有序集合内获取指定分数区间内的成员数。

1
2
3
4
5
6
7
8
9
10
11
Docker:0>zrange zset 0 -1 withscores
1) "value1"
2) "1"
3) "value2"
4) "2"
5) "value3"
6) "3"
7) "value4"
8) "4"
Docker:0>zcount zset 2 3
"2"

zrank

ZRANK key member

返回有序集合中指定成员的索引(下标):

zrevrange

zrevrange key start stop [WITHSCORES]

与zrange功能类似,不同的是zrevrange会将集合先反序[reverse]之后再执行zrange返回。

zincrby

修改有序集合内成员的分数,将有序集合内成员的分数增加increment分值,increment可以为浮点型整型也可以为负数或正数。

zincrby key increment member

zrem

zrem key member [member …]

从集合中移除指定的成员。

Redis相关问题一

Redis 相关问题一

  1. Redis为什么那么快?

完全基于内存,绝大部分请求是纯粹的内存操作,非常快速。数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1);

数据结构简单,对数据操作也简单,Redis中的数据结构是专门进行设计的;

采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗 CPU,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗;

使用多路I/O复用模型,非阻塞IO;

使用底层模型不同,它们之间底层实现方式以及与客户端之间通信的应用协议不一样,Redis直接自己构建了VM 机制,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求;

Redis相关问题三

Redis 相关问题三

  1. Redis高并发会出现哪些问题?

1) 如果redis宕机了,或者链接不上,怎么办?

解决方法:

①配置主从复制,配置哨兵模式(相当于古代门派的长老级别可以选择掌门人的权利),一旦发现主机宕机,让下一个从机当做主机。

②如果最坏的情况,只能关闭Redis连接,去往数据库连接。但由于数据量大,这样SQL数据库也会宕掉的。

2) 如果redis缓存在高峰期到期失效,在这个时刻请求会向雪崩一样,直接访问数据库如何处理?

设置条件查询判断,判断redis缓存里是否有数据,如果没有,则去往数据库连接。当然要加分布式锁,利用redis的单线程+多路IO复用技术,原子性原理,让其它的线程请求等待,假若第一个线程进去获取到分布式锁在查询数据的途中宕掉了,不能让其它线程一直等待,设置等待一定时间判断是否取回数据,如果没有,递归调用自己的方法让第二个线程继续拿分布式锁查询数据库。当第二个锁从数据库拿到数据时,把数据值设置到redis数据库缓存中,设置失效时间,避免占内存,方便使用提高效率。

3) 如果用户不停地查询一条不存在的数据,缓存没有,数据库也没有,那么会出现什么?

如果数据不存在,缓存中没有,数据库也没有,当然如果不设置判断,会一直调用数据库,使数据库效率降低,访问量大时甚至会宕机。

解决方案:从数据库查询,如果数据库没有,则返回值为Null,判断数据库返回的值,如果为Null,则自定义把标识的字段存到Redis中,用key,value的方法,jedis.setex(key,”empty”),设置失效时间跟具体情况而定,然后调用String json=jedis.get(key),判断是否获取的值”empty”.equal(json),如果相等,则抛出自定义异常,给用户提示,或者直接return null。这样用户再次查询的时候由于先从reids缓存中查询,redis会有对应的Key获取之前设置的value值,这样就不会再次调用数据库,影响效率等问题。