点击空白处退出提示
中石油智能文传项目
我要开发同款作品详情
项目背景:为100多万中石油员工提供智能办公服务,可以快速高效的线上完成公文、督办、信息、会议等业务
项目职责:4个系统以及三个关联方的整体计划、协调工作,并独立完成一级督办系统从0到1的DDD建模设计、开发、
部署以及上线工作
工作业绩:采用RocketMQ实现一级督办、二级督办、日常催办、统推督办系统解耦、异步、一致性,极大的缩短了接
口的运行时间
项目时间:2019.1-2020.10
项目问题:
1. 督办信息发布频繁Full GC
技术挑战:高并发情况下一级督办发布督办信息后通知二级督办接收数据,由于对象太大导致新生代占满大量零
时存活对象进入老年代 ,导致JVM每隔一小时执行一次Full GC,影响系统性能
解决方案:我们机器是8核16G的,JVM参数:-Xms8g -Xmx8g -Xmn4g -XX:SurvivorRatio=6 -
XX:MaxTenuringThreshold=15 -XX:PretenureSizeThreshold=3145728 -XX:+UseParNewGC -
XX:+UseConcMarkSweepGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:gc.log,设计堆内
存为8G,新生代为4G,Eden和Survivor的占比为6:1:1,每个Survivor区大概占600M,保证每次young GC的时
候存活对象进入Survivor,减少Full GC
实现效果:调高Survivor区大小后,Full GC保持在每月执行一次的概率,极大提高了系统性能
2. 一级督办和二级督办强一致性分布式事务问题
技术挑战:一级督办发布督办信息后需要通知二级督办接收因为接收的二级单位是多选,在下发的时候同步下
发,一般情况下需要下发几百个二级、三级单位,每次下发在二级督办系统就要执行600ms以上的时间,如果单
位上千则时间就会达到秒级以上,极大影响了系统性能
解决方案:为了提高系统性能设计用RocketMQ异步调用二级督办,但是采用MQ会导致消息丢失、消息重复消
0mG3pcQS202210101022
费等问题,所以我采用RocketMQ的分布式事务机制发送half消息保证一级督办发送消息到RocketMQ解决消息
丢失问题,在二级督办采用Redis nx特性保证不重复消费这个消息,采用zookeeper保证数据一致性
实现效果:保证一级督办、二级督办数据最终一致性,系统间解耦,增大了系统运行效率
3. 基于 nginx + redis + ehcache 3层缓存架构的缓存雪崩问题
技术挑战:因为一级督办在每月1号并发量在五千以上,必须保证多级缓存的高可用,因为一些不可抗力尤其是
redis全体宕机,则并发全部打到数据库,直接把数据库打死
解决方案:缓存雪崩可能会导致整个系统崩溃,因此考虑了比较完善的方案,分为事前、事中、事后三个层面来
应对缓存雪崩的场景。
事前:确保Redis本身的高可用性,数据恢复备份、主从架构+哨兵,Redis cluster,一旦主节点挂了,从节
点跟上
事中:当redis不可用时,少量请求可以走缓存生产服务的本地缓存ehcache获取数据,基于hystrix对商品服
务和redis操作做限流保护 配置降级、超时、熔断策略;从而保证发生缓存雪崩时缓存生产服务不会被拖死
事后:基于redis的数据备份,快速将redis重新跑起来对外提供服务
实现效果:使用事前,事中,事后一整套方案确保了系统的的高可用性
4. 分布式缓存重建并发冲突解决方案
技术挑战:在特殊场景下数据在所有的缓存中都不存了,就需要重新查询数据写入缓存、重建缓存、分布式重建
缓存在不同的机器上,不同的服务实例中,去做上面的事情,就会导致多个机器分布式重建去读取相同的缓存,
再写入缓存,可能导致旧数据覆盖掉新数据
解决方案:
基于zookeeper分布式锁的解决方案变更缓存重建以及空缓存请求重建,更新redis之前,都需要先获取商品id的
分布式锁
拿到分布式锁之后,需要根据时间版本比较一下,如果自己的版本新于redis中的版本,那么就更新,否则就不更
新。
如果拿不到分布式锁,那么就等待,直到自己获取到分布式锁
实现效果:使同服务的不同实例强制按顺序去更新缓存,杜绝了旧数据覆盖新数据的问题
5. 获取督办信息时缓存穿透导致的MySQL压力倍增问题
技术挑战:在并发较高时,大量的请求没有命中缓存,可能导致大量流量全打在商品服务的MySQL上,导致
MySQL压力过大,有随时被打死的风险。
解决方案:使用hystrix线程池对商品服务进行限流,正常情况下,设置10个线程,并设置等待队列。
实现效果:避免了MySQL被打死的风险,确保了MySQL的可用性。
6. Nginx缓存命中率低问题
技术挑战:用户流量是均匀打落到各个nginx上去的,实际上每个nginx都会发送请求去redis上获取缓存数据,
放到自己的本地,缓存命中率很低而且导致redis的压力暴增。
解决方案:双层nginx部署架构 + lua脚本实现一致性hash流量分发策略实现效果
实现效果:Nginx缓存命中率提升了,降低了redis的压力
7. 数据库分库分表
技术挑战:随着时间的推移数据库每张表中的数据量越来越大,尤其是督办信息表,单表数据量太大导致sql执行
效率降低
解决方案:使用sharding-jdbc,将数据库水平拆分为16个库,每个库16张表,将之前的单表分成了256张表,部
署2台数据库物理服务器,数据库服务器配置为8核32G,每台物理服务器上放8个逻辑库,分库分表完成后订单
表单表数据量在120万左右。最开始采用程序对数据进行双写不停机迁移,之后如果数据量再过大直接成倍扩容
物理数据库服务器数量即可。
实现效果:将数据均匀的分到了各个库的各个表里,减少了单表数据量,提高了sql查询效率,同时实现了动态的
缩容和扩容
8. 督办信息创建等核心接口的幂等性保障
技术挑战:服务之间的重试调用,服务重复调用会导致重复创建督办信息,从而导致系统数据出现混乱。
解决方案:在开始业务逻辑处理之前,首先使用接口类名称+接口方法名称+订单唯一标识拼接这个请求对应的唯
一标识,然后基于Redis nx特性插入这个key查看是否创建督办信息的幂等性。
实现效果:通过Redis nx特性,保障了督办信息创建数据的正确性。
声明:本文仅代表作者观点,不代表本站立场。如果侵犯到您的合法权益,请联系我们删除侵权资源!如果遇到资源链接失效,请您通过评论或工单的方式通知管理员。未经允许,不得转载,本站所有资源文章禁止商业使用运营!
下载安装【程序员客栈】APP
实时对接需求、及时收发消息、丰富的开放项目需求、随时随地查看项目状态
评论