网站搭建阿里,wordpress教程 知乎,电子商务网站建设服务外包,手机网页设计用什么软件尼恩说在前面
在40岁老架构师 尼恩的读者交流群(50)中#xff0c;最近有小伙伴拿到了一线互联网企业如得物、阿里、滴滴、极兔、有赞、shein 希音、百度、网易的面试资格#xff0c;遇到很多很重要的面试题#xff1a; Disruptor 官方说能达到每秒600w OPS订单处理能力)中最近有小伙伴拿到了一线互联网企业如得物、阿里、滴滴、极兔、有赞、shein 希音、百度、网易的面试资格遇到很多很重要的面试题 Disruptor 官方说能达到每秒600w OPS订单处理能力怎么实现的 Disruptor 什么情况下发生消费数据丢失 该怎么解决 小伙伴 没有回答好导致面试挂了。
Disruptor 是队列之王相关面试题也是一个非常常见的面试题考察的是高性能的基本功。
如何才能回答得很漂亮才能 让面试官刮目相看、口水直流呢
这里尼恩给大家做一下系统化、体系化的梳理让面试官爱到 “不能自已、口水直流”然后帮大家 实现 ”offer自由”。
当然这道面试题以及参考答案也会收入咱们的 《尼恩Java面试宝典》V175版本PDF集群供后面的小伙伴参考提升大家的 3高 架构、设计、开发水平。 注本文以 PDF 持续更新最新尼恩 架构笔记、面试题 的PDF文件请关注本公众号【技术自由圈】获取。 队列之王 Disruptor 简介
Disruptor是英国外汇交易公司LMAX开发的一个高性能队列研发的初衷是解决内存队列的延迟问题在性能测试中发现竟然与I/O操作处于同样的数量级。
基于Disruptor开发的系统单线程能支撑每秒600万订单2010年在QCon演讲后获得了业界关注。 2011年企业应用软件专家Martin Fowler专门撰写长文介绍Disruptor。
2011年Disruptor还获得了Oracle官方的Duke大奖。
目前包括Apache Storm、Camel、Log4j 2在内的很多知名项目都应用了Disruptor以获取高性能。
Disruptor通过以下设计来来实现 单线程能支撑每秒600万订单的问题: 核心架构1无锁架构 生产和消费都是无锁架构。具体来说生产者位点/消费者位点的操作都是无锁操作或者使用轻量级CAS原子操作。 无锁架构好处是既没有锁的竞争, 也没有线程的内核态、用户态切换的开销。 关于内核态、用户态的原理请参见尼恩的葵花宝典。 核心架构2环形数组架构 数组元素不会被回收避免频繁的GC所以为了避免垃圾回收采用数组而非链表。 同时数组对处理器的缓存机制更加友好。 数组长度2^n通过位运算加快定位的速度。 下标采取递增的形式。不用担心index溢出的问题。 index是long类型即使100万QPS的处理速度也需要30万年才能用完。 核心架构3cache line padding 两个维度的CPU 缓存行加速享受到 CPU Cache 那风驰电掣的速度带来的红利 第一维度 对 位点等核心组件进行 CPU cache line padding实现高并发访问修改和取值。 第二个维度 ringbuffer 是一个数据加载的时候一般也会塞满整个 CPU cache line。也就是说 从内存加载数据到 CPU Cache 里面的时候 如果是加载数组里面的数据(如 Disruptor)那么 CPU 就会加载到数组里面连续的多个数据。 所以Disruptor 数组的遍历、还是位点的增长 很容易享受到 CPU Cache 那风驰电掣的速度带来的红利。
SpringBoot Disruptor 使用实战 有关 Disruptor的 简单实战请参见 尼恩的 《Disruptor 学习圣经 V3》 由于过于简单这里不做啰嗦。 下面来看一个SpringBoot Disruptor的 使用实战
使用 Disruptor 实现一个生产消费模型步骤是 准备好简单的一个springboot应用 定义事件Event : 你可以把 Event 理解为存放在队列中等待消费的消息对象。 创建事件工厂 事件工厂用于生产事件我们在初始化 Disruptor 类的时候需要用到。 创建处理事件的 Handler Event 在对应的 Handler 中被处理你可以将其理解为生产消费者模型中的消费者。 创建并装配 Disruptor : 事件的生产和消费需要用到Disruptor 对象。 定义生产者并使用生产者发消息 对简单的SpringBoot Disruptor 进行扩容实现 容量监控预警 动态扩容
定义一个Event和工厂
首先定义一个Event来包含需要传递的数据 由于需要让Disruptor为我们创建事件我们同时还声明了一个EventFactory来创建Event对象。
public class LongEventFactory implements EventFactory { Override public Object newInstance() { return new LongEvent(); }
} 定义
事件处理器消费者
我们还需要一个事件消费者也就是一个事件处理器。
这个例子中事件处理器的工作就是简单地把事件中存储的数据打印到终端 /** * 类似于消费者* disruptor会回调此处理器的方法*/static class LongEventHandler implements EventHandlerLongEvent {Overridepublic void onEvent(LongEvent longEvent, long l, boolean b) throws Exception {System.out.println(longEvent.getValue());}}disruptor会回调此处理器的方法
定义事件源(生产者)
事件都会有一个生成事件的源类似于 生产者的角色.
注意这是一个 600wqps 能力的 异步生产者。 这里定义两个版本 生产者的角色的接口定义如下 入门级一个简单 DisruptorProducer 生产者的定义和使用
定义一个简单 DisruptorProducer 生产者
大致的代码如下
package com.crazymaker.cloud.disruptor.demo.business.impl;Slf4j
public class DisruptorProducer implements AsyncProducer {//一个translator可以看做一个事件初始化器publicEvent方法会调用它//填充Eventprivate static final EventTranslatorOneArgLongEvent, Long TRANSLATOR new EventTranslatorOneArgLongEvent, Long() {public void translateTo(LongEvent event, long sequence, Long data) {event.setValue(data);}};private final RingBufferLongEvent ringBuffer;public DisruptorProducer() {this.ringBuffer disruptor().getRingBuffer();}public void publishData(Long data) {log.info(生产一个数据 data | ringBuffer.remainingCapacity() ringBuffer.remainingCapacity());ringBuffer.publishEvent(TRANSLATOR, data);}private DisruptorLongEvent disruptor() {ThreadFactory namedThreadFactory new ThreadFactoryBuilder().setNameFormat(DisruptorThreadPool).build();LongEventFactory eventFactory new LongEventFactory();int bufferSize 1024;DisruptorLongEvent disruptor new Disruptor(eventFactory, bufferSize, namedThreadFactory,ProducerType.MULTI, new BlockingWaitStrategy());// 连接 消费者 处理器 两个消费者LongEventWorkHandler1 handler1 new LongEventWorkHandler1();LongEventWorkHandler2 handler2 new LongEventWorkHandler2();disruptor.handleEventsWith(handler1, handler2);//为消费者配置异常处理器disruptor.handleExceptionsFor(handler1).with(exceptionHandler);disruptor.handleExceptionsFor(handler2).with(exceptionHandler);// 开启 分裂者事件分发disruptor.start();return disruptor;}ExceptionHandler exceptionHandler ...//省略非核心代码 异常处理器实现
}
上面的代码通过 disruptor() 方法创建和装配 一个Disruptor对象 Disruptor 里边有一个环形队列。然后 disruptor() 方法给 Disruptor对象设置消费者并且为消费者设置异常处理器。
使用这一个简单 DisruptorProducer 生产者
定义一个配置类用于实例化 生产者 定义controller 注入这个 生产者就可以异步发布数据 给消费者了 springboot应用启动之后 可以通过 httpclient 工具测试一下 看一下测试数据 具体的代码和演示过程后面参考尼恩录制和发布《尼恩Java面试宝典》配套视频。
Disruptor消费数据丢失问题的分析与解决
在处理高并发、大数据量等场景时Disruptor虽然其高性能、低延迟然而在使用过程中一些用户可能会遇到消费数据丢失问题。
为了解决这些问题我们需要深入了解Disruptor的工作原理并采取相应的解决方案。
消费数据丢失问题的根因
消费线程丢失问题通常发生在消费者处理速度跟不上生产者的时候。
由于Disruptor采用环形队列来存储数据当队列满时新的数据会覆盖旧的数据。
Disruptor 中生产和消费的index是long类型即使100万QPS的处理速度也需要30万年才能用完。
生产和消费的index 下标采取递增的形式。不用担心index溢出的问题。
生产和消费的index 是通过 取模 映射到 ring 环形数据的。 如果消费者速度慢 生产者快消费跟不上生产的index/Sequence就会越来越大取模的时候又会从0开始去覆盖ring前面的数据从而导致没有消费的数据被丢失。 从上图可以看到只要生产者 的Sequence 大于消费者 一个ring 的数量 就开始 覆盖旧的数据也就是开始丢失数据。
消费数据丢失问题解决方案 增加消费者数量增加消费者线程的数量可以并行处理更多的数据提高消费速度。 同时合理配置消费者与生产者的数量比例确保队列生产者 的Sequence 不会大于消费者 一个ring 的数量。 增加ring环形数组的大小通过增加数组的大小从而保证一个环可以存放足够多的数据但这个可能会导致OOM。 剩余容量监控与告警 通过Prometheus 对 remainingCapacity剩余容量 进行实时监控当remainingCapacity 超过80%阈值及时发出告警通知相关人员处理进行微服务实例的 HPA 横向扩容或者进行 Disruptor 队列进行动态扩容。 Disruptor 动态扩容 对 Disruptor 框架进行合理封装从单个Disruptor 队列模式变成 ringbuffer 数组的形式并且可以结合nacos 或者 Zookeeper 这种发布订阅组件 对 ringbuffer 数组 进行在线扩容。
总之通过增加消费者数量、增加ring环形数组的大小、剩余容量监控与告警 Disruptor 动态扩容等方式可以有效解决 消费数据丢失问题。
高级版Spring Boot Prometheus 监控剩余容量 大小
我们的微服务项目中使用了 spring boot集成 prometheus。 我们可以通过将remainingCapacity 作为指标暴露到 prometheus 中通过如下代码 增加这个代码之后请求 /actuator/prometheus 之后可以看到对应的返回 这样当这个值低于20%我们就认为这个剩余空间不够可以扩容了。
Disruptor 如何 动态扩容
关于 Disruptor 动态扩容的方案可以实现一个可以扩容的子类 定义一个环形队列的数据 private DisruptorLongEvent[] executors;
在构造函数中初始化为1 public ResizableDisruptorProducer() {executors new Disruptor[1];executors[0] disruptor();this.ringBuffer executors[0].getRingBuffer();}发布事件的时候通过取模的方式确定使用executors 数组 其中的一个RingBuffer 在next方法执行indx 取模和 获取 ringbuffer 的操作 这里参考了netty源码里边 PowerOfTwoEventExecutorChooser 反应器选择的方式使用位运算取模从而实现高性能取模。
什么时候扩容呢 当监控发现超过80%的阈值后运维会收到告警然后可以通过naocos、Zookeeper的发布订阅 通知微服务进行扩容。
微服务 扩容要回调下面的risize方法 具体的代码和演示过程后面参考尼恩录制和发布《尼恩Java面试宝典》配套视频。
在使用Disruptor框架时需要根据实际情况选择合适的监控和扩容解决方案并不断优化和调整系统配置以满足日益增长的业务需求。
说在最后
以上的内容如果大家能对答如流如数家珍基本上 面试官会被你 震惊到、吸引到。最终让面试官爱到 “不能自已、口水直流”。offer 也就来了。
在面试之前建议大家系统化的刷一波 5000页《尼恩Java面试宝典》V174在刷题过程中如果有啥问题大家可以来 找 40岁老架构师尼恩交流。
另外如果没有面试机会可以找尼恩来帮扶、领路。
尼恩已经指导了大量的就业困难的小伙伴上岸前段时间帮助一个40岁就业困难小伙伴拿到了一个年薪100W的offer小伙伴实现了 逆天改命 。
尼恩技术圣经系列PDF
《NIO圣经一次穿透NIO、Selector、Epoll底层原理》《Docker圣经大白话说Docker底层原理6W字实现Docker自由》《K8S学习圣经大白话说K8S底层原理14W字实现K8S自由》《SpringCloud Alibaba 学习圣经10万字实现SpringCloud 自由》《大数据HBase学习圣经一本书实现HBase学习自由》《大数据Flink学习圣经一本书实现大数据Flink自由》《响应式圣经10W字实现Spring响应式编程自由》《Go学习圣经Go语言实现高并发CRUD业务开发》
……完整版尼恩技术圣经PDF集群请找尼恩领取 《尼恩 架构笔记》《尼恩高并发三部曲》《尼恩Java面试宝典》PDF请到下面公号【技术自由圈】取↓↓↓