github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/p2p/metrics.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 19:16:41</date> 10 //</624450104941613056> 11 12 13 //包含网络层使用的仪表和计时器。 14 15 package p2p 16 17 import ( 18 "fmt" 19 "net" 20 "sync" 21 "sync/atomic" 22 "time" 23 24 "github.com/ethereum/go-ethereum/p2p/enode" 25 26 "github.com/ethereum/go-ethereum/event" 27 "github.com/ethereum/go-ethereum/log" 28 "github.com/ethereum/go-ethereum/metrics" 29 ) 30 31 const ( 32 MetricsInboundConnects = "p2p/InboundConnects" //已注册的入站连接仪表的名称 33 MetricsInboundTraffic = "p2p/InboundTraffic" //已注册的入站流量表的名称 34 MetricsOutboundConnects = "p2p/OutboundConnects" //已注册的出站连接仪表的名称 35 MetricsOutboundTraffic = "p2p/OutboundTraffic" //已注册的出站流量表的名称 36 37 MeteredPeerLimit = 1024 //这些对等点的数量是单独计量的 38 ) 39 40 var ( 41 ingressConnectMeter = metrics.NewRegisteredMeter(MetricsInboundConnects, nil) //计量入口连接 42 ingressTrafficMeter = metrics.NewRegisteredMeter(MetricsInboundTraffic, nil) //计量累计入口流量的仪表 43 egressConnectMeter = metrics.NewRegisteredMeter(MetricsOutboundConnects, nil) //计量出口连接 44 egressTrafficMeter = metrics.NewRegisteredMeter(MetricsOutboundTraffic, nil) //计量累计出口流量的仪表 45 46 PeerIngressRegistry = metrics.NewPrefixedChildRegistry(metrics.EphemeralRegistry, MetricsInboundTraffic+"/") //包含对等入口的注册表 47 PeerEgressRegistry = metrics.NewPrefixedChildRegistry(metrics.EphemeralRegistry, MetricsOutboundTraffic+"/") //包含对等出口的注册表 48 49 meteredPeerFeed event.Feed //对等度量的事件源 50 meteredPeerCount int32 //实际存储的对等连接计数 51 ) 52 53 //MeteredPeerEventType是由计量连接发出的对等事件类型。 54 type MeteredPeerEventType int 55 56 const ( 57 //PeerConnected是当对等机成功时发出的事件类型 58 //做了握手。 59 PeerConnected MeteredPeerEventType = iota 60 61 //PeerDisconnected是对等端断开连接时发出的事件类型。 62 PeerDisconnected 63 64 //PeerHandshakeFailed是对等端失败时发出的事件类型。 65 //在握手之前进行握手或断开连接。 66 PeerHandshakeFailed 67 ) 68 69 //MeteredPeerEvent是对等端连接或断开连接时发出的事件。 70 type MeteredPeerEvent struct { 71 Type MeteredPeerEventType //对等事件类型 72 IP net.IP //对等机的IP地址 73 ID enode.ID //对等节点ID 74 Elapsed time.Duration //连接和握手/断开连接之间所用的时间 75 Ingress uint64 //事件发生时的入口计数 76 Egress uint64 //事件发生时的出口计数 77 } 78 79 //subscribeMeteredPeerEvent为对等生命周期事件注册订阅 80 //如果启用了度量集合。 81 func SubscribeMeteredPeerEvent(ch chan<- MeteredPeerEvent) event.Subscription { 82 return meteredPeerFeed.Subscribe(ch) 83 } 84 85 //meteredconn是一个围绕net.conn的包装器,用于测量 86 //入站和出站网络流量。 87 type meteredConn struct { 88 net.Conn //与计量包装的网络连接 89 90 connected time.Time //对等机连接时间 91 ip net.IP //对等机的IP地址 92 id enode.ID //对等节点ID 93 94 //TrafficMetered表示对等端是否在流量注册中心注册。 95 //如果计量的对等计数未达到 96 //对等连接的时刻。 97 trafficMetered bool 98 ingressMeter metrics.Meter //对等机的读取字节数 99 egressMeter metrics.Meter //为对等机的写入字节计数 100 101 lock sync.RWMutex //保护计量连接内部的锁 102 } 103 104 //newmeteredconn创建一个新的计量连接,碰撞入口或出口 105 //连接仪表,也会增加计量的对等计数。如果度量 106 //系统被禁用或未指定IP地址,此函数返回 107 //原始对象。 108 func newMeteredConn(conn net.Conn, ingress bool, ip net.IP) net.Conn { 109 //如果禁用度量值,则短路 110 if !metrics.Enabled { 111 return conn 112 } 113 if ip.IsUnspecified() { 114 log.Warn("Peer IP is unspecified") 115 return conn 116 } 117 //碰撞连接计数器并包装连接 118 if ingress { 119 ingressConnectMeter.Mark(1) 120 } else { 121 egressConnectMeter.Mark(1) 122 } 123 return &meteredConn{ 124 Conn: conn, 125 ip: ip, 126 connected: time.Now(), 127 } 128 } 129 130 //读取将网络读取委托给基础连接,从而中断公共连接 131 //和同龄人的入口,一路上的交通米数。 132 func (c *meteredConn) Read(b []byte) (n int, err error) { 133 n, err = c.Conn.Read(b) 134 ingressTrafficMeter.Mark(int64(n)) 135 c.lock.RLock() 136 if c.trafficMetered { 137 c.ingressMeter.Mark(int64(n)) 138 } 139 c.lock.RUnlock() 140 return n, err 141 } 142 143 //写入将网络写入委托给基础连接,从而中断公共连接 144 //而同行的出口,一路上的交通量是米。 145 func (c *meteredConn) Write(b []byte) (n int, err error) { 146 n, err = c.Conn.Write(b) 147 egressTrafficMeter.Mark(int64(n)) 148 c.lock.RLock() 149 if c.trafficMetered { 150 c.egressMeter.Mark(int64(n)) 151 } 152 c.lock.RUnlock() 153 return n, err 154 } 155 156 //当对等握手完成时,将调用握手。将对等机注册到 157 //使用对等机的IP和节点ID的入口和出口流量注册, 158 //同时发出Connect事件。 159 func (c *meteredConn) handshakeDone(id enode.ID) { 160 if atomic.AddInt32(&meteredPeerCount, 1) >= MeteredPeerLimit { 161 //不要在流量注册表中注册对等机。 162 atomic.AddInt32(&meteredPeerCount, -1) 163 c.lock.Lock() 164 c.id, c.trafficMetered = id, false 165 c.lock.Unlock() 166 log.Warn("Metered peer count reached the limit") 167 } else { 168 key := fmt.Sprintf("%s/%s", c.ip, id.String()) 169 c.lock.Lock() 170 c.id, c.trafficMetered = id, true 171 c.ingressMeter = metrics.NewRegisteredMeter(key, PeerIngressRegistry) 172 c.egressMeter = metrics.NewRegisteredMeter(key, PeerEgressRegistry) 173 c.lock.Unlock() 174 } 175 meteredPeerFeed.Send(MeteredPeerEvent{ 176 Type: PeerConnected, 177 IP: c.ip, 178 ID: id, 179 Elapsed: time.Since(c.connected), 180 }) 181 } 182 183 //close将关闭操作委托给基础连接,取消注册 184 //来自流量注册中心的对等机发出关闭事件。 185 func (c *meteredConn) Close() error { 186 err := c.Conn.Close() 187 c.lock.RLock() 188 if c.id == (enode.ID{}) { 189 //如果对等端在握手之前断开连接。 190 c.lock.RUnlock() 191 meteredPeerFeed.Send(MeteredPeerEvent{ 192 Type: PeerHandshakeFailed, 193 IP: c.ip, 194 Elapsed: time.Since(c.connected), 195 }) 196 return err 197 } 198 id := c.id 199 if !c.trafficMetered { 200 //如果对等端没有在流量注册中心注册。 201 c.lock.RUnlock() 202 meteredPeerFeed.Send(MeteredPeerEvent{ 203 Type: PeerDisconnected, 204 IP: c.ip, 205 ID: id, 206 }) 207 return err 208 } 209 ingress, egress := uint64(c.ingressMeter.Count()), uint64(c.egressMeter.Count()) 210 c.lock.RUnlock() 211 212 //减少计量的对等计数 213 atomic.AddInt32(&meteredPeerCount, -1) 214 215 //从流量注册表中注销对等机 216 key := fmt.Sprintf("%s/%s", c.ip, id) 217 PeerIngressRegistry.Unregister(key) 218 PeerEgressRegistry.Unregister(key) 219 220 meteredPeerFeed.Send(MeteredPeerEvent{ 221 Type: PeerDisconnected, 222 IP: c.ip, 223 ID: id, 224 Ingress: ingress, 225 Egress: egress, 226 }) 227 return err 228 } 229