From f29cccf9ddacf2ecf3ea048465b8fc89e290f184 Mon Sep 17 00:00:00 2001 From: lanyuanxiaoyao Date: Tue, 23 May 2023 15:54:11 +0800 Subject: [PATCH] =?UTF-8?q?feature(web):=20=E5=A2=9E=E5=8A=A0=E4=B8=80?= =?UTF-8?q?=E4=B8=AA=E7=9B=B4=E6=8E=A5=E9=80=9A=E8=BF=87=20zookeeper=20?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E8=BF=90=E8=A1=8C=E6=97=B6=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=E7=9A=84=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../entity/zookeeper/ZookeeperNode.java | 50 ++++++++ .../forest/service/ZookeeperService.java | 5 + .../web/controller/RunningController.java | 82 +++++++++++++ .../service/web/entity/ZookeeperNodeVO.java | 114 ++++++++++++++++++ .../resources/static/components/common.js | 10 +- .../static/components/running-tab.js | 57 +++++++++ .../src/main/resources/static/index.html | 2 + .../zookeeper/ZookeeperController.java | 22 +++- 8 files changed, 336 insertions(+), 6 deletions(-) create mode 100644 service-configuration/src/main/java/com/lanyuanxiaoyao/service/configuration/entity/zookeeper/ZookeeperNode.java create mode 100644 service-web/src/main/java/com/lanyuanxiaoyao/service/web/controller/RunningController.java create mode 100644 service-web/src/main/java/com/lanyuanxiaoyao/service/web/entity/ZookeeperNodeVO.java create mode 100644 service-web/src/main/resources/static/components/running-tab.js diff --git a/service-configuration/src/main/java/com/lanyuanxiaoyao/service/configuration/entity/zookeeper/ZookeeperNode.java b/service-configuration/src/main/java/com/lanyuanxiaoyao/service/configuration/entity/zookeeper/ZookeeperNode.java new file mode 100644 index 0000000..be4a74c --- /dev/null +++ b/service-configuration/src/main/java/com/lanyuanxiaoyao/service/configuration/entity/zookeeper/ZookeeperNode.java @@ -0,0 +1,50 @@ +package com.lanyuanxiaoyao.service.configuration.entity.zookeeper; + +/** + * Zookeeper 节点 + * + * @author lanyuanxiaoyao + * @date 2023-05-23 + */ +public class ZookeeperNode { + private String path; + private String label; + private Long createTime; + private Long modifiedTime; + + public ZookeeperNode() { + } + + public ZookeeperNode(String path, String label, Long createTime, Long modifiedTime) { + this.path = path; + this.label = label; + this.createTime = createTime; + this.modifiedTime = modifiedTime; + } + + public String getPath() { + return path; + } + + public String getLabel() { + return label; + } + + public Long getCreateTime() { + return createTime; + } + + public Long getModifiedTime() { + return modifiedTime; + } + + @Override + public String toString() { + return "ZookeeperNode{" + + "path='" + path + '\'' + + ", label='" + label + '\'' + + ", createTime=" + createTime + + ", modifiedTime=" + modifiedTime + + '}'; + } +} diff --git a/service-forest/src/main/java/com/lanyuanxiaoyao/service/forest/service/ZookeeperService.java b/service-forest/src/main/java/com/lanyuanxiaoyao/service/forest/service/ZookeeperService.java index 05bc2d9..2ba107f 100644 --- a/service-forest/src/main/java/com/lanyuanxiaoyao/service/forest/service/ZookeeperService.java +++ b/service-forest/src/main/java/com/lanyuanxiaoyao/service/forest/service/ZookeeperService.java @@ -3,6 +3,8 @@ package com.lanyuanxiaoyao.service.forest.service; import com.dtflys.forest.annotation.BaseRequest; import com.dtflys.forest.annotation.Get; import com.dtflys.forest.annotation.Query; +import com.lanyuanxiaoyao.service.configuration.entity.zookeeper.ZookeeperNode; +import org.eclipse.collections.api.list.ImmutableList; /** * Zookeeper 查询 @@ -20,4 +22,7 @@ public interface ZookeeperService { @Get("/get_data") String getData(@Query("path") String path); + + @Get("/get_children") + ImmutableList getChildren(@Query("path") String path); } diff --git a/service-web/src/main/java/com/lanyuanxiaoyao/service/web/controller/RunningController.java b/service-web/src/main/java/com/lanyuanxiaoyao/service/web/controller/RunningController.java new file mode 100644 index 0000000..1f53fd1 --- /dev/null +++ b/service-web/src/main/java/com/lanyuanxiaoyao/service/web/controller/RunningController.java @@ -0,0 +1,82 @@ +package com.lanyuanxiaoyao.service.web.controller; + +import com.eshore.odcp.hudi.connector.entity.RunMeta; +import com.eshore.odcp.hudi.connector.utils.NameHelper; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.lanyuanxiaoyao.service.configuration.entity.AmisResponse; +import com.lanyuanxiaoyao.service.forest.service.ZookeeperService; +import com.lanyuanxiaoyao.service.web.entity.ZookeeperNodeVO; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +/** + * 运行时监控 + * + * @author lanyuanxiaoyao + * @date 2023-05-23 + */ +@RestController +@RequestMapping("running") +public class RunningController extends BaseController { + private static final Logger logger = LoggerFactory.getLogger(RunningController.class); + private static final ExecutorService EXECUTOR = Executors.newWorkStealingPool(20); + + private final ZookeeperService zookeeperService; + private final ObjectMapper mapper; + + @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") + public RunningController(ZookeeperService zookeeperService, Jackson2ObjectMapperBuilder builder) { + this.zookeeperService = zookeeperService; + this.mapper = builder.build(); + } + + @GetMapping("sync") + public AmisResponse sync() { + return responseCrudData( + zookeeperService.getChildren(NameHelper.ZK_SYNC_RUNNING_LOCK_PATH) + .asParallel(EXECUTOR, 1) + .collect(node -> { + RunMeta.SyncRunMeta meta = null; + try { + String data = zookeeperService.getData(node.getPath()); + meta = mapper.readValue(data, RunMeta.SyncRunMeta.class); + } catch (JsonProcessingException e) { + logger.warn("Json parse failure for" + node.getPath(), e); + } + return new ZookeeperNodeVO(node, meta); + }) + .toSortedListBy(ZookeeperNodeVO::getCreateTime) + .toReversed() + .toImmutable() + ); + } + + @GetMapping("compaction") + public AmisResponse compaction() { + return responseCrudData( + zookeeperService.getChildren(NameHelper.ZK_COMPACTION_RUNNING_LOCK_PATH) + .asParallel(EXECUTOR, 1) + .collect(node -> { + RunMeta.CompactionRunMeta meta = null; + try { + String data = zookeeperService.getData(node.getPath()); + meta = mapper.readValue(data, RunMeta.CompactionRunMeta.class); + } catch (JsonProcessingException e) { + logger.warn("Json parse failure for" + node.getPath(), e); + } + return new ZookeeperNodeVO(node, meta); + }) + .toSortedListBy(ZookeeperNodeVO::getCreateTime) + .toReversed() + .toImmutable() + ); + } +} diff --git a/service-web/src/main/java/com/lanyuanxiaoyao/service/web/entity/ZookeeperNodeVO.java b/service-web/src/main/java/com/lanyuanxiaoyao/service/web/entity/ZookeeperNodeVO.java new file mode 100644 index 0000000..1f95bd2 --- /dev/null +++ b/service-web/src/main/java/com/lanyuanxiaoyao/service/web/entity/ZookeeperNodeVO.java @@ -0,0 +1,114 @@ +package com.lanyuanxiaoyao.service.web.entity; + +import cn.hutool.core.util.ObjectUtil; +import com.eshore.odcp.hudi.connector.entity.RunMeta; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.lanyuanxiaoyao.service.configuration.entity.zookeeper.ZookeeperNode; +import com.lanyuanxiaoyao.service.web.utils.DatetimeUtil; + +import java.time.Instant; +import java.util.Optional; + +/** + * Zookeeper 节点 + * + * @author lanyuanxiaoyao + * @date 2023-05-23 + */ +public class ZookeeperNodeVO { + @JsonIgnore + private final ZookeeperNode node; + private final RunMeta runMeta; + private String createTimeFromNow; + private String modifiedTimeFromNow; + + public ZookeeperNodeVO(ZookeeperNode node, RunMeta runMeta) { + this.node = node; + this.runMeta = runMeta; + + long now = Instant.now().toEpochMilli(); + if (ObjectUtil.isNotNull(node.getCreateTime()) && node.getCreateTime() != 0) { + this.createTimeFromNow = DatetimeUtil.fromNow(now, node.getCreateTime()); + } + if (ObjectUtil.isNotNull(node.getModifiedTime()) && node.getModifiedTime() != 0) { + this.modifiedTimeFromNow = DatetimeUtil.fromNow(now, node.getModifiedTime()); + } + } + + public String getPath() { + return node.getPath(); + } + + public String getLabel() { + return node.getLabel(); + } + + public Long getCreateTime() { + return node.getCreateTime(); + } + + public Long getModifiedTime() { + return node.getModifiedTime(); + } + + public String getCluster() { + return Optional.of(runMeta).map(RunMeta::getCluster).orElse(null); + } + + public String getFlinkJobId() { + return Optional.of(runMeta).map(RunMeta::getFlinkJobId).orElse(null); + } + + public String getFlinkJobName() { + return Optional.of(runMeta).map(RunMeta::getFlinkJobName).orElse(null); + } + + public String getHost() { + return Optional.of(runMeta).map(RunMeta::getHost).orElse(null); + } + + public String getApplicationId() { + return Optional.of(runMeta).map(RunMeta::getApplicationId).orElse(null); + } + + public String getContainerId() { + return Optional.of(runMeta).map(RunMeta::getContainerId).orElse(null); + } + + public String getContainerPath() { + return Optional.of(runMeta).map(RunMeta::getContainerPath).orElse(null); + } + + public String getRunType() { + return Optional.of(runMeta).map(RunMeta::getRunType).orElse(null); + } + + public String getExecutorVersion() { + return Optional.of(runMeta).map(RunMeta::getExecutorVersion).orElse(null); + } + + public String getJvmPid() { + return Optional.of(runMeta).map(RunMeta::getJvmPid).orElse(null); + } + + public String getApplicationProxy() { + return Optional.of(runMeta).map(RunMeta::getApplicationProxy).orElse(null); + } + + public String getCreateTimeFromNow() { + return createTimeFromNow; + } + + public String getModifiedTimeFromNow() { + return modifiedTimeFromNow; + } + + @Override + public String toString() { + return "ZookeeperNodeVO{" + + "node=" + node + + ", createTimeFormNow='" + createTimeFromNow + '\'' + + ", modifiedTimeFormNow='" + modifiedTimeFromNow + '\'' + + '}'; + } +} diff --git a/service-web/src/main/resources/static/components/common.js b/service-web/src/main/resources/static/components/common.js index 36bc15b..fd4c784 100644 --- a/service-web/src/main/resources/static/components/common.js +++ b/service-web/src/main/resources/static/components/common.js @@ -1,9 +1,9 @@ -function timeAndFrom(field, fromNow, emptyText) { - if (!emptyText) { - emptyText = '未停止' +function timeAndFrom(field, fromNow, emptyText = '未停止', showSource = true) { + let tpl = "${" + fromNow + "}" + if (showSource) { + tpl = tpl + "
${IF(" + field + " === 0, '(" + emptyText + ")', CONCATENATE('(',DATETOSTR(DATE(" + field + ")),')'))}" } - // language=TEXT - return "${" + fromNow + "}
${IF(" + field + " === 0, '(" + emptyText + ")', CONCATENATE('(',DATETOSTR(DATE(" + field + ")),')'))}" + return tpl } function yarnCrudColumns() { diff --git a/service-web/src/main/resources/static/components/running-tab.js b/service-web/src/main/resources/static/components/running-tab.js new file mode 100644 index 0000000..00f06f3 --- /dev/null +++ b/service-web/src/main/resources/static/components/running-tab.js @@ -0,0 +1,57 @@ +function runningTable(name) { + return { + type: 'table', + title: `${name}`, + itemAction: { + type: 'button', + actionType: 'dialog', + dialog: { + title: 'Path', + body: '${path}', + actions: [], + } + }, + columns: [ + {name: 'label', label: '名称'}, + { + name: 'createTime', + label: '创建时间', + type: 'tpl', + tpl: timeAndFrom('createTime', 'createTimeFromNow', undefined, false), + align: 'center', + width: 70, + }, + ] + } +} + +function runningTab() { + return { + title: '运行中', + tab: [ + { + type: 'grid', + columns: [ + { + body: [ + { + type: 'service', + api: '${base}/running/sync', + body: runningTable('同步') + } + ] + }, + { + body: [ + { + type: 'service', + api: '${base}/running/compaction', + body: runningTable('压缩') + } + ] + } + ] + } + ], + } +} \ No newline at end of file diff --git a/service-web/src/main/resources/static/index.html b/service-web/src/main/resources/static/index.html index 5c183ea..bd38247 100644 --- a/service-web/src/main/resources/static/index.html +++ b/service-web/src/main/resources/static/index.html @@ -39,6 +39,7 @@ +