From a782025420861653f5b554e26d6776112ad50949 Mon Sep 17 00:00:00 2001 From: Kriszu <39726513+wangsizhu0504@users.noreply.github.com> Date: Tue, 24 Oct 2023 21:46:59 +0800 Subject: [PATCH] fix: translate blog article --- blog/0-streampark-flink-on-k8s.md | 204 ++-- .../0-streampark-flink-on-k8s.md | 311 ++++++ .../1-flink-framework-streampark.md | 246 +++++ .../2-streampark-usercase-chinaunion.md | 175 ++++ .../3-streampark-usercase-bondex-paimon.md | 938 ++++++++++++++++++ .../4-streampark-usercase-shunwang.md | 213 ++++ .../5-streampark-usercase-dustess.md | 266 +++++ .../6-streampark-usercase-joyme.md | 161 +++ .../7-streampark-usercase-haibo.md | 101 ++ 9 files changed, 2510 insertions(+), 105 deletions(-) create mode 100644 i18n/zh-CN/docusaurus-plugin-content-blog/0-streampark-flink-on-k8s.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-blog/1-flink-framework-streampark.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-blog/2-streampark-usercase-chinaunion.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-blog/3-streampark-usercase-bondex-paimon.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-blog/4-streampark-usercase-shunwang.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-blog/5-streampark-usercase-dustess.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-blog/6-streampark-usercase-joyme.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-blog/7-streampark-usercase-haibo.md diff --git a/blog/0-streampark-flink-on-k8s.md b/blog/0-streampark-flink-on-k8s.md index ccea49e55..748877590 100644 --- a/blog/0-streampark-flink-on-k8s.md +++ b/blog/0-streampark-flink-on-k8s.md @@ -1,35 +1,34 @@ --- slug: streampark-flink-on-k8s -title: StreamPark Flink on Kubernetes 实践 +title: StreamPark Flink on Kubernetes practice tags: [StreamPark, 生产实践, FlinkSQL, Kubernetes] --- -# StreamPark Flink on Kubernetes 实践 +# StreamPark Flink on Kubernetes practice -雾芯科技创立于2018年1月。目前主营业务包括 RELX 悦刻品牌产品的研发、设计、制造及销售。凭借覆盖全产业链的核心技术与能力,RELX 悦刻致力于为用户提供兼具高品质和安全性的产品。 + Wuxin Technology was founded in January 2018. The current main business includes the research and development, design, manufacturing and sales of RELX brand products. With core technologies and capabilities covering the entire industry chain, RELX is committed to providing users with products that are both high quality and safe. -## **为什么选择 Native Kubernetes** +## **Why Choose Native Kubernetes** -Native Kubernetes 具有以下优势: +Native Kubernetes offers the following advantages: -- 更短的 Failover 时间 -- 可以实现资源托管,不需要手动创建 TaskManager 的 Pod,可以自动完成销毁 -- 具有更加便捷的 HA,Flink 1.12版本之后在 Native Kubernetes 模式下,可以依赖于原生 Kubernetes 的 Leader选举机制来完成 JobManager 的 HA +- Shorter Failover time +- Resource hosting can be implemented without the need to manually create TaskManager Pods, which can be automatically destroyed +- With more convenient HA, in Native Kubernetes mode after Flink version 1.12, you can rely on the Leader election mechanism of native Kubernetes to complete JobManager's HA -Native Kubernetes 和 Standalone Kubernetes 主要区别在于 Flink 与 Kubernetes 交互的方式不同以及由此产生的一系列优势。Standalone Kubernetes 需要用户自定义 JobManager 和 TaskManager 的 Kubernetes 资源描述文件,提交作业时需要用 kubectl 结合资源描述文件启动 Flink 集群。而 Native Kubernetes 模式 Flink Client 里面集成了一个 Kubernetes Client,它可以直接和 Kubernetes API Server 进行通讯,完成 JobManager Deployment 以及 ConfigMap 的创建。JobManager Development 创建完成之后,它里面的 Resource Manager 模块可以直接和 Kubernetes API Server 进行通讯,完成 TaskManager pod 的创建和销毁工作以及 Taskmanager 的弹性伸缩。因此生产环境中推荐使用 Flink on Native Kubernetes 模式部署 Flink 任务。 + The main difference between Native Kubernetes and Standalone Kubernetes lies in the way Flink interacts with Kubernetes and the resulting series of advantages. Standalone Kubernetes requires users to customize the Kubernetes resource description files of JobManager and TaskManager. When submitting a job, you need to use kubectl combined with the resource description file to start the Flink cluster. The Native Kubernetes mode Flink Client integrates a Kubernetes Client, which can directly communicate with the Kubernetes API Server to complete the creation of JobManager Deployment and ConfigMap. After JobManager Development is created, the Resource Manager module in it can directly communicate with the Kubernetes API Server to complete the creation and destruction of TaskManager pods and the elastic scaling of Taskmanager. Therefore, it is recommended to use Flink on Native Kubernetes mode to deploy Flink tasks in production environments. ![](/blog/relx/nativekubernetes_architecture.png) -## **当 Flink On Kubernetes 遇见 StreamPark** +When Flink On Kubernetes meets StreamPark -Flink on Native Kubernetes 目前支持 Application 模式和 Session 模式,两者对比 Application 模式部署规避了 Session 模式的资源隔离问题、以及客户端资源消耗问题,因此**生产环境更推荐采用 Application Mode 部署 Flink 任务。**下面我们分别看看使用原始脚本的方式和使用 StreamPark 开发部署一个 Flink on Native Kubernetes 作业的流程。 + Flink on Native Kubernetes currently supports Application mode and Session mode. Compared with the two, Application mode deployment avoids the resource isolation problem and client resource consumption problem of Session mode. Therefore, it is recommended to use Application Mode to deploy Flink tasks in ** production environments. **Let’s take a look at the method of using the original script and the process of using StreamPark to develop and deploy a Flink on Native Kubernetes job. +Deploy Kubernetes using scripts -### ***使用脚本方式部署Kubernetes*** +In the absence of a platform that supports Flink on Kubernetes task development and deployment, you need to use scripts to submit and stop tasks. This is also the default method provided by Flink. The specific steps are as follows: -在没有一个支持 Flink on Kubernetes 任务开发部署的平台的情况下,需要使用脚本的方式进行任务的提交和停止,这也是 Flink 提供的默认的方式,具体步骤如下: - -1. 在 Flink 客户端节点准备 kubectl 和 Docker 命令运行环境,创建部署 Flink 作业使用的 Kubernetes Namespace 和 Service Account 以及进行 RBAC -2. 编写 Dockerfile 文件,将 Flink 基础镜像和用户的作业 Jar 打包到一起 +1. Prepare the kubectl and Docker command running environment on the Flink client node, create the Kubernetes Namespace and Service Account used to deploy the Flink job, and perform RBAC +2. Write a Dockerfile file to package the Flink base image and the user’s job Jar together ```dockerfile @@ -38,7 +37,7 @@ RUN mkdir -p $FLINK_HOME/usrlib COPY my-flink-job.jar $FLINK_HOME/usrlib/my-flink-job.jar ``` -4. 使用 Flink 客户端脚本启动 Flink 任务 +4. Use Flink client script to start Flink tasks ```shell @@ -52,159 +51,154 @@ COPY my-flink-job.jar $FLINK_HOME/usrlib/my-flink-job.jar local:///opt/flink/usrlib/my-flink-job.jar ``` -5. 使用 Kubectl 命令获取到 Flink 作业的 WebUI 访问地址和 JobId +5. Use the Kubectl command to obtain the WebUI access address and JobId of the Flink job. ```shell -kubectl -n flink-cluster get svc +kubectl -n flink-cluster get svc ``` -6. 使用Flink命令停止作业 +6. Stop the job using Flink command ```shell -./bin/flink cancel - --target kubernetes-application - -Dkubernetes.cluster-id=my-first-application-cluster +./bin/flink cancel + --target kubernetes-application + -Dkubernetes.cluster-id=my-first-application-cluster -Dkubernetes.namespace=flink-cluster ``` -以上就是使用 Flink 提供的最原始的脚本方式把一个 Flink 任务部署到 Kubernetes 上的过程,只做到了最基本的任务提交,如果要达到生产使用级别,还有一系列的问题需要解决,如:方式过于原始无法适配大批量任务、无法记录任务checkpoint 和实时状态跟踪、任务运维和监控困难、无告警机制、 无法集中化管理等等。 + The above is the process of deploying a Flink task to Kubernetes using the most original script method provided by Flink. Only the most basic task submission is achieved. If it is to reach the production use level, there are still a series of problems that need to be solved, such as: the method is too Originally, it was unable to adapt to large batches of tasks, unable to record task checkpoints and real-time status tracking, difficult to operate and monitor tasks, had no alarm mechanism, and could not be managed in a centralized manner, etc. -## **使用 StreamPark 部署 Flink on Kubernetes** +## **Deploy Flink on Kubernetes using StreamPark** ------- + There will be higher requirements for using Flink on Kubernetes in enterprise-level production environments. Generally, you will choose to build your own platform or purchase related commercial products. No matter which solution meets the product capabilities: large-scale task development and deployment, status tracking, operation and maintenance monitoring , failure alarms, unified task management, high availability, etc. are common demands. -对于企业级生产环境使用 Flink on Kubernetes 会有着更高的要求, 一般会选择自建平台或者购买相关商业产品, 不论哪种方案在产品能力上满足: **大批量任务开发部署、状态跟踪、运维监控、失败告警、任务统一管理、高可用性** 等这些是普遍的诉求。 + In response to the above issues, we investigated open source projects in the open source field that support the development and deployment of Flink on Kubernetes tasks. During the investigation, we also encountered other excellent open source projects. After comprehensively comparing multiple open source projects, we came to the conclusion: ** Whether StreamPark is completed The overall performance such as speed, user experience, and stability are all very good, so we finally chose StreamPark as our one-stop real-time computing platform. ** -针对以上问题我们调研了开源领域支持开发部署 Flink on Kubernetes 任务的开源项目,调研的过程中也不乏遇到了其他优秀的开源项目,在综合对比了多个开源项目后得出结论: **StreamPark 不论是完成度还是使用体验、稳定性等整体表现都非常出色,因此最终选择了 StreamPark 作为我们的一站式实时计算平台。**下面我们看看 StreamPark 是如何支持 Flink on Kubernetes : + Let’s take a look at how StreamPark supports Flink on Kubernetes: -### **基础环境配置** +### **Basic environment configuration** -基础环境配置包括 Kubernetes 和 Docker 仓库信息以及 Flink 客户端的信息配置。对于 Kubernetes 基础环境最为简单的方式是直接拷贝 Kubernetes 节点的 .kube/config 到 StreamPark 节点用户目录,之后使用 kubectl 命令创建 Flink 专用的 Kubernetes Namespace 以及进行 RBAC 配置。 + Basic environment configuration includes Kubernetes and Docker warehouse information as well as Flink client information configuration. The simplest way for the Kubernetes basic environment is to directly copy the .kube/config of the Kubernetes node to the StreamPark node user directory, and then use the kubectl command to create a Flink-specific Kubernetes Namespace and perform RBAC configuration. ```shell -# 创建Flink作业使用的k8s namespace +# Create k8s namespace used by Flink jobs kubectl create ns flink-cluster -# 对default用户进行RBAC资源绑定 +# Bind RBAC resources to the default user kubectl create clusterrolebinding flink-role-binding-default --clusterrole=edit --serviceaccount=flink-cluster:default + ``` -Docker 账户信息直接在 Docker Setting 界面配置即可: +Docker account information can be configured directly in the Docker Setting interface: ![](/blog/relx/docker_setting.png) -StreamPark 可适配多版本 Flink 作业开发,Flink 客户端直接在 StreamPark Setting 界面配置即可: +StreamPark can adapt to multi-version Flink job development. The Flink client can be configured directly on the StreamPark Setting interface: ![](/blog/relx/flinkversion_setting.png) -### **作业开发** +### **Job development** -StreamPark 做好基础环境配置之后只需要三步即可开发部署一个 Flink 作业: +After StreamPark has configured the basic environment, it only takes three steps to develop and deploy a Flink job: ![](/blog/relx/development_process.png) -StreamPark 既支持 Upload Jar 也支持直接编写 Flink SQL 作业, **Flink SQL 作业只需要输入SQL 和 依赖项即可, 该方式大大提升了开发体验,** **并且规避了依赖冲突等问题,**对此部分本文不重点介绍。 + StreamPark supports both Upload Jar and direct writing of Flink SQL jobs. **Flink SQL jobs only need to enter SQL and dependencies. This method greatly improves the development experience and avoids problems such as dependency conflicts.** This article does not focus on this part。 -这里需要选择部署模式为 kubernetes application, 并且需要在作业开发页面进行以下参数的配置:红框中参数为 Flink on Kubernetes 基础参数。 + Here you need to select the deployment mode as kubernetes application, and configure the following parameters on the job development page: The parameters in the red box are the basic parameters of Flink on Kubernetes. ![](/blog/relx/kubernetes_base_parameters.png) -下面参数为 Flink 作业和资源相关的参数,Resolve Order 的选择与代码加载模式有关,对于 DataStream API 开发的 Upload Jar上传的作业选择使用 Child-first,Flink SQL 作业选择使用 Parent-first 加载。 + The following parameters are parameters related to Flink jobs and resources. The choice of Resolve Order is related to the code loading mode. For jobs uploaded by the Upload Jar developed by the DataStream API, choose to use Child-first, and for Flink SQL jobs, choose to use Parent-first loading. ![](/blog/relx/flink_parameters.png) -最后就是下面这两个重量级参数了,对于 Native Kubernetes 而言,k8s-pod-template 一般只需要进行 pod-template 配置即可,Dynamic Option 是 pod-template 参数的补充,对于一些个性化配置可以在 Dynamic Option 中配置。更多 Dynamic Option 直接参考 Flink 官网即可。 + Finally, there are the following two heavyweight parameters. For Native Kubernetes, k8s-pod-template generally only requires pod-template configuration. Dynamic Option is a supplement to the pod-template parameters. For some personalized configurations, you can Configured in Dynamic Option. For more Dynamic Option, please directly refer to the Flink official website. ![](/blog/relx/pod_template.png) -### **作业上线** +### **Job online** -作业开发完成之后是作业上线环节,在这一环节中 StreamPark 做了大量的工作,具体如下: +After the job development is completed, the job comes online. In this step, StreamPark has done a lot of work, as follows: -- 准备环境 -- 作业中的依赖下载 -- 构建作业(打JAR包) -- 构建镜像 -- 推送镜像到远程仓库 +- Prepare environment +- Dependency download in job +- Build job (JAR package) +- Build image +- Push the image to the remote warehouse -**对于用户来说: 只需要点击任务列表中的云状的上线按钮即可。** +**For users: Just click the cloud-shaped online button in the task list** ![](/blog/relx/operation.png) -在镜像构建和推送的时候我们可以看到 StreamPark 做的一系列工作: **读取配置、构建镜像、推送镜像到远程仓库...** 这里要给StreamPark 一个大大的赞! +We can see a series of work done by StreamPark when building and pushing the image.: **Read the configuration, build the image, and push the image to the remote warehouse...** I want to give StreamPark a big thumbs up! ![](/blog/relx/step_details.png) -### **作业提交** +### **Assignment submission** -最后只需要点击 Operation 里 start Application 按钮便可启动一个 Flink on Kubernetes 作业,作业启动成功之后点击作业名便可跳转到 Jobmanager WebUI 页面、整个过程非常简单丝滑。 + Finally, you only need to click the start Application button in Operation to start a Flink on Kubernetes job. After the job is successfully started, click on the job name to jump to the Jobmanager WebUI page. The whole process is very simple and smooth. ![](/blog/relx/homework_submit.png) -整个过程仅需上述三步,即可完成在 StreamPark 上开发和部署一个Flink on Kubernetes 作业。而 StreamPark 对于 Flink on Kubernetes 的支持远远不止提交个任务这么简单。 - -### **作业管理** + The entire process only requires the above three steps to complete the development and deployment of a Flink on Kubernetes job on StreamPark. StreamPark's support for Flink on Kubernetes goes far beyond simply submitting a task. -**在作业提交之后,StreamPark 能实时获取到任务的最新 checkpoint 地址、任务的运行状态、集群实时的资源消耗信息,针对运行的任务可以非常方便的一键启停, 在停止作业时支持记录 savepoint 的位置, 以及再次启动时从 savepoint 恢复状态等功能,从而保证了生产环境的数据一致性,真正具备 Flink on Kubernetes 的 一站式开发、部署、运维监控的能力。** +### **Job management** -接下来我们来看看这一块的能力 StreamPark 是如何进行支持的: +**After the job is submitted, StreamPark can obtain the latest checkpoint address of the task, the running status of the task, and the real-time resource consumption information of the cluster in real time. It can very conveniently start and stop the running task with one click, and supports recording the savepoint location when stopping the job. , as well as functions such as restoring the state from savepoint when restarting, thus ensuring the data consistency of the production environment and truly possessing the one-stop development, deployment, operation and maintenance monitoring capabilities of Flink on Kubernetes.** -- **实时记录checkpoint** +Next, let’s take a look at how StreamPark supports this capability: ------- +- **Record checkpoint in real time** -在作业提交之后,有时候需要更改作业逻辑但是要保证数据的一致性,那么就需要平台具有实时记录每一次 checkpoint 位置的能力, 以及停止时记录最后的 savepoint 位置的能力,StreamPark 在 Flink on Kubernetes 上很好的实现了该功能。默认会每隔5秒获取一次 checkpoint 信息记录到对应的表中,并且会按照 Flink 中保留 checkpoint 数量的策略,只保留 state.checkpoints.num-retained 个,超过的部分则删除。在任务停止时有勾选 savepoint 的选项,如勾选了savepoint 选项,在任务停止时会做 savepoint 操作,同样会记录 savepoint 具体位置到表中。 + After the job is submitted, sometimes it is necessary to change the job logic but to ensure data consistency, then the platform needs to have the ability to record the location of each checkpoint in real time, as well as the ability to record the last savepoint location when stopped. StreamPark is on Flink on Kubernetes This function is implemented very well. By default, checkpoint information will be obtained and recorded in the corresponding table every 5 seconds, and according to the policy of retaining the number of checkpoints in Flink, only state.checkpoints.num-retained will be retained, and the excess will be deleted. There is an option to check the savepoint when the task is stopped. If the savepoint option is checked, the savepoint operation will be performed when the task is stopped, and the specific location of the savepoint will also be recorded in the table. -默认 savepoint 的根路径只需要在 Flink Home flink-conf.yaml 文件中配置即可自动识别,除了默认地址,在停止时也可以自定义指定 savepoint 的根路径。 + The root path of the default savepoint only needs to be configured in the Flink Home flink-conf.yaml file to automatically identify it. In addition to the default address, the root path of the savepoint can also be customized and specified when stopping. ![](/blog/relx/savepoint.png) ![](/blog/relx/checkpoint.png) -- **实时跟踪运行状态** +- **Track running status in real time** ------- - -对于生产环境的挑战,很重要的一点就是监控是否到位,Flink on Kubernetes 更是如此。这点很重要, 也是最基本需要具备的能力,StreamPark 可实时监控 Flink on Kubernetes 作业的运行状态并在平台上展示给用户,在页面上可以很方便的根据各种运行状态来检索任务。 + For challenges in the production environment, a very important point is whether monitoring is in place, especially for Flink on Kubernetes. This is very important and is the most basic capability. StreamPark can monitor the running status of Flink on Kubernetes jobs in real time and display it to users on the platform. Tasks can be easily retrieved based on various running statuses on the page. ![](/blog/relx/run_status.png) -- **完善的告警机制** - ------- +- **Complete alarm mechanism** -除此之外 StreamPark 还具备完善的报警功能: 支持邮件、钉钉、微信和短信 等。这也是当初公司调研之后选择 StreamPark 作为 Flink on Kubernetes 一站式平台的重要原因。 + In addition, StreamPark also has complete alarm functions: supporting email, DingTalk, WeChat and SMS, etc. This is also an important reason why the company chose StreamPark as the one-stop platform for Flink on Kubernetes after initial research. ![](/blog/relx/alarm.png) -通过以上我们看到 StreamPark 在支持 Flink on Kubernetes 开发部署过程中具备的能力, 包括:**作业的开发能力、部署能力、监控能力、运维能力、异常处理能力等,StreamPark 提供的是一套相对完整的解决方案。 且已经具备了一些 CICD/DevOps 的能力,整体的完成度还在持续提升。是在整个开源领域中对于 Flink on Kubernetes 一站式开发部署运维工作全链路都支持的产品,StreamPark 是值得被称赞的。** + From the above, we can see that StreamPark has the capabilities to support the development and deployment process of Flink on Kubernetes, including: ** job development capabilities, deployment capabilities, monitoring capabilities, operation and maintenance capabilities, exception handling capabilities, etc. StreamPark provides a relatively complete set of s solution. And it already has some CICD/DevOps capabilities, and the overall completion level continues to improve. It is a product that supports the full link of Flink on Kubernetes one-stop development, deployment, operation and maintenance work in the entire open source field. StreamPark is worthy of praise. ** -## **StreamPark 在雾芯科技的落地实践** +## **StreamPark’s implementation in Wuxin Technology** -StreamPark 在雾芯科技落地较晚,目前主要用于实时数据集成作业和实时指标计算作业的开发部署,有 Jar 任务也有 Flink SQL 任务,全部使用 Native Kubernetes 部署;数据源有CDC、Kafka 等,Sink 端有 Maxcompute、kafka、Hive 等,以下是公司开发环境StreamPark 平台截图: + StreamPark was launched late in Wuxin Technology. It is currently mainly used for the development and deployment of real-time data integration jobs and real-time indicator calculation jobs. There are Jar tasks and Flink SQL tasks, all deployed using Native Kubernetes; data sources include CDC, Kafka, etc., and Sink end There are Maxcompute, kafka, Hive, etc. The following is a screenshot of the company's development environment StreamPark platform: ![](/blog/relx/screenshot.png) -## 遇到的问题 +## Problems encountered -任何新技术都有探索与踩坑的过程,失败的经验是宝贵的,这里介绍下 StreamPark 在雾芯科技落地过程中踩的一些坑和经验,**这块的内容不仅仅关于 StreamPark 的部分, 相信会带给所有使用 Flink on Kubernetes 的小伙伴一些参考。 + Any new technology has a process of exploration and pitfalls. The experience of failure is precious. Here are some pitfalls and experiences that StreamPark has stepped into during the implementation of fog core technology. **The content of this section is not only about StreamPark. I believe it will bring some reference to all friends who use Flink on Kubernetes. -### **常见问题总结如下** +### **FAQs are summarized below** -- **kubernetes pod 拉取镜像失败** +- **Kubernetes pod failed to pull the image** -这个问题主要在于 Kubernetes pod-template 缺少 docker的 imagePullSecrets +The main problem is that Kubernetes pod-template lacks docker’s imagePullSecrets -- **scala 版本不一致** +- **Scala version inconsistent** -由于 StreamPark 部署需要 Scala 环境,而且 Flink SQL 运行需要用到 StreamPark 提供的 Flink SQL Client,因此一定要保证 Flink 作业的 Scala 版本和 StreamPark 的 Scala 版本保持一致。 + Since StreamPark deployment requires a Scala environment, and Flink SQL operation requires the Flink SQL Client provided by StreamPark, it is necessary to ensure that the Scala version of the Flink job is consistent with the Scala version of StreamPark. -- **注意类冲突** +- **Be aware of class conflicts** -进行 Flink SQL 作业开发的时候需要注意 Flink 镜像和 Flink connector 及 UDF 中有没有类冲突,最好的避免类冲突的办法是将 Flink 镜像和常用的 Flink connector 及用户 UDF 打成一个可用的基础镜像,之后其他 Flink SQL 作业直接复用即可。 + When developing Flink SQL jobs, you need to pay attention to whether there are any class conflicts between the Flink image and the Flink connector and UDF. The best way to avoid class conflicts is to make the Flink image and the commonly used Flink connector and user UDF into a usable basic image. After that, other Flink SQL jobs can be reused directly. -- **没有 Hadoop 环境怎么存储 checkpoint?** +- **How to store checkpoint without Hadoop environment?** -HDFS 阿里云 OSS/AWS S3 都可以进行 checkpoint 和 savepoint 存储,Flink 基础镜像已经有了对于 OSS 和 S3 的支持,如果没有 HDFS 可以使用阿里云 OSS 或者 S3存储状态和 checkpoint 和 savepoint 数据,只需要在 Flink 动态参数中简单配置一下即可。 + HDFS, Alibaba Cloud OSS/AWS S3 can both perform checkpoint and savepoint storage. The Flink basic image already has support for OSS and S3. If you do not have HDFS, you can use Alibaba Cloud OSS or S3 to store status and checkpoint and savepoint data. You only need to use Flink Simply configure it in the dynamic parameters. ```shell @@ -218,19 +212,19 @@ HDFS 阿里云 OSS/AWS S3 都可以进行 checkpoint 和 savepoint 存储,Flin -Dstate.savepoints.dir=oss://realtime-xxx/streamx/dev/savepoints/ ``` -- **改了代码重新发布后并未生效** +- **The changed code did not take effect after it was republished** -该问题与 Kubernetes pod 镜像拉取策略有关,建议将 Pod 镜像拉取策略设置为 Always: +This issue is related to the Kubernetes pod image pull policy. It is recommended to set the Pod image pull policy to Always: ‍-Dkubernetes.container.image.pull-policy=Always -- **任务每次重启都会导致多出一个 Job 实例** +- **Each restart of the task will result in one more Job instance** -在配置了基于 kubernetes 的HA的前提条件下,当需要停止 Flink 任务时,需要通过 StreamPark 的 cancel 来进行,不要直接通过 kubernetes 集群删除 Flink 任务的 Deployment。因为 Flink 的关闭有其自有的关闭流程,在删除 pod 同时 Configmap 中的相应配置文件也会被一并删除,而直接删除 pod 会导致 Configmap 的残留。当相同名称的任务重启时,会出现两个相同 Job 现象,因为在启动时,任务会加载之前残留的配置文件,尝试将已经关闭的任务恢复。 + Under the premise that kubernetes-based HA is configured, when you need to stop the Flink task, you need to use cancel of StreamPark. Do not delete the Deployment of the Flink task directly through the kubernetes cluster. Because Flink's shutdown has its own shutdown process, when deleting a pod, the corresponding configuration files in the Configmap will also be deleted. Direct deletion of the pod will result in the remnants of the Configmap. When a task with the same name is restarted, two identical jobs will appear because at startup, the task will load the remaining configuration files and try to restore the closed task. -- **kubernetes pod 域名访问怎么实现** +- **How to implement kubernetes pod domain name access** -域名配置只需要按照 Kubernetes 资源在 pod-template 中配置即,可针对以上问题给大家分享一个本人总结的一个 pod-template.yaml 模板: +Domain name configuration only needs to be configured in pod-template according to Kubernetes resources. I can share with you a pod-template.yaml template that I summarized based on the above issues: ```yaml @@ -242,7 +236,7 @@ spec: serviceAccount: default containers: - name: flink-main-container - image: + image: imagePullSecrets: - name: regsecret hostAliases: @@ -258,15 +252,15 @@ spec: ``` -### **最佳实践** +### **Best Practices** -悦刻的大数据组件很多基于阿里云,比如 Maxcompute、阿里云 Redis,同时我们这边 Flink SQL 作业需要用到一些 UDF。最开始我们是采用使用 Flink Base image + maven dependency + upload udf jar 的方式,但是实践过程中遇到了一些比如版本冲突、类冲突的问题,同时如果是大批量作业的话这种方式开发效率比较低,最后我们采取将公司级别的常用的 Flink connector 和 udf 和 Flink base image 打包成公司级别的基础镜像,新 Flink SQL 作业使用该基础镜像之后直接写 Flink SQL 即可,大大提高了开发效率。 + Many of RELX's big data components are based on Alibaba Cloud, such as Maxcompute and Alibaba Cloud Redis. At the same time, our Flink SQL jobs need to use some UDFs. At first, we adopted the method of using Flink Base image + maven dependency + upload udf jar, but in practice we encountered some problems such as version conflicts and class conflicts. At the same time, if it is a large-volume job, the development efficiency of this method is relatively low. Finally, we packaged the commonly used Flink connectors, udf and Flink base image at the company level into a company-level base image. New Flink SQL jobs can directly write Flink SQL after using this base image, which greatly improves development efficiency. -**下面分享一个制作基础镜像的简单步骤:** +**Let’s share a simple step to create a basic image:** -**1. 准备需要的 JAR** +**1. Prepare the required JAR** -将常用 Flink Connector Jar 和用户 Udf Jar 放置在同一文件夹 lib 下,以下都是Flink 1.13.6 常用的一些 connector 包 +Place the commonly used Flink Connector Jar and the user Udf Jar in the same folder lib. The following are some commonly used connector packages in Flink 1.13.6 ```jar bigdata-udxf-1.0.0-shaded.jar @@ -278,34 +272,34 @@ ververica-connector-odps-1.13-vvr-4.0.7.jar ververica-connector-redis-1.13-vvr-4.0.7.jar ``` -**2. 准备 Dockerfile** +**2. Prepare Dockerfile** -创建 Dockerfile 文件,并将 Dockerfile 文件跟上面文件夹放置在同一文件夹下 +Create a Dockerfile file and place the Dockerfile file in the same folder as the above folder ```shell FROM flink:1.13.6-scala_2.11COPY lib $FLINK_HOME/lib/ ``` -**3. 基础镜像制作并推送私有仓库** +**3. Create a basic image and push it to a private warehouse** ```shell -docker login --username=xxxdocker \ +docker login --username=xxxdocker \ build -t udf_flink_1.13.6-scala_2.11:latest \ .docker tag udf_flink_1.13.6-scala_2.11:latest \ k8s-harbor.xxx.com/streamx/udf_flink_1.13.6-scala_2.11:latestdocker \ push k8s-harbor.xxx.com/streamx/udf_flink_1.13.6-scala_2.11:latest ``` -## **未来期待** +## **Future Expectations** -- **StreamPark 对于 Flink 作业 Metric 监控的支持** +- **StreamPark supports Flink job metric monitoring** -StreamPark 如果可以对接 Flink Metric 数据而且可以在 StreamPark 平台上展示每时每刻 Flink 的实时消费数据情况就太棒了 +It would be great if StreamPark could connect to Flink Metric data and display Flink’s real-time consumption data at every moment on the StreamPark platform. -- **StreamPark 对于Flink 作业日志持久化的支持** +- **StreamPark supports Flink job log persistence** -对于部署到 YARN 的 Flink 来说,如果 Flink 程序挂了,我们可以去 YARN 上看历史日志,但是对于 Kubernetes 来说,如果程序挂了,那么 Kubernetes 的 pod 就消失了,就没法查日志了。所以用户需要借助 Kubernetes 上的工具进行日志持久化,如果 StreamPark 支持 Kubernetes 日志持久化接口就更好了。 + For Flink deployed to YARN, if the Flink program hangs, we can go to YARN to view the historical logs. However, for Kubernetes, if the program hangs, the Kubernetes pod will disappear and there will be no way to check the logs. Therefore, users need to use tools on Kubernetes for log persistence. It would be better if StreamPark supports the Kubernetes log persistence interface. -- **镜像过大的问题改进** +- **Improvement of the problem of too large image** -StreamPark 目前对于 Flink on Kubernetes 作业的镜像支持是将基础镜像和用户代码打成一个 Fat 镜像推送到 Docker 仓库,这种方式存在的问题就是镜像过大的时候耗时比较久,希望未来基础镜像可以复用不需要每次都与业务代码打到一起,这样可以极大地提升开发效率和节约成本。 +StreamPark's current image support for Flink on Kubernetes jobs is to combine the basic image and user code into a Fat image and push it to the Docker warehouse. The problem with this method is that it takes a long time when the image is too large. It is hoped that the basic image can be restored in the future. There is no need to hit the business code together every time, which can greatly improve development efficiency and save costs. diff --git a/i18n/zh-CN/docusaurus-plugin-content-blog/0-streampark-flink-on-k8s.md b/i18n/zh-CN/docusaurus-plugin-content-blog/0-streampark-flink-on-k8s.md new file mode 100644 index 000000000..ccea49e55 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-blog/0-streampark-flink-on-k8s.md @@ -0,0 +1,311 @@ +--- +slug: streampark-flink-on-k8s +title: StreamPark Flink on Kubernetes 实践 +tags: [StreamPark, 生产实践, FlinkSQL, Kubernetes] +--- + +# StreamPark Flink on Kubernetes 实践 + +雾芯科技创立于2018年1月。目前主营业务包括 RELX 悦刻品牌产品的研发、设计、制造及销售。凭借覆盖全产业链的核心技术与能力,RELX 悦刻致力于为用户提供兼具高品质和安全性的产品。 + +## **为什么选择 Native Kubernetes** + +Native Kubernetes 具有以下优势: + +- 更短的 Failover 时间 +- 可以实现资源托管,不需要手动创建 TaskManager 的 Pod,可以自动完成销毁 +- 具有更加便捷的 HA,Flink 1.12版本之后在 Native Kubernetes 模式下,可以依赖于原生 Kubernetes 的 Leader选举机制来完成 JobManager 的 HA + +Native Kubernetes 和 Standalone Kubernetes 主要区别在于 Flink 与 Kubernetes 交互的方式不同以及由此产生的一系列优势。Standalone Kubernetes 需要用户自定义 JobManager 和 TaskManager 的 Kubernetes 资源描述文件,提交作业时需要用 kubectl 结合资源描述文件启动 Flink 集群。而 Native Kubernetes 模式 Flink Client 里面集成了一个 Kubernetes Client,它可以直接和 Kubernetes API Server 进行通讯,完成 JobManager Deployment 以及 ConfigMap 的创建。JobManager Development 创建完成之后,它里面的 Resource Manager 模块可以直接和 Kubernetes API Server 进行通讯,完成 TaskManager pod 的创建和销毁工作以及 Taskmanager 的弹性伸缩。因此生产环境中推荐使用 Flink on Native Kubernetes 模式部署 Flink 任务。 + +![](/blog/relx/nativekubernetes_architecture.png) + +## **当 Flink On Kubernetes 遇见 StreamPark** + +Flink on Native Kubernetes 目前支持 Application 模式和 Session 模式,两者对比 Application 模式部署规避了 Session 模式的资源隔离问题、以及客户端资源消耗问题,因此**生产环境更推荐采用 Application Mode 部署 Flink 任务。**下面我们分别看看使用原始脚本的方式和使用 StreamPark 开发部署一个 Flink on Native Kubernetes 作业的流程。 + +### ***使用脚本方式部署Kubernetes*** + +在没有一个支持 Flink on Kubernetes 任务开发部署的平台的情况下,需要使用脚本的方式进行任务的提交和停止,这也是 Flink 提供的默认的方式,具体步骤如下: + +1. 在 Flink 客户端节点准备 kubectl 和 Docker 命令运行环境,创建部署 Flink 作业使用的 Kubernetes Namespace 和 Service Account 以及进行 RBAC +2. 编写 Dockerfile 文件,将 Flink 基础镜像和用户的作业 Jar 打包到一起 + +```dockerfile + +FROM flink:1.13.6-scala_2.11 +RUN mkdir -p $FLINK_HOME/usrlib +COPY my-flink-job.jar $FLINK_HOME/usrlib/my-flink-job.jar +``` + +4. 使用 Flink 客户端脚本启动 Flink 任务 + +```shell + +./bin/flink run-application \ + --target kubernetes-application \ + -Dkubernetes.namespace=flink-cluster \ + -Dkubernetes.jobmanager.service-account=default \ + -Dkubernetes.cluster-id=my-first-application-cluster \ + -Dkubernetes.container.image=relx_docker_url/streamx/relx_flink_1.13.6-scala_2.11:latest \ + -Dkubernetes.rest-service.exposed.type=NodePort \ + local:///opt/flink/usrlib/my-flink-job.jar +``` + +5. 使用 Kubectl 命令获取到 Flink 作业的 WebUI 访问地址和 JobId + +```shell +kubectl -n flink-cluster get svc +``` + +6. 使用Flink命令停止作业 + +```shell +./bin/flink cancel + --target kubernetes-application + -Dkubernetes.cluster-id=my-first-application-cluster + -Dkubernetes.namespace=flink-cluster +``` + +以上就是使用 Flink 提供的最原始的脚本方式把一个 Flink 任务部署到 Kubernetes 上的过程,只做到了最基本的任务提交,如果要达到生产使用级别,还有一系列的问题需要解决,如:方式过于原始无法适配大批量任务、无法记录任务checkpoint 和实时状态跟踪、任务运维和监控困难、无告警机制、 无法集中化管理等等。 + +## **使用 StreamPark 部署 Flink on Kubernetes** + +------ + +对于企业级生产环境使用 Flink on Kubernetes 会有着更高的要求, 一般会选择自建平台或者购买相关商业产品, 不论哪种方案在产品能力上满足: **大批量任务开发部署、状态跟踪、运维监控、失败告警、任务统一管理、高可用性** 等这些是普遍的诉求。 + +针对以上问题我们调研了开源领域支持开发部署 Flink on Kubernetes 任务的开源项目,调研的过程中也不乏遇到了其他优秀的开源项目,在综合对比了多个开源项目后得出结论: **StreamPark 不论是完成度还是使用体验、稳定性等整体表现都非常出色,因此最终选择了 StreamPark 作为我们的一站式实时计算平台。**下面我们看看 StreamPark 是如何支持 Flink on Kubernetes : + +### **基础环境配置** + +基础环境配置包括 Kubernetes 和 Docker 仓库信息以及 Flink 客户端的信息配置。对于 Kubernetes 基础环境最为简单的方式是直接拷贝 Kubernetes 节点的 .kube/config 到 StreamPark 节点用户目录,之后使用 kubectl 命令创建 Flink 专用的 Kubernetes Namespace 以及进行 RBAC 配置。 + +```shell +# 创建Flink作业使用的k8s namespace +kubectl create ns flink-cluster +# 对default用户进行RBAC资源绑定 +kubectl create clusterrolebinding flink-role-binding-default --clusterrole=edit --serviceaccount=flink-cluster:default +``` + +Docker 账户信息直接在 Docker Setting 界面配置即可: + +![](/blog/relx/docker_setting.png) + +StreamPark 可适配多版本 Flink 作业开发,Flink 客户端直接在 StreamPark Setting 界面配置即可: + +![](/blog/relx/flinkversion_setting.png) + +### **作业开发** + +StreamPark 做好基础环境配置之后只需要三步即可开发部署一个 Flink 作业: + +![](/blog/relx/development_process.png) + +StreamPark 既支持 Upload Jar 也支持直接编写 Flink SQL 作业, **Flink SQL 作业只需要输入SQL 和 依赖项即可, 该方式大大提升了开发体验,** **并且规避了依赖冲突等问题,**对此部分本文不重点介绍。 + +这里需要选择部署模式为 kubernetes application, 并且需要在作业开发页面进行以下参数的配置:红框中参数为 Flink on Kubernetes 基础参数。 + +![](/blog/relx/kubernetes_base_parameters.png) + +下面参数为 Flink 作业和资源相关的参数,Resolve Order 的选择与代码加载模式有关,对于 DataStream API 开发的 Upload Jar上传的作业选择使用 Child-first,Flink SQL 作业选择使用 Parent-first 加载。 + +![](/blog/relx/flink_parameters.png) + +最后就是下面这两个重量级参数了,对于 Native Kubernetes 而言,k8s-pod-template 一般只需要进行 pod-template 配置即可,Dynamic Option 是 pod-template 参数的补充,对于一些个性化配置可以在 Dynamic Option 中配置。更多 Dynamic Option 直接参考 Flink 官网即可。 + +![](/blog/relx/pod_template.png) + +### **作业上线** + +作业开发完成之后是作业上线环节,在这一环节中 StreamPark 做了大量的工作,具体如下: + +- 准备环境 +- 作业中的依赖下载 +- 构建作业(打JAR包) +- 构建镜像 +- 推送镜像到远程仓库 + +**对于用户来说: 只需要点击任务列表中的云状的上线按钮即可。** + +![](/blog/relx/operation.png) + +在镜像构建和推送的时候我们可以看到 StreamPark 做的一系列工作: **读取配置、构建镜像、推送镜像到远程仓库...** 这里要给StreamPark 一个大大的赞! + +![](/blog/relx/step_details.png) + +### **作业提交** + +最后只需要点击 Operation 里 start Application 按钮便可启动一个 Flink on Kubernetes 作业,作业启动成功之后点击作业名便可跳转到 Jobmanager WebUI 页面、整个过程非常简单丝滑。 + +![](/blog/relx/homework_submit.png) + +整个过程仅需上述三步,即可完成在 StreamPark 上开发和部署一个Flink on Kubernetes 作业。而 StreamPark 对于 Flink on Kubernetes 的支持远远不止提交个任务这么简单。 + +### **作业管理** + +**在作业提交之后,StreamPark 能实时获取到任务的最新 checkpoint 地址、任务的运行状态、集群实时的资源消耗信息,针对运行的任务可以非常方便的一键启停, 在停止作业时支持记录 savepoint 的位置, 以及再次启动时从 savepoint 恢复状态等功能,从而保证了生产环境的数据一致性,真正具备 Flink on Kubernetes 的 一站式开发、部署、运维监控的能力。** + +接下来我们来看看这一块的能力 StreamPark 是如何进行支持的: + +- **实时记录checkpoint** + +------ + +在作业提交之后,有时候需要更改作业逻辑但是要保证数据的一致性,那么就需要平台具有实时记录每一次 checkpoint 位置的能力, 以及停止时记录最后的 savepoint 位置的能力,StreamPark 在 Flink on Kubernetes 上很好的实现了该功能。默认会每隔5秒获取一次 checkpoint 信息记录到对应的表中,并且会按照 Flink 中保留 checkpoint 数量的策略,只保留 state.checkpoints.num-retained 个,超过的部分则删除。在任务停止时有勾选 savepoint 的选项,如勾选了savepoint 选项,在任务停止时会做 savepoint 操作,同样会记录 savepoint 具体位置到表中。 + +默认 savepoint 的根路径只需要在 Flink Home flink-conf.yaml 文件中配置即可自动识别,除了默认地址,在停止时也可以自定义指定 savepoint 的根路径。 + +![](/blog/relx/savepoint.png) + +![](/blog/relx/checkpoint.png) + +- **实时跟踪运行状态** + +------ + +对于生产环境的挑战,很重要的一点就是监控是否到位,Flink on Kubernetes 更是如此。这点很重要, 也是最基本需要具备的能力,StreamPark 可实时监控 Flink on Kubernetes 作业的运行状态并在平台上展示给用户,在页面上可以很方便的根据各种运行状态来检索任务。 + +![](/blog/relx/run_status.png) + +- **完善的告警机制** + +------ + +除此之外 StreamPark 还具备完善的报警功能: 支持邮件、钉钉、微信和短信 等。这也是当初公司调研之后选择 StreamPark 作为 Flink on Kubernetes 一站式平台的重要原因。 + +![](/blog/relx/alarm.png) + +通过以上我们看到 StreamPark 在支持 Flink on Kubernetes 开发部署过程中具备的能力, 包括:**作业的开发能力、部署能力、监控能力、运维能力、异常处理能力等,StreamPark 提供的是一套相对完整的解决方案。 且已经具备了一些 CICD/DevOps 的能力,整体的完成度还在持续提升。是在整个开源领域中对于 Flink on Kubernetes 一站式开发部署运维工作全链路都支持的产品,StreamPark 是值得被称赞的。** + +## **StreamPark 在雾芯科技的落地实践** + +StreamPark 在雾芯科技落地较晚,目前主要用于实时数据集成作业和实时指标计算作业的开发部署,有 Jar 任务也有 Flink SQL 任务,全部使用 Native Kubernetes 部署;数据源有CDC、Kafka 等,Sink 端有 Maxcompute、kafka、Hive 等,以下是公司开发环境StreamPark 平台截图: + +![](/blog/relx/screenshot.png) + +## 遇到的问题 + +任何新技术都有探索与踩坑的过程,失败的经验是宝贵的,这里介绍下 StreamPark 在雾芯科技落地过程中踩的一些坑和经验,**这块的内容不仅仅关于 StreamPark 的部分, 相信会带给所有使用 Flink on Kubernetes 的小伙伴一些参考。 + +### **常见问题总结如下** + +- **kubernetes pod 拉取镜像失败** + +这个问题主要在于 Kubernetes pod-template 缺少 docker的 imagePullSecrets + +- **scala 版本不一致** + +由于 StreamPark 部署需要 Scala 环境,而且 Flink SQL 运行需要用到 StreamPark 提供的 Flink SQL Client,因此一定要保证 Flink 作业的 Scala 版本和 StreamPark 的 Scala 版本保持一致。 + +- **注意类冲突** + +进行 Flink SQL 作业开发的时候需要注意 Flink 镜像和 Flink connector 及 UDF 中有没有类冲突,最好的避免类冲突的办法是将 Flink 镜像和常用的 Flink connector 及用户 UDF 打成一个可用的基础镜像,之后其他 Flink SQL 作业直接复用即可。 + +- **没有 Hadoop 环境怎么存储 checkpoint?** + +HDFS 阿里云 OSS/AWS S3 都可以进行 checkpoint 和 savepoint 存储,Flink 基础镜像已经有了对于 OSS 和 S3 的支持,如果没有 HDFS 可以使用阿里云 OSS 或者 S3存储状态和 checkpoint 和 savepoint 数据,只需要在 Flink 动态参数中简单配置一下即可。 + +```shell + +-Dstate.backend=rocksdb +-Dcontainerized.master.env.ENABLE_BUILT_IN_PLUGINS=flink-oss-fs-hadoop-1.13.6.jar +-Dcontainerized.taskmanager.env.ENABLE_BUILT_IN_PLUGINS=flink-oss-fs-hadoop-1.13.6.jar +-Dfs.oss.endpoint=xxyy.aliyuncs.com +-Dfs.oss.accessKeyId=xxxxxxxxxx +-Dfs.oss.accessKeySecret=xxxxxxxxxx +-Dstate.checkpoints.dir=oss://realtime-xxx/streamx/dev/checkpoints/ +-Dstate.savepoints.dir=oss://realtime-xxx/streamx/dev/savepoints/ +``` + +- **改了代码重新发布后并未生效** + +该问题与 Kubernetes pod 镜像拉取策略有关,建议将 Pod 镜像拉取策略设置为 Always: + +‍-Dkubernetes.container.image.pull-policy=Always + +- **任务每次重启都会导致多出一个 Job 实例** + +在配置了基于 kubernetes 的HA的前提条件下,当需要停止 Flink 任务时,需要通过 StreamPark 的 cancel 来进行,不要直接通过 kubernetes 集群删除 Flink 任务的 Deployment。因为 Flink 的关闭有其自有的关闭流程,在删除 pod 同时 Configmap 中的相应配置文件也会被一并删除,而直接删除 pod 会导致 Configmap 的残留。当相同名称的任务重启时,会出现两个相同 Job 现象,因为在启动时,任务会加载之前残留的配置文件,尝试将已经关闭的任务恢复。 + +- **kubernetes pod 域名访问怎么实现** + +域名配置只需要按照 Kubernetes 资源在 pod-template 中配置即,可针对以上问题给大家分享一个本人总结的一个 pod-template.yaml 模板: + +```yaml + +apiVersion: v1 +kind: Pod +metadata: + name: pod-template +spec: + serviceAccount: default + containers: + - name: flink-main-container + image: + imagePullSecrets: + - name: regsecret + hostAliases: + - ip: "192.168.0.1" + hostnames: + - "node1" + - ip: "192.168.0.2" + hostnames: + - "node2" + - ip: "192.168.0.3" + hostnames: + - "node3" + +``` + +### **最佳实践** + +悦刻的大数据组件很多基于阿里云,比如 Maxcompute、阿里云 Redis,同时我们这边 Flink SQL 作业需要用到一些 UDF。最开始我们是采用使用 Flink Base image + maven dependency + upload udf jar 的方式,但是实践过程中遇到了一些比如版本冲突、类冲突的问题,同时如果是大批量作业的话这种方式开发效率比较低,最后我们采取将公司级别的常用的 Flink connector 和 udf 和 Flink base image 打包成公司级别的基础镜像,新 Flink SQL 作业使用该基础镜像之后直接写 Flink SQL 即可,大大提高了开发效率。 + +**下面分享一个制作基础镜像的简单步骤:** + +**1. 准备需要的 JAR** + +将常用 Flink Connector Jar 和用户 Udf Jar 放置在同一文件夹 lib 下,以下都是Flink 1.13.6 常用的一些 connector 包 + +```jar +bigdata-udxf-1.0.0-shaded.jar +flink-connector-jdbc_2.11-1.13.6.jar +flink-sql-connector-kafka_2.11-1.13.6.jar +flink-sql-connector-mysql-cdc-2.0.2.jar +hudi-flink-bundle_2.11-0.10.0.jar +ververica-connector-odps-1.13-vvr-4.0.7.jar +ververica-connector-redis-1.13-vvr-4.0.7.jar +``` + +**2. 准备 Dockerfile** + +创建 Dockerfile 文件,并将 Dockerfile 文件跟上面文件夹放置在同一文件夹下 + +```shell +FROM flink:1.13.6-scala_2.11COPY lib $FLINK_HOME/lib/ +``` + +**3. 基础镜像制作并推送私有仓库** + +```shell +docker login --username=xxxdocker \ +build -t udf_flink_1.13.6-scala_2.11:latest \ +.docker tag udf_flink_1.13.6-scala_2.11:latest \ +k8s-harbor.xxx.com/streamx/udf_flink_1.13.6-scala_2.11:latestdocker \ +push k8s-harbor.xxx.com/streamx/udf_flink_1.13.6-scala_2.11:latest +``` + +## **未来期待** + +- **StreamPark 对于 Flink 作业 Metric 监控的支持** + +StreamPark 如果可以对接 Flink Metric 数据而且可以在 StreamPark 平台上展示每时每刻 Flink 的实时消费数据情况就太棒了 + +- **StreamPark 对于Flink 作业日志持久化的支持** + +对于部署到 YARN 的 Flink 来说,如果 Flink 程序挂了,我们可以去 YARN 上看历史日志,但是对于 Kubernetes 来说,如果程序挂了,那么 Kubernetes 的 pod 就消失了,就没法查日志了。所以用户需要借助 Kubernetes 上的工具进行日志持久化,如果 StreamPark 支持 Kubernetes 日志持久化接口就更好了。 + +- **镜像过大的问题改进** + +StreamPark 目前对于 Flink on Kubernetes 作业的镜像支持是将基础镜像和用户代码打成一个 Fat 镜像推送到 Docker 仓库,这种方式存在的问题就是镜像过大的时候耗时比较久,希望未来基础镜像可以复用不需要每次都与业务代码打到一起,这样可以极大地提升开发效率和节约成本。 diff --git a/i18n/zh-CN/docusaurus-plugin-content-blog/1-flink-framework-streampark.md b/i18n/zh-CN/docusaurus-plugin-content-blog/1-flink-framework-streampark.md new file mode 100644 index 000000000..dcd97dd7b --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-blog/1-flink-framework-streampark.md @@ -0,0 +1,246 @@ +--- +slug: flink-development-framework-streampark +title: Flink 开发利器 StreamPark +tags: [StreamPark, DataStream, FlinkSQL] +--- + +
+ +# 1. 背景 + +Hadoop 体系虽然在目前应用非常广泛,但架构繁琐、运维复杂度过高、版本升级困难,且由于部门原因,数据中台需求排期较长,我们急需探索敏捷性开发的数据平台模式。在目前云原生架构的普及和湖仓一体化的大背景下,我们已经确定了将 Doris 作为离线数据仓库,将 TiDB(目前已经应用于生产)作为实时数据平台,同时因为 Doris 具有 on MySQL 的 ODBC 能力,所以又可以对外部数据库资源进行整合,统一对外输出报表 + +![](/blog/belle/doris.png) + +
(这里借用一下 Doris 官方的架构图)
+ +

+ +# 2. 遇到的问题 + +在数据引擎上,我们确定使用 Spark 和 Flink + +* 使用 Spark on K8s client 客户端模式做离线数据处理 +* 使用 Flink on K8s Native-Application/Session 模式做实时任务流管理 + +在这里,实际上有一些问题我们一直没有彻底解决: + +用过 Native-Application 模式的朋友都知道,每提交一个任务,都需要打包新的镜像,提交到私有仓库,然后再调用 Flink Run 指令沟通 K8s,去拉取镜像运行 Pod。任务提交之后,还需要去 K8s 查看 log, 但是: + +1. 任务运行监控怎么处理? +2. 使用 Cluster 模式还是 NodePort 暴露端口访问 Web UI? +3. 提交任务能否简化打包镜像的流程? +4. 如何减少开发压力? + +

+ +# 3. 解决问题的过程 + +以上的这些其实都是需要解决的问题,如果单纯地使用命令行去提交每个任务,是不现实的,任务量大了,会变得不可维护。如何解决这些问题变成一个不得不面对的问题。 + +
+ +## 简化镜像构建 + +首先,针对 Flink 原生镜像需要二次 build 的问题:我们利用了 MinIO 作为外部存储,并使用 s3-fuse 通过 DaemonSet 的方式直接挂载在了每个宿主节点上,我们所需要提交的 jar 包都可以放到上面统一管理。这样的话,即使扩缩容 Flink 节点,也能实现 S3 挂载自动伸缩。 + +![](/blog/belle/k8s.png) + +Flink 从 1.13 版本开始,就支持 Pod Template,我们可以在 Pod Template 中利用数据卷挂载的方式再将宿主机目录挂载到每个 pod 中,从而无需镜像打包而直接在 K8s 上运行 Flink 程序。如上图,我们将 S3 先通过 s3-fuse Pod 挂载在 Node 1、Node 2 的 `/mnt/data-s3fs` 目录下,然后再将 `/mnt/data-s3fs` 挂载到 Pod A 中。 + +但是,因为对象存储随机写入或追加文件需要重写整个对象,导致这种方式仅适合于频繁读。而这刚好满足我们现在的场景。 + +
+ +## 引入 StreamPark + +之前我们写 Flink SQL 基本上都是使用 Java 包装 SQL,打 jar 包,提交到 S3 平台上。通过命令行方式提交代码,但这种方式始终不友好,流程繁琐,开发和运维成本太大。我们希望能够进一步简化流程,将 Flink TableEnvironment 抽象出来,有平台负责初始化、打包运行 Flink 任务,实现 Flink 应用程序的构建、测试和部署自动化。 + +这是个开源兴起的时代,我们自然而然的将目光投向开源领域中:在一众开源项目中,经过对比各个项目综合评估发现 Zeppelin StreamPark 这两个项目对 Flink 的支持较为完善,都宣称支持 Flink on K8s ,最终进入到我们的目标选择范围中,以下是两者在 K8s 相关支持的简单比较(目前如果有更新,麻烦批评指正)。 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
功能ZeppelinStreamPark
任务状态监控 稍低 ,不能作为任务状态监控工具 较高
任务资源管理,但目前版本还不是很健全
本地化部署 稍低 ,on K8s 模式只能将 Zeppelin 部署在 K8s 中,否则就需要打通 Pod 和外部网络,但是这在生产环境中很少这样做的 可以本地化部署
多语言支持 较高 ,支持 Python/Scala/Java 多语言 一般 ,目前 K8s 模式和 YARN 模式同时支持 FlinkSQL,并可以根据自身需求,使用 Java/Scala 开发 DataStream
Flink WebUI 代理 目前还支持的不是很完整 ,主开发大佬目前是考虑整合 Ingress 较好 ,目前支持 ClusterIp/NodePort/LoadBalance 模式
学习成本 成本较低 ,需要增加额外的参数学习,这个和原生的 FlinkSQL 在参数上有点区别 无成本 ,K8s 模式下 FlinkSQL 为原生支持的 SQL 格式;同时支持 Custome-Code(用户编写代码开发Datastream/FlinkSQL 任务)
Flink 多版本支持 支持 支持
Flink 原生镜像侵入 有侵入 ,需要在 Flink 镜像中提前部署 jar 包,会同 JobManager 启动在同一个 Pod 中,和 zeppelin-server 通信 无侵入 ,但是会产生较多镜像,需要定时清理
代码多版本管理 支持 支持
+ +
(PS: 此处仅从调研用户角度出发,我们对双方开发都保持极大的尊重)
+ +
+ +调研过程中,我们与两者的主开发人员都进行了多次沟通。经过我们反复研究之后,还是决定将 StreamPark 作为我们目前的 Flink 开发工具来使用。 + + + +
(StreamPark 官网的闪屏)
+ +
+ +经过开发同学长时间开发测试,StreamPark 目前已经具备: + +* 完善的SQL 校验功能 +* 实现了自动 build/push 镜像 +* 使用自定义类加载器,通过 Child-first 加载方式 解决了 YARN 和 K8s 两种运行模式支持了自由切换 Flink 多版本 +* 与 Flink-Kubernetes 进行深度整合,提交任务后返回 WebUI,通过 remote rest api + remote K8s,追踪任务执行状态 +* 同时支持了 Flink 1.12、1.13、1.14 等版本 + +以上基本解决了我们目前开发和运维中存在的大部分问题。 + + + +
(StreamPark 对 Flink 多版本的支持演示视频)
+ +
+ +在目前最新发布的 1.2.0 版本中,StreamPark 较为完善地支持了 K8s-Native-Application 和 K8s-Session-Application 模式。 + + + +
(StreamPark K8s 部署演示视频)
+ +
+ +### K8s Native Application 模式 + +在 StreamPark 中,我们只需要配置相应的参数,并在 Maven POM 中填写相应的依赖,或者上传依赖 jar 包,点击 Apply,相应的依赖就会生成。这就意味着我们也可以将所有使用的 UDF 打成 jar 包,以及各种 connector.jar,直接在 SQL 中使用。如下图: + +![](/blog/belle/dependency.png) + +SQL 校验能力和 Zeppelin 基本一致: + +![](/blog/belle/sqlverify.png) + +我们也可以指定资源,指定 Flink Run 中的动态参数 Dynamic Option,甚至参数可以整合 Pod Template + +![](/blog/belle/pod.png) + +程序保存后,点击运行时,也可以指定 savepoint。任务提交成功后,StreamPark 会根据 FlinkPod 网络 Exposed Type(loadBalancer/NodePort/ClusterIp),返回相应的 WebURL,从而自然的实现 WebUI 跳转。但是,目前因为线上私有 K8s 集群出于安全性考虑,尚未打通 Pod 与客户端节点网络(目前也没有这个规划)。所以么,我们只使用 NodePort。如果后续任务数过多,有使用 ClusterIP 的需求的话,我们可能会将 StreamPark 部署在 K8s,或者同 Ingress 做进一步整合。 + +![](/blog/belle/start.png) + +注意:K8s master 如果使用 vip 做均衡代理的情况下,Flink 1.13 版本会返回 vip 的 ip 地址,在 1.14 版本中已经修复该问题。 + +下面是 K8s Application 模式下具体提交流程 + +![](/blog/belle/flow.png) + +
(以上是依据个人理解绘制的任务提交流程图,如有错误,敬请谅解)
+ +
+ +### K8s Native Session 模式 + +StreamPark 还较好地支持了 K8s Native-Sesson 模式,这为我们后续做离线 FlinkSQL 开发或部分资源隔离做了较好的技术支持。 + +Native-Session 模式需要事先使用 Flink 命令创建一个运行在 K8s 中的 Flink 集群。如下: + +```shell +./kubernetes-session.sh \ +-Dkubernetes.cluster-id=flink-on-k8s-flinkSql-test \ +-Dkubernetes.context=XXX \ +-Dkubernetes.namespace=XXXX \ +-Dkubernetes.service-account=XXXX \ +-Dkubernetes.container.image=XXXX \ +-Dkubernetes.container.image.pull-policy=Always \ +-Dkubernetes.taskmanager.node-selector=XXXX \ +-Dkubernetes.rest-service.exposed.type=Nodeport +``` + +![](/blog/belle/flinksql.png) + +如上图,使用该 ClusterId 作为 StreamPark 的任务参数 Kubernetes ClusterId。保存提交任务后,任务会很快处于 Running 状态: + +![](/blog/belle/detail.png) + +我们顺着 application info 的 WebUI 点击跳转: + +![](/blog/belle/dashboard.png) + +可以看到,其实 StreamPark 是将 jar 包通过 REST API 上传到 Flink 集群上,并调度执行任务的。 + +
+ +### Custom Code 模式 + +另我们惊喜的是,StreamPark 还支持代码编写 DataStream/FlinkSQL 任务。对于特殊需求,我们可以自己写 Java/Scala 实现。可以根据 StreamPark 推荐的脚手架方式编写任务,也可以编写一个标准普通的 Flink 任务,通过这种方式我们可以将代码管理交由 git 实现,平台可以用来自动化编译打包与部署。当然,如果能用 SQL 实现的功能,我们会尽量避免自定义 DataStream,减少不必要的运维麻烦。 + +

+ +# 4. 意见和规划 + +## 改进意见 + +当然 StreamPark 还有很多需要改进的地方,就目前测试来看: + +* **资源管理还有待加强**:多文件系统jar包等资源管理功能尚未添加,任务版本功能有待加强。 +* **前端 button 功能还不够丰富**:比如任务添加后续可以增加复制等功能按钮。 +* **任务提交日志也需要可视化展示**:任务提交伴随着加载 class 文件,打 jar 包,build 镜像,提交镜像,提交任务等过程,每一个环节出错,都会导致任务的失败,但是失败日志往往不明确,或者因为某种原因导致异常未正常抛出,没有转换任务状态,用户会无从下手改进。 + +众所周知,一个新事物的出现一开始总会不是那么完美。尽管有些许问题和需要改进的 point,但是瑕不掩瑜,我们仍然选择 StreamPark 作为我们的 Flink DevOps,我们也将会和主开发人员一道共同完善 StreamPark,也欢迎更多的人来使用,为 StreamPark 带来更多进步。 + +
+ +## 未来规划 + +* 我们会继续跟进 Doris,并将业务数据 + 日志数据统一入 Doris,通过 Flink 实现湖仓一体; +* 我们也会逐步将探索 StreamPark 同 DolphinScheduler 2.x 进行整合,完善DolphinScheduler 离线任务,逐步用 Flink 替换掉 Spark,实现真正的流批一体; +* 基于我们自身在 S3 上的探索积累,fat-jar 包 build 完成之后不再构建镜像,直接利用 Pod Tempelet 挂载 PVC 到 Flink Pod 中的目录,进一步优化代码提交流程; +* 将 StreamPark 持续应用到我们生产中,并汇同社区开发人员,共同努力,增强 StreamPark 在 Flink 流上的开发部署能力与运行监控能力,努力把 StreamPark 打造成一个功能完善的流数据 DevOps。 + +附: + +StreamPark GitHub:[https://github.com/apache/incubator-streampark](https://github.com/apache/incubator-streampark)
+Doris GitHub:[https://github.com/apache/doris](https://github.com/apache/doris) + +![](/blog/belle/author.png) diff --git a/i18n/zh-CN/docusaurus-plugin-content-blog/2-streampark-usercase-chinaunion.md b/i18n/zh-CN/docusaurus-plugin-content-blog/2-streampark-usercase-chinaunion.md new file mode 100644 index 000000000..98e5b3d7c --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-blog/2-streampark-usercase-chinaunion.md @@ -0,0 +1,175 @@ +--- +slug: streampark-usercase-chinaunion +title: 联通 Flink 实时计算平台化运维实践 +tags: [StreamPark, 生产实践, FlinkSQL] +--- + +# 联通 Flink 实时计算平台化运维实践 + +**摘要:**本文整理自联通数科实时计算团队负责人、Apache StreamPark Committer 穆纯进在 Flink Forward Asia 2022 平台建设专场的分享,本篇内容主要分为四个部分: + +- 实时计算平台背景介绍 +- Flink 实时作业运维挑战 +- 基于 StreamPark 一体化管理 +- 未来规划与演进 + +## **实时计算平台背景介绍** + +![](/blog/chinaunion/overall_architecture.png) + + + +上图是实时计算平台的整体架构,最底层是数据源,由于一些敏感信息,没有将数据源的详细信息列出,它主要包含三部分,分别是业务数据库、用户行为日志、用户位置,联通的数据源非常多,业务数据库这一项就有几万张表;主要通过 Flink SQL 和 DataStream API 来处理数据 ,数据处理流程包括 Flink 对数据源的实时解析、规则的实时计算以及实时产品;用户在可视化订阅平台上进行实时数据订阅,用户可以在地图上画一个电子围栏,并设置一些规则,如来自于哪里,在围栏里驻留多长时间等,还可以筛选一些特征,符合这些规则的用户信息会实时进行推送,然后是实时安全部分,当某个用户连接了高危基站或是有异常操作行为时,我们会认为可能存在诈骗行为,会对手机号码进行关停等等,还有用户的一些实时特征以及实时大屏。 + + + +![](/blog/chinaunion/data_processing_processes.png) + +上图是数据处理的详细的流程。 + +第一部分是采集解析,我们的数据源来自于业务的数据库,包含 OGG 和 DTS 格式的消息、日志消息、用户行为和用户位置数据,总共 50 多种数据源,后续还会逐渐增加,所有数据源均使用 Flink 做实时解析;并增加了 Metrics 来监控数据源的延迟情况。 + +第二部分是实时计算, 这个环节处理的数据量很大,数据量在万亿级别,支撑了 10000+的数据实时订阅,有 200 多个 Flink 任务,我们将某一种同类型的业务封装成一种场景,同一个 Flink 作业可以支持相同场景的多个订阅,目前 Flink 作业数还在不停的增长,后续可能会增加到 500 多个;其中面临的一个很大挑战是每天万亿级的数据实时关联电子围栏、用户特征等信息,电子围栏有几万个,用户特征涉及数亿用户,最初我们将电子围栏信息和用户特征放到 HBase, 但这样会导致 HBase 压力很大,经常遇到性能问题造成数据延迟,而且一旦产生数据积压,需要很长的时间去消化,得益于 Flink State 的强大,我们将电子围栏信息和用户特征放到状态里,目前已经很好的支撑了大并发的场景,同时我们也增加了数据处理的性能监控;最后是实时产品和营销触达前端的一些应用。 + +![](/blog/chinaunion/platform_evolution.png) + +2018 年采用了三方黑盒的计算引擎,不能支持灵活定制个性化功能,且依赖过多外部系统,导致外部系统负载高,运维复杂;2019 年使用了 Spark Streaming 的微批处理,2020 年开始使用 Flink 的流式计算,从 2021 年开始,几乎所有 Spark Streaming 的微批处理都被 Flink 替代了,同时上线了 Apache StreamPark 对我们的 Flink 作业进行管理。 + +![](/blog/chinaunion/platform_background.png) + +总结一下平台背景,主要包含以下几部分: + +- 数据量大:日均万亿的数据处理。 +- 数据源多:集成了 50 多种实时数据源。 +- 订阅多:支撑了 10000+的数据服务订阅。 +- 用户多:支撑了 30 多个内部和外部用户使用。 + +![](/blog/chinaunion/operational_background.png) + +运维背景也可以分为以下几部分: + +- 支撑需求多:50 多种数据源,10000+的数据服务订阅。 +- 实时作业多:现在有 200+Flink 生产作业,并且持续快速增长中, 未来可达 500+。 +- 上线频率高:每天都有新增的或增强的 Flink 作业上线操作。 +- 开发人员多:50+研发人员参与开发 Flink 实时计算任务。 +- 使用用户多:30+内部和外部组织的用户使用。 +- 监控延迟低:一旦发现问题我们要立马进行处理,避免引起用户的投诉。 + +## **Flink 实时作业运维挑战** + +![](/blog/chinaunion/difficulties.png) + +基于平台和运维背景,尤其是 Flink 作业越来越多的情况下,遇到了很大的挑战,主要有两方面,分别是作业运维困境和业务支撑困境。 + + + +在作业运维困境上,首先作业部署流程长、效率低;在联通安全是第一红线下,在服务器上部署程序的时候,要连接 VPN、登录 4A、打包编译、部署、然后再启动,整个流程比较长,最初在开发 Flink 的时候,都是用脚本启动的,导致代码分支是不可控的,部署完之后也难以追溯,再就是脚本很难与 git 上的代码进行同步,因为对于脚本代码,开发人员更喜欢在服务器上直接改,很容易忘记上传 git。 + + + +由于作业运维困境上的种种因素,会产生业务支撑困境,如导致上线故障率高、影响数据质量、上线时间长、数据延迟高、告警漏发处理等,引起的投诉,此外,我们的业务影响不明确,一旦出现问题,处理问题会成为第一优先级。 + +## **基于 StreamPark 一体化管理** + +![](/blog/chinaunion/job_management.png) + +对于以上的两种困境,我们基于 StreamPark 一体化管理解决了很多问题,首先来看一下 StreamPark 的双线演进,分别是 Flink 作业管理和 Flink 作业 DevOps 平台;在作业管理上,StreamPark 支持将 Flink 实时作业部署到不同的集群里去,比如 Flink 原生自带的 Standalone 模式,Flink on Yarn 的 Session、Application、PerJob 模式,在最新的版本中将支持 Kubernetes Native Session 模式;中间层是项目管理、作业管理、集群管理、团队管理、变量管理、告警管理。 + + + +- 项目管理:当部署 Flink 程序的时候,可以在项目管理里填写 git 地址,同时选择要部署的分支。 +- 作业管理:可以指定 Flink 作业的执行模式,比如你要提交到什么类型的集群里去,同时还可以配置一些资源,比如 TaskManager 的数量、TaskManager/JobManager 的内存大小、并行度等等,还可以设置一些容错,比如 Flink 作业失败后,StreamPark 可以支持它自动拉起,同时支持传入一些动态参数。 +- 集群管理:可以在界面上添加和管理大数据集群。 +- 团队管理:在企业的实际生产过程中会有多个团队,团队之间是隔离的。 +- 变量管理:可以把一些变量统一维护在一个地方,比如 Kafka 的 Broker 地址定义成一个变量,在配置 Flink 作业或者 SQL 的时候,就可以以变量的方式来替换 Broker 的 IP,且后续这个 Kafka 要下线的时候,也可以通过这个变量去查看到底哪些作业使用了这个集群,方便我们去做一些后续的流程。 +- 告警管理:支持多种告警模式,如微信、钉钉、短信和邮件。 + + + +StreamPark 支持 Flink SQL、Flink Jar 的提交,支持资源配置,支持状态跟踪,如状态是运行状态,失败状态等,同时支持指标大屏和各种日志查看。 + +![](/blog/chinaunion/devops_platform.png) + +Flink 作业 DevOps 平台,主要包括以下几部分: +- 团队:StreamPark 支持多个团队,每个团队都有团队的管理员,他拥有所有权限,同时还有团队的开发者,他只有少量的一部分权限。 +- 编译、打包:在创建 Flink 项目时,可以把 git 地址、分支、打包的命令等配置在项目里,然后一键点击 build 按钮进行编译、打包。 +- 发布、部署:发布和部署的时候会创建 Flink 作业,在 Flink 作业里可以选择执行模式、部署集群、资源设置、容错设置、变量填充,最后通过一键启动停止,启动 Flink 作业。 +- 状态监测:Flink 作业启动完成之后,就是状态的实时跟踪,包括 Flink 的运行状态、运行时长、Checkpoint 信息等,并支持一键跳转到 Flink 的 Web UI。 +- 日志、告警:包含构建的一些日志和启动日志,同时支持钉钉、微信、邮件、短信等告警方式。 + +![](/blog/chinaunion/multi_team_support.png) + +企业一般有多个团队同时开发实时作业,在我们公司包含实时采集团队、数据处理团队和实时的营销团队,StreamPark 支持多个团队的资源隔离。 + +![](/blog/chinaunion/platformized_management.png) + +Flink 作业平台化管理面临如下挑战: +- 脚本数量多:平台有几百个脚本,分散在多个服务器上。 +- 脚本类型多:在启动 Flink 作业时,会有启动脚本、停止脚本和守护脚本,而且操作权限很难控制。 +- 脚本不一致:服务器上的脚本与 git 上的脚本不一致。 +- 脚本确权难:Flink 作业的责任人,用途不明确。 +- 分支不可控:启动作业的时候,需要在脚本里指定 git 分支,导致分支不可追溯的。 + + + +基于以上的挑战,StreamPark 通过项目管理来解决了责任人不明确,分支不可追溯的问题,因为在创建项目的时候需要手动指定一些分支,一旦打包成功,这些分支是有记录的;通过作业管理对配置进行了集中化,避免了脚本太过于分散,而且作业启动、停止的权限有严格的控制,避免了脚本化权限不可控的状态,StreamPark 以接口的方式与集群进行交互来获取作业信息,这样做会让作业控制更加精细。 + + + +可以看一下上图中下面的图,通过项目管理进行打包,通过作业管理进行配置,然后发布,可以进行一键启停,通过 API 提交作业。 + +![图片](/blog/chinaunion/development_efficiency.png) + +早期我们需要通过 7 步进行部署,包括连接 VPN、登录 4A、执行编译脚本、执行启动脚本、打开 Yarn、搜索作业名、进入 Flink UI 等 7 个步骤,StreamPark 可以支持 4 个一键进行部署,包括一键打包、一键发布、一键启动、一键到 Flink UI。 + +![图片](/blog/chinaunion/submission_process.png) + +上图是我们 StreamPark 的作业提交流程,首先 StreamPark 会将作业进行发布,发布的时候会上传一些资源,然后会进行作业的提交,提交的时候会带上配置的一些参数,以 Flink Submit 的方式调用接口发布到集群上;这里会有多个 Flink Submit 对应着不同的执行模式,比如 Yarn Session、Yarn Application、Kubernetes Session、Kubernetes Application 等都是在这里控制的,提交作业之后,如果是 Flink on Yarn 作业,会得到这个 Flink 作业的 Application ID 或者 Job ID,这个 ID 会保存在我们的数据库中,如果是基于 Kubernetes 执行的话,也会得到 Job ID,后面我们在跟踪作业状态的时候,主要就是通过保存的这些 ID 去跟踪作业的状态。 + +![图片](/blog/chinaunion/status_acquisition_bottleneck.png) + +如上所述,如果是 Flink on Yarn 作业,在提交作业的时候会获取两个 ID,Application ID 或者 Job ID,基于这两个 ID 可以获取我们的状态,但当 Flink 作业非常多的时候会遇到一些问题,StreamPark 它是有一个状态获取器,它会通过我们保存的数据库里的 Application ID 或者 Job ID,去向 ResourceManager 做一个请求,会做每五秒钟周期性的轮询,如果作业特别多,每次轮询 ResourceManager 会负责再去调用 Job Manager 的地址访问它的状态,这就会导致 ResourceManager 的连接数压力较大和连接数过高。 + + + +上图中 ResourceManager 的连接数阶段性、周期性的持续走高,可以看到 ResourceManager 处于比较红的状态,从主机上去监控的时候,它的连接数确实比较高。 + +![图片](/blog/chinaunion/state_optimization.png) + +针对上面的问题,我们做了一些优化,首先 StreamPark 保存了提交作业之后的 Application ID 或者 Job ID,同时也会获取 Job Manager 直接访问的地址,并保存在数据库中,每次轮询时不再通过 ResourceManager 获取作业的状态,它可以直接调用各个 Job Manager 的地址实时获取状态,极大的降低了 ResourceManager 的连接数;从上图最后的部分可以看到,基本不会产生太大的连接数,大大减轻了 ResourceManager 的压力,且后续当 Flink 作业越来越多时获取状态也不会遇到瓶颈的问题。 + +![图片](/blog/chinaunion/state_recovery.png) + +StreamPark 解决的另一个问题是 Flink 从状态恢复的保障,以前我们用脚本做运维的时候,在启动 Flink 的时候,尤其是在业务升级的时候,要从上一个最新的 Checkpoint 来恢复,但经常有开发人员忘记从上一个检查点进行恢复,导致数据质量产生很大的问题,遭到投诉,StreamPark 的流程是在首次启动的时候,每五秒钟轮询一次获取 Checkpoint 的记录,同时保存在数据库之中,在 StreamPark 上手动停止 Flink 作业的时候,可以选择做不做 Savepoint,如果选择了做 Savepoint,会将 Savepoint 的路径保存在数据库中,同时每次的 Checkpoint 记录也保存在数据库中,当下次启动 Flink 作业的时候,默认会选择最新的 Checkpoint 或者 Savepoint 记录,有效避免了无法从上一个检查点去恢复的问题,也避免了导致问题后要进行 offset 回拨重跑作业造成的资源浪费,同时也保证了数据处理的一致性。 + +![图片](/blog/chinaunion/multiple_environments_and_components.png) + +StreamPark 还解决了在多环境下多个组件的引用挑战,比如在企业中通常会有多套环境,如开发环境、测试环境、生产环境等,一般来说每套环境下都会有多个组件,比如 Kafka,HBase、Redis 等,而且在同一套环境里还可能会存在多个相同的组件,比如在联通的实时计算平台,从上游的 Kafka 消费数据的时候,将符合要求的数据再写到下游的 Kafka,这个时候同一套环境会涉及到两套 Kafka,单纯从 IP 很难判断是哪个环境哪个组件,所以我们将所有组件的 IP 地址都定义成一个变量,比如 Kafka 集群,开发环境、测试环境、生产环境都有 Kafka.cluster 这个变量,但它们指向的 Broker 的地址是不一样的,这样不管是在哪个环境下配置 Flink 作业,只要引用这个变量就可以了,大大降低了生产上的故障率。 + +![图片](/blog/chinaunion/multiple_execution_modes.png) + +StreamPark 支持 Flink 多执行的模式,包括基于 on Yarn 的 Application/ Perjob / Session 三种部署模式,还支持 Kubernetes 的 Application 和 Session 两种部署模式,还有一些 Remote 的模式。 + +![图片](/blog/chinaunion/versioning.png) + +StreamPark 也支持 Flink 的多版本,比如联通现在用的是 1.14.x,现在 1.16.x 出来后我们也想体验一下,但不可能把所有的作业都升级到 1.16.x,我们可以把新上线的升级到 1.16.x,这样可以很好的满足使用新版本的要求,同时也兼容老版本。 + +## **未来规划与演进** + +![图片](/blog/chinaunion/contribution_and_enhancement.png) + +未来我们将加大力度参与 StreamPark 建设,以下我们计划要增强的方向。 +- 高可用:StreamPark 目前不支持高可用,这方面还需要做一些加强。 +- 状态的管理:在企业实践中 Flink 作业在上线时,每个算子会有 UID。如果 Flink UID 不做设置,做 Flink 作业的升级的时候,就有可能出现状态无法恢复的情况,目前通过平台还无法解决这个问题,所以我们想在平台上增加这个功能,在 Flink Jar 提交时,增加检测算子是否设置 UID 的功能,如果没有,会发出提醒,这样可以避免每次上线 Flink 作业时,作业无法恢复的问题;之前遇到这种情况的时候,我们需要使用状态处理的 API,从原来的状态里进行反序列化,然后再用状态处理 API 去制作新的状态,供升级后的 Flink 加载状态。 +- 更细致的监控:目前支持 Flink 作业失败之后,StreamPark 发出告警。我们希望 Task 失败之后也可以发出告警,我们需要知道失败的原因;还有作业反压监控告警、Checkpoint 超时、失败告警性能指标采集,也有待加强。 +- 流批一体:结合 Flink 流批一体引擎和数据湖流批一体存储探索流批一体平台。 + +![](/blog/chinaunion/road_map.png) + +上图是 StreamPark 的 Roadmap。 +- 数据源:StreamPark 会支持更多数据源的快速接入,达到数据一键入户。 +- 运维中心:获取更多 Flink Metrics 进一步加强监控运维的能力。 +- K8S-operator:现有的 Flink on K8S 还是有点重,经历了打 Jar 包、打镜像、推镜像的过程,后续需要改进优化,积极拥抱上游对接的 K8S-operator。 +- 流式数仓:增强对 Flink SQL 作业能力的支持,简化 Flink SQL 作业的提交,计划对接 Flink SQL Gateway;SQL 数仓方面的能力加强,包括元数据存储、统一建表语法校验、运行测试、交互式查询,积极拥抱 Flink 上游,探索实时数仓和流式数仓。 + + diff --git a/i18n/zh-CN/docusaurus-plugin-content-blog/3-streampark-usercase-bondex-paimon.md b/i18n/zh-CN/docusaurus-plugin-content-blog/3-streampark-usercase-bondex-paimon.md new file mode 100644 index 000000000..b7eb7f456 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-blog/3-streampark-usercase-bondex-paimon.md @@ -0,0 +1,938 @@ +--- +slug: streampark-usercase-bondex-with-paimon +title: 海程邦达基于 Apache Paimon + StreamPark 的流式数仓实践 +tags: [StreamPark, 生产实践, paimon, streaming-warehouse] +--- + +# 海程邦达基于 Apache Paimon + StreamPark 的流式数仓实践 + +![](/blog/bondex/Bondex.png) + +**导读:**本文主要介绍作为供应链物流服务商海程邦达在数字化转型过程中采用 Paimon + StreamPark 平台实现流式数仓的落地方案。我们以 Apache StreamPark 流批一体平台提供了一个易于上手的生产操作手册,以帮助用户提交 Flink 任务并迅速掌握 Paimon 的使用方法。 + +- 公司业务情况介绍 +- 大数据技术痛点以及选型 +- 生产实践 +- 问题排查分析 +- 未来规划 + +## 01 公司业务情况介绍 + +海程邦达集团一直专注于供应链物流领域,通过打造优秀的国际化物流平台,为客户提供端到端一站式智慧型供应链物流服务。集团现有员工 2000 余人,年营业额逾 120 亿人民币,网络遍及全球 200 余个港口,在海内外有超 80 家分、子公司,助力中国企业与世界互联互通。 + +### **业务背景** + +随着公司规模的不断扩大和业务复杂性的增加,为了更好地实现资源优化和流程改进,公司运营与流程管理部需要实时监控公司的业务运转情况,以确保业务流程的稳定性和高效性。 + +公司运营与流程管理部负责监督公司各类业务流程的执行,包括海运、空运、铁运各个大区和事业部的订单量,大客户的订单量,航线订单量,关务、仓储、陆运各个操作站点的委托量,公司当天各个大区和事业部实际收入和支出情况等。通过对这些流程的监控和分析,公司能够识别出潜在的问题和瓶颈,提出改进措施和建议,以优化公司运营效率。 + +**实时数仓架构:** + +![](/blog/bondex/realtime_warehouse.png) + +当前系统要求直接从生产系统收集实时数据,但存在多个数据源需要进行关联查询,而帆软报表在处理多个数据源时展示不够友好,且无法再次聚合多个数据源。定时查询生产系统会给生产系统数据库带来压力,影响生产系统的稳定运行。因此,我们需要引入一个可以通过 [Flink CDC](https://github.com/ververica/flink-cdc-connectors) 技术实现流式处理的数仓,以解决实时数据处理的问题。这个数仓需要能够从多个数据源收集实时数据并在此基础上实现复杂的关联 SQL 查询、机器学习等操作,并且可以避免不定时查询生产系统,从而减轻生产系统的压力,保障生产系统的稳定运行。 + +## 02 大数据技术痛点以及选型 + +海程邦达大数据团队建立以来一直以高效运维工具或平台来实现对人员的高效配置,优化重复劳动,手工作业。 + +在离线批数处理已能够支持集团基础驾驶舱和管理报表的情况下,集团运管部门提出了业务要实时统计订单数量,操作单量的需求,财务部门有现金流实时展示的需求,在这样的背景下,基于大数据的流批一体方案势在必行。 + +虽然大数据部门已经使用了 [Apache Doris](https://github.com/apache/doris) 来实现湖仓一体的存储和计算,此前已在 Doris 社区发表湖仓一体建设的文章,但是有些问题有待解决,流式数据存储无法复用、中间层数据不可查、做不到实时聚合计算问题。 + +按照架构演进时间排序,近几年通用的架构解决方案如下: + +### **hadoop架构** + +传统数仓和互联网数仓的分界点,在互联网早期的时候,大家对于数据分析的要求也不高,主要是做实时性不高的报表、支撑决策,对应的离线数据分析方案就产生了。 + +**优点:**数据类型支持丰富,支持海量运算,机器配置要求低,时效性低,容错 + +**缺点:**不支持实时;运维复杂;查询优化器不如 MPP,响应慢 + +选型依据:不支持实时;运维复杂,不符合人员精简配置原则;性能差 + +### **lambda架构** + +Lambda 架构是由 Storm 的作者 Nathan Marz 提出的一个实时大数据处理框架。Marz 在 Twitter 工作期间开发了著名的实时大数据处理框架 [Apache Storm](https://github.com/apache/storm) ,Lambda 架构是其根据多年进行分布式大数据系统的经验总结提炼而成。 + +![](/blog/bondex/lambda.png) + +数据流处理分为 ServingLayer、SpeedLayer、BatchLayer 三层: + +- Batch层: 对离线数据进行处理,最后提供 view 服务给到业务; +- Speed层: 对实时增量数据进行处理,最后提供 view 服务给到业务; +- Serving层: 响应用户的请求,实现离线和增量数据的聚合计算,并最终提供服务; + +优点是:离线和实时分开计算,使用两套框架,架构稳定 + +缺点是:离线和实时数据很难保持一致性,运维人员需要维护两套框架三层架构,开发人员需要写三套代码 + +选型依据:数据一致性不可控;运维、开发工作量大,不符合人员精简配置的原则; + +### **kappa架构** + +kappa 架构只用一套数据流处理架构来解决离线和实时数据,用实时流来解决所有问题,旨在提供快速可靠的查询访问结果。它非常适合各种数据处理工作负载,包括连续数据管道、实时数据处理、机器学习模型和实时数据分析、物联网系统以及许多其他具有单一技术堆栈的用例。 + +它通常使用流处理引擎实现,例如Apache Flink、Apache Storm、Apache Kinesis、 Apache Kafka,旨在处理大量数据流并提供快速可靠的查询访问结果。 + +![](/blog/bondex/kappa.png) + +**优点是:**单数据流处理框架 + +**缺点是:**虽然它的架构相对 lamabda 架构简单,但是流式处理框架的设置和维护相对复杂,不具备真正意义上的离线数据处理能力;流平台中存储大数据成本高昂 + +选型依据:离线数据处理能力需要保留,控制成本 + +### **Iceberg** + +为此我们也调研了 [Apache Iceberg](https://github.com/apache/Iceberg) ,它的快照功能一定程度上能够实现流批一体,但是它的问题是基于 kafka 做的实时表中间层不可查或者无法复用已经存在的表,对 kafka 有强依赖,需要利用 kafka 将中间结果写到 iceberg 表,增加了系统的复杂度和可维护性。 + +选型依据:无 kafka 实时架构已落地,中间数据无法实现可查可复用 + +### **流式数仓(kappa架构的延续)** + +海程邦达大数据团队自 FTS0.3.0 版本开始参与流式数仓建设,旨在进一步降低数据处理框架的复杂度和人员的精简配置,前期的宗旨是既然是趋势就要参与进来,过程中不断学习精进,向最前沿的技术靠拢,团队一致认为有坑就踩坑,摸着石头也要过河,好在经过几个版本的迭代,在社区的高效配合下,最开始出现的问题也慢慢得以解决 + +**流式数仓架构如下:** + +![](/blog/bondex/streaming_warehouse.png) + +延续了 kappa 架构的特点,一套流处理架构,好处在与,底层 Paimon 的技术支撑使得数据在全链路可查,数仓分层架构得以复用,同时兼顾了离线和实时的处理能力,减少存储和计算的浪费 + +## 03 生 产 实 践 + +本方案采用 Flink Application On K8s 集群,Flink CDC 实时摄取业务系统关系型数据库数据,通过 StreamPark 任务平台提交 Flink + Paimon Streaming Data Warehouse 任务, 最后采用 Trino 引擎接入 Finereport 提供服务和开发人员的查询。Paimon 底层存储支持 S3 协议,因为公司大数据服务依赖于阿里云所以使用对象存储OSS作为数据文件系统。 + +[StreamPark](https://github.com/apache/incubator-streampark) 是一个实时计算平台,与 [Paimon](https://github.com/apache/incubator-paimon) 结合使用其强大功能来处理实时数据流。此平台提供以下主要功能: + +**实时数据处理:**StreamPark 支持提交实时数据流任务,能够实时获取、转换、过滤和分析数据。这对于需要快速响应实时数据的应用非常重要,例如实时监控、实时推荐和实时风控等领域。 + +**可扩展性:**可以高效处理大规模实时数据,具备良好的可扩展性。可以在分布式计算环境中运行,并能够自动处理并行化、故障恢复和负载均衡等问题,以确保高效且可靠地处理数据。 + +**Flink 集成:**基于 [Apache Flink](https://github.com/apache/flink) 构建,利用 Flink 的强大流处理引擎来实现高性能和鲁棒性。用户可以充分利用 Flink 的特性和生态系统,如广泛的连接器、状态管理和事件时间处理等。 + +**易用性:**提供了直观的图形界面和简化的 API,可以轻松地构建和部署数据处理任务,而无需深入了解底层技术细节。 + +通过在 StreamPark 平台上提交 Paimon 任务,我们可以建立一个全链路实时流动、可查询和分层可复用的 Pipline。 + +![](/blog/bondex/pipline.png) + +主要采用组件版本如下: + +- flink-1.16.0-scala-2.12 +- paimon-flink-1.16-0.4-20230424.001927-40.jar +- apache-streampark_2.12-2.0.0 +- kubernetes v1.18.3 + +### **环境构建** + +下载 flink-1.16.0-scala-2.12.tar.gz 可以在 flink官网 下载对应版本的安装包到StreamPark 部署服务器 + +```shell +#解压 +tar zxvf flink-1.16.0-scala-2.12.tar.gz + +#修改 flink-conf 配置文件并启动集群 + +jobmanager.rpc.address: localhost +jobmanager.rpc.port: 6123 +jobmanager.bind-host: localhost +jobmanager.memory.process.size: 4096m +taskmanager.bind-host: localhost +taskmanager.host: localhost +taskmanager.memory.process.size: 4096m +taskmanager.numberOfTaskSlots: 4 +parallelism.default: 4 +akka.ask.timeout: 100s +web.timeout: 1000000 + +#checkpoints&&savepoints +state.checkpoints.dir: file:///opt/flink/checkpoints +state.savepoints.dir: file:///opt/flink/savepoints +execution.checkpointing.interval: 2min + +#当作业手动取消/暂停时,将会保留作业的 Checkpoint 状态信息 +execution.checkpointing.externalized-checkpoint-retention: RETAIN_ON_CANCELLATION +state.backend: rocksdb + +#已完成的CP保存个数 +state.checkpoints.num-retained: 2000 +state.backend.incremental: true +execution.checkpointing.checkpoints-after-tasks-finish.enabled: true + +#OSS +fs.oss.endpoint: oss-cn-zhangjiakou-internal.aliyuncs.com +fs.oss.accessKeyId: xxxxxxxxxxxxxxxxxxxxxxx +fs.oss.accessKeySecret: xxxxxxxxxxxxxxxxxxxxxxx +fs.oss.impl: org.apache.hadoop.fs.aliyun.oss.AliyunOSSFileSystem +jobmanager.execution.failover-strategy: region +rest.port: 8081 +rest.address: localhost +``` + +建议可以在本地添加 FLINK_HOME 方便在上 k8s 之前本地排查问题使用 + +vim /etc/profile + +```shell +#FLINK +export FLINK_HOME=/data/src/flink-1.16.0-scala-2.12 +export PATH=$PATH:$FLINK_HOME/bin +source /etc/profile +``` + +在 StreamPark 添加 Flink conf: + +![](/blog/bondex/flink_conf.jpg) + +构建 Flink 1.16.0 基础镜像从 dockerhub拉取对应版本的镜像 + +```dockerfile +#拉取镜像 +docker pull flink:1.16.0-scala_2.12-java8 + +#打上 tag +docker tagflink:1.16.0-scala_2.12-java8 registry-vpc.cn-zhangjiakou.aliyuncs.com/xxxxx/flink:1.16.0-scala_2.12-java8 + +#push 到公司仓库 +docker pushregistry-vpc.cn-zhangjiakou.aliyuncs.com/xxxxx/flink:1.16.0-scala_2.12-java8 +``` + +创建 Dockerfile 文件 & target 目录将 flink-oss-fs-hadoop JAR包放置在该目录 Shaded Hadoop OSS file system jar 包下载地址: + +https://repository.apache.org/snapshots/org/apache/paimon/paimon-oss/ + +. + +├── Dockerfile + +└── target + + └── flink-oss-fs-hadoop-1.16.0.jar + +```shell +touch Dockerfile + +mkdir target + +#vim Dockerfile +FROM registry-vpc.cn-zhangjiakou.aliyuncs.com/xxxxx/flink:1.16.0-scala_2.12-java8 + +RUN mkdir /opt/flink/plugins/oss-fs-hadoop + +COPY target/flink-oss-fs-hadoop-1.16.0.jar /opt/flink/plugins/oss-fs-hadoop +``` + +### **build 基础镜像** + +```shell +docker build -t flink-table-store:v1.16.0 . + +docker tag flink-table-store:v1.16.0 registry-vpc.cn-zhangjiakou.aliyuncs.com/xxxxx/flink-table-store:v1.16.0 + +docker push registry-vpc.cn-zhangjiakou.aliyuncs.com/xxxxx/flink-table-store:v1.16.0 +``` + +接下来准备 Paimon jar 包,可以在 Apache [Repository](https://repository.apache.org/content/groups/snapshots/org/apache/paimon) 下载对应版本,需要注意的是要和 flink 大版本保持一致 + +### **使用 StreamPark 管理作业** + +**前提条件:** + +- Kubernetes 客户端连接配置 +- Kubernetes RBAC 配置 +- 容器镜像仓库配置 (案例中使用的是阿里云镜像免费版) +- 创建挂载 checkpoint/savepoint 的 pvc 资源 + +**Kubernetes 客户端连接配置:** + +将 k8s master节点~/.kube/config 配置直接拷贝到 StreamPark 服务器的目录,之后在 StreamPark 服务器执行以下命令显示 k8s 集群 running 代表权限和网络验证成功。 + +```shell +kubectl cluster-info +``` + +Kubernetes RBAC 配置,创建 streamx 命名空间: + +```shell +kubectl create ns streamx +``` + +使用 default 账户创建 clusterrolebinding 资源: + +```shell +kubectl create secret docker-registry streamparksecret +--docker-server=registry-vpc.cn-zhangjiakou.aliyuncs.com +--docker-username=xxxxxx +--docker-password=xxxxxx -n streamx``` +``` + +**容器镜像仓库配置:** + +案例中使用阿里云容器镜像服务ACR,也可以使用自建镜像服务harbor代替。 + +创建命名空间 StreamPark (安全设置需要设置为私有) + +![](/blog/bondex/aliyun.png) + +在 StreamPark 配置镜像仓库,任务构建镜像会推送到镜像仓库 + +![](/blog/bondex/dockersystem_setting.png) + +创建 k8s secret 密钥用来拉取 ACR 中的镜像 streamparksecret 为密钥名称 自定义 + +```shell +kubectl create secret docker-registry streamparksecret +--docker-server=registry-vpc.cn-zhangjiakou.aliyuncs.com +--docker-username=xxxxxx +--docker-password=xxxxxx -n streamx +``` + +创建挂载 checkpoint/savepoint 的 pvc 资源,基于阿里云的对象存储OSS做K8S的持久化 + +**OSS CSI 插件:** + +可以使用 OSS CSI 插件来帮助简化存储管理。您可以使用 csi 配置创建 pv,并且 pvc、pod 像往常一样定义,yaml 文件参考: +https://bondextest.oss-cn-zhangjiakou.aliyuncs.com/ossyaml.zip + +**配置要求:** + +\- 创建具有所需 RBAC 权限的服务帐户,参考: + +https://github.com/kubernetes-sigs/alibaba-cloud-csi-driver/blob/master/docs/oss.md + +```shell +kubectl -f rbac.yaml +``` + +\- 部署OSS CSI 插件 + +```shell +kubectl -f oss-plugin.yaml +``` + +\- 创建 CP&SP 的 PV + +```shell +kubectl -f checkpoints_pv.yaml kubectl -f savepoints_pv.yaml +``` + +\- 创建 CP&SP 的 PVC + +```shell +kubectl -f checkpoints_pvc.yaml kubectl -f savepoints_pvc.yaml +``` + +配置好依赖环境,接下来我们就开始使用 Paimon 进行流式数仓的分层开发。 + +### **案例** + +统计海运空运实时委托单量 + +任务提交:初始化 Paimon catalog 配置 + +![](/blog/bondex/paimon_catalog_setting.png) + +```sql +SET 'execution.runtime-mode' = 'streaming'; +set 'table.exec.sink.upsert-materialize' = 'none'; +SET 'sql-client.execution.result-mode' = 'tableau'; +-- 创建并使用 FTS Catalog 底层存储方案采用阿里云oss +CREATE CATALOG `table_store` WITH ( +'type' = 'paimon', +'warehouse' = 'oss://xxxxx/xxxxx' #自定义oss存储路径 +); +USE CATALOG `table_store`; +``` + +一个任务同时抽取 postgres、mysql、sqlserver 三种数据库的表数据写入到 Paimon + +![](/blog/bondex/application_setting.png) + +![](/blog/bondex/pom.jpg) + +![](/blog/bondex/pod_template.png) + +**信息如下:** + +``` +Development Mode:Flink SQL + +Execution Mode :kubernetes application + +Flink Version :flink-1.16.0-scala-2.12 + +Kubernetes Namespace :streamx + +Kubernetes ClusterId :(任务名自定义即可) + +#上传到阿里云镜像仓库的基础镜像 +Flink Base Docker Image :registry-vpc.cn-zhangjiakou.aliyuncs.com/xxxxx/flink-table-store:v1.16.0 + +Rest-Service Exposed Type:NodePort + +#paimon基础依赖包: + +paimon-flink-1.16-0.4-20230424.001927-40.jar + +flink-shaded-hadoop-2-uber-2.8.3-10.0.jar + +#flinkcdc依赖包下载地址: + +https://github.com/ververica/flink-cdc-connectors/releases/tag/release-2.2.0 +``` + +**pod template:** + +```yaml +apiVersion: v1 +kind: Pod +metadata: +name: pod-template +spec: + +containers: + - name: flink-main-container + volumeMounts: + - name: flink-checkpoints-csi-pvc + mountPath: /opt/flink/checkpoints + - name: flink-savepoints-csi-pvc + mountPath: /opt/flink/savepoints + +volumes: + - name: flink-checkpoints-csi-pvc + persistentVolumeClaim: + claimName: flink-checkpoints-csi-pvc + - name: flink-savepoints-csi-pvc + persistentVolumeClaim: + claimName: flink-savepoints-csi-pvc + +imagePullSecrets: +- name: streamparksecret +``` + +**Flink sql:** + +1. 构建源表和paimon中ods表的关系,这里就是源表和目标表一对一映射 + +```sql +-- postgre数据库 示例 +CREATE TEMPORARY TABLE `shy_doc_hdworkdochd` ( +`doccode` varchar(50) not null COMMENT '主键', +`businessmodel` varchar(450) COMMENT '业务模式', +`businesstype` varchar(450) COMMENT '业务性质', +`transporttype` varchar(50) COMMENT '运输类型', +...... +`bookingguid` varchar(50) COMMENT '操作编号', +PRIMARY KEY (`doccode`) NOT ENFORCED +) WITH ( +'connector' = 'postgres-cdc', +'hostname' = '数据库服务器IP地址', +'port' = '端口号', +'username' = '用户名', +'password' = '密码', +'database-name' = '数据库名', +'schema-name' = 'dev', +'decoding.plugin.name' = 'wal2json',, +'table-name' = 'doc_hdworkdochd', +'debezium.slot.name' = 'hdworkdochdslotname03' +); + +CREATE TEMPORARY TABLE `shy_base_enterprise` ( +`entguid` varchar(50) not null COMMENT '主键', +`entorgcode` varchar(450) COMMENT '客户编号', +`entnature` varchar(450) COMMENT '客户类型', +`entfullname` varchar(50) COMMENT '客户名称', +PRIMARY KEY (`entguid`,`entorgcode`) NOT ENFORCED +) WITH ( +'connector' = 'postgres-cdc', +'hostname' = '数据库服务器IP地址', +'port' = '端口号', +'username' = '用户名', +'password' = '密码', +'database-name' = '数据库名', +'schema-name' = 'dev', +'decoding.plugin.name' = 'wal2json', +'table-name' = 'base_enterprise', +'debezium.snapshot.mode'='never', -- 增量同步(全量+增量忽略该属性) +'debezium.slot.name' = 'base_enterprise_slotname03' +); + +-- 根据源表结构在paimon上ods层创建对应的目标表 +CREATE TABLE IF NOT EXISTS ods.`ods_shy_jh_doc_hdworkdochd` ( +`o_year` BIGINT NOT NULL COMMENT '分区字段', +`create_date` timestamp NOT NULL COMMENT '创建时间', +PRIMARY KEY (`o_year`, `doccode`) NOT ENFORCED +) PARTITIONED BY (`o_year`) +WITH ( +'changelog-producer.compaction-interval' = '2m' +) LIKE `shy_doc_hdworkdochd` (EXCLUDING CONSTRAINTS EXCLUDING OPTIONS); +CREATE TABLE IF NOT EXISTS ods.`ods_shy_base_enterprise` ( +`create_date` timestamp NOT NULL COMMENT '创建时间', +PRIMARY KEY (`entguid`,`entorgcode`) NOT ENFORCED +) +WITH ( +'changelog-producer.compaction-interval' = '2m' +) LIKE `shy_base_enterprise` (EXCLUDING CONSTRAINTS EXCLUDING OPTIONS); + +-- 设置作业名,执行作业任务将源表数据实时写入到paimon对应表中 +SET 'pipeline.name' = 'ods_doc_hdworkdochd'; +INSERT INTO +ods.`ods_shy_jh_doc_hdworkdochd` +SELECT +* +,YEAR(`docdate`) AS `o_year` +,TO_TIMESTAMP(CONVERT_TZ(cast(CURRENT_TIMESTAMP as varchar), 'UTC', 'Asia/Shanghai')) AS `create_date` +FROM +`shy_doc_hdworkdochd` where `docdate` is not null and `docdate` > '2023-01-01'; +SET 'pipeline.name' = 'ods_shy_base_enterprise'; +INSERT INTO +ods.`ods_shy_base_enterprise` +SELECT +* +,TO_TIMESTAMP(CONVERT_TZ(cast(CURRENT_TIMESTAMP as varchar), 'UTC', 'Asia/Shanghai')) AS `create_date` +FROM +`shy_base_enterprise` where entorgcode is not null and entorgcode <> ''; + +-- mysql数据库 示例 +CREATE TEMPORARY TABLE `doc_order` ( +`id` BIGINT NOT NULL COMMENT '主键', +`order_no` varchar(50) NOT NULL COMMENT '订单号', +`business_no` varchar(50) COMMENT 'OMS服务号', +...... +`is_deleted` int COMMENT '是否作废', +PRIMARY KEY (`id`) NOT ENFORCED +) WITH ( +'connector' = 'mysql-cdc', +'hostname' = '数据库服务器地址', +'port' = '端口号', +'username' = '用户名', +'password' = '密码', +'database-name' = '库名', +'table-name' = 'doc_order' +); + +-- 根据源表结构在paimon上ods层创建对应的目标表 +CREATE TABLE IF NOT EXISTS ods.`ods_bondexsea_doc_order` ( +`o_year` BIGINT NOT NULL COMMENT '分区字段', +`create_date` timestamp NOT NULL COMMENT '创建时间', +PRIMARY KEY (`o_year`, `id`) NOT ENFORCED +) PARTITIONED BY (`o_year`) +WITH ( +'changelog-producer.compaction-interval' = '2m' +) LIKE `doc_order` (EXCLUDING CONSTRAINTS EXCLUDING OPTIONS); + +-- 设置作业名,执行作业任务将源表数据实时写入到paimon对应表中 +SET 'pipeline.name' = 'ods_bondexsea_doc_order'; +INSERT INTO +ods.`ods_bondexsea_doc_order` +SELECT +* +,YEAR(`gmt_create`) AS `o_year` +,TO_TIMESTAMP(CONVERT_TZ(cast(CURRENT_TIMESTAMP as varchar), 'UTC', 'Asia/Shanghai')) AS `create_date` +FROM `doc_order` where gmt_create > '2023-01-01'; + +-- sqlserver数据库 示例 +CREATE TEMPORARY TABLE `OrderHAWB` ( +`HBLIndex` varchar(50) NOT NULL COMMENT '主键', +`CustomerNo` varchar(50) COMMENT '客户编号', +...... +`CreateOPDate` timestamp COMMENT '制单日期', +PRIMARY KEY (`HBLIndex`) NOT ENFORCED +) WITH ( +'connector' = 'sqlserver-cdc', +'hostname' = '数据库服务器地址', +'port' = '端口号', +'username' = '用户名', +'password' = '密码', +'database-name' = '数据库名', +'schema-name' = 'dbo', +-- 'debezium.snapshot.mode' = 'initial' -- 全量增量都抽取 +'scan.startup.mode' = 'latest-offset',-- 只抽取增量数据 +'table-name' = 'OrderHAWB' +); + +-- 根据源表结构在paimon上ods层创建对应的目标表 +CREATE TABLE IF NOT EXISTS ods.`ods_airsea_airfreight_orderhawb` ( +`o_year` BIGINT NOT NULL COMMENT '分区字段', +`create_date` timestamp NOT NULL COMMENT '创建时间', +PRIMARY KEY (`o_year`, `HBLIndex`) NOT ENFORCED +) PARTITIONED BY (`o_year`) +WITH ( +'changelog-producer.compaction-interval' = '2m' +) LIKE `OrderHAWB` (EXCLUDING CONSTRAINTS EXCLUDING OPTIONS); + +-- 设置作业名,执行作业任务将源表数据实时写入到paimon对应表中 +SET 'pipeline.name' = 'ods_airsea_airfreight_orderhawb'; +INSERT INTO +ods.`ods_airsea_airfreight_orderhawb` +SELECT +RTRIM(`HBLIndex`) as `HBLIndex` +...... +,`CreateOPDate` +,YEAR(`CreateOPDate`) AS `o_year` +,TO_TIMESTAMP(CONVERT_TZ(cast(CURRENT_TIMESTAMP as varchar), 'UTC', 'Asia/Shanghai')) AS `create_date` +FROM `OrderHAWB` where CreateOPDate > '2023-01-01'; +``` + +业务表数据实时写入 Paimon ods 表效果如下: + +![](/blog/bondex/ods.png) + +2. 将ods层表的数据打宽写入 dwd 层中,这里其实就是将 ods 层相关业务表合并写入dwd 中,这里主要是处理 count_order 字段的值,因为源表中的数据存在逻辑删除和物理删除所以通过 count 函数统计会有问题,所以我们这里采用 sum 聚合来计算单量,每个reference_no对应的count_order是1,如果逻辑作废通过sql将它处理成0,物理删除 Paimon 会自动处理。 + +dim 维表我们这边直接拿的 doris 里面处理好的维表来使用,维表更新频率低,所以没有在 Paimon 里面进行二次开发。 + +```sql +-- 在paimon-dwd层创建宽表 +CREATE TABLE IF NOT EXISTS dwd.`dwd_business_order` ( +`reference_no` varchar(50) NOT NULL COMMENT '委托单号主键', +`bondex_shy_flag` varchar(8) NOT NULL COMMENT '区分', +`is_server_item` int NOT NULL COMMENT '是否已经关联订单', +`order_type_name` varchar(50) NOT NULL COMMENT '业务分类', +`consignor_date` DATE COMMENT '统计日期', +`consignor_code` varchar(50) COMMENT '客户编号', +`consignor_name` varchar(160) COMMENT '客户名称', +`sales_code` varchar(32) NOT NULL COMMENT '销售编号', +`sales_name` varchar(200) NOT NULL COMMENT '销售名称', +`delivery_center_op_id` varchar(32) NOT NULL COMMENT '交付编号', +`delivery_center_op_name` varchar(200) NOT NULL COMMENT '交付名称', +`pol_code` varchar(100) NOT NULL COMMENT '起运港代码', +`pot_code` varchar(100) NOT NULL COMMENT '中转港代码', +`port_of_dest_code` varchar(100) NOT NULL COMMENT '目的港代码', +`is_delete` int not NULL COMMENT '是否作废', +`order_status` varchar(8) NOT NULL COMMENT '订单状态', +`count_order` BIGINT not NULL COMMENT '订单数', +`o_year` BIGINT NOT NULL COMMENT '分区字段', +`create_date` timestamp NOT NULL COMMENT '创建时间', +PRIMARY KEY (`o_year`,`reference_no`,`bondex_shy_flag`) NOT ENFORCED +) PARTITIONED BY (`o_year`) +WITH ( +-- 每个 partition 下设置 2 个 bucket +'bucket' = '2', +'changelog-producer' = 'full-compaction', +'snapshot.time-retained' = '2h', +'changelog-producer.compaction-interval' = '2m' +); + +-- 设置作业名,将ods层的相关业务表合并写入到dwd层 +SET 'pipeline.name' = 'dwd_business_order'; +INSERT INTO +dwd.`dwd_business_order` +SELECT +o.doccode, +......, +YEAR (o.docdate) AS o_year +,TO_TIMESTAMP(CONVERT_TZ(cast(CURRENT_TIMESTAMP as varchar), 'UTC', 'Asia/Shanghai')) AS `create_date` +FROM +ods.ods_shy_jh_doc_hdworkdochd o +INNER JOIN ods.ods_shy_base_enterprise en ON o.businessguid = en.entguid +LEFT JOIN dim.dim_hhl_user_code sales ON o.salesguid = sales.USER_GUID +LEFT JOIN dim.dim_hhl_user_code op ON o.bookingguid = op.USER_GUID +UNION ALL +SELECT +business_no, +......, +YEAR ( gmt_create ) AS o_year +,TO_TIMESTAMP(CONVERT_TZ(cast(CURRENT_TIMESTAMP as varchar), 'UTC', 'Asia/Shanghai')) AS `create_date` +FROM +ods.ods_bondexsea_doc_order +UNION ALL +SELECT + HBLIndex, + ......, + YEAR ( CreateOPDate ) AS o_year +,TO_TIMESTAMP(CONVERT_TZ(cast(CURRENT_TIMESTAMP as varchar), 'UTC', 'Asia/Shanghai')) AS `create_date` +FROM + ods.`ods_airsea_airfreight_orderhawb` +; +``` + +flink ui 可以看到 ods 数据经过 paimon 实时 join 清洗到表 dwd_business_order + +![](/blog/bondex/dwd_business_order.png) + +2.将dwd层数据轻度聚合到dwm层中,将相关数据写入dwm.`dwm_business_order_count` 表中,该表数据会根据主键对聚合字段做 sum,sum_orderCount 字段就是聚合结果,物理删除的数据 sum 时 paimon 会自动处理。 + +```sql +-- 创建dwm层轻度汇总表,根据日期、销售、操作、业务类别、客户、起运港、目的港汇总单量 +CREATE TABLE IF NOT EXISTS dwm.`dwm_business_order_count` ( +`l_year` BIGINT NOT NULL COMMENT '统计年', +`l_month` BIGINT NOT NULL COMMENT '统计月', +`l_date` DATE NOT NULL COMMENT '统计日期', +`bondex_shy_flag` varchar(8) NOT NULL COMMENT '区分', +`order_type_name` varchar(50) NOT NULL COMMENT '业务分类', +`is_server_item` int NOT NULL COMMENT '是否已经关联订单', +`customer_code` varchar(50) NOT NULL COMMENT '客户编号', +`sales_code` varchar(50) NOT NULL COMMENT '销售编号', +`delivery_center_op_id` varchar(50) NOT NULL COMMENT '交付编号', +`pol_code` varchar(100) NOT NULL COMMENT '起运港代码', +`pot_code` varchar(100) NOT NULL COMMENT '中转港代码', +`port_of_dest_code` varchar(100) NOT NULL COMMENT '目的港代码', +`customer_name` varchar(200) NOT NULL COMMENT '客户名称', +`sales_name` varchar(200) NOT NULL COMMENT '销售名称', +`delivery_center_op_name` varchar(200) NOT NULL COMMENT '交付名称', +`sum_orderCount` BIGINT NOT NULL COMMENT '订单数', +`create_date` timestamp NOT NULL COMMENT '创建时间', +PRIMARY KEY (`l_year`, + `l_month`, + `l_date`, + `order_type_name`, + `bondex_shy_flag`, + `is_server_item`, + `customer_code`, + `sales_code`, + `delivery_center_op_id`, + `pol_code`, + `pot_code`, + `port_of_dest_code`) NOT ENFORCED +) WITH ( +'changelog-producer' = 'full-compaction', + 'changelog-producer.compaction-interval' = '2m', + 'merge-engine' = 'aggregation', -- 使用 aggregation 聚合计算 sum + 'fields.sum_orderCount.aggregate-function' = 'sum', + 'fields.create_date.ignore-retract'='true', + 'fields.sales_name.ignore-retract'='true', + 'fields.customer_name.ignore-retract'='true', + 'snapshot.time-retained' = '2h', +'fields.delivery_center_op_name.ignore-retract'='true' +); +-- 设置作业名 +SET 'pipeline.name' = 'dwm_business_order_count'; +INSERT INTO +dwm.`dwm_business_order_count` +SELECT +YEAR(o.`consignor_date`) AS `l_year` +,MONTH(o.`consignor_date`) AS `l_month` +......, +,TO_TIMESTAMP(CONVERT_TZ(cast(CURRENT_TIMESTAMP as varchar), 'UTC', 'Asia/Shanghai')) AS create_date +FROM +dwd.`dwd_business_order` o +; +``` + +Flink UI 效果如下 dwd_business_orders 数据聚合写到 dwm_business_order_count: + +![](/blog/bondex/dwm_business_order_count.png) + +4.将 dwm 层数据聚合到 dws 层中,dws 层是做了更小维度的汇总 + +```sql +-- 创建根据操作人、业务类型聚合当天的单量 +CREATE TABLE IF NOT EXISTS dws.`dws_business_order_count_op` ( + `l_year` BIGINT NOT NULL COMMENT '统计年', + `l_month` BIGINT NOT NULL COMMENT '统计月', + `l_date` DATE NOT NULL COMMENT '统计日期', + `order_type_name` varchar(50) NOT NULL COMMENT '业务分类', + `delivery_center_op_id` varchar(50) NOT NULL COMMENT '交付编号', + `delivery_center_op_name` varchar(200) NOT NULL COMMENT '交付名称', + `sum_orderCount` BIGINT NOT NULL COMMENT '订单数', + `create_date` timestamp NOT NULL COMMENT '创建时间', + PRIMARY KEY (`l_year`, `l_month`,`l_date`,`order_type_name`,`delivery_center_op_id`) NOT ENFORCED +) WITH ( + 'merge-engine' = 'aggregation', -- 使用 aggregation 聚合计算 sum + 'fields.sum_orderCount.aggregate-function' = 'sum', + 'fields.create_date.ignore-retract'='true', + 'snapshot.time-retained' = '2h', + 'fields.delivery_center_op_name.ignore-retract'='true' +); +-- 设置作业名 +SET 'pipeline.name' = 'dws_business_order_count_op'; +INSERT INTO + dws.`dws_business_order_count_op` +SELECT + o.`l_year` + ,o.`l_month` + ,o.`l_date` + ,o.`order_type_name` + ,o.`delivery_center_op_id` + ,o.`delivery_center_op_name` + ,o.`sum_orderCount` + ,TO_TIMESTAMP(CONVERT_TZ(cast(CURRENT_TIMESTAMP as varchar), 'UTC', 'Asia/Shanghai')) AS create_date +FROM + dwm.`dwm_business_order_count` o +; +``` + +Flink UI 效果如下 dws_business_order_count_op 数据写到 dws_business_order_count_op: + +![](/blog/bondex/dws_business_order_count_op.png) + +总体数据流转示例 + +![](/blog/bondex/all_datastream.jpg) + +源表: + +![](/blog/bondex/source.png) + +paimon-ods: + +![](/blog/bondex/paimon-ods.png) + +paimon-dwd: + +![](/blog/bondex/paimon-dwd.png) + +paimon-dwm: + +![](/blog/bondex/paimon-dwm.png) + +paimon-dws: + +![](/blog/bondex/paimon-dws.png) + +特别提醒 sqlserver 数据库抽取时如果源表数据量过大全量抽取会锁表,建议在业务允许的情况下采用增量抽取。对于全量抽取 sqlserver 可以采用中转的方式 sqlserver 全量数据导入到 mysql,从 mysql 再到 paimon-ods ,后面再通过 sqlserever 做增量抽取。 + +## 04 问题排查分析 + +**1. 聚合数据计算不准** + +sqlserver cdc 采集数据到 paimon 表,说明: + +**dwd 表:** + +'changelog-producer' = 'input' + +**ads 表:** + +'merge-engine' = 'aggregation', -- 使用 aggregation 聚合计算 sum + +'fields.sum_amount.aggregate-function' = 'sum' + +ADS 层聚合表采用 agg sum 会出现 dwd 数据流不产生 update_before,产生错误数据流 update_after 比如上游源表 update 10 到 30 dwd 层数据会变更为 30,ads 聚合层数据也会变更为 30,但是现在变为了 append 数据变成了 10+30=40 的错误数据。 + +解决办法: + +By specifying 'changelog-producer' = 'full-compaction', +Table Store will compare the results between full compactions and produce the differences as changelog. +The latency of changelog is affected by the frequency of full compactions. + +By specifying changelog-producer.compaction-interval table property (default value 30min), +users can define the maximum interval between two full compactions to ensure latency. +This table property does not affect normal compactions and they may still be performed once in a while by writers to reduce reader costs. + +这样能解决上述问题。但是随之而来出现了新的问题。默认 changelog-producer.compaction-interval 是 30min,意味着 上游的改动到 ads 查询要间隔 30min,生产过程中发现将压缩间隔时间改成 1min 或者 2 分钟的情况下,又会出现上述 ADS 层聚合数据不准的情况。 + +```sql +'changelog-producer.compaction-interval' = '2m' +``` + +需要在写入 Flink Table Store 时需要配置 table.exec.sink.upsert-materialize= none,避免产生 Upsert 流,以保证 Flink Table Store 中能够保存完整的 changelog,为后续的流读操作做准备。 + +```sql +set 'table.exec.sink.upsert-materialize' = 'none' +``` + +**2. 相同 sequence.field 导致 dwd 明细宽表无法收到 update 数据更新** + +**mysql cdc 采集数据到 paimon 表** + +说明: + +在 MySQL 源端执行 update 数据修改成功后,dwd_orders 表数据能同步成功 + +![](/blog/bondex/dwd_orders.png) + +但是查看 dwd_enriched_orders 表数据无法同步,启动流模式查看数据,发现没有数据流向 + +![](/blog/bondex/log.png) + +**解决:** + +排查发现是由于配置了参数 'sequence.field' = 'o_orderdate'(使用 o_orderdate 生成 sequence id,相同主键合并时选择 sequence id 更大的记录)导致的,因为在修改价格的时候 o_orderdate 字段时间不变, 继而'sequence.field' 是相同的,导致顺序不确定,所以 ROW1 和 ROW2,它们的 o_orderdate 是一样的,所以在更新时会随机选择,所有将该参数去掉即可,去掉后正常按照输入的先后顺序,自动生成一个 sequence number,不会影响同步结果。 + +**3. Aggregate function 'last_non_null_value' does not support retraction** + +报错: +Caused by: java.lang.UnsupportedOperationException: Aggregate function 'last_non_null_value' does not support retraction, If you allow this function to ignore retraction messages, you can configure 'fields.${field_name}.ignore-retract'='true'. + +可以在官方文档找到解释: + +Only sum supports retraction (UPDATE_BEFORE and DELETE), others aggregate functions do not support retraction. + +可以理解为:除了 SUM 函数,其他的 Agg 函数都不支持 Retraction,为了避免接收到 DELETE 和 UPDATEBEFORE 消息报错,需要通过给指定字段配 'fields.${field_name}.ignore-retract'='true' 忽略,解决这个报错 + +```sql +WITH ( + +'merge-engine' = 'aggregation', -- 使用 aggregation 聚合计算 sum + +'fields.sum_orderCount.aggregate-function' = 'sum', + +'fields.create_date.ignore-retract'='true' #create_date 字段 + +); +``` + +**4. paimon任务中断失败** + +任务异常中断 导致pod挂掉,查看loki日志显示akka.pattern.AskTimeoutException: Ask timed out on + +![](/blog/bondex/loki.png) + +java.util.concurrent.TimeoutException: Invocation of [RemoteRpcInvocation(JobMasterGateway.updateTaskExecutionState(TaskExecutionState))] at recipient [akka.tcp://flink@fts-business-order-count.streamx:6123/user/rpc/jobmanager_2] timed out. This is usually caused by: 1) Akka failed sending the message silently, due to problems like oversized payload or serialization failures. In that case, you should find detailed error information in the logs. 2) The recipient needs more time for responding, due to problems like slow machines or network jitters. In that case, you can try to increase akka.ask.timeout.\n" + +初步判断应该是由于以上2个原因导致触发了 akka 的超时机制,那就调整集群的akka超时间配置和进行单个任务拆分或者调大资源配置。 + + + +我们这边先看如何进行参数修改: + + + +| key | default | describe | +| ---------------- | ------- | ------------------------------------------------------------ | +| akka.ask.timeout | 10s | Timeout used for all futures and blocking Akka calls. If Flink fails due to timeouts then you should try to increase this value. Timeouts can be caused by slow machines or a congested network. The timeout value requires a time-unit specifier (ms/s/min/h/d). | +| web.timeout | 600000 | Timeout for asynchronous operations by the web monitor in milliseconds. | + +在 conf/flink-conf.yaml 最后增加下面参数: + +**akka.ask.timeout: 100s** + +**web.timeout:1000000** + +然后在 streampark 手动刷新下 flink-conf.yaml 验证参数是否同步成功。 + +**5. snapshot no such file or director** + +发现 cp 出现失败情况 + +![](/blog/bondex/cp_fail.jpg) + +对应时间点日志显示 Snapshot 丢失,任务显示为 running 状态,但是源表 mysql 数据无法写入 paimon ods 表 + +![](/blog/bondex/status_log.png) + +定位cp失败原因为:计算量大,CPU密集性,导致TM内线程一直在processElement,而没有时间做CP + +无法读取 Snapshot 原因为:flink 集群资源不够,Writer 和 Committer 产生竞争,Full-Compaction 时读到了已过期部分的不完整的 Snapshot,目前官方针对这个问题已经修复: + +https://github.com/apache/incubator-paimon/pull/1308 + +而解决 cp 失败的解决办法增加并行度,增加 deploymenttaskmanager slot 和 jobmanager cpu + +``` +-D kubernetes.jobmanager.cpu=0.8 + +-D kubernetes.jobmanager.cpu.limit-factor=1 + +-D taskmanager.numberOfTaskSlots=8 + +-D jobmanager.adaptive-batch-scheduler.default-source-parallelism=2 +``` + +![](/blog/bondex/dynamic_properties.jpg) + +![](/blog/bondex/flink_dashboard.png) + +在复杂的实时任务中,可以通过修改动态参数的方式,增加资源。 + +## 05 未 来 规 划 + +- 自建的数据平台 bondata 正在集成 paimon 的元数据信息、数据指标体系、血缘、一键 pipline 等功能,形成海程邦达的数据资产,并将在此基础上展开一站式数据治理 +- 后面将基于 trino Catalog接入Doris,实现真正的离线数据和实时数据的one service +- 采用 doris + paimon 的架构方案继续推进集团内部流批一体数仓建设的步伐 + +在这里要感谢之信老师和 StreamPark 社区在使用 StreamPark + Paimon 过程中的大力支持,在学习使用过程中遇到的问题,都能在第一时间给到解惑并得到解决,我们后面也会积极参与社区的交流和建设,让 paimon 能为更多开发者和企业提供流批一体的数据湖解决方案。 diff --git a/i18n/zh-CN/docusaurus-plugin-content-blog/4-streampark-usercase-shunwang.md b/i18n/zh-CN/docusaurus-plugin-content-blog/4-streampark-usercase-shunwang.md new file mode 100644 index 000000000..410f162f3 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-blog/4-streampark-usercase-shunwang.md @@ -0,0 +1,213 @@ +--- +slug: streampark-usercase-shunwang +title: StreamPark 在顺网科技的大规模生产实践 +tags: [StreamPark, 生产实践, FlinkSQL] +--- + +# StreamPark 在顺网科技的大规模生产实践 + +![](/blog/shunwang/autor.png) + +**导读:**本文主要介绍顺网科技在使用 Flink 计算引擎中遇到的一些挑战,基于 StreamPark 作为实时数据平台如何来解决这些问题,从而大规模支持公司的业务。 + + +- 公司业务介绍 +- 遇到的挑战 +- 为什么用 StreamPark +- 落地实践 +- 带来的收益 +- 未来规划 + +## **公司业务介绍** + +杭州顺网科技股份有限公司成立于 2005 年,秉承科技连接快乐的企业使命,是国内具有影响力的泛娱乐技术服务平台之一。多年来公司始终以产品和技术为驱动,致力于以数字化平台服务为人们创造沉浸式的全场景娱乐体验。 + + + +自顺网科技成立以来,随着业务快速发展,顺网科技服务了 8 万家线下实体店,拥有超过 5000 万互联网用户,年触达超 1.4 亿网民,每 10 家公共上网服务场所有 7 家使用顺网科技产品。 + +在拥有庞大的用户群体的情况下,顺网科技为了给用户提供更加优质的产品体验,实现企业的数字化转型,从 2015 年开始大力发展大数据, Flink 在顺网科技的实时计算中一直扮演着重要的角色。在顺网科技,实时计算大概分为 4 个应用场景: + +- 用户画像实时更新:包括网吧画像和网民画像。 +- 实时风控:包括活动防刷、异地登录监测等。 +- 数据同步:包括 Kafka 数据同步到 Hive / Iceberg / ClickHouse 等。 +- 实时数据分析:包括游戏、语音、广告、直播等业务实时大屏。 + +到目前为止,顺网科技每日需要处理 TB 级别的数据,总共拥有 700+ 个实时任务,其中 FlinkSQL 任务占比为 95% 以上。随着公司业务快速发展和数据时效性要求变高,预计在今年年底 Flink 任务会达到 900+。 + +## **遇到的挑战** + +Flink 作为当下实时计算领域中最流行的技术框架之一,拥有高吞吐、低延迟、有状态计算等强大的特性。在探索中我们发现 Flink 虽然拥有强大的计算能力,但是对于作业开发管理和运维问题,社区并没有提供有效的解决方案。我们对 Flink 作业开发管理上遇到的一些痛点大概总结为 4 个方面,如下: + +![图片](/blog/shunwang/pain.png) + +在面对 Flink 作业管理和运维上的的一系列痛点后,我们一直在寻找合适的解决方案来降低开发同学使用 Flink 门槛,提高工作效率。 + +在没有遇到 StreamPark 之前,我们调研了部分公司的 Flink 管理解决方案,发现都是通过自研实时作业平台的方式来开发和管理 Flink 作业。于是,我们也决定自研一套实时计算管理平台,来满足了开发同学对于 Flink 作业管理和运维的基础需求,我们这套平台叫 Streaming-Launcher,大体功能如下: + +![图片](/blog/shunwang/launcher.png) + +但是后续开发同学在使用过程中,发现 Streaming-Launcher 存在比较多的缺陷:Flink 开发成本依然过高、工作效率低下、问题排查困难。我们总结了 Streaming-Launcher 存在的缺陷,大致如下: + +### **SQL开发流程繁琐** + +作业务开发需要多个工具完成一个 SQL 作业开发,提高了开发同学的使用门槛。 + +![cc0b1414ed43942e0ef5e9129c2bf817](/blog/shunwang/sql_develop.png) + +### **SQL-Client 存在弊端** + +Flink 提供的 SQL-Client 目前对作业运行模式支持上,存在一定的弊端。 + +![图片](/blog/shunwang/sql_client.png) + +### **作业缺少统一管理** + +Streaming-Launcher 中,没有提供统一的作业管理界面。开发同学无法直观的看到作业运行情况,只能通过告警信息来判断作业运行情况,这对开发同学来说非常不友好。如果因为 Yarn 集群稳定性问题或者网络波动等不确定因素,一下子失败大批量任务,在开发同学手动恢复作业的过程中,很容易漏恢复某个任务而造成生产事故。 + +### **问题诊断流程繁琐** + +一个作业查看日志需要通过多个步骤,一定程度上降低了开发同学工作效率。 + +![图片](/blog/shunwang/step.png) + +## **为什么用** **StreamPark** + +面对自研平台 Streaming-Launcher 存在的缺陷,我们一直在思考如何将 Flink 的使用门槛降到更低,进一步提高工作效率。考虑到人员投入成本和时间成本,我们决定向开源社区求助寻找合适的开源项目来对我们的 Flink 任务进行管理和运维。 + + + +### 01 **StreamPark 解决 Flink 问题的利器** + +很幸运在 2022 年 6 月初,我们在 GitHub 机缘巧合之间认识到了 StreamPark,我们满怀希望地对 StreamPark 进行了初步的探索。发现 StreamPark 具备的能力大概分为三大块:用户权限管理、作业运维管理和开发脚手架。 + +**用户权限管理** + +在 StreamPark 平台中为了避免用户权限过大,发生一些不必要的误操作,影响作业运行稳定性和环境配置的准确性,提供了相应的一些用户权限管理功能,这对企业级用户来说,非常有必要。 + + + +![图片](/blog/shunwang/permission.png) + + + +**作业运维管理** + +**我们在对 StreamPark 做调研的时候,最关注的是 StreamPark 对于作业的管理的能力。**StreamPark 是否有能力管理作业一个完整的生命周期:作业开发、作业部署、作业管理、问题诊断等。**很幸运,StreamPark 在这一方面非常优秀,对于开发同学来说只需要关注业务本身,不再需要特别关心 Flink 作业管理和运维上遇到的一系列痛点。**在 StreamPark 作业开发管理管理中,大致分为三个模块:作业管理基础功能,Jar 作业管理,FlinkSQL 作业管理。如下: + +![图片](/blog/shunwang/homework_manager.png) + +**开发脚手架** + +通过进一步的研究发现,StreamPark 不仅仅是一个平台,还包含 Flink 作业开发脚手架, 在 StreamPark 中,针对编写代码的 Flink 作业,提供一种更好的解决方案,将程序配置标准化,提供了更为简单的编程模型,同时还提供了一些列 Connectors,降低了 DataStream 开发的门槛。 + + + +![图片](/blog/shunwang/connectors.png) + + + + + +### 02 **StreamPark 解决自研平台的问题** + +上面我们简单介绍了 StreamPark 的核心能力。在顺网科技的技术选型过程中,我们发现 StreamPark 所具备强大的功能不仅包含了现有 Streaming-Launcher 的基础功能,还提供了更完整的对应方案解决了 Streaming-Launcher 的诸多不足。在这部分,着重介绍下 StreamPark 针对我们自研平台 Streaming-Launcher 的不足所提供的解决方案。 + + + +![图片](/blog/shunwang/function.png) + + + +**Flink 作业一站式的开发能力** + +StreamPark 为了降低 Flink 作业开发门槛,提高开发同学工作效率,**提供了 FlinkSQL IDE、参数管理、任务管理、代码管理、一键编译、一键作业上下线等使用的功能**。在调研中,我们发现 StreamPark 集成的这些功能可以进一步提升开发同学的工作效率。在某种程度上来说,开发同学不需要去关心 Flink 作业管理和运维的难题,只要专注于业务的开发。同时,这些功能也解决了 Streaming-Launcher 中 SQL 开发流程繁琐的痛点。 + +![图片](/blog/shunwang/application.png) + +**支持多种部署模式** + +在 Streaming-Launcher 中,由于只支持 Yarn Session 模式,对于开发同学来说,其实非常不灵活。StreamPark 对于这一方面也提供了完善的解决方案。**StreamPark 完整的支持了Flink 的所有部署模式:Remote、Yarn Per-Job、Yarn Application、Yarn Session、K8s Session、K8s Application****,**可以让开发同学针对不同的业务场景自由选择合适的运行模式。** + +**作业统一管理中心** + +对于开发同学来说,作业运行状态是他们最关心的内容之一。在 Streaming-Launcher 中由于缺乏作业统一管理界面,开发同学只能通过告警信息和 Yarn 中Application 的状态信息来判断任务状态,这对开发同学来说非常不友好。StreamPark 针对这一点,提供了作业统一管理界面,可以一目了然查看到每个任务的运行情况。 + +![图片](/blog/shunwang/management.png) + +在 Streaming-Launcher 中,开发同学在作业问题诊断的时候,需要通过多个步骤才能定位作业运行日志。StreamPark 提供了一键跳转功能,能快速定位到作业运行日志。 + +![图片](/blog/shunwang/logs.png) + + + +## 落 地 实 践 + +在 StreamPark 引入顺网科技时,由于公司业务的特点和开发同学的一些定制化需求,我们对 StreamPark 的功能做了一些增加和优化,同时也总结了一些在使用过程中遇到的问题和对应的解决方案。 + +### 01 **结合 Flink-SQL-Gateway 的能力** + +在顺网科技,我们基于 Flink-SQL-Gateway 自研了 ODPS 平台来方便业务开发同学管理 Flink 表的元数据。业务开发同学在 ODPS 上对 Flink 表进行 DDL 操作,然后在 StreamPark 上对创建的 Flink 表进行分析查询操作。在整个业务开发流程上,我们对 Flink 表的创建和分析实现了解耦,让开发流程显得比较清晰。 + +开发同学如果想在 ODPS 上查询实时数据,我们需要提供一个 Flink SQL 的运行环境。我们使用 StreamPark 运行了一个 Yarn Session 的 Flink 环境提供给 ODPS 做实时查询。 + +![图片](/blog/shunwang/homework.png) + +目前 StreamPark 社区为了进一步降低实时作业开发门槛,正在对接 Flink-SQL-Gateway。 + +https://github.com/apache/streampark/issues/2274 + + + +### 02 **增强 Flink 集群管理能力** + +在顺网科技,存在大量从 Kafka 数据同步到 Iceberg / PG / Clickhouse / Hive 的作业。这些作业需要的 Yarn 对于资源要求和时效性要求不高,但是如果全部使用 Yarn Application 和 per-job 模式,每个任务都会启动 JobManager,那么会造成 Yarn 资源的浪费。对此,我们决定使用 Yarn Session 模式运行这些大量的数据同步作业。 + +在实践中我们发现业务开发同学很难直观的知道在每个 Yarn Session 中运行了多少个作业,其中包括作业总数和正在运行中的作业数量。基于这个原因,我们为了方便开发同学可以直观地观察到 Yarn Session 中的作业数量,在 Flink Cluster 界面增加了 All Jobs 和 Running Jobs 来表示在一个 Yarn Session 中总的作业数和正在运行的作业数。 + +![图片](/blog/shunwang/cluster.png) + + + +### 03 **增强告警能力** + +因为每个公司的短信告警平台实现都各不相同,所以 StreamPark 社区并没有抽象出统一的短信告警功能。在此,我们通过 Webhook 的方式,自己实现了短信告警功能。 + +![图片](/blog/shunwang/alarm.png) + + + +### 04 **增加阻塞队列解决限流问题** + +在生产实践中,我们发现在大批量任务同时失败的时候,比如 Yarn Session 集群挂了,飞书 / 微信等平台在多线程同时调用告警接口时会存在限流的问题,那么大量的告警信息因为飞书 / 微信等平台限流问题,StreamPark 只会发送一部分的告警信息,这样非常容易误导开发同学排查问题。在顺网科技,我们增加了一个阻塞队列和一个告警线程,来解决限流问题。 + +![图片](/blog/shunwang/queue.png) + +当作业监控调度器检测到作业异常时,会产生一条作业异常的消息发送的阻塞队列中,在告警线程中会一直消费阻塞队列中的消息,在得到作业异常消息后则会根据用户配置的告警信息单线程发送到不同的平台中。虽然这样做可能会让用户延迟收到告警,但是我们在实践中发现同时有 100+ 个 Flink 作业失败,用户接受到告警的延迟时间小于 3s。对于这种延迟时间,我们业务开发同学完全是可以接受的。该改进目前已经记录 ISSUE,正在考虑贡献到社区中。 + +https://github.com/apache/streampark/issues/2142 + + + +## 带来的收益 + +我们从 StreamX 1.2.3(StreamPark 前身)开始探索和使用,经过一年多时间的磨合,我们发现 StreamPark 真实解决了 Flink 作业在开发管理和运维上的诸多痛点。 + +StreamPark 给顺网科技带来的最大的收益就是降低了 Flink 的使用门槛,提升了开发效率。我们业务开发同学在原先的 Streaming-Launcher 中需要使用 vscode、GitLab 和调度平台等多个工具完成一个 FlinkSQL 作业开发,从开发到编译到发布的流程中经过多个工具使用,流程繁琐。StreamPark 提供一站式服务,可以在 StreamPark 上完成作业开发编译发布,简化了整个开发流程。 + +**目前 StreamPark 在顺网科技已经大规模在生产环境投入使用,StreamPark 从最开始管理的 500+ 个 FlinkSQL 作业增加到了近 700 个 FlinkSQL作业,同时管理了 10+ 个 Yarn Sesssion Cluster。** + +![图片](/blog/shunwang/achievements1.png) + +![图片](/blog/shunwang/achievements2.png) + +## 未 来 规 划 + +顺网科技作为 StreamPark 早期的用户之一,在 1 年期间内一直和社区同学保持交流,参与 StreamPark 的稳定性打磨,我们将生产运维中遇到的 Bug 和新的 Feature 提交给了社区。在未来,我们希望可以在 StreamPark 上管理 Flink 表的元数据信息,基于 Flink 引擎通过多 Catalog 实现跨数据源查询分析功能。目前 StreamPark 正在对接 Flink-SQL-Gateway 能力,这一块在未来对于表元数据的管理和跨数据源查询功能会提供了很大的帮助。 + +由于在顺网科技多是已 Yarn Session 模式运行的作业,我们希望 StreamPark 可以提供更多对于 Remote集群、Yarn Session 集群和 K8s Session 集群功能支持,比如监控告警,优化操作流程等方面。 + +考虑到未来,随着业务发展可能会使用 StreamPark 管理更多的 Flink 实时作业,单节点模式下的 StreamPark 可能并不安全。所以我们对于 StreamPark 的 HA 也是非常期待。 + +对于 StreamPark 对接 Flink-SQL-Gateway 能力、丰富 Flink Cluster 功能和 StreamPark HA,我们后续也会参与建设中。 + diff --git a/i18n/zh-CN/docusaurus-plugin-content-blog/5-streampark-usercase-dustess.md b/i18n/zh-CN/docusaurus-plugin-content-blog/5-streampark-usercase-dustess.md new file mode 100644 index 000000000..81fe77522 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-blog/5-streampark-usercase-dustess.md @@ -0,0 +1,266 @@ +--- +slug: streampark-usercase-dustess +title: StreamPark 在尘锋信息的最佳实践,化繁为简极致体验 +tags: [StreamPark, 生产实践, FlinkSQL] +--- + +# StreamPark 在尘锋信息的最佳实践,化繁为简极致体验 + +**摘要:**本文源自 StreamPark 在尘锋信息的生产实践, 作者是资深数据开发工程师Gump。主要内容为: + +1. 技术选型 +2. 落地实践 +3. 业务支撑 & 能力开放 +4. 未来规划 +5. 结束语 + +尘锋信息是基于企业微信生态的一站式私域运营管理解决方案供应商,致力于成为全行业首席私域运营与管理专家,帮助企业构建数字时代私域运营管理新模式,助力企业实现高质量发展。 + +目前,尘锋已在全国拥有13个城市中心,覆盖华北、华中、华东、华南、西南五大区域,为超30个行业的10,000+家企业提供数字营销服务。 + +## **01 技术选型** + +尘锋信息在2021年进入了快速发展时期,随着服务行业和企业客户的增加,实时需求越来越多,落地实时计算平台迫在眉睫。 + +由于公司处于高速发展期,需求紧迫且变化快,所以团队的技术选型遵循以下原则: + +- 快:由于业务紧迫,我们需要快速落地规划的技术选型并运用生产 +- 稳:满足快的基础上,所选择技术一定要稳定服务业务 +- 新:在以上基础,所选择的技术也尽量的新 +- 全:所选择技术能够满足公司快速发展和变化的业务,能够符合团队长期发展目标,能够支持且快速支持二次开发 + +首先在计算引擎方面:我们选择 Flink,原因如下: + +- 团队成员对 Flink 有深入了解,熟读源码 +- Flink 支持批流一体,虽然目前公司的批处理架构还是基于 Hive、Spark 等。使用 Flink 进行流计算,便于后期建设批流一体和湖仓一体 +- 目前国内 Flink 生态已经越来越成熟,Flink 也开始着手踏破边界向流式数仓发展 + +在平台层面,我们综合对比了 StreamPark 、 Apache Zeppelin 和 flink-streaming-platform-web,也深入阅读了源码和并做了优缺点分析,关于后两个项目本文就不展开赘述,感兴趣的朋友可以去 GitHub 搜索,我们最终选择 StreamPark,理由如下: + +### **完成度高** + +#### **1. 支持Flink 多版本** + +//视频链接( Flink 多版本支持 Demo ) + + + +新建任务时可以**自由选择Flink版本**,Flink 二进制版本包会自动上传至 HDFS(如果使用 Yarn 提交),且一个版本的二进制包只会在 HDFS 保存一份。任务启动时会自动根据上下文加载 HDFS 中的 Flink 二进制包,非常优雅。能够满足多版本共存,及升级Flink 新版本试用测试的场景。 + +![](/blog/dustess/flink_home.png) + +#### **2. 支持多种部署模式** + +StreamPark 支持 Flink **所有主流的提交模式**,如 standalone、yarn-session 、yarn application、yarn-perjob、kubernetes-session、kubernetes-application 而且StreamPark 不是简单的拼接 Flink run 命令来进行的任务提交,而是引入了 Flink Client 源码包,直接调用 Flink Client API 来进行的任务提交。这样的好处是代码模块化、易读、便于扩展,稳定,且能在后期根据 Flink 版本升级进行很快的适配。 + +![](/blog/dustess/execution_mode.png) + +Flink SQL 可以极大提升开发效率和提高 Flink 的普及。StreamPark 对于 **Flink SQL 的支持非常到位**,优秀的 SQL 编辑器,依赖管理,任务多版本管理等等。StreamPark 官网介绍后期会加入 Flink SQL 的元数据管理整合,大家拭目以待。 + +![](/blog/dustess/flink_sql.png) + +![](/blog/dustess/flink_sql_version.png) + +#### **4. JAVA任务在线构建** + +//视频链接( JAVA 任务构建 Demo) + + + +Flink SQL 现在虽然足够强大,但使用 Java 和 Scala 等 JVM 语言开发 Flink 任务会更加灵活、定制化更强、便于调优和提升资源利用率。与 SQL 相比 Jar 包提交任务最大的问题是Jar包的上传管理等,没有优秀的工具产品会严重降低开发效率和加大维护成本。 + +StreamPark 除了支持 Jar 上传,更提供了**在线更新构建**的功能,优雅解决了以上问题: + +1、新建 Project :填写 GitHub/Gitlab(支持企业私服)地址及用户名密码, StreamPark 就能 Pull 和 Build 项目。 + +2、创建 StreamPark Custom-Code 任务时引用 Project,指定主类,启动任务时可选自动 Pull、Build 和绑定生成的 Jar,非常优雅! + +同时 StreamPark 社区最近也在完善整个任务编译、上线的流程,以后的 StreamPark 会在此基础上更加完善和专业。 + +![](/blog/dustess/system_list.png) + +#### **5. 完善的任务参数配置** + +对于使用 Flink 做数据开发而言,Flink run 提交的参数几乎是难以维护的。StreamPark 也非常**优雅的解决**了此类问题,原因是上面提到的 StreamPark 直接调用 Flink Client API,并且从 StreamPark 产品前端打通了整个流程。 + +![](/blog/dustess/parameter_configuration.png) + +大家可以看到,StreamPark 的任务参数设置涵盖了主流的所有参数,并且非常细心的对每个参数都做了介绍和最佳实践的最优推荐。这对于刚使用 Flink 的同学来说也是非常好的事情,避免踩坑! + +#### **6. 优秀的配置文件设计** + +对于 Flink 任务的原生参数,上面的任务参数已经涵盖了很大一部分。StreamPark 还提供了强大的**Yaml 配置文件** 模式和 **编程模型**。 + +![](/blog/dustess/extended_parameters.jpg) + +1、对于 Flink SQL 任务,直接使用任务的 Yaml 配置文件可以配置 StreamPark 已经内置的参数,如常见的 **CheckPoint、重试机制、State Backend、table planer 、mode** 等等。 + +2、对于 Jar 任务,StreamPark 提供了通用的编程模型,该模型封装了 Flink 原生 API ,结合 StreamPark 提供的封装包可以非常优雅的获取配置文件中的自定义参数,这块文档详见: + +编程模型: + +``` +http://www.streamxhub.com/docs/development/dev-model +``` + +内置配置文件参数: + +``` +http://www.streamxhub.com/docs/development/config +``` + +除此之外: + +StreamPark 也**支持Apache Flink 原生任务**,参数配置可以由 Java 任务内部代码静态维护,可以覆盖非常多的场景,比如存量 Flink 任务无缝迁移等等 + +#### **7. Checkpoint 管理** + +关于 Flink 的 Checkpoint(Savepoint)机制,最大的困难是维护 ,StreamPark 也非常优雅的解决此问题: + +- StreamPark 会**自动维护**任务 Checkpoint 的目录及版本至系统中方便检索 +- 当用户需要更新重启应用时,可以选择是否保存 Savepoint +- 重新启动任务时可选择 Checkpoint/Savepoint 从指定版本的恢复 + +如下,开发同学能够非常直观方便的升级或处理异常任务,非常强大 + +![](/blog/dustess/checkpoint.png) + +![](/blog/dustess/recover.jpg) + +#### **8. 完善的报警功能** + +对于流式计算此类7*24H常驻任务来说,监控报警是非常重要的 ,StreamPark 对于此类问题也有**完善的解决方案**: + +- 自带基于邮件的报警方式,0开发成本,配置即可使用 +- 得益于 StreamPark 源码优秀的模块化,可以在 Task Track 处进行代码增强,引入公司内部的 SDK 进行电话、群组等报警方式,开发成本也非常低 + +![](/blog/dustess/alarm_email.png) + +### **源码优秀** + +遵循技术选型原则,一个新的技术必须足够了解底层原理和架构思想后,才会考虑应用生产。在选择 StreamPark 之前,对其架构和源码进入过深入研究和阅读。发现 StreamPark 所选用的底层技术是国人非常熟悉的:MySQL、Spring Boot、Mybatis Plus、Vue 等,代码风格统一,实现优雅,注释完善,各模块独立抽象合理,使用了较多的设计模式,且代码质量很高,非常适合后期的排错及二次开发。 + +![](/blog/dustess/code_notebook.png) + +StreamPark 于 2021年11月成功被开源中国评选为GVP - Gitee「最有价值开源项目」,足以见得其质量和潜力。 + +![](/blog/dustess/certificate.png) + +### **03 社区活跃** + +目前社区非常活跃,从2021年11月底落地 StreamPark (基于1.2.0-release),当时StreamPark 刚刚才被大家认识,还有一些体验上的小 Bug(不影响核心功能)。当时为了快速上线,屏蔽掉了一些功能和修复了一些小 Bug,正当准备贡献给社区时发现早已修复,这也可以看出目前社区的迭代周期非常快。以后我们公司团队也会努力和社区保持一致,将新特性快速落地,提升数据开发效率和降低维护成本。 + +## **02 落地实践** + +StreamPark 的环境搭建非常简单,跟随官网的搭建教程可以在小时内完成搭建。目前已经支持了前后端分离打包部署的模式,可以满足更多公司的需求,而且已经有 Docker Build 相关的 PR,相信以后 StreamPark 的编译部署会更加方便快捷。相关文档如下: + +``` +http://www.streamxhub.com/docs/user-guide/deployment +``` + +为了快速落地和生产使用,我们选择了稳妥的 On Yarn 资源管理模式(虽然 StreamPark 已经很完善的支持 K8S),且已经有较多公司通过 StreamPark 落地了 K8S 部署方式,大家可以参考: + +``` +http://www.streamxhub.com/blog/flink-development-framework-streamx +``` + +StreamPark 整合 Hadoop 生态可以说是0成本的(前提是按照 Flink 官网将 Flink 与 Hadoop 生态整合,能够通过 Flink 脚本启动任务即可) + +目前我们也正在进行 K8S 的测试及方案设计,在未来一段时间会整体迁移至 K8S + +### **01 落地 FlinkSQL 任务** + +目前我们公司基于 Flink SQL 的任务主要为业务比较简单的实时 ETL 和计算场景,数量在10个左右,上线至今都十分稳定。 + +![](/blog/dustess/online_flinksql.png) + +StreamPark 非常贴心的准备了 Demo SQL 任务,可以直接在刚搭建的平台上运行,从这些细节可以看出社区对用户体验非常重视。前期我们的简单任务都是通过 Flink SQL 来编写及运行,StreamPark 对于 Flink SQL 的支持得非常好,优秀的 SQL 编辑器,创新型的 POM 及 Jar 包依赖管理,可以满足非常多的 SQL 场景下的问题。 + +目前我们正在进行元数据层面、权限、UDF等相关的方案调研、设计等 + +### **02 落地 Jar 任务** + +由于目前团队的数据开发同学大多有 Java 和 Scala 语言基础,为了更加灵活的开发、更加透明的调优 Flink 任务及覆盖更多场景,我们也快速的落地了基于 Jar 包的构建方式。我们落地分为了两个阶段 + +第一阶段:**StreamPark 提供了原生 Apache Flink 项目的支持**,我们将存量的任务Git地址配置至 StreamPark,底层使用 Maven 打包为 Jar 包,创建 StreamPark 的 Apache Flink任务,无缝的进行了迁移。在这个过程中,StreamPark 只是作为了任务提交和状态维护的一个平台工具,远远没有使用到上面提到的其他功能。 + +第二阶段:第一阶段将任务都迁移至 StreamPark 上之后,任务已经在平台上运行,但是任务的配置,如 checkpoint,容错以及 Flink 任务内部的业务参数的调整都需要修改源码 push 及 build,效率十分低下且不透明。 + +于是,根据 StreamPark 的 QuickStart 我们快速整合了StreamPark 的编程模型,也就是StreamPark Flink 任务(对于 Apache Flink)的封装。 + +如: + +``` +StreamingContext = ParameterTool + StreamExecutionEnvironment +``` + +- StreamingContext 为 StreamPark 的封装对象 +- ParameterTool 为解析配置文件后的参数对象 + +``` + String value = ParameterTool.get("${user.custom.key}") +``` + +- StreamExecutionEnvironment 为 Apache Flink 原生任务上下文 + +## **03 业务支撑 & 能力开放** + +目前尘锋基于 StreamPark 的实时计算平台从去年11月底上线至今,已经上线 50+ Flink 任务,其中 10+为 Flink SQL 任务,40+ 为 Jar 任务。目前主要还是数据团队内部使用,近期会将实时计算平台开放全公司业务团队使用,任务量会大量增加。 + +![](/blog/dustess/online_jar.png) + +### **01 实时数仓** + +时数仓主要是用 Jar 任务,因为模式比较通用,使用 Jar 任务可以通用化的处理大量的数据表同步和计算,甚至做到配置化同步等,我们的实时数仓主要基 Apache Doris 来存储,使用 Flink 来进行清洗计算(目标是存算分离) + +使用 StreamPark 整合其他组件也是非常简单,同时我们也将 Apache Doris 和 Kafka 相关的配置也抽象到了配置文件中,大大提升了我们的开发效率和灵活度。 + +### **02 能力开放** + +数据团队外的其他业务团队也有很多的流处理场景,于是我们将基于 StreamPark 的实时计算平台二次开发后,将以下能力开放全公司业务团队 + +- 业务能力开放:实时数仓上游将所有业务表通过日志采集写入 Kafka,业务团队可基于 Kafka 进行业务相关开发,也可通过实时数仓(Apache Doris)进行 OLAP分析 +- 计算能力开放:将大数据平台的服务器资源开放业务团队使用 +- 解决方案开放:Flink 生态的成熟 Connector、Exactly Once 语义支持,可减少业务团队流处理相关的开发成本及维护成本 + +目前 StreamPark 还不支持多业务组功能,多业务组功能会抽象后贡献社区。 + +![](/blog/dustess/manager.png) + +![](/blog/dustess/task_retrieval.png) + +## **04 未来规划** + +### **01 Flink on K8S** + +目前我司 Flink 任务都运行在 Yarn 上,满足当下需求,但 Flink on kubernetes 有以下优点: + +- **统一运维**。公司统一化运维,有专门的部门运维 K8S +- **CPU 隔离**。K8S Pod 之间 CPU 隔离,实时任务不相互影响,更加稳定 +- **存储计算分离**。Flink 计算资源和状态存储分离,计算资源能够和其他组件资源进行混部,提升机器使用率 +- **弹性扩缩容**。能够弹性扩缩容,更好的节省人力和物力成本 + +目前本人也在整理和落地相关的技术架构及方案,并已在实验环境使用 StreamPark 完成了 Flink on kubernetes 的技术验证,生产落地这一目标由于有 StreamPark 的平台支持,以及社区同学的热心帮心,相信在未来不久就能达成。 + +### **02 流批一体建设** + +个人认为批/流最大的区别在于算子 Task 的调度策略 和 数据在算子间的流转策略: + +- **批处理**上下游算子 Task 存在先后调度(上游Task结束释放资源),数据存在 Shuffle 策略(落地磁盘),缺点是时效性较低且计算无中间状态,但优点是吞吐量大,适合离线超大数据量计算。 +- **流处理**上下游算子 Task 同时拉起(同时占用资源),数据通过网络在节点间流式计算,缺点是吞吐量不足,优点是时效性高及计算有中间状态,适合实时及增量计算场景。 + +如上,个人认为选择**批处理**还是**流处理**,**是数据开发针对不同数据量和不同业务场景的一种调优方式**。但目前由于计算引擎和计算平台会将离线、实时区分,会造成开发及维护的撕裂,成本巨高不下。如果要实现批流一体,要实现以下几个方面: + +- 存储的统一(元数据的统一):支持批及流的写入/读取 +- 计算引擎的统一 :能够使用一套 API 或 SQL 开发离线和实时任务 +- 数据平台的统一 :能够支持实时任务常驻,也能支持离线调度策略 + +关于批流统一这一块,目前也正在调研、整理、感兴趣的小伙伴欢迎一块探讨项目学习。 + +## **05 结束语** + +以上就是 StreamPark 在尘锋信息生产实践的全部分享内容,感谢大家看到这里。写这篇文章的初心是为大家带来一点 StreamPark 的生产实践的经验和参考,并且和 StreamPark 社区的小伙伴们一道,共同建设 StreamPark ,未来也准备会有更多的参与和建设。非常感谢 StreamPark 的开发者们,能够提供这样优秀的产品,足够多的细节都感受到了大家的用心。虽然目前公司生产使用的(1.2.0-release)版本,在任务分组检索,编辑返回跳页等交互体验上还有些许不足,但瑕不掩瑜,相信 StreamPark 会越来越好,**也相信 StreamPark 会推动 Apache Flink 的普及**。最后用 Apache Flink 社区的一句话来作为结束吧:实时即未来! + + + +![](/blog/dustess/author.png) diff --git a/i18n/zh-CN/docusaurus-plugin-content-blog/6-streampark-usercase-joyme.md b/i18n/zh-CN/docusaurus-plugin-content-blog/6-streampark-usercase-joyme.md new file mode 100644 index 000000000..ed4174ced --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-blog/6-streampark-usercase-joyme.md @@ -0,0 +1,161 @@ +--- +slug: streampark-usercase-joyme +title: StreamPark 在 Joyme 的生产实践 +tags: [StreamPark, 生产实践, FlinkSQL] +--- + +
+ +**摘要:** 本文带来 StreamPark 在 Joyme 中的生产实践, 作者是 Joyme 的大数据工程师秦基勇, 主要内容为: + +- 遇见StreamPark +- Flink Sql 作业开发 +- Custom code 作业开发 +- 监控告警 +- 常见问题 +- 社区印象 +- 总结 + +## 1 遇见 StreamPark + +遇见 StreamPark 是必然的,基于我们现有的实时作业开发模式,不得不寻找一个开源的平台来支撑我司的实时业务。我们的现状如下: + +- 编写作业打包到服务器,然后执行 Flink run 命令进行提交,过程繁琐,效率低下 +- Flink Sql 通过自研的老平台提交,老平台开发人员已离职,后续的代码无人维护,即便有人维护也不得不面对维护成本高的问题 +- 其中一部分作者是 SparkStreaming 作业,两套流引擎,框架不统一,开发成本大 +- 实时作业有 Scala 和 Java 开发,语言和技术栈不统一 + +基于以上种种原因,我们需要一个开源平台来管理我们的实时作业,同时我们也需要进行重构,统一开发模式,统一开发语言,将项目集中管理。 + +第一次遇见 StreamPark 就基本确定了,我们根据官网的文档快速进行了部署安装,搭建以后进行了一些操作,界面友好,Flink 多版本支持,权限管理,作业监控等一系列功能已能较好的满足我们的需求,进一步了解到其社区也很活跃,从 1.1.0 版本开始见证了 StreamPark 功能完善的过程,开发团队是非常有追求的,相信会不断的完善。 + +## 2 Flink SQL 作业开发 + +Flink Sql 开发模式带来了很大的便利,对于一些简单的指标开发,只需要简单的 Sql 就可以完成,不需要写一行代码。Flink Sql 方便了很多同学的开发工作,毕竟一些做仓库的同学在编写代码方面还是有些难度。 + +打开 StreamPark 的任务新增界面进行添加新任务,默认 Development Mode 就是 Flink Sql 模式。直接在 Flink Sql 部分编写Sql 逻辑。 + +Flink Sql 部分,按照 Flink 官网的文档逐步编写逻辑 Sql 即可,对于我司来说,一般就三部分: 接入 Source ,中间逻辑处理,最后 Sink。基本上 Source 都是消费 kafka 的数据,逻辑处理层会有关联 MySQL 去做维表查询,最后 Sink 部分大多是 Es,Redis,MySQL。 + +### **1. 编写SQL** + +```sql +-- 连接kafka +CREATE TABLE source_table ( + `Data` ROW +) WITH ( +'connector.type' = 'kafka', +'connector.version' = 'universal', +'connector.topic' = '主题', +'connector.properties.bootstrap.servers'='broker地址', +'connector.startup-mode' = 'latest-offset', +'update-mode' = 'append', +'format.type' = 'json', +'connector.properties.group.id' = '消费组id', +'format.derive-schema' = 'true' +); + +-- 落地表sink +CREATE TABLE sink_table ( +`uid` STRING +) WITH ( +'connector.type' = 'jdbc', +'connector.url' = 'jdbc:mysql://xxx/xxx?useSSL=false', +'connector.username' = 'username', +'connector.password' = 'password', +'connector.table' = 'tablename', +'connector.write.flush.max-rows' = '50', +'connector.write.flush.interval' = '2s', +'connector.write.max-retries' = '3' +); + +-- 代码逻辑过 +INSERT INTO sink_table +SELECT Data.uid FROM source_table; +``` + +### **2. 添加依赖** + +关于依赖这块是 StreamPark 里特有的,在 StreamPark 中创新型的将一个完整的 Flink Sql 任务拆分成两部分组成: Sql 和 依赖, Sql 很好理解不多啰嗦, 依赖是 Sql 里需要用到的一些 Connector 的 Jar, 如 Sql 里用到了 Kafka 和 MySQL 的 Connector, 那就需要引入这两个 Connector 的依赖, 在 StreamPark 中添加依赖两种方式,一种是基于标准的 Maven pom 坐标方式,另一种是从本地上传需要的 Jar 。这两种也可以混着用,按需添加,点击应用即可, 在提交作业的时候就会自动加载这些依赖。 + +![](/blog/joyme/add_dependency.png) + +### **3. 参数配置** + +在任务的添加和修改页面中已经罗列了一些常用的参数设置,更多的参数设置则提供了一个 yaml 配置文件,我们这里只是设置了 checkpoint 和 savepoint 这两个配置。一是 checkpoint 的位置,二是 执行 checkpoint 的频率。其他的配置基本没有动,这部分用户可以根据自己的需要按需配置。 + +剩下的一些参数设置就要根据作业的具体情况去对症下药的配置了,处理的数据量大了,逻辑复杂了,可能就需要更多的内存,并行度给多一些。有时候需要根据作业的运行情况进行多次调整。 + +![](/blog/joyme/checkpoint_configuration.png) + +### **4. 动态参数设置** + +由于我们的模式部署是 on Yarn,在动态选项配置里配置了 Yarn 的队列名称。也有一些配置了开启增量的 Checkpoint 选项和状态过期时间,基本的这些参数都可以从 Flink 的官网去查询到。之前有一些作业确实经常出现内存溢出的问题,加上增量参数和过期参数以后,作业的运行情况好多了。还有就是 Flink Sql 作业设计到状态这种比较大和逻辑复杂的情况下,我个人感觉还是用 Streaming 代码来实现比较好控制一些。 + +- -Dyarn.application.queue= yarn队列名称 +- -Dstate.backend.incremental=true +- -Dtable.exec.state.ttl=过期时间 + +完成配置以后提交,然后在 application 界面进行部署。 + +![](/blog/joyme/application_job.png) + +## 3 Custom Code 作业开发 + +Streaming 作业我们是使用 Flink java 进行开发,将之前 Spark scala,Flink scala,Flink java 的作业进行了重构,然后工程整合到了一起,目的就是为了维护起来方便。Custom code 作业需要提交代码到 Git,然后配置项目: + +![](/blog/joyme/project_configuration.png) + +配置完成以后,根据对应的项目进行编译,也就完成项目的打包环节。这样后面的 Constom code 作业也可以引用。每次需要上线都需要进行编译才可以,否则只能是上次编译的代码。这里有个问题,为了安全,我司的 gitlab 账号密码都是定期更新的。这样就会导致,StreamPark 已经配置好的项目还是之前的密码,结果导致编译时从 git 里拉取项目失败,导致整个编译环节失败,针对这个问题,我们联系到社区,了解到这部分已经在后续的 1.2.1 版本中支持了项目的修改操作。 + +![](/blog/joyme/flink_system.png) + +新建任务,选择 Custom code ,选择 Flink 版本,选择项目以及模块 Jar 包,选择开发的应用模式为 Apache Flink (标准的 Flink 程序),程序主函数入口类,任务的名称。 + +![](/blog/joyme/add_projectconfiguration.png) + +以及任务的并行度,监控的方式等,内存大小根据任务需要进行配置。Program Args 程序的参数则根据程序需要自行定义入口参数,比如:我们统一启动类是 StartJobApp,那么启动作业就需要传入作业的 Full name 告诉启动类要去找哪个类来启动此次任务,也就是一个反射机制,作业配置完成以后同样也是 Submit 提交,然后在 application 界面部署任务。 + +![](/blog/joyme/application_interface.png) + +## 4 监控告警 + +StreamPark 的监控需要在 setting 模块去配置发送邮件的基本信息。 + +![](/blog/joyme/system_setting.png) + +然后在任务里配置重启策略:监控在多久内几次异常,然后是报警还是重启的策略,同时发送报警要发到哪个邮箱。目前我司使用版本是 1.2.1 只支持邮件发送。 + +![](/blog/joyme/email_setting.png) + +当我们的作业出现失败的情况下,就可以接收到报警邮箱。这报警还是很好看的有木有,可以清楚看到我们的哪个作业,什么状态。也可以点击下面的具体地址进行查看。 + +![](/blog/joyme/alarm_eamil.png) + +关于报警这一块目前我们基于 StreamPark 的 t_flink_app 表进行了一个定时任务的开发。为什么要这么做?因为发送邮件这种通知,大部分人可能不会去及时去看。所以我们选择监控每个任务的状态去把对应的监控信息发送我们的飞书报警群,这样可以及时发现问题去解决任务。一个简单的 python 脚本,然后配置了 crontab 去定时执行。 + +## 5 常见问题 + +关于作业的异常问题,我们归纳分析了基本分为这么几种情况: + +### **1. 作业启动失败** + +作业启动失败的问题,就是点击启动运行部署。发现起不来,这时候需要看界面的详情信息的日志。在我们的任务列表中有一个眼睛的按钮,点进去。在start logs 中会找到提交的作业日志信息,点进去查看,如果有明显的提示信息,直接解决就可以了。如果没有,就需要去查看后台部署任务的目录 logs/下面的 streamx.out,打开以后会找到启动失败的日志信息。 + +![](/blog/joyme/start_log.png) + +### **2. 作业运行失败** + +如果是任务已经起来了,但是在运行阶段失败了。这种情况表面看上去和上面的情况一样,实则完全不同,这种情况是已经将任务提交给集群了,但是任务运行不起来,那就是我们的任务自身有问题了。同样可以用上面第一种情况的排查方式打开作业的具体日志,找到任务在 yarn 上运行的信息,根据日志里记录的 yarn 的 tackurl 去 yarn 的日志里查看具体的原因,是 Sql 的 Connector 不存在,还是代码的哪行代码空指针了,都可以看到具体的堆栈信息。有了具体信息,就可以对症下药了。 + +![](/blog/joyme/yarn_log.png) + +## 6 社区印象 + +很多时候我们在 StreamPark 用户群里讨论问题,都会得到社区小伙伴的即时响应。提交的一些 issue 在当下不能解决的,基本也会在下一个版本或者最新的代码分支中进行修复。在群里,我们也看到很多不是社区的小伙伴,也在积极互相帮助去解决问题。群里也有很多其他社区的大佬,很多小伙伴也积极加入了社区的开发工作。整个社区给我的感觉还是很活跃! + +## 7 总结 + +目前我司线上运行 60 个实时作业,Flink sql 与 Custom-code 差不多各一半。后续也会有更多的实时任务进行上线。很多同学都会担心 StreamPark 稳不稳定的问题,就我司根据几个月的生产实践而言,StreamPark 只是一个帮助你开发作业,部署,监控和管理的一个平台。到底稳不稳,还是要看自家的 Hadoop yarn 集群稳不稳定(我们用的onyan模式),其实已经跟 StreamPark关系不大了。还有就是你写的 Flink Sql 或者是代码健不健壮。更多的是这两方面应该是大家要考虑的,这两方面没问题再充分利用 StreamPark 的灵活性才能让作业更好的运行,单从一方面说 StreamPark 稳不稳定,实属偏激。 + +以上就是 StreamPark 在乐我无限的全部分享内容,感谢大家看到这里。非常感谢 StreamPark 提供给我们这么优秀的产品,这就是做的利他人之事。从1.0 到 1.2.1 平时遇到那些bug都会被即时的修复,每一个issue都被认真对待。目前我们还是 onyarn的部署模式,重启yarn还是会导致作业的lost状态,重启yarn也不是天天都干的事,关于这个社区也会尽早的会去修复这个问题。相信 StreamPark 会越来越好,未来可期。 \ No newline at end of file diff --git a/i18n/zh-CN/docusaurus-plugin-content-blog/7-streampark-usercase-haibo.md b/i18n/zh-CN/docusaurus-plugin-content-blog/7-streampark-usercase-haibo.md new file mode 100644 index 000000000..821cacd3f --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-blog/7-streampark-usercase-haibo.md @@ -0,0 +1,101 @@ +--- +slug: streampark-usercase-haibo +title: StreamPark 一站式计算利器在海博科技的生产实践,助力智慧城市建设 +tags: [StreamPark, 生产实践, FlinkSQL] +--- + +# StreamPark 一站式计算利器在海博科技的生产实践,助力智慧城市建设 + +**摘要:**本文「 StreamPark 一站式计算利器在海博科技的生产实践,助力智慧城市建设 」作者是海博科技大数据架构师王庆焕,主要内容为: + +1. 选择 StreamPark +2. 快速上手 +3. 应用场景 +4. 功能扩展 +5. 未来期待 + +海博科技是一家行业领先的人工智能物联网产品和解决方案公司。目前在公共安全、智慧城市、智慧制造领域,为全国客户提供包括算法、软件和硬件产品在内的全栈式整体解决方案。 + +## **01. 选择 StreamPark** + +海博科技自 2020 年开始使用 Flink SQL 汇聚、处理各类实时物联数据。随着各地市智慧城市建设步伐的加快,需要汇聚的各类物联数据的数据种类、数据量也不断增加,导致线上维护的 Flink SQL 任务越来越多,一个专门的能够管理众多 Flink SQL 任务的计算平台成为了迫切的需求。 + +在体验对比了 Apache Zeppelin 和 StreamPark 之后,我们选择了 StreamPark 作为公司的实时计算平台。相比 Apache Zeppelin, StreamPark 并不出名。‍‍‍‍‍‍‍‍‍‍‍‍但是在体验了 StreamPark 发行的初版,阅读其设计文档后,我们发现其基于 **一站式** 设计的思想,能够覆盖 Flink 任务开发的全生命周期,使得配置、开发、部署、运维全部在一个平台即可完成。我们的开发、运维、测试的同学可以使用 StreamPark 协同工作,**低代码** + **一站式** 的设计思想坚定了我们使用 StreamPark 的信心。 + +//视频链接( StreamX 官方闪屏) + + + +## **02. 落地实践** + +### **1. 快速上手** + +使用 StreamPark 完成一个实时汇聚任务就像把大象放进冰箱一样简单,仅需三步即可完成: + +- 编辑 SQL + +![](/blog/haibo/flink_sql.png) + +- 上传依赖包 + +![](/blog/haibo/dependency.png) + +- 部署运行 + +![](/blog/haibo/deploy.png) + +仅需上述三步,即可完成 Mysql 到 Elasticsearch 的汇聚任务,大大提升数据接入效率。 + +### **2. 生产实践** + +StreamPark 在海博主要用于运行实时 Flink SQL任务: 读取 Kafka 上的数据,进行处理输出至 Clickhouse 或者 Elasticsearch 中。 + +从2021年10月开始,公司逐渐将 Flink SQL 任务迁移至 StreamPark 平台来集中管理,承载我司实时物联数据的汇聚、计算、预警。 + +截至目前,StreamPark 已在多个政府、公安生产环境进行部署,汇聚处理城市实时物联数据、人车抓拍数据。以下是在某市专网部署的 StreamPark 平台截图 : + +![](/blog/haibo/application.png) + +## **03. 应用场景** + +#### **1. 实时物联感知数据汇聚** + +汇聚实时的物联感知数据,我们直接使用 StreamPark 开发 Flink SQL 任务,针对 Flink SQL 未提供的方法,StreamPark 也支持 Udf 相关功能,用户通过 StreamPark 上传 Udf 包,即可在 SQL 中调用相关 Udf,实现更多复杂的逻辑操作。 + +“SQL+UDF” 的方式,能够满足我们绝大部分的数据汇聚场景,如果后期业务变动,也只需要在 StreamPark 中修改 SQL 语句,即可完成业务变更与上线。 + +![](/blog/haibo/data_aggregation.png) + +#### **2. Flink CDC数据库同步** + +为了实现各类数据库与数据仓库之前的同步,我们使用 StreamPark 开发 Flink CDC SQL 任务。借助于 Flink CDC 的能力,实现了 Oracle 与 Oracle 之间的数据同步, Mysql/Postgresql 与 Clickhouse 之间的数据同步。 + +![](/blog/haibo/flink_cdc.png) + +**3. 数据分析模型管理** + +针对无法使用 Flink SQL 需要开发 Flink 代码的任务,例如: 实时布控模型、离线数据分析模型,StreamPark 提供了 Custom code 的方式, 允许用户上传可执行的 Flink Jar 包并运行。 + +目前,我们已经将人员,车辆等 20 余类分析模型上传至 StreamPark,交由 StreamPark 管理运行。 + +![](/blog/haibo/data_aggregation.png) + +**综上:** 无论是 Flink SQL 任务还是 Custome code 任务,StreamPark 均提供了很好的支持,满足各种不同的业务场景。 但是 StreamPark 缺少任务调度的能力,如果你需要定期调度任务, StreamPark 目前无法满足。社区成员正在努力开发调度相关的模块,在即将发布的 1.2.3 中 会支持任务调度功能,敬请期待。 + +## **04. 功能扩展** + +Datahub 是 Linkedin 开发的一个元数据管理平台,提供了数据源管理、数据血缘、数据质量检查等功能。海博科技基于 StreamPark 和 Datahub 进行了二次开发,实现了数据表级/字段级的血缘功能。通过数据血缘功能,帮助用户检查 Flink SQL 的字段血缘关系。并将血缘关系保存至Linkedin/Datahub 元数据管理平台。 + +//两个视频链接(基于 StreamX 开发的数据血缘功能) + + + +## **05. 未来期待** + +目前,StreamPark 社区的 Roadmap 显示 StreamPark 1.3.0 将迎来全新的 Workbench 体验、统一的资源管理中心 (JAR/UDF/Connectors 统一管理)、批量任务调度等功能。这也是我们非常期待的几个全新功能。 + +Workbench 将使用全新的工作台式的 SQL 开发风格,选择数据源即可生成 SQL,进一步提升 Flink 任务开发效率。统一的 UDF 资源中心将解决当前每个任务都要上传依赖包的问题。批量任务调度功能将解决当前 StreamPark 无法调度任务的遗憾。 + +下图是 StreamPark 开发者设计的原型图,敬请期待。 + +![](/blog/haibo/data_source.png)