mirror of
https://github.com/joyieldInc/predixy.git
synced 2025-12-24 22:46:41 +08:00
305 lines
7.6 KiB
C++
305 lines
7.6 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();
|
|
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) {//dc maybe nullptr even we 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;
|
|
}
|
|
}
|
|
}
|