Open toantd1202 opened 4 years ago
packets
, errs
, drop
, fifo
, compressed
, multicast
cho cả luồn receive
và transmit
. Ngoài ra Colls
(va chạm) và carrier
chỉ có trong luồng transmit
.ip address
, MAC address
, device name
, tình trạng hoạt động, loại giao diện.Đối với bandwidth
, các metrics
ứng với tiền tố như node_network_receive
và node_network_transmit
. Các metrics
này trả về kiểu dữ liệu là counter
. node_network_receive
trả về các giá trị ứng với luồng xuống(nhận) về host tại các mốc thời gian tương ứng, ngược lại các metrics node_network_transmit
trả về các giá trị, thông số của luồn up(truyền), trong cùng một thời điểm, cả hai luồng đều có thể hoạt động, vì vậy, độ rộng của bandwidth
là tổng của cả luồng lên và luồng xuống.
Các đơn vị thường dùng cho các luồng như:
byte
: các dữ liệu đựơc đo bằng đơn vị là byte
-đơn vị chuẩn, nếu muốn trả về đơn vị là bit
thì ta thực hiện nhân giá trị trả về của metrics
tương ứng với 8, ví dụ: rate(node_network_transmit_bytes_total[5m]) * 8
, tốc độ truyền dữ liệu trong 5 phút được trả về với đơn vị là bit
packets
: gói data truyền/nhậnerrs
: lỗi xảy ra trong quá trình truyền/nhậndrop
, fifo
, compressd
.colls
: số lượng các va chạm trên luồng truyềncarrier
: số lượng sóng mang sử dụngMetrics | description | types |
---|---|---|
node_network_receive_bytes_total | Network device statistic receive_bytes | counter |
node_network_receive_compressed_total | Network device statistic receive_compressed | counter |
node_network_receive_drop_total | Network device statistic receive_drop | counter |
node_network_receive_errs_total | Network device statistic receive_errs | counter |
node_network_receive_fifo_total | Network device statistic receive_fifo | counter |
node_network_receive_frame_total | Network device statistic receive_frame | counter |
node_network_receive_multicast_total | Network device statistic receive_multicast | counter |
node_network_receive_packets_total | Network device statistic receive_packets | counter |
node_network_speed_bytes | speed_bytes value of /sys/class/net/ |
gauge |
node_network_transmit_bytes_total | Network device statistic transmit_bytes | counter |
node_network_transmit_carrier_total | Network device statistic transmit_carrier | counter |
node_network_transmit_colls_total | Network device statistic transmit_colls | counter |
node_network_transmit_compressed_total | Network device statistic transmit_compressed | counter |
node_network_transmit_drop_total | Network device statistic transmit_drop | counter |
node_network_transmit_errs_total | Network device statistic transmit_errs | counter |
node_network_transmit_fifo_total | Network device statistic transmit_fifo | counter |
node_network_transmit_packets_total | Network device statistic transmit_packets | counter |
node_network_transmit_queue_length | transmit_queue_length value of /sys/class/net/ |
gauge |
node_network_receive_bytes_total
: tổng số byte dữ liệu nhận vềnode_network_transmit_bytes_total
: tổng số byte dữ liệu truyềnTổng băng thông được sử dụng:
node_network_receive_bytes_total + node_network_transmit_bytes_total
node_network_transmit_errs_total
: tổng số lỗi truyền đinode_network_transmit_packets_total
: tổng số gói truyềnĐể tính tỷ lệ lỗi truyền trong 5 phút ta có thể sử dụng:
rate(node_network_transmit_errs_total[5m]) / rate(node_network_transmit_packets_total[5m])
Ta cũng có thể xác định đơn vị truyền cực đại thông qua metrics
: node_network_mtu_bytes
, metrics trả về kiểu dữ liệu là gauge.
Đối với các container, để giám sát network, ta sử dụng cAdvisor
, một node exporter hỗ trợ việc giám sát các container.
Tương tự như node exporter
, cAdvisor
cũng có các metrics giám sát mạng như:
Metrics | description | types |
---|---|---|
container_network_receive_bytes_total | Cumulative count of bytes received | counter |
container_network_receive_errors_total | Cumulative count of errors encountered while receiving | counter |
container_network_receive_packets_dropped_total | Cumulative count of packets dropped while receiving | counter |
container_network_receive_packets_total | Cumulative count of packets received | counter |
container_network_transmit_bytes_total | Cumulative count of bytes transmitted | counter |
container_network_transmit_errors_total | Cumulative count of errors encountered while transmitting | counter |
container_network_transmit_packets_dropped_total | Cumulative count of packets dropped while transmitting | counter |
container_network_transmit_packets_total | Cumulative count of packets transmitted | counter |
Với việc sử dụng metrics
node_network_info
, các thông tin của interface được trả về với với các giá trị như ip address
, device name
, tình trạng hoạt động.
ví dụ:
node_network_info{address="00:00:00:00:00:00",broadcast="00:00:00:00:00:00",device="lo",duplex="",ifalias="",operstate="unknown"} 1
node_network_info{address="02:42:ac:17:00:03",broadcast="ff:ff:ff:ff:ff:ff",device="eth0",duplex="full",ifalias="",operstate="up"} 1
Hay với node_network_address_assign_type
cho biết địa chỉ MAC đến từ đâu.
Giao diện mạng máy chủ có thể đang nhận quá nhiều dữ liệu (> 100MB/s)
- alert: HostUnusualNetworkThroughputIn
expr: sum by (instance) (irate(node_network_receive_bytes_total[2m])) / 1024 / 1024 > 100
for: 5m
labels:
severity: warning
annotations:
summary: "Host unusual network throughput in (instance {{ $labels.instance }})"
description: "Host network interfaces are probably receiving too much data (> 100 MB/s)\n VALUE = {{ $value }}\n LABELS: {{ $labels }}"
Giao diện mạng máy chủ có thể đang gửi quá nhiều dữ liệu (100 MB/s)
- alert: HostUnusualNetworkThroughputOut
expr: sum by (instance) (irate(node_network_transmit_bytes_total[2m])) / 1024 / 1024 > 100
for: 5m
labels:
severity: warning
annotations:
summary: "Host unusual network throughput out (instance {{ $labels.instance }})"
description: "Host network interfaces are probably sending too much data (> 100 MB/s)\n VALUE = {{ $value }}\n LABELS: {{ $labels }}"
Lỗi truyền bạn có thể sử dụng
- alert: networktransmiterr
expr: rate(node_network_transmit_errs_total[5m]) / rate(node_network_transmit_packets_total[5m])
for: 5m
labels:
severity: warning
annotations:
summary: "transmit error > (instance {{ $labels.instance }})"
description: "Host network interfaces are transmit error too much (> 100 MB/s)\n VALUE = {{ $value }}\n LABELS: {{ $labels }}"
OK, đọc thêm làm thế nào để exporter collect được các metrics như vậy nhé. Dẫn chứng đến code luôn.
Prometheus cung cấp các collectors
tùy chỉnh. Có thể viết các exporters trong các client libraries
. Trong exporter, có gauge
và counter
metrics. Sử dụng prometheus_client để nhập các thư viện. Như này đúng không anh!
import time
from prometheus_client.core import GaugeMetricFamily, REGISTRY, CounterMetricFamily
from prometheus_client import start_http_server
class CustomCollector(object):
def __init__(self):
pass
def collect(self):
g = GaugeMetricFamily("MemoryUsage", 'Help text', labels=['instance'])
g.add_metric(["instance01.us.west.local"], 20)
yield g
c = CounterMetricFamily("HttpRequests", 'Help text', labels=['app'])
c.add_metric(["example"], 2000)
yield c
if __name__ == '__main__':
start_http_server(8000)
REGISTRY.register(CustomCollector())
while True:
time.sleep(1)
Ý anh là từng metrics nó catch chỗ nào. Rồi ở đấy nó xử lí cái gì để ra được cái metrics ý em.
g.add_metric(["instance01.us.west.local"], 20)
VD: như này là fix cứng giá trị. Còn các metrics phải tính toán thì sao
@vtdat anh!!!
Prometheus exporter cho các metrics phần cứng và hệ điều hành được hiển thị bởi các *NIX kernels, được viết bằng Go
với các metrics collectors
có thể cài cắm được để lấy dữ liệu.
Exporter thu thập các metrics của nút máy chủ đang hoạt động (một số cũng có thể thu thập từ xa) và hiển thị chúng qua HTTP, cấu hình mặc định của nút này được đặt tại /metrics
. Điều này cho phép Prometheus scrape target thông qua HTTP GET.
Collectors
được kích hoạt bằng cách sử dụng cờ --collector.<name>
. Collectors được bật theo mặc định và có thể tắt bằng cách sử dụng cờ --no-collector.<name>
.
Đối với các metrics về network ta có: | name | description | os |
---|---|---|---|
netclass | Exposes network interface info from /sys/class/net/ |
Linux | |
netdev | Exposes network interface statistics such as bytes transferred | Darwin, Dragonfly, FreeBSD, Linux, OpenBSD | |
netstat | Exposes network statistics from /proc/net/netstat . This is the same information as netstat -s |
Linux |
ví dụ: các metrics về network có tiền tố là node_network
, bằng cách sử dụng các thư viện hỗ trợ cho việc lấy các thông tin về network interface (ifaddrs.h, net/if.h), sẽ được collectors như sau:
package collector
import (
"errors"
"regexp"
"strconv"
"github.com/go-kit/kit/log"
"github.com/go-kit/kit/log/level"
)
#cgo CFLAGS: -D_IFI_OQDROPS
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <ifaddrs.h>
#include <net/if.h>
import "C"
func getNetDevStats(ignore regexp.Regexp, accept regexp.Regexp, logger log.Logger) (map[string]map[string]string, error) { netDev := map[string]map[string]string{}
var ifap, ifa *C.struct_ifaddrs
if C.getifaddrs(&ifap) == -1 {
return nil, errors.New("getifaddrs() failed")
}
defer C.freeifaddrs(ifap)
for ifa = ifap; ifa != nil; ifa = ifa.ifa_next {
if ifa.ifa_addr.sa_family == C.AF_LINK {
dev := C.GoString(ifa.ifa_name)
if ignore != nil && ignore.MatchString(dev) {
level.Debug(logger).Log("msg", "Ignoring device", "device", dev)
continue
}
if accept != nil && !accept.MatchString(dev) {
level.Debug(logger).Log("msg", "Ignoring device", "device", dev)
continue
}
devStats := map[string]string{}
data := (*C.struct_if_data)(ifa.ifa_data)
devStats["receive_packets"] = convertFreeBSDCPUTime(uint64(data.ifi_ipackets))
devStats["transmit_packets"] = convertFreeBSDCPUTime(uint64(data.ifi_opackets))
devStats["receive_errs"] = convertFreeBSDCPUTime(uint64(data.ifi_ierrors))
devStats["transmit_errs"] = convertFreeBSDCPUTime(uint64(data.ifi_oerrors))
devStats["receive_bytes"] = convertFreeBSDCPUTime(uint64(data.ifi_ibytes))
devStats["transmit_bytes"] = convertFreeBSDCPUTime(uint64(data.ifi_obytes))
devStats["receive_multicast"] = convertFreeBSDCPUTime(uint64(data.ifi_imcasts))
devStats["transmit_multicast"] = convertFreeBSDCPUTime(uint64(data.ifi_omcasts))
devStats["receive_drop"] = convertFreeBSDCPUTime(uint64(data.ifi_iqdrops))
devStats["transmit_drop"] = convertFreeBSDCPUTime(uint64(data.ifi_oqdrops))
netDev[dev] = devStats
}
}
return netDev, nil
}
func convertFreeBSDCPUTime(counter uint64) string { return strconv.FormatUint(counter, 10) }
Em nghĩ là với các metrics phải tính toán thì sẽ sử dụng rules để tính dựa trên các số liệu từ các metrics có liên quan.
@vtdat anh!!! Dẫn chứng code mới: netstat
io.Reader
hoặc io.Writer
, tạo một đối tượng khác (Reader hoặc Writer) cũng thực hiện trên giao diện nhưng cung cấp bộ đệm và một số trợ giúp cho I/O văn bản.const (
netStatsSubsystem = "netstat"
)
khai báo hằng số netStatsSubsystem
nhận giá trị là chuỗi netstat
var (
netStatFields = kingpin.Flag("collector.netstat.fields", "Regexp of fields to return for netstat collector.").Default("^(.*_(InErrors|InErrs)|Ip_Forwarding|Ip(6|Ext)_(InOctets|OutOctets)|Icmp6?_(InMsgs|OutMsgs)|TcpExt_(Listen.*|Syncookies.*|TCPSynRetrans)|Tcp_(ActiveOpens|InSegs|OutSegs|PassiveOpens|RetransSegs|CurrEstab)|Udp6?_(InDatagrams|OutDatagrams|NoPorts|RcvbufErrors|SndbufErrors))$").String()
)
kingpin
: Kingpin là một trình phân tích cú pháp dòng lệnh an toàn. Nó hỗ trợ cờ, lệnh lồng nhau và đối số vị trí.
Flag("collector.netstat.fields", "Regexp of fields to return for netstat collector.")
: khai báo cờ -collector.netstat.fields
được lưu vào netStatFields
Default()
: xác định các giá trị mặc định cho cờ.func registerCollector(collector string, isDefaultEnabled bool, factory func(logger log.Logger) (Collector, error)) {
var helpDefaultState string
if isDefaultEnabled {
helpDefaultState = "enabled"
} else {
helpDefaultState = "disabled"
}
flagName := fmt.Sprintf("collector.%s", collector)
flagHelp := fmt.Sprintf("Enable the %s collector (default: %s).", collector, helpDefaultState)
defaultValue := fmt.Sprintf("%v", isDefaultEnabled)
flag := kingpin.Flag(flagName, flagHelp).Default(defaultValue).Action(collectorFlagAction(collector)).Bool()
collectorState[collector] = flag
factories[collector] = factory
}
registerCollector("netstat", defaultEnabled, NewNetStatCollector)
: tạo ra định dạng dữ liệu được collecter mà prometheus có thể hiểu và sử dụng, với collector
=netstat
, isDefaultEnabled
=defaultEnabled
, factory
=NewNetStatCollector
.NewNetStatCollector lấy và trả về một Collector mới hiển thị các số liệu thống kê mạng.
func NewNetStatCollector(logger log.Logger) (Collector, error) {
pattern := regexp.MustCompile(*netStatFields)
return &netStatCollector{
fieldPattern: pattern,
logger: logger,
}, nil
}
NewNetStatCollector(logger log.Logger) (Collector, error)
pattern := regexp.MustCompile(*netStatFields)
Tạo các biến toàn cục với các biểu thức dựa trên các giá trị của cờ netStatFields
.
Trả về các giá trị cho struct netStatCollector
return &netStatCollector{
fieldPattern: pattern,
logger: logger,
}
Tạo ra các metrics
func (c *netStatCollector) Update(ch chan<- prometheus.Metric) error {
netStats, err := getNetStats(procFilePath("net/netstat"))
if err != nil {
return fmt.Errorf("couldn't get netstats: %s", err)
}
snmpStats, err := getNetStats(procFilePath("net/snmp"))
if err != nil {
return fmt.Errorf("couldn't get SNMP stats: %s", err)
}
snmp6Stats, err := getSNMP6Stats(procFilePath("net/snmp6"))
if err != nil {
return fmt.Errorf("couldn't get SNMP6 stats: %s", err)
}
// Hợp nhất kết quả của snmpStats vào netStats (có thể xung đột, nhưng các khóa luôn là duy nhất cho trường hợp sử dụng đã cho).
for k, v := range snmpStats {
netStats[k] = v
}
for k, v := range snmp6Stats {
netStats[k] = v
}
for protocol, protocolStats := range netStats {
for name, value := range protocolStats {
key := protocol + "_" + name
v, err := strconv.ParseFloat(value, 64)
if err != nil {
return fmt.Errorf("invalid value %s in netstats: %s", value, err)
}
if !c.fieldPattern.MatchString(key) {
continue
}
ch <- prometheus.MustNewConstMetric(
prometheus.NewDesc(
prometheus.BuildFQName(namespace, netStatsSubsystem, key),
fmt.Sprintf("Statistic %s.", protocol+name),
nil, nil,
),
prometheus.UntypedValue, v,
)
}
}
return nil
}
Các file lấy dữ liệu như sau:
file netstat
file snmp
file snmp6
Update()
: cung cấp chức năng để thực hiện các chương trình Go an toàn, tự cập nhật (hoặc các mục tiêu, một tệp khác).
func MustNewConstMetric(desc *Desc, valueType ValueType, value float64, labelValues ...string) Metric {
m, err := NewConstMetric(desc, valueType, value, labelValues...)
if err != nil {
panic(err)
}
return m
}
getNetStats(procFilePath("net/netstat"))
: dữ liệu được lấy từ file với đường dẫn cụ thể chỉ đến file.
trong đó:
func procFilePath(name string) string {
return filepath.Join(*procPath, name)
}
Lấy ra dữ liệu từ file netstats
:
func getNetStats(fileName string) (map[string]map[string]string, error) {
file, err := os.Open(fileName)
if err != nil {
return nil, err
}
defer file.Close()
return parseNetStats(file, fileName)
}
getNetStats
: sử dụng os.Open()
để mở file lấy dữ liệu, ở đây cụ thể là đường dẫn tới netstat
.Phân tích cú pháp, dữ liệu NetStats
func parseNetStats(r io.Reader, fileName string) (map[string]map[string]string, error) {
var (
netStats = map[string]map[string]string{}
scanner = bufio.NewScanner(r)
)
for scanner.Scan() {
nameParts := strings.Split(scanner.Text(), " ")
scanner.Scan()
valueParts := strings.Split(scanner.Text(), " ")
// Remove trailing :.
protocol := nameParts[0][:len(nameParts[0])-1]
netStats[protocol] = map[string]string{}
if len(nameParts) != len(valueParts) {
return nil, fmt.Errorf("mismatch field count mismatch in %s: %s",
fileName, protocol)
}
for i := 1; i < len(nameParts); i++ {
netStats[protocol][nameParts[i]] = valueParts[i]
}
}
return netStats, scanner.Err()
}
parseNetStats(r io.Reader, fileName string)
: thực hiện đọc file có tên netstat
định nghĩa 1 số biến:
var (
netStats = map[string]map[string]string{}
scanner = bufio.NewScanner(r)
)
strings.Split()
:Split() method trong Golang (được xác định trong thư viện strings) chia một chuỗi thành một danh sách các chuỗi con bằng cách phát hiện một dấu phân cách (ví dụ: ",") được chỉ định. Phương thức trả về các chuỗi con dưới dạng một slice.
ví dụ:
s := strings.Split("a,b,c", ",")
fmt.Println(s)
// Output: [a b c]
Lấy dữ liệu SNMP6Stats
func getSNMP6Stats(fileName string) (map[string]map[string]string, error) {
file, err := os.Open(fileName)
if err != nil {
// On systems with IPv6 disabled, this file won't exist.
// Do nothing.
if os.IsNotExist(err) {
return nil, nil
}
return nil, err
}
defer file.Close()
return parseSNMP6Stats(file)
}
Phân tích cú pháp trong SNMPStats:
func parseSNMP6Stats(r io.Reader) (map[string]map[string]string, error) {
var (
netStats = map[string]map[string]string{}
scanner = bufio.NewScanner(r)
)
for scanner.Scan() {
stat := strings.Fields(scanner.Text())
if len(stat) < 2 {
continue
}
// Expect to have "6" in metric name, skip line otherwise
if sixIndex := strings.Index(stat[0], "6"); sixIndex != -1 {
protocol := stat[0][:sixIndex+1]
name := stat[0][sixIndex+1:]
if _, present := netStats[protocol]; !present {
netStats[protocol] = map[string]string{}
}
netStats[protocol][name] = stat[1]
}
}
return netStats, scanner.Err()
}
strings.Fields()
: để tách một chuỗi thành các chuỗi con loại bỏ bất kỳ ký tự khoảng trắng nào, bao gồm cả dòng mới.
ví dụ:
s := strings.Fields(" a \t b \n")
fmt.Println(s)
// Output: [a b]
tao MR đi em
Monitoring Network