Set DB max_overflow to match thread pool size

Set max_overflow config option of database to match the number of
workers that can be spawned simultaneously. The maximum number of RPC
workers that can be spawned is determined by executor_thread_pool_size
config option.

This ensures there won't be lack of DB sessions when many worker
threads/eventlets are spawned when the engine is under load.

The DB connections that are part of overflow bucket are closed
automatically when they are not in use, so heat doesn't run out of
'lsof' limit.

Closes-Bug: #1491185
Change-Id: I4fcfe50b53b4d476f7483bb860667c42d0c54a19
This commit is contained in:
Anant Patil 2015-12-30 09:51:39 +05:30
parent f03483c582
commit d7c2de60cb
2 changed files with 44 additions and 0 deletions

View File

@ -370,6 +370,7 @@ class EngineService(service.Service):
self._client = rpc_messaging.get_rpc_client(
version=self.RPC_API_VERSION)
self._configure_db_conn_pool_size()
self.service_manage_cleanup()
self.manage_thread_grp = threadgroup.ThreadGroup()
self.manage_thread_grp.add_timer(cfg.CONF.periodic_interval,
@ -378,6 +379,18 @@ class EngineService(service.Service):
super(EngineService, self).start()
def _configure_db_conn_pool_size(self):
# bug #1491185
# Set the DB max_overflow to match the thread pool size.
# The overflow connections are automatically closed when they are
# not used; setting it is better than setting DB max_pool_size.
worker_pool_size = cfg.CONF.executor_thread_pool_size
# Update max_overflow only if it is not adequate
if ((cfg.CONF.database.max_overflow is None) or
(cfg.CONF.database.max_overflow < worker_pool_size)):
cfg.CONF.set_override('max_overflow', worker_pool_size,
group='database')
def _stop_rpc_server(self):
# Stop rpc connection at first for preventing new requests
LOG.debug("Attempting to stop engine service...")

View File

@ -230,8 +230,10 @@ class ServiceEngineTest(common.HeatTestCase):
return_value=mock.Mock())
@mock.patch('oslo_service.threadgroup.ThreadGroup',
return_value=mock.Mock())
@mock.patch.object(service.EngineService, '_configure_db_conn_pool_size')
def test_engine_service_start_in_non_convergence_mode(
self,
configure_db_conn_pool_size,
thread_group_class,
engine_listener_class,
thread_group_manager_class,
@ -267,8 +269,10 @@ class ServiceEngineTest(common.HeatTestCase):
return_value=mock.Mock())
@mock.patch('oslo_service.threadgroup.ThreadGroup',
return_value=mock.Mock())
@mock.patch.object(service.EngineService, '_configure_db_conn_pool_size')
def test_engine_service_start_in_convergence_mode(
self,
configure_db_conn_pool_size,
thread_group_class,
worker_service_class,
engine_listener_class,
@ -380,3 +384,30 @@ class ServiceEngineTest(common.HeatTestCase):
def test_engine_service_reset(self, setup_logging_mock):
self.eng.reset()
setup_logging_mock.assert_called_once_with(cfg.CONF, 'heat')
@mock.patch('oslo_messaging.Target',
return_value=mock.Mock())
@mock.patch('heat.common.messaging.get_rpc_client',
return_value=mock.Mock())
@mock.patch('heat.engine.stack_lock.StackLock.generate_engine_id',
return_value=mock.Mock())
@mock.patch('heat.engine.service.ThreadGroupManager',
return_value=mock.Mock())
@mock.patch('heat.engine.service.EngineListener',
return_value=mock.Mock())
@mock.patch('heat.engine.worker.WorkerService',
return_value=mock.Mock())
@mock.patch('oslo_service.threadgroup.ThreadGroup',
return_value=mock.Mock())
def test_engine_service_configures_connection_pool(
self,
thread_group_class,
worker_service_class,
engine_listener_class,
thread_group_manager_class,
sample_uuid_method,
rpc_client_class,
target_class):
self.eng.start()
self.assertEqual(cfg.CONF.executor_thread_pool_size,
cfg.CONF.database.max_overflow)