.NET-记一次架构优化实战与方案-底层服务优化
目录
前言
经过上一篇《.NET-记一次架构优化实战与方案-前端优化》与大家分享了对页面加载优化的心得和经历。虽然优化前端的性能效率,但是由于底层服务的触发方式,根本性问题仍然存在的。
问题分析
在本系列第一篇文章我们提到,底层服务是一系列的JOB,那么问题主要存在以下两点:
- 代码冗余
- 时效低
代码冗余
例如:
- 领奖方法不统一,一次性的写一套,可循环的又写一套。

- 每个类型任务都需要独自的实现该任务的完成任务 JOB 与发放奖励 JOB

以上问题直接导致了后续开发、日常维护成本过高。
因为早期开发时缺少沟通,没有封装成公共的方法,而JOB每个开发人员都单独实现了一套,当然他们未必那么蠢,可能是某个先完成了,后续的先前COPY后修改一下。
试想一下,没新增一个任务类型就要重写一份完成任务的JOB和自动发奖的JOB,这是一个N*2的工作量。如果后续有个规则改了,那是不是每个JOB都跑去改一次?
时效低
由于任务完成是由定时服务根据业务数据源定时批量执行:
- 定时任务频率低,则导致数据集中过多处理
- 定时任务频率高,则导致 Job 对数据库的压力剧增或者 99%的无用查询,无结果并不代表不会造成消耗,因为查询都是要经过下面步骤,建立连接、词法分析、语法分析、选取执行方式、到存储引擎读取数据、返回客户端。
- 随着数据源数据量增加,查询耗时也逐渐增加
以上问题直接导致了,用户完成任务后无法及时查看完成任务并领奖,如需及时查看状态需要在展示页面逻辑额外添加查询后更新的操作
优化实施
流程图

方案一(抽离公共点)
目的:减少代码冗余,提高可维护性,提高后续新任务的开发效率
具体实施:从业务流程图可以直观的观察出,整个底层业务流程基本一致,只有数据源上的差异,因此可以从以下方面入手优化:
- 抽离出唯一的自动发奖 Job,发奖JOB基于【任务完成结果】进行发奖,逐步去除原个性任务自动发奖 Job。
- 自动发奖与手动领奖的具体执行流程一致的,可将其封装成公共方法。分别由H5领奖按钮与领奖JOB进行调用。
- 任务完成 Job 使用模板模式,由基类统一业务执行流程,每个任务类型只需继承任务父类,再由子类重写查询数据源。当然也可以简单粗暴点不使用设计模式,把查询数据源后的完成任务的方法封装成一个公共方法供不同任务类型的JOB去调用。
从我角度来看,这种方案处理没有任何坏处的。如果真要计较,那就是所涉及的JOB都得改,但是从上述分析出,如果真要重构,工作量也是在写父类模板和封装公共方法,查询数据源代码是可以复用的。但是带来的收益就是良好的扩展性和可维护性。
方案二(业务埋点)
该方案主要对任务参与的触发方式变更,不同的任务类型由对应的业务最终流程的完成点进行发送队列消息,由任务服务(消费端)订阅相关消息执行任务完成流程。
通俗讲叫业务埋点,当然也可以称其为事件驱动。
架构图

事件驱动架构
服务之间是高内聚的,它们的耦合度应该很低,当服务需要相互协作时,假设服务“A”需要触发服务“B”中的某段逻辑,平常的方式是让服务A直接串行调用服务B中的某个方法。但前提是A必须知道B的存在,如果B出异常了就会影响到A的正常执行。
这样它们之间就是强耦合的,A必须依赖于B了。这样使得系统更难以维护与扩展,因此引入事件驱动来降低服务间的耦合度。
当服务A需要触发服务B的逻辑时,不要直接调用它,我们可以将消息发送到消息队列,由服务B订阅相应的队列,并在事件发生时异步执行操作。这意味着服务A、B都依赖于中间件消息队列,但他们之间将不需要知道彼此的存在,因此它们之间于此解耦。
如果将此方案引入我们的活动业务中,收益主要分为短期与长期。
短期收入
- 减少无用重复的查询:无需重复查询数据源,只需由业务端推送可靠的消息,减少对数据库的多余压力
- 用户体验良好:时效性高,原集中时间点批量处理,现分散到不同的时间点执行
- 伸缩性优秀:RabbitMQ 自带负载均衡功能,在消费能力不足情况下,可以做到业务无损的动态横向扩展。虽然JOB也可以做到,但是需要对物理表做特殊处理,增加中间状态
长期收益
事件驱动架构长期收益比短期要大,以RabbitMQ与投资业务举个例子。初期完成核心业务投资理财,投资后我们需要APP通知用户,在此投资无论成功与否都往RabbitMQ发送消息,投资成功RouteKey=TZ.SUCCESS,投资失败RouteKey=TZ.FAILE。APP通知服务订阅队列NoticeQueue绑定RouteKey=TZ.#,其中包括成功和失败的消息,服务根据消息状态发送APP通知。哪天业务拓展需要增加投资成功积分,只需要添加积分服务订阅队列IntegrationQueue并绑定RouteKey=TZ.SUCCESS消息即可。接着又多了任务活动、信用消费等,如此类推。
由此可见,如同广播一样,我不知道你们谁要,如果你们需要的就好好监听着,不需要就当耳旁风。
复杂点
分布式事务
既然我们使用了RabbitMQ中间件,那么分布式事务会选择基于可靠消息的方案:
- 消息可靠性:保证业务端的本地事务执行成功的同时也保证队列消息正常发布
- 消息补偿:保证消息消费端的正常消费,如果消费失败后需重新投递,如果重新投递失败可由补偿服务补偿发送。
- 幂等处理:因存在自动重试机制,避免重复执行业务导致的意外问题。
模型图

这种基于可靠消息的方案,也叫本地消息事务表的方案,可根据自己情况自研解决,也可使用类似开源分布式事务框架 CAP 解决。https://github.com/dotnetcore/CAP
结束
本系列到此基本上分享完了,如果大家有更加好的意见,可在下方评论反馈给我。
.NET-记一次架构优化实战与方案-底层服务优化的更多相关文章
- .NET-记一次架构优化实战与方案-目录
前言 本系列是根据我公司的某块业务优化进行改写的,为了避免触发法律的红线,我对部分代码做了截取并打码. 因为优化方案是针对现有业务的问题情况进行的,不做任何太过过分吹牛逼.一切以基于现有的业务,优化处 ...
- .NET-记一次架构优化实战与方案-前端优化
目录 .NET-记一次架构优化实战与方案-梳理篇 .NET-记一次架构优化实战与方案-前端优化 .NET-记一次架构优化实战与方案-底层服务优化 前言 上一篇<.NET-记一次架构优化实战与方案 ...
- .NET-记一次架构优化实战与方案-梳理篇
目录 .NET-记一次架构优化实战与方案-梳理篇 .NET-记一次架构优化实战与方案-前端优化 .NET-记一次架构优化实战与方案-底层服务优化 前言 程序员输出是他敲写的代码,那么输入就是他思考好的 ...
- .NET-架构优化实战-底层服务优化
原文:.NET-架构优化实战-底层服务优化 前言 问题分析 在本系列第一篇文章我们提到,底层问题主要存在以下两点: 代码冗余 时效低 代码冗余 例如: 领奖方法不统一,一次性的写一套,可循环的又写一套 ...
- MySQL架构优化实战系列4:SQL优化步骤与常用管理命令
- MySQL——索引优化实战
上篇文章中介绍了索引的基本内容,这篇文章我们继续介绍索引优化实战.在介绍索引优化实战之前,首先要介绍两个与索引相关的重要概念,这两个概念对于索引优化至关重要. 本篇文章用于测试的user表结构: 索引 ...
- .NET-架构优化实战-梳理篇
原文:.NET-架构优化实战-梳理篇 前言 程序员输出是他敲写的代码,那么输入就是他思考好的设计.因此不做设计是不存在,设计只分优秀的设计和糟糕的设计.为了避免过度设计浪费成本,需要针对现有业务与问题 ...
- 企业级Web Nginx 服务优化
企业级Web Nginx 服务优化 http://blog.51cto.com/search/result?q=%E4%BC%81%E4%B8%9A%E7%BA%A7Web+Nginx+%E6%9C% ...
- Java生鲜电商平台-SpringCloud微服务架构高并发参数优化实战
Java生鲜电商平台-SpringCloud微服务架构高并发参数优化实战 一.写在前面 在Java生鲜电商平台平台中相信不少朋友都在自己公司使用Spring Cloud框架来构建微服务架构,毕竟现在这 ...
随机推荐
- 【LeetCode】两数相加
题目描述 给出两个非空的链表用来表示两个非负的整数.其中,它们各自的位数是按照逆序的方式存储的,并且它们的每个节点只能存储一位数字. 如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和. ...
- DAY4(PYTHON)列表的嵌套,range,for
li=['a','b','开心','c'] print(li[2].replace ( ' 心 ', ' kaixin ' ) ) 输出:'a','b','开kaixin','c' li= ['abc ...
- Bayboy功能详解
Bayboy功能详解 一.Badboy中的检查点 1.1以sogou.com搜索为例,搜索测试 步骤:打开Badboy工具,在地址栏中输入搜狗网址:输入 测试 进行搜索:点击红色按钮停止录制 1.2添 ...
- 关于一体机外卖单不打印外卖单号FAQ(适用正餐6.0.09,轻餐4.0.6.1,轻餐4.0.6.2)
适用情景:升级版本后打印机打印出的外卖小票不出现外卖单号. 解决方案:设置-功能设置-小票设置-小票自定义-前台小票-外卖订单-------选择编辑,选中右侧中外卖单号或者外卖订单编号,点击保存即可. ...
- SQL 中常用存储过程xp_cmdshell运行cmd命令
目的: 使用SQL语句,在D盘创建一个文件夹myfile 首先查询系统配置 SELECT * FROM sys.configurations WHERE name='xp_cmdshell' OR n ...
- Linux: 软件包管理之rpm与yum [转]
软件包的安装和卸载时很平常的事,但在Linux上面却不简单..Linux的其中一个哲学就是一个程序只做一件事,并且做好.组合小程序来完成复杂的任务,这样做有很多好处,但是各个小程序之间往往会存在着复杂 ...
- Vue技巧小结(持续更新)
1. 动态生成的input自动focus 背景: input元素在需要时才插入DOM,这时元素用autofocus属性第一次是可以获取焦点,但是如果有第二个,就不再生效,所以得另外的办法. 方法: / ...
- 关于Three.js基本几何形状
一.有关球体SphereGeometry构造函数参数说明 SphereGeometry(radius, widthSegments, heightSegments, phiStart, phiLeng ...
- 【大数据技术】Hadoop三大组件架构原理(HDFS-YARN-MapReduce)
目前,Hadoop还只是数据仓库产品的一个补充,和数据仓库一起构建混搭架构为上层应用联合提供服务. Hadoop集群具体来说包含两个集群:HDFS集群和YARN集群,两者逻辑上分离,但物理上常在一起. ...
- C#中webbrowser与javascript(js)交互的方法
今天在做一个项目的时候需要用c#搞一个webbrowser,然后有些地方还需要与js交互.所以就查了一下资料,发现很多博客提到了但是却没有说下具体的操作.所以我就写一下. 开发环境是Visual St ...