.NET-记一次架构优化实战与方案-底层服务优化

目录

  1. .NET-记一次架构优化实战与方案-梳理篇

  2. .NET-记一次架构优化实战与方案-前端优化

  3. .NET-记一次架构优化实战与方案-底层服务优化

前言

  通过上一篇《.NET-记一次架构优化实战与方案-前端优化》与你们分享了对页面加载优化的心得和经历。虽然优化前端的性能效率,可是因为底层服务的触发方式,根本性问题仍然存在的。html

问题分析

  在本系列第一篇文章咱们提到,底层服务是一系列的JOB,那么问题主要存在如下两点:前端

  • 代码冗余
  • 时效低

代码冗余

例如:git

  • 领奖方法不统一,一次性的写一套,可循环的又写一套。
  
    •  
  • 每一个类型任务都须要独自的实现该任务的完成任务 JOB 与发放奖励 JOB

  

  以上问题直接致使了后续开发、平常维护成本太高。github

  由于早期开发时缺乏沟通,没有封装成公共的方法,而JOB每一个开发人员都单独实现了一套,固然他们未必那么蠢,多是某个先完成了,后续的先前COPY后修改一下。数据库

  试想一下,没新增一个任务类型就要重写一份完成任务的JOB和自动发奖的JOB,这是一个N*2的工做量。若是后续有个规则改了,那是否是每一个JOB都跑去改一次?设计模式

时效低

  因为任务完成是由定时服务根据业务数据源定时批量执行:架构

  1. 定时任务频率低,则致使数据集中过多处理
  2. 定时任务频率高,则致使 Job 对数据库的压力剧增或者 99%的无用查询,无结果并不表明不会形成消耗,由于查询都是要通过下面步骤,创建链接、词法分析、语法分析、选取执行方式、到存储引擎读取数据、返回客户端。
  3. 随着数据源数据量增长,查询耗时也逐渐增长

  以上问题直接致使了,用户完成任务后没法及时查看完成任务并领奖,如需及时查看状态须要在展现页面逻辑额外添加查询后更新的操做负载均衡

优化实施

流程图

方案一(抽离公共点)

目的:减小代码冗余,提升可维护性,提升后续新任务的开发效率框架

具体实施:从业务流程图能够直观的观察出,整个底层业务流程基本一致,只有数据源上的差别,所以能够从如下方面入手优化:前端优化

  1. 抽离出惟一的自动发奖 Job,发奖JOB基于【任务完成结果】进行发奖,逐步去除原个性任务自动发奖 Job。
  2. 自动发奖与手动领奖的具体执行流程一致的,可将其封装成公共方法。分别由H5领奖按钮与领奖JOB进行调用。
  3. 任务完成 Job 使用模板模式,由基类统一业务执行流程,每一个任务类型只需继承任务父类,再由子类重写查询数据源。固然也能够简单粗暴点不使用设计模式,把查询数据源后的完成任务的方法封装成一个公共方法供不一样任务类型的JOB去调用。

从我角度来看,这种方案处理没有任何坏处的。若是真要计较,那就是所涉及的JOB都得改,可是从上述分析出,若是真要重构,工做量也是在写父类模板和封装公共方法,查询数据源代码是能够复用的。可是带来的收益就是良好的扩展性和可维护性。

方案二(业务埋点)

该方案主要对任务参与的触发方式变动,不一样的任务类型由对应的业务最终流程的完成点进行发送队列消息,由任务服务(消费端)订阅相关消息执行任务完成流程。

通俗讲叫业务埋点,固然也能够称其为事件驱动。

架构图

事件驱动架构

  服务之间是高内聚的,它们的耦合度应该很低,当服务须要相互协做时,假设服务“A”须要触发服务“B”中的某段逻辑,日常的方式是让服务A直接串行调用服务B中的某个方法。但前提是A必须知道B的存在,若是B出异常了就会影响到A的正常执行。

这样它们之间就是强耦合的,A必须依赖于B了。这样使得系统更难以维护与扩展,所以引入事件驱动来下降服务间的耦合度

  当服务A须要触发服务B的逻辑时,不要直接调用它,咱们能够将消息发送到消息队列,由服务B订阅相应的队列,并在事件发生时异步执行操做。这意味着服务A、B都依赖于中间件消息队列,但他们之间将不须要知道彼此的存在,所以它们之间于此解耦。

若是将此方案引入咱们的活动业务中,收益主要分为短时间与长期。

短时间收入

  1.  减小无用重复的查询:无需重复查询数据源,只需由业务端推送可靠的消息,减小对数据库的多余压力
  2. 用户体验良好:时效性高,原集中时间点批量处理,现分散到不一样的时间点执行
  3. 伸缩性优秀:RabbitMQ 自带负载均衡功能,在消费能力不足状况下,能够作到业务无损的动态横向扩展。虽然JOB也能够作到,可是须要对物理表作特殊处理,增长中间状态

长期收益

  事件驱动架构长期收益比短时间要大,以RabbitMQ与投资业务举个例子。初期完成核心业务投资理财,投资后咱们须要APP通知用户,在此投资不管成功与否都往RabbitMQ发送消息,投资成功RouteKey=TZ.SUCCESS,投资失败RouteKey=TZ.FAILE。APP通知服务订阅队列NoticeQueue绑定RouteKey=TZ.#,其中包括成功和失败的消息,服务根据消息状态发送APP通知。哪天业务拓展须要增长投资成功积分,只须要添加积分服务订阅队列IntegrationQueue并绑定RouteKey=TZ.SUCCESS消息便可。接着又多了任务活动、信用消费等,如此类推。

  因而可知,如同广播同样,我不知道大家谁要,若是大家须要的就好好监听着,不须要就当耳旁风。

复杂点

分布式事务

  既然咱们使用了RabbitMQ中间件,那么分布式事务会选择基于可靠消息的方案:

  1. 消息可靠性:保证业务端的本地事务执行成功的同时也保证队列消息正常发布
  2. 消息补偿:保证消息消费端的正常消费,若是消费失败后需从新投递,若是从新投递失败可由补偿服务补偿发送。
  3. 幂等处理:因存在自动重试机制,避免重复执行业务致使的意外问题。

模型图

  

  这种基于可靠消息的方案,也叫本地消息事务表的方案,可根据本身状况自研解决,也可以使用相似开源分布式事务框架 CAP 解决。https://github.com/dotnetcore/CAP

结束

  本系列到此基本上分享完了,若是你们有更加好的意见,可在下方评论反馈给我。

相关文章
相关标签/搜索