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