2012-11-02 20:13:41 +00:00
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
#include <Poco/Net/NetException.h>
|
2013-12-10 17:07:09 +00:00
|
|
|
|
#include <Poco/Net/DNS.h>
|
2012-11-02 20:13:41 +00:00
|
|
|
|
|
2014-06-03 14:32:04 +00:00
|
|
|
|
#include <statdaemons/PoolWithFailoverBase.h>
|
|
|
|
|
|
2012-11-02 20:13:41 +00:00
|
|
|
|
#include <DB/Client/ConnectionPool.h>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
/** Пул соединений с отказоустойчивостью.
|
|
|
|
|
* Инициализируется несколькими другими IConnectionPool-ами.
|
|
|
|
|
* При получении соединения, пытается создать или выбрать живое соединение из какого-нибудь пула,
|
|
|
|
|
* перебирая их в некотором порядке, используя не более указанного количества попыток.
|
|
|
|
|
* Предпочитаются пулы с меньшим количеством ошибок;
|
|
|
|
|
* пулы с одинаковым количеством ошибок пробуются в случайном порядке.
|
|
|
|
|
*
|
|
|
|
|
* Замечание: если один из вложенных пулов заблокируется из-за переполнения, то этот пул тоже заблокируется.
|
|
|
|
|
*/
|
2014-12-30 14:11:02 +00:00
|
|
|
|
class ConnectionPoolWithFailover : public PoolWithFailoverBase<IConnectionPool, Settings *>, public IConnectionPool
|
2012-11-02 20:13:41 +00:00
|
|
|
|
{
|
|
|
|
|
public:
|
2014-06-03 14:32:04 +00:00
|
|
|
|
typedef IConnectionPool::Entry Entry;
|
2014-12-30 14:11:02 +00:00
|
|
|
|
typedef PoolWithFailoverBase<IConnectionPool, Settings *> Base;
|
2012-11-02 20:13:41 +00:00
|
|
|
|
|
2013-12-11 11:51:01 +00:00
|
|
|
|
ConnectionPoolWithFailover(ConnectionPools & nested_pools_,
|
2014-02-17 23:56:45 +00:00
|
|
|
|
LoadBalancing load_balancing,
|
|
|
|
|
size_t max_tries_ = DBMS_CONNECTION_POOL_WITH_FAILOVER_DEFAULT_MAX_TRIES,
|
2014-04-06 23:15:27 +00:00
|
|
|
|
time_t decrease_error_period_ = DBMS_CONNECTION_POOL_WITH_FAILOVER_DEFAULT_DECREASE_ERROR_PERIOD)
|
2014-06-03 14:32:04 +00:00
|
|
|
|
: Base(nested_pools_, max_tries_, decrease_error_period_,
|
|
|
|
|
&Logger::get("ConnectionPoolWithFailover")), default_load_balancing(load_balancing)
|
2012-11-02 20:13:41 +00:00
|
|
|
|
{
|
2014-06-03 14:32:04 +00:00
|
|
|
|
std::string local_hostname = Poco::Net::DNS::hostName();
|
2012-11-02 20:13:41 +00:00
|
|
|
|
|
2014-06-03 14:32:04 +00:00
|
|
|
|
hostname_differences.resize(nested_pools.size());
|
|
|
|
|
for (size_t i = 0; i < nested_pools.size(); ++i)
|
2012-11-06 18:20:00 +00:00
|
|
|
|
{
|
2014-06-03 14:32:04 +00:00
|
|
|
|
ConnectionPool & connection_pool = dynamic_cast<ConnectionPool &>(*nested_pools[i].pool);
|
2013-12-10 17:07:09 +00:00
|
|
|
|
const std::string & host = connection_pool.getHost();
|
2014-06-03 14:32:04 +00:00
|
|
|
|
|
|
|
|
|
size_t hostname_difference = 0;
|
2013-12-10 17:07:09 +00:00
|
|
|
|
for (size_t i = 0; i < std::min(local_hostname.length(), host.length()); ++i)
|
|
|
|
|
if (local_hostname[i] != host[i])
|
|
|
|
|
++hostname_difference;
|
2014-04-06 23:15:27 +00:00
|
|
|
|
|
2014-06-03 14:32:04 +00:00
|
|
|
|
hostname_differences[i] = hostname_difference;
|
2012-11-06 18:20:00 +00:00
|
|
|
|
}
|
2014-06-03 14:32:04 +00:00
|
|
|
|
}
|
2012-11-02 20:13:41 +00:00
|
|
|
|
|
2014-06-03 14:32:04 +00:00
|
|
|
|
/** Выделяет соединение для работы. */
|
|
|
|
|
Entry get(Settings * settings = nullptr) override
|
|
|
|
|
{
|
2014-12-30 14:11:02 +00:00
|
|
|
|
applyLoadBalancing(settings);
|
2014-06-03 14:32:04 +00:00
|
|
|
|
return Base::get(settings);
|
|
|
|
|
}
|
2014-04-06 23:15:27 +00:00
|
|
|
|
|
2015-01-29 14:22:15 +00:00
|
|
|
|
/** Выделяет до указанного количества соединений для работы.
|
2015-01-12 12:08:11 +00:00
|
|
|
|
* Соединения предоставляют доступ к разным репликам одного шарда.
|
|
|
|
|
*/
|
|
|
|
|
std::vector<Entry> getMany(Settings * settings = nullptr) override
|
2014-12-30 14:11:02 +00:00
|
|
|
|
{
|
|
|
|
|
applyLoadBalancing(settings);
|
2015-01-12 12:08:11 +00:00
|
|
|
|
return Base::getMany(settings);
|
2014-12-30 14:11:02 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-06-03 14:32:04 +00:00
|
|
|
|
protected:
|
|
|
|
|
bool tryGet(ConnectionPoolPtr pool, Settings * settings, Entry & out_entry, std::stringstream & fail_message) override
|
2013-12-10 17:07:09 +00:00
|
|
|
|
{
|
2014-06-03 14:32:04 +00:00
|
|
|
|
try
|
2013-12-10 17:07:09 +00:00
|
|
|
|
{
|
2014-06-03 14:32:04 +00:00
|
|
|
|
out_entry = pool->get(settings);
|
|
|
|
|
out_entry->forceConnected();
|
|
|
|
|
return true;
|
2013-12-10 17:07:09 +00:00
|
|
|
|
}
|
2014-06-03 14:32:04 +00:00
|
|
|
|
catch (const Exception & e)
|
2013-12-10 17:07:09 +00:00
|
|
|
|
{
|
2014-06-03 14:32:04 +00:00
|
|
|
|
if (e.code() != ErrorCodes::NETWORK_ERROR && e.code() != ErrorCodes::SOCKET_TIMEOUT)
|
|
|
|
|
throw;
|
2013-12-10 17:07:09 +00:00
|
|
|
|
|
2014-06-03 14:32:04 +00:00
|
|
|
|
fail_message << "Code: " << e.code() << ", e.displayText() = " << e.displayText() << ", e.what() = " << e.what();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-11-02 20:13:41 +00:00
|
|
|
|
|
2014-06-03 14:32:04 +00:00
|
|
|
|
private:
|
|
|
|
|
std::vector<size_t> hostname_differences; /// Расстояния от имени этого хоста до имен хостов пулов.
|
2014-02-17 23:56:45 +00:00
|
|
|
|
LoadBalancing default_load_balancing;
|
2014-12-30 14:11:02 +00:00
|
|
|
|
|
|
|
|
|
void applyLoadBalancing(Settings * settings)
|
|
|
|
|
{
|
|
|
|
|
LoadBalancing load_balancing = default_load_balancing;
|
|
|
|
|
if (settings)
|
|
|
|
|
load_balancing = settings->load_balancing;
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < nested_pools.size(); ++i)
|
|
|
|
|
{
|
|
|
|
|
if (load_balancing == LoadBalancing::NEAREST_HOSTNAME)
|
|
|
|
|
nested_pools[i].priority = hostname_differences[i];
|
|
|
|
|
else if (load_balancing == LoadBalancing::RANDOM)
|
|
|
|
|
nested_pools[i].priority = 0;
|
|
|
|
|
else if (load_balancing == LoadBalancing::IN_ORDER)
|
|
|
|
|
nested_pools[i].priority = i;
|
|
|
|
|
else
|
|
|
|
|
throw Exception("Unknown load_balancing_mode: " + toString(static_cast<int>(load_balancing)), ErrorCodes::LOGICAL_ERROR);
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-11-02 20:13:41 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|