MXS-1777 Tune code for cases with slow, or new servers.

Changes that allow slow or new servers to quickly apply samples towards the
server average. The most important changes are to not ignore the first N samples,
and apply an average to the server as soon as there is one available.
The new ResponseStat::make_valid() will use filter samples to add an average,
if no averages have yet been added, even if the number of  filter samples is less
than the filter limit.
This commit is contained in:
Niclas Antti
2018-09-06 08:39:11 +03:00
parent 0e5d827f7a
commit fa7ec95069
5 changed files with 41 additions and 23 deletions

View File

@ -16,10 +16,11 @@
namespace maxscale
{
ResponseStat::ResponseStat(int ignore_first_n, int num_filter_samples,
maxbase::Duration sync_duration) :
m_ignore_first_n{ignore_first_n},
m_num_filter_samples {num_filter_samples},
ResponseStat::ResponseStat(int num_filter_samples,
int num_synch_medians,
maxbase::Duration sync_duration)
: m_num_filter_samples {num_filter_samples},
m_num_synch_medians{num_synch_medians},
m_sync_duration{sync_duration},
m_sample_count{0},
m_samples(num_filter_samples),
@ -30,11 +31,6 @@ ResponseStat::ResponseStat(int ignore_first_n, int num_filter_samples,
void ResponseStat::query_started()
{
if (m_ignore_first_n)
{
--m_ignore_first_n;
return;
}
m_last_start = maxbase::Clock::now();
}
@ -57,6 +53,18 @@ void ResponseStat::query_ended()
m_last_start = maxbase::TimePoint();
}
bool ResponseStat::make_valid()
{
if (!m_average.num_samples() && m_sample_count)
{
maxbase::Duration new_sample = m_samples[m_sample_count / 2];
m_average.add(std::chrono::duration<double>(new_sample).count());
m_sample_count = 0;
}
return is_valid();
}
bool ResponseStat::is_valid() const
{
return m_average.num_samples();
@ -72,10 +80,12 @@ maxbase::Duration ResponseStat::average() const
return maxbase::Duration(m_average.average());
}
bool ResponseStat::sync_time_reached(int num_synch_medians)
bool ResponseStat::sync_time_reached()
{
auto now = maxbase::Clock::now();
bool reached = m_next_sync < now || m_average.num_samples() >= num_synch_medians;
bool reached = m_next_sync < now
|| m_average.num_samples() >= m_num_synch_medians;
if (reached)
{
m_next_sync = now + m_sync_duration;

View File

@ -32,24 +32,26 @@ namespace maxscale
class ResponseStat
{
public:
/* @param ignore_first_n - the first few queries tend to have more overhead
* @param n_filter_samples - collect num samples, use median
* @param num_synch_samples - this many medians before the average should be synced, or
* @param sync_duration - this much time between syncs.
/*
* @param num_filter_samples - collect num samples, use median
* @param num_synch_medians - this many medians before the average should be synced, or
* @param sync_duration - this much time between syncs.
*/
ResponseStat(int ignore_first_n = 5,
int num_filter_samples = 3,
ResponseStat(int num_filter_samples = 5,
int num_synch_medians = 500,
maxbase::Duration sync_duration = std::chrono::seconds(5));
void query_started();
void query_ended();// ok to call without a query_started
bool make_valid(); // make valid even if there are too few filter_samples
bool is_valid() const;
int num_samples() const;
maxbase::Duration average() const;
bool sync_time_reached(int num_synch_medians); // is it time to apply the average?
bool sync_time_reached(); // is it time to apply the average?
void reset();
private:
int m_ignore_first_n;
const int m_num_filter_samples;
const int m_num_synch_medians;
const maxbase::Duration m_sync_duration;
int m_sample_count;
std::vector<maxbase::Duration> m_samples; // N sampels from which median is used

View File

@ -100,8 +100,9 @@ void RWSplitSession::close()
for (auto& backend : m_backends)
{
const ResponseStat& stat = backend->response_stat();
if (stat.is_valid())
ResponseStat& stat = backend->response_stat();
if (stat.make_valid())
{
server_add_response_average(backend->server(),
stat.average().secs(), stat.num_samples());
@ -628,7 +629,8 @@ void RWSplitSession::clientReply(GWBUF *writebuf, DCB *backend_dcb)
ResponseStat& stat = backend->response_stat();
stat.query_ended();
if (stat.is_valid() && stat.sync_time_reached(500)) // nantti, TODO
if (stat.is_valid() && (stat.sync_time_reached() ||
backend->server()->response_time->num_samples()==0))
{
server_add_response_average(backend->server(),
stat.average().secs(), stat.num_samples());