我的 HBase 集群中的数据节点不时触发一些 tcp rcvpruned 和 backlog 丢弃:
似乎至少有两个角度可以解决这个问题:
- 调整 HBase/HDFS 等...以便不会触发这些
- 调整 Linux 网络堆栈以便能够处理这些
我对进一步了解这两个指标以及对这两条路径的任何可行建议感兴趣。有人能就具体的下一步行动提出建议吗?
答案1
tcp_v4_rcv
[0] 调用sk_add_backlog
,如果失败则递增TCPBacklogDrop
2014 } else if (unlikely(sk_add_backlog(sk, skb,
2015 sk->sk_rcvbuf + sk->sk_sndbuf))) {
2016 bh_unlock_sock(sk);
2017 NET_INC_STATS_BH(net, LINUX_MIB_TCPBACKLOGDROP);
2018 goto discard_and_relse;
2019 }
sk_add_backlog
sk_rcvqueues_full
仅当[1]时才失败:
801 /* The per-socket spinlock must be held here. */
802 static inline __must_check int sk_add_backlog(struct sock *sk, struct sk_buff *skb,
803 unsigned int limit)
804 {
805 if (sk_rcvqueues_full(sk, skb, limit))
806 return -ENOBUFS;
807
808 __sk_add_backlog(sk, skb);
809 sk->sk_backlog.len += skb->truesize;
810 return 0;
811 }
底层函数__sk_add_backlog
最近[2]允许至少一个数据包通过:
+ * Do not take into account this skb truesize,
+ * to allow even a single big packet to come.
我认为将该补丁应用于内核应该可以解决问题。您也可以尝试增加操作系统和应用程序中的默认 rcv 缓冲区大小(setsockopt
SO_RCVBUF
)
您的第二个问题是关于RcvPruned
- Linux 增加tcp_prune_queue
[3] 中的统计信息。该函数通常在套接字超出其 rcv 限制时调用。因此,您可以再次增加rmem
/SO_RCVBUF
和/或调整应用程序以更频繁地进行 read() 调用(我假设您的丢失与 Java 的 Stop-The-World GC 暂停密切相关。因此,请调整您的 GC)。
[0]http://lxr.free-electrons.com/source/net/ipv4/tcp_ipv4.c?v=3.15#L2014
[1]http://lxr.free-electrons.com/source/include/net/sock.h?v=3.15#L802
[2]https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=0fd7bac6b6157eed6cf0cb86a1e88ba29e57c033
[3]http://lxr.free-electrons.com/source/net/ipv4/tcp_input.c?v=3.15#L4662