我們將食べログ內部的Pub/Sub消息基礎架構替換成Apache Kafka的故事
这篇文章是食之旅2021年日历的第21天的文章。???
首先
你好。我是技术部微服务化团队的@SinceK13。
微服务团队的使命是构建一个系统基础设施,以解决在庞大的单体式服务中进行开发所带来的困难,并使小团队能够自主决策进行开发。
本篇将介绍我们在微服务团队中所进行的工作,将食べログ的内部生产订阅(Pub/Sub)消息基础设施升级为使用 Apache Kafka(以下简称 Kafka)进行的生产订阅(Pub/Sub)消息基础设施的故事。
此外,同一团队的 @weakboson 在12/14日发布了一个标题为”支持食评网餐厅搜索的Debezium和Apache Kafka”的文章,介绍了与本篇文章不同的Kafka应用案例。如果您对此感兴趣的话,欢迎不妨一看^^
Pub/Sub消息传递是一种方式
消息(数据)的发送者被编程为在没有特定接收者的情况下发送消息(数据)。
发送者被称为发布者(Publisher),接收者被称为订阅者(Subscriber),因此被称为“发布-订阅消息模型(Pub/Sub消息模型)”。
调解者被称为“消息代理人”因为其调解消息。
在代表性的基于主题的Pub/Sub消息系统中,消息按照“主题”进行分类,发布者根据主题发送消息,订阅者接收他们感兴趣的主题的消息。

Pub/Sub消息传递的特点
主要有以下三个特点。
非同期:当发布者发送消息后,可以在等待订阅者的响应之前开始下一个处理。
疎結合:只要发布者和订阅者能够与消息代理进行通信,它们便无需了解彼此的存在。
可扩展:无论是发布者还是订阅者,它们之间没有限制为一对一的关系,即使它们增多,也无需互相关注。

当面这种特点对于想在微服务之间执行异步处理的情况非常有用。
之前的Pub/Sub消息基础设施的配置

另外,以前的Pub/Sub消息传递基础设施中有一个功能,即可以跟踪消息的机制。
在Pub/Sub消息传递中,我之前提到发布者和订阅者无需知道彼此的存在,但从业务角度来看,有时需要查询消息的情况,因此需要这样的机制。
具体来说,我们在发布(或试图发布)的消息中都会分配一个在整个系统中唯一的“相关ID(correlation id)”,并且在消息发布者、消息API进行消息中继、订阅者成功处理以及有时的处理失败等不同的节点上,会与时间戳和数据一起将日志输出与相关ID关联起来(称为跟踪日志)。通过这种方式,可以使用相关ID来跟踪消息的流动。
追踪日志将以 JSON 格式输出以下项目。
学科
练习
题目
主题
议题
以前的Pub/Sub消息基础设施存在以下问题。
-
- 内製 Pub/Sub が不安定でときどきメッセージ消失を起こしてしまう
-
- メッセージは正常に処理されても即消えてしまい、トレースログは数日間しか保持されない
- メッセージの追跡調査や処理に失敗した時のリトライはサーバに入って CLI で行う必要があり大変
根据去年 @tkyowa 在Advent Calendar中提到的“逐步改善食べログ的大规模遗留系统”的努力,正如他所说,这个Pub/Sub消息平台的功能的业务重要性逐年增加,迫切需要尽快改进。
配置新的 Pub/Sub 消息平台

技术选择
为了防止消息消失

-
- 大量のメッセージを高速に処理できる
-
- Broker 複数台構成が前提でメッセージを複数台に同期して冗長化する
耐障害性が高い(1台でも稼働していればメッセージを消失しない設定が可能)
メッセージをディスクに書き込む
データの永続化が可能
Consumer Group ごとに独立してメッセージを読み出すことができる
ファンアウトと同等のことができる
根据这些特点,我们可以说它是一个高速且不容易发生消息消失的消息代理。
即使只有一个操作,也可以设置不让消息消失。以三个代理器的配置为例进行说明。
以下是经纪人(Broker)和制片人(Producer)的关键设置。
经纪人设定
制作人的设定

此外,“即便消息被正常处理,也会立即消失”这个问题通过 Kafka 的偏移量(offset)这一已读管理概念得以解决。
Kafka 并非像队列一样删除已处理消息,而是通过偏移量这一位置信息进行管理。
已处理消息会被保存一定的时间或容量,因此可以查询过去的消息,也可以回滚偏移量以便重新处理。
为了便于对消息跟踪调查和处理失败时进行重试。
为解决以下问题,即“当消息跟踪调查或处理失败时,需要进入服务器并在CLI中执行重试,这是非常麻烦的”,我们提出了通过GUI可操作的解决方案。
食べログ将Web服务器和AP服务器的日志传输到Google Cloud Platform(以下简称GCP)的Cloud Logging,因此在GCP的日志浏览器上进行日志调查是常见的做法。
因此,通过将Pub/Sub消息传输基础设施的跟踪日志也传送到Cloud Logging,使得可以像其他日志一样进行调查。
此外,通过将跟踪日志导出到BigQuery中,我们可以进行更详细的调查。
另外,我们选择了 Karafka 作为 Ruby 版的 Kafka 库。Karafka 是一个非常全面支持 Consumer 功能的 gem。它提供了与部署相关的 SIGNAL 处理、Graceful 关机以及 CLI 等功能。
此外,Karafka 还提供了一个名为 Karafka Sidekiq Backend 的 gem,可以将 Consumer 的消息处理委托给 Sidekiq。
因为以前的Pub/Sub消息平台也使用了Sidekiq,所以通过使用Karafka Sidekiq后端,订阅方的代码几乎可以直接重用。
此外,还可以使用 Sidekiq WebUI 从 Sidekiq 的图形用户界面中进行进度查看、强制停止以及重试处理失败的消息,这使得调查工作更加容易。由于 Kafka 消费者没有管理界面,所以使用 Karafka Sidekiq 后端也是一个优点。
此外,使用Karafka Sidekiq Backend可以使Sidekiq处理消息,因此可以更容易地处理处理时间长达数十秒至数分钟的重型消息,这也是选择Karafka Sidekiq Backend的理由之一。虽然可以直接使用Kafka Consumer来处理消息,但是如果消息处理时间超过Consumer的生存检查间隔,那么就会被视为消息处理失败,因此当处理时间较长的消息时,推荐使用Karafka Sidekiq Backend。
最终的结果
留言不再消失了。
由于选择了Kafka作为消息中间件,我们成功解决了自研的发布/订阅系统不稳定且偶尔发生消息丢失的问题。从7月开始,我们已经开始在新的发布/订阅消息基础设施上进行正式运营,并且至今从未发生过任何消息丢失,一直保持运行状态。
不久前,我们能够进行几周甚至几个月前的调查了。
在以前的Pub/Sub消息基础设施中存在一个问题,即“即使消息被正确处理,它也会立即消失,并且跟踪日志只会保留几天”,但是Kafka会将消息写到磁盘上以实现持久化。此外,通过将跟踪日志传输到GCP并长期保留,我们现在可以对数周甚至数月之前的调查进行分析。
现在可以通过GUI轻松进行调查,重新尝试处理失败的消息。
使用以前的Pub/Sub消息传递基础设施时,存在一个问题:“当消息调查或处理失败时,需要进入服务器并使用CLI进行重试,非常麻烦”。然而,通过将追踪日志传输到Cloud Logging,现在可以通过GUI轻松进行调查。此外,通过将追踪日志导出到BigQuery,还可以进行更详细的基于SQL的调查。另外一个成果是,现在可以使用与其他日志相同的方法进行追踪日志的调查。

最后
我们正在招募与我们一起推进改进的伙伴加入微服务团队。微服务化团队拥有决策参与权,从系统改进的初期阶段,如战略制定和技术选择等,具有很大的自主权和挑战性的职位。如果您对食べログ的“连接用户和餐厅”概念表示赞同,请务必申请加入我们。
欢迎希望先进行非正式交谈以进行信息交流的人。在申请时,请在自由文本框中注明“希望非正式交谈”。
明天是@sadashi关于“如何应对食评应用上的技术债务”的讲座。敬请期待!