这是我参与「第五届青训营 」笔记创作活动的第6天。
一、本堂课重点内容:
学习系统设计的具体流程,学习电商秒杀系统所包含的业务,掌握系统设计常遇到的挑战,学习如何解决系统常遇到的问题,根据原理编写系统程序,优化程序。
二、详细知识点介绍:
(1)系统设计方法论
场景分析(scenario):什么系统,需要哪些功能,多大的并发量
存储设计(storage):数据如何组织,sql存储,nosql存储
服务设计(service):业务功能实现和逻辑整合
可扩展性(scale):解决设计缺陷,提高鲁棒性、扩展性
(2)电商秒杀业务介绍
商品:具有交易价值和属性的信息载体。SPU:standard product unit。SKU:stock keeping unit.
秒杀业务的特点:瞬时流量高,读多写少,实时性要求高。
秒杀的挑战:资源成本,反欺诈,高性能,防止超卖,流量管控,扩展性,鲁棒性。
功能:秒杀活动的发布,秒杀商品的详情,秒杀下单。
并发:万人参与秒杀,QPS,TPS。
存储:MySQL->redis->localcache
子服务:用户服务,风控服务,活动服务,订单服务
基础组件:ID生成器,缓存组件,MQ组件,限流组件
扩展:流量隔离,CDN,缓存优化,流量管控,数据库扩展,服务水平扩展,MQ扩展,redis扩展,服务垂直扩展。
(3)课程实践
(4)课程总结
因为sql是存在硬盘中的,所以性能差,用redis可以解决这个问题,因为redis缓存在内存中。
扣减库存时要保证事务的原子性,防止抢购数量超出库存数。
用Nginx做限流。
三、实践练习例子:
(1)获取物品详情
@GetMapping("/detail")
@RateLimit(rate = RateEnum.RATE_5000_PER_SECONDS)
public ResponseData<?> getProductDetail(@RequestParam(name = "promoId") Long promoId,
@RequestParam(name = "skuId") Long skuId,
@RequestParam(name = "spuId") Long spuId) {
if (promoId <= 0 || skuId <= 0 || spuId <= 0) {
throw new BizException(ResponseEnum.ILLEGAL_ARGUMENT);
}
String key = Constant.generatePromoProductKey(promoId, skuId, spuId);
HPromoProductModel promoProductModel = cacheService.getVal(key);
if (promoProductModel == null) {
promoProductModel = hPromotionService.getPromotionProductDetail(promoId, skuId, spuId);
}
if (promoProductModel == null || !promoProductModel.checkPromo()) {
log.error("promo activity not exist, params = {}", JSON.toJSONString(promoProductModel));
throw new BizException(ResponseEnum.ACTIVITY_NOT_EXIST);
}
log.info("get promo product detail success, res = {}", promoProductModel.getPromoId());
return ResponseData.Success(promoProductModel);
}
(2)创建订单
@PostMapping("/order")
@RateLimit(rate = RateEnum.RATE_1000_PER_SECONDS)
public ResponseData<?> createOrder(@RequestBody CreateOrderRequest createOrderRequest) {
// 登录验证 mock
if (createOrderRequest.getUserId() == null) {
throw new BizException(ResponseEnum.USER_NOT_LOGIN);
}
// risk management
if (!riskManagementService.riskManagement(createOrderRequest.getUserId())) {
throw new BizException(ResponseEnum.USER_UNDER_RISK);
}
CreateOrderModel model = createOrderRequest.convert(PromoConverter::convertCreateOrderModel);
OrderModel order = hPromoOrderService.createOrder(model);
return ResponseData.Success(order);
}
四、课后个人总结:
客户端直接从源站点获取数据,当服务器访问量大时会影响访问速度,进而影响用户体验,且无法保证客户端与原站点间的距离足够段,适合传输数据。CDN解决的正是如何将数据快速可靠的从原站点传递到客户端,通过CDN对数据的分发,用户可以从一个距离较近的服务器获取数据,而不是源站点,从而达到快速访问,且减少原站点负载压力的目的。