Redis数据库
一、Redis数据库简介
Redis是一个开源的使用ANSI C语言编写、遵守BSD协议、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。
它通常被称为数据结构服务器,因为值(value)可以是 字符串(String), 哈希(Hash), 列表(list), 集合(sets) 和 有序集合(sorted sets)等类型。
二、Redis数据库基础知识
-
查看数据库
1、单个Redis实例中默认是16个数据库,数据库从0号库到15号库,默认使用0号库。
2、使用SELECT命令切换数据库,SELECT 0;选择0号库。
3、使用DBSIZE命令查看当前数据库中的key数量。
-
清空数据库
1、使用FLUSHDB可以清空当前数据库。
2、使用FLUSHALL会清空所有数据库中的数据。
-
查看数据库中的所有key
1、使用KEYS *用于获取当前数据库中的key。
2、使用KEYS ??用于获取当前数据库中的key xx,?代表一位任意字符。
三、Redis五大数据类型
Redis不仅仅是key-value键值存储结构,而是一个数据结构存储服务器,支持多种类型的values。五大数据类型包括String、List、Set、Hash、Zset。
String(字符串)
Binary-safe string:二进制安全字符串,Redis的string类型可以包含任何数据。比如jpg图片或者序列化对象等。但是很少会去存储图片。
-
字符串类型的读写
1、使用SET命令写入一个字符串
SET k1 v1
2、使用GET命令读出一个key的值
GET k1
3、使用del命令删除指定key
del k1
List(列表)
Redis列表是简单的字符串列表,按照插入的顺序排序。可以添加一个元素到列表的头部(左边)或者尾部(右边)。List的底层实现是一个链表。
-
List类型的读写
1、使用LPUSH/RPUSH命令插入一个列表
LPUSH list1 1,2,3,4,5 RPUSH list2 1,2,3,4,5
2、使用LRANGE读取
LRANGE list1 0 -1 #0 -1获取列表指定范围内的元素 LRANGE list2 0 -1
3、使用lpop移出并获取列表的第一个元素
lpop list1
4、使用rpop移除并获取列表最后一个元素
rpop list1
Set(集合)
Redis的Set是不重复且无序的字符串元素的集合。
-
Set类型的读写
1、使用SADD写入一个集合
sadd set1 1 1 2 3 4 5 #实际插入的结果为1 2 3 4 5
2、使用SMEMBERS读取一个集合
SMEMBERS set1
3、使用sismembers 判断 member 元素是否是集合 key 的成员。
sismembres set1 4
4、使用srem 移除集合中一个或多个成员
srem set1 2
Hash(哈希)
Redis hash是一个键值对集合,它是一个string类型的field和value的映射表,hash适合用于存储对象。
-
hash类型的读写
1、使用HSET写入
HSET user name To HSET user age 20
2、使用HGET读取一个hash值
HGET user name HGET user age
3、使用hdel命令删除一个或多个哈希表字段,这里需要注意的是hdel不是删除key,而是删除key中的某个field,如果只带上key一个参数,则会报错。
hdel user name
Zset(sorted set:有序集合)
Redis zset类似Sets,但是每个字符串元素都关联到一个叫score浮动数值(floating number value)。里面的元素总是通过score进行着排序,所以不同的是,它是可以检索的一系列元素。
-
Zset类型的读写
1、使用ZADD写入一个Zset
ZADD zset1 60 V1 70 V2 80 V3 90 V4 100 V5
2、使用ZRANGE读取一个Zset
ZRANGE zset1 0 -1 #0 -1表示获取全部值
四、Redis存在的问题
缓存穿透
-
缓存穿透
正常情况下,我们去查询数据都是存在。那么请求去查询一条压根儿数据库中根本就不存在的数据,也就是缓存和数据库都查询不到这条数据,但是请求每次都会打到数据库上面去。 这种查询不存在数据的现象我们称为缓存穿透。
-
解决方式
缓存空值:
之所以会发生穿透,就是因为缓存中没有存储这些空数据的key。从而导致每次查询都到数据库去了。
那么我们就可以为这些key对应的值设置为null 丢到缓存里面去。后面再出现查询这个key 的请求的时候,直接返回null 。
这样,就不用在到数据库中去走一圈了,但是别忘了设置过期时间。
BloomFilter:
BloomFilter 类似于一个hbase set 用来判断某个元素(key)是否存在于某个集合中。
这种方式在大数据场景应用比较多,比如 Hbase 中使用它去判断数据是否在磁盘上。还有在爬虫场景判断url 是否已经被爬取过。
这种方案可以加在第一种方案中,在缓存之前在加一层 BloomFilter ,在查询的时候先去 BloomFilter 去查询 key 是否存在,如果不存在就直接返回,存在再走查缓存 -> 查 DB。
缓存击穿
-
缓存击穿
缓存击穿是我们可能遇到的第二个使用缓存方案可能遇到的问题。
在平常高并发的系统中,大量的请求同时查询一个 key 时,此时这个key正好失效了,就会导致大量的请求都打到数据库上面去,导致数据库压力激增。这种现象我们称为缓存击穿。
-
解决方式
缓存击穿的现象是多个线程同时去查询数据库中的同一条数据,可以在第一个查询数据的请求上使用一个 互斥锁来锁住它。
其他的线程走到这一步拿不到锁就等着,等第一个线程查询到了数据,然后做缓存。后面的线程进来发现已经有缓存了,就直接走缓存。
缓存雪崩
-
缓存雪崩
缓存雪崩是指当某一时刻发生大规模的缓存失效的情况(如:缓存服务宕机),会有大量的请求进来直接打到DB上面。导致数据库压力激增而宕机。
-
解决方式
事前:
使用集群缓存,保证缓存服务的高可用
这种方案就是在发生雪崩前对缓存集群实现高可用,如果是使用 Redis,可以使用 主从+哨兵 ,Redis Cluster 来避免 Redis 全盘崩溃的情况。
事中:
ehcache本地缓存 + Hystrix限流&降级,避免MySQL被打死
使用 ehcache 本地缓存的目的也是考虑在 Redis Cluster 完全不可用的时候,ehcache 本地缓存还能够支撑一阵。
使用 Hystrix进行限流 & 降级 ,比如一秒来了5000个请求,我们可以设置假设只能有一秒 2000个请求能通过这个组件,那么其他剩余的 3000 请求就会走限流逻辑。
然后去调用我们自己开发的降级组件(降级),比如设置的一些默认值呀之类的。以此来保护最后的 MySQL 不会被大量的请求给打死。
事后:
开启Redis持久化机制,尽快恢复缓存集群
一旦重启,就能从磁盘上自动加载数据恢复内存中的数据
五、Redis测试点
-
缓存增加/更新功能是否正确,查看缓存数据是否正确
-
缓存删除 2.1 缓存有效,验证相关业务功能 2.2 缓存被删除,验证相关业务功能 2.3 缓存过期失效,redis设置失效时间
-
缓存穿透
-
缓存击穿
-
缓存雪崩
-
缓存淘汰机制
-
redis缓存服务异常测试(如:宕机)
-
缓存超时
-
缓存数据恢复数据(宕机/误删后快速恢复)