Redis简单学习笔记

1.Redis简介

Redis是完全开元免费的是一个高性能的NOSQL的key-value数据库

Redis是一个开元的使用ANSI C语言编写,支持网络,可基于内存亦可持久化的日志型,Key-Value数据库

2.NoSQL

泛指非关系型数据库:数据与数据之间没有关联关系。可以用命名来解决
比较适用于:

(1)数据模型简单

(2)需要灵活性更强的IT系统

(3)对数据库性能要求较高

(4)不要要高度的数据一致性

(5)对于给定key,比较容易映射复杂值的环境

与其他Key-value:

1.Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。

2.Redis不仅仅支持简单的key-value类型的数据,同时还提供list、set、zset、hash等数据结构的存储。

3.Redis支持数据的备份、集群等高可用功能

Redis的特点

1.性能极高

-Redis能读的速度是110000次/s,写的速度是81000次/s 2.丰富的数据类型

2.丰富的数据类型

-Redis支持类型String,List,Hash,Set以及OrderSet数据类型操作

3.原子

-Redis的所有操作都是原子性的,意思就是要买成功执行,要买失败完全不执行。单个操作是原子性的,多个操作也支持事务

4.丰富的特性

-Redis还支持public/subscribe通知key国旗等等特性

3. 其余的数据库类型

1.键值存储数据库

这一类数据主要会使用一个哈希表,这个表中有一个特定的键和一个指针指向特定的数据。key/value模型对于it系统来说优势在于简单,易部署。但是如果DBA只对部分只进行查询或者更新的时候,key/value就显得效率低下

2.文档型数据库

该类型的数据模型是版本化的文档,半结构化的文档以特定的格式存储,比如JSON。文档型数据库可以看做是键值型数据库的升级版,允许之间嵌套键值。而且文档型数据库比键值数据库的查询效率更高。

3.图形数据库

同其他行列以及港星结构的SQL数据库不同,它是使用灵活的图形模型,并且能够扩展到多个服务器上面。NoSQL数据库没有标准的查询语言,因此进行数据-库查询需要定制数据模型。

Redis总结

Redis单个key存入512m大小
Redis支持多种类型的数据结构
Redis是单线程 原子性
Redis可以持久化 因为使用了RDB和AOF机制
Redis支持集群 而且redis支持库(0-15)16个库
Redis还可以做消息队列 比如聊天室 IM
企业级开发中可以用作数据库、缓存和消息中间件等大部分功能
优点:
1.丰富的数据结构
2.高速读写,Redis使用自己实现的分离器,代码量很短,没有使用lock
缺点:
1.持久化。Redis直接将数据存储到内存中,呀将数据保存到磁盘上
2.耗内存,占用内存过高。

Redis配置

1.Redis默认不是以守护进程的方式运行, 可以通过该配置项修改,使用yes启用守护进程

daemonize no //改为yes

Redis采用是单进程多线程的模式,当redis.conf中选项daemonize设置成yes时代表开启守护进程模式,在该模式下,Redis会在后台运行,并将进程pid号写入至redis.conf选项pidfile设置的文件中,此时Redis将一直运行,除非手动kill该进程。但当daemonize选项设置成no时,当前界面进入Redis的命令行界面,exit强制退出或者关闭连接工具

2.当Redis以守护进程方式运行时,Redis默认会把pid写入/var/run/redis pid文件,可以通过pidfile指定

pidfile /var/run/redis.pid

3.Redis作为优秀的中间缓存件,时常会存储大量的数据,即使采取了集群部署来动态扩容,也应该即时的整理内存,维持系统性能(如果一直新增,内存很快就会沾满)

在Redis中有两种解决方案:

一是为数据设置超时时间

设定内存空间,建议内存不要超过256-512M

二是采用LRU算法动态将不用的数据删除。

内存管理的一种页面置换对于在内存中但又不用的数据块叫做LRU,操作系统会根据那些数据属于LRU而将其移除内存而腾出空间来加载另外的数据。
1.volatile-lru:设超时时间的数据中,删除最不常使用的数据
2.allkeys-lru:查询所有的key中最近不常使用的数据进行删除,这是应用最广泛的策略
3.volatile-random:在已经设定了超时的数据中心随即删除
4.allkeys-random:查询所有的key之后随即删除
5.volatile-ttl:查询全部设定超时时间的数据之后排序,将马上要过期的数据进行删除操作
6.Noeviction:如果设置为该属性则不会进行删除操作,如果内存溢出则报错返回

远程服务上执行命令 :

redis-cli -h ip地址 -p 端口 -a 密码

Redis关闭

1.断电,非正常关闭 容易数据丢失

查询PID ps -ef | grep -i redis
kill -9 PID

2.正常关闭,数据保存

./bin/redis-cli shutdown

redis常用命令

Expire key seconds
1.限时的优惠活动信息
2.网站数据缓存
3.手机验证码
4.限制网站访客访问频率

Redis命名规范

1.key不要太长,尽量不要超过1024字节,这不仅消耗内存,而且还会降低查找效率;
2.key也不要太短,太短的话,key的可读性会降低
3.在一个项目中,key最好使用同一的命名模式,例如user:123:password;

Redis数据类型

1.string

string是Redis最基本的数据类型,一个key对应一个value
string类型是二进制安全的。Redis的string可以包含任何数据,比如jpg图片或者序列化的对象
string类型是Redis最基本的数据类型,一个键最大能存储512MB
二进制安全是指,在传输数据时,保证二进制数据的信息安全,也就是不被篡改,破译等,如果被攻击,能够及时检测出来。
二进制安全特点 :

1.编码解码发生在客户完成,执行效率高
2.不需要频繁的编解码,不会出现乱码。

2.string命令

2.1赋值语法:
SET KEY_NAME VALUE

Redis set命令用于设置给定key的值,如果key已经存储值,set就覆盖旧值且无视类型

SETNX key value

只有在key不存在时设置key的值。Setnx(SET If Not exists)命令在指定的key不存在时,为key设置指定的值。

MSET key value [key value...]

同时设置一个或多个key-value对

2.2取值语法
GET KEY_NAME

Redis get命令用于获取指定key的值。如果key不存在,返回nil。如果key存储的值不是字符串类型,返回一个错误。

GETRANGE key Start end

用于获取存储在指定key中字符串的子字符串,字符串的截取范围由start和end两个偏移量决定(包括start和end在内)

GETBIT key offset

对于key所存储的字符串值,获取指定偏移量上的位

2.3自增/自减
incr key value

incr命令将key中储存的数字值增1.如果key不存在,那么key的值会先被初始化为0,然后执行incr操作。

自增:incrby KEY_NAME 增量值

incrby命令将key中储存的数字加上指定的增量值

自减decr KEY_NAME 或者 DECYBY KEY_NAME减值

decr命令将key中储存的数字减1

字符串拼接:append KEY_NAME VALUE
appen命令用于指定的key追加至末尾,如果不存在,为其赋值

2.4应用场景
1.string通常用于保存单个字符串或JSON字符串数据
2.因string是二进制安全的,所以你完全可以把一个图片的内容作为字符串来存储
3.计数器(常规key-value缓存应用,常规技术:微博数,粉丝数)
incr等指令本身就是有原子操作的特性,所以我们完全可以利用Redis的incr,incrby,decr,decrby等指令来实现原子技术的效果。

2.Hash

Redis hash是一个string类型的field和value的映射表,hash特别适合用于存储对象,Redis中每个hash可以存储2^32 -1键值对
可以看成具有key和value的map容器,该类型非常适合于存储值对象的信息,如uname,upass,age等。该数据仅占用很少的磁盘空间。

2.1Hash命令
2.1.1赋值语法
HSET KEY Field value //为指定的key,设定fild/value
HMSET KEY Field Value [field1,value]...同时将多个field-value( 域-值)对设置到哈希表key中。
2.1.2取值语法
HGET KEY FIELD //获取存储在HASH中的值,根据field得到value
HMSET key field [field] //获取key所有给定字段的值
HGETALL key //返回HASH表中所有的字段和值
HKEYS key//获取所有哈希表中的字段
HLEN key//获取哈希表中字段的数量
2.1.3删除语法
HDEL KEY field[field2] //删除一个或多个HASH表字段
2.1.4其他语法
HSETNX key field value //只有在字段field不存在时,设置哈希表字段的值
HINCRBY key field increment //为哈希表key中的指定字段的整数值加上增量increment
HINCRBYFLOAT key field increment //为哈希表key中的指定字段的浮点数值加上增量increment。
HEXISTS key field //查看哈希表key中,指定的字段是否存在

2.1.5应用场景

Hash的应用场景:
1、常用于存储一个对象
2、为什么不用string存储一个对象?
hash是最接近关系型数据库结构的数据类型,可以将数据库一条记录或程序中一个对象转换成hashmap存放在redis中。
用户id为查找的key,存储的value用户对象包含姓名,年龄,生日等信息,如果用普通的key/value结构来存储,主要有两种存储方式:

第一种方式将用户id作为查找key,把其他信息封装成一个对象以序列化的方式存储,这种方式的缺点是,增加了序列化/反序列化的开销,并且在需要修改其中一项信息时,需要把整个对象取回,并且修改操作需要并发进行保护,引入CAS等复杂问题。

第二种方法是这个用户信息对象有多少成员就存成多少key-value对,用用户id+对应属性的名称作为唯一表示来取得对应属性的值,虽然省去了序列化和并发问题,但是用户id为重复存储,如果存在大量这样的数据,内存浪费还是非常可观的。

Hash总结:
Redis提供的hash很好的解决了这个问题,Redis的hash实际是内部存储的value为一个hashmap,并提供了直接存取这个map成员的的接口

3.list类型

3.1简介

Redis列表是简单的字符串列表,按照插入顺序排序,你可以添加一个元素到列表的头部或者尾部,一个列表最多可以包含2^32 -1个元素,类似于java中的linklist

3.2命令

3.2.1赋值语法
LPUSH key value 将一个或者多个值插入到列表头部(从左侧添加)
RPUSH key value 在列表中添加一个或者多个值(从右侧添加)
LPUSHX key value 将一个值插入到已存在的列表头部。如果列表不在,操作无效
RPUSHR key value 一个值插入已存在的列表尾部,如果列表不在操作无效

3.2.2取值语法:
LLEN key 获取列表长度
LINDEX key index 通过索引获取列表中的元素
LRANGE key start stop 获取列表指定范围内的元素
描述:返回列表中指定区间的元素,区间以偏移量start和end指定,其中0表示列表的第一个元素,1表示列表的第二个元素,依次类推。也可以使用负数下表,以-1表示列表的最后一个元素,-2表示列表的倒数第二个元素

3.2.3删除语法:
LPOP key 移出并获取列表第一个元素 (从左侧删除)
RPOP key 移除列表的最后一个元素,返回值为移除的元素(从右侧删除)
BLPOP key timeout 移出并获取列表的第一个元素,如果没有原色会阻塞列表知道等待超时或发现可弹出元素为止。
BRPOP key timeout 移出并获取列表的最后一个元素,如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
LTRIM key start stop 对一个列表进行修改,就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除。

3.2.3修改语法:
LSET key index value 通过索引设置列表元素的值
LINSERT key BEFFORE|AFTER word value 在列表前或后插入元素
描述:将值value插入到列表key当中,位于值world之前或之后。

3.2.4高级语法:
RPOPLPUSH source destination 移除列表的最后一个元素,并将该元素添加到另外一个列表并返回
实例描述:
RPOPLPUSH a1 a2 //a1最后的元素移到a2的左侧
RPOPLPUSH a1 a1 //循环列表,将最后元素移到最左侧
BRPOPLPUSH source destination timeout //从列表弹出一个值,将弹出的元素插入另外一个列表中并返回它,如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止

3.2.5应用场景:
项目常应用于:1、对于数据量大的集合数据删减,2、任务队列

1、对数据量大的集合数据删减
列表数据显示,关注列表,粉丝列表、留言评价等…分页、热点新闻(top5)等
利用LRANGE还可以很方便的实现分页的功能,在博客系统中,每篇博文的评论也可以存入一个单独的list中

2.任务队列
list通常用来实现一个消息队列,而且还可以确保先后顺序,不必像mysql那样还需要通过order by来进行排序
任务队列介绍(生产者和消费者模式):
在处理web客户端发送的命令请求时,某些操作的执行时间可能会比我们预期的要长一些,通过将执行任务的相关信息放到队列里面,并在之后对队列进行处理,用户可以推迟执行那些需要一段时间才能完成的操作,这种将工作缴费人物处理器来执行的做法被称为任务队列
RPOPLPUSH source destination //移除列表的最后一个元素,并将钙元素添加到另一个列表并返回
示例描述:
常用案例:订单系统的下单流程,用户系统登录注册短信等

4.set类型

Redis的Set是String类型的无序集合 集合成员是唯一的,这就意味着集合中不能出现重复的数据。
Redis的集合对象set底层存储结构使用了intset和hashtable两种数据结构存储的,intset我们可以理解为数组,hashtable就是普通的哈希表
intset内部其实是一个数据,而且存储数据的时候是有序的,因为在查找数据的时候是通过二分查找来实现的

4.2命令
4.2.1赋值语法
sadd key member1 向集合添加一个或多个成员

4.2.2取值语法:
scard key 获取集合成员数
smembers key 返回集合中的所有成员
sismember key member 判断member元素是否是集合key的成员
srangmember key 返回集合中一个或多个随机数

4.2.2删除语法:
srem key member1 移除集合中一个或多个成员
spop key 移除并返回集合中的一个随机元素
smove source destination member 将member元素从source集合移动到destination集合

4.2.3差集语法:
sdiff key 返回给定所有集合得差集
sdiffstore destination key1 返回给定所有集合得差集并存储在destination 中

4.2.4交集语法:
sinter key1 返回给定所有集合得交集
sinterstore destination key1 返回给定所有集合得交集并存储在destination中

4.2.5并集语法:
sunion key1 返回所有给定集合得并集
sunionstore destination key 所有给定集合得并集存储在destination集合中

4.2.6应用场景
常用于对两个集合间的数据计算 进行交集、并集、差集运算
1、以非常方便的实现如共同关注,共同喜好,二度好友等功能。对上面的所有集合操作,你还可以使用不同的命令选择将结果返回给客户端还是存集到一个新的集合中。
2、利用唯一性,可以统计访问网站所有独立IP

5.zset类型

5.1简介

1.Redis有序集合和集合一样是string类型元素的集合,且不允许重复的成员。
2.不同的是每个元素都会关联一个double类型的分数。Redis正是通过分数来为集合中的成员从小到大的排序。
3.有序集合得成员是唯一的。但分数却可以重复
4.集合是通过哈希表实现的,所以添加,删除,查找的复杂度为O(1)。集合中最大的成员数为2^32 -1
Redis的Zset是有序、且不重复

5.2命令

5.2.1赋值语法
ZADD key source member1 [member2 source2] 向有序集合添加一个或多个成员,或者更新已存在成员的分数。

127.0.0.1:6379> zadd z1 95 java 80 html 90 db
(integer) 3

5.2.2取值语法
ZCARD key 获取有序集合得成员数

127.0.0.1:6379> zcard z1
(integer) 3

ZCOUNT key min max 计算在有序集合中指定区间分数的成员数

127.0.0.1:6379> zcount z1 0 100
(integer) 3
127.0.0.1:6379> zcount z1 0 60
(integer) 0

ZRANK key member 返回有序集合中指定成员的索引

127.0.0.1:6379> zrank z1 html
(integer) 0

ZRANGE key start stop [WITHSCORES] 通过索引区间返回有序集合指定区间内的成员(低到高)
示例:

127.0.0.1:6379> zadd z1 95 java 80 html 90 db
(integer) 3
127.0.0.1:6379> zrange z1 0 -1
1) "html"
2) "db"
3) "java"

ZREVRANGE key start stop [WITHSCORES] 返回有序集中指定区间内的成员,通过索引,分数从高到低

127.0.0.1:6379> zrevrange z1 0 -1
1) "java"  //95
2) "db"  //90
3) "html"  //80

5.2.3删除语法
del key 移除集合

ZREM key member [member...] 移除有序集合中的一个或多个成员
127.0.0.1:6379> zrem z1 db
(integer) 1

ZRENRANGERBYRANK key start stop 移除有序集合中给定的排名区间的所有成员(第一名是0)

127.0.0.1:6379> zremrangebyrank z1 0 -1
(integer) 2

ZRENRANGERBYSCORE key min max 移除有序集合中给定的分数区间的所有成员

127.0.0.1:6379> zremrangebyscore z1 0 90
(integer) 0
127.0.0.1:6379> zremrangebyscore z1 0 95
(integer) 0
127.0.0.1:6379> zrange z1 0 -1
1) "html"

5.2.4应用场景
常用于:排行榜
1.比如Twitter 的public timeline 可以发表时间作为score来存储,这样获取时就是按照时间排好序的
2.比如一个存储全班同学成绩的Sorted Set,其集合value可以是同学的学号,而score就可以是其考试得分,这样在数据插入集合得时候,就已经进行了天然的排序。
3.还可以用Sorted Set来做带权重的队列,比如普通消息的score为1,重要消息的score为2,然后工作线程可以选择按score的倒序来获取工作任务,让重要的任务优先执行

6.Redis之发布订阅功能

6.1简介
Redis发布订阅(pub/sub)是一种消息通信模式,发送者(pub)发送消息,订阅者(sub)接收消息
Redis客户端可以订阅任意数量的频道

6.2示例

展示了频道channel1,以及订阅这个频道的三个客户端–client2、client5和client1之间的关系
Redis简单学习笔记_第1张图片
当有新消息通过PUBLISH命令发送给频道channel1时,这个消息就会被发送给订阅它的三个客户端:

Redis简单学习笔记_第2张图片
6.3命令

6.3.1订阅频道:
SUBSCRIBE channel [channel...] 订阅给定的一个或多个频道的消息
PSUBSCRIBE pattern [pattern] 订阅一个或多个符合给定模式的频道

6.3.2发布频道
PUBLISH channel [channel.....] 将信息发送给指定的频道。

6.3.3退订频道
UNSUBSCRIBE [channel [channel....]] 指退订给定的频道
PUNSUBSCRIBE [pattern [pattern....]] 退订所有给定模式的频道

6.3.4应用场景
这一功能最明显的用法就是构建实时消息系统,比如普通的即时聊天,群聊等功能
1.在一个博客网站中,有100个粉丝订阅了你,当你发布新文章,就可以推送消息给粉丝们。
2.微信公众号模式

6.Redis多数据库

Redis下,数据库是由一个整数索引标识,而不是由一个数据库名称,默认情况下一个客户端连接到数据库0.
redis配置文件下面的参数来控制数据库总数
database 16 //从0开始1 2 3 4…15
select 数据库,数据库的切换
数据库清空:
flushdb //清除当前数据库的所有key
flushall //清除整个redis的数据库所有key

7.Redis事务

Redis事务可以一次执行多个命令,按顺序地串行化执行,执行中不会被其它命令插入,不需加塞

7.1简介
Redis事务可以一次执行多个命令,(允许再一次单独的步骤中执行一组命令),并且带有一下两个重要特征:

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

1.Redis会将一个事物中的所有命令序列化,然后按顺序执行
2.执行中不会被其他命令插入,不会出现加塞行为

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

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

事务的错误处理:
队列中某个命令出现了报告错误,执行时整个的所有队列都会被取消

7.2命令:
DISCARD 取消事务,放弃执行事务块内的所有命令。
EXEC 执行所有事务块内的命令。
MUITI 标记一个事务块的开始
UNWATCH 取消WATCH命令对所有key的监视
WATCH key[key…] 监视一个或多个key,如果在事务执行之前这个或这些key被其它命令所改动,那么事务将被打断。

7.2示例1:
转账功能,A向B账号转账50元
一个事物的例子,它先以MUTI开始一个事物,然后将多个命令入队到事务中,最后由exec命令触发事务
1.输入Multi命令开始,输入命令都会依次进入命令队列中,但不会执行
2.直到输入exec后,redis会将之前的命令队列中的命令依次执行

7.3示例2 DISCARD放弃队列执行
Redis简单学习笔记_第3张图片
1.输入multi命令开始,输入的命令都会依次进入命令队列中,但不会执行
2.直到输入exec后,Redis会将之前的命令队列中命令依次执行
3.命令队列的过程中可以通过DISCARD来放弃队列运行

7.4示例3 事务的错误处理
事务的错误处理:
如果执行的某个命令报出了错误,则只有报错的命令不会被执行,而其他的命令都会执行,不会回滚。类似于java的运行时错误
Redis简单学习笔记_第4张图片
Redis简单学习笔记_第5张图片
7.4示例4 事务的错误处理
事务的错误处理:
队列中某个命令出现了报告错误,执行时整个的所有队列都会被取消。类似于java中编译时错误
Redis简单学习笔记_第6张图片
Redis简单学习笔记_第7张图片
7.5示例5 事务的错误处理
WATCH key [key…] 监视一个或多个key,如果在事务执行之前这个(或者这些key)被其他命令所改动,那么事务将被打断。
Redis简单学习笔记_第8张图片
7.6示例6 事务的错误处理
Redis unwatch命令用于取消watch命令对所有key的监视。
如果在执行了watch命令之后,exec命令或DISCARD命令先被执行的话,那就不需要在执行UNWATCH了

7.7应用场景
一组命令必须同时都执行,或者都不执行
我们想要保证一组命令再执行过程中不被其他命令插入。
商品秒杀(活动)

8.Redis脚本

Redis脚本使用Lua解释器来执行脚本。Redis2.6版本通过内嵌支持Lua环境。执行脚本的命令为EVAL。

9.Redis数据淘汰策略 redis.conf

Redis官方给的警告,当内存不足时,Redis会根据配置的缓存策略淘汰部分keys,以保证写入成功。当无淘汰策略时或没有找到合适淘汰的key时,Redis直接返回out of memory错误。
最大缓存配置
在redis,允许用户设置最大使用内存大小
maxmemory 512G
Redis提供6种数淘汰策略:

  1. volatile-lru:从已设置过期时间的数据集中挑选最近最少使用的数据淘汰
  2. volatile-lfu:从已设置过期的keys中,删除一段时间内使用次数最少使用的
  3. volatile-ttl:从已设置过期时间的数据集中挑选最近将要国旗的数据淘汰
  4. volatile-random:从已设置过期时间的数据集中随机选择数据淘汰
  5. allkeys-lru:从数据集中挑选最近最少使用的数据淘汰
  6. allkeys-lfu:从所有keys中,删除一段时间使用次数最少使用的
  7. allkeys-random:从数据集中随机选择数据淘汰
  8. no-enviction(驱逐):禁止驱逐数据(不采用任何淘汰策略。默认即为此配置),针对写操作,返回错误信息。
    建议:了解了redis的淘汰策略之后,在平时使用时应主动设置/更新key的expire时间,主动剔除不活跃的旧数据,有助于提升查询性能。

10.Redis持久化

10.1简介
数据存放于:
内存:高效,断电(关机)内存数据会丢失
硬盘:读写速度慢于内存,断电数据不会丢失
10.2 RDB
RDB是redis的默认持久化机制,RDB相当于照快照,保存的是一种状态。几十G数据-》几KB快照
快照是默认的持久化方式,这种方式就是将内存中数据以快照的方式写入到二进制文件中,默认的文件名为dump.rdb
优点:
快照保存数据极快、还原数据极快
适用于灾难备份
缺点:
小内存的机器不适合使用,RDB机制符合要求就会照快照

快照条件:

  1. 服务器正常关闭时 ./bin/redis-cli shutdown
  2. key满足一定条件就会进行快照
    在这里插入图片描述

10.3 AOF
由于快照方式是在一定间隔时间做一次的,所以如果redis意外down掉的话,就会丢失最后一次快照后的所有修改。如果应用要求不能丢失任何修改的话,可以采用AOF持久化方式。
append-only file:aof 比快照方式有更好的持久化性,是由于在使用aof持久化方式时,redis会将每一个收到的写命令都通过write函数追加到文件中(默认是appendonly:aof)。当redis重启时就会通过重新执行文件中保存的写命令来再内存中重建整个数据库的内容。
有三种方式如下(默认是:每秒sync一次)

  1. appenonly yes //启用aof持久化方式
  2. # appendfsync always //收到写命令就立即写入磁盘,最慢,但是保证完全的持久化
  3. appendfsync everysec //每秒写入磁盘一次,在性能和持久化方面做了很好的折中
  4. # appendfsync no //完全依赖os,性能最好,持久化没保证

产生的问题:
aof方式同时也会带来了另一个问题,持久化文件会变得越来越大。例如我们用incr test命令100次,文件中必须保存全部的100条命令,其中有99条都是多余的。

11.Redis缓存与数据库一致性

11.1解决方案
11.1.1 一、实时同步
对强一致要求比较高的,应采用实时同步的方案,即查询缓存查询不到再从DB查询,保存到缓存;更新缓存时,先更新数据库,再将缓存的设置国旗(建议不要去更新缓存内容,直接设置缓存过期)
@Cacheable:查询时使用,注意Long类型需转换为String类型,否则会抛出异常
@CachePut:更新时使用此注解,一定会从DB上查询数据
@CacheEvict:删除时使用
@Caching:组合用法

11.1.2 二、异步队列

对于并发编程较高的,可采用异步低劣的方式同步,可采用kafka等消息中间件处理消息生产和消费。

11.1.3 三、使用阿里的同步工具canal

canal实现方式是模拟mysql slave和master的同步机制,监控DBbitlog的日志更新来触发缓存的更新,此种方法可以解放程序员的双手,减少工作量,但在使用时会有些局限性。
Redis简单学习笔记_第9张图片
1.master将改变记录到二进制日志(binary log)中,(这些记录叫做二进制日志时间,binary log events,可以通过show binlog events 进行查看)
2.slave将master的binary log events 拷贝到它的中继日志(relay log)
3.slave重做中继日志中的事件,将改变反映它自己的数据
Redis简单学习笔记_第10张图片
1.canal模拟mysql slave 的交互协议,伪装自己为mysql slave,向mysql master发送dump协议
2.mysql master收到dump请求,开始推送binary log给slave
3.canal解析binary log对象

11.1.3 三、使用阿里的同步工具canal
面对mysql的API进行编程,利用触发器进行缓存同步,但UDF主要是C/C++语言实现,学习成本比较高。

12.总结

12.1 缓存穿透
缓存穿透是指查询一个一定不存在的数据,由于缓存时不命中时需要从数据库查询,查不到数据则不写入缓存,这将是导致这个而过不存在的数据每次请求都要到数据库区查询,造成缓存穿透。

解决办法:
持久层查询不到就缓存空结果,查询时先判断缓存中是否exists(key),如果有直接返回空,没有则查询后返回
注意insert时需清除查询的key,否则即便DB中有值也查询不到

12.2 雪崩

雪崩:缓存大量失效的时候,引发大量查询数据库。
解决办法:

  1. 用锁/分布式锁或者队列串行访问
  2. 缓存失效时间均匀分布

12.3 热点key
热点key:某个key访问非常频繁,当key失效的时候有大量线程来构建缓存,导致负载增加,系统崩溃。
解决办法:

  1. 使用锁,单机用synchronized,lock等,分布式用分布式锁。
  2. 缓存过期时间不设置,而是设置key对应的value中。如果检测到存的时间超过过期时间则异步更新缓存。
  3. 在value设置一个比过期时间t0小的过期时间值t1,当t1过期的时候延长t1并做更新缓存操作。
  4. 设置标签缓存,标签缓存设置过期时间,标签缓存过期后,需异步的更新实际缓存。

你可能感兴趣的:(Redis)