Я сделал Внутренний распределенный сервер времени (без хозяев) для нашей будущей распределенной системы баз данных NoSQL. Он должен обрабатывать проблемы византийских часов и перекоса часов, пока 2/3 часов в распределенной системе являются правильными.
Однако я хотел бы увидеть, как кто-то еще реализовал этот вид шаблонов (не заинтересованный в реализациях шаблонов master / slave, таких как основанные на IEEE 1588) — предпочтительно некоторый открытый исходный код, который уже используется — чтобы утверждать, что я правильно его реализовал как это трудно написать модульные тесты для него.
Кто-нибудь знает о такой реализации с открытым исходным кодом? В языке программирования мы используем C ++, поэтому я бы предпочел ссылки на C / C ++, хотя это может быть не так уж важно, если код читается человеком.
Вот код (частично псевдокод для простоты) моей реализации:
/*!
\brief Maximum allowed clock skew in milliseconds
\details A network node that has a clock skew greater than this value will be ignore
* and an error message will be logged
\note Maximum divergence (drift) between two clocks on the network nodes will be 3x this amount if we
* have a worst case Byzantium clock issue
*/
#define MAX_ALLOWED_CLOCK_SCEW_MS 333
/*!
\class CTimeServer
\brief Internal distributed time server
\details The time server frequently recieves the time from all the other master server nodes
* in the DBMS and calculates the current time by averaging all of the recieves timestamps.
\note If a server node has a greater clock skew than \c MAX_ALLOWED_CLOCK_SCEW_MS then it its
* timestamp is ignored and an error message is logged
\note Clocks are accurately synchronized until more than 1/3 of the nodes have Byzantium clock issues
\author Inge Eivind Henriksen
\date February 2014
*/
class CTimeServer
{
private:
/** System offset in milliseconds */
std::atomic<int> offsetAverageMs;
/*!
\brief Node offsets type
\par key Node ID
\par value Offset in milliseconds
*/
typedef std::map<int, int> nodeOffset_t;
/*!
\brief Iterator type for \c nodeOffset_t
\relates nodeOffset_t
*/
typedef nodeOffset_t::iterator nodeOffsetIter_t;
/** Node offsets */
nodeOffset_t nodeOffsets;
/*!
\brief Calculates the offset time in milliseconds between all the nodes in the distributed system
*/
int CalculateOffsetMs() {
bool exists;
nodeOffsetIter_t offsets_iter(&nodeOffsets);
int offsetMs = offsets_iter.first(&exists);
int averageMs = 0;
while (exists)
{
averageMs += offsetMs;
averageMs /= 2;
// Get the next file manager in the map
offsetMs = offsets_iter.next(&exists);
}
return averageMs;
}
public:
CTimeServer() {
offsetAverageMs = 0;
}
/*!
\brief Register the time of a node
\param nodeHostName [in] Network node host name or IP address
\param nodeId [in] Network node ID
\param timestamp [in] Network node timestamp
*/
void RegisterNodeTime(const wchar_t *nodeHostName, int nodeId, time_t timestamp) {
int now = (int)time(NULL);
int offset = (int)timestamp - now;
// Make sure the node clock is within the permitted values
if (abs(offset) > MAX_ALLOWED_CLOCK_SCEW_MS)
{
// Node clock skew was outside the permitted limit, so remove it from the list of valid time offsets
nodeOffsets.erase(nodeId);
// Throw an error
std::wstringstream err;
err << L"Network node " << nodeHostName << L" exceeded the maximum allowed clock skew of "<< MAX_ALLOWED_CLOCK_SCEW_MS << L" ms by " << offset << " ms. Set the clock to correct this problem.";
throw err.str().c_str();
}
nodeOffsets.update(nodeId, offset);
// Recalculate the offset average
offsetAverageMs.store(CalculateOffsetMs());
}
/*!
\brief Get the distributed system time
\returns The distributed system time
*/
time_t GetTime() {
int now = (int)time(NULL);
return (time_t)(now + offsetAverageMs.load()));
}
Существует довольно много литературы по протоколам синхронизации времени, особенно для беспроводных сенсорных сетей, где среда развертывания не подходит для мастеров времени. Есть достойное введение в тему эта страница. Протокол, который, кажется, привлек наибольшее внимание, — это протокол синхронизации времени затопления (FTSP) от бумага под этим именем Мароти, Куси, Симона и Ледечи. Существует реализация, которую я нашел для TinyOS, описанной на его вики, который имеет вид кода, который вы ищете.
Есть предостережение относительно любой системы без хозяина: нет понятия «правильного» времени. Лучшее, что вы можете получить — это сходимость узлов к общему времени. Это время консенсуса, но его не следует считать авторитетно «правильным».
Других решений пока нет …