• [技术干货] SpringBoot整合Redis-转载
     一、Redis复制是什么? Redis复制就是主从复制,当主服务器数据发生变化时,自动将新的数据同步到从数据库。 读数据库可以进行读写操作,从数据库一般指用于读操作。 Redis复制可以保证主数据库崩溃时可以进行数据恢复。 二、Redis复制能干嘛? 读写分离 容灾恢复 数据备份 水平扩容支撑高并发 三、Redis复制的缺点 1、复制延迟 由于所有的写操作都发生在master数据库,然后同步到slave数据库中,所以会有一定的数据延迟,当系统负担过重时,延迟越大,slave机器的增加也会增加数据延迟的时间。 2、master宕机 如果master宕机了,默认情况下不会将salve数据库自动升级为master数据库。 四、乐观复制策略 Redis采用乐观复制策略,容忍一段时间内主从数据库不一致,但保证最终一致性。这个策略保证了性能,在复制的时候,主数据库不会阻塞,可以继续提供服务。 五、Redis复制常用命令 1、info replication 查看节点的主从关系和配置信息。 2、replicaof 主库Ip 主库port 在从数据库的redis.conf中配置。 3、slaveof 主库IP 主库port 在运行期间修改slave节点的信息,如果该数据库已经是其它主数据库的从数据库了,那么它会停止与其的主从关系,转而成为新配置的主库的从数据库。 4、slaveof no one 使当前数据库停止与其它数据库的同步,升级为主数据库。 六、Redis复制工作流程 1、slave启动成功后,会连接master数据库,发送一个sync命令,同步数据;如果是第一次连接,则会进行一次全量复制,slave自身的数据会被master数据覆盖清除; 2、master数据库收到sync命令后,通过RDB开始保存快照,同时将所有接收到的用于修改数据库的命令缓存起来,master数据库执行完RDB持久化后,master将RBD文件和所有缓存的命令发送到所有的slave数据库,完成一次数据同步; 3、slave收到RDB文件和命令缓存后,将其加载到内存中,从而完成复制初始化; 4、repl-ping-replica-period 10,表示master发出ping包的周期默认是10秒; 5、完成首次数据全量同步后,master继续将新的收集到的修改命令定期传给slave数据库,完成数据同步; 6、如果从机重启了,master的backlog中会记录offset,master会将offset后面的数据复制给slave。 7187:C 14 Mar 22:14:24.106 # nzbc Redis is starting nzbc 7187:C 14 Mar 22:14:24.107 # Redis version=6.0.8, bits=64, commit=00000000, modified=0, pid=7187, just started 7187:C 14 Mar 22:14:24.108 # Configuration loaded 7188:S 14 Mar 22:14:24.110 * Increased maximum number of open files to 10032 (it was originally set to 256).                 _._            _.-``__ ''-._       _.-``    `.  `_.  ''-._           Redis 6.0.8 (00000000/0) 64 bit   .-`` .-```.  ```\/    _.,_ ''-._  (    '      ,       .-`  | `,    )     Running in standalone mode  |`-._`-...-` __...-.``-._|'` _.-'|     Port: 6380  |    `-._   `._    /     _.-'    |     PID: 7188   `-._    `-._  `-./  _.-'    _.-'  |`-._`-._    `-.__.-'    _.-'_.-'|  |    `-._`-._        _.-'_.-'    |           http://redis.io   `-._    `-._`-.__.-'_.-'    _.-'  |`-._`-._    `-.__.-'    _.-'_.-'|  |    `-._`-._        _.-'_.-'    |   `-._    `-._`-.__.-'_.-'    _.-'       `-._    `-.__.-'    _.-'           `-._        _.-'               `-.__.-'  7188:S 14 Mar 22:14:24.120 # Server initialized 7188:S 14 Mar 22:14:24.114 * DB loaded from disk: 0.000 seconds 7188:S 14 Mar 22:14:24.122 * Before turning into a slave, using my master parameters to synthesize a cached master: I may be able to synchronize with the new master with just a partial transfer. 7188:S 14 Mar 22:14:24.122 * Ready to accept connections 7188:S 14 Mar 22:14:24.123 * Connecting to MASTER 127.0.0.1:6379 7188:S 14 Mar 22:14:24.123 * MASTER <-> SLAVE sync started 7188:S 14 Mar 22:14:24.123 * Non blocking connect for SYNC fired the event. 7188:S 14 Mar 22:14:24.124 * Master replied to PING, replication can continue... 7188:S 14 Mar 22:14:24.124 * Trying a partial resynchronization (request 9b3cs5w9g6x3004fa9a0999361035b71ecf70ab4:30783). 7188:S 14 Mar 22:14:24.130 * Full resync from master: cb4as85df693ad62f09ce4f486e0d43ec8f36334:0 7188:S 14 Mar 22:14:24.130 * Discarding previously cached master state. 7188:S 14 Mar 22:14:24.163 * MASTER <-> SLAVE sync: receiving 5484 bytes from master 7188:S 14 Mar 22:14:24.165 * MASTER <-> SLAVE sync: Flushing old data 7188:S 14 Mar 22:14:24.165 * MASTER <-> SLAVE sync: Loading DB in memory 7188:S 14 Mar 22:14:24.167 * MASTER <-> SLAVE sync: Finished with success 七、Redis哨兵是什么? Redis提供了哨兵sentinel机制来监控Redis的性能,如果主数据库宕机了,根据投票数自动将某一个从数据库提升为主数据库,继续对外提供服务。  1、Redis哨兵的作用  主从监控,监控主从数据库是否运行正常; 消息通知,哨兵可以将故障信息发送给客户端; 故障转移,如果master异常。哨兵会进行主备切换,将其中一个slave转为master; 配置中心,客户端通过连接哨兵获取Redis服务集群的主节点信息; 2、使用哨兵的注意事项:  八、实战演练 1、搭建3个哨兵服务器 监控Redis主从服务器,不存放数据。  2、sentinel.conf参数选项说明 bind 0.0.0.0 daemonize yes protected-mode no port 6391 logfile "/myredis/sentinel1.log" pidfile /var/run/redis-sentinel6391.pid dir /myredis sentinel monitor mymaster 127.0.0.1 6379 2 sentinel auth-pass mymaster 123456 设置要监控的master服务器,quorum表示至少有几个哨兵认为客观下线,同意故障转移的法定票数,因此哨兵服务器一般为奇数个。 sentinel monitor <master-name> 127.0.0.1 6379 <quorum>。 master服器设置了密码: sentinel auth-pass <master-name> <password>。 通过命令,完成哨兵sentinel的启动,两种方式,任选其一: redis-sentinel /path/to/sentinel.conf redis-server /path/to/sentinel.conf --sentinel 九、哨兵运行流程和选举原理 当一个主从配置中的master失效后,sentinel会选举出一个新的master用于接替原master的工作,其它slave服务器自动指向新master,实现数据同步。 1、主观下线 指定多少毫秒之后,主节点没有应答哨兵,此时哨兵会主观上认为主节点已经下线。 sentinel down-after-millisecnds <master-name> <millisecnds> 2、客观下线 多个哨兵sentinel进行投票,根据投票结果才能确认一个master客观上已经宕机。 3、选举master三步走: (1)先选出一个master服务器   当master数据库宕机后,各个哨兵sentinel节点会进行协商,先通过Raft算法选举出一个领导者哨兵节点,再由领导者进行master的选举。 根据Redis.conf中,优先级slave-priority或者replica-priority最高的从节点(数字越小优先级越高)。 复制偏移位置offset最大的从节点; 最小Run ID的从节点 (2)其它slave服务器连接到master服务器 执行slaveof no one命令会选举出新的master,并通过slaveof命令将其它从节点成为新master服务器的从节点。 (3)如果旧master服务器恢复正常了,也要成为新master服务器的slave从服务器。 ———————————————— 版权声明:本文为CSDN博主「哪 吒」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/guorui_java/article/details/129544024 
  • [技术干货] centos下安装redis6.0.2方法及踩坑记录。
    最近又要搭建一个新的测试环境来进行测试,虽然说之前已经搭建过几次,包括redis也都部署过几次了,但是每次都是需要花大量的时间进行搜索。并且每次都会踩坑,为了之后能够节省时间,所以专门针对这次的安装,做一个记录,谈不上教程,就是把过程中遇到的问题,以及搜索出来整理的方法和大家分享。安装 Redis 6.0.2 的步骤如下:准备工作确保已经安装了 C/C++ 编译器和 make 工具,可以使用以下命令检查:gcc --version make --version 如果查询到版本号,则表示已经安装成功。下载 Redis 源码从Redis官方网站下载 Redis 6.0.2 版本的源码包并解压,或者使用以下命令进行下载并解压:wget 下载链接tar xzf redis-6.0.2.tar.gz cd redis-6.0.2 编译安装 Redis执行以下命令编译安装 Redis:make MALLOC=libc make install PREFIX=/usr/local/bin/redis 其中 MALLOC 参数指定内存分配方式,默认为 jemalloc,这里改为 libc。PREFIX 参数指定安装目录,如果不指定则默认安装在 /usr/local/bin 下。配置 Redis将 Redis 的配置文件 redis.conf 复制到安装目录下,并根据实际需求修改配置参数。例如,可以修改绑定地址、端口号、日志文件路径等。同时,也可以通过配置密码或 ACL 来保护 Redis 实例的安全。具体配置参数详见 Redis 官方文档。cp redis.conf /usr/local/bin/redis/ vi /usr/local/bin/redis/redis.conf 启动 Redis执行以下命令启动 Redis:cd /usr/local/bin/redis/ redis-server redis.conf 也可以将 Redis 作为系统服务运行,以便于管理和自动化启动。具体方法可以参考 Redis 官方文档中的相关章节。以上是建立在所有东西都不报错的情况下,但是大部分情况下都会有报错的情况产生的。最常见的可能就是编译出错了。如果编译过程中报错,可以先检查是否缺少必需的依赖包,例如 tcl、jemalloc 等。可以使用以下命令来安装:yum install -y tcl yum install -y jemalloc-devel 此外,还需要确保配置正确的编译参数,例如 MALLOC 参数,可以指定为 libc 或 jemalloc。还有就是版本兼容性问题了啊,最开始没注意用的是centos6.x的版本。。结果就是出问题 。后来才发现CentOS 7.x 可以直接安装 Redis 6.0.2,但 CentOS 6.x 只支持 Redis 5.x 版本。还有就是一个真的就特别无语的问题,手抖把redis配置里面的内存多敲了,结果内存占用就特别大。在 Redis 的 redis.conf 配置文件中,有一个 maxmemory 参数,表示 Redis 实例可以使用的内存最大值。如果指定的值超过了物理内存大小,则可能会导致 Redis 宕机或无法启动。并且上面还有一个关联性问题,刚开始redis内存设置过大,还是没有感知,结果启动Java项目的时候一直OutOfMemoryError 错误。这个时候才感觉到不对劲,一个个去排查才发现问题,所以如果在 Linux 系统上同时运行 Redis 和 Java 程序,需要注意操作系统的内存限制。避免java程序无法启动。忘了说个问题编译的时候如果是redis6.0版本以上可能会遇到的问题。注:如果在make过程中出现如下错误(如果redis版本是6.0以上会出现问题)server.c: 在函数‘writeCommandsDeniedByDiskError’中: server.c:3790:1: 警告:在有返回值的函数中,控制流程到达函数尾 [-Wreturn-type] } ^ server.c: 在函数‘iAmMaster’中: server.c:4964:1: 警告:在有返回值的函数中,控制流程到达函数尾 [-Wreturn-type] } ^ make[1]: *** [server.o] 错误 1 make[1]: 离开目录“/opt/app/redis-6.0.5/src” make: *** [all] 错误 2是gcc版本老问题,新版本的redis6.0以上,不兼容。查看gcc版本: (我的为gcc 版本 4.8.5 20150623 (Red Hat 4.8.5-39) (GCC))gcc -v解决办法:升级gcc版本gcc -v # 查看gcc版本 yum -y install centos-release-scl # 升级到9.1版本 yum -y install devtoolset-9-gcc devtoolset-9-gcc-c++ devtoolset-9-binutils scl enable devtoolset-9 bash 以上为临时启用,如果要长期使用gcc 9.1的话: echo "source /opt/rh/devtoolset-9/enable" >>/etc/profile升级之后的版本为:gcc version 9.3.1 20200408 (Red Hat 9.3.1-2) (GCC)再次进行make,然后make install安装成功会出现:Hint: It’s a good idea to run ‘make test’。以上的内容就作为自己的一个安装踩坑记录,也希望可以给大家提供帮助。
  • [其他] 关于Redis缓存
    一、缓存预热Redis缓存预热是指在服务器启动或应用程序启动之前,将一些数据先存储到Redis中,以提高Redis的性能和数据一致性。这可以减少服务器在启动或应用程序启动时的数据传输量和延迟,从而提高应用程序的性能和可靠性。1、缓存预热常见步骤(1)数据准备在应用程序启动或服务器启动之前,准备一些数据,这些数据可以是静态数据、缓存数据或其他需要预热的数据。(2)数据存储将数据存储到Redis中,可以使用Redis的列表(List)数据类型或集合(Set)数据类型。(3)数据预热在服务器启动或应用程序启动之前,将数据存储到Redis中。可以使用Redis的客户端工具或命令行工具来执行此操作。(4)数据清洗在服务器启动或应用程序启动之后,可能会对存储在Redis中的数据进行清洗和处理。例如,可以删除过期的数据、修改错误的数据等。需要注意的是,Redis缓存预热可能会增加服务器的开销,因此应该在必要时进行。同时,为了减少预热的次数,可以考虑使用Redis的其他数据类型,如哈希表(Hash)或有序集合(Sorted Set)。此外,为了提高数据一致性和性能,可以使用Redis的持久化功能,将数据存储到Redis中,并在服务器重启后自动恢复数据。2、代码实现@Component @Slf4j public class BloomFilterInit {     @Resource     private RedisTemplate redisTemplate;     //初始化白名单数据     @PostConstruct     public void init() {         //1 白名单客户加载到布隆过滤器         String key = "customer:1";         //2 计算hashValue,由于存在计算出来负数的可能,我们取绝对值         int hashValue = Math.abs(key.hashCode());         //3 通过hashValue和2的32次方后取余,获得对应的下标坑位         long index = (long)(hashValue % Math.pow(2,32));         log.info(key+" 对应的坑位index:{}",index);         //4 设置redis里面的bitmap对应类型白名单:whitelistCustomer的坑位,将该值设置为1         redisTemplate.opsForValue().setBit("whitelistCustomer",index,true);     } }二、缓存雪崩Redis缓存雪崩是指在缓存系统中,由于某些原因,缓存的数据突然大量地被删除或修改,导致缓存系统的性能下降,甚至无法正常工作。1、什么情况会发生缓存雪崩?(1)误删除由于误操作或故障,缓存系统可能会误删除一些正常的数据。这种情况通常会在数据库中发生。(2)误修改由于误操作或故障,缓存系统可能会误修改一些正常的数据。这种情况通常会在数据库中发生。(3)负载波动缓存系统通常会承受一定的负载波动,例如,在高峰期间,数据量可能会大幅增加,从而导致缓存系统的性能下降。(4)数据变化频繁如果缓存系统中的数据变化频繁,例如,每秒钟都会有大量的数据插入或删除,那么缓存系统可能会因为响应过慢而导致雪崩。2、Redis缓存集群实现高可用(1)主从 + 哨兵(2)Redis集群(3)开启Redis持久化机制aof/rdb,尽快恢复缓存集群。3、如何避免Redis缓存雪崩?(1)数据备份定期备份数据,以防止误删除或误修改。(2)数据同步定期同步数据,以防止数据不一致。(3)负载均衡使用负载均衡器将请求分配到多个Redis实例上,以减轻单个实例的负载。(4)数据优化优化数据库结构,减少数据变化频繁的情况。(5)监控与告警监控Redis实例的性能指标,及时发现缓存系统的异常,并发出告警。三、缓存穿透Redis缓存穿透是指在Redis缓存系统中,由于某些原因,缓存的数据无法被正常访问或处理,导致缓存失去了它的作用。1、什么情况会发生缓存穿透?(1)数据量过大当缓存中存储的数据量过大时,缓存的数据量可能会超过Redis的数据存储限制,从而导致缓存失去了它的作用。(2)数据更新频繁当缓存中存储的数据更新频繁时,缓存的数据可能会出现异步的变化,导致缓存无法被正常访问。(3)数据过期当缓存中存储的数据过期时,缓存的数据可能会失去它的作用,因为Redis会在一定时间后自动将过期的数据删除。(4)数据权限限制当缓存中存储的数据受到权限限制时,只有拥有足够权限的用户才能访问和处理这些数据,从而导致缓存失去了它的作用。(5)Redis性能瓶颈当Redis服务器的性能达到极限时,Redis缓存可能会因为响应过慢而导致穿透。2、如何避免Redis缓存穿透?(1)设置合理的缓存大小根据实际需求设置合理的缓存大小,以避免缓存穿透。(2)优化数据结构根据实际需求优化数据结构,以减少数据的大小和更新频率。(3)设置合理的过期时间设置合理的过期时间,以避免缓存失去它的作用。(4)增加Redis的并发处理能力通过增加Redis的并发处理能力,以提高缓存的处理能力和响应速度。(5)优化Redis服务器的硬件和软件配置通过优化Redis服务器的硬件和软件配置,以提高Redis的性能和处理能力。、通过空对象缓存解决缓存穿透如果发生了缓存穿透,可以针对要查询的数据,在Redis中插入一条数据,添加一个约定好的默认值,比如defaultNull。比如你想通过某个id查询某某订单,Redis中没有,MySQL中也没有,此时,就可以在Redis中插入一条,存为defaultNull,下次再查询就有了,因为是提前约定好的,前端也明白是啥意思,一切OK,岁月静好。这种方式只能解决key相同的情况,如果key都不同,则完蛋。五、Google布隆过滤器Guava解决缓存穿透1、引入pom<!--guava Google 开源的 Guava 中自带的布隆过滤器--> <dependency>     <groupId>com.google.guava</groupId>     <artifactId>guava</artifactId>     <version>23.0</version> </dependency>2、创建布隆过滤器BloomFilter<Integer> bloomFilter = BloomFilter.create(Funnels.integerFunnel(), 100);(3)布隆过滤器中添加元素bloomFilter.mightContain(1)(4)判断布隆过滤器中是否存在bloomFilter.mightContain(1)3、fpp误判率@Service @Slf4j public class GuavaBloomFilterService {     public static final int SIZE = 1000000;     //误判率     public static double fpp = 0.01;     //创建guava布隆过滤器     private static BloomFilter<Integer> bloomFilter = BloomFilter.create(Funnels.integerFunnel(), SIZE, fpp);          public void guavaBloomFilter() {         for (int i = 1; i <= SIZE; i++) {             bloomFilter.put(i);         }         ArrayList<Integer> list = new ArrayList<>(10000);         for (int i = SIZE + 1; i <= SIZE + (10000); i++) {             if (bloomFilter.mightContain(i)) {                 log.info("被误判了:{}", i);                 list.add(i);             }         }         log.info("误判总数量:{}", list.size());     } }六、Redis缓存击穿Redis缓存击穿是指在Redis缓存系统中,由于某些原因,缓存的数据无法被正常访问或处理,导致缓存失去了它的作用。1、什么情况会发生缓存击穿?根本原因:热点Key失效。(1)数据量过大当缓存中存储的数据量过大时,缓存的数据量可能会超过Redis的数据存储限制,从而导致缓存失去了它的作用。(2)数据更新频繁当缓存中存储的数据更新频繁时,缓存的数据可能会出现异步的变化,导致缓存无法被正常访问。(3)数据过期当缓存中存储的数据过期时,缓存的数据可能会失去它的作用,因为Redis会在一定时间后自动将过期的数据删除。(4)数据权限限制当缓存中存储的数据受到权限限制时,只有拥有足够权限的用户才能访问和处理这些数据,从而导致缓存失去了它的作用。(5)Redis性能瓶颈当Redis服务器的性能达到极限时,Redis缓存可能会因为响应过慢而导致击穿。2、如何避免Redis缓存击穿?(1)设置合理的缓存大小根据实际需求设置合理的缓存大小,以避免缓存穿透。(2)优化数据结构根据实际需求优化数据结构,以减少数据的大小和更新频率。(3)设置合理的过期时间设置合理的过期时间,以避免缓存失去它的作用。(4)增加Redis的并发处理能力通过增加Redis的并发处理能力,以提高缓存的处理能力和响应速度。(5)优化Redis服务器的硬件和软件配置通过优化Redis服务器的硬件和软件配置,以提高Redis的性能和处理能力。七、Redis缓存击穿解决方案1、互斥更新通过双检加锁机制。2、差异失效时间更新从缓存B,再更新主缓存A,而且让从缓存B的缓存失效时间长于A,保证A失效时,B还在。引用自:https://mp.weixin.qq.com/s/np6qcAzEGIDDJTfmAsqFUw
  • [其他] Redis和MySQL如何保持数据一致性?
    在高并发的场景下,大量的请求直接访问MySQL很容易造成性能问题。所以,我们都会用Redis来做数据的缓存,削减对数据库的请求。但是,MySQL和Redis是两种不同的数据库,如何保证不同数据库之间数据的一致性就非常关键了。数据不一致的原因导致数据不一致的原因1、在高并发的业务场景下,数据库大多数情况都是用户并发访问最薄弱的环节。2、所以,就需要使用redis做一个缓冲操作,让请求先访问到redis,而不是直接访问MySQL等数据库。3、读取缓存步骤一般没有什么问题,但是一旦涉及到数据更新:数据库和缓存更新,就容易出现缓存(Redis)和数据库(MySQL)间的数据一致性问题。4、这个业务场景,主要是解决读数据从Redis缓存,一般都是按照下图的流程来进行业务操作。缓存先后删除问题不管是先写MySQL数据库,再删除Redis缓存;还是先删除缓存,再写库,都有可能出现数据不一致的情况。先删除缓存1、如果先删除Redis缓存数据,然而还没有来得及写入MySQL,另一个线程就来读取2、这个时候发现缓存为空,则去Mysql数据库中读取旧数据写入缓存,此时缓存中为脏数据。3、然后数据库更新后发现Redis和Mysql出现了数据不一致的问题后删除缓存1、如果先写了库,然后再删除缓存,不幸的写库的线程挂了,导致了缓存没有删除2、这个时候就会直接读取旧缓存,最终也导致了数据不一致情况3、因为写和读是并发的,没法保证顺序,就会出现缓存和数据库的数据不一致的问题解决方案延时双删策略基本思路在写库前后都进行redis.del(key)操作,并且设定合理的超时时间。伪代码如下:public void write( String key, Object data ){ redis.delKey( key ); db.updateData( data ); Thread.sleep( 500 ); redis.delKey( key );}br具体步骤1、先删除缓存2、再写数据库3、休眠500毫秒4、再次删除缓存问题:这个500毫秒怎么确定的,具体该休眠多久时间呢?1、需要评估自己的项目的读数据业务逻辑的耗时。2、这么做的目的,就是确保读请求结束,写请求可以删除读请求造成的缓存脏数据。3、当然这种策略还要考虑redis和数据库主从同步的耗时。4、最后的的写数据的休眠时间:则在读数据业务逻辑的耗时基础上,加几百ms即可。比如:休眠1秒。设置缓存过期时间是关键点1、从理论上来说,给缓存设置过期时间,是保证最终一致性的解决方案2、所有的写操作以数据库为准,只要到达缓存过期时间,缓存删除3、如果后面还有读请求的话,就会从数据库中读取新值然后回填缓存方案缺点结合双删策略+缓存超时设置,这样最差的情况就是:1、在缓存过期时间内发生数据存在不一致2、同时又增加了写请求的耗时。异步更新缓存(基于Mysql binlog的同步机制)整体思路1、涉及到更新的数据操作,利用Mysql binlog 进行增量订阅消费2、将消息发送到消息队列3、通过消息队列消费将增量数据更新到Redis上4、.操作情况读取Redis缓存:热数据都在Redis上写Mysql:增删改都是在Mysql进行操作更新Redis数据:Mysql的数据操作都记录到binlog,通过消息队列及时更新到Redis上Redis更新过程数据操作主要分为两种:1、一种是全量(将所有数据一次性写入Redis)2、一种是增量(实时更新)这里说的是增量,指的是mysql的update、insert、delate变更数据。读取binlog后分析 ,利用消息队列,推送更新各台的redis缓存数据。1、这样一旦MySQL中产生了新的写入、更新、删除等操作,就可以把binlog相关的消息推送至Redis2、Redis再根据binlog中的记录,对Redis进行更新3、其实这种机制,很类似MySQL的主从备份机制,因为MySQL的主备也是通过binlog来实现的数据一致性这里的消息推送工具你也可以采用别的第三方:kafka、rabbitMQ等来实现推送更新Redis!总结在高并发应用场景下,如果是对数据一致性要求高的情况下,要定位好导致数据和缓存不一致的原因。解决高并发场景下数据一致性的方案有两种,分别是延时双删策略和异步更新缓存两种方案。另外,设置缓存的过期时间是保证数据保持一致性的关键操作,需要结合业务进行合理的设置。引用自:https://mp.weixin.qq.com/s/Mgd8y7t--fHin4x9AZR2jQ
  • [其他] Redis的使用场景
    1、缓存String类型例如:热点数据缓存(例如报表、明星出轨),对象缓存、全页缓存、可以提升热点数据的访问数据。2、数据共享分布式String 类型,因为 Redis 是分布式的独立服务,可以在多个应用之间共享例如:分布式Session<dependency>   <groupId>org.springframework.session</groupId>   <artifactId>spring-session-data-redis</artifactId>  </dependency>3、分布式锁String 类型setnx方法,只有不存在时才能添加成功,返回truepublic static boolean getLock(String key) {     Long flag = jedis.setnx(key, "1");     if (flag == 1) {         jedis.expire(key, 10);     }     return flag == 1; } public static void releaseLock(String key) {     jedis.del(key); }4、全局IDint类型,incrby,利用原子性incrby userid 1000分库分表的场景,一次性拿一段5、计数器int类型,incr方法例如:文章的阅读量、微博点赞数、允许一定的延迟,先写入Redis再定时同步到数据库6、限流int类型,incr方法以访问者的ip和其他信息作为key,访问一次增加一次计数,超过次数则返回false7、位统计String类型的bitcount(1.6.6的bitmap数据结构介绍)字符是以8位二进制存储的set k1 a setbit k1 6 1 setbit k1 7 0 get k1  /* 6 7 代表的a的二进制位的修改 a 对应的ASCII码是97,转换为二进制数据是01100001 b 对应的ASCII码是98,转换为二进制数据是01100010 因为bit非常节省空间(1 MB=8388608 bit),可以用来做大数据量的统计。 */例如:在线用户统计,留存用户统计setbit onlineusers 01  setbit onlineusers 11  setbit onlineusers 20支持按位与、按位或等等操作BITOPANDdestkeykey[key...] ,对一个或多个 key 求逻辑并,并将结果保存到 destkey 。        BITOPORdestkeykey[key...] ,对一个或多个 key 求逻辑或,并将结果保存到 destkey 。  BITOPXORdestkeykey[key...] ,对一个或多个 key 求逻辑异或,并将结果保存到 destkey 。  BITOPNOTdestkeykey ,对给定 key 求逻辑非,并将结果保存到 destkey 。计算出7天都在线的用户BITOP "AND" "7_days_both_online_users" "day_1_online_users" "day_2_online_users" ...  "day_7_online_users"8、购物车String 或hash。所有String可以做的hash都可以做key:用户id;field:商品id;value:商品数量。+1:hincr。-1:hdecr。删除:hdel。全选:hgetall。商品数:hlen。9、用户消息时间线timelinelist,双向链表,直接作为timeline就好了。插入有序10、消息队列List提供了两个阻塞的弹出操作:blpop/brpop,可以设置超时时间blpop:blpop key1 timeout 移除并获取列表的第一个元素,如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。brpop:brpop key1 timeout 移除并获取列表的最后一个元素,如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。上面的操作。其实就是java的阻塞队列。学习的东西越多。学习成本越低队列:先进先出:rpush blpop,左头右尾,右边进入队列,左边出队列栈:先进后出:rpush brpop11、抽奖自带一个随机获得值spop myset12、点赞、签到、打卡微博ID是t1001,用户ID是u3001用 like:t1001 来维护 t1001 这条微博的所有点赞用户点赞了这条微博:sadd like:t1001 u3001取消点赞:srem like:t1001 u3001是否点赞:sismember like:t1001 u3001点赞的所有用户:smembers like:t1001点赞数:scard like:t1001是不是比数据库简单多了。13、商品标签用 tags:i5001 来维护商品所有的标签。sadd tags:i5001 画面清晰细腻sadd tags:i5001 真彩清晰显示屏sadd tags:i5001 流程至极14、商品筛选// 获取差集 sdiff set1 set2 // 获取交集(intersection ) sinter set1 set2 // 获取并集 sunion set1 set2如:iPhone11 上市了sadd brand:apple iPhone11 sadd brand:ios iPhone11 sad screensize:6.0-6.24 iPhone11 sad screentype:lcd iPhone 11筛选商品,苹果的、ios的、屏幕在6.0-6.24之间的,屏幕材质是LCD屏幕sinter brand:apple brand:ios screensize:6.0-6.24 screentype:lcd15、用户关注、推荐模型follow 关注 fans 粉丝相互关注:sadd 1:follow 2sadd 2:fans 1sadd 1:fans 2sadd 2:follow 1我关注的人也关注了他(取交集):sinter 1:follow 2:fans可能认识的人:用户1可能认识的人(差集):sdiff 2:follow 1:follow用户2可能认识的人:sdiff 1:follow 2:follow16、排行榜id 为6001 的新闻点击数加1:zincrby hotNews:20190926 1 n6001获取今天点击最多的15条:zrevrange hotNews:20190926 0 15 withscores引用自:https://mp.weixin.qq.com/s/I3fKeerhggozvx9FOUchpA
  • [技术干货] 图解Redis,Redis主从复制与Redis哨兵机制-转载
     大家好,我是哪吒。  上一篇分享了2023年再不会Redis,就要被淘汰了,完成了Redis的初体验。  今天分享一下Redis的持久化、事务、管道相关的知识点,实现快速入门,丰富个人简历,提高面试level,给自己增加一点谈资,秒变面试小达人,BAT不是梦。  一、Redis复制是什么? Redis复制就是主从复制,当主服务器数据发生变化时,自动将新的数据同步到从数据库。  读数据库可以进行读写操作,从数据库一般指用于读操作。  Redis复制可以保证主数据库崩溃时可以进行数据恢复。  二、Redis复制能干嘛? 读写分离 容灾恢复 数据备份 水平扩容支撑高并发 三、Redis复制的缺点 1、复制延迟 由于所有的写操作都发生在master数据库,然后同步到slave数据库中,所以会有一定的数据延迟,当系统负担过重时,延迟越大,slave机器的增加也会增加数据延迟的时间。  2、master宕机 如果master宕机了,默认情况下不会将salve数据库自动升级为master数据库。  四、乐观复制策略 Redis采用乐观复制策略,容忍一段时间内主从数据库不一致,但保证最终一致性。这个策略保证了性能,在复制的时候,主数据库不会阻塞,可以继续提供服务。  五、Redis复制常用命令 1、info replication 查看节点的主从关系和配置信息。  2、replicaof 主库Ip 主库port 在从数据库的redis.conf中配置。  3、slaveof 主库IP 主库port 在运行期间修改slave节点的信息,如果该数据库已经是其它主数据库的从数据库了,那么它会停止与其的主从关系,转而成为新配置的主库的从数据库。  4、slaveof no one 使当前数据库停止与其它数据库的同步,升级为主数据库。  六、Redis复制工作流程 1、slave启动成功后,会连接master数据库,发送一个sync命令,同步数据;如果是第一次连接,则会进行一次全量复制,slave自身的数据会被master数据覆盖清除;  2、master数据库收到sync命令后,通过RDB开始保存快照,同时将所有接收到的用于修改数据库的命令缓存起来,master数据库执行完RDB持久化后,master将RBD文件和所有缓存的命令发送到所有的slave数据库,完成一次数据同步;  3、slave收到RDB文件和命令缓存后,将其加载到内存中,从而完成复制初始化;  4、repl-ping-replica-period 10,表示master发出ping包的周期默认是10秒;  5、完成首次数据全量同步后,master继续将新的收集到的修改命令定期传给slave数据库,完成数据同步;  6、如果从机重启了,master的backlog中会记录offset,master会将offset后面的数据复制给slave。  7187:C 14 Mar 22:14:24.106 # nzbc Redis is starting nzbc 7187:C 14 Mar 22:14:24.107 # Redis version=6.0.8, bits=64, commit=00000000, modified=0, pid=7187, just started 7187:C 14 Mar 22:14:24.108 # Configuration loaded 7188:S 14 Mar 22:14:24.110 * Increased maximum number of open files to 10032 (it was originally set to 256).                 _._            _.-``__ ''-._       _.-``    `.  `_.  ''-._           Redis 6.0.8 (00000000/0) 64 bit   .-`` .-```.  ```\/    _.,_ ''-._  (    '      ,       .-`  | `,    )     Running in standalone mode  |`-._`-...-` __...-.``-._|'` _.-'|     Port: 6380  |    `-._   `._    /     _.-'    |     PID: 7188   `-._    `-._  `-./  _.-'    _.-'  |`-._`-._    `-.__.-'    _.-'_.-'|  |    `-._`-._        _.-'_.-'    |           http://redis.io   `-._    `-._`-.__.-'_.-'    _.-'  |`-._`-._    `-.__.-'    _.-'_.-'|  |    `-._`-._        _.-'_.-'    |   `-._    `-._`-.__.-'_.-'    _.-'       `-._    `-.__.-'    _.-'           `-._        _.-'               `-.__.-'  7188:S 14 Mar 22:14:24.120 # Server initialized 7188:S 14 Mar 22:14:24.114 * DB loaded from disk: 0.000 seconds 7188:S 14 Mar 22:14:24.122 * Before turning into a slave, using my master parameters to synthesize a cached master: I may be able to synchronize with the new master with just a partial transfer. 7188:S 14 Mar 22:14:24.122 * Ready to accept connections 7188:S 14 Mar 22:14:24.123 * Connecting to MASTER 127.0.0.1:6379 7188:S 14 Mar 22:14:24.123 * MASTER <-> SLAVE sync started 7188:S 14 Mar 22:14:24.123 * Non blocking connect for SYNC fired the event. 7188:S 14 Mar 22:14:24.124 * Master replied to PING, replication can continue... 7188:S 14 Mar 22:14:24.124 * Trying a partial resynchronization (request 9b3cs5w9g6x3004fa9a0999361035b71ecf70ab4:30783). 7188:S 14 Mar 22:14:24.130 * Full resync from master: cb4as85df693ad62f09ce4f486e0d43ec8f36334:0 7188:S 14 Mar 22:14:24.130 * Discarding previously cached master state. 7188:S 14 Mar 22:14:24.163 * MASTER <-> SLAVE sync: receiving 5484 bytes from master 7188:S 14 Mar 22:14:24.165 * MASTER <-> SLAVE sync: Flushing old data 7188:S 14 Mar 22:14:24.165 * MASTER <-> SLAVE sync: Loading DB in memory 7188:S 14 Mar 22:14:24.167 * MASTER <-> SLAVE sync: Finished with success 七、Redis哨兵是什么? Redis提供了哨兵sentinel机制来监控Redis的性能,如果主数据库宕机了,根据投票数自动将某一个从数据库提升为主数据库,继续对外提供服务。  1、Redis哨兵的作用  主从监控,监控主从数据库是否运行正常; 消息通知,哨兵可以将故障信息发送给客户端; 故障转移,如果master异常。哨兵会进行主备切换,将其中一个slave转为master; 配置中心,客户端通过连接哨兵获取Redis服务集群的主节点信息; 2、使用哨兵的注意事项:  八、实战演练 1、搭建3个哨兵服务器 监控Redis主从服务器,不存放数据。  2、sentinel.conf参数选项说明 bind 0.0.0.0 daemonize yes protected-mode no port 6391 logfile "/myredis/sentinel1.log" pidfile /var/run/redis-sentinel6391.pid dir /myredis sentinel monitor mymaster 127.0.0.1 6379 2 sentinel auth-pass mymaster 123456   设置要监控的master服务器,quorum表示至少有几个哨兵认为客观下线,同意故障转移的法定票数,因此哨兵服务器一般为奇数个。  sentinel monitor <master-name> 127.0.0.1 6379 <quorum>。  master服务器设置了密码:  sentinel auth-pass <master-name> <password>。  通过命令,完成哨兵sentinel的启动,两种方式,任选其一:  redis-sentinel /path/to/sentinel.conf redis-server /path/to/sentinel.conf --sentinel 九、哨兵运行流程和选举原理 当一个主从配置中的master失效后,sentinel会选举出一个新的master用于接替原master的工作,其它slave服务器自动指向新master,实现数据同步。  1、主观下线 指定多少毫秒之后,主节点没有应答哨兵,此时哨兵会主观上认为主节点已经下线。  sentinel down-after-millisecnds <master-name> <millisecnds>  2、客观下线 多个哨兵sentinel进行投票,根据投票结果才能确认一个master客观上已经宕机。  3、选举master三步走: (1)先选出一个master服务器   当master数据库宕机后,各个哨兵sentinel节点会进行协商,先通过Raft算法选举出一个领导者哨兵节点,再由领导者进行master的选举。  根据Redis.conf中,优先级slave-priority或者replica-priority最高的从节点(数字越小优先级越高)。 复制偏移位置offset最大的从节点; 最小Run ID的从节点 (2)其它slave服务器连接到master服务器  执行slaveof no one命令会选举出新的master,并通过slaveof命令将其它从节点成为新master服务器的从节点。  (3)如果旧master服务器恢复正常了,也要成为新master服务器的slave从服务器。 ———————————————— 版权声明:本文为CSDN博主「哪 吒」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/guorui_java/article/details/129544024 
  • [技术干货] Redis与MySQL的双写一致性问题【转】
    Redis与MySQL双写一致性是指在使用缓存和数据库同时存储数据的场景下( 主要是存在高并发的情况),如何保证两者的数据一致性(内容相同或者尽可能接近)。 正常业务流程:读没什么问题,关键就在于写(更新)操作,这就会出现几个问题了,这里是先更新数据库,然后对缓存操作。但对于缓存操作,是更新缓存还是删除缓存呢?或者为什么不是先操作(删除、更新)缓存在更新数据库呢?总结一下就是到底先操作缓存再操作数据库,还是先操作数据库再操作缓存?带着这几个问题接着往下讲。首先讲一下操作缓存,包括两种:更新缓存和删除缓存,如何选择?更新缓存? 删除缓存?假设都先更新数据库(因为先操作缓存再操作数据库问题较大,后面会讲) 更新缓存先更新数据库,再更新缓存。如果两个请求同时对同一条数据进行修改,那么可能出现先后顺序颠倒,导致缓存中的数据是旧的。之后的读请求读到的都是旧数据,只有当缓存失效后,才能从数据库中得到正确的值。删除缓存先更新数据库,再删除缓存。会有这样一种情况:缓存刚好失效,请求B从数据库中查询数据,得到旧值。此时请求A更新数据库,将新值写入数据库,并删除缓存。而请求B又将旧值写入缓存中,导致脏数据从上面看出现脏数据的要求要比更新缓存的要求更多,必须满足以下几个条件:缓存失效读请求 + 写请求并发更新数据库 + 删除缓存的时间要比读数据库 + 写缓存时间短前面两个很好满足,我们再看看第三点,这个真的会出现吗?数据库在更新时一般是加锁的,读操作的速度远快于写操作的,所以第三点发生概率极低(当然也可能发生)注:这里我其实不是很理解,单纯看确实发生概率低,但如果出现网络延迟等情况呢,不也会发生吗?希望好心人解惑,我反正没理解。因此,在选择删除缓存时,还需要结合其他技术来优化性能和一致性。例如:使用消息队列来异步地删除或更新缓存,避免阻塞主线程或者丢失消息。使用延时双删来增加删除成功率和减少不一致时间窗口。即在更新数据库后立即删除一次缓存,并在一定时间间隔后再次删除一次。 对比在更新缓存中, 每次去更新缓存,但是缓存中的数据不一定会被马上读取,这就会导致缓存中可能存放了很多不常访问的数据,浪费缓存资源。而且很多情况下,写到缓存中的值,并不是与数据库中的值一一对应的,很有可能是先查询数据库,再经过一系列「计算」得出一个值,才把这个值才写到缓存中。​ 由此可见,这种更新缓存的方案,不仅缓存利用率不高,还会造成机器性能的浪费。所以我们一般考虑删除缓存先更新缓存再更新数据库在更新数据时,先将新数据写入缓存(Redis),再将新数据写入数据库(MySQL) 但其存在一下问题:缓存更新成功,但数据库更新失败,导致数据不一致 例:用户修改了自己的昵称,系统先将新的昵称写入缓存,然后再更新数据库。但是在更新数据库的过程中,发生了网络故障或者数据库宕机等异常情况,导致数据库中的昵称没有被修改。这样就会出现缓存中的昵称和数据库中的昵称不一致的情况。缓存更新成功,但数据库更新延迟,导致其他请求读取到旧的数据 例:用户下单了一个商品,系统先将订单状态写入缓存,然后再更新数据库。但是在更新数据库的过程中,由于并发量大或者其他原因,导致数据库的写入速度慢于缓存的写入速度。这样就会出现其他请求从缓存中读取到订单状态为已支付,而从数据库中读取到订单状态为未支付的情况。缓存更新成功,但在数据库更新之前有其他请求查询了缓存和数据库,并将旧的数据写回缓存,覆盖了新的数据 例:用户A修改了自己的头像,并上传到服务器上。系统先将新的头像地址写入缓存,并返回给用户A显示。然后再将新的头像地址更新到数据库中。但是在这个过程中,用户B访问了用户A的个人主页,并从缓存中读取到了新的头像地址。由于缓存失效策略或者其他原因(比如重启),导致缓存被清空或者过期。这时候用户B再次访问用户A 的个人主页,并从数据库中读取到了旧的头像地址,并将其写回缓存中。这样就会出现缓存中 的头像地址和 数据库 中 的头像地址不一致 的情况。上面说了一堆,其实总结就是缓存更新成功了,数据库没更新(更新失败),导致缓存存的是最新值,数据库存的是旧值。如果缓存失效了,就会拿到数据库中的旧值。 后面我自己也搞疑惑了,既然是因为数据库更新失败导致的问题,那我是不是只要保证数据库更新成功就可以解决数据不一致的问题,当数据库更新失败时,不停的重试更新数据库,直到数据库更新完成。后面发现自己太天真,其中存在很多问题,比如:如果数据库更新失败的原因是数据库宕机或者网络故障,那么你不停地重试更新数据库可能会造成更大的压力和延迟,甚至导致数据库恢复困难。如果数据库更新失败的原因是数据冲突或者业务逻辑错误,那么你不停地重试更新数据库可能会导致数据丢失或者数据错乱,甚至影响其他用户的数据。如果你不停地重试更新数据库,那么你需要考虑如何保证重试的幂等性和顺序性,以及如何处理重试过程中发生的异常情况。 所以,这种方法并不是一个很好的解决方案。先更新数据库,再更新缓存当有一个更新操作时,先更新数据库数据,然后再更新对应的缓存数据 但是,这种方案也有一些问题和风险,比如:如果更新数据库成功了,但是更新缓存失败了,那么就会导致缓存中就会保留旧的数据,而数据库中已经是新的数据,即脏数据。如果在更新数据库和更新缓存之间,有其他请求查询了同一个数据,并且发现缓存存在,那么就会从缓存中读取旧的数据。这样也会造成缓存和数据库之间的不一致性。 因此,在使用更新缓存操作时,无论谁先谁后,但凡后者发生异常,就会对业务造成影响。(还是上面那张图)那么如何处理异常情况来保证数据一致性呢这些问题的源头都是多线程并发所导致的,所以最简单的方法就是加锁(分布式锁)。两个线程要修改同一条数据,每个线程在改之前,先去申请分布式锁,拿到锁的线程才允许更新数据库和缓存,拿不到锁的线程,返回失败,等待下次重试。这么做的目的,就是为了只允许一个线程去操作数据和缓存,避免并发问题。​ 但加锁费时费力,肯定不推荐。并且,每次去更新缓存,但是缓存中的数据不一定会被马上读取,这就会导致缓存中可能存放了很多不常访问的数据,浪费缓存资源。而且很多情况下,写到缓存中的值,并不是与数据库中的值一一对应的,很有可能是先查询数据库,再经过一系列「计算」得出一个值,才把这个值才写到缓存中。​ 由此可见,这种更新数据库 + 更新缓存的方案,不仅缓存利用率不高,还会造成机器性能的浪费。所以此时我们需要考虑另外一种方案:删除缓存先删除缓存再更新数据库当有一个更新操作时,先删除对应的缓存数据,然后再更新数据库数据 但是,这种方案也有一些问题和风险,比如:如果删除缓存后,更新数据库失败了,那么就会导致缓存丢失,下次查询时需要重新从数据库加载数据,增加了数据库压力和响应时间。如果在删除缓存和更新数据库之间,有其他请求查询了同一个数据,并且发现缓存不存在,那么就会从数据库中读取旧的数据,并写入到缓存中。这样就会造成缓存和数据库之间的不一致性。先更新数据库,再删除缓存当有一个更新操作时,先更新数据库数据,再删除缓存上面其实讲过了,我再重复一遍吧会有这样一种情况:缓存刚好失效,请求B从数据库中查询数据,得到旧值。此时请求A更新数据库,将新值写入数据库,并删除缓存。而请求B又将旧值写入缓存中,导致脏数据从上面看出现脏数据的要求要比更新缓存的要求更多,必须满足以下几个条件:缓存失效读请求 + 写请求并发更新数据库 + 删除缓存的时间要比读数据库 + 写缓存时间短前面两个很好满足,我们再看看第三点,这个真的会出现吗?数据库在更新时一般是加锁的,读操作的速度远快于写操作的,所以第三点发生概率极低所以,解决双写问题更适合的方法是先更新数据库,再删除缓存,当然具体场景具体分析,不定说一定就是这个。讲解了这些操作后会出现的问题,那么为了避免这些问题,如何做呢?先删除缓存再更新数据库,然后使用异步线程或消息队列来重建缓存。先更新数据库再删除缓存,并设置一个合理的过期时间来保证缓存的有效性。使用分布式锁或乐观锁来控制并发访问,并保证每次只有一个请求能够操作缓存和数据库 ……下面讲几种常见的方法以保证双写一致性解决方案1. 重试上面也提到过,当第二步操作失败时,我就重试嘛,尽可能地补救,但重试的成本太大,上面讲过就不重复了。2. 异步重试​ 既然重试方法占用资源,那我就做异步。在删除或更新缓存时,如果操作失败,不立即返回错误,而是通过一些机制(如消息队列、定时任务、订阅binlog等)来触发缓存的重试操作。这样可以避免同步重试缓存时的性能损耗和阻塞问题,但也可能导致缓存和数据库的数据不一致的时间较长。2.1 使用消息队列实现重试消息队列保证可靠性:写到队列中的消息,成功消费之前不会丢失(重启项目也不担心)消息队列保证消息成功投递:下游从队列拉取消息,成功消费后才会删除消息,否则还会继续投递消息给消费者(符合我们重试的需求)使用消息队列异步重试缓存的情况是指,当信息发生变化时,先更新数据库,然后删缓存,如果删除成功就皆大欢喜,如果删除失败,则将需要删除的key发送到消息队列。另外有一个消费者线程从消息队列中获取要删除的key,并根据key删除或更新Redis中的缓存。如果操作失败,则重新发送到消息队列中进行重试。注:也可以不先尝试删除,直接发送给消息队列,让消息队列举例来说,假设有一个用户信息表,需要将用户信息缓存在Redis中。如果采用使用消息队列异步重试缓存的方案,可以有以下几个步骤:当用户信息发生变化时,先更新数据库,并返回成功结果给前端。尝试去删除缓存,成功则结束操作,失败则将要删除或更新缓存的操作生成一个消息(比如包含key和操作类型),并发送到消息队列中(比如使用Kafka或RabbitMQ)。另外有一个消费者线程从消息队列中订阅并获取这些消息,并根据消息内容删除或更新Redis中的对应信息。如果删除或更新缓存成功,则把这个消息从消息队列中移除(丢弃),以免重复操作。如果删除或更新缓存失败,则执行失败策略,比如设置一个延迟时间或者一个重试次数限制,然后重新发送这个消息到消息队列中进行重试。如果重试超过一定次数仍然失败,则向业务层发送报错信息,并记录日志。2.2 Binlog实现异步重试删除使用binlog实现一致性的基本思路是利用binlog日志来记录数据库的变更操作,然后通过主从复制或者增量备份的方式来同步或者恢复数据。举例来说,如果我们有一个主数据库和一个从数据库,我们可以在主数据库上开启binlog日志,并设置从数据库作为它的复制节点。这样,当主数据库上发生任何变更操作时,它会将对应的binlog日志发送给从数据库,从数据库则会根据binlog日志来执行相同的操作,从而保证数据一致性。另外,如果我们需要恢复某个时间点之前的数据,我们也可以利用binlog日志来实现。首先,我们需要找到对应时间点之前的最近一个全量备份文件,并将其恢复到目标数据库。然后,我们需要找到对应时间点之前的所有增量备份文件(即binlog日志文件),并按照顺序将其应用到目标数据库。这样,我们就可以恢复出目标时间点之前的数据状态了。使用 Binlog 实时更新/删除 Redis 缓存。利用 Canal,即将负责更新缓存的服务伪装成一个 MySQL 的从节点,从 MySQL 接收 Binlog,解析 Binlog 之后,得到实时的数据变更信息,然后根据变更信息去更新/删除 Redis 缓存;MQ+Canal 策略,将 Canal Server 接收到的 Binlog 数据直接投递到 MQ 进行解耦,使用 MQ 异步消费 Binlog 日志,以此进行数据同步;注:binlog日志是MySQL的二进制日志,它记录了对数据库的变更操作,比如插入、更新、删除等。 binlog日志有两个主要作用,一个是主从复制,另一个是增量备份。主从复制是指在一个主数据库和一个或多个从数据库之间实现数据的同步。主数据库会将自己的binlog日志发送给从数据库,从数据库则会根据binlog日志来执行相同的操作,从而保证数据一致性。这样可以提高数据的可用性和可靠性,也可以实现负载均衡和故障转移。增量备份是指在全量备份的基础上,定期备份数据库的变更操作。全量备份是指将整个数据库的数据完整地备份到一个文件中。增量备份则是指将每次变更操作对应的binlog日志文件备份到另一个文件中。这样可以减少备份所占用的空间和时间,也可以实现灵活地恢复数据到任意时间点。至此,我们可以得出结论,想要保证数据库和缓存一致性,推荐采用「先更新数据库,再删除缓存」方案,并配合「消息队列」或「订阅变更日志」的方式来做。3. 延时双删我们重点在将先更新数据库,在删除缓存。那如果我要先删除缓存,再更新数据库呢?回顾之前讲的先删除缓存,再更新数据库,它会出现旧值覆盖缓存的问题,那好办,我们直接把这个旧值给删了不就完了吗,延时双删就是这个原理,它的基本思路是:先删除缓存再更新数据库休眠一段时间(根据系统情况确定)再次删除缓存这样做的目的是为了防止在更新数据库后,有其他线程读取到旧的缓存数据,并将其写回缓存,导致数据不一致。举个例子:假设有一个用户信息表,其中有一个字段是用户积分。现在有两个线程A和B同时对用户积分进行操作:线程A要给用户增加100积分线程B要给用户减少50积分如果使用延时双删策略,那么线程A和B的执行过程可能如下:线程A先删除缓存中的用户信息线程A再从数据库中读取用户信息,发现用户积分为1000线程A将用户积分加上100,变为1100,并更新到数据库中线程A休眠5秒(假设这个时间足够让数据库同步)线程A再次删除缓存中的用户信息线程B先删除缓存中的用户信息线程B再从数据库中读取用户信息,发现用户积分为1100(因为线程A已经更新了)线程B将用户积分减去50,变为1050,并更新到数据库中线程B休眠5秒(假设这个时间足够让数据库同步)线程B再次删除缓存中的用户信息这样最终结果就是:数据库中的用户积分为1050,缓存中没有该用户信息。当下次有请求查询该用户信息时,就会从数据库中读取并写入到缓存中。这样就保证了数据一致性。延时双删适用于高并发场景,特别是对数据的修改操作比较频繁,而查询操作比较少的情况。这样可以减轻数据库的压力,提高性能,同时保证数据的最终一致性。延时双删也适用于数据库有主从同步延迟的场景,因为它可以避免在更新数据库后,从库还没有同步完成时,读取到旧的缓存数据,并将其写回缓存。注: 这个休眠时间 = 读业务逻辑数据的耗时 + 几百毫秒。 为了确保读请求结束,写请求可以删除读请求可能带来的缓存脏数据。总结好了,总结一下这篇文章的重点。Redis与MySQL的双写一致性问题是指在使用缓存和数据库同时存储数据的场景下,如何保证两者的数据一致性。这个问题主要涉及到以下几个方面:缓存更新策略:缓存更新策略有三种,分别是先更新缓存再更新数据库,先更新数据库再更新缓存,先删除缓存再更新数据库 和先更新数据库再删除缓存。每种策略都有可能导致数据不一致的情况。数据库主从同步延迟:如果使用了主从复制模式来提高数据库的可用性和读写分离能力,那么就可能存在主从同步延迟的问题。也就是说,在主库上执行了写操作后,并不会立即同步到从库上。这样,在读取数据时,如果从主库读取,则可能获取到最新的数据;而如果从从库读取,则可能获取到旧的数据。这样也会导致与缓存中的数据不一致。为了解决这些问题 , 可以采用以下几种方法 :采用先删除缓存,再更新数据库方案,在并发场景下依旧有不一致问题,解决方案是延迟双删,但这个延迟时间很难评估。采用先更新数据库,再删除缓存方案,为了保证两步都成功执行,需配合消息队列或订阅变更日志的方案来做,本质是通过重试的方式保证数据最终一致性。采用先更新数据库,再删除缓存方案,读写分离 + 主从库延迟也会导致缓存和数据库不一致,缓解此问题的方案是延迟双删,凭借经验发送延迟消息到队列中,延迟删除缓存,同时也要控制主从库延迟,尽可能降低不一致发生的概率。总之,根据场景选择适合自己的方案
  • [其他] Redis的Bigkey问题
    大厂的Redis开发规范中明确规定“拒绝bigkey(防止网卡流量、慢查询)”。String类型控制在10KB以内,hash、list、set、zset元素个数不要超过5000。bigkey会造成哪些问题?1.内存不均,集群迁移困难;2.超时删除,阻塞线程;3.网络流量阻塞;如何发现bigkey?(1)通过redis-cli --bigkeys查找。(2)计算每个键值的字节数,通过memory usage key查找出现bigkey时如何删除?1.String类型的用del删除。2.其它类型使用hscan、sscan、zscan方式渐进式删除,同时要避免bigkey过期时间自动删除问题,因为它会造成主线程阻塞。参考:https://blog.csdn.net/guorui_java/article/details/129637212
  • [热门活动] 【华为云开年采购季】研发工具、Redis、漏洞扫描等新客1.98元起,下单抽FreeBuds耳机!
     #华为云开年采购季#15+云原生产品全场低至3折,新客1.98元起! -Redis低至6折,Kafka、RabbitMQ、RocketMQ等低至5.5折,3年5折! -数字资产链新客119元起,华为链新客19.8元起! -软件开发生产线CodeArts,新客试用1.98元起! -漏洞扫描、二进制成分分析、APP合规检测6.6折起! -Serverless应用引擎CAE,新客试用109元起! -ROMAConnect集成平台,打通新老应用,试用19.8元起! 下单抽FreeBuds无线耳机!更多产品优惠戳:http://t.cn/A6a7JhLQ 活动有效期至2023年3月31日,上云正当时!>点击这里,马上进入活动专场<
  • [技术干货] 怎么配置redis外网指定的ip访问
    怎么配置redis外网指定的ip访问?相信大部分人都还没学会这个技能,为了让大家学会,给大家总结了以下内容,话不多说,一起往下看吧。                                                           # bind 192.168.1.100 10.0.0.1 # bind 192.168.1.8 # bind 127.0.0.1修改完成后,需要重新启动redis服务。redis-server redis.conf如果iptables 没有开启6379端口,用这个方法开启端口命令:/sbin/iptables -I INPUT -p tcp --dport 6379 -j ACCEPT保存防火墙修改命令:/etc/rc.d/init.d/iptables save通过iptables 允许指定的外网ip访问修改 Linux 的防火墙(iptables),开启你的redis服务端口,默认是6379。//只允许127.0.0.1访问6379iptables -A INPUT -s 127.0.0.1 -p tcp --dport 6379 -j ACCEPT//其他ip访问全部拒绝iptables -A INPUT -p TCP --dport 6379 -j REJECT未配置拒绝前配置拒绝后另外一种方式是通过bind方式启用上文描述的就是配置redis外网并指定ip访问redis服务的方法,具体使用情况还需要大家自己动手实验使用过才能领会。原文链接:https://www.yisu.com/zixun/145042.html
  • [技术干货] 使用spring自带的Cacheable注解处理Redis缓存
    本文不为Redis安装和使用范畴,有兴趣的朋友可以联系我,也可以自行百度:Redis安装和使用   Redis实现缓存添加,更新和删除的方法有很多. 1:较为笨拙的方法,也是最稳定的方法,也是一些自动化缓存更新的原理但是代码就多了点,在需要用到缓存的地方,去判断,           先从缓存取,取不到,去数据库查找,找到返回该数据,并写入缓存 2:使用aop的思想,在需要用到缓存的地方左上标识(用注解实现即可,方法很多),剩下的原理同上,这是个一劳永逸的过程 3:就是这篇文章要讲的:使用spring自带的Cacheable注解处理Redis缓存,以下为具体的细节描述 1)使用maven项目管理 <dependency>             <groupId>org.springframework</groupId>             <artifactId>spring-context</artifactId>             <version>4.1.6.RELEASE</version> </dependency> 2)在需要使用到的地方加上Cacheable注解    cacheable能够实现自动缓存接口的返回结果,所以我们可以把注解直接加到我们需要缓存结果的接口上。 放的位置可以试service也可以是dao,以下是放到service和dao层的示例: 放到service层上: @Cacheable(value="workDetailV150",key="'workDetailV150'.concat(#param.workId.toString()).concat(#param.userId.toString())") public CliDresserWorkDetailV150 getWorkDetail(CliGetWorkDetailParam param) throws Exception {       return doGetWorkDetail(param); } 放到dao层上: @Cacheable(value="getWorkDetailPhotos",key="'getWorkDetailPhotos'.concat(#root.args[0])") List<String> getWorkDetailPhotos(Integer workId);  有没有看到,两者的不同,在dao层上,因为用了mybatis的缘故,这里只有接口,那么用workId放到key里面是存不到redis的,因为spring cache拿到的是null。所以这里必须用#root.args[x]的方式设置。 问题来了,那个这里有一个value还有一个key,他们分别代表了什么呢? 3)缓存的清除 如果我们缓存的实体更新了,怎么办?不能够get的还是旧的东西。这时候就需要强制清除相关联的缓存了。方法就是提供一个空的接口方法,在该方法上添加@CacheEvict的注解,如下:   @CacheEvict(value = "workDetailV150", allEntries=true) public void evictWorkDetailCache(){  } 4)Cacheable注解key的说明   这个地方主要简单说明一下3个要素:1.字符串、2.接口参数、3.环境参数,以及一个函数 字符串很好说了用单引号括起来就可以了。 接口参数直接用#加参数名,如果是参数内的属性那么继续用.串联接好了。 环境参数:  属性名称    描述    示例 methodName    当前方法名    root.methodName method    当前方法    root.method.name target    当前被调用的对象    root.target targetClass    当前被调用的对象的class    root.targetClass args    当前方法参数组成的数组    root.args[0] caches    当前被调用的方法使用的Cache    root.caches[0].name 最后是关键函数concat,意思很明白了,就是连接字符串用的。  使用过程,或者有什么不明白的,我们可以互相讨论,共同进步!欢迎大家骚扰~~~ ———————————————— 原文链接:https://blog.csdn.net/u011271894/article/details/77969070 
  • [热门活动] 华为云11.11助力应用现代化,多重福利等你来拿
    华为云11.11助力应用现代化,多重福利等你来拿!>点击这里,马上进入活动专场<
  • [热门活动] 【华为云11.11】年度钜惠,多重福利来袭!数字资产链、Redis、Kafka软件开发平台全场3折起,首购1.98元,下单抽好礼!
    #华为云11.11# 实惠更实用·“11”都如愿云中间件、DevSecOps、数字资产管理年度钜惠,多重福利来袭!福利一:全场低至3折,新客试用1.98元起!福利二:领万元礼包,15+款产品券后低至5.8折!福利三:下单抽好礼,有机会获FreeBuds耳机!福利四:新购满额送,华为P50 Pro等好礼等你拿!现在上云,一惠到底!活动有效期至2022年11月30日,上云正当时!>点击这里,马上进入活动专场<
  • [技术干货] Redis下载及安装(windows版)
     安装和配置Redis 前言:windows没有32位的Redis,所以32位机器的朋友考虑换一下机器。 1、windows环境下的redis需要去github上获取: https://github.com/MicrosoftArchive/redis/releases 2、直接下载最新版本,选择.msi格式的安装版本(另外一种.zip通过命令安装) 3、直接运行.msi的安装包,一直next,直到下面界面,勾选上再next 4、这一步选择端口,然后next(后面可以通过配置文件修改的) 5、选择最大缓存容量,点击next(后面可以通过配置文件修改的) 6、接下来可以点击install进行安装了,安装完毕后,进入redis安装目录找到配置文件,注意是redis.windows-service.conf,不是redis.windows.conf,后者是以非系统服务方式启动程序使用的配置文件. 7、在配置文件中,找到requirepass foobared字样,在其后面追加一行,输入requirepass 123456。这是访问Redis时所需的密码,一般测试情况下可以不用设定密码。不过,即使是作为本地访问,也建议设定一个密码。此处以简单的123456来演示,然后保存退出 8、进入计算机服务中(右键计算机-->管理-->服务和应用程序-->服务),再在右侧找到Redis名称的服务,查看启动情况。如未启动,则手动启动之。正常情况下,服务应该正常启动并运行了,但是因为前面修改过配置文件,需要重启服务,切记 9、测试一下redis能否正常工作。用命令进入redis安装路径,输入redis-cli并回车(redis-cli是客户端程序)如图正常提示进入,并显示正确端口号,则表示服务已经启动。 10、使用服务前需要先通过密码验证。输入“auth 123456”并回车(123456是之前设定的密码)。返回提示OK表示验证通过。 然后再验证set和get。一切正常,说明可以开始随便盘它了。 可视化工具 redis常用的可视化工具 Redis Desktop Manager。 下载地址:https://github.com/uglide/RedisDesktopManager/releases/download/0.9.3/redis-desktop-manager-0.9.3.817.exe 这位朋友的百度云盘里也有(感谢):https://blog.csdn.net/u012688704/article/details/82251338 下载完成之后直接点击安装包安装即可,无需任何配置。 然后直接连接Redis就可以盘了 ———————————————— 原文链接:https://blog.csdn.net/weixin_41381863/article/details/88231397 
  • [问题求助] GaussDB(for opengauss)中如何同步档案数据到redis?
    工作中需要同步GaussDB(for opengauss)中的档案数据到redis,有没有什么好的方案,华为有提供相应的工具吗?