Skip to content

Commit 3aca8bb

Browse files
authored
Allow opting out of new routing algorithm via a flag (#2590)
* env var based routing selection * add a flag for using old routing * move oldRouting into pool context from group * fix tests
1 parent bf08ffa commit 3aca8bb

34 files changed

+260
-19
lines changed

CHANGELOG

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ Release 6.0.25 (Not yet released)
44
* [Standalone] Adds a config option to specify the stop timeout for Passenger: `--stop-timeout 120` or `PASSENGER_STOP_TIMEOUT=120`.
55
* [Standalone] Changes Passenger's (not apps') start timeout to 25s (from 15s), stop timeouts default to 60s.
66
* [Ruby] Fixes an issue where Bundler would try to re-exec the process name instead of the script. Closes GH-2567 and GH-2577.
7+
* [Enterprise] Adds a temporary flag to allow reverting to previous routing behaviour, in order to mitigate possible performance regressions, this flag will become a no-op and eventually removed once the routing issues have been fixed. Closes GH-2579.
8+
- Apache: PassengerOldRouting on
9+
- Nginx: passenger_old_routing on;
10+
- Standalone: --old-routing
711
* Updated various library versions used in precompiled binaries (used for e.g. gem installs):
812
- cmake: 3.31.2 -> 3.31.3
913
- curl: 8.11.0 -> 8.11.1

dev/configkit-schemas/index.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,12 @@
302302
"read_only" : true,
303303
"type" : "boolean"
304304
},
305+
"old_routing" : {
306+
"default_value" : false,
307+
"has_default_value" : "static",
308+
"read_only" : true,
309+
"type" : "boolean"
310+
},
305311
"request_freelist_limit" : {
306312
"default_value" : 1024,
307313
"has_default_value" : "static",
@@ -806,6 +812,12 @@
806812
"read_only" : true,
807813
"type" : "boolean"
808814
},
815+
"old_routing" : {
816+
"default_value" : false,
817+
"has_default_value" : "static",
818+
"read_only" : true,
819+
"type" : "boolean"
820+
},
809821
"oom_score" : {
810822
"read_only" : true,
811823
"type" : "string"
@@ -1690,6 +1702,12 @@
16901702
"read_only" : true,
16911703
"type" : "boolean"
16921704
},
1705+
"old_routing" : {
1706+
"default_value" : false,
1707+
"has_default_value" : "static",
1708+
"read_only" : true,
1709+
"type" : "boolean"
1710+
},
16931711
"passenger_root" : {
16941712
"read_only" : true,
16951713
"required" : true,

resources/templates/standalone/http.erb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ passenger_user_switching off;
3232
<%= nginx_http_option(:pool_idle_time) %>
3333
<%= nginx_http_option(:max_preloader_idle_time) %>
3434
<%= nginx_http_option(:turbocaching) %>
35+
<%= nginx_http_option(:old_routing) %>
3536
<%= nginx_http_option(:instance_registry_dir) %>
3637
<%= nginx_http_option(:spawn_dir) %>
3738
<%= nginx_http_option(:disable_security_update_check) %>

src/agent/Core/ApplicationPool/Context.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,16 +61,19 @@ struct Context {
6161
boost::object_pool<Process> processObjectPool;
6262
mutable boost::mutex agentConfigSyncher;
6363

64+
// Whether to use the old routing algorithm
65+
bool oldRouting;
6466

6567
/****** Dependencies ******/
6668

6769
SpawningKit::FactoryPtr spawningKitFactory;
6870
Json::Value agentConfig;
6971

7072

71-
Context()
73+
Context(bool _oldRouting)
7274
: sessionObjectPool(64, 1024),
73-
processObjectPool(4, 64)
75+
processObjectPool(4, 64),
76+
oldRouting(_oldRouting)
7477
{ }
7578

7679
void finalize() {

src/agent/Core/ApplicationPool/Group.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,6 @@
2727
#define _PASSENGER_APPLICATION_POOL2_GROUP_H_
2828

2929
#include <string>
30-
#include <map>
31-
#include <queue>
3230
#include <deque>
3331
#include <boost/thread.hpp>
3432
#include <boost/bind/bind.hpp>
@@ -202,7 +200,6 @@ class Group: public boost::enable_shared_from_this<Group> {
202200
Callback shutdownCallback;
203201
GroupPtr selfPointer;
204202

205-
206203
/****** Initialization and shutdown ******/
207204

208205
static ApiKey generateApiKey(const Pool *pool);
@@ -233,9 +230,13 @@ class Group: public boost::enable_shared_from_this<Group> {
233230
/****** Process list management ******/
234231

235232
Process *findProcessWithStickySessionId(unsigned int id) const;
233+
Process *findProcessWithStickySessionIdOrLowestBusyness(unsigned int id) const;
234+
Process *findProcessWithLowestBusyness(const ProcessList &processes) const;
235+
Process *findEnabledProcessWithLowestBusyness() const;
236236
Process *findBestProcessPreferringStickySessionId(unsigned int id) const;
237237
Process *findBestProcess(const ProcessList &processes) const;
238238
Process *findBestEnabledProcess() const;
239+
bool useNewRouting() const;
239240

240241
void addProcessToList(const ProcessPtr &process, ProcessList &destination);
241242
void removeProcessFromList(const ProcessPtr &process, ProcessList &source);

src/agent/Core/ApplicationPool/Group/ProcessListManagement.cpp

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,73 @@ Group::findProcessWithStickySessionId(unsigned int id) const {
6363
return NULL;
6464
}
6565

66+
Process *
67+
Group::findProcessWithStickySessionIdOrLowestBusyness(unsigned int id) const {
68+
int leastBusyProcessIndex = -1;
69+
int lowestBusyness = 0;
70+
unsigned int i, size = enabledProcessBusynessLevels.size();
71+
const int *enabledProcessBusynessLevels = &this->enabledProcessBusynessLevels[0];
72+
for (i = 0; i < size; i++) {
73+
Process *process = enabledProcesses[i].get();
74+
if (process->getStickySessionId() == id) {
75+
return process;
76+
} else if (leastBusyProcessIndex == -1 || enabledProcessBusynessLevels[i] < lowestBusyness) {
77+
leastBusyProcessIndex = i;
78+
lowestBusyness = enabledProcessBusynessLevels[i];
79+
}
80+
}
81+
82+
if (leastBusyProcessIndex == -1) {
83+
return NULL;
84+
} else {
85+
return enabledProcesses[leastBusyProcessIndex].get();
86+
}
87+
}
88+
89+
Process *
90+
Group::findProcessWithLowestBusyness(const ProcessList &processes) const {
91+
if (processes.empty()) {
92+
return NULL;
93+
}
94+
95+
int lowestBusyness = -1;
96+
Process *leastBusyProcess = NULL;
97+
ProcessList::const_iterator it;
98+
ProcessList::const_iterator end = processes.end();
99+
for (it = processes.begin(); it != end; it++) {
100+
Process *process = (*it).get();
101+
int busyness = process->busyness();
102+
if (lowestBusyness == -1 || lowestBusyness > busyness) {
103+
lowestBusyness = busyness;
104+
leastBusyProcess = process;
105+
}
106+
}
107+
return leastBusyProcess;
108+
}
109+
110+
/**
111+
* Cache-optimized version of findProcessWithLowestBusyness() for the common case.
112+
*/
113+
Process *
114+
Group::findEnabledProcessWithLowestBusyness() const {
115+
if (enabledProcesses.empty()) {
116+
return NULL;
117+
}
118+
119+
int leastBusyProcessIndex = -1;
120+
int lowestBusyness = 0;
121+
unsigned int i, size = enabledProcessBusynessLevels.size();
122+
const int *enabledProcessBusynessLevels = &this->enabledProcessBusynessLevels[0];
123+
124+
for (i = 0; i < size; i++) {
125+
if (leastBusyProcessIndex == -1 || enabledProcessBusynessLevels[i] < lowestBusyness) {
126+
leastBusyProcessIndex = i;
127+
lowestBusyness = enabledProcessBusynessLevels[i];
128+
}
129+
}
130+
return enabledProcesses[leastBusyProcessIndex].get();
131+
}
132+
66133
/**
67134
* Return the process with the given sticky session ID if it exists.
68135
* If not, then find the "best" enabled process to route a request to,

src/agent/Core/ApplicationPool/Group/SessionManagement.cpp

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
#include <Core/ApplicationPool/Pool.h>
3131
#endif
3232
#include <Core/ApplicationPool/Group.h>
33-
#include <cassert>
3433

3534
/*************************************************************************
3635
*
@@ -63,18 +62,26 @@ using namespace boost;
6362
*/
6463
Group::RouteResult
6564
Group::route(const Options &options) const {
65+
Process *process = nullptr;
6666
if (OXT_LIKELY(enabledCount > 0)) {
6767
if (options.stickySessionId == 0) {
68-
Process *process = findBestProcess(enabledProcesses);
68+
if (OXT_LIKELY(useNewRouting())) {
69+
process = findBestProcess(enabledProcesses);
70+
} else {
71+
process = findEnabledProcessWithLowestBusyness();
72+
}
6973
if (process != nullptr) {
7074
assert(process->canBeRoutedTo());
7175
return RouteResult(process);
7276
} else {
7377
return RouteResult(NULL, true);
7478
}
7579
} else {
76-
Process *process = findBestProcessPreferringStickySessionId(
77-
options.stickySessionId);
80+
if (OXT_LIKELY(useNewRouting())) {
81+
process = findBestProcessPreferringStickySessionId(options.stickySessionId);
82+
}else{
83+
process = findProcessWithStickySessionIdOrLowestBusyness(options.stickySessionId);
84+
}
7885
if (process != nullptr) {
7986
if (process->canBeRoutedTo()) {
8087
return RouteResult(process);
@@ -86,7 +93,11 @@ Group::route(const Options &options) const {
8693
}
8794
}
8895
} else {
89-
Process *process = findBestProcess(disablingProcesses);
96+
if (OXT_LIKELY(useNewRouting())) {
97+
process = findBestProcess(disablingProcesses);
98+
} else {
99+
process = findProcessWithLowestBusyness(disablingProcesses);
100+
}
90101
if (process != nullptr) {
91102
assert(process->canBeRoutedTo());
92103
return RouteResult(process);
@@ -313,7 +324,12 @@ Group::get(const Options &newOptions, const GetCallback &callback,
313324
assert(m_spawning || restarting() || poolAtFullCapacity());
314325

315326
if (disablingCount > 0 && !restarting()) {
316-
Process *process = findBestProcess(disablingProcesses);
327+
Process *process = nullptr;
328+
if (OXT_LIKELY(useNewRouting())) {
329+
process = findBestProcess(disablingProcesses);
330+
} else {
331+
process = findProcessWithLowestBusyness(disablingProcesses);
332+
}
317333
if (process != nullptr && !process->isTotallyBusy()) {
318334
return newSession(process, newOptions.currentTime);
319335
}
@@ -341,6 +357,10 @@ Group::get(const Options &newOptions, const GetCallback &callback,
341357
}
342358
}
343359

360+
bool
361+
Group::useNewRouting() const {
362+
return !pool->context->oldRouting;
363+
}
344364

345365
} // namespace ApplicationPool2
346366
} // namespace Passenger

src/agent/Core/ApplicationPool/Options.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828

2929
#include <string>
3030
#include <vector>
31-
#include <utility>
3231
#include <boost/shared_array.hpp>
3332
#include <WrapperRegistry/Registry.h>
3433
#include <DataStructures/HashedStaticString.h>
@@ -79,7 +78,7 @@ class Options {
7978
template<typename OptionsClass, typename StaticStringClass>
8079
static vector<StaticStringClass *> getStringFields(OptionsClass &options) {
8180
vector<StaticStringClass *> result;
82-
result.reserve(20);
81+
result.reserve(30);
8382

8483
result.push_back(&options.appRoot);
8584
result.push_back(&options.appGroupName);

src/agent/Core/Config.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ using namespace std;
155155
* max_instances_per_app unsigned integer - read_only
156156
* max_pool_size unsigned integer - default(6)
157157
* multi_app boolean - default(false),read_only
158+
* old_routing boolean - default(false),read_only
158159
* oom_score string - read_only
159160
* passenger_root string required read_only
160161
* pid_file string - read_only

src/agent/Core/Controller/Config.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ parseControllerBenchmarkMode(const StaticString &mode) {
115115
* max_instances_per_app unsigned integer - read_only
116116
* min_spare_clients unsigned integer - default(0)
117117
* multi_app boolean - default(true),read_only
118+
* old_routing boolean - default(false),read_only
118119
* request_freelist_limit unsigned integer - default(1024)
119120
* response_buffer_high_watermark unsigned integer - default(134217728)
120121
* server_software string - default("Phusion_Passenger/6.0.25")
@@ -138,6 +139,7 @@ class ControllerSchema: public ServerKit::HttpServerSchema {
138139
add("thread_number", UINT_TYPE, REQUIRED | READ_ONLY);
139140
add("multi_app", BOOL_TYPE, OPTIONAL | READ_ONLY, true);
140141
add("turbocaching", BOOL_TYPE, OPTIONAL | READ_ONLY, true);
142+
add("old_routing", BOOL_TYPE, OPTIONAL | READ_ONLY, false);
141143
add("integration_mode", STRING_TYPE, OPTIONAL | READ_ONLY, DEFAULT_INTEGRATION_MODE);
142144

143145
add("user_switching", BOOL_TYPE, OPTIONAL, true);
@@ -349,6 +351,7 @@ class ControllerMainConfig {
349351
bool userSwitching: 1;
350352
bool defaultStickySessions: 1;
351353
bool gracefulExit: 1;
354+
bool oldRouting: 1;
352355

353356
/*******************/
354357
/*******************/
@@ -366,7 +369,8 @@ class ControllerMainConfig {
366369
singleAppMode(!config["multi_app"].asBool()),
367370
userSwitching(config["user_switching"].asBool()),
368371
defaultStickySessions(config["default_sticky_sessions"].asBool()),
369-
gracefulExit(config["graceful_exit"].asBool())
372+
gracefulExit(config["graceful_exit"].asBool()),
373+
oldRouting(config["old_routing"].asBool())
370374

371375
/*******************/
372376
{
@@ -396,6 +400,7 @@ class ControllerMainConfig {
396400
SWAP_BITFIELD(bool, userSwitching);
397401
SWAP_BITFIELD(bool, defaultStickySessions);
398402
SWAP_BITFIELD(bool, gracefulExit);
403+
SWAP_BITFIELD(bool, oldRouting);
399404

400405
/*******************/
401406

0 commit comments

Comments
 (0)