mock cluster mointer data

This commit is contained in:
silenceqi 2020-12-04 21:21:46 +08:00
parent 652e2061af
commit 66f9f0b900
4 changed files with 870 additions and 116 deletions

View File

@ -0,0 +1,531 @@
import { func } from "prop-types";
let data = JSON.parse(`{
"cluster_stats" : {
"indices" : {
"completion" : {
"size_in_bytes" : 0
},
"shards" : {
"replication" : 0,
"primaries" : 11,
"total" : 11,
"index" : {
"replication" : {
"avg" : 0,
"min" : 0,
"max" : 0
},
"shards" : {
"min" : 1,
"avg" : 1,
"max" : 1
},
"primaries" : {
"avg" : 1,
"min" : 1,
"max" : 1
}
}
},
"mappings" : {
"field_types" : [
{
"name" : "alias",
"count" : 3,
"index_count" : 1
},
{
"name" : "binary",
"count" : 9,
"index_count" : 1
},
{
"name" : "boolean",
"count" : 101,
"index_count" : 6
},
{
"name" : "byte",
"count" : 1,
"index_count" : 1
},
{
"name" : "date",
"count" : 136,
"index_count" : 10
},
{
"name" : "double",
"count" : 103,
"index_count" : 1
},
{
"count" : 9,
"name" : "flattened",
"index_count" : 1
},
{
"name" : "float",
"count" : 142,
"index_count" : 2
},
{
"name" : "geo_point",
"count" : 7,
"index_count" : 1
},
{
"name" : "half_float",
"count" : 10,
"index_count" : 2
},
{
"name" : "integer",
"count" : 71,
"index_count" : 4
},
{
"count" : 20,
"name" : "ip",
"index_count" : 1
},
{
"name" : "keyword",
"count" : 1312,
"index_count" : 10
},
{
"name" : "long",
"count" : 2623,
"index_count" : 8
},
{
"name" : "nested",
"count" : 14,
"index_count" : 5
},
{
"name" : "object",
"count" : 2724,
"index_count" : 10
},
{
"count" : 121,
"name" : "scaled_float",
"index_count" : 1
},
{
"name" : "text",
"count" : 201,
"index_count" : 9
}
]
},
"query_cache" : {
"miss_count" : 31874,
"cache_size" : 0,
"memory_size_in_bytes" : 0,
"total_count" : 31874,
"evictions" : 0,
"hit_count" : 0,
"cache_count" : 0
},
"docs" : {
"deleted" : 692,
"count" : 102865
},
"fielddata" : {
"memory_size_in_bytes" : 1760,
"evictions" : 0
},
"count" : 11,
"store" : {
"size_in_bytes" : 5.2982999E7,
"reserved_in_bytes" : 0
},
"analysis" : {
"built_in_filters" : [ ],
"built_in_tokenizers" : [ ],
"tokenizer_types" : [ ],
"analyzer_types" : [ ],
"filter_types" : [ ],
"char_filter_types" : [ ],
"built_in_char_filters" : [ ],
"built_in_analyzers" : [ ]
},
"segments" : {
"version_map_memory_in_bytes" : 0,
"norms_memory_in_bytes" : 2496,
"file_sizes" : { },
"max_unsafe_auto_id_timestamp" : -1,
"count" : 36,
"fixed_bit_set_memory_in_bytes" : 14048,
"term_vectors_memory_in_bytes" : 0,
"points_memory_in_bytes" : 0,
"index_writer_memory_in_bytes" : 0,
"memory_in_bytes" : 332776,
"terms_memory_in_bytes" : 109824,
"doc_values_memory_in_bytes" : 202632,
"stored_fields_memory_in_bytes" : 17824
}
},
"nodes" : {
"jvm" : {
"max_uptime_in_millis" : 3.1722515E7,
"mem" : {
"heap_max_in_bytes" : 1.073741824E9,
"heap_used_in_bytes" : 3.3389824E8
},
"versions" : [
{
"vm_version" : "15.0.1+9",
"using_bundled_jdk" : true,
"bundled_jdk" : true,
"count" : 1,
"vm_vendor" : "AdoptOpenJDK",
"version" : "15.0.1",
"vm_name" : "OpenJDK 64-Bit Server VM"
}
],
"threads" : 86
},
"process" : {
"open_file_descriptors" : {
"avg" : 402,
"min" : 402,
"max" : 402
},
"cpu" : {
"percent" : 0
}
},
"network_types" : {
"http_types" : {
"security4" : 1
},
"transport_types" : {
"security4" : 1
}
},
"os" : {
"available_processors" : 8,
"pretty_names" : [
{
"pretty_name" : "Mac OS X",
"count" : 1
}
],
"names" : [
{
"name" : "Mac OS X",
"count" : 1
}
],
"mem" : {
"used_in_bytes" : 1.6490479616E10,
"free_percent" : 4,
"total_in_bytes" : 1.7179869184E10,
"free_in_bytes" : 6.89389568E8,
"used_percent" : 96
},
"allocated_processors" : 8
},
"versions" : [
"7.10.0"
],
"discovery_types" : {
"zen" : 1
},
"plugins" : [ ],
"count" : {
"data_warm" : 1,
"data" : 1,
"data_content" : 1,
"coordinating_only" : 0,
"ingest" : 1,
"master" : 1,
"transform" : 1,
"total" : 1,
"remote_cluster_client" : 1,
"data_cold" : 1,
"voting_only" : 0,
"ml" : 1,
"data_hot" : 1
},
"packaging_types" : [
{
"flavor" : "default",
"count" : 1,
"type" : "tar"
}
],
"fs" : {
"total_in_bytes" : 1.000240963584E12,
"free_in_bytes" : 9.55349225472E11,
"available_in_bytes" : 9.39232976896E11
},
"ingest" : {
"number_of_pipelines" : 1,
"processor_stats" : {
"gsub" : {
"current" : 0,
"time_in_millis" : 0,
"count" : 0,
"failed" : 0
},
"script" : {
"current" : 0,
"time_in_millis" : 0,
"count" : 0,
"failed" : 0
}
}
}
},
"cluster_uuid" : "JFpIbacZQamv9hkgQEDZ2Q",
"timestamp" : 1.606981605839E12,
"status" : "yellow"
}
}`);
let nodesStats = JSON.parse(`[
{
"key" : "node-1",
"doc_count" : 11,
"metrics" : {
"buckets" : [
{
"key_as_string" : "2020-12-04T09:40:00.000Z",
"key" : 1607074800000,
"doc_count" : 1,
"heap_percent" : {
"value" : 54.0
},
"heap_used" : {
"value" : 5.84281136E8
},
"index_time" : {
"value" : 5935.0
},
"cpu_used" : {
"value" : 0.0
},
"search_query_total" : {
"value" : 39044.0
},
"index_total" : {
"value" : 5130.0
},
"search_query_time" : {
"value" : 7314.0
}
},
{
"key_as_string" : "2020-12-04T09:40:30.000Z",
"key" : 1607074830000,
"doc_count" : 3,
"heap_percent" : {
"value" : 63.0
},
"heap_used" : {
"value" : 6.776044E8
},
"index_time" : {
"value" : 6037.0
},
"cpu_used" : {
"value" : 1.0
},
"search_query_total" : {
"value" : 39121.0
},
"index_total" : {
"value" : 5285.0
},
"search_query_time" : {
"value" : 7328.0
},
"ds" : {
"value" : 77.0
},
"ds1" : {
"value" : 14.0
},
"ds3" : {
"value" : 155.0
},
"ds4" : {
"value" : 102.0
}
},
{
"key_as_string" : "2020-12-04T09:41:00.000Z",
"key" : 1607074860000,
"doc_count" : 3,
"heap_percent" : {
"value" : 64.0
},
"heap_used" : {
"value" : 6.92956392E8
},
"index_time" : {
"value" : 6181.0
},
"cpu_used" : {
"value" : 1.0
},
"search_query_total" : {
"value" : 39231.0
},
"index_total" : {
"value" : 5426.0
},
"search_query_time" : {
"value" : 7343.0
},
"ds" : {
"value" : 110.0
},
"ds1" : {
"value" : 15.0
},
"ds3" : {
"value" : 141.0
},
"ds4" : {
"value" : 144.0
}
},
{
"key_as_string" : "2020-12-04T09:41:30.000Z",
"key" : 1607074890000,
"doc_count" : 3,
"heap_percent" : {
"value" : 64.0
},
"heap_used" : {
"value" : 6.9177856E8
},
"index_time" : {
"value" : 6304.0
},
"cpu_used" : {
"value" : 1.0
},
"search_query_total" : {
"value" : 39339.0
},
"index_total" : {
"value" : 5582.0
},
"search_query_time" : {
"value" : 7358.0
},
"ds" : {
"value" : 108.0
},
"ds1" : {
"value" : 15.0
},
"ds3" : {
"value" : 156.0
},
"ds4" : {
"value" : 123.0
}
},
{
"key_as_string" : "2020-12-04T09:42:00.000Z",
"key" : 1607074920000,
"doc_count" : 1,
"heap_percent" : {
"value" : 16.0
},
"heap_used" : {
"value" : 1.81371952E8
},
"index_time" : {
"value" : 6323.0
},
"cpu_used" : {
"value" : 1.0
},
"search_query_total" : {
"value" : 39375.0
},
"index_total" : {
"value" : 5631.0
},
"search_query_time" : {
"value" : 7361.0
},
"ds" : {
"value" : 36.0
},
"ds1" : {
"value" : 3.0
},
"ds3" : {
"value" : 49.0
},
"ds4" : {
"value" : 19.0
}
}
]
}
}
]`);
export default {
'GET /dashboard/cluster/overview': function(req, res){
let cluster_stats = data.cluster_stats;
let result = {
elasticsearch:{
cluster_stats:{
status: cluster_stats.status,
indices: {
count: cluster_stats.indices.count,
docs: cluster_stats.indices.docs,
shards: cluster_stats.indices.shards,
store: cluster_stats.indices.store,
},
nodes: {
count:{
total: cluster_stats.nodes.count.total,
},
fs: cluster_stats.nodes.fs,
jvm: {
max_uptime_in_millis: cluster_stats.nodes.jvm.max_uptime_in_millis,
mem: cluster_stats.nodes.jvm.mem,
}
}
}
}
};
res.send(result);
},
'GET /dashboard/cluster/nodes_stats': function(req, res) {
// var statsData = [{
// node_name: nodesStats.source_node.name,
// node_id: nodesStats.source_node.uuid,
// timestamp: nodesStats.timestamp,
// node_stats: {
// jvm: nodesStats.node_stats.jvm,
// process: nodesStats.node_stats.process,
// node_master: nodesStats.node_stats.node_master,
// indices: {
// search: nodesStats.node_stats.indices.search,
// indexing: nodesStats.node_stats.indices.indices,
// },
// fs: nodesStats.node_stats.fs,
// os: nodesStats.node_stats.os,
// }
// }];
res.send({
nodes_stats: nodesStats
});
},
};

View File

@ -1,7 +1,9 @@
import React, { PureComponent,Fragment } from 'react'; import React, { PureComponent,Fragment } from 'react';
import { connect } from 'dva'; import { connect } from 'dva';
import { formatMessage, FormattedMessage } from 'umi/locale'; import { formatMessage, FormattedMessage } from 'umi/locale';
import { Row, Col, Card } from 'antd'; import { Row, Col, Card,Statistic,Icon, Divider, Skeleton } from 'antd';
import moment from 'moment';
import { import {
G2, G2,
@ -11,6 +13,7 @@ import {
Tooltip, Tooltip,
Legend, Legend,
} from 'bizcharts'; } from 'bizcharts';
import { func } from 'prop-types';
let generateHeapData = (target)=>{ let generateHeapData = (target)=>{
let data = []; let data = [];
@ -168,8 +171,8 @@ let generateIndexLatencyData = (target)=>{
} }
componentDidMount() { componentDidMount() {
let {generateFunc }= this.props; //let {generateFunc }= this.props;
generateFunc(this); //generateFunc(this);
} }
render() { render() {
//console.log(data.length) //console.log(data.length)
@ -196,7 +199,7 @@ let generateIndexLatencyData = (target)=>{
let pos = `${xname}*${yname}`; let pos = `${xname}*${yname}`;
return ( return (
<Chart <Chart
data={this.state.data} data={this.props.data}
scale={scale} scale={scale}
height={300} height={300}
forceFit forceFit
@ -243,15 +246,106 @@ const styles ={
textAlign:"center" textAlign:"center"
} }
}; };
// @connect(({ monitor, loading }) => (
// monitor, let HealthCircle = (props)=>{
// loading: loading.models.monitor, return (
// })) <div style={{
class ClusterMonitor extends PureComponent { background: props.color,
componentDidMount() { width: 12,
const { dispatch } = this.props; height: 12,
borderRadius: 12,
}}></div>
)
} }
let formatter = {
bytes: (value)=>{
if(null == value || value == ''){
return "0 Bytes";
}
var unitArr = new Array("Bytes","KB","MB","GB","TB","PB","EB","ZB","YB");
var index=0;
var srcsize = parseFloat(value);
index = Math.floor(Math.log(srcsize)/Math.log(1024));
var size = srcsize/Math.pow(1024,index);
size = size.toFixed(1);
return size + unitArr[index];
}
}
@connect(({ clusterMonitor }) => ({
clusterMonitor
}))
class StatsCharts extends PureComponent {
state = {
heapStats: [],
cpuStats:[],
searchLatency:[],
indexLatency:[],
timeScale: {min: moment().subtract(1, 'h').valueOf(), max: new Date()},
}
componentDidMount(){
let {dispatch} = this.props;
let me = this;
setInterval(function(){
dispatch({
type: 'clusterMonitor/fetchClusterNodeStats',
callback: ({nodes_stats})=> {
// var heapStats = [], cpuStats=[],searchLatency=[], indexLatency=[];
// for(let st of nodes_stats){
// var fields = {
// time: st.timestamp,
// type: st.node_name,
// }
// heapStats.push({
// ...fields,
// heap_ratio: st.node_stats.jvm.mem.heap_used_percent,
// });
// cpuStats.push({
// ...fields,
// cpu_ratio: st.node_stats.process.cpu.percent,
// });
// }
let nodesStats = nodes_stats;
let nodeCpu = [],nodeHeap=[],nodeSearchLatency=[],nodeIndexLatency=[];
let now = moment(1607085646112);
for(let ns of nodesStats){
let i = 0;
for(let bk of ns.metrics.buckets){
let fields = {
time: now.subtract(300-30*i , 's').valueOf(), //bk.key_as_string,
type: ns.key,
};
i++;
nodeCpu.push({
...fields,
cpu_ratio: bk.cpu_used.value,
});
nodeHeap.push({
...fields,
heap_ratio: bk.heap_percent.value,
});
nodeSearchLatency.push({
...fields,
latency: bk.ds1 ? (bk.ds1.value/bk.ds.value).toFixed(2): 0,
});
nodeIndexLatency.push({
...fields,
latency: bk.ds1 ? (bk.ds4.value/bk.ds3.value).toFixed(2): 0,
});
}
}
me.setState({
heapStats: nodeHeap,
cpuStats: nodeCpu,
searchLatency: nodeSearchLatency,
indexLatency: nodeIndexLatency,
timeScale: {min: moment().subtract(1, 'h').valueOf(), max: new Date()},
});
}
});
}, 10000);
}
render(){ render(){
return ( return (
<div> <div>
@ -259,14 +353,15 @@ class ClusterMonitor extends PureComponent {
<Col xl={12} lg={24} md={24} sm={24} xs={24}> <Col xl={12} lg={24} md={24} sm={24} xs={24}>
<Card> <Card>
<SliderChart title="内存使用占比(%)" xname="time" yname="heap_ratio" <SliderChart title="内存使用占比(%)" xname="time" yname="heap_ratio"
generateFunc={generateHeapData} data={this.state.heapStats}
unit="%" unit="%"
scale={{ scale={{
time: { time: {
alias: "时间", alias: "时间",
type: "time", type: "time",
mask: "HH:mm", mask: "HH:mm",
tickCount: 10, tickCount: 6,
...this.state.timeScale,
nice: false, nice: false,
}, },
heap_ratio: { heap_ratio: {
@ -285,6 +380,8 @@ class ClusterMonitor extends PureComponent {
<Col xl={12} lg={24} md={24} sm={24} xs={24}> <Col xl={12} lg={24} md={24} sm={24} xs={24}>
<Card> <Card>
<SliderChart title="CPU使用占比(%)" xname="time" yname="cpu_ratio" <SliderChart title="CPU使用占比(%)" xname="time" yname="cpu_ratio"
type="cpu_ratio"
data={this.state.cpuStats}
generateFunc={generateCpuData} generateFunc={generateCpuData}
unit="%" unit="%"
scale={{ scale={{
@ -292,7 +389,8 @@ class ClusterMonitor extends PureComponent {
alias: "时间", alias: "时间",
type: "time", type: "time",
mask: "HH:mm", mask: "HH:mm",
tickCount: 10, tickCount: 6,
...this.state.timeScale,
nice: false, nice: false,
}, },
cpu_ratio: { cpu_ratio: {
@ -314,6 +412,8 @@ class ClusterMonitor extends PureComponent {
<Col xl={12} lg={24} md={24} sm={24} xs={24}> <Col xl={12} lg={24} md={24} sm={24} xs={24}>
<Card> <Card>
<SliderChart title="搜索延迟(ms)" xname="time" yname="latency" <SliderChart title="搜索延迟(ms)" xname="time" yname="latency"
type="search_latency"
data={this.state.searchLatency}
generateFunc={generateSearchLatencyData} generateFunc={generateSearchLatencyData}
unit="ms" unit="ms"
scale={{ scale={{
@ -321,7 +421,8 @@ class ClusterMonitor extends PureComponent {
alias: "时间", alias: "时间",
type: "time", type: "time",
mask: "HH:mm", mask: "HH:mm",
tickCount: 10, tickCount: 6,
...this.state.timeScale,
nice: false, nice: false,
}, },
heap_ratio: { heap_ratio: {
@ -340,6 +441,8 @@ class ClusterMonitor extends PureComponent {
<Col xl={12} lg={24} md={24} sm={24} xs={24}> <Col xl={12} lg={24} md={24} sm={24} xs={24}>
<Card> <Card>
<SliderChart title="索引延迟(ms)" xname="time" yname="latency" <SliderChart title="索引延迟(ms)" xname="time" yname="latency"
type="index_latency"
data={this.state.indexLatency}
generateFunc={generateIndexLatencyData} generateFunc={generateIndexLatencyData}
unit="ms" unit="ms"
scale={{ scale={{
@ -347,7 +450,8 @@ class ClusterMonitor extends PureComponent {
alias: "时间", alias: "时间",
type: "time", type: "time",
mask: "HH:mm", mask: "HH:mm",
tickCount: 10, tickCount: 6,
...this.state.timeScale,
nice: false, nice: false,
}, },
cpu_ratio: { cpu_ratio: {
@ -363,7 +467,85 @@ class ClusterMonitor extends PureComponent {
/> />
</Card> </Card>
</Col> </Col>
</Row></div>
)
}
}
@connect(({ clusterMonitor }) => ({
clusterMonitor
}))
class ClusterMonitor extends PureComponent {
state={
}
componentDidMount() {
const { dispatch } = this.props;
dispatch({
type: 'clusterMonitor/fetchClusterOverview',
});
}
render() {
let vstyle = {
fontSize: 16,
};
let descStryle= {color:'#6a717d', fontSize: 12};
const {clusterMonitor} = this.props;
console.log(clusterMonitor);
let clusterStats = {};
if(clusterMonitor.elasticsearch){
let rawStats = clusterMonitor.elasticsearch.cluster_stats;
clusterStats = {
status: rawStats.status,
nodes_count: rawStats.nodes.count.total,
disk_avaiable: (rawStats.nodes.fs.available_in_bytes/rawStats.nodes.fs.total_in_bytes * 100).toFixed(2) + "%",
disk_desc: formatter.bytes(rawStats.nodes.fs.available_in_bytes) + "/" + formatter.bytes(rawStats.nodes.fs.total_in_bytes),
jvm_mem: (rawStats.nodes.jvm.mem.heap_used_in_bytes/rawStats.nodes.jvm.mem.heap_max_in_bytes * 100).toFixed(2) + "%",
jvm_desc: formatter.bytes(rawStats.nodes.jvm.mem.heap_used_in_bytes) + "/" + formatter.bytes(rawStats.nodes.jvm.mem.heap_max_in_bytes),
shards_count: rawStats.indices.shards.total,
shards_desc: "主:" + rawStats.indices.shards.primaries + ",从:" + rawStats.indices.shards.replication,
docs: rawStats.indices.docs.count,
indices_count: rawStats.indices.count,
online_duration: moment.duration(rawStats.nodes.jvm.max_uptime_in_millis).humanize(),
};
}
return (
<div>
<Card style={{marginBottom:5}}>
<Row>
<Col md={3} xs={8}>
<Statistic valueStyle={vstyle} title="在线时长" value={clusterStats.online_duration} />
</Col>
<Col md={2} xs={4}>
<Statistic valueStyle={vstyle} title="健康情况" value={clusterStats.status} prefix={<HealthCircle color="yellow"/>} />
</Col>
<Col md={2} xs={4}>
<Statistic valueStyle={vstyle} title="节点数" value={clusterStats.nodes_count} />
</Col>
<Col md={5} xs={8}>
<Statistic valueStyle={vstyle} title="磁盘可用率" value={clusterStats.disk_avaiable} suffix={
<div style={descStryle}>({clusterStats.disk_desc})</div>
} />
</Col>
<Col md={5} xs={8}>
<Statistic valueStyle={vstyle} title="JVM内存使用率" value={clusterStats.jvm_mem} suffix={
<div style={descStryle}>({clusterStats.jvm_desc})</div>
} />
</Col>
<Col md={3} xs={8}>
<Statistic valueStyle={vstyle} title="分片数" value={clusterStats.shards_count} suffix={
<div style={descStryle}>({clusterStats.shards_desc})</div>
} />
</Col>
<Col md={2} xs={4}>
<Statistic valueStyle={vstyle} title="索引个数" value={clusterStats.indices_count} />
</Col>
<Col md={2} xs={4}>
<Statistic valueStyle={vstyle} title="文档数" value={clusterStats.docs} />
</Col>
</Row> </Row>
</Card>
<StatsCharts/>
</div> </div>
); );
} }

View File

@ -0,0 +1,32 @@
import {getClusterOverview, getClusterNodeStats} from "@/services/dashboard";
export default {
namespace: 'clusterMonitor',
state: {
},
effects:{
*fetchClusterOverview({callback}, {call, put}){
let clusterData = yield call(getClusterOverview);
yield put({type: 'saveData', payload: clusterData})
if(callback && typeof callback == 'function'){
callback(clusterData);
}
},
*fetchClusterNodeStats({callback}, {call, put}){
let nodesStats = yield call(getClusterNodeStats);
//yield put({type: 'saveData', payload: nodesStats})
if(callback && typeof callback == 'function'){
callback(nodesStats);
}
}
},
reducers:{
saveData(state, {payload}){
return {
...state,
...payload
};
},
}
};

View File

@ -0,0 +1,9 @@
import request from '@/utils/request';
export async function getClusterOverview(){
return request('/dashboard/cluster/overview');
}
export async function getClusterNodeStats(){
return request('/dashboard/cluster/nodes_stats');
}