eth, metrics, p2p: prepare metrics and net packets to eth/62

This commit is contained in:
Péter Szilágyi 2015-07-02 14:13:46 +03:00
parent d51d0022ce
commit c51e153b5c
7 changed files with 149 additions and 48 deletions

View File

@ -39,6 +39,7 @@ import (
const ( const (
eth60 = 60 // Constant to check for old protocol support eth60 = 60 // Constant to check for old protocol support
eth61 = 61 // Constant to check for new protocol support eth61 = 61 // Constant to check for new protocol support
eth62 = 62 // Constant to check for experimental protocol support
) )
var ( var (
@ -329,7 +330,7 @@ func (d *Downloader) syncWithPeer(p *peer, hash common.Hash, td *big.Int) (err e
if err = d.fetchBlocks60(); err != nil { if err = d.fetchBlocks60(); err != nil {
return err return err
} }
case eth61: case eth61, eth62:
// New eth/61, use forward, concurrent hash and block retrieval algorithm // New eth/61, use forward, concurrent hash and block retrieval algorithm
number, err := d.findAncestor(p) number, err := d.findAncestor(p)
if err != nil { if err != nil {

View File

@ -176,7 +176,7 @@ func (pm *ProtocolManager) Stop() {
} }
func (pm *ProtocolManager) newPeer(pv, nv int, p *p2p.Peer, rw p2p.MsgReadWriter) *peer { func (pm *ProtocolManager) newPeer(pv, nv int, p *p2p.Peer, rw p2p.MsgReadWriter) *peer {
return newPeer(pv, nv, p, rw) return newPeer(pv, nv, p, newMeteredMsgWriter(rw))
} }
// handle is the callback invoked to manage the life cycle of an eth peer. When // handle is the callback invoked to manage the life cycle of an eth peer. When
@ -281,14 +281,11 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
case BlockHashesMsg: case BlockHashesMsg:
// A batch of hashes arrived to one of our previous requests // A batch of hashes arrived to one of our previous requests
msgStream := rlp.NewStream(msg.Payload, uint64(msg.Size)) msgStream := rlp.NewStream(msg.Payload, uint64(msg.Size))
reqHashInPacketsMeter.Mark(1)
var hashes []common.Hash var hashes []common.Hash
if err := msgStream.Decode(&hashes); err != nil { if err := msgStream.Decode(&hashes); err != nil {
break break
} }
reqHashInTrafficMeter.Mark(int64(32 * len(hashes)))
// Deliver them all to the downloader for queuing // Deliver them all to the downloader for queuing
err := pm.downloader.DeliverHashes(p.id, hashes) err := pm.downloader.DeliverHashes(p.id, hashes)
if err != nil { if err != nil {
@ -340,7 +337,6 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
case BlocksMsg: case BlocksMsg:
// Decode the arrived block message // Decode the arrived block message
msgStream := rlp.NewStream(msg.Payload, uint64(msg.Size)) msgStream := rlp.NewStream(msg.Payload, uint64(msg.Size))
reqBlockInPacketsMeter.Mark(1)
var blocks []*types.Block var blocks []*types.Block
if err := msgStream.Decode(&blocks); err != nil { if err := msgStream.Decode(&blocks); err != nil {
@ -349,7 +345,6 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
} }
// Update the receive timestamp of each block // Update the receive timestamp of each block
for _, block := range blocks { for _, block := range blocks {
reqBlockInTrafficMeter.Mark(block.Size().Int64())
block.ReceivedAt = msg.ReceivedAt block.ReceivedAt = msg.ReceivedAt
} }
// Filter out any explicitly requested blocks, deliver the rest to the downloader // Filter out any explicitly requested blocks, deliver the rest to the downloader
@ -365,9 +360,6 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
if err := msgStream.Decode(&hashes); err != nil { if err := msgStream.Decode(&hashes); err != nil {
break break
} }
propHashInPacketsMeter.Mark(1)
propHashInTrafficMeter.Mark(int64(32 * len(hashes)))
// Mark the hashes as present at the remote node // Mark the hashes as present at the remote node
for _, hash := range hashes { for _, hash := range hashes {
p.MarkBlock(hash) p.MarkBlock(hash)
@ -390,9 +382,6 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
if err := msg.Decode(&request); err != nil { if err := msg.Decode(&request); err != nil {
return errResp(ErrDecode, "%v: %v", msg, err) return errResp(ErrDecode, "%v: %v", msg, err)
} }
propBlockInPacketsMeter.Mark(1)
propBlockInTrafficMeter.Mark(request.Block.Size().Int64())
if err := request.Block.ValidateFields(); err != nil { if err := request.Block.ValidateFields(); err != nil {
return errResp(ErrDecode, "block validation %v: %v", msg, err) return errResp(ErrDecode, "block validation %v: %v", msg, err)
} }
@ -427,7 +416,6 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
if err := msg.Decode(&txs); err != nil { if err := msg.Decode(&txs); err != nil {
return errResp(ErrDecode, "msg %v: %v", msg, err) return errResp(ErrDecode, "msg %v: %v", msg, err)
} }
propTxnInPacketsMeter.Mark(1)
for i, tx := range txs { for i, tx := range txs {
// Validate and mark the remote transaction // Validate and mark the remote transaction
if tx == nil { if tx == nil {
@ -436,7 +424,6 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
p.MarkTransaction(tx.Hash()) p.MarkTransaction(tx.Hash())
// Log it's arrival for later analysis // Log it's arrival for later analysis
propTxnInTrafficMeter.Mark(tx.Size().Int64())
jsonlogger.LogJson(&logger.EthTxReceived{ jsonlogger.LogJson(&logger.EthTxReceived{
TxHash: tx.Hash().Hex(), TxHash: tx.Hash().Hex(),
RemoteId: p.ID().String(), RemoteId: p.ID().String(),

View File

@ -18,6 +18,7 @@ package eth
import ( import (
"github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/p2p"
) )
var ( var (
@ -41,4 +42,87 @@ var (
reqBlockInTrafficMeter = metrics.NewMeter("eth/req/blocks/in/traffic") reqBlockInTrafficMeter = metrics.NewMeter("eth/req/blocks/in/traffic")
reqBlockOutPacketsMeter = metrics.NewMeter("eth/req/blocks/out/packets") reqBlockOutPacketsMeter = metrics.NewMeter("eth/req/blocks/out/packets")
reqBlockOutTrafficMeter = metrics.NewMeter("eth/req/blocks/out/traffic") reqBlockOutTrafficMeter = metrics.NewMeter("eth/req/blocks/out/traffic")
reqHeaderInPacketsMeter = metrics.NewMeter("eth/req/header/in/packets")
reqHeaderInTrafficMeter = metrics.NewMeter("eth/req/header/in/traffic")
reqHeaderOutPacketsMeter = metrics.NewMeter("eth/req/header/out/packets")
reqHeaderOutTrafficMeter = metrics.NewMeter("eth/req/header/out/traffic")
reqStateInPacketsMeter = metrics.NewMeter("eth/req/state/in/packets")
reqStateInTrafficMeter = metrics.NewMeter("eth/req/state/in/traffic")
reqStateOutPacketsMeter = metrics.NewMeter("eth/req/state/out/packets")
reqStateOutTrafficMeter = metrics.NewMeter("eth/req/state/out/traffic")
miscInPacketsMeter = metrics.NewMeter("eth/misc/in/packets")
miscInTrafficMeter = metrics.NewMeter("eth/misc/in/traffic")
miscOutPacketsMeter = metrics.NewMeter("eth/misc/out/packets")
miscOutTrafficMeter = metrics.NewMeter("eth/misc/out/traffic")
) )
// meteredMsgReadWriter is a wrapper around a p2p.MsgReadWriter, capable of
// accumulating the above defined metrics based on the data stream contents.
type meteredMsgReadWriter struct {
p2p.MsgReadWriter
}
// newMeteredMsgWriter wraps a p2p MsgReadWriter with metering support. If the
// metrics system is disabled, this fucntion returns the original object.
func newMeteredMsgWriter(rw p2p.MsgReadWriter) p2p.MsgReadWriter {
if !metrics.Enabled {
return rw
}
return &meteredMsgReadWriter{rw}
}
func (rw *meteredMsgReadWriter) ReadMsg() (p2p.Msg, error) {
// Read the message and short circuit in case of an error
msg, err := rw.MsgReadWriter.ReadMsg()
if err != nil {
return msg, err
}
// Account for the data traffic
packets, traffic := miscInPacketsMeter, miscInTrafficMeter
switch msg.Code {
case BlockHashesMsg:
packets, traffic = reqHashInPacketsMeter, reqHashInTrafficMeter
case BlocksMsg:
packets, traffic = reqBlockInPacketsMeter, reqBlockInTrafficMeter
case BlockHeadersMsg:
packets, traffic = reqHeaderInPacketsMeter, reqHeaderInTrafficMeter
case NodeDataMsg:
packets, traffic = reqStateInPacketsMeter, reqStateInTrafficMeter
case NewBlockHashesMsg:
packets, traffic = propHashInPacketsMeter, propHashInTrafficMeter
case NewBlockMsg:
packets, traffic = propBlockInPacketsMeter, propBlockInTrafficMeter
case TxMsg:
packets, traffic = propTxnInPacketsMeter, propTxnInTrafficMeter
}
packets.Mark(1)
traffic.Mark(int64(msg.Size))
return msg, err
}
func (rw *meteredMsgReadWriter) WriteMsg(msg p2p.Msg) error {
// Account for the data traffic
packets, traffic := miscOutPacketsMeter, miscOutTrafficMeter
switch msg.Code {
case BlockHashesMsg:
packets, traffic = reqHashOutPacketsMeter, reqHashOutTrafficMeter
case BlocksMsg:
packets, traffic = reqBlockOutPacketsMeter, reqBlockOutTrafficMeter
case BlockHeadersMsg:
packets, traffic = reqHeaderOutPacketsMeter, reqHeaderOutTrafficMeter
case NodeDataMsg:
packets, traffic = reqStateOutPacketsMeter, reqStateOutTrafficMeter
case NewBlockHashesMsg:
packets, traffic = propHashOutPacketsMeter, propHashOutTrafficMeter
case NewBlockMsg:
packets, traffic = propBlockOutPacketsMeter, propBlockOutTrafficMeter
case TxMsg:
packets, traffic = propTxnOutPacketsMeter, propTxnOutTrafficMeter
}
packets.Mark(1)
traffic.Mark(int64(msg.Size))
// Send the packet to the p2p layer
return rw.MsgReadWriter.WriteMsg(msg)
}

View File

@ -129,9 +129,7 @@ func (p *peer) MarkTransaction(hash common.Hash) {
// SendTransactions sends transactions to the peer and includes the hashes // SendTransactions sends transactions to the peer and includes the hashes
// in its transaction hash set for future reference. // in its transaction hash set for future reference.
func (p *peer) SendTransactions(txs types.Transactions) error { func (p *peer) SendTransactions(txs types.Transactions) error {
propTxnOutPacketsMeter.Mark(1)
for _, tx := range txs { for _, tx := range txs {
propTxnOutTrafficMeter.Mark(tx.Size().Int64())
p.knownTxs.Add(tx.Hash()) p.knownTxs.Add(tx.Hash())
} }
return p2p.Send(p.rw, TxMsg, txs) return p2p.Send(p.rw, TxMsg, txs)
@ -139,27 +137,17 @@ func (p *peer) SendTransactions(txs types.Transactions) error {
// SendBlockHashes sends a batch of known hashes to the remote peer. // SendBlockHashes sends a batch of known hashes to the remote peer.
func (p *peer) SendBlockHashes(hashes []common.Hash) error { func (p *peer) SendBlockHashes(hashes []common.Hash) error {
reqHashOutPacketsMeter.Mark(1)
reqHashOutTrafficMeter.Mark(int64(32 * len(hashes)))
return p2p.Send(p.rw, BlockHashesMsg, hashes) return p2p.Send(p.rw, BlockHashesMsg, hashes)
} }
// SendBlocks sends a batch of blocks to the remote peer. // SendBlocks sends a batch of blocks to the remote peer.
func (p *peer) SendBlocks(blocks []*types.Block) error { func (p *peer) SendBlocks(blocks []*types.Block) error {
reqBlockOutPacketsMeter.Mark(1)
for _, block := range blocks {
reqBlockOutTrafficMeter.Mark(block.Size().Int64())
}
return p2p.Send(p.rw, BlocksMsg, blocks) return p2p.Send(p.rw, BlocksMsg, blocks)
} }
// SendNewBlockHashes announces the availability of a number of blocks through // SendNewBlockHashes announces the availability of a number of blocks through
// a hash notification. // a hash notification.
func (p *peer) SendNewBlockHashes(hashes []common.Hash) error { func (p *peer) SendNewBlockHashes(hashes []common.Hash) error {
propHashOutPacketsMeter.Mark(1)
propHashOutTrafficMeter.Mark(int64(32 * len(hashes)))
for _, hash := range hashes { for _, hash := range hashes {
p.knownBlocks.Add(hash) p.knownBlocks.Add(hash)
} }
@ -168,33 +156,55 @@ func (p *peer) SendNewBlockHashes(hashes []common.Hash) error {
// SendNewBlock propagates an entire block to a remote peer. // SendNewBlock propagates an entire block to a remote peer.
func (p *peer) SendNewBlock(block *types.Block, td *big.Int) error { func (p *peer) SendNewBlock(block *types.Block, td *big.Int) error {
propBlockOutPacketsMeter.Mark(1)
propBlockOutTrafficMeter.Mark(block.Size().Int64())
p.knownBlocks.Add(block.Hash()) p.knownBlocks.Add(block.Hash())
return p2p.Send(p.rw, NewBlockMsg, []interface{}{block, td}) return p2p.Send(p.rw, NewBlockMsg, []interface{}{block, td})
} }
// SendBlockHeaders sends a batch of block headers to the remote peer.
func (p *peer) SendBlockHeaders(headers []*types.Header) error {
return p2p.Send(p.rw, BlockHeadersMsg, headers)
}
// SendNodeData sends a batch of arbitrary internal data, corresponding to the
// hashes requested.
func (p *peer) SendNodeData(data [][]byte) error {
return p2p.Send(p.rw, NodeDataMsg, data)
}
// RequestHashes fetches a batch of hashes from a peer, starting at from, going // RequestHashes fetches a batch of hashes from a peer, starting at from, going
// towards the genesis block. // towards the genesis block.
func (p *peer) RequestHashes(from common.Hash) error { func (p *peer) RequestHashes(from common.Hash) error {
glog.V(logger.Debug).Infof("Peer [%s] fetching hashes (%d) from %x...\n", p.id, downloader.MaxHashFetch, from[:4]) glog.V(logger.Debug).Infof("%v fetching hashes (%d) from %x...\n", p, downloader.MaxHashFetch, from[:4])
return p2p.Send(p.rw, GetBlockHashesMsg, getBlockHashesData{from, uint64(downloader.MaxHashFetch)}) return p2p.Send(p.rw, GetBlockHashesMsg, getBlockHashesData{from, uint64(downloader.MaxHashFetch)})
} }
// RequestHashesFromNumber fetches a batch of hashes from a peer, starting at the // RequestHashesFromNumber fetches a batch of hashes from a peer, starting at
// requested block number, going upwards towards the genesis block. // the requested block number, going upwards towards the genesis block.
func (p *peer) RequestHashesFromNumber(from uint64, count int) error { func (p *peer) RequestHashesFromNumber(from uint64, count int) error {
glog.V(logger.Debug).Infof("Peer [%s] fetching hashes (%d) from #%d...\n", p.id, count, from) glog.V(logger.Debug).Infof("%v fetching hashes (%d) from #%d...\n", p, count, from)
return p2p.Send(p.rw, GetBlockHashesFromNumberMsg, getBlockHashesFromNumberData{from, uint64(count)}) return p2p.Send(p.rw, GetBlockHashesFromNumberMsg, getBlockHashesFromNumberData{from, uint64(count)})
} }
// RequestBlocks fetches a batch of blocks corresponding to the specified hashes. // RequestBlocks fetches a batch of blocks corresponding to the specified hashes.
func (p *peer) RequestBlocks(hashes []common.Hash) error { func (p *peer) RequestBlocks(hashes []common.Hash) error {
glog.V(logger.Debug).Infof("[%s] fetching %v blocks\n", p.id, len(hashes)) glog.V(logger.Debug).Infof("%v fetching %v blocks\n", p, len(hashes))
return p2p.Send(p.rw, GetBlocksMsg, hashes) return p2p.Send(p.rw, GetBlocksMsg, hashes)
} }
// RequestHeaders fetches a batch of blocks' headers corresponding to the
// specified hashes.
func (p *peer) RequestHeaders(hashes []common.Hash) error {
glog.V(logger.Debug).Infof("%v fetching %v headers\n", p, len(hashes))
return p2p.Send(p.rw, GetBlockHeadersMsg, hashes)
}
// RequestNodeData fetches a batch of arbitrary data from a node's known state
// data, corresponding to the specified hashes.
func (p *peer) RequestNodeData(hashes []common.Hash) error {
glog.V(logger.Debug).Infof("%v fetching %v state data\n", p, len(hashes))
return p2p.Send(p.rw, GetNodeDataMsg, hashes)
}
// Handshake executes the eth protocol handshake, negotiating version number, // Handshake executes the eth protocol handshake, negotiating version number,
// network IDs, difficulties, head and genesis blocks. // network IDs, difficulties, head and genesis blocks.
func (p *peer) Handshake(td *big.Int, head common.Hash, genesis common.Hash) error { func (p *peer) Handshake(td *big.Int, head common.Hash, genesis common.Hash) error {

View File

@ -24,10 +24,10 @@ import (
) )
// Supported versions of the eth protocol (first is primary). // Supported versions of the eth protocol (first is primary).
var ProtocolVersions = []uint{61, 60} var ProtocolVersions = []uint{62, 61, 60}
// Number of implemented message corresponding to different protocol versions. // Number of implemented message corresponding to different protocol versions.
var ProtocolLengths = []uint64{9, 8} var ProtocolLengths = []uint64{13, 9, 8}
const ( const (
NetworkId = 1 NetworkId = 1
@ -36,6 +36,7 @@ const (
// eth protocol message codes // eth protocol message codes
const ( const (
// Protocol messages belonging to eth/60
StatusMsg = iota StatusMsg = iota
NewBlockHashesMsg NewBlockHashesMsg
TxMsg TxMsg
@ -44,7 +45,15 @@ const (
GetBlocksMsg GetBlocksMsg
BlocksMsg BlocksMsg
NewBlockMsg NewBlockMsg
// Protocol messages belonging to eth/61
GetBlockHashesFromNumberMsg GetBlockHashesFromNumberMsg
// Protocol messages belonging to eth/62
GetBlockHeadersMsg
BlockHeadersMsg
GetNodeDataMsg
NodeDataMsg
) )
type errCode int type errCode int
@ -102,15 +111,14 @@ type statusData struct {
GenesisBlock common.Hash GenesisBlock common.Hash
} }
// getBlockHashesData is the network packet for the hash based block retrieval // getBlockHashesData is the network packet for the hash based hash retrieval.
// message.
type getBlockHashesData struct { type getBlockHashesData struct {
Hash common.Hash Hash common.Hash
Amount uint64 Amount uint64
} }
// getBlockHashesFromNumberData is the network packet for the number based block // getBlockHashesFromNumberData is the network packet for the number based hash
// retrieval message. // retrieval.
type getBlockHashesFromNumberData struct { type getBlockHashesFromNumberData struct {
Number uint64 Number uint64
Amount uint64 Amount uint64
@ -121,3 +129,8 @@ type newBlockData struct {
Block *types.Block Block *types.Block
TD *big.Int TD *big.Int
} }
// nodeDataData is the network response packet for a node data retrieval.
type nodeDataData []struct {
Value []byte
}

View File

@ -31,8 +31,8 @@ import (
// MetricsEnabledFlag is the CLI flag name to use to enable metrics collections. // MetricsEnabledFlag is the CLI flag name to use to enable metrics collections.
var MetricsEnabledFlag = "metrics" var MetricsEnabledFlag = "metrics"
// enabled is the flag specifying if metrics are enable or not. // Enabled is the flag specifying if metrics are enable or not.
var enabled = false var Enabled = false
// Init enables or disables the metrics system. Since we need this to run before // Init enables or disables the metrics system. Since we need this to run before
// any other code gets to create meters and timers, we'll actually do an ugly hack // any other code gets to create meters and timers, we'll actually do an ugly hack
@ -41,7 +41,7 @@ func init() {
for _, arg := range os.Args { for _, arg := range os.Args {
if strings.TrimLeft(arg, "-") == MetricsEnabledFlag { if strings.TrimLeft(arg, "-") == MetricsEnabledFlag {
glog.V(logger.Info).Infof("Enabling metrics collection") glog.V(logger.Info).Infof("Enabling metrics collection")
enabled = true Enabled = true
} }
} }
} }
@ -49,7 +49,7 @@ func init() {
// NewMeter create a new metrics Meter, either a real one of a NOP stub depending // NewMeter create a new metrics Meter, either a real one of a NOP stub depending
// on the metrics flag. // on the metrics flag.
func NewMeter(name string) metrics.Meter { func NewMeter(name string) metrics.Meter {
if !enabled { if !Enabled {
return new(metrics.NilMeter) return new(metrics.NilMeter)
} }
return metrics.GetOrRegisterMeter(name, metrics.DefaultRegistry) return metrics.GetOrRegisterMeter(name, metrics.DefaultRegistry)
@ -58,7 +58,7 @@ func NewMeter(name string) metrics.Meter {
// NewTimer create a new metrics Timer, either a real one of a NOP stub depending // NewTimer create a new metrics Timer, either a real one of a NOP stub depending
// on the metrics flag. // on the metrics flag.
func NewTimer(name string) metrics.Timer { func NewTimer(name string) metrics.Timer {
if !enabled { if !Enabled {
return new(metrics.NilTimer) return new(metrics.NilTimer)
} }
return metrics.GetOrRegisterTimer(name, metrics.DefaultRegistry) return metrics.GetOrRegisterTimer(name, metrics.DefaultRegistry)
@ -68,7 +68,7 @@ func NewTimer(name string) metrics.Timer {
// process. // process.
func CollectProcessMetrics(refresh time.Duration) { func CollectProcessMetrics(refresh time.Duration) {
// Short circuit if the metrics system is disabled // Short circuit if the metrics system is disabled
if !enabled { if !Enabled {
return return
} }
// Create the various data collectors // Create the various data collectors

View File

@ -38,8 +38,14 @@ type meteredConn struct {
} }
// newMeteredConn creates a new metered connection, also bumping the ingress or // newMeteredConn creates a new metered connection, also bumping the ingress or
// egress connection meter. // egress connection meter. If the metrics system is disabled, this function
// returns the original object.
func newMeteredConn(conn net.Conn, ingress bool) net.Conn { func newMeteredConn(conn net.Conn, ingress bool) net.Conn {
// Short circuit if metrics are disabled
if !metrics.Enabled {
return conn
}
// Otherwise bump the connection counters and wrap the connection
if ingress { if ingress {
ingressConnectMeter.Mark(1) ingressConnectMeter.Mark(1)
} else { } else {