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

本文涉及的产品
短信服务,200条 3个月
短信服务,100条 3个月
国际/港澳台短信套餐包,全球plus 100条 6个月
简介: .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);
        }
    }


目录
相关文章
|
1天前
|
存储 算法 Linux
探索现代操作系统的架构与优化
本文深入探讨了现代操作系统的核心架构及其性能优化策略。通过对主流操作系统架构的分析,揭示其在多任务处理、内存管理和文件系统等方面的特点。同时,针对当前技术趋势,提出一系列优化措施,旨在提升系统的运行效率和用户体验。通过实例分析,展示如何在实际场景中应用这些优化技术,确保系统在高负载下的稳定运行。
|
4天前
|
Cloud Native 持续交付 微服务
云原生时代的微服务架构实践
【9月更文挑战第30天】随着云计算技术的不断进步,云原生已经成为现代软件开发的重要趋势。本文将通过深入浅出的方式,介绍如何在云原生环境下设计并实施微服务架构,以及如何利用容器化技术和自动化工具来提升服务的可维护性和可扩展性。我们将一起探讨微服务架构的核心原则、优势,以及在云平台中部署和管理微服务的最佳实践。无论你是初学者还是有经验的开发者,这篇文章都将成为你探索云原生和微服务世界的一盏明灯。
|
7天前
|
监控 Cloud Native 持续交付
云原生时代的微服务架构设计原则与实践
【9月更文挑战第27天】本文深入探讨了在云原生环境下,如何高效地实施微服务架构。通过分析微服务的基本概念、设计原则和关键技术,结合实际案例,指导读者理解并应用微服务架构于云计算项目之中。文章旨在为软件开发者和架构师提供一条清晰的路径,以实现更加灵活、可扩展且易于维护的系统。
|
6天前
|
缓存 算法 安全
探索现代操作系统的架构与优化
本文旨在深入探讨现代操作系统的核心架构,并详细分析其性能优化策略。通过对操作系统的基本功能、主要组件以及它们之间的交互进行剖析,帮助读者理解操作系统在提高硬件资源利用率和用户体验方面所发挥的关键作用。此外,文章还将介绍几种常见的性能优化方法,包括进程调度算法、内存管理技术和I/O系统优化等,并通过实际案例展示这些优化技术的应用效果。
|
11天前
|
设计模式 Cloud Native API
云原生时代的微服务架构实践
【9月更文挑战第23天】在这篇文章中,我们将深入探讨云原生环境下的微服务架构设计原则、优势以及实施策略。文章不仅涉及理论概念,还结合具体的代码示例,帮助读者理解如何在实际项目中应用微服务架构。通过阅读本文,你将获得构建、部署和管理微服务的实用知识,为你的云原生项目奠定坚实的基础。
|
9天前
|
存储 运维 负载均衡
后端开发中的微服务架构实践与思考
本文旨在探讨后端开发中微服务架构的应用及其带来的优势与挑战。通过分析实际案例,揭示如何有效地实施微服务架构以提高系统的可维护性和扩展性。同时,文章也讨论了在采用微服务过程中需要注意的问题和解决方案。
|
11天前
|
消息中间件 弹性计算 运维
云消息队列RabbitMQ 版架构优化评测
云消息队列RabbitMQ 版架构优化评测
30 6
|
9天前
|
运维 持续交付 API
深入理解并实践微服务架构:从理论到实战
深入理解并实践微服务架构:从理论到实战
33 3
|
8天前
|
人工智能 算法 安全
探索现代操作系统的架构与优化
本文深入探讨现代操作系统的核心架构及其性能优化技术。通过分析操作系统的基本功能和设计原则,阐述其在资源管理、内存分配及多任务处理方面的创新方法。进一步,文章将聚焦于如何通过内核调优、算法改进等手段提升系统效率,确保在高负载环境下的稳定性和响应速度。最后,讨论未来操作系统可能面临的挑战与发展趋势,为相关领域的研究和实践提供参考。
|
12天前
|
人工智能 Cloud Native Java
新趋势、新开源、新实践|云栖大会 AI 原生应用架构专场邀您参会
新趋势、新开源、新实践|云栖大会 AI 原生应用架构专场邀您参会
下一篇
无影云桌面