使用物化视图实时查询微服务


分布式系统架构由于其灵活性、可扩展性和容错性而变得越来越流行。然而,实时查询来自多个微服务的数据可能具有挑战性,因为它可能需要复杂且耗时的数据检索操作。物化视图与命令查询职责分离(CQRS) 模式相结合,可以通过实现微服务数据的高效实时查询来提供应对这一挑战的解决方案。

在本文中,我们将通过在线商店应用程序的示例来探讨如何使用流数据库中的物化视图来实时查询微服务。

场景和问题
让我们考虑一个在线商店应用程序的示例,该应用程序使用微服务架构来处理各种功能,例如产品、目录、客户、库存和订单管理。每个微服务负责处理特定的领域或业务功能,并将数据存储在自己的数据存储中。例如,产品服务将有关产品的信息存储在产品数据库中。
如果没有物化视图,实时查询来自多个微服务的数据可能会很困难。例如,当客户在网站上搜索产品时,网站可能需要从不同的微服务中检索产品信息、目录、定价和库存状态。这可能会导致对不同微服务进行多次往返查询,从而导致响应时间变慢并增加数据库负载。

假设您应用上述案例的API 组合模式来在单个 API 调用中查询来自多个微服务的数据。

除了可扩展性和维护问题之外,它还导致微服务之间的紧密耦合,查询微服务需要知道其查询的微服务返回的结构,并且增加了实现的复杂性,因为它需要额外的逻辑来聚合和组合来自多个微服务的数据。

API 组合可能会导致额外的性能开销,因为编排器微服务可能需要等待多个微服务的响应,然后才能将结果返回给客户端。

最重要的是,它可能不提供实时或来自多个微服务的数据的近实时更新。如果查询的微服务中的数据频繁更改,则 API 组成可能无法反映最新的数据,从而导致查询结果中潜在的不一致或信息陈旧。

使用物化视图进行查询
现在,让我们看看如何利用物化视图来实时优化微服务的查询,并提高在线商店的性能。

将查询与命令分开
首先,我们定义将修改系统中的数据的命令和将从系统中读取数据的查询。我们可以使用 CQRS 将处理命令(写入操作)的责任与查询(读取操作)分开。这允许每个独立操作的优化。例如,产品可以存储和更新在 SQL/NOSQL 等传统数据库中,而产品列表、搜索结果、订单历史或用户推荐可能是一些需要优化性能的常见视图,可以存储在 SQL/NOSQL 等传统数据库中。物化视图形式的流数据库,根据流中的事件实时更新。

识别查询,创建物化视图
我们重点关注CQRS的查询部分。实现它的一种方法是使用读取优化的物化视图。

物化视图是数据的预先计算视图,独立于主事务数据库进行存储和更新。物化视图可用于通过降低与查询主数据库相关的复杂性和延迟来优化读取操作。

我们识别需要实时或近实时访问在线商店应用程序中的数据(例如最近查看的产品)的查询。这里的主要目标是以非规范化格式保存查询服务所需的数据,以实现快速检索。物化视图针对 UI 上的特定查询或视图进行非规范化和优化,从而实现更快、更高效的数据检索。

物化视图可以使用不同的技术创建,例如关系数据库、NoSQL 数据库或专用缓存系统。但是,如果您希望通过订阅其他微服务数据库的状态更改来获得实时更新并保持数据一致,您可以选择使用流数据库。

流数据库是一种数据库,旨在使用来自各种来源的数据并实时处理连续数据流,并使得可以使用 SQL 从物化视图查询这些数据。您可以在我的其他博客文章中详细了解流式数据库与传统数据库的区别以及如何选择正确的流式数据库。

保持物化视图同步
接下来,我们应该使物化视图保持最新。流数据库可以使用变更数据捕获流程和内置连接器从所有数据库中实时摄取数据作为事件流。如果您使用 PostgreSQL 作为特定微服务的数据源,则可以利用 RisingWave 的PostgreSQL CDC 连接器从更改日志中直接获取实时数据(无需使用 Kafka 等消息代理)。升浪通过将这些流连接在一起来构建物化视图,并在新事件发生时保持视图最新(事件驱动的更新)。例如,当新产品添加到产品目录微服务时,可以捕获相应的事件并用于更新产品列表的物化视图,确保视图始终是最新的。

RisingWave是一个开源流数据库,内置了用于各种数据库的完全托管的 CDC 源连接器,还可以从Kafka、Pulsar、Kinesis或Redpanda等其他源收集数据,并且允许您查询实时流使用 SQL。您可以获得始终最新的物化视图。

查询物化视图
最后,您添加一个新的查询服务,用于处理来自 UI 的查询(仅读取请求)。查询处理程序将 API 请求转换为查询,并从流数据库物化视图中获取数据。例如,当用户搜索产品时,可以从搜索列表的物化视图中检索搜索结果,而不是对不同的微服务进行多个 API 调用。

使用 RisingWave 创建和查询物化视图
GitHub 存储库上,您可以找到使用 RisingWave 流数据库的物化视图的多个用例。了解如何简单地连接到 MySQL 作为源并定义数据库表来检索我们感兴趣的数据并在流数据库中获取实时更新。

create table order_events (
    order_id int,
    order_date bigint,
    customer_name varchar,
    price decimal,
    product_id int,
    order_status smallint,
    PRIMARY KEY (order_id)
) with (
    connector = 'mysql-cdc',
    hostname = 'mysql',
    port = '3306',
    username = 'root',
    password = '123456',
    database.name = 'mydb',
    table.name = 'orders',
    server.id = '1'
);


然后我们创建一个物化视图来统计总订单价格和平均订单价格:


CREATE MATERIALIZED VIEW order_details AS
SELECT
    order_id,
    SUM(item_price) AS total_price,
    AVG(item_price) AS avg_price
FROM
    order_events
GROUP BY
    order_id;


使用流式数据库进行查询的物化视图的好处
正如我们在网上商店应用程序的新架构中所看到的,它引入了新的组件,如流式数据库,和查询处理程序,并提供了几个好处:

  • 简单的查询:物化视图可以通过提前聚合数据来简化查询逻辑,你不需要编写带有一堆连接的复杂查询。
  • 提高性能:物化视图可以针对特定的查询进行优化,减少与查询主数据库相关的延迟。
  • 实时的数据访问:流数据库中的物化视图可以提供来自多个微服务的实时数据。
  • 增加可扩展性:流式数据库可以独立于主数据库进行部署,允许查询方进行横向扩展。
  • 更好的容错性:流式数据库可以作为主数据库故障时的后备方案。


结论
流式数据库中带有增量更新的物化视图的CQRS是应对跨多个微服务查询数据挑战的有效解决方案。通过分离读写操作和预先计算数据的视图,这种整合提供了更好的性能、可扩展性和容错性。