当我们在讨论“技术方案选型”时,我们实际是在讨论什么?

一、摘要

所谓文无第一,武无第二;大多数做技术的人都不会轻易承认自己技术比别人“菜”,所以当大家面临一个技术方案选型的问题时,通常都会穷尽自己毕生所学来表达自己独到的见解,并且通常情况下都会对前人做的方案一顿指摘,好像不如此不足以体现自己的“专业”。

今天这篇文章我从自己实际的经历来深度分析一下,到底如何正确的讨论技术方案选型。

二、消息队列

消息队列是一种用于在分布式系统中实现异步通信的机制。从对消息队列的描述上看就非常唬人,又是“分布式”,又是“异步通信”,实际上消息队列也确实是任何一个中大型项目中都必需的中间件,甚至很大程度上可以决定一个项目从技术角度上的成功与否。因此选择哪种消息队列一直是技术选型中非常重要的一环。

能作为消息队列的中间件有很多种,我确实没有全部用过,但熟悉我的朋友应该知道我一直都在从事自动化运维相关的工作,而自动化系统中动辄涉及到上万台的服务器和交换机需要维护,需要处理它们产生的日志,需要采集它们的实时信息,还需要对它们做各种各样的配置操作。考虑到高性能、高可靠、可扩展,消息队列就不可或缺,因此我在过去研发过的项目中使用过比较经典的几种消息队列,但本质上都是生产者消费者模型,如下图所示。

img

添加图片注释,不超过 140 字(可选)

不同的消息队列可以用于不同的业务场景,也各有优劣。

2.1 日志分析与告警系统(Kafka)

生产环境中的设备无时无刻不在产生日志和告警,这些信息本身只是一串字符,而系统需要在收集到这些信息后,对它们做分析处理,打标聚合,最后再根据规则决定是否告警,是否派单给值班人。

当有成千上万台设备同时产生日志时,如果不使用消息队列,那通常出现的现象就是负责处理日志的服务 CPU 和内存被打爆,或者日志处理延迟很高,这种情况在实际生产环境中都是不能够接受的。

因此我们需要引入消息队列来缓冲这些日志,与此同时由多个服务并行的去处理这些缓冲下来的日志,这就是典型的生产者消费者模型。设备是生产者,日志分析服务是消费者,而消息队列就是居中协调的角色。我当时使用了 Kafka 作为日志分析与告警系统的消息队列,有几个主要的优劣如下:

优点:

  • 高吞吐量: Kafka 能够处理大量的日志数据,每秒可以处理数百万条消息,适用于大规模数据流处理。
  • 低延迟: Kafka 的设计使其具有低延迟的特点,非常适合实时数据处理和实时告警系统。
  • 持久化存储: Kafka 的消息可以持久化到磁盘,确保日志数据的可靠性和持久性,即使在系统故障时也不会丢失消息。
  • 灵活的消费模型: 支持多种消费模型(如点对点、发布/订阅),使得日志数据可以被多个消费者同时处理,适用于多种分析和告警需求。

缺点:

  • 复杂性: Kafka 的部署和维护相对复杂,需要专业知识和经验来配置和管理集群,尤其是在处理大规模数据时。
  • 硬件需求高: 为了实现高吞吐量和低延迟,Kafka 需要较高的硬件配置(如高速磁盘、充足的内存和CPU),这可能增加成本。
  • 学习曲线陡峭: Kafka 的概念和配置选项较多,学习和掌握需要一定的时间和精力。
  • 运维成本: 由于其复杂性和对资源的需求,Kafka 的运维成本较高,需要专门的团队进行监控和维护。

Kafka 作为业内“性能最强”的消息队列,最典型的应用场景就是大数据实时处理和日志收集,因此使用它作为日志分析与告警系统的消息队列的优点显而易见。

但这个项目是我职业生涯中第一个接手的大型项目,也是我第一次接触到消息中间件。当时所管理的网络设备大概有八九千台,就算极端情况下有 50% 的设备同一秒产生日志,并且每台设备一次性产生 100 条日志,最大吞吐也不到 50 w / s,实际上大多数情况下,只会有少数的设备会同时产生多条告警。

再加上当时在建设系统初期,并没有足够多的资源可供使用,也没有专业的运维团队来负责维护中间件,我只能凭着一腔热血和边学边干的方式把 Kafka 集群搭建起来,消费者服务运行的过程中不断的踩到各种各样的坑,幸运的是 Kafka 生态足够完善和友好,在我一步步的摸索下,最终这个项目成功地实现秒级分析处理告警。

但现在仔细想来这个场景下是否真的需要用到 Kafka?在业务体量没有那么大的情况下,再加上人手不足,是否可以牺牲一部分性能和可扩展性来达到项目的正常交付和可持续运维呢?

2.2 分布式任务调度系统(RabbitMQ)

我所负责的另一个项目中涉及到对交换机的操作,具体业务逻辑是:会有不同的用户在前端创建交换机的配置任务或者采集任务,这些任务会分发给不同的 worker 来实际执行,但要保证用户创建的任务不能丢,并且不能重复执行任务。这又是一个非常典型的生产者消费者模型。

比较“短平快”的方式就是使用 Redis 来作为消息队列,用户创建的任务发送到 Redis 的 List 中,多个 worker 都去读取这个 List,这种方式的缺点也显然易见:

  • 不支持重复消费:消费者拉取消息后,这条消息就会从 List 中被删除,无法被其它消费者再次消费
  • 消息丢失:消费者拉取到消息后,如果发生异常宕机,那这条消息就会丢失

所以使用 Redis 的 List 无法满足我们的业务场景,Redis 还提供了另一种发布订阅的方式:pub/sub,但这种方式会将消息暂存在订阅者的 buffer 中,实时转发给订阅者,甚至都没有将数据写入到 AOF,所以一旦 Redis 宕机,未被消费的任务就会全部丢失。

Redis 在最新的版本中引入了 Stream 功能,它的主要功能包括:

  • 支持「阻塞式」拉取消息
  • 支持发布 / 订阅模式
  • 支持消息 ACK 机制
  • 数据会写入到 RDB 和 AOF 做持久化

上述这些能力已经尽可能的让 Redis 具备了完整消息队列的能力,但无论如何努力,Redis 与专业的消息队列相比始终都稍逊一筹,因为 Redis 在以下两个极端场景下,都会导致数据丢失。

  • AOF 持久化配置为每秒写盘,但这个写盘过程是异步的,Redis 宕机时会存在数据丢失的可能
  • 主从复制也是异步的,主从切换时,也存在丢失数据的可能(从库还未同步完成主库发来的数据,就成为主库)

Redis 本身的设计就无法保证严格的数据完整性。但 Kafka、RabbitMQ 这类消息队列就不一样了,它们的数据都会存储在磁盘上,磁盘的成本要比内存小很多。并且专业的消息队列在生产者发布消息时,队列中间件通常会等待「多个节点/副本」都写入完成才会返回成功,以此保证消息的完整性。这样即便其中一个节点宕机,也能保证集群的数据不丢失。这也是为什么 RabbitMQ 和 Kafka 在设计上会复杂很多的原因。

所以在分布式任务调度的项目中,我最终选择了 RabbitMQ,虽然在当时使用 RabbitMQ 同样面临和使用 Kafka 一样的难题,但出于业务场景的考虑,我也只能硬着头皮上,艰难的部署好 RabbitMQ 集群,并且额外配置了集群的监控来保证稳定性。

三、何为技术方案选型

技术选型是指在软件开发或系统设计过程中,选择适合项目需求的技术栈(包括编程语言、框架、库、工具和平台等)的过程。技术选型的重要性在于它对项目的成功与否有着直接影响。但技术方案选型绝不仅仅是局限在“技术”领域,它是需要从需求的分析,团队的人力,社区的支持等等多个方面综合考量来决定的。

所以当我们在讨论技术方案选型时,一定要避开盲目自嗨,理想主义的陷阱,从业务场景和资源配置角度综合考虑,毕竟:没有最好的技术方案,只有最适合的技术方案。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值