Introduction
Hi all,这是我首次在 SegmentFault 上发文章,先简单介绍下我自己吧,我叫 Jason Thon,魔都一枚小开发,喜欢撸猫撸狗打电玩,练习时长两年半,擅长各种 Bug 制作技巧与 Debug 手艺。
在这篇文章里,我将介绍一款与我一同练习时长一年,擅长流处理的新型云原生计算框架 Lightflus。在我的公众号文章: Lightflus: 云原生流处理框架 中,小范围地宣传了一下这款框架,并被 Rust 中文社区转发,一时得到了一点关注度。也因此有了动力继续做下去。
Lightflus 如我的文章中所言,是基于我对现代数据栈的思考,尝试去面向未来数据计算框架开发的一款框架。其目标要解决的问题是主流流计算框架如 Flink 所没有解决的:
- Cloud-Native:因为历史原因,目前 Flink 并没有真的做到 Cloud-Native;
- 上手门槛高:Flink 需要很专业的团队才能玩得转,不是所有公司都有 BAT 这样的开发资源的;
- 云中立:Flink 在商业上不是云中立的,客户只能在某云上使用 Flink 的云版本。这就导致 许多用户怕被云厂商绑定,只能去做各种重复建设的活,浪费大量时间和资源在一件人效比极低的事情上。而 Lightflus 与云无关,理论上什么云环境都能用,用户可以将 Lightflus 非常简单地部署到自己的公有云或私有云环境中;
- Pay-as-you-go:因为沉重的历史包袱,Flink 实现 SaaS 化比较艰难,用户需要付很多额外的钱在一个对主营业务没那么重要的东西上。但 Lightflus 模块化和轻量化的设计,SaaS 化的路径就会简单很多;
Lightflus 尝试通过技术创新,来解决如上的问题。简单来讲,Lightflus 给开发者搭了个云端的流计算“开发环境”,让他们能够更加简单(便宜)地去开发流数据的价值。在未来 Cloud IDE 成熟后,会进一步释放 Lightflus 在 DataOps 上的价值;
Github 与社区
欢迎大家到 Github 去试用下 Lightflus,我们非常希望能得到各位的任何关于产品的建议!
再谈谈社区,其实我是非常欢迎任何人来做 Lightflus 的 contributor 的,但社区是有规范的(包括 PR、提 issue 等),这一块我会逐步完善起来。对于开源生态,我都是拥抱的态度,我会让 Lightflus 加速融入到开源生态中。
下面让我们来详细领略下 Lightflus 这款新型流计算框架吧~
Lightflus 的技术架构
应用架构
Lightflus 的整体应用架构如下图
Lightflus 本质是个分布式实时 DAG 计算引擎,它从指定的流数据源(如 Kafka、MQTT 等)消费数据,经过 User-Defined 的 DAG 计算出结果后,写入指定的数据存储层(如 MySQL,Redis,ElasticSearch 等)或数据管道(如 Kafka)中。
技术架构
Lightflus 由 Master 和 Worker 节点组成,其中 Master 节点有 ApiServer 和 Coordinator 两个服务;
- ApiServer 主要负责与 Client 端或 CLI 工具的交互,提供标准的 REST Api 接口;
- Coordinator 负责集群管理、Checkpoint 管理、动态扩缩容管理等;
- Worker 是主要的计算负载并负责与数据源 Connection 、计算中间结果的 Dispatch、状态管理等;计算图会被构建成一个 Actor System,通过 Channel 在 Actor 间同步计算结果;
API
Lightflus 采用 Typescirpt
作为 API 的开发语言,这么做有几个目的:
Typescirpt
是类型安全的,可以避免很多类型错误,还能够规定 Dataflow 算子转换的输入输出结构,减轻 Runtime 的负担;Typescript
可以有两种编译中间产物:JavaScript
和WebAssembly
,而两者的 Runtime 现在正逐步融合,在未来,用户可以根据自己的需求来决定 Lightflus 使用哪种编译中间产物;Typescript
在写法上与 Java 差异不太大(当然,Typescript
玩法更加丰富),现有的数据开发工程师也能很容易转过来;Typescript
是 web 的语言,天生支持云端化;
Runtime
Lightflus 的核心计算引擎是 Rust
编写的,这么做的目的是:
Rust
能很大程度上保证内存安全,并且拥有接近 C/C++ 的性能;Rust
生态内有成熟的技术可以作为Typescirpt
运行的底层引擎;Rust
在工程化上更加成熟,能很好地模块化,还能通过软件工程来有效管理 Lightflus 的代码产出质量;
核心计算引擎采用 Actor
大规模并行计算模型,这种并行计算模型经过时间充分的检验,证明是目前大规模并行流处理最适合的计算模型,在可扩展性、高可用、容错上也都有成熟的解决方案。Lightflus 是站在巨人的肩膀上起步的,产品能够更快地到达较高的成熟度;
Let's Try Lightflus!
本地部署 Standalone 集群
在 Flink 的世界里,即使是最简单的流任务(如 word count),想要在线上运转起来,都需要折腾不少时间。虽然 Flink 社区努力把 Flink 的使用门槛降到最低,但你想让它哪怕在本地环境正常工作,依旧需要花费不少力气。
而 Lightflus 就非常简单了,只需要执行一行命令:
docker-compose up
docker-compose.yml
文件配置如下:
coordinator:
image: lightflus/coordinator:v1.0.0-alpha
hostname: coordinator
ports:
- '8791:8791'
environment:
RUST_LOG: INFO
WORKER_1: worker
depends_on:
- worker
healthcheck:
test:
[
"CMD",
"/lightflus/runtime/tools/healthcheck",
"-TARGET",
"localhost:8791",
"-METHOD",
"/coordinator.CoordinatorApi/Probe",
"-SERVICE",
"0",
"-PROBE",
"1"
]
interval: 3s
timeout: 5s
retries: 3
start_period: 5s
worker:
image: lightflus/worker:v1.0.0-alpha
hostname: worker
ports:
- '8792:8792'
environment:
RUST_LOG: INFO
healthcheck:
test:
[
"CMD",
"/lightflus/runtime/tools/healthcheck",
"-TARGET",
"localhost:8792",
"-METHOD",
"/worker.TaskWorkerApi/Probe",
"-SERVICE",
"1",
"-PROBE",
"0"
]
interval: 2s
timeout: 1s
retries: 3
start_period: 5s
apiserver:
image: lightflus/apiserver:v1.0.0-alpha
environment:
RUST_LOG: INFO
LIGHTFLUS_COORDINATOR_URI: http://coordinator:8791
ports:
- "8080:8080"
depends_on:
- coordinator
等待 docker 完成镜像拉取和服务启动、检测的过程后,Lightflus Standalone 就能成功启动了,这个时间你还可以喝杯咖啡养养神。
开始编写流任务
我们从最简单也是最常被拿来当例子的 Word Count
来看我们如何编写和部署 Lightflus 的流任务;
准备
由于 Lightflus API 依赖 NodeJS 环境和 Typescript 编译器,因此首先要安装 NodeJS,通过 npm
安装 typescript
依赖,具体可以参考微软的文档;
环境准备
我们需要启动如下的服务
- kafka
- redis
我在这里提供一份 docker-compose.yml
文件供大家参考:
version: "3.9"
services:
zookeeper:
image: 'bitnami/zookeeper:latest'
ports:
- '2181:2181'
environment:
- ALLOW_ANONYMOUS_LOGIN=yes
kafka:
image: 'bitnami/kafka:latest'
ports:
- '9092:9092'
environment:
- KAFKA_BROKER_ID=1
- KAFKA_CFG_LISTENERS=PLAINTEXT://:9092
- KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://kafka:9092
- KAFKA_CFG_ZOOKEEPER_CONNECT=zookeeper:2181
- ALLOW_PLAINTEXT_LISTENER=yes
depends_on:
- zookeeper
redis:
image: 'bitnami/redis:latest'
ports:
- '6379:6379'
environment:
- ALLOW_EMPTY_PASSWORD=yes
执行命令:docker-compose up -f /path/to/docker-compose.yml
启动服务;
在 Lightflus 的 Github 项目仓库里,我准备了一份完整的 docker-compose.yml
文件,如有需要,大家可以直接 clone 仓库后在项目根目录启动即可;
初始化项目
创建一个 nodejs 项目,准备好 typescript
开发环境后,下载 lightflus-api
依赖:
npm i lightflus-api
并初始化 tsconfig.json
文件:
npx tsc --init
编写代码
在准备好后,我们开始编写 word count
的代码,代码非常简单:
// wordCount example
async function wordCount(ctx: ExecutionContext) {
// 从 kafka 中获取字符串流
let source = Kafka
.builder()
.brokers(["localhost:9092"])
// 消费的 topic 为 topic
.topic("topic")
// groupId 为 word_count
.group("word_count")
// 反序列化的类型
.build(undefined, typeof "");
// 将统计的结果存储在 Redis 里
let sink = Redis.new<{ t0: number, t1: string }>()
.host("localhost")
.keyExtractor((v) => v.t1)
.valueExtractor((v) => v.t0.toString());
// 创建一个 Dataflow
let stream = source.createFlow(ctx);
// 设计 Dataflow 的结构
await stream.flatMap(value => value.split(" ").map(v => {
return { t0: 1, t1: v };
}))
.keyBy(v => v.t1)
.reduce((v1, v2) => {
return { t1: v1.t1, t0: v1.t0 + v2.t0 };
})
// 将 Dataflow 计算的结果写入 redis sink 里
.sink(sink)
// 执行
.execute();
}
// 我们指定这个任务的 id 和所属的 namespace
wordCount(ExecutionContext.new("wordCount", "default")).then();
保存该段代码为文件 wordCount.ts
部署流任务
首先设置 Lightflus 服务地址的环境变量
export LIGHTFLUS_ENDPOINT=localhost:8080
我们可以直接通过 nodejs 来编译上面的代码:
yarn tsc -p .
然后运行编译后的文件
node wordCount.js
这样我们就成功将 word count 任务部署到 Lightflus 本地集群上了。
让 Dataflow 跑起来!
接下来一个重要的步骤就是让刚刚部署的 word count 任务跑起来。
我们发送一条数据到 Kafka 对应的 topic 里:
hello hello hello world world world
如果一切安好,那么我们将在 Redis 里找到数据:
redis> GET hello
"3"
redis> GET world
"3"
如果此时再发送这个数据到 Kafka 里,状态就会更新为:
redis> GET hello
"6"
redis> GET world
"6"
Notes
- 由于本地 standalone 模式默认使用内存存储的状态管理器,因此在 Lightflus 集群关闭后,所有状态都会被抹除;
In The Future
Lightflus 目前有两个大的 Roadmap。
- 第一个是支持流批一体,应该说这是目前分布式计算框架的基本趋势,Lightflus 在产品规划上也必然是往这个方向努力的;
- 第二个则是支持原生的存储,目前 Flink 也正在做这件事,但总的来讲流存储/流数仓整体还处于初期阶段。当然,因为 Flink 的 底层功能相对已经比较成熟了,他们可以很快在这些功能上搭起一个流数仓的产品。Lightflus 从规划上看,必然也是要完善基础功能后才会去发力存储的,这个是一个比较长远的规划。
All in All
Lightflus 因为起步较晚,目前还处于完善基础功能的阶段。但用户的使用是任何软件前进路上最大的动力,也因此我们会重视每一个前来试用 Lightflus 的用户的建议。我们也会不断去迭代 Lightflus,让它能不断逼近一个优秀的计算框架。