Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 52 additions & 7 deletions labs/cluster-management/README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,63 @@

## Arthas Native Agent - 集群管理

![](images/cluster_management.png)

# 快速开始


# 快速开始 - 单体模式(适用快速体验)

![](asserts/cluster_management_single.png)
## 单体模式启动native-agent-management-web
native-agent的管理页面,启动需要指定prxoy地址,启动参数

| 参数 | 必填 | 解释 |
|---------------|-----|-----------------------|
| port | N | http端口 ,默认3939 |
| proxy-address | Y | native-agent-proxy的地址 |
example:
```shell
java -jar native-agent-management-web.jar --proxy-address 161.169.97.114:2233
```

## 单体模式启动native-agent-proxy
proxy启动参数

| 参数 | 必填 | 解释 |
|--------------------|-----|--------------------------------------|
| port | N | http/ws端口 ,默认2233 |

```shell
java -jar native-agent-proxy.jar
```

## 单体模式启动native-agent
native-agent,启动在需要动态attach的服务器上。同时需要依赖arthas-agent。请把arthas-agent、arthas-core、arthas-spy放在和native-agent同一个目录下。

| 参数 | 必填 | 解释 |
|---------------|-----|----------------------------|
| http-port | N | http端口 ,默认2671 |
| ws-port | N | ws端口,默认2672 |
| ip | Y | native-agent的ip |
| proxy-address | Y | native-agent-proxy的地址,用于注册 |
```shell
java -jar native-agent.jar --ip 127.0.0.1 --proxy-address 127.0.0.1 :2233
```




# 集群模式
![](asserts/cluster_management.png)

## 启动native-agent
native-agent,启动在需要动态attach的服务器上
native-agent,启动在需要动态attach的服务器上。同时需要依赖arthas-agent。请把arthas-agent、arthas-core、arthas-spy放在和native-agent同一个目录下。

启动参数

| 参数 | 必填 | 解释 |
|----------------------|-----|-------------------------------------|
| http-port | N | http端口 ,默认2671 |
| ws-port | N | ws端口,默认2672 |
| ip | Y | native-agent的ip地址 |
| registration-typ | Y | 注册中心类型(目前实现的有etcd和zookeeper,推荐etcd) |
| registration-address | Y | 注册中心的地址 |

Expand Down Expand Up @@ -57,11 +102,11 @@ java -jar native-agent-management-web.jar --registration-type etcd --registrati

## 监控指定JVM
进入native-agent-server管理页面,点击VIEW JAVA PROCESS INFO 按钮,可以查看到当前服务器上的Java进程
![](images/native_agent_list.png)
![](asserts/native_agent_list.png)
进入到Java进程页后,我们可以点击Monitor按钮,Monitor目标Java进程
![](images/native_agent_java_process_page.png)
![](asserts/native_agent_java_process_page.png)
之后点击MONITOR按钮就可以进入到监控界面了
![](images/native_agent_moniotr_page.png)
![](asserts/native_agent_moniotr_page.png)

# 扩展注册中心
目前实现的有zookeeper和etcd,如果想要扩展注册中心,可以看看下面的实现。下面演示的是native-agent-management-web的扩展,其他也是同样的道理。
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,18 @@ public static String post(String url, String json) throws IOException {
}
}


public static Response postAndResponse(String url, String json) throws IOException {
RequestBody body = RequestBody.create(json, JSON);
Request request = new Request.Builder()
.url(url)
.post(body)
.header("Content-Type", "application/json")
.build();

try (Response response = client.newCall(request).execute()) {
return response;
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.alibaba.arthas.nat.agent.management.web.discovery.impl;

import com.alibaba.arthas.nat.agent.management.web.discovery.NativeAgentProxyDiscovery;

import java.util.Arrays;
import java.util.List;

/**
* @description: NativeAgentManagementNativeAgentProxyDiscovery(Σ(っ °Д °;)っ 好长的类名)
* @author:flzjkl
* @date: 2024-10-29 20:59
*/
public class NativeAgentManagementNativeAgentProxyDiscovery implements NativeAgentProxyDiscovery {

public static String proxyAddress;

@Override
public List<String> listNativeAgentProxy(String address) {
return Arrays.asList(proxyAddress);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.alibaba.arthas.nat.agent.common.constants.NativeAgentConstants;
import com.alibaba.arthas.nat.agent.common.utils.WelcomeUtil;
import com.alibaba.arthas.nat.agent.management.web.discovery.impl.NativeAgentManagementNativeAgentProxyDiscovery;
import com.alibaba.arthas.nat.agent.management.web.server.http.HttpRequestHandler;

import com.taobao.middleware.cli.CLI;
Expand All @@ -23,20 +24,21 @@
import java.util.Arrays;

/**
* @description: native agent server
* @description: native agent management web
* @author:flzjkl
* @date: 2024-07-20 9:23
*/

@Name("arthas-native-agent-management-web")
@Summary("Bootstrap Arthas Native Management Web")
@Description("EXAMPLES:\n" + " java -jar native-agent-management-web.jar --registration-type etcd --registration-address 161.169.97.114:2379\n"
@Description("EXAMPLES:\n" + "java -jar native-agent-management-web.jar --proxy-address 161.169.97.114:2233\n"
+ "java -jar native-agent-management-web.jar --registration-type etcd --registration-address 161.169.97.114:2379\n"
+ "java -jar native-agent-management-web.jar --port 3939 --registration-type etcd --registration-address 161.169.97.114:2379\n"
+ "https://arthas.aliyun.com/doc\n")
public class NativeAgentManagementWebBootstrap {
private static final Logger logger = LoggerFactory.getLogger(NativeAgentManagementWebBootstrap.class);
private static final int DEFAULT_NATIVE_AGENT_MANAGEMENT_WEB_PORT = 3939;
private Integer port;
private String proxyAddress;
public static String registrationType;
public static String registrationAddress;

Expand All @@ -46,13 +48,19 @@ public void setPort(Integer port) {
this.port = port;
}

@Option(longName = "registration-type", required = true)
@Option(longName = "proxy-address")
@Description("native agent proxy address")
public void setProxyAddress(String proxyAddress) {
this.proxyAddress = proxyAddress;
}

@Option(longName = "registration-type")
@Description("registration type")
public void setRegistrationType(String registrationType) {
this.registrationType = registrationType;
}

@Option(longName = "registration-address", required = true)
@Option(longName = "registration-address")
@Description("registration address")
public void setRegistrationAddress(String registrationAddress) {
this.registrationAddress = registrationAddress;
Expand All @@ -75,6 +83,19 @@ public static void main(String[] args) {
}
logger.info("read input success!");

logger.info("check bootstrap params ...");
boolean checkBootstrapParamsRes = checkBootstrapParams(nativeAgentManagementWebBootstrap);
if (!checkBootstrapParamsRes) {
throw new RuntimeException("Failed to verify the bootstrap parameters. " +
"Please read the documentation and check the parameters you entered");
}
if (nativeAgentManagementWebBootstrap.getRegistrationType() == null
&& nativeAgentManagementWebBootstrap.getRegistrationAddress() == null
&& nativeAgentManagementWebBootstrap.getProxyAddress() != null) {
nativeAgentManagementWebBootstrap.setRegistrationType("native-agent-management");
nativeAgentManagementWebBootstrap.setRegistrationAddress("127.0.0,1:" + nativeAgentManagementWebBootstrap.getPortOrDefault());
NativeAgentManagementNativeAgentProxyDiscovery.proxyAddress = nativeAgentManagementWebBootstrap.getProxyAddress();
}
// Start the http server
logger.info("start the http server... httPort:{}", nativeAgentManagementWebBootstrap.getPortOrDefault());
NioEventLoopGroup bossGroup = new NioEventLoopGroup();
Expand Down Expand Up @@ -106,6 +127,21 @@ protected void initChannel(SocketChannel ch) {
}
}

private static boolean checkBootstrapParams(NativeAgentManagementWebBootstrap managementBootstrap) {
String address = managementBootstrap.getRegistrationAddress();
String type = managementBootstrap.getRegistrationType();
String proxyAddress = managementBootstrap.getProxyAddress();
// single
if (address == null && type == null && proxyAddress != null) {
return true;
}
// cluster
if (address != null && type != null && proxyAddress == null) {
return true;
}
return false;
}

public int getPortOrDefault() {
if (this.port == null) {
return DEFAULT_NATIVE_AGENT_MANAGEMENT_WEB_PORT;
Expand All @@ -122,6 +158,10 @@ public String getRegistrationAddress() {
return registrationAddress;
}

public String getProxyAddress() {
return proxyAddress;
}

public Integer getPort() {
return port;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
package com.alibaba.arthas.nat.agent.management.web.server.http;

import com.alibaba.arthas.nat.agent.management.web.discovery.NativeAgentProxyDiscovery;
import com.alibaba.arthas.nat.agent.management.web.discovery.impl.NativeAgentManagementNativeAgentProxyDiscovery;
import com.alibaba.arthas.nat.agent.management.web.factory.NativeAgentProxyDiscoveryFactory;
import com.alibaba.arthas.nat.agent.management.web.server.NativeAgentManagementWebBootstrap;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.TypeReference;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.*;

import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;
import java.util.Random;
Expand All @@ -34,6 +34,7 @@ public FullHttpResponse handle(ChannelHandlerContext ctx, FullHttpRequest reques
return responseFindAvailableProxyAddress(ctx, request);
}


return null;
}

Expand All @@ -48,6 +49,7 @@ public FullHttpResponse responseFindAvailableProxyAddress(ChannelHandlerContext
HttpResponseStatus.OK,
Unpooled.copiedBuffer(availableProxyAddress, StandardCharsets.UTF_8)
);
fillCorsHead(response);
return response;
}

Expand All @@ -67,4 +69,15 @@ public String findAvailableProxyAddress() {
}


private void fillCorsHead(FullHttpResponse fullHttpResponse) {
// 设置跨域响应头
fullHttpResponse.headers().set(HttpHeaderNames.ACCESS_CONTROL_ALLOW_ORIGIN, "*");
fullHttpResponse.headers().set(HttpHeaderNames.ACCESS_CONTROL_ALLOW_METHODS, "GET, POST, PUT, DELETE, OPTIONS");
fullHttpResponse.headers().set(HttpHeaderNames.ACCESS_CONTROL_ALLOW_HEADERS, "X-Requested-With, Content-Type, Authorization");

// 设置其他必要的头部
fullHttpResponse.headers().set(HttpHeaderNames.CONTENT_TYPE, "application/json");
fullHttpResponse.headers().set(HttpHeaderNames.CONTENT_LENGTH, fullHttpResponse.content().readableBytes());
}

}
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
native-agent-management=com.alibaba.arthas.nat.agent.management.web.discovery.impl.NativeAgentManagementNativeAgentProxyDiscovery
zookeeper=com.alibaba.arthas.nat.agent.management.web.discovery.impl.ZookeeperNativeAgentProxyDiscovery
etcd=com.alibaba.arthas.nat.agent.management.web.discovery.impl.EtcdNativeAgentProxyDiscovery
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.alibaba.arthas.nat.agent.proxy.discovery.impl;

import com.alibaba.arthas.nat.agent.proxy.discovery.NativeAgentDiscovery;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
* @description: NativeAgentProxyNativeAgentDiscovery
* @author:flzjkl
* @date: 2024-10-28 21:07
*/
public class NativeAgentProxyNativeAgentDiscovery implements NativeAgentDiscovery {

/**
* key: native agent ip : http port : ws port , value: expiration time
*/
private static Map<String, LocalDateTime> nativeAgentMap = new ConcurrentHashMap<>();
private final static int INITIAL_DELAY_SECONDS = 5;
private final static int PERIOD_SECONDS = 5;

public static void storageNativeAgent(String address, LocalDateTime expirationTime) {
nativeAgentMap.put(address, expirationTime);
}

public static void nativeAgentCheckScheduled () {
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
Runnable task = () -> {
LocalDateTime now = LocalDateTime.now();
nativeAgentMap.forEach((key, expirationTime) ->{
if (now.isAfter(expirationTime)) {
nativeAgentMap.remove(key);
}
});
};
scheduler.scheduleAtFixedRate(task, INITIAL_DELAY_SECONDS, PERIOD_SECONDS, TimeUnit.SECONDS);
}


@Override
public Map<String, String> findNativeAgent(String address) {
Map<String, String> res = new HashMap<>();
for (String key : nativeAgentMap.keySet()) {
String[] split = key.split("@");
res.put(split[0], split[1]);
}
return res;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.alibaba.arthas.nat.agent.proxy.registry.impl;

import com.alibaba.arthas.nat.agent.proxy.registry.NativeAgentProxyRegistry;

/**
* @description: NativeAgentManagementNativeAgentProxyRegistry(...好长的类名)
* @author:flzjkl
* @date: 2024-10-29 20:26
*/
public class NativeAgentManagementNativeAgentProxyRegistry implements NativeAgentProxyRegistry {

@Override
public void register(String address, String k, String v) {
// do nothing
}

}
Loading