Merge lp:~hloeung/ubuntu-repository-cache/auto-apache2-mpm-tuning into lp:ubuntu-repository-cache

Proposed by Haw Loeung
Status: Merged
Approved by: Haw Loeung
Approved revision: 296
Merged at revision: 289
Proposed branch: lp:~hloeung/ubuntu-repository-cache/auto-apache2-mpm-tuning
Merge into: lp:ubuntu-repository-cache
Diff against target: 303 lines (+200/-18)
5 files modified
config.yaml (+15/-15)
lib/ubuntu_repository_cache/apache.py (+40/-0)
lib/ubuntu_repository_cache/tests/test_apache.py (+141/-0)
templates/apache2/mpm_worker.template (+3/-2)
tox.ini (+1/-1)
To merge this branch: bzr merge lp:~hloeung/ubuntu-repository-cache/auto-apache2-mpm-tuning
Reviewer Review Type Date Requested Status
Stuart Bishop (community) Approve
Barry Price Approve
Review via email: mp+392920@code.launchpad.net

Commit message

Automatically calculate MPM worker tuning configs

Description of the change

Currently, these are the flavors/instance types generally used:

GCE - https://cloud.google.com/compute/docs/machine-types#n1_machine_types
n1-standard-16 = 16 vCPUs, 60GiB RAM

AWS - https://aws.amazon.com/ec2/instance-types/#Compute_Optimized
c5.xlarge = 4 vCPUs, 8GiB RAM
c3.4xlarge = 16 vCPUs, 30GiB RAM
c4.8xlarge = 36 vCPUs, 60GiB RAM

Azure - https://docs.microsoft.com/en-us/azure/virtual-machines/dv2-dsv2-series
Standard_D2_v2 = 2 vCPUs, 7GiB RAM
Standard_D3_v2 = 4 vCPUs, 14GiB RAM

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.

296. By Haw Loeung

Fixed comments

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

LGTM +1

review: Approve
Revision history for this message
Stuart Bishop (stub) wrote :

This all looks great

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

Change successfully merged at revision 289

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'config.yaml'
--- config.yaml 2020-09-30 04:32:54 +0000
+++ config.yaml 2020-11-02 03:11:48 +0000
@@ -111,37 +111,37 @@
111 description: Select the worker or prefork multi-processing module111 description: Select the worker or prefork multi-processing module
112 apache2_mpm_startservers:112 apache2_mpm_startservers:
113 type: int113 type: int
114 default: 2114 default: 0
115 description: Initial number of server processes to start115 description: Initial number of server processes to start (0 means auto calculate)
116 apache2_mpm_minsparethreads:116 apache2_mpm_minsparethreads:
117 type: int117 type: int
118 default: 100118 default: 0
119 description: Minimum number of worker threads which are kept spare119 description: Minimum number of worker threads which are kept spare (0 means auto calculate)
120 apache2_mpm_maxsparethreads:120 apache2_mpm_maxsparethreads:
121 type: int121 type: int
122 default: 200122 default: 0
123 description: Maximum number of worker threads which are kept spare123 description: Maximum number of worker threads which are kept spare (0 means auto calculate)
124 apache2_mpm_threadlimit:124 apache2_mpm_threadlimit:
125 type: int125 type: int
126 default: 64126 default: 0
127 description: |127 description: |
128 Sets the upper limit on the configurable number of threads per128 Sets the upper limit on the configurable number of threads per
129 child process129 child process (0 means autocalculate)
130 apache2_mpm_threadsperchild:130 apache2_mpm_threadsperchild:
131 type: int131 type: int
132 default: 64132 default: 0
133 description: Constant number of worker threads in each server process133 description: Constant number of worker threads in each server process (0 means autocalculate)
134 apache2_mpm_serverlimit:134 apache2_mpm_serverlimit:
135 type: int135 type: int
136 default: 256136 default: 0
137 description: Upper limit on configurable number of processes137 description: Upper limit on configurable number of processes (0 means autocalculate)
138 apache2_mpm_maxrequestworkers:138 apache2_mpm_maxrequestworkers:
139 type: int139 type: int
140 default: 16384140 default: 0
141 description: Maximum number of simultaneous client connections141 description: Maximum number of simultaneous client connections (0 means autocalculate)
142 apache2_mpm_maxconnectionsperchild:142 apache2_mpm_maxconnectionsperchild:
143 type: int143 type: int
144 default: 0144 default: 10000
145 description: Maximum number of requests a server process serves145 description: Maximum number of requests a server process serves
146 logrotate_rotate:146 logrotate_rotate:
147 type: string147 type: string
148148
=== modified file 'lib/ubuntu_repository_cache/apache.py'
--- lib/ubuntu_repository_cache/apache.py 2020-10-06 10:04:18 +0000
+++ lib/ubuntu_repository_cache/apache.py 2020-11-02 03:11:48 +0000
@@ -1,5 +1,6 @@
1'''Functions related to apache use within this charm'''1'''Functions related to apache use within this charm'''
22
3import multiprocessing
3import os4import os
4import subprocess5import subprocess
5import json6import json
@@ -71,6 +72,44 @@
71 return host.service_running(SERVICE)72 return host.service_running(SERVICE)
7273
7374
75def tune_mpm_configs(config):
76 cpu_count = multiprocessing.cpu_count()
77
78 if not config['startservers']:
79 config['startservers'] = 1
80
81 if not config['serverlimit']:
82 # Benchmarking shows single process multiple threads performs better
83 # than multiple processes multiple threads.
84 config['serverlimit'] = 1
85
86 if not config['threadsperchild']:
87 # We could take into consideration how much memory the system
88 # has but the ratio of vCPU to RAM between public clouds seems
89 # good enough so this is not needed.
90 config['threadsperchild'] = 256 * cpu_count
91 # Cap at 8192
92 if config['threadsperchild'] > 8192:
93 config['threadsperchild'] = 8192
94
95 if not config['threadlimit']:
96 # Hard limit should match per child limit.
97 config['threadlimit'] = config['threadsperchild']
98
99 if not config['maxrequestworkers']:
100 # Calculate max. workers based on serverlimit and threadsperchild.
101 config['maxrequestworkers'] = config['serverlimit'] * config['threadsperchild']
102
103 if not config['minsparethreads']:
104 # Use 50% of max. workers.
105 config['minsparethreads'] = int(config['maxrequestworkers'] * 0.5)
106
107 if not config['maxsparethreads']:
108 config['maxsparethreads'] = config['maxrequestworkers']
109
110 return config
111
112
74def create_mpm_workerfile():113def create_mpm_workerfile():
75 '''Create the multi-processing module (MPM) configuration'''114 '''Create the multi-processing module (MPM) configuration'''
76115
@@ -85,6 +124,7 @@
85 'maxrequestworkers': config['apache2_mpm_maxrequestworkers'],124 'maxrequestworkers': config['apache2_mpm_maxrequestworkers'],
86 'maxconnectionsperchild': config['apache2_mpm_maxconnectionsperchild'],125 'maxconnectionsperchild': config['apache2_mpm_maxconnectionsperchild'],
87 }126 }
127 mpm_context = tune_mpm_configs(mpm_context)
88 conf_mpm_worker = '/etc/apache2/conf-available/000mpm-worker.conf'128 conf_mpm_worker = '/etc/apache2/conf-available/000mpm-worker.conf'
89 templating.render('apache2/mpm_worker.template', conf_mpm_worker, mpm_context)129 templating.render('apache2/mpm_worker.template', conf_mpm_worker, mpm_context)
90 subprocess.check_call(['a2enconf', '000mpm-worker'])130 subprocess.check_call(['a2enconf', '000mpm-worker'])
91131
=== added file 'lib/ubuntu_repository_cache/tests/test_apache.py'
--- lib/ubuntu_repository_cache/tests/test_apache.py 1970-01-01 00:00:00 +0000
+++ lib/ubuntu_repository_cache/tests/test_apache.py 2020-11-02 03:11:48 +0000
@@ -0,0 +1,141 @@
1import os
2import shutil
3import tempfile
4import unittest
5from unittest import mock
6
7from .. import apache
8
9from charmhelpers.core import unitdata
10
11
12class ApacheTestCase(unittest.TestCase):
13 def setUp(self):
14 self.maxDiff = None
15 patcher = mock.patch('charmhelpers.core.hookenv.config')
16 self.mock_config = patcher.start()
17 self.addCleanup(patcher.stop)
18
19 self.tmpdir = tempfile.mkdtemp(prefix='charm-unittests-')
20 self.addCleanup(shutil.rmtree, self.tmpdir)
21 os.environ['UNIT_STATE_DB'] = os.path.join(self.tmpdir, '.unit-state.db')
22 unitdata.kv().set('squid-cache-disk', 5000)
23 unitdata.kv().set('squid-disk-caches', [('/srv', 2000)])
24
25 @mock.patch('multiprocessing.cpu_count')
26 def test_tune_mpm_configs(self, cpu_count):
27
28 cpu_count.return_value = 4
29 config = {
30 'startservers': 0,
31 'minsparethreads': 0,
32 'maxsparethreads': 0,
33 'threadlimit': 0,
34 'threadsperchild': 0,
35 'serverlimit': 0,
36 'maxrequestworkers': 0,
37 'maxconnectionsperchild': 10000,
38 }
39 expected = {
40 'startservers': 1,
41 'minsparethreads': 512,
42 'maxsparethreads': 1024,
43 'threadlimit': 1024,
44 'threadsperchild': 1024,
45 'serverlimit': 1,
46 'maxrequestworkers': 1024,
47 'maxconnectionsperchild': 10000,
48 }
49 self.assertEqual(apache.tune_mpm_configs(config), expected)
50
51 cpu_count.return_value = 40
52 config = {
53 'startservers': 0,
54 'minsparethreads': 0,
55 'maxsparethreads': 0,
56 'threadlimit': 0,
57 'threadsperchild': 0,
58 'serverlimit': 0,
59 'maxrequestworkers': 0,
60 'maxconnectionsperchild': 10000,
61 }
62 expected = {
63 'startservers': 1,
64 'minsparethreads': 4096,
65 'maxsparethreads': 8192,
66 'threadlimit': 8192,
67 'threadsperchild': 8192,
68 'serverlimit': 1,
69 'maxrequestworkers': 8192,
70 'maxconnectionsperchild': 10000,
71 }
72 self.assertEqual(apache.tune_mpm_configs(config), expected)
73
74 cpu_count.return_value = 1
75 config = {
76 'startservers': 0,
77 'minsparethreads': 0,
78 'maxsparethreads': 0,
79 'threadlimit': 0,
80 'threadsperchild': 0,
81 'serverlimit': 0,
82 'maxrequestworkers': 0,
83 'maxconnectionsperchild': 10000,
84 }
85 expected = {
86 'startservers': 1,
87 'minsparethreads': 128,
88 'maxsparethreads': 256,
89 'threadlimit': 256,
90 'threadsperchild': 256,
91 'serverlimit': 1,
92 'maxrequestworkers': 256,
93 'maxconnectionsperchild': 10000,
94 }
95 self.assertEqual(apache.tune_mpm_configs(config), expected)
96
97 cpu_count.return_value = 2
98 config = {
99 'startservers': 0,
100 'minsparethreads': 0,
101 'maxsparethreads': 0,
102 'threadlimit': 0,
103 'threadsperchild': 0,
104 'serverlimit': 0,
105 'maxrequestworkers': 0,
106 'maxconnectionsperchild': 10000,
107 }
108 expected = {
109 'startservers': 1,
110 'minsparethreads': 256,
111 'maxsparethreads': 512,
112 'threadlimit': 512,
113 'threadsperchild': 512,
114 'serverlimit': 1,
115 'maxrequestworkers': 512,
116 'maxconnectionsperchild': 10000,
117 }
118 self.assertEqual(apache.tune_mpm_configs(config), expected)
119
120 cpu_count.return_value = 4
121 config = {
122 'startservers': 5,
123 'minsparethreads': 10,
124 'maxsparethreads': 100,
125 'threadlimit': 32,
126 'threadsperchild': 32,
127 'serverlimit': 10,
128 'maxrequestworkers': 8192,
129 'maxconnectionsperchild': 5000,
130 }
131 expected = {
132 'startservers': 5,
133 'minsparethreads': 10,
134 'maxsparethreads': 100,
135 'threadlimit': 32,
136 'threadsperchild': 32,
137 'serverlimit': 10,
138 'maxrequestworkers': 8192,
139 'maxconnectionsperchild': 5000,
140 }
141 self.assertEqual(apache.tune_mpm_configs(config), expected)
0142
=== modified file 'templates/apache2/mpm_worker.template'
--- templates/apache2/mpm_worker.template 2015-02-12 00:05:14 +0000
+++ templates/apache2/mpm_worker.template 2020-11-02 03:11:48 +0000
@@ -1,5 +1,5 @@
1#1#
2# JUJU WARNING: This file is managed by Juju, do NOT edit 2# JUJU WARNING: This file is managed by Juju, do NOT edit
3#3#
44
5# worker MPM5# worker MPM
@@ -12,10 +12,11 @@
12<IfModule mpm_worker_module>12<IfModule mpm_worker_module>
13 StartServers {{ startservers }}13 StartServers {{ startservers }}
14 MinSpareThreads {{ minsparethreads }}14 MinSpareThreads {{ minsparethreads }}
15 MaxSpareThreads {{ maxsparethreads }} 15 MaxSpareThreads {{ maxsparethreads }}
16 ThreadLimit {{ threadlimit }}16 ThreadLimit {{ threadlimit }}
17 ThreadsPerChild {{ threadsperchild }}17 ThreadsPerChild {{ threadsperchild }}
18 ServerLimit {{ serverlimit }}18 ServerLimit {{ serverlimit }}
19 MaxRequestWorkers {{ maxrequestworkers }}19 MaxRequestWorkers {{ maxrequestworkers }}
20 MaxConnectionsPerChild {{ maxconnectionsperchild }}20 MaxConnectionsPerChild {{ maxconnectionsperchild }}
21</IfModule>21</IfModule>
22
2223
=== modified file 'tox.ini'
--- tox.ini 2020-08-11 04:12:28 +0000
+++ tox.ini 2020-11-02 03:11:48 +0000
@@ -10,7 +10,7 @@
10[testenv:unit]10[testenv:unit]
11commands =11commands =
12 pytest --ignore {toxinidir}/tests/functional \12 pytest --ignore {toxinidir}/tests/functional \
13 {posargs:-v --cov=lib --cov=reactive --cov=actions --cov-report=term-missing --cov-branch}13 {posargs:-v --cov=lib --cov=reactive --cov-report=term-missing --cov-branch}
14deps = -r{toxinidir}/tests/unit/requirements.txt14deps = -r{toxinidir}/tests/unit/requirements.txt
15 -r{toxinidir}/requirements.txt15 -r{toxinidir}/requirements.txt
16setenv =16setenv =

Subscribers

People subscribed via source and target branches