diff --git a/common/src/main/java/org/tron/common/prometheus/MetricKeys.java b/common/src/main/java/org/tron/common/prometheus/MetricKeys.java index 95a38c4b47..d473dac2cc 100644 --- a/common/src/main/java/org/tron/common/prometheus/MetricKeys.java +++ b/common/src/main/java/org/tron/common/prometheus/MetricKeys.java @@ -67,6 +67,15 @@ public static class Histogram { public static final String BLOCK_FETCH_LATENCY = "tron:block_fetch_latency_seconds"; public static final String BLOCK_RECEIVE_DELAY = "tron:block_receive_delay_seconds"; public static final String BLOCK_TRANSACTION_COUNT = "tron:block_transaction_count"; + /** + * Transaction fetch round-trip latency in seconds: from sending + * {@code GET_DATA (FETCH_INV_DATA)} to receiving the full {@code TXS} + * message. + *

Transactions pushed via gossip without a prior {@code GET_DATA} + * (i.e. not actively fetched by this node) are not sampled; + *

Companion to {@link #BLOCK_FETCH_LATENCY} for the TX path. + */ + public static final String TX_FETCH_LATENCY = "tron:tx_fetch_latency_seconds"; private Histogram() { throw new IllegalStateException("Histogram"); diff --git a/common/src/main/java/org/tron/common/prometheus/MetricsHistogram.java b/common/src/main/java/org/tron/common/prometheus/MetricsHistogram.java index fa42a59aea..d8adf7e18c 100644 --- a/common/src/main/java/org/tron/common/prometheus/MetricsHistogram.java +++ b/common/src/main/java/org/tron/common/prometheus/MetricsHistogram.java @@ -48,6 +48,8 @@ public class MetricsHistogram { init(MetricKeys.Histogram.BLOCK_FETCH_LATENCY, "fetch block latency."); init(MetricKeys.Histogram.BLOCK_RECEIVE_DELAY, "receive block delay time, receiveTime - blockTime."); + init(MetricKeys.Histogram.TX_FETCH_LATENCY, + "fetch transaction latency: GET_DATA send to full TXS received round-trip."); init(MetricKeys.Histogram.BLOCK_TRANSACTION_COUNT, "Distribution of transaction counts per block.", diff --git a/framework/src/main/java/org/tron/core/net/messagehandler/TransactionsMsgHandler.java b/framework/src/main/java/org/tron/core/net/messagehandler/TransactionsMsgHandler.java index e153e21f33..7189150e9e 100644 --- a/framework/src/main/java/org/tron/core/net/messagehandler/TransactionsMsgHandler.java +++ b/framework/src/main/java/org/tron/core/net/messagehandler/TransactionsMsgHandler.java @@ -14,6 +14,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.tron.common.es.ExecutorServiceManager; +import org.tron.common.prometheus.MetricKeys; +import org.tron.common.prometheus.Metrics; import org.tron.common.utils.Sha256Hash; import org.tron.core.ChainBaseManager; import org.tron.core.config.args.Args; @@ -87,9 +89,17 @@ public void processMessage(PeerConnection peer, TronMessage msg) throws P2pExcep } TransactionsMessage transactionsMessage = (TransactionsMessage) msg; check(peer, transactionsMessage); + long now = System.currentTimeMillis(); for (Transaction trx : transactionsMessage.getTransactions().getTransactionsList()) { Item item = new Item(new TransactionMessage(trx).getMessageId(), InventoryType.TRX); - peer.getAdvInvRequest().remove(item); + // Observe end-to-end fetch latency (GET_DATA send → full TXS received) + // before consuming the timestamp. Null means this tx wasn't actively + // fetched (e.g. pushed via gossip), in which case no sample is recorded. + Long requestTime = peer.getAdvInvRequest().remove(item); + if (requestTime != null) { + Metrics.histogramObserve(MetricKeys.Histogram.TX_FETCH_LATENCY, + (now - requestTime) / Metrics.MILLISECONDS_PER_SECOND); + } } int smartContractQueueSize = 0; int trxHandlePoolQueueSize = 0;