github.com/turingchain2020/turingchain@v1.1.21/system/p2p/dht/manage/conns.go (about)

     1  // Package manage p2p manage
     2  package manage
     3  
     4  import (
     5  	"context"
     6  	"fmt"
     7  	"sort"
     8  	"strings"
     9  	"sync"
    10  	"time"
    11  
    12  	"github.com/turingchain2020/turingchain/common/log/log15"
    13  	p2pty "github.com/turingchain2020/turingchain/system/p2p/dht/types"
    14  	"github.com/turingchain2020/turingchain/types"
    15  	core "github.com/libp2p/go-libp2p-core"
    16  	"github.com/libp2p/go-libp2p-core/metrics"
    17  	"github.com/libp2p/go-libp2p-core/network"
    18  	"github.com/libp2p/go-libp2p-core/peer"
    19  	kb "github.com/libp2p/go-libp2p-kbucket"
    20  	"github.com/multiformats/go-multiaddr"
    21  )
    22  
    23  var (
    24  	log = log15.New("module", "p2p.connManage")
    25  )
    26  
    27  const (
    28  	maxBounds    = 30 //最大连接数包含连接被连接
    29  	maxOutBounds = 15 //对外连接的最大节点数量
    30  )
    31  
    32  // ConnManager p2p connection manager
    33  type ConnManager struct {
    34  	ctx              context.Context
    35  	neighborStore    sync.Map
    36  	host             core.Host
    37  	bandwidthTracker *metrics.BandwidthCounter
    38  	routingTable     *kb.RoutingTable
    39  	cfg              *p2pty.P2PSubConfig
    40  }
    41  
    42  // NewConnManager new connection manager
    43  func NewConnManager(ctx context.Context, host core.Host, rt *kb.RoutingTable, tracker *metrics.BandwidthCounter, cfg *p2pty.P2PSubConfig) *ConnManager {
    44  	connM := &ConnManager{}
    45  	connM.ctx = ctx
    46  	connM.host = host
    47  	connM.routingTable = rt
    48  	connM.bandwidthTracker = tracker
    49  	connM.cfg = cfg
    50  
    51  	return connM
    52  
    53  }
    54  
    55  // RateCalculate means bytes sent / received per second.
    56  func (s *ConnManager) RateCalculate(ratebytes float64) string {
    57  	kbytes := ratebytes / 1024
    58  	rate := fmt.Sprintf("%.3f KB/s", kbytes)
    59  
    60  	if kbytes/1024 > 0.1 {
    61  		rate = fmt.Sprintf("%.3f MB/s", kbytes/1024)
    62  	}
    63  
    64  	return rate
    65  }
    66  
    67  // BandTrackerByProtocol returns all protocols band info
    68  func (s *ConnManager) BandTrackerByProtocol() *types.NetProtocolInfos {
    69  	bandprotocols := s.bandwidthTracker.GetBandwidthByProtocol()
    70  	var infos netprotocols
    71  	for id, stat := range bandprotocols {
    72  		if id == "" || stat.RateIn+stat.RateOut == 0 {
    73  			continue
    74  		}
    75  		var info sortNetProtocols
    76  		info.Protocol = string(id)
    77  		info.Ratein = s.RateCalculate(stat.RateIn)
    78  		info.Rateout = s.RateCalculate(stat.RateOut)
    79  		info.Ratetotal = s.RateCalculate(stat.RateIn + stat.RateOut)
    80  		infos = append(infos, &info)
    81  	}
    82  
    83  	sort.Sort(infos) //对Ratetotal 进行排序
    84  	var netinfoArr []*types.ProtocolInfo
    85  	for _, info := range infos {
    86  		var protoinfo types.ProtocolInfo
    87  		protoinfo.Ratetotal = info.Ratetotal
    88  		protoinfo.Rateout = info.Rateout
    89  		protoinfo.Ratein = info.Ratein
    90  		protoinfo.Protocol = info.Protocol
    91  		if strings.Contains(protoinfo.Ratetotal, "0.000") {
    92  			continue
    93  		}
    94  		netinfoArr = append(netinfoArr, &protoinfo)
    95  	}
    96  
    97  	return &types.NetProtocolInfos{Protoinfo: netinfoArr}
    98  
    99  }
   100  
   101  // MonitorAllPeers monitory all peers
   102  func (s *ConnManager) MonitorAllPeers() {
   103  	ticker1 := time.NewTicker(time.Minute)
   104  	ticker2 := time.NewTicker(time.Minute * 2)
   105  	for {
   106  		select {
   107  		case <-s.ctx.Done():
   108  			return
   109  		case <-ticker1.C:
   110  			s.printMonitorInfo()
   111  		case <-ticker2.C:
   112  			s.procConnections()
   113  		}
   114  	}
   115  }
   116  
   117  func (s *ConnManager) printMonitorInfo() {
   118  	var LatencyInfo = fmt.Sprintln("--------------时延--------------------")
   119  	peers := s.FetchConnPeers()
   120  	bandByPeer := s.bandwidthTracker.GetBandwidthByPeer()
   121  	var trackerInfo = fmt.Sprintln("------------BandTracker--------------")
   122  	for _, pid := range peers {
   123  		//统计每个节点的时延,统计最多MaxBounds个
   124  		tduration := s.host.Peerstore().LatencyEWMA(pid)
   125  		if tduration == 0 {
   126  			continue
   127  		}
   128  		LatencyInfo += fmt.Sprintln("PeerID:", pid.Pretty(), "LatencyEWMA:", tduration)
   129  		if stat, ok := bandByPeer[pid]; ok {
   130  			trackerInfo += fmt.Sprintf("PeerID:%s,RateIn:%f bytes/s,RateOut:%f bytes/s,totalIn:%d bytes,totalOut:%d\n",
   131  				pid,
   132  				stat.RateIn,
   133  				stat.RateOut,
   134  				stat.TotalIn,
   135  				stat.TotalOut)
   136  		}
   137  		//protocols rate
   138  		log.Debug(LatencyInfo)
   139  
   140  		insize, outsize := s.BoundSize()
   141  		trackerInfo += fmt.Sprintln("peerstoreNum:", len(s.host.Peerstore().Peers()), ",conn num:", insize+outsize, "inbound num", insize, "outbound num", outsize,
   142  			"dht size", s.routingTable.Size())
   143  		trackerInfo += fmt.Sprintln("-------------------------------------")
   144  		log.Debug(trackerInfo)
   145  	}
   146  }
   147  
   148  func (s *ConnManager) procConnections() {
   149  	//处理当前连接的节点问题
   150  	_, outBoundSize := s.BoundSize()
   151  	if outBoundSize > maxOutBounds || s.Size() > maxBounds {
   152  		return
   153  	}
   154  	//如果连接的节点数较少,尝试连接内置的和配置的种子节点
   155  	//无须担心重新连接的问题,底层会自己判断是否已经连接了此节点,如果已经连接了就会忽略
   156  	for _, seed := range s.cfg.Seeds {
   157  		info, err := genAddrInfo(seed)
   158  		if err != nil {
   159  			panic(`invalid seeds format in config, use format of "/ip4/118.89.190.76/tcp/13803/p2p/16Uiu2HAmRao56AsxpobLBvbNfDttheQxnke9y1uWQRMWW7XaEdk5"`)
   160  		}
   161  		_ = s.host.Connect(context.Background(), *info)
   162  	}
   163  
   164  	for _, node := range s.cfg.BootStraps {
   165  		info, err := genAddrInfo(node)
   166  		if err != nil {
   167  			panic(`invalid bootStraps format in config, use format of "/ip4/118.89.190.76/tcp/13803/p2p/16Uiu2HAmRao56AsxpobLBvbNfDttheQxnke9y1uWQRMWW7XaEdk5"`)
   168  		}
   169  		_ = s.host.Connect(context.Background(), *info)
   170  	}
   171  	if s.cfg.RelayEnable {
   172  		//对relay中中继服务器要长期保持连接
   173  		for _, node := range s.cfg.RelayNodeAddr {
   174  			info, err := genAddrInfo(node)
   175  			if err != nil {
   176  				panic(`invalid relayNodeAddr in config, use format of "/ip4/118.89.190.76/tcp/13803/p2p/16Uiu2HAmRao56AsxpobLBvbNfDttheQxnke9y1uWQRMWW7XaEdk5"`)
   177  			}
   178  			if len(s.host.Network().ConnsToPeer(info.ID)) == 0 {
   179  				s.host.Connect(context.Background(), *info)
   180  			}
   181  		}
   182  	}
   183  
   184  }
   185  
   186  func genAddrInfo(addr string) (*peer.AddrInfo, error) {
   187  	mAddr, err := multiaddr.NewMultiaddr(addr)
   188  	if err != nil {
   189  		return nil, err
   190  	}
   191  	return peer.AddrInfoFromP2pAddr(mAddr)
   192  }
   193  
   194  // AddNeighbors add neighbors by peer info
   195  func (s *ConnManager) AddNeighbors(pr *peer.AddrInfo) {
   196  	if pr == nil {
   197  		return
   198  	}
   199  	s.neighborStore.Store(pr.ID.Pretty(), pr)
   200  }
   201  
   202  // IsNeighbors check is neighbors by id
   203  func (s *ConnManager) IsNeighbors(pid peer.ID) bool {
   204  	_, ok := s.neighborStore.Load(pid.Pretty())
   205  	return ok
   206  }
   207  
   208  // Delete delete peer by id
   209  func (s *ConnManager) Delete(pid peer.ID) {
   210  	_ = s.host.Network().ClosePeer(pid)
   211  	s.routingTable.Remove(pid)
   212  }
   213  
   214  // FetchNearestPeers fetch nearest peer ids
   215  func (s *ConnManager) FetchNearestPeers(count int) []peer.ID {
   216  	if s.routingTable == nil {
   217  		return nil
   218  	}
   219  	return s.routingTable.NearestPeers(kb.ConvertPeerID(s.host.ID()), count)
   220  }
   221  
   222  // Size connections size
   223  func (s *ConnManager) Size() int {
   224  	return len(s.host.Network().Conns())
   225  }
   226  
   227  // FetchConnPeers 获取连接的Peer's ID 这个连接包含被连接的peer以及主动连接的peer.
   228  func (s *ConnManager) FetchConnPeers() []peer.ID {
   229  	var peers = make(map[string]peer.ID)
   230  	var allconns conns
   231  
   232  	for _, conn := range s.host.Network().Conns() {
   233  		allconns = append(allconns, conn)
   234  	}
   235  
   236  	//对当前连接的节点时长进行排序
   237  	sort.Sort(allconns)
   238  	//log.Debug("FetchConnPeers", "stream Num", len(conn.GetStreams()), "pid", conn.RemotePeer().Pretty())
   239  	for _, conn := range allconns {
   240  		peers[conn.RemotePeer().Pretty()] = conn.RemotePeer()
   241  		if len(peers) >= maxBounds {
   242  			break
   243  		}
   244  	}
   245  	return convertMapToArr(peers)
   246  }
   247  
   248  func convertMapToArr(in map[string]peer.ID) []peer.ID {
   249  	var pids []peer.ID
   250  	for _, id := range in {
   251  		pids = append(pids, id)
   252  	}
   253  	return pids
   254  }
   255  
   256  // CheckDirection 检查连接的节点ID是被连接的还是主动连接的
   257  func (s *ConnManager) CheckDirection(pid peer.ID) network.Direction {
   258  	for _, conn := range s.host.Network().ConnsToPeer(pid) {
   259  		return conn.Stat().Direction
   260  	}
   261  	return network.DirUnknown
   262  }
   263  
   264  // OutBounds get out bounds conn peers
   265  func (s *ConnManager) OutBounds() []peer.ID {
   266  	var peers []peer.ID
   267  	for _, con := range s.host.Network().Conns() {
   268  		if con.Stat().Direction == network.DirOutbound {
   269  			peers = append(peers, con.RemotePeer())
   270  		}
   271  	}
   272  	return peers
   273  }
   274  
   275  // InBounds get in bounds conn peers
   276  func (s *ConnManager) InBounds() []peer.ID {
   277  	var peers []peer.ID
   278  	for _, con := range s.host.Network().Conns() {
   279  		if con.Stat().Direction == network.DirInbound {
   280  			peers = append(peers, con.RemotePeer())
   281  		}
   282  	}
   283  	return peers
   284  }
   285  
   286  // BoundSize get in out conn bound size
   287  func (s *ConnManager) BoundSize() (insize int, outsize int) {
   288  	for _, con := range s.host.Network().Conns() {
   289  		if con.Stat().Direction == network.DirOutbound {
   290  			outsize++
   291  		}
   292  		if con.Stat().Direction == network.DirInbound {
   293  			insize++
   294  		}
   295  	}
   296  	return insize, outsize
   297  }
   298  
   299  // GetNetRate get rateinfo
   300  func (s *ConnManager) GetNetRate() metrics.Stats {
   301  	return s.bandwidthTracker.GetBandwidthTotals()
   302  }
   303  
   304  //对系统的连接时长按照从大到小的顺序排序
   305  type conns []network.Conn
   306  
   307  //Len
   308  func (c conns) Len() int { return len(c) }
   309  
   310  //Swap
   311  func (c conns) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
   312  
   313  //Less
   314  func (c conns) Less(i, j int) bool { //从大到小排序,即index=0 ,表示数值最大
   315  	return c[i].Stat().Opened.After(c[j].Stat().Opened)
   316  }
   317  
   318  type sortNetProtocols struct {
   319  	Protocol  string
   320  	Ratetotal string
   321  	Ratein    string
   322  	Rateout   string
   323  }
   324  
   325  type netprotocols []*sortNetProtocols
   326  
   327  //Len
   328  func (n netprotocols) Len() int { return len(n) }
   329  
   330  //Swap
   331  func (n netprotocols) Swap(i, j int) { n[i], n[j] = n[j], n[i] }
   332  
   333  //Less
   334  func (n netprotocols) Less(i, j int) bool { //从小到大排序,即index=0 ,表示数值最小
   335  	return n[i].Ratetotal < n[j].Ratetotal
   336  }