我为我们即将推出的分布式 NoSQL 数据库系统制作了一个内部分布式时间服务器(没有主服务器)。只要分布式系统中 2/3 的时钟是正确的,它就应该处理拜占庭时钟和时钟偏差问题。
不过,我想看看其他人是如何实现这种模式的(对基于 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()));
}
最佳答案
有大量关于时间同步协议(protocol)的文献,特别是对于无线传感器网络,其部署环境不适合时间掌握者。在 this page 上对该主题有一个不错的介绍。 .似乎最受关注的协议(protocol)是泛洪时间同步协议(protocol) (FTSP),来自 paper。 Maróti、Kusy、Simon 和 Lédeczi 以这个名字命名。我在其 wiki 上找到了一个针对 TinyOS 的实现。 ,其中包含您正在寻找的代码类型。
对于任何无主系统都有一个警告:没有“正确”时间的概念。您可以获得的最好结果是将节点收敛到一个公共(public)时间引用。这是一个共识时间,但不应被视为权威的“正确”时间。
关于c++ - 内部分布式时间服务器实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22065401/
我正在尝试使用ruby和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我
我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
最近,当我启动我的Rails服务器时,我收到了一长串警告。虽然它不影响我的应用程序,但我想知道如何解决这些警告。我的估计是imagemagick以某种方式被调用了两次?当我在警告前后检查我的git日志时。我想知道如何解决这个问题。-bcrypt-ruby(3.1.2)-better_errors(1.0.1)+bcrypt(3.1.7)+bcrypt-ruby(3.1.5)-bcrypt(>=3.1.3)+better_errors(1.1.0)bcrypt和imagemagick有关系吗?/Users/rbchris/.rbenv/versions/2.0.0-p247/lib/ru
在Rails4.0.2中,我使用s3_direct_upload和aws-sdkgems直接为s3存储桶上传文件。在开发环境中它工作正常,但在生产环境中它会抛出如下错误,ActionView::Template::Error(noimplicitconversionofnilintoString)在View中,create_cv_url,:id=>"s3_uploader",:key=>"cv_uploads/{unique_id}/${filename}",:key_starts_with=>"cv_uploads/",:callback_param=>"cv[direct_uplo
我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden
我需要检查DateTime是否采用有效的ISO8601格式。喜欢:#iso8601?我检查了ruby是否有特定方法,但没有找到。目前我正在使用date.iso8601==date来检查这个。有什么好的方法吗?编辑解释我的环境,并改变问题的范围。因此,我的项目将使用jsapiFullCalendar,这就是我需要iso8601字符串格式的原因。我想知道更好或正确的方法是什么,以正确的格式将日期保存在数据库中,或者让ActiveRecord完成它们的工作并在我需要时间信息时对其进行操作。 最佳答案 我不太明白你的问题。我假设您想检查
这个问题在这里已经有了答案:Railsformattingdate(4个答案)关闭4年前。我想格式化Time.Now函数以显示YYYY-MM-DDHH:MM:SS而不是:“2018-03-0909:47:19+0000”该函数需要放在时间中.现在功能。require‘roo’require‘roo-xls’require‘byebug’file_name=ARGV.first||“Template.xlsx”excel_file=Roo::Spreadsheet.open(“./#{file_name}“,extension::xlsx)xml=Nokogiri::XML::Build
我正在尝试解析一个CSV文件并使用SQL命令自动为其创建一个表。CSV中的第一行给出了列标题。但我需要推断每个列的类型。Ruby中是否有任何函数可以找到每个字段中内容的类型。例如,CSV行:"12012","Test","1233.22","12:21:22","10/10/2009"应该产生像这样的类型['integer','string','float','time','date']谢谢! 最佳答案 require'time'defto_something(str)if(num=Integer(str)rescueFloat(s
我想在Ruby中创建一个用于开发目的的极其简单的Web服务器(不,不想使用现成的解决方案)。代码如下:#!/usr/bin/rubyrequire'socket'server=TCPServer.new('127.0.0.1',8080)whileconnection=server.acceptheaders=[]length=0whileline=connection.getsheaders想法是从命令行运行这个脚本,提供另一个脚本,它将在其标准输入上获取请求,并在其标准输出上返回完整的响应。到目前为止一切顺利,但事实证明这真的很脆弱,因为它在第二个请求上中断并出现错误:/usr/b