1.12306整体结构深度优化,节假日春节提前预售火车票。预售点会有大量人潮抢购。由于高并发导致服务瘫痪。1.1解决方案内存计算和剩余票异步交易系统(调峰方案)数据库高可用建设(读写分离)1.1.1调峰方案1.调峰方案:针对瞬时流量,首先我们想到的是中间件Peakshaving,将直接调用转化为间接异步推送。中间队列瞬间接受前端流量,另一端平滑推送消息。2.答疑:下单时,我们需要答疑解惑。因为每个人的回答速度不同,所以抢票的时间是错开的。3.按时间段出票:分多个时间段出票1.1.2数据同步方案架构后台管理员根据日期生成出行计划、座位信息、车次信息,通过同步数据到ES和redislogstash中间。2、用户下单分析用户下单时,经历了下单、扣库存、付款的过程。高并发场景下,保证门票不买多卖不多,支付后门票真实有效。2.1下单分析(异步下单的优势)1、方案一:用户下单后,立即扣掉库存,等待用户付款。而创建订单和扣除库存是原子操作。保证不超卖。解决问题:极并发请求下,每创建一个订单,内存操作对性能影响很大。订单数据需要保存到数据库中,给数据库带来了很大的压力。如果很多人下单,但不付款。会导致很多票卖不出去。2、解决方案2在极并发场景下,当库存降为0时,很多用户抢单却无法支付。而对数据的IO操作是避免不了的。3.选项3.用户选择出行计划,点击下单-->进入订单服务集群,--》判断redis库存是否充足,no(直接响应机票已售罄),yes(预扣)inventory)-》将订单信息发送给mq,es同步库存信息-》如果用户支付,订单处理服务会存储订单信息并返回成功信息,如果支付超时,redis会返回inventory,es返回库存2.1下单操作2.1.1nginx限流配置为了防止一些抢票助手发送无用的请求,使用nginx进行限流操作1.限制访问频率:limit_req_zone:单位时间内的请求数,使用漏斗算法2.限制并发连接数:limit_conn_zone:同时连接数。2.1.2订货流程1.订单生成:预扣库存找到对应日期、对应车次、对应座位类型(站票、座票、硬卧、软卧等)的计划库存,进行库存扣减.分配座位遍历指定座位类型的所有车厢的key(集合)。遍历集合得到每辆车的座位(集合)。遍历集合获取每个座位对应的状态。如果座位未售出,请标记座位并更改座位状态。生成订单在创建订单的时候,我们可以使用一个线程来完成。而线程执行完成后,我们需要获取线程的执行结果,使用Callable来执行订单创建。在线程中创建订单对象。将指定日期的乘车计划封装到一个对象中。生成订单。Redis排队使用Redis中的ZSet集合来存储排队信息,使用:车次+登机日期+用户id作为key,使用当前系统时间的纳秒值作为value。2、同步ES库存:订单服务向mq发送同步信息(乘车日期、座位类型、车次)。es同步服务监听mq,获取发送信息。根据搜索条件查询数据,进行库存扣减。3.发送订单数据:创建订单和用户信息,设置交换和队列。发送订单信息,发送订单数据,跳转到订单成功界面。下单成功界面调用排队界面显示排队信息。2.1.3订单处理流程1.环境准备:因为下订单,写操作远大于读操作,所以mysql采用双主双从构建模式。2、保存订单:订单服务监控mq,如果有订单产生,则将订单信息存入仓库。3、删除排队信息:订单保存成功后,将删除排队信息。4、通过websocket将订单结果发送给客户端:保存订单数据后,调用WebSocketServer完成消息推送。2.2订单优化用户已经下过订单,再次提交订单是否会扣款?用户虽然下了单,但一直没有付款。预扣库存是否存在线程安全问题。2.2.1预扣库存优化当用户购买了指定列车的车票后,我们就可以不再预扣仓库。根据用户信息和乘车计划id查询订单信息,查到则不扣库存。2.2.2库存回滚1、方案一(延迟队列):延迟队列:消息发送后,消费者在一定时间后才能拿到消息进行消费。2、方案二(死信队列):死信队列:队列中一条消息成为死信队列后,该消息会被重发到另一个交换机,即死信队列。消息变成死信队列:消息被拒绝,requeue参数设置为false。消息过期。队列达到最大长度。因为扣库存是一个多服务,所以需要通过分布式锁来解决(mysql实现,zookeeper实现,redis实现)。
