redis简单学习笔记


@author gxz
@date 20180829
@desc redis学习文档

1. redis是单线程工作模型

(1)纯内存操作
(2)单线程操作,避免了频繁的上下文切换
(3)采用了非阻塞I/O多路复用机制

2. redis数据类型

(1)String
(2)hash
(3)list
使用List的数据结构,可以做简单的消息队列的功能。另外还有一个就是,可以利用lrange命令,做基于redis的分页功能,性能极佳,用户体验好。
(4)set
(5)sorted set

3. redis的过期策略以及内存淘汰机制

redis采用的是定期删除+惰性删除策略
(1)为什么不用定时策略?
定时删除,用一个定时器负责监视key,过期则自动删除,虽然内存及时释放,但是十分消耗CPU资源。
在大并发请求下,CPU要将时间应用在处理请求,而不是删除key,因此没有采用这一策略。
(2)定期删除+惰性删除是如何工作的呢?
定期删除,redis默认每个100ms检查,是否有过期的key,有过期的key则删除。需要说明的是,
redis不是每个100ms将所有的key检查一次,而是随机抽取进行检查。因此,如果只采用定期删除策略,会导致很多key到时间没有删除。于是,惰性删除派上用场。也就是说在你获取某个key的时候,redis会检查一下,这个key如果设置了过期时间,且已经过期,则删除。
(3)采用定期删除+惰性删除其他问题
如果定期删除没删除key,然后也没有即时去请求key,即惰性删除也没生效。这样,redis的内存会越来越多,那么应该采用内存淘汰机制。
redis.windows.conf中有一行配置信息:
# maxmemory-policy noeviction
该配置就是配置内存淘汰策略的:
1)noeviction:当内存不足以容纳新写入数据时,新写入操作会报错。应该没人用吧.
2)allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key。推荐使用,目前项目在用这种。
3)allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个key。应该也没人用吧,你不删最少使用Key,去随机删。
4)volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key。这种情况一般是把redis既当缓存,又做持久化存储的时候才用。不推荐
5)volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key。依然不推荐
6)volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除。不推荐
ps:如果没有设置 expire 的key, 不满足先决条件(prerequisites); 那么 volatile-lru, volatile-random 和 volatile-ttl 策略的行为, 和 noeviction(不删除) 基本上一致。

4. redis和数据库双写一致性问题

5. 如何应对缓存穿透和缓存雪崩问题

这两个问题,一般中小型传统软件企业,很难碰到这个问题。如果有大并发的项目,流量有几百万左右,这两个问题一定要深刻考虑。
(1)缓存穿透,即黑客故意去请求缓存中不存在的数据,导致所有的请求都怼到数据库上,从而数据库连接异常。
解决方案:
(一)利用互斥锁,缓存失效的时候,先去获得锁,得到锁了,再去请求数据库。没得到锁,则休眠一段时间重试。
(二)采用异步更新策略,无论key是否取到值,都直接返回。value值中维护一个缓存失效时间,缓存如果过期,异步起一个线程去读数据库,更新缓存。需要做缓存预热(项目启动前,先加载缓存)操作。
(三)提供一个能迅速判断请求是否有效的拦截机制,比如,利用布隆过滤器,内部维护一系列合法有效的key。迅速判断出,请求所携带的key是否合法有效。如果不合法,则直接返回。

(2)缓存雪崩,即缓存同一时间大面积的失效,这个时候又来了一波请求,结果请求都怼到数据库上,从而导致数据库异常。
解决方案:
(一)给缓存的失效时间,加上一个随机值,避免集体失效
(二)使用互斥锁,但是该方案吞吐量明显下降
(三)双缓存。两个缓存,缓存A和缓存B,缓存A的失效时间为20分钟,缓存B不设置失效时间。自己做缓存预热操作。

6. 如何解决redis的并发竞争key问题

这个问题大致就是,同时有多个子系统去set一个key。
不推荐使用redis事务机制,因为生产环境,基本都是redis集群环境,做了数据分片操作。你一个事物中涉及到多个key操作的时候,这多个key不一定都都存储在同一个redis-server上。
解决方案:
(1)如果对这个key操作,不要求顺序
这种情况下,准备一个分布式锁,大家去抢锁,抢到锁就做set操作即可,比较简单。
(2)如果对这个key操作,要求顺序
在这种情况下,如果想让总体效率最大化,可以采用排队的机制进行。
将所有需要对同一个key的请求进行入队操作,然后用一个消费者线程从队头依次读出请求,并对相应的key进行操作。
这样对于同一个key的所有请求就都是顺序访问,正常逻辑下则不会有写失败的情况下产生 。从而最大化写逻辑的总体效率。

================

redis的rdb的配置选项和它的工作原理:

save 900 1 // 表示的是900s内,有1条写入,则产生快照

save 300 1000 // 表示的是300s内,有1000次的写入,则产生快照

save 60 10000 // 表示的是60s内,有10000次的写入,则产生快照

(这3个选项都屏蔽,则rdb被禁用)

stop-writes-on-bgsave-error yes // 后台dump备份进程出错的时候,主进程停止不停写入?

rdbcompression yes // 导出的rdb文件是否需要压缩

rdbchecksum yes //导出的rdb恢复时数据要不要检验rdb的完整性

dbfilename dump.rdb //导出来的rdb文件名

dir ./ //rdb的放置路径

上面的就是rdb的常用配置,那它的备份原理是啥?

非常的简单,只要满足上面的save的3个条件中的任何一条,都会直接从内存中dump出一份镜像到磁盘上,速度非常的快

那我们考虑,如果我们在某一个时刻set存入一条数据,那这时突然redis宕机,那这个时候我们set的数据就会丢失,这是它的一个弊端,就是在发生一些异常的情况的时候,我们可能会丢失1-n分钟内的数据

那我们接下来看一下aof日志的一些配置和原理,它解决了上面rdb不能解决的一些问题:

同样,还是来看一下相关的配置内容:

appendonly no # 是否打开 aof日志功能

appendfsync always # 每1个命令,都立即同步到aof. 安全,速度慢

appendfsync everysec # 折衷方案,每秒写1次

no-appendfsync-on-rewrite yes: # 正在导出rdb快照的过程中,要不要停止同步aof

auto-aof-rewrite-percentage 100 #aof文件大小比起上次重写时的大小,增长率100%时,重写

auto-aof-rewrite-min-size 64mb #aof文件,至少超过64M时,重写

那我们开启了aof的日志的功能的时候,这时候我们每一次进行操作,aof就会将所有的操作记录到aof的日志中,我们可以通过appendfsync和我们具体的业务场景来具体指定多长时间写入文件,当然了推荐是everysec,那这样的话,由于我们记录的是每隔一秒的操作,那如果redis突然宕机的话,我们可以通过aof来恢复数据,这样的话就解决了上述rdb出现的数据丢失的问题,当然了这也会丢失大概1秒的数据吧,损失就会降低很多

我们来看一下相关的问题:

1 注: 在dump rdb过程中,aof如果停止同步,会不会丢失?

 答: 不会,所有的操作缓存在内存的队列里, dump完成后,统一操作.

2 注: aof重写是指什么?

答: aof重写是指把内存中的数据,逆化成命令,写入到.aof日志里,以解决 aof日志过大的问题.

3 问: 如果rdb文件,和aof文件都存在,优先用谁来恢复数据?

答: aof,不会使用rdb来进行恢复数据

4 问: 2种是否可以同时用?

答: 可以,而且推荐这么做

5 问: 恢复时rdb和aof哪个恢复的快

答: rdb快,因为其是数据的内存映射,直接载入到内存,而aof是命令,需要逐条执行

分布式锁的实现方式

参考: 分布式锁的实现方式

目前几乎很多大型网站及应用都是分布式部署的,分布式场景中的数据一致性问题一直是一个比较重要的话题。
分布式的CAP理论告诉我们“任何一个分布式系统都无法满足一致性(Consistency)、可用性(Availability)和分区容错性(Partion tolerance),最多只能同时满足两项”。所以,很多系统在设计之初就要对这三者做出取舍。
在互联网领域的绝大多数场景中,都需要牺牲一致性来换取系统的高可用性,系统往往只需要保证“最终一致性”,只要这个最终时间是在用户可以接受的范围内即可。

针对分布式锁的实现,目前比较常用的有以下几种方案:
(1)基于数据库实现分布式锁、(2)基于缓存(redis, memcached, tair)实现分布式锁、(3)基于zookeeper实现分布式锁

分析这几种实现方案之前我们先来想一下,我们需要的分布式锁应该是怎么样的?(这里以并发锁为例,资源锁同理)可以保证在分布式部署的应用集群中,同一个方法在同一时间只能被一台机器上的一个线程执行。

这把锁是一把可重入锁(避免死锁)
这把锁最好是一把阻塞锁(根据业务需求考虑要不要这条)
有高可用的获取锁和释放锁功能
获取锁和释放锁的性能要好

使用zookeeper实现Java跨JVM的分布式锁

参考:
Zookeeper的功能以及工作原理

https://blog.csdn.net/nimasike/article/details/51567653#reply

1. 基于Zookeeper分布式锁的流程

首先创建一个锁的根节点
想要获取锁的客户端在根节点下面创建子节点
获取根节点下面的所有子节点
对子节点按节点自增序号从小到大进行排序
判断本节点是不是第一个节点,若是,则获得锁;若不是,则监听比该节点序号小的那个节点的删除事件
若监听事件生效,则回到第二步重新进行判断,直到获取到锁

在使用Curator时,同zookeeper版本有一个适配问题,参考 http://curator.apache.org/zk-compatibility.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值