diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..651a9d95 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,51 @@ +--- +name: 报告Bug +about: 报告KnowStreaming的相关Bug +title: '' +labels: bug +assignees: '' + +--- + +- [ ] 我已经在 [issues](https://github.com/didi/KnowStreaming/issues) 搜索过相关问题了,并没有重复的。 + + 你是否希望来认领这个Bug。 + + 「 Y / N 」 + +### 环境信息 + +* KnowStreaming version : xxx +* Operating System version : xxx +* Java version : xxx + + +### 重现该问题的步骤 + +1. xxx + + + +2. xxx + + +3. xxx + + + +### 预期结果 + + + +### 实际结果 + + + + +--- + +如果有异常,请附上异常Trace: + +``` +Just put your stack trace here! +``` diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..3bedae4a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: true +contact_links: + - name: 讨论问题 + url: https://github.com/didi/KnowStreaming/discussions/new + about: 发起问题、讨论 等等 + - name: KnowStreaming官网 + url: https://knowstreaming.com/ + about: KnowStreaming website diff --git a/.github/ISSUE_TEMPLATE/detail_optimizing.md b/.github/ISSUE_TEMPLATE/detail_optimizing.md new file mode 100644 index 00000000..bbf168f1 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/detail_optimizing.md @@ -0,0 +1,26 @@ +--- +name: 优化建议 +about: 相关功能优化建议 +title: '' +labels: Optimization Suggestions +assignees: '' + +--- + +- [ ] 我已经在 [issues](https://github.com/didi/KnowStreaming/issues) 搜索过相关问题了,并没有重复的。 + + 你是否希望来认领这个优化建议。 + + 「 Y / N 」 + +### 环境信息 + +* KnowStreaming version : xxx +* Operating System version : xxx +* Java version : xxx + +### 需要优化的功能点 + + +### 建议如何优化 + diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000..7bfc5d9b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: 提议新功能/需求 +about: 给KnowStreaming提一个功能需求 +title: '' +labels: feature +assignees: '' + +--- + +- [ ] 我在 [issues](https://github.com/didi/KnowStreaming/issues) 中并未搜索到与此相关的功能需求。 +- [ ] 我在 [release note](https://github.com/didi/KnowStreaming/releases) 已经发布的版本中并没有搜到相关功能. + +你是否希望来认领这个Feature。 + +「 Y / N 」 + + +## 这里描述需求 + + diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md new file mode 100644 index 00000000..e9bf5c05 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/question.md @@ -0,0 +1,12 @@ +--- +name: 提个问题 +about: 问KnowStreaming相关问题 +title: '' +labels: question +assignees: '' + +--- + +- [ ] 我已经在 [issues](https://github.com/didi/KnowStreaming/issues) 搜索过相关问题了,并没有重复的。 + +## 在这里提出你的问题 diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..9ca3226e --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,22 @@ +请不要在没有先创建Issue的情况下创建Pull Request。 + +## 变更的目的是什么 + +XXXXX + +## 简短的更新日志 + +XX + +## 验证这一变化 + +XXXX + +请遵循此清单,以帮助我们快速轻松地整合您的贡献: + +* [ ] 确保有针对更改提交的 Github issue(通常在您开始处理之前)。诸如拼写错误之类的琐碎更改不需要 Github issue。您的Pull Request应该只解决这个问题,而不需要进行其他更改—— 一个 PR 解决一个问题。 +* [ ] 格式化 Pull Request 标题,如[ISSUE #123] support Confluent Schema Registry。 Pull Request 中的每个提交都应该有一个有意义的主题行和正文。 +* [ ] 编写足够详细的Pull Request描述,以了解Pull Request的作用、方式和原因。 +* [ ] 编写必要的单元测试来验证您的逻辑更正。如果提交了新功能或重大更改,请记住在test 模块中添加 integration-test +* [ ] 确保编译通过,集成测试通过 + diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..a70c8889 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,74 @@ + +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +education, socio-economic status, nationality, personal appearance, race, +religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at shirenchuang@didiglobal.com . All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8a8b38a9..06577128 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,28 +1,150 @@ -# Contribution Guideline -Thanks for considering to contribute this project. All issues and pull requests are highly appreciated. -## Pull Requests -Before sending pull request to this project, please read and follow guidelines below. +# 为KnowStreaming做贡献 -1. Branch: We only accept pull request on `dev` branch. -2. Coding style: Follow the coding style used in LogiKM. -3. Commit message: Use English and be aware of your spell. -4. Test: Make sure to test your code. -Add device mode, API version, related log, screenshots and other related information in your pull request if possible. +欢迎👏🏻来到KnowStreaming!本文档是关于如何为KnowStreaming做出贡献的指南。 -NOTE: We assume all your contribution can be licensed under the [AGPL-3.0](LICENSE). +如果您发现不正确或遗漏的内容, 请留下意见/建议。 -## Issues +## 行为守则 +请务必阅读并遵守我们的 [行为准则](./CODE_OF_CONDUCT.md). -We love clearly described issues. :) -Following information can help us to resolve the issue faster. -* Device mode and hardware information. -* API version. -* Logs. -* Screenshots. -* Steps to reproduce the issue. \ No newline at end of file +## 贡献 + +**KnowStreaming** 欢迎任何角色的新参与者,包括 **User** 、**Contributor**、**Committer**、**PMC** 。 + +我们鼓励新人积极加入 **KnowStreaming** 项目,从User到Contributor、Committer ,甚至是 PMC 角色。 + +为了做到这一点,新人需要积极地为 **KnowStreaming** 项目做出贡献。以下介绍如何对 **KnowStreaming** 进行贡献。 + + +### 创建/打开 Issue + +如果您在文档中发现拼写错误、在代码中**发现错误**或想要**新功能**或想要**提供建议**,您可以在 GitHub 上[创建一个Issue](https://github.com/didi/KnowStreaming/issues/new/choose) 进行报告。 + + +如果您想直接贡献, 您可以选择下面标签的问题。 + +- [contribution welcome](https://github.com/didi/KnowStreaming/labels/contribution%20welcome) : 非常需要解决/新增 的Issues +- [good first issue](https://github.com/didi/KnowStreaming/labels/good%20first%20issue): 对新人比较友好, 新人可以拿这个Issue来练练手热热身。 + + 请注意,任何 PR 都必须与有效issue相关联。否则,PR 将被拒绝。 + + + +### 开始你的贡献 + +**分支介绍** + +我们将 `dev`分支作为开发分支, 说明这是一个不稳定的分支。 + +此外,我们的分支模型符合 [https://nvie.com/posts/a-successful-git-branching-model/](https://nvie.com/posts/a-successful-git-branching-model/). 我们强烈建议新人在创建PR之前先阅读上述文章。 + + + +**贡献流程** + +为方便描述,我们这里定义一下2个名词: + +自己Fork出来的仓库是私人仓库, 我们这里称之为 :**分叉仓库** +Fork的源项目,我们称之为:**源仓库** + + +现在,如果您准备好创建PR, 以下是贡献者的工作流程: + +1. Fork [KnowStreaming](https://github.com/didi/KnowStreaming) 项目到自己的仓库 + +2. 从源仓库的`dev`拉取并创建自己的本地分支,例如: `dev` +3. 在本地分支上对代码进行修改 +4. Rebase 开发分支, 并解决冲突 +5. commit 并 push 您的更改到您自己的**分叉仓库** +6. 创建一个 Pull Request 到**源仓库**的`dev`分支中。 +7. 等待回复。如果回复的慢,请无情的催促。 + + +更为详细的贡献流程请看:[贡献流程](./docs/contributer_guide/贡献流程.md) + +创建Pull Request时: + +1. 请遵循 PR的 [模板](./.github/PULL_REQUEST_TEMPLATE.md) +2. 请确保 PR 有相应的issue。 +3. 如果您的 PR 包含较大的更改,例如组件重构或新组件,请编写有关其设计和使用的详细文档(在对应的issue中)。 +4. 注意单个 PR 不能太大。如果需要进行大量更改,最好将更改分成几个单独的 PR。 +5. 在合并PR之前,尽量的将最终的提交信息清晰简洁, 将多次修改的提交尽可能的合并为一次提交。 +6. 创建 PR 后,将为PR分配一个或多个reviewers。 + + +如果您的 PR 包含较大的更改,例如组件重构或新组件,请编写有关其设计和使用的详细文档。 + + +# 代码审查指南 + +Commiter将轮流review代码,以确保在合并前至少有一名Commiter + +一些原则: + +- 可读性——重要的代码应该有详细的文档。API 应该有 Javadoc。代码风格应与现有风格保持一致。 +- 优雅:新的函数、类或组件应该设计得很好。 +- 可测试性——单元测试用例应该覆盖 80% 的新代码。 +- 可维护性 - 遵守我们的编码规范。 + + +# 开发者 + +## 成为Contributor + +只要成功提交并合并PR , 则为Contributor + +贡献者名单请看:[贡献者名单](./docs/contributer_guide/开发者名单.md) + +## 尝试成为Commiter + +一般来说, 贡献8个重要的补丁并至少让三个不同的人来Review他们(您需要3个Commiter的支持)。 +然后请人给你提名, 您需要展示您的 + +1. 至少8个重要的PR和项目的相关问题 +2. 与团队合作的能力 +3. 了解项目的代码库和编码风格 +4. 编写好代码的能力 + +当前的Commiter可以通过在KnowStreaming中的Issue标签 `nomination`(提名)来提名您 + +1. 你的名字和姓氏 +2. 指向您的Git个人资料的链接 +3. 解释为什么你应该成为Commiter +4. 详细说明提名人与您合作的3个PR以及相关问题,这些问题可以证明您的能力。 + +另外2个Commiter需要支持您的**提名**,如果5个工作日内没有人反对,您就是提交者,如果有人反对或者想要更多的信息,Commiter会讨论并通常达成共识(5个工作日内) 。 + + +# 开源奖励计划 + + +我们非常欢迎开发者们为KnowStreaming开源项目贡献一份力量,相应也将给予贡献者激励以表认可与感谢。 + + +## 参与贡献 + +1. 积极参与 Issue 的讨论,如答疑解惑、提供想法或报告无法解决的错误(Issue) +2. 撰写和改进项目的文档(Wiki) +3. 提交补丁优化代码(Coding) + + +## 你将获得 + +1. 加入KnowStreaming开源项目贡献者名单并展示 +2. KnowStreaming开源贡献者证书(纸质&电子版) +3. KnowStreaming贡献者精美大礼包(KnowStreamin/滴滴 周边) + + +## 相关规则 + +- Contributer和Commiter都会有对应的证书和对应的礼包 +- 每季度有KnowStreaming项目团队评选出杰出贡献者,颁发相应证书。 +- 年末进行年度评选 + +贡献者名单请看:[贡献者名单](./docs/contributer_guide/开发者名单.md) \ No newline at end of file diff --git a/README.md b/README.md index 1ae6ca59..9cc19762 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,14 @@ ## `Know Streaming` 简介 -`Know Streaming`是一套云原生的Kafka管控平台,脱胎于众多互联网内部多年的Kafka运营实践经验,专注于Kafka运维管控、监控告警、资源治理、多活容灾等核心场景。在用户体验、监控、运维管控上进行了平台化、可视化、智能化的建设,提供一系列特色的功能,极大地方便了用户和运维人员的日常使用,让普通运维人员都能成为Kafka专家。整体具有以下特点: +`Know Streaming`是一套云原生的Kafka管控平台,脱胎于众多互联网内部多年的Kafka运营实践经验,专注于Kafka运维管控、监控告警、资源治理、多活容灾等核心场景。在用户体验、监控、运维管控上进行了平台化、可视化、智能化的建设,提供一系列特色的功能,极大地方便了用户和运维人员的日常使用,让普通运维人员都能成为Kafka专家。 + +我们现在正在收集 Know Streaming 用户信息,以帮助我们进一步改进 Know Streaming。 +请在 [issue#663](https://github.com/didi/KnowStreaming/issues/663) 上提供您的使用信息来支持我们:[谁在使用 Know Streaming](https://github.com/didi/KnowStreaming/issues/663) + + + +整体具有以下特点: - 👀  **零侵入、全覆盖** - 无需侵入改造 `Apache Kafka` ,一键便能纳管 `0.10.x` ~ `3.x.x` 众多版本的Kafka,包括 `ZK` 或 `Raft` 运行模式的版本,同时在兼容架构上具备良好的扩展性,帮助您提升集群管理水平; @@ -99,9 +106,13 @@ ## 成为社区贡献者 -点击 [这里](CONTRIBUTING.md),了解如何成为 Know Streaming 的贡献者 +1. [贡献源码](https://doc.knowstreaming.com/product/10-contribution) 了解如何成为 Know Streaming 的贡献者 +2. [具体贡献流程](https://doc.knowstreaming.com/product/10-contribution#102-贡献流程) +3. [开源激励计划](https://doc.knowstreaming.com/product/10-contribution#105-开源激励计划) +4. [贡献者名单](https://doc.knowstreaming.com/product/10-contribution#106-贡献者名单) +获取KnowStreaming开源社区证书。 ## 加入技术交流群 @@ -134,6 +145,11 @@ PS: 提问请尽量把问题一次性描述清楚,并告知环境信息情况 微信加群:添加`mike_zhangliang`、`PenceXie`的微信号备注KnowStreaming加群。
+ +加群之前有劳点一下 star,一个小小的 star 是对KnowStreaming作者们努力建设社区的动力。 + +感谢感谢!!! + wx ## Star History diff --git a/Releases_Notes.md b/Releases_Notes.md index f453b582..a3df746f 100644 --- a/Releases_Notes.md +++ b/Releases_Notes.md @@ -1,4 +1,36 @@ +## v3.0.1 + +**Bug修复** +- 修复重置 Group Offset 时,提示信息中缺少 Dead 状态也可进行重置的信息; +- 修复 Ldap 某个属性不存在时,会直接抛出空指针导致登陆失败的问题; +- 修复集群 Topic 列表页,健康分详情信息中,检查时间展示错误的问题; +- 修复更新健康检查结果时,出现死锁的问题; +- 修复 Replica 索引模版错误的问题; +- 修复 FAQ 文档中的错误链接; +- 修复 Broker 的 TopN 指标不存在时,页面数据不展示的问题; +- 修复 Group 详情页,图表时间范围选择不生效的问题; + + +**体验优化** +- 集群 Group 列表按照 Group 维度进行展示; +- 优化避免因 ES 中该指标不存在,导致日志中出现大量空指针的问题; +- 优化全局 Message & Notification 展示效果; +- 优化 Topic 扩分区名称 & 描述展示; + + +**新增** +- Broker 列表页面,新增 JMX 是否成功连接的信息; + + +**ZK 部分(未完全发布)** +- 后端补充 Kafka ZK 指标采集,Kafka ZK 信息获取相关功能; +- 增加本地缓存,避免同一采集周期内 ZK 指标重复采集; +- 增加 ZK 节点采集失败跳过策略,避免不断对存在问题的节点不断尝试; +- 修复 zkAvgLatency 指标转 Long 时抛出异常问题; +- 修复 ks_km_zookeeper 表中,role 字段类型错误问题; + +--- ## v3.0.0 @@ -25,7 +57,7 @@ - 集群信息中,新增 Kafka 集群运行模式字段 - 新增 docker-compose 的部署方式 - +--- ## v3.0.0-beta.3 diff --git a/bin/init_es_template.sh b/bin/init_es_template.sh index e6beba96..86fcfb66 100644 --- a/bin/init_es_template.sh +++ b/bin/init_es_template.sh @@ -439,7 +439,7 @@ curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: appl curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: application/json' http://${esaddr}:${port}/_template/ks_kafka_replication_metric -d '{ "order" : 10, "index_patterns" : [ - "ks_kafka_partition_metric*" + "ks_kafka_replication_metric*" ], "settings" : { "index" : { @@ -500,30 +500,7 @@ curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: appl } }, "aliases" : { } - }[root@10-255-0-23 template]# cat ks_kafka_replication_metric -PUT _template/ks_kafka_replication_metric -{ - "order" : 10, - "index_patterns" : [ - "ks_kafka_replication_metric*" - ], - "settings" : { - "index" : { - "number_of_shards" : "10" - } - }, - "mappings" : { - "properties" : { - "timestamp" : { - "format" : "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis", - "index" : true, - "type" : "date", - "doc_values" : true - } - } - }, - "aliases" : { } - }' + }' curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: application/json' http://${esaddr}:${port}/_template/ks_kafka_topic_metric -d '{ "order" : 10, @@ -640,7 +617,92 @@ curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: appl } }, "aliases" : { } - }' + }' + +curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: application/json' http://${SERVER_ES_ADDRESS}/_template/ks_kafka_zookeeper_metric -d '{ + "order" : 10, + "index_patterns" : [ + "ks_kafka_zookeeper_metric*" + ], + "settings" : { + "index" : { + "number_of_shards" : "10" + } + }, + "mappings" : { + "properties" : { + "routingValue" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "clusterPhyId" : { + "type" : "long" + }, + "metrics" : { + "properties" : { + "AvgRequestLatency" : { + "type" : "double" + }, + "MinRequestLatency" : { + "type" : "double" + }, + "MaxRequestLatency" : { + "type" : "double" + }, + "OutstandingRequests" : { + "type" : "double" + }, + "NodeCount" : { + "type" : "double" + }, + "WatchCount" : { + "type" : "double" + }, + "NumAliveConnections" : { + "type" : "double" + }, + "PacketsReceived" : { + "type" : "double" + }, + "PacketsSent" : { + "type" : "double" + }, + "EphemeralsCount" : { + "type" : "double" + }, + "ApproximateDataSize" : { + "type" : "double" + }, + "OpenFileDescriptorCount" : { + "type" : "double" + }, + "MaxFileDescriptorCount" : { + "type" : "double" + } + } + }, + "key" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "timestamp" : { + "format" : "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis", + "type" : "date" + } + } + }, + "aliases" : { } + }' for i in {0..6}; do @@ -650,6 +712,7 @@ do curl -s -o /dev/null -X PUT http://${esaddr}:${port}/ks_kafka_group_metric${logdate} && \ curl -s -o /dev/null -X PUT http://${esaddr}:${port}/ks_kafka_partition_metric${logdate} && \ curl -s -o /dev/null -X PUT http://${esaddr}:${port}/ks_kafka_replication_metric${logdate} && \ + curl -s -o /dev/null -X PUT http://${esaddr}:${port}/ks_kafka_zookeeper_metric${logdate} && \ curl -s -o /dev/null -X PUT http://${esaddr}:${port}/ks_kafka_topic_metric${logdate} || \ exit 2 -done \ No newline at end of file +done diff --git a/docs/contributer_guide/代码规范.md b/docs/contributer_guide/代码规范.md new file mode 100644 index 00000000..be0bcfd2 --- /dev/null +++ b/docs/contributer_guide/代码规范.md @@ -0,0 +1 @@ +TODO. \ No newline at end of file diff --git a/docs/contributer_guide/开发者名单.md b/docs/contributer_guide/开发者名单.md new file mode 100644 index 00000000..3f2c708d --- /dev/null +++ b/docs/contributer_guide/开发者名单.md @@ -0,0 +1,6 @@ + +开源贡献者证书发放名单(定期更新) + + +贡献者名单请看:[贡献者名单](https://doc.knowstreaming.com/product/10-contribution#106-贡献者名单) + diff --git a/docs/contributer_guide/贡献流程.md b/docs/contributer_guide/贡献流程.md new file mode 100644 index 00000000..42679379 --- /dev/null +++ b/docs/contributer_guide/贡献流程.md @@ -0,0 +1,6 @@ + + +
+
+ +请点击:[贡献流程](https://doc.knowstreaming.com/product/10-contribution#102-贡献流程) \ No newline at end of file diff --git a/docs/dev_guide/assets/support_kerberos_zk/need_modify_code.png b/docs/dev_guide/assets/support_kerberos_zk/need_modify_code.png new file mode 100644 index 00000000..c51c1c00 Binary files /dev/null and b/docs/dev_guide/assets/support_kerberos_zk/need_modify_code.png differ diff --git a/docs/dev_guide/assets/support_kerberos_zk/success_1.png b/docs/dev_guide/assets/support_kerberos_zk/success_1.png new file mode 100644 index 00000000..f15ed55e Binary files /dev/null and b/docs/dev_guide/assets/support_kerberos_zk/success_1.png differ diff --git a/docs/dev_guide/assets/support_kerberos_zk/success_2.png b/docs/dev_guide/assets/support_kerberos_zk/success_2.png new file mode 100644 index 00000000..f15ed55e Binary files /dev/null and b/docs/dev_guide/assets/support_kerberos_zk/success_2.png differ diff --git a/docs/dev_guide/assets/support_kerberos_zk/watch_user_acl.png b/docs/dev_guide/assets/support_kerberos_zk/watch_user_acl.png new file mode 100644 index 00000000..b076316b Binary files /dev/null and b/docs/dev_guide/assets/support_kerberos_zk/watch_user_acl.png differ diff --git a/docs/dev_guide/支持Kerberos认证的ZK.md b/docs/dev_guide/支持Kerberos认证的ZK.md new file mode 100644 index 00000000..116643ba --- /dev/null +++ b/docs/dev_guide/支持Kerberos认证的ZK.md @@ -0,0 +1,69 @@ + +## 支持Kerberos认证的ZK + + +### 1、修改 KnowStreaming 代码 + +代码位置:`src/main/java/com/xiaojukeji/know/streaming/km/persistence/kafka/KafkaAdminZKClient.java` + +将 `createZKClient` 的 `135行 的 false 改为 true +![need_modify_code.png](assets/support_kerberos_zk/need_modify_code.png) + + +修改完后重新进行打包编译,打包编译见:[打包编译](https://github.com/didi/KnowStreaming/blob/master/docs/install_guide/%E6%BA%90%E7%A0%81%E7%BC%96%E8%AF%91%E6%89%93%E5%8C%85%E6%89%8B%E5%86%8C.md +) + + + +### 2、查看用户在ZK的ACL + +假设我们使用的用户是 `kafka` 这个用户。 + +- 1、查看 server.properties 的配置的 zookeeper.connect 的地址; +- 2、使用 `zkCli.sh -serve zookeeper.connect的地址` 登录到ZK页面; +- 3、ZK页面上,执行命令 `getAcl /kafka` 查看 `kafka` 用户的权限; + +此时,我们可以看到如下信息: +![watch_user_acl.png](assets/support_kerberos_zk/watch_user_acl.png) + +`kafka` 用户需要的权限是 `cdrwa`。如果用户没有 `cdrwa` 权限的话,需要创建用户并授权,授权命令为:`setAcl` + + +### 3、创建Kerberos的keytab并修改 KnowStreaming 主机 + +- 1、在 Kerberos 的域中创建 `kafka/_HOST` 的 `keytab`,并导出。例如:`kafka/dbs-kafka-test-8-53`; +- 2、导出 keytab 后上传到安装 KS 的机器的 `/etc/keytab` 下; +- 3、在 KS 机器上,执行 `kinit -kt zookeepe.keytab kafka/dbs-kafka-test-8-53` 看是否能进行 `Kerberos` 登录; +- 4、可以登录后,配置 `/opt/zookeeper.jaas` 文件,例子如下: +```sql +Client { + com.sun.security.auth.module.Krb5LoginModule required + useKeyTab=true + storeKey=false + serviceName="zookeeper" + keyTab="/etc/keytab/zookeeper.keytab" + principal="kafka/dbs-kafka-test-8-53@XXX.XXX.XXX"; +}; +``` +- 5、需要配置 `KDC-Server` 对 `KnowStreaming` 的机器开通防火墙,并在KS的机器 `/etc/host/` 配置 `kdc-server` 的 `hostname`。并将 `krb5.conf` 导入到 `/etc` 下; + + +### 4、修改 KnowStreaming 的配置 + +- 1、在 `/usr/local/KnowStreaming/KnowStreaming/bin/startup.sh` 中的47行的JAVA_OPT中追加如下设置 +```bash +-Dsun.security.krb5.debug=true -Djava.security.krb5.conf=/etc/krb5.conf -Djava.security.auth.login.config=/opt/zookeeper.jaas +``` + +- 2、重启KS集群后再 start.out 中看到如下信息,则证明Kerberos配置成功; + +![success_1.png](assets/support_kerberos_zk/success_1.png) + +![success_2.png](assets/support_kerberos_zk/success_2.png) + + +### 5、补充说明 + +- 1、多Kafka集群如果用的是一样的Kerberos域的话,只需在每个`ZK`中给`kafka`用户配置`crdwa`权限即可,这样集群初始化的时候`zkclient`是都可以认证; +- 2、当前需要修改代码重新打包才可以支持,后续考虑通过页面支持Kerberos认证的ZK接入; +- 3、多个Kerberos域暂时未适配; \ No newline at end of file diff --git a/docs/install_guide/版本升级手册.md b/docs/install_guide/版本升级手册.md index a75f71fd..2fef58f0 100644 --- a/docs/install_guide/版本升级手册.md +++ b/docs/install_guide/版本升级手册.md @@ -4,13 +4,148 @@ - 如果想升级至具体版本,需要将你当前版本至你期望使用版本的变更统统执行一遍,然后才能正常使用。 - 如果中间某个版本没有升级信息,则表示该版本直接替换安装包即可从前一个版本升级至当前版本。 - ### 6.2.0、升级至 `master` 版本 暂无 +### 6.2.1、升级至 `v3.0.1` 版本 -### 6.2.1、升级至 `v3.0.0` 版本 +**ES 索引模版** +```bash +# 新增 ks_kafka_zookeeper_metric 索引模版。 +# 可通过再次执行 bin/init_es_template.sh 脚本,创建该索引模版。 + +# 索引模版内容 +PUT _template/ks_kafka_zookeeper_metric +{ + "order" : 10, + "index_patterns" : [ + "ks_kafka_zookeeper_metric*" + ], + "settings" : { + "index" : { + "number_of_shards" : "10" + } + }, + "mappings" : { + "properties" : { + "routingValue" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "clusterPhyId" : { + "type" : "long" + }, + "metrics" : { + "properties" : { + "AvgRequestLatency" : { + "type" : "double" + }, + "MinRequestLatency" : { + "type" : "double" + }, + "MaxRequestLatency" : { + "type" : "double" + }, + "OutstandingRequests" : { + "type" : "double" + }, + "NodeCount" : { + "type" : "double" + }, + "WatchCount" : { + "type" : "double" + }, + "NumAliveConnections" : { + "type" : "double" + }, + "PacketsReceived" : { + "type" : "double" + }, + "PacketsSent" : { + "type" : "double" + }, + "EphemeralsCount" : { + "type" : "double" + }, + "ApproximateDataSize" : { + "type" : "double" + }, + "OpenFileDescriptorCount" : { + "type" : "double" + }, + "MaxFileDescriptorCount" : { + "type" : "double" + } + } + }, + "key" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "timestamp" : { + "format" : "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis", + "type" : "date" + } + } + }, + "aliases" : { } + } +``` + + +**SQL 变更** + +```sql +DROP TABLE IF EXISTS `ks_km_zookeeper`; +CREATE TABLE `ks_km_zookeeper` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `cluster_phy_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '物理集群ID', + `host` varchar(128) NOT NULL DEFAULT '' COMMENT 'zookeeper主机名', + `port` int(16) NOT NULL DEFAULT '-1' COMMENT 'zookeeper端口', + `role` varchar(16) NOT NULL DEFAULT '' COMMENT '角色, leader follower observer', + `version` varchar(128) NOT NULL DEFAULT '' COMMENT 'zookeeper版本', + `status` int(16) NOT NULL DEFAULT '0' COMMENT '状态: 1存活,0未存活,11存活但是4字命令使用不了', + `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uniq_cluster_phy_id_host_port` (`cluster_phy_id`,`host`, `port`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Zookeeper信息表'; + + +DROP TABLE IF EXISTS `ks_km_group`; +CREATE TABLE `ks_km_group` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `cluster_phy_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群id', + `name` varchar(192) COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT 'Group名称', + `member_count` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '成员数', + `topic_members` text CHARACTER SET utf8 COMMENT 'group消费的topic列表', + `partition_assignor` varchar(255) CHARACTER SET utf8 NOT NULL COMMENT '分配策略', + `coordinator_id` int(11) NOT NULL COMMENT 'group协调器brokerId', + `type` int(11) NOT NULL COMMENT 'group类型 0:consumer 1:connector', + `state` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '' COMMENT '状态', + `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uniq_cluster_phy_id_name` (`cluster_phy_id`,`name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Group信息表'; + +``` + +--- + + +### 6.2.2、升级至 `v3.0.0` 版本 **SQL 变更** @@ -22,7 +157,7 @@ ADD COLUMN `zk_properties` TEXT NULL COMMENT 'ZK配置' AFTER `jmx_properties`; --- -### 6.2.2、升级至 `v3.0.0-beta.2`版本 +### 6.2.3、升级至 `v3.0.0-beta.2`版本 **配置变更** @@ -93,7 +228,7 @@ ALTER TABLE `logi_security_oplog` --- -### 6.2.3、升级至 `v3.0.0-beta.1`版本 +### 6.2.4、升级至 `v3.0.0-beta.1`版本 **SQL 变更** @@ -112,7 +247,7 @@ ALTER COLUMN `operation_methods` set default ''; --- -### 6.2.4、`2.x`版本 升级至 `v3.0.0-beta.0`版本 +### 6.2.5、`2.x`版本 升级至 `v3.0.0-beta.0`版本 **升级步骤:** diff --git a/docs/user_guide/faq.md b/docs/user_guide/faq.md index 98dfbf83..a91cdf79 100644 --- a/docs/user_guide/faq.md +++ b/docs/user_guide/faq.md @@ -37,7 +37,7 @@ ## 8.4、`Jmx`连接失败如何解决? -- 参看 [Jmx 连接配置&问题解决](./9-attachment#jmx-连接失败问题解决) 说明。 +- 参看 [Jmx 连接配置&问题解决](https://doc.knowstreaming.com/product/9-attachment#91jmx-%E8%BF%9E%E6%8E%A5%E5%A4%B1%E8%B4%A5%E9%97%AE%E9%A2%98%E8%A7%A3%E5%86%B3) 说明。   diff --git a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/cluster/ClusterZookeepersManager.java b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/cluster/ClusterZookeepersManager.java new file mode 100644 index 00000000..8219cd7e --- /dev/null +++ b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/cluster/ClusterZookeepersManager.java @@ -0,0 +1,19 @@ +package com.xiaojukeji.know.streaming.km.biz.cluster; + +import com.xiaojukeji.know.streaming.km.common.bean.dto.cluster.ClusterZookeepersOverviewDTO; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.PaginationResult; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; +import com.xiaojukeji.know.streaming.km.common.bean.vo.zookeeper.ClusterZookeepersOverviewVO; +import com.xiaojukeji.know.streaming.km.common.bean.vo.zookeeper.ClusterZookeepersStateVO; +import com.xiaojukeji.know.streaming.km.common.bean.vo.zookeeper.ZnodeVO; + +/** + * 多集群总体状态 + */ +public interface ClusterZookeepersManager { + Result getClusterPhyZookeepersState(Long clusterPhyId); + + PaginationResult getClusterPhyZookeepersOverview(Long clusterPhyId, ClusterZookeepersOverviewDTO dto); + + Result getZnodeVO(Long clusterPhyId, String path); +} diff --git a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/cluster/impl/ClusterBrokersManagerImpl.java b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/cluster/impl/ClusterBrokersManagerImpl.java index 50c3596d..6b180126 100644 --- a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/cluster/impl/ClusterBrokersManagerImpl.java +++ b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/cluster/impl/ClusterBrokersManagerImpl.java @@ -24,6 +24,7 @@ import com.xiaojukeji.know.streaming.km.core.service.broker.BrokerMetricService; import com.xiaojukeji.know.streaming.km.core.service.broker.BrokerService; import com.xiaojukeji.know.streaming.km.core.service.kafkacontroller.KafkaControllerService; import com.xiaojukeji.know.streaming.km.core.service.topic.TopicService; +import com.xiaojukeji.know.streaming.km.persistence.kafka.KafkaJMXClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -51,6 +52,9 @@ public class ClusterBrokersManagerImpl implements ClusterBrokersManager { @Autowired private KafkaControllerService kafkaControllerService; + @Autowired + private KafkaJMXClient kafkaJMXClient; + @Override public PaginationResult getClusterPhyBrokersOverview(Long clusterPhyId, ClusterBrokersOverviewDTO dto) { // 获取集群Broker列表 @@ -75,6 +79,10 @@ public class ClusterBrokersManagerImpl implements ClusterBrokersManager { //获取controller信息 KafkaController kafkaController = kafkaControllerService.getKafkaControllerFromDB(clusterPhyId); + //获取jmx状态信息 + Map jmxConnectedMap = new HashMap<>(); + brokerList.forEach(elem -> jmxConnectedMap.put(elem.getBrokerId(), kafkaJMXClient.getClientWithCheck(clusterPhyId, elem.getBrokerId()) != null)); + // 格式转换 return PaginationResult.buildSuc( this.convert2ClusterBrokersOverviewVOList( @@ -83,7 +91,8 @@ public class ClusterBrokersManagerImpl implements ClusterBrokersManager { metricsResult.getData(), groupTopic, transactionTopic, - kafkaController + kafkaController, + jmxConnectedMap ), paginationResult ); @@ -165,22 +174,24 @@ public class ClusterBrokersManagerImpl implements ClusterBrokersManager { List metricsList, Topic groupTopic, Topic transactionTopic, - KafkaController kafkaController) { - Map metricsMap = metricsList == null? new HashMap<>(): metricsList.stream().collect(Collectors.toMap(BrokerMetrics::getBrokerId, Function.identity())); + KafkaController kafkaController, + Map jmxConnectedMap) { + Map metricsMap = metricsList == null ? new HashMap<>() : metricsList.stream().collect(Collectors.toMap(BrokerMetrics::getBrokerId, Function.identity())); - Map brokerMap = brokerList == null? new HashMap<>(): brokerList.stream().collect(Collectors.toMap(Broker::getBrokerId, Function.identity())); + Map brokerMap = brokerList == null ? new HashMap<>() : brokerList.stream().collect(Collectors.toMap(Broker::getBrokerId, Function.identity())); List voList = new ArrayList<>(pagedBrokerIdList.size()); for (Integer brokerId : pagedBrokerIdList) { Broker broker = brokerMap.get(brokerId); BrokerMetrics brokerMetrics = metricsMap.get(brokerId); + Boolean jmxConnected = jmxConnectedMap.get(brokerId); - voList.add(this.convert2ClusterBrokersOverviewVO(brokerId, broker, brokerMetrics, groupTopic, transactionTopic, kafkaController)); + voList.add(this.convert2ClusterBrokersOverviewVO(brokerId, broker, brokerMetrics, groupTopic, transactionTopic, kafkaController, jmxConnected)); } return voList; } - private ClusterBrokersOverviewVO convert2ClusterBrokersOverviewVO(Integer brokerId, Broker broker, BrokerMetrics brokerMetrics, Topic groupTopic, Topic transactionTopic, KafkaController kafkaController) { + private ClusterBrokersOverviewVO convert2ClusterBrokersOverviewVO(Integer brokerId, Broker broker, BrokerMetrics brokerMetrics, Topic groupTopic, Topic transactionTopic, KafkaController kafkaController, Boolean jmxConnected) { ClusterBrokersOverviewVO clusterBrokersOverviewVO = new ClusterBrokersOverviewVO(); clusterBrokersOverviewVO.setBrokerId(brokerId); if (broker != null) { @@ -203,6 +214,7 @@ public class ClusterBrokersManagerImpl implements ClusterBrokersManager { } clusterBrokersOverviewVO.setLatestMetrics(brokerMetrics); + clusterBrokersOverviewVO.setJmxConnected(jmxConnected); return clusterBrokersOverviewVO; } diff --git a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/cluster/impl/ClusterZookeepersManagerImpl.java b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/cluster/impl/ClusterZookeepersManagerImpl.java new file mode 100644 index 00000000..b285cac9 --- /dev/null +++ b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/cluster/impl/ClusterZookeepersManagerImpl.java @@ -0,0 +1,137 @@ +package com.xiaojukeji.know.streaming.km.biz.cluster.impl; + +import com.didiglobal.logi.log.ILog; +import com.didiglobal.logi.log.LogFactory; +import com.xiaojukeji.know.streaming.km.biz.cluster.ClusterZookeepersManager; +import com.xiaojukeji.know.streaming.km.common.bean.dto.cluster.ClusterZookeepersOverviewDTO; +import com.xiaojukeji.know.streaming.km.common.bean.entity.cluster.ClusterPhy; +import com.xiaojukeji.know.streaming.km.common.bean.entity.config.ZKConfig; +import com.xiaojukeji.know.streaming.km.common.bean.entity.metrics.ZookeeperMetrics; +import com.xiaojukeji.know.streaming.km.common.bean.entity.param.metric.ZookeeperMetricParam; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.PaginationResult; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.ResultStatus; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.Znode; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.ZookeeperInfo; +import com.xiaojukeji.know.streaming.km.common.bean.vo.zookeeper.ClusterZookeepersOverviewVO; +import com.xiaojukeji.know.streaming.km.common.bean.vo.zookeeper.ClusterZookeepersStateVO; +import com.xiaojukeji.know.streaming.km.common.bean.vo.zookeeper.ZnodeVO; +import com.xiaojukeji.know.streaming.km.common.constant.MsgConstant; +import com.xiaojukeji.know.streaming.km.common.enums.zookeeper.ZKRoleEnum; +import com.xiaojukeji.know.streaming.km.common.utils.ConvertUtil; +import com.xiaojukeji.know.streaming.km.common.utils.PaginationUtil; +import com.xiaojukeji.know.streaming.km.common.utils.Tuple; +import com.xiaojukeji.know.streaming.km.core.service.cluster.ClusterPhyService; +import com.xiaojukeji.know.streaming.km.core.service.version.metrics.ZookeeperMetricVersionItems; +import com.xiaojukeji.know.streaming.km.core.service.zookeeper.ZnodeService; +import com.xiaojukeji.know.streaming.km.core.service.zookeeper.ZookeeperMetricService; +import com.xiaojukeji.know.streaming.km.core.service.zookeeper.ZookeeperService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + + +@Service +public class ClusterZookeepersManagerImpl implements ClusterZookeepersManager { + private static final ILog LOGGER = LogFactory.getLog(ClusterZookeepersManagerImpl.class); + + @Autowired + private ClusterPhyService clusterPhyService; + + @Autowired + private ZookeeperService zookeeperService; + + @Autowired + private ZookeeperMetricService zookeeperMetricService; + + @Autowired + private ZnodeService znodeService; + + @Override + public Result getClusterPhyZookeepersState(Long clusterPhyId) { + ClusterPhy clusterPhy = clusterPhyService.getClusterByCluster(clusterPhyId); + if (clusterPhy == null) { + return Result.buildFromRSAndMsg(ResultStatus.CLUSTER_NOT_EXIST, MsgConstant.getClusterPhyNotExist(clusterPhyId)); + } + +// // TODO +// private Integer healthState; +// private Integer healthCheckPassed; +// private Integer healthCheckTotal; + + List infoList = zookeeperService.listFromDBByCluster(clusterPhyId); + + ClusterZookeepersStateVO vo = new ClusterZookeepersStateVO(); + vo.setTotalServerCount(infoList.size()); + vo.setAliveFollowerCount(0); + vo.setTotalFollowerCount(0); + vo.setAliveObserverCount(0); + vo.setTotalObserverCount(0); + vo.setAliveServerCount(0); + for (ZookeeperInfo info: infoList) { + if (info.getRole().equals(ZKRoleEnum.LEADER.getRole())) { + vo.setLeaderNode(info.getHost()); + } + + if (info.getRole().equals(ZKRoleEnum.FOLLOWER.getRole())) { + vo.setTotalFollowerCount(vo.getTotalFollowerCount() + 1); + vo.setAliveFollowerCount(info.alive()? vo.getAliveFollowerCount() + 1: vo.getAliveFollowerCount()); + } + + if (info.getRole().equals(ZKRoleEnum.OBSERVER.getRole())) { + vo.setTotalObserverCount(vo.getTotalObserverCount() + 1); + vo.setAliveObserverCount(info.alive()? vo.getAliveObserverCount() + 1: vo.getAliveObserverCount()); + } + + if (info.alive()) { + vo.setAliveServerCount(vo.getAliveServerCount() + 1); + } + } + + Result metricsResult = zookeeperMetricService.collectMetricsFromZookeeper(new ZookeeperMetricParam( + clusterPhyId, + infoList.stream().filter(elem -> elem.alive()).map(item -> new Tuple(item.getHost(), item.getPort())).collect(Collectors.toList()), + ConvertUtil.str2ObjByJson(clusterPhy.getZkProperties(), ZKConfig.class), + ZookeeperMetricVersionItems.ZOOKEEPER_METRIC_WATCH_COUNT + )); + if (metricsResult.failed()) { + LOGGER.error( + "class=ClusterZookeepersManagerImpl||method=getClusterPhyZookeepersState||clusterPhyId={}||errMsg={}", + clusterPhyId, metricsResult.getMessage() + ); + return Result.buildSuc(vo); + } + Float watchCount = metricsResult.getData().getMetric(ZookeeperMetricVersionItems.ZOOKEEPER_METRIC_WATCH_COUNT); + vo.setWatchCount(watchCount != null? watchCount.intValue(): null); + + return Result.buildSuc(vo); + } + + @Override + public PaginationResult getClusterPhyZookeepersOverview(Long clusterPhyId, ClusterZookeepersOverviewDTO dto) { + //获取集群zookeeper列表 + List clusterZookeepersOverviewVOList = ConvertUtil.list2List(zookeeperService.listFromDBByCluster(clusterPhyId), ClusterZookeepersOverviewVO.class); + + //搜索 + clusterZookeepersOverviewVOList = PaginationUtil.pageByFuzzyFilter(clusterZookeepersOverviewVOList, dto.getSearchKeywords(), Arrays.asList("host")); + + //分页 + PaginationResult paginationResult = PaginationUtil.pageBySubData(clusterZookeepersOverviewVOList, dto); + + return paginationResult; + } + + @Override + public Result getZnodeVO(Long clusterPhyId, String path) { + Result result = znodeService.getZnode(clusterPhyId, path); + if (result.failed()) { + return Result.buildFromIgnoreData(result); + } + return Result.buildSuc(ConvertUtil.obj2ObjByJSON(result.getData(), ZnodeVO.class)); + } + + /**************************************************** private method ****************************************************/ + +} diff --git a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/group/GroupManager.java b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/group/GroupManager.java index 5c1518ca..a3686c03 100644 --- a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/group/GroupManager.java +++ b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/group/GroupManager.java @@ -1,11 +1,14 @@ package com.xiaojukeji.know.streaming.km.biz.group; +import com.xiaojukeji.know.streaming.km.common.bean.dto.cluster.ClusterGroupSummaryDTO; import com.xiaojukeji.know.streaming.km.common.bean.dto.group.GroupOffsetResetDTO; import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationBaseDTO; import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationSortDTO; import com.xiaojukeji.know.streaming.km.common.bean.entity.result.PaginationResult; import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; import com.xiaojukeji.know.streaming.km.common.bean.entity.topic.TopicPartitionKS; +import com.xiaojukeji.know.streaming.km.common.bean.po.group.GroupMemberPO; +import com.xiaojukeji.know.streaming.km.common.bean.vo.group.GroupOverviewVO; import com.xiaojukeji.know.streaming.km.common.bean.vo.group.GroupTopicConsumedDetailVO; import com.xiaojukeji.know.streaming.km.common.bean.vo.group.GroupTopicOverviewVO; import com.xiaojukeji.know.streaming.km.common.exception.AdminOperateException; @@ -22,6 +25,10 @@ public interface GroupManager { String searchGroupKeyword, PaginationBaseDTO dto); + PaginationResult pagingGroupTopicMembers(Long clusterPhyId, String groupName, PaginationBaseDTO dto); + + PaginationResult pagingClusterGroupsOverview(Long clusterPhyId, ClusterGroupSummaryDTO dto); + PaginationResult pagingGroupTopicConsumedMetrics(Long clusterPhyId, String topicName, String groupName, @@ -31,4 +38,6 @@ public interface GroupManager { Result> listClusterPhyGroupPartitions(Long clusterPhyId, String groupName, Long startTime, Long endTime); Result resetGroupOffsets(GroupOffsetResetDTO dto, String operator) throws Exception; + + List getGroupTopicOverviewVOList (Long clusterPhyId, List groupMemberPOList); } diff --git a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/group/impl/GroupManagerImpl.java b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/group/impl/GroupManagerImpl.java index 5ccc3e98..97d464ed 100644 --- a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/group/impl/GroupManagerImpl.java +++ b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/group/impl/GroupManagerImpl.java @@ -3,11 +3,14 @@ package com.xiaojukeji.know.streaming.km.biz.group.impl; import com.didiglobal.logi.log.ILog; import com.didiglobal.logi.log.LogFactory; import com.xiaojukeji.know.streaming.km.biz.group.GroupManager; +import com.xiaojukeji.know.streaming.km.common.bean.dto.cluster.ClusterGroupSummaryDTO; import com.xiaojukeji.know.streaming.km.common.bean.dto.group.GroupOffsetResetDTO; import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationBaseDTO; import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationSortDTO; import com.xiaojukeji.know.streaming.km.common.bean.dto.partition.PartitionOffsetDTO; +import com.xiaojukeji.know.streaming.km.common.bean.entity.group.Group; import com.xiaojukeji.know.streaming.km.common.bean.entity.group.GroupTopic; +import com.xiaojukeji.know.streaming.km.common.bean.entity.group.GroupTopicMember; import com.xiaojukeji.know.streaming.km.common.bean.entity.metrics.GroupMetrics; import com.xiaojukeji.know.streaming.km.common.bean.entity.result.PaginationResult; import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; @@ -15,11 +18,15 @@ import com.xiaojukeji.know.streaming.km.common.bean.entity.topic.Topic; import com.xiaojukeji.know.streaming.km.common.bean.entity.topic.TopicPartitionKS; import com.xiaojukeji.know.streaming.km.common.bean.entity.result.ResultStatus; import com.xiaojukeji.know.streaming.km.common.bean.po.group.GroupMemberPO; +import com.xiaojukeji.know.streaming.km.common.bean.vo.group.GroupOverviewVO; import com.xiaojukeji.know.streaming.km.common.bean.vo.group.GroupTopicConsumedDetailVO; import com.xiaojukeji.know.streaming.km.common.bean.vo.group.GroupTopicOverviewVO; import com.xiaojukeji.know.streaming.km.common.constant.MsgConstant; +import com.xiaojukeji.know.streaming.km.common.constant.PaginationConstant; +import com.xiaojukeji.know.streaming.km.common.converter.GroupConverter; import com.xiaojukeji.know.streaming.km.common.enums.AggTypeEnum; import com.xiaojukeji.know.streaming.km.common.enums.OffsetTypeEnum; +import com.xiaojukeji.know.streaming.km.common.enums.SortTypeEnum; import com.xiaojukeji.know.streaming.km.common.enums.group.GroupStateEnum; import com.xiaojukeji.know.streaming.km.common.exception.AdminOperateException; import com.xiaojukeji.know.streaming.km.common.exception.NotExistException; @@ -71,30 +78,60 @@ public class GroupManagerImpl implements GroupManager { String searchGroupKeyword, PaginationBaseDTO dto) { PaginationResult paginationResult = groupService.pagingGroupMembers(clusterPhyId, topicName, groupName, searchTopicKeyword, searchGroupKeyword, dto); - if (paginationResult.failed()) { - return PaginationResult.buildFailure(paginationResult, dto); - } if (!paginationResult.hasData()) { return PaginationResult.buildSuc(new ArrayList<>(), paginationResult); } - // 获取指标 - Result> metricsListResult = groupMetricService.listLatestMetricsAggByGroupTopicFromES( - clusterPhyId, - paginationResult.getData().getBizData().stream().map(elem -> new GroupTopic(elem.getGroupName(), elem.getTopicName())).collect(Collectors.toList()), - Arrays.asList(GroupMetricVersionItems.GROUP_METRIC_LAG), - AggTypeEnum.MAX - ); - if (metricsListResult.failed()) { - // 如果查询失败,则输出错误信息,但是依旧进行已有数据的返回 - log.error("method=pagingGroupMembers||clusterPhyId={}||topicName={}||groupName={}||result={}||errMsg=search es failed", clusterPhyId, topicName, groupName, metricsListResult); + List groupTopicVOList = this.getGroupTopicOverviewVOList(clusterPhyId, paginationResult.getData().getBizData()); + + return PaginationResult.buildSuc(groupTopicVOList, paginationResult); + } + + @Override + public PaginationResult pagingGroupTopicMembers(Long clusterPhyId, String groupName, PaginationBaseDTO dto) { + Group group = groupService.getGroupFromDB(clusterPhyId, groupName); + + //没有topicMember则直接返回 + if (group == null || ValidateUtils.isEmptyList(group.getTopicMembers())) { + return PaginationResult.buildSuc(dto); } - return PaginationResult.buildSuc( - this.convert2GroupTopicOverviewVOList(paginationResult.getData().getBizData(), metricsListResult.getData()), - paginationResult - ); + //排序 + List groupTopicMembers = PaginationUtil.pageBySort(group.getTopicMembers(), PaginationConstant.DEFAULT_GROUP_TOPIC_SORTED_FIELD, SortTypeEnum.DESC.getSortType()); + + //分页 + PaginationResult paginationResult = PaginationUtil.pageBySubData(groupTopicMembers, dto); + + List groupMemberPOList = paginationResult.getData().getBizData().stream().map(elem -> new GroupMemberPO(clusterPhyId, elem.getTopicName(), groupName, group.getState().getState(), elem.getMemberCount())).collect(Collectors.toList()); + + return PaginationResult.buildSuc(this.getGroupTopicOverviewVOList(clusterPhyId, groupMemberPOList), paginationResult); + } + + @Override + public PaginationResult pagingClusterGroupsOverview(Long clusterPhyId, ClusterGroupSummaryDTO dto) { + List groupList = groupService.listClusterGroups(clusterPhyId); + + // 类型转化 + List voList = groupList.stream().map(elem -> GroupConverter.convert2GroupOverviewVO(elem)).collect(Collectors.toList()); + + // 搜索groupName + voList = PaginationUtil.pageByFuzzyFilter(voList, dto.getSearchGroupName(), Arrays.asList("name")); + + //搜索topic + if (!ValidateUtils.isBlank(dto.getSearchTopicName())) { + voList = voList.stream().filter(elem -> { + for (String topicName : elem.getTopicNameList()) { + if (topicName.contains(dto.getSearchTopicName())) { + return true; + } + } + return false; + }).collect(Collectors.toList()); + } + + // 分页 后 返回 + return PaginationUtil.pageBySubData(voList, dto); } @Override @@ -104,7 +141,7 @@ public class GroupManagerImpl implements GroupManager { List latestMetricNames, PaginationSortDTO dto) throws NotExistException, AdminOperateException { // 获取消费组消费的TopicPartition列表 - Map consumedOffsetMap = groupService.getGroupOffset(clusterPhyId, groupName); + Map consumedOffsetMap = groupService.getGroupOffsetFromKafka(clusterPhyId, groupName); List partitionList = consumedOffsetMap.keySet() .stream() .filter(elem -> elem.topic().equals(topicName)) @@ -113,7 +150,7 @@ public class GroupManagerImpl implements GroupManager { Collections.sort(partitionList); // 获取消费组当前运行信息 - ConsumerGroupDescription groupDescription = groupService.getGroupDescription(clusterPhyId, groupName); + ConsumerGroupDescription groupDescription = groupService.getGroupDescriptionFromKafka(clusterPhyId, groupName); // 转换存储格式 Map tpMemberMap = new HashMap<>(); @@ -166,7 +203,7 @@ public class GroupManagerImpl implements GroupManager { return rv; } - ConsumerGroupDescription description = groupService.getGroupDescription(dto.getClusterId(), dto.getGroupName()); + ConsumerGroupDescription description = groupService.getGroupDescriptionFromKafka(dto.getClusterId(), dto.getGroupName()); if (ConsumerGroupState.DEAD.equals(description.state()) && !dto.isCreateIfNotExist()) { return Result.buildFromRSAndMsg(ResultStatus.KAFKA_OPERATE_FAILED, "group不存在, 重置失败"); } @@ -185,6 +222,22 @@ public class GroupManagerImpl implements GroupManager { return groupService.resetGroupOffsets(dto.getClusterId(), dto.getGroupName(), offsetMapResult.getData(), operator); } + @Override + public List getGroupTopicOverviewVOList(Long clusterPhyId, List groupMemberPOList) { + // 获取指标 + Result> metricsListResult = groupMetricService.listLatestMetricsAggByGroupTopicFromES( + clusterPhyId, + groupMemberPOList.stream().map(elem -> new GroupTopic(elem.getGroupName(), elem.getTopicName())).collect(Collectors.toList()), + Arrays.asList(GroupMetricVersionItems.GROUP_METRIC_LAG), + AggTypeEnum.MAX + ); + if (metricsListResult.failed()) { + // 如果查询失败,则输出错误信息,但是依旧进行已有数据的返回 + log.error("method=completeMetricData||clusterPhyId={}||result={}||errMsg=search es failed", clusterPhyId, metricsListResult); + } + return this.convert2GroupTopicOverviewVOList(groupMemberPOList, metricsListResult.getData()); + } + /**************************************************** private method ****************************************************/ @@ -293,4 +346,31 @@ public class GroupManagerImpl implements GroupManager { ); } + private List convert2GroupTopicOverviewVOList(String groupName, String state, List groupTopicList, List metricsList) { + if (metricsList == null) { + metricsList = new ArrayList<>(); + } + + // + Map metricsMap = new HashMap<>(); + for (GroupMetrics metrics : metricsList) { + if (!groupName.equals(metrics.getGroup())) continue; + metricsMap.put(metrics.getTopic(), metrics); + } + + List voList = new ArrayList<>(); + for (GroupTopicMember po : groupTopicList) { + GroupTopicOverviewVO vo = ConvertUtil.obj2Obj(po, GroupTopicOverviewVO.class); + vo.setGroupName(groupName); + vo.setState(state); + GroupMetrics metrics = metricsMap.get(po.getTopicName()); + if (metrics != null) { + vo.setMaxLag(ConvertUtil.Float2Long(metrics.getMetrics().get(GroupMetricVersionItems.GROUP_METRIC_LAG))); + } + + voList.add(vo); + } + return voList; + } + } diff --git a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/topic/TopicStateManager.java b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/topic/TopicStateManager.java index ec3a3207..f2c05300 100644 --- a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/topic/TopicStateManager.java +++ b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/topic/TopicStateManager.java @@ -1,8 +1,10 @@ package com.xiaojukeji.know.streaming.km.biz.topic; -import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationSortDTO; +import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationBaseDTO; import com.xiaojukeji.know.streaming.km.common.bean.dto.topic.TopicRecordDTO; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.PaginationResult; import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; +import com.xiaojukeji.know.streaming.km.common.bean.vo.group.GroupTopicOverviewVO; import com.xiaojukeji.know.streaming.km.common.bean.vo.topic.TopicBrokersPartitionsSummaryVO; import com.xiaojukeji.know.streaming.km.common.bean.vo.topic.TopicRecordVO; import com.xiaojukeji.know.streaming.km.common.bean.vo.topic.TopicStateVO; @@ -23,4 +25,6 @@ public interface TopicStateManager { Result> getTopicPartitions(Long clusterPhyId, String topicName, List metricsNames); Result getTopicBrokersPartitionsSummary(Long clusterPhyId, String topicName); + + PaginationResult pagingTopicGroupsOverview(Long clusterPhyId, String topicName, String searchGroupName, PaginationBaseDTO dto); } diff --git a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/topic/impl/TopicStateManagerImpl.java b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/topic/impl/TopicStateManagerImpl.java index 9c03737a..afc907da 100644 --- a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/topic/impl/TopicStateManagerImpl.java +++ b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/topic/impl/TopicStateManagerImpl.java @@ -2,17 +2,22 @@ package com.xiaojukeji.know.streaming.km.biz.topic.impl; import com.didiglobal.logi.log.ILog; import com.didiglobal.logi.log.LogFactory; +import com.xiaojukeji.know.streaming.km.biz.group.GroupManager; import com.xiaojukeji.know.streaming.km.biz.topic.TopicStateManager; +import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationBaseDTO; import com.xiaojukeji.know.streaming.km.common.bean.dto.topic.TopicRecordDTO; import com.xiaojukeji.know.streaming.km.common.bean.entity.broker.Broker; import com.xiaojukeji.know.streaming.km.common.bean.entity.cluster.ClusterPhy; import com.xiaojukeji.know.streaming.km.common.bean.entity.metrics.PartitionMetrics; import com.xiaojukeji.know.streaming.km.common.bean.entity.metrics.TopicMetrics; import com.xiaojukeji.know.streaming.km.common.bean.entity.partition.Partition; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.PaginationResult; import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; import com.xiaojukeji.know.streaming.km.common.bean.entity.result.ResultStatus; import com.xiaojukeji.know.streaming.km.common.bean.entity.topic.Topic; +import com.xiaojukeji.know.streaming.km.common.bean.po.group.GroupMemberPO; import com.xiaojukeji.know.streaming.km.common.bean.vo.broker.BrokerReplicaSummaryVO; +import com.xiaojukeji.know.streaming.km.common.bean.vo.group.GroupTopicOverviewVO; import com.xiaojukeji.know.streaming.km.common.bean.vo.topic.TopicBrokersPartitionsSummaryVO; import com.xiaojukeji.know.streaming.km.common.bean.vo.topic.TopicRecordVO; import com.xiaojukeji.know.streaming.km.common.bean.vo.topic.TopicStateVO; @@ -32,6 +37,7 @@ import com.xiaojukeji.know.streaming.km.common.utils.PaginationUtil; import com.xiaojukeji.know.streaming.km.common.utils.ValidateUtils; import com.xiaojukeji.know.streaming.km.core.service.broker.BrokerService; import com.xiaojukeji.know.streaming.km.core.service.cluster.ClusterPhyService; +import com.xiaojukeji.know.streaming.km.core.service.group.GroupService; import com.xiaojukeji.know.streaming.km.core.service.partition.PartitionMetricService; import com.xiaojukeji.know.streaming.km.core.service.partition.PartitionService; import com.xiaojukeji.know.streaming.km.core.service.topic.TopicConfigService; @@ -77,6 +83,12 @@ public class TopicStateManagerImpl implements TopicStateManager { @Autowired private TopicConfigService topicConfigService; + @Autowired + private GroupService groupService; + + @Autowired + private GroupManager groupManager; + @Override public TopicBrokerAllVO getTopicBrokerAll(Long clusterPhyId, String topicName, String searchBrokerHost) throws NotExistException { Topic topic = topicService.getTopic(clusterPhyId, topicName); @@ -346,6 +358,19 @@ public class TopicStateManagerImpl implements TopicStateManager { return Result.buildSuc(vo); } + @Override + public PaginationResult pagingTopicGroupsOverview(Long clusterPhyId, String topicName, String searchGroupName, PaginationBaseDTO dto) { + PaginationResult paginationResult = groupService.pagingGroupMembers(clusterPhyId, topicName, "", "", searchGroupName, dto); + + if (!paginationResult.hasData()) { + return PaginationResult.buildSuc(new ArrayList<>(), paginationResult); + } + + List groupTopicVOList = groupManager.getGroupTopicOverviewVOList(clusterPhyId, paginationResult.getData().getBizData()); + + return PaginationResult.buildSuc(groupTopicVOList, paginationResult); + } + /**************************************************** private method ****************************************************/ private boolean checkIfIgnore(ConsumerRecord consumerRecord, String filterKey, String filterValue) { diff --git a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/version/impl/VersionControlManagerImpl.java b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/version/impl/VersionControlManagerImpl.java index 52a91520..70f4814b 100644 --- a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/version/impl/VersionControlManagerImpl.java +++ b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/version/impl/VersionControlManagerImpl.java @@ -14,7 +14,6 @@ import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; import com.xiaojukeji.know.streaming.km.common.bean.entity.version.VersionControlItem; import com.xiaojukeji.know.streaming.km.common.bean.vo.config.metric.UserMetricConfigVO; import com.xiaojukeji.know.streaming.km.common.bean.vo.version.VersionItemVO; -import com.xiaojukeji.know.streaming.km.common.constant.Constant; import com.xiaojukeji.know.streaming.km.common.enums.version.VersionEnum; import com.xiaojukeji.know.streaming.km.common.utils.ConvertUtil; import com.xiaojukeji.know.streaming.km.common.utils.VersionUtil; @@ -108,10 +107,15 @@ public class VersionControlManagerImpl implements VersionControlManager { allVersionItemVO.addAll(ConvertUtil.list2List(versionControlService.listVersionControlItem(METRIC_BROKER.getCode()), VersionItemVO.class)); allVersionItemVO.addAll(ConvertUtil.list2List(versionControlService.listVersionControlItem(METRIC_PARTITION.getCode()), VersionItemVO.class)); allVersionItemVO.addAll(ConvertUtil.list2List(versionControlService.listVersionControlItem(METRIC_REPLICATION.getCode()), VersionItemVO.class)); + allVersionItemVO.addAll(ConvertUtil.list2List(versionControlService.listVersionControlItem(METRIC_ZOOKEEPER.getCode()), VersionItemVO.class)); allVersionItemVO.addAll(ConvertUtil.list2List(versionControlService.listVersionControlItem(WEB_OP.getCode()), VersionItemVO.class)); Map map = allVersionItemVO.stream().collect( - Collectors.toMap(u -> u.getType() + "@" + u.getName(), Function.identity() )); + Collectors.toMap( + u -> u.getType() + "@" + u.getName(), + Function.identity(), + (v1, v2) -> v1) + ); return Result.buildSuc(map); } diff --git a/km-collector/src/main/java/com/xiaojukeji/know/streaming/km/collector/metric/ReplicaMetricCollector.java b/km-collector/src/main/java/com/xiaojukeji/know/streaming/km/collector/metric/ReplicaMetricCollector.java index 5f712f93..3f9e0035 100644 --- a/km-collector/src/main/java/com/xiaojukeji/know/streaming/km/collector/metric/ReplicaMetricCollector.java +++ b/km-collector/src/main/java/com/xiaojukeji/know/streaming/km/collector/metric/ReplicaMetricCollector.java @@ -91,7 +91,7 @@ public class ReplicaMetricCollector extends AbstractMetricCollector ret = replicaMetricService.collectReplicaMetricsFromKafkaWithCache( + Result ret = replicaMetricService.collectReplicaMetricsFromKafka( clusterPhyId, metrics.getTopic(), metrics.getBrokerId(), diff --git a/km-collector/src/main/java/com/xiaojukeji/know/streaming/km/collector/metric/ZookeeperMetricCollector.java b/km-collector/src/main/java/com/xiaojukeji/know/streaming/km/collector/metric/ZookeeperMetricCollector.java new file mode 100644 index 00000000..37f86d4e --- /dev/null +++ b/km-collector/src/main/java/com/xiaojukeji/know/streaming/km/collector/metric/ZookeeperMetricCollector.java @@ -0,0 +1,122 @@ +package com.xiaojukeji.know.streaming.km.collector.metric; + +import com.didiglobal.logi.log.ILog; +import com.didiglobal.logi.log.LogFactory; +import com.xiaojukeji.know.streaming.km.common.bean.entity.cluster.ClusterPhy; +import com.xiaojukeji.know.streaming.km.common.bean.entity.config.ZKConfig; +import com.xiaojukeji.know.streaming.km.common.bean.entity.kafkacontroller.KafkaController; +import com.xiaojukeji.know.streaming.km.common.bean.entity.param.metric.ZookeeperMetricParam; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; +import com.xiaojukeji.know.streaming.km.common.bean.entity.version.VersionControlItem; +import com.xiaojukeji.know.streaming.km.common.utils.Tuple; +import com.xiaojukeji.know.streaming.km.common.utils.ValidateUtils; +import com.xiaojukeji.know.streaming.km.common.bean.event.metric.ZookeeperMetricEvent; +import com.xiaojukeji.know.streaming.km.common.constant.Constant; +import com.xiaojukeji.know.streaming.km.common.enums.version.VersionItemTypeEnum; +import com.xiaojukeji.know.streaming.km.common.utils.ConvertUtil; +import com.xiaojukeji.know.streaming.km.common.utils.EnvUtil; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.ZookeeperInfo; +import com.xiaojukeji.know.streaming.km.common.bean.entity.metrics.ZookeeperMetrics; +import com.xiaojukeji.know.streaming.km.common.bean.po.metrice.ZookeeperMetricPO; +import com.xiaojukeji.know.streaming.km.core.service.kafkacontroller.KafkaControllerService; +import com.xiaojukeji.know.streaming.km.core.service.version.VersionControlService; +import com.xiaojukeji.know.streaming.km.core.service.zookeeper.ZookeeperMetricService; +import com.xiaojukeji.know.streaming.km.core.service.zookeeper.ZookeeperService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import static com.xiaojukeji.know.streaming.km.common.enums.version.VersionItemTypeEnum.METRIC_ZOOKEEPER; + +/** + * @author didi + */ +@Component +public class ZookeeperMetricCollector extends AbstractMetricCollector { + protected static final ILog LOGGER = LogFactory.getLog("METRIC_LOGGER"); + + @Autowired + private VersionControlService versionControlService; + + @Autowired + private ZookeeperMetricService zookeeperMetricService; + + @Autowired + private ZookeeperService zookeeperService; + + @Autowired + private KafkaControllerService kafkaControllerService; + + @Override + public void collectMetrics(ClusterPhy clusterPhy) { + Long startTime = System.currentTimeMillis(); + Long clusterPhyId = clusterPhy.getId(); + List items = versionControlService.listVersionControlItem(clusterPhyId, collectorType().getCode()); + List aliveZKList = zookeeperService.listFromDBByCluster(clusterPhyId) + .stream() + .filter(elem -> Constant.ALIVE.equals(elem.getStatus())) + .collect(Collectors.toList()); + KafkaController kafkaController = kafkaControllerService.getKafkaControllerFromDB(clusterPhyId); + + ZookeeperMetrics metrics = ZookeeperMetrics.initWithMetric(clusterPhyId, Constant.COLLECT_METRICS_COST_TIME_METRICS_NAME, (float)Constant.INVALID_CODE); + if (ValidateUtils.isEmptyList(aliveZKList)) { + // 没有存活的ZK时,发布事件,然后直接返回 + publishMetric(new ZookeeperMetricEvent(this, Arrays.asList(metrics))); + return; + } + + // 构造参数 + ZookeeperMetricParam param = new ZookeeperMetricParam( + clusterPhyId, + aliveZKList.stream().map(elem -> new Tuple(elem.getHost(), elem.getPort())).collect(Collectors.toList()), + ConvertUtil.str2ObjByJson(clusterPhy.getZkProperties(), ZKConfig.class), + kafkaController == null? Constant.INVALID_CODE: kafkaController.getBrokerId(), + null + ); + + for(VersionControlItem v : items) { + try { + if(null != metrics.getMetrics().get(v.getName())) { + continue; + } + param.setMetricName(v.getName()); + + Result ret = zookeeperMetricService.collectMetricsFromZookeeper(param); + if(null == ret || ret.failed() || null == ret.getData()){ + continue; + } + + metrics.putMetric(ret.getData().getMetrics()); + + if(!EnvUtil.isOnline()){ + LOGGER.info( + "class=ZookeeperMetricCollector||method=collectMetrics||clusterPhyId={}||metricName={}||metricValue={}", + clusterPhyId, v.getName(), ConvertUtil.obj2Json(ret.getData().getMetrics()) + ); + } + } catch (Exception e){ + LOGGER.error( + "class=ZookeeperMetricCollector||method=collectMetrics||clusterPhyId={}||metricName={}||errMsg=exception!", + clusterPhyId, v.getName(), e + ); + } + } + + metrics.putMetric(Constant.COLLECT_METRICS_COST_TIME_METRICS_NAME, (System.currentTimeMillis() - startTime) / 1000.0f); + + publishMetric(new ZookeeperMetricEvent(this, Arrays.asList(metrics))); + + LOGGER.info( + "class=ZookeeperMetricCollector||method=collectMetrics||clusterPhyId={}||startTime={}||costTime={}||msg=msg=collect finished.", + clusterPhyId, startTime, System.currentTimeMillis() - startTime + ); + } + + @Override + public VersionItemTypeEnum collectorType() { + return METRIC_ZOOKEEPER; + } +} diff --git a/km-collector/src/main/java/com/xiaojukeji/know/streaming/km/collector/sink/ZookeeperMetricESSender.java b/km-collector/src/main/java/com/xiaojukeji/know/streaming/km/collector/sink/ZookeeperMetricESSender.java new file mode 100644 index 00000000..4f9dad53 --- /dev/null +++ b/km-collector/src/main/java/com/xiaojukeji/know/streaming/km/collector/sink/ZookeeperMetricESSender.java @@ -0,0 +1,28 @@ +package com.xiaojukeji.know.streaming.km.collector.sink; + +import com.didiglobal.logi.log.ILog; +import com.didiglobal.logi.log.LogFactory; +import com.xiaojukeji.know.streaming.km.common.utils.ConvertUtil; +import com.xiaojukeji.know.streaming.km.common.bean.event.metric.ZookeeperMetricEvent; +import com.xiaojukeji.know.streaming.km.common.bean.po.metrice.ZookeeperMetricPO; +import org.springframework.context.ApplicationListener; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; + +import static com.xiaojukeji.know.streaming.km.common.constant.ESIndexConstant.ZOOKEEPER_INDEX; + +@Component +public class ZookeeperMetricESSender extends AbstractMetricESSender implements ApplicationListener { + protected static final ILog LOGGER = LogFactory.getLog("METRIC_LOGGER"); + + @PostConstruct + public void init(){ + LOGGER.info("class=ZookeeperMetricESSender||method=init||msg=init finished"); + } + + @Override + public void onApplicationEvent(ZookeeperMetricEvent event) { + send2es(ZOOKEEPER_INDEX, ConvertUtil.list2List(event.getZookeeperMetrics(), ZookeeperMetricPO.class)); + } +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/dto/cluster/ClusterGroupSummaryDTO.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/dto/cluster/ClusterGroupSummaryDTO.java new file mode 100644 index 00000000..d199e0d8 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/dto/cluster/ClusterGroupSummaryDTO.java @@ -0,0 +1,18 @@ +package com.xiaojukeji.know.streaming.km.common.bean.dto.cluster; + +import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationBaseDTO; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * @author wyb + * @date 2022/10/17 + */ +@Data +public class ClusterGroupSummaryDTO extends PaginationBaseDTO { + @ApiModelProperty("查找该Topic") + private String searchTopicName; + + @ApiModelProperty("查找该Group") + private String searchGroupName; +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/dto/cluster/ClusterZookeepersOverviewDTO.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/dto/cluster/ClusterZookeepersOverviewDTO.java new file mode 100644 index 00000000..2b3a6e9d --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/dto/cluster/ClusterZookeepersOverviewDTO.java @@ -0,0 +1,13 @@ +package com.xiaojukeji.know.streaming.km.common.bean.dto.cluster; + +import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationBaseDTO; +import lombok.Data; + +/** + * @author wyc + * @date 2022/9/23 + */ +@Data +public class ClusterZookeepersOverviewDTO extends PaginationBaseDTO { + +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/config/ZKConfig.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/config/ZKConfig.java index 39e6fdf5..66a727e5 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/config/ZKConfig.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/config/ZKConfig.java @@ -1,8 +1,8 @@ package com.xiaojukeji.know.streaming.km.common.bean.entity.config; +import com.xiaojukeji.know.streaming.km.common.constant.Constant; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; -import lombok.Data; import java.io.Serializable; import java.util.Properties; @@ -11,7 +11,6 @@ import java.util.Properties; * @author zengqiao * @date 22/02/24 */ -@Data @ApiModel(description = "ZK配置") public class ZKConfig implements Serializable { @ApiModelProperty(value="ZK的jmx配置") @@ -21,11 +20,51 @@ public class ZKConfig implements Serializable { private Boolean openSecure = false; @ApiModelProperty(value="ZK的Session超时时间", example = "15000") - private Long sessionTimeoutUnitMs = 15000L; + private Integer sessionTimeoutUnitMs = 15000; @ApiModelProperty(value="ZK的Request超时时间", example = "5000") - private Long requestTimeoutUnitMs = 5000L; + private Integer requestTimeoutUnitMs = 5000; @ApiModelProperty(value="ZK的Request超时时间") private Properties otherProps = new Properties(); + + public JmxConfig getJmxConfig() { + return jmxConfig == null? new JmxConfig(): jmxConfig; + } + + public void setJmxConfig(JmxConfig jmxConfig) { + this.jmxConfig = jmxConfig; + } + + public Boolean getOpenSecure() { + return openSecure != null && openSecure; + } + + public void setOpenSecure(Boolean openSecure) { + this.openSecure = openSecure; + } + + public Integer getSessionTimeoutUnitMs() { + return sessionTimeoutUnitMs == null? Constant.DEFAULT_SESSION_TIMEOUT_UNIT_MS: sessionTimeoutUnitMs; + } + + public void setSessionTimeoutUnitMs(Integer sessionTimeoutUnitMs) { + this.sessionTimeoutUnitMs = sessionTimeoutUnitMs; + } + + public Integer getRequestTimeoutUnitMs() { + return requestTimeoutUnitMs == null? Constant.DEFAULT_REQUEST_TIMEOUT_UNIT_MS: requestTimeoutUnitMs; + } + + public void setRequestTimeoutUnitMs(Integer requestTimeoutUnitMs) { + this.requestTimeoutUnitMs = requestTimeoutUnitMs; + } + + public Properties getOtherProps() { + return otherProps == null? new Properties() : otherProps; + } + + public void setOtherProps(Properties otherProps) { + this.otherProps = otherProps; + } } diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/group/Group.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/group/Group.java new file mode 100644 index 00000000..3b2e22e9 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/group/Group.java @@ -0,0 +1,74 @@ +package com.xiaojukeji.know.streaming.km.common.bean.entity.group; + +import com.xiaojukeji.know.streaming.km.common.constant.Constant; +import com.xiaojukeji.know.streaming.km.common.enums.group.GroupStateEnum; +import com.xiaojukeji.know.streaming.km.common.enums.group.GroupTypeEnum; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.apache.kafka.clients.admin.ConsumerGroupDescription; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author wyb + * @date 2022/10/10 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class Group { + /** + * 集群id + */ + private Long clusterPhyId; + + /** + * group类型 + * @see GroupTypeEnum + */ + private GroupTypeEnum type; + + /** + * group名称 + */ + private String name; + + /** + * group状态 + * @see GroupStateEnum + */ + private GroupStateEnum state; + + /** + * group成员数量 + */ + private Integer memberCount; + + /** + * group消费的topic列表 + */ + private List topicMembers; + + /** + * group分配策略 + */ + private String partitionAssignor; + + /** + * group协调器brokerId + */ + private int coordinatorId; + + public Group(Long clusterPhyId, String groupName, ConsumerGroupDescription groupDescription) { + this.clusterPhyId = clusterPhyId; + this.type = groupDescription.isSimpleConsumerGroup()? GroupTypeEnum.CONSUMER: GroupTypeEnum.CONNECTOR; + this.name = groupName; + this.state = GroupStateEnum.getByRawState(groupDescription.state()); + this.memberCount = groupDescription.members() == null? 0: groupDescription.members().size(); + this.topicMembers = new ArrayList<>(); + this.partitionAssignor = groupDescription.partitionAssignor(); + this.coordinatorId = groupDescription.coordinator() == null? Constant.INVALID_CODE: groupDescription.coordinator().id(); + } +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/group/GroupTopicMember.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/group/GroupTopicMember.java new file mode 100644 index 00000000..5fe960b1 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/group/GroupTopicMember.java @@ -0,0 +1,27 @@ +package com.xiaojukeji.know.streaming.km.common.bean.entity.group; + +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author wyb + * @date 2022/10/10 + */ +@Data +@NoArgsConstructor +public class GroupTopicMember { + /** + * Topic名称 + */ + private String topicName; + + /** + * 消费此Topic的成员数量 + */ + private Integer memberCount; + + public GroupTopicMember(String topicName, Integer memberCount) { + this.topicName = topicName; + this.memberCount = memberCount; + } +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/metrics/ZookeeperMetrics.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/metrics/ZookeeperMetrics.java new file mode 100644 index 00000000..823125b5 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/metrics/ZookeeperMetrics.java @@ -0,0 +1,28 @@ +package com.xiaojukeji.know.streaming.km.common.bean.entity.metrics; + +import lombok.Data; +import lombok.ToString; + +/** + * @author zengqiao + * @date 20/6/17 + */ +@Data +@ToString +public class ZookeeperMetrics extends BaseMetrics { + public ZookeeperMetrics(Long clusterPhyId) { + super(clusterPhyId); + } + + public static ZookeeperMetrics initWithMetric(Long clusterPhyId, String metric, Float value) { + ZookeeperMetrics metrics = new ZookeeperMetrics(clusterPhyId); + metrics.setClusterPhyId( clusterPhyId ); + metrics.putMetric(metric, value); + return metrics; + } + + @Override + public String unique() { + return "ZK@" + clusterPhyId; + } +} \ No newline at end of file diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/param/metric/ZookeeperMetricParam.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/param/metric/ZookeeperMetricParam.java new file mode 100644 index 00000000..ef2b09c8 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/param/metric/ZookeeperMetricParam.java @@ -0,0 +1,47 @@ +package com.xiaojukeji.know.streaming.km.common.bean.entity.param.metric; + +import com.xiaojukeji.know.streaming.km.common.bean.entity.config.ZKConfig; +import com.xiaojukeji.know.streaming.km.common.utils.Tuple; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * @author didi + */ +@Data +@NoArgsConstructor +public class ZookeeperMetricParam extends MetricParam { + private Long clusterPhyId; + + private List> zkAddressList; + + private ZKConfig zkConfig; + + private String metricName; + + private Integer kafkaControllerId; + + public ZookeeperMetricParam(Long clusterPhyId, + List> zkAddressList, + ZKConfig zkConfig, + String metricName) { + this.clusterPhyId = clusterPhyId; + this.zkAddressList = zkAddressList; + this.zkConfig = zkConfig; + this.metricName = metricName; + } + + public ZookeeperMetricParam(Long clusterPhyId, + List> zkAddressList, + ZKConfig zkConfig, + Integer kafkaControllerId, + String metricName) { + this.clusterPhyId = clusterPhyId; + this.zkAddressList = zkAddressList; + this.zkConfig = zkConfig; + this.kafkaControllerId = kafkaControllerId; + this.metricName = metricName; + } +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/result/ResultStatus.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/result/ResultStatus.java index 842e1106..252146c9 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/result/ResultStatus.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/result/ResultStatus.java @@ -56,6 +56,7 @@ public enum ResultStatus { KAFKA_OPERATE_FAILED(8010, "Kafka操作失败"), MYSQL_OPERATE_FAILED(8020, "MySQL操作失败"), ZK_OPERATE_FAILED(8030, "ZK操作失败"), + ZK_FOUR_LETTER_CMD_FORBIDDEN(8031, "ZK四字命令被禁止"), ES_OPERATE_ERROR(8040, "ES操作失败"), HTTP_REQ_ERROR(8050, "第三方http请求异常"), diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/version/VersionMetricControlItem.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/version/VersionMetricControlItem.java index c7409104..5c3f6506 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/version/VersionMetricControlItem.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/version/VersionMetricControlItem.java @@ -23,6 +23,8 @@ public class VersionMetricControlItem extends VersionControlItem{ public static final String CATEGORY_PERFORMANCE = "Performance"; public static final String CATEGORY_FLOW = "Flow"; + public static final String CATEGORY_CLIENT = "Client"; + /** * 指标单位名称,非指标的没有 */ diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/Znode.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/Znode.java new file mode 100644 index 00000000..0bcb56d2 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/Znode.java @@ -0,0 +1,19 @@ +package com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper; + + +import com.xiaojukeji.know.streaming.km.common.utils.Tuple; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.apache.zookeeper.data.Stat; + +@Data +public class Znode { + @ApiModelProperty(value = "节点名称", example = "broker") + private String name; + + @ApiModelProperty(value = "节点数据", example = "saassad") + private String data; + + @ApiModelProperty(value = "节点属性", example = "") + private Stat stat; +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/ZookeeperInfo.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/ZookeeperInfo.java new file mode 100644 index 00000000..e943952e --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/ZookeeperInfo.java @@ -0,0 +1,42 @@ +package com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper; + +import com.xiaojukeji.know.streaming.km.common.bean.entity.BaseEntity; +import com.xiaojukeji.know.streaming.km.common.constant.Constant; +import lombok.Data; + +@Data +public class ZookeeperInfo extends BaseEntity { + /** + * 集群Id + */ + private Long clusterPhyId; + + /** + * 主机 + */ + private String host; + + /** + * 端口 + */ + private Integer port; + + /** + * 角色 + */ + private String role; + + /** + * 版本 + */ + private String version; + + /** + * ZK状态 + */ + private Integer status; + + public boolean alive() { + return !(Constant.DOWN.equals(status)); + } +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/BaseFourLetterWordCmdData.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/BaseFourLetterWordCmdData.java new file mode 100644 index 00000000..3e5713a8 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/BaseFourLetterWordCmdData.java @@ -0,0 +1,9 @@ +package com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword; + +import java.io.Serializable; + +/** + * 四字命令结果数据的基础类 + */ +public class BaseFourLetterWordCmdData implements Serializable { +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/ConfigCmdData.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/ConfigCmdData.java new file mode 100644 index 00000000..d0982f47 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/ConfigCmdData.java @@ -0,0 +1,38 @@ +package com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword; + +import lombok.Data; + + +/** + * clientPort=2183 + * dataDir=/data1/data/zkData2/version-2 + * dataLogDir=/data1/data/zkLog2/version-2 + * tickTime=2000 + * maxClientCnxns=60 + * minSessionTimeout=4000 + * maxSessionTimeout=40000 + * serverId=2 + * initLimit=15 + * syncLimit=10 + * electionAlg=3 + * electionPort=4445 + * quorumPort=4444 + * peerType=0 + */ +@Data +public class ConfigCmdData extends BaseFourLetterWordCmdData { + private Long clientPort; + private String dataDir; + private String dataLogDir; + private Long tickTime; + private Long maxClientCnxns; + private Long minSessionTimeout; + private Long maxSessionTimeout; + private Integer serverId; + private String initLimit; + private Long syncLimit; + private Long electionAlg; + private Long electionPort; + private Long quorumPort; + private Long peerType; +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/MonitorCmdData.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/MonitorCmdData.java new file mode 100644 index 00000000..2fb3c9da --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/MonitorCmdData.java @@ -0,0 +1,39 @@ +package com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword; + +import lombok.Data; + +/** + * zk_version 3.4.6-1569965, built on 02/20/2014 09:09 GMT + * zk_avg_latency 0 + * zk_max_latency 399 + * zk_min_latency 0 + * zk_packets_received 234857 + * zk_packets_sent 234860 + * zk_num_alive_connections 4 + * zk_outstanding_requests 0 + * zk_server_state follower + * zk_znode_count 35566 + * zk_watch_count 39 + * zk_ephemerals_count 10 + * zk_approximate_data_size 3356708 + * zk_open_file_descriptor_count 35 + * zk_max_file_descriptor_count 819200 + */ +@Data +public class MonitorCmdData extends BaseFourLetterWordCmdData { + private String zkVersion; + private Float zkAvgLatency; + private Long zkMaxLatency; + private Long zkMinLatency; + private Long zkPacketsReceived; + private Long zkPacketsSent; + private Long zkNumAliveConnections; + private Long zkOutstandingRequests; + private String zkServerState; + private Long zkZnodeCount; + private Long zkWatchCount; + private Long zkEphemeralsCount; + private Long zkApproximateDataSize; + private Long zkOpenFileDescriptorCount; + private Long zkMaxFileDescriptorCount; +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/ServerCmdData.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/ServerCmdData.java new file mode 100644 index 00000000..883231d6 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/ServerCmdData.java @@ -0,0 +1,30 @@ +package com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword; + +import lombok.Data; + +/** + * Zookeeper version: 3.5.9-83df9301aa5c2a5d284a9940177808c01bc35cef, built on 01/06/2021 19:49 GMT + * Latency min/avg/max: 0/0/2209 + * Received: 278202469 + * Sent: 279449055 + * Connections: 31 + * Outstanding: 0 + * Zxid: 0x20033fc12 + * Mode: leader + * Node count: 10084 + * Proposal sizes last/min/max: 36/32/31260 leader特有 + */ +@Data +public class ServerCmdData extends BaseFourLetterWordCmdData { + private String zkVersion; + private Float zkAvgLatency; + private Long zkMaxLatency; + private Long zkMinLatency; + private Long zkPacketsReceived; + private Long zkPacketsSent; + private Long zkNumAliveConnections; + private Long zkOutstandingRequests; + private String zkServerState; + private Long zkZnodeCount; + private Long zkZxid; +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/parser/ConfigCmdDataParser.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/parser/ConfigCmdDataParser.java new file mode 100644 index 00000000..35ec153b --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/parser/ConfigCmdDataParser.java @@ -0,0 +1,116 @@ +package com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.parser; + +import com.didiglobal.logi.log.ILog; +import com.didiglobal.logi.log.LogFactory; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.ConfigCmdData; +import com.xiaojukeji.know.streaming.km.common.utils.zookeeper.FourLetterWordUtil; +import lombok.Data; + +import java.util.HashMap; +import java.util.Map; + +/** + * clientPort=2183 + * dataDir=/data1/data/zkData2/version-2 + * dataLogDir=/data1/data/zkLog2/version-2 + * tickTime=2000 + * maxClientCnxns=60 + * minSessionTimeout=4000 + * maxSessionTimeout=40000 + * serverId=2 + * initLimit=15 + * syncLimit=10 + * electionAlg=3 + * electionPort=4445 + * quorumPort=4444 + * peerType=0 + */ +@Data +public class ConfigCmdDataParser implements FourLetterWordDataParser { + private static final ILog LOGGER = LogFactory.getLog(ConfigCmdDataParser.class); + + private Result dataResult = null; + + @Override + public String getCmd() { + return FourLetterWordUtil.ConfigCmd; + } + + @Override + public ConfigCmdData parseAndInitData(Long clusterPhyId, String host, int port, String cmdData) { + Map dataMap = new HashMap<>(); + for (String elem : cmdData.split("\n")) { + if (elem.isEmpty()) { + continue; + } + + int idx = elem.indexOf('='); + if (idx >= 0) { + dataMap.put(elem.substring(0, idx), elem.substring(idx + 1).trim()); + } + } + + ConfigCmdData configCmdData = new ConfigCmdData(); + dataMap.entrySet().stream().forEach(elem -> { + try { + switch (elem.getKey()) { + case "clientPort": + configCmdData.setClientPort(Long.valueOf(elem.getValue())); + break; + case "dataDir": + configCmdData.setDataDir(elem.getValue()); + break; + case "dataLogDir": + configCmdData.setDataLogDir(elem.getValue()); + break; + case "tickTime": + configCmdData.setTickTime(Long.valueOf(elem.getValue())); + break; + case "maxClientCnxns": + configCmdData.setMaxClientCnxns(Long.valueOf(elem.getValue())); + break; + case "minSessionTimeout": + configCmdData.setMinSessionTimeout(Long.valueOf(elem.getValue())); + break; + case "maxSessionTimeout": + configCmdData.setMaxSessionTimeout(Long.valueOf(elem.getValue())); + break; + case "serverId": + configCmdData.setServerId(Integer.valueOf(elem.getValue())); + break; + case "initLimit": + configCmdData.setInitLimit(elem.getValue()); + break; + case "syncLimit": + configCmdData.setSyncLimit(Long.valueOf(elem.getValue())); + break; + case "electionAlg": + configCmdData.setElectionAlg(Long.valueOf(elem.getValue())); + break; + case "electionPort": + configCmdData.setElectionPort(Long.valueOf(elem.getValue())); + break; + case "quorumPort": + configCmdData.setQuorumPort(Long.valueOf(elem.getValue())); + break; + case "peerType": + configCmdData.setPeerType(Long.valueOf(elem.getValue())); + break; + default: + LOGGER.warn( + "class=ConfigCmdDataParser||method=parseAndInitData||name={}||value={}||msg=data not parsed!", + elem.getKey(), elem.getValue() + ); + } + } catch (Exception e) { + LOGGER.error( + "class=ConfigCmdDataParser||method=parseAndInitData||clusterPhyId={}||host={}||port={}||name={}||value={}||errMsg=exception!", + clusterPhyId, host, port, elem.getKey(), elem.getValue(), e + ); + } + }); + + return configCmdData; + } +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/parser/FourLetterWordDataParser.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/parser/FourLetterWordDataParser.java new file mode 100644 index 00000000..58bb2368 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/parser/FourLetterWordDataParser.java @@ -0,0 +1,10 @@ +package com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.parser; + +/** + * 四字命令结果解析类 + */ +public interface FourLetterWordDataParser { + String getCmd(); + + T parseAndInitData(Long clusterPhyId, String host, int port, String cmdData); +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/parser/MonitorCmdDataParser.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/parser/MonitorCmdDataParser.java new file mode 100644 index 00000000..55921c12 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/parser/MonitorCmdDataParser.java @@ -0,0 +1,117 @@ +package com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.parser; + +import com.didiglobal.logi.log.ILog; +import com.didiglobal.logi.log.LogFactory; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.MonitorCmdData; +import com.xiaojukeji.know.streaming.km.common.utils.zookeeper.FourLetterWordUtil; +import lombok.Data; + +import java.util.HashMap; +import java.util.Map; + +/** + * zk_version 3.4.6-1569965, built on 02/20/2014 09:09 GMT + * zk_avg_latency 0 + * zk_max_latency 399 + * zk_min_latency 0 + * zk_packets_received 234857 + * zk_packets_sent 234860 + * zk_num_alive_connections 4 + * zk_outstanding_requests 0 + * zk_server_state follower + * zk_znode_count 35566 + * zk_watch_count 39 + * zk_ephemerals_count 10 + * zk_approximate_data_size 3356708 + * zk_open_file_descriptor_count 35 + * zk_max_file_descriptor_count 819200 + */ +@Data +public class MonitorCmdDataParser implements FourLetterWordDataParser { + private static final ILog LOGGER = LogFactory.getLog(MonitorCmdDataParser.class); + + @Override + public String getCmd() { + return FourLetterWordUtil.MonitorCmd; + } + + @Override + public MonitorCmdData parseAndInitData(Long clusterPhyId, String host, int port, String cmdData) { + Map dataMap = new HashMap<>(); + for (String elem : cmdData.split("\n")) { + if (elem.isEmpty()) { + continue; + } + + int idx = elem.indexOf('\t'); + if (idx >= 0) { + dataMap.put(elem.substring(0, idx), elem.substring(idx + 1).trim()); + } + } + + MonitorCmdData monitorCmdData = new MonitorCmdData(); + dataMap.entrySet().stream().forEach(elem -> { + try { + switch (elem.getKey()) { + case "zk_version": + monitorCmdData.setZkVersion(elem.getValue().split("-")[0]); + break; + case "zk_avg_latency": + monitorCmdData.setZkAvgLatency(Float.valueOf(elem.getValue())); + break; + case "zk_max_latency": + monitorCmdData.setZkMaxLatency(Long.valueOf(elem.getValue())); + break; + case "zk_min_latency": + monitorCmdData.setZkMinLatency(Long.valueOf(elem.getValue())); + break; + case "zk_packets_received": + monitorCmdData.setZkPacketsReceived(Long.valueOf(elem.getValue())); + break; + case "zk_packets_sent": + monitorCmdData.setZkPacketsSent(Long.valueOf(elem.getValue())); + break; + case "zk_num_alive_connections": + monitorCmdData.setZkNumAliveConnections(Long.valueOf(elem.getValue())); + break; + case "zk_outstanding_requests": + monitorCmdData.setZkOutstandingRequests(Long.valueOf(elem.getValue())); + break; + case "zk_server_state": + monitorCmdData.setZkServerState(elem.getValue()); + break; + case "zk_znode_count": + monitorCmdData.setZkZnodeCount(Long.valueOf(elem.getValue())); + break; + case "zk_watch_count": + monitorCmdData.setZkWatchCount(Long.valueOf(elem.getValue())); + break; + case "zk_ephemerals_count": + monitorCmdData.setZkEphemeralsCount(Long.valueOf(elem.getValue())); + break; + case "zk_approximate_data_size": + monitorCmdData.setZkApproximateDataSize(Long.valueOf(elem.getValue())); + break; + case "zk_open_file_descriptor_count": + monitorCmdData.setZkOpenFileDescriptorCount(Long.valueOf(elem.getValue())); + break; + case "zk_max_file_descriptor_count": + monitorCmdData.setZkMaxFileDescriptorCount(Long.valueOf(elem.getValue())); + break; + default: + LOGGER.warn( + "class=MonitorCmdDataParser||method=parseAndInitData||name={}||value={}||msg=data not parsed!", + elem.getKey(), elem.getValue() + ); + } + } catch (Exception e) { + LOGGER.error( + "class=MonitorCmdDataParser||method=parseAndInitData||clusterPhyId={}||host={}||port={}||name={}||value={}||errMsg=exception!", + clusterPhyId, host, port, elem.getKey(), elem.getValue(), e + ); + } + }); + + return monitorCmdData; + } +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/parser/ServerCmdDataParser.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/parser/ServerCmdDataParser.java new file mode 100644 index 00000000..c4cbcd0f --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/parser/ServerCmdDataParser.java @@ -0,0 +1,97 @@ +package com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.parser; + +import com.didiglobal.logi.log.ILog; +import com.didiglobal.logi.log.LogFactory; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.ServerCmdData; +import com.xiaojukeji.know.streaming.km.common.utils.zookeeper.FourLetterWordUtil; +import lombok.Data; + +import java.util.HashMap; +import java.util.Map; + +/** + * Zookeeper version: 3.5.9-83df9301aa5c2a5d284a9940177808c01bc35cef, built on 01/06/2021 19:49 GMT + * Latency min/avg/max: 0/0/2209 + * Received: 278202469 + * Sent: 279449055 + * Connections: 31 + * Outstanding: 0 + * Zxid: 0x20033fc12 + * Mode: leader + * Node count: 10084 + * Proposal sizes last/min/max: 36/32/31260 leader特有 + */ +@Data +public class ServerCmdDataParser implements FourLetterWordDataParser { + private static final ILog LOGGER = LogFactory.getLog(ServerCmdDataParser.class); + + @Override + public String getCmd() { + return FourLetterWordUtil.ServerCmd; + } + + @Override + public ServerCmdData parseAndInitData(Long clusterPhyId, String host, int port, String cmdData) { + Map dataMap = new HashMap<>(); + for (String elem : cmdData.split("\n")) { + if (elem.isEmpty()) { + continue; + } + + int idx = elem.indexOf(':'); + if (idx >= 0) { + dataMap.put(elem.substring(0, idx), elem.substring(idx + 1).trim()); + } + } + + ServerCmdData serverCmdData = new ServerCmdData(); + dataMap.entrySet().stream().forEach(elem -> { + try { + switch (elem.getKey()) { + case "Zookeeper version": + serverCmdData.setZkVersion(elem.getValue().split("-")[0]); + break; + case "Latency min/avg/max": + String[] data = elem.getValue().split("/"); + serverCmdData.setZkMinLatency(Long.valueOf(data[0])); + serverCmdData.setZkAvgLatency(Float.valueOf(data[1])); + serverCmdData.setZkMaxLatency(Long.valueOf(data[2])); + break; + case "Received": + serverCmdData.setZkPacketsReceived(Long.valueOf(elem.getValue())); + break; + case "Sent": + serverCmdData.setZkPacketsSent(Long.valueOf(elem.getValue())); + break; + case "Connections": + serverCmdData.setZkNumAliveConnections(Long.valueOf(elem.getValue())); + break; + case "Outstanding": + serverCmdData.setZkOutstandingRequests(Long.valueOf(elem.getValue())); + break; + case "Mode": + serverCmdData.setZkServerState(elem.getValue()); + break; + case "Node count": + serverCmdData.setZkZnodeCount(Long.valueOf(elem.getValue())); + break; + case "Zxid": + serverCmdData.setZkZxid(Long.parseUnsignedLong(elem.getValue().trim().substring(2), 16)); + break; + default: + LOGGER.warn( + "class=ServerCmdDataParser||method=parseAndInitData||name={}||value={}||msg=data not parsed!", + elem.getKey(), elem.getValue() + ); + } + } catch (Exception e) { + LOGGER.error( + "class=ServerCmdDataParser||method=parseAndInitData||clusterPhyId={}||host={}||port={}||name={}||value={}||errMsg=exception!", + clusterPhyId, host, port, elem.getKey(), elem.getValue(), e + ); + } + }); + + return serverCmdData; + } +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/event/metric/BaseMetricEvent.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/event/metric/BaseMetricEvent.java index df1fe834..cfe5995a 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/event/metric/BaseMetricEvent.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/event/metric/BaseMetricEvent.java @@ -8,8 +8,6 @@ import org.springframework.context.ApplicationEvent; */ @Getter public class BaseMetricEvent extends ApplicationEvent { - - public BaseMetricEvent(Object source) { super( source ); } diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/event/metric/ZookeeperMetricEvent.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/event/metric/ZookeeperMetricEvent.java new file mode 100644 index 00000000..19279d53 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/event/metric/ZookeeperMetricEvent.java @@ -0,0 +1,20 @@ +package com.xiaojukeji.know.streaming.km.common.bean.event.metric; + +import com.xiaojukeji.know.streaming.km.common.bean.entity.metrics.ZookeeperMetrics; +import lombok.Getter; + +import java.util.List; + +/** + * @author didi + */ +@Getter +public class ZookeeperMetricEvent extends BaseMetricEvent { + + private List zookeeperMetrics; + + public ZookeeperMetricEvent(Object source, List zookeeperMetrics) { + super( source ); + this.zookeeperMetrics = zookeeperMetrics; + } +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/po/group/GroupMemberPO.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/po/group/GroupMemberPO.java index 3d999952..7992ac17 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/po/group/GroupMemberPO.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/po/group/GroupMemberPO.java @@ -3,7 +3,6 @@ package com.xiaojukeji.know.streaming.km.common.bean.po.group; import com.baomidou.mybatisplus.annotation.TableName; import com.xiaojukeji.know.streaming.km.common.bean.po.BasePO; import com.xiaojukeji.know.streaming.km.common.constant.Constant; -import com.xiaojukeji.know.streaming.km.common.enums.group.GroupStateEnum; import lombok.Data; import lombok.NoArgsConstructor; @@ -23,12 +22,19 @@ public class GroupMemberPO extends BasePO { private Integer memberCount; - public GroupMemberPO(Long clusterPhyId, String topicName, String groupName, Date updateTime) { + public GroupMemberPO(Long clusterPhyId, String topicName, String groupName, String state, Integer memberCount) { this.clusterPhyId = clusterPhyId; this.topicName = topicName; this.groupName = groupName; - this.state = GroupStateEnum.UNKNOWN.getState(); - this.memberCount = 0; + this.state = state; + this.memberCount = memberCount; + } + public GroupMemberPO(Long clusterPhyId, String topicName, String groupName, String state, Integer memberCount, Date updateTime) { + this.clusterPhyId = clusterPhyId; + this.topicName = topicName; + this.groupName = groupName; + this.state = state; + this.memberCount = memberCount; this.updateTime = updateTime; } } \ No newline at end of file diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/po/group/GroupPO.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/po/group/GroupPO.java new file mode 100644 index 00000000..49ac5bf3 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/po/group/GroupPO.java @@ -0,0 +1,61 @@ +package com.xiaojukeji.know.streaming.km.common.bean.po.group; + + +import com.baomidou.mybatisplus.annotation.TableName; +import com.xiaojukeji.know.streaming.km.common.bean.po.BasePO; +import com.xiaojukeji.know.streaming.km.common.constant.Constant; +import com.xiaojukeji.know.streaming.km.common.enums.group.GroupStateEnum; +import com.xiaojukeji.know.streaming.km.common.enums.group.GroupTypeEnum; +import lombok.Data; +import lombok.NoArgsConstructor; + + +@Data +@NoArgsConstructor +@TableName(Constant.MYSQL_TABLE_NAME_PREFIX + "group") +public class GroupPO extends BasePO { + /** + * 集群id + */ + private Long clusterPhyId; + + /** + * group类型 + * + * @see GroupTypeEnum + */ + private Integer type; + + /** + * group名称 + */ + private String name; + + /** + * group状态 + * + * @see GroupStateEnum + */ + private String state; + + /** + * group成员数量 + */ + private Integer memberCount; + + /** + * group消费的topic列表 + */ + private String topicMembers; + + /** + * group分配策略 + */ + private String partitionAssignor; + + /** + * group协调器brokerId + */ + private int coordinatorId; + +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/po/metrice/ZookeeperMetricPO.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/po/metrice/ZookeeperMetricPO.java new file mode 100644 index 00000000..96921739 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/po/metrice/ZookeeperMetricPO.java @@ -0,0 +1,24 @@ +package com.xiaojukeji.know.streaming.km.common.bean.po.metrice; + +import lombok.Data; +import lombok.NoArgsConstructor; + +import static com.xiaojukeji.know.streaming.km.common.utils.CommonUtils.monitorTimestamp2min; + +@Data +@NoArgsConstructor +public class ZookeeperMetricPO extends BaseMetricESPO { + public ZookeeperMetricPO(Long clusterPhyId){ + super(clusterPhyId); + } + + @Override + public String getKey() { + return "ZK@" + clusterPhyId + "@" + monitorTimestamp2min(timestamp); + } + + @Override + public String getRoutingValue() { + return String.valueOf(clusterPhyId); + } +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/po/zookeeper/ZookeeperInfoPO.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/po/zookeeper/ZookeeperInfoPO.java new file mode 100644 index 00000000..69968ef6 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/po/zookeeper/ZookeeperInfoPO.java @@ -0,0 +1,40 @@ +package com.xiaojukeji.know.streaming.km.common.bean.po.zookeeper; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.xiaojukeji.know.streaming.km.common.bean.po.BasePO; +import com.xiaojukeji.know.streaming.km.common.constant.Constant; +import lombok.Data; + +@Data +@TableName(Constant.MYSQL_TABLE_NAME_PREFIX + "zookeeper") +public class ZookeeperInfoPO extends BasePO { + /** + * 集群Id + */ + private Long clusterPhyId; + + /** + * 主机 + */ + private String host; + + /** + * 端口 + */ + private Integer port; + + /** + * 角色 + */ + private String role; + + /** + * 版本 + */ + private String version; + + /** + * ZK状态 + */ + private Integer status; +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/cluster/res/ClusterBrokersOverviewVO.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/cluster/res/ClusterBrokersOverviewVO.java index be1b529d..b172403c 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/cluster/res/ClusterBrokersOverviewVO.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/cluster/res/ClusterBrokersOverviewVO.java @@ -31,6 +31,9 @@ public class ClusterBrokersOverviewVO extends BrokerMetadataVO { @ApiModelProperty(value = "jmx端口") private Integer jmxPort; + @ApiModelProperty(value = "jmx连接状态 true:连接成功 false:连接失败") + private Boolean jmxConnected; + @ApiModelProperty(value = "是否存活 true:存活 false:不存活") private Boolean alive; } diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/group/GroupOverviewVO.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/group/GroupOverviewVO.java new file mode 100644 index 00000000..df976643 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/group/GroupOverviewVO.java @@ -0,0 +1,27 @@ +package com.xiaojukeji.know.streaming.km.common.bean.vo.group; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +/** + * @author wyb + * @date 2022/10/9 + */ +@Data +@ApiModel(value = "Group信息") +public class GroupOverviewVO { + @ApiModelProperty(value = "Group名称", example = "group-know-streaming-test") + private String name; + + @ApiModelProperty(value = "Group状态", example = "Empty") + private String state; + + @ApiModelProperty(value = "group的成员数", example = "12") + private Integer memberCount; + + @ApiModelProperty(value = "Topic列表", example = "[topic1,topic2]") + private List topicNameList; +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/group/GroupTopicOverviewVO.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/group/GroupTopicOverviewVO.java index 205fb923..40d2f652 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/group/GroupTopicOverviewVO.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/group/GroupTopicOverviewVO.java @@ -10,7 +10,7 @@ import lombok.Data; */ @Data @ApiModel(value = "GroupTopic信息") -public class GroupTopicOverviewVO extends GroupTopicBasicVO{ +public class GroupTopicOverviewVO extends GroupTopicBasicVO { @ApiModelProperty(value = "最大Lag", example = "12345678") private Long maxLag; } diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/metrics/line/MetricMultiLinesVO.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/metrics/line/MetricMultiLinesVO.java index a3874292..917769d2 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/metrics/line/MetricMultiLinesVO.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/metrics/line/MetricMultiLinesVO.java @@ -1,16 +1,12 @@ package com.xiaojukeji.know.streaming.km.common.bean.vo.metrics.line; -import com.xiaojukeji.know.streaming.km.common.bean.vo.metrics.point.MetricPointVO; -import com.xiaojukeji.know.streaming.km.common.utils.ValidateUtils; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; -import java.util.ArrayList; import java.util.List; -import java.util.stream.Collectors; /** * @author didi @@ -26,19 +22,4 @@ public class MetricMultiLinesVO { @ApiModelProperty(value = "指标名称对应的指标线") private List metricLines; - - public List getMetricPoints(String resName) { - if (ValidateUtils.isNull(metricLines)) { - return new ArrayList<>(); - } - - List voList = metricLines.stream().filter(elem -> elem.getName().equals(resName)).collect(Collectors.toList()); - if (ValidateUtils.isEmptyList(voList)) { - return new ArrayList<>(); - } - - // 仅获取idx=0的指标 - return voList.get(0).getMetricPoints(); - } - } diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/zookeeper/ClusterZookeepersOverviewVO.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/zookeeper/ClusterZookeepersOverviewVO.java new file mode 100644 index 00000000..477b3bf4 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/zookeeper/ClusterZookeepersOverviewVO.java @@ -0,0 +1,29 @@ +package com.xiaojukeji.know.streaming.km.common.bean.vo.zookeeper; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * @author wyc + * @date 2022/9/23 + */ +@Data +@ApiModel(description = "Zookeeper信息概览") +public class ClusterZookeepersOverviewVO { + @ApiModelProperty(value = "主机ip", example = "121.0.0.1") + private String host; + + @ApiModelProperty(value = "主机存活状态,1:Live,0:Down", example = "1") + private Integer status; + + @ApiModelProperty(value = "端口号", example = "2416") + private Integer port; + + @ApiModelProperty(value = "版本", example = "1.1.2") + private String version; + + @ApiModelProperty(value = "角色", example = "Leader") + private String role; + +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/zookeeper/ClusterZookeepersStateVO.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/zookeeper/ClusterZookeepersStateVO.java new file mode 100644 index 00000000..ceb2041f --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/zookeeper/ClusterZookeepersStateVO.java @@ -0,0 +1,47 @@ +package com.xiaojukeji.know.streaming.km.common.bean.vo.zookeeper; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + + +/** + * @author wyc + * @date 2022/9/23 + */ +@Data +@ApiModel(description = "ZK状态信息") +public class ClusterZookeepersStateVO { + @ApiModelProperty(value = "健康检查状态", example = "1") + private Integer healthState; + + @ApiModelProperty(value = "健康检查通过数", example = "1") + private Integer healthCheckPassed; + + @ApiModelProperty(value = "健康检查总数", example = "1") + private Integer healthCheckTotal; + + @ApiModelProperty(value = "ZK的Leader机器", example = "127.0.0.1") + private String leaderNode; + + @ApiModelProperty(value = "Watch数", example = "123456") + private Integer watchCount; + + @ApiModelProperty(value = "节点存活数", example = "8") + private Integer aliveServerCount; + + @ApiModelProperty(value = "总节点数", example = "10") + private Integer totalServerCount; + + @ApiModelProperty(value = "Follower角色存活数", example = "8") + private Integer aliveFollowerCount; + + @ApiModelProperty(value = "Follower角色总数", example = "10") + private Integer totalFollowerCount; + + @ApiModelProperty(value = "Observer角色存活数", example = "3") + private Integer aliveObserverCount; + + @ApiModelProperty(value = "Observer角色总数", example = "3") + private Integer totalObserverCount; +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/zookeeper/ZnodeStatVO.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/zookeeper/ZnodeStatVO.java new file mode 100644 index 00000000..c5cd0aa9 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/zookeeper/ZnodeStatVO.java @@ -0,0 +1,44 @@ +package com.xiaojukeji.know.streaming.km.common.bean.vo.zookeeper; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * @author wyc + * @date 2022/9/23 + */ +@Data +public class ZnodeStatVO { + @ApiModelProperty(value = "节点被创建时的事物的ID", example = "0x1f09") + private Long czxid; + + @ApiModelProperty(value = "创建时间", example = "Sat Mar 16 15:38:34 CST 2019") + private Long ctime; + + @ApiModelProperty(value = "节点最后一次被修改时的事物的ID", example = "0x1f09") + private Long mzxid; + + @ApiModelProperty(value = "最后一次修改时间", example = "Sat Mar 16 15:38:34 CST 2019") + private Long mtime; + + @ApiModelProperty(value = "子节点列表最近一次呗修改的事物ID", example = "0x31") + private Long pzxid; + + @ApiModelProperty(value = "子节点版本号", example = "0") + private Integer cversion; + + @ApiModelProperty(value = "数据版本号", example = "0") + private Integer version; + + @ApiModelProperty(value = "ACL版本号", example = "0") + private Integer aversion; + + @ApiModelProperty(value = "创建临时节点的事物ID,持久节点事物为0", example = "0") + private Long ephemeralOwner; + + @ApiModelProperty(value = "数据长度,每个节点都可保存数据", example = "22") + private Integer dataLength; + + @ApiModelProperty(value = "子节点的个数", example = "6") + private Integer numChildren; +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/zookeeper/ZnodeVO.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/zookeeper/ZnodeVO.java new file mode 100644 index 00000000..b00a5ff7 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/zookeeper/ZnodeVO.java @@ -0,0 +1,22 @@ +package com.xiaojukeji.know.streaming.km.common.bean.vo.zookeeper; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * @author wyc + * @date 2022/9/23 + */ +@Data +public class ZnodeVO { + + @ApiModelProperty(value = "节点名称", example = "broker") + private String name; + + @ApiModelProperty(value = "节点数据", example = "saassad") + private String data; + + @ApiModelProperty(value = "节点属性", example = "") + private ZnodeStatVO stat; + +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/Constant.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/Constant.java index edd897ff..639ad0f3 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/Constant.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/Constant.java @@ -23,8 +23,8 @@ public class Constant { public static final Integer YES = 1; public static final Integer NO = 0; - public static final Integer ALIVE = 1; - public static final Integer DOWN = 0; + public static final Integer ALIVE = 1; + public static final Integer DOWN = 0; public static final Integer ONE_HUNDRED = 100; @@ -33,6 +33,7 @@ public class Constant { public static final Long B_TO_MB = 1024L * 1024L; public static final Integer DEFAULT_SESSION_TIMEOUT_UNIT_MS = 15000; + public static final Integer DEFAULT_REQUEST_TIMEOUT_UNIT_MS = 5000; public static final Float MIN_HEALTH_SCORE = 10f; @@ -42,6 +43,7 @@ public class Constant { */ public static final Integer DEFAULT_CLUSTER_HEALTH_SCORE = 90; + public static final Integer PER_BATCH_MAX_VALUE = 100; public static final String DEFAULT_USER_NAME = "know-streaming-app"; @@ -66,4 +68,5 @@ public class Constant { public static final Integer DEFAULT_RETRY_TIME = 3; + public static final Integer ZK_ALIVE_BUT_4_LETTER_FORBIDDEN = 11; } diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/ESConstant.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/ESConstant.java index af8bd2c3..1b8a7740 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/ESConstant.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/ESConstant.java @@ -34,6 +34,8 @@ public class ESConstant { public static final String TOTAL = "total"; + public static final Integer DEFAULT_RETRY_TIME = 3; + private ESConstant() { } } diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/ESIndexConstant.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/ESIndexConstant.java index 0de516f7..1f5654d0 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/ESIndexConstant.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/ESIndexConstant.java @@ -558,7 +558,7 @@ public class ESIndexConstant { public final static String REPLICATION_TEMPLATE = "{\n" + " \"order\" : 10,\n" + " \"index_patterns\" : [\n" + - " \"ks_kafka_partition_metric*\"\n" + + " \"ks_kafka_replication_metric*\"\n" + " ],\n" + " \"settings\" : {\n" + " \"index\" : {\n" + @@ -619,12 +619,13 @@ public class ESIndexConstant { " }\n" + " },\n" + " \"aliases\" : { }\n" + - " }[root@10-255-0-23 template]# cat ks_kafka_replication_metric\n" + - "PUT _template/ks_kafka_replication_metric\n" + - "{\n" + + " }"; + + public final static String ZOOKEEPER_INDEX = "ks_kafka_zookeeper_metric"; + public final static String ZOOKEEPER_TEMPLATE = "{\n" + " \"order\" : 10,\n" + " \"index_patterns\" : [\n" + - " \"ks_kafka_replication_metric*\"\n" + + " \"ks_kafka_zookeeper_metric*\"\n" + " ],\n" + " \"settings\" : {\n" + " \"index\" : {\n" + @@ -633,15 +634,76 @@ public class ESIndexConstant { " },\n" + " \"mappings\" : {\n" + " \"properties\" : {\n" + + " \"routingValue\" : {\n" + + " \"type\" : \"text\",\n" + + " \"fields\" : {\n" + + " \"keyword\" : {\n" + + " \"ignore_above\" : 256,\n" + + " \"type\" : \"keyword\"\n" + + " }\n" + + " }\n" + + " },\n" + + " \"clusterPhyId\" : {\n" + + " \"type\" : \"long\"\n" + + " },\n" + + " \"metrics\" : {\n" + + " \"properties\" : {\n" + + " \"AvgRequestLatency\" : {\n" + + " \"type\" : \"double\"\n" + + " },\n" + + " \"MinRequestLatency\" : {\n" + + " \"type\" : \"double\"\n" + + " },\n" + + " \"MaxRequestLatency\" : {\n" + + " \"type\" : \"double\"\n" + + " },\n" + + " \"OutstandingRequests\" : {\n" + + " \"type\" : \"double\"\n" + + " },\n" + + " \"NodeCount\" : {\n" + + " \"type\" : \"double\"\n" + + " },\n" + + " \"WatchCount\" : {\n" + + " \"type\" : \"double\"\n" + + " },\n" + + " \"NumAliveConnections\" : {\n" + + " \"type\" : \"double\"\n" + + " },\n" + + " \"PacketsReceived\" : {\n" + + " \"type\" : \"double\"\n" + + " },\n" + + " \"PacketsSent\" : {\n" + + " \"type\" : \"double\"\n" + + " },\n" + + " \"EphemeralsCount\" : {\n" + + " \"type\" : \"double\"\n" + + " },\n" + + " \"ApproximateDataSize\" : {\n" + + " \"type\" : \"double\"\n" + + " },\n" + + " \"OpenFileDescriptorCount\" : {\n" + + " \"type\" : \"double\"\n" + + " },\n" + + " \"MaxFileDescriptorCount\" : {\n" + + " \"type\" : \"double\"\n" + + " }\n" + + " }\n" + + " },\n" + + " \"key\" : {\n" + + " \"type\" : \"text\",\n" + + " \"fields\" : {\n" + + " \"keyword\" : {\n" + + " \"ignore_above\" : 256,\n" + + " \"type\" : \"keyword\"\n" + + " }\n" + + " }\n" + + " },\n" + " \"timestamp\" : {\n" + " \"format\" : \"yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis\",\n" + - " \"index\" : true,\n" + - " \"type\" : \"date\",\n" + - " \"doc_values\" : true\n" + + " \"type\" : \"date\"\n" + " }\n" + " }\n" + " },\n" + " \"aliases\" : { }\n" + " }"; - } diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/PaginationConstant.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/PaginationConstant.java index 68dd9358..9b8def80 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/PaginationConstant.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/PaginationConstant.java @@ -18,4 +18,14 @@ public class PaginationConstant { * 默认页大小 */ public static final Integer DEFAULT_PAGE_SIZE = 10; + + /** + * group列表的默认排序规则 + */ + public static final String DEFAULT_GROUP_SORTED_FIELD = "name"; + + /** + * groupTopic列表的默认排序规则 + */ + public static final String DEFAULT_GROUP_TOPIC_SORTED_FIELD = "topicName"; } diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/converter/GroupConverter.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/converter/GroupConverter.java new file mode 100644 index 00000000..131bd243 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/converter/GroupConverter.java @@ -0,0 +1,62 @@ +package com.xiaojukeji.know.streaming.km.common.converter; + +import com.xiaojukeji.know.streaming.km.common.bean.entity.group.Group; +import com.xiaojukeji.know.streaming.km.common.bean.entity.group.GroupTopicMember; +import com.xiaojukeji.know.streaming.km.common.bean.po.group.GroupPO; +import com.xiaojukeji.know.streaming.km.common.bean.vo.group.GroupOverviewVO; +import com.xiaojukeji.know.streaming.km.common.enums.group.GroupStateEnum; +import com.xiaojukeji.know.streaming.km.common.enums.group.GroupTypeEnum; +import com.xiaojukeji.know.streaming.km.common.utils.ConvertUtil; +import com.xiaojukeji.know.streaming.km.common.utils.ValidateUtils; + +import java.util.ArrayList; +import java.util.stream.Collectors; + +/** + * @author wyb + * @date 2022/10/10 + */ +public class GroupConverter { + + private GroupConverter() { + + } + + public static GroupOverviewVO convert2GroupOverviewVO(Group group) { + GroupOverviewVO vo = ConvertUtil.obj2Obj(group, GroupOverviewVO.class); + + vo.setState(group.getState().getState()); + vo.setTopicNameList(group.getTopicMembers().stream().map(elem -> elem.getTopicName()).collect(Collectors.toList())); + + return vo; + } + + public static Group convert2Group(GroupPO po) { + if (po == null) { + return null; + } + + Group group = ConvertUtil.obj2Obj(po, Group.class); + if (!ValidateUtils.isBlank(po.getTopicMembers())) { + group.setTopicMembers(ConvertUtil.str2ObjArrayByJson(po.getTopicMembers(), GroupTopicMember.class)); + } else { + group.setTopicMembers(new ArrayList<>()); + } + + group.setType(GroupTypeEnum.getTypeByCode(po.getType())); + group.setState(GroupStateEnum.getByState(po.getState())); + return group; + } + + public static GroupPO convert2GroupPO(Group group) { + if (group == null) { + return null; + } + + GroupPO po = ConvertUtil.obj2Obj(group, GroupPO.class); + po.setTopicMembers(ConvertUtil.obj2Json(group.getTopicMembers())); + po.setType(group.getType().getCode()); + po.setState(group.getState().getState()); + return po; + } +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/converter/ZnodeConverter.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/converter/ZnodeConverter.java new file mode 100644 index 00000000..9b197358 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/converter/ZnodeConverter.java @@ -0,0 +1,19 @@ +package com.xiaojukeji.know.streaming.km.common.converter; + +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.Znode; +import com.xiaojukeji.know.streaming.km.common.utils.Tuple; +import org.apache.zookeeper.data.Stat; + +public class ZnodeConverter { + ZnodeConverter(){ + + } + + public static Znode convert2Znode(Tuple dataAndStat, String path) { + Znode znode = new Znode(); + znode.setStat(dataAndStat.getV2()); + znode.setData(dataAndStat.getV1() == null ? null : new String(dataAndStat.getV1())); + znode.setName(path.substring(path.lastIndexOf('/') + 1)); + return znode; + } +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/enums/group/GroupTypeEnum.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/enums/group/GroupTypeEnum.java new file mode 100644 index 00000000..ebb91ea1 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/enums/group/GroupTypeEnum.java @@ -0,0 +1,36 @@ +package com.xiaojukeji.know.streaming.km.common.enums.group; + +import lombok.Getter; + +/** + * @author wyb + * @date 2022/10/11 + */ +@Getter +public enum GroupTypeEnum { + + UNKNOWN(-1, "Unknown"), + + CONSUMER(0, "Consumer客户端的消费组"), + + CONNECTOR(1, "Connector的消费组"); + + private final Integer code; + + private final String msg; + + GroupTypeEnum(Integer code, String msg) { + this.code = code; + this.msg = msg; + } + + public static GroupTypeEnum getTypeByCode(Integer code) { + if (code == null) return UNKNOWN; + for (GroupTypeEnum groupTypeEnum : GroupTypeEnum.values()) { + if (groupTypeEnum.code.equals(code)) { + return groupTypeEnum; + } + } + return UNKNOWN; + } +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/enums/health/HealthStateEnum.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/enums/health/HealthStateEnum.java new file mode 100644 index 00000000..a9490fb6 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/enums/health/HealthStateEnum.java @@ -0,0 +1,31 @@ +package com.xiaojukeji.know.streaming.km.common.enums.health; + +import lombok.Getter; + + +/** + * 健康状态 + */ +@Getter +public enum HealthStateEnum { + UNKNOWN(-1, "未知"), + + GOOD(0, "好"), + + MEDIUM(1, "中"), + + POOR(2, "差"), + + DEAD(3, "宕机"), + + ; + + private final int dimension; + + private final String message; + + HealthStateEnum(int dimension, String message) { + this.dimension = dimension; + this.message = message; + } +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/enums/version/VersionItemTypeEnum.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/enums/version/VersionItemTypeEnum.java index 15f13175..004dad6d 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/enums/version/VersionItemTypeEnum.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/enums/version/VersionItemTypeEnum.java @@ -9,7 +9,9 @@ public enum VersionItemTypeEnum { METRIC_GROUP(102, "group_metric"), METRIC_BROKER(103, "broker_metric"), METRIC_PARTITION(104, "partition_metric"), - METRIC_REPLICATION (105, "replication_metric"), + METRIC_REPLICATION(105, "replication_metric"), + + METRIC_ZOOKEEPER(110, "zookeeper_metric"), /** * 服务端查询 diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/enums/zookeeper/ZKRoleEnum.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/enums/zookeeper/ZKRoleEnum.java new file mode 100644 index 00000000..fd379dc8 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/enums/zookeeper/ZKRoleEnum.java @@ -0,0 +1,22 @@ +package com.xiaojukeji.know.streaming.km.common.enums.zookeeper; + +import lombok.Getter; + +@Getter +public enum ZKRoleEnum { + LEADER("leader"), + + FOLLOWER("follower"), + + OBSERVER("observer"), + + UNKNOWN("unknown"), + + ; + + private final String role; + + ZKRoleEnum(String role) { + this.role = role; + } +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/jmx/JmxAttribute.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/jmx/JmxAttribute.java index cc7bfcb4..a9bea1c3 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/jmx/JmxAttribute.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/jmx/JmxAttribute.java @@ -22,6 +22,12 @@ public class JmxAttribute { public static final String PERCENTILE_99 = "99thPercentile"; + public static final String MAX = "Max"; + + public static final String MEAN = "Mean"; + + public static final String MIN = "Min"; + public static final String VALUE = "Value"; public static final String CONNECTION_COUNT = "connection-count"; diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/jmx/JmxName.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/jmx/JmxName.java index d2d1651e..db8b3197 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/jmx/JmxName.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/jmx/JmxName.java @@ -63,6 +63,12 @@ public class JmxName { /*********************************************************** cluster ***********************************************************/ public static final String JMX_CLUSTER_PARTITION_UNDER_REPLICATED = "kafka.cluster:type=Partition,name=UnderReplicated"; + /*********************************************************** zookeeper ***********************************************************/ + + public static final String JMX_ZK_REQUEST_LATENCY_MS = "kafka.server:type=ZooKeeperClientMetrics,name=ZooKeeperRequestLatencyMs"; + public static final String JMX_ZK_SYNC_CONNECTS_PER_SEC = "kafka.server:type=SessionExpireListener,name=ZooKeeperSyncConnectsPerSec"; + public static final String JMX_ZK_DISCONNECTORS_PER_SEC = "kafka.server:type=SessionExpireListener,name=ZooKeeperDisconnectsPerSec"; + private JmxName() { } } diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/utils/ConvertUtil.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/utils/ConvertUtil.java index b20a069c..71b611fd 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/utils/ConvertUtil.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/utils/ConvertUtil.java @@ -389,4 +389,16 @@ public class ConvertUtil { } return null; } + + public static Integer float2Integer(Float f) { + if (null == f) { + return null; + } + try { + return f.intValue(); + } catch (Exception e) { + // ignore exception + } + return null; + } } diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/utils/ValidateUtils.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/utils/ValidateUtils.java index 5060e7ea..fbe94674 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/utils/ValidateUtils.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/utils/ValidateUtils.java @@ -2,6 +2,7 @@ package com.xiaojukeji.know.streaming.km.common.utils; import org.apache.commons.lang.StringUtils; +import java.lang.reflect.Array; import java.util.Arrays; import java.util.List; import java.util.Map; @@ -56,6 +57,18 @@ public class ValidateUtils { return false; } + public static boolean isNotEmpty(T[] array) { + return !isEmpty(array); + } + + public static boolean isEmpty(Object[] array) { + return getLength(array) == 0; + } + + public static int getLength(Object array) { + return array == null ? 0 : Array.getLength(array); + } + /** * 是空字符串 */ @@ -65,7 +78,7 @@ public class ValidateUtils { } else if (isNull(seq1) || isNull(seq2) || seq1.size() != seq2.size()) { return false; } - for (Object elem: seq1) { + for (Object elem : seq1) { if (!seq2.contains(elem)) { return false; } diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/utils/zookeeper/FourLetterWordUtil.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/utils/zookeeper/FourLetterWordUtil.java new file mode 100644 index 00000000..a3ae31af --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/utils/zookeeper/FourLetterWordUtil.java @@ -0,0 +1,163 @@ +package com.xiaojukeji.know.streaming.km.common.utils.zookeeper; + +import com.didiglobal.logi.log.ILog; +import com.didiglobal.logi.log.LogFactory; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.ResultStatus; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.parser.FourLetterWordDataParser; +import com.xiaojukeji.know.streaming.km.common.utils.BackoffUtils; +import com.xiaojukeji.know.streaming.km.common.utils.ValidateUtils; +import org.apache.zookeeper.common.ClientX509Util; +import org.apache.zookeeper.common.X509Exception; +import org.apache.zookeeper.common.X509Util; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.SocketTimeoutException; +import java.util.HashSet; +import java.util.Set; + +public class FourLetterWordUtil { + private static final ILog LOGGER = LogFactory.getLog(FourLetterWordUtil.class); + + public static final String MonitorCmd = "mntr"; + public static final String ConfigCmd = "conf"; + public static final String ServerCmd = "srvr"; + + private static final Set supportedCommands = new HashSet<>(); + + public static Result executeFourLetterCmd(Long clusterPhyId, + String host, + int port, + boolean secure, + int timeout, + FourLetterWordDataParser dataParser) { + try { + if (!supportedCommands.contains(dataParser.getCmd())) { + return Result.buildFromRSAndMsg(ResultStatus.PARAM_ILLEGAL, String.format("ZK %s命令暂未进行支持", dataParser.getCmd())); + } + + String cmdData = send4LetterWord(host, port, dataParser.getCmd(), secure, timeout); + if (cmdData.contains("not executed because it is not in the whitelist.")) { + return Result.buildFromRSAndMsg(ResultStatus.ZK_FOUR_LETTER_CMD_FORBIDDEN, cmdData); + } + if (ValidateUtils.isBlank(cmdData)) { + return Result.buildFromRSAndMsg(ResultStatus.ZK_OPERATE_FAILED, cmdData); + } + + return Result.buildSuc(dataParser.parseAndInitData(clusterPhyId, host, port, cmdData)); + } catch (Exception e) { + LOGGER.error( + "class=FourLetterWordUtil||method=executeFourLetterCmd||clusterPhyId={}||host={}||port={}||cmd={}||secure={}||timeout={}||errMsg=exception!", + clusterPhyId, host, port, dataParser.getCmd(), secure, timeout, e + ); + + return Result.buildFromRSAndMsg(ResultStatus.ZK_OPERATE_FAILED, e.getMessage()); + } + } + + + /**************************************************** private method ****************************************************/ + + private static String send4LetterWord( + String host, + int port, + String cmd, + boolean secure, + int timeout) throws IOException, X509Exception.SSLContextException { + long startTime = System.currentTimeMillis(); + + LOGGER.info("connecting to {} {}", host, port); + + Socket socket = null; + OutputStream outputStream = null; + BufferedReader bufferedReader = null; + try { + InetSocketAddress hostaddress = host != null + ? new InetSocketAddress(host, port) + : new InetSocketAddress(InetAddress.getByName(null), port); + if (secure) { + LOGGER.info("using secure socket"); + try (X509Util x509Util = new ClientX509Util()) { + SSLContext sslContext = x509Util.getDefaultSSLContext(); + SSLSocketFactory socketFactory = sslContext.getSocketFactory(); + SSLSocket sslSock = (SSLSocket) socketFactory.createSocket(); + sslSock.connect(hostaddress, timeout); + sslSock.startHandshake(); + socket = sslSock; + } + } else { + socket = new Socket(); + socket.connect(hostaddress, timeout); + } + socket.setSoTimeout(timeout); + + outputStream = socket.getOutputStream(); + outputStream.write(cmd.getBytes()); + outputStream.flush(); + + // 等待InputStream有数据 + while (System.currentTimeMillis() - startTime <= timeout && socket.getInputStream().available() <= 0) { + BackoffUtils.backoff(10); + } + + bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream())); + StringBuilder sb = new StringBuilder(); + String line; + while ((line = bufferedReader.readLine()) != null) { + sb.append(line).append("\n"); + } + return sb.toString(); + } catch (SocketTimeoutException e) { + throw new IOException("Exception while executing four letter word: " + cmd, e); + } finally { + if (outputStream != null) { + try { + outputStream.close(); + } catch (IOException e) { + LOGGER.error( + "class=FourLetterWordUtil||method=send4LetterWord||clusterPhyId={}||host={}||port={}||cmd={}||secure={}||timeout={}||errMsg=exception!", + host, port, cmd, secure, timeout, e + ); + } + } + + if (bufferedReader != null) { + try { + bufferedReader.close(); + } catch (IOException e) { + LOGGER.error( + "class=FourLetterWordUtil||method=send4LetterWord||host={}||port={}||cmd={}||secure={}||timeout={}||errMsg=exception!", + host, port, cmd, secure, timeout, e + ); + } + } + + if (socket != null) { + try { + socket.close(); + } catch (IOException e) { + LOGGER.error( + "class=FourLetterWordUtil||method=send4LetterWord||host={}||port={}||cmd={}||secure={}||timeout={}||errMsg=exception!", + host, port, cmd, secure, timeout, e + ); + } + } + } + } + + static { + supportedCommands.add(MonitorCmd); + supportedCommands.add(ConfigCmd); + supportedCommands.add(ServerCmd); + } + +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/utils/zookeeper/ZookeeperUtils.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/utils/zookeeper/ZookeeperUtils.java new file mode 100644 index 00000000..9d8c6c5b --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/utils/zookeeper/ZookeeperUtils.java @@ -0,0 +1,59 @@ +package com.xiaojukeji.know.streaming.km.common.utils.zookeeper; + +import com.xiaojukeji.know.streaming.km.common.utils.Tuple; +import org.apache.zookeeper.client.ConnectStringParser; +import org.apache.zookeeper.common.NetUtils; + +import java.util.ArrayList; +import java.util.List; + +import static org.apache.zookeeper.common.StringUtils.split; + +public class ZookeeperUtils { + private static final int DEFAULT_PORT = 2181; + + /** + * 解析ZK地址 + * @see ConnectStringParser + */ + public static List> connectStringParser(String connectString) throws Exception { + List> ipPortList = new ArrayList<>(); + + if (connectString == null) { + return ipPortList; + } + + // parse out chroot, if any + int off = connectString.indexOf('/'); + if (off >= 0) { + connectString = connectString.substring(0, off); + } + + List hostsList = split(connectString, ","); + for (String host : hostsList) { + int port = DEFAULT_PORT; + String[] hostAndPort = NetUtils.getIPV6HostAndPort(host); + if (hostAndPort.length != 0) { + host = hostAndPort[0]; + if (hostAndPort.length == 2) { + port = Integer.parseInt(hostAndPort[1]); + } + } else { + int pidx = host.lastIndexOf(':'); + if (pidx >= 0) { + // otherwise : is at the end of the string, ignore + if (pidx < host.length() - 1) { + port = Integer.parseInt(host.substring(pidx + 1)); + } + host = host.substring(0, pidx); + } + } + + ipPortList.add(new Tuple<>(host, port)); + } + + return ipPortList; + } + + +} diff --git a/km-console/packages/config-manager-fe/package-lock.json b/km-console/packages/config-manager-fe/package-lock.json index bf0a4f18..08574fb2 100644 --- a/km-console/packages/config-manager-fe/package-lock.json +++ b/km-console/packages/config-manager-fe/package-lock.json @@ -12241,9 +12241,9 @@ "dev": true }, "typescript": { - "version": "3.9.10", - "resolved": "https://registry.npmmirror.com/typescript/-/typescript-3.9.10.tgz", - "integrity": "sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==", + "version": "4.6.4", + "resolved": "https://registry.npmmirror.com/typescript/-/typescript-4.6.4.tgz", + "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==", "dev": true }, "unbox-primitive": { diff --git a/km-console/packages/config-manager-fe/package.json b/km-console/packages/config-manager-fe/package.json index 945e8b5c..013ffec0 100644 --- a/km-console/packages/config-manager-fe/package.json +++ b/km-console/packages/config-manager-fe/package.json @@ -95,7 +95,7 @@ "react-router-dom": "5.2.1", "stats-webpack-plugin": "^0.7.0", "ts-loader": "^8.0.11", - "typescript": "^3.5.3", + "typescript": "4.6.4", "webpack": "^4.40.0", "webpack-bundle-analyzer": "^4.5.0", "webpack-cli": "^3.2.3", diff --git a/km-console/packages/config-manager-fe/src/components/Message/index.tsx b/km-console/packages/config-manager-fe/src/components/Message/index.tsx new file mode 100644 index 00000000..5791939c --- /dev/null +++ b/km-console/packages/config-manager-fe/src/components/Message/index.tsx @@ -0,0 +1,54 @@ +import React from 'react'; +import { IconFont } from '@knowdesign/icons'; +import { message } from 'knowdesign'; +import { ArgsProps, ConfigOnClose } from 'knowdesign/es/basic/message'; + +type ConfigContent = React.ReactNode; +type ConfigDuration = number | (() => void); +type JointContent = ConfigContent | ArgsProps; + +message.config({ + top: 16, +}); + +function isArgsProps(content: JointContent): content is ArgsProps { + return Object.prototype.toString.call(content) === '[object Object]' && !!(content as ArgsProps).content; +} + +const openMessage = ( + type: 'info' | 'success' | 'warning' | 'error', + content: JointContent, + duration?: ConfigDuration, + onClose?: ConfigOnClose +) => { + if (isArgsProps(content)) { + message[type]({ + icon: , + ...content, + }); + } else { + message[type]({ + icon: , + content, + duration, + onClose, + }); + } +}; + +const customMessage = { + info(content: JointContent, duration?: ConfigDuration, onClose?: ConfigOnClose) { + openMessage('info', content, duration, onClose); + }, + success(content: JointContent, duration?: ConfigDuration, onClose?: ConfigOnClose) { + openMessage('success', content, duration, onClose); + }, + warning(content: JointContent, duration?: ConfigDuration, onClose?: ConfigOnClose) { + openMessage('warning', content, duration, onClose); + }, + error(content: JointContent, duration?: ConfigDuration, onClose?: ConfigOnClose) { + openMessage('error', content, duration, onClose); + }, +}; + +export default customMessage; diff --git a/km-console/packages/config-manager-fe/src/components/Notification/index.tsx b/km-console/packages/config-manager-fe/src/components/Notification/index.tsx new file mode 100644 index 00000000..9673d511 --- /dev/null +++ b/km-console/packages/config-manager-fe/src/components/Notification/index.tsx @@ -0,0 +1,33 @@ +import React from 'react'; +import { notification } from 'knowdesign'; +import { ArgsProps } from 'knowdesign/es/basic/notification'; +import { IconFont } from '@knowdesign/icons'; + +notification.config({ + top: 16, + duration: 3, +}); + +const open = (type: 'info' | 'success' | 'warning' | 'error', content: ArgsProps) => { + notification[type]({ + icon: , + ...content, + }); +}; + +const customNotification = { + info(content: ArgsProps) { + open('info', content); + }, + success(content: ArgsProps) { + open('success', content); + }, + warning(content: ArgsProps) { + open('warning', content); + }, + error(content: ArgsProps) { + open('error', content); + }, +}; + +export default customNotification; diff --git a/km-console/packages/config-manager-fe/src/constants/axiosConfig.ts b/km-console/packages/config-manager-fe/src/constants/axiosConfig.ts index 3e05e105..b99fd274 100644 --- a/km-console/packages/config-manager-fe/src/constants/axiosConfig.ts +++ b/km-console/packages/config-manager-fe/src/constants/axiosConfig.ts @@ -1,7 +1,8 @@ /* eslint-disable @typescript-eslint/ban-ts-comment */ // @ts-nocheck -import { notification, Utils } from 'knowdesign'; +import { Utils } from 'knowdesign'; +import notification from '@src/components/Notification'; export const goLogin = () => { if (!window.location.pathname.toLowerCase().startsWith('/login')) { @@ -37,10 +38,9 @@ serviceInstance.interceptors.response.use( (config: any) => { const res: { code: number; message: string; data: any } = config.data; if (res.code !== 0 && res.code !== 200) { - const desc = res.message; notification.error({ - message: desc, - duration: 3, + message: '错误信息', + description: res.message, }); throw res; } diff --git a/km-console/packages/config-manager-fe/src/pages/ConfigManage/index.tsx b/km-console/packages/config-manager-fe/src/pages/ConfigManage/index.tsx index 1430fbb6..3c85fdf5 100644 --- a/km-console/packages/config-manager-fe/src/pages/ConfigManage/index.tsx +++ b/km-console/packages/config-manager-fe/src/pages/ConfigManage/index.tsx @@ -1,20 +1,6 @@ import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState } from 'react'; -import { - Button, - Form, - Input, - Select, - Switch, - Modal, - message, - ProTable, - Drawer, - Space, - Divider, - Tooltip, - AppContainer, - Utils, -} from 'knowdesign'; +import { Button, Form, Input, Select, Switch, Modal, ProTable, Drawer, Space, Divider, Tooltip, AppContainer, Utils } from 'knowdesign'; +import message from '@src/components/Message'; import { IconFont } from '@knowdesign/icons'; import { PlusOutlined } from '@ant-design/icons'; import moment from 'moment'; @@ -81,7 +67,7 @@ const EditConfigDrawer = forwardRef((_, ref) => { // 如果内容可以格式化为 JSON,进行处理 config.value = JSON.stringify(JSON.parse(config.value), null, 2); } catch (_) { - return; + // } } form.setFieldsValue({ ...config, status: config.status === 1 }); @@ -476,7 +462,7 @@ export default () => { rowKey: 'id', dataSource: data, paginationProps: pagination, - columns, + columns: columns as any, lineFillColor: true, attrs: { onChange: onTableChange, diff --git a/km-console/packages/config-manager-fe/src/pages/UserManage/RoleTabContent.tsx b/km-console/packages/config-manager-fe/src/pages/UserManage/RoleTabContent.tsx index 5adeac58..f7db974b 100644 --- a/km-console/packages/config-manager-fe/src/pages/UserManage/RoleTabContent.tsx +++ b/km-console/packages/config-manager-fe/src/pages/UserManage/RoleTabContent.tsx @@ -11,7 +11,6 @@ import { Transfer, Row, Col, - message, Tooltip, Spin, AppContainer, @@ -19,6 +18,7 @@ import { Popover, IconFont, } from 'knowdesign'; +import message from '@src/components/Message'; import moment from 'moment'; import { LoadingOutlined, PlusOutlined } from '@ant-design/icons'; import { defaultPagination } from '@src/constants/common'; diff --git a/km-console/packages/config-manager-fe/src/pages/UserManage/UserTabContent.tsx b/km-console/packages/config-manager-fe/src/pages/UserManage/UserTabContent.tsx index 34bf6180..0ca3ca29 100644 --- a/km-console/packages/config-manager-fe/src/pages/UserManage/UserTabContent.tsx +++ b/km-console/packages/config-manager-fe/src/pages/UserManage/UserTabContent.tsx @@ -1,5 +1,6 @@ import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState } from 'react'; -import { Form, ProTable, Select, Button, Input, Modal, message, Drawer, Space, Divider, AppContainer, Utils } from 'knowdesign'; +import { Form, ProTable, Select, Button, Input, Modal, Drawer, Space, Divider, AppContainer, Utils } from 'knowdesign'; +import message from '@src/components/Message'; import { IconFont } from '@knowdesign/icons'; import { PlusOutlined, QuestionCircleOutlined } from '@ant-design/icons'; import moment from 'moment'; diff --git a/km-console/packages/layout-clusters-fe/package-lock.json b/km-console/packages/layout-clusters-fe/package-lock.json index 307d3d6e..dfb11c4b 100644 --- a/km-console/packages/layout-clusters-fe/package-lock.json +++ b/km-console/packages/layout-clusters-fe/package-lock.json @@ -13341,9 +13341,9 @@ "dev": true }, "typescript": { - "version": "3.9.10", - "resolved": "https://registry.npmmirror.com/typescript/-/typescript-3.9.10.tgz", - "integrity": "sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==", + "version": "4.6.4", + "resolved": "https://registry.npmmirror.com/typescript/-/typescript-4.6.4.tgz", + "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==", "dev": true }, "ua-parser-js": { diff --git a/km-console/packages/layout-clusters-fe/package.json b/km-console/packages/layout-clusters-fe/package.json index 732d9c7f..cee05daa 100644 --- a/km-console/packages/layout-clusters-fe/package.json +++ b/km-console/packages/layout-clusters-fe/package.json @@ -111,7 +111,7 @@ "react-refresh": "^0.10.0", "react-router-dom": "5.2.1", "ts-loader": "^8.0.11", - "typescript": "^3.8.2", + "typescript": "4.6.4", "webpack": "^4.40.0", "webpack-cli": "^3.2.3", "webpack-dev-server": "^3.2.1", diff --git a/km-console/packages/layout-clusters-fe/src/api/index.ts b/km-console/packages/layout-clusters-fe/src/api/index.ts index d3e48939..bbf11d0a 100755 --- a/km-console/packages/layout-clusters-fe/src/api/index.ts +++ b/km-console/packages/layout-clusters-fe/src/api/index.ts @@ -14,6 +14,7 @@ export enum MetricType { Broker = 103, Partition = 104, Replication = 105, + Zookeeper = 110, Controls = 901, } @@ -61,6 +62,8 @@ const api = { phyClusterState: getApi(`/physical-clusters/state`), getOperatingStateList: (clusterPhyId: number) => getApi(`/clusters/${clusterPhyId}/groups-overview`), + getGroupTopicList: (clusterPhyId: number, groupName: string) => getApi(`/clusters/${clusterPhyId}/groups/${groupName}/topics-overview`), + // 物理集群接口 phyCluster: getApi(`/physical-clusters`), getPhyClusterBasic: (clusterPhyId: number) => getApi(`/physical-clusters/${clusterPhyId}/basic`), @@ -127,6 +130,7 @@ const api = { getApi(`/clusters/${clusterPhyId}/topics/${topicName}/brokers-partitions-summary`), getTopicPartitionsDetail: (clusterPhyId: string, topicName: string) => getApi(`/clusters/${clusterPhyId}/topics/${topicName}/partitions`), getTopicMessagesList: (topicName: string, clusterPhyId: number) => getApi(`/clusters/${clusterPhyId}/topics/${topicName}/records`), // Messages列表 + getTopicGroupList: (topicName: string, clusterPhyId: number) => getApi(`/clusters/${clusterPhyId}/topics/${topicName}/groups-overview`), // Consumers列表 getTopicMessagesMetadata: (topicName: string, clusterPhyId: number) => getApi(`/clusters//${clusterPhyId}/topics/${topicName}/metadata`), // Messages列表 getTopicACLsList: (topicName: string, clusterPhyId: number) => getApi(`/clusters/${clusterPhyId}/topics/${topicName}/acl-Bindings`), // ACLs列表 getTopicConfigs: (topicName: string, clusterPhyId: number) => getApi(`/clusters/${clusterPhyId}/config-topics/${topicName}/configs`), // Configuration列表 diff --git a/km-console/packages/layout-clusters-fe/src/components/CardBar/index.tsx b/km-console/packages/layout-clusters-fe/src/components/CardBar/index.tsx index 954839cd..0de8e813 100644 --- a/km-console/packages/layout-clusters-fe/src/components/CardBar/index.tsx +++ b/km-console/packages/layout-clusters-fe/src/components/CardBar/index.tsx @@ -138,7 +138,7 @@ const CardBar = (props: CardBarProps) => { dataIndex: 'updateTime', key: 'updateTime', render: (value: number) => { - return moment(value).format('YYYY-MM-DD hh:mm:ss'); + return moment(value).format('YYYY-MM-DD HH:mm:ss'); }, }, { diff --git a/km-console/packages/layout-clusters-fe/src/components/SingleChartHeader/IndicatorDrawer.tsx b/km-console/packages/layout-clusters-fe/src/components/ChartOperateBar/MetricSelect.tsx similarity index 83% rename from km-console/packages/layout-clusters-fe/src/components/SingleChartHeader/IndicatorDrawer.tsx rename to km-console/packages/layout-clusters-fe/src/components/ChartOperateBar/MetricSelect.tsx index 9c7a4833..badae226 100644 --- a/km-console/packages/layout-clusters-fe/src/components/SingleChartHeader/IndicatorDrawer.tsx +++ b/km-console/packages/layout-clusters-fe/src/components/ChartOperateBar/MetricSelect.tsx @@ -1,15 +1,12 @@ -import React, { useState, useEffect } from 'react'; -import { Drawer, Button, Space, Divider, AppContainer, ProTable } from 'knowdesign'; +import React, { useState, useEffect, forwardRef, useImperativeHandle } from 'react'; +import { Drawer, Button, Space, Divider, AppContainer, ProTable, Utils } from 'knowdesign'; import { IconFont } from '@knowdesign/icons'; -import { IindicatorSelectModule } from './index'; +import { MetricSelect } from './index'; import './style/indicator-drawer.less'; import { useLocation } from 'react-router-dom'; interface PropsType extends React.HTMLAttributes { - onClose: () => void; - visible: boolean; - isGroup?: boolean; // 是否分组 - indicatorSelectModule: IindicatorSelectModule; + metricSelect: MetricSelect; } interface MetricInfo { @@ -27,25 +24,25 @@ type CategoryData = { metrics: MetricInfo[]; }; -const ExpandedRow = ({ metrics, category, selectedMetrics, selectedMetricChange }: any) => { - const innerColumns = [ - { - title: '指标名称', - dataIndex: 'name', - key: 'name', - }, - { - title: '单位', - dataIndex: 'unit', - key: 'unit', - }, - { - title: '描述', - dataIndex: 'desc', - key: 'desc', - }, - ]; +const expandedRowColumns = [ + { + title: '指标名称', + dataIndex: 'name', + key: 'name', + }, + { + title: '单位', + dataIndex: 'unit', + key: 'unit', + }, + { + title: '描述', + dataIndex: 'desc', + key: 'desc', + }, +]; +const ExpandedRow = ({ metrics, category, selectedMetrics, selectedMetricChange }: any) => { return (
{ +const MetricSelect = forwardRef(({ metricSelect }: PropsType, ref) => { const [global] = AppContainer.useGlobalValue(); const { pathname } = useLocation(); const [confirmLoading, setConfirmLoading] = useState(false); const [categoryData, setCategoryData] = useState([]); const [selectedCategories, setSelectedCategories] = useState([]); const [childrenSelectedRowKeys, setChildrenSelectedRowKeys] = useState({}); + const [visible, setVisible] = useState(false); const columns = [ { @@ -96,13 +94,13 @@ const IndicatorDrawer = ({ onClose, visible, indicatorSelectModule }: PropsType) ]; const formateTableData = () => { - const tableData = indicatorSelectModule.tableData; + const tableData = metricSelect.tableData; const categoryData: { [category: string]: MetricInfo[]; } = {}; tableData.forEach(({ name, desc }) => { - const metricDefine = global.getMetricDefine(indicatorSelectModule?.metricType, name); + const metricDefine = global.getMetricDefine(metricSelect?.metricType, name); const returnData = { name, desc, @@ -125,12 +123,12 @@ const IndicatorDrawer = ({ onClose, visible, indicatorSelectModule }: PropsType) }; const formateSelectedKeys = () => { - const newKeys = indicatorSelectModule.selectedRows; + const newKeys = metricSelect.selectedRows; const result: SelectedMetrics = {}; const selectedCategories: string[] = []; newKeys.forEach((name: string) => { - const metricDefine = global.getMetricDefine(indicatorSelectModule?.metricType, name); + const metricDefine = global.getMetricDefine(metricSelect?.metricType, name); if (metricDefine) { if (!result[metricDefine.category]) { result[metricDefine.category] = [name]; @@ -217,10 +215,10 @@ const IndicatorDrawer = ({ onClose, visible, indicatorSelectModule }: PropsType) const allRowKeys: string[] = []; Object.entries(childrenSelectedRowKeys).forEach(([, arr]) => allRowKeys.push(...arr)); - indicatorSelectModule.submitCallback(allRowKeys).then( + metricSelect.submitCallback(allRowKeys).then( () => { setConfirmLoading(false); - onClose(); + setVisible(false); }, () => { setConfirmLoading(false); @@ -231,7 +229,7 @@ const IndicatorDrawer = ({ onClose, visible, indicatorSelectModule }: PropsType) const rowSelection = { selectedRowKeys: selectedCategories, onChange: rowChange, - // getCheckboxProps: (record: any) => indicatorSelectModule.checkboxProps && indicatorSelectModule.checkboxProps(record), + // getCheckboxProps: (record: any) => metricSelect.checkboxProps && metricSelect.checkboxProps(record), getCheckboxProps: (record: CategoryData) => { const isAllSelected = record.metrics.length === childrenSelectedRowKeys[record.category]?.length; const isNotCheck = !childrenSelectedRowKeys[record.category] || childrenSelectedRowKeys[record.category]?.length === 0; @@ -241,25 +239,33 @@ const IndicatorDrawer = ({ onClose, visible, indicatorSelectModule }: PropsType) }, }; - useEffect(formateTableData, [indicatorSelectModule.tableData]); + useEffect(formateTableData, [metricSelect.tableData]); useEffect(() => { visible && formateSelectedKeys(); - }, [visible, indicatorSelectModule.selectedRows]); + }, [visible, metricSelect.selectedRows]); + + useImperativeHandle( + ref, + () => ({ + open: () => setVisible(true), + }), + [] + ); return ( <> setVisible(false)} visible={visible} maskClosable={false} extra={ -
-
-
{scopeLabel}
-
-
- - 全选 - - } - size="small" - placeholder={searchPlaceholder} - onChange={(e) => setScopeSearchValue(e.target.value)} - /> -
-
- - - {customList - .filter((item) => item.label.includes(scopeSearchValue)) - .map((item) => ( - - {item.label} - - ))} - - -
+ {hasCustomScope && ( +
+
{scopeLabel}
+
+
+ + 全选 + + } + size="small" + placeholder={searchPlaceholder} + onChange={(e) => setScopeSearchValue(e.target.value)} + /> +
+
+ + + {customList + .filter((item) => item.label.includes(scopeSearchValue)) + .map((item) => ( + + {item.label} + + ))} + + +
-
- - +
+ + +
-
+ )}
); @@ -185,7 +188,7 @@ const NodeScope = ({ nodeScopeModule, change }: propsType) => { visible={popVisible} content={clickContent} placement="bottomRight" - overlayClassName="d-node-scope-popover" + overlayClassName={`d-node-scope-popover ${hasCustomScope ? 'large-size' : ''}`} onVisibleChange={visibleChange} > diff --git a/km-console/packages/layout-clusters-fe/src/components/SingleChartHeader/image/empty.png b/km-console/packages/layout-clusters-fe/src/components/ChartOperateBar/image/empty.png similarity index 100% rename from km-console/packages/layout-clusters-fe/src/components/SingleChartHeader/image/empty.png rename to km-console/packages/layout-clusters-fe/src/components/ChartOperateBar/image/empty.png diff --git a/km-console/packages/layout-clusters-fe/src/components/SingleChartHeader/index.tsx b/km-console/packages/layout-clusters-fe/src/components/ChartOperateBar/index.tsx similarity index 80% rename from km-console/packages/layout-clusters-fe/src/components/SingleChartHeader/index.tsx rename to km-console/packages/layout-clusters-fe/src/components/ChartOperateBar/index.tsx index 5284093b..42d66366 100644 --- a/km-console/packages/layout-clusters-fe/src/components/SingleChartHeader/index.tsx +++ b/km-console/packages/layout-clusters-fe/src/components/ChartOperateBar/index.tsx @@ -1,9 +1,9 @@ -import React, { useEffect, useState } from 'react'; -import { Tooltip, Select, Utils, Divider, Button } from 'knowdesign'; +import React, { useEffect, useRef, useState } from 'react'; +import { Select, Divider, Button } from 'knowdesign'; import { IconFont } from '@knowdesign/icons'; import moment from 'moment'; import { DRangeTime } from 'knowdesign'; -import IndicatorDrawer from './IndicatorDrawer'; +import MetricSelect from './MetricSelect'; import NodeScope from './NodeScope'; import './style/index.less'; @@ -24,8 +24,8 @@ export interface KsHeaderOptions { data: number | number[]; }; } -export interface IindicatorSelectModule { - metricType?: MetricType; +export interface MetricSelect { + metricType: MetricType; hide?: boolean; drawerTitle?: string; selectedRows: (string | number)[]; @@ -47,20 +47,27 @@ export interface IcustomScope { } export interface InodeScopeModule { + hasCustomScope: boolean; customScopeList: IcustomScope[]; scopeName?: string; scopeLabel?: string; searchPlaceholder?: string; change?: () => void; } + interface PropsType { - indicatorSelectModule?: IindicatorSelectModule; + metricSelect?: MetricSelect; hideNodeScope?: boolean; hideGridSelect?: boolean; nodeScopeModule?: InodeScopeModule; onChange: (options: KsHeaderOptions) => void; } +interface ScopeData { + isTop: boolean; + data: any; +} + // 列布局选项 const GRID_SIZE_OPTIONS = [ { @@ -77,15 +84,17 @@ const GRID_SIZE_OPTIONS = [ }, ]; -const SingleChartHeader = ({ - indicatorSelectModule, +const MetricOperateBar = ({ + metricSelect, nodeScopeModule = { + hasCustomScope: false, customScopeList: [], }, hideNodeScope = false, hideGridSelect = false, onChange: onChangeCallback, }: PropsType): JSX.Element => { + const metricSelectRef = useRef(null); const [gridNum, setGridNum] = useState(GRID_SIZE_OPTIONS[1].value); const [rangeTime, setRangeTime] = useState<[number, number]>(() => { const curTimeStamp = moment().valueOf(); @@ -93,16 +102,35 @@ const SingleChartHeader = ({ }); const [isRelativeRangeTime, setIsRelativeRangeTime] = useState(true); const [isAutoReload, setIsAutoReload] = useState(false); - const [indicatorDrawerVisible, setIndicatorDrawerVisible] = useState(false); - - const [scopeData, setScopeData] = useState<{ - isTop: boolean; - data: any; - }>({ + const [scopeData, setScopeData] = useState({ isTop: true, data: 5, }); + const sizeChange = (value: number) => setGridNum(value); + + const timeChange = (curRangeTime: [number, number], isRelative: boolean) => { + setRangeTime([...curRangeTime]); + setIsRelativeRangeTime(isRelative); + }; + + const reloadRangeTime = () => { + if (isRelativeRangeTime) { + const timeLen = rangeTime[1] - rangeTime[0] || 0; + const curTimeStamp = moment().valueOf(); + setRangeTime([curTimeStamp - timeLen, curTimeStamp]); + } else { + setRangeTime([...rangeTime]); + } + }; + + const nodeScopeChange = (data: any, isTop?: any) => { + setScopeData({ + isTop, + data, + }); + }; + useEffect(() => { onChangeCallback({ rangeTime, @@ -129,68 +157,37 @@ const SingleChartHeader = ({ }; }, [isRelativeRangeTime, rangeTime]); - const sizeChange = (value: number) => { - setGridNum(value); - }; - - const timeChange = (curRangeTime: [number, number], isRelative: boolean) => { - setRangeTime([...curRangeTime]); - setIsRelativeRangeTime(isRelative); - }; - - const reloadRangeTime = () => { - if (isRelativeRangeTime) { - const timeLen = rangeTime[1] - rangeTime[0] || 0; - const curTimeStamp = moment().valueOf(); - setRangeTime([curTimeStamp - timeLen, curTimeStamp]); - } else { - setRangeTime([...rangeTime]); - } - }; - - const openIndicatorDrawer = () => { - setIndicatorDrawerVisible(true); - }; - - const closeIndicatorDrawer = () => { - setIndicatorDrawerVisible(false); - }; - - const nodeScopeChange = (data: any, isTop?: any) => { - setScopeData({ - isTop, - data, - }); - }; - return ( <>
+ {/* 刷新 */}
+ {/* 时间选择 */}
+ {/* 节点范围 */} {!hideNodeScope && } + {/* 分栏 */} {!hideGridSelect && ( { + setCurPartition(id); + }} + > + + {partitionList.map((partition) => ( + + ))} + + )} + {showMode === 'chart' && ( + { + setTimeRange(o); + }} + > + )} + {showMode === 'chart' &&
} + setShowMode(key)}> + +
+ +
+
+ +
+ +
+
+
+
+
+ {showMode === 'table' && ( + + )} + {showMode === 'chart' && ( +
+ { + return data.map((metricData: any) => { + const partitionMetricData = metricData.metricLine?.metricPoints || []; + return { + name: metricData.metricName, + data: partitionMetricData.map((item: any) => [item.timeStamp, item.value, item.unit]), + lineStyle: { + width: 1.5, + }, + smooth: 0.25, + symbol: 'emptyCircle', + symbolSize: 4, + emphasis: { + disabled: true, + }, + }; + }); + }} + /> +
+ )} +
+ + ); +}; diff --git a/km-console/packages/layout-clusters-fe/src/pages/ConsumerGroup/ResetOffsetDrawer.tsx b/km-console/packages/layout-clusters-fe/src/pages/ConsumerGroup/ResetOffsetDrawer.tsx new file mode 100644 index 00000000..b03f6832 --- /dev/null +++ b/km-console/packages/layout-clusters-fe/src/pages/ConsumerGroup/ResetOffsetDrawer.tsx @@ -0,0 +1,187 @@ +import React, { useState, useEffect } from 'react'; +import { Button, DatePicker, Drawer, Form, notification, Radio, Utils, Space, Divider, message } from 'knowdesign'; +import { useParams } from 'react-router-dom'; +import EditTable from '../TestingProduce/component/EditTable'; +import Api from '@src/api/index'; +import moment from 'moment'; + +const CustomSelectResetTime = (props: { value?: string; onChange?: (val: Number | String) => void }) => { + const { value, onChange } = props; + const [timeSetMode, setTimeSetMode] = useState('newest'); + useEffect(() => { + onChange('newest'); + }, []); + return ( + <> + { + setTimeSetMode(e.target.value); + if (e.target.value === 'newest') { + onChange('newest'); + } + }} + value={timeSetMode} + > + 最新Offset + 自定义 + + {timeSetMode === 'custom' && ( + { + onChange(v.valueOf()); + }} + > + )} + + ); +}; + +export default (props: any) => { + const { record, visible, setVisible } = props; + const routeParams = useParams<{ + clusterId: string; + }>(); + const [form] = Form.useForm(); + const defaultResetType = 'assignedTime'; + const [resetType, setResetType] = useState(defaultResetType); + const customFormRef: any = React.createRef(); + const clusterPhyId = Number(routeParams.clusterId); + const [partitionIdList, setPartitionIdList] = useState([]); + useEffect(() => { + form.setFieldsValue({ + resetType: defaultResetType, + }); + }, []); + + useEffect(() => { + visible && + Utils.request(Api.getTopicsMetaData(record?.topicName, +routeParams.clusterId)) + .then((res: any) => { + const partitionLists = (res?.partitionIdList || []).map((item: any) => { + return { + label: item, + value: item, + }; + }); + setPartitionIdList(partitionLists); + }) + .catch((err) => { + message.error(err); + }); + }, [visible]); + const confirm = () => { + let tableData; + if (customFormRef.current) { + tableData = customFormRef.current.getTableData(); + } + const formData = form.getFieldsValue(); + let resetParams: any = { + clusterId: clusterPhyId, + createIfNotExist: false, + groupName: record.groupName, + topicName: record.topicName, + }; + if (formData.resetType === 'assignedTime') { + resetParams.resetType = formData.timestamp === 'newest' ? 0 : 2; + if (resetParams.resetType === 2) { + resetParams.timestamp = formData.timestamp; + } + } + if (formData.resetType === 'partition') { + resetParams.resetType = 3; + resetParams.offsetList = tableData + ? tableData.map((item: { key: string; value: string }) => ({ partitionId: item.key, offset: item.value })) + : []; + } + Utils.put(Api.resetGroupOffset(), resetParams).then((data) => { + if (data === null) { + notification.success({ + message: '重置offset成功', + }); + setVisible(false); + } else { + notification.error({ + message: '重置offset失败', + }); + setVisible(false); + } + }); + }; + return ( + <> + + + + + + } + className="cluster-detail-consumer-resetoffset" + onClose={(_) => { + setVisible(false); + }} + > +
+ + { + setResetType(e.target.value); + }} + > + 重置到指定时间 + 重置分区 + + + {resetType === 'assignedTime' && ( + + + + )} + {resetType === 'partition' && ( + + + + )} +
+
+ + ); +}; diff --git a/km-console/packages/layout-clusters-fe/src/pages/ConsumerGroup/config.tsx b/km-console/packages/layout-clusters-fe/src/pages/ConsumerGroup/config.tsx new file mode 100644 index 00000000..8edd9280 --- /dev/null +++ b/km-console/packages/layout-clusters-fe/src/pages/ConsumerGroup/config.tsx @@ -0,0 +1,117 @@ +/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ +import React from 'react'; +import { AppContainer } from 'knowdesign'; +import TagsWithHide from '@src/components/TagsWithHide'; +import { ClustersPermissionMap } from '../CommonConfig'; + +export const runningStatusEnum: any = { + 1: 'Doing', + 2: 'Prepare', + 3: 'Success', + 4: 'Failed', + 5: 'Canceled', +}; + +export const defaultPagination = { + current: 1, + pageSize: 10, + position: 'bottomRight', + showSizeChanger: true, + pageSizeOptions: ['10', '20', '50', '100', '200', '500'], +}; + +export const getGroupColumns = (arg?: any) => { + const columns = [ + { + title: 'ConsumerGroup', + dataIndex: 'name', + key: 'name', + lineClampTwo: true, + render: (v: any, r: any) => { + return ( + { + window.location.hash = `groupName=${v || ''}`; + }} + > + {v} + + ); + }, + width: 200, + }, + { + title: '消费的Topic', + dataIndex: 'topicNameList', + key: 'topicNameList', + width: 200, + render(t: any, r: any) { + return t && t.length > 0 ? `共有${num}个`} /> : '-'; + }, + }, + { + title: 'Status', + dataIndex: 'state', + key: 'state', + width: 200, + }, + { + title: 'Member数', + dataIndex: 'memberCount', + key: 'memberCount', + width: 200, + render: (t: number) => (t ? t.toLocaleString() : '-'), + }, + ]; + return columns; +}; + +export const getGtoupTopicColumns = (arg?: any) => { + const [global] = AppContainer.useGlobalValue(); + const columns: any = [ + { + title: 'Topic名称', + dataIndex: 'topicName', + key: 'topicName', + needTooltip: true, + lineClampOne: true, + width: 150, + }, + { + title: 'Status', + dataIndex: 'state', + key: 'state', + width: 150, + }, + { + title: 'Max Lag', + dataIndex: 'maxLag', + key: 'maxLag', + width: 150, + render: (t: number) => (t ? t.toLocaleString() : '-'), + }, + { + title: 'Member数', + dataIndex: 'memberCount', + key: 'memberCount', + width: 150, + render: (t: number) => (t ? t.toLocaleString() : '-'), + }, + ]; + if (global.hasPermission && global.hasPermission(ClustersPermissionMap.CONSUMERS_RESET_OFFSET)) { + columns.push({ + title: '操作', + dataIndex: 'desc', + key: 'desc', + width: 150, + render: (value: any, record: any) => { + return ( + + ); + }, + }); + } + return columns; +}; diff --git a/km-console/packages/layout-clusters-fe/src/pages/ConsumerGroup/index.less b/km-console/packages/layout-clusters-fe/src/pages/ConsumerGroup/index.less new file mode 100644 index 00000000..82c5bcf5 --- /dev/null +++ b/km-console/packages/layout-clusters-fe/src/pages/ConsumerGroup/index.less @@ -0,0 +1,186 @@ +.brokerList { + .d-table-box-header { + padding: 0 0 12px 0; + } + .tag-success, + .tag-error { + padding: 2px 8px; + border-radius: 4px; + margin-left: 4px; + } + .tag-success { + background: #f1faf2; + color: #73d380; + } + .tag-error { + background: #fff0ef; + color: #ff7066; + } +} + +.operating-state { + .consumers-search { + display: contents; + .search-input-short { + margin-right: 8px; + } + } + .pro-table-wrap { + // padding: 17px 24px; + background: #fff; + border-radius: 12px; + } +} +.consumer-group-detail-drawer { + &-table { + .dcloud-table-cell { + padding: 7px 16px 8px 2px !important; + } + .dcloud-table-row-expand-icon-cell { + padding: 7px 7px 5px 24px !important; + } + + .dcloud-table-expanded-row-fixed { + padding: 16px 20px !important; + .dcloud-table-cell { + font-size: 12px !important; + } + } + } + + .dcloud-drawer-extra { + button { + width: 90px; + } + .divider { + width: 1px; + height: 17px; + margin: 0 16px; + background: rgba(206, 212, 218, 0.6); + } + } + .dcloud-drawer-body { + padding-top: 2px !important; + } +} + +.consumer-group-detail { + // border: 1px solid #EFF2F7; + // border-radius: 8px; + // padding: 12px 16px; + .title-and-mode { + display: flex; + align-items: center; + justify-content: space-between; + height: 60px; + &-header { + font-family: @font-family-bold; + font-size: 13px; + } + h4 { + font-family: PingFangSC-Semibold; + } + .right { + display: flex; + justify-content: center; + align-items: center; + .d-range-time-input { + height: 27px !important; + padding: 0 11px; + input { + line-height: 100%; + } + } + .divider { + width: 1px; + height: 20px; + background: rgba(206, 212, 218, 0.6); + margin: 0 8px; + } + .switch-mode { + .dcloud-radio-button-wrapper { + font-size: 14px; + width: 34px; + height: 23px; + padding: 0; + line-height: 22px; + text-align: center; + } + } + } + } + .single-chart, + .table { + background: #f8f9fa; + // margin-top: 12px; + border-radius: 8px; + .dcloud-table { + height: 210px; + overflow: auto; + background-color: transparent; + .dcloud-table-content .dcloud-table-cell { + background-color: transparent; + } + } + .dcloud-pagination { + height: 32px; + margin-bottom: 0; + margin-top: 8px; + } + } + .single-chart { + padding: 16px 22px 4px; + .single-chart-header { + display: none; + } + } + .content-with-copy { + display: flex; + align-items: center; + .content { + flex: 1; + display: inline-block; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + word-break: break-all; + } + .copy-icon { + width: 20px; + height: 20px; + padding-top: 2px; + border-radius: 50%; + margin-left: 4px; + font-size: 16px; + color: #adb5bc; + opacity: 0; + &:hover { + background: rgba(33, 37, 41, 0.04); + color: #74788d; + } + } + } + .dcloud-table-cell-row-hover { + .copy-icon { + opacity: 1; + } + } +} +.cluster-detail-consumer-resetoffset { + .reset-offset-form { + .dcloud-radio-wrapper { + width: 154px; + } + } + .operate-wrap { + display: flex; + justify-content: center; + align-items: center; + .operate-btns-divider { + width: 1px; + height: 17px; + background: rgba(0, 0, 0, 0.13); + margin: 0 16px; + } + } +} diff --git a/km-console/packages/layout-clusters-fe/src/pages/ConsumerGroup/index.tsx b/km-console/packages/layout-clusters-fe/src/pages/ConsumerGroup/index.tsx new file mode 100644 index 00000000..55647ae0 --- /dev/null +++ b/km-console/packages/layout-clusters-fe/src/pages/ConsumerGroup/index.tsx @@ -0,0 +1,134 @@ +import React, { useState, useEffect, memo } from 'react'; +import { useParams } from 'react-router-dom'; +import { ProTable, Utils, AppContainer, SearchInput, Divider, Form, Input, Button } from 'knowdesign'; +import { IconFont } from '@knowdesign/icons'; +import API from '../../api'; +import { getGroupColumns, defaultPagination } from './config'; +import { tableHeaderPrefix } from '@src/constants/common'; +import BrokerDetail from '../BrokerDetail'; +import DBreadcrumb from 'knowdesign/es/extend/d-breadcrumb'; +import ConsumerGroupHealthCheck from '@src/components/CardBar/ConsumerGroupHealthCheck'; +import GroupDetail from './Detail'; +import './index.less'; + +const { request } = Utils; + +const BrokerList: React.FC = (props: any) => { + const [global] = AppContainer.useGlobalValue(); + const [form] = Form.useForm(); + const urlParams = useParams(); // 获取地址栏参数 + const [loading, setLoading] = useState(false); + const [data, setData] = useState([]); + const [searchKeywords, setSearchKeywords] = useState(''); + const [pagination, setPagination] = useState(defaultPagination); + const [searchWords, setSearchWords] = useState<{ groupName: string; topicName: string }>({ groupName: '', topicName: '' }); + // 请求接口获取数据 + const genData = async ({ pageNo, pageSize }: any) => { + if (urlParams?.clusterId === undefined) return; + + setLoading(true); + const params = { + searchGroupName: searchWords.groupName ? searchWords.groupName.slice(0, 128) : undefined, + searchTopicName: searchWords.topicName ? searchWords.topicName.slice(0, 128) : undefined, + pageNo, + pageSize, + }; + + request(API.getOperatingStateList(urlParams?.clusterId), { params }) + .then((res: any) => { + setPagination({ + current: res.pagination?.pageNo, + pageSize: res.pagination?.pageSize, + total: res.pagination?.total, + }); + setData(res?.bizData || []); + setLoading(false); + }) + .catch((err) => { + setLoading(false); + }); + }; + + // 查询 + const onFinish = (formData: any) => { + setSearchWords(formData); + }; + + const onTableChange = (pagination: any, filters: any, sorter: any) => { + genData({ pageNo: pagination.current, pageSize: pagination.pageSize, filters, sorter }); + }; + + useEffect(() => { + genData({ + pageNo: 1, + pageSize: pagination.pageSize, + }); + }, [searchWords]); + + return ( +
+
+ +
+
+ +
+
+
+
+
genData({ pageNo: pagination.current, pageSize: pagination.pageSize })} + > + +
+ +
+ + + + + + +
+
+
+ + + +
+
+
+
+ +
+ {} +
+ ); +}; + +export default BrokerList; diff --git a/km-console/packages/layout-clusters-fe/src/pages/Consumers/ConsumerGroupDetail.tsx b/km-console/packages/layout-clusters-fe/src/pages/Consumers/ConsumerGroupDetail.tsx index 1e057d29..8c220330 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/Consumers/ConsumerGroupDetail.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/Consumers/ConsumerGroupDetail.tsx @@ -98,7 +98,7 @@ export default (props: any) => { dataIndex: 'OffsetConsumed', key: 'OffsetConsumed', render: (v: any, record: any) => { - return record?.latestMetrics?.metrics?.OffsetConsumed; + return record?.latestMetrics?.metrics?.OffsetConsumed.toLocaleString(); }, sorter: true, // sorter: { @@ -115,7 +115,7 @@ export default (props: any) => { dataIndex: 'LogEndOffset', key: 'LogEndOffset', render: (v: any, record: any) => { - return record?.latestMetrics?.metrics?.LogEndOffset; + return record?.latestMetrics?.metrics?.LogEndOffset.toLocaleString(); }, sorter: true, // sorter: { @@ -132,7 +132,7 @@ export default (props: any) => { dataIndex: 'Lag', key: 'Lag', render: (v: any, record: any) => { - return record?.latestMetrics?.metrics?.Lag; + return record?.latestMetrics?.metrics?.Lag.toLocaleString(); }, sorter: true, // sorter: { diff --git a/km-console/packages/layout-clusters-fe/src/pages/Consumers/ResetOffsetDrawer.tsx b/km-console/packages/layout-clusters-fe/src/pages/Consumers/ResetOffsetDrawer.tsx index c079393b..bba5059e 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/Consumers/ResetOffsetDrawer.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/Consumers/ResetOffsetDrawer.tsx @@ -1,11 +1,14 @@ import React, { useState, useEffect } from 'react'; -import { Button, DatePicker, Drawer, Form, notification, Radio, Utils, Space, Divider, message } from 'knowdesign'; +import { Button, DatePicker, Drawer, Form, Radio, Utils, Space, Divider } from 'knowdesign'; +import notification from '@src/components/Notification'; + +import message from '@src/components/Message'; import { useParams } from 'react-router-dom'; import EditTable from '../TestingProduce/component/EditTable'; import Api from '@src/api/index'; import moment from 'moment'; -const CustomSelectResetTime = (props: { value?: string; onChange?: (val: Number | String) => void }) => { +const CustomSelectResetTime = (props: { value?: string; onChange?: (val: number | string) => void }) => { const { value, onChange } = props; const [timeSetMode, setTimeSetMode] = useState('newest'); useEffect(() => { @@ -81,7 +84,7 @@ export default (props: any) => { tableData = customFormRef.current.getTableData(); } const formData = form.getFieldsValue(); - let resetParams: any = { + const resetParams: any = { clusterId: clusterPhyId, createIfNotExist: false, groupName: record.groupName, diff --git a/km-console/packages/layout-clusters-fe/src/pages/Consumers/index.tsx b/km-console/packages/layout-clusters-fe/src/pages/Consumers/index.tsx index 4e06d92a..53c0f02c 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/Consumers/index.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/Consumers/index.tsx @@ -108,11 +108,13 @@ const AutoPage = (props: any) => { title: 'Max Lag', dataIndex: 'maxLag', key: 'maxLag', + render: (t: number) => (t ? t.toLocaleString() : '-'), }, { title: 'Member数', dataIndex: 'memberCount', key: 'memberCount', + render: (t: number) => (t ? t.toLocaleString() : '-'), }, ]; diff --git a/km-console/packages/layout-clusters-fe/src/pages/Jobs/ExpandedRow.tsx b/km-console/packages/layout-clusters-fe/src/pages/Jobs/ExpandedRow.tsx index 399be7a7..4de68b47 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/Jobs/ExpandedRow.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/Jobs/ExpandedRow.tsx @@ -153,6 +153,7 @@ export const ExpandedRow: any = ({ record, data, loading }: any) => {
Github: - 5K + 5.4K + Star的项目 Know Streaming
diff --git a/km-console/packages/layout-clusters-fe/src/pages/Login/login.tsx b/km-console/packages/layout-clusters-fe/src/pages/Login/login.tsx index 39c72a76..0400dbf0 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/Login/login.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/Login/login.tsx @@ -1,5 +1,6 @@ import React from 'react'; -import { Form, Button, Input, Row, InputNumber, Utils, message } from 'knowdesign'; +import { Form, Button, Input, Row, InputNumber, Utils } from 'knowdesign'; +import message from '@src/components/Message'; import { FormMap } from './config'; import Api from '../../api'; import { useHistory } from 'react-router-dom'; diff --git a/km-console/packages/layout-clusters-fe/src/pages/MutliClusterPage/AccessCluster.tsx b/km-console/packages/layout-clusters-fe/src/pages/MutliClusterPage/AccessCluster.tsx index 7435d9a7..e5c1f649 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/MutliClusterPage/AccessCluster.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/MutliClusterPage/AccessCluster.tsx @@ -1,4 +1,5 @@ -import { Button, Divider, Drawer, Form, Input, InputNumber, message, Radio, Select, Spin, Space, Utils } from 'knowdesign'; +import { Button, Divider, Drawer, Form, Input, InputNumber, Radio, Select, Spin, Space, Utils } from 'knowdesign'; +import message from '@src/components/Message'; import * as React from 'react'; import { useIntl } from 'react-intl'; import api from '@src/api'; diff --git a/km-console/packages/layout-clusters-fe/src/pages/MutliClusterPage/List.tsx b/km-console/packages/layout-clusters-fe/src/pages/MutliClusterPage/List.tsx index d15cffcb..18723cd8 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/MutliClusterPage/List.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/MutliClusterPage/List.tsx @@ -1,4 +1,5 @@ -import { AppContainer, Divider, Form, Input, List, message, Modal, Progress, Spin, Tooltip, Utils } from 'knowdesign'; +import { AppContainer, Divider, Form, Input, List, Modal, Progress, Spin, Tooltip, Utils } from 'knowdesign'; +import message from '@src/components/Message'; import { IconFont } from '@knowdesign/icons'; import moment from 'moment'; import API from '@src/api'; @@ -11,7 +12,7 @@ import { useIntl } from 'react-intl'; import api, { MetricType } from '@src/api'; import { getHealthClassName, getHealthProcessColor, getHealthText } from '../SingleClusterDetail/config'; import { ClustersPermissionMap } from '../CommonConfig'; -import { getUnit, getDataNumberUnit } from '@src/constants/chartConfig'; +import { getDataUnit } from '@src/constants/chartConfig'; import SmallChart from '@src/components/SmallChart'; import { SearchParams } from './HomePage'; @@ -235,14 +236,14 @@ const ClusterList = (props: { searchParams: SearchParams; showAccessCluster: any // 如果单位是 字节 ,进行单位换算 if (line.unit.toLowerCase().includes('byte')) { - const [unit, size] = getUnit(line.value); + const [unit, size] = getDataUnit['Memory'](line.value); line.value = Number((line.value / size).toFixed(2)); line.unit = line.unit.toLowerCase().replace('byte', unit); } // Messages 指标值特殊处理 if (line.metricName === 'LeaderMessages') { - const [unit, size] = getDataNumberUnit(line.value); + const [unit, size] = getDataUnit['Num'](line.value); line.value = Number((line.value / size).toFixed(2)); line.unit = unit + line.unit; } diff --git a/km-console/packages/layout-clusters-fe/src/pages/SecurityACLs/EditDrawer.tsx b/km-console/packages/layout-clusters-fe/src/pages/SecurityACLs/EditDrawer.tsx index 9b2a7203..8afcdccc 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/SecurityACLs/EditDrawer.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/SecurityACLs/EditDrawer.tsx @@ -1,5 +1,6 @@ import React, { forwardRef, useEffect, useImperativeHandle, useRef, useState } from 'react'; -import { Button, Form, Input, Select, message, Drawer, Space, Divider, Utils, Radio, AutoComplete, Alert } from 'knowdesign'; +import { Button, Form, Input, Select, Drawer, Space, Divider, Utils, Radio, AutoComplete, Alert } from 'knowdesign'; +import message from '@src/components/Message'; import api from '@src/api'; import { useParams } from 'react-router-dom'; import { UsersProps } from '../SecurityUsers'; diff --git a/km-console/packages/layout-clusters-fe/src/pages/SecurityACLs/index.tsx b/km-console/packages/layout-clusters-fe/src/pages/SecurityACLs/index.tsx index a98f6269..d361f3e7 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/SecurityACLs/index.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/SecurityACLs/index.tsx @@ -1,5 +1,6 @@ import React, { useEffect, useRef, useState } from 'react'; -import { Button, Form, Input, Select, Modal, message, ProTable, AppContainer, DKSBreadcrumb, Utils, Divider } from 'knowdesign'; +import { Button, Form, Input, Select, Modal, ProTable, AppContainer, DKSBreadcrumb, Utils, Divider } from 'knowdesign'; +import message from '@src/components/Message'; import { IconFont } from '@knowdesign/icons'; import ACLsCardBar from '@src/components/CardBar/ACLsCardBar'; import api from '@src/api'; diff --git a/km-console/packages/layout-clusters-fe/src/pages/SecurityUsers/index.tsx b/km-console/packages/layout-clusters-fe/src/pages/SecurityUsers/index.tsx index 9f493bd7..6291ed42 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/SecurityUsers/index.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/SecurityUsers/index.tsx @@ -4,7 +4,6 @@ import { Form, Input, Modal, - message, ProTable, Drawer, Space, @@ -16,6 +15,7 @@ import { Tooltip, Alert, } from 'knowdesign'; +import message from '@src/components/Message'; import { IconFont } from '@knowdesign/icons'; import { CloseOutlined, EyeInvisibleOutlined, EyeOutlined, LoadingOutlined } from '@ant-design/icons'; import './index.less'; diff --git a/km-console/packages/layout-clusters-fe/src/pages/SingleClusterDetail/DetailChart/config.tsx b/km-console/packages/layout-clusters-fe/src/pages/SingleClusterDetail/DetailChart/config.tsx index 65ec2fd9..405f95c0 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/SingleClusterDetail/DetailChart/config.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/SingleClusterDetail/DetailChart/config.tsx @@ -14,7 +14,7 @@ const messagesInTooltipFormatter = (date: any, arr: any) => {
- + ${params.seriesName} @@ -55,7 +55,7 @@ const messagesInTooltipFormatter = (date: any, arr: any) => { }; export const getChartConfig = (props: any) => { - const { metricName, lineColor, isDefaultMetric = false } = props; + const { lineColor, isDefaultMetric = false } = props; return { option: getBasicChartConfig({ // TODO: time 轴图表联动有问题,先切换为 category @@ -63,7 +63,6 @@ export const getChartConfig = (props: any) => { title: { show: false }, legend: { show: false }, grid: { top: 24, bottom: 12 }, - lineColor: [lineColor], tooltip: isDefaultMetric ? { formatter: function (params: any) { @@ -87,6 +86,7 @@ export const getChartConfig = (props: any) => { smooth: 0.25, symbol: 'emptyCircle', symbolSize: 4, + color: '#556ee6', // 面积图样式 areaStyle: { color: lineColor, diff --git a/km-console/packages/layout-clusters-fe/src/pages/SingleClusterDetail/DetailChart/index.tsx b/km-console/packages/layout-clusters-fe/src/pages/SingleClusterDetail/DetailChart/index.tsx index 3df6ee1e..b9337f09 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/SingleClusterDetail/DetailChart/index.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/SingleClusterDetail/DetailChart/index.tsx @@ -5,16 +5,16 @@ import { arrayMoveImmutable } from 'array-move'; import api from '@src/api'; import { useParams } from 'react-router-dom'; import { - MetricDefaultChartDataType, - MetricChartDataType, + OriginMetricData, + FormattedMetricData, formatChartData, supplementaryPoints, resolveMetricsRank, MetricInfo, } from '@src/constants/chartConfig'; import { MetricType } from '@src/api'; -import { getDataNumberUnit, getUnit } from '@src/constants/chartConfig'; -import SingleChartHeader, { KsHeaderOptions } from '@src/components/SingleChartHeader'; +import { getDataUnit } from '@src/constants/chartConfig'; +import ChartOperateBar, { KsHeaderOptions } from '@src/components/ChartOperateBar'; import RenderEmpty from '@src/components/RenderEmpty'; import DragGroup from '@src/components/DragGroup'; import { getChartConfig } from './config'; @@ -162,13 +162,13 @@ const DetailChart = (props: { children: JSX.Element }): JSX.Element => { metricsNames: selectedMetricNames.filter((name) => name !== DEFAULT_METRIC), }, }).then( - (res: MetricDefaultChartDataType[]) => { + (res: OriginMetricData[]) => { // 如果当前请求不是最新请求,则不做任何操作 if (curFetchingTimestamp.current.messagesIn !== curTimestamp) { return; } - const formattedMetricData: MetricChartDataType[] = formatChartData( + const formattedMetricData: FormattedMetricData[] = formatChartData( res, global.getMetricDefine || {}, MetricType.Cluster, @@ -224,7 +224,7 @@ const DetailChart = (props: { children: JSX.Element }): JSX.Element => { let valueWithUnit = Number(value); let unit = ((global.getMetricDefine && global.getMetricDefine(MetricType.Cluster, key)?.unit) || '') as string; if (unit.toLowerCase().includes('byte')) { - const [unitName, unitSize]: [string, number] = getUnit(Number(value)); + const [unitName, unitSize]: [string, number] = getDataUnit['Memory'](Number(value)); unit = unit.toLowerCase().replace('byte', unitName); valueWithUnit /= unitSize; } @@ -235,7 +235,7 @@ const DetailChart = (props: { children: JSX.Element }): JSX.Element => { }; return returnValue; }); - return [timeStamp, values.MessagesIn || '0', valuesWithUnit] as [number, number | string, typeof valuesWithUnit]; + return [timeStamp, parsedValue || '0', valuesWithUnit] as [number, number | string, typeof valuesWithUnit]; }); result.sort((a, b) => (a[0] as number) - (b[0] as number)); const line = { @@ -244,9 +244,9 @@ const DetailChart = (props: { children: JSX.Element }): JSX.Element => { data: result as any, }; if (maxValue > 0) { - const [unitName, unitSize]: [string, number] = getDataNumberUnit(maxValue); + const [unitName, unitSize]: [string, number] = getDataUnit['Num'](maxValue); line.unit = `${unitName}${line.unit}`; - result.forEach((point) => ((point[1] as number) /= unitSize)); + result.forEach((point) => parseFloat(((point[1] as number) /= unitSize).toFixed(3))); } if (result.length) { @@ -308,11 +308,11 @@ const DetailChart = (props: { children: JSX.Element }): JSX.Element => { return (
- { item.configItem.indexOf('Group Re-Balance') > -1 ? 'ReBalance' : item.configItem.includes('副本未同步') - ? 'UNDER_REPLICA' - : item.configItem; + ? 'UNDER_REPLICA' + : item.configItem; values[`weight_${item.configItemName}`] = itemValue?.weight; values[`value_${item.configItemName}`] = itemValue?.value; diff --git a/km-console/packages/layout-clusters-fe/src/pages/TestingConsumer/Consume.tsx b/km-console/packages/layout-clusters-fe/src/pages/TestingConsumer/Consume.tsx index be43d454..90625de8 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/TestingConsumer/Consume.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/TestingConsumer/Consume.tsx @@ -1,6 +1,7 @@ /* eslint-disable no-case-declarations */ import { DownloadOutlined } from '@ant-design/icons'; -import { AppContainer, Divider, message, Tooltip, Utils } from 'knowdesign'; +import { AppContainer, Divider, Tooltip, Utils } from 'knowdesign'; +import message from '@src/components/Message'; import { IconFont } from '@knowdesign/icons'; import * as React from 'react'; import moment from 'moment'; diff --git a/km-console/packages/layout-clusters-fe/src/pages/TestingProduce/Produce.tsx b/km-console/packages/layout-clusters-fe/src/pages/TestingProduce/Produce.tsx index 8f5e3479..18f0b2c5 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/TestingProduce/Produce.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/TestingProduce/Produce.tsx @@ -1,4 +1,5 @@ -import { AppContainer, Form, message, Tabs, Utils } from 'knowdesign'; +import { AppContainer, Form, Tabs, Utils } from 'knowdesign'; +import message from '@src/components/Message'; import * as React from 'react'; import ConfigForm from './component/ConfigFrom'; import TestResult from '../TestingConsumer/component/Result'; diff --git a/km-console/packages/layout-clusters-fe/src/pages/TestingProduce/component/EditTable.tsx b/km-console/packages/layout-clusters-fe/src/pages/TestingProduce/component/EditTable.tsx index a5300af2..55b06e25 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/TestingProduce/component/EditTable.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/TestingProduce/component/EditTable.tsx @@ -1,6 +1,7 @@ /* eslint-disable react/display-name */ import React, { useState } from 'react'; -import { Table, Input, InputNumber, Popconfirm, Form, Typography, Button, message, Select } from 'knowdesign'; +import { Table, Input, InputNumber, Popconfirm, Form, Typography, Button, Select } from 'knowdesign'; +import message from '@src/components/Message'; import { IconFont } from '@knowdesign/icons'; import './style/edit-table.less'; import { CheckOutlined, CloseOutlined, PlusSquareOutlined } from '@ant-design/icons'; diff --git a/km-console/packages/layout-clusters-fe/src/pages/TopicDashboard/index.tsx b/km-console/packages/layout-clusters-fe/src/pages/TopicDashboard/index.tsx index 72797227..ccf4104f 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/TopicDashboard/index.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/TopicDashboard/index.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { MetricType } from '@src/api'; import TopicHealthCheck from '@src/components/CardBar/TopicHealthCheck'; -import DashboardDragChart from '@src/components/DashboardDragChart'; +import DraggableCharts from '@src/components/DraggableCharts'; import { AppContainer } from 'knowdesign'; import DBreadcrumb from 'knowdesign/es/extend/d-breadcrumb'; @@ -19,7 +19,7 @@ const TopicDashboard = () => { />
- + ); }; diff --git a/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/ConfigurationEdit.tsx b/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/ConfigurationEdit.tsx index 7fc4ab80..ff8c6cd0 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/ConfigurationEdit.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/ConfigurationEdit.tsx @@ -1,5 +1,6 @@ import React from 'react'; -import { Drawer, Form, Input, Space, Button, Utils, Row, Col, Divider, message } from 'knowdesign'; +import { Drawer, Form, Input, Space, Button, Utils, Row, Col, Divider } from 'knowdesign'; +import message from '@src/components/Message'; import { IconFont } from '@knowdesign/icons'; import { useParams } from 'react-router-dom'; import Api from '@src/api'; diff --git a/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/ConsumerGroupDetail.tsx b/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/ConsumerGroupDetail.tsx new file mode 100644 index 00000000..bd502b1a --- /dev/null +++ b/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/ConsumerGroupDetail.tsx @@ -0,0 +1,502 @@ +import React, { useState, useEffect } from 'react'; +import { useParams, useHistory } from 'react-router-dom'; +import { AppContainer, Divider, Drawer, ProTable, Select, SingleChart, Space, Tooltip, Utils } from 'knowdesign'; +import { IconFont } from '@knowdesign/icons'; +import { DRangeTime } from 'knowdesign'; +import { CHART_COLOR_LIST, getBasicChartConfig } from '@src/constants/chartConfig'; +import Api from '@src/api/index'; +import { hashDataParse } from '@src/constants/common'; +import { ClustersPermissionMap } from '../CommonConfig'; +import ResetOffsetDrawer from './ResetOffsetDrawer'; +import SwitchTab from '@src/components/SwitchTab'; +import ContentWithCopy from '@src/components/CopyContent'; + +const { Option } = Select; + +export interface MetricLine { + createTime?: number; + metricPoints: Array<{ + aggType: string; + createTime: number; + timeStamp: number; + unit: string; + updateTime: number; + value: number; + }>; + name: string; + updateTime?: number; +} +export interface MetricData { + metricLines?: Array; + metricLine?: MetricLine; + metricName: string; +} + +export interface HashData { + groupName: string; + topicName: string; +} + +const metricConsts = ['LogEndOffset', 'OffsetConsumed', 'Lag']; +const metricWithType = [ + { metricName: 'LogEndOffset', metricType: 104 }, + { metricName: 'OffsetConsumed', metricType: 102 }, + { metricName: 'Lag', metricType: 102 }, +]; + +export default (props: any) => { + const { scene, visible, setVisible, hashData } = props; + const params = useParams<{ + clusterId: string; + }>(); + const history = useHistory(); + const [global] = AppContainer.useGlobalValue(); + // const { record } = props; + const now = Date.now(); + const [allGroupMetricsData, setAllGroupMetricsData] = useState>([]); + const [groupMetricsData, setGroupMetricsData] = useState>([]); + const [timeRange, setTimeRange] = useState([now - 24 * 60 * 60 * 1000, now]); + const [consumerList, setConsumerList] = useState([]); + const [partitionList, setPartitionList] = useState([]); + const [curPartition, setCurPartition] = useState(''); + const [showMode, setShowMode] = useState('table'); + const [pageIndex, setPageIndex] = useState(1); + const [pageTotal, setPageTotal] = useState(1); + const [pageSize, setPageSize] = useState(10); + const [consumerListLoading, setConsumerListLoading] = useState(true); + const [consumerChartLoading, setConsumerChartLoading] = useState(false); + // const [hashData, setHashData] = useState({ groupName: '', topicName: '' }); + // const [visible, setVisible] = useState(false); + const [sortObj, setSortObj] = useState<{ + sortField: string; + sortType: 'desc' | 'asc' | ''; + }>({ sortField: '', sortType: '' }); + const [pagination, setPagination] = useState({ + current: 1, + pageSize: 10, + position: 'bottomRight', + showSizeChanger: true, + pageSizeOptions: ['10', '20', '50', '100', '200', '500'], + showTotal: (total: number) => `共 ${total} 条目`, + }); + const clusterId = Number(params.clusterId); + const columns = [ + { + title: 'Topic Partition', + dataIndex: 'partitionId', + key: 'partitionId', + lineClampOne: true, + needTooltip: true, + width: 180, + render: (v: string, record: any) => { + return `${record.topicName}-${v}`; + }, + }, + { + title: 'Member ID', + dataIndex: 'memberId', + key: 'memberId', + width: 200, + render: (v: string) => { + return v ? : '-'; + }, + }, + { + title: 'Current Offset', + dataIndex: 'OffsetConsumed', + key: 'OffsetConsumed', + render: (v: any, record: any) => { + return record?.latestMetrics?.metrics?.OffsetConsumed.toLocaleString(); + }, + sorter: true, + // sorter: { + // compare: (a: any, b: any) => { + // let value1 = a?.metrics?.find((item: any) => item.metricName === 'OffsetConsumed' && item.metricType === 102)?.metricValue + // let value2 = b?.metrics?.find((item: any) => item.metricName === 'OffsetConsumed' && item.metricType === 102)?.metricValue + // return value1 - value2 + // }, + // multiple: 1 + // } + }, + { + title: 'Log End Offset', + dataIndex: 'LogEndOffset', + key: 'LogEndOffset', + render: (v: any, record: any) => { + return record?.latestMetrics?.metrics?.LogEndOffset.toLocaleString(); + }, + sorter: true, + // sorter: { + // compare: (a: any, b: any) => { + // let value1 = a?.metrics?.find((item: any) => item.metricName === 'LogEndOffset' && item.metricType === 104)?.metricValue + // let value2 = b?.metrics?.find((item: any) => item.metricName === 'LogEndOffset' && item.metricType === 104)?.metricValue + // return value1 - value2 + // }, + // multiple: 2 + // } + }, + { + title: 'Lag', + dataIndex: 'Lag', + key: 'Lag', + render: (v: any, record: any) => { + return record?.latestMetrics?.metrics?.Lag.toLocaleString(); + }, + sorter: true, + // sorter: { + // compare: (a: any, b: any) => { + // let value1 = a?.metrics?.find((item: any) => item.metricName === 'Lag' && item.metricType === 102)?.metricValue + // let value2 = b?.metrics?.find((item: any) => item.metricName === 'Lag' && item.metricType === 102)?.metricValue + // return value1 - value2 + // }, + // multiple: 3 + // } + }, + { + title: 'Host', + dataIndex: 'host', + key: 'host', + }, + { + title: 'Client ID', + dataIndex: 'clientId', + key: 'clientId', + needTooltip: true, + lineClampOne: true, + width: 200, + }, + ]; + const getTopicGroupMetric = ({ + hashData, + pagination = { current: 1, pageSize: 10 }, + sorter = {}, + }: { + hashData: HashData; + pagination?: any; + sorter?: any; + }) => { + setConsumerListLoading(true); + const params: any = { + // metricRealTimes: metricWithType, + latestMetricNames: metricConsts, + pageNo: pagination.current, + pageSize: pagination.pageSize, + sortField: sorter.field || undefined, + sortType: sorter.order ? sorter.order.substring(0, sorter.order.indexOf('end')) : undefined, + }; + // if (sorter.sortField && sorter.sortType) { + // params.sortField = sorter.sortField; + // params.sortType = sorter.sortType; + // } + return Utils.post( + Api.getTopicGroupMetric({ + clusterId, + groupName: hashData.groupName, + topicName: hashData.topicName, + }), + params + ) + .then((data: any) => { + if (!data) return; + + setPagination({ + current: data.pagination?.pageNo, + pageSize: data.pagination?.pageSize, + total: data.pagination?.total, + }); + setConsumerList(data?.bizData); + }) + .finally(() => { + setConsumerListLoading(false); + }); + }; + const getTopicGroupPartitionsHistory = (hashData: HashData) => { + return Utils.request(Api.getTopicGroupPartitionsHistory(clusterId, hashData.groupName), { + params: { + startTime: timeRange[0], + endTime: timeRange[1], + }, + }); + }; + const getTopicGroupMetricHistory = (partitions: Array, hashData: HashData) => { + const params = { + aggType: 'sum', + groupTopics: partitions?.map((p) => ({ + partition: p.value, + topic: hashData.topicName, + })), + group: hashData.groupName, + metricsNames: metricWithType.map((item) => item.metricName), + startTime: timeRange[0], + endTime: timeRange[1], + topNu: 0, + }; + Utils.post(Api.getTopicGroupMetricHistory(clusterId), params).then((data: Array) => { + setAllGroupMetricsData(data); + }); + }; + const getConsumersMetadata = (hashData: HashData) => { + return Utils.request(Api.getConsumersMetadata(clusterId, hashData.groupName, hashData.topicName)); + }; + + const getTopicsMetaData = (hashData: HashData) => { + return Utils.request(Api.getTopicsMetaData(hashData.topicName, clusterId)); + }; + + const onClose = () => { + setVisible(false); + setSortObj({ + sortField: '', + sortType: '', + }); + // clean hash' + // scene === 'topicDetail' && history.goBack(); + // scene !== 'topicDetail' && window.history.pushState('', '', location.pathname); + }; + + const onTableChange = (pagination: any, filters: any, sorter: any) => { + getTopicGroupMetric({ hashData, pagination, sorter }); + // setPageIndex(pagination.current); + }; + + useEffect(() => { + if (curPartition === '' || allGroupMetricsData.length === 0) return; + const filteredData = allGroupMetricsData.map((item) => { + const allData = item.metricLines.reduce( + (acc, cur) => { + if (acc.metricLine.metricPoints.length === 0) { + acc.metricLine.metricPoints = cur.metricPoints.map((p) => ({ + timeStamp: p.timeStamp, + value: Number(p.value), + })); + } else { + acc.metricLine.metricPoints.forEach((mp) => { + const curMetricPoint = cur.metricPoints.find((curmp) => curmp.timeStamp === mp.timeStamp); + mp.value += curMetricPoint ? Number(curMetricPoint.value) : 0; + }); + } + return acc; + }, + { + metricName: item.metricName, + metricLine: { + name: 'all', + metricPoints: [], + }, + } + ); + return curPartition === '__all__' + ? allData + : { + metricName: item.metricName, + metricLine: item.metricLines.find((line) => line.name.indexOf(curPartition) >= 0), + }; + }); + setGroupMetricsData(filteredData); + }, [curPartition, allGroupMetricsData]); + + useEffect(() => { + // const hashData = hashDataParse(location.hash); + if (!hashData.groupName || !hashData.topicName) return; + // setHashData(hashData); + // 获取分区列表 为图表模式做准备 + visible && + getConsumersMetadata(hashData).then((res: any) => { + if (!res.exist) { + setVisible(false); + // history.push(`/cluster/${params?.clusterId}/consumers`); + return; + } + getTopicsMetaData(hashData) + // .then((data: any) => { + // if (data.length > 0) { + // setCurPartition(data[0].partition); + // } + // setPartitionList(data); + // return data; + // }) + .then((data: any) => { + const partitionLists = (data?.partitionIdList || []).map((item: any) => { + return { + label: item, + value: item, + }; + }); + setCurPartition(partitionLists?.[0]?.value); + setPartitionList(partitionLists); + getTopicGroupMetricHistory(partitionLists, hashData); + }) + .catch((e) => { + // history.push(`/cluster/${params?.clusterId}/consumers`); + setVisible(false); + }); + // 获取Consumer列表 表格模式 + getTopicGroupMetric({ hashData: hashData as HashData }); + }); + }, [visible]); + + useEffect(() => { + if (partitionList.length === 0) return; + getTopicGroupMetricHistory(partitionList, hashData); + }, [timeRange]); + + return ( + + {global.hasPermission && + global.hasPermission( + scene === 'topicDetail' ? ClustersPermissionMap.TOPIC_RESET_OFFSET : ClustersPermissionMap.CONSUMERS_RESET_OFFSET + ) && } + + + } + > +
+
+
+
+ {showMode === 'chart' && ( + + )} + {showMode === 'chart' && ( + { + setTimeRange(o); + }} + > + )} + {showMode === 'chart' &&
} + setShowMode(key)}> + +
+ +
+
+ +
+ +
+
+
+
+
+ {showMode === 'table' && ( + // { + // setSortObj({ + // sortField: sorter.field || '', + // sortType: sorter.order ? sorter.order.substring(0, sorter.order.indexOf('end')) : '', + // }); + // setPageIndex(pagination.current); + // }} + // >
+ + )} + {showMode === 'chart' && ( +
+ { + return data.map((metricData: any) => { + const partitionMetricData = metricData.metricLine?.metricPoints || []; + return { + name: metricData.metricName, + data: partitionMetricData.map((item: any) => [item.timeStamp, item.value, item.unit]), + lineStyle: { + width: 1.5, + }, + smooth: 0.25, + symbol: 'emptyCircle', + symbolSize: 4, + emphasis: { + disabled: true, + }, + }; + }); + }} + /> +
+ )} +
+
+ ); +}; diff --git a/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/ConsumerGroups.tsx b/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/ConsumerGroups.tsx index 9fa3be5c..9d1c6a6d 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/ConsumerGroups.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/ConsumerGroups.tsx @@ -1,50 +1,58 @@ import React, { useState, useEffect } from 'react'; import { ProTable, Utils } from 'knowdesign'; import Api from '@src/api'; +import { useParams } from 'react-router-dom'; +import ConsumerGroupDetail from './ConsumerGroupDetail'; const { request } = Utils; -const getColmns = (solveClick: any) => { - const columns = [ + +const getColmns = (arg: any) => { + const baseColumns: any = [ { title: 'ConsumerGroup', - dataIndex: 'ConsumerGroup', - key: 'ConsumerGroup', + dataIndex: 'groupName', + key: 'groupName', + render: (v: any, r: any) => { + return arg.getGroupInfo(v)}>{v}; + }, }, { - title: '关联KafkaUser', - dataIndex: 'kafkaUser', - key: 'kafkaUser', + title: '消费的Topic', + dataIndex: 'topicName', + key: 'topicName', }, + // { + // title: 'Principle', + // dataIndex: 'kafkaUser', + // key: 'kafkaUser', + // }, { title: 'Status', - dataIndex: 'status', - key: 'status', + dataIndex: 'state', + key: 'state', }, { title: 'Max Lag', dataIndex: 'maxLag', key: 'maxLag', + render: (t: number) => (t ? t.toLocaleString() : '-'), }, { title: 'Member数', - dataIndex: 'member', - key: 'member', - }, - { - title: '操作', - dataIndex: 'option', - key: 'option', - // eslint-disable-next-line react/display-name - render: (_t: any, r: any) => { - return solveClick(r)}>解决; - }, + dataIndex: 'memberCount', + key: 'memberCount', + render: (t: number) => (t ? t.toLocaleString() : '-'), }, ]; - return columns; + + return baseColumns; }; const TopicGroup = (props: any) => { + const { hashData } = props; + const urlParams = useParams(); // 获取地址栏参数 const [loading, setLoading] = useState(false); const [data, setData] = useState([]); + const [visible, setVisible] = useState(false); const [pagination, setPagination] = useState({ current: 1, pageSize: 10, @@ -52,32 +60,22 @@ const TopicGroup = (props: any) => { showSizeChanger: true, pageSizeOptions: ['10', '20', '50', '100', '200', '500'], showTotal: (total: number) => `共 ${total} 条目`, - // locale: { - // items_per_page: '条', - // }, - // selectComponentClass: CustomSelect, }); - const solveClick = (record: any) => {}; + const [groupName, setGroupName] = useState(''); // 请求接口获取数据 const genData = async ({ pageNo, pageSize, filters = null, sorter = null }: any) => { - // if (clusterId === undefined) return; - - // filters = filters || filteredInfo; + if (urlParams?.clusterId === undefined || hashData?.topicName === undefined) return; setLoading(true); - // const params = dealTableRequestParams({ searchKeywords, pageNo, pageSize, sorter, filters, isPhyId: true }); const params = { - filterKey: 'string', - filterPartitionId: 1, - filterValue: 'string', - maxRecords: 100, - pullTimeoutUnitMs: 10000, - truncate: true, + searchGroupName: props.searchKeywords ? props.searchKeywords.slice(0, 128) : undefined, + pageNo, + pageSize, }; - request(Api.getTopicMessagesList('你好', 2), { params }) + request(Api.getTopicGroupList(hashData?.topicName, urlParams?.clusterId), { params }) .then((res: any) => { setPagination({ current: res.pagination?.pageNo, @@ -97,38 +95,62 @@ const TopicGroup = (props: any) => { }); }; - const onTableChange = (pagination: any, filters: any, sorter: any) => { - setPagination(pagination); - // const asc = sorter?.order && sorter?.order === 'ascend' ? true : false; - // const sortColumn = sorter.field && toLine(sorter.field); - // genData({ pageNo: pagination.current, pageSize: pagination.pageSize, filters, asc, sortColumn, queryTerm: searchResult, ...allParams }); + const getGroupInfo = (groupName: string) => { + setVisible(true); + setGroupName(groupName); }; - // useEffect(() => { - // genData({ - // pageNo: 1, - // pageSize: pagination.pageSize, - // // sorter: defaultSorter - // }); - // }, [props]); + const onTableChange = (pagination: any, filters: any, sorter: any) => { + // setPagination(pagination); + // const asc = sorter?.order && sorter?.order === 'ascend' ? true : false; + // const sortColumn = sorter.field && toLine(sorter.field); + genData({ pageNo: pagination.current, pageSize: pagination.pageSize }); + }; + + useEffect(() => { + props.positionType === 'ConsumerGroups' && + genData({ + pageNo: 1, + pageSize: pagination.pageSize, + // sorter: defaultSorter + }); + }, [props.searchKeywords]); return ( - +
+ + {} +
+ // ); }; diff --git a/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/ResetOffsetDrawer.tsx b/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/ResetOffsetDrawer.tsx new file mode 100644 index 00000000..c079393b --- /dev/null +++ b/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/ResetOffsetDrawer.tsx @@ -0,0 +1,197 @@ +import React, { useState, useEffect } from 'react'; +import { Button, DatePicker, Drawer, Form, notification, Radio, Utils, Space, Divider, message } from 'knowdesign'; +import { useParams } from 'react-router-dom'; +import EditTable from '../TestingProduce/component/EditTable'; +import Api from '@src/api/index'; +import moment from 'moment'; + +const CustomSelectResetTime = (props: { value?: string; onChange?: (val: Number | String) => void }) => { + const { value, onChange } = props; + const [timeSetMode, setTimeSetMode] = useState('newest'); + useEffect(() => { + onChange('newest'); + }, []); + return ( + <> + { + setTimeSetMode(e.target.value); + if (e.target.value === 'newest') { + onChange('newest'); + } + }} + value={timeSetMode} + > + 最新Offset + 自定义 + + {timeSetMode === 'custom' && ( + { + onChange(v.valueOf()); + }} + > + )} + + ); +}; + +export default (props: any) => { + const { record } = props; + const routeParams = useParams<{ + clusterId: string; + }>(); + const [form] = Form.useForm(); + const defaultResetType = 'assignedTime'; + const [resetType, setResetType] = useState(defaultResetType); + const [resetOffsetVisible, setResetOffsetVisible] = useState(false); + const customFormRef: any = React.createRef(); + const clusterPhyId = Number(routeParams.clusterId); + const [partitionIdList, setPartitionIdList] = useState([]); + useEffect(() => { + form.setFieldsValue({ + resetType: defaultResetType, + }); + }, []); + + useEffect(() => { + Utils.request(Api.getTopicsMetaData(record?.topicName, +routeParams.clusterId)) + .then((res: any) => { + const partitionLists = (res?.partitionIdList || []).map((item: any) => { + return { + label: item, + value: item, + }; + }); + setPartitionIdList(partitionLists); + }) + .catch((err) => { + message.error(err); + }); + }, []); + const confirm = () => { + let tableData; + if (customFormRef.current) { + tableData = customFormRef.current.getTableData(); + } + const formData = form.getFieldsValue(); + let resetParams: any = { + clusterId: clusterPhyId, + createIfNotExist: false, + groupName: record.groupName, + topicName: record.topicName, + }; + if (formData.resetType === 'assignedTime') { + resetParams.resetType = formData.timestamp === 'newest' ? 0 : 2; + if (resetParams.resetType === 2) { + resetParams.timestamp = formData.timestamp; + } + } + if (formData.resetType === 'partition') { + resetParams.resetType = 3; + resetParams.offsetList = tableData + ? tableData.map((item: { key: string; value: string }) => ({ partitionId: item.key, offset: item.value })) + : []; + } + Utils.put(Api.resetGroupOffset(), resetParams).then((data) => { + if (data === null) { + notification.success({ + message: '重置offset成功', + }); + setResetOffsetVisible(false); + } else { + notification.error({ + message: '重置offset失败', + }); + setResetOffsetVisible(false); + } + }); + }; + return ( + <> + + + + + + + + } + className="cluster-detail-consumer-resetoffset" + onClose={(_) => { + setResetOffsetVisible(false); + }} + > +
+ + { + setResetType(e.target.value); + }} + > + 重置到指定时间 + 重置分区 + + + {resetType === 'assignedTime' && ( + + + + )} + {resetType === 'partition' && ( + + + + )} +
+
+ + ); +}; diff --git a/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/index.tsx b/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/index.tsx index cd2d6d66..bc3f6ed4 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/index.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/index.tsx @@ -1,13 +1,16 @@ import React, { useState, useEffect } from 'react'; import { useHistory, useParams } from 'react-router-dom'; -import { Tabs, Utils, Drawer, Tag, AppContainer, SearchInput, notification } from 'knowdesign'; +import { Tabs, Utils, Drawer, Tag, AppContainer, SearchInput } from 'knowdesign'; +import notification from '@src/components/Notification'; + import Api from '@src/api'; import BrokersDetail from './BrokersDetail'; import Messages from './Messages'; import ConsumerGroups from './ConsumerGroups'; import ACLs from './ACLs'; import Configuration from './Configuration'; -import Consumers from '@src/pages/Consumers'; +import Consumers from './ConsumerGroups'; +// import Consumers from '@src/pages/Consumers'; import './index.less'; import TopicDetailHealthCheck from '@src/components/CardBar/TopicDetailHealthCheck'; import { hashDataParse } from '@src/constants/common'; @@ -115,35 +118,34 @@ const TopicDetail = (props: any) => { useEffect(() => { global?.clusterInfo?.id && hashDataParse(location.hash).topicName ? Utils.request(Api.getTopicMetadata(+global?.clusterInfo?.id, hashDataParse(location.hash)?.topicName), { - init: { - errorNoTips: true, - }, - }) - .then((topicData: any) => { - if (topicData?.exist && !hashDataParse(location.hash).groupName) { - setHashData(topicData); - setVisible(true); - } else { + init: { + errorNoTips: true, + }, + }) + .then((topicData: any) => { + if (topicData?.exist && !hashDataParse(location.hash).groupName) { + setHashData(topicData); + setVisible(true); + } else { + history.replace(`/cluster/${urlParams?.clusterId}/topic/list`); + // history.push(`/`); + setVisible(false); + } + }) + .catch((err) => { history.replace(`/cluster/${urlParams?.clusterId}/topic/list`); - // history.push(`/`); setVisible(false); - } - }) - .catch((err) => { - history.replace(`/cluster/${urlParams?.clusterId}/topic/list`); - setVisible(false); - notification.error({ - message: '错误', - duration: 3, - description: `${'Topic不存在或Topic名称有误'}`, - }); - }) + notification.error({ + message: '错误', + description: 'Topic不存在或Topic名称有误', + }); + }) : setVisible(false); }, [hashDataParse(location.hash).topicName, global?.clusterInfo]); return ( {hashData?.topicName} @@ -192,12 +194,9 @@ const TopicDetail = (props: any) => { {positionType === 'Messages' && } - + {positionType === 'ConsumerGroups' && ( + + )} {positionType === 'ACLs' && } diff --git a/km-console/packages/layout-clusters-fe/src/pages/TopicList/Create.tsx b/km-console/packages/layout-clusters-fe/src/pages/TopicList/Create.tsx index 288b99c7..6f1cb667 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/TopicList/Create.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/TopicList/Create.tsx @@ -1,6 +1,7 @@ import React, { useState, useEffect } from 'react'; import { useParams } from 'react-router-dom'; -import { Alert, Button, Checkbox, Divider, Drawer, Form, Input, InputNumber, Modal, notification, Select, Utils } from 'knowdesign'; +import { Alert, Button, Checkbox, Divider, Drawer, Form, Input, InputNumber, Modal, Select, Utils } from 'knowdesign'; +import notification from '@src/components/Notification'; import { PlusOutlined, DownOutlined, UpOutlined } from '@ant-design/icons'; import Api from '@src/api/index'; diff --git a/km-console/packages/layout-clusters-fe/src/pages/TopicList/Delete.tsx b/km-console/packages/layout-clusters-fe/src/pages/TopicList/Delete.tsx index 75af2070..69109225 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/TopicList/Delete.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/TopicList/Delete.tsx @@ -1,6 +1,7 @@ import React, { useState } from 'react'; import { useParams } from 'react-router-dom'; -import { Button, Form, Input, Modal, notification, Utils } from 'knowdesign'; +import { Button, Form, Input, Modal, Utils } from 'knowdesign'; +import notification from '@src/components/Notification'; import { IconFont } from '@knowdesign/icons'; import Api from '@src/api/index'; diff --git a/km-console/packages/layout-clusters-fe/src/pages/TopicList/ExpandPartition.tsx b/km-console/packages/layout-clusters-fe/src/pages/TopicList/ExpandPartition.tsx index b17a41ab..bf87fb59 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/TopicList/ExpandPartition.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/TopicList/ExpandPartition.tsx @@ -1,9 +1,10 @@ import React, { useEffect, useState } from 'react'; import { useParams } from 'react-router-dom'; -import { AppContainer, Button, Divider, Drawer, Form, InputNumber, notification, SingleChart, Space, Spin, Utils } from 'knowdesign'; +import { AppContainer, Button, Divider, Drawer, Form, InputNumber, SingleChart, Space, Spin, Tooltip, Utils } from 'knowdesign'; +import notification from '@src/components/Notification'; import Api, { MetricType } from '@src/api/index'; -import { getBasicChartConfig, getUnit } from '@src/constants/chartConfig'; -import { formatChartData, MetricDefaultChartDataType } from '@src/constants/chartConfig'; +import { getBasicChartConfig, getDataUnit } from '@src/constants/chartConfig'; +import { formatChartData, OriginMetricData } from '@src/constants/chartConfig'; const ExpandPartition = (props: { record: any; onConfirm: () => void }) => { const [global] = AppContainer.useGlobalValue(); @@ -60,7 +61,7 @@ const ExpandPartition = (props: { record: any; onConfirm: () => void }) => { ); const empiricalMinValue = 10 * 1024 * record.partitionNum; - const lines = data.map((metric: MetricDefaultChartDataType) => { + const lines = data.map((metric: OriginMetricData) => { const child = metric.metricLines[0]; child.name = metric.metricName; return child; @@ -87,7 +88,7 @@ const ExpandPartition = (props: { record: any; onConfirm: () => void }) => { }); }, [expandPartitionsVisible]); const formattedMinBytesInOut = (v: number) => { - const [unit, size] = getUnit(v); + const [unit, size] = getDataUnit['Memory'](v); return `${(v / size).toFixed(2)}${unit}/s`; }; return ( @@ -130,11 +131,15 @@ const ExpandPartition = (props: { record: any; onConfirm: () => void }) => {
Topic名称 : - {record.topicName} + + {record.topicName} +
描述 : - {record.description} + + {record.description || '-'} +
diff --git a/km-console/packages/layout-clusters-fe/src/pages/TopicList/index.less b/km-console/packages/layout-clusters-fe/src/pages/TopicList/index.less index 453363c6..0fa44077 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/TopicList/index.less +++ b/km-console/packages/layout-clusters-fe/src/pages/TopicList/index.less @@ -142,6 +142,7 @@ color: #74788d; } .desc-field { + flex-shrink: 0; width: 34px; } .val, @@ -149,17 +150,28 @@ color: #495057; letter-spacing: 0; font-weight: 400; - } - .val { - width: 105px; margin-left: 12px; } - .desc-val { - width: 809px; - height: 36px; + .val { + max-width: 208px; overflow: hidden; - -webkit-box-orient: vertical; + text-overflow: ellipsis; + white-space: nowrap; + } + .desc-val { + height: 36px; + display: -webkit-box; + overflow: hidden; + text-overflow: ellipsis; -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + word-break: break-all; + } + &:first-child { + margin-right: 40px; + } + &:last-child { + flex: 1; } } } diff --git a/km-console/packages/layout-clusters-fe/src/pages/index.tsx b/km-console/packages/layout-clusters-fe/src/pages/index.tsx index 4e1d1808..16d73de9 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/index.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/index.tsx @@ -1,6 +1,7 @@ import React, { useState, useEffect, useCallback } from 'react'; import { Redirect, useHistory, useLocation } from 'react-router-dom'; -import { DProLayout, AppContainer, RouteGuard, notification, Spin } from 'knowdesign'; +import { DProLayout, AppContainer, RouteGuard, Spin } from 'knowdesign'; +import notification from '@src/components/Notification'; import { pageRoutes } from './pageRoutes'; import { leftMenus, systemKey } from '@src/constants/menu'; import { ClustersPermissionMap } from './CommonConfig'; diff --git a/km-console/packages/layout-clusters-fe/src/pages/pageRoutes.ts b/km-console/packages/layout-clusters-fe/src/pages/pageRoutes.ts index 13422a46..50e6ac71 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/pageRoutes.ts +++ b/km-console/packages/layout-clusters-fe/src/pages/pageRoutes.ts @@ -10,7 +10,7 @@ import BrokerControllerChangeLog from './BrokerControllerChangeLog'; import TopicBoard from './TopicDashboard'; import TopicList from './TopicList'; -import Consumers from './Consumers/index'; +import Consumers from './ConsumerGroup'; import Jobs from './Jobs'; diff --git a/km-console/packages/layout-clusters-fe/src/style-addition.less b/km-console/packages/layout-clusters-fe/src/style-addition.less index 451c31bf..f4b7e04b 100644 --- a/km-console/packages/layout-clusters-fe/src/style-addition.less +++ b/km-console/packages/layout-clusters-fe/src/style-addition.less @@ -11,6 +11,7 @@ @select-item-selected-font-weight: normal; @btn-danger-bg: #F5483B; @btn-danger-border: #F5483B; +@notification-icon-size: 20px; // 自定义变量 // Input @input-bg: rgba(33, 37, 41, 0.06); @@ -656,3 +657,109 @@ .@{ant-prefix}-empty-img-default{ width: 100% !important; } + +// message 样式覆盖 +.@{message-prefix-cls} { + &-notice-content { + padding: 8px 12px; + font-size: 14px; + border-radius: 4px; + background: #fff; + } + &-success, + &-info, + &-warning, + &-error, + &-loading { + margin: unset; + padding: unset; + color: #000; + border-style: unset; + border-width: unset; + border-radius: unset; + } + + &-success { + background-color: unset; + border-color: unset; + } + + &-info, + &-loading { + background-color: unset; + border-color: unset; + } + + &-warning { + background-color: unset; + border-color: unset; + } + + &-error { + background-color: unset; + border-color: unset; + } + + .@{iconfont-css-prefix} { + top: 2px; + color: unset; + } +} + +// Notification 样式覆盖 +.@{notification-prefix-cls} { + &-notice { + width: 348px; + color: #000; + background-color: #fff; + border: unset; + border-radius: 4px; + box-shadow: 0 2px 4px 0 rgba(0,0,0,0.02), 0 4px 6px 6px rgba(0,0,0,0.02), 0 4px 6px 0 rgba(0,0,0,0.06); + &-message { + font-family: @font-family-bold; + font-size: 16px; + color: #000; + } + &-description { + font-size: 14px; + color: rgba(0,0,0,0.60); + } + &-with-icon &-message { + font-size: 16px; + margin-left: 26px; + } + &-with-icon &-description { + font-size: 14px; + margin-left: 26px; + } + &-icon { + top: 18px; + font-size: @notification-icon-size; + line-height: @notification-icon-size; + } + .@{iconfont-css-prefix}&-icon { + color: @notification-content-color !important; + } + &-success { + background-color: #fff; + border: unset; + } + &-warning { + background-color: #fff; + border: unset; + } + &-error { + background-color: #fff; + border: unset; + } + &-close { + color: rgba(0,0,0,0.60); + + &:hover { + & when not (@theme = dark) { + color: shade(@white, 30%); + } + } + } + } +} diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/cache/CollectedMetricsLocalCache.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/cache/CollectedMetricsLocalCache.java index bc5b1c34..2fc0a4ff 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/cache/CollectedMetricsLocalCache.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/cache/CollectedMetricsLocalCache.java @@ -24,11 +24,6 @@ public class CollectedMetricsLocalCache { .maximumSize(10000) .build(); - private static final Cache replicaMetricsValueCache = Caffeine.newBuilder() - .expireAfterWrite(90, TimeUnit.SECONDS) - .maximumSize(20000) - .build(); - public static Float getBrokerMetrics(String brokerMetricKey) { return brokerMetricsCache.getIfPresent(brokerMetricKey); } @@ -64,17 +59,6 @@ public class CollectedMetricsLocalCache { partitionMetricsCache.put(partitionMetricsKey, metricsList); } - public static Float getReplicaMetrics(String replicaMetricsKey) { - return replicaMetricsValueCache.getIfPresent(replicaMetricsKey); - } - - public static void putReplicaMetrics(String replicaMetricsKey, Float value) { - if (value == null) { - return; - } - replicaMetricsValueCache.put(replicaMetricsKey, value); - } - public static String genBrokerMetricKey(Long clusterPhyId, Integer brokerId, String metricName) { return clusterPhyId + "@" + brokerId + "@" + metricName; } diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/cache/ZookeeperLocalCache.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/cache/ZookeeperLocalCache.java new file mode 100644 index 00000000..24f6c7f2 --- /dev/null +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/cache/ZookeeperLocalCache.java @@ -0,0 +1,46 @@ +package com.xiaojukeji.know.streaming.km.core.cache; + +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.BaseFourLetterWordCmdData; + +import java.util.concurrent.TimeUnit; + +public class ZookeeperLocalCache { + private static final Cache fourLetterCmdFailedServerCache = Caffeine.newBuilder() + .expireAfterWrite(10, TimeUnit.MINUTES) + .maximumSize(10000) + .build(); + + private static final Cache fourLetterCmdDataCache = Caffeine.newBuilder() + .expireAfterWrite(60, TimeUnit.SECONDS) + .maximumSize(10000) + .build(); + + public static boolean canUse(String host, int port, String cmd) { + String data = fourLetterCmdFailedServerCache.getIfPresent(gen4lwFailedKey(host, port, cmd)); + + return data == null; + } + + public static void setFailed(String host, int port, String cmd) { + fourLetterCmdFailedServerCache.put(gen4lwFailedKey(host, port, cmd), ""); + } + + public static BaseFourLetterWordCmdData getData(String host, int port, String cmd) { + return fourLetterCmdDataCache.getIfPresent(gen4lwFailedKey(host, port, cmd)); + } + + public static void putData(String host, int port, String cmd, BaseFourLetterWordCmdData cmdData) { + fourLetterCmdDataCache.put(gen4lwFailedKey(host, port, cmd), cmdData); + } + + /**************************************************** private method ****************************************************/ + + private static String gen4lwFailedKey(String host, int port, String cmd) { + return host + "@" + port + "@" + cmd; + } + + + +} diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/broker/BrokerService.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/broker/BrokerService.java index 62f03e65..c8c300a0 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/broker/BrokerService.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/broker/BrokerService.java @@ -67,4 +67,8 @@ public interface BrokerService { * 获取总的Broker数 */ Integer countAllBrokers(); + + boolean allServerDown(Long clusterPhyId); + + boolean existServerDown(Long clusterPhyId); } diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/broker/impl/BrokerMetricServiceImpl.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/broker/impl/BrokerMetricServiceImpl.java index 93c343ff..e82882e1 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/broker/impl/BrokerMetricServiceImpl.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/broker/impl/BrokerMetricServiceImpl.java @@ -37,6 +37,8 @@ import com.xiaojukeji.know.streaming.km.core.service.version.metrics.BrokerMetri import com.xiaojukeji.know.streaming.km.core.service.version.metrics.ReplicaMetricVersionItems; import com.xiaojukeji.know.streaming.km.persistence.es.dao.BrokerMetricESDAO; import com.xiaojukeji.know.streaming.km.persistence.kafka.KafkaJMXClient; +import org.apache.kafka.clients.admin.LogDirDescription; +import org.apache.kafka.clients.admin.ReplicaInfo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; @@ -49,6 +51,7 @@ import java.util.*; import java.util.stream.Collectors; import static com.xiaojukeji.know.streaming.km.common.bean.entity.result.ResultStatus.*; +import static com.xiaojukeji.know.streaming.km.common.enums.version.VersionEnum.*; /** * @author didi @@ -105,7 +108,11 @@ public class BrokerMetricServiceImpl extends BaseMetricService implements Broker registerVCHandler( BROKER_METHOD_GET_HEALTH_SCORE, this::getMetricHealthScore); registerVCHandler( BROKER_METHOD_GET_PARTITIONS_SKEW, this::getPartitionsSkew); registerVCHandler( BROKER_METHOD_GET_LEADERS_SKEW, this::getLeadersSkew); - registerVCHandler( BROKER_METHOD_GET_LOG_SIZE, this::getLogSize); +// registerVCHandler( BROKER_METHOD_GET_LOG_SIZE, this::getLogSize); + + registerVCHandler( BROKER_METHOD_GET_LOG_SIZE, V_0_10_0_0, V_1_0_0, "getLogSizeFromJmx", this::getLogSizeFromJmx); + registerVCHandler( BROKER_METHOD_GET_LOG_SIZE, V_1_0_0, V_MAX, "getLogSizeFromClient", this::getLogSizeFromClient); + registerVCHandler( BROKER_METHOD_IS_BROKER_ALIVE, this::isBrokerAlive); } @@ -351,7 +358,7 @@ public class BrokerMetricServiceImpl extends BaseMetricService implements Broker ); } - private Result getLogSize(VersionItemParam metricParam) { + private Result getLogSizeFromJmx(VersionItemParam metricParam) { BrokerMetricParam param = (BrokerMetricParam)metricParam; String metric = param.getMetric(); @@ -360,19 +367,17 @@ public class BrokerMetricServiceImpl extends BaseMetricService implements Broker List partitions = partitionService.listPartitionByBroker(clusterId, brokerId); - JmxConnectorWrap jmxConnectorWrap = kafkaJMXClient.getClientWithCheck(clusterId, brokerId); - if (ValidateUtils.isNull(jmxConnectorWrap)){return Result.buildFailure(VC_JMX_INIT_ERROR);} - Float logSizeSum = 0f; for(Partition p : partitions) { try { - Result metricsResult = replicaMetricService.collectReplicaMetricsFromKafkaWithCache( + Result metricsResult = replicaMetricService.collectReplicaMetricsFromKafka( clusterId, p.getTopicName(), brokerId, p.getPartitionId(), ReplicaMetricVersionItems.REPLICATION_METRIC_LOG_SIZE ); + if(null == metricsResult || metricsResult.failed() || null == metricsResult.getData()) { continue; } @@ -391,6 +396,28 @@ public class BrokerMetricServiceImpl extends BaseMetricService implements Broker return Result.buildSuc(BrokerMetrics.initWithMetric(clusterId, brokerId, metric, logSizeSum)); } + private Result getLogSizeFromClient(VersionItemParam metricParam) { + BrokerMetricParam param = (BrokerMetricParam)metricParam; + + String metric = param.getMetric(); + Long clusterId = param.getClusterId(); + Integer brokerId = param.getBrokerId(); + + Result> descriptionMapResult = brokerService.getBrokerLogDirDescFromKafka(clusterId, brokerId); + if(null == descriptionMapResult || descriptionMapResult.failed() || null == descriptionMapResult.getData()) { + return Result.buildFromIgnoreData(descriptionMapResult); + } + + Float logSizeSum = 0f; + for (LogDirDescription logDirDescription: descriptionMapResult.getData().values()) { + for (ReplicaInfo replicaInfo: logDirDescription.replicaInfos().values()) { + logSizeSum += replicaInfo.size(); + } + } + + return Result.buildSuc(BrokerMetrics.initWithMetric(clusterId, brokerId, metric, logSizeSum)); + } + private Result getLeadersSkew(VersionItemParam metricParam) { BrokerMetricParam param = (BrokerMetricParam)metricParam; diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/broker/impl/BrokerServiceImpl.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/broker/impl/BrokerServiceImpl.java index fbede23c..3fd74ee5 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/broker/impl/BrokerServiceImpl.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/broker/impl/BrokerServiceImpl.java @@ -262,14 +262,32 @@ public class BrokerServiceImpl extends BaseVersionControlService implements Brok return version; } - - @Override public Integer countAllBrokers() { LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); return brokerDAO.selectCount(lambdaQueryWrapper); } + @Override + public boolean allServerDown(Long clusterPhyId) { + List poList = this.getAllBrokerPOsFromDB(clusterPhyId); + if (ValidateUtils.isEmptyList(poList)) { + return false; + } + + return poList.stream().filter(elem -> elem.getStatus().equals(Constant.DOWN)).count() == poList.size(); + } + + @Override + public boolean existServerDown(Long clusterPhyId) { + List poList = this.getAllBrokerPOsFromDB(clusterPhyId); + if (ValidateUtils.isEmptyList(poList)) { + return false; + } + + return poList.stream().filter(elem -> elem.getStatus().equals(Constant.DOWN)).count() > 0; + } + /**************************************************** private method ****************************************************/ private List listAllBrokersAndUpdateCache(Long clusterPhyId) { @@ -343,17 +361,9 @@ public class BrokerServiceImpl extends BaseVersionControlService implements Brok private Broker getStartTimeAndBuildBroker(Long clusterPhyId, Node newNode, JmxConfig jmxConfig) { try { - Object object = jmxDAO.getJmxValue( - clusterPhyId, - newNode.id(), - newNode.host(), - null, - jmxConfig, - new ObjectName("java.lang:type=Runtime"), - "StartTime" - ); + Long startTime = jmxDAO.getServerStartTime(clusterPhyId, newNode.host(), null, jmxConfig); - return Broker.buildFrom(clusterPhyId, newNode, object != null? (Long) object: null); + return Broker.buildFrom(clusterPhyId, newNode, startTime); } catch (Exception e) { log.error("class=BrokerServiceImpl||method=getStartTimeAndBuildBroker||clusterPhyId={}||brokerNode={}||jmxConfig={}||errMsg=exception!", clusterPhyId, newNode, jmxConfig, e); } diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/cluster/impl/ClusterMetricServiceImpl.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/cluster/impl/ClusterMetricServiceImpl.java index 9fdd9ec0..3d004f78 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/cluster/impl/ClusterMetricServiceImpl.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/cluster/impl/ClusterMetricServiceImpl.java @@ -85,7 +85,7 @@ public class ClusterMetricServiceImpl extends BaseMetricService implements Clust public static final String CLUSTER_METHOD_GET_TOTAL_LOG_SIZE = "getTotalLogSize"; public static final String CLUSTER_METHOD_GET_PARTITION_SIZE = "getPartitionSize"; public static final String CLUSTER_METHOD_GET_PARTITION_NO_LEADER_SIZE = "getPartitionNoLeaderSize"; - public static final String CLUSTER_METHOD_GET_HEALTH_SCORE = "getTopicHealthScore"; + public static final String CLUSTER_METHOD_GET_HEALTH_SCORE = "getClusterHealthScore"; public static final String CLUSTER_METHOD_GET_METRIC_FROM_KAFKA_BY_TOTAL_BROKERS_JMX = "getMetricFromKafkaByTotalBrokersJMX"; public static final String CLUSTER_METHOD_GET_METRIC_FROM_KAFKA_BY_CONTROLLER_JMX = "getMetricFromKafkaByControllerJMX"; public static final String CLUSTER_METHOD_GET_ZK_COUNT = "getZKCount"; @@ -188,7 +188,7 @@ public class ClusterMetricServiceImpl extends BaseMetricService implements Clust registerVCHandler( CLUSTER_METHOD_GET_PARTITION_SIZE, this::getPartitionSize); registerVCHandler( CLUSTER_METHOD_GET_PARTITION_NO_LEADER_SIZE, this::getPartitionNoLeaderSize); - registerVCHandler( CLUSTER_METHOD_GET_HEALTH_SCORE, this::getTopicHealthScore); + registerVCHandler( CLUSTER_METHOD_GET_HEALTH_SCORE, this::getClusterHealthScore); registerVCHandler( CLUSTER_METHOD_GET_METRIC_FROM_KAFKA_BY_TOTAL_BROKERS_JMX, this::getMetricFromKafkaByTotalBrokersJMX); registerVCHandler( CLUSTER_METHOD_GET_METRIC_FROM_KAFKA_BY_CONTROLLER_JMX, this::getMetricFromKafkaByControllerJMX); @@ -364,7 +364,7 @@ public class ClusterMetricServiceImpl extends BaseMetricService implements Clust /** * 获取集群的健康分 */ - private Result getTopicHealthScore(VersionItemParam metricParam){ + private Result getClusterHealthScore(VersionItemParam metricParam){ ClusterMetricParam param = (ClusterMetricParam)metricParam; ClusterMetrics clusterMetrics = healthScoreService.calClusterHealthScore(param.getClusterId()); return Result.buildSuc(clusterMetrics); diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/group/GroupService.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/group/GroupService.java index 790a7c47..8dc1c535 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/group/GroupService.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/group/GroupService.java @@ -1,6 +1,7 @@ package com.xiaojukeji.know.streaming.km.core.service.group; import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationBaseDTO; +import com.xiaojukeji.know.streaming.km.common.bean.entity.group.Group; import com.xiaojukeji.know.streaming.km.common.bean.entity.result.PaginationResult; import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; import com.xiaojukeji.know.streaming.km.common.bean.po.group.GroupMemberPO; @@ -16,27 +17,47 @@ import java.util.Map; public interface GroupService { /** - * 从Kafka中获取消费组 - * @param clusterPhyId 集群ID - * @return - * @throws NotExistException - * @throws AdminOperateException + * 从Kafka中获取消费组名称列表 */ List listGroupsFromKafka(Long clusterPhyId) throws NotExistException, AdminOperateException; - Map getGroupOffset(Long clusterPhyId, String groupName) throws NotExistException, AdminOperateException; + /** + * 从Kafka中获取消费组详细信息 + */ + Group getGroupFromKafka(Long clusterPhyId, String groupName) throws NotExistException, AdminOperateException; - ConsumerGroupDescription getGroupDescription(Long clusterPhyId, String groupName) throws NotExistException, AdminOperateException; + Map getGroupOffsetFromKafka(Long clusterPhyId, String groupName) throws NotExistException, AdminOperateException; - int replaceDBData(GroupMemberPO groupMemberPO); + ConsumerGroupDescription getGroupDescriptionFromKafka(Long clusterPhyId, String groupName) throws NotExistException, AdminOperateException; - void batchReplace(List newGroupMemberList); + Result resetGroupOffsets(Long clusterPhyId, String groupName, Map offsetMap, String operator) throws NotExistException, AdminOperateException; + /** + * 批量更新DB + */ + void batchReplaceGroupsAndMembers(Long clusterPhyId, List newGroupList, long updateTime); + + int deleteByUpdateTimeBeforeInDB(Long clusterPhyId, Date beforeTime); + + /** + * DB-Group相关接口 + */ GroupStateEnum getGroupStateFromDB(Long clusterPhyId, String groupName); - List listGroupByTopic(Long clusterPhyId, String topicName); + Group getGroupFromDB(Long clusterPhyId, String groupName); - List listGroup(Long clusterPhyId); + List listClusterGroups(Long clusterPhyId); + + List getGroupsFromDB(Long clusterPhyId); + + Integer calGroupCount(Long clusterPhyId); + + Integer calGroupStatCount(Long clusterPhyId, GroupStateEnum stateEnum); + + /** + * DB-GroupTopic相关接口 + */ + List listGroupByTopic(Long clusterPhyId, String topicName); PaginationResult pagingGroupMembers(Long clusterPhyId, String topicName, @@ -45,15 +66,5 @@ public interface GroupService { String searchGroupKeyword, PaginationBaseDTO dto); - int deleteByUpdateTimeBeforeInDB(Long clusterPhyId, Date beforeTime); - - List getGroupsFromDB(Long clusterPhyId); - - GroupMemberPO getGroupFromDB(Long clusterPhyId, String groupName, String topicName); - - Integer calGroupCount(Long clusterPhyId); - - Integer calGroupStatCount(Long clusterPhyId, GroupStateEnum stateEnum); - - Result resetGroupOffsets(Long clusterPhyId, String groupName, Map offsetMap, String operator) throws NotExistException, AdminOperateException; -} + GroupMemberPO getGroupTopicFromDB(Long clusterPhyId, String groupName, String topicName); +} \ No newline at end of file diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/group/impl/GroupMetricServiceImpl.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/group/impl/GroupMetricServiceImpl.java index 427edc2c..936897a3 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/group/impl/GroupMetricServiceImpl.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/group/impl/GroupMetricServiceImpl.java @@ -24,7 +24,6 @@ import com.xiaojukeji.know.streaming.km.core.service.health.score.HealthScoreSer import com.xiaojukeji.know.streaming.km.core.service.partition.PartitionService; import com.xiaojukeji.know.streaming.km.core.service.version.BaseMetricService; import com.xiaojukeji.know.streaming.km.persistence.es.dao.GroupMetricESDAO; -import com.xiaojukeji.know.streaming.km.persistence.kafka.KafkaAdminClient; import org.apache.kafka.clients.admin.OffsetSpec; import org.apache.kafka.common.TopicPartition; import org.springframework.beans.factory.annotation.Autowired; @@ -183,7 +182,7 @@ public class GroupMetricServiceImpl extends BaseMetricService implements GroupMe List metricsList = new ArrayList<>(); try { - Map groupOffsetMap = groupService.getGroupOffset(clusterId, groupName); + Map groupOffsetMap = groupService.getGroupOffsetFromKafka(clusterId, groupName); // 组织 GROUP_METRIC_OFFSET_CONSUMED 指标 for (Map.Entry entry: groupOffsetMap.entrySet()) { diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/group/impl/GroupServiceImpl.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/group/impl/GroupServiceImpl.java index 4cf29d2a..1a923f21 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/group/impl/GroupServiceImpl.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/group/impl/GroupServiceImpl.java @@ -7,11 +7,15 @@ import com.didiglobal.logi.log.ILog; import com.didiglobal.logi.log.LogFactory; import com.didiglobal.logi.security.common.dto.oplog.OplogDTO; import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationBaseDTO; +import com.xiaojukeji.know.streaming.km.common.bean.entity.group.Group; +import com.xiaojukeji.know.streaming.km.common.bean.entity.group.GroupTopicMember; import com.xiaojukeji.know.streaming.km.common.bean.entity.result.PaginationResult; import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; import com.xiaojukeji.know.streaming.km.common.bean.entity.result.ResultStatus; import com.xiaojukeji.know.streaming.km.common.bean.po.group.GroupMemberPO; +import com.xiaojukeji.know.streaming.km.common.bean.po.group.GroupPO; import com.xiaojukeji.know.streaming.km.common.constant.KafkaConstant; +import com.xiaojukeji.know.streaming.km.common.converter.GroupConverter; import com.xiaojukeji.know.streaming.km.common.enums.group.GroupStateEnum; import com.xiaojukeji.know.streaming.km.common.enums.operaterecord.ModuleEnum; import com.xiaojukeji.know.streaming.km.common.enums.operaterecord.OperationEnum; @@ -24,6 +28,7 @@ import com.xiaojukeji.know.streaming.km.core.service.group.GroupService; import com.xiaojukeji.know.streaming.km.core.service.oprecord.OpLogWrapService; import com.xiaojukeji.know.streaming.km.core.service.version.BaseVersionControlService; import com.xiaojukeji.know.streaming.km.persistence.kafka.KafkaAdminClient; +import com.xiaojukeji.know.streaming.km.persistence.mysql.group.GroupDAO; import com.xiaojukeji.know.streaming.km.persistence.mysql.group.GroupMemberDAO; import org.apache.kafka.clients.admin.*; import org.apache.kafka.clients.consumer.OffsetAndMetadata; @@ -41,6 +46,9 @@ import static com.xiaojukeji.know.streaming.km.common.enums.version.VersionItemT public class GroupServiceImpl extends BaseVersionControlService implements GroupService { private static final ILog log = LogFactory.getLog(GroupServiceImpl.class); + @Autowired + private GroupDAO groupDAO; + @Autowired private GroupMemberDAO groupMemberDAO; @@ -79,7 +87,43 @@ public class GroupServiceImpl extends BaseVersionControlService implements Group } @Override - public Map getGroupOffset(Long clusterPhyId, String groupName) throws NotExistException, AdminOperateException { + public Group getGroupFromKafka(Long clusterPhyId, String groupName) throws NotExistException, AdminOperateException { + // 获取消费组的详细信息 + ConsumerGroupDescription groupDescription = this.getGroupDescriptionFromKafka(clusterPhyId, groupName); + if (groupDescription == null) { + return null; + } + + Group group = new Group(clusterPhyId, groupName, groupDescription); + + // 获取消费组消费过哪些Topic + Map memberMap = new HashMap<>(); + for (TopicPartition tp : this.getGroupOffsetFromKafka(clusterPhyId, groupName).keySet()) { + memberMap.putIfAbsent(tp.topic(), new GroupTopicMember(tp.topic(), 0)); + } + + // 记录成员信息 + for (MemberDescription memberDescription : groupDescription.members()) { + Set partitionList = new HashSet<>(); + if (!ValidateUtils.isNull(memberDescription.assignment().topicPartitions())) { + partitionList = memberDescription.assignment().topicPartitions(); + } + + Set topicNameSet = partitionList.stream().map(elem -> elem.topic()).collect(Collectors.toSet()); + for (String topicName : topicNameSet) { + memberMap.putIfAbsent(topicName, new GroupTopicMember(topicName, 0)); + + GroupTopicMember member = memberMap.get(topicName); + member.setMemberCount(member.getMemberCount() + 1); + } + } + group.setTopicMembers(memberMap.values().stream().collect(Collectors.toList())); + + return group; + } + + @Override + public Map getGroupOffsetFromKafka(Long clusterPhyId, String groupName) throws NotExistException, AdminOperateException { AdminClient adminClient = kafkaAdminClient.getClient(clusterPhyId); Map offsetMap = new HashMap<>(); @@ -99,7 +143,7 @@ public class GroupServiceImpl extends BaseVersionControlService implements Group } @Override - public ConsumerGroupDescription getGroupDescription(Long clusterPhyId, String groupName) throws NotExistException, AdminOperateException { + public ConsumerGroupDescription getGroupDescriptionFromKafka(Long clusterPhyId, String groupName) throws NotExistException, AdminOperateException { AdminClient adminClient = kafkaAdminClient.getClient(clusterPhyId); try { @@ -117,40 +161,12 @@ public class GroupServiceImpl extends BaseVersionControlService implements Group } @Override - public int replaceDBData(GroupMemberPO groupMemberPO) { - return groupMemberDAO.replace(groupMemberPO); - } - - @Override - public void batchReplace(List newGroupMemberList) { - if (newGroupMemberList == null || newGroupMemberList.isEmpty()) { - return; - } - - Long clusterPhyId = newGroupMemberList.get(0).getClusterPhyId(); - if (clusterPhyId == null) { - return; - } - - List dbGroupMemberList = listGroup(clusterPhyId); - - - Map dbGroupMemberMap = dbGroupMemberList.stream().collect(Collectors.toMap(elem -> elem.getGroupName() + elem.getTopicName(), Function.identity())); - for (GroupMemberPO groupMemberPO : newGroupMemberList) { - GroupMemberPO po = dbGroupMemberMap.remove(groupMemberPO.getGroupName() + groupMemberPO.getTopicName()); - try { - if (po != null) { - groupMemberPO.setId(po.getId()); - groupMemberDAO.updateById(groupMemberPO); - } else { - groupMemberDAO.insert(groupMemberPO); - } - } catch (Exception e) { - log.error("method=batchReplace||clusterPhyId={}||groupName={}||errMsg=exception", clusterPhyId, groupMemberPO.getGroupName(), e); - } - - } + public void batchReplaceGroupsAndMembers(Long clusterPhyId, List newGroupList, long updateTime) { + // 更新Group信息 + this.batchReplaceGroups(clusterPhyId, newGroupList, updateTime); + // 更新Group-Topic信息 + this.batchReplaceGroupMembers(clusterPhyId, newGroupList, updateTime); } @Override @@ -176,14 +192,6 @@ public class GroupServiceImpl extends BaseVersionControlService implements Group return groupMemberDAO.selectList(lambdaQueryWrapper); } - @Override - public List listGroup(Long clusterPhyId) { - LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); - lambdaQueryWrapper.eq(GroupMemberPO::getClusterPhyId, clusterPhyId); - - return groupMemberDAO.selectList(lambdaQueryWrapper); - } - @Override public PaginationResult pagingGroupMembers(Long clusterPhyId, String topicName, @@ -208,8 +216,33 @@ public class GroupServiceImpl extends BaseVersionControlService implements Group return PaginationResult.buildSuc(iPage.getRecords(), iPage); } + @Override + public Group getGroupFromDB(Long clusterPhyId, String groupName) { + LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); + lambdaQueryWrapper.eq(GroupPO::getClusterPhyId, clusterPhyId); + lambdaQueryWrapper.eq(GroupPO::getName, groupName); + + GroupPO groupPO = groupDAO.selectOne(lambdaQueryWrapper); + return GroupConverter.convert2Group(groupPO); + } + + @Override + public List listClusterGroups(Long clusterPhyId) { + LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); + lambdaQueryWrapper.eq(GroupPO::getClusterPhyId, clusterPhyId); + + return groupDAO.selectList(lambdaQueryWrapper).stream().map(elem -> GroupConverter.convert2Group(elem)).collect(Collectors.toList()); + } + @Override public int deleteByUpdateTimeBeforeInDB(Long clusterPhyId, Date beforeTime) { + // 删除过期Group信息 + LambdaQueryWrapper groupPOLambdaQueryWrapper = new LambdaQueryWrapper<>(); + groupPOLambdaQueryWrapper.eq(GroupPO::getClusterPhyId, clusterPhyId); + groupPOLambdaQueryWrapper.le(GroupPO::getUpdateTime, beforeTime); + groupDAO.delete(groupPOLambdaQueryWrapper); + + // 删除过期GroupMember信息 LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(GroupMemberPO::getClusterPhyId, clusterPhyId); queryWrapper.le(GroupMemberPO::getUpdateTime, beforeTime); @@ -218,17 +251,19 @@ public class GroupServiceImpl extends BaseVersionControlService implements Group @Override public List getGroupsFromDB(Long clusterPhyId) { - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(GroupMemberPO::getClusterPhyId, clusterPhyId); - List poList = groupMemberDAO.selectList(queryWrapper); + LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); + lambdaQueryWrapper.eq(GroupPO::getClusterPhyId, clusterPhyId); + + List poList = groupDAO.selectList(lambdaQueryWrapper); if (poList == null) { poList = new ArrayList<>(); } - return new ArrayList<>(poList.stream().map(elem -> elem.getGroupName()).collect(Collectors.toSet())); + + return new ArrayList<>(poList.stream().map(elem -> elem.getName()).collect(Collectors.toSet())); } @Override - public GroupMemberPO getGroupFromDB(Long clusterPhyId, String groupName, String topicName) { + public GroupMemberPO getGroupTopicFromDB(Long clusterPhyId, String groupName, String topicName) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(GroupMemberPO::getClusterPhyId, clusterPhyId); queryWrapper.eq(GroupMemberPO::getTopicName, topicName); @@ -239,28 +274,19 @@ public class GroupServiceImpl extends BaseVersionControlService implements Group @Override public Integer calGroupCount(Long clusterPhyId) { - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(GroupMemberPO::getClusterPhyId, clusterPhyId); - List poList = groupMemberDAO.selectList(queryWrapper); - if (poList == null) { - poList = new ArrayList<>(); - } + LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); + lambdaQueryWrapper.eq(GroupPO::getClusterPhyId, clusterPhyId); - return poList.stream().map(elem -> elem.getGroupName()).collect(Collectors.toSet()).size(); + return groupDAO.selectCount(lambdaQueryWrapper); } @Override public Integer calGroupStatCount(Long clusterPhyId, GroupStateEnum stateEnum) { - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(GroupMemberPO::getClusterPhyId, clusterPhyId); - queryWrapper.eq(GroupMemberPO::getState, stateEnum.getState()); + LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); + lambdaQueryWrapper.eq(GroupPO::getClusterPhyId, clusterPhyId); + lambdaQueryWrapper.eq(GroupPO::getState, stateEnum.getState()); - List poList = groupMemberDAO.selectList(queryWrapper); - if (poList == null) { - poList = new ArrayList<>(); - } - - return poList.stream().map(elem -> elem.getGroupName()).collect(Collectors.toSet()).size(); + return groupDAO.selectCount(lambdaQueryWrapper); } @Override @@ -303,4 +329,74 @@ public class GroupServiceImpl extends BaseVersionControlService implements Group /**************************************************** private method ****************************************************/ + private void batchReplaceGroupMembers(Long clusterPhyId, List newGroupList, long updateTime) { + if (ValidateUtils.isEmptyList(newGroupList)) { + return; + } + + List dbPOList = this.listClusterGroupsMemberPO(clusterPhyId); + Map dbPOMap = dbPOList.stream().collect(Collectors.toMap(elem -> elem.getGroupName() + elem.getTopicName(), Function.identity())); + + for (Group group: newGroupList) { + for (GroupTopicMember member : group.getTopicMembers()) { + try { + GroupMemberPO newPO = new GroupMemberPO(clusterPhyId, member.getTopicName(), group.getName(), group.getState().getState(), member.getMemberCount(), new Date(updateTime)); + + GroupMemberPO dbPO = dbPOMap.remove(newPO.getGroupName() + newPO.getTopicName()); + if (dbPO != null) { + newPO.setId(dbPO.getId()); + groupMemberDAO.updateById(newPO); + continue; + } + + groupMemberDAO.insert(newPO); + } catch (Exception e) { + log.error( + "method=batchReplaceGroupMembers||clusterPhyId={}||groupName={}||topicName={}||errMsg=exception", + clusterPhyId, group.getName(), member.getTopicName(), e + ); + } + } + } + } + + private void batchReplaceGroups(Long clusterPhyId, List newGroupList, long updateTime) { + if (ValidateUtils.isEmptyList(newGroupList)) { + return; + } + + List dbGroupList = this.listClusterGroupsPO(clusterPhyId); + Map dbGroupMap = dbGroupList.stream().collect(Collectors.toMap(elem -> elem.getName(), Function.identity())); + + for (Group newGroup: newGroupList) { + try { + GroupPO newPO = GroupConverter.convert2GroupPO(newGroup); + newPO.setUpdateTime(new Date(updateTime)); + + GroupPO dbPO = dbGroupMap.remove(newGroup.getName()); + if (dbPO != null) { + newPO.setId(dbPO.getId()); + groupDAO.updateById(newPO); + continue; + } + + groupDAO.insert(newPO); + } catch (Exception e) { + log.error("method=batchGroupReplace||clusterPhyId={}||groupName={}||errMsg=exception", clusterPhyId, newGroup.getName(), e); + } + } + } + + private List listClusterGroupsPO(Long clusterPhyId) { + LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); + lambdaQueryWrapper.eq(GroupPO::getClusterPhyId, clusterPhyId); + return groupDAO.selectList(lambdaQueryWrapper); + } + + private List listClusterGroupsMemberPO(Long clusterPhyId) { + LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); + lambdaQueryWrapper.eq(GroupMemberPO::getClusterPhyId, clusterPhyId); + + return groupMemberDAO.selectList(lambdaQueryWrapper); + } } diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/health/checkresult/HealthCheckResultService.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/health/checkresult/HealthCheckResultService.java index 19cb292a..6aaddcdb 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/health/checkresult/HealthCheckResultService.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/health/checkresult/HealthCheckResultService.java @@ -20,4 +20,6 @@ public interface HealthCheckResultService { List getResHealthCheckResult(Long clusterPhyId, Integer dimension, String resNme); Map getClusterHealthConfig(Long clusterPhyId); + + void batchReplace(Long clusterPhyId, List healthCheckResults); } diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/health/checkresult/impl/HealthCheckResultServiceImpl.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/health/checkresult/impl/HealthCheckResultServiceImpl.java index 09c30a1b..cad2f396 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/health/checkresult/impl/HealthCheckResultServiceImpl.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/health/checkresult/impl/HealthCheckResultServiceImpl.java @@ -3,10 +3,12 @@ package com.xiaojukeji.know.streaming.km.core.service.health.checkresult.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.didiglobal.logi.log.ILog; import com.didiglobal.logi.log.LogFactory; +import com.google.common.collect.Lists; import com.xiaojukeji.know.streaming.km.common.bean.entity.config.healthcheck.BaseClusterHealthConfig; import com.xiaojukeji.know.streaming.km.common.bean.entity.health.HealthCheckResult; import com.xiaojukeji.know.streaming.km.common.bean.po.config.PlatformClusterConfigPO; import com.xiaojukeji.know.streaming.km.common.bean.po.health.HealthCheckResultPO; +import com.xiaojukeji.know.streaming.km.common.constant.Constant; import com.xiaojukeji.know.streaming.km.common.enums.config.ConfigGroupEnum; import com.xiaojukeji.know.streaming.km.common.enums.health.HealthCheckNameEnum; import com.xiaojukeji.know.streaming.km.common.utils.ConvertUtil; @@ -88,4 +90,17 @@ public class HealthCheckResultServiceImpl implements HealthCheckResultService { } return configMap; } + + @Override + public void batchReplace(Long clusterPhyId, List healthCheckResults) { + List> healthCheckResultPartitions = Lists.partition(healthCheckResults, Constant.PER_BATCH_MAX_VALUE); + for (List checkResultPartition : healthCheckResultPartitions) { + List healthCheckResultPos = ConvertUtil.list2List(checkResultPartition, HealthCheckResultPO.class); + try { + healthCheckResultDAO.batchReplace(healthCheckResultPos); + } catch (Exception e) { + log.error("method=batchReplace||clusterPhyId={}||checkResultList={}||errMsg=exception!", clusterPhyId, healthCheckResultPos, e); + } + } + } } diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/health/score/HealthScoreService.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/health/score/HealthScoreService.java index 5997edec..48f8933b 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/health/score/HealthScoreService.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/health/score/HealthScoreService.java @@ -15,35 +15,16 @@ public interface HealthScoreService { * @param clusterPhyId 集群ID * @return */ + @Deprecated ClusterMetrics calClusterHealthScore(Long clusterPhyId); - /** - * 获取集群Topics健康分指标 - * @param clusterPhyId 集群ID - * @return - */ - ClusterMetrics calClusterTopicsHealthScore(Long clusterPhyId); - - /** - * 获取集群Brokers健康分指标 - * @param clusterPhyId 集群ID - * @return - */ - ClusterMetrics calClusterBrokersHealthScore(Long clusterPhyId); - - /** - * 获取集群Groups健康分指标 - * @param clusterPhyId 集群ID - * @return - */ - ClusterMetrics calClusterGroupsHealthScore(Long clusterPhyId); - /** * 获取集群健康分指标 * @param clusterPhyId 集群ID * @param topicName Topic名称 * @return */ + @Deprecated TopicMetrics calTopicHealthScore(Long clusterPhyId, String topicName); /** @@ -52,6 +33,7 @@ public interface HealthScoreService { * @param brokerId brokerId * @return */ + @Deprecated BrokerMetrics calBrokerHealthScore(Long clusterPhyId, Integer brokerId); /** @@ -60,6 +42,7 @@ public interface HealthScoreService { * @param groupName group名称 * @return */ + @Deprecated GroupMetrics calGroupHealthScore(Long clusterPhyId, String groupName); /** diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/health/score/impl/HealthScoreServiceImpl.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/health/score/impl/HealthScoreServiceImpl.java index c443c3bb..6ba01bb9 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/health/score/impl/HealthScoreServiceImpl.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/health/score/impl/HealthScoreServiceImpl.java @@ -136,60 +136,6 @@ public class HealthScoreServiceImpl implements HealthScoreService { return metrics; } - @Override - public ClusterMetrics calClusterTopicsHealthScore(Long clusterPhyId) { - List healthScoreResultList = this.getDimensionHealthScoreResult(clusterPhyId, HealthCheckDimensionEnum.TOPIC); - - ClusterMetrics metrics = new ClusterMetrics(clusterPhyId); - if (ValidateUtils.isEmptyList(healthScoreResultList)) { - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_SCORE_TOPICS, Constant.MIN_HEALTH_SCORE); - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_CHECK_PASSED_TOPICS, 0.0f); - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_CHECK_TOTAL_TOPICS, 0.0f); - } else { - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_SCORE_TOPICS, Math.max(this.getDimensionHealthScore(healthScoreResultList), Constant.MIN_HEALTH_SCORE)); - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_CHECK_PASSED_TOPICS, getHealthCheckPassed(healthScoreResultList)); - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_CHECK_TOTAL_TOPICS, Float.valueOf(healthScoreResultList.size())); - } - - return metrics; - } - - @Override - public ClusterMetrics calClusterBrokersHealthScore(Long clusterPhyId) { - List healthScoreResultList = this.getDimensionHealthScoreResult(clusterPhyId, HealthCheckDimensionEnum.BROKER); - - ClusterMetrics metrics = new ClusterMetrics(clusterPhyId); - if (ValidateUtils.isEmptyList(healthScoreResultList)) { - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_SCORE_BROKERS, Constant.MIN_HEALTH_SCORE); - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_CHECK_PASSED_BROKERS, 0.0f); - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_CHECK_TOTAL_BROKERS, 0.0f); - } else { - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_SCORE_BROKERS, Math.max(this.getDimensionHealthScore(healthScoreResultList), Constant.MIN_HEALTH_SCORE)); - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_CHECK_PASSED_BROKERS, getHealthCheckPassed(healthScoreResultList)); - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_CHECK_TOTAL_BROKERS, Float.valueOf(healthScoreResultList.size())); - } - - return metrics; - } - - @Override - public ClusterMetrics calClusterGroupsHealthScore(Long clusterPhyId) { - List healthScoreResultList = this.getDimensionHealthScoreResult(clusterPhyId, HealthCheckDimensionEnum.GROUP); - - ClusterMetrics metrics = new ClusterMetrics(clusterPhyId); - if (ValidateUtils.isEmptyList(healthScoreResultList)) { - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_SCORE_GROUPS, Constant.MIN_HEALTH_SCORE); - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_CHECK_PASSED_GROUPS, 0.0f); - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_CHECK_TOTAL_GROUPS, 0.0f); - } else { - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_SCORE_GROUPS, Math.max(this.getDimensionHealthScore(healthScoreResultList), Constant.MIN_HEALTH_SCORE)); - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_CHECK_PASSED_GROUPS, this.getHealthCheckPassed(healthScoreResultList)); - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_CHECK_TOTAL_GROUPS, Float.valueOf(healthScoreResultList.size())); - } - - return metrics; - } - @Override public TopicMetrics calTopicHealthScore(Long clusterPhyId, String topicName) { List healthScoreResultList = this.getResHealthScoreResult(clusterPhyId, HealthCheckDimensionEnum.TOPIC.getDimension(), topicName); diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/replica/ReplicaMetricService.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/replica/ReplicaMetricService.java index 987303f8..c0a44586 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/replica/ReplicaMetricService.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/replica/ReplicaMetricService.java @@ -13,12 +13,14 @@ public interface ReplicaMetricService { * 从kafka中采集指标 */ Result collectReplicaMetricsFromKafka(Long clusterId, String topic, Integer partitionId, Integer brokerId, String metric); - Result collectReplicaMetricsFromKafkaWithCache(Long clusterPhyId, String topic, Integer brokerId, Integer partitionId, String metric); + Result collectReplicaMetricsFromKafka(Long clusterId, String topicName, Integer partitionId, Integer brokerId, List metricNameList); /** * 从ES中获取指标 */ + @Deprecated Result> getMetricPointsFromES(Long clusterPhyId, Integer brokerId, String topicName, Integer partitionId, MetricDTO dto); + @Deprecated Result getLatestMetricsFromES(Long clusterPhyId, Integer brokerId, String topicName, Integer partitionId, List metricNames); } diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/replica/impl/ReplicaMetricServiceImpl.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/replica/impl/ReplicaMetricServiceImpl.java index 460e6520..848c8601 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/replica/impl/ReplicaMetricServiceImpl.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/replica/impl/ReplicaMetricServiceImpl.java @@ -17,7 +17,6 @@ import com.xiaojukeji.know.streaming.km.common.jmx.JmxConnectorWrap; import com.xiaojukeji.know.streaming.km.common.utils.BeanUtil; import com.xiaojukeji.know.streaming.km.common.utils.ConvertUtil; import com.xiaojukeji.know.streaming.km.common.utils.ValidateUtils; -import com.xiaojukeji.know.streaming.km.core.cache.CollectedMetricsLocalCache; import com.xiaojukeji.know.streaming.km.core.service.partition.PartitionService; import com.xiaojukeji.know.streaming.km.core.service.replica.ReplicaMetricService; import com.xiaojukeji.know.streaming.km.core.service.version.BaseMetricService; @@ -77,32 +76,36 @@ public class ReplicaMetricServiceImpl extends BaseMetricService implements Repli } @Override - public Result collectReplicaMetricsFromKafkaWithCache(Long clusterPhyId, - String topic, - Integer brokerId, - Integer partitionId, - String metric) { - String replicaMetricsKey = CollectedMetricsLocalCache.genReplicaMetricCacheKey(clusterPhyId, brokerId, topic, partitionId, metric); + public Result collectReplicaMetricsFromKafka(Long clusterId, String topicName, Integer partitionId, Integer brokerId, List metricNameList) { + ReplicationMetrics metrics = new ReplicationMetrics(clusterId, topicName, brokerId, partitionId); + for (String metricName: metricNameList) { + try { + if (metrics.getMetrics().containsKey(metricName)) { + continue; + } - Float keyValue = CollectedMetricsLocalCache.getReplicaMetrics(replicaMetricsKey); - if(null != keyValue){ - ReplicationMetrics replicationMetrics = new ReplicationMetrics(clusterPhyId, topic, partitionId, brokerId); - replicationMetrics.putMetric(metric, keyValue); - return Result.buildSuc(replicationMetrics); + Result ret = this.collectReplicaMetricsFromKafka( + clusterId, + metrics.getTopic(), + metrics.getBrokerId(), + metrics.getPartitionId(), + metricName + ); + + if (null == ret || ret.failed() || null == ret.getData()) { + continue; + } + + metrics.putMetric(ret.getData().getMetrics()); + } catch (Exception e) { + LOGGER.error( + "method=collectReplicaMetricsFromKafka||clusterPhyId={}||topicName={}||partition={}||brokerId={}||metricName={}||errMsg=exception!", + clusterId, topicName, partitionId, brokerId, e + ); + } } - Result ret = collectReplicaMetricsFromKafka(clusterPhyId, topic, partitionId, brokerId, metric); - if(null == ret || ret.failed() || null == ret.getData()){return ret;} - - // 更新cache - ret.getData().getMetrics().entrySet().stream().forEach( - metricNameAndValueEntry -> CollectedMetricsLocalCache.putReplicaMetrics( - replicaMetricsKey, - metricNameAndValueEntry.getValue() - ) - ); - - return ret; + return Result.buildSuc(metrics); } @Override @@ -167,8 +170,8 @@ public class ReplicaMetricServiceImpl extends BaseMetricService implements Repli Integer brokerId = metricParam.getBrokerId(); Integer partitionId = metricParam.getPartitionId(); - Result endRet = this.collectReplicaMetricsFromKafkaWithCache(clusterId, topic, brokerId, partitionId, REPLICATION_METRIC_LOG_END_OFFSET); - Result startRet = this.collectReplicaMetricsFromKafkaWithCache(clusterId, topic, brokerId, partitionId, REPLICATION_METRIC_LOG_START_OFFSET); + Result endRet = this.collectReplicaMetricsFromKafka(clusterId, topic, brokerId, partitionId, REPLICATION_METRIC_LOG_END_OFFSET); + Result startRet = this.collectReplicaMetricsFromKafka(clusterId, topic, brokerId, partitionId, REPLICATION_METRIC_LOG_START_OFFSET); ReplicationMetrics replicationMetrics = new ReplicationMetrics(clusterId, topic, brokerId, partitionId); if(null != endRet && endRet.successful() && null != startRet && startRet.successful()){ diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/version/metrics/ClusterMetricVersionItems.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/version/metrics/ClusterMetricVersionItems.java index 53b98479..00a5e0cd 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/version/metrics/ClusterMetricVersionItems.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/version/metrics/ClusterMetricVersionItems.java @@ -20,22 +20,35 @@ import static com.xiaojukeji.know.streaming.km.core.service.cluster.impl.Cluster @Component public class ClusterMetricVersionItems extends BaseMetricVersionMetric { + /** + * 健康分 + */ public static final String CLUSTER_METRIC_HEALTH_SCORE = "HealthScore"; + public static final String CLUSTER_METRIC_HEALTH_SCORE_TOPICS = "HealthScore_Topics"; + public static final String CLUSTER_METRIC_HEALTH_SCORE_BROKERS = "HealthScore_Brokers"; + public static final String CLUSTER_METRIC_HEALTH_SCORE_GROUPS = "HealthScore_Groups"; + public static final String CLUSTER_METRIC_HEALTH_SCORE_CLUSTER = "HealthScore_Cluster"; + + /** + * 健康巡检 + */ public static final String CLUSTER_METRIC_HEALTH_CHECK_PASSED = "HealthCheckPassed"; public static final String CLUSTER_METRIC_HEALTH_CHECK_TOTAL = "HealthCheckTotal"; - public static final String CLUSTER_METRIC_HEALTH_SCORE_TOPICS = "HealthScore_Topics"; + public static final String CLUSTER_METRIC_HEALTH_CHECK_PASSED_TOPICS = "HealthCheckPassed_Topics"; public static final String CLUSTER_METRIC_HEALTH_CHECK_TOTAL_TOPICS = "HealthCheckTotal_Topics"; - public static final String CLUSTER_METRIC_HEALTH_SCORE_BROKERS = "HealthScore_Brokers"; + public static final String CLUSTER_METRIC_HEALTH_CHECK_PASSED_BROKERS = "HealthCheckPassed_Brokers"; public static final String CLUSTER_METRIC_HEALTH_CHECK_TOTAL_BROKERS = "HealthCheckTotal_Brokers"; - public static final String CLUSTER_METRIC_HEALTH_SCORE_GROUPS = "HealthScore_Groups"; + public static final String CLUSTER_METRIC_HEALTH_CHECK_PASSED_GROUPS = "HealthCheckPassed_Groups"; public static final String CLUSTER_METRIC_HEALTH_CHECK_TOTAL_GROUPS = "HealthCheckTotal_Groups"; - public static final String CLUSTER_METRIC_HEALTH_SCORE_CLUSTER = "HealthScore_Cluster"; + public static final String CLUSTER_METRIC_HEALTH_CHECK_PASSED_CLUSTER = "HealthCheckPassed_Cluster"; public static final String CLUSTER_METRIC_HEALTH_CHECK_TOTAL_CLUSTER = "HealthCheckTotal_Cluster"; + + public static final String CLUSTER_METRIC_TOTAL_REQ_QUEUE_SIZE = "TotalRequestQueueSize"; public static final String CLUSTER_METRIC_TOTAL_RES_QUEUE_SIZE = "TotalResponseQueueSize"; public static final String CLUSTER_METRIC_EVENT_QUEUE_SIZE = "EventQueueSize"; diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/version/metrics/ZookeeperMetricVersionItems.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/version/metrics/ZookeeperMetricVersionItems.java new file mode 100644 index 00000000..9b0d4d2b --- /dev/null +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/version/metrics/ZookeeperMetricVersionItems.java @@ -0,0 +1,141 @@ +package com.xiaojukeji.know.streaming.km.core.service.version.metrics; + +import com.xiaojukeji.know.streaming.km.common.bean.entity.version.VersionMetricControlItem; +import com.xiaojukeji.know.streaming.km.common.constant.Constant; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; + +import static com.xiaojukeji.know.streaming.km.common.bean.entity.version.VersionMetricControlItem.*; +import static com.xiaojukeji.know.streaming.km.common.enums.version.VersionItemTypeEnum.METRIC_ZOOKEEPER; +import static com.xiaojukeji.know.streaming.km.common.jmx.JmxAttribute.*; +import static com.xiaojukeji.know.streaming.km.common.jmx.JmxName.*; +import static com.xiaojukeji.know.streaming.km.core.service.zookeeper.impl.ZookeeperMetricServiceImpl.*; + +@Component +public class ZookeeperMetricVersionItems extends BaseMetricVersionMetric { + + /** + * 性能 + */ + public static final String ZOOKEEPER_METRIC_AVG_REQUEST_LATENCY = "AvgRequestLatency"; + public static final String ZOOKEEPER_METRIC_MIN_REQUEST_LATENCY = "MinRequestLatency"; + public static final String ZOOKEEPER_METRIC_MAX_REQUEST_LATENCY = "MaxRequestLatency"; + public static final String ZOOKEEPER_METRIC_OUTSTANDING_REQUESTS = "OutstandingRequests"; + public static final String ZOOKEEPER_METRIC_NODE_COUNT = "NodeCount"; + public static final String ZOOKEEPER_METRIC_WATCH_COUNT = "WatchCount"; + public static final String ZOOKEEPER_METRIC_NUM_ALIVE_CONNECTIONS = "NumAliveConnections"; + public static final String ZOOKEEPER_METRIC_PACKETS_RECEIVED = "PacketsReceived"; + public static final String ZOOKEEPER_METRIC_PACKETS_SENT = "PacketsSent"; + public static final String ZOOKEEPER_METRIC_EPHEMERALS_COUNT = "EphemeralsCount"; + public static final String ZOOKEEPER_METRIC_APPROXIMATE_DATA_SIZE = "ApproximateDataSize"; + public static final String ZOOKEEPER_METRIC_OPEN_FILE_DESCRIPTOR_COUNT = "OpenFileDescriptorCount"; + public static final String ZOOKEEPER_METRIC_MAX_FILE_DESCRIPTOR_COUNT = "MaxFileDescriptorCount"; + + public static final String ZOOKEEPER_METRIC_KAFKA_ZK_DISCONNECTS_PER_SEC = "KafkaZKDisconnectsPerSec"; + public static final String ZOOKEEPER_METRIC_KAFKA_ZK_SYNC_CONNECTS_PER_SEC = "KafkaZKSyncConnectsPerSec"; + public static final String ZOOKEEPER_METRIC_KAFKA_ZK_REQUEST_LATENCY_99TH = "KafkaZKRequestLatencyMs_99thPercentile"; + public static final String ZOOKEEPER_METRIC_KAFKA_ZK_REQUEST_LATENCY_MAX = "KafkaZKRequestLatencyMs_Max"; + public static final String ZOOKEEPER_METRIC_KAFKA_ZK_REQUEST_LATENCY_MEAN = "KafkaZKRequestLatencyMs_Mean"; + public static final String ZOOKEEPER_METRIC_KAFKA_ZK_REQUEST_LATENCY_MIN = "KafkaZKRequestLatencyMs_Min"; + + + public static final String ZOOKEEPER_METRIC_COLLECT_COST_TIME = Constant.COLLECT_METRICS_COST_TIME_METRICS_NAME; + + @Override + public int versionItemType() { + return METRIC_ZOOKEEPER.getCode(); + } + + @Override + public List init(){ + List items = new ArrayList<>(); + + // 性能指标 + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_AVG_REQUEST_LATENCY).unit("ms").desc("平均响应延迟").category(CATEGORY_PERFORMANCE) + .extendMethod(ZOOKEEPER_METHOD_GET_METRIC_FROM_SERVER_CMD)); + + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_MIN_REQUEST_LATENCY).unit("ms").desc("最小响应延迟").category(CATEGORY_PERFORMANCE) + .extendMethod(ZOOKEEPER_METHOD_GET_METRIC_FROM_SERVER_CMD)); + + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_MAX_REQUEST_LATENCY).unit("ms").desc("最大响应延迟").category(CATEGORY_PERFORMANCE) + .extendMethod(ZOOKEEPER_METHOD_GET_METRIC_FROM_SERVER_CMD)); + + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_OUTSTANDING_REQUESTS).unit("个").desc("堆积请求数").category(CATEGORY_PERFORMANCE) + .extendMethod(ZOOKEEPER_METHOD_GET_METRIC_FROM_SERVER_CMD)); + + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_NODE_COUNT).unit("个").desc("ZNode数量").category(CATEGORY_PERFORMANCE) + .extendMethod(ZOOKEEPER_METHOD_GET_METRIC_FROM_SERVER_CMD)); + + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_WATCH_COUNT).unit("个").desc("Watch数量").category(CATEGORY_PERFORMANCE) + .extendMethod(ZOOKEEPER_METHOD_GET_METRIC_FROM_MONITOR_CMD)); + + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_NUM_ALIVE_CONNECTIONS).unit("个").desc("客户端连接数量").category(CATEGORY_PERFORMANCE) + .extendMethod(ZOOKEEPER_METHOD_GET_METRIC_FROM_SERVER_CMD)); + + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_PACKETS_RECEIVED).unit("个").desc("接受包的数量").category(CATEGORY_PERFORMANCE) + .extendMethod(ZOOKEEPER_METHOD_GET_METRIC_FROM_SERVER_CMD)); + + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_PACKETS_SENT).unit("个").desc("发送包的数量").category(CATEGORY_PERFORMANCE) + .extendMethod(ZOOKEEPER_METHOD_GET_METRIC_FROM_SERVER_CMD)); + + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_EPHEMERALS_COUNT).unit("个").desc("临时节点数").category(CATEGORY_PERFORMANCE) + .extendMethod(ZOOKEEPER_METHOD_GET_METRIC_FROM_MONITOR_CMD)); + + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_APPROXIMATE_DATA_SIZE).unit("byte").desc("文件大小(近似值)").category(CATEGORY_PERFORMANCE) + .extendMethod(ZOOKEEPER_METHOD_GET_METRIC_FROM_MONITOR_CMD)); + + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_OPEN_FILE_DESCRIPTOR_COUNT).unit("个").desc("已打开的文件描述符数").category(CATEGORY_PERFORMANCE) + .extendMethod(ZOOKEEPER_METHOD_GET_METRIC_FROM_MONITOR_CMD)); + + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_MAX_FILE_DESCRIPTOR_COUNT).unit("个").desc("允许打开的最大文件描述符数").category(CATEGORY_PERFORMANCE) + .extendMethod(ZOOKEEPER_METHOD_GET_METRIC_FROM_MONITOR_CMD)); + + // JMX指标 + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_KAFKA_ZK_REQUEST_LATENCY_99TH).unit("ms").desc("ZK请求99分位延迟").category(CATEGORY_CLIENT) + .extend( buildJMXMethodExtend( ZOOKEEPER_METHOD_GET_METRIC_FROM_KAFKA_BY_JMX ) + .jmxObjectName( JMX_ZK_REQUEST_LATENCY_MS ).jmxAttribute(PERCENTILE_99))); + + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_KAFKA_ZK_REQUEST_LATENCY_MAX).unit("ms").desc("ZK请求最大延迟").category(CATEGORY_CLIENT) + .extend( buildJMXMethodExtend( ZOOKEEPER_METHOD_GET_METRIC_FROM_KAFKA_BY_JMX ) + .jmxObjectName( JMX_ZK_REQUEST_LATENCY_MS ).jmxAttribute(MAX))); + + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_KAFKA_ZK_REQUEST_LATENCY_MIN).unit("ms").desc("ZK请求最小延迟").category(CATEGORY_CLIENT) + .extend( buildJMXMethodExtend( ZOOKEEPER_METHOD_GET_METRIC_FROM_KAFKA_BY_JMX ) + .jmxObjectName( JMX_ZK_REQUEST_LATENCY_MS ).jmxAttribute(MIN))); + + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_KAFKA_ZK_REQUEST_LATENCY_MEAN).unit("ms").desc("ZK请求平均延迟").category(CATEGORY_CLIENT) + .extend( buildJMXMethodExtend( ZOOKEEPER_METHOD_GET_METRIC_FROM_KAFKA_BY_JMX ) + .jmxObjectName( JMX_ZK_REQUEST_LATENCY_MS ).jmxAttribute(MEAN))); + + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_KAFKA_ZK_DISCONNECTS_PER_SEC).unit("个").desc("断开连接数").category(CATEGORY_CLIENT) + .extend( buildJMXMethodExtend( ZOOKEEPER_METHOD_GET_METRIC_FROM_KAFKA_BY_JMX ) + .jmxObjectName( JMX_ZK_DISCONNECTORS_PER_SEC ).jmxAttribute(RATE_MIN_1))); + + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_KAFKA_ZK_SYNC_CONNECTS_PER_SEC).unit("个").desc("同步连接数").category(CATEGORY_CLIENT) + .extend( buildJMXMethodExtend( ZOOKEEPER_METHOD_GET_METRIC_FROM_KAFKA_BY_JMX ) + .jmxObjectName( JMX_ZK_SYNC_CONNECTS_PER_SEC ).jmxAttribute(RATE_MIN_1))); + return items; + } +} + diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/ZnodeService.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/ZnodeService.java new file mode 100644 index 00000000..43e7744d --- /dev/null +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/ZnodeService.java @@ -0,0 +1,13 @@ +package com.xiaojukeji.know.streaming.km.core.service.zookeeper; + +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.Znode; + +import java.util.List; + +public interface ZnodeService { + + Result> listZnodeChildren(Long clusterPhyId, String path, String keyword); + + Result getZnode(Long clusterPhyId, String path); +} diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/ZookeeperMetricService.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/ZookeeperMetricService.java new file mode 100644 index 00000000..2dc48851 --- /dev/null +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/ZookeeperMetricService.java @@ -0,0 +1,21 @@ +package com.xiaojukeji.know.streaming.km.core.service.zookeeper; + +import com.xiaojukeji.know.streaming.km.common.bean.dto.metrices.MetricDTO; +import com.xiaojukeji.know.streaming.km.common.bean.entity.param.metric.ZookeeperMetricParam; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; +import com.xiaojukeji.know.streaming.km.common.bean.entity.metrics.ZookeeperMetrics; +import com.xiaojukeji.know.streaming.km.common.bean.vo.metrics.line.MetricLineVO; + +import java.util.List; + +public interface ZookeeperMetricService { + /** + * ZK指标获取 + * @param param 参数,因为ZK 四字命令在使用时,是短连接,所以参数内容会复杂一些,后续可以考虑优化为长连接 + * @return + */ + Result collectMetricsFromZookeeper(ZookeeperMetricParam param); + Result batchCollectMetricsFromZookeeper(Long clusterPhyId, List metricNameList); + + Result> listMetricsFromES(Long clusterPhyId, MetricDTO dto); +} diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/ZookeeperService.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/ZookeeperService.java new file mode 100644 index 00000000..8d3a78b1 --- /dev/null +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/ZookeeperService.java @@ -0,0 +1,30 @@ +package com.xiaojukeji.know.streaming.km.core.service.zookeeper; + +import com.xiaojukeji.know.streaming.km.common.bean.entity.config.ZKConfig; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.ZookeeperInfo; + +import java.util.List; + +public interface ZookeeperService { + /** + * 从ZK集群中获取ZK信息 + */ + Result> listFromZookeeper(Long clusterPhyId, String zookeeperAddress, ZKConfig zkConfig); + + void batchReplaceDataInDB(Long clusterPhyId, List infoList); + + List listFromDBByCluster(Long clusterPhyId); + + /** + * 所有服务挂掉 + * @return + */ + boolean allServerDown(Long clusterPhyId); + + /** + * 存在服务挂掉 + * @return + */ + boolean existServerDown(Long clusterPhyId); +} diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/impl/ZnodeServiceImpl.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/impl/ZnodeServiceImpl.java new file mode 100644 index 00000000..9b9a70ef --- /dev/null +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/impl/ZnodeServiceImpl.java @@ -0,0 +1,81 @@ +package com.xiaojukeji.know.streaming.km.core.service.zookeeper.impl; + +import com.didiglobal.logi.log.ILog; +import com.didiglobal.logi.log.LogFactory; +import com.xiaojukeji.know.streaming.km.common.bean.entity.cluster.ClusterPhy; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.ResultStatus; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.Znode; +import com.xiaojukeji.know.streaming.km.common.constant.MsgConstant; +import com.xiaojukeji.know.streaming.km.common.converter.ZnodeConverter; +import com.xiaojukeji.know.streaming.km.common.exception.NotExistException; +import com.xiaojukeji.know.streaming.km.common.utils.Tuple; +import com.xiaojukeji.know.streaming.km.core.service.cluster.ClusterPhyService; +import com.xiaojukeji.know.streaming.km.core.service.zookeeper.ZnodeService; +import com.xiaojukeji.know.streaming.km.persistence.kafka.zookeeper.service.KafkaZKDAO; +import org.apache.zookeeper.data.Stat; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import java.util.List; +import java.util.stream.Collectors; + + +@Service +public class ZnodeServiceImpl implements ZnodeService { + private static final ILog LOGGER = LogFactory.getLog(ZnodeServiceImpl.class); + + @Autowired + private KafkaZKDAO kafkaZKDAO; + + @Autowired + private ClusterPhyService clusterPhyService; + + + + @Override + public Result> listZnodeChildren(Long clusterPhyId, String path, String keyword) { + ClusterPhy clusterPhy = clusterPhyService.getClusterByCluster(clusterPhyId); + if (clusterPhy == null) { + return Result.buildFromRSAndMsg(ResultStatus.NOT_EXIST, MsgConstant.getClusterPhyNotExist(clusterPhyId)); + } + + List children; + try { + children = kafkaZKDAO.getChildren(clusterPhyId, path, false); + } catch (NotExistException e) { + LOGGER.error("class=ZnodeServiceImpl||method=listZnodeChildren||clusterPhyId={}||errMsg={}", clusterPhyId, "create ZK client create failed"); + return Result.buildFromRSAndMsg(ResultStatus.NOT_EXIST, "ZK客户端创建失败"); + } catch (Exception e) { + LOGGER.error("class=ZnodeServiceImpl||method=listZnodeChildren||clusterPhyId={}||errMsg={}", clusterPhyId, "ZK operate failed"); + return Result.buildFromRSAndMsg(ResultStatus.ZK_OPERATE_FAILED, "ZK操作失败"); + } + + //关键字搜索 + if (keyword != null) { + children = children.stream().filter(elem -> elem.contains(keyword)).collect(Collectors.toList()); + } + return Result.buildSuc(children); + } + + @Override + public Result getZnode(Long clusterPhyId, String path) { + ClusterPhy clusterPhy = clusterPhyService.getClusterByCluster(clusterPhyId); + if (clusterPhy == null) { + return Result.buildFromRSAndMsg(ResultStatus.NOT_EXIST, MsgConstant.getClusterPhyNotExist(clusterPhyId)); + } + + //获取zookeeper上的原始数据 + Tuple dataAndStat; + try { + dataAndStat = kafkaZKDAO.getDataAndStat(clusterPhyId, path); + } catch (NotExistException e) { + LOGGER.error("class=ZnodeServiceImpl||method=getZnode||clusterPhyId={}||errMsg={}", clusterPhyId, "create ZK client create failed"); + return Result.buildFromRSAndMsg(ResultStatus.NOT_EXIST, "ZK客户端创建失败"); + } catch (Exception e) { + LOGGER.error("class=ZnodeServiceImpl||method=getZnode||clusterPhyId={}||errMsg={}", clusterPhyId, "ZK operate failed"); + return Result.buildFromRSAndMsg(ResultStatus.ZK_OPERATE_FAILED, "ZK操作失败"); + } + + return Result.buildSuc(ZnodeConverter.convert2Znode(dataAndStat, path)); + } +} diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/impl/ZookeeperMetricServiceImpl.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/impl/ZookeeperMetricServiceImpl.java new file mode 100644 index 00000000..212513aa --- /dev/null +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/impl/ZookeeperMetricServiceImpl.java @@ -0,0 +1,305 @@ +package com.xiaojukeji.know.streaming.km.core.service.zookeeper.impl; + +import com.didiglobal.logi.log.ILog; +import com.didiglobal.logi.log.LogFactory; +import com.xiaojukeji.know.streaming.km.common.bean.dto.metrices.MetricDTO; +import com.xiaojukeji.know.streaming.km.common.bean.entity.cluster.ClusterPhy; +import com.xiaojukeji.know.streaming.km.common.bean.entity.config.ZKConfig; +import com.xiaojukeji.know.streaming.km.common.bean.entity.param.VersionItemParam; +import com.xiaojukeji.know.streaming.km.common.bean.entity.param.metric.ZookeeperMetricParam; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.ResultStatus; +import com.xiaojukeji.know.streaming.km.common.bean.entity.version.VersionJmxInfo; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.BaseFourLetterWordCmdData; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.ServerCmdData; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.parser.MonitorCmdDataParser; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.parser.ServerCmdDataParser; +import com.xiaojukeji.know.streaming.km.common.bean.vo.metrics.line.MetricLineVO; +import com.xiaojukeji.know.streaming.km.common.bean.vo.metrics.point.MetricPointVO; +import com.xiaojukeji.know.streaming.km.common.constant.Constant; +import com.xiaojukeji.know.streaming.km.common.constant.MsgConstant; +import com.xiaojukeji.know.streaming.km.common.enums.version.VersionItemTypeEnum; +import com.xiaojukeji.know.streaming.km.common.exception.VCHandlerNotExistException; +import com.xiaojukeji.know.streaming.km.common.jmx.JmxConnectorWrap; +import com.xiaojukeji.know.streaming.km.common.utils.*; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.ZookeeperInfo; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.MonitorCmdData; +import com.xiaojukeji.know.streaming.km.common.bean.entity.metrics.ZookeeperMetrics; +import com.xiaojukeji.know.streaming.km.common.bean.po.metrice.ZookeeperMetricPO; +import com.xiaojukeji.know.streaming.km.common.utils.zookeeper.FourLetterWordUtil; +import com.xiaojukeji.know.streaming.km.core.cache.ZookeeperLocalCache; +import com.xiaojukeji.know.streaming.km.core.service.cluster.ClusterPhyService; +import com.xiaojukeji.know.streaming.km.core.service.version.BaseMetricService; +import com.xiaojukeji.know.streaming.km.core.service.zookeeper.ZookeeperMetricService; +import com.xiaojukeji.know.streaming.km.core.service.zookeeper.ZookeeperService; +import com.xiaojukeji.know.streaming.km.persistence.es.dao.ZookeeperMetricESDAO; +import com.xiaojukeji.know.streaming.km.persistence.kafka.KafkaJMXClient; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import javax.management.ObjectName; +import java.util.*; +import java.util.stream.Collectors; + +import static com.xiaojukeji.know.streaming.km.common.bean.entity.result.ResultStatus.*; +import static com.xiaojukeji.know.streaming.km.common.bean.entity.result.ResultStatus.VC_JMX_CONNECT_ERROR; +import static com.xiaojukeji.know.streaming.km.core.service.version.metrics.ZookeeperMetricVersionItems.*; + + +@Service +public class ZookeeperMetricServiceImpl extends BaseMetricService implements ZookeeperMetricService { + private static final ILog LOGGER = LogFactory.getLog(ZookeeperMetricServiceImpl.class); + + public static final String ZOOKEEPER_METHOD_DO_NOTHING = "doNothing"; + public static final String ZOOKEEPER_METHOD_GET_METRIC_FROM_MONITOR_CMD = "getMetricFromMonitorCmd"; + public static final String ZOOKEEPER_METHOD_GET_METRIC_FROM_SERVER_CMD = "getMetricFromServerCmd"; + public static final String ZOOKEEPER_METHOD_GET_METRIC_FROM_KAFKA_BY_JMX = "getMetricFromKafkaByJMX"; + public static final String ZOOKEEPER_METHOD_GET_METRIC_FROM_HEALTH_SERVICE = "getMetricFromHealthService"; + + @Autowired + private ClusterPhyService clusterPhyService; + + @Autowired + private ZookeeperService zookeeperService; + + @Autowired + private ZookeeperMetricESDAO zookeeperMetricESDAO; + + @Autowired + private KafkaJMXClient kafkaJMXClient; + + @Override + protected VersionItemTypeEnum getVersionItemType() { + return VersionItemTypeEnum.METRIC_ZOOKEEPER; + } + + @Override + protected List listMetricPOFields(){ + return BeanUtil.listBeanFields(ZookeeperMetricPO.class); + } + + @Override + protected void initRegisterVCHandler(){ + registerVCHandler( ZOOKEEPER_METHOD_DO_NOTHING, this::doNothing); + registerVCHandler( ZOOKEEPER_METHOD_GET_METRIC_FROM_MONITOR_CMD, this::getMetricFromMonitorCmd); + registerVCHandler( ZOOKEEPER_METHOD_GET_METRIC_FROM_SERVER_CMD, this::getMetricFromServerCmd); + registerVCHandler( ZOOKEEPER_METHOD_GET_METRIC_FROM_KAFKA_BY_JMX, this::getMetricFromKafkaByJMX); + } + + @Override + public Result collectMetricsFromZookeeper(ZookeeperMetricParam param) { + try { + return (Result)doVCHandler(param.getClusterPhyId(), param.getMetricName(), param); + } catch (VCHandlerNotExistException e) { + return Result.buildFailure(VC_HANDLE_NOT_EXIST); + } + } + + @Override + public Result batchCollectMetricsFromZookeeper(Long clusterPhyId, List metricNameList) { + ClusterPhy clusterPhy = clusterPhyService.getClusterByCluster(clusterPhyId); + if (null == clusterPhy) { + return Result.buildFromRSAndMsg(ResultStatus.CLUSTER_NOT_EXIST, MsgConstant.getClusterPhyNotExist(clusterPhyId)); + } + + List aliveZKList = zookeeperService.listFromDBByCluster(clusterPhyId).stream() + .filter(elem -> Constant.ALIVE.equals(elem.getStatus())) + .collect(Collectors.toList()); + + if (ValidateUtils.isEmptyList(aliveZKList)) { + // 没有指标可以获取 + return Result.buildSuc(new ZookeeperMetrics(clusterPhyId)); + } + + // 构造参数 + ZookeeperMetricParam param = new ZookeeperMetricParam( + clusterPhyId, + aliveZKList.stream().map(elem -> new Tuple(elem.getHost(), elem.getPort())).collect(Collectors.toList()), + ConvertUtil.str2ObjByJson(clusterPhy.getZkProperties(), ZKConfig.class), + null + ); + + ZookeeperMetrics metrics = new ZookeeperMetrics(clusterPhyId); + for(String metricName : metricNameList) { + try { + if(metrics.getMetrics().containsKey(metricName)) { + continue; + } + param.setMetricName(metricName); + + Result ret = this.collectMetricsFromZookeeper(param); + if(null == ret || ret.failed() || null == ret.getData()){ + continue; + } + + metrics.putMetric(ret.getData().getMetrics()); + } catch (Exception e){ + LOGGER.error( + "class=ZookeeperMetricServiceImpl||method=collectMetricsFromZookeeper||clusterPhyId={}||metricName={}||errMsg=exception!", + clusterPhyId, metricName, e + ); + } + } + + return Result.buildSuc(metrics); + } + + @Override + public Result> listMetricsFromES(Long clusterPhyId, MetricDTO dto) { + Map> pointVOMap = zookeeperMetricESDAO.listMetricsByClusterPhyId( + clusterPhyId, + dto.getMetricsNames(), + dto.getAggType(), + dto.getStartTime(), + dto.getEndTime() + ); + + // 格式转化 + List voList = new ArrayList<>(); + pointVOMap.entrySet().stream().forEach(entry -> + voList.add(new MetricLineVO(String.valueOf(clusterPhyId), entry.getKey(), entry.getValue())) + ); + return Result.buildSuc(voList); + } + + + /**************************************************** private method ****************************************************/ + + private Result getMetricFromServerCmd(VersionItemParam metricParam) { + ZookeeperMetricParam param = (ZookeeperMetricParam)metricParam; + + Result rz = null; + for (Tuple hostPort: param.getZkAddressList()) { + ServerCmdData cmdData = null; + + BaseFourLetterWordCmdData baseCmdData = ZookeeperLocalCache.getData(hostPort.getV1(), hostPort.getV2(), FourLetterWordUtil.ServerCmd); + if (baseCmdData != null) { + cmdData = (ServerCmdData) baseCmdData; + } else if (ZookeeperLocalCache.canUse(hostPort.getV1(), hostPort.getV2(), FourLetterWordUtil.ServerCmd)) { + Result cmdDataResult = FourLetterWordUtil.executeFourLetterCmd( + param.getClusterPhyId(), + hostPort.getV1(), + hostPort.getV2(), + param.getZkConfig() != null ? param.getZkConfig().getOpenSecure(): false, + param.getZkConfig() != null ? param.getZkConfig().getRequestTimeoutUnitMs(): Constant.DEFAULT_REQUEST_TIMEOUT_UNIT_MS, + new ServerCmdDataParser() + ); + + if (cmdDataResult.failed()) { + ZookeeperLocalCache.setFailed(hostPort.getV1(), hostPort.getV2(), FourLetterWordUtil.ServerCmd); + + rz = Result.buildFromIgnoreData(cmdDataResult); + continue; + } + + cmdData = cmdDataResult.getData(); + ZookeeperLocalCache.putData(hostPort.getV1(), hostPort.getV2(), FourLetterWordUtil.ServerCmd, cmdData); + } else { + // baseCmdData为空 且 当前地址不可使用 + continue; + } + + ZookeeperMetrics metrics = new ZookeeperMetrics(param.getClusterPhyId()); + metrics.putMetric(ZOOKEEPER_METRIC_AVG_REQUEST_LATENCY, cmdData.getZkAvgLatency()); + metrics.putMetric(ZOOKEEPER_METRIC_MIN_REQUEST_LATENCY, cmdData.getZkMinLatency().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_MAX_REQUEST_LATENCY, cmdData.getZkMaxLatency().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_OUTSTANDING_REQUESTS, cmdData.getZkOutstandingRequests().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_NODE_COUNT, cmdData.getZkZnodeCount().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_NUM_ALIVE_CONNECTIONS, cmdData.getZkNumAliveConnections().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_PACKETS_RECEIVED, cmdData.getZkPacketsReceived().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_PACKETS_SENT, cmdData.getZkPacketsSent().floatValue()); + + return Result.buildSuc(metrics); + } + + return rz != null? rz: Result.buildSuc(new ZookeeperMetrics(param.getClusterPhyId())); + } + + private Result getMetricFromMonitorCmd(VersionItemParam metricParam) { + ZookeeperMetricParam param = (ZookeeperMetricParam)metricParam; + + Result rz = null; + for (Tuple hostPort: param.getZkAddressList()) { + MonitorCmdData cmdData = null; + + BaseFourLetterWordCmdData baseCmdData = ZookeeperLocalCache.getData(hostPort.getV1(), hostPort.getV2(), FourLetterWordUtil.MonitorCmd); + if (baseCmdData != null) { + cmdData = (MonitorCmdData) baseCmdData; + } else if (ZookeeperLocalCache.canUse(hostPort.getV1(), hostPort.getV2(), FourLetterWordUtil.MonitorCmd)) { + Result cmdDataResult = FourLetterWordUtil.executeFourLetterCmd( + param.getClusterPhyId(), + hostPort.getV1(), + hostPort.getV2(), + param.getZkConfig() != null ? param.getZkConfig().getOpenSecure(): false, + param.getZkConfig() != null ? param.getZkConfig().getRequestTimeoutUnitMs(): Constant.DEFAULT_REQUEST_TIMEOUT_UNIT_MS, + new MonitorCmdDataParser() + ); + + if (cmdDataResult.failed()) { + ZookeeperLocalCache.setFailed(hostPort.getV1(), hostPort.getV2(), FourLetterWordUtil.MonitorCmd); + + rz = Result.buildFromIgnoreData(cmdDataResult); + continue; + } + + cmdData = cmdDataResult.getData(); + ZookeeperLocalCache.putData(hostPort.getV1(), hostPort.getV2(), FourLetterWordUtil.MonitorCmd, cmdData); + } else { + continue; + } + + ZookeeperMetrics metrics = new ZookeeperMetrics(param.getClusterPhyId()); + metrics.putMetric(ZOOKEEPER_METRIC_AVG_REQUEST_LATENCY, cmdData.getZkAvgLatency()); + metrics.putMetric(ZOOKEEPER_METRIC_MIN_REQUEST_LATENCY, cmdData.getZkMinLatency().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_MAX_REQUEST_LATENCY, cmdData.getZkMaxLatency().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_OUTSTANDING_REQUESTS, cmdData.getZkOutstandingRequests().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_NODE_COUNT, cmdData.getZkZnodeCount().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_WATCH_COUNT, cmdData.getZkWatchCount().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_NUM_ALIVE_CONNECTIONS, cmdData.getZkNumAliveConnections().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_PACKETS_RECEIVED, cmdData.getZkPacketsReceived().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_PACKETS_SENT, cmdData.getZkPacketsSent().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_EPHEMERALS_COUNT, cmdData.getZkEphemeralsCount().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_APPROXIMATE_DATA_SIZE, cmdData.getZkApproximateDataSize().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_OPEN_FILE_DESCRIPTOR_COUNT, cmdData.getZkOpenFileDescriptorCount().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_MAX_FILE_DESCRIPTOR_COUNT, cmdData.getZkMaxFileDescriptorCount().floatValue()); + + return Result.buildSuc(metrics); + } + + return rz != null? rz: Result.buildSuc(new ZookeeperMetrics(param.getClusterPhyId())); + } + + private Result doNothing(VersionItemParam metricParam) { + ZookeeperMetricParam param = (ZookeeperMetricParam)metricParam; + return Result.buildSuc(new ZookeeperMetrics(param.getClusterPhyId())); + } + + private Result getMetricFromKafkaByJMX(VersionItemParam metricParam) { + ZookeeperMetricParam param = (ZookeeperMetricParam)metricParam; + + String metricName = param.getMetricName(); + Long clusterPhyId = param.getClusterPhyId(); + Integer kafkaControllerId = param.getKafkaControllerId(); + + //1、获取jmx的属性信息 + VersionJmxInfo jmxInfo = getJMXInfo(clusterPhyId, metricName); + if(null == jmxInfo) { + return Result.buildFailure(VC_ITEM_JMX_NOT_EXIST); + } + + //2、获取jmx连接 + JmxConnectorWrap jmxConnectorWrap = kafkaJMXClient.getClientWithCheck(clusterPhyId, kafkaControllerId); + if (ValidateUtils.isNull(jmxConnectorWrap)) { + return Result.buildFailure(VC_JMX_INIT_ERROR); + } + + try { + //2、获取jmx指标 + String value = jmxConnectorWrap.getAttribute(new ObjectName(jmxInfo.getJmxObjectName()), jmxInfo.getJmxAttribute()).toString(); + + return Result.buildSuc(ZookeeperMetrics.initWithMetric(clusterPhyId, metricName, Float.valueOf(value))); + } catch (Exception e) { + return Result.buildFailure(VC_JMX_CONNECT_ERROR); + } + } +} diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/impl/ZookeeperServiceImpl.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/impl/ZookeeperServiceImpl.java new file mode 100644 index 00000000..84d7eb4c --- /dev/null +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/impl/ZookeeperServiceImpl.java @@ -0,0 +1,170 @@ +package com.xiaojukeji.know.streaming.km.core.service.zookeeper.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.didiglobal.logi.log.ILog; +import com.didiglobal.logi.log.LogFactory; +import com.xiaojukeji.know.streaming.km.common.bean.entity.config.ZKConfig; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.ResultStatus; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.ServerCmdData; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.parser.ServerCmdDataParser; +import com.xiaojukeji.know.streaming.km.common.constant.Constant; +import com.xiaojukeji.know.streaming.km.common.enums.zookeeper.ZKRoleEnum; +import com.xiaojukeji.know.streaming.km.common.utils.ConvertUtil; +import com.xiaojukeji.know.streaming.km.common.utils.Tuple; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.ZookeeperInfo; +import com.xiaojukeji.know.streaming.km.common.bean.po.zookeeper.ZookeeperInfoPO; +import com.xiaojukeji.know.streaming.km.common.utils.ValidateUtils; +import com.xiaojukeji.know.streaming.km.common.utils.zookeeper.FourLetterWordUtil; +import com.xiaojukeji.know.streaming.km.common.utils.zookeeper.ZookeeperUtils; +import com.xiaojukeji.know.streaming.km.core.service.zookeeper.ZookeeperService; +import com.xiaojukeji.know.streaming.km.persistence.mysql.zookeeper.ZookeeperDAO; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Service +public class ZookeeperServiceImpl implements ZookeeperService { + private static final ILog LOGGER = LogFactory.getLog(ZookeeperServiceImpl.class); + + @Autowired + private ZookeeperDAO zookeeperDAO; + + @Override + public Result> listFromZookeeper(Long clusterPhyId, String zookeeperAddress, ZKConfig zkConfig) { + List> addressList = null; + try { + addressList = ZookeeperUtils.connectStringParser(zookeeperAddress); + } catch (Exception e) { + LOGGER.error( + "class=ZookeeperServiceImpl||method=listFromZookeeperCluster||clusterPhyId={}||zookeeperAddress={}||errMsg=exception!", + clusterPhyId, zookeeperAddress, e + ); + + return Result.buildFromRSAndMsg(ResultStatus.PARAM_ILLEGAL, e.getMessage()); + } + + List aliveZKList = new ArrayList<>(); + for (Tuple hostPort: addressList) { + aliveZKList.add(this.getFromZookeeperCluster( + clusterPhyId, + hostPort.getV1(), + hostPort.getV2(), + zkConfig + )); + } + return Result.buildSuc(aliveZKList); + } + + @Override + public void batchReplaceDataInDB(Long clusterPhyId, List infoList) { + // DB 中的信息 + List dbInfoList = this.listRawFromDBByCluster(clusterPhyId); + Map dbMap = new HashMap<>(); + dbInfoList.stream().forEach(elem -> dbMap.put(elem.getHost() + elem.getPort(), elem)); + + // 新获取到的信息 + List newInfoList = ConvertUtil.list2List(infoList, ZookeeperInfoPO.class); + for (ZookeeperInfoPO newInfo: newInfoList) { + try { + ZookeeperInfoPO oldInfo = dbMap.remove(newInfo.getHost() + newInfo.getPort()); + if (oldInfo == null) { + zookeeperDAO.insert(newInfo); + } else if (!Constant.DOWN.equals(newInfo.getStatus())) { + // 存活时,直接使用获取到的数据 + newInfo.setId(oldInfo.getId()); + zookeeperDAO.updateById(newInfo); + } else { + // 如果挂了,则版本和角色信息,使用先前的信息。 + // 挂掉之后,如果角色是leader,则需要调整一下 + newInfo.setId(oldInfo.getId()); + newInfo.setRole(ZKRoleEnum.LEADER.getRole().equals(oldInfo.getRole())? ZKRoleEnum.FOLLOWER.getRole(): oldInfo.getRole()); + newInfo.setVersion(oldInfo.getVersion()); + zookeeperDAO.updateById(newInfo); + } + } catch (Exception e) { + LOGGER.error("class=ZookeeperServiceImpl||method=batchReplaceDataInDB||clusterPhyId={}||newInfo={}||errMsg=exception", clusterPhyId, newInfo, e); + } + } + + // 删除剩余的ZK节点 + dbMap.entrySet().forEach(entry -> { + try { + zookeeperDAO.deleteById(entry.getValue().getId()); + } catch (Exception e) { + LOGGER.error("class=ZookeeperServiceImpl||method=batchReplaceDataInDB||clusterPhyId={}||expiredInfo={}||errMsg=exception", clusterPhyId, entry.getValue(), e); + } + }); + } + + @Override + public List listFromDBByCluster(Long clusterPhyId) { + return ConvertUtil.list2List(this.listRawFromDBByCluster(clusterPhyId), ZookeeperInfo.class); + } + + @Override + public boolean allServerDown(Long clusterPhyId) { + List infoList = this.listFromDBByCluster(clusterPhyId); + if (ValidateUtils.isEmptyList(infoList)) { + return false; + } + + // 所有服务挂掉 + return infoList.stream().filter(elem -> !elem.alive()).count() == infoList.size(); + } + + @Override + public boolean existServerDown(Long clusterPhyId) { + List infoList = this.listFromDBByCluster(clusterPhyId); + if (ValidateUtils.isEmptyList(infoList)) { + // 不存在挂掉的服务 + return false; + } + + // 存在挂掉的服务 + return infoList.stream().filter(elem -> !elem.alive()).count() > 0; + } + + /**************************************************** private method ****************************************************/ + + private List listRawFromDBByCluster(Long clusterPhyId) { + LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); + lambdaQueryWrapper.eq(ZookeeperInfoPO::getClusterPhyId, clusterPhyId); + + return zookeeperDAO.selectList(lambdaQueryWrapper); + } + + private ZookeeperInfo getFromZookeeperCluster(Long clusterPhyId, String host, Integer port, ZKConfig zkConfig) { + ZookeeperInfo zookeeperInfo = new ZookeeperInfo(); + zookeeperInfo.setClusterPhyId(clusterPhyId); + zookeeperInfo.setHost(host); + zookeeperInfo.setPort(port); + zookeeperInfo.setRole(""); + zookeeperInfo.setVersion(""); + zookeeperInfo.setStatus(Constant.DOWN); + + Result serverCmdDataResult = FourLetterWordUtil.executeFourLetterCmd( + clusterPhyId, + host, + port, + zkConfig != null ? zkConfig.getOpenSecure(): false, + zkConfig != null ? zkConfig.getRequestTimeoutUnitMs(): Constant.DEFAULT_REQUEST_TIMEOUT_UNIT_MS, + new ServerCmdDataParser() + ); + if (serverCmdDataResult.hasData()) { + zookeeperInfo.setRole(serverCmdDataResult.getData().getZkServerState()); + zookeeperInfo.setVersion(serverCmdDataResult.getData().getZkVersion()); + zookeeperInfo.setStatus(Constant.ALIVE); + } else if (serverCmdDataResult.getCode().equals(ResultStatus.ZK_FOUR_LETTER_CMD_FORBIDDEN.getCode())) { + zookeeperInfo.setStatus(Constant.ZK_ALIVE_BUT_4_LETTER_FORBIDDEN); + } else { + return zookeeperInfo; + } + + return zookeeperInfo; + } +} diff --git a/km-dist/README.md b/km-dist/README.md index 5c6d192a..f5a71758 100644 --- a/km-dist/README.md +++ b/km-dist/README.md @@ -11,9 +11,6 @@ - logback-spring.xml:日志配置 -- docs:产品相关文档 - - - helm:安装KnowStreaming的Helm相关文件 diff --git a/km-dist/ReleaseKnowStreaming.xml b/km-dist/ReleaseKnowStreaming.xml index 80503225..046a5cfd 100755 --- a/km-dist/ReleaseKnowStreaming.xml +++ b/km-dist/ReleaseKnowStreaming.xml @@ -17,14 +17,6 @@ logback-spring.xml - - ../docs - docs - - * - */* - - ../bin bin diff --git a/km-dist/docker/manager/es_template_create.sh b/km-dist/docker/manager/es_template_create.sh index 615bf54d..b52d4291 100644 --- a/km-dist/docker/manager/es_template_create.sh +++ b/km-dist/docker/manager/es_template_create.sh @@ -443,7 +443,7 @@ curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: appl curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: application/json' http://${SERVER_ES_ADDRESS}/_template/ks_kafka_replication_metric -d '{ "order" : 10, "index_patterns" : [ - "ks_kafka_partition_metric*" + "ks_kafka_replication_metric*" ], "settings" : { "index" : { @@ -504,29 +504,6 @@ curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: appl } }, "aliases" : { } - }[root@10-255-0-23 template]# cat ks_kafka_replication_metric -PUT _template/ks_kafka_replication_metric -{ - "order" : 10, - "index_patterns" : [ - "ks_kafka_replication_metric*" - ], - "settings" : { - "index" : { - "number_of_shards" : "10" - } - }, - "mappings" : { - "properties" : { - "timestamp" : { - "format" : "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis", - "index" : true, - "type" : "date", - "doc_values" : true - } - } - }, - "aliases" : { } }' curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: application/json' http://${SERVER_ES_ADDRESS}/_template/ks_kafka_topic_metric -d '{ @@ -646,6 +623,91 @@ curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: appl "aliases" : { } }' +curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: application/json' http://${SERVER_ES_ADDRESS}/_template/ks_kafka_zookeeper_metric -d '{ + "order" : 10, + "index_patterns" : [ + "ks_kafka_zookeeper_metric*" + ], + "settings" : { + "index" : { + "number_of_shards" : "10" + } + }, + "mappings" : { + "properties" : { + "routingValue" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "clusterPhyId" : { + "type" : "long" + }, + "metrics" : { + "properties" : { + "AvgRequestLatency" : { + "type" : "double" + }, + "MinRequestLatency" : { + "type" : "double" + }, + "MaxRequestLatency" : { + "type" : "double" + }, + "OutstandingRequests" : { + "type" : "double" + }, + "NodeCount" : { + "type" : "double" + }, + "WatchCount" : { + "type" : "double" + }, + "NumAliveConnections" : { + "type" : "double" + }, + "PacketsReceived" : { + "type" : "double" + }, + "PacketsSent" : { + "type" : "double" + }, + "EphemeralsCount" : { + "type" : "double" + }, + "ApproximateDataSize" : { + "type" : "double" + }, + "OpenFileDescriptorCount" : { + "type" : "double" + }, + "MaxFileDescriptorCount" : { + "type" : "double" + } + } + }, + "key" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "timestamp" : { + "format" : "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis", + "type" : "date" + } + } + }, + "aliases" : { } + }' + for i in {0..6}; do logdate=_$(date -d "${i} day ago" +%Y-%m-%d) @@ -654,6 +716,7 @@ do curl -s -o /dev/null -X PUT http://${SERVER_ES_ADDRESS}/ks_kafka_group_metric${logdate} && \ curl -s -o /dev/null -X PUT http://${SERVER_ES_ADDRESS}/ks_kafka_partition_metric${logdate} && \ curl -s -o /dev/null -X PUT http://${SERVER_ES_ADDRESS}/ks_kafka_replication_metric${logdate} && \ + curl -s -o /dev/null -X PUT http://${SERVER_ES_ADDRESS}/ks_kafka_zookeeper_metric${logdate} && \ curl -s -o /dev/null -X PUT http://${SERVER_ES_ADDRESS}/ks_kafka_topic_metric${logdate} || \ exit 2 done diff --git a/km-dist/init/sql/ddl-ks-km.sql b/km-dist/init/sql/ddl-ks-km.sql index d9e4e16c..907ff355 100644 --- a/km-dist/init/sql/ddl-ks-km.sql +++ b/km-dist/init/sql/ddl-ks-km.sql @@ -355,3 +355,37 @@ CREATE TABLE `ks_km_app_node` ( PRIMARY KEY (`id`), KEY `idx_app_host` (`app_name`,`host_name`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='km集群部署的node信息'; + + +DROP TABLE IF EXISTS `ks_km_zookeeper`; +CREATE TABLE `ks_km_zookeeper` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `cluster_phy_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '物理集群ID', + `host` varchar(128) NOT NULL DEFAULT '' COMMENT 'zookeeper主机名', + `port` int(16) NOT NULL DEFAULT '-1' COMMENT 'zookeeper端口', + `role` varchar(16) NOT NULL DEFAULT '-1' COMMENT '角色, leader follower observer', + `version` varchar(128) NOT NULL DEFAULT '' COMMENT 'zookeeper版本', + `status` int(16) NOT NULL DEFAULT '0' COMMENT '状态: 1存活,0未存活,11存活但是4字命令使用不了', + `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uniq_cluster_phy_id_host_port` (`cluster_phy_id`,`host`, `port`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Zookeeper信息表'; + + +DROP TABLE IF EXISTS `ks_km_group`; +CREATE TABLE `ks_km_group` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `cluster_phy_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群id', + `name` varchar(192) COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT 'Group名称', + `member_count` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '成员数', + `topic_members` text CHARACTER SET utf8 COMMENT 'group消费的topic列表', + `partition_assignor` varchar(255) CHARACTER SET utf8 NOT NULL COMMENT '分配策略', + `coordinator_id` int(11) NOT NULL COMMENT 'group协调器brokerId', + `type` int(11) NOT NULL COMMENT 'group类型 0:consumer 1:connector', + `state` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '' COMMENT '状态', + `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uniq_cluster_phy_id_name` (`cluster_phy_id`,`name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Group信息表'; \ No newline at end of file diff --git a/km-dist/init/template/ks_kafka_replication_metric b/km-dist/init/template/ks_kafka_replication_metric index b7beda54..c9c254be 100644 --- a/km-dist/init/template/ks_kafka_replication_metric +++ b/km-dist/init/template/ks_kafka_replication_metric @@ -11,6 +11,49 @@ PUT _template/ks_kafka_replication_metric }, "mappings" : { "properties" : { + "brokerId" : { + "type" : "long" + }, + "partitionId" : { + "type" : "long" + }, + "routingValue" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "clusterPhyId" : { + "type" : "long" + }, + "topic" : { + "type" : "keyword" + }, + "metrics" : { + "properties" : { + "LogStartOffset" : { + "type" : "float" + }, + "Messages" : { + "type" : "float" + }, + "LogEndOffset" : { + "type" : "float" + } + } + }, + "key" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, "timestamp" : { "format" : "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis", "index" : true, @@ -20,4 +63,4 @@ PUT _template/ks_kafka_replication_metric } }, "aliases" : { } - } \ No newline at end of file + } diff --git a/km-dist/init/template/ks_kafka_zookeeper_metric b/km-dist/init/template/ks_kafka_zookeeper_metric new file mode 100644 index 00000000..abb54a61 --- /dev/null +++ b/km-dist/init/template/ks_kafka_zookeeper_metric @@ -0,0 +1,85 @@ +PUT _template/ks_kafka_zookeeper_metric +{ + "order" : 10, + "index_patterns" : [ + "ks_kafka_zookeeper_metric*" + ], + "settings" : { + "index" : { + "number_of_shards" : "10" + } + }, + "mappings" : { + "properties" : { + "routingValue" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "clusterPhyId" : { + "type" : "long" + }, + "metrics" : { + "properties" : { + "AvgRequestLatency" : { + "type" : "double" + }, + "MinRequestLatency" : { + "type" : "double" + }, + "MaxRequestLatency" : { + "type" : "double" + }, + "OutstandingRequests" : { + "type" : "double" + }, + "NodeCount" : { + "type" : "double" + }, + "WatchCount" : { + "type" : "double" + }, + "NumAliveConnections" : { + "type" : "double" + }, + "PacketsReceived" : { + "type" : "double" + }, + "PacketsSent" : { + "type" : "double" + }, + "EphemeralsCount" : { + "type" : "double" + }, + "ApproximateDataSize" : { + "type" : "double" + }, + "OpenFileDescriptorCount" : { + "type" : "double" + }, + "MaxFileDescriptorCount" : { + "type" : "double" + } + } + }, + "key" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "timestamp" : { + "format" : "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis", + "type" : "date" + } + } + }, + "aliases" : { } + } \ No newline at end of file diff --git a/km-dist/init/template/template.sh b/km-dist/init/template/template.sh index e6beba96..86fcfb66 100644 --- a/km-dist/init/template/template.sh +++ b/km-dist/init/template/template.sh @@ -439,7 +439,7 @@ curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: appl curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: application/json' http://${esaddr}:${port}/_template/ks_kafka_replication_metric -d '{ "order" : 10, "index_patterns" : [ - "ks_kafka_partition_metric*" + "ks_kafka_replication_metric*" ], "settings" : { "index" : { @@ -500,30 +500,7 @@ curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: appl } }, "aliases" : { } - }[root@10-255-0-23 template]# cat ks_kafka_replication_metric -PUT _template/ks_kafka_replication_metric -{ - "order" : 10, - "index_patterns" : [ - "ks_kafka_replication_metric*" - ], - "settings" : { - "index" : { - "number_of_shards" : "10" - } - }, - "mappings" : { - "properties" : { - "timestamp" : { - "format" : "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis", - "index" : true, - "type" : "date", - "doc_values" : true - } - } - }, - "aliases" : { } - }' + }' curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: application/json' http://${esaddr}:${port}/_template/ks_kafka_topic_metric -d '{ "order" : 10, @@ -640,7 +617,92 @@ curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: appl } }, "aliases" : { } - }' + }' + +curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: application/json' http://${SERVER_ES_ADDRESS}/_template/ks_kafka_zookeeper_metric -d '{ + "order" : 10, + "index_patterns" : [ + "ks_kafka_zookeeper_metric*" + ], + "settings" : { + "index" : { + "number_of_shards" : "10" + } + }, + "mappings" : { + "properties" : { + "routingValue" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "clusterPhyId" : { + "type" : "long" + }, + "metrics" : { + "properties" : { + "AvgRequestLatency" : { + "type" : "double" + }, + "MinRequestLatency" : { + "type" : "double" + }, + "MaxRequestLatency" : { + "type" : "double" + }, + "OutstandingRequests" : { + "type" : "double" + }, + "NodeCount" : { + "type" : "double" + }, + "WatchCount" : { + "type" : "double" + }, + "NumAliveConnections" : { + "type" : "double" + }, + "PacketsReceived" : { + "type" : "double" + }, + "PacketsSent" : { + "type" : "double" + }, + "EphemeralsCount" : { + "type" : "double" + }, + "ApproximateDataSize" : { + "type" : "double" + }, + "OpenFileDescriptorCount" : { + "type" : "double" + }, + "MaxFileDescriptorCount" : { + "type" : "double" + } + } + }, + "key" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "timestamp" : { + "format" : "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis", + "type" : "date" + } + } + }, + "aliases" : { } + }' for i in {0..6}; do @@ -650,6 +712,7 @@ do curl -s -o /dev/null -X PUT http://${esaddr}:${port}/ks_kafka_group_metric${logdate} && \ curl -s -o /dev/null -X PUT http://${esaddr}:${port}/ks_kafka_partition_metric${logdate} && \ curl -s -o /dev/null -X PUT http://${esaddr}:${port}/ks_kafka_replication_metric${logdate} && \ + curl -s -o /dev/null -X PUT http://${esaddr}:${port}/ks_kafka_zookeeper_metric${logdate} && \ curl -s -o /dev/null -X PUT http://${esaddr}:${port}/ks_kafka_topic_metric${logdate} || \ exit 2 -done \ No newline at end of file +done diff --git a/km-extends/km-account/src/main/java/com/xiaojukeji/know/streaming/km/account/login/ldap/remote/LdapAuthentication.java b/km-extends/km-account/src/main/java/com/xiaojukeji/know/streaming/km/account/login/ldap/remote/LdapAuthentication.java index 82043877..8f907dbe 100644 --- a/km-extends/km-account/src/main/java/com/xiaojukeji/know/streaming/km/account/login/ldap/remote/LdapAuthentication.java +++ b/km-extends/km-account/src/main/java/com/xiaojukeji/know/streaming/km/account/login/ldap/remote/LdapAuthentication.java @@ -5,6 +5,7 @@ import com.didiglobal.logi.security.exception.LogiSecurityException; import com.xiaojukeji.know.streaming.km.account.KmAccountConfig; import com.xiaojukeji.know.streaming.km.account.common.ldap.LdapPrincipal; import com.xiaojukeji.know.streaming.km.account.common.ldap.exception.LdapException; +import com.xiaojukeji.know.streaming.km.common.utils.ValidateUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -12,6 +13,8 @@ import org.springframework.stereotype.Component; import javax.naming.Context; import javax.naming.NamingEnumeration; +import javax.naming.directory.Attribute; +import javax.naming.directory.Attributes; import javax.naming.directory.SearchControls; import javax.naming.directory.SearchResult; import javax.naming.ldap.InitialLdapContext; @@ -71,7 +74,7 @@ public class LdapAuthentication { env.put(Context.SECURITY_PRINCIPAL, kmAccountConfig.getSecurityPrincipal()); env.put(Context.SECURITY_CREDENTIALS, kmAccountConfig.getSecurityCredentials()); try { - return new InitialLdapContext(env, null); + return new InitialLdapContext(env, null); } catch (Exception e) { LOGGER.error("method=getLdapContext||errMsg=exception", e); @@ -101,18 +104,21 @@ public class LdapAuthentication { // maybe more than one element while (en.hasMoreElements()) { - Object obj = en.nextElement(); - if (obj instanceof SearchResult) { - SearchResult si = (SearchResult) obj; - + SearchResult obj = en.nextElement(); + if (!ValidateUtils.isNull(obj)) { // 携带LDAP更多元信息以填充用户元信息 LdapPrincipal ldapPrincipal = new LdapPrincipal(); - ldapPrincipal.setUserDN(si.getName() + "," + kmAccountConfig.getLdapBaseDN()); - ldapPrincipal.setSAMAccountName(this.keyValueSplit(si.getAttributes().get("samaccountname").toString())); - ldapPrincipal.setDepartment(this.keyValueSplit(si.getAttributes().get("department").toString())); - ldapPrincipal.setCompany(this.keyValueSplit(si.getAttributes().get("company").toString())); - ldapPrincipal.setDisplayName(this.keyValueSplit(si.getAttributes().get("displayname").toString())); - ldapPrincipal.setMail(this.keyValueSplit(si.getAttributes().get("mail").toString())); + ldapPrincipal.setUserDN(obj.getName() + "," + kmAccountConfig.getLdapBaseDN()); + + Attributes attributes = obj.getAttributes(); + //校验成功后 在获取值 + if (!ValidateUtils.isNull(attributes)) { + ldapPrincipal.setSAMAccountName(getStringValueFromAttributes(attributes, "samaccountname")); + ldapPrincipal.setDepartment(getStringValueFromAttributes(attributes, "department")); + ldapPrincipal.setCompany(getStringValueFromAttributes(attributes, "company")); + ldapPrincipal.setDisplayName(getStringValueFromAttributes(attributes, "displayname")); + ldapPrincipal.setMail(getStringValueFromAttributes(attributes, "mail")); + } return ldapPrincipal; } } @@ -126,6 +132,29 @@ public class LdapAuthentication { } } + private String getStringValueFromAttributes(Attributes attributes, String attrId) { + //增加 多重校验 + int two = 2; + Attribute attribute = attributes.get(attrId); + if (ValidateUtils.isNull(attribute)) { + return ""; + } + + String str = attribute.toString(); + if (ValidateUtils.isBlank(str)) { + return ""; + } + //分割字符串 + String[] split = str.split(":\\s+"); + if (ValidateUtils.isNotEmpty(split)) { + if (split.length >= two) { + return split[1]; + } + } + + return ""; + } + private void closeLdapContext(LdapContext ctx) { if (ctx == null) { return; @@ -137,8 +166,4 @@ public class LdapAuthentication { LOGGER.error("method=closeLdapContext||errMsg=exception", e); } } - - public String keyValueSplit(String keyValue){ - return keyValue.split(":\\s+")[1]; - } } diff --git a/km-extends/km-monitor/src/main/java/com/xiaojukeji/know/streaming/km/monitor/component/AbstractMonitorSinkService.java b/km-extends/km-monitor/src/main/java/com/xiaojukeji/know/streaming/km/monitor/component/AbstractMonitorSinkService.java index b4fd1986..b2ca9283 100644 --- a/km-extends/km-monitor/src/main/java/com/xiaojukeji/know/streaming/km/monitor/component/AbstractMonitorSinkService.java +++ b/km-extends/km-monitor/src/main/java/com/xiaojukeji/know/streaming/km/monitor/component/AbstractMonitorSinkService.java @@ -37,29 +37,32 @@ public abstract class AbstractMonitorSinkService implements ApplicationListener< @Override public void onApplicationEvent(BaseMetricEvent event) { executor.execute( () -> { - if(event instanceof BrokerMetricEvent){ + if (event instanceof BrokerMetricEvent) { BrokerMetricEvent brokerMetricEvent = (BrokerMetricEvent)event; sinkMetrics(brokerMetric2SinkPoint(brokerMetricEvent.getBrokerMetrics())); - }else if(event instanceof ClusterMetricEvent){ + } else if(event instanceof ClusterMetricEvent) { ClusterMetricEvent clusterMetricEvent = (ClusterMetricEvent)event; sinkMetrics(clusterMetric2SinkPoint(clusterMetricEvent.getClusterMetrics())); - }else if(event instanceof TopicMetricEvent){ + } else if(event instanceof TopicMetricEvent) { TopicMetricEvent topicMetricEvent = (TopicMetricEvent)event; sinkMetrics(topicMetric2SinkPoint(topicMetricEvent.getTopicMetrics())); - }else if(event instanceof PartitionMetricEvent){ + } else if(event instanceof PartitionMetricEvent) { PartitionMetricEvent partitionMetricEvent = (PartitionMetricEvent)event; sinkMetrics(partitionMetric2SinkPoint(partitionMetricEvent.getPartitionMetrics())); - }else if(event instanceof GroupMetricEvent){ + } else if(event instanceof GroupMetricEvent) { GroupMetricEvent groupMetricEvent = (GroupMetricEvent)event; sinkMetrics(groupMetric2SinkPoint(groupMetricEvent.getGroupMetrics())); - }else if(event instanceof ReplicaMetricEvent){ + } else if(event instanceof ReplicaMetricEvent) { ReplicaMetricEvent replicaMetricEvent = (ReplicaMetricEvent)event; sinkMetrics(replicationMetric2SinkPoint(replicaMetricEvent.getReplicationMetrics())); + } else if(event instanceof ZookeeperMetricEvent) { + ZookeeperMetricEvent zookeeperMetricEvent = (ZookeeperMetricEvent)event; + sinkMetrics(zookeeperMetric2SinkPoint(zookeeperMetricEvent.getZookeeperMetrics())); } } ); } @@ -72,6 +75,7 @@ public abstract class AbstractMonitorSinkService implements ApplicationListener< public abstract Boolean sinkMetrics(List pointList); /**************************************************** private method ****************************************************/ + private List brokerMetric2SinkPoint(List brokerMetrics){ List pointList = new ArrayList<>(); @@ -161,8 +165,23 @@ public abstract class AbstractMonitorSinkService implements ApplicationListener< return pointList; } - private List genSinkPoint(String metricPre, Map metrics, - long timeStamp, Map tagsMap){ + private List zookeeperMetric2SinkPoint(List zookeeperMetricsList){ + List pointList = new ArrayList<>(); + + for(ZookeeperMetrics z : zookeeperMetricsList){ + Map tagsMap = new HashMap<>(); + tagsMap.put(CLUSTER_ID.getName(), z.getClusterPhyId()); + + pointList.addAll(genSinkPoint("Zookeeper", z.getMetrics(), z.getTimestamp(), tagsMap)); + } + + return pointList; + } + + private List genSinkPoint(String metricPre, + Map metrics, + long timeStamp, + Map tagsMap) { List pointList = new ArrayList<>(); for(String metricName : metrics.keySet()){ diff --git a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/BaseMetricESDAO.java b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/BaseMetricESDAO.java index a6615fbc..faeb64cb 100644 --- a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/BaseMetricESDAO.java +++ b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/BaseMetricESDAO.java @@ -40,8 +40,7 @@ public class BaseMetricESDAO extends BaseESDAO { /** * 不同维度 kafka 监控数据 */ - private static Map ariusStatsEsDaoMap = Maps - .newConcurrentMap(); + private static Map ariusStatsEsDaoMap = Maps.newConcurrentMap(); /** * 检查 es 索引是否存在,不存在则创建索引 diff --git a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/BrokerMetricESDAO.java b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/BrokerMetricESDAO.java index edc186f4..7ee76a3e 100644 --- a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/BrokerMetricESDAO.java +++ b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/BrokerMetricESDAO.java @@ -92,7 +92,7 @@ public class BrokerMetricESDAO extends BaseMetricESDAO { Table> table = HashBasedTable.create(); //2、查询指标 - for(String metric : metricBrokerIds.keySet()){ + for(String metric : metrics) { table.putAll( this.listBrokerMetricsByBrokerIds( clusterPhyId, @@ -207,11 +207,12 @@ public class BrokerMetricESDAO extends BaseMetricESDAO { } for(String metric : metrics){ - String value = esAggrMap.get(metric).getUnusedMap().get(VALUE).toString(); + Object value = esAggrMap.get(metric).getUnusedMap().get(VALUE); + if(null == value){continue;} MetricPointVO metricPoint = new MetricPointVO(); metricPoint.setAggType(aggType); - metricPoint.setValue(value); + metricPoint.setValue(value.toString()); metricPoint.setName(metric); metricMap.put(metric, metricPoint); @@ -243,12 +244,13 @@ public class BrokerMetricESDAO extends BaseMetricESDAO { try { if (null != esBucket.getUnusedMap().get(KEY)) { Long timestamp = Long.valueOf(esBucket.getUnusedMap().get(KEY).toString()); - String value = esBucket.getAggrMap().get(metric).getUnusedMap().get(VALUE).toString(); + Object value = esBucket.getAggrMap().get(metric).getUnusedMap().get(VALUE); + if(null == value){return;} MetricPointVO metricPoint = new MetricPointVO(); metricPoint.setAggType(aggType); metricPoint.setTimeStamp(timestamp); - metricPoint.setValue(value); + metricPoint.setValue(value.toString()); metricPoint.setName(metric); metricPoints.add(metricPoint); @@ -290,13 +292,14 @@ public class BrokerMetricESDAO extends BaseMetricESDAO { try { if (null != esBucket.getUnusedMap().get(KEY)) { Long brokerId = Long.valueOf(esBucket.getUnusedMap().get(KEY).toString()); - Double value = Double.valueOf(esBucket.getAggrMap().get(HIST).getBucketList().get(0).getAggrMap() - .get(metric).getUnusedMap().get(VALUE).toString()); + Object value = esBucket.getAggrMap().get(HIST).getBucketList().get(0).getAggrMap() + .get(metric).getUnusedMap().get(VALUE); + if(null == value){return;} List> brokerValue = (null == metricBrokerValueMap.get(metric)) ? new ArrayList<>() : metricBrokerValueMap.get(metric); - brokerValue.add(new Tuple<>(brokerId, value)); + brokerValue.add(new Tuple<>(brokerId, Double.valueOf(value.toString()))); metricBrokerValueMap.put(metric, brokerValue); } }catch (Exception e){ diff --git a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/ClusterMetricESDAO.java b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/ClusterMetricESDAO.java index 82a86253..d53f83bf 100644 --- a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/ClusterMetricESDAO.java +++ b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/ClusterMetricESDAO.java @@ -169,11 +169,12 @@ public class ClusterMetricESDAO extends BaseMetricESDAO { } for(String metric : metrics){ - String value = esAggrMap.get(metric).getUnusedMap().get(VALUE).toString(); + Object value = esAggrMap.get(metric).getUnusedMap().get(VALUE); + if(null == value){continue;} MetricPointVO metricPoint = new MetricPointVO(); metricPoint.setAggType(aggType); - metricPoint.setValue(value); + metricPoint.setValue(value.toString()); metricPoint.setName(metric); metricMap.put(metric, metricPoint); @@ -194,12 +195,13 @@ public class ClusterMetricESDAO extends BaseMetricESDAO { try { if (null != esBucket.getUnusedMap().get(KEY)) { Long timestamp = Long.valueOf(esBucket.getUnusedMap().get(KEY).toString()); - String value = esBucket.getAggrMap().get(metric).getUnusedMap().get(VALUE).toString(); + Object value = esBucket.getAggrMap().get(metric).getUnusedMap().get(VALUE); + if(null == value){return;} MetricPointVO metricPoint = new MetricPointVO(); metricPoint.setAggType(aggType); metricPoint.setTimeStamp(timestamp); - metricPoint.setValue(value); + metricPoint.setValue(value.toString()); metricPoint.setName(metric); metricPoints.add(metricPoint); diff --git a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/GroupMetricESDAO.java b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/GroupMetricESDAO.java index cf65e6ef..782adc2f 100644 --- a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/GroupMetricESDAO.java +++ b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/GroupMetricESDAO.java @@ -173,8 +173,9 @@ public class GroupMetricESDAO extends BaseMetricESDAO { } for(String metric : metrics){ - String value = esAggrMap.get(metric).getUnusedMap().get(VALUE).toString(); - groupMetricPO.getMetrics().put(metric, Float.valueOf(value)); + Object value = esAggrMap.get(metric).getUnusedMap().get(VALUE); + if(value == null){continue;} + groupMetricPO.getMetrics().put(metric, Float.parseFloat(value.toString())); } return groupMetricPO; @@ -192,12 +193,13 @@ public class GroupMetricESDAO extends BaseMetricESDAO { try { if (null != esBucket.getUnusedMap().get(KEY)) { Long timestamp = Long.valueOf(esBucket.getUnusedMap().get(KEY).toString()); - String value = esBucket.getAggrMap().get(metric).getUnusedMap().get(VALUE).toString(); + Object value = esBucket.getAggrMap().get(metric).getUnusedMap().get(VALUE); + if(value == null){return;} MetricPointVO metricPoint = new MetricPointVO(); metricPoint.setAggType(aggType); metricPoint.setTimeStamp(timestamp); - metricPoint.setValue(value); + metricPoint.setValue(value.toString()); metricPoint.setName(metric); metricPoints.add(metricPoint); diff --git a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/TopicMetricESDAO.java b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/TopicMetricESDAO.java index e9089c17..e70f2656 100644 --- a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/TopicMetricESDAO.java +++ b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/TopicMetricESDAO.java @@ -337,12 +337,13 @@ public class TopicMetricESDAO extends BaseMetricESDAO { try { if (null != esBucket.getUnusedMap().get(KEY)) { Long timestamp = Long.valueOf(esBucket.getUnusedMap().get(KEY).toString()); - String value = esBucket.getAggrMap().get(metric).getUnusedMap().get(VALUE).toString(); + Object value = esBucket.getAggrMap().get(metric).getUnusedMap().get(VALUE); + if(value == null){return;} MetricPointVO metricPoint = new MetricPointVO(); metricPoint.setAggType(aggType); metricPoint.setTimeStamp(timestamp); - metricPoint.setValue(value); + metricPoint.setValue(value.toString()); metricPoint.setName(metric); metricPoints.add(metricPoint); diff --git a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/ZookeeperMetricESDAO.java b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/ZookeeperMetricESDAO.java new file mode 100644 index 00000000..8b391a3a --- /dev/null +++ b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/ZookeeperMetricESDAO.java @@ -0,0 +1,106 @@ +package com.xiaojukeji.know.streaming.km.persistence.es.dao; + +import com.didiglobal.logi.elasticsearch.client.response.query.query.ESQueryResponse; +import com.didiglobal.logi.elasticsearch.client.response.query.query.aggs.ESAggr; +import com.xiaojukeji.know.streaming.km.common.bean.vo.metrics.point.MetricPointVO; +import com.xiaojukeji.know.streaming.km.common.constant.ESConstant; +import com.xiaojukeji.know.streaming.km.common.utils.MetricsUtils; +import com.xiaojukeji.know.streaming.km.persistence.es.dsls.DslsConstant; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static com.xiaojukeji.know.streaming.km.common.constant.ESConstant.*; +import static com.xiaojukeji.know.streaming.km.common.constant.ESIndexConstant.ZOOKEEPER_INDEX; +import static com.xiaojukeji.know.streaming.km.common.constant.ESIndexConstant.ZOOKEEPER_TEMPLATE; + +@Component +public class ZookeeperMetricESDAO extends BaseMetricESDAO { + + @PostConstruct + public void init() { + super.indexName = ZOOKEEPER_INDEX; + super.indexTemplate = ZOOKEEPER_TEMPLATE; + checkCurrentDayIndexExist(); + BaseMetricESDAO.register(indexName, this); + } + + /** + * 获取指定集群,指定指标,一段时间内的值 + */ + public Map> listMetricsByClusterPhyId(Long clusterPhyId, + List metricNameList, + String aggType, + Long startTime, + Long endTime) { + //1、获取需要查下的索引 + String realIndex = realIndex(startTime, endTime); + + //2、根据查询的时间区间大小来确定指标点的聚合区间大小 + String interval = MetricsUtils.getInterval(endTime - startTime); + + //3、构造agg查询条件 + String aggDsl = buildAggsDSL(metricNameList, aggType); + + //4、构造dsl查询条件,开始查询 + try { + String dsl = dslLoaderUtil.getFormatDslByFileName( + DslsConstant.GET_ZOOKEEPER_AGG_LIST_METRICS, clusterPhyId, startTime, endTime, interval, aggDsl); + + return esOpClient.performRequestWithRouting( + String.valueOf(clusterPhyId), + realIndex, + dsl, + s -> handleListESQueryResponse(s, metricNameList, aggType), + ESConstant.DEFAULT_RETRY_TIME + ); + } catch (Exception e){ + LOGGER.error("class=ZookeeperMetricESDAO||method=listMetricsByClusterPhyId||clusterPhyId={}||errMsg=exception!", + clusterPhyId, e + ); + } + + return new HashMap<>(); + } + + /**************************************************** private method ****************************************************/ + + private Map> handleListESQueryResponse(ESQueryResponse response, List metrics, String aggType){ + Map esAggrMap = checkBucketsAndHitsOfResponseAggs(response); + if(null == esAggrMap) { + return new HashMap<>(); + } + + Map> metricMap = new HashMap<>(); + for(String metric : metrics){ + List metricPoints = new ArrayList<>(); + + esAggrMap.get(HIST).getBucketList().forEach( esBucket -> { + try { + if (null != esBucket.getUnusedMap().get(KEY)) { + Long timestamp = Long.valueOf(esBucket.getUnusedMap().get(KEY).toString()); + String value = esBucket.getAggrMap().get(metric).getUnusedMap().get(VALUE).toString(); + + MetricPointVO metricPoint = new MetricPointVO(); + metricPoint.setAggType(aggType); + metricPoint.setTimeStamp(timestamp); + metricPoint.setValue(value); + metricPoint.setName(metric); + + metricPoints.add(metricPoint); + } + }catch (Exception e){ + LOGGER.error("method=handleESQueryResponse||metric={}||errMsg=exception!", metric, e); + } + } ); + + metricMap.put(metric, optimizeMetricPoints(metricPoints)); + } + + return metricMap; + } +} diff --git a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dsls/DslsConstant.java b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dsls/DslsConstant.java index 3f158f36..f15fe7a8 100644 --- a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dsls/DslsConstant.java +++ b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dsls/DslsConstant.java @@ -80,4 +80,6 @@ public class DslsConstant { public static final String COUNT_GROUP_NOT_METRIC_VALUE = "GroupMetricESDAO/countGroupNotMetricValue"; + /**************************************************** Zookeeper ****************************************************/ + public static final String GET_ZOOKEEPER_AGG_LIST_METRICS = "ZookeeperMetricESDAO/getAggListZookeeperMetrics"; } diff --git a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/jmx/JmxDAO.java b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/jmx/JmxDAO.java index a3747c0a..017bcf04 100644 --- a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/jmx/JmxDAO.java +++ b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/jmx/JmxDAO.java @@ -12,5 +12,7 @@ import javax.management.ObjectName; public interface JmxDAO { Object getJmxValue(String jmxHost, Integer jmxPort, JmxConfig jmxConfig, ObjectName objectName, String attribute); - Object getJmxValue(Long clusterPhyId, Integer brokerId, String jmxHost, Integer jmxPort, JmxConfig jmxConfig, ObjectName objectName, String attribute); + Object getJmxValue(Long clusterPhyId, String jmxHost, Integer jmxPort, JmxConfig jmxConfig, ObjectName objectName, String attribute); + + Long getServerStartTime(Long clusterPhyId, String jmxHost, Integer jmxPort, JmxConfig jmxConfig); } diff --git a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/jmx/impl/JmxDAOImpl.java b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/jmx/impl/JmxDAOImpl.java index ec8349cc..77eb3252 100644 --- a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/jmx/impl/JmxDAOImpl.java +++ b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/jmx/impl/JmxDAOImpl.java @@ -19,24 +19,28 @@ public class JmxDAOImpl implements JmxDAO { @Override public Object getJmxValue(String jmxHost, Integer jmxPort, JmxConfig jmxConfig, ObjectName objectName, String attribute) { - return this.getJmxValue(null, null, jmxHost, jmxPort, jmxConfig, objectName, attribute); + return this.getJmxValue(null, jmxHost, jmxPort, jmxConfig, objectName, attribute); } @Override - public Object getJmxValue(Long clusterPhyId, Integer brokerId, String jmxHost, Integer jmxPort, JmxConfig jmxConfig, ObjectName objectName, String attribute) { + public Object getJmxValue(Long clusterPhyId, String jmxHost, Integer jmxPort, JmxConfig jmxConfig, ObjectName objectName, String attribute) { JmxConnectorWrap jmxConnectorWrap = null; try { - jmxConnectorWrap = new JmxConnectorWrap(clusterPhyId, brokerId, null, jmxHost, jmxPort, jmxConfig); + jmxConnectorWrap = new JmxConnectorWrap(clusterPhyId, null, null, jmxHost, jmxPort, jmxConfig); if (!jmxConnectorWrap.checkJmxConnectionAndInitIfNeed()) { - log.error("method=getJmxValue||clusterPhyId={}||brokerId={}||jmxHost={}||jmxPort={}||jmxConfig={}||errMgs=create jmx client failed", - clusterPhyId, brokerId, jmxHost, jmxPort, jmxConfig); + log.error( + "method=getJmxValue||clusterPhyId={}||jmxHost={}||jmxPort={}||jmxConfig={}||errMgs=create jmx client failed", + clusterPhyId, jmxHost, jmxPort, jmxConfig + ); return null; } return jmxConnectorWrap.getAttribute(objectName, attribute); } catch (Exception e) { - log.error("method=getJmxValue||clusterPhyId={}||brokerId={}||jmxHost={}||jmxPort={}||jmxConfig={}||objectName={}||attribute={}||msg=get attribute failed||errMsg={}", - clusterPhyId, brokerId, jmxHost, jmxPort, jmxConfig, objectName, attribute, e); + log.error( + "method=getJmxValue||clusterPhyId={}||jmxHost={}||jmxPort={}||jmxConfig={}||objectName={}||attribute={}||msg=get attribute failed||errMsg=exception!", + clusterPhyId, jmxHost, jmxPort, jmxConfig, objectName, attribute, e + ); } finally { if (jmxConnectorWrap != null) { jmxConnectorWrap.close(); @@ -45,4 +49,27 @@ public class JmxDAOImpl implements JmxDAO { return null; } + + @Override + public Long getServerStartTime(Long clusterPhyId, String jmxHost, Integer jmxPort, JmxConfig jmxConfig) { + try { + Object object = this.getJmxValue( + clusterPhyId, + jmxHost, + jmxPort, + jmxConfig, + new ObjectName("java.lang:type=Runtime"), + "StartTime" + ); + + return object == null? null: (Long) object; + } catch (Exception e) { + log.error( + "class=JmxDAOImpl||method=getServerStartTime||clusterPhyId={}||jmxHost={}||jmxPort={}||jmxConfig={}||errMsg=exception!", + clusterPhyId, jmxHost, jmxPort, jmxConfig, e + ); + } + + return null; + } } diff --git a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/kafka/KafkaAdminZKClient.java b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/kafka/KafkaAdminZKClient.java index c8849ee7..e6275a60 100644 --- a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/kafka/KafkaAdminZKClient.java +++ b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/kafka/KafkaAdminZKClient.java @@ -133,6 +133,8 @@ public class KafkaAdminZKClient extends AbstractClusterLoadedChangedHandler impl kafkaZkClient = KafkaZkClient.apply( zookeeperAddress, false, +// 添加支持zk的Kerberos认证 +// true, Constant.DEFAULT_SESSION_TIMEOUT_UNIT_MS, Constant.DEFAULT_SESSION_TIMEOUT_UNIT_MS, 5, diff --git a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/mysql/group/GroupDAO.java b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/mysql/group/GroupDAO.java new file mode 100644 index 00000000..eb4465c3 --- /dev/null +++ b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/mysql/group/GroupDAO.java @@ -0,0 +1,9 @@ +package com.xiaojukeji.know.streaming.km.persistence.mysql.group; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.xiaojukeji.know.streaming.km.common.bean.po.group.GroupPO; +import org.springframework.stereotype.Repository; + +@Repository +public interface GroupDAO extends BaseMapper { +} diff --git a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/mysql/health/HealthCheckResultDAO.java b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/mysql/health/HealthCheckResultDAO.java index 225437d7..64830fd1 100644 --- a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/mysql/health/HealthCheckResultDAO.java +++ b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/mysql/health/HealthCheckResultDAO.java @@ -4,7 +4,11 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.xiaojukeji.know.streaming.km.common.bean.po.health.HealthCheckResultPO; import org.springframework.stereotype.Repository; +import java.util.List; + @Repository public interface HealthCheckResultDAO extends BaseMapper { int replace(HealthCheckResultPO healthCheckResultPO); + + int batchReplace(List healthCheckResultPos); } diff --git a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/mysql/zookeeper/ZookeeperDAO.java b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/mysql/zookeeper/ZookeeperDAO.java new file mode 100644 index 00000000..73a177ae --- /dev/null +++ b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/mysql/zookeeper/ZookeeperDAO.java @@ -0,0 +1,9 @@ +package com.xiaojukeji.know.streaming.km.persistence.mysql.zookeeper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.xiaojukeji.know.streaming.km.common.bean.po.zookeeper.ZookeeperInfoPO; +import org.springframework.stereotype.Repository; + +@Repository +public interface ZookeeperDAO extends BaseMapper { +} diff --git a/km-persistence/src/main/resources/dsl/ZookeeperMetricESDAO/getAggListZookeeperMetrics b/km-persistence/src/main/resources/dsl/ZookeeperMetricESDAO/getAggListZookeeperMetrics new file mode 100644 index 00000000..c498368b --- /dev/null +++ b/km-persistence/src/main/resources/dsl/ZookeeperMetricESDAO/getAggListZookeeperMetrics @@ -0,0 +1,37 @@ +{ + "size": 0, + "query": { + "bool": { + "must": [ + { + "term": { + "clusterPhyId": { + "value": %d + } + } + }, + { + "range": { + "timestamp": { + "gte": %d, + "lte": %d + } + } + } + ] + } + }, + "aggs": { + "hist": { + "date_histogram": { + "field": "timestamp", + "fixed_interval": "%s", + "time_zone": "Asia/Shanghai", + "min_doc_count": 0 + }, + "aggs": { + %s + } + } + } +} \ No newline at end of file diff --git a/km-persistence/src/main/resources/mybatis/HealthCheckResultMapper.xml b/km-persistence/src/main/resources/mybatis/HealthCheckResultMapper.xml index bc1bf8ca..076b7522 100644 --- a/km-persistence/src/main/resources/mybatis/HealthCheckResultMapper.xml +++ b/km-persistence/src/main/resources/mybatis/HealthCheckResultMapper.xml @@ -20,4 +20,16 @@ VALUES (#{dimension}, #{configName}, #{clusterPhyId}, #{resName}, #{passed}) + + + insert into ks_km_health_check_result (dimension, config_name, cluster_phy_id, res_name, passed) + values + + (#{item.dimension}, #{item.configName}, #{item.clusterPhyId}, #{item.resName}, #{item.passed}) + + on duplicate key update + dimension = dimension, config_name = config_name, cluster_phy_id = cluster_phy_id, + res_name = res_name, passed = passed + + diff --git a/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/cluster/ClusterGroupsController.java b/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/cluster/ClusterGroupsController.java index 4515d695..b035ea02 100644 --- a/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/cluster/ClusterGroupsController.java +++ b/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/cluster/ClusterGroupsController.java @@ -1,12 +1,15 @@ package com.xiaojukeji.know.streaming.km.rest.api.v3.cluster; import com.xiaojukeji.know.streaming.km.biz.group.GroupManager; +import com.xiaojukeji.know.streaming.km.common.bean.dto.cluster.ClusterGroupSummaryDTO; import com.xiaojukeji.know.streaming.km.common.bean.dto.cluster.ClusterGroupsOverviewDTO; import com.xiaojukeji.know.streaming.km.common.bean.dto.metrices.MetricGroupPartitionDTO; +import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationBaseDTO; import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.field.PaginationFuzzySearchFieldDTO; import com.xiaojukeji.know.streaming.km.common.bean.entity.result.PaginationResult; import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; import com.xiaojukeji.know.streaming.km.common.bean.entity.topic.TopicPartitionKS; +import com.xiaojukeji.know.streaming.km.common.bean.vo.group.GroupOverviewVO; import com.xiaojukeji.know.streaming.km.common.bean.vo.metrics.line.MetricMultiLinesVO; import com.xiaojukeji.know.streaming.km.common.bean.vo.group.GroupTopicOverviewVO; import com.xiaojukeji.know.streaming.km.common.constant.ApiPrefix; @@ -37,7 +40,8 @@ public class ClusterGroupsController { @Autowired private GroupMetricService groupMetricService; - @ApiOperation(value = "集群Groups信息列表") + @Deprecated + @ApiOperation(value = "集群Groups信息列表", notes = "废弃, 下一个版本删除") @PostMapping(value = "clusters/{clusterPhyId}/groups-overview") @ResponseBody public PaginationResult getClusterPhyGroupsOverview(@PathVariable Long clusterPhyId, @@ -53,6 +57,13 @@ public class ClusterGroupsController { ); } + @ApiOperation(value = "集群Groups信息列表") + @GetMapping(value = "clusters/{clusterPhyId}/groups-overview") + @ResponseBody + public PaginationResult getGroupsOverview(@PathVariable Long clusterPhyId, ClusterGroupSummaryDTO dto) { + return groupManager.pagingClusterGroupsOverview(clusterPhyId, dto); + } + @ApiOperation(value = "集群Groups指标信息") @PostMapping(value = "clusters/{clusterPhyId}/group-metrics") @ResponseBody @@ -70,8 +81,17 @@ public class ClusterGroupsController { return groupManager.listClusterPhyGroupPartitions(clusterPhyId, groupName, startTime, endTime); } + @ApiOperation(value = "Group的Topic列表") + @GetMapping(value = "clusters/{clusterPhyId}/groups/{groupName}/topics-overview") + public PaginationResult getGroupTopicsOverview(@PathVariable Long clusterPhyId, + @PathVariable String groupName, + PaginationBaseDTO dto) { + return groupManager.pagingGroupTopicMembers(clusterPhyId, groupName, dto); + } + /**************************************************** private method ****************************************************/ + @Deprecated private Tuple getSearchKeyWords(ClusterGroupsOverviewDTO dto) { if (ValidateUtils.isEmptyList(dto.getFuzzySearchDTOList())) { return new Tuple<>("", ""); diff --git a/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/cluster/ClusterZookeepersController.java b/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/cluster/ClusterZookeepersController.java new file mode 100644 index 00000000..99faa832 --- /dev/null +++ b/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/cluster/ClusterZookeepersController.java @@ -0,0 +1,63 @@ +package com.xiaojukeji.know.streaming.km.rest.api.v3.cluster; + +import com.xiaojukeji.know.streaming.km.biz.cluster.ClusterZookeepersManager; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.PaginationResult; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; +import com.xiaojukeji.know.streaming.km.common.bean.vo.zookeeper.ClusterZookeepersOverviewVO; +import com.xiaojukeji.know.streaming.km.common.constant.ApiPrefix; +import com.xiaojukeji.know.streaming.km.common.constant.Constant; +import com.xiaojukeji.know.streaming.km.common.bean.dto.cluster.ClusterZookeepersOverviewDTO; +import com.xiaojukeji.know.streaming.km.common.bean.vo.zookeeper.ClusterZookeepersStateVO; +import com.xiaojukeji.know.streaming.km.common.bean.vo.zookeeper.ZnodeVO; +import com.xiaojukeji.know.streaming.km.core.service.zookeeper.ZnodeService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + + +/** + * @author zengqiao + * @date 22/09/19 + */ +@Api(tags = Constant.SWAGGER_API_TAG_PREFIX + "集群ZK-相关接口(REST)") +@RestController +@RequestMapping(ApiPrefix.API_V3_PREFIX) +public class ClusterZookeepersController { + @Autowired + private ClusterZookeepersManager clusterZookeepersManager; + + @Autowired + private ZnodeService znodeService; + + @ApiOperation("集群Zookeeper状态信息") + @GetMapping(value = "clusters/{clusterPhyId}/zookeepers-state") + public Result getClusterZookeepersState(@PathVariable Long clusterPhyId) { + return clusterZookeepersManager.getClusterPhyZookeepersState(clusterPhyId); + } + + @ApiOperation("集群Zookeeper信息列表") + @PostMapping(value = "clusters/{clusterPhyId}/zookeepers-overview") + public PaginationResult getClusterZookeepersOverview(@PathVariable Long clusterPhyId, + @RequestBody ClusterZookeepersOverviewDTO dto) { + return clusterZookeepersManager.getClusterPhyZookeepersOverview(clusterPhyId, dto); + } + + @ApiOperation("Zookeeper节点数据") + @GetMapping(value = "clusters/{clusterPhyId}/znode-data") + public Result getClusterZookeeperData(@PathVariable Long clusterPhyId, + @RequestParam String path) { + return clusterZookeepersManager.getZnodeVO(clusterPhyId, path); + } + + @ApiOperation("Zookeeper节点列表") + @GetMapping(value = "clusters/{clusterPhyId}/znode-children") + public Result> getClusterZookeeperChild(@PathVariable Long clusterPhyId, + @RequestParam String path, + @RequestParam(required = false) String keyword) { + return znodeService.listZnodeChildren(clusterPhyId, path, keyword); + } + +} diff --git a/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/group/GroupController.java b/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/group/GroupController.java index 17986b16..55e7e778 100644 --- a/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/group/GroupController.java +++ b/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/group/GroupController.java @@ -55,7 +55,7 @@ public class GroupController { public Result getGroupMetadataCombineExist(@PathVariable Long clusterPhyId, @PathVariable String groupName, @PathVariable String topicName) { - GroupMemberPO po = groupService.getGroupFromDB(clusterPhyId, groupName, topicName); + GroupMemberPO po = groupService.getGroupTopicFromDB(clusterPhyId, groupName, topicName); if (po == null) { return Result.buildSuc(new GroupMetadataCombineExistVO(clusterPhyId, groupName, topicName, false)); } diff --git a/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/replica/ReplicaMetricsController.java b/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/replica/ReplicaMetricsController.java index 13e2c855..7e276aff 100644 --- a/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/replica/ReplicaMetricsController.java +++ b/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/replica/ReplicaMetricsController.java @@ -26,6 +26,7 @@ public class ReplicaMetricsController { @Autowired private ReplicaMetricService replicationMetricService; + @Deprecated @ApiOperation(value = "Replica指标-单个Replica") @PostMapping(value = "clusters/{clusterPhyId}/brokers/{brokerId}/topics/{topicName}/partitions/{partitionId}/metric-points") @ResponseBody @@ -45,7 +46,7 @@ public class ReplicaMetricsController { @PathVariable String topicName, @PathVariable Integer partitionId, @RequestBody List metricsNames) { - Result metricsResult = replicationMetricService.getLatestMetricsFromES(clusterPhyId, brokerId, topicName, partitionId, metricsNames); + Result metricsResult = replicationMetricService.collectReplicaMetricsFromKafka(clusterPhyId, topicName, partitionId, brokerId, metricsNames); if (metricsResult.failed()) { return Result.buildFromIgnoreData(metricsResult); } diff --git a/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/topic/TopicStateController.java b/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/topic/TopicStateController.java index d1e09e66..b0371537 100644 --- a/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/topic/TopicStateController.java +++ b/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/topic/TopicStateController.java @@ -3,7 +3,6 @@ package com.xiaojukeji.know.streaming.km.rest.api.v3.topic; import com.xiaojukeji.know.streaming.km.biz.topic.TopicStateManager; import com.xiaojukeji.know.streaming.km.common.bean.dto.metrices.MetricDTO; import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationBaseDTO; -import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationSortDTO; import com.xiaojukeji.know.streaming.km.common.bean.dto.topic.TopicRecordDTO; import com.xiaojukeji.know.streaming.km.common.bean.entity.metrics.BaseMetrics; import com.xiaojukeji.know.streaming.km.common.bean.entity.result.PaginationResult; @@ -11,6 +10,7 @@ import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; import com.xiaojukeji.know.streaming.km.common.bean.po.KafkaAclPO; import com.xiaojukeji.know.streaming.km.common.bean.vo.acl.AclBindingVO; import com.xiaojukeji.know.streaming.km.common.bean.vo.group.GroupTopicBasicVO; +import com.xiaojukeji.know.streaming.km.common.bean.vo.group.GroupTopicOverviewVO; import com.xiaojukeji.know.streaming.km.common.bean.vo.metrics.point.MetricPointVO; import com.xiaojukeji.know.streaming.km.common.bean.vo.topic.TopicBrokersPartitionsSummaryVO; import com.xiaojukeji.know.streaming.km.common.bean.vo.topic.TopicStateVO; @@ -136,8 +136,17 @@ public class TopicStateController { @ApiOperation(value = "TopicGroups基本信息列表") @GetMapping(value = "clusters/{clusterPhyId}/topics/{topicName}/groups-basic") @ResponseBody - public Result> getTopicGroupsBasic(@PathVariable Long clusterPhyId, - @PathVariable String topicName) { + public Result> getTopicGroupsBasic(@PathVariable Long clusterPhyId, @PathVariable String topicName) { return Result.buildSuc(ConvertUtil.list2List(groupService.listGroupByTopic(clusterPhyId, topicName), GroupTopicBasicVO.class)); } + + @ApiOperation("Topic的Group列表") + @GetMapping(value = "clusters/{clusterPhyId}/topics/{topicName}/groups-overview") + public PaginationResult getTopicGroupsOverview(@PathVariable Long clusterPhyId, + @PathVariable String topicName, + @RequestParam(required = false) String searchGroupName, + PaginationBaseDTO dto) { + return topicStateManager.pagingTopicGroupsOverview(clusterPhyId, topicName, searchGroupName, dto); + } + } diff --git a/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/version/VersionController.java b/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/version/VersionController.java index 52cc4807..f8e00430 100644 --- a/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/version/VersionController.java +++ b/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/version/VersionController.java @@ -15,7 +15,6 @@ import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; -import javax.validation.Valid; import java.util.List; import java.util.Map; import java.util.SortedMap; diff --git a/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/zk/ZookeeperMetricsController.java b/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/zk/ZookeeperMetricsController.java new file mode 100644 index 00000000..bb2ea098 --- /dev/null +++ b/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/zk/ZookeeperMetricsController.java @@ -0,0 +1,52 @@ +package com.xiaojukeji.know.streaming.km.rest.api.v3.zk; + +import com.xiaojukeji.know.streaming.km.common.bean.dto.metrices.MetricDTO; +import com.xiaojukeji.know.streaming.km.common.bean.entity.metrics.BaseMetrics; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; +import com.xiaojukeji.know.streaming.km.common.bean.vo.metrics.line.MetricLineVO; +import com.xiaojukeji.know.streaming.km.common.constant.ApiPrefix; +import com.xiaojukeji.know.streaming.km.common.constant.Constant; +import com.xiaojukeji.know.streaming.km.common.bean.entity.metrics.ZookeeperMetrics; +import com.xiaojukeji.know.streaming.km.core.service.zookeeper.ZookeeperMetricService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + + +/** + * @author zengqiao + * @date 22/09/19 + */ +@Api(tags = Constant.SWAGGER_API_TAG_PREFIX + "ZKMetrics-相关接口(REST)") +@RestController +@RequestMapping(ApiPrefix.API_V3_PREFIX) +public class ZookeeperMetricsController { + private static final Logger LOGGER = LoggerFactory.getLogger(ZookeeperMetricsController.class); + + @Autowired + private ZookeeperMetricService zookeeperMetricService; + + @ApiOperation(value = "ZK-最近指标", notes = "") + @PostMapping(value = "clusters/{clusterPhyId}/zookeeper-latest-metrics") + @ResponseBody + public Result getLatestMetrics(@PathVariable Long clusterPhyId, @RequestBody List metricsNames) { + Result metricsResult = zookeeperMetricService.batchCollectMetricsFromZookeeper(clusterPhyId, metricsNames); + if (metricsResult.failed()) { + return Result.buildFromIgnoreData(metricsResult); + } + + return Result.buildSuc(metricsResult.getData()); + } + + @ApiOperation(value = "ZK-多指标历史信息", notes = "多条指标线") + @PostMapping(value = "clusters/{clusterPhyId}/zookeeper-metrics") + @ResponseBody + public Result> getMetricsLine(@PathVariable Long clusterPhyId, @RequestBody MetricDTO dto) { + return zookeeperMetricService.listMetricsFromES(clusterPhyId, dto); + } +} diff --git a/km-rest/src/main/resources/application.yml b/km-rest/src/main/resources/application.yml index 08cac4af..4a4b7f1c 100644 --- a/km-rest/src/main/resources/application.yml +++ b/km-rest/src/main/resources/application.yml @@ -84,7 +84,8 @@ client-pool: es: client: address: 127.0.0.1:8091,127.0.0.1:8061,127.0.0.1:8061 - client-cnt: 10 + pass: # ES账号密码,如果有账号密码,按照 username:password 的格式填写,没有则不需要填写 + client-cnt: 10 # 创建的ES客户端数 io-thread-cnt: 2 max-retry-cnt: 5 diff --git a/km-rest/src/test/java/com/xiaojukeji/know/streaming/km/persistence/es/ClusterMetricESDAOTest.java b/km-rest/src/test/java/com/xiaojukeji/know/streaming/km/persistence/es/ClusterMetricESDAOTest.java index c69f7129..d0f96bff 100644 --- a/km-rest/src/test/java/com/xiaojukeji/know/streaming/km/persistence/es/ClusterMetricESDAOTest.java +++ b/km-rest/src/test/java/com/xiaojukeji/know/streaming/km/persistence/es/ClusterMetricESDAOTest.java @@ -5,13 +5,13 @@ import com.xiaojukeji.know.streaming.km.common.bean.entity.search.SearchTerm; import com.xiaojukeji.know.streaming.km.common.bean.entity.search.SearchPage; import com.xiaojukeji.know.streaming.km.common.bean.entity.search.SearchRange; import com.xiaojukeji.know.streaming.km.common.bean.entity.search.SearchSort; +import com.xiaojukeji.know.streaming.km.common.bean.po.metrice.ClusterMetricPO; +import com.xiaojukeji.know.streaming.km.common.bean.vo.metrics.point.MetricPointVO; import com.xiaojukeji.know.streaming.km.persistence.es.dao.ClusterMetricESDAO; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; +import java.util.*; public class ClusterMetricESDAOTest extends KnowStreamApplicationTest { @@ -28,6 +28,53 @@ public class ClusterMetricESDAOTest extends KnowStreamApplicationTest { clusterMetricESDAO.listClusterMetricsByClusterIds(metrics, "avg", clusterIds, startTime, endTime); } + /** + * 测试 + * 获取集群 clusterPhyId 中每个 metric 在指定时间[startTime、endTime]区间内聚合计算(avg、max)之后的统计值 + */ + @Test + public void getClusterMetricsPointTest(){ + Long clusterId = 1L; + List metrics = Arrays.asList( + "Connections", "BytesIn_min_15", "PartitionURP", + "HealthScore_Topics", "EventQueueSize", "ActiveControllerCount", + "GroupDeads", "BytesIn_min_5", "HealthCheckTotal_Topics", + "Partitions", "BytesOut", "Groups", + "BytesOut_min_15", "TotalRequestQueueSize", "HealthCheckPassed_Groups", + "TotalProduceRequests", "HealthCheckPassed", "TotalLogSize", + "GroupEmptys", "PartitionNoLeader", "HealthScore_Brokers", + "Messages", "Topics", "PartitionMinISR_E", + "HealthCheckTotal", "Brokers", "Replicas", + "HealthCheckTotal_Groups", "GroupRebalances", "MessageIn", + "HealthScore", "HealthCheckPassed_Topics", "HealthCheckTotal_Brokers", + "PartitionMinISR_S", "BytesIn", "BytesOut_min_5", + "GroupActives", "MessagesIn", "GroupReBalances", + "HealthCheckPassed_Brokers", "HealthScore_Groups", "TotalResponseQueueSize", + "Zookeepers", "LeaderMessages", "HealthScore_Cluster", + "HealthCheckPassed_Cluster", "HealthCheckTotal_Cluster"); + Long endTime = System.currentTimeMillis(); + Long startTime = endTime - 4 * 60 * 60 * 1000; + + Map metricPointVOS = clusterMetricESDAO.getClusterMetricsPoint( + clusterId, metrics, "avg", startTime, endTime); + + assert null != metricPointVOS; + } + + /** + * 测试 + * 获取集群 clusterId 最新的统计指标 + */ + @Test + public void getClusterLatestMetricsTest(){ + Long clusterId = 1L; + List metrics = Collections.emptyList(); + + ClusterMetricPO clusterLatestMetrics = clusterMetricESDAO.getClusterLatestMetrics(clusterId, metrics); + + assert null != clusterLatestMetrics; + } + @Test public void pagingClusterWithLatestMetricsTest(){ List clusterIds = new ArrayList<>(); diff --git a/km-rest/src/test/java/com/xiaojukeji/know/streaming/km/persistence/es/ReplicationMetricESDAOTest.java b/km-rest/src/test/java/com/xiaojukeji/know/streaming/km/persistence/es/ReplicationMetricESDAOTest.java index 6fe0ab4e..98224a3d 100644 --- a/km-rest/src/test/java/com/xiaojukeji/know/streaming/km/persistence/es/ReplicationMetricESDAOTest.java +++ b/km-rest/src/test/java/com/xiaojukeji/know/streaming/km/persistence/es/ReplicationMetricESDAOTest.java @@ -2,11 +2,14 @@ package com.xiaojukeji.know.streaming.km.persistence.es; import com.xiaojukeji.know.streaming.km.KnowStreamApplicationTest; import com.xiaojukeji.know.streaming.km.common.bean.po.metrice.ReplicationMetricPO; +import com.xiaojukeji.know.streaming.km.common.bean.vo.metrics.point.MetricPointVO; import com.xiaojukeji.know.streaming.km.persistence.es.dao.ReplicationMetricESDAO; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import java.util.ArrayList; +import java.util.Collections; +import java.util.Map; public class ReplicationMetricESDAOTest extends KnowStreamApplicationTest { @@ -15,7 +18,7 @@ public class ReplicationMetricESDAOTest extends KnowStreamApplicationTest { @Test public void getReplicationLatestMetricsTest(){ - Long clusterPhyId = 2l; + Long clusterPhyId = 2L; Integer brokerId = 1; String topic = "know-streaming-test-251"; Integer partitionId = 1; @@ -24,4 +27,22 @@ public class ReplicationMetricESDAOTest extends KnowStreamApplicationTest { assert null != replicationMetricPO; } + + /** + * 测试 + * 获取集群 clusterPhyId 中每个 metric 的指定 partitionId 在指定时间[startTime、endTime]区间内聚合计算(avg、max)之后的统计值 + */ + @Test + public void getReplicationMetricsPointTest(){ + Long clusterPhyId = 2L; + Integer brokerId = 1; + String topic = "know-streaming-test-251"; + Integer partitionId = 1; + Long endTime = System.currentTimeMillis(); + Long startTime = endTime - 4 * 60 * 60 * 1000; + Map metricPointVOMap = replicationMetricESDAO.getReplicationMetricsPoint( + clusterPhyId, topic, brokerId, partitionId, Collections.emptyList(), "avg", startTime, endTime); + + assert null != metricPointVOMap; + } } diff --git a/km-rest/src/test/java/com/xiaojukeji/know/streaming/km/persistence/es/TopicMetricESDAOTest.java b/km-rest/src/test/java/com/xiaojukeji/know/streaming/km/persistence/es/TopicMetricESDAOTest.java index e3da2f2c..09db0971 100644 --- a/km-rest/src/test/java/com/xiaojukeji/know/streaming/km/persistence/es/TopicMetricESDAOTest.java +++ b/km-rest/src/test/java/com/xiaojukeji/know/streaming/km/persistence/es/TopicMetricESDAOTest.java @@ -15,7 +15,6 @@ import org.springframework.util.CollectionUtils; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.Map; public class TopicMetricESDAOTest extends KnowStreamApplicationTest { @@ -38,14 +37,20 @@ public class TopicMetricESDAOTest extends KnowStreamApplicationTest { @Test public void getTopicsAggsMetricsValueTest(){ Long clusterId = 2L; - String topic = "know-streaming-test-251"; - String topic1 = "topic_test01"; - List metrics = Arrays.asList("BytesIn", "BytesIn_min_5"); + List topicList = Arrays.asList("know-streaming-test-251", "topic_test01"); + List metrics = Arrays.asList( + "Messages", "BytesIn_min_15", "BytesRejected", + "PartitionURP", "HealthCheckTotal", "ReplicationCount", + "CollectMetricsCostTimeUnitSec", "FailedFetchRequests", "BytesIn_min_5", + "HealthScore", "LogSize", "BytesOut", + "FailedProduceRequests", "BytesOut_min_15", "BytesIn", + "BytesOut_min_5", "MessagesIn", "TotalProduceRequests", + "HealthCheckPassed"); Long endTime = System.currentTimeMillis(); Long startTime = endTime - 4 * 60 * 60 * 1000; Table ret = topicMetricESDAO.getTopicsAggsMetricsValue( - clusterId, Arrays.asList(topic, topic1), metrics, "max", startTime, endTime); + clusterId, topicList, metrics, "max", startTime, endTime); assert null != ret; } @@ -90,7 +95,14 @@ public class TopicMetricESDAOTest extends KnowStreamApplicationTest { String topic = "know-streaming-test-251"; String topic1 = "know-streaming-123"; String topic2 = "1209test"; - List metrics = Arrays.asList("BytesIn", "BytesIn_min_5"); + List metrics = Arrays.asList( + "Messages", "BytesIn_min_15", "BytesRejected", + "PartitionURP", "HealthCheckTotal", "ReplicationCount", + "CollectMetricsCostTimeUnitSec", "FailedFetchRequests", "BytesIn_min_5", + "HealthScore", "LogSize", "BytesOut", + "FailedProduceRequests", "BytesOut_min_15", "BytesIn", + "BytesOut_min_5", "MessagesIn", "TotalProduceRequests", + "HealthCheckPassed"); List topicMetricPO = topicMetricESDAO.listTopicLatestMetric(clusterId, Arrays.asList(topic,topic1,topic2), metrics); @@ -101,7 +113,14 @@ public class TopicMetricESDAOTest extends KnowStreamApplicationTest { @Test public void listBrokerMetricsByTopicsTest(){ Long clusterId = 2L; - List metrics = Arrays.asList("BytesIn", "BytesIn_min_5"); + List metrics = Arrays.asList( + "Messages", "BytesIn_min_15", "BytesRejected", + "PartitionURP", "HealthCheckTotal", "ReplicationCount", + "CollectMetricsCostTimeUnitSec", "FailedFetchRequests", "BytesIn_min_5", + "HealthScore", "LogSize", "BytesOut", + "FailedProduceRequests", "BytesOut_min_15", "BytesIn", + "BytesOut_min_5", "MessagesIn", "TotalProduceRequests", + "HealthCheckPassed"); List topics = Arrays.asList("QAtest_1_13", "__consumer_offsets"); Long endTime = System.currentTimeMillis(); Long startTime = endTime - 4 * 60 * 60 * 1000; diff --git a/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/AbstractHealthCheckTask.java b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/AbstractHealthCheckTask.java new file mode 100644 index 00000000..4d614881 --- /dev/null +++ b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/AbstractHealthCheckTask.java @@ -0,0 +1,113 @@ +package com.xiaojukeji.know.streaming.km.task.health; + +import com.didiglobal.logi.job.common.TaskResult; +import com.didiglobal.logi.log.ILog; +import com.didiglobal.logi.log.LogFactory; +import com.xiaojukeji.know.streaming.km.common.bean.entity.cluster.ClusterPhy; +import com.xiaojukeji.know.streaming.km.common.bean.entity.config.healthcheck.BaseClusterHealthConfig; +import com.xiaojukeji.know.streaming.km.common.bean.entity.health.HealthCheckResult; +import com.xiaojukeji.know.streaming.km.common.bean.entity.param.cluster.ClusterPhyParam; +import com.xiaojukeji.know.streaming.km.common.constant.Constant; +import com.xiaojukeji.know.streaming.km.common.enums.health.HealthCheckDimensionEnum; +import com.xiaojukeji.know.streaming.km.common.utils.ValidateUtils; +import com.xiaojukeji.know.streaming.km.core.service.health.checker.AbstractHealthCheckService; +import com.xiaojukeji.know.streaming.km.core.service.health.checkresult.HealthCheckResultService; +import com.xiaojukeji.know.streaming.km.task.metrics.AbstractAsyncMetricsDispatchTask; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Map; + +public abstract class AbstractHealthCheckTask extends AbstractAsyncMetricsDispatchTask { + private static final ILog log = LogFactory.getLog(AbstractHealthCheckTask.class); + + @Autowired + private HealthCheckResultService healthCheckResultService; + + public abstract AbstractHealthCheckService getCheckService(); + + @Override + public TaskResult processClusterTask(ClusterPhy clusterPhy, long triggerTimeUnitMs) { + return this.calAndUpdateHealthCheckResult(clusterPhy, triggerTimeUnitMs); + } + + private TaskResult calAndUpdateHealthCheckResult(ClusterPhy clusterPhy, long triggerTimeUnitMs) { + // 获取配置,<配置名,配置信息> + Map healthConfigMap = healthCheckResultService.getClusterHealthConfig(clusterPhy.getId()); + + // 检查结果 + List resultList = new ArrayList<>(); + + // 遍历Check-Service + List paramList = this.getCheckService().getResList(clusterPhy.getId()); + if (ValidateUtils.isEmptyList(paramList)) { + // 当前无该维度的资源,则直接设置为 + resultList.addAll(this.getNoResResult(clusterPhy.getId(), this.getCheckService(), healthConfigMap)); + } + + // 遍历资源 + for (ClusterPhyParam clusterPhyParam: paramList) { + resultList.addAll(this.checkAndGetResult(clusterPhyParam, healthConfigMap)); + } + + try { + healthCheckResultService.batchReplace(clusterPhy.getId(), resultList); + } catch (Exception e) { + log.error("class=AbstractHealthCheckTask||method=processSubTask||clusterPhyId={}||errMsg=exception!", clusterPhy.getId(), e); + } + + // 删除10分钟之前的检查结果 + try { + healthCheckResultService.deleteByUpdateTimeBeforeInDB(clusterPhy.getId(), new Date(triggerTimeUnitMs - 10 * 60 * 1000)); + } catch (Exception e) { + log.error("class=AbstractHealthCheckTask||method=processSubTask||clusterPhyId={}||errMsg=exception!", clusterPhy.getId(), e); + } + + return TaskResult.SUCCESS; + } + + private List getNoResResult(Long clusterPhyId, AbstractHealthCheckService healthCheckService, Map healthConfigMap) { + List resultList = new ArrayList<>(); + + // 进行检查 + for (BaseClusterHealthConfig clusterHealthConfig: healthConfigMap.values()) { + HealthCheckDimensionEnum dimensionEnum = healthCheckService.getHealthCheckDimensionEnum(); + if (!clusterHealthConfig.getCheckNameEnum().getDimensionEnum().equals(dimensionEnum)) { + // 类型不匹配 + continue; + } + + // 记录 + HealthCheckResult checkResult = new HealthCheckResult( + dimensionEnum.getDimension(), + clusterHealthConfig.getCheckNameEnum().getConfigName(), + clusterPhyId, + "-1" + ); + checkResult.setPassed(Constant.YES); + resultList.add(checkResult); + } + + return resultList; + } + + private List checkAndGetResult(ClusterPhyParam clusterPhyParam, + Map healthConfigMap) { + List resultList = new ArrayList<>(); + + // 进行检查 + for (BaseClusterHealthConfig clusterHealthConfig: healthConfigMap.values()) { + HealthCheckResult healthCheckResult = this.getCheckService().checkAndGetResult(clusterPhyParam, clusterHealthConfig); + if (healthCheckResult == null) { + continue; + } + + // 记录 + resultList.add(healthCheckResult); + } + + return resultList; + } +} diff --git a/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/BrokerHealthCheckTask.java b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/BrokerHealthCheckTask.java index 7b611823..ef02be8e 100644 --- a/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/BrokerHealthCheckTask.java +++ b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/BrokerHealthCheckTask.java @@ -1,30 +1,13 @@ package com.xiaojukeji.know.streaming.km.task.health; import com.didiglobal.logi.job.annotation.Task; -import com.didiglobal.logi.job.common.TaskResult; import com.didiglobal.logi.job.core.consensual.ConsensualEnum; -import com.didiglobal.logi.log.ILog; -import com.didiglobal.logi.log.LogFactory; -import com.xiaojukeji.know.streaming.km.common.bean.entity.cluster.ClusterPhy; -import com.xiaojukeji.know.streaming.km.common.bean.entity.config.healthcheck.BaseClusterHealthConfig; -import com.xiaojukeji.know.streaming.km.common.bean.entity.health.HealthCheckResult; -import com.xiaojukeji.know.streaming.km.common.bean.entity.param.cluster.ClusterPhyParam; -import com.xiaojukeji.know.streaming.km.common.constant.Constant; -import com.xiaojukeji.know.streaming.km.common.enums.health.HealthCheckDimensionEnum; -import com.xiaojukeji.know.streaming.km.common.utils.ValidateUtils; import com.xiaojukeji.know.streaming.km.core.service.health.checker.AbstractHealthCheckService; import com.xiaojukeji.know.streaming.km.core.service.health.checker.broker.HealthCheckBrokerService; -import com.xiaojukeji.know.streaming.km.core.service.health.checkresult.HealthCheckResultService; -import com.xiaojukeji.know.streaming.km.task.metrics.AbstractAsyncMetricsDispatchTask; import lombok.AllArgsConstructor; import lombok.NoArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.Map; - @NoArgsConstructor @AllArgsConstructor @Task(name = "BrokerHealthCheckTask", @@ -33,98 +16,12 @@ import java.util.Map; autoRegister = true, consensual = ConsensualEnum.BROADCAST, timeout = 2 * 60) -public class BrokerHealthCheckTask extends AbstractAsyncMetricsDispatchTask { - private static final ILog log = LogFactory.getLog(BrokerHealthCheckTask.class); - - @Autowired - private HealthCheckResultService healthCheckResultService; - +public class BrokerHealthCheckTask extends AbstractHealthCheckTask { @Autowired private HealthCheckBrokerService healthCheckBrokerService; @Override - public TaskResult processClusterTask(ClusterPhy clusterPhy, long triggerTimeUnitMs) { - return this.calAndUpdateHealthCheckResult(clusterPhy, triggerTimeUnitMs); - } - - private TaskResult calAndUpdateHealthCheckResult(ClusterPhy clusterPhy, long triggerTimeUnitMs) { - // 获取配置,<配置名,配置信息> - Map healthConfigMap = healthCheckResultService.getClusterHealthConfig(clusterPhy.getId()); - - // 检查结果 - List resultList = new ArrayList<>(); - - // 遍历Check-Service - List paramList = healthCheckBrokerService.getResList(clusterPhy.getId()); - if (ValidateUtils.isEmptyList(paramList)) { - // 当前无该维度的资源,则直接设置为 - resultList.addAll(this.getNoResResult(clusterPhy.getId(), healthCheckBrokerService, healthConfigMap)); - } - - // 遍历资源 - for (ClusterPhyParam clusterPhyParam: paramList) { - resultList.addAll(this.checkAndGetResult(healthCheckBrokerService, clusterPhyParam, healthConfigMap)); - } - - for (HealthCheckResult checkResult: resultList) { - try { - healthCheckResultService.replace(checkResult); - } catch (Exception e) { - log.error("class=BrokerHealthCheckTask||method=processSubTask||clusterPhyId={}||checkResult={}||errMsg=exception!", clusterPhy.getId(), checkResult, e); - } - } - - // 删除10分钟之前的检查结果 - try { - healthCheckResultService.deleteByUpdateTimeBeforeInDB(clusterPhy.getId(), new Date(triggerTimeUnitMs - 10 * 60 * 1000)); - } catch (Exception e) { - log.error("class=BrokerHealthCheckTask||method=processSubTask||clusterPhyId={}||errMsg=exception!", clusterPhy.getId(), e); - } - - return TaskResult.SUCCESS; - } - - private List getNoResResult(Long clusterPhyId, AbstractHealthCheckService healthCheckService, Map healthConfigMap) { - List resultList = new ArrayList<>(); - - // 进行检查 - for (BaseClusterHealthConfig clusterHealthConfig: healthConfigMap.values()) { - HealthCheckDimensionEnum dimensionEnum = healthCheckService.getHealthCheckDimensionEnum(); - if (!clusterHealthConfig.getCheckNameEnum().getDimensionEnum().equals(dimensionEnum)) { - // 类型不匹配 - continue; - } - - // 记录 - HealthCheckResult checkResult = new HealthCheckResult( - dimensionEnum.getDimension(), - clusterHealthConfig.getCheckNameEnum().getConfigName(), - clusterPhyId, - "-1" - ); - checkResult.setPassed(Constant.YES); - resultList.add(checkResult); - } - - return resultList; - } - - private List checkAndGetResult(AbstractHealthCheckService healthCheckService, - ClusterPhyParam clusterPhyParam, - Map healthConfigMap) { - List resultList = new ArrayList<>(); - - // 进行检查 - for (BaseClusterHealthConfig clusterHealthConfig: healthConfigMap.values()) { - HealthCheckResult healthCheckResult = healthCheckService.checkAndGetResult(clusterPhyParam, clusterHealthConfig); - if (healthCheckResult == null) { - continue; - } - - // 记录 - resultList.add(healthCheckResult); - } - - return resultList; + public AbstractHealthCheckService getCheckService() { + return healthCheckBrokerService; } } diff --git a/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/ClusterHealthCheckTask.java b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/ClusterHealthCheckTask.java index cb7f78b2..43c16cb8 100644 --- a/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/ClusterHealthCheckTask.java +++ b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/ClusterHealthCheckTask.java @@ -1,30 +1,13 @@ package com.xiaojukeji.know.streaming.km.task.health; import com.didiglobal.logi.job.annotation.Task; -import com.didiglobal.logi.job.common.TaskResult; import com.didiglobal.logi.job.core.consensual.ConsensualEnum; -import com.didiglobal.logi.log.ILog; -import com.didiglobal.logi.log.LogFactory; -import com.xiaojukeji.know.streaming.km.common.bean.entity.cluster.ClusterPhy; -import com.xiaojukeji.know.streaming.km.common.bean.entity.config.healthcheck.BaseClusterHealthConfig; -import com.xiaojukeji.know.streaming.km.common.bean.entity.health.HealthCheckResult; -import com.xiaojukeji.know.streaming.km.common.bean.entity.param.cluster.ClusterPhyParam; -import com.xiaojukeji.know.streaming.km.common.constant.Constant; -import com.xiaojukeji.know.streaming.km.common.enums.health.HealthCheckDimensionEnum; -import com.xiaojukeji.know.streaming.km.common.utils.ValidateUtils; import com.xiaojukeji.know.streaming.km.core.service.health.checker.AbstractHealthCheckService; import com.xiaojukeji.know.streaming.km.core.service.health.checker.cluster.HealthCheckClusterService; -import com.xiaojukeji.know.streaming.km.core.service.health.checkresult.HealthCheckResultService; -import com.xiaojukeji.know.streaming.km.task.metrics.AbstractAsyncMetricsDispatchTask; import lombok.AllArgsConstructor; import lombok.NoArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.Map; - @NoArgsConstructor @AllArgsConstructor @Task(name = "ClusterHealthCheckTask", @@ -33,98 +16,12 @@ import java.util.Map; autoRegister = true, consensual = ConsensualEnum.BROADCAST, timeout = 2 * 60) -public class ClusterHealthCheckTask extends AbstractAsyncMetricsDispatchTask { - private static final ILog log = LogFactory.getLog(ClusterHealthCheckTask.class); - - @Autowired - private HealthCheckResultService healthCheckResultService; - +public class ClusterHealthCheckTask extends AbstractHealthCheckTask { @Autowired private HealthCheckClusterService healthCheckClusterService; @Override - public TaskResult processClusterTask(ClusterPhy clusterPhy, long triggerTimeUnitMs) { - return this.calAndUpdateHealthCheckResult(clusterPhy, triggerTimeUnitMs); - } - - private TaskResult calAndUpdateHealthCheckResult(ClusterPhy clusterPhy, long triggerTimeUnitMs) { - // 获取配置,<配置名,配置信息> - Map healthConfigMap = healthCheckResultService.getClusterHealthConfig(clusterPhy.getId()); - - // 检查结果 - List resultList = new ArrayList<>(); - - // 遍历Check-Service - List paramList = healthCheckClusterService.getResList(clusterPhy.getId()); - if (ValidateUtils.isEmptyList(paramList)) { - // 当前无该维度的资源,则直接设置为 - resultList.addAll(this.getNoResResult(clusterPhy.getId(), healthCheckClusterService, healthConfigMap)); - } - - // 遍历资源 - for (ClusterPhyParam clusterPhyParam: paramList) { - resultList.addAll(this.checkAndGetResult(healthCheckClusterService, clusterPhyParam, healthConfigMap)); - } - - for (HealthCheckResult checkResult: resultList) { - try { - healthCheckResultService.replace(checkResult); - } catch (Exception e) { - log.error("class=ClusterHealthCheckTask||method=processSubTask||clusterPhyId={}||checkResult={}||errMsg=exception!", clusterPhy.getId(), checkResult, e); - } - } - - // 删除10分钟之前的检查结果 - try { - healthCheckResultService.deleteByUpdateTimeBeforeInDB(clusterPhy.getId(), new Date(triggerTimeUnitMs - 10 * 60 * 1000)); - } catch (Exception e) { - log.error("class=ClusterHealthCheckTask||method=processSubTask||clusterPhyId={}||errMsg=exception!", clusterPhy.getId(), e); - } - - return TaskResult.SUCCESS; - } - - private List getNoResResult(Long clusterPhyId, AbstractHealthCheckService healthCheckService, Map healthConfigMap) { - List resultList = new ArrayList<>(); - - // 进行检查 - for (BaseClusterHealthConfig clusterHealthConfig: healthConfigMap.values()) { - HealthCheckDimensionEnum dimensionEnum = healthCheckService.getHealthCheckDimensionEnum(); - if (!clusterHealthConfig.getCheckNameEnum().getDimensionEnum().equals(dimensionEnum)) { - // 类型不匹配 - continue; - } - - // 记录 - HealthCheckResult checkResult = new HealthCheckResult( - dimensionEnum.getDimension(), - clusterHealthConfig.getCheckNameEnum().getConfigName(), - clusterPhyId, - "-1" - ); - checkResult.setPassed(Constant.YES); - resultList.add(checkResult); - } - - return resultList; - } - - private List checkAndGetResult(AbstractHealthCheckService healthCheckService, - ClusterPhyParam clusterPhyParam, - Map healthConfigMap) { - List resultList = new ArrayList<>(); - - // 进行检查 - for (BaseClusterHealthConfig clusterHealthConfig: healthConfigMap.values()) { - HealthCheckResult healthCheckResult = healthCheckService.checkAndGetResult(clusterPhyParam, clusterHealthConfig); - if (healthCheckResult == null) { - continue; - } - - // 记录 - resultList.add(healthCheckResult); - } - - return resultList; + public AbstractHealthCheckService getCheckService() { + return healthCheckClusterService; } } diff --git a/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/GroupHealthCheckTask.java b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/GroupHealthCheckTask.java index 581a679a..d24f981d 100644 --- a/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/GroupHealthCheckTask.java +++ b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/GroupHealthCheckTask.java @@ -1,29 +1,13 @@ package com.xiaojukeji.know.streaming.km.task.health; import com.didiglobal.logi.job.annotation.Task; -import com.didiglobal.logi.job.common.TaskResult; import com.didiglobal.logi.job.core.consensual.ConsensualEnum; -import com.didiglobal.logi.log.ILog; -import com.didiglobal.logi.log.LogFactory; -import com.xiaojukeji.know.streaming.km.common.bean.entity.cluster.ClusterPhy; -import com.xiaojukeji.know.streaming.km.common.bean.entity.config.healthcheck.BaseClusterHealthConfig; -import com.xiaojukeji.know.streaming.km.common.bean.entity.health.HealthCheckResult; -import com.xiaojukeji.know.streaming.km.common.bean.entity.param.cluster.ClusterPhyParam; -import com.xiaojukeji.know.streaming.km.common.constant.Constant; -import com.xiaojukeji.know.streaming.km.common.enums.health.HealthCheckDimensionEnum; -import com.xiaojukeji.know.streaming.km.common.utils.ValidateUtils; import com.xiaojukeji.know.streaming.km.core.service.health.checker.AbstractHealthCheckService; import com.xiaojukeji.know.streaming.km.core.service.health.checker.group.HealthCheckGroupService; -import com.xiaojukeji.know.streaming.km.core.service.health.checkresult.HealthCheckResultService; -import com.xiaojukeji.know.streaming.km.task.metrics.AbstractAsyncMetricsDispatchTask; import lombok.AllArgsConstructor; import lombok.NoArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.Map; @NoArgsConstructor @AllArgsConstructor @@ -33,98 +17,13 @@ import java.util.Map; autoRegister = true, consensual = ConsensualEnum.BROADCAST, timeout = 2 * 60) -public class GroupHealthCheckTask extends AbstractAsyncMetricsDispatchTask { - private static final ILog log = LogFactory.getLog(GroupHealthCheckTask.class); - - @Autowired - private HealthCheckResultService healthCheckResultService; +public class GroupHealthCheckTask extends AbstractHealthCheckTask { @Autowired private HealthCheckGroupService healthCheckGroupService; @Override - public TaskResult processClusterTask(ClusterPhy clusterPhy, long triggerTimeUnitMs) { - return this.calAndUpdateHealthCheckResult(clusterPhy, triggerTimeUnitMs); - } - - private TaskResult calAndUpdateHealthCheckResult(ClusterPhy clusterPhy, long triggerTimeUnitMs) { - // 获取配置,<配置名,配置信息> - Map healthConfigMap = healthCheckResultService.getClusterHealthConfig(clusterPhy.getId()); - - // 检查结果 - List resultList = new ArrayList<>(); - - // 遍历Check-Service - List paramList = healthCheckGroupService.getResList(clusterPhy.getId()); - if (ValidateUtils.isEmptyList(paramList)) { - // 当前无该维度的资源,则直接设置为 - resultList.addAll(this.getNoResResult(clusterPhy.getId(), healthCheckGroupService, healthConfigMap)); - } - - // 遍历资源 - for (ClusterPhyParam clusterPhyParam: paramList) { - resultList.addAll(this.checkAndGetResult(healthCheckGroupService, clusterPhyParam, healthConfigMap)); - } - - for (HealthCheckResult checkResult: resultList) { - try { - healthCheckResultService.replace(checkResult); - } catch (Exception e) { - log.error("class=GroupHealthCheckTask||method=processSubTask||clusterPhyId={}||checkResult={}||errMsg=exception!", clusterPhy.getId(), checkResult, e); - } - } - - // 删除10分钟之前的检查结果 - try { - healthCheckResultService.deleteByUpdateTimeBeforeInDB(clusterPhy.getId(), new Date(triggerTimeUnitMs - 10 * 60 * 1000)); - } catch (Exception e) { - log.error("class=GroupHealthCheckTask||method=processSubTask||clusterPhyId={}||errMsg=exception!", clusterPhy.getId(), e); - } - - return TaskResult.SUCCESS; - } - - private List getNoResResult(Long clusterPhyId, AbstractHealthCheckService healthCheckService, Map healthConfigMap) { - List resultList = new ArrayList<>(); - - // 进行检查 - for (BaseClusterHealthConfig clusterHealthConfig: healthConfigMap.values()) { - HealthCheckDimensionEnum dimensionEnum = healthCheckService.getHealthCheckDimensionEnum(); - if (!clusterHealthConfig.getCheckNameEnum().getDimensionEnum().equals(dimensionEnum)) { - // 类型不匹配 - continue; - } - - // 记录 - HealthCheckResult checkResult = new HealthCheckResult( - dimensionEnum.getDimension(), - clusterHealthConfig.getCheckNameEnum().getConfigName(), - clusterPhyId, - "-1" - ); - checkResult.setPassed(Constant.YES); - resultList.add(checkResult); - } - - return resultList; - } - - private List checkAndGetResult(AbstractHealthCheckService healthCheckService, - ClusterPhyParam clusterPhyParam, - Map healthConfigMap) { - List resultList = new ArrayList<>(); - - // 进行检查 - for (BaseClusterHealthConfig clusterHealthConfig: healthConfigMap.values()) { - HealthCheckResult healthCheckResult = healthCheckService.checkAndGetResult(clusterPhyParam, clusterHealthConfig); - if (healthCheckResult == null) { - continue; - } - - // 记录 - resultList.add(healthCheckResult); - } - - return resultList; + public AbstractHealthCheckService getCheckService() { + return healthCheckGroupService; } } diff --git a/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/TopicHealthCheckTask.java b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/TopicHealthCheckTask.java index 8badae99..25a1e531 100644 --- a/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/TopicHealthCheckTask.java +++ b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/TopicHealthCheckTask.java @@ -1,30 +1,13 @@ package com.xiaojukeji.know.streaming.km.task.health; import com.didiglobal.logi.job.annotation.Task; -import com.didiglobal.logi.job.common.TaskResult; import com.didiglobal.logi.job.core.consensual.ConsensualEnum; -import com.didiglobal.logi.log.ILog; -import com.didiglobal.logi.log.LogFactory; -import com.xiaojukeji.know.streaming.km.common.bean.entity.cluster.ClusterPhy; -import com.xiaojukeji.know.streaming.km.common.bean.entity.config.healthcheck.BaseClusterHealthConfig; -import com.xiaojukeji.know.streaming.km.common.bean.entity.health.HealthCheckResult; -import com.xiaojukeji.know.streaming.km.common.bean.entity.param.cluster.ClusterPhyParam; -import com.xiaojukeji.know.streaming.km.common.constant.Constant; -import com.xiaojukeji.know.streaming.km.common.enums.health.HealthCheckDimensionEnum; -import com.xiaojukeji.know.streaming.km.common.utils.ValidateUtils; import com.xiaojukeji.know.streaming.km.core.service.health.checker.AbstractHealthCheckService; import com.xiaojukeji.know.streaming.km.core.service.health.checker.topic.HealthCheckTopicService; -import com.xiaojukeji.know.streaming.km.core.service.health.checkresult.HealthCheckResultService; -import com.xiaojukeji.know.streaming.km.task.metrics.AbstractAsyncMetricsDispatchTask; import lombok.AllArgsConstructor; import lombok.NoArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.Map; - @NoArgsConstructor @AllArgsConstructor @Task(name = "TopicHealthCheckTask", @@ -33,98 +16,13 @@ import java.util.Map; autoRegister = true, consensual = ConsensualEnum.BROADCAST, timeout = 2 * 60) -public class TopicHealthCheckTask extends AbstractAsyncMetricsDispatchTask { - private static final ILog log = LogFactory.getLog(TopicHealthCheckTask.class); - - @Autowired - private HealthCheckResultService healthCheckResultService; +public class TopicHealthCheckTask extends AbstractHealthCheckTask { @Autowired private HealthCheckTopicService healthCheckTopicService; @Override - public TaskResult processClusterTask(ClusterPhy clusterPhy, long triggerTimeUnitMs) { - return this.calAndUpdateHealthCheckResult(clusterPhy, triggerTimeUnitMs); - } - - private TaskResult calAndUpdateHealthCheckResult(ClusterPhy clusterPhy, long triggerTimeUnitMs) { - // 获取配置,<配置名,配置信息> - Map healthConfigMap = healthCheckResultService.getClusterHealthConfig(clusterPhy.getId()); - - // 检查结果 - List resultList = new ArrayList<>(); - - // 遍历Check-Service - List paramList = healthCheckTopicService.getResList(clusterPhy.getId()); - if (ValidateUtils.isEmptyList(paramList)) { - // 当前无该维度的资源,则直接设置为 - resultList.addAll(this.getNoResResult(clusterPhy.getId(), healthCheckTopicService, healthConfigMap)); - } - - // 遍历资源 - for (ClusterPhyParam clusterPhyParam: paramList) { - resultList.addAll(this.checkAndGetResult(healthCheckTopicService, clusterPhyParam, healthConfigMap)); - } - - for (HealthCheckResult checkResult: resultList) { - try { - healthCheckResultService.replace(checkResult); - } catch (Exception e) { - log.error("class=TopicHealthCheckTask||method=processSubTask||clusterPhyId={}||checkResult={}||errMsg=exception!", clusterPhy.getId(), checkResult, e); - } - } - - // 删除10分钟之前的检查结果 - try { - healthCheckResultService.deleteByUpdateTimeBeforeInDB(clusterPhy.getId(), new Date(triggerTimeUnitMs - 10 * 60 * 1000)); - } catch (Exception e) { - log.error("class=TopicHealthCheckTask||method=processSubTask||clusterPhyId={}||errMsg=exception!", clusterPhy.getId(), e); - } - - return TaskResult.SUCCESS; - } - - private List getNoResResult(Long clusterPhyId, AbstractHealthCheckService healthCheckService, Map healthConfigMap) { - List resultList = new ArrayList<>(); - - // 进行检查 - for (BaseClusterHealthConfig clusterHealthConfig: healthConfigMap.values()) { - HealthCheckDimensionEnum dimensionEnum = healthCheckService.getHealthCheckDimensionEnum(); - if (!clusterHealthConfig.getCheckNameEnum().getDimensionEnum().equals(dimensionEnum)) { - // 类型不匹配 - continue; - } - - // 记录 - HealthCheckResult checkResult = new HealthCheckResult( - dimensionEnum.getDimension(), - clusterHealthConfig.getCheckNameEnum().getConfigName(), - clusterPhyId, - "-1" - ); - checkResult.setPassed(Constant.YES); - resultList.add(checkResult); - } - - return resultList; - } - - private List checkAndGetResult(AbstractHealthCheckService healthCheckService, - ClusterPhyParam clusterPhyParam, - Map healthConfigMap) { - List resultList = new ArrayList<>(); - - // 进行检查 - for (BaseClusterHealthConfig clusterHealthConfig: healthConfigMap.values()) { - HealthCheckResult healthCheckResult = healthCheckService.checkAndGetResult(clusterPhyParam, clusterHealthConfig); - if (healthCheckResult == null) { - continue; - } - - // 记录 - resultList.add(healthCheckResult); - } - - return resultList; + public AbstractHealthCheckService getCheckService() { + return healthCheckTopicService; } } diff --git a/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/metadata/SyncKafkaGroupTask.java b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/metadata/SyncKafkaGroupTask.java index e2f749fe..cbec5bd2 100644 --- a/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/metadata/SyncKafkaGroupTask.java +++ b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/metadata/SyncKafkaGroupTask.java @@ -6,15 +6,10 @@ import com.didiglobal.logi.job.core.consensual.ConsensualEnum; import com.didiglobal.logi.log.ILog; import com.didiglobal.logi.log.LogFactory; import com.xiaojukeji.know.streaming.km.common.bean.entity.cluster.ClusterPhy; -import com.xiaojukeji.know.streaming.km.common.bean.po.group.GroupMemberPO; -import com.xiaojukeji.know.streaming.km.common.enums.group.GroupStateEnum; -import com.xiaojukeji.know.streaming.km.common.exception.AdminOperateException; -import com.xiaojukeji.know.streaming.km.common.exception.NotExistException; +import com.xiaojukeji.know.streaming.km.common.bean.entity.group.Group; import com.xiaojukeji.know.streaming.km.common.utils.ValidateUtils; import com.xiaojukeji.know.streaming.km.core.service.group.GroupService; import com.xiaojukeji.know.streaming.km.core.service.topic.TopicService; -import org.apache.kafka.clients.admin.*; -import org.apache.kafka.common.TopicPartition; import org.springframework.beans.factory.annotation.Autowired; import java.util.*; @@ -38,98 +33,58 @@ public class SyncKafkaGroupTask extends AbstractAsyncMetadataDispatchTask { @Override public TaskResult processClusterTask(ClusterPhy clusterPhy, long triggerTimeUnitMs) throws Exception { - + // 获取集群的Group列表 List groupNameList = groupService.listGroupsFromKafka(clusterPhy.getId()); - TaskResult tr = updateGroupMembersTask(clusterPhy, groupNameList, triggerTimeUnitMs); - if (!TaskResult.SUCCESS.equals(tr)) { - return tr; + TaskResult allSuccess = TaskResult.SUCCESS; + + // 获取Group详细信息 + List groupList = new ArrayList<>(); + for (String groupName : groupNameList) { + try { + Group group = groupService.getGroupFromKafka(clusterPhy.getId(), groupName); + if (group == null) { + continue; + } + + groupList.add(group); + } catch (Exception e) { + log.error("method=processClusterTask||clusterPhyId={}||groupName={}||errMsg=exception", clusterPhy.getId(), groupName, e); + allSuccess = TaskResult.FAIL; + } + } + + // 过滤掉无效的Topic + this.filterTopicIfTopicNotExist(clusterPhy.getId(), groupList); + + // 更新DB中的Group信息 + groupService.batchReplaceGroupsAndMembers(clusterPhy.getId(), groupList, triggerTimeUnitMs); + + // 如果存在错误,则直接返回 + if (!TaskResult.SUCCESS.equals(allSuccess)) { + return allSuccess; } // 删除历史的Group groupService.deleteByUpdateTimeBeforeInDB(clusterPhy.getId(), new Date(triggerTimeUnitMs - 5 * 60 * 1000)); - return tr; + return allSuccess; } - - private TaskResult updateGroupMembersTask(ClusterPhy clusterPhy, List groupNameList, long triggerTimeUnitMs) { - List groupMemberPOList = new ArrayList<>(); - TaskResult tr = TaskResult.SUCCESS; - - for (String groupName : groupNameList) { - try { - List poList = this.getGroupMembers(clusterPhy.getId(), groupName, new Date(triggerTimeUnitMs)); - groupMemberPOList.addAll(poList); - } catch (Exception e) { - log.error("method=updateGroupMembersTask||clusterPhyId={}||groupName={}||errMsg=exception", clusterPhy.getId(), groupName, e); - tr = TaskResult.FAIL; - } - } - - groupMemberPOList = this.filterGroupIfTopicNotExist(clusterPhy.getId(), groupMemberPOList); - groupService.batchReplace(groupMemberPOList); - - return tr; - } - - private List getGroupMembers(Long clusterPhyId, String groupName, Date updateTime) throws NotExistException, AdminOperateException { - Map groupMap = new HashMap<>(); - - // 获取消费组消费过哪些Topic - Map offsetMap = groupService.getGroupOffset(clusterPhyId, groupName); - for (TopicPartition topicPartition : offsetMap.keySet()) { - GroupMemberPO po = groupMap.get(topicPartition.topic()); - if (po == null) { - po = new GroupMemberPO(clusterPhyId, topicPartition.topic(), groupName, updateTime); - } - groupMap.put(topicPartition.topic(), po); - } - - // 在上面的基础上,补充消费组的详细信息 - ConsumerGroupDescription consumerGroupDescription = groupService.getGroupDescription(clusterPhyId, groupName); - if (consumerGroupDescription == null) { - return new ArrayList<>(groupMap.values()); - } - - groupMap.forEach((key, val) -> val.setState(GroupStateEnum.getByRawState(consumerGroupDescription.state()).getState())); - - for (MemberDescription memberDescription : consumerGroupDescription.members()) { - Set partitionList = new HashSet<>(); - if (!ValidateUtils.isNull(memberDescription.assignment().topicPartitions())) { - partitionList = memberDescription.assignment().topicPartitions(); - } - - Set topicNameSet = partitionList.stream().map(elem -> elem.topic()).collect(Collectors.toSet()); - for (String topicName : topicNameSet) { - groupMap.putIfAbsent(topicName, new GroupMemberPO(clusterPhyId, topicName, groupName, updateTime)); - - GroupMemberPO po = groupMap.get(topicName); - po.setMemberCount(po.getMemberCount() + 1); - po.setState(GroupStateEnum.getByRawState(consumerGroupDescription.state()).getState()); - } - } - - // 如果该消费组没有正在消费任何Topic的特殊情况,但是这个Group存在 - if (groupMap.isEmpty()) { - GroupMemberPO po = new GroupMemberPO(clusterPhyId, "", groupName, updateTime); - po.setState(GroupStateEnum.getByRawState(consumerGroupDescription.state()).getState()); - groupMap.put("", po); - } - - return new ArrayList<>(groupMap.values()); - } - - private List filterGroupIfTopicNotExist(Long clusterPhyId, List poList) { - if (poList.isEmpty()) { - return poList; + private void filterTopicIfTopicNotExist(Long clusterPhyId, List groupList) { + if (ValidateUtils.isEmptyList(groupList)) { + return; } // 集群Topic集合 Set dbTopicSet = topicService.listTopicsFromDB(clusterPhyId).stream().map(elem -> elem.getTopicName()).collect(Collectors.toSet()); dbTopicSet.add(""); //兼容没有消费Topic的group - + // 过滤Topic不存在的消费组 - return poList.stream().filter(elem -> dbTopicSet.contains(elem.getTopicName())).collect(Collectors.toList()); + for (Group group: groupList) { + group.setTopicMembers( + group.getTopicMembers().stream().filter(elem -> dbTopicSet.contains(elem.getTopicName())).collect(Collectors.toList()) + ); + } } } diff --git a/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/metadata/SyncZookeeperTask.java b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/metadata/SyncZookeeperTask.java new file mode 100644 index 00000000..5af37be2 --- /dev/null +++ b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/metadata/SyncZookeeperTask.java @@ -0,0 +1,47 @@ +package com.xiaojukeji.know.streaming.km.task.metadata; + +import com.didiglobal.logi.job.annotation.Task; +import com.didiglobal.logi.job.common.TaskResult; +import com.didiglobal.logi.job.core.consensual.ConsensualEnum; +import com.didiglobal.logi.log.ILog; +import com.didiglobal.logi.log.LogFactory; +import com.xiaojukeji.know.streaming.km.common.bean.entity.cluster.ClusterPhy; +import com.xiaojukeji.know.streaming.km.common.bean.entity.config.ZKConfig; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; +import com.xiaojukeji.know.streaming.km.common.utils.ConvertUtil; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.ZookeeperInfo; +import com.xiaojukeji.know.streaming.km.core.service.zookeeper.ZookeeperService; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.List; + + +@Task(name = "SyncZookeeperTask", + description = "ZK信息同步到DB", + cron = "0 0/1 * * * ? *", + autoRegister = true, + consensual = ConsensualEnum.BROADCAST, + timeout = 2 * 60) +public class SyncZookeeperTask extends AbstractAsyncMetadataDispatchTask { + private static final ILog log = LogFactory.getLog(SyncZookeeperTask.class); + + @Autowired + private ZookeeperService zookeeperService; + + @Override + public TaskResult processClusterTask(ClusterPhy clusterPhy, long triggerTimeUnitMs) { + Result> infoResult = zookeeperService.listFromZookeeper( + clusterPhy.getId(), + clusterPhy.getZookeeper(), + ConvertUtil.str2ObjByJson(clusterPhy.getZkProperties(), ZKConfig.class) + ); + + if (infoResult.failed()) { + return new TaskResult(TaskResult.FAIL_CODE, infoResult.getMessage()); + } + + zookeeperService.batchReplaceDataInDB(clusterPhy.getId(), infoResult.getData()); + + return TaskResult.SUCCESS; + } +} diff --git a/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/metrics/ReplicaMetricCollectorTask.java b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/metrics/ReplicaMetricCollectorTask.java index 6b93e324..7e52c2f4 100644 --- a/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/metrics/ReplicaMetricCollectorTask.java +++ b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/metrics/ReplicaMetricCollectorTask.java @@ -1,32 +1,32 @@ -package com.xiaojukeji.know.streaming.km.task.metrics; - -import com.didiglobal.logi.job.annotation.Task; -import com.didiglobal.logi.job.common.TaskResult; -import com.didiglobal.logi.job.core.consensual.ConsensualEnum; -import com.xiaojukeji.know.streaming.km.collector.metric.ReplicaMetricCollector; -import com.xiaojukeji.know.streaming.km.common.bean.entity.cluster.ClusterPhy; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; - -/** - * @author didi - */ -@Slf4j -@Task(name = "ReplicaMetricCollectorTask", - description = "Replica指标采集任务", - cron = "0 0/1 * * * ? *", - autoRegister = true, - consensual = ConsensualEnum.BROADCAST, - timeout = 2 * 60) -public class ReplicaMetricCollectorTask extends AbstractAsyncMetricsDispatchTask { - - @Autowired - private ReplicaMetricCollector replicaMetricCollector; - - @Override - public TaskResult processClusterTask(ClusterPhy clusterPhy, long triggerTimeUnitMs) throws Exception { - replicaMetricCollector.collectMetrics(clusterPhy); - - return TaskResult.SUCCESS; - } -} +//package com.xiaojukeji.know.streaming.km.task.metrics; +// +//import com.didiglobal.logi.job.annotation.Task; +//import com.didiglobal.logi.job.common.TaskResult; +//import com.didiglobal.logi.job.core.consensual.ConsensualEnum; +//import com.xiaojukeji.know.streaming.km.collector.metric.ReplicaMetricCollector; +//import com.xiaojukeji.know.streaming.km.common.bean.entity.cluster.ClusterPhy; +//import lombok.extern.slf4j.Slf4j; +//import org.springframework.beans.factory.annotation.Autowired; +// +///** +// * @author didi +// */ +//@Slf4j +//@Task(name = "ReplicaMetricCollectorTask", +// description = "Replica指标采集任务", +// cron = "0 0/1 * * * ? *", +// autoRegister = true, +// consensual = ConsensualEnum.BROADCAST, +// timeout = 2 * 60) +//public class ReplicaMetricCollectorTask extends AbstractAsyncMetricsDispatchTask { +// +// @Autowired +// private ReplicaMetricCollector replicaMetricCollector; +// +// @Override +// public TaskResult processClusterTask(ClusterPhy clusterPhy, long triggerTimeUnitMs) throws Exception { +// replicaMetricCollector.collectMetrics(clusterPhy); +// +// return TaskResult.SUCCESS; +// } +//} diff --git a/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/metrics/ZookeeperMetricCollectorTask.java b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/metrics/ZookeeperMetricCollectorTask.java new file mode 100644 index 00000000..f533a30a --- /dev/null +++ b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/metrics/ZookeeperMetricCollectorTask.java @@ -0,0 +1,33 @@ +package com.xiaojukeji.know.streaming.km.task.metrics; + +import com.didiglobal.logi.job.annotation.Task; +import com.didiglobal.logi.job.common.TaskResult; +import com.didiglobal.logi.job.core.consensual.ConsensualEnum; +import com.didiglobal.logi.log.ILog; +import com.didiglobal.logi.log.LogFactory; +import com.xiaojukeji.know.streaming.km.collector.metric.ZookeeperMetricCollector; +import com.xiaojukeji.know.streaming.km.common.bean.entity.cluster.ClusterPhy; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * @author didi + */ +@Task(name = "ZookeeperMetricCollectorTask", + description = "Zookeeper指标采集任务", + cron = "0 0/1 * * * ? *", + autoRegister = true, + consensual = ConsensualEnum.BROADCAST, + timeout = 2 * 60) +public class ZookeeperMetricCollectorTask extends AbstractAsyncMetricsDispatchTask { + private static final ILog log = LogFactory.getLog(ZookeeperMetricCollectorTask.class); + + @Autowired + private ZookeeperMetricCollector zookeeperMetricCollector; + + @Override + public TaskResult processClusterTask(ClusterPhy clusterPhy, long triggerTimeUnitMs) throws Exception { + zookeeperMetricCollector.collectMetrics(clusterPhy); + + return TaskResult.SUCCESS; + } +} diff --git a/pom.xml b/pom.xml index 8a810fa4..060523b5 100644 --- a/pom.xml +++ b/pom.xml @@ -15,7 +15,7 @@ - 3.0.0 + 3.0.1 8 8