Apache/InLong InLong Manager 支持配置 Flink 任务并发度/Adjust sort resources according to data scale心得和随笔

audit已经实现了对于InLong系统的Agent、DataProxy、Sort模块的入流量、出流量进行实时审计对账。 对账的粒度有分钟、小时、天三种粒度。

1. audit的数据缓存在org.apache.inlong.audit.cache的各个类中,有DayCache HalfHourCache等等

2. 调用api的方式

请求audit数据的api在org.apache.inlong.audit.config.OpenApiConstants中,通过org.apache.inlong.audit.service.ApiService来调用。调用的时候注意参数的合法性,有合法性检查,以免请求不到数据。居然没有用controller,挺神奇的,贴一段代码上来,便于以后研究

private void initHttpServer() {

点击查看代码
 private void initHttpServer() {
        int bindPort = Configuration.getInstance().get(KEY_HTTP_SERVER_BIND_PORT, DEFAULT_HTTP_SERVER_BIND_PORT);
        try {
            HttpServer server = HttpServer.create(new InetSocketAddress(bindPort),
                    Configuration.getInstance().get(KEY_API_BACKLOG_SIZE, DEFAULT_API_BACKLOG_SIZE));
            server.setExecutor(Executors.newFixedThreadPool(
                    Configuration.getInstance().get(KEY_API_THREAD_POOL_SIZE, DEFAULT_API_THREAD_POOL_SIZE)));
            server.createContext(Configuration.getInstance().get(KEY_API_DAY_PATH, DEFAULT_API_DAY_PATH),
                    new AuditHandler(DAY));
            server.createContext(Configuration.getInstance().get(KEY_API_HOUR_PATH, DEFAULT_API_HOUR_PATH),
                    new AuditHandler(HOUR));
            server.createContext(Configuration.getInstance().get(KEY_API_MINUTES_PATH, DEFAULT_API_MINUTES_PATH),
........省略类似的方法.........
            server.start();
            LOGGER.info("Init http server success. Bind port is: {}", bindPort);
        } catch (Exception e) {
            LOGGER.error("Init http server has exception!", e);
        }
    }

3. 请求方法样例,查询分钟数据

http://172.28.128.1:10080/audit/query/minutes?startTime=2024-07-01T00:00:00&endTime=2024-07-06T23:59:59&inlongGroupId=test_pulsar_group&inlongStreamId=test_pulsar_stream&auditId=1073741825&auditCycle=1
注意填写ipconfig中的地址,不是wsl中ifconfig的地址
注意!一定要启动inlong/manager和mysql,否则前者导致获取不到配置文件,后者导致获取不到数据

以太网适配器 vEthernet (WSL (Hyper-V firewall)):

   连接特定的 DNS 后缀 . . . . . . . :
   本地链接 IPv6 地址. . . . . . . . : fe80::15f7:1f2:8c88:287b%64
   IPv4 地址 . . . . . . . . . . . . : 172.28.128.1
   子网掩码  . . . . . . . . . . . . : 255.255.240.0
   默认网关. . . . . . . . . . . . . :

返回

点击查看代码
{
    "success": true,
    "errMsg": "",
    "data": [
        {
            "auditVersion": 0,
            "logTs": "2024-07-06 22:16:00",
            "inlongGroupId": "test_pulsar_group",
            "inlongStreamId": "test_pulsar_stream",
            "auditId": "1073741825",
            "auditTag": "-1",
            "count": 10000,
            "size": 157788,
            "delay": 0
        }
    ]
}

4. audit如何处理MySQL中的审计数据

audit会把从MQ中查询到的数据放入数据库(默认MySQL),然后进行缓存。在org.apache.inlong.audit.service.EtlService中,调用
mysqlToHalfHourCache等方法,

点击查看代码
private void mysqlToHalfHourCache() {
        DataQueue dataQueue = new DataQueue(queueSize);
        mysqlSourceOfHalfHourCache =
                new JdbcSource(dataQueue, buildMysqlSourceConfig(AuditCycle.MINUTE_30, statBackTimes));
        mysqlSourceOfHalfHourCache.start();

        cacheSinkOfHalfHourCache = new CacheSink(dataQueue, HalfHourCache.getInstance().getCache());
        cacheSinkOfHalfHourCache.start();


        DataQueue dataQueue = new DataQueue(queueSize);
        mysqlSourceOfHalfHourCache =
                new JdbcSource(dataQueue, buildMysqlSourceConfig(AuditCycle.MINUTE_30, statBackTimes));
        mysqlSourceOfHalfHourCache.start();

        cacheSinkOfHalfHourCache = new CacheSink(dataQueue, HalfHourCache.getInstance().getCache());
        cacheSinkOfHalfHourCache.start();
    }

实现方法的考虑

从manager中进行parallelism的调控,从flinkInfo中的inlongStreamInfoList中获取streamID inlongGroupId
然后通过分钟级接口进行查询,获得size和count,用于data scale 的计算

注意,单独编译子模块的时候,由于是1.13.0-SNAPSHOT开发分支,需要设置../pom.xml,以免跑到远程仓库找镜像然后找不到导致编译失败

maven生命周期的整理

清理声明周期(Clean Lifecycle):

clean:清理项目构建产生的临时文件和目录。

默认声明周期(Default Lifecycle):

validate:验证项目是否正确且所有必要信息可用。
compile:编译项目的源代码。
test:运行测试代码。
package:将编译后的代码打包成可分发的格式,如 JAR。
verify:对打包的代码进行额外的检验,以确保质量。
install:将打包的代码安装到本地 Maven 仓库,供其他项目使用。
deploy:将打包的代码部署到远程仓库,供其他开发人员和项目使用。

关于编译

docker太强了,可以搭建独立的编译环境,甚至可以通过

cd /mnt/c/Users/zhang/Desktop/ApacheInLong/inlong
docker run -v `pwd`:/inlong -w /inlong maven:3.6-openjdk-8 mvn clean install -DskipTests

使用maven:3.6-openjdk-8镜像启动一个Docker容器,并将当前目录(即项目目录)挂载到容器的/inlong目录中。然后,在容器中执行mvn clean install -DskipTests命令来编译项目。完成上述步骤后,Docker容器将使用Maven编译项目,并根据指定的参数进行构建。编译生成的结果将存储在项目目录中,可以在Windows宿主机上访问和使用。完美地解决了我的maven各种奇怪的依赖/路径/环境问题!成为docker忠实粉丝。

使用docker编译inlong出现了问题,docker命令是

docker run -v pwd:/inlong  -w /inlong maven:3.6-openjdk-8 mvn clean install -DskipTests

,问题是

[ERROR] Failed to execute goal org.codehaus.mojo:exec-maven-plugin:1.6.0:exec (version) on project tubemq-server: Command execution failed.: Cannot run program "/inlong/inlong-tubemq/tubemq-server/src/saveServerVersion.sh" (in directory "/inlong/inlong-tubemq/tubemq-server"): error=13, Permission denied -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException
[ERROR]
[ERROR] After correcting the problems, you can resume the build with the command
[ERROR]   mvn <args> -rf :tubemq-server

解决方法:这个问题是由于Docker容器内的权限问题导致的。默认情况下,Docker容器中的文件可能没有执行权限。要解决这个问题,可以在运行Docker容器之前,确保脚本文件具有执行权限。修改Docker命令,使其在执行Maven构建之前,先授予脚本执行权限。

docker run -v `pwd`:/inlong -w /inlong maven:3.6-openjdk-8 bash -c "chmod +x /inlong/inlong-tubemq/tubemq-server/src/saveServerVersion.sh && mvn clean install -DskipTests"

Q:为啥即使我用docker run -v pwd:/inlong -w /inlong maven:3.6-openjdk-8 bash -c "chmod +x /inlong/inlong-tubemq/tubemq-server/src/saveServerVersion.sh && mvn compile -DskipTests",这docker每次启动都会检查和安装依赖?

A:Docker 每次启动都会检查和安装依赖的原因是因为 Docker 容器是无状态的,并且每次运行都会创建一个新的容器实例。为了避免每次启动时都重新安装依赖,可以使用以下方法: 1. 使用 Dockerfile 创建一个自定义镜像 2. 使用 Docker Compose 3. 持久化 Maven 依赖缓存 由于每次都重新下载依赖时间太久了,考虑自己搞个maven:3.6-openjdk-8的镜像,但是带inlong的所有依赖
Q:Docker是无状态的,那为啥MySQL docker可以保存数据? A: Docker 容器本身是无状态的,这意味着当容器停止或删除后,其内部的所有数据都会丢失。然而,通过使用卷(Volumes),Docker 可以实现数据的持久化,从而保存状态。

Docker Volumes
Docker 卷是一种特殊的目录,可以将主机上的目录挂载到 Docker 容器中,使得容器中的数据可以在容器重启、删除或重建后依然保留。这就是为什么 Docker 中的 MySQL 容器可以保存数据的原因。
考虑下列命令:
docker run --name my-mysql -e MYSQL_ROOT_PASSWORD=root -v /my/local/data:/var/lib/mysql -d mysql:5.7
-v /my/local/data:/var/lib/mysql 将主机上的 /my/local/data 目录挂载到容器中的/var/lib/mysql目录。MySQL 的数据存储在 /var/lib/mysql 目录下,因此这确保了数据在容器重启或删除后仍然保存在主机上的 /my/local/data 目录中。

小事故:本来想挂载docker到windows目录的,但是挂载了之后发现读取不到文件,估计是没有权限(后来发现可能路径没有加/mnt/),而且官方不推荐,就不用了
2024.7.15 更正,别瞎搞,要挂载windows目录很简单,只需要用windows的目录完全照搬就可以了。发现了一个很有趣的问题,就是/mnt/c格式的指令要在linux wsl terminal中执行,windows格式的目录要在windows powershell中执行,需要注意
也就是说用
docker run -v D:\develop\ApacheInLong\inlong:/inlong -v D:\UserProgram\mavenRepo:/root/.m2/repository -w /inlong maven:3.6-openjdk-8 mvn clean install -DskipTests编译
启动docker:

docker run --name maven-inlong-official -it \
  --privileged \
  -v /home/peterzh/osp/inlong-dev/inlong:/inlong \
  -v /usr/share/maven-repo:/root/.m2/repository \
  -w /inlong \
  maven:3.6-openjdk-8 bash
 编译的时候有个脚本执行没权限,先赋予执行权限,否则会失败
chmod 700 inlong-tubemq/tubemq-client/src/saveServerVersion.sh 

已经启动的没法挂载
已经在运行的容器
docker exec
启动一个已经创建的容器
docker start

考虑到开发的便捷性,感觉还是idea或者vscod连接到wsl,直接操作比较好,写完了可以直接编译,windows环境怎么都配不好xs

2024.7.15
之前一直在研究auditid是什么鬼东西,本来都要问doleyzi了,结果发现auditUtil里面有一大堆自己定义的常量。因为用buildaudit没法生成正确的auditid。比如
AUDIT_ID_AGENT_TASK_HEARTBEAT = 1073741839;
位于inlong-agent/agent-common/src/main/java/org/apache/inlong/agent/metrics/audit/AuditUtils.java
看来连伟大的钒哥也没有记得inlong的所有实现,这说明了维护大型项目的解耦的重要作用。

如果用

docker run -v /home/peterzh/inlong:/inlong -v /usr/share/maven-repo:/root/.m2/repository -w /inlong maven:3.6-openjdk-8 bash

启动docker的话会出现瞬间自动关闭的问题,如果你只是运行 bash,它会启动一个非交互式 shell,然后立即退出。为了保持容器的运行,你需要启动一个交互式 shell。

docker run --name maven -it -v /home/peterzh/inlong:/inlong -v /usr/share/maven-repo:/root/.m2/repository -w /inlong maven:3.6-openjdk-8 bash 

同时,如果用

docker run -v /home/peterzh/inlong:/inlong -v /usr/share/maven-repo:/root/.m2/repository -w /inlong maven:3.6-openjdk-8 bash -c "chmod +x inlong-tubemq/tubemq-server/src/saveServerVersion.sh && mvn clean install -DskipTests"

那么docker每次启动都会自动执行

chmod +x inlong-tubemq/tubemq-server/src/saveServerVersion.sh && mvn clean install -DskipTests

,这不好。docker还是要多研究

7.16
学习到了测试自己的代码可以把编译好的jar包放到docker-compose up生成的container的里面,替换原来的lilb就可以测试了,不用自己搭环境,非常好!

使用docker编译的时候,遇到了test,里面需要再启动docker,

Caused by: org.testcontainers.containers.ContainerFetchException: Can't get Docker image: RemoteDockerImage(imageName=elasticsearch:7.9.3, imagePullPolicy=DefaultPullPolicy(), imageNameSubstitutor=org.testcontainers.utility.ImageNameSubstitutor$LogWrappedImageNameSubstitutor@fffb4a8)
Caused by: java.lang.IllegalStateException: Could not find a valid Docker environment. Please see logs and check configuration

可能的解决方法:

挂载 Docker 套接字:
在运行构建容器时,通常需要将宿主机的 Docker 套接字挂载到容器中。这允许容器内的进程使用宿主机的 Docker 守护进程来启动新的 Docker 容器。例如:

bash
复制代码
docker run -v /var/run/docker.sock:/var/run/docker.sock ...
使用合适的 Docker 镜像:
构建用于测试的 Docker 容器时,使用已安装 Docker 的镜像,例如 docker:dind 镜像,这样容器内部就自带了 Docker 环境。

2024.7.18
终于跑起来了,发现是我傻掉了home\peterzh\inlong\inlong-distribution\target\apache-inlong-1.13.0-SNAPSHOT-bin\apache-inlong-1.13.0-SNAPSHOT\inlong-manager,居然只把lib拷贝到了docker里面,一直提示flinkservice holder没有定义,我以为真的没有定义,结果一看发现是flinkservice的东西都在plugins里面,怪不得我看见我定义在sort properties的maxpercore也是nullpointerexception。看来即使是大佬说的话也要思考xs。
自用复制文件到docker的命令

 docker cp /home/peterzh/inlong/inlong-distribution/target/apache-inlong-1.13.0-SNAPSHOT-bin/apache-inlong-1.13.0-SNAPSHOT/inlong-manager/ manager:/tmp/all
cp -r /tmp/all/. /opt/inlong-manager/

注意到docker中用.表示所有文件(可能)

2024.7.18
发现了一些问题,dataproxy的ip似乎由manager写死在inlong_cluster_node中了,但是docker会动态分配ip,导致没法找到合适的ip,所以agent发送失败。所以我有的时候会发送成功,有的时候不成功,因为agent是通过ip和proxy交互的,而不是域名

2024.7.22
还是基本功不行,悲
又忘记了docker重启之后只要不是volume都会被重置。
发现了用环境变量logging.level.root=DEBUG可以覆盖配置文件中的相关环境变量,终于用上DEBUG版的manager了
试了commit,生成新的dockerimage,似乎不能成功保存配置文件

2024.8.10
dashboard,数据流中点击执行工作流,flink web dashboard会出现新的job
http://localhost:8081/#/overview

使用自定义docker网络定义每个容器的ip可以有效防止重启容器之后容器之间无法通讯的情况
具体问题为telnet 127.0.0.1 46801会显示拒绝访问,不知道为什么
以下是参考的配置文件,pulsar经常会卡死,换用了kafka,配了kafka magic方便监控
clickhouse也配进来了,省的每次都重启,而且配网络也麻烦

点击查看代码
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License.  You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
version: '2.4'

networks:
  custom_network:
    driver: bridge
    ipam:
      config:
        - subnet: 172.18.0.0/16

services:
  mysql:
    image: mysql:8.0.28
    container_name: mysql
    platform: "linux/x86_64"
    ports:
      - "3306:3306"
    environment:
      - MYSQL_ROOT_PASSWORD=inlong
    healthcheck:
      test: "/usr/bin/mysql --user=root --password=inlong --execute \"SHOW DATABASES;\""
      timeout: 20s
      interval: 2s
      retries: 10
    volumes:
      - ./mysql:/var/lib/mysql
      - ./sql:/docker-entrypoint-initdb.d
    command: --authentication_policy=mysql_native_password
    networks:
      custom_network:
        ipv4_address: 172.18.0.2

  zookeeper:
    image: wurstmeister/zookeeper
    container_name: zookeeper
    ports:
      - 2181:2181
    networks:
      custom_network:
        ipv4_address: 172.18.0.3

  kafka:
    image: wurstmeister/kafka
    ports:
      - "9092:9092"
    environment:
      - KAFKA_BROKER_ID=0
      - KAFKA_ZOOKEEPER_CONNECT=zookeeper:2181
      - KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://kafka:9092
      - KAFKA_LISTENERS=PLAINTEXT://0.0.0.0:9092
    depends_on:
      - zookeeper
    networks:
      custom_network:
        ipv4_address: 172.18.0.4
  
  kafkamagic:
    image: digitsy/kafka-magic
    container_name: kafkamagic
    ports:
      - "8080:80"
    environment:
      - KAFKA_HOST=kafka
      - KAFKA_PORT=9092
      - KMAGIC_ALLOW_TOPIC_DELETE="true"
      - KMAGIC_ALLOW_SCHEMA_DELETE="true"
    depends_on:
      - kafka
    volumes:
      - .:/config
    networks:
      custom_network:
        ipv4_address: 172.18.0.5

  manager:
    image: inlong/manager:${VERSION_TAG}
    container_name: manager
    depends_on:
      mysql:
        condition: service_healthy
    ports:
      - "8083:8083"
    environment:
      - JDBC_URL=mysql:3306
      - USERNAME=root
      - PASSWORD=inlong
      - ZK_URL=tubemq-server:2181
      - FLINK_HOST=jobmanager
      - FLINK_PORT=8081
      - AUDIT_QUERY_URL=http://audit:10080
    networks:
      custom_network:
        ipv4_address: 172.18.0.6

  dashboard:
    image: inlong/dashboard:${VERSION_TAG}
    container_name: dashboard
    depends_on:
      - manager
    ports:
      - "80:80"
    environment:
      - MANAGER_API_ADDRESS=manager:8083
    networks:
      custom_network:
        ipv4_address: 172.18.0.7

  dataproxy:
    image: inlong/dataproxy:${VERSION_TAG}
    container_name: dataproxy
    depends_on:
      - manager
    ports:
      - "46801:46801"
      - "46802:46802"
    environment:
      - MANAGER_OPENAPI_IP=manager
      - MANAGER_OPENAPI_PORT=8083
      # pulsar or kafka
      - MQ_TYPE=kafka
      - ETH_NAME=eth0
    networks:
      custom_network:
        ipv4_address: 172.18.0.8

  agent:
    image: inlong/agent:${VERSION_TAG}
    container_name: agent
    depends_on:
      - manager
      - dataproxy
    environment:
      - MANAGER_OPENAPI_IP=manager
      - MANAGER_OPENAPI_PORT=8083
      - DATAPROXY_IP=dataproxy
      - DATAPROXY_PORT=46801
    volumes:
      - ./collect-data:/data/collect-data
    networks:
      custom_network:
        ipv4_address: 172.18.0.9

  audit:
    image: inlong/audit:${VERSION_TAG}
    container_name: audit
    privileged: true
    depends_on:
      mysql:
        condition: service_healthy
    environment:
      - AUDIT_JDBC_URL=mysql:3306
      - AUDIT_JDBC_USERNAME=root
      - AUDIT_JDBC_PASSWORD=inlong
      - MANAGER_OPENAPI_IP=manager
      - MANAGER_OPENAPI_PORT=8083
      - AUDIT_PROXY_ADDRESS=audit:10081
      # pulsar or kafka
      - MQ_TYPE=kafka
    ports:
      - "10080:10080"
      - "10081:10081"
    networks:
      custom_network:
        ipv4_address: 172.18.0.10

  jobmanager:
    image: apache/flink:1.15-scala_2.12
    container_name: jobmanager
    environment:
      - |
        FLINK_PROPERTIES=
        jobmanager.rpc.address: jobmanager
    ports:
      - "8081:8081"
    command: jobmanager
    networks:
      custom_network:
        ipv4_address: 172.18.0.11

  taskmanager:
    image: apache/flink:1.15-scala_2.12
    container_name: taskmanager
    environment:
      - |
        FLINK_PROPERTIES=
        jobmanager.rpc.address: jobmanager
        taskmanager.numberOfTaskSlots: 2
    command: taskmanager
    networks:
      custom_network:
        ipv4_address: 172.18.0.12

  clickhouse:
    image: clickhouse/clickhouse-server:22.8
    container_name: clickhouse
    environment:
      - CLICKHOUSE_USER=admin
      - CLICKHOUSE_PASSWORD=inlong
      - CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT=1
    ports: 
      - "8123:8123"
    networks:
      custom_network:
        ipv4_address: 172.18.0.13

当使用windows terminal和wsl的terminal启动docker时,对于docker-compose.yml没有linux语法的时候,没有区别,但是如果有的话,比如\(PWD,就会有区别,挂载volume路径包含\)PWD的话一定要用linux terminal

8.11
发现mysql->clickhouse数据同步的官网文档有点问题,
image
这里用的是test.source_table,多了个schema,其实只要source_table就行,因为库名已经指定了,否则会出现表名变成test.test.source_table的问题,导致没法找到source
image

8.23
碰到了audit url的@value注解注入失败的情况,在 FlinkService 中手动使用 new 关键字创建 FlinkParallelismOptimizer 实例,而不是通过 Spring 的依赖注入机制来管理这个对象,确实会导致 @Value 注解无法注入属性。这是因为 @Value 注解依赖于 Spring 的依赖注入容器,如果对象不是由 Spring 管理的,Spring 将无法注入配置值。

使用ApplicationContext手动管理spring context,可以解决问题

package org.apache.inlong.manager.plugin.util;

import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

/**
* Get the ApplicationContext
 */
@Component
public class ApplicationContextProvider implements ApplicationContextAware {

    private static ApplicationContext context;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        context = applicationContext;
    }

    public static ApplicationContext getContext() {
        return context;
    }
}

然后在需要使用的地方,使用

FlinkParallelismOptimizer flinkParallelismOptimizer = ApplicationContextProvider.getContext().getBean(FlinkParallelismOptimizer.class);

就可以在不被Spring管理的类中注入spring管理的类了

2024.8.31
经历了32个comment之后,终于合并了,感动
谨此纪念
https://github.com/apache/inlong/pull/10916

posted @ 2024-07-07 11:00  peterzh6  阅读(28)  评论(0编辑  收藏  举报