设为首页 - 加入收藏 ASP站长网(Aspzz.Cn)- 科技、建站、经验、云计算、5G、大数据,站长网!
热搜: 手机 数据 公司
当前位置: 首页 > 服务器 > 安全 > 正文

一篇文了解分布式队列编程:从模型、实战到优化(4)

发布时间:2021-01-08 08:29 所属栏目:53 来源:网络整理
导读:典型的后台任务处理应用包括工单处理、火车票预订系统、机票选座等.我们所面对的问题是为运营人员创建工单.一次可以为多个运营人员创建多个工单.这个应用场景和火车票购买非常类似.工单相对来说更加抽象,所以,下文

典型的后台任务处理应用包括工单处理、火车票预订系统、机票选座等.我们所面对的问题是为运营人员创建工单.一次可以为多个运营人员创建多个工单.这个应用场景和火车票购买非常类似.工单相对来说更加抽象,所以,下文会结合火车票购买和运营人员工单分配这两种场景同时讲解.

典型的工单创建要经历两个阶段:数据筛选阶段、工单创建阶段.例如,在火车票预订场景,数据筛选阶段用户选择特定时间、特定类型的火车,而在工单创建阶段,用户下单购买火车票.

挑战

工单创建往往会面临如下挑战:

  • 数据一致性问题.以火车票预订为例,用户筛选火车票和最终购买之间往往有一定的时延,意味着两个操作之间数据是不一致的.在筛选阶段,工程师们需决定是否进行车票锁定,如果不锁定,则无法保证出票成功.反之,如果在筛选地时候锁定车票,则会大大降低系统效率和出票吞吐量.
  • 约束问题.工单创建需要满足很多约束,主要包含两种类型:动态约束,与操作者的操作行为有关,例如购买几张火车票的决定往往发生在筛选最后阶段.隐性约束,这种约束很难通过界面进行展示,例如一个用户购买了5张火车票,这些票应该是在同一个车厢的临近位置.
  • 优化问题.工单创建往往是约束下的优化,这是典型的统筹优化问题,而统筹优化往往需要比较长的时间.
  • 响应时间问题.对于多任务工单,一个请求意味着多个任务产生.这些任务的创建往往需要遵循事务性原则,即All or Nothing.在数据层面,这意味着工单之间需要满足串行化需求(Serializability).大数据量的串行化往往意味着锁冲突延迟甚至失败.无论是延迟机制所导致的长时延,还是高创建失败率,都会大大伤害用户体验.

构思

如果将用户筛选的最终规则做为消息存储下来,并发送给工单创建系统.此时,工单创建系统将具备创建工单所需的全局信息,具备在满足各种约束的条件下进行统筹优化的能力.如果工单创建阶段采用单实例部署,就可以避免数据锁定问题,同时也意味着没有锁冲突,所以也不会有死锁或任务延迟问题.

居于以上思路,在多工单处理系统的模型中,筛选阶段的规则创建系统将充当生产者角色,工单创建系统将充当消费者角色,筛选规则将作为消息在两者之间进行传递.这就是典型的分布式队列编程架构.根据工单创建量的不同,可以采用数据库或开源的分布式消息中间件作为分布式队列.

架构

该架构流程如下图:

  • 用户首选进行规则创建,这个过程主要是一些搜索筛选操作.
  • 用户点击工单创建,TicketRule Generator将把所有的筛选性组装成规则消息并发送到队列里面去.
  • Ticket Generator作为一个消费者,实时从队列中读取工单创建请求,开始真正创建工单.

采用该架构,我们在数据锁定、运筹优化、原子性问题都能得到比较好成果:

  • 数据锁定推迟到工单创建阶段,可以减少数据锁定范围,最大程度的降低工单创建对其他在线操作的影响范围.
  • 如果需要进行统筹优化,可以将Ticket Generator以单例模式进行部署(参见单例服务优化).这样,Ticket Generator可以读取一段时间内的工单请求,进行全局优化.例如,在我们的项目中,在某种条件下,运营人员需要满足分级公平原则,即相同级别的运营人员的工单数量应该接近,不同级别的运营人员工单数量应该有所区分.如果不集中进行统筹优化,实现这种优化规则将会很困难.
  • 保障了约束完整性.例如,在我们的场景里面,每个运营人员每天能够处理的工单是有数量限制的,如果采用并行处理的方式,这种完整性约束将会很难实施.

3.优化篇

接下来重点阐述工程师运用分布式队列编程构架的时候,在生产者、分布式队列以及消费者这三个环节的注意点以及优化建议.

确定采用分布式队列编程模型之后,主体架构就算完成了,但工程师的工作还远远未结束.天下事必做于细,细节是一个不错的架构向一个优秀的系统进阶的关键因素.优化篇选取了作者以及其同事在运用分布式队列编程模型架构时所碰到的典型问题和解决方案.

这里些问题出现的频率较高,如果你经验不够,很可能会“踩坑”.希望通过这些讲解,帮助读者降低分布式队列编程模型的使用门槛.本文将对分布式队列编程模型的三种角色:生产者(Producer),消费者(Consumer)分别进行优化讨论.

生产者优化

在分布式队列编程中,生产者往往并非真正的生产源头,只是整个数据流中的一个节点,这种生产者的操作是处理-转发(Process-Forward)模式.

这种模式给工程师们带来的第一个问题是吞吐量问题.这种模式下运行的生产者,一边接收上游的数据,一边将处理完的数据发送给下游.本质上,它是一个非常经典的数学问题,其抽象模型是一些没有盖子的水箱,每个水箱接收来自上一个水箱的水,进行处理之后,再将水发送到下一个水箱.

工程师需要预测水源的流量、每个环节水箱的处理能力、水龙头的排水速度,最终目的是避免水溢出水箱,或者尽可能地减小溢出事件的概率.实际上流式编程框架以及其开发者花了大量的精力去处理和优化这个问题.下文的缓存优化和批量写入优化都是针对该问题的解决方案.

第二个需要考虑的问题是持久化.由于各种原因,系统总是会宕机.如果信息比较敏感,例如计费信息、火车票订单信息等,工程师们需要考虑系统宕机所带来的损失,找到让损失最小化的解决方案.持久化优化重点解决这一类问题.

缓存优化

处于“处理-转发”模式下运行的生产者往往被设计成请求驱动型的服务,即每个请求都会触发一个处理线程,线程处理完后将结果写入分布式队列.如果由于某种原因队列服务不可用,或者性能恶化,随着新请求的到来,生产者的处理线程就会产生堆积.这可能会导致如下两个问题:

  • 系统可用性降低.由于每个线程都需要一定的内存开销,线程过多会使系统内存耗尽,甚至可能产生雪崩效应导致最终完全不可用.
  • 信息丢失.为了避免系统崩溃,工程师可能会给请求驱动型服务设置一个处理线程池,设置最大处理线程数量.这是一种典型的降级策略,目的是为了系统崩溃.但是,后续的请求会因为没有处理线程而被迫阻塞,最终可能产生信息丢失.例如:对于广告计费采集,如果采集系统因为线程耗尽而不接收客户端的计费行为,这些计费行为就会丢失.

(编辑:ASP站长网)

网友评论
推荐文章
    热点阅读