Netty-ByteBuf
参考文献
https://netty.io/4.1/api/index.html
ByteBuffer
12345678910+--------------------------------------------------------------------------------+| ByteBuffer |+-------------------+-----------------------------------+-------+----------------+| | 可读区 (readable) | | |+--------+----------+-----------------------------------+-------+-------+--------+| | | [数据, 数据, 数据, 数 ...
Netty(四)-线程模型
参考文献
Scalable IO in Java --Doug Lea
线程模型
基本的线程池化模式可以描述为
从池的空闲线程列表中选择一个Thread,并且指派它去运行一个已提交的任务(一个Runnable的实现);
当任务完成时,将该Thread返回给该列表,使其可被重用。
Reactor线程模式
Reactor线程模式是一种基于事件驱动的编程模式.
它将事件的处理分解为两个基本操作:事件的分发和事件的处理.
Reactor模式通常包括以下角色:
Reactor:Reactor是整个模式的核心,它负责监听和分发事件,将事件分发给相应的处理器进行处理.Reactor通常使用事件循环来轮询事件队列,将事件分发给相应的处理器.
Handler:Handler是事件处理器,负责处理具体的事件.当Reactor将事件分发给Handler时,Handler会执行相应的业务逻辑,并将处理结果返回给Reactor.
Acceptor :Acceptor 是连接处理器,负责处理新的连接请求.当有新的连接请求到来时,Acceptor 会创建一个新的连接,并将其注册 ...
解决方案-ID生成器
参考文献
雪花算法
雪花算法是一种用于生成全局唯一ID的算法,也称为Twitter雪花算法。它能够在分布式系统中生成唯一的ID,而不需要集中式的ID生成器来维护。雪花算法的原理如下:
雪花算法的ID由64位二进制数组成,其中第1位为符号位,始终为0;第2-42位为时间戳,记录当前时间与一个固定的起始时间之间的差值,精确到毫秒级别;第43-52位为机器ID,用于标识不同的机器,最多能够标识1024台机器;第53-64位为序列号,表示同一毫秒内生成的不同ID,最多能够生成4096个ID。
在生成ID之前,需要先初始化一些参数,包括起始时间、机器ID等。起始时间可以设置为某个固定的时间点,机器ID可以通过配置文件或者其他方式来获取。
在生成ID时,雪花算法会先获取当前时间,计算出时间戳,并将时间戳左移22位,使其占据ID的前42位。然后再将机器ID左移12位,占据ID的43-52位。最后,将序列号加1,并将其与机器ID和时间戳拼接起来,即为最终的ID。
如果在同一毫秒内生成的ID超过了4096个,序列号会重新从0开始计数。如果在同一毫秒内生成的ID超过了4096个,并且当前时间已经超过了 ...
分布式事务
参考文献
分布式事务,这一篇就够了
理论
事务
事务是一个不可分割的数据库操作序列,也是数据库并发控制的基本单位,其执行的结果必须使数据库从一种一致性状态变到另一种一致性状态.事务是逻辑上的一组操作,要么都执行,要么都不执行(支持连续SQL的集体成功或集体撤销.);
事务应该具有 4 个属性:原子性、一致性、隔离性、持久性.这四个属性通常称为 ACID 特性.
分布式事务
分布式事务指在分布式系统中,涉及到多个操作的一组事务,这些操作可能分布在不同的计算机上,这些操作必须要保证原子性、一致性、隔离性和持久性,以确保数据的正确性和可靠性.
在分布式系统中,由于存在多个数据节点,因此需要保证数据的一致性.如果在分布式系统中的每个节点都采用独立的事务处理,则可能会导致数据不一致的问题.为了解决这个问题,需要引入分布式事务,以保证多个节点之间的数据操作是一致的.
本质上来说,分布式事务就是为了保证不同数据库的数据一致性.
分布式事务的实现可以采用两种方式:基于两阶段提交协议(2PC)和基于补偿事务的方案.基于2PC的方案是一种经典的实现方式,它通过协调器来实现多个节点之间的事务协调, ...
解决方案-如何优雅地重试
参考文献
如何优雅地重试
解决方案-数据库缓存不一致问题
参考文献
数据库缓存数据不一致
一致性
“⼀致性”包含了两种情况:
缓存中有数据,那么,缓存的数据值需要和数据库中的值相同;
缓存中本⾝没有数据,那么,数据库中的值必须是最新值.
产生的原因
数据库缓存不一致问题通常是由于缓存和数据库的数据更新不同步或者同步出现问题导致的.
并发更新:在多个并发线程同时更新数据时,可能会出现数据不一致的问题.例如,一个线程更新了数据库中的数据,但是缓存中的数据并没有及时更新,这时另一个线程读取缓存中的数据就会与数据库中的数据不一致.
缓存更新失败:在更新缓存时,如果由于网络或其他原因导致缓存更新失败,就可能会导致缓存和数据库中的数据不一致.
数据库更新失败:在更新数据库时,如果由于网络或其他原因导致数据库更新失败,就可能会导致缓存和数据库中的数据不一致.
缓存过期:在缓存中存储的数据可能会因为时间到期或者缓存空间不足等原因被清除,但是数据库中的数据仍然存在,这时就会出现缓存和数据库中的数据不一致.
缓存穿透:如果请求一个不存在的数据,就会导致缓存中没有该数据,但是每次请求都会访问数据库,这就会出现缓存和数据库中的数据不一致.
解决方 ...
RabbitMQ-如何保证消息不丢失
参考文献
RabbitMQ如何保证消息不丢失?
确保消息到MQ
生产者配置(结合Spring)
在 Spring 中,通过 RabbitTemplate 来发送消息到 RabbitMQ,可以通过配置 RabbitTemplate 的 ConfirmCallback 和 ReturnCallback 来实现消息的确认机制。
ConfirmCallback 是消息发送确认的回调函数接口,该接口方法如下:
12345678910public interface ConfirmCallback { /** * 消息确认回调方法 * @param correlationData 相关数据 * @param ack 消息是否成功到达交换机 * @param cause 失败原因 */ void confirm(CorrelationData correlationData, boolean ack, String cause);}
ReturnCallback 是消息发送失败后的回调函数接口,该接口方法如下:
12 ...
RabbitMQ-死信队列
参考文献
死信队列
RabbitMQ中的死信队列(Dead Letter Queue,DLQ)是一种特殊的队列,用于接收那些未能被消费者正确处理的消息.当一条消息被认为“死亡”时(如过期、被拒绝、超出队列限制等),RabbitMQ会将其路由到预先设定的死信队列中,以便后续进一步处理.
死信队列的作用
容错处理:当某些消息无法正常处理时,可以将其转发至死信队列,以免影响整个消息队列的正常运行.
调试方便:死信队列可以用于存储消费者处理失败的消息,方便开发人员进行问题排查和调试.
业务逻辑处理:死信队列也可以作为一个处理逻辑的触发点,例如当某些消息无法被正确处理时,可以将其路由到死信队列中触发其他业务逻辑的处理.
死信队列的创建步骤
创建一个普通队列,并设置相关参数(如队列名、交换机、路由键等).
设置队列的死信参数(如死信交换机、死信路由键等),以便将“死亡”的消息路由到指定的死信队列中.这些参数可以在创建队列时进行设置,也可以在之后通过队列属性进行修改.
创建一个死信队列,用于接收那些未能被消费者正确处理的消息.同样需要设置相关参数(如队列名、交换机、路由键等).
...
RabbitMQ-处理消息积压
参考文献
消息积压对RabbitMQ的影响
系统性能下降:如果消息队列中的消息没有及时处理,会导致队列变得越来越长,消费者从队列中获取消息的速度会减缓,从而影响整个系统的性能.
内存消耗增加:消息队列中的消息如果一直没有被消费,将一直占用内存.如果队列中积压的消息很多,将会占用大量的内存资源,导致内存消耗增加.
系统崩溃:如果 RabbitMQ 中的消息积压到一定程度,可能会导致系统崩溃.
消息丢失:当 RabbitMQ 中的消息积压到一定程度,可能会导致一些消息被直接删除,从而导致消息丢失的情况.
RabbitMQ处理消息积压
增加消费者数量
可以通过增加消费者数量来提高消息的处理速度.可以在消费者端通过增加线程数或者增加消费者实例数来实现
设置消息过期时间
RabbitMQ 设置消息过期时间是一种处理消息积压的方案,可以通过让已经过期的消息自动被删除,从而减轻队列负担,提高队列的处理能力.具体的操作步骤如下:
设置队列的过期时间
首先,需要在队列声明时设置队列的过期时间,即 x-message-ttl 参数,表示消息的存活时间.当队列中的消息存活时间超过指定时间 ...
Java并发编程-面试题(一)
参考文献
Java中线程的实现方式?
继承Thread类,重写run方法
实现Runnable接口,重写run方法
实现Callable接口,重写call方法,配合FutureTask
Callable一般用于有返回结果的非阻塞的执行方法
同步非阻塞
线程的状态
NEW
RUNNABLE
READY
RUNNING
WAITING
TIMED_WAITING
BLOCKED
TERMINATED
并发编程的三大特性
原子性
问题存在的原因: 分时复用机制引起
使用synchroinzed和Lock接口实现的锁
使用CAS
有序性
问题存在的原因: 重排序引起
使用volatile
使用synchroinzed和Lock接口实现的锁
Happens-Before
可见性
问题存在的原因: CPU缓存引起
使用volatile
使用synchroinzed和Lock接口实现的锁
使用final
Happens-Before原则
程序次序规则
管程锁定规则
volatile变量规则
线程启动规则
线程终止规则
线程中断规则
对象终结规则
Java锁的分 ...