使用 Spring Boot、Cassandra、Pulsar、React 和 Hilla 构建实时应用程序

本文介绍了如何使用Spring Boot、Apache Cassandra、Pulsar和React构建实时应用程序,重点讲述设置Cassandra和Pulsar实例、发布和消费Pulsar消息、将数据持久化到Cassandra以及在React中展示实时数据的流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

当谈到在分布式系统中管理大量数据时,Apache Cassandra和Apache Pulsar是经常出现的两个名字。

Apache Cassandra是一个高度可扩展的NoSQL数据库,擅长处理跨多个节点的高速写入和查询。它是用户配置文件管理、产品目录和实时分析等用例的理想解决方案。

创建了一个用于分布式消息传递和流的平台,称为Apache Pulsar,用于管理移动数据。它可以处理标准消息传递工作负载和更复杂的流式处理用例,包括实时数据处理和事件驱动架构。

本文介绍了构建与 Pulsar 和 Cassandra 交互的基于 Spring Boot 和 React 的 Web 应用程序的主要步骤,在收到股票数据时实时显示股票数据。这不是一个完整的教程,它只涵盖了最重要的步骤。您可以在 GitHub 上找到该应用程序的完整源代码。

您将学习如何:

  • 使用 DataStax Astra DB 和 Astra Streaming 设置 Cassandra 和 Pulsar 实例。

  • 在 Spring Boot 应用程序中发布和使用 Pulsar 消息。

  • 使用接收器将脉冲星消息存储在Cassandra中。

  • 使用 Vaadin 的 Hilla 框架在 React 中查看实时和存储的数据。

使用的技术和库

  • Apache Cassandra(与Astra DB)

  • Apache Pulsar(带Astra Streaming)

  • 弹簧启动

  • 阿帕奇脉冲星的春天

  • Apache Cassandra 的 Spring Data

  • 反应

  • 希拉

  • 阿尔法华帝原料药

要求

  • Java 17 或更高版本

  • 节点 18 或更高版本

  • 中级Java技能和对Spring Boot的熟悉程度

在 Spring 引导中存储敏感数据

Cassandra和Pulsar的大部分设置都是基于配置的。虽然将配置放入 可能很诱人,但这不是一个聪明的主意,因为文件受源代码管理,您可能会无意中泄露机密。application.properties

相反,请创建一个本地配置文件并将其添加到以确保它不会离开您的计算机。本地配置文件中的设置将由 Spring 引导自动应用:config/local/application.properties.gitignore

mkdir -p config/local

touch config/local/application.properties

echo "

# Contains secrets that shouldn't go into the repository

config/local/" >> .gitignore

在生产中使用 Spring 引导时,您可以为其提供作为环境变量的选项。

使用 DataStax Astra 设置 Cassandra 和 Pulsar

本文中使用的两种 Apache 技术都是开源项目,可以在本地安装。但是,使用云服务设置实例是一个更简单的选择。

在本文中,我们将使用 DataStax 免费套餐服务设置示例 Web 应用程序所需的数据基础架构。

首先登录到您现有的帐户或在Astra DataStax的官方网站上注册一个新帐户,您将需要在其中单独创建数据库和流媒体服务。

卡桑德拉设置

首先从官方点击“创建数据库” 来自官方 Astra DataStax.将数据从流下沉到 Astra DB 需要将这两个服务都部署在同时支持 Astra 流和 Astra DB 的区域中:

  1. 输入新数据库实例的名称。

  1. 选择密钥空间名称。(键空间存储您的表组,有点像关系数据库中的架构)。

  1. 选择云提供商和区域。
    注意:要使演示应用程序正常工作,您需要在也支持流式处理的区域中部署数据库服务。

  1. 选择“创建数据库”。

Cassandra:连接到服务

创建数据库服务的初始化后,您需要生成令牌并下载“安全连接捆绑包”,用于加密应用程序和云数据库 (mTLS) 之间的数据传输。导航到数据库仪表板“连接”标签页,您将在其中找到生成一次性令牌的按钮(请记住下载它)和捆绑包下载按钮:

spring.cassandra.schema-action=CREATE_IF_NOT_EXISTS
spring.cassandra.keyspace-name=<KEYSPACE_NAME>
spring.cassandra.username=<ASTRADB_TOKEN_CLIENT_ID>
spring.cassandra.password=<ASTRADB_TOKEN_SECRET>

# Increase timeouts when connecting to Astra from a dev workstation
spring.cassandra.contact-points=<ASTRADB_DATACENTER_ID>
spring.cassandra.port=9042
spring.cassandra.local-datacenter=<ASTRADB_REGION>

datastax.astra.secure-connect-bundle=<secure-connect-astra-stock-db.zip>

的脉冲星参数。application.properties

脉冲星设置

首先从Astra DataStax主页单击“创建流”:

  1. 输入新流式处理实例的名称。

  1. 选择提供商和区域。
    注意:请记住使用用于创建数据库服务的同一提供程序和区域。

  1. 选择“创建流”。

脉冲星:启用自动主题创建

除了启动并运行流服务之外,您还需要定义应用程序用于使用和生成消息的主题。您可以使用 UI 显式创建主题,但更方便的方法是为创建的实例启用“允许自动创建主题”设置:

  1. 单击新创建的流实例,导航到“命名空间和主题”标签页,然后单击“修改命名空间”。

  1. 导航到默认命名空间下的“设置”选项卡(不是顶级“设置”选项卡),然后一直向下滚动。

  1. 将“允许创建主题”更改为“允许自动创建主题”。

更改此默认设置将允许应用程序自动创建新主题,而无需在 Astra 中进行任何额外的管理工作。这样,您就成功建立了用于托管主动和被动数据的基础架构。

脉冲星:连接到服务

设置流式处理实例后,需要创建令牌才能从应用访问服务。大多数必要的属性都位于“流式处理仪表板”的“连接”标签页上。“主题名称”输入可在“命名空间和主题”标签表中找到:

## Client
spring.pulsar.client.service-url=<Broker Service URL>
spring.pulsar.client.auth-plugin-class-name=org.apache.pulsar.client.impl.auth.AuthenticationToken
spring.pulsar.client.authentication.token=<Astra_Streaming_Token>

## Producer
spring.pulsar.producer.topic-name=persistent://<TENANT_NAME>/default/<TOPIC_NAME>
spring.pulsar.producer.producer-name=<name of your choice>

## Consumer
spring.pulsar.consumer.topics=persistent://<TENANT_NAME>/default/<TOPIC_NAME>
spring.pulsar.consumer.subscription-name=<name of your choice>
spring.pulsar.consumer.consumer-name=<name of your choice>
spring.pulsar.consumer.subscription-type=key_shared

的脉冲星参数。application.properties

从 Spring 启动发布脉冲星消息

Spring for Apache Pulsar 库负责根据给定的配置设置 Pulsar 生产者和消费者。

在应用程序中,StockPriceProducer 组件处理消息发布。为了获取股票数据,它先使用外部 API 调用,然后再使用 .PulsarTemplate

自动将 连接到类并将其保存到字段中:PulsarTemplate

@Component
public class StockPriceProducer {

    private final PulsarTemplate<StockPrice> pulsarTemplate;

    public StockPriceProducer(PulsarTemplate<StockPrice> pulsarTemplate) {
        this.pulsarTemplate = pulsarTemplate;
    }

    //...

}

然后使用它来发布消息:

private void publishStockPrices(Stream<StockPrice> stockPrices) {
    // Publish items to Pulsar with 100ms intervals
    Flux.fromStream(stockPrices)
            // Delay elements for the demo, don't do this in real life
            .delayElements(Duration.ofMillis(100))
            .subscribe(stockPrice -> {
                try {
                    pulsarTemplate.sendAsync(stockPrice);
                } catch (PulsarClientException e) {
                    throw new RuntimeException(e);
                }
            });
}

您需要为自定义类型配置架构。在 中,定义以下 Bean:StockPriceApplication.java

@Bean
public SchemaResolver.SchemaResolverCustomizer<DefaultSchemaResolver> schemaResolverCustomizer() {
    return (schemaResolver) -> schemaResolver.addCustomSchemaMapping(StockPrice.class, Schema.JSON(StockPrice.class));
}

在 Spring 引导中使用脉冲星消息

Spring for Apache Pulsar 库附带了一个注释,方便收听 Pulsar 消息。在这里,消息被发送到项目反应器接收器,以便 UI 可以将它们用作:@PulsarListenerFlux

@Service
public class StockPriceConsumer {
    private final Sinks.Many<StockPrice> stockPriceSink = Sinks.many().multicast().directBestEffort();
    private final Flux<StockPrice> stockPrices = stockPriceSink.asFlux();

    @PulsarListener
    private void stockPriceReceived(StockPrice stockPrice) {
        stockPriceSink.tryEmitNext(stockPrice);
    }

    public Flux<StockPrice> getStockPrices() {
        return stockPrices;
    }
}

创建用于从 React 访问数据的服务器端点

该项目使用Hilla,一个用于Spring Boot的全栈Web框架。它管理反应式数据类型的 websocket 连接,并允许类型安全的服务器通信。

客户端可以利用 StockPriceEndpoint 创建的匹配 TypeScript 方法来获取数据:

@Endpoint
@AnonymousAllowed
public class StockPriceEndpoint {
    private final StockPriceProducer producer;
    private final StockPriceConsumer consumer;
    private final StockPriceService service;

    StockPriceEndpoint(StockPriceProducer producer, StockPriceConsumer consumer, StockPriceService service) {
        this.producer = producer;
        this.consumer = consumer;
        this.service = service;
    }

    public List<StockSymbol> getSymbols() {
        return StockSymbol.supportedSymbols();
    }

    public void produceDataForTicker(String ticker) {
        producer.produceStockPriceData(ticker);
    }

    public Flux<StockPrice> getStockPriceStream() {
        return consumer.getStockPrices();
    }

    public List<StockPrice> findAllByTicker(String ticker) {
        return service.findAllByTicker(ticker);
    }
}

在 React 中显示实时更新图表

仪表板视图有一个顶点图烛条图,用于显示股票数据。它绑定到以下类型的状态:ApexAxisChartSeries

const [series, setSeries] = useState<ApexAxisChartSeries>([]);

该视图使用 React 效果挂钩来调用服务器终结点并订阅新数据。它返回一个处置器函数,以便在不再需要时关闭 websocket:

useEffect(() => {
  const subscription = StockPriceEndpoint
    .getStockPriceStream()
    .onNext((stockPrice) => updateSeries(stockPrice));
  return () => subscription.cancel();
}, []);

系列绑定到模板。由于后端和前端是被动的,因此每当收到新的 Pulsar 消息时,图表都会自动更新:

<ReactApexChart type="candlestick" options={options} series={series} height={350} ></div>

将脉冲星消息持久化到 Cassandra

在您需要一个可靠、可扩展且安全的平台来存储来自 Pulsar 的事件数据以进行进一步分析、处理或共享的情况下,将 Pulsar 消息下沉到 Astra DB 非常有用。也许需要出于合规性和审核目的保留事件数据的副本,需要在共享数据库中存储来自多个租户的事件数据,或者出于某些其他用例。

Astra Streaming 提供了许多完全托管的 Apache Pulsar 连接器,您可以使用它们将事件数据保存到各种数据库和第三方解决方案,如 Snowflake。在本文中,我们将流数据保存到 Astra 数据库中。

创建接收器

首先从 Astra 流媒体仪表板中选择“接收器”标签页。

  1. 选择“默认”命名空间:

  • 从可用的“接收器类型”列表中,选择“Astra DB”。

  • 为水槽指定您选择的名称

  1. 选择从应用向该主题发布消息后可用的“库存 Feed”。

选择数据流输入后,选择要保留脉冲星消息的数据库:

  • 要启用表创建,请粘贴具有有效角色的 Astra DB 令牌。您会注意到密钥空间 输入有效令牌后,选择用于创建数据库的密钥空间名称。

  • 然后输入表名称。
    注意:这需要与您在 StockPrice.java 类中使用的注释值匹配,以回读数据。@Table("stock_price")

接下来,您需要将 Pulsar 消息中的属性映射到数据库表列。属性字段会自动映射到我们的演示应用程序中,因此您只需单击“创建”即可继续。例如,如果要将部分数据保存到数据库,则打开架构定义将使您能够查看所使用的属性名称并在字段之间创建自定义映射。

创建接收器后,将开始初始化过程。之后,状态将更改为“活动”。然后,您完成了自动将股票数据保存到数据库中以便应用程序轻松访问的操作。接收器仪表板提供在发生错误时对接收器日志文件的访问。

在表中显示 Cassandra 数据

存储在 Cassandra 中的历史数据显示在数据网格组件中。DetailsView 包含一个 Vaadin Grid 组件,该组件绑定到保存在状态变量中的对象数组:StockPrice

const [stockData, setStockData] = useState<StockPrice[]>([]);

该视图有一个下拉选择器,用于选择要查看的股票。更新选择时,视图将从服务器终结点提取该股票的数据:

async function getDataFor(ticker?: string) {
  if (ticker) setStockData(await StockPriceEndpoint.findAllByTicker(ticker));
}

数组绑定到模板中的网格。 定义列应映射到的属性:StockDataGridColumns

<Grid items={stockData} className="flex-grow">
  <GridColumn path="time" ></GridColumn>
  <GridColumn path="open" ></GridColumn>
  <GridColumn path="high" ></GridColumn>
  <GridColumn path="low" ></GridColumn>
  <GridColumn path="close" ></GridColumn>
  <GridColumn path="volume" ></GridColumn>
</Grid>

结论

在本文中,我们展示了如何使用开源 Java 堆栈构建可扩展的实时应用程序。您可以克隆已完成的应用程序,并将其用作您自己的实验的基础。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值