阅读:1903回复:0
大数据量、高并发业务怎么优化?一. 大数据量上传写入优化 1.1 如上功能描述很简单,但是对于技术侧想要做好这个功能,保证大用户量(比如达到百万级别)下,系统正常运行,功能正常其实是需要仔细思考的,博主这里给出思路:
1.2 批量写入代码优化
spring.datasource.master.jdbc-url=jdbc:mysql://localhost:3306/test_db?allowMultiQueries=true&characterEncoding=utf8&autoReconnect=true&useSSL=false&rewriteBatchedStatements=true
insert into im_notice_app_ref(notice_id, app_id, create_time) values <foreach collection="list" separator="," item="item"> (#{item.noticeId}, #{item.appId}, #{item.createTime}) </foreach> 二. 大事务优化,减小影响范围,提升系统处理能力 @Transactional 大于 Spring 提供得事务注解,许多人都知道,但是在高并发下,不建议使用,推荐通过编程式事务来手动控制事务提交或者回滚,减少事务影响范围 如下是一段订单超时未支付回滚业务数据得代码,采用 @Transactional 事务注解 @Transactional(rollbackFor = Exception.class) public void doUnPaidTask(Long orderId) { // 1. 查询订单是否存在 Order order = orderService.getById(orderId); if (order == null) { throw new BusinessException(String.format("订单不存在,orderId:%s", orderId)); } if (order.getOrderStatus() != OrderStatusEnum.ORDER_PRE_PAY.getOrderStatus()) { throw new BusinessException(String.format("订单状态错误,order:%s", order)); } // 2. 设置订单为已取消状态 order.setOrderStatus((byte) OrderStatusEnum.ORDER_CLOSED_BY_EXPIRED.getOrderStatus()); order.setUpdateTime(new Date()); if (!orderService.updateById(order)) { throw new BusinessException("更新数据已失效"); } // 3.商品货品数量增加 LambdaQueryWrapper<OrderItem> queryWrapper = Wrappers.lambdaQuery(); queryWrapper.eq(OrderItem::getOrderId, orderId); List<OrderItem> orderItems = orderItemService.list(queryWrapper); for (OrderItem orderItem : orderItems) { if (orderItem.getSeckillId() != null) { // 秒杀单商品项处理 Long seckillId = orderItem.getSeckillId(); SeckillService seckillService = SpringContextUtil.getBean(SeckillService.class); if (!seckillService.addStock(seckillId)) { throw new BusinessException("秒杀商品货品库存增加失败"); } } else { // 普通单商品项处理 Long goodsId = orderItem.getGoodsId(); Integer goodsCount = orderItem.getGoodsCount(); if (!goodsDao.addStock(goodsId, goodsCount)) { throw new BusinessException("秒杀商品货品库存增加失败"); } } } // 4. 返还优惠券 couponService.releaseCoupon(orderId); log.info("---------------订单orderId:{},未支付超时取消成功", orderId); } 采用编程式事务对其优化,代码如 @Resource private PlatformTransactionManager platformTransactionManager; @Resource private TransactionDefinition transactionDefinition; public void doUnPaidTask(Long orderId) { // 启用编程式事务 // 1. 在开启事务钱查询订单是否存在 Order order = orderService.getById(orderId); if (order == null) { throw new BusinessException(String.format("订单不存在,orderId:%s", orderId)); } if (order.getOrderStatus() != OrderStatusEnum.ORDER_PRE_PAY.getOrderStatus()) { throw new BusinessException(String.format("订单状态错误,order:%s", order)); } // 2. 开启事务 TransactionStatus transaction = platformTransactionManager.getTransaction(transactionDefinition); try { // 3. 设置订单为已取消状态 order.setOrderStatus((byte) OrderStatusEnum.ORDER_CLOSED_BY_EXPIRED.getOrderStatus()); order.setUpdateTime(new Date()); if (!orderService.updateById(order)) { throw new BusinessException("更新数据已失效"); } // 4. 商品货品数量增加 LambdaQueryWrapper<OrderItem> queryWrapper = Wrappers.lambdaQuery(); queryWrapper.eq(OrderItem::getOrderId, orderId); List<OrderItem> orderItems = orderItemService.list(queryWrapper); for (OrderItem orderItem : orderItems) { if (orderItem.getSeckillId() != null) { // 秒杀单商品项处理 Long seckillId = orderItem.getSeckillId(); SeckillService seckillService = SpringContextUtil.getBean(SeckillService.class); RedisCache redisCache = SpringContextUtil.getBean(RedisCache.class); if (!seckillService.addStock(seckillId)) { throw new BusinessException("秒杀商品货品库存增加失败"); } redisCache.increment(Constants.SECKILL_GOODS_STOCK_KEY + seckillId); redisCache.deleteCacheSet(Constants.SECKILL_SUCCESS_USER_ID + seckillId, order.getUserId()); } else { // 普通单商品项处理 Long goodsId = orderItem.getGoodsId(); Integer goodsCount = orderItem.getGoodsCount(); if (!goodsDao.addStock(goodsId, goodsCount)) { throw new BusinessException("秒杀商品货品库存增加失败"); } } } // 5. 返还优惠券 couponService.releaseCoupon(orderId); // 6. 所有更新操作完成后,提交事务 platformTransactionManager.commit(transaction); log.info("---------------订单orderId:{},未支付超时取消成功", orderId); } catch (Exception e) { log.info("---------------订单orderId:{},未支付超时取消失败", orderId, e); // 7. 发生异常,回滚事务 platformTransactionManager.rollback(transaction); } } 可以看到采用编程式事务后,我们将查询逻辑排除在事务之外,减小了其影响范围,也就提升了性能,在高并发场景下, 性能优先的场景,我们甚至可以考虑不适用事务 三. 客户端海量日志上报优化 线上项目客户端,采用tcp协议与日志采集服务建立连接,上报日志数据。业务高峰期下,会有同时成千个客户端建立连接实时上报日志数据 如上场景,高峰期下,对日志采集服务会造成不小的压力,处理服务处理不当,会造成高峰期下,服务卡顿、CPU占用过高、内存溢出等。 这里给出海量日志高并发下优化点:
原文地址:https://www.cnblogs.com/wayn111/archive/2022/12/08/16964992.html |
|