• [其他] Redis 实现限流器的三种方法
     互联网应用往往是高并发的场景,互联网的特性就是瞬时、激增,比如鹿晗官宣了,此时,如果没有流量管控,很容易导致系统雪崩。  而限流是用来保证系统稳定性的常用手段,当系统遭遇瞬时流量激增,很可能会因系统资源耗尽导致宕机,限流可以把一超出系统承受能力外的流量直接拒绝掉,保证大部分流量可以正常访问,从而保证系统只接收承受范围以内的请求。  我们常用的限流算法有:漏桶算法、令牌桶算法。  漏桶算法 漏桶算法很形象,我们可以想像有一个大桶,大桶底部有一个固定大小的洞,Web请求就像水一样,先进入大桶,然后以固定的速率从底部漏出来,无论进入桶中的水多么迅猛,漏桶算法始终以固定的速度来漏水。   对应到Web请求就是:  当桶中无水时表示当前无请求等待,可以直接处理当前的请求; 当桶中有水时表示当前有请求正在等待处理,此时新来的请求也是需要进行等待处理; 当桶中水已经装满,并且进入的速率大于漏水的速率,水就会溢出来,此时系统就会拒绝新来的请求; 令牌桶算法 令牌桶跟漏桶算法有点不一样,令牌桶算法也有一个大桶,桶中装的都是令牌,有一个固定的“人”在不停的往桶中放令牌,每个请求来的时候都要从桶中拿到令牌,要不然就无法进行请求操作。   当没有请求来时,桶中的令牌会越来越多,一直到桶被令牌装满为止,多余的令牌会被丢弃 当请求的速率大于令牌放入桶的速率,桶中的令牌会越来越少,直止桶变空为止,此时的请求会等待新令牌的产生 漏桶算法 VS 令牌桶算法 漏桶算法是桶中有水就需要等待,桶满就拒绝请求。而令牌桶是桶变空了需要等待令牌产生; 漏桶算法漏水的速率固定,令牌桶算法往桶中放令牌的速率固定; 令牌桶可以接收的瞬时流量比漏桶大,比如桶的容量为100,令牌桶会装满100个令牌,当有瞬时80个并发过来时可以从桶中迅速拿到令牌进行处理,而漏桶的消费速率固定,当瞬时80个并发过来时,可能需要进行排队等待;   介绍了算法,接下来我们介绍下Redis实现限流的几种方式。  第一种:基于Redis的setNX的操作 我们在使用Redis的分布式锁的时候,大家都知道是依靠了setNX的指令,在CAS(Compare and swap)的操作的时候,同时给指定的key设置了过期实践(expire),我们在限流的主要目的就是为了在单位时间内,有且仅有N数量的请求能够访问我的代码程序。所以依靠setnx可以很轻松的做到这方面的功能。  比如我们需要在10秒内限定20个请求,那么我们在setnx的时候可以设置过期时间10,当请求的setnx数量达到20时候即达到了限流效果。代码比较简单就不做展示了。  当然这种做法的弊端是很多的,比如当统计1-10秒的时候,无法统计2-11秒之内,如果需要统计N秒内的M个请求,那么我们的Redis中需要保持N个key等等问题。  第二种:基于Redis的数据结构zset 其实限流涉及的最主要的就是滑动窗口,上面也提到1-10怎么变成2-11。其实也就是起始值和末端值都各+1即可。  而我们如果用Redis的list数据结构可以轻而易举的实现该功能  我们可以将请求打造成一个zset数组,当每一次请求进来的时候,value保持唯一,可以用UUID生成,而score可以用当前时间戳表示,因为score我们可以用来计算当前时间戳之内有多少的请求数量。而zset数据结构也提供了range方法让我们可以很轻易的获取到2个时间戳内有多少请求(解决了第一种方案中无法统计2-11秒的问题)。  示例代码:  public Response limitRequest(){     Long currentTime = new Date().getTime();          if(redisTemplate.hasKey("limit")) {         // intervalTime 限流的时间(滑动窗口)         Integer count = redisTemplate.opsForZSet().rangeByScore("limit", currentTime -  intervalTime, currentTime).size();                           if (count != null && count > 10) {             return Response.ok("每分钟最多只能访问10次");         }     }     redisTemplate.opsForZSet().add("limit", getID(), currentTime);     return Response.ok("成功访问"); }  private String getID() {     return UUID.randomUUID().toString(); } 点击并拖拽以移动 通过上述代码可以做到滑动窗口的效果,并且能保证每N秒内至多M个请求,缺点就是zset的数据结构会越来越大。实现方式相对也是比较简单的。  第三种:基于Redis的令牌桶算法 令牌桶算法提及到输入速率和输出速率,当输出速率大于输入速率,那么就是超出流量限制了。  也就是说我们每访问一次请求的时候,可以从Redis中获取一个令牌,如果拿到令牌了,那就说明没超出限制,而如果拿不到,则结果相反。  依靠上述的思想,我们可以结合Redis的List数据结构很轻易的做到这样的代码,只是简单实现依靠List的leftPop方法来获取令牌。  示例代码:  // 输出令牌 public Response limitRequest(Long id){     Object result = redisTemplate.opsForList().leftPop("limit_list");     if(result == null){         return Response.ok("当前令牌桶中无令牌, 请稍后重试.");     }     return Response.ok("成功访问"); }  再依靠Java的定时任务,定时往令牌桶List中加入新的令牌(使用List的rightPush方法),当然令牌也需要唯一性,这里还是用UUID生成令牌:  // 10S的速率往令牌桶中添加UUID,保证唯一性 @Scheduled(fixedDelay = 10_000, initialDelay = 0) public void setIntervalTimeTask(){     redisTemplate.opsForList().rightPush("limit_list", UUID.randomUUID().toString()); }     点击并拖拽以移动 到这里,你觉得结束了吗,其实,上面的setIntervalTimeTask方法有个问题 —— 允许你思考10秒钟 —— 就是没有判断当前令牌桶的大小(令牌桶阈值),所以要优化这段代码,就加入一句判断List大小的代码即可,不然无限往里面加,越来越多,是有问题的,这里代码就不贴了,大家自行优化即可。  综上,代码实现起始都不是很难,针对这些限流方式我们可以在AOP或者filter中加入以上代码,用来做到接口的限流,最终保护系统的稳定。  
  • [其他] Redis 的数据一致性方案
     Redis 的数据一致性方案分析 一般的业务场景都是读多写少的,当客户端的请求太多,对数据库的压力越来越大,引入缓存来降低数据库的压力是必然选择,目前业内主流的选择基本是使用 Redis 作为数据库的缓存。但是引入缓存以后,对我们系统的设计带来了很大的挑战,其中缓存和数据库的数据一致性问题就是一个非常棘手的问题,今天我们就来聊一聊在项目中,我们用什么方案来解决数据一致性的问题。  一、Redis 的使用场景 我们在实际项目中,通常情况下的应用是读多写少的,我们一般用 Redis 来解决读数据库的压力问题,也就是说用 Redis 作为缓存来减轻由于客户端频繁查询数据库而对数据库造成的压力。  因此在项目中由客户端直接查询数据库返回数据,变成了客户端查询 Redis 缓存,缓存有数据则直接返回数据,缓存没有数据再去查询数据库,同时数据库的数据写入到 Redis 缓存。   在以上的使用场景中,我们一般缓存热点数据,比如电商平台中的热销商品,用户的登录信息,新闻类平台中的热点新闻等。  二、Redis 数据一致性问题产生的原因与分析 当数据库的数据发生变化的时候,引入 Redis 缓存以后,增加了数据操作难度,既要操作数据库又要操作 Redis,对 Redis和数据库的操作有 2 种方案:  1、先操作 Redis,再操作数据库  2、先操作数据库,再操作 Redis  我们无论选择以上的哪个方案,都希望数据操作要么都成功,要么都失败,我们不希望看到一个失败,一个成功的结果,因为这样就产生了数据不一致的问题。  举个例子说明:  假设 Redis 里缓存了一个热点商品数据,有个 key 为 1001 的商品名称为“华为手机”,数据库里这个 1001 号的商品名称也是华为手机;此时商家觉得商品名称叫华为手机有点宽泛,需要精确一下,把 1001 号商品的名称修改为其对应的具体名称“华为 P40 Pro”。  1、如果我们选择先操作 Redis,再操作数据库的方案,当操作 Redis 成功,操作数据库失败的时候,Redis 里的名称修改为“华为 P40 Pro”,但是数据库的名称还是“华为手机”,产生了数据不一致问题。  2、如果我们选择先操作数据库,再操作 Redis 的方案,当操作数据库成功,操作 Redis 失败的时候,数据库里的名称修改为“华为 P40 Pro”,但是 Redis 的名称还是“华为手机”,产生了数据不一致问题。  由于 Redis 和数据库是 2 个不同的中间件,我们无法通过事务来很好地解决数据一致性的问题,因此只能在数据实时一致性和系统性能上做权衡,选择一个可以接收的方案。  因为数据库是稳定的持久化的系统,比 Redis可靠,我们一般都是以数据库的数据为准,解决这个数据一致性问题的原则就是:我们可以为 Redis 缓存数据设置一个过期的时间,当 Redis 数据过期了就去数据库查询,然后再把数据库的数据写入 Redis 缓存中,确保数据的一致性。  如果在这个过期时间范围内,数据发生了更新操作,当更新操作有一个失败,有一个成功,就会产生不一致的问题,这个过期时间设置的太短了,数据库的压力还是很大,过期时间设置的太长了,不一致性的问题就会凸显,因此我们需要基于以数据库的数据为准的原则下,继续探讨数据一致性问题的解决方案。  三、数据更新时,如何操作 Redis 当数据更新时,操作数据库我们都很熟悉,直接更新数据库的值就可以了,但是操作 Redis,我们应该怎么办?  1、有人会说,这还不简单,数据变化时,直接更新缓存  2、也有人会说数据变化时把缓存的数据删掉,当查询请求发现缓存没有数据,就会从数据库加载新的数据。  以上的两种方法都可以,那我们该如何选择呢?  如果我们选择更新 Redis 的方案,我们要评估一下更新的代价大不大,比如拿到数据更新到 Redis 需要经过很多表的关联查询,或者多个接口的调用查询,经过大量计算才能得到数据的话,就不要使用更新 Redis 的方案了,因为面对这么复杂的更新流程,不如直接删掉方便。如果要更新的数据直接可以获取到,那么选择更新 Redis 的方案就是可行的。  直接删除 Redis 缓存数据是更加简单的方案,因为缓存数据删了,只能从数据库读取了,这样可以避免不一致性,互联网公司一般选择删除 Redis 的方案。  下面我们用一张图来表示可选的方案:   通过上图,我们可以看出当数据发生变化时,Redis 与数据库的处理流程我们可以从 Redis更新还是删除这 2 个方面分析,然后再从先操作 Redis还是先操作数据库这 2 个方面分析,下面我们按此思路继续深入分析。  四、选择 Redis 更新方案 1、先更新 Redis,再更新数据库 首先不推荐选择这种方案。  因为我们的数据一致性的基本原则是以数据库的数据为准,所以先更新缓存的话,会存在缓存更新成功,数据库更新失败的情况,此时面临的问题就需要回滚掉刚才更新缓存成功的操作,那么就需要从业务代码里加入很多判断逻辑来处理这种异常,需要考虑数据变化是 insert,update,delete 等,根据不同的场景执行不同的回滚方案,这种回滚操作比较麻烦,对我们业务代码的倾入性也比较大,所以不推荐选择这种方案。  当然,如果业务层面可以接受这种数据的不一致性,异常情况就不需要考虑,选择这种方案也是可以的。  2、先更新数据库,再更新 Redis 先更新数据库,再更新 Redis 的方案,由于把数据库操作放到了前面,如果数据库操作失败,那么客户端再发起一次就可以了。  如果数据库操作成功,Redis 操作失败,此时由于数据库的数据已经设置成功,我们的重点就是讨论如何把 Redis的数据操作成功即可。从客户端层面来看,他提交的数据已经在我们系统里存在了,此时的问题就是我们系统内部如何解决的问题。  对于 Redis 操作失败,我们可选的方案有以下几个,根据业务要求的数据一致性级别,进行权衡选择即可。  1、不做任何操作,等着Redis里的缓存数据过期后,自动从数据库同步最新的数据,此时最严重的数据不一致性周期就是在缓存过期的一段时间(考虑一下这个过期时间的范围);如果在这个时间段内,又有新的更新请求,也许这次就更新缓存成功了。  2、如果数据一致性要求比较高,那么 Redis 操作失败后,我们把这个操作记录下来,异步处理,用 Redis 的数据去和数据库比对,如果不一致,再次更新缓存确保缓存数据与数据库数据一致。  五、选择 Redis 删除方案 由于目前数据发生变化,主流的方案是选择删除 Redis,所以我们对这个方案重点进行分析。  1、先更新数据库,再删除 Redis 我们如果更新数据库成功,删除 Redis 失败,那么 Redis 里存放的就是一个旧值,也就是删除缓存失败导致缓存和数据库的数据不一致了。  对于删除 Redis 失败的异常情况来进行分析,我们一般有如下的方案:  1、我们可以重试删除,比如:我们可以把删除动作发送到消息队列 MQ,MQ的消费者再去删除这个key,一致尝试删除操作,确保缓存删除成功,这个方案缺陷就是删除缓存的地方,通过代码实现对业务逻辑产生了入侵。  2、另外一种方案,就是完全异步的方案,对业务逻辑没有入侵,通过监听 binlog 的变化来删除缓存。我们更新数据库会产生 binlog,我们可以用一个服务监听数据库 binlog 的变化,异步去删除缓存,阿里开源的 canal 就是可以监听 binlog 的工具,只要数据发生变化就可以删除 Redis 的数据。  2、先删除 Redis,再更新数据库 我们如果删除 Redis 缓存成功,更新数据库失败的话,因为我们是以数据库为准,再查一次就可以了,这个方案看似很理想,感觉没什么问题,其实在并发下也可能产生数据一致性问题。  我们先看一个并发环境下的更新和查询流程:   ​ 上面的图表示,Thread-1 是个更新流程,Thread-2 是个查询流程,cpu 执行顺序是:Thread-1 删除缓存成功,此时 Thread-2 获取到 CPU 执行查询缓存没有数据,然后查询数据库把数据库的值写入缓存,因为此时 Thread-1 更新数据库还没有执行,所以缓存里的值是一个旧值(old),最后 CPU 执行 Thread-1 更新数据库成功的代码,那么此时数据库的值是新增(new),这样就产生了数据不一致行的问题。  要解决以上的问题,我们我们一般有如下的可选方案:  1、并发下多线程操作能不能让同一个操作里的 2 个步骤同时操作完成,下一个线程才能执行,让各个线程排队操作,有人说加锁,如果一个服务部署到了多个机器,就变成了分布式锁,或者是分布式队列按顺序去操作数据库或者 Redis,带来的副作用就是数据库本来是并发的,现在变成串行的了,所以这个方案看起来不太可行,加锁或者排队执行的方案降低了系统性能。  2、另外一种放啊就是延时双删的方案,也就是先删除缓存,再更新数据库,当更新数据后休眠一段时间再删除一次缓存。  伪代码如下:  redes.del(key); db.update(data); Thread.sleep(2000); redes.del(key); 点击并拖拽以移动 六、总结 以上谈到的都是一些解决方案,没有说哪个方案更好,或者哪个方案不行,以上的方案都是基于实时一致性和系统性能的情况下进行权衡选择,根据不同的业务,不同的数据一致性要求,结合系统的性能综合考虑,选择适合自己系统的方案就好。  总的来说,由于我们的基本原则是以数据库为准,那么我们选择的方案就应该把操作数据库放到前面,也就是说我们应该先操作数据库,再操作 Redis,对于并发很高的场景,我们可以在操作数据库之前通过消息队列来降低客户端对数据库的请求压力。  
  • [其他] 秒杀场景下乐观锁和悲观锁结合使用
    在Java中,乐观锁和悲观锁可以同时使用,特别是在秒杀场景下,这种混合使用的策略可以有效提高系统的性能和并发处理能力。首先,我们来了解一下乐观锁和悲观锁的基本概念:悲观锁:是一种预防性的锁策略,它假设在操作数据时很可能会发生冲突,因此在数据处理前先锁定数据,防止其他线程或事务对数据进行修改,直到操作完成后才释放锁。乐观锁:是一种无锁机制,它假设在操作数据时不太可能发生冲突,因此不使用传统的锁机制,而是通过版本号或其他检测手段来确保数据的一致性。当更新数据时,会检查版本号是否发生变化,如果变化则说明数据已被其他线程修改,从而采取相应的措施。在秒杀场景下,两种锁的使用方式如下:使用悲观锁保护关键资源:在秒杀场景中,可以使用悲观锁来保护关键资源,如库存数量。在业务层的秒杀方法中,可以使用synchronized关键字或其他锁机制来实现悲观锁,确保在减库存和下订单的过程中,相关数据不会被其他线程修改。使用乐观锁处理并发更新:在商品表中增加一个版本号字段,每次更新库存时同时更新版本号。这样,在多个线程尝试同时更新库存时,可以通过比较版本号来判断是否有冲突发生,如果没有冲突,则正常更新;如果有冲突,则可以选择重试或采取其他措施。综上所述,乐观锁和悲观锁的混合使用可以在保证数据一致性的同时,提高系统的并发处理能力。在秒杀场景下,这种策略尤为重要,因为它可以帮助系统应对高并发的压力,确保秒杀活动的顺利进行。在实际开发中,需要根据具体的业务需求和技术架构来决定如何合理地结合使用这两种锁机制。
  • [其他] redis如何实现悲观锁
    Redis可以通过使用分布式锁来实现悲观锁。以下是一个简单的示例,演示了如何使用Redis实现悲观锁:首先,在Redis中存储一个键值对,其中键是商品ID,值是一个包含库存数量的哈希表。例如,可以使用以下命令设置初始值:SET product:1 {"stock": 10}当用户请求购买商品时,先获取当前的商品信息,包括库存数量。可以使用以下命令获取商品信息:GET product:1检查库存是否充足。如果库存不足,则返回错误信息给用户。否则,将库存减一,并更新商品信息。可以使用以下命令进行操作:// 获取分布式锁 SET lock:product:1 <unique_identifier> NX PX <lock_timeout> // 如果成功获取到锁,执行以下命令更新库存和商品信息 GET product:1 // 检查库存是否充足 // 如果库存不足,执行以下命令释放锁并取消事务 DELETE lock:product:1 // 如果库存充足,执行以下命令更新库存和商品信息 DECR stock SET product:1 {"stock": new_stock} // 释放锁 DELETE lock:product:1如果在执行事务期间有其他客户端修改了商品信息,那么由于分布式锁的存在,其他客户端无法获取到锁,因此无法执行事务。此时,需要等待锁被释放后重新尝试执行事务。需要注意的是,悲观锁是一种基于锁的机制,它在事务开始时就锁定资源,以防止其他事务同时修改数据。悲观锁适用于写多读少的场景,因为每次读取数据都需要额外的加锁和解锁操作。对于高并发场景,可以考虑结合其他技术如乐观锁、限流等来提高系统的稳定性和性能。
  • [其他] redis如何实现乐观锁
    Redis可以通过使用版本号(version)或时间戳(timestamp)等机制来实现乐观锁。以下是一个简单的示例,演示了如何使用Redis实现乐观锁:首先,在Redis中存储一个键值对,其中键是商品ID,值是一个包含库存数量和版本号的哈希表。例如,可以使用以下命令设置初始值:SET product:1 {"stock": 10, "version": 1}当用户请求购买商品时,先获取当前的商品信息,包括库存数量和版本号。可以使用以下命令获取商品信息:GET product:1检查库存是否充足。如果库存不足,则返回错误信息给用户。否则,将库存减一,并更新版本号。可以使用以下命令进行操作:WATCH product:1 MULTI GET product:1 // 检查库存是否充足 // 如果库存不足,执行以下命令取消事务 DISCARD // 如果库存充足,执行以下命令更新库存和版本号 DECR stock HINCRBY product:1 version 1 EXEC如果在执行事务期间有其他客户端修改了商品信息,那么WATCH命令会监视到这个变化,并使事务失败。此时,需要重新获取最新的商品信息,并再次尝试执行事务。如果事务成功执行,说明用户成功购买了商品。可以返回相应的结果给用户。需要注意的是,乐观锁是一种无锁机制,它假设冲突发生的概率较低,因此不会像传统锁那样在事务开始时就锁定资源。相反,它在数据提交时检查版本号或其他标记,以确保没有其他事务修改过这些数据。如果检测到冲突,事务将重新尝试直到成功为止。此外,乐观锁适用于读多写少的场景,因为每次读取数据都需要额外的版本号检查。对于高并发场景,可以考虑结合其他技术如分布式锁、限流等来提高系统的稳定性和性能。
  • [其他] redis解决秒杀场景的一人一单问题
    Redis可以通过使用分布式锁和乐观锁机制来解决秒杀场景中的一人一单问题。在秒杀场景中,确保每个用户只能购买单个商品是非常重要的,以防止库存超卖和保证公平性。以下是Redis解决这一问题的几种方法:分布式锁:通过Redis的SETNX命令或者Redlock算法,可以在多个实例间实现一个分布式锁。这个锁可以确保同一时间只有一个请求能够执行特定的代码块,从而防止多个线程或进程同时修改同一份资源。乐观锁:乐观锁是一种无锁机制,它不需要像传统锁那样在事务开始时就锁定资源。相反,它在数据提交时检查版本号或其他标记,以确保没有其他事务修改过这些数据。如果检测到冲突,事务将重新尝试直到成功为止。在Redis中,可以使用INCR等命令来更新版本号或时间戳。限流:通过Redis的计数器和限流功能,可以控制进入秒杀流程的请求数量,避免系统因瞬间高并发而崩溃。队列:利用Redis的列表(List)数据结构作为队列,可以将用户的购买请求排入队列中,然后逐个处理,确保每个用户有序且公平地参与秒杀。预减库存:在用户进入秒杀流程之前,可以先通过Redis的原子操作减少库存,这样可以确保库存不会超卖。缓存预热:在秒杀活动开始前,可以将部分数据预热到Redis缓存中,减少对后端数据库的压力。数据一致性:结合消息队列等中间件技术,确保Redis缓存与后端数据库之间的数据一致性。监控与应急预案:建立实时监控机制,一旦发现异常立即触发应急预案,如熔断、降级等。综上所述,通过上述策略的组合使用,Redis可以帮助秒杀系统在高并发压力下保持稳定运行,同时确保一人一单的公平性。在实际应用中,需要根据具体的业务场景和技术架构来选择最合适的解决方案。
  • [技术干货] 实际生产中,Redis是否需要做备份恢复
    前言Redis作为一个高性能的内存数据库,广泛应用于各种业务场景中,用于缓存、消息队列、分布式锁等多种功能。然而,正因为Redis的数据存储在内存中,其数据的持久化和安全性就成了一个不容忽视的问题。那么,在实际应用中,我们是否需要对Redis进行备份恢复操作呢?本文将就此问题进行探讨。一、Redis的数据持久化机制Redis提供了多种数据持久化机制,如RDB(Redis DataBase)和AOF(Append Only File)。RDB通过定期将内存中的数据快照保存到磁盘上,实现数据的持久化;而AOF则通过记录Redis执行的写操作命令,将命令追加到文件中,从而在Redis重启时重新执行这些命令来恢复数据。这些机制为Redis的数据安全提供了一定的保障,但并不能完全替代备份恢复操作。二、为什么需要备份恢复数据安全:尽管Redis提供了持久化机制,但硬件故障、人为误操作等因素仍可能导致数据丢失。定期备份Redis数据,可以在数据丢失时迅速恢复,减少业务损失。数据迁移:在业务升级、服务器扩容等场景下,可能需要将Redis数据从一个实例迁移到另一个实例。通过备份恢复操作,可以方便地实现数据的迁移。版本回滚:当Redis升级新版本后,可能出现兼容性问题或性能下降。此时,可以通过恢复之前的备份数据,将Redis版本回滚到稳定状态。三、如何备份恢复Redis数据备份:可以使用Redis提供的SAVE或BGSAVE命令,或者利用第三方工具如Redis Sentinel、Redis Cluster等进行数据备份。备份时需要注意数据的完整性和一致性,避免在备份过程中出现数据丢失或损坏。恢复:当需要恢复Redis数据时,可以先停止Redis服务,然后删除原有的数据文件,将备份文件替换为新的数据文件,最后重新启动Redis服务。在恢复过程中,要确保备份文件的完整性和正确性,避免因为备份文件的问题导致恢复失败。四、备份恢复的注意事项定期备份:建议定期(如每天、每周)对Redis数据进行备份,确保数据的实时性和完整性。备份存储:备份数据应存储在安全可靠的地方,如远程服务器或云存储服务,以防本地硬件故障导致备份数据丢失。备份验证:定期对备份数据进行验证,确保备份数据的完整性和可用性。可以通过在测试环境中恢复备份数据并验证其功能来实现。备份策略:根据业务需求和数据量大小,选择合适的备份策略,如全量备份、增量备份等。总结在实际应用中,Redis内存数据库需要进行备份恢复操作。通过定期备份和验证,我们可以在数据丢失或需要迁移时迅速恢复数据,保障业务的正常运行。同时,结合Redis自身的持久化机制,我们可以进一步提高数据的安全性和可靠性。
  • [技术干货] Redis实现商品秒杀的示例代码【转】
    随着互联网的发展和消费者的需求越来越高,商品的销售也变得越来越激烈。而对于商家来说,最直观的解决方式即为促销活动。然而,促销活动也会引发一定的风险。如果处理得不当,可能会出现“抢购”活动中的库存不足等问题。本文将利用Redis实现商品秒杀,来避免这些问题的发生。技术栈本次实现采用的技术栈如下:SpringBootRedisMybatis-plusVue功能实现步骤在实现商品秒杀之前,我们需要先准备好基本的开发环境。本文将假定您已经设置好了相关环境。接下来,请按照以下步骤进行功能的实现。步骤一:准备商品库存数据首先,我们需要在数据库中创建一个名为“goods”的表,用于存储商品的库存数据。表结构如下:CREATE TABLE `goods` (   `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '秒杀商品ID',   `goods_name` varchar(32) DEFAULT NULL COMMENT '商品名称',   `goods_count` int(11) DEFAULT NULL COMMENT '商品库存数量',   `start_time` datetime DEFAULT NULL COMMENT '秒杀开始时间',   `end_time` datetime DEFAULT NULL COMMENT '秒杀结束时间',   PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 在表中添加一些假数据,用于测试秒杀功能。步骤二:实现商品秒杀接下来,我们需要实现商品秒杀功能。这里,我们采用Redis作为秒杀的核心工具,通过前后端协作来实现秒杀。1. Redis实现秒杀在Redis中,我们可以使用List类型来存储待秒杀的商品ID,使用Set类型来存储已经秒杀成功的商品ID。同时,为了防止一个用户重复抢购同一个商品,我们还需要使用Hash类型来存储每个用户的秒杀订单信息。具体实现方式如下:初始化Redis中的商品列表和已秒杀商品集合,将数据库中的商品库存数量存入Redis中。// 商品列表名称 String redisKey = "goods:" + seckillGoods.getId(); // 添加所有库存商品 for (int i = 0; i < seckillGoods.getGoodsCount(); i++) {     redisTemplate.opsForList().rightPush(redisKey, String.valueOf(seckillGoods.getId())); } 判断用户是否已经秒杀成功过。// 查询用户是否已经秒杀过该商品 Object orderObj = redisTemplate.opsForHash().get("seckill_orders", seckillUser.getId() + ":" + seckillGoods.getId()); if (orderObj != null) {     throw new SEckillException(ErrorCodeEnum.REPEAT_SEC_KILL_ERROR); } // 查询用户是否在排队中 Object userInQueueObj = redisTemplate.opsForSet().isMember("seckill_queues:" + seckillGoods.getId(), seckillUser.getId()); if (userInQueueObj != null) {     throw new SEckillException(ErrorCodeEnum.WAITING_IN_QUEUE_ERROR); } 利用Redis的事务实现处理抢购成功的逻辑。// 开启事务 redisTemplate.setEnableTransactionSupport(true); redisTemplate.multi(); // 从商品列表中弹出一个商品 redisTemplate.opsForList().leftPop(redisKey); // 利用setValueAt等方法,获取用户信息和商品信息,此处略过 // 判断是否获取到商品信息 if (seckillGoods == null) {     redisTemplate.discard();     throw new SEckillException(ErrorCodeEnum.SEC_KILL_FINISH_ERROR); } // 秒杀成功,生成秒杀订单 redisTemplate.opsForHash().put("seckill_orders", seckillUser.getId() + ":" + seckillGoods.getId(), seckillOrder); // 秒杀成功的商品写入Set中 redisTemplate.opsForSet().add("seckill_success:" + seckillGoods.getId(), String.valueOf(seckillGoods.getId())); // 提交事务 redisTemplate.exec(); 以上代码,通过将Redis事务化实现了秒杀成功时,商品列表从一个元素弹出、将秒杀订单存入Hash中,以及在已秒杀商品集合中添加记录。当秒杀失败时,Redis将自动回滚整个事务。2. 前端页面实现秒杀在前端页面中,我们需要使用Vue同时发送两个请求,一个请求用于获取商品详情,另一个请求用于提交秒杀订单。具体实现方式如下:获取商品详情。created() {     // 发送请求获取商品详情信息     axios.get('/seckill/goods/' + this.$route.params.id)         .then(res => {             this.goods = res.data;         })         .catch(err => {             console.log(err);         }) } 提交秒杀订单。seckill() {     // 发送秒杀请求     axios.post('/seckill/order/' + this.goods.id)         .then(res => {             if (res.data.code == 200) {                 alert('秒杀成功!');             } else {                 alert(res.data.msg);             }         })         .catch(err => {             console.log(err);         }) } 以上代码,通过使用Axios向后端发送商品详情和秒杀请求来实现秒杀功能。步骤三:优化Redis性能在实际的项目中,我们需要考虑如何优化Redis性能。以下是一些优化配置方案:增加Redis实例的数量以提高可用性和性能。设置Redis缓存的过期时间,防止内存泄漏和Redis存储空间的浪费。使用Redis的集群功能,将数据分散在多个Redis节点上,以提高Redis的容错性。技术讲解接下来,让我们来更加详细地讲解一下这个项目的实现技术和原理。Redis的List类型在实现商品秒杀时,我们需要用到Redis的List类型来存储待秒杀的商品ID,以及使用左边出队和右边进队等操作来模拟抢购的过程。Redis的List类型是一个双向链表结构,可以在头部、尾部、任意位置插入、删除数据。使用List类型可以实现类似队列和栈的功能。以下是使用Redis的List类型的一些命令:LPUSH:在列表的左边插入一个或多个元素。RPUSH:在列表的右边插入一个或多个元素。LPOP:从列表的左边移除并返回一个元素。RPOP:从列表的右边移除并返回一个元素。LINDEX:返回列表中指定索引位置的元素。Redis的Set类型在实现商品秒杀时,我们还需要使用Redis的Set类型来存储已经秒杀成功的商品ID。Redis的Set类型是一个无序集合,可以存储多个字符串类型的元素。Set类型支持去重和集合操作。以下是使用Redis的Set类型的一些命令:SADD:将一个或多个元素添加到集合中。SREM:从集合中移除给定元素。SCARD:返回集合的元素数量。SMEMBERS:返回集合中的所有元素。SISMEMBER:判断元素是否在集合中。Redis的Hash类型在实现商品秒杀时,我们还需要使用Redis的Hash类型来存储每个用户的秒杀订单信息。Redis的Hash类型是一个字典结构,可以在O(1)时间内存储、修改和查询元素。以下是使用Redis的Hash类型的一些命令:HSET:设置哈希表中指定字段的值。HGET:获取哈希表中指定字段的值。HGETALL:获取哈希表中所有字段和值。HDEL:删除哈希表中一个或多个字段。HEXISTS:判断哈希表中指定字段是否存在。在实现商品秒杀时,我们需要保证秒杀成功时商品列表中需要弹出一个元素、同时将秒杀订单信息存入Hash中,并且在已秒杀商品集合中添加记录。为了保证这三个操作同时完成,我们需要使用Redis的事务来保证原子性。Redis的事务是一组命令的集合,这些命令会被一次性、按照顺序地执行。在执行事务期间,其他客户端的操作不会干扰该事务的执行。以下是使用Redis事务的一些命令:MULTI:开启事务。EXEC:提交事务,执行事务中的所有命令。DISCARD:撤销事务。Mybatis-plus在本项目中,我们使用了Mybatis-plus作为ORM框架来操作数据库。Mybatis-plus是Mybatis的增强版本,可以大幅度提高开发效率。Mybatis-plus的一些特点如下:无需编写Mapper接口,可以使用自动生成的通用Mapper接口对数据库进行操作。支持Lambda表达式,可改善代码可读性。丰富的查询条件API,支持链式调用。本项目中用到的一些Mybatis-plus的注解如下:@TableName:指定实体类对应的数据库表名。@TableField:指定实体类字段对应的数据库列名。@Autowired:在Spring中自动装配需要使用的Bean。开发流程开发流程如下:准备项目环境,包括SpringBoot、Redis、Mybatis-plus、Vue等组件。在数据库中创建秒杀商品表seckill_goods,并添加一些测试数据。根据实际需求,在后端代码中实现商品秒杀功能,其中需要用到Redis的List、Set和Hash类型,以及使用Redis事务保证原子性。在前端页面中使用Vue,向后端发送商品详情和秒杀请求,实现商品秒杀。优化Redis性能,增加Redis实例的数量、设置缓存过期时间和使用Redis集群等方式。测试和部署项目。Redis的事务​​​​​​​
  • [技术干货] Redis中的两种持久化方案:RDB与AOF
    前言Redis,作为一种高性能的键值对数据库,被广泛应用于各种场景中。然而,由于其数据存储在内存中,一旦Redis服务器发生宕机或故障,数据将会丢失。为了解决这个问题,Redis提供了两种持久化方案:RDB(Redis DataBase)和AOF(Append Only File)。本文将深入探讨这两种持久化方案的区别,并给出何时使用哪种的建议。1. RDB持久化RDB持久化通过生成数据快照的方式,将某一时刻的Redis数据持久化到磁盘中。Redis会定期(如每隔一段时间或当数据达到一定数量)执行一次快照操作,生成一个二进制的RDB文件。当Redis重启时,会加载这个RDB文件来恢复数据。优势:RDB文件紧凑,适合用于数据备份和传输。数据恢复速度快,因为Redis只需要加载RDB文件到内存中即可。在某些场景下,如数据集较大且变化不频繁时,RDB能提供较好的性能。劣势:RDB是定时生成快照的,因此可能会丢失最近一次快照之后的数据。在数据频繁更新的场景下,RDB可能会带来较大的性能开销,因为每次生成快照都需要遍历整个数据集。2. AOF持久化AOF持久化通过记录服务器接收到的所有写操作命令,将这些命令以文本形式追加到一个AOF文件中。当Redis重启时,会重新执行AOF文件中的命令来恢复数据。优势:AOF提供了更高的数据安全性,因为即使Redis宕机,也只会丢失最近一次写入命令之后的数据。AOF文件易于理解和解析,方便进行故障排查和数据恢复。在数据频繁更新的场景下,AOF的性能开销相对较小,因为它只记录变化的命令,而不是整个数据集。劣势:AOF文件通常比RDB文件大,因为AOF记录了所有的写操作命令。数据恢复速度相对较慢,因为Redis需要逐条执行AOF文件中的命令来恢复数据。何时使用RDB,何时使用AOF?选择哪种持久化方案,取决于你的具体需求和场景。以下是一些建议:如果你更关心数据的安全性,希望尽可能减少数据丢失的风险,那么AOF是一个更好的选择。因为AOF记录了所有的写操作命令,即使Redis宕机,也只会丢失最近一次写入命令之后的数据。如果你更关心数据恢复的速度,希望在Redis重启时能够尽快恢复数据,那么RDB可能更适合你。因为RDB文件紧凑,加载速度快,可以更快地恢复数据。你也可以同时开启RDB和AOF两种持久化方式,以实现更高的数据安全性和更快的数据恢复速度。但需要注意的是,这会增加磁盘空间的占用和性能开销。总之,RDB和AOF各有优缺点,选择哪种持久化方案取决于你的具体需求和场景。在实际应用中,建议根据实际情况进行选择和调整,以达到最佳的数据安全性和性能平衡。
  • [技术干货] 如何防止Redis数据丢失
    Redis定义Redis是一种高性能的键值对数据库,广泛应用于各种场景,如缓存、消息队列、计数器等。然而,由于其内存存储的特性,数据丢失的风险始终存在。为了保障数据安全,我们需要采取一系列措施来防止Redis数据丢失。1. 持久化Redis提供了两种持久化方式:RDB(Redis DataBase)和AOF(Append Only File)。RDB:通过定时快照的方式,将某一时刻的数据持久化到磁盘。这种方式在数据恢复时速度较快,但可能会丢失最近一次快照之后的数据。AOF:记录服务器接收到的所有写操作命令,并在服务器启动时,通过重新执行这些命令来恢复数据。这种方式数据安全性更高,但恢复速度较慢。在实际应用中,我们可以结合两种持久化方式,既保证数据的安全性,又尽量提高数据恢复的速度。2. 备份与恢复除了Redis自身的持久化机制外,我们还需要定期进行数据备份,以防止硬件故障、自然灾害等不可预见因素导致的数据丢失。备份时,应将RDB和AOF文件都进行备份,并存储在安全可靠的地方。当数据丢失时,可以通过以下步骤进行恢复:停止Redis服务。清除当前的数据文件(谨慎操作,以防误删)。从备份中恢复RDB和AOF文件。重新启动Redis服务,数据将自动从备份文件中恢复。3. 监控与告警为了确保Redis的稳定运行,我们需要实时监控Redis的各项指标,如内存使用情况、连接数、命令执行速度等。当发现异常时,应及时进行排查和处理。同时,我们可以设置告警机制,当Redis的关键指标超过预设阈值时,自动发送告警通知给管理员,以便及时处理问题。4. 灾备与容灾为了应对可能发生的灾难性事件,我们需要制定灾备和容灾策略。这包括在不同地理位置部署多个Redis实例,实现数据的冗余备份和容错处理。当某个实例发生故障时,可以迅速切换到其他实例,保障业务的连续性。5. 安全防护为了防止恶意攻击或误操作导致的数据丢失,我们需要加强Redis的安全防护。这包括设置强密码、限制访问权限、禁用不必要的命令等。同时,定期审计和检查Redis的访问日志,及时发现和处理潜在的安全风险。总之,防止Redis数据丢失需要我们从多个方面入手,包括持久化、备份与恢复、监控与告警、灾备与容灾以及安全防护等。只有综合考虑这些因素,才能确保Redis数据的安全性和可靠性。
  • [技术干货] Redis 缓存雪崩的原因以及解决方案总结
    缓存雪崩缓存雪崩是指大量的应用请求无法在 Redis 缓存中进行处理,紧接着,应用将大量请求发送到数据库层,导致数据库层的压力激增。两个原因:原因一、缓存中有大量数据同时过期,导致大量请求无法得到处理。 具体来说,当数据保存在缓存中,并且设置了过期时间时,如果在某一个时刻,大量数据同时过期,此时,应用再访问这些数据的话,就会发生缓存缺失。紧接着,应用就会把请求发送给数据库,从数据库中读取数据。如果应用的并发请求量很大,那么数据库的压力也就很大,这会进一步影响到数据库的其他正常业务请求处理。 一般来说,一个 Redis 实例可以支持数万级别的请求处理吞吐量,而单个数据库可能只能支持数千级别的请求处理吞吐量,它们两个的处理能力可能相差了近十倍。由于缓存雪崩,Redis 缓存失效,所以,数据库就可能要承受近十倍的请求压力,从而因为压力过大而崩溃。解决方法:1、避免给大量的数据设置相同的过期时间,设置随机的过期时间 可以避免给大量的数据设置相同的过期时间。如果业务层的确要求有些数据同时失效,你可以在用 EXPIRE 命令给每个数据设置过期时间时,给这些数据的过期时间增加一个较小的随机数(例如,随机增加 1~3 分钟),这样一来,不同数据的过期时间有所差别,但差别又不会太大,既避免了大量数据同时过期,同时也保证了这些数据基本在相近的时间失效,仍然能满足业务需求2、通过服务降级(针对不同的数据采取不同的处理方式) 当业务应用访问的是非核心数据(例如电商商品属性)时,暂时停止从缓存中查询这些数据,而是直接返回预定义信息、空值或是错误信息;当业务应用访问的是核心数据(例如电商商品库存)时,仍然允许查询缓存,如果缓存缺失,也可以继续通过数据库读取。原因二、Redis 缓存实例发生故障宕机了解决方法:1、在业务系统中实现服务熔断(暂停业务应用对缓存系统的接口访问) 所谓的服务熔断,是指在发生缓存雪崩时,为了防止引发连锁的数据库雪崩,甚至是整个系统的崩溃,我们暂停业务应用对缓存系统的接口访问。再具体点说,就是业务应用调用缓存接口时,缓存客户端并不把请求发给 Redis 缓存实例,而是直接返回,等到 Redis 缓存实例重新恢复服务后,再允许应用请求发送到缓存系统。这样一来,我们就避免了大量请求因缓存缺失,而积压到数据库系统,保证了数据库系统的正常运行。2、请求限流机制(请求入口前端控制每秒进入系统的请求数) 服务熔断虽然可以保证数据库的正常运行,但是暂停了整个缓存系统的访问,对业务应用的影响范围大。为了尽可能减少这种影响,我们也可以进行请求限流。这里说的请求限流,就是指,我们在业务系统的请求入口前端控制每秒进入系统的请求数,避免过多的请求被发送到数据库。我给你举个例子。假设业务系统正常运行时,请求入口前端允许每秒进入系统的请求是 1 万个,其中,9000 个请求都能在缓存系统中进行处理,只有 1000 个请求会被应用发送到数据库进行处理。一旦发生了缓存雪崩,数据库的每秒请求数突然增加到每秒 1 万个,此时,我们就可以启动请求限流机制,在请求入口前端只允许每秒进入系统的请求数为 1000 个,再多的请求就会在入口前端被直接拒绝服务。所以,使用了请求限流,就可以避免大量并发请求压力传递到数据库层。使用服务熔断或是请求限流机制,来应对 Redis 实例宕机导致的缓存雪崩问题,是属于“事后诸葛亮”,也就是已经发生缓存雪崩了,我们使用这两个机制,来降低雪崩对数据库和整个业务系统的影响。3、事前预防(Redis缓存主从集群) 通过主从节点的方式构建 Redis 缓存高可靠集群。如果 Redis 缓存的主节点故障宕机了,从节点还可以切换成为主节点,继续提供缓存服务,避免了由于缓存实例宕机而导致的缓存雪崩问题。缓存雪崩是发生在大量数据同时失效的场景下,而接下来我要向你介绍的缓存击穿,是发生在某个热点数据失效的场景下。和缓存雪崩相比,缓存击穿失效的数据数量要小很多,应对方法也不一样,我们来看下。
  • [其他] redis内长过期时间的key对redis的性能影响
     **大量设置长过期时间的key会对Redis的性能产生影响**。  首先,当Redis中有大量设置了长过期时间的key时,Redis需要定期检查这些key是否到期,以便及时清理。这个过程会占用额外的CPU和内存资源,因为Redis需要在后台执行过期检查和清理操作。如果key的数量非常多,这种检查和清理可能会变得频繁,从而对Redis的性能造成影响。  其次,长过期时间的key在存储时会占用更多的内存空间。这是因为每个key都需要维护一些元数据,包括过期时间等信息。如果key的长度很长,那么它们占用的内存也会更多,这可能导致内存使用效率降低,进而影响Redis的性能。  再者,在删除过期key时,Redis采用了一种采样删除的策略。默认情况下,即使过期key的数量超过了总数的25%,也不会完全阻塞Redis服务器。但是,这种采样删除会导致周期性的短暂阻塞,例如每25毫秒阻塞5毫秒来执行删除操作,这也可能在一定程度上影响Redis的响应时间和性能。  最后,大量的key不仅会影响过期检查和清理的性能,还会影响Redis执行其他操作时的性能。例如,当Redis需要对数据库中的键进行查找、更新或删除操作时,键的数量越多,所需的时间就越长,这可能导致性能下降。  综上所述,为了优化性能,可以考虑定期清理不再需要的key,或者使用更合理的数据结构来减少单个key的大小和数量。此外,合理配置Redis的内存回收策略和过期策略也是提高性能的重要措施。 
  • [其他] redis的putobject和removeobject的效率对比
     Redis是一种高性能的键值存储系统,广泛应用于缓存、数据库、消息队列等场景。在Redis中,putObject和removeObject是两个常用的操作,分别用于向Redis中添加数据和删除数据。本文将对这两个操作的效率进行对比分析。  1. putObject操作  putObject操作用于向Redis中添加数据。当执行putObject操作时,Redis会将数据存储在内存中,并根据配置将其持久化到磁盘上。putObject操作的时间复杂度为O(1),即无论数据量大小,执行时间都保持不变。  2. removeObject操作  removeObject操作用于从Redis中删除数据。当执行removeObject操作时,Redis会从内存中移除对应的数据,并根据配置将其从磁盘上删除。removeObject操作的时间复杂度同样为O(1),即无论数据量大小,执行时间都保持不变。  3. 效率对比  从上述分析可以看出,putObject和removeObject操作的时间复杂度都是O(1),因此它们的执行效率相差无几。然而,在实际使用中,它们的效率可能会受到以下因素的影响:  - 内存占用:putObject操作需要将数据存储在内存中,而removeObject操作则需要从内存中移除数据。因此,如果内存资源有限,putObject操作可能会导致内存不足,从而影响其效率。相反,removeObject操作可以释放内存资源,提高系统性能。  - 磁盘I/O:根据配置,putObject和removeObject操作都可能涉及到磁盘I/O。磁盘I/O通常比内存操作慢得多,因此,如果磁盘I/O成为瓶颈,它们的效率可能会受到影响。  - 网络延迟:如果Redis服务器和客户端之间的网络延迟较大,那么putObject和removeObject操作的效率可能会受到网络延迟的影响。  综上所述,putObject和removeObject操作在时间复杂度上相差无几,但在实际使用中,它们的效率可能会受到内存占用、磁盘I/O和网络延迟等因素的影响。为了提高Redis的性能,可以采取以下措施:  - 优化内存使用:合理分配内存资源,避免内存不足的情况发生。  - 优化磁盘I/O:选择合适的持久化策略,平衡性能和数据安全性。  - 优化网络连接:尽量将Redis服务器部署在离客户端较近的位置,减小网络延迟。 
  • [专题汇总] 12月份CodeArts板块技术干货合集,提前放送。
     随着鸿蒙系统的愈发壮大,鸿蒙知识的学习也就变得越发迫切。本月给大家带来的技术干货合集就包括鸿蒙,spring,springboot,java,nginx,redis等众多内容,希望可以帮到大家。  1.Centos搭建KMS(vlmcsd)激活服务器的步骤【转】 https://bbs.huaweicloud.com/forum/thread-0251137381864278028-1-1.html  2.鸿蒙极速入门(一)-HarmonyOS简介 https://bbs.huaweicloud.com/forum/thread-0217137149871563005-1-1.html  3.鸿蒙极速入门(二)-开发准备和HelloWorld https://bbs.huaweicloud.com/forum/thread-0212137150055432004-1-1.html  4.鸿蒙极速入门(三)-TypeScript语言简介 https://bbs.huaweicloud.com/forum/thread-0217137150099699006-1-1.html  5.鸿蒙极速入门(四)-通过登录Demo了解ArkTS https://bbs.huaweicloud.com/forum/thread-0212137150569231005-1-1.html  6.鸿蒙极速入门(五)-路由管理(Router) https://bbs.huaweicloud.com/forum/thread-0217137150812608007-1-1.html      7.HarmonyOS 实战项目 https://bbs.huaweicloud.com/forum/thread-0298137147742910003-1-1.html  8.HarmonyOS 高级特性 https://bbs.huaweicloud.com/forum/thread-0263137147693666005-1-1.html  9.HarmonyOS应用开发 https://bbs.huaweicloud.com/forum/thread-02125137147620736007-1-1.html  10.HarmonyOS UI 开发 https://bbs.huaweicloud.com/forum/thread-0251137147552748004-1-1.html  11.准备HarmonyOS开发环境 https://bbs.huaweicloud.com/forum/thread-0217137147386754003-1-1.html  12.Nginx服务器安装配置SSL证书流程(实现HTTPS安装) https://bbs.huaweicloud.com/forum/thread-0224137038725392014-1-1.html  13.几款值得选的SSH客户端软件 https://bbs.huaweicloud.com/forum/thread-02107137038433887013-1-1.html  14.8个站酷免费字体且可商用 不担心字体版权 https://bbs.huaweicloud.com/forum/thread-0235137038369347011-1-1.html  15.7个加速搜索引擎收录网站实用有效方法 https://bbs.huaweicloud.com/forum/thread-02112137038294122014-1-1.html  16. Java 算法篇-深入理解递归(递归实现:青蛙爬楼梯)-转载 https://bbs.huaweicloud.com/forum/thread-0213136969605169006-1-1.html  17.【内网穿透】搭建我的世界Java版服务器,公网远程联机-转载 https://bbs.huaweicloud.com/forum/thread-02112136969569637009-1-1.html  18.【Nginx篇】Nginx轻松上手-转载 https://bbs.huaweicloud.com/forum/thread-0213136969448107005-1-1.html  19.【SpringBoot(IDEA)+Vue(Vscode)前后端交互】-转载 https://bbs.huaweicloud.com/forum/thread-02107136969215321009-1-1.html  20.【SpringBoot】| SpringBoot 集成 Redis-转载 https://bbs.huaweicloud.com/forum/thread-0240136952804547006-1-1.html  21.基于SpringBoot的个人博客管理系统的设计与实现 毕业设计开题报告-转载 https://bbs.huaweicloud.com/forum/thread-02112136952724159004-1-1.html  22.【SpringBoot篇】Spring_Task定时任务框架-转载 https://bbs.huaweicloud.com/forum/thread-02127136952689543005-1-1.html  23.【SpringCloud】Eureka基于Ribbon负载均衡的调用链路流程分析-转载 https://bbs.huaweicloud.com/forum/thread-0224136952632959005-1-1.html  24. Spring Boot单元测试-转载 https://bbs.huaweicloud.com/forum/thread-0213136952529904002-1-1.html  25.【Springboot系列】SpringBoot整合Jpa-转载 https://bbs.huaweicloud.com/forum/thread-0240136952500264005-1-1.html  26. Spring Boot + MyBatis-Plus实现数据库读写分离 -转载 https://bbs.huaweicloud.com/forum/thread-02107136952426802006-1-1.html 
  • [技术干货] Redis 搭建集群
    redis集群的优缺点Redis集群的优点包括:数据分散:Redis集群可以将数据分散到多个节点上,提高了数据的可靠性和可用性。扩展性强:Redis集群可以方便地进行扩展,通过增加节点的方式来提高系统的性能和容量,以满足不断增长的业务需求。读写分离:Redis集群可以实现读写分离,提高系统的并发作业能力和性能。高可用性:Redis集群可以避免单节点故障的问题,当一个节点宕机时,系统仍然可以正常运行。Redis集群的缺点包括:复杂性:Redis集群的搭建和管理相对复杂,需要专业的知识和技能。数据一致性:Redis集群的数据复制是异步的,不保证数据的强一致性,可能会存在数据不一致的情况。客户端实现:Redis集群的客户端实现相对复杂,需要处理节点的连接和通信等问题。资源隔离性:Redis集群的节点之间数据共享,不能很好地进行资源隔离,可能会互相影响。负载均衡:Redis集群的负载均衡机制不够完善,可能会存在某些节点负载较重的情况。redis集群的搭建方式要搭建Redis集群,可以按照以下步骤进行:创建几台虚拟机(集群模式最少要三个主节点),或者在同一台主机上创建多个Redis实例,使用不同的端口模拟不同的主机。这些实例将作为Redis集群的节点。在每台主机上安装Redis,并确保配置文件中的cluster-enabled选项已启用,表示开启集群模式。此外,还需要根据实际情况修改其他配置项,如超时时间等。Redis安装完成后,需要执行创建集群的命令。具体的命令可能会因Redis版本而异。对于Redis 5,可以使用redis-cli --cluster命令来创建集群。在此之前,需要通过redis-trib.rb工具进行集群创建和配置。创建集群时,需要指定主节点的数量和对应的从节点数量。例如,可以创建一个包含三个主节点和每个主节点对应一个从节点的集群,以确保高可用性。在集群运行过程中,如果一个主节点宕机,Redis会自动将从节点升级为主节点,以保证整个集群的可用性。redis集群监控工具Redis集群监控工具可以使用Redis自带的命令行工具redis-cli以及第三方的监控工具,比如:Redis自带的命令行工具redis-cli:可以用来监控Redis集群的状态和运行情况,包括查看集群节点数量、连接情况、内存使用情况等等。RedisLive:是一款免费开源的基于Python和tornado的Redis监控工具,以WEB的形式展现出Redis中的内存、key、实例数据等信息。Redis-Sentinel:是Redis的作者Antirez在今年6月份完成的,因为Redis实例在各个大公司的应用,每个公司都需要一个Redis集群的管理工具,被迫都自己写管理工具来管理Redis集群,Antirez考虑到社区的急迫需要,花了几个星期写出了Redis-Sentinel。Redis-Sentinel的三大功能:监测、通知、自动故障恢复。