.net core实践系列之短信服务-架构优化(一)

简介: .net core实践系列之短信服务-架构优化(一)

前言


通过前面的几篇文章,讲解了一个短信服务的架构设计与实现。然而初始方案并非100%完美的,我们仍可以对该架构做一些优化与调整。


同时我也希望通过这篇文章与大家分享一下,我的架构设计理念。


源码地址:https://github.com/SkyChenSky/Sikiro.SMS/tree/optimize (与之前的是另外的分支)


架构是设计的还是演变的?


架构


该词出自于建筑学。软件架构定义是指软件系统的基础结构,是系统中的实体及实体(服务)之间的关系所进行的抽象描述。而架构设计的目的是为了解决软件系统复杂度带来的问题。


复杂度


系统复杂度主要有下面几点:


  • 高可用
  • 高性能
  • 可扩展
  • 安全性
  • 维护成本
  • 用户规模


业务规模


系统的复杂度导致的直接原因是业务规模。为了用户流畅放心的使用产品,不得不提高系统性能与安全。当系统成为人们生活不可缺一部分时,避免机房停电、挖掘机挖断电缆导致的系统不可用,不得不去思考同城跨机房同步、异地多活的高可用方案。


答案并非二选一


我认为架构,需要在已知可见的业务复杂度与用户规模的基础上进行架构设计;伴随着技术积累与成长而对系统进行架构优化;用户的日益增长,业务的不断扩充,迫使了系统的复杂度增加,为了解决系统带来新的复杂度而进行架构演变。


因此,架构方案是在已有的业务复杂度、用户规模、技术积累度、人力时间成本等几个方面的取舍决策后的结果体现。


原架构


image.png


缺点分析


  • 一般情况下,调度任务轮询数据库,90%的动作是无用功,频繁的数据库访问会对数据库增加不少压力。
  • 为了让调度任务服务进行轮循数据,需要在API优先进行数据持久化,这无疑是降低了API的性能。
  • MongoDB的Update操作相比于Insert操作时低效的,对于日志类数据应增量添加。


因此从上述可见,调度任务服务这块是优化关键点所在。


新架构图


image.png


  • 使用了RabbitMQ的队列定时任务代替调度任务来实现定时发送。
  • 抛弃了调度任务,减少了调用链,同时也减少了应用服务数据量。
  • 对SMS集合在MongoDB里进行按年月的时间划分,对于日志类数据可以在有效的时间范围外进行方便的归档、删除。同时也避免了同集合的数据量过大导致的查询效率缓慢。


队列定时任务


RabbitMQ自身并没有定时任务,然而可以通过消息的Time-To-Live(过期时间)与Dead Letter Exchange(死信交换机)的结合模拟定时发布的功能。具体原理如下:


  • 生产者发布消息,并发布到已申明消息过期时间(TTL)的缓存队列(非真正业务消费队列)
  • 消息在缓存队列等待消息过期,然后由Dead Letter Exchange将消息重新分配到实际消费队列
  • 消费者再从实际消费队列消费并完成业务

 

image.png


Dead Letter Exchange


Dead Letter Exchange与平常的Exchange无异,主要用于消息死亡后通过Dead Letter Exchange与x-dead-letter-routing-key重新分配到新的队列进行消费处理。


消息死亡的方式有三种:


  • 消息进入了一条已经达到最大长度的队列
  • 消息因为设置了Time-To-Live的导致过期
  • 消息因basic.reject或者basic.nack动作而拒绝


Time-To-Live


两种消息过期的方式:


队列申明x-message-ttl参数
var args = new Dictionary<string, object>();
args.Add("x-message-ttl", 60000);
model.QueueDeclare("myqueue", false, false, false, args);
每条消息发布声明Expiration参数
byte[] messageBodyBytes = System.Text.Encoding.UTF8.GetBytes("Hello, world!");
IBasicProperties props = model.CreateBasicProperties();
props.ContentType = "text/plain";
props.DeliveryMode = 2;
props.Expiration = "36000000"
model.BasicPublish(exchangeName,
                   routingKey, props,
                   messageBodyBytes);


RabbitMQ.Client队列定时任务Demo


class Program
    {
        static void Main(string[] args)
        {
            var factory = new ConnectionFactory
            {
                HostName = "10.1.20.140",
                UserName = "admin",
                Password = "admin@ucsmy"
            };
            using (var connection = factory.CreateConnection())
            using (var channel = connection.CreateModel())
            {
                var queueName = "Queue.SMS.Test";
                var exchangeName = "Exchange.SMS.Test";
                var key = "Route.SMS.Test";
                DeclareDelayQueue(channel, exchangeName, queueName, key);
                DeclareReallyConsumeQueue(channel, exchangeName, queueName, key);
                var body = Encoding.UTF8.GetBytes("info: test dely publish!");
                channel.BasicPublish(exchangeName + ".Delay", key, null, body);
            }
        }
        private static void DeclareDelayQueue(IModel channel, string exchangeName, string queueName, string key)
        {
            var retryDic = new Dictionary<string, object>
            {
                {"x-dead-letter-exchange", exchangeName+".dl"},
                {"x-dead-letter-routing-key", key},
                {"x-message-ttl", 30000}
            };
            var ex = exchangeName + ".Delay";
            var qu = queueName + ".Delay";
            channel.ExchangeDeclare(ex, "topic");
            channel.QueueDeclare(qu, false, false, false, retryDic);
            channel.QueueBind(qu, ex, key);
        }
        private static void DeclareReallyConsumeQueue(IModel channel, string exchangeName, string queueName, string key)
        {
            var ex = exchangeName + ".dl";
            channel.ExchangeDeclare(ex, "topic");
            channel.QueueDeclare(queueName, false, false, false);
            channel.QueueBind(queueName, ex, key);
        }
    }


目录
相关文章
|
22天前
|
数据采集 运维 数据可视化
AR 运维系统与 MES、EMA、IoT 系统的融合架构与实践
AR运维系统融合IoT、EMA、MES数据,构建“感知-分析-决策-执行”闭环。通过AR终端实现设备数据可视化,实时呈现温度、工单等信息,提升运维效率与生产可靠性。(238字)
|
1月前
|
数据采集 存储 运维
MyEMS:技术架构深度剖析与用户实践支持体系
MyEMS 是一款开源能源管理系统,采用分层架构设计,涵盖数据采集、传输、处理与应用全流程,支持多协议设备接入与多样化能源场景。系统具备高扩展性与易用性,结合完善的文档、社区、培训与定制服务,助力不同技术背景用户高效实现能源数字化管理,降低使用门槛与运维成本,广泛适用于工业、商业及公共机构等场景。
60 0
|
12天前
|
机器学习/深度学习 数据可视化 网络架构
PINN训练新思路:把初始条件和边界约束嵌入网络架构,解决多目标优化难题
PINNs训练难因多目标优化易失衡。通过设计硬约束网络架构,将初始与边界条件内嵌于模型输出,可自动满足约束,仅需优化方程残差,简化训练过程,提升稳定性与精度,适用于气候、生物医学等高要求仿真场景。
81 4
PINN训练新思路:把初始条件和边界约束嵌入网络架构,解决多目标优化难题
|
13天前
|
缓存 运维 监控
Redis 7.0 高性能缓存架构设计与优化
🌟蒋星熠Jaxonic,技术宇宙中的星际旅人。深耕Redis 7.0高性能缓存架构,探索函数化编程、多层缓存、集群优化与分片消息系统,用代码在二进制星河中谱写极客诗篇。
|
27天前
|
消息中间件 缓存 监控
中间件架构设计与实践:构建高性能分布式系统的核心基石
摘要 本文系统探讨了中间件技术及其在分布式系统中的核心价值。作者首先定义了中间件作为连接系统组件的&quot;神经网络&quot;,强调其在数据传输、系统稳定性和扩展性中的关键作用。随后详细分类了中间件体系,包括通信中间件(如RabbitMQ/Kafka)、数据中间件(如Redis/MyCAT)等类型。文章重点剖析了消息中间件的实现机制,通过Spring Boot代码示例展示了消息生产者的完整实现,涵盖消息ID生成、持久化、批量发送及重试机制等关键技术点。最后,作者指出中间件架构设计对系统性能的决定性影响,
|
1月前
|
前端开发 Java 开发者
MVC 架构模式技术详解与实践
本文档旨在全面解析软件工程中经典且至关重要的 MVC(Model-View-Controller) 架构模式。内容将深入探讨 MVC 的核心思想、三大组件的职责与交互关系、其优势与劣势,并重点分析其在现代 Web 开发中的具体实现,特别是以 Spring MVC 框架为例,详解其请求处理流程、核心组件及基本开发实践。通过本文档,读者将能够深刻理解 MVC 的设计哲学,并掌握基于该模式进行 Web 应用开发的能力。
203 1
|
2月前
|
存储 自然语言处理 前端开发
百亿级知识库解决方案:从零带你构建高并发RAG架构(附实践代码)
本文详解构建高效RAG系统的关键技术,涵盖基础架构、高级查询转换、智能路由、索引优化、噪声控制与端到端评估,助你打造稳定、精准的检索增强生成系统。
346 2
|
边缘计算 Kubernetes 物联网
Kubernetes 赋能边缘计算:架构解析、挑战突破与实践方案
在物联网和工业互联网快速发展的背景下,边缘计算凭借就近处理数据的优势,成为解决云计算延迟高、带宽成本高的关键技术。而 Kubernetes 凭借统一管理、容器化适配和强大生态扩展性,正逐步成为边缘计算的核心编排平台。本文系统解析 Kubernetes 适配边缘环境的架构分层、核心挑战与新兴解决方案,为企业落地边缘项目提供实践参考。
119 0
|
13天前
|
Cloud Native Serverless API
微服务架构实战指南:从单体应用到云原生的蜕变之路
🌟蒋星熠Jaxonic,代码为舟的星际旅人。深耕微服务架构,擅以DDD拆分服务、构建高可用通信与治理体系。分享从单体到云原生的实战经验,探索技术演进的无限可能。
微服务架构实战指南:从单体应用到云原生的蜕变之路