blob: 89f6e862417476aae6c42b9170b5feb865b98b31 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hugegraph.pd.rest;
import java.lang.management.ManagementFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import org.apache.hugegraph.pd.common.PDException;
import org.apache.hugegraph.pd.grpc.Metapb;
import org.apache.hugegraph.pd.grpc.Pdpb;
import org.apache.hugegraph.pd.model.RestApiResponse;
import org.apache.hugegraph.pd.raft.RaftEngine;
import org.apache.hugegraph.pd.rest.MemberAPI.CallStreamObserverWrap;
import org.apache.hugegraph.pd.service.PDRestService;
import org.apache.hugegraph.pd.service.PDService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
@RestController
@Slf4j
@RequestMapping("/")
public class IndexAPI extends API {
@Autowired
PDService pdService;
@Autowired
PDRestService pdRestService;
@GetMapping(value = "/", produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public BriefStatistics index() throws PDException, ExecutionException, InterruptedException {
BriefStatistics statistics = new BriefStatistics();
statistics.leader = RaftEngine.getInstance().getLeaderGrpcAddress();
statistics.state = pdService.getStoreNodeService().getClusterStats().getState().toString();
statistics.storeSize = pdService.getStoreNodeService().getActiveStores().size();
statistics.graphSize = pdService.getPartitionService().getGraphs().size();
statistics.partitionSize = pdService.getStoreNodeService().getShardGroups().size();
return statistics;
}
@GetMapping(value = "/v1/cluster", produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public RestApiResponse cluster() throws InterruptedException, ExecutionException {
Statistics statistics = new Statistics();
try {
statistics.state =
String.valueOf(pdService.getStoreNodeService().getClusterStats().getState());
String leaderGrpcAddress = RaftEngine.getInstance().getLeaderGrpcAddress();
CallStreamObserverWrap<Pdpb.GetMembersResponse> response =
new CallStreamObserverWrap<>();
pdService.getMembers(Pdpb.GetMembersRequest.newBuilder().build(), response);
List<Member> pdList = new ArrayList<>();
for (Metapb.Member member : response.get().get(0).getMembersList()) {
Member member1 = new Member(member);
if ((leaderGrpcAddress != null) &&
(leaderGrpcAddress.equals(member.getGrpcUrl()))) {
member1.role = "Leader";
statistics.pdLeader = member1;
} else {
member1.role = "Follower";
}
pdList.add(member1);
}
statistics.pdList = pdList;
statistics.memberSize = pdList.size();
List<Store> stores = new ArrayList<>();
for (Metapb.Store store : pdService.getStoreNodeService().getStores()) {
stores.add(new Store(store));
}
statistics.stores = stores;
statistics.storeSize = statistics.stores.size();
statistics.onlineStoreSize = pdService.getStoreNodeService().getActiveStores().size();
statistics.offlineStoreSize = statistics.storeSize - statistics.onlineStoreSize;
List<Metapb.Graph> graphs = pdRestService.getGraphs();
// 图的数量,只统计/g
statistics.graphSize = graphs.stream().filter((g) -> (g.getGraphName() != null)
&&
(g.getGraphName().endsWith("/g")))
.count();
statistics.partitionSize = pdService.getStoreNodeService().getShardGroups().size();
statistics.shardCount = pdService.getConfigService().getPDConfig().getShardCount();
for (Metapb.Store store : pdService.getStoreNodeService().getStores()) {
List<Metapb.GraphStats> graphStatsList = store.getStats().getGraphStatsList();
for (Metapb.GraphStats graphStats : graphStatsList) {
statistics.keyCount += graphStats.getApproximateKeys();
statistics.dataSize += graphStats.getApproximateSize();
}
}
// 数据状态:根据图的状态推出数据状态,枚举值越大,问题越严重, 默认为正常状态
Metapb.PartitionState dataState = Metapb.PartitionState.PState_Normal;
for (Metapb.Graph graph : pdRestService.getGraphs()) {
if (graph.getState() == Metapb.PartitionState.UNRECOGNIZED) {
continue; // 未识别不参与对比,不然会抛出异常
}
if ((graph.getState() != null) &&
(graph.getState().getNumber() > dataState.getNumber())) {
dataState = graph.getState();
}
}
statistics.dataState = dataState.name();
return new RestApiResponse(statistics, Pdpb.ErrorType.OK, Pdpb.ErrorType.OK.name());
} catch (PDException e) {
log.error("PD Exception: ", e);
return new RestApiResponse(null, e.getErrorCode(), e.getMessage());
}
}
@Data
class BriefStatistics {
String state;
String leader;
int memberSize;
int storeSize;
int graphSize;
int partitionSize;
}
@Data
class Store {
long storeId;
String address;
String raftAddress;
String version;
String state;
long startTimeStamp;
public Store(Metapb.Store store) {
if (store != null) {
storeId = store.getId();
address = store.getAddress();
raftAddress = store.getRaftAddress();
version = store.getVersion();
state = String.valueOf(store.getState());
startTimeStamp = store.getStartTimestamp();
}
}
}
@Data
class Member {
String raftUrl;
String grpcUrl;
String restUrl;
String state;
String dataPath;
String role;
String serviceName; //服务名称,自定义属性
String serviceVersion; //静态定义
long startTimeStamp; //进程启动时间
public Member(Metapb.Member member) {
if (member != null) {
raftUrl = member.getRaftUrl();
grpcUrl = member.getGrpcUrl();
restUrl = member.getRestUrl();
state = String.valueOf(member.getState());
dataPath = member.getDataPath();
serviceName = grpcUrl + "-PD";
serviceVersion = VERSION;
startTimeStamp = ManagementFactory.getRuntimeMXBean().getStartTime();
}
}
public Member() {
}
}
@Data
class Statistics {
/**
* 集群状态
*/
String state;
/**
* 数据状态
*/
String dataState;
/**
* pd集群成员
*/
List<Member> pdList;
/**
* pd集群的leader
*/
Member pdLeader;
/**
* pd集群的大小
*/
int memberSize;
/**
* stores列表
*/
List<Store> stores;
/**
* store的数量
*/
int storeSize;
/**
* onlineStore
*/
int onlineStoreSize;
/**
* 离线的store的数量
*/
int offlineStoreSize;
/**
* 图的数量
*/
long graphSize;
/**
* 分区的数量
*/
int partitionSize;
/**
* 分区副本数
*/
int shardCount;
/**
* key的数量
*/
long keyCount;
/**
* 数据量
*/
long dataSize;
}
}