Compare commits

...

425 Commits

Author SHA1 Message Date
zengqiao
66e3da5d2f 产品prd 2023-02-28 10:59:12 +08:00
zengqiao
5f2adfe74e 产品PRD 2023-02-28 10:58:48 +08:00
zengqiao
cecfde906a 清空代码 2023-02-28 10:37:11 +08:00
zengqiao
258385dc9a 升级至3.3.0版本 2023-02-24 11:12:31 +08:00
zengqiao
65238231f0 补充3.3.0版本升级信息 2023-02-24 11:11:12 +08:00
zengqiao
cb22e02fbe 补充3.3.0版本变更信息 2023-02-24 11:10:42 +08:00
erge
aa0bec1206 [Optimize]package.json锁定lerna版本,更新package-lock.json文件(#957) 2023-02-23 20:14:04 +08:00
wyb
793c780015 [Bugfix]修复mm2列表请求超时(#949)
调整代码结构
2023-02-23 11:17:48 +08:00
erge
ec6f063450 [Optimize] 去除package.json 出现内部地址(#939) 2023-02-22 17:08:21 +08:00
zengqiao
f25c65b98b [Doc]补充贡献者信息 2023-02-22 14:00:52 +08:00
Luckywustone
2d99aae779 [Bugfix]ZK健康巡检日志不清晰导致问题难定位 #904
[Bugfix]ZK健康巡检日志不清晰导致问题难定位 #904
2023-02-22 13:41:02 +08:00
erge
a8847dc282 [Bugfix] 修复打包不成功(#940) 2023-02-22 11:58:33 +08:00
zengqiao
4852c01c88 [Feature]补充贡献代码相关文档(#947)
1、补充贡献者名单,如有遗漏,辛苦告知;
2、补充贡献指南;
2023-02-22 11:53:00 +08:00
zengqiao
3d6f405b69 [Bugfix]订正失效的邮箱地址(#944)
[Bugfix]订正语句(#944)
2023-02-22 11:52:40 +08:00
erge
18e3fbf41d [Optimize] 健康检查项时间和结果显示(didi#930) 2023-02-21 10:41:49 +08:00
erge
ae8cc3092b [Optimize] 新增/编辑MM2 Topic 由当前集群获取改为对应的sourceKafka集群获取& 新增/编辑MM2入参优化(#894) 2023-02-21 10:41:44 +08:00
erge
5c26e8947b [Optimize] JSON新增MM2 Drawer Title文案变更(#894) 2023-02-21 10:41:37 +08:00
erge
fbe6945d3b [Bugfix]zookeeper页面leader节点显示异常(#873) 2023-02-21 10:41:25 +08:00
zengqiao
7dc8f2dc48 [Bugfix]修复Connector列表和MM2列表搜索不生效的问题(#928) 2023-02-21 10:40:05 +08:00
zengqiao
91c60ce72c [Bugfix]修复新接入的集群,Controller-Host不显示的问题(#927)
问题原因:
1、新接入的集群,DB中暂未存储Broker信息,因此在存储Controller至DB时,查询DB中的Broker会查询为空。

解决方式:
1、存储Controller至DB前,主动获取一次Broker的信息。
2023-02-21 10:39:46 +08:00
zengqiao
687eea80c8 补充3.3.0版本变更信息 2023-02-16 14:51:43 +08:00
zengqiao
9bfe3fd1db 设置为AGPL协议 2023-02-15 17:53:46 +08:00
shizeying
03f81bc6de [Bugfix]删除idx_cluster_phy_id 索引并新增idx_cluster_update_time索引(#918) 2023-02-15 17:45:53 +08:00
slhu
eed9571ffa [Bugfix]解决在解析命令执行后返回指标的值时发生的数据类型转换错误与指标存储上报时报空指针的问题(#912)
1.zk_min_latency、zk_max_latency指标数据类型变更为float
2.使用ConvertUtil.string2Float()方法进行string到float到类型转换
2023-02-15 16:20:39 +08:00
edengyuan_v
e4651ef749 [Optimize]新增Topic时清理策略区分单选多选(#770) 2023-02-15 11:18:33 +08:00
zengqiao
f715cf7a8d 补充 3.3.0 版本变更信息 2023-02-13 11:57:51 +08:00
wyb
fad9ddb9a1 fix: 更新登录页文案 2023-02-13 11:49:00 +08:00
wyb
b6e4f50849 fix: 健康状态详情优化 & Connector 样式优化 & 无MM2任务指标兜底页 2023-02-13 11:49:00 +08:00
wyb
5c6911e398 [Optimize]Overview指标卡片展示逻辑 2023-02-13 11:49:00 +08:00
wyb
a0371ab88b feat: 新增Topic 复制功能 2023-02-13 11:49:00 +08:00
wyb
fa2abadc25 feat: 新增Mirror Maker 2.0(MM2) 2023-02-13 11:49:00 +08:00
zengqiao
f03460f3cd [Bugfix]修复 Broker Similar Config 显示错误的问题(#872) 2023-02-13 11:22:13 +08:00
zengqiao
b5683b73c2 [Optimize]优化 MySQL & ES 测试容器的初始化(#906)
主要的变更
1、knowstreaming/knowstreaming-manager 容器;
2、knowstreaming/knowstreaming-mysql 容器调整为使用 mysql:5.7 容器;
3、初始化 mysql:5.7 容器后,增加初始化 MySQL 表及数据的动作;

被影响的变更:
1、移动 km-dist/init/sql 下的MySQL初始化脚本至 km-persistence/src/main/resource/sql 下,以便项目测试时加载到所需的初始化 SQL;
2、删除无用的 km-dist/init/template 目录;
3、因为 km-dist/init/sql 和 km-dist/init/template 目录的调整,因此也调整 ReleaseKnowStreaming.xml 内的文件内容;
2023-02-13 10:33:40 +08:00
zengqiao
c062586c7e [Optimize]删除无用&多余的打包配置文件 2023-02-10 16:51:32 +08:00
fengqiongfeng
98a5c7b776 [Optimize]健康检查日志优化(#869) 2023-02-10 11:02:24 +08:00
zengqiao
e204023b1f [Feature]增加支持Topic复制的集群列表接口(#899) 2023-02-09 17:03:28 +08:00
zengqiao
4c5ffccc45 [Optimize]删除无效代码 2023-02-09 17:00:50 +08:00
zengqiao
fbcf58e19c [Feature]MM2管理-Connector元信息管理优化(#894) 2023-02-09 16:59:38 +08:00
zengqiao
e5c6d00438 [Feature]MM2管理-补充集群Group列表信息(#894) 2023-02-09 16:59:38 +08:00
zengqiao
ab6a4d7099 [Feature]MM2管理-MM2管理相关接口类(#894) 2023-02-09 16:59:38 +08:00
zengqiao
78b2b8a45e [Feature]MM2管理-MM2管理相关业务类(#894) 2023-02-09 16:59:38 +08:00
zengqiao
add2af4f3f [Feature]MM2管理-MM2管理相关服务类(#894) 2023-02-09 16:59:38 +08:00
zengqiao
235c0ed30e [Feature]MM2管理-MM2管理相关实体类(#894) 2023-02-09 16:59:38 +08:00
zengqiao
5bd93aa478 [Bugfix]修复正常情况下,集群状态统计错误的问题(#865) 2023-02-09 16:44:26 +08:00
zengqiao
f95be2c1b3 [Optimize]TaskResult增加返回任务分组信息 2023-02-09 16:36:19 +08:00
zengqiao
5110b30f62 [Feature]MM2管理-MM2健康巡检(#894) 2023-02-09 15:36:35 +08:00
zengqiao
861faa5df5 [Feature]HA-镜像Topic管理(#899)
1、底层Kafka需要是滴滴版本的Kafka;
2、新增镜像Topic的增删改查;
3、新增镜像Topic的指标查看;
2023-02-09 15:21:23 +08:00
zengqiao
efdf624c67 [Feature]HA-滴滴Kafka版本信息兼容(#899) 2023-02-09 15:21:23 +08:00
zengqiao
caccf9cef5 [Feature]MM2管理-采集MM2指标任务(#894) 2023-02-09 14:58:34 +08:00
zengqiao
6ba3dceb84 [Feature]MM2管理-采集MM2指标(#894) 2023-02-09 14:58:34 +08:00
zengqiao
9b7c41e804 [Feature]MM2管理-读写ES中的MM2指标(#894) 2023-02-09 14:58:34 +08:00
zengqiao
346aee8fe7 [Bugfix]修复Topic指标大盘获取TopN指标存在错误的问题(#896)
1、将ES排序调整为基于本地cache的排序;
2、将database的本地cache从core模块移动到persistence模块;
2023-02-09 14:20:02 +08:00
zengqiao
353d781bca [Feature]补充MM2相关索引及数据库表信息(#894) 2023-02-09 13:44:40 +08:00
EricZeng
3ce4bf231a 修复条件判断错误问题
Co-authored-by: haoqi123 <49672871+haoqi123@users.noreply.github.com>
2023-02-09 11:28:26 +08:00
EricZeng
d046cb8bf4 修复条件判断错误问题
Co-authored-by: haoqi123 <49672871+haoqi123@users.noreply.github.com>
2023-02-09 11:28:26 +08:00
zengqiao
da95c63503 [Optimize]优化TestContainers相关依赖(#892)
1、去除对mysql-connector-j的依赖;
2、整理代码;
2023-02-09 11:28:26 +08:00
haoqi
915e48de22 [Optimize]补充Testcontainers的使用说明(#890) 2023-02-09 11:05:44 +08:00
_haoqi
256f770971 [Feature]Support running tests with testcontainers(#870) 2023-02-08 14:56:44 +08:00
zengqiao
16e251cbe8 调整开源协议 2023-02-08 14:10:37 +08:00
zengqiao
67743b859a [Optimize]补充Ldap登录的配置说明(#888) 2023-02-08 13:51:45 +08:00
congchen0321
c275b42632 Update faq.md 2023-02-08 13:41:08 +08:00
zengqiao
a02760417b [Optimize]ZK-Overview页面补充默认展示的指标(#874) 2023-01-30 13:18:06 +08:00
zengqiao
0e50bfc5d4 优化PR模版 2023-01-13 16:04:25 +08:00
wuyouwuyoulian
eab988e18f For #781, Fix "The partition display is incomplete" bug 2023-01-12 11:03:30 +08:00
zengqiao
dd6004b9d4 [Bugfix]修复采集副本指标时,参数传递错误问题(#867) 2023-01-11 18:00:21 +08:00
zengqiao
ac7c32acd5 [Optimize]优化ES索引及模版的初始化文档(#832)
1、订正不同地方索引模版的shard数存在不一致的问题;
2、删除多余的template.sh,统一使用init_es_template.sh;
3、init_es_template.sh中,增加connect相关索引模版的初始化脚本,删除replica 和 zookeper索引模版的初始化脚本;
2023-01-09 15:18:41 +08:00
zengqiao
f4a219ceef [Optimize]去除Replica指标从ES读写的相关代码(#862) 2023-01-09 14:57:38 +08:00
zengqiao
a8b56fb613 [Bugfix]修复用户信息修改后,用户列表会抛出空指针异常的问题(#860) 2023-01-09 14:57:23 +08:00
zengqiao
2925a20e8e [Bugfix]修复查看消息时,选择分区不生效问题(#858) 2023-01-09 13:38:10 +08:00
zengqiao
6b3eb05735 [Bugfix]修复对ZK客户端进行配置后不生效的问题(#694)
1、修复在ks_km_physical_cluster表的zk_properties字段填写ZK 客户端的相关配置后,不生效的问题。
2、删除zk_properties字段中,暂时无需使用的jmxConfig字段。
2023-01-09 10:44:35 +08:00
zengqiao
17e0c39f83 [Optimize]优化Topic健康巡检的日志(#855) 2023-01-06 14:42:08 +08:00
zengqiao
4994639111 [Optimize]无ZK模块时,巡检详情忽略对ZK的展示(#764) 2023-01-04 10:32:18 +08:00
wyb
c187b5246f [Bugfix]修复connector指标筛选缺少指标的问题(#846) 2022-12-23 16:19:34 +08:00
wyb
6ed6d5ec8a [Bugfix]修复用户更新失败问题(#840) 2022-12-22 15:56:48 +08:00
wyb
0735b332a8 [Bugfix]修复函数映射错误(#842) 2022-12-22 08:48:59 +08:00
wyb
344cec19fe [Bugfix]connector指标采集算最大值错误(#836) 2022-12-20 09:50:42 +08:00
zengqiao
6ef365e201 bump version to 3.2.0 2022-12-16 13:58:40 +08:00
zengqiao
edfa6a9f71 调整v3.2版本容器化部署信息 2022-12-16 13:39:51 +08:00
孙超
860d0b92e2 V3.2 2022-12-16 13:27:09 +08:00
zengqiao
5bceed7105 [Optimize]缩小ES索引默认shard数 2022-12-15 14:44:18 +08:00
zengqiao
44a2fe0398 增加3.2.0版本升级信息 2022-12-14 14:14:35 +08:00
zengqiao
218459ad1b 增加3.2.0版本变更信息 2022-12-14 14:14:20 +08:00
zengqiao
7db757bc12 [Optimize]优化Connector创建时的入参
1、增加config.action.reload的默认值;
2、增加errors.tolerance的默认值;
2022-12-14 14:12:32 +08:00
zengqiao
896a943587 [Optimize]缩短ES索引默认保存时间为15天 2022-12-14 14:10:46 +08:00
zengqiao
cd2c388e68 [Optimize]优化Sonar代码扫描结果 2022-12-14 14:07:30 +08:00
wyb
4543a339b7 [Bugfix]修复job更新中的数组越界报错(#744) 2022-12-14 13:56:29 +08:00
zengqiao
1c4fbef9f2 [Feature]支持拆分API服务和Job服务部署(#829)
1、JMX检查功能是每一个KS都必须要有的,因此从Task模块移动到Core模块;
2、application.yml中补充Task模块任务的整体开关字段;
2022-12-09 16:11:03 +08:00
zengqiao
b2f0f69365 [Optimize]Overview页面的TopN查询ES流程优化(#823)
1、复用线程池,同时支持线程池的线程数可配置;
2、优化查询TopN指标时,可能会出现重复查询的问题;
3、处理代码扫描(SonarLint)反馈的问题;
2022-12-09 14:39:17 +08:00
wyb
c4fb18a73c [Bugfix]修复迁移任务状态不一致问题(#815) 2022-12-08 17:13:14 +08:00
zengqiao
5cad7b4106 [Bugfix]修复集群Topic列表页面白屏问题(#819)
集群Topic列表健康状态对应关系存在问题,导致当健康状态指标存在时,会出现白屏。
2022-12-07 16:27:27 +08:00
zengqiao
f3c4133cd2 [Bugfix]分批从ES查询Topic最近一条指标(#817) 2022-12-07 16:15:01 +08:00
zengqiao
d9c59cb3d3 增加Connect Rest接口 2022-12-07 10:20:02 +08:00
zengqiao
7a0db7161b 增加Connect 业务层方法 2022-12-07 10:20:02 +08:00
zengqiao
6aefc16fa0 增加Connect相关任务 2022-12-07 10:20:02 +08:00
zengqiao
186dcd07e0 增加3.2版本升级信息 2022-12-07 10:20:02 +08:00
zengqiao
e8652d5db5 Connect相关代码 2022-12-07 10:20:02 +08:00
zengqiao
fb5964af84 补充kafka-connect相关包 2022-12-07 10:20:02 +08:00
zengqiao
249fe7c700 调整ES相关文件位置 & 补充connectESDAO相关类 2022-12-07 10:20:02 +08:00
zengqiao
cc2a590b33 新增自定义的KSPartialKafkaAdminClient
由于原生的KafkaAdminClient在解析Group时,会将Connect集群的Group过滤掉,因此自定义KSPartialKafkaAdminClient,使其具备获取Connect Group的能力
2022-12-07 10:20:02 +08:00
zengqiao
5b3f3e5575 移动指标入ES的代码 2022-12-07 10:20:02 +08:00
wyb
36cf285397 [Bug]修复logi-securiy模块数据库选择错误(#808) 2022-12-06 20:02:49 +08:00
zengqiao
4386563c2c 调整指标采集的默认耗时值,以便在查看Top指标时即可看到 2022-12-06 16:47:53 +08:00
zengqiao
0123ce4a5a 优化Broker列表JMX端口的返回值 2022-12-06 16:47:07 +08:00
zengqiao
c3d47d3093 池化KafkaAdminClient,避免KafkaAdminClient出现性能问题 2022-12-06 16:46:11 +08:00
zengqiao
9735c4f885 删除重复采集的指标 2022-12-06 16:41:27 +08:00
zengqiao
3a3141a361 调整ZK指标的采集时间 2022-12-06 16:40:52 +08:00
zengqiao
ac30436324 [Bugfix]修复更新健康巡检结果时出现死锁的问题(#728) 2022-12-05 16:30:37 +08:00
zengqiao
7176e418f5 [Optimize]优化健康巡检相关指标的计算(#726)
1、增加缓存,减少健康状态指标计算时的IO;
2、健康巡检调整为按照资源维度并发处理;
3、明确HealthCheckResultService和HealthStateService的功能边界;
2022-12-05 16:26:31 +08:00
zengqiao
ca794f507e [Optimize]规范日志输出格式(#800)
修改log输出配置,使其输出的日志中自带class={className}的信息,后续书写代码时,就无需书写该部分内容。
2022-12-05 14:27:02 +08:00
zengqiao
0f8be4fadc [Optimize]优化日志输出 & 本地缓存统一管理(#800) 2022-12-05 14:04:19 +08:00
zengqiao
7066246e8f [Optimize]错开采集任务触发时间,降低Offset信息获取时超时情况的发生(#726)
当前指标采集任务都是整分钟触发执行的,导致会同时向Kafka请求分区Offset信息,会导致:
1、请求过多,从而出现超时;
2、同时进行,可能会导致分区重复获取Offset信息;

因此将其错开。
2022-12-05 13:49:35 +08:00
zengqiao
7d1bb48b59 [Optimize]ZK四字命令解析日志优化(#805)
增加遗漏的指标名的处理,减少warn日志该部分的信息
2022-12-05 13:39:26 +08:00
limaiwang
dd0d519677 [Optimize]更新Zookeeper详情目录结构搜索文案(#793) 2022-12-05 12:15:03 +08:00
zengqiao
4293d05fca [Optimize]优化Topic元信息更新策略(#806) 2022-12-04 17:55:27 +08:00
zengqiao
2c82baf9fc [Optimize]指标采集性能优化-part1(#726) 2022-12-04 15:41:48 +08:00
zengqiao
921161d6d0 [Bugfix]修复ReplicaMetricCollector编译失败问题(#802) 2022-12-03 14:34:38 +08:00
zengqiao
e632c6c13f [Optimize]优化Sonar扫描结果 2022-12-02 15:34:28 +08:00
zengqiao
5833a8644c [Optimize]关闭errorLogger,去除无用输出(#801) 2022-12-02 15:29:17 +08:00
zengqiao
fab41e892f [Optimize]日志统一格式&优化输出内容-part3(#800) 2022-12-02 15:14:21 +08:00
zengqiao
7a52cf67b0 [Optimize]日志统一格式&优化输出内容-part2(#800) 2022-12-02 15:01:24 +08:00
zengqiao
175b8d643a [Optimize]统一日志格式-part1(#800) 2022-12-02 14:39:57 +08:00
zengqiao
6241eb052a [Bugfix]修复KafkaJMXClient类中logger错误的问题(#794) 2022-11-30 11:15:00 +08:00
zengqiao
c2fd0a8410 [Optimize]优化Sonar扫描出的不规范代码 2022-11-29 20:54:41 +08:00
zengqiao
5127b600ec [Optimize]优化ESClient的并发访问控制(#787) 2022-11-29 10:47:57 +08:00
zengqiao
feb03aede6 [Optimize]优化线程池的名称(#789) 2022-11-28 15:11:54 +08:00
duanxiaoqiu
47b6c5d86a [Bugfix]修复创建topic选择过期策略(kafka版本0.10.1.0之前)compact和delete只能二选一(didi#770) 2022-11-27 14:18:50 +08:00
SimonTeo58
c4a81613f4 [Optimize]更新Topic-Messages抽屉文案(#771) 2022-11-24 21:54:29 +08:00
limaiwang
daeb5c4cec [Bugfix]修复集群配置不写时,校验参数报错的问题 2022-11-24 15:30:01 +08:00
WangYaobo
38def45ad6 [Doc]增加无数据排查文档(#773) 2022-11-24 10:44:37 +08:00
pen4
4b29a2fdfd update org.springframework:spring-context 5.3.18 to 5.3.19 2022-11-23 11:38:11 +08:00
zengqiao
a165ecaeef [Bugfix]修复Broker&Topic修改时,版本设置错误问题(#762)
Kafka v2.3增加了增量修改配置的功能,但是KS中错误的将其配置为0.11.0版本就具备该能力,因此对其进行调整。
2022-11-21 15:56:33 +08:00
night.liang
6637ba4ccc [Optimize] optimize zk OutstandingRequests checker’s exception log (#738) 2022-11-18 17:12:07 +08:00
duanxiaoqiu
2f807eec2b [Feat]Topic列表健康分修改为健康状态(#758) 2022-11-18 13:56:27 +08:00
石臻臻的杂货铺
636c2c6a83 Update README.md 2022-11-17 13:33:40 +08:00
zengqiao
898a55c703 [Bugfix]修复Broker列表LogSize指标存储时名称错误的问题(#759) 2022-11-17 13:27:45 +08:00
zengqiao
8ffe7e7101 [Bugfix]修复Prometheus中Group部分指标缺少的问题(#756) 2022-11-14 13:33:16 +08:00
zengqiao
7661826ea5 [Optimize]健康巡检增加ClusterParam, 从而拆分Kafka和Connect相关的巡检任务 2022-11-10 16:24:39 +08:00
zengqiao
e456be91ef [Bugfix]集群JMX配置发生变更时,进行JMX的重新加载 2022-11-10 16:04:40 +08:00
zengqiao
da0a97cabf [Optimize] 调整Task代码结构为Connector功能做准备 2022-11-09 10:28:52 +08:00
zengqiao
c1031a492a [Optimize]增加ES索引删除的功能 2022-11-09 10:28:52 +08:00
zengqiao
3c8aaf528c [Bugfix] 修复因为指标缺失导致返回的集群数错误的问题 (#741) 2022-11-09 10:28:52 +08:00
黄海婷
70ff20a2b0 styles:cardBar卡片标题图标hover样式 2022-11-07 10:38:28 +08:00
黄海婷
6918f4babe styles:job列表自定义列按钮新增hover背景色 2022-11-07 10:38:28 +08:00
黄海婷
805a704d34 styles:部分icon在hover的时候,需要有背景色 2022-11-07 10:38:28 +08:00
黄海婷
c69c289bc4 styles:部分icon在hover的时候,需要有背景色 2022-11-07 10:38:28 +08:00
zengqiao
dd5869e246 [Optimize] 调整代码结构,为Connect功能做准备 2022-11-07 10:13:26 +08:00
Richard
b51ffb81a3 [Bugfix] No thread-bound request found. (#743) 2022-11-07 10:06:54 +08:00
黄海婷
ed0efd6bd2 styles:字体颜色#adb5bc变更为#74788D 2022-11-03 16:49:35 +08:00
黄海婷
39d2fe6195 styles:消息大小测试弹窗下方提示字体加粗 2022-11-03 16:49:35 +08:00
黄海婷
7471d05c20 styles:消息大小测试弹框字符数显示字体调整 2022-11-03 16:49:35 +08:00
黄海婷
3492688733 feat:Consumer列表刷新按钮新增hover提示 2022-11-01 17:37:37 +08:00
Sean
a603783615 [Optimize].gitignore 中添加 flatten.xml 过滤,为后续引入flatten 做准备(#732) 2022-11-01 14:16:53 +08:00
night.liang
5c9096d564 [Bugfix] fix replica dsl (#708) 2022-11-01 10:45:59 +08:00
zengqiao
c27786a257 bump version to 3.1.0 2022-10-31 14:55:50 +08:00
zengqiao
81910d1958 [Hotfix] 修复新接入集群时,健康状态信息页面出现空指针问题 2022-10-31 14:55:22 +08:00
zengqiao
55d5fc4bde 增加v3.1.0版本的变更项 2022-10-31 14:05:42 +08:00
GraceWalk
f30586b150 fix: 依赖安装默认采用 taobao 镜像 2022-10-29 13:55:36 +08:00
GraceWalk
37037c19f0 fix: 更新版本信息获取方式 2022-10-29 13:55:36 +08:00
GraceWalk
1a5e2c7309 fix: 错误页面优化 2022-10-29 13:55:36 +08:00
GraceWalk
941dd4fd65 feat: 支持 Zookeeper 模块 2022-10-29 13:55:36 +08:00
GraceWalk
5f6df3681c feat: 健康状态展示优化 2022-10-29 13:55:36 +08:00
zengqiao
7d045dbf05 补充ZK健康巡检任务 2022-10-29 13:55:07 +08:00
zengqiao
4ff4accdc3 补充3.1.0版本升级信息 2022-10-29 13:55:07 +08:00
zengqiao
bbe967c4a8 补充多集群健康状态概览信息 2022-10-29 13:55:07 +08:00
zengqiao
b101cec6fa 健康分调整为健康状态 2022-10-29 13:55:07 +08:00
zengqiao
e98ec562a2 Znode信息中,补充当前节点路径信息 2022-10-29 13:55:07 +08:00
zengqiao
0e71ecc587 延长健康检查结果过期时间 2022-10-29 13:55:07 +08:00
zengqiao
0f11a65df8 补充获取ZK的namespace的方法 2022-10-29 13:55:07 +08:00
zengqiao
da00c8c877 还原消费组重置失败的提示文案 2022-10-29 13:55:07 +08:00
hongtenzone@foxmail.com
8b177877bb Add release notes 2022-10-28 15:35:26 +08:00
hongtenzone@foxmail.com
ea199dca8d Add release notes 2022-10-28 15:35:26 +08:00
renxiangde
88b5833f77 [Bugfix] 修复新建Topic后,立即查看Topic-Messages信息会提示Topic不存在的问题 (#697) 2022-10-27 11:04:26 +08:00
zwen
127b5be651 [fix]Repair that preferredReplicaElection is not called as expected 2022-10-27 10:15:15 +08:00
Mengqi777
80f001cdd5 [ISSUE #723]Ignore error and continue to package km-rest if no git directory 2022-10-26 10:14:14 +08:00
zengqiao
30d297cae1 bump version to 3.1.0-SNAPSHOT 2022-10-21 17:13:02 +08:00
zengqiao
a96853db90 bump version to v3.0.1 2022-10-21 15:02:09 +08:00
zengqiao
c1502152c0 Revert "bump version to 3.1.0"
This reverts commit 7b5c2d80
2022-10-21 14:59:42 +08:00
GraceWalk
afda292796 fix: typescript 版本更新 2022-10-21 14:47:01 +08:00
GraceWalk
163cab78ae fix: 部分文案 & 样式优化 2022-10-21 14:47:01 +08:00
GraceWalk
8f4ff36c09 fix: 优化 Topic 扩分区名称 & 描述展示 2022-10-21 14:47:01 +08:00
GraceWalk
47b6b3577a fix: Broker 列表 jmxPort 列支持展示连接状态 2022-10-21 14:47:01 +08:00
GraceWalk
f3eca3b214 fix: ConsumerGroup 列表 & 详情页重构 2022-10-21 14:47:00 +08:00
GraceWalk
62f7d3f72f fix: 图表逻辑 & 展示优化 2022-10-21 14:47:00 +08:00
GraceWalk
26e60d8a64 fix: 优化全局 Message & Notification 展示效果 2022-10-21 14:47:00 +08:00
zengqiao
df655a250c 增加v3.0.1变更内容 2022-10-21 14:36:29 +08:00
zengqiao
811fc9b400 补充v3.0.1版本升级信息 2022-10-21 14:32:57 +08:00
zengqiao
83df02783c 安装包中,去除docs相关的文档 2022-10-21 14:32:07 +08:00
zengqiao
6a5efce874 [Bugfix] 修复指标版本信息list转map时出现key冲突从而抛出异常的问题 2022-10-21 12:06:22 +08:00
zengqiao
fa0ae5e474 [Optimize] 集群Broker列表中,补充Jmx是否成功连接的信息
1、当前页面无数据时,一部分的原因是JMX连接失败导致;
2、Broker列表中增加是否连接成功的信息,便于问题的排查;
2022-10-21 12:03:19 +08:00
zengqiao
cafd665a2d [Optimize] 删除Replica指标采集任务
1、当集群存在较多副本时,指标采集的性能会严重降低;
2、Replica的指标基本上都是在实时获取时才需要,因此当前先将Replica指标采集任务关闭,后续依据产品需要再看是否开启;
2022-10-21 11:49:58 +08:00
zengqiao
e8f77a456b [Optimize] 优化ZK指标的获取,减少重复采集的出现 (#709)
1、避免不同集群,相同的ZK地址时,指标重复获取的情况;
2、避免集群某个ZK地址获取指标失败时,下一个周期还会继续尝试从该地址获取指标;
2022-10-21 11:26:07 +08:00
_haoqi
4510c62ebd [ISSUE #677] 重启会导致部分信息采集抛出空指针 2022-10-20 15:36:32 +08:00
zengqiao
79864955e1 [Feature] 集群Group列表按照Group维度进行展示 (#580) 2022-10-20 13:29:43 +08:00
Richard
ff26a8d46c fix issue:
* [issue #700] Adjust the prompt and replace the Arrays.asList() with the Collections.singletonList()
2022-10-19 15:19:43 +08:00
dianyang12138
cc226d552e fix:修复es模版错误 2022-10-19 11:44:00 +08:00
EricZeng
962f89475b Merge pull request #699 from silent-night-no-trace/dev
[ISSUE #683]  fix ldap bug
2022-10-19 10:23:47 +08:00
night.liang
ec204a1605 fix ldap bug 2022-10-18 20:16:40 +08:00
早晚会起风
58d7623938 Merge pull request #696 from chenzhongyu11/dev
[ISSUE #672] 修复健康巡检结果时间展示错误的问题
2022-10-18 10:41:47 +08:00
EricZeng
8f4ecfcdc0 Merge pull request #691 from didi/dev
补充Kafka-Group表
2022-10-17 20:30:32 +08:00
zengqiao
ef719cedbc 补充Kafka-Group表 2022-10-17 10:34:21 +08:00
EricZeng
b7856c892b Merge pull request #690 from didi/master
合并默认分支
2022-10-17 10:30:18 +08:00
EricZeng
7435a78883 Merge pull request #689 from didi/dev
优化健康检查结果替换时出现死锁问题
2022-10-17 10:26:11 +08:00
chenzy
f49206b316 修复时间展示有误的bug,由原先的12小时制改为24小时制 2022-10-16 22:57:50 +08:00
EricZeng
7d500a0721 Merge pull request #684 from RichardZhengkay/dev
fix issue: [#662]
2022-10-15 14:39:37 +08:00
EricZeng
98a519f20b Merge pull request #682 from haoqi123/fix_678
[ISSUE #678] zk-Latency avg为多位小数会抛出空指针
2022-10-15 14:17:23 +08:00
Richard
39b655bb43 fix issue:
* [issue #662] Fix deadlocks caused by adding data using MySQL's REPLACE method
2022-10-14 14:03:16 +08:00
_haoqi
78d56a49fe 修改zk-Latency avg为小数时的数值转换异常问题 2022-10-14 11:53:48 +08:00
EricZeng
d2e9d1fa01 Merge pull request #673 from didi/dev
fix [ISSUE-666] Error in ks_km_zookeeper table role type #666
2022-10-13 18:57:06 +08:00
zengqiao
41ff914dc3 修复ZK元信息表role字段类型错误问题 2022-10-13 18:50:41 +08:00
shirenchuang
3ba447fac2 update readme 2022-10-13 18:49:06 +08:00
shirenchuang
e9cc380a2e update readme 2022-10-13 18:30:13 +08:00
EricZeng
017cac9bbe Merge pull request #670 from RichardZhengkay/dev
fix issue: [#666]
2022-10-13 18:25:15 +08:00
Richard
9ad72694af fix issue:
* [issue #666] Fix the type of role phase in ks_km_zookeeper table
2022-10-13 18:00:43 +08:00
shirenchuang
e8f9821870 Merge remote-tracking branch 'origin/master' 2022-10-13 16:31:03 +08:00
shirenchuang
bb167b9f8d update readme 2022-10-13 15:31:34 +08:00
石臻臻的杂货铺
28fbb5e130 Merge pull request #665 from zwOvO/patch-1
[ISSUE #664]关于'JMX-连接失败问题解决'的超链接修复
2022-10-13 10:17:29 +08:00
EricZeng
16101e81e8 Merge pull request #661 from didi/dev
合并开发分支
2022-10-13 10:16:14 +08:00
赤月
aced504d2a Update faq.md 2022-10-12 22:08:29 +08:00
shirenchuang
abb064d9d1 update readme add who's using know streaming 2022-10-12 19:15:19 +08:00
zengqiao
dc1899a1cd 修复集群ZK列表中缺少返回服务状态字段的问题 2022-10-12 16:45:47 +08:00
zengqiao
442f34278c 指标信息中,增加返回ZK的指标信息 2022-10-12 16:44:07 +08:00
zengqiao
a6dcbcd35b 删除未被使用的import 2022-10-12 16:43:16 +08:00
zengqiao
2b600e96eb 健康检查任务优化 2022-10-12 16:41:27 +08:00
zengqiao
177bb80f31 application.yml文件中增加ES用户名密码的配置项 2022-10-12 16:36:04 +08:00
zengqiao
63fbe728c4 增加ZK指标上报普罗米修斯 2022-10-12 11:11:25 +08:00
EricZeng
b33020840b ZookeeperService中增加服务存活统计方法(#659) 2022-10-12 11:07:52 +08:00
zengqiao
c5caf7c0d6 ZookeeperService中增加服务存活统计方法 2022-10-12 11:02:41 +08:00
EricZeng
0f0473db4c 增加float转integer方法(#658)
增加float转integer方法
2022-10-12 10:09:16 +08:00
zengqiao
beadde3e06 增加float转integer方法 2022-10-11 18:46:16 +08:00
EricZeng
a423a20480 修复获取TopN的Broker指标时,会出现部分指标缺失的问题(#657)
修复获取TopN的Broker指标时,会出现部分指标缺失的问题
2022-10-11 18:44:02 +08:00
shirenchuang
79f0a23813 update contribuer document 2022-10-11 17:38:15 +08:00
zengqiao
780fdea2cc 修复获取TopN的Broker指标时,会出现部分指标缺失的问题 2022-10-11 16:54:39 +08:00
shirenchuang
1c0fda1adf Merge remote-tracking branch 'origin/master' 2022-10-11 10:39:08 +08:00
EricZeng
9cf13e9b30 Broker增加服务是否存活接口(#654)
Broker增加服务是否存活接口
2022-10-10 19:56:12 +08:00
zengqiao
87cd058fd8 Broker增加服务是否存活接口 2022-10-10 19:54:47 +08:00
EricZeng
81b1ec48c2 调整贡献者名单(#653)
调整贡献者名单
2022-10-10 19:52:50 +08:00
zengqiao
66dd82f4fd 调整贡献者名单 2022-10-10 19:49:22 +08:00
EricZeng
ce35b23911 修复DSL错误导致ZK指标查询失败问题(#652)
修复DSL错误导致ZK指标查询失败问题
2022-10-10 19:27:48 +08:00
zengqiao
e79342acf5 修复DSL错误导致ZK指标查询失败问题 2022-10-10 19:19:05 +08:00
EricZeng
3fc9f39d24 Merge pull request #651 from didi/master
合并主分支
2022-10-10 19:10:48 +08:00
shirenchuang
0221fb3a4a 贡献者相关文档 2022-10-10 18:02:19 +08:00
shirenchuang
f009f8b7ba 贡献者相关文档 2022-10-10 17:21:21 +08:00
shirenchuang
b76959431a 贡献者相关文档 2022-10-10 16:55:33 +08:00
shirenchuang
975370b593 贡献者相关文档 2022-10-10 15:57:07 +08:00
shirenchuang
7275030971 贡献者相关文档 2022-10-10 15:50:16 +08:00
shirenchuang
99b0be5a95 Merge branch 'master' into docs_only 2022-10-10 15:01:00 +08:00
石臻臻的杂货铺
edd3f95fc4 Update CONTRIBUTING.md 2022-10-10 14:22:24 +08:00
石臻臻的杂货铺
479f983b09 Update CONTRIBUTING.md 2022-10-10 13:58:35 +08:00
石臻臻的杂货铺
7650332252 Update CONTRIBUTING.md 2022-10-10 13:50:55 +08:00
shirenchuang
8f1a021851 readme 2022-10-10 13:46:14 +08:00
shirenchuang
ce4df4d5fd Merge remote-tracking branch 'origin/master' 2022-10-10 13:00:28 +08:00
shirenchuang
bd43ae1b5d Issue 模板 2022-10-10 12:57:53 +08:00
石臻臻的杂货铺
8fa34116b9 Merge pull request #648 from didi/docs_only
PR 模板
2022-10-10 12:39:38 +08:00
shirenchuang
7e92553017 PR 模板 2022-10-10 11:42:04 +08:00
shirenchuang
b7e243a693 Merge remote-tracking branch 'origin/master' 2022-10-09 17:23:16 +08:00
shirenchuang
35d4888afb 贡献者规约文档 2022-10-09 17:03:46 +08:00
EricZeng
b3e8a4f0f6 Merge pull request #647 from didi/dev
合并DEV分支
2022-10-09 16:54:45 +08:00
shirenchuang
321125caee issue template 2022-10-09 15:47:13 +08:00
shirenchuang
e01427aa4f issue template 2022-10-09 15:42:40 +08:00
shirenchuang
14652e7f7a issue template 2022-10-09 15:39:20 +08:00
shirenchuang
7c05899dbd issue template 2022-10-09 15:26:57 +08:00
shirenchuang
56726b703f issue template 2022-10-09 13:56:44 +08:00
shirenchuang
6237b0182f issue template 2022-10-09 12:27:27 +08:00
EricZeng
be5b662f65 Merge pull request #645 from didi/dev_feature_zk_kerberos
如何修改代码支持ZK-Kerberos认证
2022-10-09 10:39:26 +08:00
EricZeng
224698355c 恢复为原先代码
恢复为原先代码
2022-10-09 10:38:36 +08:00
EricZeng
8f47138ecd Merge pull request #643 from didi/dev_3.1
监控Kafka的ZK
2022-10-08 17:22:03 +08:00
zengqiao
d159746391 调整接入带Kerberos认证的ZK集群的文档 2022-10-08 17:00:08 +08:00
EricZeng
63df93ea5e Merge pull request #608 from luhea/dev_feature_zk_kerberos
Add zk supported kerberos
2022-10-08 16:11:37 +08:00
EricZeng
38948c0daa Merge pull request #644 from didi/master
合并主分支
2022-10-08 16:09:40 +08:00
zengqiao
6c610427b6 ZK-增加ZK信息查询接口 2022-10-08 15:46:18 +08:00
zengqiao
b4cc31c459 ZK-指标采集入ES 2022-10-08 15:31:59 +08:00
zengqiao
7d781712c9 ZK-同步ZK元信息至DB 2022-10-08 15:19:09 +08:00
zengqiao
dd61ce9b2a ZK-增加配置的默认值 2022-10-08 14:58:28 +08:00
zengqiao
69a7212986 ZK-增加四字命令信息的获取 2022-10-08 14:52:17 +08:00
EricZeng
ff05a951fd Merge pull request #642 from didi/master
合并主分支
2022-10-08 14:42:37 +08:00
EricZeng
89d5357b40 Merge pull request #641 from didi/dev
删除无效的健康分计算代码
2022-10-08 14:41:27 +08:00
zengqiao
7ca3d65c42 删除无效的健康分计算代码 2022-10-08 14:15:20 +08:00
zengqiao
7b5c2d800f bump version to 3.1.0 2022-09-29 15:13:41 +08:00
EricZeng
f414b47a78 1、补充升级至v3.0.0信息;2、增加v3.0.0变更内容;(#636)
1、补充升级至v3.0.0信息;2、增加v3.0.0变更内容;(#)
2022-09-29 13:08:32 +08:00
EricZeng
44f4e2f0f9 Merge pull request #635 from didi/dev
合并前端调整的内容
2022-09-29 11:50:25 +08:00
zengqiao
2361008bdf Merge branch 'dev' of github.com:didi/KnowStreaming into dev 2022-09-29 11:49:00 +08:00
zengqiao
7377ef3ec5 增加v3.0.0变更内容 2022-09-29 11:45:29 +08:00
lucasun
a28d064b7a Merge pull request #634 from GraceWalk/dev
前端 bug 修复 & 问题优化
2022-09-29 11:23:25 +08:00
GraceWalk
e2e57e8575 fix: 依赖版本更新 2022-09-29 11:15:47 +08:00
zengqiao
9d90bd2835 补充升级至v3.0.0信息 2022-09-29 11:04:49 +08:00
EricZeng
7445e68df4 Merge pull request #632 from didi/master
合并主分支
2022-09-29 10:53:54 +08:00
GraceWalk
ab42625ad2 fix: 数字展示格式化 2022-09-29 10:52:31 +08:00
GraceWalk
18789a0a53 fix: IconFont 组件改为从独立包引入 2022-09-29 10:51:52 +08:00
zengqiao
68a37bb56a Merge branch 'master' of github.com:didi/KnowStreaming 2022-09-29 10:49:46 +08:00
GraceWalk
3b33652c47 fix: Rebalance 卡片 icon 颜色调整 2022-09-29 10:48:52 +08:00
GraceWalk
1e0c4c3904 feat: Topic 详情消息 Value 列支持复制 2022-09-29 10:48:09 +08:00
zengqiao
04e223de16 修改协议文案 2022-09-29 10:48:00 +08:00
GraceWalk
c4a691aa8a fix: 多集群列表兼容集群无 ZK 情况 2022-09-29 10:44:28 +08:00
GraceWalk
ff9dde163a feat: 图表支持存储拖拽排序 & 补点逻辑优化 2022-09-29 10:42:44 +08:00
EricZeng
eb7efbd1a5 增加字段校验注解(#631)
增加字段校验注解(#631)
2022-09-29 09:59:02 +08:00
zengqiao
8c8c362c54 Merge branch 'dev' of github.com:didi/KnowStreaming into dev 2022-09-28 20:19:35 +08:00
zengqiao
66e119ad5d 增加字段校验注解 2022-09-28 20:16:06 +08:00
EricZeng
6dedc04a05 Merge pull request #630 from didi/dev
合并开发分支
2022-09-28 20:14:51 +08:00
EricZeng
0cf8bad0df Merge pull request #629 from didi/master
合并主分支
2022-09-28 20:06:26 +08:00
zengqiao
95c9582d8b 优化消费组详情指标为实时获取 2022-09-28 20:03:23 +08:00
EricZeng
7815126ff5 1、修复Group指标防重复不生效问题;2、修复自动创建ES索引模版失败问题; (#628)
* 修复自动创建ES索引模版失败问题

* 修复Group指标防重复不生效问题

Co-authored-by: zengqiao <zengqiao@didiglobal.com>
2022-09-28 19:55:30 +08:00
zengqiao
a5fa9de54b 修复Group指标防重复不生效问题 2022-09-28 19:52:11 +08:00
zengqiao
95f1a2c630 修复自动创建ES索引模版失败问题 2022-09-28 19:46:07 +08:00
zengqiao
1e256ae1fd 修复自动创建ES索引模版失败问题 2022-09-28 19:44:33 +08:00
zengqiao
9fc9c54fa1 bump version to 3.0.0 2022-09-28 11:20:16 +08:00
zengqiao
1b362b1e02 Merge branch 'master' of github.com:didi/KnowStreaming 2022-09-28 11:16:54 +08:00
EricZeng
04e3172cca [ISSUE-624]过滤掉不存在的Topic(#625)
[ISSUE-624]过滤掉不存在的Topic(#625)
2022-09-28 11:13:15 +08:00
EricZeng
1caab7f3f7 [ISSUE-624]过滤掉不存在的Topic(#624)
[ISSUE-624]过滤掉不存在的Topic(#624)
2022-09-28 10:41:39 +08:00
zengqiao
9d33c725ad [ISSUE-624]过滤掉不存在的Topic(#624)
同步Group元信息时,如果Topic已经不存在了,则过滤掉该Group+Topic信息
2022-09-28 10:39:33 +08:00
EricZeng
6ed1d38106 [ISSUE-598]Fix start_time not set when create reassign job in MySQL-8 (#623)
[ISSUE-598]Fix start_time not set when create reassign job in MySQL-8 (#623 )
2022-09-28 10:26:56 +08:00
zengqiao
0f07ddedaf [ISSUE-598]Fix start_time not set when create reassign job in MySQL-8 2022-09-28 10:24:32 +08:00
EricZeng
289945b471 Merge pull request #622 from didi/dev
后端补充Kafka集群运行模式字段信息
2022-09-28 10:08:17 +08:00
zengqiao
f331a6d144 后端补充Kafka集群运行模式字段信息 2022-09-27 18:43:22 +08:00
EricZeng
0c8c12a651 Merge pull request #621 from didi/dev
指标发送ES类按照指标类别拆分
2022-09-27 18:38:05 +08:00
zengqiao
028c3bb2fa 指标发送ES类按照指标类别拆分 2022-09-27 10:19:18 +08:00
EricZeng
d7a5a0d405 健康巡检任务按照类型进行拆分
健康巡检任务按照类型进行拆分
2022-09-27 10:17:12 +08:00
zengqiao
5ef5f6e531 健康巡检任务按照类型进行拆分 2022-09-26 20:10:49 +08:00
EricZeng
1d205734b3 Merge pull request #619 from didi/dev
集群信息中,补充ZK配置字段
2022-09-26 19:50:26 +08:00
Peng
5edd43884f Update README.md 2022-09-26 18:43:25 +08:00
zengqiao
c1992373bc 集群信息中,补充ZK配置字段 2022-09-26 11:10:38 +08:00
EricZeng
ed562f9c8a Merge pull request #618 from didi/dev
DB中Group信息的更新方式,由replace调整为insert或update
2022-09-26 10:02:24 +08:00
zengqiao
b4d44ef8c7 DB中Group信息的更新方式,由replace调整为insert或update 2022-09-23 17:02:25 +08:00
EricZeng
ad0c16a1b4 升级Helm版本及增加Docker相关文件
升级Helm版本及增加Docker相关文件
2022-09-23 16:17:00 +08:00
wangdongfang-aden
7eabe66853 Merge pull request #616 from wangdongfang-aden/dev
添加docker-compose部署和更新helm
2022-09-23 14:50:22 +08:00
wangdongfang-aden
3983d73695 Update Chart.yaml 2022-09-23 14:47:40 +08:00
wangdongfang-aden
161d4c4562 Update 单机部署手册.md 2022-09-23 14:46:27 +08:00
wangdongfang-aden
9a1e89564e Update 单机部署手册.md 2022-09-23 14:44:49 +08:00
wangdongfang-aden
0c18c5b4f6 Update 单机部署手册.md 2022-09-23 14:43:23 +08:00
wangdongfang-aden
3e12ba34f7 Update docker-compose.yml 2022-09-23 14:33:05 +08:00
wangdongfang-aden
e71e29391b Delete ks-start.sh 2022-09-23 14:26:24 +08:00
wangdongfang-aden
9b7b9a7af0 Delete es_template_create.sh 2022-09-23 14:26:16 +08:00
wangdongfang-aden
a23819c308 Create ks-start.sh 2022-09-23 14:19:35 +08:00
wangdongfang-aden
6cb1825d96 Create es_template_create.sh 2022-09-23 14:19:10 +08:00
wangdongfang-aden
77b8c758dc Create initsql 2022-09-23 14:18:17 +08:00
wangdongfang-aden
e5a582cfad Create my.cnf 2022-09-23 14:17:25 +08:00
wangdongfang-aden
ec83db267e Create init.sh 2022-09-23 14:17:02 +08:00
wangdongfang-aden
bfd026cae7 Create dockerfile 2022-09-23 14:16:28 +08:00
wangdongfang-aden
35f1dd8082 Create dockerfile 2022-09-23 14:14:47 +08:00
wangdongfang-aden
7ed0e7dd23 Create dockerfile 2022-09-23 14:14:02 +08:00
wangdongfang-aden
1a3cbf7a9d Create knowstreaming.conf 2022-09-23 14:07:04 +08:00
wangdongfang-aden
d9e4abc3de Create ks-start.sh 2022-09-23 14:05:59 +08:00
wangdongfang-aden
a4186085d3 Create es_template_create.sh 2022-09-23 14:05:05 +08:00
wangdongfang-aden
26b1846bb4 Create docker-compose.yml 2022-09-23 14:03:14 +08:00
wangdongfang-aden
1aa89527a6 helm update 3.0.0-beta.3 2022-09-23 11:36:46 +08:00
wangdongfang-aden
eac76d7ad0 helm update 3.0.0-beta.3 2022-09-23 11:36:01 +08:00
wangdongfang-aden
cea0cd56f6 Merge pull request #607 from haoqi123/dev
[单机部署手册.md]docker-compose部署方式添加注释描述
2022-09-23 10:27:04 +08:00
EricZeng
c4b897f282 bump version to 3.0.0-beta.4
bump version to 3.0.0-beta.4
2022-09-23 10:24:52 +08:00
zengqiao
47389dbabb bump version to 3.0.0-beta.4 2022-09-23 10:17:58 +08:00
haoqi
a2f8b1a851 1. [单机部署手册.md]docker-compose部署方式添加注释描述 2022-09-22 19:46:21 +08:00
EricZeng
feac0a058f Merge pull request #613 from didi/dev
补充v3.0.0-beta.2变更信息
2022-09-22 17:30:35 +08:00
zengqiao
27eeac9fd4 补充v3.0.0-beta.2变更信息 2022-09-22 17:28:51 +08:00
EricZeng
a14db4b194 Merge pull request #612 from didi/dev
合并开发分支
2022-09-22 17:28:09 +08:00
lucasun
54ee271a47 Merge pull request #611 from GraceWalk/dev
修复前端bug和体验问题
2022-09-22 15:51:46 +08:00
GraceWalk
a3a9be4f7f fix: 更正前端本地环境接口代理地址 2022-09-22 15:37:24 +08:00
GraceWalk
d4f0a832f3 fix: 样式更新 2022-09-22 15:31:52 +08:00
GraceWalk
7dc533372c fix: 更正文件引用路径 2022-09-22 15:31:34 +08:00
GraceWalk
1737d87713 fix: 修复配置无法删除的问题 2022-09-22 15:31:13 +08:00
GraceWalk
dbb98dea11 fix: 更新登录页图片 2022-09-22 15:21:04 +08:00
GraceWalk
802b382b36 fix: Topic Messages 详情提示优化 2022-09-22 15:20:31 +08:00
GraceWalk
fc82999d45 fix: 消费测试 Message 限制最大值 2022-09-22 15:19:56 +08:00
GraceWalk
08aa000c07 refactor: 接入/编辑集群优化 2022-09-22 15:19:03 +08:00
GraceWalk
39015b5100 feat: 多集群管理列表页增加手动刷新功能 2022-09-22 15:18:13 +08:00
GraceWalk
0d635ad419 refactor: webpack 配置结构调整 2022-09-22 15:13:25 +08:00
EricZeng
9133205915 Merge pull request #610 from didi/dev
合并开发分支
2022-09-22 14:51:23 +08:00
zengqiao
725ac10c3d 1、调整KafkaZKDao位置;2、offset信息获取时,过滤掉无leader分区;3、调整验证ZK是否合法时的session超时时间 2022-09-22 11:30:46 +08:00
zengqiao
2b76358c8f Overview页面,后端增加排序信息 2022-09-22 11:24:13 +08:00
zengqiao
833c360698 bump oshi-core version to 5.6.1 2022-09-22 11:17:59 +08:00
zengqiao
7da1e67b01 FAQ补充权限识别失败问题说明 2022-09-22 11:13:54 +08:00
GraceWalk
7eb86a47dd fix: 部分依赖更新 2022-09-21 16:22:45 +08:00
GraceWalk
d67e383c28 feat: 系统管理列表增加手动刷新功能 2022-09-21 16:21:57 +08:00
GraceWalk
8749d3e1f5 fix: config 子应用 axios 配置错误兼容 2022-09-21 16:21:07 +08:00
GraceWalk
30fba21c48 fix: 生产测试单词发送消息数限制为 0~1000 2022-09-21 16:15:19 +08:00
GraceWalk
d83d35aee9 fix: 样式 & 文案优化 2022-09-21 16:12:13 +08:00
GraceWalk
1d3caeea7d feat: Cluster 图表去掉放大功能 2022-09-21 16:11:14 +08:00
luhe
c8806dbb4d 修改代码支持ZK-Kerberos认证与配置文档 2022-09-21 16:09:04 +08:00
luhe
e5802c7f50 修改代码支持ZK-Kerberos认证与配置文档 2022-09-21 16:02:38 +08:00
luhe
590f684d66 修改代码支持ZK-Kerberos认证与配置文档 2022-09-21 15:59:31 +08:00
luhe
8e5a67f565 修改代码支持ZK-Kerberos认证 2022-09-21 15:58:59 +08:00
luhe
8d2fbce11e 修改代码支持ZK-Kerberos认证 2022-09-21 15:54:30 +08:00
haoqi
26916f6632 1. [单机部署手册.md]docker-compose部署方式添加注释描述
2. 更改docker-compose中ui对外访问port为80
2022-09-21 12:55:43 +08:00
EricZeng
fbfa0d2d2a Merge pull request #600 from haoqi123/dev
docker-compose addition
2022-09-21 10:49:08 +08:00
haoqi
e626b99090 1. 删除km-dist/docker文件夹,以[单机部署手册.md]为准 2022-09-20 19:30:20 +08:00
haoqi123
203859b71b Merge branch 'didi:dev' into dev 2022-09-20 19:25:12 +08:00
haoqi
9a25c22f3a 1. 调整docker-compose.yml中各个服务的镜像
2. 经过@wangdongfang-aden大哥的调试将helm与docker镜像合二为一,于是删减掉各个镜像的Dockerfile与启动脚本,后续也不需要额外维护
2022-09-20 19:23:18 +08:00
zengqiao
0a03f41a7c 后端增加指标摆放顺序功能 2022-09-20 14:42:22 +08:00
zengqiao
56191939c8 Merge branch 'dev' of github.com:didi/KnowStreaming into dev 2022-09-20 14:23:09 +08:00
zengqiao
beb754aaaa 修复JMX连接被关闭,抛出IOException后,未进行连接重建的问题 2022-09-20 14:22:06 +08:00
EricZeng
f234f740ca Merge pull request #603 from didi/dev
合并开发分支
2022-09-20 10:51:39 +08:00
EricZeng
e14679694c Merge pull request #602 from f1558/dev
fix issue
2022-09-20 10:31:16 +08:00
zengqiao
e06712397e 修复因DB中Broker信息不存在导致TotalLogSize指标获取时抛空指针问题 2022-09-20 10:27:30 +08:00
Richard
b6c6df7ffc fix issue
* SQL specification comments to avoid direct operation failure
2022-09-20 09:42:42 +08:00
zengqiao
375c6f56c9 修改GroupOffsetResetEnum类名为OffsetTypeEnum 2022-09-19 13:55:59 +08:00
EricZeng
0bf85c97b5 Merge pull request #555 from superspeedone/dev
Dev
2022-09-19 11:18:28 +08:00
EricZeng
630e582321 Merge pull request #593 from Mengqi777/mengqi-dev
fix: adjust os judgment method with uname
2022-09-19 10:34:16 +08:00
EricZeng
a89fe23bdd Merge pull request #597 from WYAOBO/dev
文档更新
2022-09-19 10:15:38 +08:00
haoqi
a7a5fa9a31 1. 调整docker-compose.yml中networks配置
2. ks-manager添加健康检查
3. 更新单机部署手册
2022-09-18 19:10:22 +08:00
_haoqi
c73a7eee2f 1. 调整docker-compose服务,容器名称 2022-09-16 20:03:58 +08:00
_haoqi
121f8468d5 1. 调整文件格式LF
2. 调整docker-compose服务,容器名称
2022-09-16 17:33:19 +08:00
haoqi
7b0b6936e0 1. 调整docker-compose.yml中容器名称 2022-09-16 15:54:34 +08:00
Peng
597ea04a96 Update README.md 2022-09-16 15:20:04 +08:00
Peng
f7f90aeaaa Update README.md 2022-09-16 15:18:29 +08:00
_haoqi
227479f695 1. 修改dockerfile
2. 删除无用配置文件
2022-09-16 15:13:18 +08:00
WYAOBO
6477fb3fe0 Merge branch 'didi:dev' into dev 2022-09-16 14:50:13 +08:00
wangdongfang-aden
4223f4f3c4 Merge pull request #596 from wangdongfang-aden/dev
helm update 3.0.0-beta.2
2022-09-16 14:45:43 +08:00
wangdongfang-aden
7288874d72 helm update 3.0.0-beta.2 2022-09-16 14:44:14 +08:00
wangdongfang-aden
68f76f2daf helm update 3.0.0-beta.2 2022-09-16 14:42:34 +08:00
wyb
fe6ddebc49 文档更新 2022-09-16 14:41:45 +08:00
wangdongfang-aden
12b5acd073 helm update 3.0.0-beta.2 2022-09-16 14:41:40 +08:00
wangdongfang-aden
a6f1fe07b3 helm update 3.0.0-beta.2 2022-09-16 14:41:02 +08:00
wangdongfang-aden
85e3f2a946 helm update 3.0.0-beta.2 2022-09-16 14:40:34 +08:00
pokemeng
d4f416de14 fix: adjust os judgment method with uname 2022-09-16 11:34:03 +08:00
haoqi
0d9a6702c1 1. 更改es初始化脚本输出追加为重定向 2022-09-15 17:13:58 +08:00
haoqi
d11285cdbf Merge branch 'master' into dev
# Conflicts:
#	km-dist/init/sql/ddl-logi-security.sql
2022-09-15 17:01:39 +08:00
EricZeng
5f1f33d2b9 Merge pull request #591 from didi/master
合并主分支
2022-09-15 16:59:11 +08:00
zengqiao
474daf752d bump version to 3.0.0-beta.3 2022-09-15 16:54:52 +08:00
haoqi
27d1b92690 1. 添加init容器,只用于初始化es索引 2022-09-15 16:22:51 +08:00
haoqi
792f8d939d 1. 更改Dockerfile 2022-09-15 15:06:19 +08:00
haoqi
0c14c641d0 1. 添加docker-compose部署方式
2. 更改manage服务初始化方式
3. 更改es初始化方式
2022-09-15 14:26:45 +08:00
haoqi
61efdf492f 添加docker-compose部署方式 2022-09-13 23:20:41 +08:00
superspeedone
405e6e0c1d Topic消息查询支持Timestamp排序,接口支持按指定日期查询 2022-09-09 18:56:45 +08:00
superspeedone
0d227aef49 Topic消息查询支持Timestamp排序,接口支持按指定日期查询 2022-09-09 17:29:22 +08:00
superspeedone
0e49002f42 Topic消息查询支持Timestamp排序,接口支持按指定日期查询 2022-09-09 15:45:31 +08:00
superspeedone
8e50d145d5 Topic消息查询支持Timestamp排序,支持查询最新消息或最早消息 #534 2022-09-07 11:17:59 +08:00
superspeedone
0f35427645 Merge branch 'dev' of https://github.com/superspeedone/KnowStreaming into dev 2022-09-05 15:41:08 +08:00
yanweiwen
fa7ad64140 Topic消息查询支持Timestamp排序,支持查询最新消息或最早消息 #534 2022-09-05 14:46:40 +08:00
1120 changed files with 145 additions and 132872 deletions

51
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -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 : <font size=4 color =red> xxx </font>
* Operating System version : <font size=4 color =red> xxx </font>
* Java version : <font size=4 color =red> xxx </font>
### 重现该问题的步骤
1. xxx
2. xxx
3. xxx
### 预期结果
<!-- 写下应该出现的预期结果?-->
### 实际结果
<!-- 实际发生了什么? -->
---
如果有异常请附上异常Trace:
```
Just put your stack trace here!
```

8
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -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

View File

@@ -0,0 +1,26 @@
---
name: 优化建议
about: 相关功能优化建议
title: ''
labels: Optimization Suggestions
assignees: ''
---
- [ ] 我已经在 [issues](https://github.com/didi/KnowStreaming/issues) 搜索过相关问题了,并没有重复的。
你是否希望来认领这个优化建议。
「 Y / N 」
### 环境信息
* KnowStreaming version : <font size=4 color =red> xxx </font>
* Operating System version : <font size=4 color =red> xxx </font>
* Java version : <font size=4 color =red> xxx </font>
### 需要优化的功能点
### 建议如何优化

View File

@@ -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 」
## 这里描述需求
<!--请尽可能的描述清楚您的需求 -->

12
.github/ISSUE_TEMPLATE/question.md vendored Normal file
View File

@@ -0,0 +1,12 @@
---
name: 提个问题
about: 问KnowStreaming相关问题
title: ''
labels: question
assignees: ''
---
- [ ] 我已经在 [issues](https://github.com/didi/KnowStreaming/issues) 搜索过相关问题了,并没有重复的。
## 在这里提出你的问题

23
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,23 @@
请不要在没有先创建Issue的情况下创建Pull Request。
## 变更的目的是什么
XXXXX
## 简短的更新日志
XX
## 验证这一变化
XXXX
请遵循此清单,以帮助我们快速轻松地整合您的贡献:
* [ ] 一个 PRPull Request的简写只解决一个问题禁止一个 PR 解决多个问题;
* [ ] 确保 PR 有对应的 Issue通常在您开始处理之前创建除非是书写错误之类的琐碎更改不需要 Issue
* [ ] 格式化 PR 及 Commit-Log 的标题及内容,例如 #861 。PSCommit-Log 需要在 Git Commit 代码时进行填写,在 GitHub 上修改不了;
* [ ] 编写足够详细的 PR 描述,以了解 PR 的作用、方式和原因;
* [ ] 编写必要的单元测试来验证您的逻辑更正。如果提交了新功能或重大更改,请记住在 test 模块中添加 integration-test
* [ ] 确保编译通过,集成测试通过;

6
.gitignore vendored
View File

@@ -109,4 +109,8 @@ out/*
dist/ dist/
dist/* dist/*
km-rest/src/main/resources/templates/ km-rest/src/main/resources/templates/
*dependency-reduced-pom* *dependency-reduced-pom*
#filter flattened xml
*/.flattened-pom.xml
.flattened-pom.xml
*/*/.flattened-pom.xml

View File

@@ -1,28 +0,0 @@
# 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.
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.
NOTE: We assume all your contribution can be licensed under the [Apache License 2.0](LICENSE).
## Issues
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.

BIN
KS-PRD-3.0-beta1.docx Normal file

Binary file not shown.

BIN
KS-PRD-3.0-beta2.docx Normal file

Binary file not shown.

BIN
KS-PRD-3.1-ZK.docx Normal file

Binary file not shown.

BIN
KS-PRD-3.2-Connect.docx Normal file

Binary file not shown.

BIN
KS-PRD-3.3-MM2.docx Normal file

Binary file not shown.

139
README.md
View File

@@ -1,139 +0,0 @@
<p align="center">
<img src="https://user-images.githubusercontent.com/71620349/185368586-aed82d30-1534-453d-86ff-ecfa9d0f35bd.png" width = "256" div align=center />
</p>
<p align="center">
<a href="https://knowstreaming.com">产品官网</a> |
<a href="https://github.com/didi/KnowStreaming/releases">下载地址</a> |
<a href="https://doc.knowstreaming.com/product">文档资源</a> |
<a href="https://demo.knowstreaming.com">体验环境</a>
</p>
<p align="center">
<!--最近一次提交时间-->
<a href="https://img.shields.io/github/last-commit/didi/KnowStreaming">
<img src="https://img.shields.io/github/last-commit/didi/KnowStreaming" alt="LastCommit">
</a>
<!--最新版本-->
<a href="https://github.com/didi/KnowStreaming/blob/master/LICENSE">
<img src="https://img.shields.io/github/v/release/didi/KnowStreaming" alt="License">
</a>
<!--License信息-->
<a href="https://github.com/didi/KnowStreaming/blob/master/LICENSE">
<img src="https://img.shields.io/github/license/didi/KnowStreaming" alt="License">
</a>
<!--Open-Issue-->
<a href="https://github.com/didi/KnowStreaming/issues">
<img src="https://img.shields.io/github/issues-raw/didi/KnowStreaming" alt="Issues">
</a>
<!--知识星球-->
<a href="https://z.didi.cn/5gSF9">
<img src="https://img.shields.io/badge/join-%E7%9F%A5%E8%AF%86%E6%98%9F%E7%90%83-red" alt="Slack">
</a>
</p>
---
## `Know Streaming` 简介
`Know Streaming`是一套云原生的Kafka管控平台脱胎于众多互联网内部多年的Kafka运营实践经验专注于Kafka运维管控、监控告警、资源治理、多活容灾等核心场景。在用户体验、监控、运维管控上进行了平台化、可视化、智能化的建设提供一系列特色的功能极大地方便了用户和运维人员的日常使用让普通运维人员都能成为Kafka专家。整体具有以下特点
- 👀 &nbsp;**零侵入、全覆盖**
- 无需侵入改造 `Apache Kafka` ,一键便能纳管 `0.10.x` ~ `3.x.x` 众多版本的Kafka包括 `ZK``Raft` 运行模式的版本,同时在兼容架构上具备良好的扩展性,帮助您提升集群管理水平;
- 🌪️ &nbsp;**零成本、界面化**
- 提炼高频 CLI 能力,设计合理的产品路径,提供清新美观的 GUI 界面,支持 Cluster、Broker、Topic、Group、Message、ACL 等组件 GUI 管理普通用户5分钟即可上手
- 👏 &nbsp;**云原生、插件化**
- 基于云原生构建,具备水平扩展能力,只需要增加节点即可获取更强的采集及对外服务能力,提供众多可热插拔的企业级特性,覆盖可观测性生态整合、资源治理、多活容灾等核心场景;
- 🚀 &nbsp;**专业能力**
- 集群管理:支持集群一键纳管,健康分析、核心组件观测 等功能;
- 观测提升:多维度指标观测大盘、观测指标最佳实践 等功能;
- 异常巡检:集群多维度健康巡检、集群多维度健康分 等功能;
- 能力增强Topic扩缩副本、Topic副本迁移 等功能;
&nbsp;
**产品图**
<p align="center">
<img src="http://img-ys011.didistatic.com/static/dc2img/do1_sPmS4SNLX9m1zlpmHaLJ" width = "768" height = "473" div align=center />
</p>
## 文档资源
**`开发相关手册`**
- [打包编译手册](docs/install_guide/源码编译打包手册.md)
- [单机部署手册](docs/install_guide/单机部署手册.md)
- [版本升级手册](docs/install_guide/版本升级手册.md)
- [本地源码启动手册](docs/dev_guide/本地源码启动手册.md)
**`产品相关手册`**
- [产品使用指南](docs/user_guide/用户使用手册.md)
- [2.x与3.x新旧对比手册](docs/user_guide/新旧对比手册.md)
- [FAQ](docs/user_guide/faq.md)
**点击 [这里](https://doc.knowstreaming.com/product),也可以从官网获取到更多文档**
## 成为社区贡献者
点击 [这里](CONTRIBUTING.md),了解如何成为 Know Streaming 的贡献者
## 加入技术交流群
**`1、知识星球`**
<p align="left">
<img src="https://user-images.githubusercontent.com/71620349/185357284-fdff1dad-c5e9-4ddf-9a82-0be1c970980d.JPG" height = "180" div align=left />
</p>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
👍 我们正在组建国内最大,最权威的 **[Kafka中文社区](https://z.didi.cn/5gSF9)**
在这里你可以结交各大互联网的 Kafka大佬 以及 4000+ Kafka爱好者一起实现知识共享实时掌控最新行业资讯期待 👏 &nbsp; 您的加入中~ https://z.didi.cn/5gSF9
有问必答~ 互动有礼~
PS: 提问请尽量把问题一次性描述清楚,并告知环境信息情况~!如使用版本、操作步骤、报错/警告信息等方便大V们快速解答
&nbsp;
**`2、微信群`**
微信加群:添加`mike_zhangliang``PenceXie`的微信号备注KnowStreaming加群。
## Star History
[![Star History Chart](https://api.star-history.com/svg?repos=didi/KnowStreaming&type=Date)](https://star-history.com/#didi/KnowStreaming&Date)

View File

@@ -1,335 +0,0 @@
## v3.0.0-beta.2
**文档**
- 新增登录系统对接文档
- 优化前端工程打包构建部分文档说明
- FAQ补充KnowStreaming连接特定JMX IP的说明
**Bug修复**
- 修复logi_security_oplog表字段过短导致删除Topic等操作无法记录的问题
- 修复ES查询时抛java.lang.NumberFormatException: For input string: "{"value":0,"relation":"eq"}" 问题
- 修复LogStartOffset和LogEndOffset指标单位错误问题
- 修复进行副本变更时旧副本数为NULL的问题
- 修复集群Group列表在第二页搜索时搜索时返回的分页信息错误问题
- 修复重置Offset时返回的错误信息提示不一致的问题
- 修复集群查看系统查看LoadRebalance等页面权限点缺失问题
- 修复查询不存在的Topic时错误信息提示不明显的问题
- 修复Windows用户打包前端工程报错的问题
- package-lock.json锁定前端依赖版本号修复因依赖自动升级导致打包失败等问题
- 系统管理子应用补充后端返回的Code码拦截解决后端接口返回报错不展示的问题
- 修复用户登出后,依旧可以访问系统的问题
- 修复巡检任务配置时,数值显示错误的问题
- 修复Broker/Topic Overview 图表和图表详情问题
- 修复Job扩缩副本任务明细数据错误的问题
- 修复重置Offset时分区IDOffset数值无限制问题
- 修复扩缩/迁移副本时无法选中Kafka系统Topic的问题
- 修复Topic的Config页面编辑表单时不能正确回显当前值的问题
- 修复Broker Card返回数据后依旧展示加载态的问题
**体验优化**
- 优化默认用户密码为 admin/admin
- 缩短新增集群后,集群信息加载的耗时
- 集群Broker列表增加Controller角色信息
- 副本变更任务结束后,增加进行优先副本选举的操作
- Task模块任务分为Metrics、Common、Metadata三类任务每类任务配备独立线程池减少对Job模块的线程池以及不同类任务之间的相互影响
- 删除代码中存在的多余无用文件
- 自动新增ES索引模版及近7天索引减少用户搭建时需要做的事项
- 优化前端工程打包流程
- 优化登录页文案页面左侧栏内容单集群详情样式Topic列表趋势图等
- 首次进入Broker/Topic图表详情时进行预缓存数据从而优化体验
- 优化Topic详情Partition Tab的展示
- 多集群列表页增加编辑功能
- 优化副本变更时,迁移时间支持分钟级别粒度
- logi-security版本升级至2.10.13
- logi-elasticsearch-client版本升级至1.0.24
**能力提升**
- 支持Ldap登录认证
---
## v3.0.0-beta.1
**文档**
- 新增Task模块说明文档
- FAQ补充 `Specified key was too long; max key length is 767 bytes ` 错误说明
- FAQ补充 `出现ESIndexNotFoundException报错` 错误说明
**Bug修复**
- 修复 Consumer 点击 Stop 未停止检索的问题
- 修复创建/编辑角色权限报错问题
- 修复多集群管理/单集群详情均衡卡片状态错误问题
- 修复版本列表未排序问题
- 修复Raft集群Controller信息不断记录问题
- 修复部分版本消费组描述信息获取失败问题
- 修复分区Offset获取失败的日志中缺少Topic名称信息问题
- 修复GitHub图地址错误及图裂问题
- 修复Broker默认使用的地址和注释不一致问题
- 修复 Consumer 列表分页不生效问题
- 修复操作记录表operation_methods字段缺少默认值问题
- 修复集群均衡表中move_broker_list字段无效的问题
- 修复KafkaUser、KafkaACL信息获取时日志一直重复提示不支持问题
- 修复指标缺失时,曲线出现掉底的问题
**体验优化**
- 优化前端构建时间和打包体积,增加依赖打包的分包策略
- 优化产品样式和文案展示
- 优化ES客户端数为可配置
- 优化日志中大量出现的MySQL Key冲突日志
**能力提升**
- 增加周期任务用于主动创建缺少的ES模版及索引的能力减少额外的脚本操作
- 增加JMX连接的Broker地址可选择的能力
---
## v3.0.0-beta.0
**1、多集群管理**
- 增加健康监测体系、关键组件&指标 GUI 展示
- 增加 2.8.x 以上 Kafka 集群接入,覆盖 0.10.x-3.x
- 删除逻辑集群、共享集群、Region 概念
**2、Cluster 管理**
- 增加集群概览信息、集群配置变更记录
- 增加 Cluster 健康分,健康检查规则支持自定义配置
- 增加 Cluster 关键指标统计和 GUI 展示,支持自定义配置
- 增加 Cluster 层 I/O、Disk 的 Load Reblance 功能,支持定时均衡任务(企业版)
- 删除限流、鉴权功能
- 删除 APPID 概念
**3、Broker 管理**
- 增加 Broker 健康分
- 增加 Broker 关键指标统计和 GUI 展示,支持自定义配置
- 增加 Broker 参数配置功能,需重启生效
- 增加 Controller 变更记录
- 增加 Broker Datalogs 记录
- 删除 Leader Rebalance 功能
- 删除 Broker 优先副本选举
**4、Topic 管理**
- 增加 Topic 健康分
- 增加 Topic 关键指标统计和 GUI 展示,支持自定义配置
- 增加 Topic 参数配置功能,可实时生效
- 增加 Topic 批量迁移、Topic 批量扩缩副本功能
- 增加查看系统 Topic 功能
- 优化 Partition 分布的 GUI 展示
- 优化 Topic Message 数据采样
- 删除 Topic 过期概念
- 删除 Topic 申请配额功能
**5、Consumer 管理**
- 优化了 ConsumerGroup 展示形式,增加 Consumer Lag 的 GUI 展示
**6、ACL 管理**
- 增加原生 ACL GUI 配置功能,可配置生产、消费、自定义多种组合权限
- 增加 KafkaUser 功能,可自定义新增 KafkaUser
**7、消息测试企业版**
- 增加生产者消息模拟器,支持 Data、Flow、Header、Options 自定义配置(企业版)
- 增加消费者消息模拟器,支持 Data、Flow、Header、Options 自定义配置(企业版)
**8、Job**
- 优化 Job 模块,支持任务进度管理
**9、系统管理**
- 优化用户、角色管理体系,支持自定义角色配置页面及操作权限
- 优化审计日志信息
- 删除多租户体系
- 删除工单流程
---
## v2.6.0
版本上线时间2022-01-24
### 能力提升
- 增加简单回退工具类
### 体验优化
- 补充周期任务说明文档
- 补充集群安装部署使用说明文档
- 升级Swagger、SpringFramework、SpringBoot、EChats版本
- 优化Task模块的日志输出
- 优化corn表达式解析失败后退出无任何日志提示问题
- Ldap用户接入时增加部门及邮箱信息等
- 对Jmx模块增加连接失败后的回退机制及错误日志优化
- 增加线程池、客户端池可配置
- 删除无用的jmx_prometheus_javaagent-0.14.0.jar
- 优化迁移任务名称
- 优化创建Region时Region容量信息不能立即被更新问题
- 引入lombok
- 更新视频教程
- 优化kcm_script.sh脚本中的LogiKM地址为可通过程序传入
- 第三方接口及网关接口,增加是否跳过登录的开关
- extends模块相关配置调整为非必须在application.yml中配置
### bug修复
- 修复批量往DB写入空指标数组时报SQL语法异常的问题
- 修复网关增加配置及修改配置时version不变化问题
- 修复集群列表页,提示框遮挡问题
- 修复对高版本Broker元信息协议解析失败的问题
- 修复Dockerfile执行时提示缺少application.yml文件的问题
- 修复逻辑集群更新时,会报空指针的问题
## v2.5.0
版本上线时间2021-07-10
### 体验优化
- 更改产品名为LogiKM
- 更新产品图标
## v2.4.1+
版本上线时间2021-05-21
### 能力提升
- 增加直接增加权限和配额的接口(v2.4.1)
- 增加接口调用可绕过登录的功能(v2.4.1)
### 体验优化
- Tomcat 版本提升至8.5.66(v2.4.2)
- op接口优化拆分util接口为topic、leader两类接口(v2.4.1)
- 简化Gateway配置的Key长度(v2.4.1)
### bug修复
- 修复页面展示版本错误问题(v2.4.2)
## v2.4.0
版本上线时间2021-05-18
### 能力提升
- 增加App与Topic自动化审批开关
- Broker元信息中增加Rack信息
- 升级MySQL 驱动支持MySQL 8+
- 增加操作记录查询界面
### 体验优化
- FAQ告警组说明优化
- 用户手册共享及 独享集群概念优化
- 用户管理界面,前端限制用户删除自己
### bug修复
- 修复op-util类中创建Topic失败的接口
- 周期同步Topic到DB的任务修复将Topic列表查询从缓存调整为直接查DB
- 应用下线审批失败的功能修复将权限为0(无权限)的数据进行过滤
- 修复登录及权限绕过的漏洞
- 修复研发角色展示接入集群、暂停监控等按钮的问题
## v2.3.0
版本上线时间2021-02-08
### 能力提升
- 新增支持docker化部署
- 可指定Broker作为候选controller
- 可新增并管理网关配置
- 可获取消费组状态
- 增加集群的JMX认证
### 体验优化
- 优化编辑用户角色、修改密码的流程
- 新增consumerID的搜索功能
- 优化“Topic连接信息”、“消费组重置消费偏移”、“修改Topic保存时间”的文案提示
- 在相应位置增加《资源申请文档》链接
### bug修复
- 修复Broker监控图表时间轴展示错误的问题
- 修复创建夜莺监控告警规则时,使用的告警周期的单位不正确的问题
## v2.2.0
版本上线时间2021-01-25
### 能力提升
- 优化工单批量操作流程
- 增加获取Topic75分位/99分位的实时耗时数据
- 增加定时任务可将无主未落DB的Topic定期写入DB
### 体验优化
- 在相应位置增加《集群接入文档》链接
- 优化物理集群、逻辑集群含义
- 在Topic详情页、Topic扩分区操作弹窗增加展示Topic所属Region的信息
- 优化Topic审批时Topic数据保存时间的配置流程
- 优化Topic/应用申请、审批时的错误提示文案
- 优化Topic数据采样的操作项文案
- 优化运维人员删除Topic时的提示文案
- 优化运维人员删除Region的删除逻辑与提示文案
- 优化运维人员删除逻辑集群的提示文案
- 优化上传集群配置文件时的文件类型限制条件
### bug修复
- 修复填写应用名称时校验特殊字符出错的问题
- 修复普通用户越权访问应用详情的问题
- 修复由于Kafka版本升级导致的数据压缩格式无法获取的问题
- 修复删除逻辑集群或Topic之后界面依旧展示的问题
- 修复进行Leader rebalance操作时执行结果重复提示的问题
## v2.1.0
版本上线时间2020-12-19
### 体验优化
- 优化页面加载时的背景样式
- 优化普通用户申请Topic权限的流程
- 优化Topic申请配额、申请分区的权限限制
- 优化取消Topic权限的文案提示
- 优化申请配额表单的表单项名称
- 优化重置消费偏移的操作流程
- 优化创建Topic迁移任务的表单内容
- 优化Topic扩分区操作的弹窗界面样式
- 优化集群Broker监控可视化图表样式
- 优化创建逻辑集群的表单内容
- 优化集群安全协议的提示文案
### bug修复
- 修复偶发性重置消费偏移失败的问题

View File

@@ -1,655 +0,0 @@
esaddr=127.0.0.1
port=8060
curl -s --connect-timeout 10 -o /dev/null http://${esaddr}:${port}/_cat/nodes >/dev/null 2>&1
if [ "$?" != "0" ];then
echo "Elasticserach 访问失败, 请安装完后检查并重新执行该脚本 "
exit
fi
curl -s --connect-timeout 10 -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: application/json' http://${esaddr}:${port}/_template/ks_kafka_broker_metric -d '{
"order" : 10,
"index_patterns" : [
"ks_kafka_broker_metric*"
],
"settings" : {
"index" : {
"number_of_shards" : "10"
}
},
"mappings" : {
"properties" : {
"brokerId" : {
"type" : "long"
},
"routingValue" : {
"type" : "text",
"fields" : {
"keyword" : {
"ignore_above" : 256,
"type" : "keyword"
}
}
},
"clusterPhyId" : {
"type" : "long"
},
"metrics" : {
"properties" : {
"NetworkProcessorAvgIdle" : {
"type" : "float"
},
"UnderReplicatedPartitions" : {
"type" : "float"
},
"BytesIn_min_15" : {
"type" : "float"
},
"HealthCheckTotal" : {
"type" : "float"
},
"RequestHandlerAvgIdle" : {
"type" : "float"
},
"connectionsCount" : {
"type" : "float"
},
"BytesIn_min_5" : {
"type" : "float"
},
"HealthScore" : {
"type" : "float"
},
"BytesOut" : {
"type" : "float"
},
"BytesOut_min_15" : {
"type" : "float"
},
"BytesIn" : {
"type" : "float"
},
"BytesOut_min_5" : {
"type" : "float"
},
"TotalRequestQueueSize" : {
"type" : "float"
},
"MessagesIn" : {
"type" : "float"
},
"TotalProduceRequests" : {
"type" : "float"
},
"HealthCheckPassed" : {
"type" : "float"
},
"TotalResponseQueueSize" : {
"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,
"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_cluster_metric -d '{
"order" : 10,
"index_patterns" : [
"ks_kafka_cluster_metric*"
],
"settings" : {
"index" : {
"number_of_shards" : "10"
}
},
"mappings" : {
"properties" : {
"routingValue" : {
"type" : "text",
"fields" : {
"keyword" : {
"ignore_above" : 256,
"type" : "keyword"
}
}
},
"clusterPhyId" : {
"type" : "long"
},
"metrics" : {
"properties" : {
"Connections" : {
"type" : "double"
},
"BytesIn_min_15" : {
"type" : "double"
},
"PartitionURP" : {
"type" : "double"
},
"HealthScore_Topics" : {
"type" : "double"
},
"EventQueueSize" : {
"type" : "double"
},
"ActiveControllerCount" : {
"type" : "double"
},
"GroupDeads" : {
"type" : "double"
},
"BytesIn_min_5" : {
"type" : "double"
},
"HealthCheckTotal_Topics" : {
"type" : "double"
},
"Partitions" : {
"type" : "double"
},
"BytesOut" : {
"type" : "double"
},
"Groups" : {
"type" : "double"
},
"BytesOut_min_15" : {
"type" : "double"
},
"TotalRequestQueueSize" : {
"type" : "double"
},
"HealthCheckPassed_Groups" : {
"type" : "double"
},
"TotalProduceRequests" : {
"type" : "double"
},
"HealthCheckPassed" : {
"type" : "double"
},
"TotalLogSize" : {
"type" : "double"
},
"GroupEmptys" : {
"type" : "double"
},
"PartitionNoLeader" : {
"type" : "double"
},
"HealthScore_Brokers" : {
"type" : "double"
},
"Messages" : {
"type" : "double"
},
"Topics" : {
"type" : "double"
},
"PartitionMinISR_E" : {
"type" : "double"
},
"HealthCheckTotal" : {
"type" : "double"
},
"Brokers" : {
"type" : "double"
},
"Replicas" : {
"type" : "double"
},
"HealthCheckTotal_Groups" : {
"type" : "double"
},
"GroupRebalances" : {
"type" : "double"
},
"MessageIn" : {
"type" : "double"
},
"HealthScore" : {
"type" : "double"
},
"HealthCheckPassed_Topics" : {
"type" : "double"
},
"HealthCheckTotal_Brokers" : {
"type" : "double"
},
"PartitionMinISR_S" : {
"type" : "double"
},
"BytesIn" : {
"type" : "double"
},
"BytesOut_min_5" : {
"type" : "double"
},
"GroupActives" : {
"type" : "double"
},
"MessagesIn" : {
"type" : "double"
},
"GroupReBalances" : {
"type" : "double"
},
"HealthCheckPassed_Brokers" : {
"type" : "double"
},
"HealthScore_Groups" : {
"type" : "double"
},
"TotalResponseQueueSize" : {
"type" : "double"
},
"Zookeepers" : {
"type" : "double"
},
"LeaderMessages" : {
"type" : "double"
},
"HealthScore_Cluster" : {
"type" : "double"
},
"HealthCheckPassed_Cluster" : {
"type" : "double"
},
"HealthCheckTotal_Cluster" : {
"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" : { }
}'
curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: application/json' http://${esaddr}:${port}/_template/ks_kafka_group_metric -d '{
"order" : 10,
"index_patterns" : [
"ks_kafka_group_metric*"
],
"settings" : {
"index" : {
"number_of_shards" : "10"
}
},
"mappings" : {
"properties" : {
"group" : {
"type" : "keyword"
},
"partitionId" : {
"type" : "long"
},
"routingValue" : {
"type" : "text",
"fields" : {
"keyword" : {
"ignore_above" : 256,
"type" : "keyword"
}
}
},
"clusterPhyId" : {
"type" : "long"
},
"topic" : {
"type" : "keyword"
},
"metrics" : {
"properties" : {
"HealthScore" : {
"type" : "float"
},
"Lag" : {
"type" : "float"
},
"OffsetConsumed" : {
"type" : "float"
},
"HealthCheckTotal" : {
"type" : "float"
},
"HealthCheckPassed" : {
"type" : "float"
}
}
},
"groupMetric" : {
"type" : "keyword"
},
"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,
"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_partition_metric -d '{
"order" : 10,
"index_patterns" : [
"ks_kafka_partition_metric*"
],
"settings" : {
"index" : {
"number_of_shards" : "10"
}
},
"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,
"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_replication_metric -d '{
"order" : 10,
"index_patterns" : [
"ks_kafka_partition_metric*"
],
"settings" : {
"index" : {
"number_of_shards" : "10"
}
},
"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,
"type" : "date",
"doc_values" : true
}
}
},
"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,
"index_patterns" : [
"ks_kafka_topic_metric*"
],
"settings" : {
"index" : {
"number_of_shards" : "10"
}
},
"mappings" : {
"properties" : {
"brokerId" : {
"type" : "long"
},
"routingValue" : {
"type" : "text",
"fields" : {
"keyword" : {
"ignore_above" : 256,
"type" : "keyword"
}
}
},
"topic" : {
"type" : "keyword"
},
"clusterPhyId" : {
"type" : "long"
},
"metrics" : {
"properties" : {
"BytesIn_min_15" : {
"type" : "float"
},
"Messages" : {
"type" : "float"
},
"BytesRejected" : {
"type" : "float"
},
"PartitionURP" : {
"type" : "float"
},
"HealthCheckTotal" : {
"type" : "float"
},
"ReplicationCount" : {
"type" : "float"
},
"ReplicationBytesOut" : {
"type" : "float"
},
"ReplicationBytesIn" : {
"type" : "float"
},
"FailedFetchRequests" : {
"type" : "float"
},
"BytesIn_min_5" : {
"type" : "float"
},
"HealthScore" : {
"type" : "float"
},
"LogSize" : {
"type" : "float"
},
"BytesOut" : {
"type" : "float"
},
"BytesOut_min_15" : {
"type" : "float"
},
"FailedProduceRequests" : {
"type" : "float"
},
"BytesIn" : {
"type" : "float"
},
"BytesOut_min_5" : {
"type" : "float"
},
"MessagesIn" : {
"type" : "float"
},
"TotalProduceRequests" : {
"type" : "float"
},
"HealthCheckPassed" : {
"type" : "float"
}
}
},
"brokerAgg" : {
"type" : "keyword"
},
"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,
"type" : "date",
"doc_values" : true
}
}
},
"aliases" : { }
}'
for i in {0..6};
do
logdate=_$(date -d "${i} day ago" +%Y-%m-%d)
curl -s --connect-timeout 10 -o /dev/null -X PUT http://${esaddr}:${port}/ks_kafka_broker_metric${logdate} && \
curl -s -o /dev/null -X PUT http://${esaddr}:${port}/ks_kafka_cluster_metric${logdate} && \
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_topic_metric${logdate} || \
exit 2
done

View File

@@ -1,16 +0,0 @@
#!/bin/bash
cd `dirname $0`/../libs
target_dir=`pwd`
pid=`ps ax | grep -i 'ks-km' | grep ${target_dir} | grep java | grep -v grep | awk '{print $1}'`
if [ -z "$pid" ] ; then
echo "No ks-km running."
exit -1;
fi
echo "The ks-km (${pid}) is running..."
kill ${pid}
echo "Send shutdown request to ks-km (${pid}) OK"

View File

@@ -1,82 +0,0 @@
error_exit ()
{
echo "ERROR: $1 !!"
exit 1
}
[ ! -e "$JAVA_HOME/bin/java" ] && JAVA_HOME=$HOME/jdk/java
[ ! -e "$JAVA_HOME/bin/java" ] && JAVA_HOME=/usr/java
[ ! -e "$JAVA_HOME/bin/java" ] && unset JAVA_HOME
if [ -z "$JAVA_HOME" ]; then
if $darwin; then
if [ -x '/usr/libexec/java_home' ] ; then
export JAVA_HOME=`/usr/libexec/java_home`
elif [ -d "/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home" ]; then
export JAVA_HOME="/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home"
fi
else
JAVA_PATH=`dirname $(readlink -f $(which javac))`
if [ "x$JAVA_PATH" != "x" ]; then
export JAVA_HOME=`dirname $JAVA_PATH 2>/dev/null`
fi
fi
if [ -z "$JAVA_HOME" ]; then
error_exit "Please set the JAVA_HOME variable in your environment, We need java(x64)! jdk8 or later is better!"
fi
fi
export WEB_SERVER="ks-km"
export JAVA_HOME
export JAVA="$JAVA_HOME/bin/java"
export BASE_DIR=`cd $(dirname $0)/..; pwd`
export CUSTOM_SEARCH_LOCATIONS=file:${BASE_DIR}/conf/
#===========================================================================================
# JVM Configuration
#===========================================================================================
JAVA_OPT="${JAVA_OPT} -server -Xms2g -Xmx2g -Xmn1g -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=320m"
JAVA_OPT="${JAVA_OPT} -XX:-OmitStackTraceInFastThrow -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${BASE_DIR}/logs/java_heapdump.hprof"
## jdk版本高的情况 有些 参数废弃了
JAVA_MAJOR_VERSION=$($JAVA -version 2>&1 | sed -E -n 's/.* version "([0-9]*).*$/\1/p')
if [[ "$JAVA_MAJOR_VERSION" -ge "9" ]] ; then
JAVA_OPT="${JAVA_OPT} -Xlog:gc*:file=${BASE_DIR}/logs/km_gc.log:time,tags:filecount=10,filesize=102400"
else
JAVA_OPT="${JAVA_OPT} -Djava.ext.dirs=${JAVA_HOME}/jre/lib/ext:${JAVA_HOME}/lib/ext"
JAVA_OPT="${JAVA_OPT} -Xloggc:${BASE_DIR}/logs/km_gc.log -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M"
fi
JAVA_OPT="${JAVA_OPT} -jar ${BASE_DIR}/libs/${WEB_SERVER}.jar"
JAVA_OPT="${JAVA_OPT} --spring.config.additional-location=${CUSTOM_SEARCH_LOCATIONS}"
JAVA_OPT="${JAVA_OPT} --logging.config=${BASE_DIR}/conf/logback-spring.xml"
JAVA_OPT="${JAVA_OPT} --server.max-http-header-size=524288"
if [ ! -d "${BASE_DIR}/logs" ]; then
mkdir ${BASE_DIR}/logs
fi
echo "$JAVA ${JAVA_OPT}"
# check the start.out log output file
if [ ! -f "${BASE_DIR}/logs/start.out" ]; then
touch "${BASE_DIR}/logs/start.out"
fi
# start
echo -e "---- 启动脚本 ------\n $JAVA ${JAVA_OPT}" > ${BASE_DIR}/logs/start.out 2>&1 &
nohup $JAVA ${JAVA_OPT} >> ${BASE_DIR}/logs/start.out 2>&1 &
echo "${WEB_SERVER} is startingyou can check the ${BASE_DIR}/logs/start.out"

View File

@@ -1,264 +0,0 @@
# Task模块简介
## 1、Task简介
在 KnowStreaming 中(下面简称KS)Task模块主要是用于执行一些周期任务包括Cluster、Broker、Topic等指标的定时采集集群元数据定时更新至DB集群状态的健康巡检等。在KS中与Task模块相关的代码我们都统一存放在km-task模块中。
Task模块是基于 LogiCommon 中的Logi-Job组件实现的任务周期执行Logi-Job 的功能类似 XXX-Job它是 XXX-Job 在 KnowStreaming 的内嵌实现,主要用于简化 KnowStreaming 的部署。
Logi-Job 的任务总共有两种执行模式,分别是:
+ 广播模式同一KS集群下同一任务周期中所有KS主机都会执行该定时任务。
+ 抢占模式同一KS集群下同一任务周期中仅有某一台KS主机会执行该任务。
KS集群范围定义连接同一个DB且application.yml中的spring.logi-job.app-name的名称一样的KS主机为同一KS集群。
## 2、使用指南
Task模块基于Logi-Job的广播模式与抢占模式分别实现了任务的抢占执行、重复执行以及均衡执行他们之间的差别是
+ 抢占执行同一个KS集群同一个任务执行周期中仅有一台KS主机执行该任务
+ 重复执行同一个KS集群同一个任务执行周期中所有KS主机都执行该任务。比如3台KS主机3个Kafka集群此时每台KS主机都会去采集这3个Kafka集群的指标
+ 均衡执行同一个KS集群同一个任务执行周期中每台KS主机仅执行该任务的一部分所有的KS主机共同协作完成了任务。比如3台KS主机3个Kafka集群稳定运行情况下每台KS主机将仅采集1个Kafka集群的指标3台KS主机共同完成3个Kafka集群指标的采集。
下面我们看一下具体例子。
### 2.1、抢占模式——抢占执行
功能说明:
+ 同一个KS集群同一个任务执行周期中仅有一台KS主机执行该任务。
代码例子:
```java
// 1、实现Job接口重写excute方法
// 2、在类上添加@Task注解并且配置好信息指定为随机抢占模式
// 效果KS集群中每5秒会有一台KS主机输出 "测试定时任务运行中"
@Task(name = "TestJob",
description = "测试定时任务",
cron = "*/5 * * * * ?",
autoRegister = true,
consensual = ConsensualEnum.RANDOM, // 这里一定要设置为RANDOM
timeout = 6 * 60)
public class TestJob implements Job {
@Override
public TaskResult execute(JobContext jobContext) throws Exception {
System.out.println("测试定时任务运行中");
return new TaskResult();
}
}
```
### 2.2、广播模式——重复执行
功能说明:
+ 同一个KS集群同一个任务执行周期中所有KS主机都执行该任务。比如3台KS主机3个Kafka集群此时每台KS主机都会去重复采集这3个Kafka集群的指标。
代码例子:
```java
// 1、实现Job接口重写excute方法
// 2、在类上添加@Task注解并且配置好信息指定为广播抢占模式
// 效果KS集群中每5秒每台KS主机都会输出 "测试定时任务运行中"
@Task(name = "TestJob",
description = "测试定时任务",
cron = "*/5 * * * * ?",
autoRegister = true,
consensual = ConsensualEnum.BROADCAST, // 这里一定要设置为BROADCAST
timeout = 6 * 60)
public class TestJob implements Job {
@Override
public TaskResult execute(JobContext jobContext) throws Exception {
System.out.println("测试定时任务运行中");
return new TaskResult();
}
}
```
### 2.3、广播模式——均衡执行
功能说明:
+ 同一个KS集群同一个任务执行周期中每台KS主机仅执行该任务的一部分所有的KS主机共同协作完成了任务。比如3台KS主机3个Kafka集群稳定运行情况下每台KS主机将仅采集1个Kafka集群的指标3台KS主机共同完成3个Kafka集群指标的采集。
代码例子:
+ 该模式有点特殊是KS基于Logi-Job的广播模式做的一个扩展以下为一个使用例子
```java
// 1、继承AbstractClusterPhyDispatchTask实现processSubTask方法
// 2、在类上添加@Task注解并且配置好信息指定为广播模式
// 效果在本样例中每隔1分钟ks会将所有的kafka集群列表在ks集群主机内均衡拆分每台主机会将分发到自身的Kafka集群依次执行processSubTask方法,实现KS集群的任务协同处理。
@Task(name = "kmJobTask",
description = "km job 模块调度执行任务",
cron = "0 0/1 * * * ? *",
autoRegister = true,
consensual = ConsensualEnum.BROADCAST,
timeout = 6 * 60)
public class KMJobTask extends AbstractClusterPhyDispatchTask {
@Autowired
private JobService jobService;
@Override
protected TaskResult processSubTask(ClusterPhy clusterPhy, long triggerTimeUnitMs) throws Exception {
jobService.scheduleJobByClusterId(clusterPhy.getId());
return TaskResult.SUCCESS;
}
}
```
## 3、原理简介
### 3.1、Task注解说明
```java
public @interface Task {
String name() default ""; //任务名称
String description() default ""; //任务描述
String owner() default "system"; //拥有者
String cron() default ""; //定时执行的时间策略
int retryTimes() default 0; //失败以后所能重试的最大次数
long timeout() default 0; //在超时时间里重试
//是否自动注册任务到数据库中
//如果设置为false需要手动去数据库km_task表注册定时任务信息。数据库记录和@Task注解缺一不可
boolean autoRegister() default false;
//执行模式:广播、随机抢占
//广播模式:同一集群下的所有服务器都会执行该定时任务
//随机抢占模式:同一集群下随机一台服务器执行该任务
ConsensualEnum consensual() default ConsensualEnum.RANDOM;
}
```
### 3.2、数据库表介绍
+ logi_task记录项目中的定时任务信息一个定时任务对应一条记录。
+ logi_job具体任务执行信息。
+ logi_job_log定时任务的执行日志。
+ logi_worker记录机器信息实现集群控制。
### 3.3、均衡执行简介
#### 3.3.1、类关系图
这里以KMJobTask为例简单介绍KM中的定时任务实现逻辑。
![img](http://img-ys011.didistatic.com/static/dc2img/do1_knC85EtQ8Vbn1BcBzcjz)
+ Job使用logi组件实现定时任务必须实现该接口。
+ Comparable & EntufyIdInterface比较接口实现任务的排序逻辑。
+ AbstractDispatchTask实现广播模式下任务的均衡分发。
+ AbstractClusterPhyDispatchTask对分发到当前服务器的集群列表进行枚举。
+ KMJobTask:实现对单个集群的定时任务处理。
#### 3.3.2、关键类代码
+ **AbstractDispatchTask类**
```java
// 实现Job接口的抽象类进行任务的负载均衡执行
public abstract class AbstractDispatchTask<E extends Comparable & EntifyIdInterface> implements Job {
// 罗列所有的任务
protected abstract List<E> listAllTasks();
// 执行被分配给该KS主机的任务
protected abstract TaskResult processTask(List<E> subTaskList, long triggerTimeUnitMs);
// 被Logi-Job触发执行该方法
// 该方法进行任务的分配
@Override
public TaskResult execute(JobContext jobContext) {
try {
long triggerTimeUnitMs = System.currentTimeMillis();
// 获取所有的任务
List<E> allTaskList = this.listAllTasks();
// 计算当前KS机器需要执行的任务
List<E> subTaskList = this.selectTask(allTaskList, jobContext.getAllWorkerCodes(), jobContext.getCurrentWorkerCode());
// 进行任务处理
return this.processTask(subTaskList, triggerTimeUnitMs);
} catch (Exception e) {
// ...
}
}
}
```
+ **AbstractClusterPhyDispatchTask类**
```java
// 继承AbstractDispatchTask的抽象类对Kafka集群进行负载均衡执行
public abstract class AbstractClusterPhyDispatchTask extends AbstractDispatchTask<ClusterPhy> {
// 执行被分配的任务,具体由子类实现
protected abstract TaskResult processSubTask(ClusterPhy clusterPhy, long triggerTimeUnitMs) throws Exception;
// 返回所有的Kafka集群
@Override
public List<ClusterPhy> listAllTasks() {
return clusterPhyService.listAllClusters();
}
// 执行被分配给该KS主机的Kafka集群任务
@Override
public TaskResult processTask(List<ClusterPhy> subTaskList, long triggerTimeUnitMs) { // ... }
}
```
+ **KMJobTask类**
```java
// 加上@Task注解并配置任务执行信息
@Task(name = "kmJobTask",
description = "km job 模块调度执行任务",
cron = "0 0/1 * * * ? *",
autoRegister = true,
consensual = ConsensualEnum.BROADCAST,
timeout = 6 * 60)
// 继承AbstractClusterPhyDispatchTask类
public class KMJobTask extends AbstractClusterPhyDispatchTask {
@Autowired
private JobService jobService;
// 执行该Kafka集群的Job模块的任务
@Override
protected TaskResult processSubTask(ClusterPhy clusterPhy, long triggerTimeUnitMs) throws Exception {
jobService.scheduleJobByClusterId(clusterPhy.getId());
return TaskResult.SUCCESS;
}
}
```
#### 3.3.3、均衡执行总结
均衡执行的实现原理总结起来就是以下几点:
+ Logi-Job设置为广播模式触发所有的KS主机执行任务
+ 每台KS主机被触发执行后按照统一的规则对任务列表KS集群主机列表进行排序。然后按照顺序将任务列表均衡的分配给排序后的KS集群主机。KS集群稳定运行情况下这一步保证了每台KS主机之间分配到的任务列表不重复不丢失。
+ 最后每台KS主机执行被分配到的任务。
## 4、注意事项
+ 不能100%保证任务在一个周期内且仅且执行一次可能出现重复执行或丢失的情况所以必须严格是且仅且执行一次的任务不建议基于Logi-Job进行任务控制。
+ 尽量让Logi-Job仅负责任务的触发后续的执行建议放到自己创建的线程池中进行。

Binary file not shown.

Before

Width:  |  Height:  |  Size: 382 KiB

View File

@@ -1,43 +0,0 @@
## 4.2、Kafka 多版本兼容方案
&emsp;&emsp;当前 KnowStreaming 支持纳管多个版本的 kafka 集群,由于不同版本的 kafka 在指标采集、接口查询、行为操作上有些不一致,因此 KnowStreaming 需要一套机制来解决多 kafka 版本的纳管兼容性问题。
### 4.2.1、整体思路
&emsp;&emsp;由于需要纳管多个 kafka 版本,而且未来还可能会纳管非 kafka 官方的版本kafka 的版本号会存在着多种情况所以首先要明确一个核心思想KnowStreaming 提供尽可能多的纳管能力,但是不提供无限的纳管能力,每一个版本的 KnowStreaming 只纳管其自身声明的 kafka 版本,后续随着 KnowStreaming 自身版本的迭代,会逐步支持更多 kafka 版本的纳管接入。
### 4.2.2、构建版本兼容列表
&emsp;&emsp;每一个版本的 KnowStreaming 都声明一个自身支持纳管的 kafka 版本列表,并且对 kafka 的版本号进行归一化处理,后续所有 KnowStreaming 对不同 kafka 集群的操作都和这个集群对应的版本号严格相关。
&emsp;&emsp;KnowStreaming 对外提供自身所支持的 kafka 版本兼容列表,用以声明自身支持的版本范围。
&emsp;&emsp;对于在集群接入过程中,如果希望接入当前 KnowStreaming 不支持的 kafka 版本的集群KnowStreaming 建议在于的过程中选择相近的版本号接入。
### 4.2.3、构建版本兼容性字典
&emsp;&emsp;在构建了 KnowStreaming 支持的 kafka 版本列表的基础上KnowStreaming 在实现过程中,还会声明自身支持的所有兼容性,构建兼容性字典。
&emsp;&emsp;当前 KnowStreaming 支持的 kafka 版本兼容性字典包括三个维度:
- 指标采集:同一个指标在不同 kafka 版本下可能获取的方式不一样,不同版本的 kafka 可能会有不同的指标,因此对于指标采集的处理需要构建兼容性字典。
- kafka api同一个 kafka 的操作处理的方式在不同 kafka 版本下可能存在不一致topic 的创建,因此 KnowStreaming 针对不同 kafka-api 的处理需要构建兼容性字典。
- 平台操作KnowStreaming 在接入不同版本的 kafka 集群的时候,在平台页面上会根据不同的 kafka 版。
兼容性字典的核心设计字段如下:
| 兼容性维度 | 兼容项名称 | 最小 Kafka 版本号(归一化) | 最大 Kafka 版本号(归一化) | 处理器 |
| ---------- | ---------- | --------------------------- | --------------------------- | ------ |
KS-KM 根据其需要纳管的 kafka 版本,按照上述三个维度构建了完善了兼容性字典。
### 4.2.4、兼容性问题
&emsp;&emsp;KS-KM 的每个版本针对需要纳管的 kafka 版本列表,事先分析各个版本的差异性和产品需求,同时 KS-KM 构建了一套专门处理兼容性的服务,来进行兼容性的注册、字典构建、处理器分发等操作,其中版本兼容性处理器是来具体处理不同 kafka 版本差异性的地方。
![registerHandler](http://img-ys011.didistatic.com/static/dc2img/do1_WxVTzndYE59ah5DFrMfn)
&emsp;&emsp;如上图所示KS-KM 的 topic 服务在面对不同 kafka 版本时,其 topic 的创建、删除、扩容由于 kafka 版本自身的差异,导致 KnowStreaming 的处理也不一样,所以需要根据不同的 kafka 版本来实现不同的兼容性处理器,同时向 KnowStreaming 的兼容服务进行兼容性的注册,构建兼容性字典,后续在 KnowStreaming 的运行过程中,针对不同的 kafka 版本即可分发到不同的处理器中执行。
&emsp;&emsp;后续随着 KnowStreaming 产品的发展,如果有新的兼容性的地方需要增加,只需要实现新版本的处理器,增加注册项即可。

View File

@@ -1,152 +0,0 @@
## 3.3、指标说明
当前 KnowStreaming 支持针对 kafka 集群的多维度指标的采集和展示,同时也支持多个 kafka 版本的指标进行兼容,以下是 KnowStreaming 支持的指标说明。
现在对当前 KnowStreaming 支持的指标从指标名称、指标单位、指标说明、kafka 版本、企业/开源版指标 五个维度进行说明。
### 3.3.1、Cluster 指标
| 指标名称 | 指标单位 | 指标含义 | kafka 版本 | 企业/开源版指标 |
| ------------------------- | -------- | ------------------------------------ | ---------------- | --------------- |
| HealthScore | 分 | 集群总体的健康分 | 全部版本 | 开源版 |
| HealthCheckPassed | 个 | 集群总体健康检查通过数 | 全部版本 | 开源版 |
| HealthCheckTotal | 个 | 集群总体健康检查总数 | 全部版本 | 开源版 |
| HealthScore_Topics | 分 | 集群 Topics 的健康分 | 全部版本 | 开源版 |
| HealthCheckPassed_Topics | 个 | 集群 Topics 健康检查通过数 | 全部版本 | 开源版 |
| HealthCheckTotal_Topics | 个 | 集群 Topics 健康检查总数 | 全部版本 | 开源版 |
| HealthScore_Brokers | 分 | 集群 Brokers 的健康分 | 全部版本 | 开源版 |
| HealthCheckPassed_Brokers | 个 | 集群 Brokers 健康检查通过数 | 全部版本 | 开源版 |
| HealthCheckTotal_Brokers | 个 | 集群 Brokers 健康检查总数 | 全部版本 | 开源版 |
| HealthScore_Groups | 分 | 集群 Groups 的健康分 | 全部版本 | 开源版 |
| HealthCheckPassed_Groups | 个 | 集群 Groups 健康检查总数 | 全部版本 | 开源版 |
| HealthCheckTotal_Groups | 个 | 集群 Groups 健康检查总数 | 全部版本 | 开源版 |
| HealthScore_Cluster | 分 | 集群自身的健康分 | 全部版本 | 开源版 |
| HealthCheckPassed_Cluster | 个 | 集群自身健康检查通过数 | 全部版本 | 开源版 |
| HealthCheckTotal_Cluster | 个 | 集群自身健康检查总数 | 全部版本 | 开源版 |
| TotalRequestQueueSize | 个 | 集群中总的请求队列数 | 全部版本 | 开源版 |
| TotalResponseQueueSize | 个 | 集群中总的响应队列数 | 全部版本 | 开源版 |
| EventQueueSize | 个 | 集群中 Controller 的 EventQueue 大小 | 2.0.0 及以上版本 | 开源版 |
| ActiveControllerCount | 个 | 集群中存活的 Controller 数 | 全部版本 | 开源版 |
| TotalProduceRequests | 个 | 集群中的 Produce 每秒请求数 | 全部版本 | 开源版 |
| TotalLogSize | byte | 集群总的已使用的磁盘大小 | 全部版本 | 开源版 |
| ConnectionsCount | 个 | 集群的连接(Connections)个数 | 全部版本 | 开源版 |
| Zookeepers | 个 | 集群中存活的 zk 节点个数 | 全部版本 | 开源版 |
| ZookeepersAvailable | 是/否 | ZK 地址是否合法 | 全部版本 | 开源版 |
| Brokers | 个 | 集群的 broker 的总数 | 全部版本 | 开源版 |
| BrokersAlive | 个 | 集群的 broker 的存活数 | 全部版本 | 开源版 |
| BrokersNotAlive | 个 | 集群的 broker 的未存活数 | 全部版本 | 开源版 |
| Replicas | 个 | 集群中 Replica 的总数 | 全部版本 | 开源版 |
| Topics | 个 | 集群中 Topic 的总数 | 全部版本 | 开源版 |
| Partitions | 个 | 集群的 Partitions 总数 | 全部版本 | 开源版 |
| PartitionNoLeader | 个 | 集群中的 PartitionNoLeader 总数 | 全部版本 | 开源版 |
| PartitionMinISR_S | 个 | 集群中的小于 PartitionMinISR 总数 | 全部版本 | 开源版 |
| PartitionMinISR_E | 个 | 集群中的等于 PartitionMinISR 总数 | 全部版本 | 开源版 |
| PartitionURP | 个 | 集群中的未同步的 Partition 总数 | 全部版本 | 开源版 |
| MessagesIn | 条/s | 集群每条消息写入条数 | 全部版本 | 开源版 |
| Messages | 条 | 集群总的消息条数 | 全部版本 | 开源版 |
| LeaderMessages | 条 | 集群中 leader 总的消息条数 | 全部版本 | 开源版 |
| BytesIn | byte/s | 集群的每秒写入字节数 | 全部版本 | 开源版 |
| BytesIn_min_5 | byte/s | 集群的每秒写入字节数5 分钟均值 | 全部版本 | 开源版 |
| BytesIn_min_15 | byte/s | 集群的每秒写入字节数15 分钟均值 | 全部版本 | 开源版 |
| BytesOut | byte/s | 集群的每秒流出字节数 | 全部版本 | 开源版 |
| BytesOut_min_5 | byte/s | 集群的每秒流出字节数5 分钟均值 | 全部版本 | 开源版 |
| BytesOut_min_15 | byte/s | 集群的每秒流出字节数15 分钟均值 | 全部版本 | 开源版 |
| Groups | 个 | 集群中 Group 的总数 | 全部版本 | 开源版 |
| GroupActives | 个 | 集群中 ActiveGroup 的总数 | 全部版本 | 开源版 |
| GroupEmptys | 个 | 集群中 EmptyGroup 的总数 | 全部版本 | 开源版 |
| GroupRebalances | 个 | 集群中 RebalanceGroup 的总数 | 全部版本 | 开源版 |
| GroupDeads | 个 | 集群中 DeadGroup 的总数 | 全部版本 | 开源版 |
| Alive | 是/否 | 集群是否存活1存活0没有存活 | 全部版本 | 开源版 |
| AclEnable | 是/否 | 集群是否开启 Acl10否 | 全部版本 | 开源版 |
| Acls | 个 | ACL 数 | 全部版本 | 开源版 |
| AclUsers | 个 | ACL-KafkaUser 数 | 全部版本 | 开源版 |
| AclTopics | 个 | ACL-Topic 数 | 全部版本 | 开源版 |
| AclGroups | 个 | ACL-Group 数 | 全部版本 | 开源版 |
| Jobs | 个 | 集群任务总数 | 全部版本 | 开源版 |
| JobsRunning | 个 | 集群 running 任务总数 | 全部版本 | 开源版 |
| JobsWaiting | 个 | 集群 waiting 任务总数 | 全部版本 | 开源版 |
| JobsSuccess | 个 | 集群 success 任务总数 | 全部版本 | 开源版 |
| JobsFailed | 个 | 集群 failed 任务总数 | 全部版本 | 开源版 |
| LoadReBalanceEnable | 是/否 | 是否开启均衡, 10否 | 全部版本 | 企业版 |
| LoadReBalanceCpu | 是/否 | CPU 是否均衡, 10否 | 全部版本 | 企业版 |
| LoadReBalanceNwIn | 是/否 | BytesIn 是否均衡, 10否 | 全部版本 | 企业版 |
| LoadReBalanceNwOut | 是/否 | BytesOut 是否均衡, 10否 | 全部版本 | 企业版 |
| LoadReBalanceDisk | 是/否 | Disk 是否均衡, 10否 | 全部版本 | 企业版 |
### 3.3.2、Broker 指标
| 指标名称 | 指标单位 | 指标含义 | kafka 版本 | 企业/开源版指标 |
| ----------------------- | -------- | ------------------------------------- | ---------- | --------------- |
| HealthScore | 分 | Broker 健康分 | 全部版本 | 开源版 |
| HealthCheckPassed | 个 | Broker 健康检查通过数 | 全部版本 | 开源版 |
| HealthCheckTotal | 个 | Broker 健康检查总数 | 全部版本 | 开源版 |
| TotalRequestQueueSize | 个 | Broker 的请求队列大小 | 全部版本 | 开源版 |
| TotalResponseQueueSize | 个 | Broker 的应答队列大小 | 全部版本 | 开源版 |
| ReplicationBytesIn | byte/s | Broker 的副本流入流量 | 全部版本 | 开源版 |
| ReplicationBytesOut | byte/s | Broker 的副本流出流量 | 全部版本 | 开源版 |
| MessagesIn | 条/s | Broker 的每秒消息流入条数 | 全部版本 | 开源版 |
| TotalProduceRequests | 个/s | Broker 上 Produce 的每秒请求数 | 全部版本 | 开源版 |
| NetworkProcessorAvgIdle | % | Broker 的网络处理器的空闲百分比 | 全部版本 | 开源版 |
| RequestHandlerAvgIdle | % | Broker 上请求处理器的空闲百分比 | 全部版本 | 开源版 |
| PartitionURP | 个 | Broker 上的未同步的副本的个数 | 全部版本 | 开源版 |
| ConnectionsCount | 个 | Broker 上网络链接的个数 | 全部版本 | 开源版 |
| BytesIn | byte/s | Broker 的每秒数据写入量 | 全部版本 | 开源版 |
| BytesIn_min_5 | byte/s | Broker 的每秒数据写入量5 分钟均值 | 全部版本 | 开源版 |
| BytesIn_min_15 | byte/s | Broker 的每秒数据写入量15 分钟均值 | 全部版本 | 开源版 |
| BytesOut | byte/s | Broker 的每秒数据流出量 | 全部版本 | 开源版 |
| BytesOut_min_5 | byte/s | Broker 的每秒数据流出量5 分钟均值 | 全部版本 | 开源版 |
| BytesOut_min_15 | byte/s | Broker 的每秒数据流出量15 分钟均值 | 全部版本 | 开源版 |
| ReassignmentBytesIn | byte/s | Broker 的每秒数据迁移写入量 | 全部版本 | 开源版 |
| ReassignmentBytesOut | byte/s | Broker 的每秒数据迁移流出量 | 全部版本 | 开源版 |
| Partitions | 个 | Broker 上的 Partition 个数 | 全部版本 | 开源版 |
| PartitionsSkew | % | Broker 上的 Partitions 倾斜度 | 全部版本 | 开源版 |
| Leaders | 个 | Broker 上的 Leaders 个数 | 全部版本 | 开源版 |
| LeadersSkew | % | Broker 上的 Leaders 倾斜度 | 全部版本 | 开源版 |
| LogSize | byte | Broker 上的消息容量大小 | 全部版本 | 开源版 |
| Alive | 是/否 | Broker 是否存活1存活0没有存活 | 全部版本 | 开源版 |
### 3.3.3、Topic 指标
| 指标名称 | 指标单位 | 指标含义 | kafka 版本 | 企业/开源版指标 |
| --------------------- | -------- | ------------------------------------- | ---------- | --------------- |
| HealthScore | 分 | 健康分 | 全部版本 | 开源版 |
| HealthCheckPassed | 个 | 健康项检查通过数 | 全部版本 | 开源版 |
| HealthCheckTotal | 个 | 健康项检查总数 | 全部版本 | 开源版 |
| TotalProduceRequests | 条/s | Topic 的 TotalProduceRequests | 全部版本 | 开源版 |
| BytesRejected | 个/s | Topic 的每秒写入拒绝量 | 全部版本 | 开源版 |
| FailedFetchRequests | 个/s | Topic 的 FailedFetchRequests | 全部版本 | 开源版 |
| FailedProduceRequests | 个/s | Topic 的 FailedProduceRequests | 全部版本 | 开源版 |
| ReplicationCount | 个 | Topic 总的副本数 | 全部版本 | 开源版 |
| Messages | 条 | Topic 总的消息数 | 全部版本 | 开源版 |
| MessagesIn | 条/s | Topic 每秒消息条数 | 全部版本 | 开源版 |
| BytesIn | byte/s | Topic 每秒消息写入字节数 | 全部版本 | 开源版 |
| BytesIn_min_5 | byte/s | Topic 每秒消息写入字节数5 分钟均值 | 全部版本 | 开源版 |
| BytesIn_min_15 | byte/s | Topic 每秒消息写入字节数15 分钟均值 | 全部版本 | 开源版 |
| BytesOut | byte/s | Topic 每秒消息流出字节数 | 全部版本 | 开源版 |
| BytesOut_min_5 | byte/s | Topic 每秒消息流出字节数5 分钟均值 | 全部版本 | 开源版 |
| BytesOut_min_15 | byte/s | Topic 每秒消息流出字节数15 分钟均值 | 全部版本 | 开源版 |
| LogSize | byte | Topic 的大小 | 全部版本 | 开源版 |
| PartitionURP | 个 | Topic 未同步的副本数 | 全部版本 | 开源版 |
### 3.3.4、Partition 指标
| 指标名称 | 指标单位 | 指标含义 | kafka 版本 | 企业/开源版指标 |
| -------------- | -------- | ----------------------------------------- | ---------- | --------------- |
| LogEndOffset | 条 | Partition 中 leader 副本的 LogEndOffset | 全部版本 | 开源版 |
| LogStartOffset | 条 | Partition 中 leader 副本的 LogStartOffset | 全部版本 | 开源版 |
| Messages | 条 | Partition 总的消息数 | 全部版本 | 开源版 |
| BytesIn | byte/s | Partition 的每秒消息流入字节数 | 全部版本 | 开源版 |
| BytesOut | byte/s | Partition 的每秒消息流出字节数 | 全部版本 | 开源版 |
| LogSize | byte | Partition 的大小 | 全部版本 | 开源版 |
### 3.3.5、Group 指标
| 指标名称 | 指标单位 | 指标含义 | kafka 版本 | 企业/开源版指标 |
| ----------------- | -------- | -------------------------- | ---------- | --------------- |
| HealthScore | 分 | 健康分 | 全部版本 | 开源版 |
| HealthCheckPassed | 个 | 健康检查通过数 | 全部版本 | 开源版 |
| HealthCheckTotal | 个 | 健康检查总数 | 全部版本 | 开源版 |
| OffsetConsumed | 条 | Consumer 的 CommitedOffset | 全部版本 | 开源版 |
| LogEndOffset | 条 | Consumer 的 LogEndOffset | 全部版本 | 开源版 |
| Lag | 条 | Group 消费者的 Lag 数 | 全部版本 | 开源版 |
| State | 个 | Group 组的状态 | 全部版本 | 开源版 |

View File

@@ -1,90 +0,0 @@
## 6.1、本地源码启动手册
### 6.1.1、打包方式
`Know Streaming` 采用前后端分离的开发模式,使用 Maven 对项目进行统一的构建管理。maven 在打包构建过程中,会将前后端代码一并打包生成最终的安装包。
`Know Streaming` 除了使用安装包启动之外,还可以通过本地源码启动完整的带前端页面的项目,下面我们正式开始介绍本地源码如何启动 `Know Streaming`
### 6.1.2、环境要求
**系统支持**
`windows7+``Linux``Mac`
**环境依赖**
- Maven 3.6.3
- Node v12.20.0
- Java 8+
- MySQL 5.7
- Idea
- Elasticsearch 7.6
- Git
### 6.1.3、环境初始化
安装好环境信息之后,还需要初始化 MySQL 与 Elasticsearch 信息,包括:
- 初始化 MySQL 表及数据
- 初始化 Elasticsearch 索引
具体见:[单机部署手册](../install_guide/单机部署手册.md) 中的最后一步,部署 KnowStreaming 服务中的初始化相关工作。
### 6.1.4、本地启动
**第一步:本地打包**
执行 `mvn install` 可对项目进行前后端同时进行打包,通过该命令,除了可以对后端进行打包之外,还可以将前端相关的静态资源文件也一并打包出来。
**第二步:修改配置**
```yaml
# 修改 km-rest/src/main/resources/application.yml 中相关的配置
# 修改MySQL的配置中间省略了一些非必需修改的配置
spring:
datasource:
know-streaming:
jdbc-url: 修改为实际MYSQL地址
username: 修改为实际MYSQL用户名
password: 修改为实际MYSQL密码
logi-job:
jdbc-url: 修改为实际MYSQL地址
username: 修改为实际MYSQL用户名
password: 修改为实际MYSQL密码
logi-security:
jdbc-url: 修改为实际MYSQL地址
username: 修改为实际MYSQL用户名
password: 修改为实际MYSQL密码
# 修改ES的配置中间省略了一些非必需修改的配置
es.client.address: 修改为实际ES地址
```
**第三步:配置 IDEA**
`Know Streaming`的 Main 方法在:
```java
km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/KnowStreaming.java
```
IDEA 更多具体的配置如下图所示:
<p align="center">
<img src="http://img-ys011.didistatic.com/static/dc2img/do1_BW1RzgEMh4n6L4dL4ncl" width = "512" height = "318" div align=center />
</p>
**第四步:启动项目**
最后就是启动项目,在本地 console 中输出了 `KnowStreaming-KM started` 则表示我们已经成功启动 `Know Streaming` 了。
### 6.1.5、本地访问
`Know Streaming` 启动之后,可以访问一些信息,包括:
- 产品页面http://localhost:8080 ,默认账号密码:`admin` / `admin2022_` 进行登录。`v3.0.0-beta.2`版本开始,默认账号密码为`admin` / `admin`
- 接口地址http://localhost:8080/swagger-ui.html 查看后端提供的相关接口。
更多信息,详见:[KnowStreaming 官网](https://knowstreaming.com/)

View File

@@ -1,199 +0,0 @@
![Logo](https://user-images.githubusercontent.com/71620349/185368586-aed82d30-1534-453d-86ff-ecfa9d0f35bd.png)
## 登录系统对接
[KnowStreaming](https://github.com/didi/KnowStreaming)以下简称KS 除了实现基于本地MySQL的用户登录认证方式外还已经实现了基于Ldap的登录认证。
但是登录认证系统并非仅此两种。因此为了具有更好的拓展性KS具有自定义登陆认证逻辑快速对接已有系统的特性。
在KS中我们将登陆认证相关的一些文件放在[km-extends](https://github.com/didi/KnowStreaming/tree/master/km-extends)模块下的[km-account](https://github.com/didi/KnowStreaming/tree/master/km-extends/km-account)模块里。
本文将介绍KS如何快速对接自有的用户登录认证系统。
### 对接步骤
- 创建一个登陆认证类,实现[LogiCommon](https://github.com/didi/LogiCommon)的LoginExtend接口
- 将[application.yml](https://github.com/didi/KnowStreaming/blob/master/km-rest/src/main/resources/application.yml)中的spring.logi-security.login-extend-bean-name字段改为登陆认证类的bean名称
```Java
//LoginExtend 接口
public interface LoginExtend {
/**
* 验证登录信息,同时记住登录状态
*/
UserBriefVO verifyLogin(AccountLoginDTO var1, HttpServletRequest var2, HttpServletResponse var3) throws LogiSecurityException;
/**
* 登出接口,清楚登录状态
*/
Result<Boolean> logout(HttpServletRequest var1, HttpServletResponse var2);
/**
* 检查是否已经登录
*/
boolean interceptorCheck(HttpServletRequest var1, HttpServletResponse var2, String var3, List<String> var4) throws IOException;
}
```
### 对接例子
我们以Ldap对接为例说明KS如何对接登录认证系统。
+ 编写[LdapLoginServiceImpl](https://github.com/didi/KnowStreaming/blob/master/km-extends/km-account/src/main/java/com/xiaojukeji/know/streaming/km/account/login/ldap/LdapLoginServiceImpl.java)类实现LoginExtend接口。
+ 设置[application.yml](https://github.com/didi/KnowStreaming/blob/master/km-rest/src/main/resources/application.yml)中的spring.logi-security.login-extend-bean-name=ksLdapLoginService。
完成上述两步即可实现KS对接Ldap认证登陆。
```Java
@Service("ksLdapLoginService")
public class LdapLoginServiceImpl implements LoginExtend {
@Override
public UserBriefVO verifyLogin(AccountLoginDTO loginDTO,
HttpServletRequest request,
HttpServletResponse response) throws LogiSecurityException {
String decodePasswd = AESUtils.decrypt(loginDTO.getPw());
// 去LDAP验证账密
LdapPrincipal ldapAttrsInfo = ldapAuthentication.authenticate(loginDTO.getUserName(), decodePasswd);
if (ldapAttrsInfo == null) {
// 用户不存在,正常来说上如果有问题,上一步会直接抛出异常
throw new LogiSecurityException(ResultCode.USER_NOT_EXISTS);
}
// 进行业务相关操作
// 记录登录状态Ldap因为无法记录登录状态因此有KnowStreaming进行记录
initLoginContext(request, response, loginDTO.getUserName(), user.getId());
return CopyBeanUtil.copy(user, UserBriefVO.class);
}
@Override
public Result<Boolean> logout(HttpServletRequest request, HttpServletResponse response) {
//清理cookie和session
return Result.buildSucc(Boolean.TRUE);
}
@Override
public boolean interceptorCheck(HttpServletRequest request, HttpServletResponse response, String requestMappingValue, List<String> whiteMappingValues) throws IOException {
// 检查是否已经登录
String userName = HttpRequestUtil.getOperator(request);
if (StringUtils.isEmpty(userName)) {
// 未登录,则进行登出
logout(request, response);
return Boolean.FALSE;
}
return Boolean.TRUE;
}
}
```
### 实现原理
因为登陆和登出整体实现逻辑是一致的,所以我们以登陆逻辑为例进行介绍。
+ 登陆原理
登陆走的是[LogiCommon](https://github.com/didi/LogiCommon)自带的LoginController。
```java
@RestController
public class LoginController {
//登陆接口
@PostMapping({"/login"})
public Result<UserBriefVO> login(HttpServletRequest request, HttpServletResponse response, @RequestBody AccountLoginDTO loginDTO) {
try {
//登陆认证
UserBriefVO userBriefVO = this.loginService.verifyLogin(loginDTO, request, response);
return Result.success(userBriefVO);
} catch (LogiSecurityException var5) {
return Result.fail(var5);
}
}
}
```
而登陆操作是调用LoginServiceImpl类来实现但是具体由哪个登陆认证类来执行登陆操作却由loginExtendBeanTool来指定。
```java
//LoginServiceImpl类
@Service
public class LoginServiceImpl implements LoginService {
//实现登陆操作但是具体哪个登陆类由loginExtendBeanTool来管理
public UserBriefVO verifyLogin(AccountLoginDTO loginDTO, HttpServletRequest request, HttpServletResponse response) throws LogiSecurityException {
return this.loginExtendBeanTool.getLoginExtendImpl().verifyLogin(loginDTO, request, response);
}
}
```
而loginExtendBeanTool类会优先去查找用户指定的登陆认证类如果失败则调用默认的登陆认证函数。
```java
//LoginExtendBeanTool类
@Component("logiSecurityLoginExtendBeanTool")
public class LoginExtendBeanTool {
public LoginExtend getLoginExtendImpl() {
LoginExtend loginExtend;
//先调用用户指定登陆类,如果失败则调用系统默认登陆认证
try {
//调用的类由spring.logi-security.login-extend-bean-name指定
loginExtend = this.getCustomLoginExtendImplBean();
} catch (UnsupportedOperationException var3) {
loginExtend = this.getDefaultLoginExtendImplBean();
}
return loginExtend;
}
}
```
+ 认证原理
认证的实现则比较简单向Spring中注册我们的拦截器PermissionInterceptor。
拦截器会调用LoginServiceImpl类的拦截方法LoginServiceImpl后续处理逻辑就和前面登陆是一致的。
```java
public class PermissionInterceptor implements HandlerInterceptor {
/**
* 拦截预处理
* @return boolean false:拦截, 不向下执行, true:放行
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//免登录相关校验,如果验证通过,提前返回
//走拦截函数,进行普通用户验证
return loginService.interceptorCheck(request, response, classRequestMappingValue, whiteMappingValues);
}
}
```

View File

@@ -1,126 +0,0 @@
![Logo](https://user-images.githubusercontent.com/71620349/185368586-aed82d30-1534-453d-86ff-ecfa9d0f35bd.png)
## JMX-连接失败问题解决
集群正常接入`KnowStreaming`之后即可以看到集群的Broker列表此时如果查看不了Topic的实时流量或者是Broker的实时流量信息时那么大概率就是`JMX`连接的问题了。
下面我们按照步骤来一步一步的检查。
### 1、问题说明
**类型一JMX配置未开启**
未开启时,直接到`2、解决方法`查看如何开启即可。
![check_jmx_opened](http://img-ys011.didistatic.com/static/dc2img/do1_dRX6UHE2IUSHqsN95DGb)
**类型二:配置错误**
`JMX`端口已经开启的情况下,有的时候开启的配置不正确,此时也会导致出现连接失败的问题。这里大概列举几种原因:
- `JMX`配置错误:见`2、解决方法`
- 存在防火墙或者网络限制:网络通的另外一台机器`telnet`试一下看是否可以连接上。
- 需要进行用户名及密码的认证:见`3、解决方法 —— 认证的JMX`
错误日志例子:
```
# 错误一: 错误提示的是真实的IP这样的话基本就是JMX配置的有问题了。
2021-01-27 10:06:20.730 ERROR 50901 --- [ics-Thread-1-62] c.x.k.m.c.utils.jmx.JmxConnectorWrap : JMX connect exception, host:192.168.0.1 port:9999.
java.rmi.ConnectException: Connection refused to host: 192.168.0.1; nested exception is:
# 错误二错误提示的是127.0.0.1这个IP这个是机器的hostname配置的可能有问题。
2021-01-27 10:06:20.730 ERROR 50901 --- [ics-Thread-1-62] c.x.k.m.c.utils.jmx.JmxConnectorWrap : JMX connect exception, host:127.0.0.1 port:9999.
java.rmi.ConnectException: Connection refused to host: 127.0.0.1;; nested exception is:
```
**类型三连接特定IP**
Broker 配置了内外网而JMX在配置时可能配置了内网IP或者外网IP此时 `KnowStreaming` 需要连接到特定网络的IP才可以进行访问。
比如:
Broker在ZK的存储结构如下所示我们期望连接到 `endpoints` 中标记为 `INTERNAL` 的地址,但是 `KnowStreaming` 却连接了 `EXTERNAL` 的地址,此时可以看 `4、解决方法 —— JMX连接特定网络` 进行解决。
```json
{
"listener_security_protocol_map": {"EXTERNAL":"SASL_PLAINTEXT","INTERNAL":"SASL_PLAINTEXT"},
"endpoints": ["EXTERNAL://192.168.0.1:7092","INTERNAL://192.168.0.2:7093"],
"jmx_port": 8099,
"host": "192.168.0.1",
"timestamp": "1627289710439",
"port": -1,
"version": 4
}
```
### 2、解决方法
这里仅介绍一下比较通用的解决方式,如若有更好的方式,欢迎大家指导告知一下。
修改`kafka-server-start.sh`文件:
```
# 在这个下面增加JMX端口的配置
if [ "x$KAFKA_HEAP_OPTS" = "x" ]; then
export KAFKA_HEAP_OPTS="-Xmx1G -Xms1G"
export JMX_PORT=9999 # 增加这个配置, 这里的数值并不一定是要9999
fi
```
&nbsp;
修改`kafka-run-class.sh`文件
```
# JMX settings
if [ -z "$KAFKA_JMX_OPTS" ]; then
KAFKA_JMX_OPTS="-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Djava.rmi.server.hostname=${当前机器的IP}"
fi
# JMX port to use
if [ $JMX_PORT ]; then
KAFKA_JMX_OPTS="$KAFKA_JMX_OPTS -Dcom.sun.management.jmxremote.port=$JMX_PORT -Dcom.sun.management.jmxremote.rmi.port=$JMX_PORT"
fi
```
### 3、解决方法 —— 认证的JMX
如果您是直接看的这个部分,建议先看一下上一节:`2、解决方法`以确保`JMX`的配置没有问题了。
`JMX`的配置等都没有问题的情况下,如果是因为认证的原因导致连接不了的,可以在集群接入界面配置你的`JMX`认证信息。
<img src='http://img-ys011.didistatic.com/static/dc2img/do1_EUU352qMEX1Jdp7pxizp' width=350>
### 4、解决方法 —— JMX连接特定网络
可以手动往`ks_km_physical_cluster`表的`jmx_properties`字段增加一个`useWhichEndpoint`字段,从而控制 `KnowStreaming` 连接到特定的JMX IP及PORT。
`jmx_properties`格式:
```json
{
"maxConn": 100, # KM对单台Broker的最大JMX连接数
"username": "xxxxx", # 用户名,可以不填写
"password": "xxxx", # 密码,可以不填写
"openSSL": true, # 开启SSL, true表示开启ssl, false表示关闭
"useWhichEndpoint": "EXTERNAL" #指定要连接的网络名称填写EXTERNAL就是连接endpoints里面的EXTERNAL地址
}
```
&nbsp;
SQL例子
```sql
UPDATE ks_km_physical_cluster SET jmx_properties='{ "maxConn": 10, "username": "xxxxx", "password": "xxxx", "openSSL": false , "useWhichEndpoint": "xxx"}' where id={xxx};
```
注意:
+ 目前此功能只支持采用 `ZK` 做分布式协调的kafka集群。

View File

@@ -1,265 +0,0 @@
## 2.1、单机部署
**风险提示**
⚠️ 脚本全自动安装,会将所部署机器上的 MySQL、JDK、ES 等进行删除重装,请注意原有服务丢失风险。
### 2.1.1、安装说明
-`v3.0.0-beta.1` 版本为例进行部署;
- 以 CentOS-7 为例,系统基础配置要求 4C-8G
- 部署完成后,可通过浏览器:`IP:PORT` 进行访问,默认端口是 `8080`,系统默认账号密码: `admin` / `admin2022_`
- `v3.0.0-beta.2`版本开始,默认账号密码为`admin` / `admin`
- 本文为单机部署,如需分布式部署,[请联系我们](https://knowstreaming.com/support-center)
**软件依赖**
| 软件名 | 版本要求 | 默认端口 |
| ------------- | ------------ | -------- |
| MySQL | v5.7 或 v8.0 | 3306 |
| ElasticSearch | v7.6+ | 8060 |
| JDK | v8+ | - |
| CentOS | v6+ | - |
| Ubuntu | v16+ | - |
&nbsp;
### 2.1.2、脚本部署
**在线安装**
```bash
# 在服务器中下载安装脚本, 该脚本中会在当前目录下重新安装MySQL。重装后的mysql密码存放在当前目录的mysql.password文件中。
wget https://s3-gzpu.didistatic.com/pub/knowstreaming/deploy_KnowStreaming-3.0.0-beta.1.sh
# 执行脚本
sh deploy_KnowStreaming.sh
# 访问地址
127.0.0.1:8080
```
**离线安装**
```bash
# 将安装包下载到本地且传输到目标服务器
wget https://s3-gzpu.didistatic.com/pub/knowstreaming/KnowStreaming-3.0.0-beta.1-offline.tar.gz
# 解压安装包
tar -zxf KnowStreaming-3.0.0-beta.1-offline.tar.gz
# 执行安装脚本
sh deploy_KnowStreaming-offline.sh
# 访问地址
127.0.0.1:8080
```
&nbsp;
### 2.1.3、容器部署
**环境依赖**
- Kubernetes >= 1.14 Helm >= 2.17.0
- 默认依赖全部安装ElasticSearch3 节点集群模式) + MySQL(单机) + KnowStreaming-manager + KnowStreaming-ui
- 使用已有的 ElasticSearch(7.6.x) 和 MySQL(5.7) 只需调整 values.yaml 部分参数即可
**安装命令**
```bash
# 相关镜像在Docker Hub都可以下载
# 快速安装(NAMESPACE需要更改为已存在的安装启动需要几分钟初始化请稍等~)
helm install -n [NAMESPACE] [NAME] http://download.knowstreaming.com/charts/knowstreaming-manager-0.1.3.tgz
# 获取KnowStreaming前端ui的service. 默认nodeport方式.
# (http://nodeIP:nodeport默认用户名密码admin/admin2022_)
# `v3.0.0-beta.2`版本开始,默认账号密码为`admin` / `admin`
# 添加仓库
helm repo add knowstreaming http://download.knowstreaming.com/charts
# 拉取最新版本
helm pull knowstreaming/knowstreaming-manager
```
&nbsp;
### 2.1.4、手动部署
**部署流程**
1. 安装 `JDK-11``MySQL``ElasticSearch` 等依赖服务
2. 安装 KnowStreaming
&nbsp;
#### 2.1.4.1、安装 MySQL 服务
**yum 方式安装**
```bash
# 配置yum源
wget https://dev.mysql.com/get/mysql57-community-release-el7-9.noarch.rpm
rpm -ivh mysql57-community-release-el7-9.noarch.rpm
# 执行安装
yum -y install mysql-server mysql-client
# 服务启动
systemctl start mysqld
# 获取初始密码并修改
old_pass=`grep 'temporary password' /var/log/mysqld.log | awk '{print $NF}' | tail -n 1`
mysql -NBe "alter user USER() identified by 'Didi_km_678';" --connect-expired-password -uroot -p$old_pass
```
**rpm 方式安装**
```bash
# 下载安装包
wget https://s3-gzpu.didistatic.com/knowsearch/mysql5.7.tar.gz
# 解压到指定目录
tar -zxf mysql5.7.tar.gz -C /tmp/
# 执行安装
yum -y localinstall /tmp/libaio-*.rpm /tmp/mysql-*.rpm
# 服务启动
systemctl start mysqld
# 获取初始密码并修改
old_pass=`grep 'temporary password' /var/log/mysqld.log | awk '{print $NF}' | tail -n 1`
mysql -NBe "alter user USER() identified by 'Didi_km_678';" --connect-expired-password -uroot -p$old_pass
```
&nbsp;
#### 2.1.4.2、配置 JDK 环境
```bash
# 下载安装包
wget https://s3-gzpu.didistatic.com/pub/jdk11.tar.gz
# 解压到指定目录
tar -zxf jdk11.tar.gz -C /usr/local/
# 更改目录名
mv /usr/local/jdk-11.0.2 /usr/local/java11
# 添加到环境变量
echo "export JAVA_HOME=/usr/local/java11" >> ~/.bashrc
echo "export CLASSPATH=/usr/java/java11/lib" >> ~/.bashrc
echo "export PATH=$JAVA_HOME/bin:$PATH:$HOME/bin" >> ~/.bashrc
source ~/.bashrc
```
&nbsp;
#### 2.1.4.3、ElasticSearch 实例搭建
- ElasticSearch 用于存储平台采集的 Kafka 指标;
- 以下安装示例为单节点模式,如需集群部署可以参考:[Elasticsearch 官方文档](https://www.elastic.co/guide/en/elasticsearch/reference/7.6/elasticsearch-intro.html)
```bash
# 下载安装包
wget https://s3-gzpu.didistatic.com/pub/elasticsearch.tar.gz
# 创建ES数据存储目录
mkdir -p /data/es_data
# 创建ES所属用户
useradd arius
# 配置用户的打开文件数
echo "arius soft nofile 655350" >> /etc/security/limits.conf
echo "arius hard nofile 655350" >> /etc/security/limits.conf
echo "vm.max_map_count = 655360" >> /etc/sysctl.conf
sysctl -p
# 解压安装包
tar -zxf elasticsearch.tar.gz -C /data/
# 更改目录所属组
chown -R arius:arius /data/
# 修改配置文件(参考以下配置)
vim /data/elasticsearch/config/elasticsearch.yml
cluster.name: km_es
node.name: es-node1
node.master: true
node.data: true
path.data: /data/es_data
http.port: 8060
discovery.seed_hosts: ["127.0.0.1:9300"]
# 修改内存配置
vim /data/elasticsearch/config/jvm.options
-Xms2g
-Xmx2g
# 启动服务
su - arius
export JAVA_HOME=/usr/local/java11
sh /data/elasticsearch/control.sh start
# 确认状态
sh /data/elasticsearch/control.sh status
```
&nbsp;
#### 2.1.4.4、KnowStreaming 实例搭建
```bash
# 下载安装包
wget https://s3-gzpu.didistatic.com/pub/knowstreaming/KnowStreaming-3.0.0-beta.1.tar.gz
# 解压安装包到指定目录
tar -zxf KnowStreaming-3.0.0-beta.1.tar.gz -C /data/
# 修改启动脚本并加入systemd管理
cd /data/KnowStreaming/
# 创建相应的库和导入初始化数据
mysql -uroot -pDidi_km_678 -e "create database know_streaming;"
mysql -uroot -pDidi_km_678 know_streaming < ./init/sql/ddl-ks-km.sql
mysql -uroot -pDidi_km_678 know_streaming < ./init/sql/ddl-logi-job.sql
mysql -uroot -pDidi_km_678 know_streaming < ./init/sql/ddl-logi-security.sql
mysql -uroot -pDidi_km_678 know_streaming < ./init/sql/dml-ks-km.sql
mysql -uroot -pDidi_km_678 know_streaming < ./init/sql/dml-logi.sql
# 创建elasticsearch初始化数据
sh ./bin/init_es_template.sh
# 修改配置文件
vim ./conf/application.yml
# 监听端口
server:
port: 8080 # web 服务端口
tomcat:
accept-count: 1000
max-connections: 10000
# ES地址
es.client.address: 127.0.0.1:8060
# 数据库配置一共三处地方修改正确的mysql地址和数据库名称以及用户名密码
jdbc-url: jdbc:mariadb://127.0.0.1:3306/know_streaming?.....
username: root
password: Didi_km_678
# 启动服务
cd /data/KnowStreaming/bin/
sh startup.sh
```

View File

@@ -1,62 +0,0 @@
![Logo](https://user-images.githubusercontent.com/71620349/185368586-aed82d30-1534-453d-86ff-ecfa9d0f35bd.png)
# `Know Streaming` 源码编译打包手册
## 1、环境信息
**系统支持**
`windows7+``Linux``Mac`
**环境依赖**
- Maven 3.6.3 (后端)
- Node v12.20.0/v14.17.3 (前端)
- Java 8+ (后端)
- Git
## 2、编译打包
整个工程中,除了`km-console`为前端模块之外,其他模块都是后端工程相关模块。
因此,如果前后端合并打包,则打对整个工程进行打包;如果前端单独打包,则仅打包 `km-console` 中的代码;如果是仅需要后端打包,则在顶层 `pom.xml` 中去掉 `km-console`模块,然后进行打包。
具体见下面描述。
### 2.1、前后端合并打包
1. 下载源码;
2. 进入 `KS-KM` 工程目录,执行 `mvn -Prelease-package -Dmaven.test.skip=true clean install -U` 命令;
3. 打包命令执行完成后,会在 `km-dist/target` 目录下面生成一个 `KnowStreaming-*.tar.gz` 的安装包。
### 2.2、前端单独打包
1. 下载源码;
2. 跳转到 [前端打包构建文档](https://github.com/didi/KnowStreaming/blob/master/km-console/README.md) 按步骤进行。打包成功后,会在 `km-rest/src/main/resources` 目录下生成名为 `templates` 的前端静态资源包;
3. 如果上一步过程中报错,请查看 [FAQ](https://github.com/didi/KnowStreaming/blob/master/docs/user_guide/faq.md) 第 8.10 条;
### 2.3、后端单独打包
1. 下载源码;
2. 修改顶层 `pom.xml` ,去掉其中的 `km-console` 模块,如下所示;
```xml
<modules>
<!-- <module>km-console</module>-->
<module>km-common</module>
<module>km-persistence</module>
<module>km-core</module>
<module>km-biz</module>
<module>km-extends/km-account</module>
<module>km-extends/km-monitor</module>
<module>km-extends/km-license</module>
<module>km-extends/km-rebalance</module>
<module>km-task</module>
<module>km-collector</module>
<module>km-rest</module>
<module>km-dist</module>
</modules>
```
3. 执行 `mvn -U clean package -Dmaven.test.skip=true`命令;
4. 执行完成之后会在 `KS-KM/km-rest/target` 目录下面生成一个 `ks-km.jar` 即为 KS 的后端部署的 Jar 包,也可以执行 `mvn -Prelease-package -Dmaven.test.skip=true clean install -U` 生成的 tar 包也仅有后端服务的功能;

View File

@@ -1,136 +0,0 @@
## 6.2、版本升级手册
注意:如果想升级至具体版本,需要将你当前版本至你期望使用版本的变更统统执行一遍,然后才能正常使用。
### 6.2.0、升级至 `master` 版本
暂无
### 6.2.1、升级至 `v3.0.0-beta.2`版本
**配置变更**
```yaml
# 新增配置
spring:
logi-security: # know-streaming 依赖的 logi-security 模块的数据库的配置,默认与 know-streaming 的数据库配置保持一致即可
login-extend-bean-name: logiSecurityDefaultLoginExtendImpl # 使用的登录系统Service的Bean名称无需修改
# 线程池大小相关配置在task模块中新增了三类线程池
# 从而减少不同类型任务之间的相互影响以及减少对logi-job内的线程池的影响
thread-pool:
task: # 任务模块的配置
metrics: # metrics采集任务配置
thread-num: 18 # metrics采集任务线程池核心线程数
queue-size: 180 # metrics采集任务线程池队列大小
metadata: # metadata同步任务配置
thread-num: 27 # metadata同步任务线程池核心线程数
queue-size: 270 # metadata同步任务线程池队列大小
common: # 剩余其他任务配置
thread-num: 15 # 剩余其他任务线程池核心线程数
queue-size: 150 # 剩余其他任务线程池队列大小
# 删除配置,下列配置将不再使用
thread-pool:
task: # 任务模块的配置
heaven: # 采集任务配置
thread-num: 20 # 采集任务线程池核心线程数
queue-size: 1000 # 采集任务线程池队列大小
```
**SQL变更**
```sql
-- 多集群管理权限2022-09-06新增
INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('2000', '多集群管理查看', '1593', '1', '2', '多集群管理查看', '0', 'know-streaming');
INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('2002', 'Topic-迁移副本', '1593', '1', '2', 'Topic-迁移副本', '0', 'know-streaming');
INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('2004', 'Topic-扩缩副本', '1593', '1', '2', 'Topic-扩缩副本', '0', 'know-streaming');
INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('2006', 'Cluster-LoadReBalance-周期均衡', '1593', '1', '2', 'Cluster-LoadReBalance-周期均衡', '0', 'know-streaming');
INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('2008', 'Cluster-LoadReBalance-立即均衡', '1593', '1', '2', 'Cluster-LoadReBalance-立即均衡', '0', 'know-streaming');
INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('2010', 'Cluster-LoadReBalance-设置集群规格', '1593', '1', '2', 'Cluster-LoadReBalance-设置集群规格', '0', 'know-streaming');
-- 系统管理权限2022-09-06新增
INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('3000', '系统管理查看', '1595', '1', '2', '系统管理查看', '0', 'know-streaming');
INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '2000', '0', 'know-streaming');
INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '2002', '0', 'know-streaming');
INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '2004', '0', 'know-streaming');
INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '2006', '0', 'know-streaming');
INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '2008', '0', 'know-streaming');
INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '2010', '0', 'know-streaming');
INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '3000', '0', 'know-streaming');
-- 修改字段长度
ALTER TABLE `logi_security_oplog`
CHANGE COLUMN `operator_ip` `operator_ip` VARCHAR(64) NOT NULL COMMENT '操作者ip' ,
CHANGE COLUMN `operator` `operator` VARCHAR(64) NULL DEFAULT NULL COMMENT '操作者账号' ,
CHANGE COLUMN `operate_page` `operate_page` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '操作页面' ,
CHANGE COLUMN `operate_type` `operate_type` VARCHAR(64) NOT NULL COMMENT '操作类型' ,
CHANGE COLUMN `target_type` `target_type` VARCHAR(64) NOT NULL COMMENT '对象分类' ,
CHANGE COLUMN `target` `target` VARCHAR(1024) NOT NULL COMMENT '操作对象' ,
CHANGE COLUMN `operation_methods` `operation_methods` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '操作方式' ;
```
---
### 6.2.2、升级至 `v3.0.0-beta.1`版本
**SQL变更**
1、在`ks_km_broker`表增加了一个监听信息字段。
2、为`logi_security_oplog`表operation_methods字段设置默认值''。
因此需要执行下面的sql对数据库表进行更新。
```sql
ALTER TABLE `ks_km_broker`
ADD COLUMN `endpoint_map` VARCHAR(1024) NOT NULL DEFAULT '' COMMENT '监听信息' AFTER `update_time`;
ALTER TABLE `logi_security_oplog`
ALTER COLUMN `operation_methods` set default '';
```
---
### 6.2.3、`2.x`版本 升级至 `v3.0.0-beta.0`版本
**升级步骤:**
1. 依旧使用**`2.x 版本的 DB`**,在上面初始化 3.0.0 版本所需数据库表结构及数据;
2. 将 2.x 版本中的集群,在 3.0.0 版本,手动逐一接入;
3. 将 Topic 业务数据,迁移至 3.0.0 表中,详见下方 SQL
**注意事项**
- 建议升级 3.0.0 版本过程中,保留 2.x 版本的使用,待 3.0.0 版本稳定使用后,再下线 2.x 版本;
- 3.0.0 版本仅需要`集群信息``Topic的描述信息`。2.x 版本的 DB 的其他数据 3.0.0 版本都不需要;
- 部署 3.0.0 版本之后集群、Topic 等指标数据都为空3.0.0 版本会周期进行采集,运行一段时间之后就会有该数据了,因此不会将 2.x 中的指标数据进行迁移;
**迁移数据**
```sql
-- 迁移Topic的备注信息。
-- 需在 3.0.0 部署完成后再执行该SQL。
-- 考虑到 2.x 版本中还存在增量数据因此建议改SQL周期执行是的增量数据也能被迁移至 3.0.0 版本中。
UPDATE ks_km_topic
INNER JOIN
(SELECT
topic.cluster_id AS cluster_id,
topic.topic_name AS topic_name,
topic.description AS description
FROM topic WHERE description != ''
) AS t
ON ks_km_topic.cluster_phy_id = t.cluster_id
AND ks_km_topic.topic_name = t.topic_name
AND ks_km_topic.id > 0
SET ks_km_topic.description = t.description;
```

View File

@@ -1,168 +0,0 @@
# FAQ
## 8.1、支持哪些 Kafka 版本?
- 支持 0.10+ 的 Kafka 版本;
- 支持 ZK 及 Raft 运行模式的 Kafka 版本;
&nbsp;
## 8.1、2.x 版本和 3.0 版本有什么差异?
**全新设计理念**
- 在 0 侵入、0 门槛的前提下提供直观 GUI 用于管理和观测 Apache Kafka®帮助用户降低 Kafka CLI 操作门槛,轻松实现对原生 Kafka 集群的可管、可见、可掌控,提升 Kafka 使用体验和降低管理成本。
- 支持海量集群一键接入,无需任何改造,即可实现集群深度纳管,真正的 0 侵入、插件化系统设计,覆盖 0.10.x-3.x.x 众多 Kafka 版本无缝纳管。
**开源协议调整**
- 3.xAGPL 3.0
- 2.xApache License 2.0
更多具体内容见:[新旧版本对比](https://doc.knowstreaming.com/product/9-attachment#92%E6%96%B0%E6%97%A7%E7%89%88%E6%9C%AC%E5%AF%B9%E6%AF%94)
&nbsp;
## 8.3、页面流量信息等无数据?
- 1、`Broker 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)
- 2、`ES` 存在问题
建议使用`ES 7.6`版本,同时创建近 7 天的索引,具体见:[快速开始](./1-quick-start.md) 中的 ES 索引模版及索引创建。
&nbsp;
## 8.4、`Jmx`连接失败如何解决?
- 参看 [Jmx 连接配置&问题解决](./9-attachment#jmx-连接失败问题解决) 说明。
&nbsp;
## 8.5、有没有 API 文档?
`KnowStreaming` 采用 Swagger 进行 API 说明,在启动 KnowStreaming 服务之后,就可以从下面地址看到。
Swagger-API 地址: [http://IP:PORT/swagger-ui.html#/](http://IP:PORT/swagger-ui.html#/)
&nbsp;
## 8.6、删除 Topic 成功后,为何过段时间又出现了?
**原因说明:**
`KnowStreaming` 会去请求 Topic 的 endoffset 信息,要获取这个信息就需要发送 metadata 请求,发送 metadata 请求的时候,如果集群允许自动创建 Topic那么当 Topic 不存在时,就会自动将该 Topic 创建出来。
**问题解决:**
因为在 `KnowStreaming` 上,禁止 Kafka 客户端内部元信息获取这个动作非常的难做到,因此短时间内这个问题不好从 `KnowStreaming` 上解决。
当然,对于不存在的 Topic`KnowStreaming` 是不会进行元信息请求的,因此也不用担心会莫名其妙的创建一个 Topic 出来。
但是,另外一点,对于开启允许 Topic 自动创建的集群,建议是关闭该功能,开启是非常危险的,如果关闭之后,`KnowStreaming` 也不会有这个问题。
最后这里举个开启这个配置后,非常危险的代码例子吧:
```java
for (int i= 0; i < 100000; ++i) {
// 如果是客户端类似这样写的那么一启动那么将创建10万个Topic出来集群元信息瞬间爆炸controller可能就不可服务了。
producer.send(new ProducerRecord<String, String>("know_streaming" + i,"hello logi_km"));
}
```
&nbsp;
## 8.7、如何在不登录的情况下,调用接口?
步骤一:接口调用时,在 header 中,增加如下信息:
```shell
# 表示开启登录绕过
Trick-Login-Switch : on
# 登录绕过的用户, 这里可以是admin, 或者是其他的, 但是必须在系统管理->用户管理中设置了该用户。
Trick-Login-User : admin
```
&nbsp;
步骤二:点击右上角"系统管理",选择配置管理,在页面中添加以下键值对。
```shell
# 模块选择
SECURITY.LOGIN
# 设置的配置键,必须是这个
SECURITY.TRICK_USERS
# 设置的value是json数组的格式包含步骤一header中设置的用户名例如
[ "admin", "logi"]
```
&nbsp;
步骤三:解释说明
设置完成上面两步之后,就可以直接调用需要登录的接口了。
但是还有一点需要注意,绕过的用户仅能调用他有权限的接口,比如一个普通用户,那么他就只能调用普通的接口,不能去调用运维人员的接口。
## 8.8、Specified key was too long; max key length is 767 bytes
**原因:** 不同版本的 InoDB 引擎参数innodb_large_prefix默认值不同即在 5.6 默认值为 OFF5.7 默认值为 ON。
对于引擎为 InnoDBinnodb_large_prefix=OFF且行格式为 Antelope 即支持 REDUNDANT 或 COMPACT 时,索引键前缀长度最大为 767 字节。innodb_large_prefix=ON且行格式为 Barracuda 即支持 DYNAMIC 或 COMPRESSED 时,索引键前缀长度最大为 3072 字节。
**解决方案:**
- 减少 varchar 字符大小低于 767/4=191。
- 将字符集改为 latin1一个字符=一个字节)。
- 开启innodb_large_prefix修改默认行格式innodb_file_format为 Barracuda并设置 row_format=dynamic。
## 8.9、出现 ESIndexNotFoundEXception 报错
**原因 **没有创建 ES 索引模版
**解决方案:**执行 init_es_template.sh 脚本,创建 ES 索引模版即可。
## 8.10、km-console 打包构建失败
首先,**请确保您正在使用最新版本**,版本列表见 [Tags](https://github.com/didi/KnowStreaming/tags)。如果不是最新版本,请升级后再尝试有无问题。
常见的原因是由于工程依赖没有正常安装,导致在打包过程中缺少依赖,造成打包失败。您可以检查是否有以下文件夹,且文件夹内是否有内容
```
KnowStreaming/km-console/node_modules
KnowStreaming/km-console/packages/layout-clusters-fe/node_modules
KnowStreaming/km-console/packages/config-manager-fe/node_modules
```
如果发现没有对应的 `node_modules` 目录或着目录内容为空,说明依赖没有安装成功。请按以下步骤操作,
1. 手动删除上述三个文件夹(如果有)
2. 如果之前是通过 `mvn install` 打包 `km-console`请到项目根目录KnowStreaming下重新输入该指令进行打包。观察打包过程有无报错。如有报错请见步骤 4。
3. 如果是通过本地独立构建前端工程的方式(指直接执行 `npm run build`),请进入 `KnowStreaming/km-console` 目录,执行下述步骤(注意:执行时请确保您在使用 `node v12` 版本)
a. 执行 `npm run i`。如有报错,请见步骤 4。
b. 执行 `npm run build`。如有报错,请见步骤 4。
4. 麻烦联系我们协助解决。推荐提供以下信息,方面我们快速定位问题,示例如下。
```
操作系统: Mac
命令行终端bash
Node 版本: v12.22.12
复现步骤: 1. -> 2.
错误截图:
```
## 8.11、在 `km-console` 目录下执行 `npm run start` 时看不到应用构建和热加载过程?如何启动单个应用?
需要到具体的应用中执行 `npm run start`,例如 `cd packages/layout-clusters-fe` 后,执行 `npm run start`
应用启动后需要到基座应用中查看(需要启动基座应用,即 layout-clusters-fe

View File

@@ -1,92 +0,0 @@
## 9.2、新旧版本对比
### 9.2.1、全新的设计理念
- 在 0 侵入、0 门槛的前提下提供直观 GUI 用于管理和观测 Apache Kafka®帮助用户降低 Kafka CLI 操作门槛,轻松实现对原生 Kafka 集群的可管、可见、可掌控,提升 Kafka 使用体验和降低管理成本。
- 支持海量集群一键接入,无需任何改造,即可实现集群深度纳管,真正的 0 侵入、插件化系统设计,覆盖 0.10.x-3.x.x 众多 Kafka 版本无缝纳管。
### 9.2.2、产品名称&协议
- Know Streaming V3.0
- 名称Know Streaming
- 协议AGPL 3.0
- Logi-KM V2.x
- 名称Logi-KM
- 协议Apache License 2.0
### 9.2.3、功能架构
- Know Streaming V3.0
![text](http://img-ys011.didistatic.com/static/dc2img/do1_VQD9ke5jewpjCIWamUKV)
- Logi-KM V2.x
![text](http://img-ys011.didistatic.com/static/dc2img/do1_F211q5lVCXQCXQNzWalu)
### 9.2.4、功能变更
- 多集群管理
- 增加健康监测体系、关键组件&指标 GUI 展示
- 增加 2.8.x 以上 Kafka 集群接入,覆盖 0.10.x-3.x
- 删除逻辑集群、共享集群、Region 概念
- Cluster 管理
- 增加集群概览信息、集群配置变更记录
- 增加 Cluster 健康分,健康检查规则支持自定义配置
- 增加 Cluster 关键指标统计和 GUI 展示,支持自定义配置
- 增加 Cluster 层 I/O、Disk 的 Load Reblance 功能,支持定时均衡任务(企业版)
- 删除限流、鉴权功能
- 删除 APPID 概念
- Broker 管理
- 增加 Broker 健康分
- 增加 Broker 关键指标统计和 GUI 展示,支持自定义配置
- 增加 Broker 参数配置功能,需重启生效
- 增加 Controller 变更记录
- 增加 Broker Datalogs 记录
- 删除 Leader Rebalance 功能
- 删除 Broker 优先副本选举
- Topic 管理
- 增加 Topic 健康分
- 增加 Topic 关键指标统计和 GUI 展示,支持自定义配置
- 增加 Topic 参数配置功能,可实时生效
- 增加 Topic 批量迁移、Topic 批量扩缩副本功能
- 增加查看系统 Topic 功能
- 优化 Partition 分布的 GUI 展示
- 优化 Topic Message 数据采样
- 删除 Topic 过期概念
- 删除 Topic 申请配额功能
- Consumer 管理
- 优化了 ConsumerGroup 展示形式,增加 Consumer Lag 的 GUI 展示
- ACL 管理
- 增加原生 ACL GUI 配置功能,可配置生产、消费、自定义多种组合权限
- 增加 KafkaUser 功能,可自定义新增 KafkaUser
- 消息测试(企业版)
- 增加生产者消息模拟器,支持 Data、Flow、Header、Options 自定义配置(企业版)
- 增加消费者消息模拟器,支持 Data、Flow、Header、Options 自定义配置(企业版)
- Job
- 优化 Job 模块,支持任务进度管理
- 系统管理
- 优化用户、角色管理体系,支持自定义角色配置页面及操作权限
- 优化审计日志信息
- 删除多租户体系
- 删除工单流程

View File

@@ -1,848 +0,0 @@
## 5.0、产品简介
`Know Streaming` 是一套云原生的 Kafka 管控平台,脱胎于众多互联网内部多年的 Kafka 运营实践经验,专注于 Kafka 运维管控、监控告警、资源治理、多活容灾等核心场景,在用户体验、监控、运维管控上进行了平台化、可视化、智能化的建设,提供一系列特色的功能,极大地方便了用户和运维人员的日常使用,让普通运维人员都能成为 Kafka 专家。
## 5.1、功能架构
![text](http://img-ys011.didistatic.com/static/dc2img/do1_jL7YJywtBtiR8VxIabsn)
## 5.2、体验路径
下面是用户第一次使用我们产品的典型体验路径:
![text](http://img-ys011.didistatic.com/static/dc2img/do1_YehqxqmsVaqU5gf3XphI)
## 5.3、常用功能
### 5.3.1、用户管理
用户管理是提供给管理员进行人员管理和用户角色管理的功能模块,可以进行新增用户和分配角色。下面是一个典型的场景:
eg团队加入了新成员需要给这位成员分配一个使用系统的账号需要以下几个步骤
- 步骤 1:点击“系统管理”>“用户管理”>“人员管理”>“新增用户”,输入“账号”、“实名”、“密码”,根据此账号所需要的权限,选择此账号所对应的角色。如果有满足权限的角色,则用户新增成功。如果没有满足权限的角色,则需要新增角色(步骤 2
- 步骤 2:点击“系统管理”>“用户管理”>“角色管理”>“新增角色”。输入角色名称和描述,给此角色分配权限,点击“确定”,角色新增成功
- 步骤 3:根据此新增的角色,参考步骤 1重新新增用户
- 步骤 4:此用户账号新增成功,可以进行登录产品使用
![text](http://img-ys011.didistatic.com/static/dc2img/do1_1gectG2B9xHKfEsapUJq)
### 5.3.2、接入集群
- 步骤 1:点击“多集群管理”>“接入集群”
- 步骤 2:填写相关集群信息
- 集群名称:支持中英文、下划线、短划线(-),最长 128 字符。平台内不能重复
- Bootstrap Servers输入 Bootstrap Servers 地址。输入完成之后会进行连接测试,测试完成之后会给出测试结果连接成功 or 连接失败(以及失败的原因)。
- Zookeeper输入 zookeeper 地址,输入完成之后会进行连接测试,测试完成之后会给出测试结果连接成功 or 连接失败(以及失败的原因)
- Metrics 选填JMX Port输入 JMX 端口号MaxConn输入服务端最大允许的连接数
- Security若有 JMX 账号密码,则输入账号密码
- Version选择所支持的 kafka 版本,如果没有匹配则可以选择相近版本
- 集群配置选填:输入用户创建 kafka 客户端进行信息获取的相关配置
- 集群描述:最多 200 字符
![text](http://img-ys011.didistatic.com/static/dc2img/do1_2uxzaT3GTLWUifVg7xhd)
### 5.3.3、新增 Topic
- 步骤 1:点击“多集群管理”>“集群卡片”>“Topic”>“Topics”>“新增 Topic”按钮>“创建 Topic“抽屉
- 步骤 2:输入“Topic 名称不能重复”、“Topic 描述”、“分区数”、“副本数”、“数据保存时间”、“清理策略(删除或压缩)”
- 步骤 3:展开“更多配置”可以打开高级配置选项,根据自己需要输入相应配置参数
- 步骤 4:点击“确定”,创建 Topic 完成
![text](http://img-ys011.didistatic.com/static/dc2img/do1_dCZapJWwGPaumUADUvlB)
### 5.3.4、Topic 扩分区
- 步骤 1:点击“多集群管理”>“集群卡片”>“Topic”>“Topics”>“Topic 列表“>操作项”扩分区“>“扩分区”抽屉
- 步骤 2:扩分区抽屉展示内容为“流量的趋势图”、“当前分区数及支持的最低消息写入速率”、“扩分区后支持的最低消息写入速率”
- 步骤 3:输入所需的分区总数,自动计算出扩分区后支持的最低消息写入速率
- 步骤 4:点击确定,扩分区完成
![text](http://img-ys011.didistatic.com/static/dc2img/do1_FeT51Tn56GtCCTbul8Ly)
### 5.3.5、Topic 批量扩缩副本
- 步骤 1:点击“多集群管理”>“集群卡片”>“Topic”>“Topics”>“批量操作下拉“>“批量扩缩副本“>“批量扩缩容”抽屉
- 步骤 2:选择所需要进行扩缩容的 Topic可多选所选择的 Topic 出现在下方 Topic 列表中
- 步骤 3:Topic 列表展示 Topic“近三天平均流量”、“近三天峰值流量及时间”、“Partition 数”、”当前副本数“、“新副本数”
- 步骤 4:扩容时,选择目标节点,新增的副本会在选择的目标节点上;缩容时不需要选择目标节点,自动删除最后一个(或几个)副本
- 步骤 5:输入迁移任务配置参数,包含限流值和任务执行时间
- 步骤 6:输入任务描述
- 步骤 7:点击“确定”,创建 Topic 扩缩副本任务
- 步骤 8:去“Job”模块的 Job 列表查看创建的任务,如果已经执行则可以查看执行进度;如果未开始执行则可以编辑任务
![text](http://img-ys011.didistatic.com/static/dc2img/do1_bqr3jDYNnTzaCSwXYnI6)
### 5.3.6、Topic 批量迁移
- 步骤 1:点击“多集群管理”>“集群卡片”>“Topic”>“Topics”>“批量操作下拉“>“批量迁移“>“批量迁移”抽屉
- 步骤 2:选择所需要进行迁移的 Topic可多选所选择的 Topic 出现在下方 Topic 列表中
- 步骤 3:选择所需要迁移的 partition 和迁移数据的时间范围
- 步骤 4:选择目标节点(节点数必须不小于最大副本数)
- 步骤 5:点击“预览任务计划”,打开“任务计划”二次抽屉,可对目标 Broker ID 进行编辑
- 步骤 6:输入迁移任务配置参数,包含限流值和任务执行时间
- 步骤 7:输入任务描述
- 步骤 8:点击“确定”,创建 Topic 迁移任务
- 步骤 9:去“Job”模块的 Job 列表查看创建的任务,如果已经执行则可以查看执行进度;如果未开始执行则可以编辑任务
![text](http://img-ys011.didistatic.com/static/dc2img/do1_ECRMSVF7NUf8HeserFuk)
### 5.3.7、设置 Cluster 健康检查规则
- 步骤 1:点击“多集群管理”>“集群卡片”>“Cluster”>“Overview”>“集群健康状态旁边 icon”>“健康度设置抽屉”
- 步骤 2:健康度设置抽屉展示出了检查项和其对应的权重,可以修改检查项的检查规则
- 步骤 3:检查规则可配置,分别为
- Cluster集群 controller 数不等于 1数字不可配置不通过
- BrokerRequestQueueSize 大于等于 10默认为 10可配置数字不通过
- BrokerNetworkProcessorAvgIdlePercent 的 Idle 小于等于 0.8%(默认为 0.8%,可配置数字)不通过
- Topic无 leader 的 Topic 数量,大于等于 1默认为 1数字可配置不通过
- TopicTopic 在 10默认为 10数字可配置个周期内 8默认为 8数字可配置个周期内处于未同步的状态则不通过
- ConsumerGroupGroup 在 10默认为 10数字可配置个周期内进行 8默认为 8数字可配置次 re-balance 不通过
- 步骤 4:设置完成后,点击“确认”,健康检查规则设置成功
![text](http://img-ys011.didistatic.com/static/dc2img/do1_Md6TtfIGYQ2BWUytqeF4)
### 5.3.8、图表指标筛选
- 步骤 1:点击“多集群管理”>“集群卡片”>“Cluster”>“Overview”>“指标筛选 icon”>“指标筛选抽屉”
- 步骤 2:指标筛选抽屉展示信息为以下几类“Health”、“Cluster”、“Broker”、“Consumer”、“Security”、“Job”
- 步骤 3:默认勾选比较重要的指标进行展示。根据需要选中/取消选中相应指标,点击”确认“,指标筛选成功,展示的图表随之变化
![text](http://img-ys011.didistatic.com/static/dc2img/do1_bRWCetcKReMAT3BjAlSZ)
### 5.3.9、编辑 Broker 配置
- 步骤 1:点击“多集群管理”>“集群卡片”>“Brokers”>“Broker ID”>“Configuration”TAB>“编辑”按钮
- 步骤 2:输入配置项的新配置内容
- 步骤 3:(选填)点击“应用于全部 Broker”将此配置项的修改应用于全部的 Broker
- 步骤 4:点击“确认”Broker 配置修改成功
![text](http://img-ys011.didistatic.com/static/dc2img/do1_anLQzYlq1gjMltsiqeRA)
### 5.3.10、重置 consumer Offset
- 步骤 1:点击“多集群管理”>“集群卡片”>“Consumer”>“Consumer Group”名称>“Consumer Group 详情”抽屉>“重置 Offset”按钮>“重置 Offset”抽屉
- 步骤 2:选择重置 Offset 的类型,可“重置到指定时间”或“重置分区”
- 步骤 3:重置到指定时间,可选择“最新 Offset”或“自定义时间”
- 步骤 4:重置分区,可选择 partition 和其重置的 offset
- 步骤 5:点击“确认”,重置 Offset 开始执行
![text](http://img-ys011.didistatic.com/static/dc2img/do1_Lv2kxCbpSsuPGYljjEtD)
### 5.3.11、新增 ACL
- 步骤 1:点击“多集群管理”>“集群卡片”>“Security”>“Users”>“新增 ACL”
- 步骤 2:输入 ACL 配置参数
- ACL 用途:生产权限、消费权限、自定义权限
- 生产权限时:可选择应用于所有 Kafka User 或者特定 Kafka User可选择应用于所有 Topic 或者特定 Topic
- 消费权限时:可选择应用于所有 Kafka User 或者特定 Kafka User可选择应用于所有 Topic 或者特定 Topic可选择应用于所有 Consumer Group 或者特定 Consumer Group
- 步骤 3:点击“确定”,新增 ACL 成功
![text](http://img-ys011.didistatic.com/static/dc2img/do1_P2a965if8t5Pjx79r1j3)
## 5.4、全部功能
### 5.4.1、登录/退出登录
- 登录:输入账号密码,点击登录
- 退出登录:鼠标悬停右上角“头像”或者“用户名”,出现小弹窗“登出”,点击“登出”,退出登录
### 5.4.2、系统管理
用户登录完成之后,点击页面右上角【系统管理】按钮,切换到系统管理的视角,可以进行配置管理、用户管理、审计日志查看。
![text](http://img-ys011.didistatic.com/static/dc2img/do1_xffkghPlUAzDiqj8wF7s)
#### 5.4.2.1、配置管理
配置管理是提供给管理员一个快速配置配置文件的能力,所配置的配置文件将会在对应模块生效。
#### 5.4.2.2、查看配置列表
- 步骤 1:点击”系统管理“>“配置管理”
- 步骤 2:列表展示配置所属模块、配置键、配置值、启用状态、更新时间、更新人。列表有操作项编辑、删除,可对配置模块、配置键、配置值、描述、启用状态进行配置,也可删除此条配置
![text](http://img-ys011.didistatic.com/static/dc2img/do1_gg8SMKKn9N6FrtFgJ2r8)
#### 5.4.2.3、新增配置
- 步骤 1:点击“系统管理”>“配置管理”>“新增配置”
- 步骤 2模块下拉选择所有可配置的模块配置键不限制输入内容500 字以内;配置值:代码编辑器样式,不限内容不限长度;启用状态开关:可以启用/禁用此项配置
![text](http://img-ys011.didistatic.com/static/dc2img/do1_d9hHB5Anb1FjP2IIiCVh)
#### 5.4.2.4、编辑配置
可对配置模块、配置键、配置值、描述、启用状态进行配置。
#### 5.4.2.5、用户管理
用户管理是提供给管理员进行人员管理和用户角色管理的功能模块,可以进行新增用户和分配角色。
#### 5.4.2.6、人员管理列表
- 步骤 1:点击“系统管理”>“用户管理”>“人员管理”
- 步骤 2:人员管理列表展示用户角色、用户实名、用户分配的角色、更新时间、编辑操作。
- 步骤 3:列表支持”用户账号“、“用户实名”、“角色名”筛选。
![text](http://img-ys011.didistatic.com/static/dc2img/do1_7LUdIbIPY61W7bqQaTDK)
#### 5.4.2.7、新增用户
- 步骤 1:点击“系统管理”>“用户管理”>“人员管理”>“新增用户”
- 步骤 2:填写“用户账号”、“用户实名”、“用户密码”这些必填参数,可以对此账号分配已经存在的角色。
![text](http://img-ys011.didistatic.com/static/dc2img/do1_lsmPRbb2uTE1QCM6Pxih)
#### 5.4.2.8、编辑用户
- 步骤 1:点击“系统管理”>“用户管理”>“人员管理”>列表操作项“编辑”
- 步骤 2:用户账号不可编辑;可以编辑“用户实名”,修改“用户密码”,重新分配“用户角色“
![text](http://img-ys011.didistatic.com/static/dc2img/do1_9HXnM9FC3krYERmZwSHL)
#### 5.4.2.9、角色管理列表
- 步骤 1:点击“系统管理”>“用户管理”>“角色管理”
- 步骤 2:角色列表展示信息为“角色 ID”、“名称”、“描述”、“分配用户数”、“最后修改人”、“最后更新时间”、操作项“查看详情”、操作项”分配用户“
- 步骤 3:列表有筛选框,可对“角色名称”进行筛选
- 步骤 4:列表操作项,“查看详情”可查看到角色绑定的权限项,”分配用户“可对此项角色下绑定的用户进行增减
![text](http://img-ys011.didistatic.com/static/dc2img/do1_iru2gmXHCY6lI6hRNBKm)
#### 5.4.2.10、新增角色
- 步骤 1:点击“系统管理”>“用户管理”>“角色管理”>“新增角色”
- 步骤 2:输入“角色名称”(角色名称只能由中英文大小写、数字、下划线\_组成长度限制在 3 128 字符)、“角色描述“(不能为空)、“分配权限“(至少需要分配一项权限),点击确认,新增角色成功添加到角色列表
![text](http://img-ys011.didistatic.com/static/dc2img/do1_dTlQYcV4gPzQGqd6uYhm)
#### 5.4.2.11、审计日志
- 步骤 1:点击“系统管理”>“审计日志“
- 步骤 2:审计日志包含所有对于系统的操作记录,操作记录列表展示信息为下
- “模块”:操作对象所属的功能模块
- “操作对象”:具体哪一个集群、任务 ID、topic、broker、角色等
- “行为”:操作记录的行为,包含“新增”、“替换”、“读取”、“禁用”、“修改”、“删除”、“编辑”等
- “操作内容”:具体操作的内容是什么
- “操作时间”:操作发生的时间
- “操作人”:此项操作所属的用户
- 步骤 3:操作记录列表可以对“模块“、”操作对象“、“操作内容”、”操作时间“进行筛选
![text](http://img-ys011.didistatic.com/static/dc2img/do1_giPBGraylRaSDcF2ZeyA)
### 5.4.3、多集群管理
#### 5.4.3.1、多集群列表
- 步骤 1:点击顶部导航栏“多集群管理”
- 步骤 2:多集群管理页面包含的信息为:”集群信息总览“、“集群列表”、“列表筛选项”、“接入集群”
- 步骤 3:集群列表筛选项为
- 集群信息总览cluster 总数、live 数、down 数
- 版本筛选:包含所有存在的集群版本
- 健康分筛选:筛选项为 0、10、20、30、40、50、60、70、80、90、100
- live、down 筛选:多选
- 下拉框筛选排序选项维度为“接入时间”、“健康分“、”Messages“、”MessageSize“、”BytesIn“、”BytesOut“、”Brokers“可对这些维度进行“升序”、“降序”排序
- 步骤 4:每个卡片代表一个集群其所展示的集群概览信息包括“健康分及健康检查项通过数”、“broker 数量”、“ZK 数量”、“版本号”、“BytesIn 均衡状态”、“BytesOut 均衡状态”、“Disk 均衡状态”、”Messages“、“MessageSize”、“BytesIn”、“BytesOut”、“接入时间”
![text](http://img-ys011.didistatic.com/static/dc2img/do1_yciHsqZQkLChT8guTEdl)
#### 5.4.3.2、接入集群
- 步骤 1:点击“多集群管理”>“接入集群”
- 步骤 2:填写相关集群信息
- 集群名称:平台内不能重复
- Bootstrap Servers输入 Bootstrap Servers 地址,输入完成之后会进行连接测试,测试完成之后会给出测试结果连接成功 or 连接失败(以及失败的原因)。
- Zookeeper输入 zookeeper 地址,输入完成之后会进行连接测试,测试完成之后会给出测试结果连接成功 or 连接失败(以及失败的原因)
- Metrics 选填JMX Port输入 JMX 端口号MaxConn输入服务端最大允许的连接数
- Security若有 JMX 账号密码,则输入账号密码
- Versionkafka 版本,如果没有匹配则可以选择相近版本
- 集群配置选填:用户创建 kafka 客户端进行信息获取的相关配置
![text](http://img-ys011.didistatic.com/static/dc2img/do1_bRWCetcKReMAT3BjAlSZ)
#### 5.4.3.3、删除集群
- 步骤 1:点击“多集群管理”>鼠标悬浮集群卡片>点击卡片右上角“删除 icon”>打开“删除弹窗”
- 步骤 2:在删除弹窗中的“集群名称”输入框,输入所要删除集群的集群名称,点击“删除”,成功删除集群,解除平台的纳管关系(集群资源不会删除)
![text](http://img-ys011.didistatic.com/static/dc2img/do1_8c9AB3k68ggrvj3yN8bl)
### 5.4.4、Cluster 管理
#### 5.4.4.1、Cluster Overview
- 步骤 1:点击“多集群管理”>“集群卡片”>进入单集群管理界面
- 步骤 2:左侧导航栏
- 一级导航Cluster二级导航Overview、Load Rebalance
- 一级导航Broker二级导航Overview、Brokers、Controller
- 一级导航Topic二级导航Overview、Topics
- 一级导航Consumer
- 一级导航Testing二级导航Produce、Consume
- 一级导航Security二级导航ACLs、Users
- 一级导航Job
![text](http://img-ys011.didistatic.com/static/dc2img/do1_YIXlGylpecRkwbhzJtpF)
#### 5.4.4.2、查看 Cluster 概览信息
- 步骤 1:点击“多集群管理”>“集群卡片”>“Cluster”>“Overview”
- 步骤 2:cluster 概览信息包括以下内容
- 集群健康分,健康检查通过项
- Cluster 信息:包含名称、版本、均衡状态
- Broker 信息Broker 总数、controller 信息、similar config 信息
- Topic 信息Topic 总数、No Leader、<Min ISRURP
- Consumer Group 信息Consumer Group 总数是否存在 Dead 情况
- 指标图表
- 历史变更记录名称时间内容类型
![text](http://img-ys011.didistatic.com/static/dc2img/do1_YIXlGylpecRkwbhzJtpF)
#### 5.4.4.3、设置 Cluster 健康检查规则
- 步骤 1:点击多集群管理>“集群卡片”>“Cluster”>“Overview”>“集群健康状态旁边 icon”>“健康度设置抽屉”
- 步骤 2:健康度设置抽屉展示出了检查项和其对应的权重,可以修改检查项的检查规则
- 步骤 3:检查规则可配置,分别为
- Cluster集群 controller 数不等于 1数字不可配置不通过
- BrokerRequestQueueSize 大于等于 10默认为 10可配置数字不通过
- BrokerNetworkProcessorAvgIdlePercent 的 Idle 小于等于 0.8%(默认为 0.8%,可配置数字)不通过
- Topic无 leader 的 Topic 数量,大于等于 1默认为 1数字可配置不通过
- TopicTopic 在 10默认为 10数字可配置个周期内 8默认为 8数字可配置个周期内处于未同步的状态
- ConsumerGroupGroup 在 10默认为 10数字可配置个周期内进行 8默认为 8数字可配置次 re-balance 不通过
- 步骤 4:设置完成后,点击“确认”,健康检查规则设置成功
![text](http://img-ys011.didistatic.com/static/dc2img/do1_ajKNtGeWgqZNFhN1r1Wv)
#### 5.4.4.4、查看 Cluster 健康检查详情
- 步骤 1:点击“多集群管理”>“集群卡片”>“Cluster”>“Overview”>“集群健康状态旁边【查看详情】”>“健康检查详情抽屉”
- 步骤 2:健康检查详情抽屉展示信息为:“检查模块”、“检查项”、“权重”、“得分”、“检查时间”、“检查结果是否通过”,若未通过会展示未通过的对象
![text](http://img-ys011.didistatic.com/static/dc2img/do1_TuXSU5PHb7PXKf3jTwkU)
#### 5.4.4.5、编辑 Cluster 信息
- 步骤 1:点击“多集群管理”>“集群卡片”>“Cluster”>“Overview”>“Cluster 名称旁边编辑 icon”>“编辑集群抽屉”
- 步骤 2:可编辑的信息包括“集群名称”、“Bootstrap Servers”、“Zookeeper”、“JMX Port”、“Maxconn最大连接数”、“Security认证措施”、“Version版本号”、“集群配置”、“集群描述”
- 步骤 3:点击“确定”,成功编辑集群信息
![text](http://img-ys011.didistatic.com/static/dc2img/do1_lqvML71UvjwpPsxqvAS1)
#### 5.4.4.6、图表指标筛选
- 步骤 1:点击“多集群管理”>“集群卡片”>“Cluster”>“Overview”>“指标筛选 icon”>“指标筛选抽屉”
- 步骤 2:指标筛选抽屉展示信息为以下几类“Health”、“Cluster”、“Broker”、“Consumer”、“Security”、“Job”
- 步骤 3:默认勾选比较重要的指标进行展示。根据需要选中/取消选中相应指标,点击”确认“,指标筛选成功,展示的图表随之变化
![text](http://img-ys011.didistatic.com/static/dc2img/do1_IEeZFWD31gMYnjjg2tvT)
#### 5.4.4.7、图表时间筛选
- 步骤 1:点击“多集群管理”>“集群卡片”>“Cluster”>“Overview”>“时间选择下拉框”>“时间选择弹窗”
- 步骤 2:选择时间“最近 15 分钟”、“最近 1 小时”、“最近 6 小时”、“最近 12 小时”、“最近 1 天”,也可以自定义时间段范围
![text](http://img-ys011.didistatic.com/static/dc2img/do1_Ah4XsKQjpQCtXjCWnKJm)
#### 5.4.4.8、查看集群历史变更记录
- 步骤 1:点击“多集群管理”>“集群卡片”>“Cluster”>“Overview”>“历史变更记录”区域
- 步骤 2:历史变更记录区域展示了历史的配置变更,每条记录可展开收起。包含“配置对象”、“变更时间”、“变更内容”、“配置类型”
![text](http://img-ys011.didistatic.com/static/dc2img/do1_jXTVLBBbzS5y6cJJMl6t)
### 5.4.5、Load Rebalance企业版
#### 5.4.5.1、查看 Load Rebalance 概览信息
- 步骤 1:点击“多集群管理”>“集群卡片”>“Cluster”>“Load Rebalance”
- 步骤 2:Load Rebalance 概览信息包含“均衡状态卡片”、“Disk 信息卡片”、“BytesIn 信息卡片”、“BytesOut 信息卡片”、“Broker 均衡状态列表”
![text](http://img-ys011.didistatic.com/static/dc2img/do1_MeEqlaIrq7hK9ncWASIw)
#### 5.4.5.2、设置集群规格
提供对集群的每个节点的 Disk、BytesIn、BytesOut 的规格进行设置的功能
- 步骤 1:点击“多集群管理”>“集群卡片”>“Cluster”>“Load Rebalance”>“State 卡片 icon“>”设置集群规格抽屉“
- 步骤 2:穿梭框左侧展示集群中的待选节点,穿梭框右侧展示已经选中的节点,选择自己所需设置规格的节点
- 步骤 3:设置“单机核数”、“单机磁盘”、“单机网络”,点击确定,完成设置
![text](http://img-ys011.didistatic.com/static/dc2img/do1_JBs3ZNQPZNrGpgwj78Je)
#### 5.4.5.3、均衡状态列表筛选
- 步骤 1:点击“多集群管理”>“集群卡片”>“Cluster”>“Load Rebalance”>“筛选列表”按钮>筛选弹窗
- 步骤 2:可选择“Disk”、“BytesIn”、“BytesOut”三种维度其各自对应“已均衡”、“未均衡”两种状态可以组合进行筛选
- 步骤 3:点击“确认”,执行筛选操作
![text](http://img-ys011.didistatic.com/static/dc2img/do1_ExXNURKB5Ud99IzWASEJ)
#### 5.4.5.4、立即均衡
- 步骤 1:点击“多集群管理”>“集群卡片”>“Cluster”>“Load Rebalance”>“立即均衡”按钮>“立即均衡抽屉”
- 步骤 2:配置均衡策略
- 指标计算周期:默认近 10mins可选择
- 均衡维度:默认 Disk、BytesIn、BytesOut可选择
- 均衡区间:在表格内自定义配置均衡区间范围(单位:%,大于 0小于 100
- Topic 黑名单:选择 topic 黑名单。通过穿梭框(支持模糊选择)选出目标 topic本次均衡略过已选的 topic
- 步骤 3:配置运行参数
- 吞吐量优先:并行度 0无限制 策略是优先执行大小最大副本
- 稳定性优先: 并行度 1 ,策略是优先执行大小最小副本
- 自定义:可以自由设置并行度和优先执行的副本策略
- 限流值流量最大值0-99999 自定义
- 步骤 4:点击“预览计划”按钮,打开执行计划弹窗。可以看到计划概览信息、计划明细信息
- 步骤 5:点击“预览计划弹窗”的“执行文件”,可以下载 json 格式的执行文件
- 步骤 6:点击“预览计划弹窗”的“立即均衡”按钮,开始执行均衡任务
![text](http://img-ys011.didistatic.com/static/dc2img/do1_I5BzRuHC9m74uE3mrjy8)
#### 5.4.5.5、周期均衡
- 步骤 1:点击“多集群管理”>“集群卡片”>“Cluster”>“Load Rebalance”>“周期均衡”按钮>“周期均衡抽屉”
- 步骤 2:配置均衡策略
- 指标计算周期:默认近 10mins可选择
- 均衡维度:默认 Disk、BytesIn、BytesOut可选择
- 均衡区间:在表格内自定义配置均衡区间范围(单位:%,大于 0小于 100
- Topic 黑名单:选择 topic 黑名单。通过穿梭框(支持模糊选择)选出目标 topic本次均衡略过已选的 topic
- 步骤 3:配置运行参数
- 任务并行度:每个节点同时迁移的副本数量
- 任务周期:时间选择器,自定义选择运行周期
- 稳定性优先: 并行度 1 ,策略是优先执行大小最小副本
- 自定义:可以自由设置并行度和优先执行的副本策略
- 限流值流量最大值0-99999 自定义
- 步骤 4:点击“预览计划”按钮,打开执行计划弹窗。可以看到计划概览信息、计划明细信息
- 步骤 5:点击“预览计划弹窗”的“执行文件”,可以下载 json 格式的执行文件
- 步骤 6:点击“预览计划弹窗”的“立即均衡”按钮,开始执行均衡任务
![text](http://img-ys011.didistatic.com/static/dc2img/do1_QGfzkR6CM8qICuFqTAuI)
### 5.4.6、Broker
#### 5.4.6.1、查看 Broker 概览信息
- 步骤 1:点击“多集群管理”>“集群卡片”>“Broker”>“Overview”
- 步骤 2:Broker 概览信息包括以下内容
- 集群健康分,健康检查通过项
- Broker 信息:包含名称、版本、均衡状态
- Broker 信息Broker 总数、controller 信息、similar config 信息
- Topic 信息Topic 总数、No Leader、<Min ISRURP
- Consumer Group 信息Consumer Group 总数是否存在 Dead 情况
- 指标图表
- 历史变更记录名称时间内容类型
![text](http://img-ys011.didistatic.com/static/dc2img/do1_NrWcctRKTaEia2UuwAie)
#### 5.4.6.2、编辑 Broker 配置
- 步骤 1:点击多集群管理>“集群卡片”>“Brokers”>“Broker ID”>“Configuration”TAB>“编辑”按钮
- 步骤 2:输入配置项的新配置内容
- 步骤 3:(选填)点击“应用于全部 Broker”将此配置项的修改应用于全部的 Broker
- 步骤 4:点击“确认”Broker 配置修改成功
![text](http://img-ys011.didistatic.com/static/dc2img/do1_wdNA5LQiNUDRGuWYCzEX)
#### 5.4.6.3、查看 Broker DataLogs
- 步骤 1:点击“多集群管理”>“集群卡片”>“Brokers”>“Broker ID”>“Data Logs”TAB>“编辑”按钮
- 步骤 2:Broker DataLogs 列表展示的信息为“Folder”、“topic”、“Partition”、“Offset Lag”、“Size”
- 步骤 3:输入框输入”Topic Name“可以筛选结果
![text](http://img-ys011.didistatic.com/static/dc2img/do1_LfTeBEkwaLsX95Ep1ix3)
#### 5.4.6.4、查看 Controller 列表
- 步骤 1:点击“多集群管理”>“集群卡片”>“Broker”>“Controller”
- 步骤 2:Controller 列表展示的信息为“Change Time”、“Broker ID”、“Broker Host”
- 步骤 3:输入框输入“Broker Host“可以筛选结果
- 步骤 4:点击 Broker ID 可以打开 Broker 详情,进行修改配置或者查看 DataLogs
![text](http://img-ys011.didistatic.com/static/dc2img/do1_PwqY9cZ1DbIpBRC2mJE9)
### 5.4.7、Topic
#### 5.4.7.1、查看 Topic 概览信息
- 步骤 1:点击“多集群管理”>“集群卡片”>“Topic”>“Overview”
- 步骤 2:Topic 概览信息包括以下内容
- 集群健康分,健康检查通过项
- TopicsTopic 总数
- PartitionsPartition 总数
- PartitionNoLeader没有 leader 的 partition 个数
- < Min ISR同步副本数小于 Min ISR
- =Min ISR同步副本数等于 Min ISR
- Topic 指标图表
![text](http://img-ys011.didistatic.com/static/dc2img/do1_LTYaGiXhE5bI3CAApWwx)
#### 5.4.7.2、查看 Topic 健康检查详情
- 步骤 1:点击多集群管理>“集群卡片”>“Topic”>“Overview”>“集群健康状态旁边【查看详情】”>“健康检查详情抽屉”
- 步骤 2:健康检查详情抽屉展示信息为:“检查项”、“权重”、“得分”、“检查时间”、“检查结果是否通过”,若未通过会展示未通过的对象
![text](http://img-ys011.didistatic.com/static/dc2img/do1_Kiq1nhPtJTgG7xcLLH9H)
#### 5.4.7.3、查看 Topic 列表
- 步骤 1:点击“多集群管理”>“集群卡片”>“Topic”>“Topics”
- 步骤 2:Topic 列表展示内容为“TopicName”、“Partitions”、“Replications”、“健康分”、“BytesIn”、“BytesOut”、“MessageSize”、“保存时间”、“描述”、操作项”扩分区“、操作项”删除“
- 步骤 3:筛选框输入“TopicName”可以对列表进行筛选点击“展示系统 Topic”开关可以筛选系统 topic
![text](http://img-ys011.didistatic.com/static/dc2img/do1_kenpn9ijRb2DbPN7wrr1)
#### 5.4.7.4、新增 Topic
- 步骤 1:点击“多集群管理”>“集群卡片”>“Topic”>“Topics”>“新增 Topic”按钮>“创建 Topic“抽屉
- 步骤 2:输入“Topic 名称不能重复”、“Topic 描述”、“分区数”、“副本数”、“数据保存时间”、“清理策略(删除或压缩)”
- 步骤 3:展开“更多配置”可以打开高级配置选项,根据自己需要输入相应配置参数
- 步骤 4:点击“确定”,创建 Topic 完成
![text](http://img-ys011.didistatic.com/static/dc2img/do1_ZsaKRRqT69Ugw5yCHpE7)
#### 5.4.7.5、Topic 扩分区
- 步骤 1:点击“多集群管理”>“集群卡片”>“Topic”>“Topics”>“Topic 列表“>操作项”扩分区“>“扩分区”抽屉
- 步骤 2:扩分区抽屉展示内容为“流量的趋势图”、“当前分区数及支持的最低消息写入速率”、“扩分区后支持的最低消息写入速率”
- 步骤 3:输入所需的分区总数,自动计算出扩分区后支持的最低消息写入速率
- 步骤 4:点击确定,扩分区完成
![text](http://img-ys011.didistatic.com/static/dc2img/do1_ifCma3pKlUnGd3UXunNi)
#### 5.4.7.6、删除 Topic
- 步骤 1:点击“多集群管理”>“集群卡片”>“Topic”>“Topics”>“Topic 列表“>操作项”删除“>“删除 Topic”弹窗
- 步骤 2:输入“TopicName”进行二次确认
- 步骤 3:点击“删除”,删除 Topic 完成
![text](http://img-ys011.didistatic.com/static/dc2img/do1_xdP42WmnyaK9zZiMWM6s)
#### 5.4.7.7、Topic 批量扩缩副本
- 步骤 1:点击“多集群管理”>“集群卡片”>“Topic”>“Topics”>“批量操作下拉“>“批量扩缩副本“>“批量扩缩容”抽屉
- 步骤 2:选择所需要进行扩缩容的 Topic可多选所选择的 Topic 出现在下方 Topic 列表中
- 步骤 3:Topic 列表展示 Topic“近三天平均流量”、“近三天峰值流量及时间”、“Partition 数”、”当前副本数“、“新副本数”
- 步骤 4:扩容时,选择目标节点,新增的副本会在选择的目标节点上;缩容时不需要选择目标节点,自动删除最后一个(或几个)副本
- 步骤 5:输入迁移任务配置参数,包含限流值和任务执行时间
- 步骤 6:输入任务描述
- 步骤 7:点击“确定”,执行 Topic 扩缩容任务
![text](http://img-ys011.didistatic.com/static/dc2img/do1_DNIdGs7Uym3yppmvGrBd)
#### 5.4.7.8、Topic 批量迁移
- 步骤 1:点击“多集群管理”>“集群卡片”>“Topic”>“Topics”>“批量操作下拉“>“批量迁移“>“批量迁移”抽屉
- 步骤 2:选择所需要进行迁移的 Topic可多选所选择的 Topic 出现在下方 Topic 列表中
- 步骤 3:选择所需要迁移的 partition 和迁移数据的时间范围
- 步骤 4:选择目标节点(节点数必须不小于最大副本数)
- 步骤 5:点击“预览任务计划”,打开“任务计划”二次抽屉,可对每个 partition 的目标 Broker ID 进行编辑,目标 broker 应该等于副本数
- 步骤 6:输入迁移任务配置参数,包含限流值和任务执行时间
- 步骤 7:输入任务描述
- 步骤 8:点击“确定”,执行 Topic 迁移任务
![text](http://img-ys011.didistatic.com/static/dc2img/do1_Xm5fExFrN7Q1m6uWcbrR)
### 5.4.8、Consumer
#### 5.4.8.1、Consumer Overview
- 步骤 1:点击“多集群管理”>“集群卡片”>“Consumer”
- 步骤 2:Consumer 概览信息包括以下内容
- 集群健康分,健康检查通过项
- GroupsConsumer Group 总数
- GroupsActives活跃的 Group 总数
- GroupsEmptysEmpty 的 Group 总数
- GroupRebalance进行 Rebalance 的 Group 总数
- GroupDeadsDead 的 Group 总数
- Consumer Group 列表
- 步骤 3:输入“Consumer Group”、“Topic Name可对列表进行筛选
- 步骤 4:点击列表“Consumer Group”名称可以查看 Comsuer Group 详情
![text](http://img-ys011.didistatic.com/static/dc2img/do1_y7EQwDvJGSVHbpLntZCX)
#### 5.4.8.2、查看 Consumer 列表
- 步骤 1:点击“多集群管理”>“集群卡片”>“Consumer”>“Consumer Group”名称>“Consumer Group 详情”抽屉
- 步骤 2:Consumer Group 详情有列表视图和图表视图
- 步骤 3:列表视图展示信息为 Consumer 列表包含”Topic Partition“、”Member ID“、”Current Offset“、“Log End Offset”、”Lag“、”Host“、”Client ID“
![text](http://img-ys011.didistatic.com/static/dc2img/do1_fb9fbUTfBDwVN8iXyQM9)
#### 5.4.8.3、重置 Offset
- 步骤 1:点击“多集群管理”>“集群卡片”>“Consumer”>“Consumer Group”名称>“Consumer Group 详情”抽屉>“重置 Offset”按钮>“重置 Offset”抽屉
- 步骤 2:选择重置 Offset 的类型,可“重置到指定时间”或“重置分区”
- 步骤 3:重置到指定时间,可选择“最新 Offset”或“自定义时间”
- 步骤 4:重置分区,可选择 partition 和其重置的 offset
- 步骤 5:点击“确认”,重置 Offset 开始执行
![text](http://img-ys011.didistatic.com/static/dc2img/do1_bflSMxUjzwR5Jq5TrHyH)
### 5.4.9、Testing企业版
#### 5.4.9.1、生产测试
- 步骤 1:点击“多集群管理”>“集群卡片”>“Testing”>“Produce”
- 步骤 2:生产配置
- Data选择数据写入的 topic输入写入数据的 key暂只支持 string 格式),输入写入数据的 value暂只支持 string 格式)。其中 key 和 value 可以随机生成
- Flow输入单次发送的消息数量默认为 1可以手动修改。选择手动生产模式代表每次点击按钮【Run】执行生产选择周期生产模式需要填写运行总时间和运行时间间隔。
- Header输入 Header 的 keyvalue
- Options选择 Froce Partition代表消息仅发送到这些选择的 Partition。选择数据压缩格式。选择 Acks 参数none 意思是消息发送了就认为发送成功leader 意思是 leader 接收到消息(不管 follower 有没有同步成功认为消息发送成功all 意思是所有的 follower 消息同步成功认为是消息发送成功
- 步骤 3:点击按钮【Run】生产测试开始可以从右侧看到生产测试的信息
![text](http://img-ys011.didistatic.com/static/dc2img/do1_1pkBHvyVpGqTyUlSusUJ)
#### 5.4.9.2、消费测试
- 步骤 1:点击“多集群管理”>“集群卡片”>“Testing”>“Consume”
- 步骤 2:消费配置
- Topic选择数据从哪个 topic 进行消费
- Start From选择数据从什么地方开始消费可以根据时间选择或者根据 Offset 进行选择
- Until选择消费截止到什么地方可以根据时间或者 offset 或者消息数等进行选择
- Filter选择过滤器的规则。包含/不包含某【keyvalue】等于/大于/小于多少条消息
- 步骤 3:点击按钮【Run】消费测试开始可以在右边看到消费的明细信息
![text](http://img-ys011.didistatic.com/static/dc2img/do1_3fjHM3uDIpV6UIVEaHeQ)
### 5.4.10、Security
注意:只有在开启集群认证的情况下才能够使用 Security 功能
#### 5.4.10.1、查看 ACL 概览信息
- 步骤 1:点击“多集群管理”>“集群卡片”>“Security”>“ACLs”
- 步骤 2:ACL 概览信息包括以下内容
- Enable是否可用
- ACLsACL 总数
- UsersUser 总数
- TopicsTopic 总数
- Consumer GroupsConsumer Group 总数
- ACL 列表
![text](http://img-ys011.didistatic.com/static/dc2img/do1_vE2GwXmBwlQCtE4HfhBz)
#### 5.4.10.2、新增 ACl
- 步骤 1:点击“多集群管理”>“集群卡片”>“Security”>“Users”>“新增 ACL”
- 步骤 2:输入 ACL 配置参数
- ACL 用途:生产权限、消费权限、自定义权限
- 生产权限时:可选择应用于所有 Kafka User 或者特定 Kafka User可选择应用于所有 Topic 或者特定 Topic
- 消费权限时:可选择应用于所有 Kafka User 或者特定 Kafka User可选择应用于所有 Topic 或者特定 Topic可选择应用于所有 Consumer Group 或者特定 Consumer Group
- 步骤 3:点击“确定”,新增 ACL 成功
![text](http://img-ys011.didistatic.com/static/dc2img/do1_ygNmK5QIQcC8BsskMDy7)
#### 5.4.10.3、查看 User 信息
- 步骤 1:点击“多集群管理”>“集群卡片”>“Security”>“ACLs”
- 步骤 2:User 列表展示内容包括“Kafka User 名称”、“认证方式”、“passwprd”、操作项”修改密码“、”操作项“删除”
- 步骤 3:筛选框输入“Kafka User”可筛选出列表中相关 Kafka User
![text](http://img-ys011.didistatic.com/static/dc2img/do1_bK7aK12qgxACxxSIrEJw)
#### 5.4.10.4、新增 Kafka User
- 步骤 1:点击“多集群管理”>“集群卡片”>“Security”>“Users”>“新增 Kafka User”
- 步骤 2:输入 Kafka User 名称、认证方式、密码
- 步骤 3:点击“确定”,新增 Kafka User 成功
![text](http://img-ys011.didistatic.com/static/dc2img/do1_1eaY4UW5X4ELbzGfHmVY)
### 5.4.11、Job
#### 5.4.11.1、查看 Job 概览信息
- 步骤 1:点击“多集群管理”>“集群卡片”>“Job“
- 步骤 2:Job 概览信息包括以下内容
- JobsJob 总数
- Doing正在运行的 Job 总数
- Prepare准备运行的 Job 总数
- Success运行成功的 Job 总数
- Fail运行失败的 Job 总数
- Job 列表
![text](http://img-ys011.didistatic.com/static/dc2img/do1_VZQD2jmZvjIxIDkzX7NL)
#### 5.4.11.2、Job 查看进度
Doing 状态下的任务可以查看进度
- 步骤 1:点击“多集群管理”>“集群卡片”>“Job”>“Job”列表>操作项“查看进度”>“查看进度”抽屉
- 步骤 2:
- 均衡任务:任务基本信息、均衡计划、任务执行明细信息
- 扩缩副本:任务基本信息、任务执行明细信息、节点流量情况
- Topic 迁移:任务基本信息、任务执行明细信息、节点流量情况
![text](http://img-ys011.didistatic.com/static/dc2img/do1_K8mefUIhHKeWqZDU8vjy)
#### 5.4.11.3、Job 编辑任务
Prepare 状态下的任务可以进行编辑
- 点击“多集群管理”>“集群卡片”>“Job”>“Job”列表>操作项“编辑”
- 对任务执行的参数进行重新配置
- 集群均衡可以对指标计算周期、均衡维度、topic 黑名单、运行配置等参数重新设置
- Topic 迁移:可以对 topic 需要迁移的 partition、迁移数据的时间范围、目标 broker 节点、限流值、执行时间、描述等参数重新配置
- topic 扩缩副本:可以对最终副本数、限流值、任务执行时间、描述等参数重新配置
- 点击“确定”,编辑任务成功
![text](http://img-ys011.didistatic.com/static/dc2img/do1_HKGRvGEA8lD3374WLckZ)

View File

@@ -1,98 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.xiaojukeji.kafka</groupId>
<artifactId>km-biz</artifactId>
<version>${km.revision}</version>
<packaging>jar</packaging>
<parent>
<artifactId>km</artifactId>
<groupId>com.xiaojukeji.kafka</groupId>
<version>${km.revision}</version>
</parent>
<properties>
<!-- maven properties -->
<maven.test.skip>true</maven.test.skip>
<downloadSources>true</downloadSources>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<file_encoding>UTF-8</file_encoding>
</properties>
<dependencies>
<dependency>
<groupId>com.xiaojukeji.kafka</groupId>
<artifactId>km-core</artifactId>
<version>${project.parent.version}</version>
</dependency>
<!-- spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- javax -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
</dependency>
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka-clients</artifactId>
<version>${kafka-clients.version}</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-util</artifactId>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
<!-- json -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -1,19 +0,0 @@
package com.xiaojukeji.know.streaming.km.biz.broker;
import com.xiaojukeji.know.streaming.km.common.bean.entity.param.config.KafkaBrokerConfigModifyParam;
import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result;
import com.xiaojukeji.know.streaming.km.common.bean.vo.config.kafka.KafkaBrokerConfigVO;
import java.util.List;
public interface BrokerConfigManager {
/**
* 获取Broker配置详细信息
* @param clusterPhyId 物理集群ID
* @param brokerId brokerId
* @return
*/
Result<List<KafkaBrokerConfigVO>> getBrokerConfigDetail(Long clusterPhyId, Integer brokerId);
Result<Void> modifyBrokerConfig(KafkaBrokerConfigModifyParam modifyParam, String operator);
}

View File

@@ -1,13 +0,0 @@
package com.xiaojukeji.know.streaming.km.biz.broker;
import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationBaseDTO;
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.broker.BrokerBasicVO;
import com.xiaojukeji.know.streaming.km.common.bean.vo.log.LogDirVO;
public interface BrokerManager {
Result<BrokerBasicVO> getBrokerBasic(Long clusterPhyId, Integer brokerId);
PaginationResult<LogDirVO> getBrokerLogDirs(Long clusterPhyId, Integer brokerId, PaginationBaseDTO dto);
}

View File

@@ -1,97 +0,0 @@
package com.xiaojukeji.know.streaming.km.biz.broker.impl;
import com.xiaojukeji.know.streaming.km.biz.broker.BrokerConfigManager;
import com.xiaojukeji.know.streaming.km.common.bean.entity.broker.Broker;
import com.xiaojukeji.know.streaming.km.common.bean.entity.config.kafkaconfig.KafkaConfigDetail;
import com.xiaojukeji.know.streaming.km.common.bean.entity.param.config.KafkaBrokerConfigModifyParam;
import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result;
import com.xiaojukeji.know.streaming.km.common.bean.po.broker.BrokerConfigPO;
import com.xiaojukeji.know.streaming.km.common.bean.vo.config.kafka.KafkaBrokerConfigVO;
import com.xiaojukeji.know.streaming.km.common.constant.KafkaConstant;
import com.xiaojukeji.know.streaming.km.common.enums.config.ConfigDiffTypeEnum;
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.service.broker.BrokerConfigService;
import com.xiaojukeji.know.streaming.km.core.service.broker.BrokerService;
import org.apache.kafka.common.config.ConfigDef;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
@Component
public class BrokerConfigManagerImpl implements BrokerConfigManager {
@Autowired
private BrokerService brokerService;
@Autowired
private BrokerConfigService brokerConfigService;
@Override
public Result<List<KafkaBrokerConfigVO>> getBrokerConfigDetail(Long clusterPhyId, Integer brokerId) {
// 获取当前broker配置
Result<List<KafkaConfigDetail>> configResult = brokerConfigService.getBrokerConfigDetailFromKafka(clusterPhyId, brokerId);
if (configResult.failed()) {
return Result.buildFromIgnoreData(configResult);
}
// 获取差异的配置
List<BrokerConfigPO> diffPOList = brokerConfigService.getBrokerConfigDiffFromDB(clusterPhyId, brokerId);
// 组装数据
return Result.buildSuc(this.convert2KafkaBrokerConfigVOList(configResult.getData(), diffPOList));
}
private List<KafkaBrokerConfigVO> convert2KafkaBrokerConfigVOList(List<KafkaConfigDetail> configList, List<BrokerConfigPO> diffPOList) {
if (ValidateUtils.isEmptyList(configList)) {
return new ArrayList<>();
}
Map<String, BrokerConfigPO> poMap = diffPOList.stream().collect(Collectors.toMap(BrokerConfigPO::getConfigName, Function.identity()));
List<KafkaBrokerConfigVO> voList = ConvertUtil.list2List(configList, KafkaBrokerConfigVO.class);
for (KafkaBrokerConfigVO vo: voList) {
BrokerConfigPO po = poMap.get(vo.getName());
if (po != null) {
vo.setExclusive(po.getDiffType().equals(ConfigDiffTypeEnum.ALONE_POSSESS.getCode()));
vo.setDifferentiated(po.getDiffType().equals(ConfigDiffTypeEnum.UN_EQUAL.getCode()));
} else {
vo.setExclusive(false);
vo.setDifferentiated(false);
}
ConfigDef.ConfigKey configKey = KafkaConstant.KAFKA_ALL_CONFIG_DEF_MAP.get(vo.getName());
if (configKey == null) {
continue;
}
try {
vo.setDocumentation(configKey.documentation);
vo.setDefaultValue(configKey.defaultValue.toString());
} catch (Exception e) {
// ignore
}
}
return voList;
}
@Override
public Result<Void> modifyBrokerConfig(KafkaBrokerConfigModifyParam modifyParam, String operator) {
if (modifyParam.getApplyAll() == null || !modifyParam.getApplyAll()) {
return brokerConfigService.modifyBrokerConfig(modifyParam, operator);
}
List<Broker> brokerList = brokerService.listAliveBrokersFromDB(modifyParam.getClusterPhyId());
for (Broker broker: brokerList) {
modifyParam.setBrokerId(broker.getBrokerId());
Result<Void> rv = brokerConfigService.modifyBrokerConfig(modifyParam, operator);
if (rv.failed()) {
return rv;
}
}
return Result.buildSuc();
}
}

View File

@@ -1,75 +0,0 @@
package com.xiaojukeji.know.streaming.km.biz.broker.impl;
import com.xiaojukeji.know.streaming.km.biz.broker.BrokerManager;
import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationBaseDTO;
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.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.vo.broker.BrokerBasicVO;
import com.xiaojukeji.know.streaming.km.common.bean.vo.log.LogDirVO;
import com.xiaojukeji.know.streaming.km.common.constant.MsgConstant;
import com.xiaojukeji.know.streaming.km.common.utils.PaginationUtil;
import com.xiaojukeji.know.streaming.km.core.service.broker.BrokerService;
import com.xiaojukeji.know.streaming.km.core.service.cluster.ClusterPhyService;
import org.apache.kafka.clients.admin.LogDirDescription;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.*;
@Component
public class BrokerManagerImpl implements BrokerManager {
@Autowired
private BrokerService brokerService;
@Autowired
private ClusterPhyService clusterPhyService;
@Override
public Result<BrokerBasicVO> getBrokerBasic(Long clusterPhyId, Integer brokerId) {
ClusterPhy clusterPhy = clusterPhyService.getClusterByCluster(clusterPhyId);
if (clusterPhy == null) {
return Result.buildFromRSAndMsg(ResultStatus.NOT_EXIST, MsgConstant.getClusterPhyNotExist(clusterPhyId));
}
Broker broker = brokerService.getBroker(clusterPhyId, brokerId);
if (broker == null) {
return Result.buildFromRSAndMsg(ResultStatus.NOT_EXIST, MsgConstant.getBrokerNotExist(clusterPhyId, brokerId));
}
return Result.buildSuc(new BrokerBasicVO(brokerId, broker.getHost(), clusterPhy.getName()));
}
@Override
public PaginationResult<LogDirVO> getBrokerLogDirs(Long clusterPhyId, Integer brokerId, PaginationBaseDTO dto) {
Result<Map<String, LogDirDescription>> dirDescResult = brokerService.getBrokerLogDirDescFromKafka(clusterPhyId, brokerId);
if (dirDescResult.failed()) {
return PaginationResult.buildFailure(dirDescResult, dto);
}
Map<String, LogDirDescription> dirDescMap = dirDescResult.hasData()? dirDescResult.getData(): new HashMap<>();
List<LogDirVO> voList = new ArrayList<>();
for (Map.Entry<String, LogDirDescription> entry: dirDescMap.entrySet()) {
entry.getValue().replicaInfos().entrySet().stream().forEach(elem -> {
LogDirVO vo = new LogDirVO();
vo.setDir(entry.getKey());
vo.setTopicName(elem.getKey().topic());
vo.setPartitionId(elem.getKey().partition());
vo.setOffsetLag(elem.getValue().offsetLag());
vo.setLogSizeUnitB(elem.getValue().size());
voList.add(vo);
});
}
return PaginationUtil.pageBySubData(
PaginationUtil.pageByFuzzyFilter(voList, dto.getSearchKeywords(), Arrays.asList("topicName")),
dto
);
}
/**************************************************** private method ****************************************************/
}

View File

@@ -1,26 +0,0 @@
package com.xiaojukeji.know.streaming.km.biz.cluster;
import com.xiaojukeji.know.streaming.km.common.bean.dto.cluster.ClusterBrokersOverviewDTO;
import com.xiaojukeji.know.streaming.km.common.bean.entity.result.PaginationResult;
import com.xiaojukeji.know.streaming.km.common.bean.vo.cluster.res.ClusterBrokersOverviewVO;
import com.xiaojukeji.know.streaming.km.common.bean.vo.cluster.res.ClusterBrokersStateVO;
/**
* 多集群总体状态
*/
public interface ClusterBrokersManager {
/**
* 获取缓存查询结果 & broker 表查询结果并集
* @param clusterPhyId kafka 物理集群 id
* @param dto 封装分页查询参数对象
* @return 返回获取到的缓存查询结果 & broker 表查询结果并集
*/
PaginationResult<ClusterBrokersOverviewVO> getClusterPhyBrokersOverview(Long clusterPhyId, ClusterBrokersOverviewDTO dto);
/**
* 根据物理集群id获取集群对应broker状态信息
* @param clusterPhyId 物理集群 id
* @return 返回根据物理集群id获取到的集群对应broker状态信息
*/
ClusterBrokersStateVO getClusterPhyBrokersState(Long clusterPhyId);
}

View File

@@ -1,12 +0,0 @@
package com.xiaojukeji.know.streaming.km.biz.cluster;
import com.xiaojukeji.know.streaming.km.common.bean.dto.cluster.ClusterTopicsOverviewDTO;
import com.xiaojukeji.know.streaming.km.common.bean.entity.result.PaginationResult;
import com.xiaojukeji.know.streaming.km.common.bean.vo.cluster.res.ClusterPhyTopicsOverviewVO;
/**
* 多集群总体状态
*/
public interface ClusterTopicsManager {
PaginationResult<ClusterPhyTopicsOverviewVO> getClusterPhyTopicsOverview(Long clusterPhyId, ClusterTopicsOverviewDTO dto);
}

View File

@@ -1,24 +0,0 @@
package com.xiaojukeji.know.streaming.km.biz.cluster;
import com.xiaojukeji.know.streaming.km.common.bean.entity.cluster.ClusterPhysState;
import com.xiaojukeji.know.streaming.km.common.bean.dto.cluster.MultiClusterDashboardDTO;
import com.xiaojukeji.know.streaming.km.common.bean.entity.result.PaginationResult;
import com.xiaojukeji.know.streaming.km.common.bean.vo.cluster.ClusterPhyDashboardVO;
/**
* 多集群总体状态
*/
public interface MultiClusterPhyManager {
/**
* 获取所有集群的状态
* @return
*/
ClusterPhysState getClusterPhysState();
/**
* 查询多集群大盘
* @param dto 分页信息
* @return
*/
PaginationResult<ClusterPhyDashboardVO> getClusterPhysDashboard(MultiClusterDashboardDTO dto);
}

View File

@@ -1,228 +0,0 @@
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.ClusterBrokersManager;
import com.xiaojukeji.know.streaming.km.common.bean.dto.cluster.ClusterBrokersOverviewDTO;
import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationSortDTO;
import com.xiaojukeji.know.streaming.km.common.bean.entity.broker.Broker;
import com.xiaojukeji.know.streaming.km.common.bean.entity.kafkacontroller.KafkaController;
import com.xiaojukeji.know.streaming.km.common.bean.entity.metrics.BrokerMetrics;
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.Topic;
import com.xiaojukeji.know.streaming.km.common.bean.vo.cluster.res.ClusterBrokersOverviewVO;
import com.xiaojukeji.know.streaming.km.common.bean.vo.cluster.res.ClusterBrokersStateVO;
import com.xiaojukeji.know.streaming.km.common.bean.vo.kafkacontroller.KafkaControllerVO;
import com.xiaojukeji.know.streaming.km.common.constant.KafkaConstant;
import com.xiaojukeji.know.streaming.km.common.enums.SortTypeEnum;
import com.xiaojukeji.know.streaming.km.common.utils.PaginationMetricsUtil;
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.BrokerConfigService;
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 org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
@Service
public class ClusterBrokersManagerImpl implements ClusterBrokersManager {
private static final ILog log = LogFactory.getLog(ClusterBrokersManagerImpl.class);
@Autowired
private TopicService topicService;
@Autowired
private BrokerService brokerService;
@Autowired
private BrokerConfigService brokerConfigService;
@Autowired
private BrokerMetricService brokerMetricService;
@Autowired
private KafkaControllerService kafkaControllerService;
@Override
public PaginationResult<ClusterBrokersOverviewVO> getClusterPhyBrokersOverview(Long clusterPhyId, ClusterBrokersOverviewDTO dto) {
// 获取集群Broker列表
List<Broker> brokerList = brokerService.listAllBrokersFromDB(clusterPhyId);
// 搜索
brokerList = PaginationUtil.pageByFuzzyFilter(brokerList, dto.getSearchKeywords(), Arrays.asList("host"));
// 获取指标
Result<List<BrokerMetrics>> metricsResult = brokerMetricService.getLatestMetricsFromES(
clusterPhyId,
brokerList.stream().filter(elem1 -> elem1.alive()).map(elem2 -> elem2.getBrokerId()).collect(Collectors.toList())
);
// 分页 + 搜索
PaginationResult<Integer> paginationResult = this.pagingBrokers(brokerList, metricsResult.hasData()? metricsResult.getData(): new ArrayList<>(), dto);
// 获取__consumer_offsetsTopic的分布
Topic groupTopic = topicService.getTopic(clusterPhyId, org.apache.kafka.common.internals.Topic.GROUP_METADATA_TOPIC_NAME);
Topic transactionTopic = topicService.getTopic(clusterPhyId, org.apache.kafka.common.internals.Topic.TRANSACTION_STATE_TOPIC_NAME);
//获取controller信息
KafkaController kafkaController = kafkaControllerService.getKafkaControllerFromDB(clusterPhyId);
// 格式转换
return PaginationResult.buildSuc(
this.convert2ClusterBrokersOverviewVOList(
paginationResult.getData().getBizData(),
brokerList,
metricsResult.getData(),
groupTopic,
transactionTopic,
kafkaController
),
paginationResult
);
}
@Override
public ClusterBrokersStateVO getClusterPhyBrokersState(Long clusterPhyId) {
ClusterBrokersStateVO clusterBrokersStateVO = new ClusterBrokersStateVO();
// 获取集群Broker列表
List<Broker> allBrokerList = brokerService.listAllBrokersFromDB(clusterPhyId);
if (allBrokerList == null) {
allBrokerList = new ArrayList<>();
}
// 设置broker数
clusterBrokersStateVO.setBrokerCount(allBrokerList.size());
// 设置版本信息
clusterBrokersStateVO.setBrokerVersionList(
this.getBrokerVersionList(clusterPhyId, allBrokerList.stream().filter(elem -> elem.alive()).collect(Collectors.toList()))
);
// 获取controller信息
KafkaController kafkaController = kafkaControllerService.getKafkaControllerFromDB(clusterPhyId);
// 设置kafka-controller信息
clusterBrokersStateVO.setKafkaControllerAlive(false);
if(null != kafkaController) {
clusterBrokersStateVO.setKafkaController(
this.convert2KafkaControllerVO(
kafkaController,
brokerService.getBroker(clusterPhyId, kafkaController.getBrokerId())
)
);
clusterBrokersStateVO.setKafkaControllerAlive(true);
}
clusterBrokersStateVO.setConfigSimilar(brokerConfigService.countBrokerConfigDiffsFromDB(clusterPhyId, Arrays.asList("broker.id", "listeners", "name", "value")) <= 0);
return clusterBrokersStateVO;
}
/**************************************************** private method ****************************************************/
private PaginationResult<Integer> pagingBrokers(List<Broker> brokerList, List<BrokerMetrics> metricsList, PaginationSortDTO dto) {
if (ValidateUtils.isBlank(dto.getSortField())) {
// 默认排序
return PaginationUtil.pageBySubData(
PaginationUtil.pageBySort(brokerList, "brokerId", SortTypeEnum.ASC.getSortType()).stream().map(elem -> elem.getBrokerId()).collect(Collectors.toList()),
dto
);
}
if (!brokerMetricService.isMetricName(dto.getSortField())) {
// 非指标字段进行排序,分页
return PaginationUtil.pageBySubData(
PaginationUtil.pageBySort(brokerList, dto.getSortField(), dto.getSortType()).stream().map(elem -> elem.getBrokerId()).collect(Collectors.toList()),
dto
);
}
// 指标字段进行排序及分页
Map<Integer, BrokerMetrics> metricsMap = metricsList.stream().collect(Collectors.toMap(BrokerMetrics::getBrokerId, Function.identity()));
brokerList.stream().forEach(elem -> {
metricsMap.putIfAbsent(elem.getBrokerId(), new BrokerMetrics(elem.getClusterPhyId(), elem.getBrokerId()));
});
// 排序
metricsList = (List<BrokerMetrics>) PaginationMetricsUtil.sortMetrics(new ArrayList<>(metricsMap.values()), dto.getSortField(), "brokerId", dto.getSortType());
return PaginationUtil.pageBySubData(
metricsList.stream().map(elem -> elem.getBrokerId()).collect(Collectors.toList()),
dto
);
}
private List<ClusterBrokersOverviewVO> convert2ClusterBrokersOverviewVOList(List<Integer> pagedBrokerIdList,
List<Broker> brokerList,
List<BrokerMetrics> metricsList,
Topic groupTopic,
Topic transactionTopic,
KafkaController kafkaController) {
Map<Integer, BrokerMetrics> metricsMap = metricsList == null? new HashMap<>(): metricsList.stream().collect(Collectors.toMap(BrokerMetrics::getBrokerId, Function.identity()));
Map<Integer, Broker> brokerMap = brokerList == null? new HashMap<>(): brokerList.stream().collect(Collectors.toMap(Broker::getBrokerId, Function.identity()));
List<ClusterBrokersOverviewVO> voList = new ArrayList<>(pagedBrokerIdList.size());
for (Integer brokerId : pagedBrokerIdList) {
Broker broker = brokerMap.get(brokerId);
BrokerMetrics brokerMetrics = metricsMap.get(brokerId);
voList.add(this.convert2ClusterBrokersOverviewVO(brokerId, broker, brokerMetrics, groupTopic, transactionTopic, kafkaController));
}
return voList;
}
private ClusterBrokersOverviewVO convert2ClusterBrokersOverviewVO(Integer brokerId, Broker broker, BrokerMetrics brokerMetrics, Topic groupTopic, Topic transactionTopic, KafkaController kafkaController) {
ClusterBrokersOverviewVO clusterBrokersOverviewVO = new ClusterBrokersOverviewVO();
clusterBrokersOverviewVO.setBrokerId(brokerId);
if (broker != null) {
clusterBrokersOverviewVO.setHost(broker.getHost());
clusterBrokersOverviewVO.setRack(broker.getRack());
clusterBrokersOverviewVO.setJmxPort(broker.getJmxPort());
clusterBrokersOverviewVO.setAlive(broker.alive());
clusterBrokersOverviewVO.setStartTimeUnitMs(broker.getStartTimestamp());
}
clusterBrokersOverviewVO.setKafkaRoleList(new ArrayList<>());
if (groupTopic != null && groupTopic.getBrokerIdSet().contains(brokerId)) {
clusterBrokersOverviewVO.getKafkaRoleList().add(groupTopic.getTopicName());
}
if (transactionTopic != null && transactionTopic.getBrokerIdSet().contains(brokerId)) {
clusterBrokersOverviewVO.getKafkaRoleList().add(transactionTopic.getTopicName());
}
if (kafkaController != null && kafkaController.getBrokerId().equals(brokerId)) {
clusterBrokersOverviewVO.getKafkaRoleList().add(KafkaConstant.CONTROLLER_ROLE);
}
clusterBrokersOverviewVO.setLatestMetrics(brokerMetrics);
return clusterBrokersOverviewVO;
}
private KafkaControllerVO convert2KafkaControllerVO(KafkaController kafkaController, Broker kafkaControllerBroker) {
if(null != kafkaController && null != kafkaControllerBroker) {
KafkaControllerVO kafkaControllerVO = new KafkaControllerVO();
kafkaControllerVO.setBrokerId(kafkaController.getBrokerId());
kafkaControllerVO.setBrokerHost(kafkaControllerBroker.getHost());
return kafkaControllerVO;
}
return null;
}
private List<String> getBrokerVersionList(Long clusterPhyId, List<Broker> brokerList) {
Set<String> brokerVersionList = new HashSet<>();
for (Broker broker : brokerList) {
brokerVersionList.add(brokerService.getBrokerVersionFromKafkaWithCacheFirst(broker.getClusterPhyId(),broker.getBrokerId(),broker.getStartTimestamp()));
}
brokerVersionList.remove("");
return new ArrayList<>(brokerVersionList);
}
}

View File

@@ -1,112 +0,0 @@
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.ClusterTopicsManager;
import com.xiaojukeji.know.streaming.km.common.bean.dto.cluster.ClusterTopicsOverviewDTO;
import com.xiaojukeji.know.streaming.km.common.bean.dto.metrices.MetricDTO;
import com.xiaojukeji.know.streaming.km.common.bean.dto.metrices.MetricsTopicDTO;
import com.xiaojukeji.know.streaming.km.common.bean.entity.metrics.TopicMetrics;
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.Topic;
import com.xiaojukeji.know.streaming.km.common.bean.vo.cluster.res.ClusterPhyTopicsOverviewVO;
import com.xiaojukeji.know.streaming.km.common.bean.vo.metrics.line.MetricMultiLinesVO;
import com.xiaojukeji.know.streaming.km.common.constant.KafkaConstant;
import com.xiaojukeji.know.streaming.km.common.converter.TopicVOConverter;
import com.xiaojukeji.know.streaming.km.common.utils.ConvertUtil;
import com.xiaojukeji.know.streaming.km.common.utils.PaginationMetricsUtil;
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.topic.TopicMetricService;
import com.xiaojukeji.know.streaming.km.core.service.topic.TopicService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.stream.Collectors;
@Service
public class ClusterTopicsManagerImpl implements ClusterTopicsManager {
private static final ILog log = LogFactory.getLog(ClusterTopicsManagerImpl.class);
@Autowired
private TopicService topicService;
@Autowired
private TopicMetricService topicMetricService;
@Override
public PaginationResult<ClusterPhyTopicsOverviewVO> getClusterPhyTopicsOverview(Long clusterPhyId, ClusterTopicsOverviewDTO dto) {
// 获取集群所有的Topic信息
List<Topic> topicList = topicService.listTopicsFromDB(clusterPhyId);
// 获取集群所有Topic的指标
Map<String, TopicMetrics> metricsMap = topicMetricService.getLatestMetricsFromCacheFirst(clusterPhyId);
// 转换成vo
List<ClusterPhyTopicsOverviewVO> voList = TopicVOConverter.convert2ClusterPhyTopicsOverviewVOList(topicList, metricsMap);
// 请求分页信息
PaginationResult<ClusterPhyTopicsOverviewVO> voPaginationResult = this.pagingTopicInLocal(voList, dto);
if (voPaginationResult.failed()) {
log.error("method=getClusterPhyTopicsOverview||clusterPhyId={}||result={}||errMsg=pagination in local failed", clusterPhyId, voPaginationResult);
return PaginationResult.buildFailure(voPaginationResult, dto);
}
// 查询指标
Result<List<MetricMultiLinesVO>> metricMultiLinesResult = topicMetricService.listTopicMetricsFromES(
clusterPhyId,
this.buildTopicOverviewMetricsDTO(voPaginationResult.getData().getBizData().stream().map(elem -> elem.getTopicName()).collect(Collectors.toList()), dto.getMetricLines())
);
if (metricMultiLinesResult.failed()) {
// 查询ES失败或者ES无数据则ES可能存在问题此时降级返回Topic的基本信息数据
log.error("method=getClusterPhyTopicsOverview||clusterPhyId={}||result={}||errMsg=get metrics from es failed", clusterPhyId, metricMultiLinesResult);
}
return PaginationResult.buildSuc(
TopicVOConverter.supplyMetricLines(
voPaginationResult.getData().getBizData(),
metricMultiLinesResult.getData() == null? new ArrayList<>(): metricMultiLinesResult.getData()
),
voPaginationResult
);
}
/**************************************************** private method ****************************************************/
private MetricsTopicDTO buildTopicOverviewMetricsDTO(List<String> topicNameList, MetricDTO metricDTO) {
MetricsTopicDTO dto = ConvertUtil.obj2Obj(metricDTO, MetricsTopicDTO.class);
dto.setTopics(topicNameList == null? new ArrayList<>(): topicNameList);
return dto;
}
private PaginationResult<ClusterPhyTopicsOverviewVO> pagingTopicInLocal(List<ClusterPhyTopicsOverviewVO> voList, ClusterTopicsOverviewDTO dto) {
List<ClusterPhyTopicsOverviewVO> metricsList = voList.stream().filter(elem -> {
if (dto.getShowInternalTopics() != null && dto.getShowInternalTopics()) {
// 仅展示系统Topic
return KafkaConstant.KAFKA_INTERNAL_TOPICS.contains(elem.getTopicName());
} else {
// 仅展示用户Topic
return !KafkaConstant.KAFKA_INTERNAL_TOPICS.contains(elem.getTopicName());
}
}).collect(Collectors.toList());
// 名称搜索
metricsList = PaginationUtil.pageByFuzzyFilter(metricsList, dto.getSearchKeywords(), Arrays.asList("topicName"));
if (!ValidateUtils.isBlank(dto.getSortField()) && !"createTime".equals(dto.getSortField())) {
// 指标排序
PaginationMetricsUtil.sortMetrics(metricsList, "latestMetrics", dto.getSortField(), "topicName", dto.getSortType());
} else {
// 信息排序
PaginationUtil.pageBySort(metricsList, dto.getSortField(), dto.getSortType(), "topicName", dto.getSortType());
}
return PaginationUtil.pageBySubData(metricsList, dto);
}
}

View File

@@ -1,181 +0,0 @@
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.MultiClusterPhyManager;
import com.xiaojukeji.know.streaming.km.common.bean.dto.metrices.MetricDTO;
import com.xiaojukeji.know.streaming.km.common.bean.dto.metrices.MetricsClusterPhyDTO;
import com.xiaojukeji.know.streaming.km.common.bean.entity.cluster.ClusterPhysState;
import com.xiaojukeji.know.streaming.km.common.bean.entity.cluster.ClusterPhy;
import com.xiaojukeji.know.streaming.km.common.bean.dto.cluster.MultiClusterDashboardDTO;
import com.xiaojukeji.know.streaming.km.common.bean.entity.kafkacontroller.KafkaController;
import com.xiaojukeji.know.streaming.km.common.bean.entity.metrics.ClusterMetrics;
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.cluster.ClusterPhyDashboardVO;
import com.xiaojukeji.know.streaming.km.common.bean.vo.metrics.line.MetricMultiLinesVO;
import com.xiaojukeji.know.streaming.km.common.constant.Constant;
import com.xiaojukeji.know.streaming.km.common.converter.ClusterVOConverter;
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.PaginationMetricsUtil;
import com.xiaojukeji.know.streaming.km.common.utils.ValidateUtils;
import com.xiaojukeji.know.streaming.km.core.service.cluster.ClusterMetricService;
import com.xiaojukeji.know.streaming.km.core.service.cluster.ClusterPhyService;
import com.xiaojukeji.know.streaming.km.core.service.kafkacontroller.KafkaControllerService;
import com.xiaojukeji.know.streaming.km.core.service.version.metrics.ClusterMetricVersionItems;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Service
public class MultiClusterPhyManagerImpl implements MultiClusterPhyManager {
private static final ILog log = LogFactory.getLog(MultiClusterPhyManagerImpl.class);
@Autowired
private ClusterPhyService clusterPhyService;
@Autowired
private ClusterMetricService clusterMetricService;
@Autowired
private KafkaControllerService kafkaControllerService;
@Override
public ClusterPhysState getClusterPhysState() {
List<ClusterPhy> clusterPhyList = clusterPhyService.listAllClusters();
Map<Long, KafkaController> controllerMap = kafkaControllerService.getKafkaControllersFromDB(
clusterPhyList.stream().map(elem -> elem.getId()).collect(Collectors.toList()),
false
);
// TODO 后续产品上,看是否需要增加一个未知的状态,否则新接入的集群,因为新接入的集群,数据存在延迟
ClusterPhysState physState = new ClusterPhysState(0, 0, clusterPhyList.size());
for (ClusterPhy clusterPhy: clusterPhyList) {
KafkaController kafkaController = controllerMap.get(clusterPhy.getId());
if (kafkaController != null && !kafkaController.alive()) {
// 存在明确的信息表示controller挂了
physState.setDownCount(physState.getDownCount() + 1);
} else if ((System.currentTimeMillis() - clusterPhy.getCreateTime().getTime() >= 5 * 60 * 1000) && kafkaController == null) {
// 集群接入时间是在近5分钟内同时kafkaController信息不存在则设置为down
physState.setDownCount(physState.getDownCount() + 1);
} else {
// 其他情况都设置为alive
physState.setLiveCount(physState.getLiveCount() + 1);
}
}
return physState;
}
@Override
public PaginationResult<ClusterPhyDashboardVO> getClusterPhysDashboard(MultiClusterDashboardDTO dto) {
// 获取集群
List<ClusterPhy> clusterPhyList = clusterPhyService.listAllClusters();
// 转为vo格式方便后续进行分页筛选等
List<ClusterPhyDashboardVO> voList = ConvertUtil.list2List(clusterPhyList, ClusterPhyDashboardVO.class);
// TODO 后续产品上,看是否需要增加一个未知的状态,否则新接入的集群,因为新接入的集群,数据存在延迟
// 获取集群controller信息并补充到vo中,
Map<Long, KafkaController> controllerMap = kafkaControllerService.getKafkaControllersFromDB(clusterPhyList.stream().map(elem -> elem.getId()).collect(Collectors.toList()), false);
for (ClusterPhyDashboardVO vo: voList) {
KafkaController kafkaController = controllerMap.get(vo.getId());
if (kafkaController != null && !kafkaController.alive()) {
// 存在明确的信息表示controller挂了
vo.setAlive(Constant.DOWN);
} else if ((System.currentTimeMillis() - vo.getCreateTime().getTime() >= 5 * 60L * 1000L) && kafkaController == null) {
// 集群接入时间是在近5分钟内同时kafkaController信息不存在则设置为down
vo.setAlive(Constant.DOWN);
} else {
// 其他情况都设置为alive
vo.setAlive(Constant.ALIVE);
}
}
// 本地分页过滤
voList = this.getAndPagingDataInLocal(voList, dto);
// ES分页过滤
PaginationResult<ClusterMetrics> latestMetricsResult = this.getAndPagingClusterWithLatestMetricsFromCache(voList, dto);
if (latestMetricsResult.failed()) {
log.error("method=getClusterPhysDashboard||pagingData={}||result={}||errMsg=search es data failed.", dto, latestMetricsResult);
return PaginationResult.buildFailure(latestMetricsResult, dto);
}
// 获取历史指标
Result<List<MetricMultiLinesVO>> linesMetricResult = clusterMetricService.listClusterMetricsFromES(
this.buildMetricsClusterPhyDTO(
latestMetricsResult.getData().getBizData().stream().map(elem -> elem.getClusterPhyId()).collect(Collectors.toList()),
dto.getMetricLines()
));
// 组装最终数据
return PaginationResult.buildSuc(
ClusterVOConverter.convert2ClusterPhyDashboardVOList(voList, linesMetricResult.getData(), latestMetricsResult.getData().getBizData()),
latestMetricsResult
);
}
/**************************************************** private method ****************************************************/
private List<ClusterPhyDashboardVO> getAndPagingDataInLocal(List<ClusterPhyDashboardVO> voList, MultiClusterDashboardDTO dto) {
// 时间排序
if ("createTime".equals(dto.getSortField())) {
voList = PaginationUtil.pageBySort(voList, "createTime", dto.getSortType(), "name", dto.getSortType());
}
// 名称搜索
if (!ValidateUtils.isBlank(dto.getSearchKeywords())) {
voList = PaginationUtil.pageByFuzzyFilter(voList, dto.getSearchKeywords(), Arrays.asList("name"));
}
// 精确搜索
return PaginationUtil.pageByPreciseFilter(voList, dto.getPreciseFilterDTOList());
}
private PaginationResult<ClusterMetrics> getAndPagingClusterWithLatestMetricsFromCache(List<ClusterPhyDashboardVO> voList, MultiClusterDashboardDTO dto) {
// 获取所有的metrics
List<ClusterMetrics> metricsList = new ArrayList<>();
for (ClusterPhyDashboardVO vo: voList) {
ClusterMetrics clusterMetrics = clusterMetricService.getLatestMetricsFromCache(vo.getId());
if (!clusterMetrics.getMetrics().containsKey(ClusterMetricVersionItems.CLUSTER_METRIC_HEALTH_SCORE)) {
Float alive = clusterMetrics.getMetrics().get(ClusterMetricVersionItems.CLUSTER_METRIC_ALIVE);
// 如果集群没有健康分,则设置一个默认的健康分数值
clusterMetrics.putMetric(ClusterMetricVersionItems.CLUSTER_METRIC_HEALTH_SCORE,
(alive != null && alive <= 0)? 0.0f: Constant.DEFAULT_CLUSTER_HEALTH_SCORE.floatValue()
);
}
metricsList.add(clusterMetrics);
}
// 范围搜索
metricsList = (List<ClusterMetrics>) PaginationMetricsUtil.rangeFilterMetrics(metricsList, dto.getRangeFilterDTOList());
// 精确搜索
metricsList = (List<ClusterMetrics>) PaginationMetricsUtil.preciseFilterMetrics(metricsList, dto.getPreciseFilterDTOList());
// 排序
PaginationMetricsUtil.sortMetrics(metricsList, dto.getSortField(), "clusterPhyId", dto.getSortType());
// 分页
return PaginationUtil.pageBySubData(metricsList, dto);
}
private MetricsClusterPhyDTO buildMetricsClusterPhyDTO(List<Long> clusterIdList, MetricDTO metricDTO) {
MetricsClusterPhyDTO dto = ConvertUtil.obj2Obj(metricDTO, MetricsClusterPhyDTO.class);
dto.setClusterPhyIds(clusterIdList);
return dto;
}
}

View File

@@ -1,34 +0,0 @@
package com.xiaojukeji.know.streaming.km.biz.group;
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.vo.group.GroupTopicConsumedDetailVO;
import com.xiaojukeji.know.streaming.km.common.bean.vo.group.GroupTopicOverviewVO;
import com.xiaojukeji.know.streaming.km.common.exception.AdminOperateException;
import com.xiaojukeji.know.streaming.km.common.exception.NotExistException;
import java.util.List;
import java.util.Set;
public interface GroupManager {
PaginationResult<GroupTopicOverviewVO> pagingGroupMembers(Long clusterPhyId,
String topicName,
String groupName,
String searchTopicKeyword,
String searchGroupKeyword,
PaginationBaseDTO dto);
PaginationResult<GroupTopicConsumedDetailVO> pagingGroupTopicConsumedMetrics(Long clusterPhyId,
String topicName,
String groupName,
List<String> latestMetricNames,
PaginationSortDTO dto)throws NotExistException, AdminOperateException;
Result<Set<TopicPartitionKS>> listClusterPhyGroupPartitions(Long clusterPhyId, String groupName, Long startTime, Long endTime);
Result<Void> resetGroupOffsets(GroupOffsetResetDTO dto, String operator) throws Exception;
}

View File

@@ -1,300 +0,0 @@
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.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.GroupTopic;
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;
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.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.enums.AggTypeEnum;
import com.xiaojukeji.know.streaming.km.common.enums.GroupOffsetResetEnum;
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.utils.ConvertUtil;
import com.xiaojukeji.know.streaming.km.common.utils.PaginationMetricsUtil;
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.group.GroupMetricService;
import com.xiaojukeji.know.streaming.km.core.service.group.GroupService;
import com.xiaojukeji.know.streaming.km.core.service.partition.PartitionService;
import com.xiaojukeji.know.streaming.km.core.service.topic.TopicService;
import com.xiaojukeji.know.streaming.km.core.service.version.metrics.GroupMetricVersionItems;
import com.xiaojukeji.know.streaming.km.persistence.es.dao.GroupMetricESDAO;
import org.apache.kafka.clients.admin.ConsumerGroupDescription;
import org.apache.kafka.clients.admin.MemberDescription;
import org.apache.kafka.clients.admin.OffsetSpec;
import org.apache.kafka.common.ConsumerGroupState;
import org.apache.kafka.common.TopicPartition;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.stream.Collectors;
@Component
public class GroupManagerImpl implements GroupManager {
private static final ILog log = LogFactory.getLog(GroupManagerImpl.class);
@Autowired
private TopicService topicService;
@Autowired
private GroupService groupService;
@Autowired
private PartitionService partitionService;
@Autowired
private GroupMetricService groupMetricService;
@Autowired
private GroupMetricESDAO groupMetricESDAO;
@Override
public PaginationResult<GroupTopicOverviewVO> pagingGroupMembers(Long clusterPhyId,
String topicName,
String groupName,
String searchTopicKeyword,
String searchGroupKeyword,
PaginationBaseDTO dto) {
PaginationResult<GroupMemberPO> 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<List<GroupMetrics>> 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);
}
return PaginationResult.buildSuc(
this.convert2GroupTopicOverviewVOList(paginationResult.getData().getBizData(), metricsListResult.getData()),
paginationResult
);
}
@Override
public PaginationResult<GroupTopicConsumedDetailVO> pagingGroupTopicConsumedMetrics(Long clusterPhyId,
String topicName,
String groupName,
List<String> latestMetricNames,
PaginationSortDTO dto) throws NotExistException, AdminOperateException {
// 获取消费组消费的TopicPartition列表
Map<TopicPartition, Long> consumedOffsetMap = groupService.getGroupOffset(clusterPhyId, groupName);
List<Integer> partitionList = consumedOffsetMap.keySet()
.stream()
.filter(elem -> elem.topic().equals(topicName))
.map(elem -> elem.partition())
.collect(Collectors.toList());
Collections.sort(partitionList);
// 获取消费组当前运行信息
ConsumerGroupDescription groupDescription = groupService.getGroupDescription(clusterPhyId, groupName);
// 转换存储格式
Map<TopicPartition, MemberDescription> tpMemberMap = new HashMap<>();
for (MemberDescription description: groupDescription.members()) {
for (TopicPartition tp: description.assignment().topicPartitions()) {
tpMemberMap.put(tp, description);
}
}
// 获取指标
PaginationResult<GroupMetrics> metricsResult = this.pagingGroupTopicPartitionMetrics(clusterPhyId, groupName, topicName, partitionList, latestMetricNames, dto);
if (metricsResult.failed()) {
return PaginationResult.buildFailure(metricsResult, dto);
}
// 数据组装
List<GroupTopicConsumedDetailVO> voList = new ArrayList<>();
for (GroupMetrics groupMetrics: metricsResult.getData().getBizData()) {
GroupTopicConsumedDetailVO vo = new GroupTopicConsumedDetailVO();
vo.setTopicName(topicName);
vo.setPartitionId(groupMetrics.getPartitionId());
MemberDescription memberDescription = tpMemberMap.get(new TopicPartition(topicName, groupMetrics.getPartitionId()));
if (memberDescription != null) {
vo.setMemberId(memberDescription.consumerId());
vo.setHost(memberDescription.host());
vo.setClientId(memberDescription.clientId());
}
vo.setLatestMetrics(groupMetrics);
voList.add(vo);
}
return PaginationResult.buildSuc(voList, metricsResult);
}
@Override
public Result<Set<TopicPartitionKS>> listClusterPhyGroupPartitions(Long clusterPhyId, String groupName, Long startTime, Long endTime) {
try {
return Result.buildSuc(groupMetricESDAO.listGroupTopicPartitions(clusterPhyId, groupName, startTime, endTime));
}catch (Exception e){
return Result.buildFailure(e.getMessage());
}
}
@Override
public Result<Void> resetGroupOffsets(GroupOffsetResetDTO dto, String operator) throws Exception {
Result<Void> rv = this.checkFieldLegal(dto);
if (rv.failed()) {
return rv;
}
ConsumerGroupDescription description = groupService.getGroupDescription(dto.getClusterId(), dto.getGroupName());
if (ConsumerGroupState.DEAD.equals(description.state()) && !dto.isCreateIfNotExist()) {
return Result.buildFromRSAndMsg(ResultStatus.KAFKA_OPERATE_FAILED, "group不存在, 重置失败");
}
if (!ConsumerGroupState.EMPTY.equals(description.state()) && !ConsumerGroupState.DEAD.equals(description.state())) {
return Result.buildFromRSAndMsg(ResultStatus.KAFKA_OPERATE_FAILED, String.format("group处于%s, 重置失败(仅Empty情况可重置)", GroupStateEnum.getByRawState(description.state()).getState()));
}
// 获取offset
Result<Map<TopicPartition, Long>> offsetMapResult = this.getPartitionOffset(dto);
if (offsetMapResult.failed()) {
return Result.buildFromIgnoreData(offsetMapResult);
}
// 重置offset
return groupService.resetGroupOffsets(dto.getClusterId(), dto.getGroupName(), offsetMapResult.getData(), operator);
}
/**************************************************** private method ****************************************************/
private Result<Void> checkFieldLegal(GroupOffsetResetDTO dto) {
if (dto == null) {
return Result.buildFromRSAndMsg(ResultStatus.PARAM_ILLEGAL, "参数为空");
}
Topic topic = topicService.getTopic(dto.getClusterId(), dto.getTopicName());
if (topic == null) {
return Result.buildFromRSAndMsg(ResultStatus.NOT_EXIST, MsgConstant.getTopicNotExist(dto.getClusterId(), dto.getTopicName()));
}
if (GroupOffsetResetEnum.PRECISE_OFFSET.getResetType() == dto.getResetType()
&& ValidateUtils.isEmptyList(dto.getOffsetList())) {
return Result.buildFromRSAndMsg(ResultStatus.PARAM_ILLEGAL, "参数错误指定offset重置需传offset信息");
}
if (GroupOffsetResetEnum.PRECISE_TIMESTAMP.getResetType() == dto.getResetType()
&& ValidateUtils.isNull(dto.getTimestamp())) {
return Result.buildFromRSAndMsg(ResultStatus.PARAM_ILLEGAL, "参数错误,指定时间重置需传时间信息");
}
return Result.buildSuc();
}
private Result<Map<TopicPartition, Long>> getPartitionOffset(GroupOffsetResetDTO dto) {
if (GroupOffsetResetEnum.PRECISE_OFFSET.getResetType() == dto.getResetType()) {
return Result.buildSuc(dto.getOffsetList().stream().collect(Collectors.toMap(
elem -> new TopicPartition(dto.getTopicName(), elem.getPartitionId()),
PartitionOffsetDTO::getOffset,
(key1 , key2) -> key2
)));
}
OffsetSpec offsetSpec = null;
if (GroupOffsetResetEnum.PRECISE_TIMESTAMP.getResetType() == dto.getResetType()) {
offsetSpec = OffsetSpec.forTimestamp(dto.getTimestamp());
} else if (GroupOffsetResetEnum.EARLIEST.getResetType() == dto.getResetType()) {
offsetSpec = OffsetSpec.earliest();
} else {
offsetSpec = OffsetSpec.latest();
}
return partitionService.getPartitionOffsetFromKafka(dto.getClusterId(), dto.getTopicName(), offsetSpec, dto.getTimestamp());
}
private List<GroupTopicOverviewVO> convert2GroupTopicOverviewVOList(List<GroupMemberPO> poList, List<GroupMetrics> metricsList) {
if (metricsList == null) {
metricsList = new ArrayList<>();
}
// <GroupName, <TopicName, GroupMetrics>>
Map<String, Map<String, GroupMetrics>> metricsMap = new HashMap<>();
metricsList.stream().forEach(elem -> {
metricsMap.putIfAbsent(elem.getGroup(), new HashMap<>());
metricsMap.get(elem.getGroup()).put(elem.getTopic(), elem);
});
List<GroupTopicOverviewVO> voList = new ArrayList<>();
for (GroupMemberPO po: poList) {
GroupTopicOverviewVO vo = ConvertUtil.obj2Obj(po, GroupTopicOverviewVO.class);
if (vo == null) {
continue;
}
GroupMetrics metrics = metricsMap.getOrDefault(po.getGroupName(), new HashMap<>()).get(po.getTopicName());
if (metrics != null) {
vo.setMaxLag(ConvertUtil.Float2Long(metrics.getMetrics().get(GroupMetricVersionItems.GROUP_METRIC_LAG)));
}
voList.add(vo);
}
return voList;
}
private PaginationResult<GroupMetrics> pagingGroupTopicPartitionMetrics(Long clusterPhyId,
String groupName,
String topicName,
List<Integer> partitionIdList,
List<String> latestMetricNames,
PaginationSortDTO dto) {
// 获取Group指标信息
Result<List<GroupMetrics>> groupMetricsResult = groupMetricService.listPartitionLatestMetricsFromES(
clusterPhyId,
groupName,
topicName,
latestMetricNames == null? Arrays.asList(): latestMetricNames
);
// 转换Group指标
List<GroupMetrics> esGroupMetricsList = groupMetricsResult.hasData()? groupMetricsResult.getData(): new ArrayList<>();
Map<Integer, GroupMetrics> esMetricsMap = new HashMap<>();
for (GroupMetrics groupMetrics: esGroupMetricsList) {
esMetricsMap.put(groupMetrics.getPartitionId(), groupMetrics);
}
List<GroupMetrics> allPartitionGroupMetrics = new ArrayList<>();
for (Integer partitionId: partitionIdList) {
allPartitionGroupMetrics.add(esMetricsMap.getOrDefault(partitionId, new GroupMetrics(clusterPhyId, groupName, topicName, partitionId)));
}
return PaginationUtil.pageBySubData(
(List<GroupMetrics>)PaginationMetricsUtil.sortMetrics(allPartitionGroupMetrics, dto.getSortField(), "partitionId", dto.getSortType()),
dto
);
}
}

View File

@@ -1,13 +0,0 @@
package com.xiaojukeji.know.streaming.km.biz.kafkaacl;
import com.xiaojukeji.know.streaming.km.common.bean.dto.acl.AclAtomDTO;
import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result;
import java.util.List;
/**
*
*/
public interface KafkaAclManager {
Result<Void> batchCreateKafkaAcl(List<AclAtomDTO> dtoList, String operator);
}

View File

@@ -1,36 +0,0 @@
package com.xiaojukeji.know.streaming.km.biz.kafkaacl.impl;
import com.didiglobal.logi.log.ILog;
import com.didiglobal.logi.log.LogFactory;
import com.xiaojukeji.know.streaming.km.biz.kafkaacl.KafkaAclManager;
import com.xiaojukeji.know.streaming.km.common.bean.dto.acl.AclAtomDTO;
import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result;
import com.xiaojukeji.know.streaming.km.common.converter.KafkaAclConverter;
import com.xiaojukeji.know.streaming.km.common.utils.ConvertUtil;
import com.xiaojukeji.know.streaming.km.core.service.acl.OpKafkaAclService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class KafkaAclManagerImpl implements KafkaAclManager {
private static final ILog log = LogFactory.getLog(KafkaAclManagerImpl.class);
@Autowired
private OpKafkaAclService opKafkaAclService;
@Override
public Result<Void> batchCreateKafkaAcl(List<AclAtomDTO> dtoList, String operator) {
log.debug("method=batchCreateKafkaAcl||dtoList={}||operator={}", ConvertUtil.obj2Json(dtoList), operator);
for (AclAtomDTO dto: dtoList) {
Result<Void> rv = opKafkaAclService.createKafkaAcl(KafkaAclConverter.convert2ACLAtomParam(dto), operator);
if (rv.failed()) {
return rv;
}
}
return Result.buildSuc();
}
}

View File

@@ -1,23 +0,0 @@
package com.xiaojukeji.know.streaming.km.biz.kafkauser;
import com.xiaojukeji.know.streaming.km.common.bean.dto.kafkauser.ClusterKafkaUserTokenDTO;
import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result;
import com.xiaojukeji.know.streaming.km.common.bean.vo.kafkauser.KafkaUserTokenVO;
public interface KafkaUserManager {
/**
* 新增KafkaUser
*/
Result<Void> createKafkaUserWithTokenEncrypted(ClusterKafkaUserTokenDTO dto, String operator);
/**
* 修改KafkaUser
*/
Result<Void> modifyKafkaUserWithTokenEncrypted(ClusterKafkaUserTokenDTO dto, String operator);
/**
* 查看密码
*/
Result<KafkaUserTokenVO> getKafkaUserTokenWithEncrypt(Long clusterPhyId, String kafkaUser);
}

View File

@@ -1,99 +0,0 @@
package com.xiaojukeji.know.streaming.km.biz.kafkauser.impl;
import com.didiglobal.logi.log.ILog;
import com.didiglobal.logi.log.LogFactory;
import com.didiglobal.logi.security.util.PWEncryptUtil;
import com.xiaojukeji.know.streaming.km.biz.kafkauser.KafkaUserManager;
import com.xiaojukeji.know.streaming.km.common.bean.dto.kafkauser.ClusterKafkaUserTokenDTO;
import com.xiaojukeji.know.streaming.km.common.bean.entity.kafkauser.KafkaUser;
import com.xiaojukeji.know.streaming.km.common.bean.entity.param.kafkauser.KafkaUserReplaceParam;
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.KafkaUserPO;
import com.xiaojukeji.know.streaming.km.common.bean.vo.kafkauser.KafkaUserTokenVO;
import com.xiaojukeji.know.streaming.km.common.converter.KafkaUserVOConverter;
import com.xiaojukeji.know.streaming.km.common.enums.cluster.ClusterAuthTypeEnum;
import com.xiaojukeji.know.streaming.km.common.utils.AESUtils;
import com.xiaojukeji.know.streaming.km.common.utils.ValidateUtils;
import com.xiaojukeji.know.streaming.km.core.service.kafkauser.KafkaUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class KafkaUserManagerImpl implements KafkaUserManager {
private static final ILog log = LogFactory.getLog(KafkaUserManagerImpl.class);
@Autowired
private KafkaUserService kafkaUserService;
@Override
public Result<Void> createKafkaUserWithTokenEncrypted(ClusterKafkaUserTokenDTO dto, String operator) {
if (!ClusterAuthTypeEnum.isScram(dto.getAuthType())) {
return Result.buildFromRSAndMsg(ResultStatus.PARAM_ILLEGAL, "不支持该认证方式");
}
String rawToken = AESUtils.decrypt(dto.getToken());
if (rawToken == null) {
return Result.buildFromRSAndMsg(ResultStatus.PARAM_ILLEGAL, "KafkaUser密钥解密失败");
}
return kafkaUserService.createKafkaUser(new KafkaUserReplaceParam(dto.getClusterId(), dto.getKafkaUser(), rawToken), operator);
}
@Override
public Result<Void> modifyKafkaUserWithTokenEncrypted(ClusterKafkaUserTokenDTO dto, String operator) {
if (!ClusterAuthTypeEnum.isScram(dto.getAuthType())) {
return Result.buildFromRSAndMsg(ResultStatus.PARAM_ILLEGAL, "不支持该认证方式");
}
String rawToken = AESUtils.decrypt(dto.getToken());
if (rawToken == null) {
return Result.buildFromRSAndMsg(ResultStatus.PARAM_ILLEGAL, "KafkaUser密钥解密失败");
}
return kafkaUserService.modifyKafkaUser(new KafkaUserReplaceParam(dto.getClusterId(), dto.getKafkaUser(), rawToken), operator);
}
@Override
public Result<KafkaUserTokenVO> getKafkaUserTokenWithEncrypt(Long clusterPhyId, String kafkaUser) {
Result<KafkaUserTokenVO> voResult = this.getKafkaUserToken(clusterPhyId, kafkaUser);
if (voResult.failed() || ValidateUtils.isNull(voResult.getData().getToken())) {
// 获取失败 或 无密钥信息,则直接返回
return voResult;
}
// 对Token进行加密
voResult.getData().setToken(AESUtils.encrypt(voResult.getData().getToken()));
return voResult;
}
/**************************************************** private method ****************************************************/
private Result<KafkaUserTokenVO> getKafkaUserToken(Long clusterPhyId, String kafkaUser) {
Result<KafkaUser> kafkaUserResult = kafkaUserService.getKafkaUserFromKafka(clusterPhyId, kafkaUser);
if (kafkaUserResult.failed()) {
return Result.buildFromIgnoreData(kafkaUserResult);
}
KafkaUserPO kafkaUserPO = kafkaUserService.getKafkaUserFromDB(clusterPhyId, kafkaUser);
if (kafkaUserPO == null) {
// DB中无数据则直接返回kafka中查询到的数据
return Result.buildSuc(KafkaUserVOConverter.convert2KafkaUserTokenVO(kafkaUserResult.getData(), false, null));
}
try {
String rawToken = PWEncryptUtil.decode(kafkaUserPO.getToken());
if (kafkaUserService.isTokenEqual2CredentialProps(clusterPhyId, kafkaUserResult.getData().getProps(), rawToken)) {
// 与DB中数据一致
return Result.buildSuc(KafkaUserVOConverter.convert2KafkaUserTokenVO(kafkaUserResult.getData(), true, rawToken));
} else {
// 与DB中数据不一致
return Result.buildSuc(KafkaUserVOConverter.convert2KafkaUserTokenVO(kafkaUserResult.getData(), false, rawToken));
}
} catch (Exception e) {
// DB中数据不一致则直接返回kafka中查询到的数据
return Result.buildSuc(KafkaUserVOConverter.convert2KafkaUserTokenVO(kafkaUserResult.getData(), false, null));
}
}
}

View File

@@ -1,33 +0,0 @@
package com.xiaojukeji.know.streaming.km.biz.reassign;
import com.xiaojukeji.know.streaming.km.common.bean.dto.reassign.change.CreateChangeReplicasPlanDTO;
import com.xiaojukeji.know.streaming.km.common.bean.dto.reassign.move.CreateMoveReplicaPlanDTO;
import com.xiaojukeji.know.streaming.km.common.bean.dto.reassign.ReassignTopicOverviewDTO;
import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result;
import com.xiaojukeji.know.streaming.km.common.bean.vo.reassign.plan.ReassignPlanVO;
import com.xiaojukeji.know.streaming.km.common.bean.vo.reassign.ReassignTopicOverviewVO;
import java.util.List;
public interface ReassignManager {
/**
* 创建迁移计划Json
* @param dtoList
* @return
*/
Result<ReassignPlanVO> createReassignmentPlanJson(List<CreateMoveReplicaPlanDTO> dtoList);
/**
* 创建副本变更Json
* @param dtoList
* @return
*/
Result<ReassignPlanVO> createReplicaChangePlanJson(List<CreateChangeReplicasPlanDTO> dtoList);
/**
* 迁移Topic的信息
* @param dto
* @return
*/
Result<List<ReassignTopicOverviewVO>> getReassignmentTopicsOverview(ReassignTopicOverviewDTO dto);
}

View File

@@ -1,165 +0,0 @@
package com.xiaojukeji.know.streaming.km.biz.reassign.impl;
import com.didiglobal.logi.log.ILog;
import com.didiglobal.logi.log.LogFactory;
import com.xiaojukeji.know.streaming.km.biz.reassign.ReassignManager;
import com.xiaojukeji.know.streaming.km.common.bean.dto.reassign.change.CreateChangeReplicasPlanDTO;
import com.xiaojukeji.know.streaming.km.common.bean.dto.reassign.move.CreateMoveReplicaPlanDTO;
import com.xiaojukeji.know.streaming.km.common.bean.dto.reassign.ReassignTopicOverviewDTO;
import com.xiaojukeji.know.streaming.km.common.bean.entity.reassign.ReassignPlan;
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.vo.metrics.point.MetricPointVO;
import com.xiaojukeji.know.streaming.km.common.bean.vo.reassign.plan.ReassignPlanVO;
import com.xiaojukeji.know.streaming.km.common.bean.vo.reassign.ReassignTopicOverviewVO;
import com.xiaojukeji.know.streaming.km.common.bean.vo.reassign.plan.ReassignTopicPlanVO;
import com.xiaojukeji.know.streaming.km.common.constant.MsgConstant;
import com.xiaojukeji.know.streaming.km.common.converter.ReassignVOConverter;
import com.xiaojukeji.know.streaming.km.common.enums.AggTypeEnum;
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.service.reassign.ReassignService;
import com.xiaojukeji.know.streaming.km.core.service.topic.TopicMetricService;
import com.xiaojukeji.know.streaming.km.core.service.topic.TopicService;
import com.xiaojukeji.know.streaming.km.core.service.version.metrics.TopicMetricVersionItems;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
@Component
public class ReassignManagerImpl implements ReassignManager {
private static final ILog log = LogFactory.getLog(ReassignManagerImpl.class);
@Autowired
private ReassignService reassignService;
@Autowired
private TopicService topicService;
@Autowired
private TopicMetricService topicMetricService;
@Override
public Result<ReassignPlanVO> createReassignmentPlanJson(List<CreateMoveReplicaPlanDTO> dtoList) {
if (ValidateUtils.isEmptyList(dtoList)) {
return Result.buildSuc(new ReassignPlanVO(new ArrayList<>()));
}
List<ReassignTopicPlanVO> topicPlanList = new ArrayList<>();
for (CreateMoveReplicaPlanDTO planDTO: dtoList) {
Result<ReassignPlan> planResult = reassignService.generateReassignmentJson(
planDTO.getClusterId(),
planDTO.getTopicName(),
planDTO.getPartitionIdList(),
planDTO.getBrokerIdList(),
planDTO.getEnableRackAwareness()
);
if (planResult.failed()) {
// 出错则直接返回错误
return Result.buildFromIgnoreData(planResult);
}
// 转换格式
topicPlanList.add(ReassignVOConverter.convert2ReassignTopicPlanVO(planResult.getData()));
}
return Result.buildSuc(new ReassignPlanVO(topicPlanList));
}
@Override
public Result<ReassignPlanVO> createReplicaChangePlanJson(List<CreateChangeReplicasPlanDTO> dtoList) {
if (ValidateUtils.isEmptyList(dtoList)) {
return Result.buildSuc(new ReassignPlanVO(new ArrayList<>()));
}
List<ReassignTopicPlanVO> topicPlanList = new ArrayList<>();
for (CreateChangeReplicasPlanDTO planDTO: dtoList) {
Result<ReassignPlan> planResult = reassignService.generateReplicaChangeReassignmentJson(
planDTO.getClusterId(),
planDTO.getTopicName(),
planDTO.getNewReplicaNum(),
planDTO.getBrokerIdList()
);
if (planResult.failed()) {
// 出错则直接返回错误
return Result.buildFromIgnoreData(planResult);
}
// 转换格式
topicPlanList.add(ReassignVOConverter.convert2ReassignTopicPlanVO(planResult.getData()));
}
return Result.buildSuc(new ReassignPlanVO(topicPlanList));
}
@Override
public Result<List<ReassignTopicOverviewVO>> getReassignmentTopicsOverview(ReassignTopicOverviewDTO dto) {
Map<String, Topic> topicMap = topicService.listTopicsFromDB(dto.getClusterId()).stream().collect(Collectors.toMap(Topic::getTopicName, Function.identity()));
Map<String, ReassignTopicOverviewVO> voMap = new HashMap<>();
for (String topicName: dto.getTopicNameList()) {
Topic topic = topicMap.get(topicName);
if (topic == null) {
return Result.buildFromRSAndMsg(ResultStatus.NOT_EXIST, MsgConstant.getTopicNotExist(dto.getClusterId(), topicName));
}
ReassignTopicOverviewVO vo = ConvertUtil.obj2Obj(topic, ReassignTopicOverviewVO.class);
vo.setPartitionIdList(new ArrayList<>(topic.getPartitionMap().keySet()));
vo.setRetentionMs(topic.getRetentionMs());
vo.setLatestDaysAvgBytesInList(new ArrayList<>());
vo.setLatestDaysMaxBytesInList(new ArrayList<>());
voMap.put(topicName, vo);
}
Long now = System.currentTimeMillis();
// 补充近三天指标
for (int idx = 0; idx < 3; ++idx) {
Long startTime = now - (idx + 1) * 24L * 60L * 60L * 1000L;
Long endTime = now - idx * 24L * 60L * 60L * 1000L;
// 查询avg指标
Result<Map<String, MetricPointVO>> avgMetricMapResult = topicMetricService.getAggMetricPointFromES(
dto.getClusterId(),
dto.getTopicNameList(),
TopicMetricVersionItems.TOPIC_METRIC_BYTES_IN,
AggTypeEnum.AVG,
startTime,
endTime
);
Map<String, MetricPointVO> avgMetricMap = avgMetricMapResult.hasData()? avgMetricMapResult.getData(): new HashMap<>();
avgMetricMap.values().forEach(elem -> elem.setTimeStamp(endTime));
// 查询max指标
Result<Map<String, MetricPointVO>> maxMetricMapResult = topicMetricService.getAggMetricPointFromES(
dto.getClusterId(),
dto.getTopicNameList(),
TopicMetricVersionItems.TOPIC_METRIC_BYTES_IN,
AggTypeEnum.MAX,
startTime,
endTime
);
Map<String, MetricPointVO> maxMetricMap = maxMetricMapResult.hasData()? maxMetricMapResult.getData(): new HashMap<>();
// 补充到vo中
this.supplyLatestMetrics(voMap, avgMetricMap, maxMetricMap);
}
return Result.buildSuc(new ArrayList<>(voMap.values()));
}
/**************************************************** private method ****************************************************/
private void supplyLatestMetrics(Map<String, ReassignTopicOverviewVO> voMap,
Map<String, MetricPointVO> avgMetricMap,
Map<String, MetricPointVO> maxMetricMap) {
for (Map.Entry<String, ReassignTopicOverviewVO> entry: voMap.entrySet()) {
entry.getValue().getLatestDaysAvgBytesInList().add(avgMetricMap.get(entry.getKey()));
entry.getValue().getLatestDaysMaxBytesInList().add(maxMetricMap.get(entry.getKey()));
}
}
}

View File

@@ -1,12 +0,0 @@
package com.xiaojukeji.know.streaming.km.biz.self;
import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result;
import com.xiaojukeji.know.streaming.km.common.bean.vo.self.SelfMetricsVO;
import java.util.Properties;
public interface SelfManager {
Result<SelfMetricsVO> metrics();
Result<Properties> version();
}

View File

@@ -1,61 +0,0 @@
package com.xiaojukeji.know.streaming.km.biz.self.impl;
import com.didiglobal.logi.log.ILog;
import com.didiglobal.logi.log.LogFactory;
import com.didiglobal.logi.security.common.vo.user.UserBriefVO;
import com.didiglobal.logi.security.service.UserService;
import com.xiaojukeji.know.streaming.km.biz.self.SelfManager;
import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result;
import com.xiaojukeji.know.streaming.km.common.bean.vo.self.SelfMetricsVO;
import com.xiaojukeji.know.streaming.km.common.utils.GitPropUtil;
import com.xiaojukeji.know.streaming.km.common.utils.NetUtils;
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.km.KmNodeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Properties;
@Component
public class SelfManagerImpl implements SelfManager {
private static final ILog log = LogFactory.getLog(SelfManagerImpl.class);
@Autowired
private BrokerService brokerService;
@Autowired
private ClusterPhyService clusterPhyService;
@Autowired
private UserService userService;
@Autowired
private KmNodeService kmNodeService;
@Override
public Result<SelfMetricsVO> metrics() {
SelfMetricsVO vo = new SelfMetricsVO();
// ks自身信息
vo.setKsIp(NetUtils.localIp());
vo.setKsClusterKey(NetUtils.localMac());
List<UserBriefVO> userBriefVOList = userService.getAllUserBriefList();
vo.setKsUserCount(ValidateUtils.isNull(userBriefVOList)? 0: userBriefVOList.size());
vo.setKsServerIps(kmNodeService.listKmHosts());
// 纳管集群信息
vo.setKafkaClusterCount(clusterPhyService.listAllClusters().size());
vo.setKafkaBrokerCount(brokerService.countAllBrokers());
return Result.buildSuc(vo);
}
@Override
public Result<Properties> version() {
return Result.buildSuc(GitPropUtil.getProps());
}
}

View File

@@ -1,22 +0,0 @@
package com.xiaojukeji.know.streaming.km.biz.topic;
import com.xiaojukeji.know.streaming.km.common.bean.dto.topic.TopicCreateDTO;
import com.xiaojukeji.know.streaming.km.common.bean.dto.topic.TopicExpansionDTO;
import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result;
public interface OpTopicManager {
/**
* 创建Topic
*/
Result<Void> createTopic(TopicCreateDTO dto, String operator);
/**
* 删除Topic
*/
Result<Void> deleteTopicCombineRes(Long clusterPhyId, String topicName, String operator);
/**
* 扩分区
*/
Result<Void> expandTopic(TopicExpansionDTO dto, String operator);
}

View File

@@ -1,15 +0,0 @@
package com.xiaojukeji.know.streaming.km.biz.topic;
import com.xiaojukeji.know.streaming.km.common.bean.entity.config.kafkaconfig.KafkaTopicDefaultConfig;
import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result;
import java.util.List;
public interface TopicConfigManager {
/**
* 获取Topic默认配置
* @param clusterPhyId 物理集群ID
* @return
*/
Result<List<KafkaTopicDefaultConfig>> getDefaultTopicConfig(Long clusterPhyId);
}

View File

@@ -1,25 +0,0 @@
package com.xiaojukeji.know.streaming.km.biz.topic;
import com.xiaojukeji.know.streaming.km.common.bean.dto.topic.TopicRecordDTO;
import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result;
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;
import com.xiaojukeji.know.streaming.km.common.bean.vo.topic.broker.TopicBrokerAllVO;
import com.xiaojukeji.know.streaming.km.common.bean.vo.topic.partition.TopicPartitionVO;
import com.xiaojukeji.know.streaming.km.common.exception.AdminOperateException;
import com.xiaojukeji.know.streaming.km.common.exception.NotExistException;
import java.util.List;
public interface TopicStateManager {
TopicBrokerAllVO getTopicBrokerAll(Long clusterPhyId, String topicName, String searchBrokerHost) throws NotExistException;
Result<List<TopicRecordVO>> getTopicMessages(Long clusterPhyId, String topicName, TopicRecordDTO dto) throws AdminOperateException;
Result<TopicStateVO> getTopicState(Long clusterPhyId, String topicName);
Result<List<TopicPartitionVO>> getTopicPartitions(Long clusterPhyId, String topicName, List<String> metricsNames);
Result<TopicBrokersPartitionsSummaryVO> getTopicBrokersPartitionsSummary(Long clusterPhyId, String topicName);
}

View File

@@ -1,173 +0,0 @@
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.topic.OpTopicManager;
import com.xiaojukeji.know.streaming.km.common.bean.dto.topic.TopicCreateDTO;
import com.xiaojukeji.know.streaming.km.common.bean.dto.topic.TopicExpansionDTO;
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.param.topic.TopicCreateParam;
import com.xiaojukeji.know.streaming.km.common.bean.entity.param.topic.TopicParam;
import com.xiaojukeji.know.streaming.km.common.bean.entity.param.topic.TopicPartitionExpandParam;
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.constant.MsgConstant;
import com.xiaojukeji.know.streaming.km.common.utils.ValidateUtils;
import com.xiaojukeji.know.streaming.km.common.utils.kafka.KafkaReplicaAssignUtil;
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.topic.OpTopicService;
import com.xiaojukeji.know.streaming.km.core.service.topic.TopicService;
import kafka.admin.AdminUtils;
import kafka.admin.BrokerMetadata;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import scala.Option;
import scala.collection.Seq;
import scala.jdk.javaapi.CollectionConverters;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Component
public class OpTopicManagerImpl implements OpTopicManager {
private static final ILog log = LogFactory.getLog(OpTopicManagerImpl.class);
@Autowired
private TopicService topicService;
@Autowired
private BrokerService brokerService;
@Autowired
private OpTopicService opTopicService;
@Autowired
private ClusterPhyService clusterPhyService;
@Override
public Result<Void> createTopic(TopicCreateDTO dto, String operator) {
log.info("method=createTopic||param={}||operator={}.", dto, operator);
ClusterPhy clusterPhy = clusterPhyService.getClusterByCluster(dto.getClusterId());
if (clusterPhy == null) {
return Result.buildFromRSAndMsg(ResultStatus.NOT_EXIST, MsgConstant.getClusterPhyNotExist(dto.getClusterId()));
}
// 构造assignmentMap
scala.collection.Map<Object, Seq<Object>> rawAssignmentMap = AdminUtils.assignReplicasToBrokers(
this.buildBrokerMetadataSeq(dto.getClusterId(), dto.getBrokerIdList()),
dto.getPartitionNum(),
dto.getReplicaNum(),
-1,
-1
);
// 类型转换
Map<Integer, List<Integer>> assignmentMap = new HashMap<>();
rawAssignmentMap.
toStream().
foreach(elem -> assignmentMap.put(
(Integer) elem._1,
CollectionConverters.asJava(elem._2).stream().map(item -> (Integer)item).collect(Collectors.toList()))
);
// 创建Topic
return opTopicService.createTopic(
new TopicCreateParam(
dto.getClusterId(),
dto.getTopicName(),
new HashMap<String, String>((Map) dto.getProperties()),
assignmentMap,
dto.getDescription()
),
operator
);
}
@Override
public Result<Void> deleteTopicCombineRes(Long clusterPhyId, String topicName, String operator) {
// 删除Topic
Result<Void> rv = opTopicService.deleteTopic(new TopicParam(clusterPhyId, topicName), operator);
if (rv.failed()) {
return rv;
}
// 删除Topic相关的ACL信息
return Result.buildSuc();
}
@Override
@Transactional
public Result<Void> expandTopic(TopicExpansionDTO dto, String operator) {
Topic topic = topicService.getTopic(dto.getClusterId(), dto.getTopicName());
if (topic == null) {
return Result.buildFromRSAndMsg(ResultStatus.NOT_EXIST, MsgConstant.getTopicNotExist(dto.getClusterId(), dto.getTopicName()));
}
TopicPartitionExpandParam expandParam = new TopicPartitionExpandParam(
dto.getClusterId(),
dto.getTopicName(),
topic.getPartitionMap(),
this.generateNewPartitionAssignment(dto.getClusterId(), topic, dto.getBrokerIdList(), dto.getIncPartitionNum())
);
// 更新DB分区数信息, 其他信息交由后台任务进行更新
Result<Void> rv = topicService.updatePartitionNum(topic.getClusterPhyId(), topic.getTopicName(), topic.getPartitionNum() + dto.getIncPartitionNum());
if (rv.failed()){
return rv;
}
rv = opTopicService.expandTopic(expandParam, operator);
if (rv.failed()) {
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
return rv;
}
return rv;
}
/**************************************************** private method ****************************************************/
private Seq<BrokerMetadata> buildBrokerMetadataSeq(Long clusterPhyId, final List<Integer> selectedBrokerIdList) {
// 选取Broker列表
List<Broker> brokerList = brokerService.listAliveBrokersFromDB(clusterPhyId).stream().filter( elem ->
selectedBrokerIdList == null || selectedBrokerIdList.contains(elem.getBrokerId())
).collect(Collectors.toList());
List<BrokerMetadata> brokerMetadataList = new ArrayList<>();
for (Broker broker: brokerList) {
brokerMetadataList.add(new BrokerMetadata(broker.getBrokerId(), Option.apply(broker.getRack())));
}
return CollectionConverters.asScala(brokerMetadataList);
}
private Map<Integer, List<Integer>> generateNewPartitionAssignment(Long clusterPhyId, Topic topic, List<Integer> brokerIdList, Integer incPartitionNum) {
if (ValidateUtils.isEmptyList(brokerIdList)) {
// 如果brokerId列表为空则获取当前集群存活的Broker列表
brokerIdList = brokerService.listAliveBrokersFromDB(clusterPhyId).stream().map( elem -> elem.getBrokerId()).collect(Collectors.toList());
}
Map<Integer, String> brokerRackMap = new HashMap<>();
for (Broker broker: brokerService.listAliveBrokersFromDB(clusterPhyId)) {
if (brokerIdList != null && !brokerIdList.contains(broker.getBrokerId())) {
continue;
}
brokerRackMap.put(broker.getBrokerId(), broker.getRack() == null? "": broker.getRack());
}
// 生成分配规则
return KafkaReplicaAssignUtil.generateNewPartitionAssignment(brokerRackMap, topic.getPartitionMap(), incPartitionNum);
}
}

View File

@@ -1,95 +0,0 @@
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.topic.TopicConfigManager;
import com.xiaojukeji.know.streaming.km.common.bean.entity.broker.Broker;
import com.xiaojukeji.know.streaming.km.common.bean.entity.config.kafkaconfig.KafkaConfigDetail;
import com.xiaojukeji.know.streaming.km.common.bean.entity.config.kafkaconfig.KafkaTopicDefaultConfig;
import com.xiaojukeji.know.streaming.km.common.bean.entity.param.broker.BrokerParam;
import com.xiaojukeji.know.streaming.km.common.bean.entity.param.VersionItemParam;
import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result;
import com.xiaojukeji.know.streaming.km.common.converter.KafkaConfigConverter;
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.utils.ValidateUtils;
import com.xiaojukeji.know.streaming.km.core.service.broker.BrokerConfigService;
import com.xiaojukeji.know.streaming.km.core.service.broker.BrokerService;
import com.xiaojukeji.know.streaming.km.core.service.topic.TopicConfigService;
import com.xiaojukeji.know.streaming.km.core.service.version.BaseVersionControlService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.*;
import java.util.stream.Collectors;
import static com.xiaojukeji.know.streaming.km.common.enums.version.VersionEnum.*;
@Component
public class TopicConfigManagerImpl extends BaseVersionControlService implements TopicConfigManager {
private static final ILog log = LogFactory.getLog(TopicConfigManagerImpl.class);
private static final String GET_DEFAULT_TOPIC_CONFIG = "getDefaultTopicConfig";
@Autowired
private BrokerService brokerService;
@Autowired
private BrokerConfigService brokerConfigService;
@Autowired
private TopicConfigService topicConfigService;
@Override
protected VersionItemTypeEnum getVersionItemType() {
return VersionItemTypeEnum.SERVICE_OP_TOPIC_CONFIG;
}
@PostConstruct
private void init() {
registerVCHandler(GET_DEFAULT_TOPIC_CONFIG, V_0_10_0_0, V_0_11_0_0, "getDefaultTopicConfigByLocal", this::getDefaultTopicConfigByLocal);
registerVCHandler(GET_DEFAULT_TOPIC_CONFIG, V_0_11_0_0, V_MAX, "getDefaultTopicConfigByClient", this::getDefaultTopicConfigByClient);
}
@Override
public Result<List<KafkaTopicDefaultConfig>> getDefaultTopicConfig(Long clusterPhyId) {
try {
List<Broker> aliveBrokerList = brokerService.listAliveBrokersFromDB(clusterPhyId);
Integer aliveBrokerId = null;
if (!aliveBrokerList.isEmpty()) {
aliveBrokerId = aliveBrokerList.get(0).getBrokerId();
}
return (Result<List<KafkaTopicDefaultConfig>>) doVCHandler(clusterPhyId, GET_DEFAULT_TOPIC_CONFIG, new BrokerParam(clusterPhyId, aliveBrokerId));
} catch (VCHandlerNotExistException e) {
return Result.buildFailure(e.getResultStatus());
}
}
private Result<List<KafkaTopicDefaultConfig>> getDefaultTopicConfigByLocal(VersionItemParam itemParam) {
BrokerParam brokerParam = (BrokerParam) itemParam;
return Result.buildSuc(KafkaConfigConverter.convert2KafkaTopicDefaultConfigList(
topicConfigService.getConfigNamesAndDocs(brokerParam.getClusterPhyId()),
new HashMap<>()
));
}
private Result<List<KafkaTopicDefaultConfig>> getDefaultTopicConfigByClient(VersionItemParam itemParam) {
BrokerParam brokerParam = (BrokerParam) itemParam;
Result<List<KafkaConfigDetail>> defaultConfigResult = brokerConfigService.getBrokerConfigDetailFromKafka(brokerParam.getClusterPhyId(), brokerParam.getBrokerId());
if (defaultConfigResult.failed()) {
// 获取配置错误,但是不直接返回
log.error("method=getDefaultTopicConfigByClient||param={}||result={}.", brokerParam, defaultConfigResult);
}
return Result.buildSuc(KafkaConfigConverter.convert2KafkaTopicDefaultConfigList(
topicConfigService.getConfigNamesAndDocs(brokerParam.getClusterPhyId()),
!defaultConfigResult.hasData()?
new HashMap<>():
defaultConfigResult.getData().stream().filter(elem -> !ValidateUtils.isNull(elem.getValue())).collect(Collectors.toMap(KafkaConfigDetail::getName, KafkaConfigDetail::getValue))
)
);
}
}

View File

@@ -1,395 +0,0 @@
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.topic.TopicStateManager;
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.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.vo.broker.BrokerReplicaSummaryVO;
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;
import com.xiaojukeji.know.streaming.km.common.bean.vo.topic.broker.TopicBrokerAllVO;
import com.xiaojukeji.know.streaming.km.common.bean.vo.topic.broker.TopicBrokerSingleVO;
import com.xiaojukeji.know.streaming.km.common.bean.vo.topic.partition.TopicPartitionVO;
import com.xiaojukeji.know.streaming.km.common.constant.Constant;
import com.xiaojukeji.know.streaming.km.common.constant.KafkaConstant;
import com.xiaojukeji.know.streaming.km.common.constant.MsgConstant;
import com.xiaojukeji.know.streaming.km.common.converter.PartitionConverter;
import com.xiaojukeji.know.streaming.km.common.converter.TopicVOConverter;
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.utils.ConvertUtil;
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.partition.PartitionMetricService;
import com.xiaojukeji.know.streaming.km.core.service.topic.TopicConfigService;
import com.xiaojukeji.know.streaming.km.core.service.partition.PartitionService;
import com.xiaojukeji.know.streaming.km.core.service.topic.TopicMetricService;
import com.xiaojukeji.know.streaming.km.core.service.topic.TopicService;
import com.xiaojukeji.know.streaming.km.core.service.version.metrics.TopicMetricVersionItems;
import org.apache.kafka.clients.admin.OffsetSpec;
import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import org.apache.kafka.common.TopicPartition;
import org.apache.kafka.common.config.TopicConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.time.Duration;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
@Component
public class TopicStateManagerImpl implements TopicStateManager {
private static final ILog log = LogFactory.getLog(TopicStateManagerImpl.class);
@Autowired
private TopicService topicService;
@Autowired
private BrokerService brokerService;
@Autowired
private PartitionService partitionService;
@Autowired
private PartitionMetricService partitionMetricService;
@Autowired
private TopicMetricService topicMetricService;
@Autowired
private ClusterPhyService clusterPhyService;
@Autowired
private TopicConfigService topicConfigService;
@Override
public TopicBrokerAllVO getTopicBrokerAll(Long clusterPhyId, String topicName, String searchBrokerHost) throws NotExistException {
Topic topic = topicService.getTopic(clusterPhyId, topicName);
List<Partition> partitionList = partitionService.listPartitionByTopic(clusterPhyId, topicName);
Map<Integer, List<Partition>> brokerIdPartitionListMap = this.convert2BrokerIdPartitionListMap(partitionList);
Map<Integer, Broker> brokerMap = brokerService.listAllBrokerByTopic(clusterPhyId, topicName).stream().collect(Collectors.toMap(Broker::getBrokerId, Function.identity()));
TopicBrokerAllVO allVO = new TopicBrokerAllVO();
allVO.setTotal(topic.getBrokerIdSet().size());
allVO.setLive((int)brokerMap.values().stream().filter(elem -> elem.alive()).count());
allVO.setDead(allVO.getTotal() - allVO.getLive());
allVO.setPartitionCount(topic.getPartitionNum());
allVO.setBrokerPartitionStateList(new ArrayList<>());
allVO.setUnderReplicatedPartitionIdList(new ArrayList<>());
allVO.setNoLeaderPartitionIdList(new ArrayList<>());
// 补充无Leader及未同步的分区
for (Partition partition: partitionList) {
if (partition.getLeaderBrokerId() == null || Constant.INVALID_CODE == partition.getLeaderBrokerId()) {
allVO.getNoLeaderPartitionIdList().add(partition.getPartitionId());
}
if (partition.getInSyncReplicaList().size() != partition.getAssignReplicaList().size()) {
allVO.getUnderReplicatedPartitionIdList().add(partition.getPartitionId());
}
}
// 补充Broker中分区的详情
for (Integer brokerId: topic.getBrokerIdSet()) {
Broker broker = brokerMap.get(brokerId);
if (!ValidateUtils.isBlank(searchBrokerHost) && (broker == null || !broker.getHost().contains(searchBrokerHost))) {
// 不满足搜索的要求则直接略过该Broker
continue;
}
allVO.getBrokerPartitionStateList().add(this.getTopicBrokerSingle(clusterPhyId, topicName, brokerIdPartitionListMap, brokerId, broker));
}
return allVO;
}
@Override
public Result<List<TopicRecordVO>> getTopicMessages(Long clusterPhyId, String topicName, TopicRecordDTO dto) throws AdminOperateException {
long startTime = System.currentTimeMillis();
// 获取集群
ClusterPhy clusterPhy = clusterPhyService.getClusterByCluster(clusterPhyId);
if (clusterPhy == null) {
return Result.buildFromRSAndMsg(ResultStatus.NOT_EXIST, MsgConstant.getClusterPhyNotExist(clusterPhyId));
}
// 获取分区beginOffset
Result<Map<TopicPartition, Long>> beginOffsetsMapResult = partitionService.getPartitionOffsetFromKafka(clusterPhyId, topicName, dto.getFilterPartitionId(), OffsetSpec.earliest(), null);
if (beginOffsetsMapResult.failed()) {
return Result.buildFromIgnoreData(beginOffsetsMapResult);
}
// 获取分区endOffset
Result<Map<TopicPartition, Long>> endOffsetsMapResult = partitionService.getPartitionOffsetFromKafka(clusterPhyId, topicName, dto.getFilterPartitionId(), OffsetSpec.latest(), null);
if (endOffsetsMapResult.failed()) {
return Result.buildFromIgnoreData(endOffsetsMapResult);
}
List<TopicRecordVO> voList = new ArrayList<>();
KafkaConsumer<String, String> kafkaConsumer = null;
try {
// 创建kafka-consumer
kafkaConsumer = new KafkaConsumer<>(this.generateClientProperties(clusterPhy, dto.getMaxRecords()));
List<TopicPartition> partitionList = new ArrayList<>();
long maxMessage = 0;
for (Map.Entry<TopicPartition, Long> entry : endOffsetsMapResult.getData().entrySet()) {
long begin = beginOffsetsMapResult.getData().get(entry.getKey());
long end = entry.getValue();
if (begin == end){
continue;
}
maxMessage += end - begin;
partitionList.add(entry.getKey());
}
maxMessage = Math.min(maxMessage, dto.getMaxRecords());
kafkaConsumer.assign(partitionList);
for (TopicPartition partition : partitionList) {
kafkaConsumer.seek(partition, Math.max(beginOffsetsMapResult.getData().get(partition), endOffsetsMapResult.getData().get(partition) - dto.getMaxRecords()));
}
// 这里需要减去 KafkaConstant.POLL_ONCE_TIMEOUT_UNIT_MS 是因为poll一次需要耗时如果这里不减去则可能会导致poll之后超过要求的时间
while (System.currentTimeMillis() - startTime <= dto.getPullTimeoutUnitMs() && voList.size() < maxMessage) {
ConsumerRecords<String, String> consumerRecords = kafkaConsumer.poll(Duration.ofMillis(KafkaConstant.POLL_ONCE_TIMEOUT_UNIT_MS));
for (ConsumerRecord<String, String> consumerRecord : consumerRecords) {
if (this.checkIfIgnore(consumerRecord, dto.getFilterKey(), dto.getFilterValue())) {
continue;
}
voList.add(TopicVOConverter.convert2TopicRecordVO(topicName, consumerRecord));
if (voList.size() >= dto.getMaxRecords()) {
break;
}
}
// 超时则返回
if (System.currentTimeMillis() - startTime + KafkaConstant.POLL_ONCE_TIMEOUT_UNIT_MS > dto.getPullTimeoutUnitMs()
|| voList.size() > dto.getMaxRecords()) {
break;
}
}
return Result.buildSuc(voList.subList(0, Math.min(dto.getMaxRecords(), voList.size())));
} catch (Exception e) {
log.error("method=getTopicMessages||clusterPhyId={}||topicName={}||param={}||errMsg=exception", clusterPhyId, topicName, dto, e);
throw new AdminOperateException(e.getMessage(), e, ResultStatus.KAFKA_OPERATE_FAILED);
} finally {
if (kafkaConsumer != null) {
try {
kafkaConsumer.close(Duration.ofMillis(KafkaConstant.POLL_ONCE_TIMEOUT_UNIT_MS));
} catch (Exception e) {
// ignore
}
}
}
}
@Override
public Result<TopicStateVO> getTopicState(Long clusterPhyId, String topicName) {
Topic topic = topicService.getTopic(clusterPhyId, topicName);
if (topic == null) {
return Result.buildFromRSAndMsg(ResultStatus.NOT_EXIST, MsgConstant.getTopicNotExist(clusterPhyId, topicName));
}
List<Partition> partitionList = partitionService.listPartitionByTopic(clusterPhyId, topicName);
if (partitionList == null) {
partitionList = new ArrayList<>();
}
TopicStateVO vo = new TopicStateVO();
// 分区信息
vo.setPartitionCount(topic.getPartitionNum());
vo.setAllPartitionHaveLeader(partitionList.stream().filter(elem -> elem.getLeaderBrokerId().equals(-1)).count() <= 0);
// 副本信息
vo.setReplicaFactor(topic.getReplicaNum());
vo.setAllReplicaInSync(partitionList.stream().filter(elem -> elem.getInSyncReplicaList().size() != topic.getReplicaNum()).count() <= 0);
// 配置信息
Map<String, String> topicConfigMap = new HashMap<>();
Result<Map<String, String>> configResult = topicConfigService.getTopicConfigFromKafka(clusterPhyId, topicName);
if (configResult.hasData()) {
topicConfigMap = configResult.getData();
}
// 最小副本
Integer minIsr = ConvertUtil.string2Integer(topicConfigMap.get(TopicConfig.MIN_IN_SYNC_REPLICAS_CONFIG));
if (minIsr == null) {
vo.setMinimumIsr(null);
vo.setAllPartitionMatchAtMinIsr(null);
} else {
vo.setMinimumIsr(minIsr);
vo.setAllPartitionMatchAtMinIsr(partitionList.stream().filter(elem -> elem.getInSyncReplicaList().size() < minIsr).count() <= 0);
}
// 压缩方式
String cleanupPolicy = topicConfigMap.get(TopicConfig.CLEANUP_POLICY_CONFIG);
if (ValidateUtils.isBlank(cleanupPolicy)) {
vo.setCompacted(null);
} else {
vo.setCompacted(cleanupPolicy.contains(TopicConfig.CLEANUP_POLICY_COMPACT));
}
return Result.buildSuc(vo);
}
@Override
public Result<List<TopicPartitionVO>> getTopicPartitions(Long clusterPhyId, String topicName, List<String> metricsNames) {
List<Partition> partitionList = partitionService.listPartitionByTopic(clusterPhyId, topicName);
if (ValidateUtils.isEmptyList(partitionList)) {
return Result.buildSuc();
}
Result<List<PartitionMetrics>> metricsResult = partitionMetricService.collectPartitionsMetricsFromKafka(clusterPhyId, topicName, metricsNames);
if (metricsResult.failed()) {
// 仅打印错误日志,但是不直接返回错误
log.error(
"class=TopicStateManagerImpl||method=getTopicPartitions||clusterPhyId={}||topicName={}||result={}||msg=get metrics from es failed",
clusterPhyId, topicName, metricsResult
);
}
// 转map
Map<Integer, PartitionMetrics> metricsMap = new HashMap<>();
if (metricsResult.hasData()) {
for (PartitionMetrics metrics: metricsResult.getData()) {
metricsMap.put(metrics.getPartitionId(), metrics);
}
}
List<TopicPartitionVO> voList = new ArrayList<>();
for (Partition partition: partitionList) {
voList.add(TopicVOConverter.convert2TopicPartitionVO(partition, metricsMap.get(partition.getPartitionId())));
}
return Result.buildSuc(voList);
}
@Override
public Result<TopicBrokersPartitionsSummaryVO> getTopicBrokersPartitionsSummary(Long clusterPhyId, String topicName) {
List<Partition> partitionList = partitionService.listPartitionByTopic(clusterPhyId, topicName);
Map<Integer, Broker> brokerMap = brokerService.listAllBrokerByTopic(clusterPhyId, topicName).stream().collect(Collectors.toMap(Broker::getBrokerId, Function.identity()));
TopicBrokersPartitionsSummaryVO vo = new TopicBrokersPartitionsSummaryVO();
// Broker统计信息
vo.setBrokerCount(brokerMap.size());
vo.setLiveBrokerCount((int)brokerMap.values().stream().filter(elem -> elem.alive()).count());
vo.setDeadBrokerCount(vo.getBrokerCount() - vo.getLiveBrokerCount());
// Partition统计信息
vo.setPartitionCount(partitionList.size());
vo.setNoLeaderPartitionCount(0);
vo.setUnderReplicatedPartitionCount(0);
// 补充无Leader及未同步的分区
for (Partition partition: partitionList) {
if (partition.getLeaderBrokerId() == null || Constant.INVALID_CODE == partition.getLeaderBrokerId()) {
vo.setNoLeaderPartitionCount(vo.getNoLeaderPartitionCount() + 1);
}
if (partition.getInSyncReplicaList().size() != partition.getAssignReplicaList().size()) {
vo.setUnderReplicatedPartitionCount(vo.getUnderReplicatedPartitionCount() + 1);
}
}
return Result.buildSuc(vo);
}
/**************************************************** private method ****************************************************/
private boolean checkIfIgnore(ConsumerRecord<String, String> consumerRecord, String filterKey, String filterValue) {
if (filterKey != null && consumerRecord.key() == null) {
// ignore
return true;
}
if (filterKey != null && consumerRecord.key() != null && !consumerRecord.key().contains(filterKey)) {
return true;
}
if (filterValue != null && consumerRecord.value() == null) {
// ignore
return true;
}
if (filterValue != null && consumerRecord.value() != null && !consumerRecord.value().contains(filterValue)) {
return true;
}
return false;
}
private TopicBrokerSingleVO getTopicBrokerSingle(Long clusterPhyId,
String topicName,
Map<Integer, List<Partition>> brokerIdPartitionListMap,
Integer brokerId,
Broker broker) {
TopicBrokerSingleVO singleVO = new TopicBrokerSingleVO();
singleVO.setBrokerId(brokerId);
singleVO.setHost(broker != null? broker.getHost(): null);
singleVO.setAlive(broker != null && broker.alive());
TopicMetrics metrics = topicMetricService.getTopicLatestMetricsFromES(clusterPhyId, brokerId, topicName, Arrays.asList(
TopicMetricVersionItems.TOPIC_METRIC_BYTES_IN,
TopicMetricVersionItems.TOPIC_METRIC_BYTES_OUT
));
if (metrics != null) {
singleVO.setBytesInOneMinuteRate(metrics.getMetrics().get(TopicMetricVersionItems.TOPIC_METRIC_BYTES_IN));
singleVO.setBytesOutOneMinuteRate(metrics.getMetrics().get(TopicMetricVersionItems.TOPIC_METRIC_BYTES_OUT));
}
singleVO.setReplicaList(this.getBrokerReplicaSummaries(brokerId, brokerIdPartitionListMap.getOrDefault(brokerId, new ArrayList<>())));
return singleVO;
}
private List<BrokerReplicaSummaryVO> getBrokerReplicaSummaries(Integer brokerId, List<Partition> partitionList) {
List<BrokerReplicaSummaryVO> voList = new ArrayList<>();
for (Partition partition: partitionList) {
BrokerReplicaSummaryVO summaryVO = new BrokerReplicaSummaryVO();
summaryVO.setTopicName(partition.getTopicName());
summaryVO.setPartitionId(partition.getPartitionId());
summaryVO.setLeaderBrokerId(partition.getLeaderBrokerId());
summaryVO.setIsLeaderReplace(brokerId.equals(partition.getLeaderBrokerId()));
summaryVO.setInSync(partition.getInSyncReplicaList().contains(brokerId));
voList.add(summaryVO);
}
return voList;
}
private Map<Integer, List<Partition>> convert2BrokerIdPartitionListMap(List<Partition> partitionList) {
Map<Integer, List<Partition>> brokerIdPartitionListMap = new HashMap<>();
for (Partition partition: partitionList) {
for (Integer brokerId: partition.getAssignReplicaList()) {
brokerIdPartitionListMap.putIfAbsent(brokerId, new ArrayList<>());
brokerIdPartitionListMap.get(brokerId).add(partition);
}
}
return brokerIdPartitionListMap;
}
private Properties generateClientProperties(ClusterPhy clusterPhy, Integer maxPollRecords) {
Properties props = ConvertUtil.str2ObjByJson(clusterPhy.getClientProperties(), Properties.class);
props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, clusterPhy.getBootstrapServers());
props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringDeserializer");
props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringDeserializer");
props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, false);
props.put(ConsumerConfig.MAX_POLL_RECORDS_CONFIG, Math.max(2, Math.min(5, maxPollRecords)));
return props;
}
}

View File

@@ -1,52 +0,0 @@
package com.xiaojukeji.know.streaming.km.biz.version;
import com.xiaojukeji.know.streaming.km.common.bean.dto.metrices.UserMetricConfigDTO;
import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result;
import com.xiaojukeji.know.streaming.km.common.bean.vo.config.metric.UserMetricConfigVO;
import com.xiaojukeji.know.streaming.km.common.bean.vo.version.VersionItemVO;
import java.util.List;
import java.util.Map;
public interface VersionControlManager {
/**
* 查询当前所有的兼容性(指标、前端操作)配置信息
* @return
*/
Result<Map<String, VersionItemVO>> listAllVersionItem();
/**
* 获取当前ks所有支持的kafka版本
* @return
*/
Result<Map<String, Long>> listAllVersions();
/**
* 获取全部集群 clusterId 中类型为 type 的指标,不论支持不支持
* @param clusterId
* @param type
* @return
*/
Result<List<VersionItemVO>> listClusterVersionControlItem(Long clusterId, Integer type);
/**
* 获取当前用户设置的用于展示的指标配置
* @param clusterId
* @param type
* @param operator
* @return
*/
Result<List<UserMetricConfigVO>> listUserMetricItem(Long clusterId, Integer type, String operator);
/**
* 更新用户配置的指标项
* @param clusterId
* @param type
* @param userMetricConfigDTO
* @param operator
* @return
*/
Result<Void> updateUserMetricItem(Long clusterId, Integer type,
UserMetricConfigDTO userMetricConfigDTO, String operator);
}

View File

@@ -1,247 +0,0 @@
package com.xiaojukeji.know.streaming.km.biz.version.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.didiglobal.logi.log.ILog;
import com.didiglobal.logi.log.LogFactory;
import com.didiglobal.logi.security.common.dto.config.ConfigDTO;
import com.didiglobal.logi.security.service.ConfigService;
import com.xiaojukeji.know.streaming.km.biz.version.VersionControlManager;
import com.xiaojukeji.know.streaming.km.common.bean.dto.metrices.UserMetricConfigDTO;
import com.xiaojukeji.know.streaming.km.common.bean.entity.config.metric.UserMetricConfig;
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.enums.version.VersionEnum;
import com.xiaojukeji.know.streaming.km.common.utils.ConvertUtil;
import com.xiaojukeji.know.streaming.km.common.utils.VersionUtil;
import com.xiaojukeji.know.streaming.km.core.service.version.VersionControlService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import javax.annotation.PostConstruct;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import static com.xiaojukeji.know.streaming.km.common.enums.version.VersionEnum.V_MAX;
import static com.xiaojukeji.know.streaming.km.common.enums.version.VersionItemTypeEnum.*;
import static com.xiaojukeji.know.streaming.km.core.service.version.metrics.BrokerMetricVersionItems.*;
import static com.xiaojukeji.know.streaming.km.core.service.version.metrics.ClusterMetricVersionItems.*;
import static com.xiaojukeji.know.streaming.km.core.service.version.metrics.GroupMetricVersionItems.*;
import static com.xiaojukeji.know.streaming.km.core.service.version.metrics.TopicMetricVersionItems.*;
@Service
public class VersionControlManagerImpl implements VersionControlManager {
protected static final ILog LOGGER = LogFactory.getLog(VersionControlManagerImpl.class);
private static final String NOT_SUPPORT_DESC = "(该指标只支持%s及以上的版本)";
private static final String NOT_SUPPORT_DESC1 = "(该指标只支持%s及以上和%s以下的版本)";
private static final String CONFIG_GROUP = "UserMetricConfig";
Set<UserMetricConfig> defaultMetrics = new HashSet<>();
@PostConstruct
public void init(){
defaultMetrics.add(new UserMetricConfig(METRIC_TOPIC.getCode(), TOPIC_METRIC_HEALTH_SCORE, true));
defaultMetrics.add(new UserMetricConfig(METRIC_TOPIC.getCode(), TOPIC_METRIC_TOTAL_PRODUCE_REQUESTS, true));
defaultMetrics.add(new UserMetricConfig(METRIC_TOPIC.getCode(), TOPIC_METRIC_FAILED_FETCH_REQ, true));
defaultMetrics.add(new UserMetricConfig(METRIC_TOPIC.getCode(), TOPIC_METRIC_FAILED_PRODUCE_REQ, true));
defaultMetrics.add(new UserMetricConfig(METRIC_TOPIC.getCode(), TOPIC_METRIC_MESSAGE_IN, true));
defaultMetrics.add(new UserMetricConfig(METRIC_TOPIC.getCode(), TOPIC_METRIC_UNDER_REPLICA_PARTITIONS, true));
defaultMetrics.add(new UserMetricConfig(METRIC_TOPIC.getCode(), TOPIC_METRIC_BYTES_IN, true));
defaultMetrics.add(new UserMetricConfig(METRIC_TOPIC.getCode(), TOPIC_METRIC_BYTES_OUT, true));
defaultMetrics.add(new UserMetricConfig(METRIC_TOPIC.getCode(), TOPIC_METRIC_BYTES_REJECTED, true));
defaultMetrics.add(new UserMetricConfig(METRIC_CLUSTER.getCode(), CLUSTER_METRIC_HEALTH_SCORE, true));
defaultMetrics.add(new UserMetricConfig(METRIC_CLUSTER.getCode(), CLUSTER_METRIC_TOTAL_REQ_QUEUE_SIZE, true));
defaultMetrics.add(new UserMetricConfig(METRIC_CLUSTER.getCode(), CLUSTER_METRIC_TOTAL_RES_QUEUE_SIZE, true));
defaultMetrics.add(new UserMetricConfig(METRIC_CLUSTER.getCode(), CLUSTER_METRIC_ACTIVE_CONTROLLER_COUNT, true));
defaultMetrics.add(new UserMetricConfig(METRIC_CLUSTER.getCode(), CLUSTER_METRIC_TOTAL_PRODUCE_REQ, true));
defaultMetrics.add(new UserMetricConfig(METRIC_CLUSTER.getCode(), CLUSTER_METRIC_TOTAL_LOG_SIZE, true));
defaultMetrics.add(new UserMetricConfig(METRIC_CLUSTER.getCode(), CLUSTER_METRIC_CONNECTIONS, true));
defaultMetrics.add(new UserMetricConfig(METRIC_CLUSTER.getCode(), CLUSTER_METRIC_MESSAGES_IN, true));
defaultMetrics.add(new UserMetricConfig(METRIC_CLUSTER.getCode(), CLUSTER_METRIC_BYTES_IN, true));
defaultMetrics.add(new UserMetricConfig(METRIC_CLUSTER.getCode(), CLUSTER_METRIC_BYTES_OUT, true));
defaultMetrics.add(new UserMetricConfig(METRIC_CLUSTER.getCode(), CLUSTER_METRIC_GROUP_REBALANCES, true));
defaultMetrics.add(new UserMetricConfig(METRIC_CLUSTER.getCode(), CLUSTER_METRIC_JOB_RUNNING, true));
defaultMetrics.add(new UserMetricConfig(METRIC_CLUSTER.getCode(), CLUSTER_METRIC_PARTITIONS_NO_LEADER, true));
defaultMetrics.add(new UserMetricConfig(METRIC_CLUSTER.getCode(), CLUSTER_METRIC_PARTITION_URP, true));
defaultMetrics.add(new UserMetricConfig(METRIC_GROUP.getCode(), GROUP_METRIC_OFFSET_CONSUMED, true));
defaultMetrics.add(new UserMetricConfig(METRIC_GROUP.getCode(), GROUP_METRIC_LAG, true));
defaultMetrics.add(new UserMetricConfig(METRIC_GROUP.getCode(), GROUP_METRIC_STATE, true));
defaultMetrics.add(new UserMetricConfig(METRIC_GROUP.getCode(), GROUP_METRIC_HEALTH_SCORE, true));
defaultMetrics.add(new UserMetricConfig(METRIC_BROKER.getCode(), BROKER_METRIC_HEALTH_SCORE, true));
defaultMetrics.add(new UserMetricConfig(METRIC_BROKER.getCode(), BROKER_METRIC_TOTAL_REQ_QUEUE, true));
defaultMetrics.add(new UserMetricConfig(METRIC_BROKER.getCode(), BROKER_METRIC_TOTAL_RES_QUEUE, true));
defaultMetrics.add(new UserMetricConfig(METRIC_BROKER.getCode(), BROKER_METRIC_MESSAGE_IN, true));
defaultMetrics.add(new UserMetricConfig(METRIC_BROKER.getCode(), BROKER_METRIC_TOTAL_PRODUCE_REQ, true));
defaultMetrics.add(new UserMetricConfig(METRIC_BROKER.getCode(), BROKER_METRIC_NETWORK_RPO_AVG_IDLE, true));
defaultMetrics.add(new UserMetricConfig(METRIC_BROKER.getCode(), BROKER_METRIC_REQ_AVG_IDLE, true));
defaultMetrics.add(new UserMetricConfig(METRIC_BROKER.getCode(), BROKER_METRIC_CONNECTION_COUNT, true));
defaultMetrics.add(new UserMetricConfig(METRIC_BROKER.getCode(), BROKER_METRIC_BYTES_IN, true));
defaultMetrics.add(new UserMetricConfig(METRIC_BROKER.getCode(), BROKER_METRIC_BYTES_OUT, true));
defaultMetrics.add(new UserMetricConfig(METRIC_BROKER.getCode(), BROKER_METRIC_PARTITIONS_SKEW, true));
defaultMetrics.add(new UserMetricConfig(METRIC_BROKER.getCode(), BROKER_METRIC_LEADERS_SKEW, true));
defaultMetrics.add(new UserMetricConfig(METRIC_BROKER.getCode(), BROKER_METRIC_UNDER_REPLICATE_PARTITION, true));
}
@Autowired
private VersionControlService versionControlService;
@Autowired
private ConfigService configService;
@Override
public Result<Map<String, VersionItemVO>> listAllVersionItem() {
List<VersionItemVO> allVersionItemVO = new ArrayList<>();
allVersionItemVO.addAll(ConvertUtil.list2List(versionControlService.listVersionControlItem(METRIC_TOPIC.getCode()), VersionItemVO.class));
allVersionItemVO.addAll(ConvertUtil.list2List(versionControlService.listVersionControlItem(METRIC_CLUSTER.getCode()), VersionItemVO.class));
allVersionItemVO.addAll(ConvertUtil.list2List(versionControlService.listVersionControlItem(METRIC_GROUP.getCode()), VersionItemVO.class));
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(WEB_OP.getCode()), VersionItemVO.class));
Map<String, VersionItemVO> map = allVersionItemVO.stream().collect(
Collectors.toMap(u -> u.getType() + "@" + u.getName(), Function.identity() ));
return Result.buildSuc(map);
}
@Override
public Result<Map<String, Long>> listAllVersions() {
return Result.buildSuc(VersionEnum.allVersionsWithOutMax());
}
@Override
public Result<List<VersionItemVO>> listClusterVersionControlItem(Long clusterId, Integer type) {
List<VersionControlItem> allItem = versionControlService.listVersionControlItem(type);
List<VersionItemVO> versionItemVOS = new ArrayList<>();
for (VersionControlItem item : allItem){
VersionItemVO itemVO = ConvertUtil.obj2Obj(item, VersionItemVO.class);
boolean support = versionControlService.isClusterSupport(clusterId, item);
itemVO.setSupport(support);
itemVO.setDesc(itemSupportDesc(item, support));
versionItemVOS.add(itemVO);
}
return Result.buildSuc(versionItemVOS);
}
@Override
public Result<List<UserMetricConfigVO>> listUserMetricItem(Long clusterId, Integer type, String operator) {
Result<List<VersionItemVO>> ret = listClusterVersionControlItem(clusterId, type);
if(null == ret || ret.failed()){
return Result.buildFail();
}
List<UserMetricConfigVO> userMetricConfigVOS = new ArrayList<>();
List<VersionItemVO> allVersionItemVOs = ret.getData();
Set<UserMetricConfig> userMetricConfigs = getUserMetricConfig(operator);
Map<String, UserMetricConfig> userMetricConfigMap = userMetricConfigs.stream().collect(
Collectors.toMap(u -> u.getType() + "@" + u.getMetric(), Function.identity() ));
for(VersionItemVO itemVO : allVersionItemVOs){
UserMetricConfigVO userMetricConfigVO = new UserMetricConfigVO();
int itemType = itemVO.getType();
String metric = itemVO.getName();
UserMetricConfig umc = userMetricConfigMap.get(itemType + "@" + metric);
userMetricConfigVO.setSet(null != umc && umc.isSet());
userMetricConfigVO.setName(itemVO.getName());
userMetricConfigVO.setType(itemVO.getType());
userMetricConfigVO.setDesc(itemVO.getDesc());
userMetricConfigVO.setMinVersion(itemVO.getMinVersion());
userMetricConfigVO.setMaxVersion(itemVO.getMaxVersion());
userMetricConfigVO.setSupport(itemVO.getSupport());
userMetricConfigVOS.add(userMetricConfigVO);
}
LOGGER.debug("method=listUserMetricItem||clusterId={}||type={}||operator={}||userMetricConfigs={}||userMetricConfigVO={}",
clusterId, type, operator, JSON.toJSONString(userMetricConfigs), JSON.toJSONString(userMetricConfigVOS));
return Result.buildSuc(userMetricConfigVOS);
}
@Override
public Result<Void> updateUserMetricItem(Long clusterId, Integer type, UserMetricConfigDTO dto, String operator) {
Map<String, Boolean> metricsSetMap = dto.getMetricsSet();
if(null == metricsSetMap || metricsSetMap.isEmpty()){
return Result.buildSuc();
}
Set<UserMetricConfig> userMetricConfigs = getUserMetricConfig(operator);
for(Map.Entry<String, Boolean> metricAndShowEntry : metricsSetMap.entrySet()){
UserMetricConfig userMetricConfig = new UserMetricConfig(type, metricAndShowEntry.getKey(), metricAndShowEntry.getValue());
userMetricConfigs.remove(userMetricConfig);
userMetricConfigs.add(userMetricConfig);
}
ConfigDTO configDTO = new ConfigDTO();
configDTO.setValueGroup(CONFIG_GROUP);
configDTO.setValueName(operator);
configDTO.setValue(JSON.toJSONString(userMetricConfigs));
configDTO.setOperator(operator);
configDTO.setStatus(1);
com.didiglobal.logi.security.common.Result<Void> result = configService.editConfig(configDTO, operator);
LOGGER.debug("method=updateUserMetricItem||clusterId={}||type={}||operator={}||userMetricConfigs={}||metricsSetMap={}",
clusterId, type, operator, JSON.toJSONString(userMetricConfigs), JSON.toJSONString(metricsSetMap));
return Result.build(result.successed());
}
/**************************************************** private method ****************************************************/
private String itemSupportDesc(VersionControlItem item, boolean support){
if(support){return item.getDesc();}
boolean bMaxVersion = (item.getMaxVersion() == V_MAX.getVersionL().longValue());
String minVersion = VersionUtil.dNormailze(item.getMinVersion());
String maxVersion = VersionUtil.dNormailze(item.getMaxVersion());
if(bMaxVersion){
return item.getDesc() + String.format(NOT_SUPPORT_DESC, minVersion);
}
return item.getDesc() + String.format(NOT_SUPPORT_DESC1, minVersion, maxVersion);
}
private Set<UserMetricConfig> getUserMetricConfig(String operator){
String value = configService.stringSetting(CONFIG_GROUP, operator, "");
if(StringUtils.isEmpty(value)){
return defaultMetrics;
}
return JSON.parseObject(value, new TypeReference<Set<UserMetricConfig>>(){});
}
public static void main(String[] args){
Set<UserMetricConfig> defaultMetrics = new HashSet<>();
defaultMetrics.add(new UserMetricConfig(METRIC_TOPIC.getCode(), TOPIC_METRIC_BYTES_IN, true));
defaultMetrics.add(new UserMetricConfig(METRIC_TOPIC.getCode(), TOPIC_METRIC_MESSAGES, true));
defaultMetrics.add(new UserMetricConfig(METRIC_TOPIC.getCode(), TOPIC_METRIC_MESSAGES, true));
String value = JSON.toJSONString(defaultMetrics);
Set<UserMetricConfig> userMetricConfigs = JSON.parseObject(value, new TypeReference<Set<UserMetricConfig>>(){});
System.out.println(value);
}
}

View File

@@ -1,33 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.xiaojukeji.kafka</groupId>
<artifactId>km-collector</artifactId>
<version>${km.revision}</version>
<packaging>jar</packaging>
<parent>
<artifactId>km</artifactId>
<groupId>com.xiaojukeji.kafka</groupId>
<version>${km.revision}</version>
</parent>
<dependencies>
<dependency>
<groupId>com.xiaojukeji.kafka</groupId>
<artifactId>km-common</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency>
<groupId>com.xiaojukeji.kafka</groupId>
<artifactId>km-core</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -1,30 +0,0 @@
package com.xiaojukeji.know.streaming.km.collector.metric;
import com.xiaojukeji.know.streaming.km.collector.service.CollectThreadPoolService;
import com.xiaojukeji.know.streaming.km.common.bean.entity.cluster.ClusterPhy;
import com.xiaojukeji.know.streaming.km.common.bean.event.metric.BaseMetricEvent;
import com.xiaojukeji.know.streaming.km.common.component.SpringTool;
import com.xiaojukeji.know.streaming.km.common.enums.version.VersionItemTypeEnum;
import com.xiaojukeji.know.streaming.km.common.utils.FutureWaitUtil;
import org.springframework.beans.factory.annotation.Autowired;
/**
* @author didi
*/
public abstract class AbstractMetricCollector<T> {
public abstract void collectMetrics(ClusterPhy clusterPhy);
public abstract VersionItemTypeEnum collectorType();
@Autowired
private CollectThreadPoolService collectThreadPoolService;
protected FutureWaitUtil<Void> getFutureUtilByClusterPhyId(Long clusterPhyId) {
return collectThreadPoolService.selectSuitableFutureUtil(clusterPhyId * 1000L + this.collectorType().getCode());
}
protected <T extends BaseMetricEvent> void publishMetric(T event){
SpringTool.publish(event);
}
}

View File

@@ -1,109 +0,0 @@
package com.xiaojukeji.know.streaming.km.collector.metric;
import com.alibaba.fastjson.JSON;
import com.didiglobal.logi.log.ILog;
import com.didiglobal.logi.log.LogFactory;
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.BrokerMetrics;
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.event.metric.BrokerMetricEvent;
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.EnvUtil;
import com.xiaojukeji.know.streaming.km.common.utils.FutureWaitUtil;
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.version.VersionControlService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import static com.xiaojukeji.know.streaming.km.common.enums.version.VersionItemTypeEnum.METRIC_BROKER;
/**
* @author didi
*/
@Component
public class BrokerMetricCollector extends AbstractMetricCollector<BrokerMetrics> {
protected static final ILog LOGGER = LogFactory.getLog("METRIC_LOGGER");
@Autowired
private VersionControlService versionControlService;
@Autowired
private BrokerMetricService brokerMetricService;
@Autowired
private BrokerService brokerService;
@Override
public void collectMetrics(ClusterPhy clusterPhy) {
Long startTime = System.currentTimeMillis();
Long clusterPhyId = clusterPhy.getId();
List<Broker> brokers = brokerService.listAliveBrokersFromDB(clusterPhy.getId());
List<VersionControlItem> items = versionControlService.listVersionControlItem(clusterPhyId, collectorType().getCode());
FutureWaitUtil<Void> future = this.getFutureUtilByClusterPhyId(clusterPhyId);
List<BrokerMetrics> brokerMetrics = new ArrayList<>();
for(Broker broker : brokers) {
BrokerMetrics metrics = new BrokerMetrics(clusterPhyId, broker.getBrokerId(), broker.getHost(), broker.getPort());
brokerMetrics.add(metrics);
future.runnableTask(
String.format("method=BrokerMetricCollector||clusterPhyId=%d||brokerId=%d", clusterPhyId, broker.getBrokerId()),
30000,
() -> collectMetrics(clusterPhyId, metrics, items)
);
}
future.waitExecute(30000);
this.publishMetric(new BrokerMetricEvent(this, brokerMetrics));
LOGGER.info("method=BrokerMetricCollector||clusterPhyId={}||startTime={}||costTime={}||msg=collect finished.",
clusterPhyId, startTime, System.currentTimeMillis() - startTime);
}
@Override
public VersionItemTypeEnum collectorType() {
return METRIC_BROKER;
}
/**************************************************** private method ****************************************************/
private void collectMetrics(Long clusterPhyId, BrokerMetrics metrics, List<VersionControlItem> items) {
long startTime = System.currentTimeMillis();
metrics.putMetric(Constant.COLLECT_METRICS_COST_TIME_METRICS_NAME, Constant.COLLECT_METRICS_ERROR_COST_TIME);
for(VersionControlItem v : items) {
try {
if(metrics.getMetrics().containsKey(v.getName())) {
continue;
}
Result<BrokerMetrics> ret = brokerMetricService.collectBrokerMetricsFromKafkaWithCacheFirst(clusterPhyId, metrics.getBrokerId(), v.getName());
if(null == ret || ret.failed() || null == ret.getData()){
continue;
}
metrics.putMetric(ret.getData().getMetrics());
if(!EnvUtil.isOnline()){
LOGGER.info("method=BrokerMetricCollector||clusterId={}||brokerId={}||metric={}||metric={}!",
clusterPhyId, metrics.getBrokerId(), v.getName(), JSON.toJSONString(ret.getData().getMetrics()));
}
} catch (Exception e){
LOGGER.error("method=BrokerMetricCollector||clusterId={}||brokerId={}||metric={}||errMsg=exception!",
clusterPhyId, metrics.getBrokerId(), v.getName(), e);
}
}
// 记录采集性能
metrics.putMetric(Constant.COLLECT_METRICS_COST_TIME_METRICS_NAME, (System.currentTimeMillis() - startTime) / 1000.0f);
}
}

View File

@@ -1,89 +0,0 @@
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.metrics.ClusterMetrics;
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.event.metric.ClusterMetricEvent;
import com.xiaojukeji.know.streaming.km.common.bean.po.metrice.ClusterMetricPO;
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.utils.FutureWaitUtil;
import com.xiaojukeji.know.streaming.km.core.service.cluster.ClusterMetricService;
import com.xiaojukeji.know.streaming.km.core.service.version.VersionControlService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
import static com.xiaojukeji.know.streaming.km.common.enums.version.VersionItemTypeEnum.METRIC_CLUSTER;
/**
* @author didi
*/
@Component
public class ClusterMetricCollector extends AbstractMetricCollector<ClusterMetricPO> {
protected static final ILog LOGGER = LogFactory.getLog("METRIC_LOGGER");
@Autowired
private VersionControlService versionControlService;
@Autowired
private ClusterMetricService clusterMetricService;
@Override
public void collectMetrics(ClusterPhy clusterPhy) {
Long startTime = System.currentTimeMillis();
Long clusterPhyId = clusterPhy.getId();
List<VersionControlItem> items = versionControlService.listVersionControlItem(clusterPhyId, collectorType().getCode());
ClusterMetrics metrics = new ClusterMetrics(clusterPhyId, clusterPhy.getKafkaVersion());
FutureWaitUtil<Void> future = this.getFutureUtilByClusterPhyId(clusterPhyId);
for(VersionControlItem v : items) {
future.runnableTask(
String.format("method=ClusterMetricCollector||clusterPhyId=%d||metricName=%s", clusterPhyId, v.getName()),
30000,
() -> {
try {
if(null != metrics.getMetrics().get(v.getName())){return null;}
Result<ClusterMetrics> ret = clusterMetricService.collectClusterMetricsFromKafka(clusterPhyId, v.getName());
if(null == ret || ret.failed() || null == ret.getData()){return null;}
metrics.putMetric(ret.getData().getMetrics());
if(!EnvUtil.isOnline()){
LOGGER.info("method=ClusterMetricCollector||clusterPhyId={}||metricName={}||metricValue={}",
clusterPhyId, v.getName(), ConvertUtil.obj2Json(ret.getData().getMetrics()));
}
} catch (Exception e){
LOGGER.error("method=ClusterMetricCollector||clusterPhyId={}||metricName={}||errMsg=exception!",
clusterPhyId, v.getName(), e);
}
return null;
});
}
future.waitExecute(30000);
metrics.putMetric(Constant.COLLECT_METRICS_COST_TIME_METRICS_NAME, (System.currentTimeMillis() - startTime) / 1000.0f);
publishMetric(new ClusterMetricEvent(this, Arrays.asList(metrics)));
LOGGER.info("method=ClusterMetricCollector||clusterPhyId={}||startTime={}||costTime={}||msg=msg=collect finished.",
clusterPhyId, startTime, System.currentTimeMillis() - startTime);
}
@Override
public VersionItemTypeEnum collectorType() {
return METRIC_CLUSTER;
}
}

View File

@@ -1,144 +0,0 @@
package com.xiaojukeji.know.streaming.km.collector.metric;
import com.alibaba.fastjson.JSON;
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.metrics.GroupMetrics;
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.event.metric.GroupMetricEvent;
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.EnvUtil;
import com.xiaojukeji.know.streaming.km.common.utils.FutureWaitUtil;
import com.xiaojukeji.know.streaming.km.common.utils.ValidateUtils;
import com.xiaojukeji.know.streaming.km.core.service.group.GroupMetricService;
import com.xiaojukeji.know.streaming.km.core.service.group.GroupService;
import com.xiaojukeji.know.streaming.km.core.service.version.VersionControlService;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import static com.xiaojukeji.know.streaming.km.common.enums.version.VersionItemTypeEnum.METRIC_GROUP;
/**
* @author didi
*/
@Component
public class GroupMetricCollector extends AbstractMetricCollector<List<GroupMetrics>> {
protected static final ILog LOGGER = LogFactory.getLog("METRIC_LOGGER");
@Autowired
private VersionControlService versionControlService;
@Autowired
private GroupMetricService groupMetricService;
@Autowired
private GroupService groupService;
@Override
public void collectMetrics(ClusterPhy clusterPhy) {
Long startTime = System.currentTimeMillis();
Long clusterPhyId = clusterPhy.getId();
List<String> groups = new ArrayList<>();
try {
groups = groupService.listGroupsFromKafka(clusterPhyId);
} catch (Exception e) {
LOGGER.error("method=GroupMetricCollector||clusterPhyId={}||msg=exception!", clusterPhyId, e);
}
if(CollectionUtils.isEmpty(groups)){return;}
List<VersionControlItem> items = versionControlService.listVersionControlItem(clusterPhyId, collectorType().getCode());
FutureWaitUtil<Void> future = getFutureUtilByClusterPhyId(clusterPhyId);
Map<String, List<GroupMetrics>> metricsMap = new ConcurrentHashMap<>();
for(String groupName : groups) {
future.runnableTask(
String.format("method=GroupMetricCollector||clusterPhyId=%d||groupName=%s", clusterPhyId, groupName),
30000,
() -> collectMetrics(clusterPhyId, groupName, metricsMap, items));
}
future.waitResult(30000);
List<GroupMetrics> metricsList = new ArrayList<>();
metricsMap.values().forEach(elem -> metricsList.addAll(elem));
publishMetric(new GroupMetricEvent(this, metricsList));
LOGGER.info("method=GroupMetricCollector||clusterPhyId={}||startTime={}||cost={}||msg=collect finished.",
clusterPhyId, startTime, System.currentTimeMillis() - startTime);
}
@Override
public VersionItemTypeEnum collectorType() {
return METRIC_GROUP;
}
/**************************************************** private method ****************************************************/
private void collectMetrics(Long clusterPhyId, String groupName, Map<String, List<GroupMetrics>> metricsMap, List<VersionControlItem> items) {
long startTime = System.currentTimeMillis();
List<GroupMetrics> groupMetricsList = new ArrayList<>();
Map<String, GroupMetrics> tpGroupPOMap = new HashMap<>();
GroupMetrics groupMetrics = new GroupMetrics(clusterPhyId, groupName, true);
groupMetrics.putMetric(Constant.COLLECT_METRICS_COST_TIME_METRICS_NAME, Constant.COLLECT_METRICS_ERROR_COST_TIME);
for(VersionControlItem v : items) {
try {
String metricName = v.getName();
Result<List<GroupMetrics>> ret = groupMetricService.collectGroupMetricsFromKafka(clusterPhyId, groupName, metricName);
if(null == ret || ret.failed() || ValidateUtils.isEmptyList(ret.getData())) {
continue;
}
ret.getData().stream().forEach(metrics -> {
if (metrics.isBGroupMetric()) {
groupMetrics.putMetric(metrics.getMetrics());
} else {
String topicName = metrics.getTopic();
Integer partitionId = metrics.getPartitionId();
String tpGroupKey = genTopicPartitionGroupKey(topicName, partitionId);
tpGroupPOMap.putIfAbsent(tpGroupKey, new GroupMetrics(clusterPhyId, partitionId, topicName, groupName, false));
tpGroupPOMap.get(tpGroupKey).putMetric(metrics.getMetrics());
}
});
if(!EnvUtil.isOnline()){
LOGGER.info("method=GroupMetricCollector||clusterPhyId={}||groupName={}||metricName={}||metricValue={}",
clusterPhyId, groupName, metricName, JSON.toJSONString(ret.getData()));
}
}catch (Exception e){
LOGGER.error("method=GroupMetricCollector||clusterPhyId={}||groupName={}||errMsg=exception!", clusterPhyId, groupName, e);
}
}
groupMetricsList.add(groupMetrics);
groupMetricsList.addAll(tpGroupPOMap.values());
// 记录采集性能
groupMetrics.putMetric(Constant.COLLECT_METRICS_COST_TIME_METRICS_NAME, (System.currentTimeMillis() - startTime) / 1000.0f);
metricsMap.put(groupName, groupMetricsList);
}
private String genTopicPartitionGroupKey(String topic, Integer partitionId){
return topic + "@" + partitionId;
}
}

View File

@@ -1,121 +0,0 @@
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.event.metric.*;
import com.xiaojukeji.know.streaming.km.common.bean.po.BaseESPO;
import com.xiaojukeji.know.streaming.km.common.bean.po.metrice.*;
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.utils.NamedThreadFactory;
import com.xiaojukeji.know.streaming.km.persistence.es.dao.BaseMetricESDAO;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import static com.xiaojukeji.know.streaming.km.common.constant.ESIndexConstant.*;
@Component
public class MetricESSender implements ApplicationListener<BaseMetricEvent> {
protected static final ILog LOGGER = LogFactory.getLog("METRIC_LOGGER");
private static final int THRESHOLD = 100;
private ThreadPoolExecutor esExecutor = new ThreadPoolExecutor(10, 20, 6000, TimeUnit.MILLISECONDS,
new LinkedBlockingDeque<>(1000),
new NamedThreadFactory("KM-Collect-MetricESSender-ES"),
(r, e) -> LOGGER.warn("class=MetricESSender||msg=KM-Collect-MetricESSender-ES Deque is blocked, taskCount:{}" + e.getTaskCount()));
@PostConstruct
public void init(){
LOGGER.info("class=MetricESSender||method=init||msg=init finished");
}
@Override
public void onApplicationEvent(BaseMetricEvent event) {
if(event instanceof BrokerMetricEvent) {
BrokerMetricEvent brokerMetricEvent = (BrokerMetricEvent)event;
send2es(BROKER_INDEX,
ConvertUtil.list2List(brokerMetricEvent.getBrokerMetrics(), BrokerMetricPO.class)
);
} else if(event instanceof ClusterMetricEvent) {
ClusterMetricEvent clusterMetricEvent = (ClusterMetricEvent)event;
send2es(CLUSTER_INDEX,
ConvertUtil.list2List(clusterMetricEvent.getClusterMetrics(), ClusterMetricPO.class)
);
} else if(event instanceof TopicMetricEvent) {
TopicMetricEvent topicMetricEvent = (TopicMetricEvent)event;
send2es(TOPIC_INDEX,
ConvertUtil.list2List(topicMetricEvent.getTopicMetrics(), TopicMetricPO.class)
);
} else if(event instanceof PartitionMetricEvent) {
PartitionMetricEvent partitionMetricEvent = (PartitionMetricEvent)event;
send2es(PARTITION_INDEX,
ConvertUtil.list2List(partitionMetricEvent.getPartitionMetrics(), PartitionMetricPO.class)
);
} else if(event instanceof GroupMetricEvent) {
GroupMetricEvent groupMetricEvent = (GroupMetricEvent)event;
send2es(GROUP_INDEX,
ConvertUtil.list2List(groupMetricEvent.getGroupMetrics(), GroupMetricPO.class)
);
} else if(event instanceof ReplicaMetricEvent) {
ReplicaMetricEvent replicaMetricEvent = (ReplicaMetricEvent)event;
send2es(REPLICATION_INDEX,
ConvertUtil.list2List(replicaMetricEvent.getReplicationMetrics(), ReplicationMetricPO.class)
);
}
}
/**
* 根据不同监控维度来发送
*/
private boolean send2es(String index, List<? extends BaseESPO> statsList){
if (CollectionUtils.isEmpty(statsList)) {
return true;
}
if (!EnvUtil.isOnline()) {
LOGGER.info("class=MetricESSender||method=send2es||ariusStats={}||size={}",
index, statsList.size());
}
BaseMetricESDAO baseMetricESDao = BaseMetricESDAO.getByStatsType(index);
if (Objects.isNull( baseMetricESDao )) {
LOGGER.error("class=MetricESSender||method=send2es||errMsg=fail to find {}", index);
return false;
}
int size = statsList.size();
int num = (size) % THRESHOLD == 0 ? (size / THRESHOLD) : (size / THRESHOLD + 1);
if (size < THRESHOLD) {
esExecutor.execute(
() -> baseMetricESDao.batchInsertStats(statsList)
);
return true;
}
for (int i = 1; i < num + 1; i++) {
int end = (i * THRESHOLD) > size ? size : (i * THRESHOLD);
int start = (i - 1) * THRESHOLD;
esExecutor.execute(
() -> baseMetricESDao.batchInsertStats(statsList.subList(start, end))
);
}
return true;
}
}

View File

@@ -1,128 +0,0 @@
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.metrics.PartitionMetrics;
import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result;
import com.xiaojukeji.know.streaming.km.common.bean.entity.topic.Topic;
import com.xiaojukeji.know.streaming.km.common.bean.entity.version.VersionControlItem;
import com.xiaojukeji.know.streaming.km.common.bean.event.metric.PartitionMetricEvent;
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.utils.FutureWaitUtil;
import com.xiaojukeji.know.streaming.km.core.service.partition.PartitionMetricService;
import com.xiaojukeji.know.streaming.km.core.service.topic.TopicService;
import com.xiaojukeji.know.streaming.km.core.service.version.VersionControlService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import static com.xiaojukeji.know.streaming.km.common.enums.version.VersionItemTypeEnum.METRIC_PARTITION;
/**
* @author didi
*/
@Component
public class PartitionMetricCollector extends AbstractMetricCollector<PartitionMetrics> {
protected static final ILog LOGGER = LogFactory.getLog("METRIC_LOGGER");
@Autowired
private VersionControlService versionControlService;
@Autowired
private PartitionMetricService partitionMetricService;
@Autowired
private TopicService topicService;
@Override
public void collectMetrics(ClusterPhy clusterPhy) {
Long startTime = System.currentTimeMillis();
Long clusterPhyId = clusterPhy.getId();
List<Topic> topicList = topicService.listTopicsFromCacheFirst(clusterPhyId);
List<VersionControlItem> items = versionControlService.listVersionControlItem(clusterPhyId, collectorType().getCode());
// 获取集群所有分区
FutureWaitUtil<Void> future = this.getFutureUtilByClusterPhyId(clusterPhyId);
Map<String, Map<Integer, PartitionMetrics>> metricsMap = new ConcurrentHashMap<>();
for (Topic topic : topicList) {
metricsMap.put(topic.getTopicName(), new ConcurrentHashMap<>());
future.runnableTask(
String.format("method=PartitionMetricCollector||clusterPhyId=%d||topicName=%s", clusterPhyId, topic.getTopicName()),
30000,
() -> collectMetrics(clusterPhyId, topic.getTopicName(), metricsMap.get(topic.getTopicName()), items)
);
}
future.waitExecute(30000);
List<PartitionMetrics> metricsList = new ArrayList<>();
metricsMap.values().forEach(elem -> metricsList.addAll(elem.values()));
this.publishMetric(new PartitionMetricEvent(this, metricsList));
LOGGER.info(
"method=PartitionMetricCollector||clusterPhyId={}||startTime={}||costTime={}||msg=collect finished.",
clusterPhyId, startTime, System.currentTimeMillis() - startTime
);
}
@Override
public VersionItemTypeEnum collectorType() {
return METRIC_PARTITION;
}
/**************************************************** private method ****************************************************/
private void collectMetrics(Long clusterPhyId, String topicName, Map<Integer, PartitionMetrics> metricsMap, List<VersionControlItem> items) {
Set<String> collectedMetricsNameSet = new HashSet<>();
for (VersionControlItem v : items) {
try {
if (collectedMetricsNameSet.contains(v.getName())) {
// 指标已存在
continue;
}
collectedMetricsNameSet.add(v.getName());
Result<List<PartitionMetrics>> ret = partitionMetricService.collectPartitionsMetricsFromKafkaWithCache(
clusterPhyId,
topicName,
v.getName()
);
if (null == ret || ret.failed() || null == ret.getData() || ret.getData().isEmpty()) {
continue;
}
// 记录已经采集的指标
collectedMetricsNameSet.addAll(ret.getData().get(0).getMetrics().keySet());
// 放到map中
for (PartitionMetrics subMetrics: ret.getData()) {
metricsMap.putIfAbsent(subMetrics.getPartitionId(), subMetrics);
PartitionMetrics allMetrics = metricsMap.get(subMetrics.getPartitionId());
allMetrics.putMetric(subMetrics.getMetrics());
}
if (!EnvUtil.isOnline()) {
LOGGER.info(
"class=PartitionMetricCollector||method=collectMetrics||clusterPhyId={}||topicName={}||metricName={}||metricValue={}!",
clusterPhyId, topicName, v.getName(), ConvertUtil.obj2Json(ret.getData())
);
}
} catch (Exception e) {
LOGGER.info(
"class=PartitionMetricCollector||method=collectMetrics||clusterPhyId={}||topicName={}||metricName={}||errMsg=exception",
clusterPhyId, topicName, v.getName(), e
);
}
}
}
}

View File

@@ -1,124 +0,0 @@
package com.xiaojukeji.know.streaming.km.collector.metric;
import com.alibaba.fastjson.JSON;
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.metrics.ReplicationMetrics;
import com.xiaojukeji.know.streaming.km.common.bean.entity.partition.Partition;
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.event.metric.ReplicaMetricEvent;
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.EnvUtil;
import com.xiaojukeji.know.streaming.km.common.utils.FutureWaitUtil;
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.VersionControlService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import static com.xiaojukeji.know.streaming.km.common.enums.version.VersionItemTypeEnum.METRIC_REPLICATION;
/**
* @author didi
*/
@Component
public class ReplicaMetricCollector extends AbstractMetricCollector<ReplicationMetrics> {
protected static final ILog LOGGER = LogFactory.getLog("METRIC_LOGGER");
@Autowired
private VersionControlService versionControlService;
@Autowired
private ReplicaMetricService replicaMetricService;
@Autowired
private PartitionService partitionService;
@Override
public void collectMetrics(ClusterPhy clusterPhy) {
Long startTime = System.currentTimeMillis();
Long clusterPhyId = clusterPhy.getId();
List<VersionControlItem> items = versionControlService.listVersionControlItem(clusterPhyId, collectorType().getCode());
List<Partition> partitions = partitionService.listPartitionByCluster(clusterPhyId);
FutureWaitUtil<Void> future = this.getFutureUtilByClusterPhyId(clusterPhyId);
List<ReplicationMetrics> metricsList = new ArrayList<>();
for(Partition partition : partitions) {
for (Integer brokerId: partition.getAssignReplicaList()) {
ReplicationMetrics metrics = new ReplicationMetrics(clusterPhyId, partition.getTopicName(), brokerId, partition.getPartitionId());
metricsList.add(metrics);
future.runnableTask(
String.format("method=ReplicaMetricCollector||clusterPhyId=%d||brokerId=%d||topicName=%s||partitionId=%d",
clusterPhyId, brokerId, partition.getTopicName(), partition.getPartitionId()),
30000,
() -> collectMetrics(clusterPhyId, metrics, items)
);
}
}
future.waitExecute(30000);
publishMetric(new ReplicaMetricEvent(this, metricsList));
LOGGER.info("method=ReplicaMetricCollector||clusterPhyId={}||startTime={}||costTime={}||msg=collect finished.",
clusterPhyId, startTime, System.currentTimeMillis() - startTime);
}
@Override
public VersionItemTypeEnum collectorType() {
return METRIC_REPLICATION;
}
/**************************************************** private method ****************************************************/
private ReplicationMetrics collectMetrics(Long clusterPhyId, ReplicationMetrics metrics, List<VersionControlItem> items) {
long startTime = System.currentTimeMillis();
metrics.putMetric(Constant.COLLECT_METRICS_COST_TIME_METRICS_NAME, Constant.COLLECT_METRICS_ERROR_COST_TIME);
for(VersionControlItem v : items) {
try {
if (metrics.getMetrics().containsKey(v.getName())) {
continue;
}
Result<ReplicationMetrics> ret = replicaMetricService.collectReplicaMetricsFromKafkaWithCache(
clusterPhyId,
metrics.getTopic(),
metrics.getBrokerId(),
metrics.getPartitionId(),
v.getName()
);
if (null == ret || ret.failed() || null == ret.getData()) {
continue;
}
metrics.putMetric(ret.getData().getMetrics());
if (!EnvUtil.isOnline()) {
LOGGER.info("method=ReplicaMetricCollector||clusterPhyId={}||topicName={}||partitionId={}||metricName={}||metricValue={}",
clusterPhyId, metrics.getTopic(), metrics.getPartitionId(), v.getName(), JSON.toJSONString(ret.getData().getMetrics()));
}
} catch (Exception e) {
LOGGER.error("method=ReplicaMetricCollector||clusterPhyId={}||topicName={}||partition={}||metricName={}||errMsg=exception!",
clusterPhyId, metrics.getTopic(), metrics.getPartitionId(), v.getName(), e);
}
}
// 记录采集性能
metrics.putMetric(Constant.COLLECT_METRICS_COST_TIME_METRICS_NAME, (System.currentTimeMillis() - startTime) / 1000.0f);
return metrics;
}
}

View File

@@ -1,137 +0,0 @@
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.metrics.TopicMetrics;
import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result;
import com.xiaojukeji.know.streaming.km.common.bean.entity.topic.Topic;
import com.xiaojukeji.know.streaming.km.common.bean.entity.version.VersionControlItem;
import com.xiaojukeji.know.streaming.km.common.bean.event.metric.TopicMetricEvent;
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.utils.FutureWaitUtil;
import com.xiaojukeji.know.streaming.km.common.utils.ValidateUtils;
import com.xiaojukeji.know.streaming.km.core.service.topic.TopicMetricService;
import com.xiaojukeji.know.streaming.km.core.service.topic.TopicService;
import com.xiaojukeji.know.streaming.km.core.service.version.VersionControlService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import static com.xiaojukeji.know.streaming.km.common.enums.version.VersionItemTypeEnum.METRIC_TOPIC;
/**
* @author didi
*/
@Component
public class TopicMetricCollector extends AbstractMetricCollector<List<TopicMetrics>> {
protected static final ILog LOGGER = LogFactory.getLog("METRIC_LOGGER");
@Autowired
private VersionControlService versionControlService;
@Autowired
private TopicService topicService;
@Autowired
private TopicMetricService topicMetricService;
private static final Integer AGG_METRICS_BROKER_ID = -10000;
@Override
public void collectMetrics(ClusterPhy clusterPhy) {
Long startTime = System.currentTimeMillis();
Long clusterPhyId = clusterPhy.getId();
List<Topic> topics = topicService.listTopicsFromCacheFirst(clusterPhyId);
List<VersionControlItem> items = versionControlService.listVersionControlItem(clusterPhyId, collectorType().getCode());
FutureWaitUtil<Void> future = this.getFutureUtilByClusterPhyId(clusterPhyId);
Map<String/*Topic名称*/, Map<Integer/*BrokerId*/, TopicMetrics/*metrics*/>> allMetricsMap = new ConcurrentHashMap<>();
for(Topic topic : topics) {
Map<Integer, TopicMetrics> metricsMap = new ConcurrentHashMap<>();
metricsMap.put(AGG_METRICS_BROKER_ID, new TopicMetrics(topic.getTopicName(), clusterPhyId));
metricsMap.get(AGG_METRICS_BROKER_ID).putMetric(Constant.COLLECT_METRICS_COST_TIME_METRICS_NAME, Constant.COLLECT_METRICS_ERROR_COST_TIME);
allMetricsMap.put(topic.getTopicName(), metricsMap);
future.runnableTask(
String.format("method=TopicMetricCollector||clusterPhyId=%d||topicName=%s", clusterPhyId, topic.getTopicName()),
30000,
() -> collectMetrics(clusterPhyId, topic.getTopicName(), metricsMap, items)
);
}
future.waitExecute(30000);
List<TopicMetrics> metricsList = new ArrayList<>();
allMetricsMap.values().forEach(elem -> metricsList.addAll(elem.values()));
this.publishMetric(new TopicMetricEvent(this, metricsList));
LOGGER.info("method=TopicMetricCollector||clusterPhyId={}||startTime={}||costTime={}||msg=collect finished.",
clusterPhyId, startTime, System.currentTimeMillis() - startTime);
}
@Override
public VersionItemTypeEnum collectorType() {
return METRIC_TOPIC;
}
/**************************************************** private method ****************************************************/
private void collectMetrics(Long clusterPhyId, String topicName, Map<Integer, TopicMetrics> metricsMap, List<VersionControlItem> items) {
long startTime = System.currentTimeMillis();
TopicMetrics aggMetrics = metricsMap.get(AGG_METRICS_BROKER_ID);
for (VersionControlItem v : items) {
try {
if (aggMetrics.getMetrics().containsKey(v.getName())) {
// 如果已经有该指标则直接continue
continue;
}
Result<List<TopicMetrics>> ret = topicMetricService.collectTopicMetricsFromKafkaWithCacheFirst(clusterPhyId, topicName, v.getName());
if (null == ret || ret.failed() || ValidateUtils.isEmptyList(ret.getData())) {
// 返回为空、错误、无数据的情况下,直接跳过
continue;
}
// 记录数据
ret.getData().stream().forEach(metrics -> {
if (metrics.isBBrokerAgg()) {
aggMetrics.putMetric(metrics.getMetrics());
} else {
metricsMap.putIfAbsent(
metrics.getBrokerId(),
new TopicMetrics(topicName, clusterPhyId, metrics.getBrokerId(), false)
);
metricsMap.get(metrics.getBrokerId()).putMetric(metrics.getMetrics());
}
});
if (!EnvUtil.isOnline()) {
LOGGER.info("method=TopicMetricCollector||clusterPhyId={}||topicName={}||metricName={}||metricValue={}.",
clusterPhyId, topicName, v.getName(), ConvertUtil.obj2Json(ret.getData())
);
}
} catch (Exception e) {
LOGGER.error("method=TopicMetricCollector||clusterPhyId={}||topicName={}||metricName={}||errMsg=exception!",
clusterPhyId, topicName, v.getName(), e
);
}
}
// 记录采集性能
aggMetrics.putMetric(Constant.COLLECT_METRICS_COST_TIME_METRICS_NAME, (System.currentTimeMillis() - startTime) / 1000.0f);
}
}

View File

@@ -1,263 +0,0 @@
package com.xiaojukeji.know.streaming.km.collector.service;
import com.didiglobal.logi.log.ILog;
import com.didiglobal.logi.log.LogFactory;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.xiaojukeji.know.streaming.km.common.utils.CommonUtils;
import com.xiaojukeji.know.streaming.km.common.utils.FutureWaitUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicLong;
@Service
public class CollectThreadPoolService {
private static final ILog LOGGER = LogFactory.getLog(CollectThreadPoolService.class);
private final AtomicLong shardIdx = new AtomicLong(0L);
@Value(value = "${thread-pool.collector.future-util.num:1}")
private Integer futureUtilNum;
@Value(value = "${thread-pool.collector.future-util.thread-num:8}")
private Integer futureUtilThreadNum;
@Value(value = "${thread-pool.collector.future-util.queue-size:10000}")
private Integer futureUtilQueueSize;
@Value(value = "${thread-pool.collector.future-util.select-suitable-enable:true}")
private Boolean futureUtilSelectSuitableEnable;
@Value(value = "${thread-pool.collector.future-util.suitable-queue-size:5000}")
private Integer futureUtilSuitableQueueSize;
private static final Map<Long, FutureWaitUtil<Void>> SHARD_ID_FUTURE_UTIL_MAP = new ConcurrentHashMap<>();
private static final Cache<Long, Long> PHYSICAL_CLUSTER_ID_SHARD_ID_CACHE = Caffeine
.newBuilder()
.expireAfterWrite(16, TimeUnit.MINUTES)
.maximumSize(1000)
.build();
@PostConstruct
private void init() {
if (futureUtilNum <= 0) {
futureUtilNum = 1;
}
// 初始化job线程池
for (int idx = 0; idx < futureUtilNum; ++idx) {
closeOldAndCreateNew((long)idx);
}
}
public FutureWaitUtil<Void> selectSuitableFutureUtil(Long clusterPhyId) {
// 获取集群对应的shardId
Long shardId = this.getShardId(clusterPhyId);
return SHARD_ID_FUTURE_UTIL_MAP.get(shardId);
}
/**************************************************** private method ****************************************************/
private Long getShardId(Long clusterPhyId) {
Long shardId = PHYSICAL_CLUSTER_ID_SHARD_ID_CACHE.getIfPresent(clusterPhyId);
if (shardId == null) {
shardId = shardIdx.incrementAndGet() % this.futureUtilNum;
}
PHYSICAL_CLUSTER_ID_SHARD_ID_CACHE.put(clusterPhyId, shardId);
return shardId;
}
/**************************************************** schedule flush method ****************************************************/
@Scheduled(cron="0 0/5 * * * ?")
public void flush() {
// 每个shard对应的集群ID这里使用cache的原因是需要将长期不使用的集群过滤掉
Map<Long, List<Long>> shardIdPhysicalClusterIdListMap = new HashMap<>();
for (Map.Entry<Long, Long> entry: PHYSICAL_CLUSTER_ID_SHARD_ID_CACHE.asMap().entrySet()) {
shardIdPhysicalClusterIdListMap.putIfAbsent(entry.getValue(), new ArrayList<>());
shardIdPhysicalClusterIdListMap.get(entry.getValue()).add(entry.getKey());
}
// 集群在线程池的分布信息
StringBuilder sb = new StringBuilder();
for (Map.Entry<Long, FutureWaitUtil<Void>> entry: SHARD_ID_FUTURE_UTIL_MAP.entrySet()) {
// 释放被canceled的任务
entry.getValue().purgeExecutor();
sb.append("shardId:").append(entry.getKey());
sb.append(" queueSize:").append(entry.getValue().getExecutorQueueSize());
sb.append(" physicalClusterIdList:").append(
CommonUtils.longList2String(shardIdPhysicalClusterIdListMap.getOrDefault(entry.getKey(), new ArrayList<>()))
);
sb.append("\t\t\t");
if (entry.getValue().getExecutorQueueSize() >= this.futureUtilSuitableQueueSize) {
LOGGER.info("JobThreadPoolInfo\t\t\t shardId:{} queueSize:{} physicalClusterIdList:{}.",
entry.getKey(),
entry.getValue().getExecutorQueueSize(),
CommonUtils.longList2String(shardIdPhysicalClusterIdListMap.getOrDefault(entry.getKey(), new ArrayList<>()))
);
}
}
LOGGER.info("JobThreadPoolInfo\t\t\t {}...", sb);
try {
if (futureUtilSelectSuitableEnable != null && futureUtilSelectSuitableEnable) {
reBalancePhysicalClusterShard(shardIdPhysicalClusterIdListMap);
}
} catch (Exception e) {
LOGGER.error("rebalance job-thread-pool failed.", e);
}
}
private void reBalancePhysicalClusterShard(Map<Long, List<Long>> shardIdPhysicalClusterIdListMap) {
List<Long> withoutClusterShardIdList = new ArrayList<>(); // 无集群任务的线程池
List<Long> idleShardIdList = new ArrayList<>(); // 空闲的线程池
List<Long> notBusyShardIdList = new ArrayList<>(); // 不忙的线程池
List<Long> busyShardIdList = new ArrayList<>(); // 忙的线程池
List<Long> overflowShardIdList = new ArrayList<>(); // 已处理不过来的线程池
// 统计各类线程池信息
for (Map.Entry<Long, List<Long>> entry: shardIdPhysicalClusterIdListMap.entrySet()) {
Integer queueSize = SHARD_ID_FUTURE_UTIL_MAP.get(entry.getKey()).getExecutorQueueSize();
if (entry.getValue().isEmpty()) {
withoutClusterShardIdList.add(entry.getKey());
}
if (queueSize == 0) {
// 队列为空
idleShardIdList.add(entry.getKey());
} else if (queueSize <= futureUtilSuitableQueueSize) {
// 队列较空闲
notBusyShardIdList.add(entry.getKey());
} else if (queueSize >= futureUtilSuitableQueueSize - 10) {
// 队列处理不过来
overflowShardIdList.add(entry.getKey());
} else {
// 队列忙
busyShardIdList.add(entry.getKey());
}
}
// 将队列满的线程池的集群拆分到不同的线程池中
this.moveShardClusterToSuitableThreadPool(overflowShardIdList, shardIdPhysicalClusterIdListMap, withoutClusterShardIdList, idleShardIdList, notBusyShardIdList, true);
// 将busy队列的线程池的集群拆分到不同的线程池中
this.moveShardClusterToSuitableThreadPool(busyShardIdList, shardIdPhysicalClusterIdListMap, withoutClusterShardIdList, idleShardIdList, notBusyShardIdList, false);
}
private void moveShardClusterToSuitableThreadPool(List<Long> needMoveShardIdList,
Map<Long, List<Long>> shardIdPhysicalClusterIdListMap,
List<Long> withoutClusterShardIdList,
List<Long> idleShardIdList,
List<Long> notBusyShardIdList,
boolean clearTaskIfFullAndOnlyOneCluster) {
for (Long needMoveShardId: needMoveShardIdList) {
List<Long> physicalClusterIdList = shardIdPhysicalClusterIdListMap.get(needMoveShardId);
if ((physicalClusterIdList == null || physicalClusterIdList.isEmpty() || physicalClusterIdList.size() == 1) && clearTaskIfFullAndOnlyOneCluster) {
// 仅一个集群,并且满了,则清空任务,重新跑任务
closeOldAndCreateNew(needMoveShardId);
continue;
}
if (physicalClusterIdList == null) {
// 无集群
continue;
}
for (int idx = 0; idx < physicalClusterIdList.size() - 1; ++idx) {
Long newSuitableShardId = this.selectAndEmptySuitableThreadPool(shardIdPhysicalClusterIdListMap, withoutClusterShardIdList, idleShardIdList, notBusyShardIdList);
if (newSuitableShardId == null) {
LOGGER.info("without suitable job-thread-pool and return.");
return;
}
modifyPhysicalClusterIdAndShardIdCache(physicalClusterIdList.get(idx), newSuitableShardId);
}
}
}
private Long selectAndEmptySuitableThreadPool(Map<Long, List<Long>> shardIdPhysicalClusterIdListMap,
List<Long> withoutClusterShardIdList,
List<Long> idleShardIdList,
List<Long> notBusyShardIdList) {
if (!withoutClusterShardIdList.isEmpty()) {
// 先放入无集群任务的线程池
return withoutClusterShardIdList.remove((int) 0);
}
// 上一条件不满足时,优先放入比较空闲的池子
Long newShardId = this.selectAndEmptySuitableThreadPool(shardIdPhysicalClusterIdListMap, idleShardIdList);
// 上一条件不满足时,最后尝试放入不忙的池子
return newShardId == null? this.selectAndEmptySuitableThreadPool(shardIdPhysicalClusterIdListMap, notBusyShardIdList): newShardId;
}
private Long selectAndEmptySuitableThreadPool(Map<Long, List<Long>> shardIdPhysicalClusterIdListMap, List<Long> taskThreadPoolList) {
if (taskThreadPoolList.size() < 2) {
// 没有空闲的线程池队列
return null;
}
// 将两个非忙的合并,空出一个新的交给需要的
Long firstNotBusyShardId = taskThreadPoolList.remove((int) 0);
Long secondNotBusyShardId = taskThreadPoolList.remove((int) 0);
List<Long> physicalClusterIdList = shardIdPhysicalClusterIdListMap.get(secondNotBusyShardId);
if (physicalClusterIdList == null || physicalClusterIdList.isEmpty()) {
return null;
}
for (Long physicalClusterId: physicalClusterIdList) {
modifyPhysicalClusterIdAndShardIdCache(physicalClusterId, firstNotBusyShardId);
}
return secondNotBusyShardId;
}
private synchronized Long modifyPhysicalClusterIdAndShardIdCache(Long physicalClusterId, Long shardId) {
if (shardId == null) {
shardId = shardIdx.incrementAndGet() % futureUtilNum;
}
PHYSICAL_CLUSTER_ID_SHARD_ID_CACHE.put(physicalClusterId, shardId);
return shardId;
}
private synchronized FutureWaitUtil<Void> closeOldAndCreateNew(Long shardId) {
// 新的
FutureWaitUtil<Void> newFutureUtil = FutureWaitUtil.init(
"CollectorMetricsFutureUtil-Shard-" + shardId,
this.futureUtilThreadNum,
this.futureUtilThreadNum,
this.futureUtilQueueSize
);
// 存储新的,返回旧的
FutureWaitUtil<Void> oldFutureUtil = SHARD_ID_FUTURE_UTIL_MAP.put(shardId, newFutureUtil);
// 为空,则直接返回
if (oldFutureUtil == null) {
return newFutureUtil;
}
LOGGER.error("close old ThreadPoolExecutor and create new, shardId:{}.", shardId);
try {
oldFutureUtil.shutdownNow();
} catch (Exception e) {
LOGGER.error("close old ThreadPoolExecutor and create new, shutdownNow failed, shardId:{}.", shardId, e);
}
return newFutureUtil;
}
}

View File

@@ -1,131 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.xiaojukeji.kafka</groupId>
<artifactId>km-common</artifactId>
<version>${km.revision}</version>
<packaging>jar</packaging>
<parent>
<artifactId>km</artifactId>
<groupId>com.xiaojukeji.kafka</groupId>
<version>${km.revision}</version>
</parent>
<properties>
<maven.test.skip>true</maven.test.skip>
<downloadSources>true</downloadSources>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<file_encoding>UTF-8</file_encoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- zookeeper -->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
</dependency>
<!-- swagger -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
</dependency>
<!-- json -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
<version>3.0.2</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</dependency>
<dependency>
<groupId>net.sf.jopt-simple</groupId>
<artifactId>jopt-simple</artifactId>
</dependency>
<dependency>
<groupId>io.github.zqrferrari</groupId>
<artifactId>logi-log</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka-clients</artifactId>
</dependency>
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka_2.13</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -1,22 +0,0 @@
package com.xiaojukeji.know.streaming.km.common.annotations;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* Kafka源码
* @author zengqiao
* @date 2020-07-20
*/
@Target({ElementType.TYPE, ElementType.LOCAL_VARIABLE})
@Retention(RUNTIME)
@Documented
public @interface KafkaSource {
int modified() default 0;
String modifyDesc() default "";
}

View File

@@ -1,18 +0,0 @@
package com.xiaojukeji.know.streaming.km.common.annotations.enterprise;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* License
*/
@Target({ElementType.PACKAGE, ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
@Retention(RUNTIME)
@Documented
public @interface EnterpriseLicense {
boolean all() default true; // 是否所有代码都是,默认是都是
}

View File

@@ -1,18 +0,0 @@
package com.xiaojukeji.know.streaming.km.common.annotations.enterprise;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* Load-reBalance能力
*/
@Target({ElementType.PACKAGE, ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
@Retention(RUNTIME)
@Documented
public @interface EnterpriseLoadReBalance {
boolean all() default true; // 是否所有代码都是,默认是都是
}

View File

@@ -1,18 +0,0 @@
package com.xiaojukeji.know.streaming.km.common.annotations.enterprise;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* Testing
*/
@Target({ElementType.PACKAGE, ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
@Retention(RUNTIME)
@Documented
public @interface EnterpriseTesting {
boolean all() default true; // 是否所有代码都是,默认是都是
}

View File

@@ -1,13 +0,0 @@
package com.xiaojukeji.know.streaming.km.common.bean.dto;
import java.io.Serializable;
/**
*
*
* @author d06679
* @date 2019/3/13
*/
public class BaseDTO implements Serializable {
private static final long serialVersionUID = 7861489615519826338L;
}

View File

@@ -1,65 +0,0 @@
package com.xiaojukeji.know.streaming.km.common.bean.dto.acl;
import com.xiaojukeji.know.streaming.km.common.bean.dto.BaseDTO;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
* @author zengqiao
* @date 22/03/01
*/
@Data
@ApiModel(description="创建Acl")
public class AclAtomDTO extends BaseDTO {
@NotNull(message = "clusterId不允许为null")
@ApiModelProperty(value = "集群ID", example = "1")
private Long clusterId;
@NotBlank(message = "kafkaUser不允许为空")
@ApiModelProperty(value = "kafkaUser名称", example = "know-streaming")
private String kafkaUser;
/**
* 定义操作 —— 操作类型
* @see org.apache.kafka.common.acl.AclOperation
*/
@ApiModelProperty(value = "操作类型,读/写/任意等", example = "2")
private Integer aclOperation;
/**
* 定义操作 — 权限状态,允许或者拒绝
* @see org.apache.kafka.common.acl.AclPermissionType
*/
@ApiModelProperty(value = "权限状态,允许/拒绝等", example = "3")
private Integer aclPermissionType;
/**
* 定义操作 — 客户端主机
*/
@ApiModelProperty(value = "客户端主机", example = "127.0.0.1")
private String aclClientHost;
/**
* 定义资源 —— 资源类型
* @see org.apache.kafka.common.resource.ResourceType
*/
@ApiModelProperty(value = "资源类型, Topic/Group等", example = "2")
private Integer resourceType;
/**
* 定义资源 —— 资源名称
*/
@ApiModelProperty(value = "资源名称")
private String resourceName;
/**
* 定义资源 —— 资源匹配方式
* @see org.apache.kafka.common.resource.PatternType
*/
@ApiModelProperty(value = "资源匹配方式", example = "3")
private Integer resourcePatternType;
}

View File

@@ -1,20 +0,0 @@
package com.xiaojukeji.know.streaming.km.common.bean.dto.cluster;
import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationSortDTO;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotNull;
import java.util.List;
/**
* @author zengqiao
* @date 22/02/24
*/
@Data
public class ClusterBrokersOverviewDTO extends PaginationSortDTO {
@NotNull(message = "latestMetricNames不允许为空")
@ApiModelProperty("需要指标点的信息")
private List<String> latestMetricNames;
}

View File

@@ -1,19 +0,0 @@
package com.xiaojukeji.know.streaming.km.common.bean.dto.cluster;
import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationMulFuzzySearchDTO;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @author zengqiao
* @date 22/02/24
*/
@Data
public class ClusterGroupsOverviewDTO extends PaginationMulFuzzySearchDTO {
@ApiModelProperty("查找该Topic")
private String topicName;
@ApiModelProperty("查找该Group")
private String groupName;
}

View File

@@ -1,30 +0,0 @@
package com.xiaojukeji.know.streaming.km.common.bean.dto.cluster;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
* @author zengqiao
* @date 20/4/23
*/
@Data
@ApiModel(description = "集群信息接入")
@JsonIgnoreProperties(ignoreUnknown = true)
public class ClusterPhyAddDTO extends ClusterPhyBaseDTO {
@NotBlank(message = "name不允许为空串")
@ApiModelProperty(value="集群名称", example = "KnowStreaming")
protected String name;
@NotNull(message = "description不允许为空")
@ApiModelProperty(value="描述", example = "测试")
protected String description;
@NotBlank(message = "kafkaVersion不允许为空")
@ApiModelProperty(value="集群的kafka版本", example = "2.5.1")
protected String kafkaVersion;
}

View File

@@ -1,37 +0,0 @@
package com.xiaojukeji.know.streaming.km.common.bean.dto.cluster;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.xiaojukeji.know.streaming.km.common.bean.dto.BaseDTO;
import com.xiaojukeji.know.streaming.km.common.bean.entity.config.JmxConfig;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.Properties;
/**
* @author zengqiao
* @date 20/4/23
*/
@Data
@ApiModel(description = "集群信息接入测试")
@JsonIgnoreProperties(ignoreUnknown = true)
public class ClusterPhyBaseDTO extends BaseDTO {
@NotNull(message = "zookeeper不允许为null")
@ApiModelProperty(value="ZK地址, 不允许修改", example = "127.0.0.1:2181")
protected String zookeeper;
@NotBlank(message = "bootstrapServers不允许为空串")
@ApiModelProperty(value="bootstrap地址", example = "127.0.0.1:9093")
protected String bootstrapServers;
@NotNull(message = "clientProperties不允许为空")
@ApiModelProperty(value="KM连接集群时使用的客户端配置")
protected Properties clientProperties;
@NotNull(message = "jmxProperties不允许为空")
@ApiModelProperty(value="Jmx配置")
protected JmxConfig jmxProperties;
}

View File

@@ -1,21 +0,0 @@
package com.xiaojukeji.know.streaming.km.common.bean.dto.cluster;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.Min;
/**
* @author zengqiao
* @date 20/4/23
*/
@Data
@ApiModel(description = "集群信息修改")
@JsonIgnoreProperties(ignoreUnknown = true)
public class ClusterPhyModifyDTO extends ClusterPhyAddDTO {
@Min(value = 0, message = "id不允许小于0")
@ApiModelProperty(value="集群Id", example = "1")
private Long id;
}

View File

@@ -1,28 +0,0 @@
package com.xiaojukeji.know.streaming.km.common.bean.dto.cluster;
import com.xiaojukeji.know.streaming.km.common.bean.dto.metrices.MetricDTO;
import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationSortDTO;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotNull;
import java.util.List;
/**
* @author zengqiao
* @date 22/02/24
*/
@Data
public class ClusterTopicsOverviewDTO extends PaginationSortDTO {
@NotNull(message = "latestMetricNames不允许为空")
@ApiModelProperty("需要指标点的信息")
private List<String> latestMetricNames;
@NotNull(message = "metricLines不允许为空")
@ApiModelProperty("需要指标曲线的信息")
private MetricDTO metricLines;
@ApiModelProperty("显示内部Topic")
private Boolean showInternalTopics;
}

View File

@@ -1,27 +0,0 @@
package com.xiaojukeji.know.streaming.km.common.bean.dto.cluster;
import com.xiaojukeji.know.streaming.km.common.bean.dto.metrices.MetricDTO;
import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationGeneralDTO;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotNull;
import java.util.List;
/**
* @author zengqiao
* @date 22/02/24
*/
@Data
@NoArgsConstructor
public class MultiClusterDashboardDTO extends PaginationGeneralDTO {
@NotNull(message = "latestMetricNames不允许为空")
@ApiModelProperty("需要指标点的信息")
private List<String> latestMetricNames;
@NotNull(message = "metricLines不允许为空")
@ApiModelProperty("需要指标曲线的信息")
private MetricDTO metricLines;
}

View File

@@ -1,26 +0,0 @@
package com.xiaojukeji.know.streaming.km.common.bean.dto.config;
import com.xiaojukeji.know.streaming.km.common.bean.dto.BaseDTO;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import java.util.Properties;
/**
* @author zengqiao
* @date 22/02/28
*/
@Data
@ApiModel(description = "Kafka配置信息")
public class KafkaConfigDTO extends BaseDTO {
@Min(value = 0, message = "clusterId不允许小于0")
@ApiModelProperty(value = "集群ID", example = "6")
private Long clusterId;
@NotNull(message = "changedProps不允许为空")
@ApiModelProperty(value = "配置值", example = "{}")
private Properties changedProps;
}

View File

@@ -1,22 +0,0 @@
package com.xiaojukeji.know.streaming.km.common.bean.dto.config;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.Min;
/**
* @author zengqiao
* @date 22/02/28
*/
@Data
@ApiModel(description = "Kafka配置信息")
public class KafkaConfigModifyBrokerDTO extends KafkaConfigDTO {
@Min(value = 0, message = "brokerId不允许小于0")
@ApiModelProperty(value = "BrokerId", example = "1")
private Integer brokerId;
@ApiModelProperty(value = "应用到全部", example = "false")
private Boolean applyAll;
}

View File

@@ -1,19 +0,0 @@
package com.xiaojukeji.know.streaming.km.common.bean.dto.config;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
/**
* @author zengqiao
* @date 22/02/28
*/
@Data
@ApiModel(description = "Kafka配置信息")
public class KafkaConfigModifyTopicDTO extends KafkaConfigDTO {
@NotBlank(message = "topicName不允许为空")
@ApiModelProperty(value = "配置名称", example = "know-streaming")
private String topicName;
}

View File

@@ -1,34 +0,0 @@
package com.xiaojukeji.know.streaming.km.common.bean.dto.config.platform;
import com.xiaojukeji.know.streaming.km.common.bean.dto.BaseDTO;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
@Data
@NoArgsConstructor
public class PlatformClusterConfigDTO extends BaseDTO {
@Min(value = 0, message = "clusterId不允许小于0")
@ApiModelProperty(value = "集群ID", example = "6")
private Long clusterId;
@NotBlank(message = "valueGroup不允许空")
@ApiModelProperty(value = "配置组", example = "3423r43r")
private String valueGroup;
@NotBlank(message = "valueName不允许空")
@ApiModelProperty(value = "配置项的名称", example = "3423r43r")
private String valueName;
@NotNull(message = "value不允许为null")
@ApiModelProperty(value = "配置值", example = "3423r43r")
private String value;
@NotNull(message = "description不允许为null")
@ApiModelProperty(value = "备注", example = "测试")
private String description;
}

View File

@@ -1,44 +0,0 @@
package com.xiaojukeji.know.streaming.km.common.bean.dto.group;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.xiaojukeji.know.streaming.km.common.bean.dto.partition.PartitionOffsetDTO;
import com.xiaojukeji.know.streaming.km.common.bean.dto.topic.ClusterTopicDTO;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.List;
/**
* 重置offset
* @author zengqiao
* @date 19/4/8
*/
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class GroupOffsetResetDTO extends ClusterTopicDTO {
@NotBlank(message = "groupName不允许为空")
@ApiModelProperty(value = "消费组名称", example = "g-know-streaming")
private String groupName;
/**
* @see com.xiaojukeji.know.streaming.km.common.enums.GroupOffsetResetEnum
*/
@NotNull(message = "resetType不允许为空")
@ApiModelProperty(value = "重置方式", example = "1")
private Integer resetType;
@ApiModelProperty(value = "重置到指定offset")
private List<PartitionOffsetDTO> offsetList;
@ApiModelProperty(value = "重置到指定时间")
private Long timestamp;
@ApiModelProperty(value = "如果不存在则创建")
private Boolean createIfNotExist;
public boolean isCreateIfNotExist() {
return createIfNotExist != null && createIfNotExist;
}
}

View File

@@ -1,18 +0,0 @@
package com.xiaojukeji.know.streaming.km.common.bean.dto.group;
import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationSortDTO;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
/**
* @author zengqiao
* @date 22/02/24
*/
@Data
public class GroupTopicConsumedDTO extends PaginationSortDTO {
@ApiModelProperty("需要指标点的信息")
private List<String> latestMetricNames;
}

View File

@@ -1,60 +0,0 @@
/*
* Copyright (c) 2015, WINIT and/or its affiliates. All rights reserved. Use, Copy is subject to authorized license.
*/
package com.xiaojukeji.know.streaming.km.common.bean.dto.job;
import com.xiaojukeji.know.streaming.km.common.bean.dto.BaseDTO;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank;
import java.util.Date;
/**
* WorkTask Vo 对象
*
* @author fengqiongfeng
* @date 2020-12-21
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class JobDTO extends BaseDTO {
private static final long serialVersionUID = 1L;
@ApiModelProperty("任务id, 创建时不需要")
private Long id;
/**
* @see com.xiaojukeji.know.streaming.km.common.enums.job.JobTypeEnum
*/
@ApiModelProperty("任务类型")
private Integer jobType;
/**
* @see com.xiaojukeji.know.streaming.km.common.enums.job.JobStatusEnum
*/
@ApiModelProperty("任务状态")
private Integer jobStatus;
@ApiModelProperty("任务执行对象")
private String target;
@ApiModelProperty(value = "任务描述")
private String jobDesc;
@NotBlank(message = "creator不允许为空或空串")
@ApiModelProperty("创建人")
private String creator;
@ApiModelProperty("计划执行时间")
private Date planTime;
@NotBlank(message = "data不允许为空或空串")
@ApiModelProperty("data")
private String jobData;
}

View File

@@ -1,30 +0,0 @@
package com.xiaojukeji.know.streaming.km.common.bean.dto.job;
import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationBaseDTO;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@NoArgsConstructor
@AllArgsConstructor
@ApiModel(description = "任务处理信息")
public class JobPaginationDTO extends PaginationBaseDTO {
@ApiModelProperty("任务类型,-1全部0Topic迁移1Topic扩缩副本2集群均衡")
private Integer type = -1;
@ApiModelProperty("执行任务对象")
private String jobTarget;
@ApiModelProperty("任务创建人")
private String creator;
@ApiModelProperty("运行状态,为空则代表全部状态")
private List<Integer> status;
}

View File

@@ -1,24 +0,0 @@
package com.xiaojukeji.know.streaming.km.common.bean.dto.kafkauser;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
/**
* @author zengqiao
* @date 20/4/23
*/
@Data
@ApiModel(description="kafkaUser信息")
public class ClusterKafkaUserDTO {
@Min(value = 1, message = "clusterId不允许为null或者小于0")
@ApiModelProperty(value = "集群ID, 默认为逻辑集群ID", example = "6")
protected Long clusterId;
@NotBlank(message = "kafkaUser不允许为空串")
@ApiModelProperty(value = "kafkaUser名称", example = "know-streaming")
protected String kafkaUser;
}

View File

@@ -1,24 +0,0 @@
package com.xiaojukeji.know.streaming.km.common.bean.dto.kafkauser;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
* @author zengqiao
* @date 20/4/23
*/
@Data
@ApiModel(description="kafkaUser密码信息")
public class ClusterKafkaUserTokenDTO extends ClusterKafkaUserDTO {
@NotBlank(message = "token不允许为空串")
@ApiModelProperty(value = "密码", example = "12313224cerce32r344rC")
private String token;
@NotNull(message = "authType不允许为空")
@ApiModelProperty(value = "认证类型", example = "1300")
private Integer authType;
}

View File

@@ -1,35 +0,0 @@
package com.xiaojukeji.know.streaming.km.common.bean.dto.metrices;
import com.xiaojukeji.know.streaming.km.common.bean.dto.BaseDTO;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* @author didi
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@ApiModel(description = "指标查询基础信息")
public class MetricDTO extends BaseDTO {
@ApiModelProperty("开始时间")
private Long startTime;
@ApiModelProperty("结束时间")
private Long endTime;
@ApiModelProperty(value = "聚合类型:avg、max、min、sum默认avg", example = "avg")
private String aggType = "avg";
@ApiModelProperty(value = "指标类型/指标名称", example = "[\"topics\"]")
private List<String> metricsNames;
@ApiModelProperty("Top-Level:5,10,15,20")
private Integer topNu = 5;
}

View File

@@ -1,25 +0,0 @@
package com.xiaojukeji.know.streaming.km.common.bean.dto.metrices;
import com.xiaojukeji.know.streaming.km.common.bean.entity.topic.TopicPartitionKS;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* @author didi
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@ApiModel(description = "Group&Partition指标查询信息")
public class MetricGroupPartitionDTO extends MetricDTO {
@ApiModelProperty("Group 名称")
private String group;
@ApiModelProperty("Group 的 topic & partition 信息")
private List<TopicPartitionKS> groupTopics;
}

View File

@@ -1,22 +0,0 @@
package com.xiaojukeji.know.streaming.km.common.bean.dto.metrices;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author didi
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@ApiModel(description = "Group&Topic指标查询信息")
public class MetricGroupTopicDTO extends MetricDTO {
@ApiModelProperty("Group名称")
private String group;
@ApiModelProperty("Topic名称")
private String topic;
}

View File

@@ -1,23 +0,0 @@
package com.xiaojukeji.know.streaming.km.common.bean.dto.metrices;
import com.xiaojukeji.know.streaming.km.common.bean.dto.BaseDTO;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author didi
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@ApiModel(description = "指标查询基础信息")
public class MetricRealTimeDTO extends BaseDTO {
@ApiModelProperty("指标类型")
private Integer metricType;
@ApiModelProperty("指标名称")
private String metricName;
}

View File

@@ -1,22 +0,0 @@
package com.xiaojukeji.know.streaming.km.common.bean.dto.metrices;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* @author didi
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@ApiModel(description = "topic指标查询信息")
public class MetricsBrokerDTO extends MetricDTO {
@ApiModelProperty("brokerId列表")
private List<Long> brokerIds;
}

View File

@@ -1,22 +0,0 @@
package com.xiaojukeji.know.streaming.km.common.bean.dto.metrices;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* @author didi
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@ApiModel(description = "物理集群指标查询信息")
public class MetricsClusterPhyDTO extends MetricDTO {
@ApiModelProperty("物理集群Id列表")
private List<Long> clusterPhyIds;
}

Some files were not shown because too many files have changed in this diff Show More