Merge ~hloeung/content-cache-charm:sysctl into content-cache-charm:master

Proposed by Haw Loeung
Status: Merged
Approved by: Barry Price
Approved revision: defaf4bd85c881d43320a59adaf58fa88175739c
Merged at revision: ede1bda2d772b2b0e6dbaab4be3881ff0cae84db
Proposed branch: ~hloeung/content-cache-charm:sysctl
Merge into: content-cache-charm:master
Diff against target: 342 lines (+147/-1)
8 files modified
lib/haproxy.py (+5/-1)
reactive/content_cache.py (+9/-0)
templates/sysctl_conf.tmpl (+3/-0)
tests/unit/files/sysctl_core_default_somaxconn_none.conf (+22/-0)
tests/unit/files/sysctl_core_somaxconn.conf (+23/-0)
tests/unit/requirements.txt (+1/-0)
tests/unit/test_content_cache.py (+82/-0)
wheelhouse.txt (+2/-0)
Reviewer Review Type Date Requested Status
Barry Price Approve
Canonical IS Reviewers Pending
Review via email: mp+462295@code.launchpad.net

Commit message

Add tuning of net.core.somaxconn

Description of the change

`net.core.somaxconn 4096` is the default as of Linux 5.4.

See also https://code.launchpad.net/~cjwatson/launchpad-mojo-specs/+git/launchpad-mojo-specs/+merge/453051

To post a comment you must log in.
Revision history for this message
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote :

This merge proposal is being monitored by mergebot. Change the status to Approved to merge.

Revision history for this message
Barry Price (barryprice) wrote :

Couple of questions inline about looseversion, LGTM otherwise!

review: Needs Information
Revision history for this message
Barry Price (barryprice) wrote :

Answered offline, distutils is included by default on <3.12, looseversion will be included via wheelhouse on 3.12+, so we're all good here. +1 from me.

review: Approve
Revision history for this message
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote :

Change successfully merged at revision ede1bda2d772b2b0e6dbaab4be3881ff0cae84db

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/lib/haproxy.py b/lib/haproxy.py
2index 8842982..8387382 100644
3--- a/lib/haproxy.py
4+++ b/lib/haproxy.py
5@@ -6,7 +6,11 @@ import subprocess
6 import socket
7
8 import jinja2
9-from distutils.version import LooseVersion
10+
11+try:
12+ from distutils.version import LooseVersion
13+except ImportError:
14+ from looseversion import LooseVersion
15
16 from lib import utils
17
18diff --git a/reactive/content_cache.py b/reactive/content_cache.py
19index bc51c18..44fe1f3 100644
20--- a/reactive/content_cache.py
21+++ b/reactive/content_cache.py
22@@ -518,6 +518,7 @@ def configure_nagios():
23
24
25 _SYSCTL_CORE_DEFAULT_QDISC = '/proc/sys/net/core/default_qdisc'
26+_SYSCTL_CORE_SOMAXCONN = '/proc/sys/net/core/somaxconn'
27 _SYSCTL_NETFILTER_CONNTRACK_MAX = '/proc/sys/net/nf_conntrack_max'
28
29
30@@ -527,6 +528,7 @@ def configure_sysctl():
31
32 context = {
33 'net_core_default_qdisc': None,
34+ 'net_core_somax_conn': None,
35 'net_ipv4_tcp_congestion_control': None,
36 }
37
38@@ -544,6 +546,13 @@ def configure_sysctl():
39 # https://blog.cloudflare.com/http-2-prioritization-with-nginx/
40 context['net_ipv4_tcp_notsent_lowat'] = '16384'
41
42+ # Bump, 4096 is the default as of Linux 5.4. Apply same tuning for earlier.
43+ somaxconn = 4096
44+ if os.path.exists(_SYSCTL_CORE_SOMAXCONN):
45+ with open(_SYSCTL_CORE_SOMAXCONN, 'r', encoding='utf-8') as f:
46+ if int(f.readline()) < somaxconn:
47+ context['net_core_somax_conn'] = somaxconn
48+
49 base = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
50 env = jinja2.Environment(loader=jinja2.FileSystemLoader(base))
51 template = env.get_template('templates/sysctl_conf.tmpl')
52diff --git a/templates/sysctl_conf.tmpl b/templates/sysctl_conf.tmpl
53index 316a34d..f295ad1 100644
54--- a/templates/sysctl_conf.tmpl
55+++ b/templates/sysctl_conf.tmpl
56@@ -8,6 +8,9 @@ net.ipv4.tcp_notsent_lowat = {{ net_ipv4_tcp_notsent_lowat }}
57 {% if net_core_default_qdisc -%}
58 net.core.default_qdisc = {{ net_core_default_qdisc }}
59 {% endif -%}
60+{% if net_core_somax_conn -%}
61+net.core.somaxconn = {{ net_core_somax_conn }}
62+{% endif -%}
63 {% if net_ipv4_tcp_mem %}
64 # Tune TCP memory
65 net.ipv4.tcp_mem = {{ net_ipv4_tcp_mem }}
66diff --git a/tests/unit/files/sysctl_core_default_somaxconn_none.conf b/tests/unit/files/sysctl_core_default_somaxconn_none.conf
67new file mode 100644
68index 0000000..0509bb2
69--- /dev/null
70+++ b/tests/unit/files/sysctl_core_default_somaxconn_none.conf
71@@ -0,0 +1,22 @@
72+net.ipv4.tcp_notsent_lowat = 16384
73+net.core.default_qdisc = fq
74+
75+
76+# Tune the TCP stack for Fast Failure Detection
77+# tcp_syn_retries set to 1, it takes ~9secs to timeout
78+# tcp_syn_retries set to 2, it takes ~21secs to timeout
79+# tcp_syn_retries set to 3, it takes ~45secs to timeout
80+# tcp_syn_retries set to 4, it takes ~93secs to timeout
81+# tcp_syn_retries set to 5, it takes ~189secs to timeout (default)
82+# Reduce TCP connection timeouts to ~45 secs.
83+net.ipv4.tcp_syn_retries = 3
84+net.ipv4.tcp_synack_retries = 3
85+
86+# Reduce TCP KeepAlive timeout from 2 hrs to 30 mins.
87+net.ipv4.tcp_keepalive_time = 1800
88+
89+# Extend the source port range for outgoing TCP connections.
90+net.ipv4.ip_local_port_range = 16384 61000
91+
92+# Allow early reuse of a same source port for outgoing connections.
93+net.ipv4.tcp_tw_reuse = 1
94diff --git a/tests/unit/files/sysctl_core_somaxconn.conf b/tests/unit/files/sysctl_core_somaxconn.conf
95new file mode 100644
96index 0000000..0ecfae9
97--- /dev/null
98+++ b/tests/unit/files/sysctl_core_somaxconn.conf
99@@ -0,0 +1,23 @@
100+net.ipv4.tcp_notsent_lowat = 16384
101+net.core.default_qdisc = fq
102+net.core.somaxconn = 4096
103+
104+
105+# Tune the TCP stack for Fast Failure Detection
106+# tcp_syn_retries set to 1, it takes ~9secs to timeout
107+# tcp_syn_retries set to 2, it takes ~21secs to timeout
108+# tcp_syn_retries set to 3, it takes ~45secs to timeout
109+# tcp_syn_retries set to 4, it takes ~93secs to timeout
110+# tcp_syn_retries set to 5, it takes ~189secs to timeout (default)
111+# Reduce TCP connection timeouts to ~45 secs.
112+net.ipv4.tcp_syn_retries = 3
113+net.ipv4.tcp_synack_retries = 3
114+
115+# Reduce TCP KeepAlive timeout from 2 hrs to 30 mins.
116+net.ipv4.tcp_keepalive_time = 1800
117+
118+# Extend the source port range for outgoing TCP connections.
119+net.ipv4.ip_local_port_range = 16384 61000
120+
121+# Allow early reuse of a same source port for outgoing connections.
122+net.ipv4.tcp_tw_reuse = 1
123diff --git a/tests/unit/requirements.txt b/tests/unit/requirements.txt
124index 66d1f72..05e9abd 100644
125--- a/tests/unit/requirements.txt
126+++ b/tests/unit/requirements.txt
127@@ -1,6 +1,7 @@
128 charmhelpers
129 charms.reactive
130 freezegun
131+looseversion
132 mock
133 psutil
134 pytest
135diff --git a/tests/unit/test_content_cache.py b/tests/unit/test_content_cache.py
136index f12286e..fe1ae18 100644
137--- a/tests/unit/test_content_cache.py
138+++ b/tests/unit/test_content_cache.py
139@@ -1472,10 +1472,15 @@ site1.local:
140 tcp_cc.return_value = None
141 process_rlimits.return_value = '1048777'
142
143+ somaxconn_path = os.path.join(self.tmpdir, 'somaxconn')
144+ with open(somaxconn_path, 'w', encoding='utf-8') as f:
145+ f.write('4096\n')
146+
147 with mock.patch.multiple(
148 'reactive.content_cache',
149 SYSCTL_CONF_PATH=sysctl_conf_path,
150 _SYSCTL_CORE_DEFAULT_QDISC='some-file-does-not-exist',
151+ _SYSCTL_CORE_SOMAXCONN=somaxconn_path,
152 _SYSCTL_NETFILTER_CONNTRACK_MAX='some-file-does-not-exist',
153 ):
154 content_cache.configure_sysctl()
155@@ -1513,10 +1518,15 @@ site1.local:
156 qdisc_path = '/proc/uptime'
157 conntrack_max_path = '/proc/uptime'
158
159+ somaxconn_path = os.path.join(self.tmpdir, 'somaxconn')
160+ with open(somaxconn_path, 'w', encoding='utf-8') as f:
161+ f.write('4096\n')
162+
163 with mock.patch.multiple(
164 'reactive.content_cache',
165 SYSCTL_CONF_PATH=sysctl_conf_path,
166 _SYSCTL_CORE_DEFAULT_QDISC=qdisc_path,
167+ _SYSCTL_CORE_SOMAXCONN=somaxconn_path,
168 _SYSCTL_NETFILTER_CONNTRACK_MAX=conntrack_max_path,
169 ):
170 content_cache.configure_sysctl()
171@@ -1538,12 +1548,17 @@ site1.local:
172 tcp_cc.return_value = None
173 process_rlimits.return_value = '1048777'
174
175+ somaxconn_path = os.path.join(self.tmpdir, 'somaxconn')
176+ with open(somaxconn_path, 'w', encoding='utf-8') as f:
177+ f.write('4096\n')
178+
179 # Use '/proc/uptime' for unit test as that will always exist.
180 qdisc_path = '/proc/uptime'
181 with mock.patch.multiple(
182 'reactive.content_cache',
183 SYSCTL_CONF_PATH=sysctl_conf_path,
184 _SYSCTL_CORE_DEFAULT_QDISC=qdisc_path,
185+ _SYSCTL_CORE_SOMAXCONN=somaxconn_path,
186 _SYSCTL_NETFILTER_CONNTRACK_MAX='some-file-does-not-exist',
187 ):
188 content_cache.configure_sysctl()
189@@ -1558,6 +1573,7 @@ site1.local:
190 'reactive.content_cache',
191 SYSCTL_CONF_PATH=sysctl_conf_path,
192 _SYSCTL_CORE_DEFAULT_QDISC=qdisc_path,
193+ _SYSCTL_CORE_SOMAXCONN=somaxconn_path,
194 _SYSCTL_NETFILTER_CONNTRACK_MAX='some-file-does-not-exist',
195 ):
196 content_cache.configure_sysctl()
197@@ -1572,6 +1588,53 @@ site1.local:
198 @mock.patch('lib.utils.process_rlimits')
199 @mock.patch('lib.utils.select_tcp_congestion_control')
200 @mock.patch('lib.utils.tune_tcp_mem')
201+ def test_configure_sysctl_somaxconn(self, tune_tcp_mem, tcp_cc, process_rlimits, call, set_flag):
202+ sysctl_conf_path = os.path.join(self.tmpdir, '90-content-cache.conf')
203+ self.mock_config.return_value = {'tune_tcp_mem_multiplier': 1.5}
204+ tune_tcp_mem.return_value = None
205+ tcp_cc.return_value = None
206+ process_rlimits.return_value = '1048777'
207+ # Use '/proc/uptime' for unit test as that will always exist.
208+ qdisc_path = '/proc/uptime'
209+
210+ somaxconn_path = os.path.join(self.tmpdir, 'somaxconn')
211+ with open(somaxconn_path, 'w', encoding='utf-8') as f:
212+ f.write('1024\n')
213+
214+ with mock.patch.multiple(
215+ 'reactive.content_cache',
216+ SYSCTL_CONF_PATH=sysctl_conf_path,
217+ _SYSCTL_CORE_DEFAULT_QDISC=qdisc_path,
218+ _SYSCTL_CORE_SOMAXCONN=somaxconn_path,
219+ _SYSCTL_NETFILTER_CONNTRACK_MAX='some-file-does-not-exist',
220+ ):
221+ content_cache.configure_sysctl()
222+ with open('tests/unit/files/sysctl_core_somaxconn.conf', 'r') as f:
223+ want = f.read()
224+ with open(sysctl_conf_path, 'r') as f:
225+ got = f.read()
226+ self.assertEqual(got, want)
227+
228+ somaxconn_path = 'some-file-does-not-exist'
229+ with mock.patch.multiple(
230+ 'reactive.content_cache',
231+ SYSCTL_CONF_PATH=sysctl_conf_path,
232+ _SYSCTL_CORE_DEFAULT_QDISC=qdisc_path,
233+ _SYSCTL_CORE_SOMAXCONN=somaxconn_path,
234+ _SYSCTL_NETFILTER_CONNTRACK_MAX='some-file-does-not-exist',
235+ ):
236+ content_cache.configure_sysctl()
237+ with open('tests/unit/files/sysctl_core_default_somaxconn_none.conf', 'r') as f:
238+ want = f.read()
239+ with open(sysctl_conf_path, 'r') as f:
240+ got = f.read()
241+ self.assertEqual(got, want)
242+
243+ @mock.patch('charms.reactive.set_flag')
244+ @mock.patch('subprocess.call')
245+ @mock.patch('lib.utils.process_rlimits')
246+ @mock.patch('lib.utils.select_tcp_congestion_control')
247+ @mock.patch('lib.utils.tune_tcp_mem')
248 def test_configure_sysctl_nf_conntrack_max(self, tune_tcp_mem, tcp_cc, process_rlimits, call, set_flag):
249 sysctl_conf_path = os.path.join(self.tmpdir, '90-content-cache.conf')
250 self.mock_config.return_value = {
251@@ -1584,10 +1647,15 @@ site1.local:
252 # Use '/proc/uptime' for unit test as that will always exist.
253 conntrack_max_path = '/proc/uptime'
254
255+ somaxconn_path = os.path.join(self.tmpdir, 'somaxconn')
256+ with open(somaxconn_path, 'w', encoding='utf-8') as f:
257+ f.write('4096\n')
258+
259 with mock.patch.multiple(
260 'reactive.content_cache',
261 SYSCTL_CONF_PATH=sysctl_conf_path,
262 _SYSCTL_CORE_DEFAULT_QDISC='some-file-does-not-exist',
263+ _SYSCTL_CORE_SOMAXCONN=somaxconn_path,
264 _SYSCTL_NETFILTER_CONNTRACK_MAX=conntrack_max_path,
265 ):
266 content_cache.configure_sysctl()
267@@ -1605,6 +1673,7 @@ site1.local:
268 'reactive.content_cache',
269 SYSCTL_CONF_PATH=sysctl_conf_path,
270 _SYSCTL_CORE_DEFAULT_QDISC='some-file-does-not-exist',
271+ _SYSCTL_CORE_SOMAXCONN=somaxconn_path,
272 _SYSCTL_NETFILTER_CONNTRACK_MAX=conntrack_max_path,
273 ):
274 content_cache.configure_sysctl()
275@@ -1626,11 +1695,16 @@ site1.local:
276 process_rlimits.return_value = '1048777'
277 qdisc_path = 'some-file-does-not-exist'
278
279+ somaxconn_path = os.path.join(self.tmpdir, 'somaxconn')
280+ with open(somaxconn_path, 'w', encoding='utf-8') as f:
281+ f.write('4096\n')
282+
283 tcp_cc.return_value = 'bbr'
284 with mock.patch.multiple(
285 'reactive.content_cache',
286 SYSCTL_CONF_PATH=sysctl_conf_path,
287 _SYSCTL_CORE_DEFAULT_QDISC=qdisc_path,
288+ _SYSCTL_CORE_SOMAXCONN=somaxconn_path,
289 _SYSCTL_NETFILTER_CONNTRACK_MAX='some-file-does-not-exist',
290 ):
291 content_cache.configure_sysctl()
292@@ -1645,6 +1719,7 @@ site1.local:
293 'reactive.content_cache',
294 SYSCTL_CONF_PATH=sysctl_conf_path,
295 _SYSCTL_CORE_DEFAULT_QDISC=qdisc_path,
296+ _SYSCTL_CORE_SOMAXCONN=somaxconn_path,
297 _SYSCTL_NETFILTER_CONNTRACK_MAX='some-file-does-not-exist',
298 ):
299 content_cache.configure_sysctl()
300@@ -1659,6 +1734,7 @@ site1.local:
301 'reactive.content_cache',
302 SYSCTL_CONF_PATH=sysctl_conf_path,
303 _SYSCTL_CORE_DEFAULT_QDISC=qdisc_path,
304+ _SYSCTL_CORE_SOMAXCONN=somaxconn_path,
305 _SYSCTL_NETFILTER_CONNTRACK_MAX='some-file-does-not-exist',
306 ):
307 content_cache.configure_sysctl()
308@@ -1679,11 +1755,16 @@ site1.local:
309 tcp_cc.return_value = None
310 process_rlimits.return_value = '1048777'
311
312+ somaxconn_path = os.path.join(self.tmpdir, 'somaxconn')
313+ with open(somaxconn_path, 'w', encoding='utf-8') as f:
314+ f.write('4096\n')
315+
316 tune_tcp_mem.return_value = '188081 250774 376162'
317 with mock.patch.multiple(
318 'reactive.content_cache',
319 SYSCTL_CONF_PATH=sysctl_conf_path,
320 _SYSCTL_CORE_DEFAULT_QDISC='some-file-does-not-exist',
321+ _SYSCTL_CORE_SOMAXCONN=somaxconn_path,
322 _SYSCTL_NETFILTER_CONNTRACK_MAX='some-file-does-not-exist',
323 ):
324 content_cache.configure_sysctl()
325@@ -1698,6 +1779,7 @@ site1.local:
326 'reactive.content_cache',
327 SYSCTL_CONF_PATH=sysctl_conf_path,
328 _SYSCTL_CORE_DEFAULT_QDISC='some-file-does-not-exist',
329+ _SYSCTL_CORE_SOMAXCONN=somaxconn_path,
330 _SYSCTL_NETFILTER_CONNTRACK_MAX='some-file-does-not-exist',
331 ):
332 content_cache.configure_sysctl()
333diff --git a/wheelhouse.txt b/wheelhouse.txt
334index 5b23121..00f7c6d 100644
335--- a/wheelhouse.txt
336+++ b/wheelhouse.txt
337@@ -1,3 +1,5 @@
338+looseversion;python_version >= '3.12'
339+
340 # Include python requirements here
341 psutil<5.9.3;python_version < '3.8'
342 psutil;python_version >= '3.8'

Subscribers

People subscribed via source and target branches