日志

  • 日志模块 + ELK,注解+AOP+反射,filebeat匹配logback规范输出。es索引数据迁移,别名迁移
    • 封装log-starter引用spi机制进行设计,使用AOP对自定义注解修饰的方法进行代理,并封装spel表达式支持参数转义
  • ES技术选型对比solr?

任务下发

任务下发:对接外部,补偿机制,规定任务超时时间,定期补偿,根据macro、micro指令的状态来判断

指令补偿,未下发会重新进行分发,搬运中的任务会询问下位系统进行事件上报,macro多阶段任务会查看是否下发下一个micro,补偿超过次数则进行报警

场景发散

单独服务对接mes分发散列保证顺序性,轻量级校验并入库,然后针对指令编号进行散列,保证同一笔指令散列到同一个队列,保证顺序性,指令的进一步封装动作放在mcs,多个mcs节点开多个消费者监听散列对应的队列。实际场景无须保证则直接多消费者对接mes即可

线程管理

背景

原本是mcs对接多个外部系统,半导体secs协议需要维护长连接,导致线程紊乱,机器内存占用过高,且客户需求对标 C# 需要子服务可以单节点部署,故引入线程调配中心(报文对接)。一个secs协议会开5~10个线程,例如内置的监听器、心跳等

解决方案

hsms线程集中管理,mcs发起连接,hsms初始化负载均衡(轮询)计算向哪一台子服务连接模块发送,由对应子服务对接外部系统,rpc直连请求子服务,并等待返回值,成功后维护路由表

子服务底层secs也是socket实现,直连外部系统长连接

心跳,由hsms定期维护,请求子服务,同步获取子服务的连接状态,状态有问题剔除路由表,超时的走重试策略,达到配置次数后注册中心查看服务是否在线,不在线剔除,并重新负载均衡进行连接

任务下发时,hsms进行分发,先过滤服务类型,随后随机选择对应子服务的节点机器分发(RPC服务名调用)。

事件上报

背景

由于最底层的天车不能推数据,需要moc去扫信号拉数据,而信号变化过快,moc扫完后只能先入库后处理,失去了时序性,上报时也是拉数据多节点上报,mcs接收时时序性就已经无法被保证了,一开始没用管控,相当于响应式处理,moc报一个事件mcs处理一个。需要加入状态机流程管控

解决方案

事件上报:业务状态扭转,状态机管控,队列重试,跳链

子服务事件上报时,解析]出CEID后将报文体入队列,mcs多消费者监听,获取消息后走状态机,手动ACK可重入队

状态机接收事件前全部加分布式锁,保证当前指令只有一台能处理,获取锁失败则重入队,保证不丢失。获取锁后,根据指令唯一标识restore状态机,并判断状态,旧状态直接丢弃,后置状态当前无法扭转的加入状态机内置队列等待,可扭转的直接执行,然后persist状态机

若最开始的消息入队列失败,导致状态机无法扭转,此时指令状态异常未结束触发补偿机制

扩展

消息积压怎么解决?消费者管够

车辆管控

路径规划

Dijkstra

路径规划,Dijkstra + 权重调配(MOC A*调度融合进来一起讲)

用每次的指令执行时间计算权重,每个路径都维护历史执行时间,完成指令后会计算全部执行时间的均值维护成权重

路径规划校验点位可以乐观锁,更新成功就说明ok

每次计算都读数据库持久化的最新路径数据,每次都是算到最终终点的最短路径,然后取下一个点位,使用乐观锁update,失败重试并将内存内路径设置为不可达,成功锁定数据并更新db该路径不可达,若其他服务拿到了旧数据,使用了这条路径,最后也会落脚到乐观锁层面,保证线程安全,且失败内存设置不可达与外部更新也达到的了一致。

A*

基础

F=G+H,G静态路径数据,根据速度长度计算的权值;H导向函数,因为实际生产场景可能绕大弯,因为轨道是固定的,按坐标系的曼哈顿距离来计算可以偏差影响较大,后面取用定值。(对比场景,直走和大弯轨,实际场景直走优于大弯轨,但是直走曼哈顿大于弯轨),导向函数不引用也就退化成Dijkstra,没有什么影响。作为精化参考,选择动态系数来取代H,也就是起点终点的阻塞时间,这个是有一个单独线程根据实时车况去刷新的

为什么距离不可以当权值,因为车不是匀速,短弯轨就是没上加速然后减速,三角形,正常的加速 匀速 减速是梯形

优化

动态系数加入,考虑前方拥堵场景,换路超车,不是静态最短路径反而执行速度更快了

动态系数的考量,后续在时间上减去了前半段路径的时间,只考虑天车到达对应路径后的时间影响

静态权重的计算通过最大速度、加速度计算以及轨道距离得到的,30km轨道,车速max 3.5m/s 加速度 2m/s²

天车平衡(相当于任务分配)

平衡检测相当于任务线程,一开始车辆数据都存储在redis,但是这种任务检测线程都是要获取全部数据集然后做过滤的,后面改回存储到db。任务线程检测车辆状态结合业务场景打标,最后车辆线程自己会检查自己的标记,按情况分配任务

小车线程动态分配

先找出未分配的小车
查ip关联车辆的缓存(服务ip拼接车辆编号),找一个车辆最少的ip,ip下无车那就直接选它
找出当前全部存活小车(均分计算每台服务应该划分的数量,同时比较服务配置上限,大于则返回上限),当前ip已分配的小车小于均分值计算差值,也就是可划分数,未分配小车遍历选取当前ip可划分数量的车

ip不可达的剔除,刚加入的ip重新分配,新加入的车考虑均分数量分配问题,主动下线的车也考虑,另开一个服务检测,注册中心查看+ping ip,ping不通的认为服务宕机,拿它的redis set去重新分配。

问题:宕机的服务怎么处理,有线程出问题了如何检测?(不知道,try catch全包了,除非内存溢出,否则会陷入心跳检测死循环,除非下位天车可以推送)

线程池采用0核心 最大线程数按业务需求进行设定的,这些都不是任务线程,相当于都是不能死的。

缓存ttl更新,心跳保活,心跳key查不到认为线程死亡需要重启。

压测

30km轨道,车速max 3.5m/s 加速度 2m/s²

websocket

根im不同,应用不用区分具体用户,每次状态变更所有客户端都要通知到位,直接广播都通知即可。主要使用推送的特性,取代轮询的拉操作。拉操作页面开多后影响性能问题,接口访问量激增。