From 454cff587ed10b5e504da93b074b77cb85055b13 Mon Sep 17 00:00:00 2001 From: Tom Weininger Date: Thu, 18 Aug 2022 10:54:45 +0200 Subject: [PATCH] Optimize HAProxy SSL cache size If a HTTPS termination listener exists, set the tune.ssl.cachesize setting to use about half of the available memory (free + buffers + cached) on the amphora minus the memory needed for network sockets based on the global max connections setting. A larger SSL cache allows for more resumed SSL sessions and therefore less computationally expensive SSL handshakes. Change-Id: I87efba18017aa3e8b9b3cc812664efc11af1c4c4 --- .../haproxy/combined_listeners/jinja_cfg.py | 22 +++++++++++++++++++ .../combined_listeners/templates/base.j2 | 3 +++ .../tweak-ssl-cachesize-6893851feed43975.yaml | 9 ++++++++ 3 files changed, 34 insertions(+) create mode 100644 releasenotes/notes/tweak-ssl-cachesize-6893851feed43975.yaml diff --git a/octavia/common/jinja/haproxy/combined_listeners/jinja_cfg.py b/octavia/common/jinja/haproxy/combined_listeners/jinja_cfg.py index 6bfb764ea3..094ea900fb 100644 --- a/octavia/common/jinja/haproxy/combined_listeners/jinja_cfg.py +++ b/octavia/common/jinja/haproxy/combined_listeners/jinja_cfg.py @@ -187,6 +187,9 @@ class JinjaTemplater(object): constants.INSECURE_FORK) enable_prometheus = prometheus_listener and feature_compatibility.get( lib_consts.PROTOCOL_PROMETHEUS, False) + term_https_listener = any( + lsnr.protocol == lib_consts.PROTOCOL_TERMINATED_HTTPS for lsnr in + listeners) jinja_dict = { 'loadbalancer': loadbalancer, @@ -209,6 +212,25 @@ class JinjaTemplater(object): except (KeyError, TypeError): pass + if term_https_listener: + try: + mem = amp_details["memory"] + # Account for 32 KB per established connection for each + # pair of HAProxy network sockets. Use 1024 as fallback + # because that is what ulimit -n typically returns. + max_conn_mem_kb = 32 * loadbalancer.get( + "global_connection_limit", 1024) + # Use half of the remaining memory for SSL caches + ssl_cache_mem_kb = (mem["free"] + mem["buffers"] + + mem["cached"] - max_conn_mem_kb) // 2 + # A cache block uses about 200 bytes of data. + # The HAProxy default of ssl_cache (20000) would take up + # 4000 KB. We don't want to go below that. + if ssl_cache_mem_kb > 4000: + jinja_dict["ssl_cache"] = ssl_cache_mem_kb * 5 + except (KeyError, TypeError): + pass + return self._get_template().render( jinja_dict, constants=constants, lib_consts=lib_consts) diff --git a/octavia/common/jinja/haproxy/combined_listeners/templates/base.j2 b/octavia/common/jinja/haproxy/combined_listeners/templates/base.j2 index 8caec84103..e5090e1e22 100644 --- a/octavia/common/jinja/haproxy/combined_listeners/templates/base.j2 +++ b/octavia/common/jinja/haproxy/combined_listeners/templates/base.j2 @@ -26,6 +26,9 @@ global {% if loadbalancer.global_connection_limit is defined %} maxconn {{ loadbalancer.global_connection_limit }} {% endif %} + {% if ssl_cache is defined %} + tune.ssl.cachesize {{ ssl_cache }} + {% endif %} {%- if cpu_count is defined and cpu_count > 1 %} nbthread {{ cpu_count - 1 }} cpu-map auto:1/1-{{ cpu_count - 1 }} 1-{{ cpu_count - 1 }} diff --git a/releasenotes/notes/tweak-ssl-cachesize-6893851feed43975.yaml b/releasenotes/notes/tweak-ssl-cachesize-6893851feed43975.yaml new file mode 100644 index 0000000000..373befe0ac --- /dev/null +++ b/releasenotes/notes/tweak-ssl-cachesize-6893851feed43975.yaml @@ -0,0 +1,9 @@ +--- +other: + - | + When a HTTPS termination listener gets configured, Octavia will tweak the + HAProxy `tune.ssl.cachesize` setting to use about half of the available + memory (free + buffers + cached) on the amphora minus the memory needed + for network sockets based on the global max connections setting. + This allows to make better reuse of existing SSL sessions and + helps to lower the number of computationally expensive SSL handshakes.