Flink软件架构及核心机制详解

Flink Checkpoint机制详解 Checkpoint是一种状态快照机制,用于在流处理作业中定期保存作业的状态。Flink作业通常会在内存中维护一些状态(如窗口、聚合结果、历史记录等),当作业运行中发生故障时,Checkpoint能帮助系统恢复到最近的有效状态,从而避免丢失数据或重复处理数据。Flink的Checkpoint机制不仅能够保证作业的容错性,还能够支持精确一次(exactly-once)语义,即每条数据只会处理一次,即使发生了故障也能正确恢复。 阅读详情

Apache Flink 的软件架构是一个分层、分布式、主从式的设计,专注于高吞吐、低延迟、Exactly-Once 状态一致性的流处理,同时统一支持批处理(作为有界流的特例)。其核心架构如下:

一、 分层 API

  1. SQL & Table API (最高抽象层):

    • 目标用户: 数据分析师、希望使用声明式语言的开发者。
    • 功能: 提供标准的关系型 SQL 查询接口以及更灵活的 Table API(类似 LINQ / DataFrame API)。Flink 会将这些 API 调用编译优化成底层的 DataStream 或 DataSet 程序。
    • 特点: 易于使用,自动优化(查询计划优化),与流批统一(同一查询语义在流和批上一致)。
  2. DataStream API & DataSet API (核心编程模型层):

    • 目标用户: 需要精细控制数据处理逻辑的开发者。
    • 功能:
      • DataStream API: 处理无界数据流的核心 API。提供丰富的算子(map, filter, keyBy, window, join, process 等)用于转换、聚合、连接、处理事件时间、管理状态等。
      • DataSet API: 处理有界数据集的 API(批处理)。提供类似 MapReduce 的操作(map, reduce, groupBy, join 等),但在内存计算和优化方面更先进。
    • 特点: 提供细粒度控制,表达能力强,是构建复杂流处理应用的基础。Flink 1.12 开始,官方推荐优先使用 DataStream API 的 BATCH 执行模式来处理有界流,DataSet API 逐渐被取代,目标是流批 API 的统一。
  3. Stateful Process Function (最低抽象层):

    • 目标用户: 需要实现非常底层、定制化逻辑(如精细状态管理、复杂事件处理、自定义定时器)的开发者。
    • 功能: 构建在 DataStream API 之上(如 ProcessFunction, KeyedProcessFunction, CoProcessFunction 等)。提供对单个事件、状态(键控状态或算子状态)和定时器(事件时间或处理时间)的细粒度访问。
    • 特点: 最灵活,但也最复杂。用于实现无法用 DataStream API 高阶算子表达的逻辑。

二、 运行时架构 (Runtime)

  1. JobManager (Master):

    • 核心大脑: 每个 Flink 集群至少有一个 JobManager(高可用模式下有多个 Active/Standby)。
    • 主要职责:
      • 作业调度: 接收用户提交的 Job Graph(作业逻辑图的并行化版本)。
      • 资源管理: 向 ResourceManager 申请执行任务所需的资源(Task Slots)。
      • Checkpoint 协调: 触发、协调分布式快照(Checkpoint / Savepoint)的生成,确保状态一致性。
      • 故障恢复: 在 TaskManager 或 Task 失败时,重新调度任务,并从最近的 Checkpoint 恢复状态。
      • 作业监控: 收集作业运行时的指标和状态。
    • 内部组件:
      • ResourceManager: 管理 TaskManager 的 Task Slots,负责资源分配和回收(与外部资源框架如 YARN/K8s 交互时,Flink 的 ResourceManager 会委托给外部框架的 ResourceManager)。
      • Dispatcher: 提供 REST 接口接收作业提交,为每个提交的作业启动一个 JobMaster,提供 Web UI。
      • JobMaster: 每个作业一个。负责单个作业的管理(调度、Checkpoint 协调、故障恢复)。是作业执行的真正协调者。
  2. TaskManager (Worker / Slave):

    • 执行引擎: 集群中运行一个或多个 TaskManager。
    • 主要职责:
      • 资源提供: 管理其上的 Task Slots。一个 Task Slot 是 TaskManager 资源(CPU、内存)的一个固定子集,用于执行一个 Task 的子任务(Subtask)。
      • 任务执行: 在其 Slot 中执行由 JobManager 分配的 Task(实际的数据处理逻辑,如算子实例)。
      • 状态存储: 存储和管理的算子状态(Keyed State, Operator State)。状态通常存储在堆内存/堆外内存,并持久化到 Checkpoint 存储。
      • 数据交换: 与其他 TaskManager(甚至同一 TM 内的不同 Slot)上的 Task 进行网络数据传输(Shuffle)。
    • 关键概念:
      • Task Slot: 资源调度的单位。一个 Slot 可以运行一个 Pipeline 的多个算子(算子链)。
      • 算子链: Flink 为了优化性能,会将多个算子(满足特定条件:One-to-One 连接、相同并行度、相同 Slot 共享组)融合(Chain)在一起,在同一个线程(同一个 Task)内执行,避免不必要的序列化和网络开销。这个融合后的实体就是一个 Task。每个 Task 由一个线程执行。
      • Subtask: 一个算子的一个并行实例。一个 Task 可以包含一个或多个融合在一起的 Subtask。
  3. 客户端:

    • 不是运行时的一部分,但用于准备和提交作业。
    • 接收用户代码(DataStream/DataSet/SQL 程序),构建 Job Graph。
    • 将 Job Graph 提交给 JobManager (Dispatcher)。
    • 可以运行在用户机器或集群边缘节点上。

三、 核心机制

  1. 分布式执行模型:

    • 用户编写的作业逻辑被转换成逻辑数据流图。
    • 逻辑图被并行化(根据算子设置的并行度)成执行图。
    • 执行图被拆分成多个 Task。
    • Task 被 JobManager 调度到 TaskManager 的 Task Slot 中执行。
    • Task 之间通过网络进行数据交换。
  2. 基于 Pipeline 的数据交换:

    • Flink 在 Task 之间(特别是 One-to-One 或 Redistributing 连接模式)采用 Pipeline 数据交换。
    • 生产者 Task 的子任务一旦产生数据,会立即推送给下游消费者 Task 的子任务(通过网络缓冲区)。
    • 关键优势: 实现真正的流式处理,极低的延迟。避免了像 Spark Streaming (Micro-Batch) 那样需要等待整个微批次构建完成再传输的开销。
  3. 容错机制 (Checkpointing):

    • 核心: 基于 Chandy-Lamport 分布式快照算法的异步屏障快照。
    • 过程:
      1. JobManager 定期触发 Checkpoint,向所有 Source Task 注入 Checkpoint Barrier。
      2. Barrier 随数据流向下游算子流动。
      3. 算子收到 Barrier 时,会对其当前状态做快照(异步写入持久化存储,如 HDFS, S3)。
      4. 算子将 Barrier 传递给下游。
      5. 当所有算子(包括 Sink)都成功完成快照后,Checkpoint 完成。
    • 恢复: 故障时,JobManager 协调所有 Task 从最近一次成功的 Checkpoint 恢复状态和重启处理。
    • 保证: 提供 Exactly-Once 状态处理语义(数据源和输出端需要配合支持)。
  4. 状态管理:

    • 键控状态: 与特定 Key 关联的状态,只能用在 KeyedStream 的算子中(如 keyBy 之后)。状态按 Key 分区存储,访问范围限定为当前 Key。类型:ValueState, ListState, MapState, ReducingState, AggregatingState。
    • 算子状态: 与算子并行实例绑定的状态,不与特定 Key 关联。类型:ListState, UnionListState, BroadcastState。通常用于 Source/Sink 或需要广播状态给所有并行实例的场景。
    • 状态后端: 负责状态存储、访问和 Checkpoint 持久化。常用实现:
      • HashMapStateBackend: 状态存储在 JVM 堆内存。速度快,但受限于内存大小。
      • EmbeddedRocksDBStateBackend: 状态存储在本地嵌入的 RocksDB 数据库中(磁盘/SSD)。支持远超内存大小的状态,但访问速度相对慢一些。Checkpoint 时状态持久化到远程存储。
  5. 时间语义:

    • 事件时间: 事件实际发生的时间(嵌入在数据记录中)。处理乱序事件的基础,是流处理最常用的时间语义。使用 Watermark 机制处理乱序和标记事件时间进度。
    • 处理时间: 数据被算子处理时的系统时间。最简单,延迟最低,但结果不确定(依赖处理速度)。
    • 摄取时间: 事件进入 Flink Source 算子的时间。是事件时间和处理时间的折中。较少使用。
  6. 资源管理与部署:

    • Standalone Cluster: Flink 自带的集群模式。
    • YARN: 将 Flink 作为 YARN 应用部署,利用 YARN 进行资源调度。
    • Kubernetes: 原生支持将 Flink 部署在 K8s 上(Session 或 Application 模式)。
    • Mesos: 支持但不如 YARN/K8s 主流。
    • 云厂商托管服务: 如 AWS Kinesis Data Analytics for Apache Flink, Ververica Platform 等。

四、 架构优势

  1. 真正的流处理引擎: Pipeline 数据交换模型提供极低延迟。
  2. 流批统一: 单一运行时引擎处理无界流和有界数据集,API 层也在逐步统一。
  3. 强大的状态管理: 丰富、高效、可扩展的状态支持,是复杂流处理的基础。
  4. Exactly-Once 语义: 成熟的 Checkpoint 机制确保状态一致性。
  5. 高吞吐与低延迟: 优化的内存管理、网络栈和序列化框架。
  6. 弹性扩展: 通过调整算子并行度轻松扩展作业处理能力。
  7. 丰富的生态系统: 支持多种数据源(Kafka, File, CDC等)、数据汇(Kafka, DB, File等)、部署模式、状态后端、指标系统等。

五、 总结架构图

  +------------------------------------------------------------------------------------------+
  |                                       Client                                             |
  |  (Prepares & Submits Job Graph)                                                          |
  +------------------------------------------------------------------------------------------+
                              |
                              | (Submits Job Graph)
                              v
  +------------------------------------------------------------------------------------------+
  |                                       JobManager (Master)                                |
  |  +---------------------+    +---------------------+    +---------------------+           |
  |  |      Dispatcher     |    |    JobMaster (per job) |    | ResourceManager    |           |
  |  | (REST, Starts JM)   |<-->| (Scheduling, Checkpoint,| <->| (Manages Task Slots)|           |
  |  +---------------------+    |  Fault Tolerance)     |    +---------------------+           |
  |                             +---------------------+                                      |
  +------------------------------------------------------------------------------------------+
                              |            ^            ^
                              | (Deploys)  | (Heartbeat/| (Requests Slots)
                              |            |  Status)   |
                              v            |            |
  +------------------------------------------------------------------------------------------+
  |                                       TaskManager 1 (Worker)                             |
  |  +---------------------+    +---------------------+    +---------------------+           |
  |  |     Task Slot 1     |    |     Task Slot 2     |    |     Task Slot n     |           |
  |  | [Operator Chain]    |    | [Operator Chain]    |    | [Operator Chain]    |           |
  |  | (Thread)            |    | (Thread)            |    | (Thread)            |           |
  |  +---------------------+    +---------------------+    +---------------------+           |
  |        |        |                |        |                |        |                   |
  |        |        | (Network Shuffle)        | (Network Shuffle)        |                   |
  |        v        v                v        v                v        v                   |
  +------------------------------------------------------------------------------------------+
          |        |                |        |                |        |
          |        +----------------+--------+----------------+        |
          |                         |        |                         |
          | (External Data Sources) |        | (External Data Sinks)   |
          v                         v        v                         v
  [Kafka, Files, Sockets...]        [Kafka, DB, Files...]

理解 Flink 的分层 API、主从式运行时架构(JobManager/TaskManager/Slot)、Pipeline 数据传输、基于 Barrier 的分布式 Checkpoint 以及灵活的状态管理,是掌握其强大流处理能力的关键。

Flink容错机制 在出现故障时,我们将系统重置回正确状态,以确保数据的完整性和准确性。在流处理中,我们采用存档和读档的策略,将之前的计算结果进行保存。这样,在系统重启后,我们可以继续处理新数据,而无需重新计算。更重要的是,在有状态的流处理中,任务需要保持其之前的状态,以便继续处理新数据。为了实现这一目标,我们将之前某个时间点的所有状态保存下来,这个“存档”被称为“检查点”。检查点是 Flink 容错机制的核心。它关注的是故障恢复的结果:在故障恢复后,处理的结果应与故障发生前完全一致。 阅读详情

相关推荐

大数据学习之Flink、10分钟了解Flink的核心组件以及它们的工作原理

的容错机制的核心组件包括和。等等.. .. ..Checkpoint是用于容错和恢复的机制 是 实现容错机制最核心的功能组件,也是四大基石之一,它在数据流处理过程中定期捕获作业状态的快照,并将其存储在可靠的存储系统中。当作业发生故障时, 可以从最近的 Checkpoint 恢复,重新处理数据流,以保证数据的完整性和一致性。Checkpoint 的频率和大小可以通过配置参数进行设置。则是用备份机制,于手动恢复的点。是提供的一种备份机制,用于将作业的状态保存到一个指定的位置。与 Checkpoint 不同, 不

2301_78038072的博客 1788

FlinkSQL演进过程,解析原理及一些优化策略

本文整理自Flink Forward 全球在线会议,演讲者云邪,由浪尖整理。1. Flink table/sql架构演变flink 1.9之前的版本,对于Table API和SQL的底...

大数据星球-浪尖 417

Flink 心跳服务机制

心跳机制是用于检测客户端或者服务端是否存活的一种机制,通过定期向对方发送请求方法,常见的心跳检测有两种: socket 套接字SO_KEEPALIVE本身带有的心跳机制,定期向对方发送心跳包,对方在收到心跳包后会自动回复; 应用自身实现心跳机制,同样也是使用定期发送请求的方式; Flink对各组件服务状态的监控统一使用心跳服务来管理,如同其上诉2实现机制一样,其主要也是调用方通过周期性定时发送心跳请求,接收方接收到心跳请求后作出对应的心跳响应;其内部实现是通过RPC相互调用的方式,并重置...

METON的博客 4118

Apache Flink架构介绍

在Flink的整个软件架构体系中,同样遵循这分层的架构设计理念,在降低系统耦合度的同时,也为上层用户构建Flink应用提供了丰富且友好的接口。Flink整个系统主要由两个组件组成,分别为JobManager和TaskManager,Flink架构也遵循Master-Slave架构设计原则,JobManager为Master节点,TaskManager为Worker(Slave)节点。所有组件之间的通信都是借助于Akka Framework,包括任务的状态以及Checkpoint触发等信息。

qq_25409421的博客 2113

Flink窗口机制详解:大数据时间处理的核心

在大数据实时处理场景中,数据以流的形式持续产生,如何对无限数据流进行有限化处理是核心问题。Flink的窗口机制通过将数据流分割成有限的“窗口”,实现对窗口内数据的聚合、转换和计算。本文将系统讲解窗口机制的核心原理、实现细节、实战技巧及优化策略,覆盖从基础概念到高级应用的全流程。基础概念:定义窗口机制核心术语,对比不同时间语义技术原理:解析窗口类型、分配策略、触发机制及水位线算法实战指南:通过Python代码演示窗口配置与数据流处理应用场景:结合日志分析、实时监控等场景讲解落地经验。

操作系统内核探秘的博客 915

Proteus仿真AT89C51驱动DHT11:温湿度数据采集与LCD1602显示的5个调试坑点总结

本文总结了在Proteus仿真环境下使用AT89C51驱动DHT11温湿度传感器并通过LCD1602显示的5个常见调试坑点,包括DHT11时序问题、LCD1602初始化错误、数据校验失败、仿真特有差异及系统稳定性问题,提供了详细的解决方案和优化代码示例,帮助开发者高效完成温湿度采集项目。

weixin_30335575的博客 355

Flink架构,功能快速介绍

这里写自定义目录标题Flink简介Flink优势统一的批处理与流处理系统 Flink简介 Flink核心是一个流式的数据流执行引擎,其针对数据流的分布式计算提供了数据分布、数据通信以及容错机制等功能。基于流执行引擎,Flink提供了诸多更高抽象层的API以便用户编写分布式任务: DataSet API: 对静态数据进行批处理操作,支持Java、Scala和Python。 DataStream API:对数据流进行流处理操作,支持Java和Scala。 Table API:对结构化数据进行查询操作,将结构化

福如意的博客 1万+

嵌入式开发实战:LWIP中PPP协议配置全流程(含CHAP认证避坑指南)

本文是一份嵌入式开发实战指南,详细解析了如何在STM32平台上配置LWIP协议栈中的PPP协议,实现从串口到IP网络的完整连接。内容涵盖工程搭建、源码整合、关键配置、串口驱动绑定、状态管理以及CHAP认证等核心流程,并重点提供了CHAP认证失败的排查与避坑指南,帮助开发者高效打通嵌入式设备的网络连接。

plant的博客 461

基于Flink SQL的实时处理架构

本博文介绍基于Flink的多数据源->数据治理->Kafka->作业治理->DB的实时处理架构。数据治理,将读库降低为原来的2/3次,并使得多数据源转为统一Schema。基于统一的Schema数据流,作业治理将基于Jstorm的业务逻辑编码项目,简化成多条SQL语句的配置。 sar案例 可以先参阅 storm项目迁移flink案例:系统活动情况报告 而...

u011250186的博客 1759

iOS自动化之打包-xcodebuild命令行打包.app并安装到ios模拟器

xcode xcodebuild xcrun ios模拟器 iOS UI自动化测试 ios自动打包安装到ios模拟器

z12347891的博客 5073

红日-VulnStack靶场-ATT&CK(二):从Weblogic漏洞到域控渗透实战

本文详细解析了红日安全团队VulnStack靶场中从Weblogic漏洞到域控渗透的完整攻击链。通过实战演示Weblogic反序列化漏洞利用、Cobalt Strike持久化控制、域内信息收集及PsExec横向移动等关键技术,复现了企业内网渗透的典型场景,并提供了防御建议。

tgb3456789的博客 934

Flink原理及架构(一)

  Flink核心是一个流式的数据流执行引擎,并且能够基于同一个Flink运行时,提供支持流处理和批处理两种类型应用 一.Flink介绍   Flink核心是一个流式的数据流执行引擎,并且能够基于同一个Flink运行时,提供支持流处理和批处理两种类型应用。其针对数据流的分布式计算提供了数据分布,数据通信及容错机制等功能。基于流执行引擎,Flink提供了跟多高抽象层的API便于用户编写分布式任务...

Unique small lu bu 1万+

openHarmony之AI Engine:万字讲解如何在应用、开发板上接入AI大模型调用

本文章介绍如何在 OpenHarmony 开发板上集成和部署各类 AI 大模型,实现终端直接聊天功能,并为语音助手、智能机器人等应用提供 AI 接口支持。

m0_67505153的博客 619

Flink-Watermark机制详解:(第39天)

Watermark机制,在Apache Flink这样的流处理框架中,扮演着至关重要的角色,特别是在处理事件时间(Event Time)窗口时,它能够有效解决数据乱序和延迟到达的问题,本文对Watermark机制的详细解析,涵盖其定义、原理、应用场景、核心算法以及优化策

syhiiu的博客 2487

【异常】Cursor导入Karpathy指南失败解决方案Failed to import GitHub/GitLab rules: Error executing git: Cloning into

摘要:本文解决了Git克隆单个文件报错的问题,指出git clone只能克隆整个仓库而非单个文件。提供了两种解决方案:1) 推荐手动创建规则文件,在Cursor项目中新建.mdc文件并粘贴Karpathy行为指南完整内容;2) 备选克隆整个仓库获取文件。指南包含编码行为规范,强调简单性、精准修改和明确目标。还说明了如何设置全局规则和即时生效的方法。

奶爸的编程之路,也就一周冷个三天 174

嵌入式Zephyr RTOS面试题及参考答案

在Zephyr中,为自定义外设编写Devicetree绑定(Bindings)有助于内核理解设备树中自定义外设节点的含义和属性。首先,需要创建一个.yaml格式的绑定文件,通常存放在目录下对应的子目录中,文件名应能反映外设的类型和功能。绑定文件的开头要定义基本信息,包括字段,用于简要描述外设的功能和用途;compatible字段,它是一个字符串列表,用于匹配设备树中自定义外设节点的compatible属性,设备树节点和绑定文件通过这个字段关联起来。接下来,要定义外设节点的属性。使用properties。

大模型大数据攻城狮的专栏 984

Flink之Checkpoint机制

目录(1)Checkpoint的背景(2)Flink 中Checkpoint(3)理解 Barrier(4)Flink 中Checkpoint 执行过程(5)严格一次语义: barrier 对齐(6)至少一次语义: barrier 不对齐(7)checkpoint 和 savepoint 的区别(8)基于State Backend的CheckPoint开发 (1)Checkpoint的背景 State场景: flink中有状态函数和运算符在各个元素(element)/事件(event)的处理过程中存储的数据

蔡政洁的博客 2189

RK356x U-Boot研究所(命令篇)3.7 pci与nvme命令的用法

RK356x U-Boot研究所(命令篇)3.7 pci与nvme命令的用法

Systemcall名屋 2084

Flink核心原理剖析

Flink基础核心原理一文速通

qq_49096347的博客 1281

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

Flink Checkpoint 详解

阳阳阳的博客 8995

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

详解 Flink 的容错机制

有状态流应用中的检查点(checkpoint),其实就是所有任务的状态在某个时间点的一个快照(一份拷贝),这个时间点应该是所有任务都恰好处理完一个相同的输入数据的时刻。在一个流应用程序运行时, Flink 会定期保存检查点,在检查点中会记录每个算子的 id 和状态;如果发生故障,Flink 就会用最近一次成功保存的检查点来恢复应用的状态,重新启动处理流程,就如同“读档”一样。检查点是 Flink 容错机制的核心。

weixin_44480009的博客 2348

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

Flink详解Exactly-Once机制

前言 ​ 通常情况下,流式计算系统都会为用户提供指定数据处理的可靠模式功能,用来表明在实际生产运行中会对数据处理做哪些保障。一般来说,流处理引擎通常为用户的应用程序提供三种数据处理语义:最多一次、至少一次和精确一次。 最多一次(At-most-Once):用户的数据只会被处理一次,不管成功还是失败,不会重试也不会重发。 至少一次(At-least-Once):系统会保证数据或事件至少被处理一次。如果中间发生错误或者丢失,那么会从源头重新发送一条然后进入处理系统,所以同一个事件或者消息会被处理多次。

长臂人猿的博客 3415

Flink 核心机制与源码剖析系列

CEP(Complex Event Processing)用于实时检测事件流中的复杂模式,如金融风控、运维监控等。Flink 的状态管理水位线与事件时间CEP 事件模式匹配机制,均有清晰的源码结构和高效实现。熟悉这些源码和原理,是深入理解 Flink、实现高可靠低延迟流处理的基础。实践中建议关注状态膨胀、延迟设置与容错机制,合理调优资源分配。

IT技术学习与工作笔记分享 1436

深度了解flink(十一) 心跳机制详解

在Flink的各个服务组件中,ResourceManager、JobMaster、TaskExecutor三者之间存在相互检测的心跳机制:ResourceManager会主动发送心跳请求探测JobMaster、TaskExecutor是否存活;JobMaster也会主动发送心跳请求探测TaskExecutor是否存活,以便进行任务重启或者失败处理。

qq_40689430的博客 1120

【Flink】(十四)Flink Runtime 核心机制剖析

本文是在Flink中文社区-进阶教程关于Runtime核心机制的学习总结,首先介绍了 Flink Runtime 的整体架构以及 Job 的基本执行流程,然后介绍在这个过程,Flink 是怎么进行资源管理、作业调度以及错误恢复的。

云祁QI 552
上一篇: Hive软件架构及关键组件解析
下一篇: Spark软件架构与运行机制详解
走过冬季
博客等级 码龄9年 1609粉丝 341原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

走过冬季

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值