ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

架构问题思考和解决方案

架构问题思考和解决方案 一、 JDK21 虚拟线程Virtual Thread深度剖析Q1虚拟线程和平台线程传统线程有什么区别底层是如何实现的思路 从调度模型、内存占用、创建开销三个维度回答。调度模型不同平台线程是操作系统原生线程由OS调度虚拟线程是JVM管理的轻量级线程Project Loom项目由JVM在用户态Carrier线程即平台线程上进行调度M:N模型。内存与开销平台线程默认栈空间较大1MB左右创建和销毁开销大虚拟线程栈是动态的类似协程初始很小几MB创建成本极低可以轻松创建百万级实例。阻塞处理当虚拟线程遇到IO阻塞如网络请求、文件读写时JVM会将其从载体线程上“卸载”让载体线程去执行其他虚拟线程IO恢复后再“挂载”回去从而实现高并发。Q2用虚拟线程重构了异步线程池具体怎么做和原来的 CompletableFuture/Reactive 方案比有什么优劣思路 强调“代码简化”和“性能提升”承认其局限性。做法以前处理一个复杂业务流程可能需要拆分成多个 CompletableFuture 链式调用或者使用WebFlux的 Mono/Flux 代码回调地狱严重。重构时将阻塞IO操作如调用下游服务、访问数据库直接放在虚拟线程中执行保持了代码的同步写法 imperative style 。优势代码可读性极高像写同步代码一样写高并发程序维护成本低。且虚拟线程的上下文切换由JVM负责比手动管理线程池和回调要高效。劣势虽然吞吐量大但对于CPU密集型任务由于受限于载体线程Platform Thread的数量虚拟线程并不能无限提升性能甚至可能因为频繁的挂起/恢复带来额外开销。Q3synchronized 会不会钉住Pinning虚拟线程如果一定要用 synchronized 怎么办思路 解释“钉住”的原因给出解决方案 ReentrantLock 或 synchronized 优化。会钉住当虚拟线程在执行 synchronized 代码块且持有了监视器锁Monitor时如果这个锁是偏向锁或轻量级锁或者虚拟机实现的原因虚拟线程可能会被“钉住”在当前载体线程Carrier Thread上无法被挂起直到它释放锁。这会阻塞载体线程影响整体吞吐量。解决方案替换锁尽量使用 java.util.concurrent.locks.ReentrantLock 它支持可中断、公平锁等高级特性且不会像 synchronized 那样容易导致钉住。减小锁粒度尽量不要在大的代码块上使用 synchronized 缩小临界区。升级JDK/调整参数在较新的JDK版本中JVM对 synchronized 在虚拟线程下的表现做了优化或者在启动参数中调整相关配置但这通常是最后手段。二、 数据库与 SQL 优化Q4如果一个核心接口需要关联8张表怎么优化的思路 从“业务抽象 - 技术拆分 - 异步化”三个层面回答体现一面的“应变能力”。业务抽象与需求对齐和PM/业务方沟通是否真的需要实时返回8张表的全部聚合数据能否分层展示或者异步生成报表垂直/水平拆分垂直如果8张表代表不同的业务域考虑拆分成多个接口前端按需加载。水平对于多表Join如果数据量巨大会尝试将Join操作下沉到服务层Application Layer而不是在DB层做。即先查主表再根据主表ID批量查询其他表N1查询变IN查询利用Redis缓存热点数据减少DB压力。宽表与物化视图对于报表类、统计分析类的多表Join考虑在离线计算如Spark/Hive或准实时数仓中构建宽表或者使用数据库的物化视图来预计算避免在线业务库做复杂的Join。异步化如果查询非常重将其改为异步任务生成结果后通知用户下载。Q5千万级订单列表查询除了索引和分页还可以做哪些优化思路 覆盖“查询条件优化”、“深分页优化”、“缓存策略”、“数据归档”。查询条件优化确保 WHERE 条件中的字段都有索引避免全表扫描。对于模糊查询如订单号、收货人尽量使用前缀匹配或引入搜索引擎ES。深分页优化传统的 LIMIT offset, size 在数据量大时很慢因为数据库要扫描前 offset 条数据。采用了基于游标Cursor的分页或者延迟关联先查ID再根据ID关联详情性能提升明显。数据归档对于历史订单定期进行归档冷热分离将冷数据迁移到历史表或归档库如HBase减少在线表的数据量。缓存穿透/击穿对热点查询条件增加本地缓存Caffeine或分布式缓存Redis并对空结果进行缓存防止恶意请求打满数据库。三、 消息队列与分布式事务RocketMQQ6RocketMQ事务消息。它的基本实现原理是什么半消息Half Message是什么思路 解释“两阶段提交”思想在MQ中的体现。原理RocketMQ事务消息基于两阶段提交2PC思想。第一阶段发送半消息发送一条“半消息”Half Message到BrokerBroker会暂存这条消息不会投递给消费者。同时生产者会执行本地事务逻辑。第二阶段确认/回滚生产者根据本地事务执行结果向Broker发送 commit 或 rollback 指令。如果 commit Broker会将半消息变为“可消费消息”投递给消费者。如果 rollback Broker会丢弃这条半消息。回查机制补救如果生产者在规定时间内没有发送 commit/rollback 如宕机Broker会定时回调生产者的 checkLocalTransaction 接口询问本地事务的执行状态再决定最终操作。半消息就是已经被发送到Broker但处于“不可见”或“暂存”状态等待生产者最终确认的消息。Q7顺序消息顺序消息在RocketMQ中是怎么保证的如果要保证全局顺序需要注意什么思路 区分“分区有序”和“全局有序”。保证机制RocketMQ的顺序消息是通过MessageQueueSelector实现的。生产者发送消息时通过一个特定的选择器如根据订单ID哈希将同一个业务逻辑的消息发送到同一个MessageQueue中。因为同一个MessageQueue内的消息是顺序存储和消费的所以能保证局部分区有序。全局顺序要保证全局顺序必须让所有消息都发到同一个MessageQueue中。但这会失去分布式并行处理的优势吞吐量会极低。因此实际生产中很少用全局顺序都是用分区顺序即保证同一笔订单的操作顺序即可。消费端注意消费端必须是单线程消费同一个MessageQueue或者使用 MessageListenerOrderly 顺序监听器否则多线程消费还是会打乱顺序。四、 多线程与线程池Q8“自定义线程池、线程隔离”。线程池的核心参数有哪些拒绝策略有哪些怎么选思路 默写参数结合实际场景解释选择。核心参数 corePoolSize 核心线程数、 maximumPoolSize 最大线程数、 keepAliveTime 非核心线程存活时间、 workQueue 工作队列、 threadFactory 线程工厂、 handler 拒绝策略。拒绝策略AbortPolicy 默认直接抛出 RejectedExecutionException 阻止系统正常运行。CallerRunsPolicy 由调用者线程提交任务的线程执行任务减缓新任务提交速度。DiscardPolicy 直接丢弃任务不抛异常。DiscardOldestPolicy 丢弃队列中最老的任务然后尝试重新提交当前任务。选择与应用为了防止大任务抢占核心业务资源使用了线程隔离。单独配置了一个线程池核心数小队列大拒绝策略选择了 CallerRunsPolicy 这样当导出任务过多时会由提交任务的Web线程来执行从而起到一种“负反馈”作用让前端请求变慢但不会拖垮整个系统。五、 系统设计 架构思维Q9自研了“通用异步报表导出引擎”的架构的设计思路为什么要用策略模式泛型思路 体现“解耦”、“复用”、“扩展性”。痛点各个业务线订单、对账、承运商都有导出需求如果每个都写一套导出逻辑会有大量重复代码且难以维护。设计思路策略模式 泛型定义了一个通用的导出接口 ExportStrategyT 其中 T 是泛型代表不同的数据类型订单DTO、对账DTO等。每个业务方只需要实现这个接口编写自己的“数据查询”和“Excel渲染”逻辑即可。模板方法引擎内部有一个抽象的模板方法负责“接收请求 - 生成任务ID - 放入线程池 - 返回任务ID给前端”的通用流程。线程隔离与限流引擎层维护了多个独立的线程池不同业务的导出任务互不干扰。同时使用Redis对任务并发数进行限流防止DB和IO被打满。异步回调与下载任务在后台线程执行生成文件后上传到OSS并通过MQ或WebSocket通知前端前端凭链接下载。优势业务方无需关心异步、线程池、限流等复杂逻辑只需关注“怎么查数据”和“怎么渲染”大大提高了开发效率和系统稳定性。六、 软实力 应变能力Q10如何推动“业务架构”层面的优化的吗思路 讲一个真实或合理虚构的故事体现沟通能力和技术影响力。场景在做物流轨迹大屏展示时最初需求是实时聚合查询8张表订单、运单、节点、车辆、司机、仓库、异常、签收数据量巨大SQL跑不动。行动不死磕SQL优化而是拉上产品经理和数据产品分析他们真正关心的指标是什么。我们发现其实很多数据是“次要”的前端展示时会被折叠或聚合。结果和前端协商将“一次性全量加载”改为“分层加载 按需展开”。第一层只查3张核心表订单、运单、最新节点第二层点击“查看详情”时再通过接口单独查其他表。同时对于历史数据我们引导产品使用“离线报表”代替实时查询。价值最终核心接口的响应时间从5秒降到了200毫秒DB压力大幅降低同时也简化了前端交互获得了业务的认可。这说明技术优化不仅仅是写代码更是通过技术手段引导业务做出更合理的设计。回答技术问题一定要有“场景 - 做法 - 原理/思考”的结构。一定要能讲出“为什么这么做”、“有没有其他方案”、“权衡点在哪里”。
返回列表