-
Notifications
You must be signed in to change notification settings - Fork 994
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
support monitoring memcached metrics and add a help doc (#1423)
Co-authored-by: 东风 <1335799468@qq.com>
- Loading branch information
Showing
7 changed files
with
434 additions
and
0 deletions.
There are no files selected for viewing
145 changes: 145 additions & 0 deletions
145
...src/main/java/org/dromara/hertzbeat/collector/collect/memcached/MemcachedCollectImpl.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
package org.dromara.hertzbeat.collector.collect.memcached; | ||
|
||
import lombok.extern.slf4j.Slf4j; | ||
import org.dromara.hertzbeat.collector.collect.AbstractCollect; | ||
import org.dromara.hertzbeat.collector.dispatch.DispatchConstants; | ||
import org.dromara.hertzbeat.common.constants.CollectorConstants; | ||
import org.dromara.hertzbeat.common.constants.CommonConstants; | ||
import org.dromara.hertzbeat.common.entity.job.Metrics; | ||
import org.dromara.hertzbeat.common.entity.job.protocol.MemcachedProtocol; | ||
import org.dromara.hertzbeat.common.entity.message.CollectRep; | ||
import org.dromara.hertzbeat.common.util.CommonUtil; | ||
|
||
import java.io.BufferedReader; | ||
import java.io.IOException; | ||
import java.io.InputStreamReader; | ||
import java.io.PrintWriter; | ||
import java.net.InetSocketAddress; | ||
import java.net.Socket; | ||
import java.net.SocketAddress; | ||
import java.net.SocketTimeoutException; | ||
import java.net.UnknownHostException; | ||
import java.util.HashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Objects; | ||
|
||
/** | ||
* | ||
*/ | ||
@Slf4j | ||
public class MemcachedCollectImpl extends AbstractCollect { | ||
public MemcachedCollectImpl() { | ||
} | ||
|
||
private static final String STATS = "stats"; | ||
private static final String STATS_SETTINGS = "stats settings"; | ||
private static final String STATS_ITEMS = "stats items"; | ||
private static final String STATS_SIZES = "stats sizes"; | ||
private static final String STATS_END_RSP = "END"; | ||
|
||
@Override | ||
public void collect(CollectRep.MetricsData.Builder builder, long monitorId, String app, Metrics metrics) { | ||
long startTime = System.currentTimeMillis(); | ||
if (metrics == null || metrics.getMemcached() == null) { | ||
builder.setCode(CollectRep.Code.FAIL); | ||
builder.setMsg("Memcached collect must has Memcached params"); | ||
return; | ||
} | ||
MemcachedProtocol memcachedProtocol = metrics.getMemcached(); | ||
String memcachedHost = memcachedProtocol.getHost(); | ||
String memcachedPort = memcachedProtocol.getPort(); | ||
Socket socket = null; | ||
try { | ||
socket = new Socket(); | ||
SocketAddress socketAddress = new InetSocketAddress(memcachedHost, Integer.parseInt(memcachedPort)); | ||
socket.connect(socketAddress); | ||
if (socket.isConnected()) { | ||
long responseTime = System.currentTimeMillis() - startTime; | ||
PrintWriter out = new PrintWriter(socket.getOutputStream(), true); | ||
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); | ||
// 发送统计命令 | ||
Map<String, String> resultMap = new HashMap<>(128); | ||
parseCMDResponse(resultMap, in, out, STATS); | ||
parseCMDResponse(resultMap, in, out, STATS_SETTINGS); | ||
parseSizesOutput(resultMap, in, out); | ||
|
||
resultMap.put(CollectorConstants.RESPONSE_TIME, Long.toString(responseTime)); | ||
|
||
// 关闭输出流和Socket连接 | ||
in.close(); | ||
out.close(); | ||
socket.close(); | ||
List<String> aliasFields = metrics.getAliasFields(); | ||
CollectRep.ValueRow.Builder valueRowBuilder = CollectRep.ValueRow.newBuilder(); | ||
for (String field : aliasFields) { | ||
String fieldValue = resultMap.get(field); | ||
valueRowBuilder.addColumns(Objects.requireNonNullElse(fieldValue, CommonConstants.NULL_VALUE)); | ||
} | ||
builder.addValues(valueRowBuilder.build()); | ||
} else { | ||
builder.setCode(CollectRep.Code.UN_CONNECTABLE); | ||
builder.setMsg("Peer connect failed:"); | ||
} | ||
} catch (UnknownHostException unknownHostException) { | ||
String errorMsg = CommonUtil.getMessageFromThrowable(unknownHostException); | ||
log.info(errorMsg); | ||
builder.setCode(CollectRep.Code.UN_CONNECTABLE); | ||
builder.setMsg("UnknownHost:" + errorMsg); | ||
} catch (SocketTimeoutException socketTimeoutException) { | ||
String errorMsg = CommonUtil.getMessageFromThrowable(socketTimeoutException); | ||
log.info(errorMsg); | ||
builder.setCode(CollectRep.Code.UN_CONNECTABLE); | ||
builder.setMsg("Socket connect timeout: " + errorMsg); | ||
} catch (IOException ioException) { | ||
String errorMsg = CommonUtil.getMessageFromThrowable(ioException); | ||
log.info(errorMsg); | ||
builder.setCode(CollectRep.Code.UN_CONNECTABLE); | ||
builder.setMsg("Connect fail:" + errorMsg); | ||
} finally { | ||
if (socket != null) { | ||
try { | ||
socket.close(); | ||
} catch (Exception e) { | ||
log.error(e.getMessage()); | ||
} | ||
} | ||
} | ||
} | ||
|
||
private static void parseCMDResponse(Map<String, String> statsMap, | ||
BufferedReader in, | ||
PrintWriter out, | ||
String cmd) throws IOException { | ||
out.println(cmd); | ||
String line; | ||
while ((line = in.readLine()) != null && !line.equals(STATS_END_RSP)) { | ||
// 解析每一行,将键值对存入HashMap | ||
String[] parts = line.split(" "); | ||
if (parts.length == 3) { | ||
statsMap.put(parts[1], parts[2]); | ||
} | ||
} | ||
} | ||
|
||
private static void parseSizesOutput(Map<String, String> statsMap, | ||
BufferedReader in, | ||
PrintWriter out) throws IOException { | ||
out.println(STATS_SIZES); | ||
String line; | ||
while ((line = in.readLine()) != null && !line.equals(STATS_END_RSP)) { | ||
String[] parts = line.split("\\s+"); | ||
// 提取 slab size 和 slab count,并放入HashMap | ||
if (parts.length >= 3 && "STAT".equals(parts[0])) { | ||
statsMap.put("item_size", parts[1]); | ||
statsMap.put("item_count", parts[2]); | ||
} | ||
} | ||
} | ||
|
||
|
||
@Override | ||
public String supportProtocol() { | ||
return DispatchConstants.PROTOCOL_MEMCACHED; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
28 changes: 28 additions & 0 deletions
28
common/src/main/java/org/dromara/hertzbeat/common/entity/job/protocol/MemcachedProtocol.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package org.dromara.hertzbeat.common.entity.job.protocol; | ||
|
||
import lombok.AllArgsConstructor; | ||
import lombok.Builder; | ||
import lombok.Data; | ||
import lombok.NoArgsConstructor; | ||
|
||
/** | ||
* | ||
*/ | ||
@Data | ||
@Builder | ||
@AllArgsConstructor | ||
@NoArgsConstructor | ||
public class MemcachedProtocol { | ||
|
||
/** | ||
* Memcached 主机ip或域名 | ||
*/ | ||
private String host; | ||
|
||
/** | ||
* Memcached 主机端口(默认11211) | ||
*/ | ||
private String port; | ||
|
||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
--- | ||
id: memcached | ||
title: Monitoring Memcached | ||
sidebar_label: Memcached Monitor | ||
keywords: [ open source monitoring tool, open source Memcached monitoring tool, monitoring memcached metrics ] | ||
--- | ||
|
||
> Collect and monitor the general performance Metrics of Memcached. | ||
**Protocol Use:Memcached** | ||
|
||
```text | ||
The default YML configuration for the memcache version is in compliance with 1.4.15. | ||
You need to use the stats command to view the parameters that your memcache can monitor | ||
``` | ||
|
||
### | ||
|
||
**1、Obtain usable parameter indicators through commands such as stats、stats setting、stats settings. | ||
|
||
```shell | ||
# telnet ip port | ||
[root@server ~]# telnet localhost 11211 | ||
Trying ::1... | ||
Connected to localhost. | ||
Escape character is '^]'. | ||
stats | ||
STAT pid 15168 | ||
STAT uptime 11691 | ||
STAT time 1702569246 | ||
STAT version 1.4.15 | ||
... | ||
``` | ||
|
||
**There is help_doc: https://www.runoob.com/memcached/memcached-stats.html** | ||
|
||
### Configuration parameter | ||
|
||
| Parameter name | Parameter help description | | ||
|---------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | ||
| Monitoring Host | Monitored IPV4, IPV6 or domain name. Note⚠️Without protocol header (eg: https://, http://) | | ||
| Monitoring name | Identify the name of this monitoring. The name needs to be unique | | ||
| Port | Port provided by Memcached | | ||
| Collection interval | Interval time of monitor periodic data collection, unit: second, and the minimum interval that can be set is 30 seconds | | ||
| Whether to detect | Whether to detect and check the availability of monitoring before adding monitoring. Adding and modifying operations will continue only after the detection is successful | | ||
| Description remarks | For more information about identifying and describing this monitoring, users can note information here | | ||
|
||
### Collection Metrics | ||
|
||
#### Metrics Set:server_info | ||
|
||
| Metric name | Metric unit | Metric help description | | ||
|------------------|-------------|---------------------------------------------------| | ||
| pid | | Memcache server process ID | | ||
| uptime | s | The number of seconds the server has been running | | ||
| version | | Memcache version | | ||
| curr_connections | | Current number of connections | | ||
| auth_errors | | Number of authentication failures | | ||
| threads | | Current number of threads | | ||
| item_size | byte | The size of the item | | ||
| item_count | | Number of items | | ||
| curr_items | | The total number of data currently stored | | ||
| total_items | | The total number of data stored since startup | | ||
| bytes | byte | The current number of bytes occupied by storage | | ||
| cmd_get | | Get command request count | | ||
| cmd_set | | Set command request count | | ||
| cmd_flush | | Flush command request count | | ||
| get_misses | | Get command misses | | ||
| delete_misses | | Delete command misses | |
Oops, something went wrong.