毕业设计中使用了有时间戳来标记流量数据包以及后续数据包的时间戳偏移, 但是秒级别的计数, 根本无法描述相邻数据包之间的时延, 时间单位至少应该为毫秒.

原始问题

我们通常所说的时间戳, 是指1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数. 是以秒为计数单位的.

在我们原始的数据结构中, 也采用了原始的32位整数作为时间戳, 但是用秒的话根本无法满足需求.

可能的方案

考虑过之后, 有以下两种方案:

  • 再来32位, 表示毫秒.
  • 将原始的方案中时间戳的含义更改, 使其表示从一个特定时间开始经过的总毫秒.

第一种方案, 需要修改原先的数据结构了, 向其中增加4个byte, 虽然我们目前的程序 不是针对嵌入式的设备, 但是需要克勤克俭用CPU缓存, 具体的数据结构这里不进行列出. 根据我们目前的定义情况, 假如每个对象增加了4个字节, 原始的128byte的CPU缓存就不够 存放了, 会造成性能下降.

第二种方案, 程序级别重新定义时间戳的含义, 假如之后的用户不了解程序设计, 很有 很有可能会对时间戳进行误用. 而且, 从特定时间开始, 到底是什么时间开始, 特定时间 开始后, 一个32位的时间戳又能表示多久呢. 我们都知道原始的32位时间戳只能表示到 2037年, 我们自定义的时间戳能达到怎样的效果.

这里我进行了简单计算, int能表示20亿的数目.

我们首先计算他能表示多少天,

$$ \frac{2 \times 10^{9} ms }{24 \times 3600 \times 1000} = 23天 $$

粗略的计算表明, 如果使用ms表示时间戳, 最多也就只能表示23天, 如果你使用unsigned int 那么翻倍也就是46天, 这样的结果有点太少了, 完全达不到我们的要求.

最终方案

使用32位时间戳表示当天偏移的毫秒数, 再加一个字段保存日期. 但这个字段不放在程序的内存中, 而是放置在数据库中.

采用这个方案的原因有以下两点:

  1. 32位的时间戳已经足够表示1天内偏移的毫秒数.
  2. 整个系统的实时性很强, 误差也不会超过10s, 存入数据库时, 将数据库当天的日期作为 日志日期写入到字段中, 这样, 可以保证我们在搜索时获得正确的时间戳, 也不需要考虑 空间占用问题, 并且, 这个新增的日期字段可以作为索引来使用.

日期字段可以通过MySQL的trigger进行设置.

1
2
3
4
CREATE TRIGGER `fdate_set` BEFORE INSERT ON `tbl_trace_data`
FOR EACH ROW BEGIN
SET NEW.fdate = CAST( DATE_FORMAT(NOW(),'%Y%m%d') AS UNSIGNED);
END

不过这样存储会有一个问题:

如果出现了快到第二天0点时存入了数据, 而设置日期时已经到了第二天 例如: 2018-03-22 23:59:55 时准备存入数据库, 之后数据库中的fdate被设置为了2018-03-23, 这是一种不匹配,

有这么一种解决方式: 可以通过判断时间戳的偏移, 如果偏移过大, 则认为它是 第一天的数据, 也就是03-22的数据. 上面只是列了最简单的Trigger设置.