-
Redis 持久化
- RDB(Redis DataBase)持久化:
- 快照方式持久化,将某一个时刻的内存数据,以二进制的方式写入磁盘;
- AOF(Append Only File)持久化:
- 文件追加持久化,记录所有非查询操作命令,并以文本的形式追加到文件中;
- 混合持久化:
- RDB + AOF 混合方式的持久化,Redis 4.0 之后新增的方式,混合持久化是结合了 RDB 和 AOF 的优点,在写入的时候,先把当前的数据以 RDB 的形式写入文件的开头,再将后续的操作命令以 AOF 的格式存入文件,这样既能保证 Redis 重启时的速度,又能减低数据丢失的风险。
- RDB(Redis DataBase)持久化:
-
限流方案
- 单机
- 用aop做一个计数器,按照接口做技术器就可以。
- 令牌桶机制
- count = max_sync,获取到令牌后再处理,处理完不放回去,定时任务每隔1s充令牌,让count = max_sync
- 集群限流方案
- 第一种方案商品系统 ----> redis <--------- ,通过decr key>=0,来获取令牌,定时任务1秒运行一次,setex key 补充令牌,缺点很明显,不一定可以完全匹配的上
- 第二种方案:在应用启动时用hset设置时间和数量,用hincirby扣减,扣减没了之后用redis的乐观锁进行充能。
- 第三种方案:创建一个分布式限流系统,商品系统从这个分布式系统中获取令牌,一次拿10个在本机的内存中进行扣减,消耗完之后在从分布式限流系统中拿。
- 单机
-
分布式事务方案
-
四种分布式事务方案:
-
-
二阶段提交:
- 要保证每个阶段的事务都执行成功才可以往下执行。
-
tcc协议,try -> confirm - > cancel
- 基础表 id 状态 item_id
- 库存表 + 库存流水表(包含状态字段)
- 优惠卷表 + 优惠卷流水表(包含状态字段)
- try阶段,扣减库存,扣减优惠卷,confirm阶段,把两个流水表状态改为success
-
最大努力提交型
-
- 事务执行者1执行成功,发送mq消息,让事务执行者2执行,这种适合业务解耦,并且事务1只要执行成功了,事务2一定要执行成功场景。
- 这个里面有个问题,有可能事务1执行成功了,发送mq消息失败了。
-
事务型消息
- 可以利用rocketmq做事务型消息,事务1先给rocketmq发送perpare消息,发送成功后,事务1继续执行,执行完成后发送commit prepare消息或者rollback消息。
- 如果prepare消息发送成功了,commit或者rollback发送失败了,rockmq会根据prepare定期反查事务1,然后事务1在决定重发commit还是rollback消息。
-
-
缓存雪崩
- 缓存雪崩是指在缓存中大量的键同时过期或失效,导致请求直接访问数据库或后端服务,给数据库或后端服务造成巨大压力,导致系统性能下降甚至崩溃的现象。
- 设置随机过期时间:
- 为缓存键设置随机的过期时间,避免大量键同时过期的情况发生,减少缓存雪崩的概率。
- 实现缓存预热:
- 在系统启动或缓存失效前,提前加载热门数据到缓存中,避免在关键时刻大量请求直接访问后端服务。
- 使用分布式缓存:
- 将缓存数据分布在多个缓存节点上,通过分散请求负载来减少单个缓存节点的压力,提高系统的可用性和抗压能力。
- 设置熔断机制:
- 在缓存失效的情况下,通过设置熔断机制,直接返回默认值或错误信息,避免请求直接访问后端服务,减轻后端服务的压力。
- 实时监控和报警:
- 监控缓存系统的状态和性能指标,及时发现异常情况,并通过报警机制通知运维人员进行处理,减少缓存雪崩的影响
-
缓存穿透
- 缓存穿透是指在缓存系统中,大量的请求查询不存在于缓存和数据库中的数据,导致这些请求直接访问数据库,占用数据库资源,而缓存无法发挥作用的现象。
- 布隆过滤器(Bloom Filter):
- 布隆过滤器是一种高效的数据结构,可以用于快速判断一个元素是否存在于集合中。在缓存层引入布隆过滤器,可以在查询请求到达时,首先通过布隆过滤器判断该请求对应的数据是否存在于缓存或数据库中,从而避免无效的查询操作。
- 缓存空值处理:
- 对于查询数据库返回的空结果,也可以将空结果缓存起来,设置一个较短的过期时间,避免频繁查询数据库。这样在下次查询相同的数据时,可以直接从缓存中获取空结果,而不需要再次查询数据库。
- 异步加载缓存:
- 当缓存未命中时,可以异步加载数据到缓存中,避免在高并发场景下直接访问数据库。在异步加载过程中,可以通过互斥锁或分布式锁来保证只有一个线程去加载数据,避免重复加载。
- 设置热点数据永不过期:
- 对于一些热点数据,可以将其设置为永不过期,或者过期时间较长,以保证这部分数据始终在缓存中可用。
- 限制恶意请求:
- 通过访问频率控制、验证码等手段,限制对缓存的恶意请求,防止攻击者通过查询不存在的数据来触发缓存穿透。
-
缓存击穿
- 缓存击穿是指在缓存系统中,某个热点数据过期或失效时,同时有大量的请求访问该数据,导致请求直接访问数据库或后端服务,给数据库或后端服务造成巨大压力,导致系统性能下降甚至崩溃的现象。
- 设置热点数据永不过期或过期时间较长:
- 对于一些热点数据,可以将其设置为永不过期,或者设置一个较长的过期时间,确保热点数据在缓存中可用,减少因为过期而触发的缓存击穿。
- 加互斥锁或分布式锁:
- 在访问热点数据时,可以引入互斥锁或分布式锁,保证只有一个线程去访问后端服务或数据库,其他线程等待结果。当第一个线程获取到数据后,其他线程可以直接从缓存获取,避免多个线程同时访问后端服务,减轻压力。
- 限制并发访问:
- 通过限制并发访问热点数据的请求量,可以控制请求的流量,避免过多请求同时访问热点数据。
-
分库分表
- 垂直拆分:
- 把相关性强的,带join可能得放到同一个库中
- 水平拆分:
- 按照某一个外键id进行拆分,同一个用户的交易记录放到一个表中
- 可以用create_time进行拆分,历史数据即使有进行扩容,也不会需求迁移等
- 垂直拆分:
-
Java 线程池中 submit() 和 execute()方法有什么区别?
- 提交方式
- submit()方法是定义在ExecutorService接口中的,它允许开发人员提交一个Callable或Runnable对象给线程池来执行,返回一个Future对象,可以用于检索结果或取消任务。
- execute()方法是定义在Executor接口中的,只接收Runnable对象,并且没有返回类型。简单来说,submit()方法更加灵活,可以处理带返回值的任务,而execute()只能处理不带返回值的任务。
- 异常处理
- 使用submit()方法时,该异常会被包装在一个ExecutionException中并重新抛出。因此,在使用该方法时,开发人员必须捕获ExecutionException或声明它可能抛出。
- 使用execute()方法时,异常将不会被重新抛出。这使得异常处理变得更加困难,因为开发人员必须自己处理异常。
- 队列策略
- 线程池通常会使用队列来保存已提交但未处理的任务。线程池如何使用这个队列,被称为队列策略。通过submit()方法提交的任务,会被添加到阻塞队列中,并保留之前提交的任务执行顺序。而对于execute()方法提交的任务,将会被添加到队列的尾部。这意味着队列中的第一个任务是最早的任务并且先被执行。
- 任务的处理过程与方式
- submit()方法在处理任务时,将任务交由一个线程池中的工作线程去处理,而另一个线程(可能是主线程)可以继续做其他事情。负责处理submit()方法提交的任务的线程,当任务结束后会自动返回给线程池并等待下一个任务,从而避免了重复创建和销毁线程的开销。
- execute()方法在处理任务时,它的任务直接在调用execute()方法的调用线程(通常是主线程)中运行,如果当前没有可用线程,则会立即创建新的线程来处理该任务,并在完成任务后销毁线程。
- 消息传递方式
- submit()方法中提交的任务可以通过Future对象获取执行结果,开发人员可以使用该对象等待线程池中对应的任务完成,并获取其返回值;
- execute()方法则没有提供返回值或者其他机制来获取任务的执行情况,因此即便一个任务执行失败了,开发人员也无法了解到在哪里以及什么地方出现了问题。
- 提交方式
-
MyBatisa 延迟加载
- 延迟加载也称为 懒加载只、惰性加载,使用延迟加载可以提高呈序的运行效率,针对数据持久层的操作,在某些特定查询的情况下去访问特定的数据库,在其他口情况下可以不访问某些数据表,尽减少 SQL的执行,从而达到提高速度的目的,是对数据库操作的一种优化。
- 说明:延迟加载只存在于数据表的级联查询中,单表查询没延迟加载的功能。
- 具体的业务场景:
-
nacos相关
- 动态刷新
-
配置存储与监听: Nacos Server作为配置中心,负责存储所有配置信息。当应用启动并配置了Nacos Config客户端后,客户端会连接到Nacos Server并根据配置的dataId和group订阅相应的配置。
-
@NacosPropertySource与@NacosValue注解: 在Spring Boot应用中,通过@NacosPropertySource注解可以指定要加载的配置源(dataId),同时通过autoRefreshed = true参数开启自动刷新功能。而@NacosValue注解则用于注入配置值到Bean的字段上,并可通过autoRefreshed = true使该值具备动态更新的能力。
-
长轮询机制: Nacos客户端实现配置实时更新的一个关键技术是长轮询(Long Polling)。客户端定期向Nacos Server发送请求检查配置是否有更新,如果没有更新,服务器会保持连接不响应,直到有新的配置变更或达到超时时间。这种方式能有效减少网络请求次数,提高效率。
-
配置变更推送: 当配置在Nacos Server端发生变更时,Nacos Server会立即通知所有订阅了该配置的客户端。客户端收到更新通知后,会立刻获取最新的配置并更新到本地环境,进而更新应用中的相关属性值。
-
动态更新应用状态: 如示例代码所示,一旦配置值如useLocalCache发生变化,通过Nacos Value注入的属性值会自动更新,从而影响到应用的行为,比如从数据库读取数据的策略变化等。
-
- 配置优先级
- 动态刷新
-
MySQL三大日志——binlog、redoLog、undoLog详解
- redoLog
- redo log是InnoDB存储引擎层的日志,又称重做日志文件,用于记录事务操作的变化,记录的是数据修改之后的值,不管事务是否提交都会记录下来。一个事务生成的redo日志是按顺序写入磁盘的,是顺序IO,在实例和介质失败(media failure)时,redo log文件就能派上用场,如数据库掉电,InnoDB存储引擎会使用redo log恢复到掉电前的时刻,以此来保证数据的完整性。
- redo log包括两部分:一个是内存中的日志缓冲(redo log buffer),另一个是磁盘上的日志文件(redo log file)。mysql每执行一条DML语句,先将记录写入redo log buffer,后续某个时间点再一次性将多个操作记录写到redo log file。这种先写日志,再写磁盘的技术就是MySQL里经常说到的WAL(Write-Ahead Logging) 技术。
- redo log实际上记录数据页的变更,而这种变更记录是没必要全部保存,因此redo log实现上采用了大小固定,循环写入的方式,当写到结尾时,会回到开头循环写日志。
- binlog
- binlog是属于MySQL Server层面的,又称为归档日志,属于逻辑日志,是以二进制的形式记录的,用于记录数据库执行的写入性操作(不包括查询)信息,依靠binlog是没有crash-safe能力的
- binlog是通过追加的方式进行写入的,可以通过max_binlog_size参数设置每个binlog文件的大小,当文件大小达到给定值之后,会生成新的文件来保存日志。
- redolog和binlog区别
- redo log是属于innoDB层面,binlog属于MySQL Server层面的,这样在数据库用别的存储引擎时可以达到一致性的要求。
- redo log是物理日志,记录该数据页更新的内容;binlog是逻辑日志,记录的是这个更新语句的原始逻辑
- redo log是循环写,日志空间大小固定;binlog是追加写,是指一份写到一定大小的时候会更换下一个文件,不会覆盖。
- binlog可以作为恢复数据使用,主从复制搭建,redo log作为异常宕机或者介质故障后的数据恢复使用。
- undo log
- 主要记录了数据的逻辑变化,比如一条INSERT语句,对应一条DELETE的undo log,对于每个UPDATE语句,对应一条相反的UPDATE的undo log,这样在发生错误时,就能回滚到事务之前的数据状态。
- 保存了事务发生之前的数据的一个版本,可以用于回滚,同时可以提供多版本并发控制下的读(MVCC),也即非锁定读
- redoLog
-
Spring中Bean的五大作用域
- Singleton(单例):默认的作用域
- 在整个应用程序中只创建一个Bean实例。
- 所有对该Bean的请求都将返回同一个实例。
- Bean是全局共享的,适用于无状态的Bean或者需要在多个组件之间共享数据的情况。
- Prototype(原型)
- 每次对Bean的请求都会创建一个新的实例。
- 没有共享状态,适用于有状态的Bean或者需要频繁创建新实例的情况。
- Request(请求)
- 在每个HTTP请求中创建一个新的Bean实例。
- 每个请求的Bean实例对于该请求是唯一的。
- 仅在Web应用程序的上下文中有效,适用于处理HTTP请求的控制器或服务。
- Session(会话)
- 在每个用户会话(Session)中创建一个新的Bean实例。
- 对于同一用户的所有请求,都将使用相同的Bean实例。
- 仅在Web应用程序的上下文中有效,适用于保存用户特定的数据或状态。
- Global Session(全局会话)
- 在整个应用程序的全局会话中创建一个新的Bean实例。
- 仅在基于Portlet的Web应用程序中有效,通常与Portlet会话一起使用。
- Singleton(单例):默认的作用域
-
MyBatis 避免 SQL 注入的方法
- 使用预编译语句(#{}),#{} 会被 MyBatis 转换为预编译的参数化查询
- 避免直接使用 $ {},${} 是字符串替换,不会预编译,存在 SQL 注入风险
- 如果必须使用 ${}(如表名、列名等动态内容),应该:
- 使用白名单验证
- 进行严格的输入过滤
- 避免直接使用用户输入
- 如果必须使用 ${}(如表名、列名等动态内容),应该:
- 使用类型处理器(TypeHandler),为特殊数据类型实现 TypeHandler 可以确保数据安全转换
-
RocketMQ 消息的有序性
- 可以实现严格有序的消息消费,但需要满足以下条件:
- 单个消息队列(Queue):在同一个 Queue 内保证 FIFO(先进先出)顺序
- 同一消息组(MessageGroup):对于顺序消息,相同 MessageGroup 的消息会被分配到同一个 Queue
- Topic 有多个 Queue
- 相同 MessageGroup/ShardingKey 的消息会进入同一 Queue
- 不同 MessageGroup 之间无序,同一 Group 内有序
- 同步发送:生产者使用同步发送模式(sync)
- 顺序消费模式:消费者注册 MessageListenerOrderly
- 可以实现严格有序的消息消费,但需要满足以下条件:
-
java 内存溢出排查指南
- 获取内存快照
- MAT (Memory Analyzer Tool):分析内存泄漏对象
- VisualVM:实时监控内存使用
- JProfiler:商业级分析工具
- 获取内存快照
-
Java CPU 使用率过高排查指南
- 使用 top 命令定位 Java 进程
- 查看线程级 CPU 使用
- 将线程 ID 转换为 16 进制
- 根据线程id去寻找相关线程看具体情况
-
InnoDB 锁表情况详解
- DDL 操作导致的锁表,表结构,创建索引等
- 当 UPDATE/DELETE 语句无法使用索引时:
- 大事务影响
- 事务涉及表中大量数据(超过阈值)
- 事务执行时间过长
- 系统资源紧张
- 当系统检测到严重资源竞争时可能自动升级锁
-
redis分布式锁怎么续期
- 手动续期(简单但不可靠)
- 在业务代码中定期(如每隔 TTL/3 时间)调用 PEXPIRE 命令重置锁的 TTL。
- 缺点:如果客户端崩溃,续期逻辑停止,锁仍会过期。
- 异步守护线程(看门狗机制)
- Redisson 的实现:启动一个后台线程(看门狗,Watchdog),定期检查锁是否仍被持有,如果是则续期。
- 默认续期间隔 = 锁 TTL 的 1/3(如 TTL=30s,则每 10s 续期一次)。
- 如果客户端正常释放锁,看门狗线程终止;如果客户端崩溃,锁最终自动过期。
- 基于 Lua 的原子续期
- 使用 Lua 脚本保证续期操作的原子性(避免因客户端阻塞导致竞态条件)
- 手动续期(简单但不可靠)
-
rockmq消息丢失怎么处理,或者怎么预防消息丢失
- RocketMQ 提供了相应的机制来确保消息不丢失,核心思想是:同步落盘 + 同步复制 + 确认机制。
- 生产者端预防措施
- 使用同步发送并检查结果:这是最基本也是最重要的要求。
- 合理配置生产者参数。
- retryTimesWhenSendFailed: 设置合理的同步发送重试次数(默认是 2)。
- retryAnotherBrokerWhenNotStoreOK: 当发送失败时,是否尝试发送到其他 Broker(默认 false,可根据场景开启)。
- Broker 端预防措施
- 刷盘策略:同步刷盘 (flushDiskType = SYNC_FLUSH)
- 生产者发送的消息,只有在被 Broker 成功刷写到磁盘后,才会向生产者返回成功 ACK。这样即使 Broker 宕机,消息也不会丢失。代价是性能大幅下降。
- 复制方式:同步双写 (brokerRole = SYNC_MASTER)
- 生产者发送的消息,只有在被 Broker 主节点成功同步到至少一个从节点后,才会向生产者返回成功 ACK。这样即使主节点磁盘损坏且无法恢复,从节点上也有一模一样的消息副本。代价是性能进一步下降,延迟更高
- 刷盘策略:同步刷盘 (flushDiskType = SYNC_FLUSH)
- 消费者端预防措施
- 使用可靠的消费模式:推荐使用 Push 模式,由 RocketMQ 客户端帮你管理偏移量,更简单可靠。
- 只有在业务处理成功后才返回消费成功。
- 监控消息堆积:在控制台上密切关注 Topic 的消息堆积量,如果发现堆积持续增长,及时排查消费端问题,防止因消息过期而被删除。
- 生产者端预防措施
- RocketMQ 提供了相应的机制来确保消息不丢失,核心思想是:同步落盘 + 同步复制 + 确认机制。
共同學(xué)習(xí),寫下你的評(píng)論
評(píng)論加載中...
作者其他優(yōu)質(zhì)文章