大明哥 大明哥

程序员、死磕 Java 创始人

死磕 Java 大明哥精心打造的 Java 进阶类系列教程,希望大家少走弯路。 更多死磕系列

  • Java现在发布的版本很快,每年两个,但是真正会被大规模使用的是3年一个的LTS版本。每3年发布一个LTS(Long-TermSupport),长期维护版本。意味着只有Java8,Java11,Java17,Java21才可能被大规模使用。每年发布两个正式版本,分别是3月份和9月份。在Java版本中,一个特性的发布都会经历孵化阶段、预览阶段和正式版本。其中孵化和预览可能会跨越多个Java版本。所以大明哥在介绍Java新特性时采用如下这种策略:每个版本的新特性,大明哥都会做一个简单的概述。单独出文介绍跟编码相关的新特性,一些如JVM、性能优化的新特性不单独出文介绍。孵化阶段的新特性不出文介绍。首

    2023-12-24
    阅读(1669)
  • 又到年底了,又是好多小伙伴主动或者被动找工作的时候了,最近好多小伙伴,都问我有没有最新面试题,有!!肯定有!!我就把我看过的和整理过的面试题,以答案都整理好,整理了目前最新版的《互联网大厂面试题》,涵盖了所有的Java面试题,并且为了各位小伙伴更好地有针对性地刷题,大明哥按照技术类别将面试题分了类,包括:Java基础、Java并发、Spring、SpringBoot、设计模式、Redis、Kafka等等共25个分类,99个PDF文件。面试题:25个文件夹99个PDF,包括Java集合、JVM、多线程、并发编程、设计模式、Java、MyBatis、ZooKeeper、Dubbo、Elastics

    2023-12-06
    阅读(1081)
  • 上一个死磕Java专栏【死磕NIO】(当然写的不是很好,争取今年将它重写一遍)是**【死磕Netty】**的铺垫,对于我们Java程序员而言,我们在实际开发过程一般都不会直接使用JavaNIO作为我们的网络编程框架,因为写出一套高质量的JavaNIO程序并不是一件容易的事,除了JavaNIO固有的复杂性和bug之外,作为NIO服务端,我们要处理的事情太多了,如网络闪断、客户端认证、消息编解码、半包读写,客户端一样也有很多复杂的事情要处理,所以如果我们对JavaNIO没有足够了解,没有足够的网络编程经验的话,利用JavaNIO来编写一个高性能的稳定网络编程框架并不是一件容易的事。所以我们一般都不

    2023-10-06
    阅读(1597)
  • 回答当Redis内存不足时,我们可以使用如下几个策略来进行优化。一、增加物理内存这是最直观有效的方法,内存不够,那就加内存,而且现在内存便宜。二、使用集群方案使用Redis集群方案将数据分散在多个节点,这样可以有效的解决Redis内存不足问题。为什么需要RedisCluster?它解决了什么问题?三、配置maxmemory-policy和maxmemorymaxmemory用于配置Redis能够使用的最大内存容量,一旦内存使用达到这个限制,Redis就会根据maxmemory-policy指定的策略来处理内存溢出。请描述一下Redis的缓存淘汰策略Redis缓存满了怎么办?四、优化数据结构使用

    2024-05-02
    阅读(12)
  • 回答Redispipeline是Redis的一种优化计划,主要通过减少网络往返次数(RTT)来提高命令执行效率。当我们需要执行多个命令时,如果采取依次调用Redis并等待Redis响应的方式来处理,然而这种一来一回的通信模式在命令多、网络延迟显著的情况下会严重影响应用的性能。采用pipeline会有如下几个显著的优势。减少网络延迟:通过pipeline,可以将多个命令打包后再一起发送,然后接收所有命令的响应。这样只需要一次往返就可以完成多个命令的交互,减少了网络延迟。提高命令吞吐率:因为减少了网络往返次数,可以在更短的时间内执行更多的命令,从而提高了系统的整体命令处理速度。扩展Redis性能瓶

    2024-05-02
    阅读(10)
  • 回答Redis在持久化时有如下几种情况会阻塞Redis服务器。执行SAVE命令:当我们手动执行SAVE命令时,Redis会阻塞所有其他客户端的请求直到RDB快照文件创建完毕。执行BGSAVE命令:虽然BGSAVE是在一个子进程中进行的,在创建RDB快照文件过程中,主进程依然可以继续响应客户端请求。但是在执行BGSAVE命令后,主进程需要进行一次fork()操作,fork()操作在内存资源紧张或者数据集较大的情况下可能非常耗时,这期间主进程会被短暂阻塞。重写AOF文件:与BGSAVE命令一样,重写AOF文件(BGREWRITEAOF)也是发生在fork子进程过程中。配置always同步策略:在a

    2024-05-02
    阅读(12)
  • 回答Redis的高性能是我们毋庸置疑的,但是Redis也会存在阻塞的情况,导致整个系统变慢,从而影响用户体验。以下几种场景会导致Redis阻塞。一、慢查询若Redis执行一个命令的时间超过指定的阈值(slowlog-log-slower-than),则Redis会将该命令记录到慢查询日志中。由于Redis执行命令是单线程,如果执行某个命令花费时间比较长,则会阻塞其他命令的执行,如果执行大量的慢查询,则会严重阻碍Redis服务的性能。关于慢查询详情请阅读:了解Redis的慢查询吗?二、操作大key大key是指key对应的value很大。大key可能导致Redis阻塞的情况有两种:超时阻塞:由于R

    2024-05-02
    阅读(12)
  • 回答Redis的慢查询是一个记录查询执行时间超过指定阈值的查询命令的功能。它的工作原理是:当一个命令的执行时间超过slowlog-log-slower-than设置的阈值时,该命令就会被记录到慢查询日志中。日志中详细记录了慢查询发生的时间、执行时长、具体什么命令等信息。它有两个参数:slowlog-log-slower-than:慢查询阈值,单位为微秒,当命令执行时间超过这个阈值时,命令会被记录到慢查询日志中。如果该值设置为负数,则会关闭Redis慢查询功能。slowlog-max-len:慢查询日志长度,用于限制慢查询日志的大小,防止消耗过多内存。慢查询日志是一个先进先出队列,当新的慢查询产

    2024-05-02
    阅读(11)
  • 回答在Redis生产环境中我们是禁止使用KEYS命令的。因为KEYS命令它会返回所有匹配的key,Redis在执行该命令时会扫描整个键空间来匹配该模式下的所有key,这个操作的时间复杂度为O(N),N表示Redis中key的总数,这意味如果在Redis中的key非常多的情况下,KEYS命令的执行可能会非常慢。同时,由于Redis是单线程的,当它在执行KEYS命令时,它会阻塞其他所有命令的执行,这会严重拖慢整个服务的吞吐量。扩展使用Scan代替keysSCAN命令是KEYS命令的一个安全替代品。SCAN命令不像KEYS一次性锁定Redis整个key空间,而是采用逐步迭代Redis中的key,每次

    2024-05-02
    阅读(13)
  • 回答Redis通过一个叫做过期字典(可以看作是hash表)来保存数据过期的时间。当我们为一个key设置过期时间,例如SETsikesike-javaEX100,Redis会在国企字典中添加一个题目,其中key指向该键(sike),value是当前时间加上指定的秒数(转换成的Unix时间戳)。数据结构如下:typedefstructredisDb{...dict*dict;//数据库键空间,保存着数据库中所有键值对dict*expires//过期字典,保存着键的过期时间...}redisDb;我们知道Redis的过期数据删除分为两种策略:惰性删除和定时删除。惰性删除:每次访问某个key时,Red

    2024-05-02
    阅读(10)
  • 回答虽然Redis最常用的用途是作为内存使用,提供高性能的缓存解决方案。但是它的功能远不止于此,以下是Redis除了作为缓存外的常见应用场景。一、消息队列Redis支持发布/订阅模式,可以用作消息队列来处理异步任务或实现系统间的消息传递。生产者通过PUBLISH命令向特定频道发布消息。消费者使用SUBSCRIBE命令订阅一个或多个频道,订阅频道后,消费者便可以接收到所有发送到该频道的消息。详细情况请阅读:怎么使用Redis实现一个消息队列二、计数器Redis的命令是原子性的,所以它非常适合用作计数器,比如网站访问统计、在线活动的用户数统计或社交媒体中的点赞和评论计数。Redis提供了四个命令来

    2024-05-02
    阅读(4)
  • 回答RedisCluster中采用哈希槽而不是一致性hash算法,主要原因是为了简化节点的管理和数据的迁移。一、故障转移在RedisCluster中,每个Master节点都有一个或多个Slave节点,Slave节点会复制Master节点的数据。当Master节点出现故障时,Slave节点会被迅速提升Master节点,接管Master节点负责的哈希槽和数据,继续提供服务。而一致性哈希算法是没有Master-Slaver的概念的,当一个节点失败时,其负责的数据会自动转移到哈希环中的下一个节点,虽然这种方案是可行的,但是还是存在一些问题的:数据重分配代价高:数据迁移到下一个节点,原节点的数据需要在下

    2024-05-02
    阅读(10)
  • 回答可以提供服务。RedisCluster扩容、缩容的本质其实是slot的迁移。在slot迁移过程,如果客户端给当前Redis节点发送请求,则有两种情况:如果该key所对应的slot还在当前Redis节点,则直接处理,并返回处理结果。如果该key所对应的slot还在迁移过程中,则该节点返回一个ASK重定向错误,告诉客户端该请求对应的slot正在进行迁移,请去目标节点发送请求吧。客户端接受ASK响应后,则先向目标节点发送一个ASKING指令,告诉目标节点,接下来的这条指令,你必须执行,然后紧接着发送原请求。如果该key所对应的slot不在当前Redis节点,或者已经被迁移到其他目标节点了,则该节

    2024-05-02
    阅读(12)
  • 回答RedisCluster中节点间采用Gossip(流言)协议进行通信。Gossip协议不需要集群中的所有节点都完全了解集群中每一个节点的详细信息,它的核心在于通过节点间的随机交换信息来实现整个集群中各节点的信息的最终一致性。在RedisCluster中,所有节点都持有一份数据,如果某个节点出现了数据变更,则该节点会把数据不断地发送给其他节点,其他节点接收到信息后进行数据变更,一段时间后,整个RedisCluster集群中的所有节点都会完成数据变更,从而保证整个集群所有节点的数据都是完整的。扩展每个节点都有一个专门用于节点间通信的端口号,就是自己提供服务的端口号+10000。每个节点会定期向

    2024-05-02
    阅读(11)
  • 回答RedisCluster采用的是一种基于Raft的选举算法,且使用Gossip协议来进行节点间的信息交换,包括节点状态的更新。整个选举过程分为如下几个步骤:故障发现在RedisCluster,每个节点都会定期向其他节点发送心跳数据(PING),如果一个主节点在指定时间内没有响应PING,那么首先发现这一情况的节点会认为该主节点可能失效了,并开始向其他节点发送带有故障主节点的FAIL消息。选举触发当超过半数的节点确认收到关于同一个主节点的FAIL消息,该主节点会被RedisCluster标记为FAIL。一旦主节点被标注为FAIL,则该主节点中的从节点会触发选举机制,共同竞争成为Master节

    2024-05-02
    阅读(12)
  • 回答一、保证足够的容错性和高可用性RedisCluster的设计目标就是保证Redis集群中即使部分节点失败的情况下仍然能保证整个集群的稳定运行。如果只有两个主节点,一旦其中一个主节点失败,那么整个集群的压力就全部集中到一个节点上了,而该节点可能因为无法承担全部的数据和请求而导致奔溃。至少三个主节点,一个主节点失败,其余主节点依然可以通过互相协作来继续提供服务。二、选举和决策的一致性在RedisCluster中,主节点使用Raft算法进行故障检测和Master选举。而Raft算法要求多数节点存活来保持集群状态的一致性和决策的有效性,即新Master的选举需要大于半数的集群Master节点同意才

    2024-05-02
    阅读(11)
  • 回答在RedisCluster中,客户端请求路由有三种:MOVED重定向:MOVED重定向是最常见的路由方式。当客户端向任意Redis节点发送请求,如果该节点不负责该请求的槽,则它会返回一个MOVED错误,附带正确节点的地址(目标节点),则客户端向目标节点发送请求。ASK重定向:ASK重定向用于RedisCluster正在进行哈希槽重分配过程的一种临时方案。当一个哈希槽正在从一个节点迁移到另外一个节点,而客户端发送的请求恰好落在这个迁移的哈希槽上,则源节点会返回一个ASK错误,指示客户端这个请求应临时发送到目标节点。Smart客户端:Smart客户端会独立维护一份集群的节点和哈希槽映射表,并能

    2024-05-02
    阅读(12)
  • 回答RedisCluster采用分片(sharding)的方式来提供数据的水平扩展能力。RedisCluster使用哈希槽来分配数据到不同的节点。每个key通过CRC16算法得到一个哈希值,然后根据这个哈希值来确定key应该被放置在哪个哈希槽中。RedisCluster一共有16384个哈希槽,每个节点负责管理一部分哈希槽。假如有三个Redis节点,那么第一个节点负责0~5460,第二个节点负责5461~10922,第三个节点负责10923~16383。当一个客户端尝试访问一个key时,同样使用CRC16算法来确定访问的key在哪一个哈希槽中,然后直接连接到负责该槽的节点。客户端请求路由目前主

    2024-05-02
    阅读(13)
  • 回答在RedisCluster中,数据的分布是通过哈希槽来实现的。Redis将所有的key"均匀"地分布在16384个哈希槽中,当我们使用某个key进行操作时,需要先确认该key是属于哪个哈希槽,然后再去进行操作。Redis采用CRC16算法对key进行哈希计算,然后将得到的哈希值与16383进行位与运算(hash%16384),这样就可以确保key被均匀地分布在0~16383这些槽位之间。hash_slot=CRC16(key)mod16384扩展CRC16CRC16(CyclicRedundancyCheck16bit)即循环冗余校验码,是一种常用的校验算法,主要用于数

    2024-05-02
    阅读(12)
  • 回答RedisCluster是Redis的一种分布式解决方案,它通过分片(sharding)来进行数据管理(「分治思想」的一种实践),并提供复制和故障转移的功能。Redis开始时只有一个Master主节点,为了提升Redis数据的可靠性,升级了主从模式。但是,这样无法解决Redis服务的可靠性。后面,加入了哨兵模式,提升了Redis的可靠性。不过,无论是主从模型还是加入了哨兵模式,处理命令的永远都是一个Master节点,Master节点里面存储了所有的数据,这样就面临两个问题:如果数据太多,导致内存暴增,会导致单一的Master节点无法加载所有的数据。Master节点在并发较高的情况下,会因为

    2024-05-02
    阅读(14)
  • 回答Redis持久化有两种:RDB和AOF。RDB:是将Redis在某个时间点的数据快照写入磁盘。AOF:是将Redis执行的每个命令追加到文件中。大key就意味着value数据比计较大,则他会对Redis持久化产生如下几个影响。一、内存和CPU使用增加在执行RDB生成快照文件时和AOF重写时,Redis需要处理Redis内存中的所有数据,如果存在大key,那么在这个处理过程中会消耗更多的内存和CPU资源。同时,AOF文件中包含了Redis执行的每一条命令,如果大key变更频繁,会导致AOF文件迅速增大,严重影响存储效率。尤其是在处理AOF重写机制时,如果有大key需要重写,那么将对CPU和磁

    2024-05-02
    阅读(12)
  • 回答缓存预热是指在系统启动之前或者高峰来临之前,提前将热点数据加载到缓存中的过程。缓存预热的目的是为了提高缓存命中率和系统的响应速度。一般来说缓存预热有如下几个作用:提高响应速度:预先将热点数据加载到缓存中,可以确保用户在实际访问时,能够从缓存中快速获取数据,从而提高系统响应速度。避免冷启动问题:系统启动后,缓存中是没有数据的,这被称之为冷启动。面对用户请求时,请求直达数据库,如果请求量较大,则会加大数据库压力。缓存预热提前将数据加载进缓存中可以避免请求直达数据库。平滑流量高峰:在流量高峰来临之前,将热点数据加载进缓存可以使系统能够更加从容地应对流量高峰,避免因为突然的流量增加而影响系统性能。

    2024-05-02
    阅读(6)
  • 回答缓存穿透是指请求一个根本不存在的数据(不在缓存中也不在数据库中),由于数据在数据库也不存在所以就无法加载到缓存中,这就导致这个不存在的数据每次请求都要到数据库里面去查询,给数据库带来了不必要的访问压力。如果这类请求非常频繁,这会严重影响数据库的性能,甚至会使数据库奔溃。缓存穿透的发生一般是这两种情况业务误操作。比如数据库和缓存中的数据被误删了,导致数据库和缓存中都没有数据了。黑客攻击。比如黑客估计访问大量不存在的业务数据。应对缓存穿透,常见的方案有三种。一、过滤非法请求在API入口增加请求参数的判断,判断参数是否合理、参数中是否有非法值、必要请求字段是否存在等等校验手段,如果判断是恶意请求

    2024-05-02
    阅读(13)
  • 回答缓存击穿属于缓存雪崩的子集,它是指缓存中的某个热点key在缓存中不存在时(比如过期),此时大量请求访问该热点key,由于无法命中缓存,会直接访问数据库,导致数据库压力剧增,严重时甚至会让数据库奔溃。缓存击穿的关键点在于单一热点缓存数据失效,瞬间海量请求压垮数据库。应对缓存击穿的方案和应对缓存雪崩一样,可以采取如下两种方案:设置热点数据永不过期。对于一些访问频率极高的热点数据,我们设置它永不过期,如果有更新的话,就更新缓存数据。使用分布式锁。当业务线程在处理请求时,如果发现访问的数据不在缓存中时,就增加一个分布式锁,然后该业务线程去加载缓存,其他线程由于获取不到分布式锁会被阻塞。具体方案请参

    2024-05-02
    阅读(12)
  • 回答缓存雪崩是指在缓存系统中,由于大量的数据同时过期或者Redis故障宕机时,由于此时Redis无法处理,于是大量请求都落在数据库上,从而导致数据库的压力剧增,甚至会造成数据库奔溃的现象,从而形成一系列连锁反应,造成整个系统崩溃。解决缓存雪崩主要从两个方面着手,由于造成它产生的原因是大量数据同时过期或者Redis服务宕机,所以我们可以从这两个方法来着手。一、大量数据过期设置不同的缓存过期时间。在原有的过期时间上加上一个随机数,这样就会使得缓存的过期时间不会太集中。设置热点数据永不过期。对于一些访问频率极高的热点数据,我们设置它永不过期,如果有更新的话,就更新缓存数据。使用分布式锁。当业务线程在

    2024-05-02
    阅读(12)
  • 回答所谓“热key”是指短时间内被大量访问的某个key。热key问题则是指某个key被大量访问,导致Redis服务压力过大,从而压垮Redis服务的情况。与大key问题相似,解决热key一般分为两个步骤:发现热key发现热key的方式有多种。提前预知。例如在做商品秒杀的时候,很容易就能判断这些参与秒杀的商品的key就是热key。在客户端收集。在访问Redis之前,加一个统计,统计访问key的访问次数,若某个key短时间的访问量大幅度增加,那么该key就是热key。使用Proxy层做收集。在应用程序和Redis之间再增加一次Proxy作为应用程序访问Redis的统一入口,由它来负责key的访问统

    2024-05-02
    阅读(9)
  • 回答当Redis主节点被标注客观下线后,Sentinel会选举出一个Leader来完成故障转移。主要分为如下几个步骤。一、选择新的主节点在执行故障转移过程中,首先需要从从节点中选择出来一个合适的节点当做主节点。选择的标准可以参考下面这篇文章。Sentinel如何选择出新的master?二、晋升主节点当选出最合适的从节点后,Sentinel会向该节点发送SLAVEOFNOONE命令来让它晋升为新的主节点。三、配置更新当从节点晋升为主节点后,Sentinel会更新其它从节点的配置,让它们开始复制新的主节点,命令为:SLAVEOF<new-master-ip><new-master

    2024-05-02
    阅读(7)
  • 回答Sentinel发现master节点客观下线后,会自动开启故障转移流程,选择一个合适的Slave节点晋升为新的Master。这个过程分为筛选备选节点和选择Master两个步骤。一、使用如下条件筛选备选节点Slave节点状态处于S_DOWN、O_DOWN、DISCONNECTED的除外。最近一次ping应答时间不超过5倍ping的间隔。假如ping的间隔为1秒,则最近一次应答延迟不应超过5秒。info_refresh应答不超过3倍info_refresh的间隔。Slave节点与Master节点失去联系的时间不能超过((now-master->s_down_since_time)+(ma

    2024-05-02
    阅读(8)
  • 回答一旦确认主节点客观下线,就需要进行故障转移。这个时候各个Sentinel之间会进行一次选举,选出一个领导者来负责这次的故障转移流程。Sentinel之间通过发送RAFT的投票协议消息来选举领导者。每个Sentinel节点都会给某一个请求它进行投票的Sentinel节点投票,但在整个选举过程中,每个Sentinel只能投一次票。通常情况下,第一个请求投票的Sentinel会获得同意。如果某个Sentinel节点发现自己得到的票数已经超过半数且超过<quorum>,那么它就成为领导者。如果这个过程中有多个Sentinel成为领导者,那么将等待一段时间重新进行选择,直到有且只有一个S

    2024-05-02
    阅读(11)
  • 回答每个Sentinel节点每隔一秒就会向Redis节点发送PING命令,已确认节点是否在线。若一个Sentinel节点在规定时间内(默认是sentineldown-after-milliseconds配置项指定的时间)没有收到被监控Redis节点的响应,它会将该节点标记为主观下线(SDOWN),即该Sentinel节点认为这个Redis节点不可达。当一个Redis节点被标注为主观下线后,由于主观下线是一家之言,会存在误判的情况,所以该Sentinel会向其他Sentinel对该Redis节点的看法,如果超过一定数量(quorum)的Sentinel都认为该Redis节点不可达,那么该节点会被

    2024-05-02
    阅读(7)
  • 回答Sentinel(哨兵)是运行在特殊模式下的Redis服务器。它不支持读写操作,主要作用是配合Redis的主从复制功能,实现对主从节点的监控、对下线的主节点进行故障转移和通知。Sentinel主要有如下几个功能:监控:Sentinel会监控所有Redis节点的状态。自动故障转移:如果Redis主节点无法正常工作,Sentinel可以自动将这个主节点下的一个从节点升级为新的主节点,并让其他从节点指向这个新的主节点。通知:当Sentinel选举了新的主节点后,可以通过API向客户端进行通知。配置提供者:客户端在初始化时,通过连接Sentinel来获得当前Redis服务的主节点地址。监控和自动故

    2024-05-02
    阅读(10)
  • 回答Redis提供了两种持久化方式:RDB和AOF,两种持久化方式对过期键的处理方式不一样。RDB对过期键的处理RDB是Redis内存的快照,它保存Redis在某一时刻的数据状态。当在进行RDB持久化时,Redis会遍历所有键的过期时间,并且不会将已经过期的键写入到RDB文件中。因此,在RDB文件中,不包含过期的键。当Redis从RDB文件恢复时,它加载的数据是快照时刻的有效数据集,不包含过期数据。AOF对过期键的处理对于过期键,AOF的处理方式是:如果Redis中的某个键过期了没有被删除,AOF文件不会有任何影响。当过期键被删除后(惰性删除和定期删除),AOF文件后会增加一个DEL命令,记录

    2024-05-02
    阅读(4)
  • 回答这里要分为主节点和从节点两个部分介绍。主节点对过期键的处理Redis主节点对过期键的处理采用一种“延迟释放”的策略,当key过期后,它的内存并不一定会立刻释放,而是等待合适的机会再释放。这种“延迟释放”的策略,Redis有两种方案:惰性删除:当你尝试访问一个Key时,Redis会首先检查这个Key是否过期,如果过期则返回null并删除它,如果没有过期则返回数据。定期删除:Redis每隔一段时间随机抽取一部分过期数据,然后删除这些过期数据。Rediskey过期了,为什么内存没释放呢?从节点对过期键的处理在主从架构中,从节点对过期键的处理会有一点特殊。从节点上key的过期时间和主节点保持一致,

    2024-05-02
    阅读(7)
  • 回答用于Redis主从复制是异步的,如果在复制过程中出现网络延迟、主从节点重启等其他时延原因都会导致主从数据不一致。一般解决主从数据不一致需要根据实际情况来分析,大明哥列几种方案。一、直接忽略任何脱离业务的架构设计都是耍流氓,绝大部分业务其实都可以接受一定时间数据不一致。如果你们业务原因接受,那么就直接不处理了,简单,省事。你去处理它,反而使得架构更加复杂。二、强制读主读写全部都在主节点,这样就不存在主从数据不一致的问题了,强一致性读写。虽然这样可以保证读取的数据是最新的,但是牺牲了读操作的并发能力。三、优化读写分离策略我们可以这样结合上面两种方案,对于非关键性的读操作,可以继续从从节点读取,

    2024-05-02
    阅读(14)
  • 回答一、复制风暴复制风暴指的是大量从节点对同一主节点或者同一台服务器的多个主节点短时间内发起全量复制的过程,这样会导致网络阻塞、主节点负载过高的问题。一般我们可以采取如下几种方案来规避:重新设计主从复制拓扑架构。比如采取层级拓扑结构,即从节点不仅仅直接从主节点复制,而是可以从其他从节点复制。使用Redis集群分散从节点同步时间二、读写分离对于读多写少的场景,我们一般都会采取读写分离的方式提高整体的并发量。对于Redis也是一样,由于从节点是主节点的副本,我们可以利用主节点提供写服务,一个或者多个从节点提供读服务,这样就最大化Redis的读负载能力。当然,这样并不是说主从架构下的读写分离没有问题

    2024-05-02
    阅读(12)
  • 回答单机版的Redis存在单点故障问题,Redis的主从架构是Redis高可用和数据备份机制的核心。Redis主从复制允许一个或多个从节点复制主节点的数据状态,其过程分为三个阶段:1、建立连接阶段这个阶段的主要作用是主从节点建立连接,为数据同步做准备。保存主节点信息:当从节点执行slaveofmasterIpmasterPort命令后,就会将主节点的IP、port信息保存下来。主从建立连接:从节点发现新的主节点后会尝试与主节点建立Socket连接。发送ping命令:当主从建立连接后,从节点会向主节点发送ping命令,主要有两个目的:检查Socket连接是否可用检查主节点是否可以处理请求身份认证

    2024-05-02
    阅读(14)
  • 回答一般来说,Redis和数据库的双写方案有如下四种:先更新缓存,再更新数据库先更新数据库,再更新缓存先删除缓存,再更新数据库先更新数据库,再删除缓存由于更新缓存比删除缓存更加复杂且容易产生数据不一致的情况,所以推荐采用删除缓存策略。针对删除缓存的方案,我们可以基于如下策略做选择:业务量不大,并发不高,推荐选择先更新缓存再删除缓存,因为这种方案相对会简单些,所面对的场景也简单些,并发量不高,加上删除缓存失败原本就是一个小概率事件,所以对删除缓存失败的情况的容错性就更大。如果是在高并发的场景下,推荐采用先删除缓存,然后再更新数据库,原因有两个:先更新数据库,再删除缓存:中间存在数据不一致的窗口期

    2024-05-02
    阅读(6)
  • 回答目前主流的缓存更新策略有如下几种:Cache-AsidePattern:旁路缓存模式。它要求应用程序在读取数据时,首先要查询缓存,如果缓存中没有所需数据(缓存未命中),则从数据库中加载数据,然后将数据添加到缓存中。Read-Through/Write-through:这种模式与Cache-AsidePattern差不多,只不过在这种模式中,应用程序与缓存之间多了一个中间层Cache-Provider,这样应用程序就不直接与缓存和数据库交互了,由Cache-Provider完成交互。Write-behind:异步写入模式,是一种先写入缓存,然后异步批量更新到数据库的策略。这种模式可以减少对数

    2024-05-02
    阅读(12)
  • 回答本质上布隆过滤器(BloomFilter)是一种数据结构,一种效率极高的概率型数据结构,用于判断一个元素是否存在于布隆过滤器中,但这个判断是一个概率事件,由于它是基于hash函数的,所以会存在一定的误判概率,它所反馈的情况是:某个元素一定不存在或者可能存在。由于布隆过滤器是一个bit向量或者bit数组,它能够在占用很少空间和以极快的时间内进行元素的插入和查询操作。所以它非常适用于解决海量数据的存在性问题。扩展什么是布隆过滤器布隆过滤器(BloomFilter)是一个叫做Bloom的老哥于1970年提出的。我们可以把它看作是由二进制向量(或者说位数组)和一系列哈希函数两部分组成的数据结构。二

    2024-05-02
    阅读(11)
  • 回答在使用Redis实现分布式锁时,我们需要考虑如下几个问题来确保分布式锁的可靠性、安全性和正确性。互斥性锁的获取和释放必须是原子性的,可以使用setnx来保证,它的语义是SetifNotExists,它可以确保只有一个客户端能成功设置值。而且setnx是原子操作。如何使用setnx实现分布式锁?它有什么优缺点?Redis中的setnx命令为什么是原子性的?性能Redis的高性能是毋庸置疑的,所以使用Redis实现分布式锁在性能方面是无话可说的。Redis采用单线程为什么还这么快?可重入可重入表示一个线程在没有释放锁之前,它是可以重复获取同一把锁的,同时需要记录该线程重入的次数,重入多少次就需

    2024-05-02
    阅读(13)
  • 回答RedLock并不一定是绝对安全的,主要存在如下两个问题:脑裂:在分布式系统中,网络脑裂是指系统的不同部分因为网络故障而无法相互通信。在使用RedLock算法时,如果发生了网络脑裂,可能会导致集群被分割成两个或多个互不通信的子集,那么在每个网路分区内,客户端可能都能从该分区内可达的大多数Redis实例中获取到锁。因为每个分区内的Redis实例是无法感知到其他分区的状态,它们会独立做出“锁可用”的决定,从而导致多个客户端会获取同一把分布式锁。时钟漂移:在RedLock中,所有节点的过期时间是一样的,如果发生了时钟漂移,导致某些节点的锁过期时间比其他节点早,这些节点的锁资源提前释放了。那么就会

    2024-05-02
    阅读(15)
  • 回答RedLock是Redis作者提出的一个多节点分布式锁算法,它主要是解决单节点Redis分布式锁可能存在的单点故障问题。其核心思想是:不在单个Redis实例上进行加锁,而是在多个互相独立的Redis节点加锁,只有在大多数节点上解锁成功,锁才算获取成功。扩展单节点有什么问题Redisson支持多种分布式锁,如可重入锁、联锁、读写锁,但是这些锁都是基于单Redis节点锁,单节点的锁有什么问题呢?单点故障:如果Redis节点因为故障等原因导致Redis实例挂掉,那么所有这个Redis实例的节点都将无法获取到锁,会严重阻碍业务。主从同步问题:当我们使用集群部署Redis,如果一个客户端在Maste

    2024-05-02
    阅读(14)
  • 回答如果任务的执行时间比锁的超时时间还长,这种情况会导致锁过早被释放了,从而会让其他线程在当前线程的任务完成之前获取到锁,这就会引发线程安全问题。为了解决这个问题,我们一般有如下几种解决方案:续租机制【推荐方案】最常见有效的方案是实现一个锁续租机制。也就是在任务执行期间,会定期更新锁的过期时间。确保锁在整个任务执行期间保持有效。Redisson提供了watchdog机制(看门狗),该机制具备锁自动续期功能,用于避免分布式锁在业务处理过程中因执行时间过长而被提前释放。watchdog会自动检测用户线程是否还活着,如果活着,它会在锁快要自动释放之前自动续期,直到用户线程完成工作。使用更长的锁超时时

    2024-05-02
    阅读(12)
  • 回答Redisson是一个在Redis的基础上实现的Java内存数据网格(In-MemoryDataGrid)。它扩展了Redis的功能,提供了许多分布式数据结构和服务,其中包括分布式锁。Redisson支持的分布式锁有:可重入锁(ReentrantLock)、公平锁(FairLock)、联锁(MultiLock)、红锁(RedLock)、读写锁(ReadWriteLock)。它简化了我们获取分布式锁的逻辑。Redisson实现分布式锁的底层原理是基于Redis的SETNX命令和Lua脚本来保证操作的原子性。扩展Redisson是什么Redisson是一个在Redis的基础上实现的Java驻内

    2024-05-02
    阅读(16)
  • 回答SETNX是"SETifNoteXists"的缩写,它所表达的意思是只有在key不存在时才设置值。它能够实现分布式锁的主要原因有两点:Redis单线程保证SETNX的原子性:SETNX是Redis中的一个命令,Redis中的命令执行都是原子性的,这就保证了SETNX在执行过程中是不会被其他命令打断的。当我们使用SETNX设置一个key时,如果这个key已经存在,SETNX将不会执行任何操作并返回0;如果这个key不存在,它将设置key的值并返回1。独占性:SETNX的语义是"SETifNoteXists"。这就意味着如果某个客户端成功使用SETNX设

    2024-05-02
    阅读(6)
  • 回答Redis中的List数据结构是一个双向链表,用于存储一个序列的数据,它类似于Java中的数组或列表,其底层实现分为两个版本:3.2版本以前使用linkedlist+ziplist当列表中元素的⻓度较⼩或者数量较少时,通常采⽤zipList来存储。原因是因为zipList是一个紧凑的数据结构,能够有效地减少内存占用。但是,在列表中元素较多或者元素较大时,zipList的性能会下降,因为在列表的头部或尾部添加或删除元素时,可能需要重新分配并复制整个ziplist。所以,zipList非常适合少量的小数据存储。同时zipList还有一个“连锁更新”的问题,也会严重影响ziplist的性能。当列

    2024-05-02
    阅读(14)
  • 使用命名空间使用冒号(:)将key分隔成不同的部分,可以创建出具有命名空间的结构,这有助于对key进行逻辑分组,类似于目录结构。例如,sike:java:java-concurrent和sike:netty:netty-rumen。同时,这样也可以避免key冲突。保持简洁但具描述性key名称应该足够简短,以减少内存使用,同时又足够描述性,以便能够轻松理解key的用途。我们要尽量避免使用过长或过于复杂的key名称。使用固定的key前缀不同类型的数据使用不同的前缀区分,例如用户模块使用user:作为前缀。使用一致的命名规则一个团队或项目中使用一套一致的命名规则,可以确保所有人都按照相同的方式来创建

    2024-05-02
    阅读(7)
  • SETNX的全称是"SETifNoteXists",其功能是只有当指定的key不存在时,才会将key的值设置为指定的value。如果key已经存在,那么SETNX命令不会执行任何操作。它是两个步骤,为何会是原子性呢?SETNX之所以被认为是原子性操作其根本原因还是因为Redis的单线程模型决定的,在Redis中,单个命令的执行是原子性的,即在任何给定的时间点,Redis只会有一个命令在被执行。因此,当SETNX命令被执行时,没有其他命令可以在它检查key是否存在和可能设置值这两个操作之间运行,保证了这两个步骤的原子性。更多阅读:Redis的线程模型是怎么样的?

    2024-05-02
    阅读(12)