100ms delays in FreeBSD 8.x

Maxim Dounin mdounin на mdounin.ru
Пн Сен 13 08:39:44 MSD 2010


Hello!

On Fri, Sep 10, 2010 at 11:13:48AM +0400, Igor Sysoev wrote:

> On Fri, Sep 03, 2010 at 05:23:15PM +0400, Igor Sysoev wrote:
> 
> > On Fri, Sep 03, 2010 at 05:15:08PM +0400, Maxim Dounin wrote:
> > 
> > > Hello!
> > > 
> > > On Thu, Sep 02, 2010 at 07:16:39PM +0400, Igor Sysoev wrote:
> > > 
> > > > Если вы используете FreeBSD 8.x, то рекомендуется поставить
> > > > sysctl net.inet.tcp.rfc3465=0 или наложить патч из ссылки,
> > > > иначе могут наблюдаться 100ms задержки в ответах.
> > > > Особенно забавно видеть эти задержки при проксировании в localhost.
> > > > 
> > > > Подробности здесь:
> > > > http://lists.freebsd.org/pipermail/freebsd-net/2010-July/025867.html
> > > > В CURRENT починили, но в 8ку пока не закоммитили.
> > > 
> > > Да, пока заметил.  MFC в 8-ку и 7-ку был две недели назад:
> > > 
> > > http://svn.freebsd.org/viewvc/base?view=revision&revision=211312
> > > http://svn.freebsd.org/viewvc/base?view=revision&revision=211313
> > 
> > Да, это я спутал с другим коммитом.
> 
> Что-то у меня не починилось.
> Есть FreeBSD 8.1-STABLE от date=2010.09.06.23.59.59 вот с такими
> настройками, имеющими хоть какое-то отношение к данной ситуации:
> 
> net.inet.tcp.syncookies=0
> net.inet.tcp.rfc1323=0
> net.inet.tcp.sack.enable=1
> 
> net.inet.tcp.recvspace=8192
> net.inet.tcp.recvbuf_auto=0
> 
> net.inet.tcp.sendspace=16384
> net.inet.tcp.sendbuf_auto=1
> net.inet.tcp.sendbuf_inc=8192
> net.inet.tcp.sendbuf_max=131072
> 
> Прочее по умолчанию.
> 
> Наблюдается задержка в ответе в 100ms.
> Ставим sysctl net.inet.tcp.rfc3465=0 - 20ms, как на FreeBSD 7.
> Ответ собирается SSI'ем с нескольких серверов, поэтому 20ms.

Нда, там ещё одна проблема того же плана.  Если хост 
нашёлся в hostcache - то ему тоже ставят cwnd в 1*mss.

http://lists.freebsd.org/pipermail/freebsd-net/2007-July/014780.html
http://www.freebsd.org/cgi/query-pr.cgi?pr=kern/92690

Выключение rfc3465 лечит по тем же причинам что и раньше.

Чем больше я смотрю на эту установку cwnd из hostcache - тем 
больше мне кажется, что правильным решением было бы её вообще 
убрать.

Ибо проблемы на congested links она может вызвать очень большие.  
Даже внутри одной сессии slow start запускается заново после 
нескольких секунд отсутствия активности - а тут кеширование на 
час.

При этом поломана для входящих соединений она была с самого начала 
(работала только для исходящих), т.е. практически не тестировалась.

Патч (к current, но вроде и на 8-ку должен накатиться) 
выключающий установку cwnd из hostcache'а прилагается.

Maxim Dounin
-------------- next part --------------
# HG changeset patch
# User Maxim Dounin <mdounin at mdounin.ru>
# Date 1284352618 -14400
# Node ID bbb9fea7978b26b95e96d463238a3acd8bfb5575
# Parent  6aec795c568cf6b9d2fabf8b8b9e25ad75b053d0
Use cwnd from hostcache only as upper bound.

Setting initial congestion window from hostcache wasn't working for
accepted connection since introduction due to tp->snd_wnd being 0.  As
a result it was instead limiting cwnd on such connections to 1*MSS.  With
net.inet.tcp.rfc3465 enabled this results bad interaction with delayed
acks and 100ms delays for hosts found in hostcache.

Additionally, it's considered unsafe to use initial congestion window
larger than thouse specified in RFC3390 as this may cause problems on
congested links.  RFC5681 says equation from RFC3390 MUST be used as
upper bound.

Links:

http://lists.freebsd.org/pipermail/freebsd-net/2007-July/014780.html
http://www.freebsd.org/cgi/query-pr.cgi?pr=kern/92690

diff --git a/netinet/tcp_input.c b/netinet/tcp_input.c
--- a/netinet/tcp_input.c
+++ b/netinet/tcp_input.c
@@ -3332,29 +3332,13 @@ tcp_mss(struct tcpcb *tp, int offer)
 		tp->snd_bandwidth = metrics.rmx_bandwidth;
 
 	/*
-	 * Set the slow-start flight size depending on whether this
-	 * is a local network or not.
+	 * Set initial congestion window per RFC3390.  Alternatively, set
+	 * flight size depending on whether this is a local network or not.
 	 *
-	 * Extend this so we cache the cwnd too and retrieve it here.
-	 * Make cwnd even bigger than RFC3390 suggests but only if we
-	 * have previous experience with the remote host. Be careful
-	 * not make cwnd bigger than remote receive window or our own
-	 * send socket buffer. Maybe put some additional upper bound
-	 * on the retrieved cwnd. Should do incremental updates to
-	 * hostcache when cwnd collapses so next connection doesn't
-	 * overloads the path again.
-	 *
-	 * RFC3390 says only do this if SYN or SYN/ACK didn't got lost.
-	 * We currently check only in syncache_socket for that.
+	 * RFC3390 says we MUST limit initial window to one segment if SYN
+	 * or SYN/ACK is lost.  We currently check only in syncache_socket()
+	 * for that.
 	 */
-#define TCP_METRICS_CWND
-#ifdef TCP_METRICS_CWND
-	if (metrics.rmx_cwnd)
-		tp->snd_cwnd = max(mss,
-				min(metrics.rmx_cwnd / 2,
-				 min(tp->snd_wnd, so->so_snd.sb_hiwat)));
-	else
-#endif
 	if (V_tcp_do_rfc3390)
 		tp->snd_cwnd = min(4 * mss, max(2 * mss, 4380));
 #ifdef INET6
@@ -3367,6 +3351,10 @@ tcp_mss(struct tcpcb *tp, int offer)
 	else
 		tp->snd_cwnd = mss * V_ss_fltsz;
 
+	/* If we have cached cwnd - use it as an upper bound. */
+	if (metrics.rmx_cwnd)
+		tp->snd_cwnd = max(mss, min(tp->snd_cwnd, metrics.rmx_cwnd));
+
 	/* Check the interface for TSO capabilities. */
 	if (mtuflags & CSUM_TSO)
 		tp->t_flags |= TF_TSO;


Подробная информация о списке рассылки nginx-ru