详细技术方案介绍一、背景1、现状:*目前在线旅客排队性能瓶颈明显,主要采用RedisList存储结构。随着队列中订单数量的增加,查询、插入、判断订单是否在队列中等操作的RT呈指数增长。*目前的旅客排队结构不能满足业务扩展的需要。为了支撑未来业务的快速迭代,旅客排队重构迫在眉睫。2.研究项目*使用Mysql存储排队信息的可行性分析(离线环境压力测试)*对外接口及影响范围梳理(目前对外提供的约20个接口分析),表格如下:接口名称接口路径调用者QPSRT(995)AverageRTRemarksEnterthequeue/queue/enterXXXXXXXXXXXX2.目标1.对外接口不变,由底层存储改造而来,兼容当前在线展示场景,实现乘客排名展示与出队解耦。排名展示保留普通队列、通道队列、优先队列(包括绝对优先),按进入时间排序。出队排序因子是在入队时按照固定规则计算的。使用更灵活的策略算法来计算队列的优先级。出队时,只需要根据排序因子进行排序,从而间接确定出队顺序。2、数据存储排名采用Redis有序集合,队列信息新增mysql存储,分128张表。3、解决当前的性能瓶颈问题,支持后续业务的快速迭代,以及后续需求的扩展。三、总体方案1、新旧方案对比重构前存储架构:redis:list数据结构,key:蜂巢中心点+模型+队列类型重构后存储架构:排序队列:redis有序集,key:蜂巢中心点+车型+队列类型(为了兼容老的)队列信息表:queue_info_xxx,存储在mysql中,按照蜂巢中心点的哈希分表,订单号+车型建立联合唯一索引部分接口新增-old比较接口查看排名是否在队列中进出队列和入队前,1.循环遍历所有队列中的所有元素,循环判断计算位置。2.查询算法组,计算预估时间。遍历查询队列中的所有元素,循环判断是否contain先判断队列中是否存在。这里也会判断,根据不同的队列类型,按照modelcycle&multi-queuetype循环出队列写入redis队列(list),插入日志权益卡,重构,然后会通过订单号从“排队信息表”中查询队列信息,有排队记录,判断是否有排名,没有排名则显示M+(排名队列有在线控制),否则查询“排序队列”,直接返回顺序。查询算法组计算出预估时间,直接查询“队列信息表”,判断是否有记录先写入“队列信息表”。如果没有超过排名阈值,写入对应的“排名队列”更新“队列信息表”的状态。如果有排名,则将其从排名队列中移除,并异步通知standby,通过更新队列信息表的“order_by”字段直接记录日志。把循环遍历全部去掉(当排队的订单增加时,RT呈指数增长,开玩笑,你能想想原因吗?)重构后,存储架构的优点:原来的O(n)时间复杂度,变成了O(1)复杂性。2、队列大小统计重构架构图:排名不限流队列:直接通过ZCARD获取(O(1)时间复杂度)排名限流队列:通过计数器获取总长度(O(1)),降级通过ZCARD获取2)关于新的容量匹配——查询列表[橙色部分]可能存在瓶颈问题——后期有2个优化方向,可以提取topN并截断bufferset队列——如果size超过N,则会转移到其他表存储3.其他流程图:队列进出流程图(此处略)4.表结构设计queue_info_[001~128]:队列信息表按照hive中线点hash分表%128规则,按天归档数据queue_manager:排名队列管理表,主要控制是否限流,hive队列信息queue_log_[001~128]:订单进出记录表,which按照hive中线点的hash%128规则分表,后面会考虑归档。表结构详解-略4.排序字段(order_by)是为排队场景设计的,时间越小越靠前。时间差可以倒序计算,公式如下:~(-1L<<39L)&(~(毫秒时间差))其他规则此处省略。5、历史队列场景兼容性问题排名展示:普通队列、通道队列、优先队列顺序出队:通过权重系数的不同配置,最终计算出不同的排名。第六,灰度方案以城市灰度为基础,优先选择交通量小的城市。7、关闭回滚计划中城市的灰度开关。现有队列中的数据会受到影响,需要迁移工具刷新数据。排队状态没有变化(可能有异常),强制退出9.数据监控&报警乘客排队Grafana监控:监控指标:城市,蜂巢,车型,普通排队数,通道排队数,priorityqueuesalarm:queuesnumberexceedthethresholdpinNailalarm10.时间规划方案调查接口(20个接口)添加改造方案,负责人,进度项接口名称接口路径调用者QPSRT(995)平均RT备注改造方案负责人progress进入team/queue/enterXXXXXXXXXXXX注:接口自测和CR在开发阶段完成,监控告警不影响测试开发,可以在测试阶段开发。11.相关组总结12.资源总结要求重构需要考虑很多细节,包括每一个可能的瓶颈,以及后续的优化和扩展问题。所有变更必须由个人负责(避免遗漏),所有自测(单元测试)必须通过后方可测试。
