当前位置: 首页 > news >正文

场景题-1

场景题-1

订单到期关闭

1、DelayQueue

无界阻塞队列,用于放置实现了Delayed接口的对象,基于PriorityQueue实现,可用于实现在指定的延迟时间之后处理元素。订单创建后放入队列中,然后使用一个常驻任务不停地执行扫描取出超时订单,理论上可用,但是实际因为DelayQueue是基于JVM内存的,所以订单量大的时候容易OOM,而且数据无法持久化,在机器重启后数据会丢失。虽然配合数据库或者rediis等可以解决持久化问题,但是目前应用基本是集群部署,多个实例上的DelayQueue如何配合使用也是个问题,所以综合来说并不推荐(单机、订单量小可尝试)。

2、时间轮

时间轮可以理解为一种像钟表一样的环形结构,圆环上被划分出许多槽位(粒度可以是毫秒、秒、分钟、小时等),每个槽位上有一个链表用于保存所有到期的任务,随着时间推移指针指向哪个槽位就执行该槽位上的任务,另外引入round(圈数)和分层时间轮的概念来满足不同的任务时间精度。

2.1 使用Netty的HashedWheelTimer我们可以实现一个时间轮,但是和Delay有一样的问题。

2.2 使用Kafka的时间轮,Kafka有很多延时性的操作,延时生产、延时拉取和延时数据删除等,具体实现是Kafka下的TimingWheel类。Kafka的时间轮性能不错,但是实现方式较复杂。

3、定时任务

基于Timer、ScheduledThreadPoolExecutop或者xxx-job这类调度框架实现,注意可能会有一些问题,首先定时任务是把分散的超时订单集中在任务调度那一刻处理,所以时间订单处理时间可能就不精准,而且订单量越大,那么调度任务执行时间长的话时间偏差也就越大,其次大数据量时,定时集中扫表,需要考虑数据库压力,不能影响正常业务。但是一般来说,订单超时关闭这种业务,对时间精确度并不是要求很高,所以需要考虑的主要是定时扫表性能问题。

大数据量库表读表性能问题,首先可以加索引,在state(状态)字段上加索引,这边会牵扯出一个问题,那就是区分度不高的字段加索引是否有用,实际上如果该字段对应的枚举占的比例相差很大,比如订单状态,成功的可能占90%,需要关闭的占10%,这样的我查询这部分需要关闭的数据,他可以过滤掉大部分数据,走索引还是可以大大提升效率的。其次可以考虑使用多线程执行,这种方案要注意的就是做好数据隔离,别重复处理一条数据,处理方案可以是扫表后处理时注意幂等控制(一次和多次请求某一个资源应该具有同样的作用),也可以采用分段处理。最后可以使用备库,扫描备注然后根据id直接去修改主库。

4、MQ方案实现延迟消息

4.1 RocketMQ延迟消息:消息写入Broker之后不会立即被消费,而是在指定时间后才会被消费处理。存在无法自由设置关单时长的问题,RocketMQ并不支持任意时长设置(商业版和最新的5.0版本可支持任意时长)。

4.2 RebbitMQ死信队列:给消息设置TTL但是并不消费,到期后消息进入死信队列(交换机-exchange),监听死信队列的消息进行消费。存在问题:死信队列的对头消息阻塞;实现方案麻烦(依赖RebbitMQ,要创建许多exchange)。

4.3 RebbitMQ插件:基于rebbitmq_delayed_message_exchange插件,消息不是通过死信队列处理,而是直接存入Erkang开发的一个数据库,定时查询需要投递的消息进入x_delayed_message队列中,所以不存在消息阻塞的问题,但是要注意有延迟时间限制,这个插件最长支持大约49天的时间。

***注意:***不建议使用MQ,一是订单量大就会堆积大量的消息,资源浪费,成本提升,而且需要注意的是这里面还会有大量的无效消息,因为大部分订单可能是提前取消和完成支付的;二是延迟时间的限制,特别是B类采购订单长关单期很难满足,另外很重要的是,MQ还是会有丢消息的风险的。

5、redis

5.1 消息监听::配置文件redis.conf中开启监听:notify-keysppace-events Ex,代码中实现KeyExpirationEventMessageListener,不推荐使用,过期的key不能保证被立即删除,也不能保证能立即发出,另外还可能存在消息丢失问题。

5.2 zset:socre设置时间戳+超时时间,member为订单号,zset会按照score排序,开启redis扫描任务,获取当前时间>score的延时任务,拿到订单号进行关单。高并发场景下可能会有多个消费者拿到同一个订单的现象。

6、Reddisson

Reddisson定义了分布式延迟队列RDelayedQueue,RDelayedQueue.offer()方法将消息放入RDelayedQueue,到期后Reddisson会将元素从RDelayedQueue转移到RBlockingDeque,RBlockingDeque.take()方法获取元素。

大量登录请求,JVM调优

登录接口一般并不会携带太多信息,高并发环境下产生的众多小对象会很快被回收,考虑JVM的调优主要就是内存的配置和垃圾收集器(吞吐量和STW)的选择,同时做好GC日志的监控。

1、堆内存设置

一般设置为操作系统内存的一半,比如一台4C8G的机器,那么就设置为4G,初始内存和最大内存建议都为4G,避免内存的频繁扩容和收缩。

-Xms4G -Xmx4G

2、垃圾收集器

新生代频繁GC,兼顾高吞吐量和较短的STW(停顿时间,JVM在执行垃圾回收过程中,所有Java执行线程被暂停的持续时间),考虑使用G1作为垃圾收集器(JDK 9 默认,需要内存最少要4G)。

-XX:+UseG1GC

-XX:MaxGCPauseMillis=150

MaxGCPauseMillis为设置的停顿时间,JVM执行时会尽量在设置的这个时间内完成回收,可以使用jstat查看实际停顿时间,如果实际停顿时间远大于这个设置的时间,就需要重新进行一些配置。

另外,可以设置GC的并发线程数

-XX:ParallelGCThreads=4

-XX: ConcGCThreads=2

3、各区大小设置

G1的内存划分是动态自适应的,但是也可以手动进行一些配置

-XX:G1HeapReagionSize=2m

-XX:G1NewSizePercent=20 //年轻代的初始大小为堆的20%

-XX:G1MaxNewSizePercent=50 //年轻代的最大大小为堆的50%

-XX:G1OldCSetRegionThresholdPercent=10 //老年代的大小为堆的10%

-XX:G1HeapWastePercent=10 //垃圾回收后留下的未使用区域的最大比例为10%

4、日志输出

以上配置还需要根据具体情况进行调整,所以增加日志来观察调整

-XX:+HeapDumpOnOutOfMemoryError //内存溢出时输出快照文件

-XX:HeapDumpPath=/path/to/dump.hprof //堆内存快照文件的存储路径

-XX:+PrintGC //输出GC信息

-XX:+PrintGCDateStamps //输出GC发生时间

-XX:+PrintGCDetails //输出GC详细信息

-Xlog:gc*=info:file=/path/to/logs/gc.log:time,uptime:filecount=10,filesize=100M //gc日志输出路径,设置文件大小和数量

业务请求量突增怎么处理

面对流量的激增的问题要注意区分情况,首先注意甄别是否是正常场景。非正常流量激增可能是被DDOS了(攻击者利用大量“肉鸡”发起大量的正常或非正常的请求,耗尽主机资源或网络资源,从而使被攻击的主机无法为正常用户提供服务,被DDOS时被攻击主机上会有大量等待状态的TCP连接,网络中充斥着大量的无用数据包,主机无法正常与外界通讯并提供服务甚至直接系统死机,在用户看来就是网站无法访问)。而正常的流量提升需要考虑两个方面:一方面是长期的可预期的业务好转,施行长期方案,即设计一个支持高并发的系统,包括架构、性能优化和容错机制等等。另一方面就是短期的热点事件影响,这时短期的简单处理就是扩容,增加集群的服务器数量,提升机器硬件配置等。

重点说下一个高并发系统相关的设计和优化要点:

1、分布式架构

将系统拆解成不同的功能模块部署在不同的机器上,相互之间通过远程调用协同工作,对外提供服务。

2、集群部署

在不同的机器上部署相同的应用或者功能模块,通过负载均衡设备对外提供服务。

3、利用缓存

Redis、Ehcache缓存、NoSql技术,提高数据访问性能

4、异步处理、消息队列

消息队列:解耦、异步、削峰填谷,减少请求响应时间,提高系统吞吐量。

kafka支持发布-订阅模式,每秒可处理百万级数据,使用更简单,当然一些高级功能就需要比较麻烦的配置;ActiveMQ/RoketMQ/RabitMQ同时支持点对点和发布-订阅模式,吞吐量相对小点,功能更多样灵活,但相应的使用起来更复杂。

5、预加载

浏览器提前下载某些资源,减少用户的等待时间。

6、代码优化

6.1、单例

IO处理、数据库连接、配置文件解析等使用单例模式

6.2、批量

如涉及数据库的操作,批量执行

6.3、Future模式

通过Future对象异步获取获取返回值,同时主流程继续处理其他业务逻辑

6.4、使用线程池
6.5、锁优化

减少锁的持有时间(同步代码块);减小锁粒度(如ConcurrentHashMap的分段锁)

6.6、缓存结果

本地缓存或者分布式缓存储存计算结果或者查询结果,减少重复的数据库查询和磁盘IO

6.7、SQL优化
6.7.1 索引失效

针对慢sql,通过explain查看执行计划,注意type、key和extra字段,分别是索引类型,使用的索引和查询时的附加操作,三者结合来看可以看出是否使用了索引,如果有走索引,判断是否走了覆盖索引或者是否全扫描索引树等等。简单来说,key要有值,不能是NULL,type应该是ref、eq_ref、range、const等这几个,extrausing index、using index condition都是可以的。

失效原因:

(1)条件字段没有索引或者不满足最左前缀匹配

(2)索引区分度不高,可能会不走索引

(3)表数据少,直接全表扫描

(4)查询语句中,索引字段用了函数计算或者数据类型不一致等

上述(4)包含sql语句的问题补充如下:

(a)MySql用了函数计算之后索引不是一定会失效,MySql 8.之后引入函数索引。

(b)sql语句使用OR,并且OR两边使用<或>,如果OR两边使用的=的话还是可以走索引的。

(c)sql语句使用LIKE,%在 字符串的首位则不走索引。

(d)隐式类型转换,varchar类型字段查询时使用int类型,索引失效,但是注意int类型字段查询时加了单引号或者双引号,参数会自动转换为int类型,能走索引。

(e)sql语句使用 != ,并不是绝对不走索引,比如用自增主键ID时就可能走索引,这个要看索引的选择和数据分布情况。

(f)sql语句使用 is nt null。

(g)sql语句使用 order by,数据量很小时,直接在内存中排序,不使用索引。

(h)sql语句使用 in, in的值比较多的时候可能就不走索引 了。

6.7.2 多表join或者查询字段太多

MySql的嵌套查询效率较低,如果不用join可以考虑代码作二次查询再进行数据关联处理,或者设计表的时候允许数据冗余或基于join关系做宽表。

6.7.3 数据库连接数不够

常见于热点数据更新,多个update语句会排队获取锁,占用连接资源 ,解决思路有1、基于缓存做数据更新,如redis,2、异步更新或者批量更新

6.7.4 数据库IO或者CPU比较高
6.7.5 深度分页问题

考虑使用子查询以及记录上一页ID的方案

6.8、 数据库优化

6.8.1 合理的数据库索引

6.8.2 分库分表

分库针对并发量大,数据库连接数不够。

分表针对表数据量大,查询性能受到很大影响。

拆分分横向拆分和纵向拆分,横向拆分就是把表中不同的记录放到不同的表中,纵向拆分就是把某条记录的多个字段拆分到不同的表中。

分库分表工具:sharing-jdbc,TDDL,MyCat

6.8.3 读写分离

读请求到从库,写请求到主库,主从库通过主从复制实现数据同步,具体读写分流实现方法有:

(a) 代码分流,在DAO层定义定义多个数据源,在实际进行读或者写操作时利用AOP在业务层或者DAO层方法调用前动态切换数据源。

(b) 借助中间件,sharing-jdbc,TDDL等均支持读写分离

注意问题:主从延迟,针对这个问题可以做一些优化,对于不能接受延迟的读请求,强制读主库。

6.9、限流、熔断、降级
6.10、容错和监控
6.11、全面的性能测试和评估

压力测试和安全测试

http://www.xdnf.cn/news/777817.html

相关文章:

  • 【数据库】《DBA实战手记》- 读书笔记
  • React前端框架
  • Agentic Workflow是什么?Agentic Workflow会成为下一个AI风口吗?
  • LeetCode - 144. 二叉树的前序遍历
  • TCP的粘包和拆包
  • PostgreSQL的扩展 auth_delay
  • 【Node.js 深度解析】npm install 遭遇:npm ERR! code CERT_HAS_EXPIRED 错误的终极解决方案
  • SQLite详细解读
  • Matlab数值计算
  • [Linux] MySQL源码编译安装
  • 软考 系统架构设计师系列知识点之杂项集萃(78)
  • Microsoft前后端不分离编程新风向:cshtml
  • OpenCV CUDA模块图像处理------图像融合函数blendLinear()
  • 高效图像处理:使用 Pillow 进行格式转换与优化
  • 【图像处理入门】4. 图像增强技术——对比度与亮度的魔法调节
  • OpenCV CUDA模块图像处理------双边滤波的GPU版本函数bilateralFilter()
  • 【Unity开发】控制手机移动端的震动
  • 【WPF】从普通 ItemsControl 到支持筛选的 ItemsControl:深入掌握 CollectionViewSource 用法
  • 【PmHub面试篇】Gateway全局过滤器统计接口调用耗时面试要点解析
  • 网络安全厂商F5推出AI Gateway,化解大模型应用风险
  • Axure-元件流程图
  • 鸿蒙开发:应用内如何做更新
  • 湖南省水利水电安全员b证在哪报名
  • 破局与进阶:ueBIM 在国产 BIM 赛道的差距认知与创新实践
  • Git 使用规范指南
  • Elasticsearch + Milvus 构建高效知识库问答系统《一》
  • 为什么 uni-app 开发的 App 没有明显出现屏幕适配问题Flutter 开发的 App 出现了屏幕适配问题
  • Java编程之建造者模式
  • [Java 基础]Java 语言的规范
  • 【如何在IntelliJ IDEA中新建Spring Boot项目(基于JDK 21 + Maven)】