2

背景

我正在使用 Apache 的 NMS 库与 ActiveMq 交谈。每条发送的消息都由生产者标记时间戳,我通过从 中减去时间戳来查看消息延迟DateTime.UtcNow,我希望看到 0-100 毫秒的延迟,但我看到报告的延迟在 -1000 到 1000 毫秒之间。显然负延迟是没有意义的,所以我最初怀疑系统时钟不同步,但我现在已经独立确认它们是正确的并且在 20 毫秒内。

更多背景

使用系统时钟测量广播消息延迟,好主意吗?

问题

我现在认为这些差异可能是由于 .Net 和 Java 之间处理日期的方式造成的。

  • 从 Java 到 .Net 的转换是有损的吗?
  • 这些转换能否解释我观察到的较大的负时间跨度?
  • 还有什么可以解释时差的吗?

MessageProducer.cs -- 生产者设置 NMSTimestamp

activeMessage.NMSTimestamp = DateTime.UtcNow;

ActiveMqMessage.cs -- NMSTimestamp 转换为 Java 时间并存储在 Message

...
public DateTime NMSTimestamp
{
    get { return DateUtils.ToDateTime(Timestamp); }
    set
    {
        Timestamp = DateUtils.ToJavaTimeUtc(value);
        if(timeToLive.TotalMilliseconds > 0)
        {
            Expiration = Timestamp + (long) timeToLive.TotalMilliseconds;
        }
    }
}
...

Message.cs -- Timestamp 保存有线格式的日期,消息编组器直接设置此值

// ActiveMqMessage extends Message
...
public long Timestamp
{
   get { return timestamp; }
   set { this.timestamp = value; }
}
...

DateUtils.cs -- 用于执行转换

namespace Apache.NMS.Util
{
    public class DateUtils
    {
        /// <summary>
        /// The start of the Windows epoch
        /// </summary>
        public static readonly DateTime windowsEpoch = new DateTime(1601, 1, 1, 0, 0, 0, 0);
        /// <summary>
        /// The start of the Java epoch
        /// </summary>
        public static readonly DateTime javaEpoch = new DateTime(1970, 1, 1, 0, 0, 0, 0);
        
        /// <summary>
        /// The difference between the Windows epoch and the Java epoch
        /// in milliseconds.
        /// </summary>
        public static readonly long epochDiff; /* = 1164447360000L; */

        static DateUtils()
        {
            epochDiff = (javaEpoch.ToFileTimeUtc() - windowsEpoch.ToFileTimeUtc())
                            / TimeSpan.TicksPerMillisecond;
        }

        public static long ToJavaTime(DateTime dateTime)
        {
            return (dateTime.ToFileTime() / TimeSpan.TicksPerMillisecond) - epochDiff;
        }

        public static DateTime ToDateTime(long javaTime)
        {
            return DateTime.FromFileTime((javaTime + epochDiff) * TimeSpan.TicksPerMillisecond);
        }

        public static long ToJavaTimeUtc(DateTime dateTime)
        {
            return (dateTime.ToFileTimeUtc() / TimeSpan.TicksPerMillisecond) - epochDiff;
        }

        public static DateTime ToDateTimeUtc(long javaTime)
        {
            return DateTime.FromFileTimeUtc((javaTime + epochDiff) * TimeSpan.TicksPerMillisecond);
        }
    }
}

我的代码计算延迟如下

var latency = (DateTime.UtcNow - msg.NMSTimestamp).TotalMilliseconds;
4

1 回答 1

3

是的,与 Java 时间的转换是有损的。这是因为 Java 时间不如 Windows 时间精确。与不同时间格式的转换保证精确到毫秒而不会丢失。但是,更精确的 Windows Ticks 将会丢失。

NMS DateTime 实用程序转换功能正常工作。您遇到的错误来自您的延迟计算代码。您正在使用var类型,这就是您的错误所在。TotalMilliseconds返回一个精度值,这将产生一个舍入错误。解决方法是将值截断为整毫秒,而不是部分毫秒,因为如上所述这是有损的。尝试使用以下具有long强类型的代码来计算延迟:

long latency = System.Math.floor((DateTime.UtcNow - msg.NMSTimestamp).TotalMilliseconds);
于 2011-11-02T17:22:56.870 回答