赞
踩
目录
4、redis做为缓存,mysql的数据如何与redis进行同步呢?
数据库有1000万数据 ,Redis只能缓存20w数据, 如何保证Redis中数据都是热点数据 ?
Redis 中比较常见的数据类型有:String(字符串)、List(列表)、Set(集合)、Hash(散列)、Zset(有序集合)。
还有特殊的数据类型:
BitMap :底层是一个由0、1组成的二进制串,常用命令:setbit key offset value;getbit key offset; 通常用于用户签到等场景:key为[当前年份:用户id],offset为[当前天数]。
HyperLogLog :能够使用极少的内存来统计巨量的数据,如统计百万级访问量网页的用户点击次数。在 Redis
中实现的 HyperLogLog
,只需要12K
内存就能统计2^64
个数据。 但是计数存在一定的误差,标准误差为 0.81% 。
Geospatial:主要用于存储地理位置信息,通过 GEO 我们可以轻松实现两个位置距离的计算、获取指定位置附近的元素等功能。
优点:
缺点:
缓存穿透是指客户端请求的数据在缓存中和数据库中都不存在,这样缓存就形同虚设(只有数据库查到了,才会让redis缓存,但现在的问题是查不到),会频繁的去访问数据库。
缓存击穿也叫热点Key问题,一个热点的Key,有大并发集中对其进行访问,突然间这个Key失效了,导致大并发全部打在数据库上,导致数据库压力剧增。
缓存雪崩是指在同一时间段,大量缓存的key同时失效,或者Redis服务宕机,导致大量请求到达数据库。
业务中有优惠券秒杀功能,要求实时性比较高,因此采用读写锁保证redis和mysql的强一致性。 主要采用redisson实现的读写锁,读的时候添加共享锁(读锁),保证读读不互斥,读写互斥;更新数据的时候添加排他锁(写锁),读读、读写都互斥。 这样可以防止写数据的时候其他线程读数据,避免了脏数据。
缓存的更新策略:当用户修改数据时,应该先删缓存还是先修改数据库?
- 先删缓存:修改数据库的途中,有别的线程来访问该数据就会把脏数据读入缓存。
- 先更新数据库:删完缓存还没提交事务的这段时间空隙,有别的线程来访问数据也会访问到脏数据并读入内存,但是发生的机率较小。
排他锁底层使用的是setnx,保证了同时只能有一个线程操作锁住的方法。
延时双删也是分布式系统中保持redis和mysql一致性的常用策略,但不具有强一致性。
Redis是内存数据库,宕机后数据会消失,需要提供持久化策略。在Redis中提供了两种数据持久化的方式:RDB 和 AOF。
Redis的过期删除策略:惰性删除 + 定期删除两种策略进行配合使用。
使用allkeys-lru(最近最少使用)淘汰策略,留下来的都是经常访问的热点数据。
看数据淘汰策略是什么,如果是默认的配置( noeviction ),会直接报错。
项目中的优惠券秒杀抢单功能存在超卖问题,可以使用Synchronized锁解决。但如果是在集群模式下, 多台服务器会对应多个jvm, synchronized锁可以锁住单台服务器的多线程,多台服务器就锁不住了,此时需要有一个多服务器共享的锁监视器,即分布式锁。
Redis实现分布式锁主要利用Redis的setnx命令(SET if not exists) ,该命令需要设置锁的过期时间,以防止服务宕机从而导致锁永远无法释放的问题。这个过期时间设置长了会影响性能,设置短了又可能会提前释放锁导致线程安全问题,这就需要合理的控制锁的有效时长。
于是我们使用采用redisson实现的分布式锁,底层是setnx和lua脚本(保证原子性)。在redisson的分布式锁中,提供了一个WatchDog(看门狗)机制:一个线程获取锁成功以后,会定期给锁续期(默认每10s续期一次)。
可重入,这样做是为了避免死锁的产生。多个锁重入需要判断是否是同一线程,在redis中进行存储的时候使用的hash结构,来存储线程信息和重入的次数:大key可以按照自己的业务进行定制,其中小key是当前线程的唯一标识,value是当前线程重入的次数。
不能解决,但可以使用redisson提供的红锁来解决,但是使用红锁性能太低了,如果业务中非要保证数据的强一致性,建议采用zookeeper实现的分布式锁。
单节点Redis的并发能力是有上限的,要进一步提高Redis的并发能力,可以搭建主从集群,实现读写分离。一般都是一主多从,主节点负责写数据,从节点负责读数据,主节点写入数据之后,需要把数据同步到从节点中。
从节点请求主节点同步数据,从节点会携带自己的replication id和offset偏移量。
主节点判断是否是第一次请求,主要判断依据就是,主节点与从节点是否是同一个replication id,如果不是,就说明是第一次同步,那主节点就会把自己replication id和offset发送给从节点,让从节点与主节点的信息保持一致。
在同时主节点会执行bgsave生成rdb文件,发送给从节点去执行,从节点先把自己的数据清空,然后执行主节点发送过来的rdb文件,这样就保持了一致。
增量同步:
从节点请求主节点同步数据,主节点还是判断是不是第一次请求,不是第一次就获取从节点的offset值,然后主节点从命令日志中获取offset值之后的数据,发送给从节点进行数据同步。
Redis提供了哨兵(Sentinel)机制来实现主从集群的自动故障恢复。哨兵的结构和作用如下:
哨兵模式的脑裂问题:
脑裂是由于网络等原因,使得哨兵无法心跳感知到主节点,于是通过选举的方式产生了一个新的主节点,于是就有了两个主节点,这样会导致客户端在老主节点那更新数据,新的主节点无法同步更新数据。
解决方案:
首先可以搭建主从集群(解决高并发),再加上使用redis中的哨兵模式(解决高可用),哨兵模式可以实现主从集群的自动故障恢复,里面就包含了对主从服务的监控、自动故障恢复、通知;
如果master故障,Sentinel会将一个slave提升为master。 当故障实例恢复后也以新的master为主;同时Sentinel也充当Redis客户端的服务发现来源,当集群发生故障转移时,会将最新信息推送给Redis的客户端,所以一般项目都会采用哨兵的模式来保证redis的高并发高可用。
主从和哨兵可以解决高可用、高并发读的问题。但是依然有两个问题没有解决: 海量数据存储问题 和 高并发写的问题。
Redis是纯内存操作,执行速度非常快,它的性能瓶颈是网络延迟和内存,而不是执行速度, I/O多路复用模型主要就是实现了高效的网络请求。
redis使用I/O多路复用结合事件的处理器来应对多个Socket请求,
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。