predixy/src/ServerGroup.cpp

308 lines
7.7 KiB
C++

/*
* predixy - A high performance and full features proxy for redis.
* Copyright (C) 2017 Joyield, Inc. <joyield.com@gmail.com>
* All rights reserved.
*/
#include <algorithm>
#include "DC.h"
#include "Proxy.h"
#include "ServerPool.h"
#include "ServerGroup.h"
ServerGroup::ServerGroup(ServerPool* pool, const String& name):
mPool(pool),
mName(name)
{
mServs.reserve(Const::MaxServInGroup);
}
ServerGroup::~ServerGroup()
{
}
Server* ServerGroup::getMaster() const
{
FuncCallTimer();
int cnt = mServs.size();
for (int i = 0; i < cnt; ++i) {
Server* s = mServs[i];
if (!s->online()) {
continue;
}
if (s->role() == Server::Master) {
return s;
}
}
return nullptr;
}
struct ServCond
{
Server* serv = nullptr;
int priority = 0;
};
Server* ServerGroup::getServer(Handler* h, Request* req) const
{
FuncCallTimer();
Server* serv = nullptr;
if (req->requireWrite()) {
int cnt = mServs.size();
for (int i = 0; i < cnt; ++i) {
Server* s = mServs[i];
if (!s->online()) {
continue;
}
if (s->role() == Server::Master) {
serv = s;
break;
}
}
} else if (auto dataCenter = mPool->proxy()->dataCenter()) {
serv = getReadServer(h, dataCenter->localDC());
} else {
serv = getReadServer(h);
}
logDebug("server group %s for req %ld get server %s",
mName.data(), req->id(), (serv ? serv->addr().data() : "None"));
return serv;
}
Server* ServerGroup::getReadServer(Handler* h) const
{
FuncCallTimer();
Server* servs[Const::MaxServInGroup];
Server* deadServs[Const::MaxServInGroup];
int n = 0;
int dn = 0;
int prior = 0;
int dprior = 0;
int pendRequests = INT_MAX;
int cnt = mServs.size();
for (int i = 0; i < cnt; ++i) {
Server* s = mServs[i];
if (!s->online()) {
continue;
}
int rp = 0;
if (s->role() == Server::Master) {
rp = mPool->masterReadPriority();
} else if (s->role() == Server::Slave) {
rp = s->isStatic() ? mPool->staticSlaveReadPriority() : mPool->dynamicSlaveReadPriority();
}
if (rp <= 0) {
continue;
}
if (s->fail()) {
if (rp > dprior) {
dprior = rp;
deadServs[0] = s;
dn = 1;
} else if (rp == dprior) {
deadServs[dn++] = s;
}
} else {
if (rp > prior) {
prior = rp;
pendRequests = h->getPendRequests(s);
servs[0] = s;
n = 1;
} else if (rp == prior) {
int preqs = h->getPendRequests(s);
if (preqs < pendRequests) {
pendRequests = preqs;
servs[0] = s;
n = 1;
} else if (preqs == pendRequests) {
servs[n++] = s;
}
}
}
}
Server** ss = nullptr;
if (n > 0) {
ss = servs;
} else if (dn > 0) {
ss = deadServs;
n = dn;
} else {
return nullptr;
}
n = h->rand() % n;
return ss[n];
}
Server* ServerGroup::getReadServer(Handler* h, DC* localDC) const
{
FuncCallTimer();
Server* servs[Const::MaxServInGroup];
int sprior[Const::MaxServInGroup];
int pendRequests[Const::MaxServInGroup];
int num = 0;
DC* dcs[Const::MaxServInGroup];
DC* deadDCs[Const::MaxServInGroup];
int n = 0;
int dn = 0;
int prior = 0;
int dprior = 0;
int cnt = mServs.size();
for (int i = 0; i < cnt; ++i) {
Server* s = mServs[i];
if (!s->online()) {
continue;
}
int rp = 0;
if (s->role() == Server::Master) {
rp = mPool->masterReadPriority();
} else if (s->role() == Server::Slave) {
rp = s->isStatic() ? mPool->staticSlaveReadPriority() : mPool->dynamicSlaveReadPriority();
}
if (rp <= 0) {
continue;
}
DC* dc = s->dc();
if (!dc) {
continue;
}
int dcrp = localDC->getReadPriority(dc);
if (dcrp <= 0) {
continue;
}
servs[num] = s;
sprior[num] = rp;
pendRequests[num++] = h->getPendRequests(s);
if (s->fail()) {
if (dcrp > dprior) {
dprior = dcrp;
deadDCs[0] = dc;
dn = 1;
} else if (dcrp == dprior) {
deadDCs[dn++] = dc;
}
} else {
if (dcrp > prior) {
prior = dcrp;
dcs[0] = dc;
n = 1;
} else if (dcrp == prior) {
dcs[n++] = dc;
}
}
}
DC** sdc = nullptr;
if (n > 0) {
sdc = dcs;
} else if (dn > 0) {
sdc = deadDCs;
n = dn;
} else {
return nullptr;
}
bool found = false;
DC* dc = nullptr;
if (n > 1) {
int m = h->idUnique().unique(sdc, n);
int weights[Const::MaxServInGroup];
int w = 0;
n = 0;
for (int i = 0; i < m; ++i) {
int dw = localDC->getReadWeight(sdc[i]);
if (dw > 0) {
w += dw;
sdc[n] = sdc[i];
weights[n++] = w;
}
}
if (w > 0) {
w = h->rand() % w;
int i = std::lower_bound(weights, weights + n, w) - weights;
dc = sdc[i];
found = true;
}
} else if (localDC->getReadWeight(sdc[0]) > 0) {
dc = sdc[0];
found = true;
}
if (!found) {
return nullptr;
}
Server* deadServs[Const::MaxServInGroup];
n = 0;
dn = 0;
prior = 0;
dprior = 0;
int preqs = INT_MAX;
for (int i = 0; i < num; ++i) {
Server* s = servs[i];
if (servs[i]->dc() != dc) {
continue;
}
if (s->fail()) {
if (sprior[i] > dprior) {
dprior = sprior[i];
deadServs[0] = s;
dn = 1;
} else if (sprior[i] == dprior) {
deadServs[dn++] = s;
}
} else {
if (sprior[i] > prior) {
prior = sprior[i];
preqs = pendRequests[i];
servs[0] = s;
n = 1;
} else if (sprior[i] == prior) {
if (pendRequests[i] < preqs) {
preqs = pendRequests[i];
servs[0] = s;
n = 1;
} else if (pendRequests[i] == preqs) {
servs[n++] = s;
}
}
}
}
Server** ss = nullptr;
if (n > 0) {
ss = servs;
} else if (dn > 0) {
ss = deadServs;
n = dn;
} else {
return nullptr;
}
n = h->rand() % n;
return ss[n];
}
/***************************************************
* other thread may read ServerGroup when add or remoev,
* but we don't use lock
*
*
**************************************************/
void ServerGroup::add(Server* s)
{
if (mServs.size() == mServs.capacity()) {
return;
}
for (unsigned i = 0; i < mServs.size(); ++i) {
if (mServs[i] == s) {
return;
}
}
mServs.push_back(s);
}
void ServerGroup::remove(Server* s)
{
for (unsigned i = 0; i < mServs.size(); ++i) {
if (mServs[i] == s) {
mServs[i] = mServs.back();
mServs.resize(mServs.size() - 1);
return;
}
}
}