Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

record文件中的时间戳可能是乱序的 #15615

Open
FlyingMusic opened this issue Dec 16, 2024 · 13 comments
Open

record文件中的时间戳可能是乱序的 #15615

FlyingMusic opened this issue Dec 16, 2024 · 13 comments

Comments

@FlyingMusic
Copy link

Describe the bug
当系统CPU资源紧张时,录制的record文件中的时间戳存在乱序可能

To Reproduce
Steps to reproduce the behavior:

Expected behavior
record文件中的数据保持时间顺序

Screenshots
利用python cyber_record读取某个record文件中的topic,打印其序列号录制时间,其中有一段是这样的:
seq: 49191, timestamp: 1733739177304346029
seq: 49194, timestamp: 1733739177598199183
seq: 49196, timestamp: 1733739177800743325
seq: 49197, timestamp: 1733739177929194262
seq: 49131, timestamp: 1733739171047058551 <- 开始出现乱序
seq: 49132, timestamp: 1733739171117104758
seq: 49133, timestamp: 1733739171234804341

Additional context
bug可能的原因
文件名:cyber/record/file/record_file_writer.cc
代码段:

bool RecordFileWriter::WriteMessage(const proto::SingleMessage& message) {
  chunk_active_->add(message);
  auto it = channel_message_number_map_.find(message.channel_name());
  if (it != channel_message_number_map_.end()) {
    it->second++;
  } else {
    channel_message_number_map_.insert(
        std::make_pair(message.channel_name(), 1));
  }
  bool need_flush = false;
  if (header_.chunk_interval() > 0 &&
      message.time() - chunk_active_->header_.begin_time() >
          header_.chunk_interval()) {
    need_flush = true;
  }
  if (!in_writing_ && header_.chunk_raw_size() > 0 &&
      chunk_active_->header_.raw_size() > header_.chunk_raw_size()) {
    need_flush = true;
  }
  if (!need_flush) {
    return true;
  }
  {
    std::unique_lock<std::mutex> flush_lock(flush_mutex_);
    chunk_flush_.swap(chunk_active_);  //这个Write线程notify_noe()后,下面的Flush线程不一定会获得执行机会(尤其当CPU紧张时),这种情况可能会持续到下一次Write线程写满chunk_active_,这个时候两个线程抢一把锁,属于未定义行为,如果还是Write线程抢到了CPU,会再进行一次swap,此后写入的数据就会追加到还没来得及落盘的chunk内,导致时间戳错乱;
//这个地方应该加一个判断chunk_flush_是否为空,只有为空是才进行swap,不知是否合适?
    flush_cv_.notify_one();
  }
  return true;
}

void RecordFileWriter::Flush() {
  while (is_writing_) {
    std::unique_lock<std::mutex> flush_lock(flush_mutex_);
    flush_cv_.wait(flush_lock,
                   [this] { return !chunk_flush_->empty() || !is_writing_; });
    if (!is_writing_) {
      break;
    }
    if (chunk_flush_->empty()) {
      continue;
    }
    in_writing_ = true;
    if (!WriteChunk(chunk_flush_->header_, *(chunk_flush_->body_.get()))) {
      AERROR << "Write chunk fail.";
    }
    in_writing_ = false;
    chunk_flush_->clear();
  }
}
@1012327963
Copy link

你那边有出现在10.0的时候会出现cyber_recorder record -a录不全的情况吗

@FlyingMusic
Copy link
Author

你那边有出现在10.0的时候会出现cyber_recorder record -a录不全的情况吗

偶尔有丢帧的情况,但录的topic是全的

@1012327963
Copy link

你那边有出现在10.0的时候会出现cyber_recorder记录-a记录不完整的情况吗?

偶尔会有丢帧的情况,但记录的主题是完整的

奇怪,我这边是topic是按照顺序的,但是数据会丢

@FlyingMusic
Copy link
Author

FlyingMusic commented Dec 16, 2024

你那边有出现在10.0的时候会出现cyber_recorder记录-a记录不完整的情况吗?

偶尔会有丢帧的情况,但记录的主题是完整的

奇怪,我这边是topic是按照顺序的,但是数据会丢

会丢啥意思?丢了某个topic?

@1012327963
Copy link

你那边有出现在10.0的时候会出现cyber_recorder记录-a记录不完整的情况吗?

有时会出现丢帧的情况,但记录的主题是完整的

奇怪,我的这篇文章的主题是按照顺序的,但是数据会丢失

会丢啥意思?丢了某个话题?

对的,某些话题没有办法正常录制下来

@FlyingMusic
Copy link
Author

你那边有出现在10.0的时候会出现cyber_recorder记录-a记录不完整的情况吗?

有时会出现丢帧的情况,但记录的主题是完整的

奇怪,我的这篇文章的主题是按照顺序的,但是数据会丢失

会丢啥意思?丢了某个话题?

对的,某些话题没有办法正常录制下来

奥 我也不是很懂,你可以看看cyber_monitor 能不能看到这些topic,确认是发出来了

@hearto1314
Copy link
Contributor

10.0 cyber_recorder 的使用问题我们尽快修复,修复完这个issue下面同步大家,谢谢。

@hearto1314
Copy link
Contributor

10.0 cyber_recorder的问题已经解决了,请大家pull最新代码编译使用。

@FlyingMusic 乱序的问题理论上不会发生,cyber_recorder 是双buffer写的机制,一个buffer没有flush完,另一个buffer如果满了会阻塞,可以使用最新版本试试。

@FlyingMusic
Copy link
Author

FlyingMusic commented Dec 19, 2024

10.0 cyber_recorder的问题已经解决了,请大家pull最新代码编译使用。

@FlyingMusic 乱序的问题理论上不会发生,cyber_recorder 是双buffer写的机制,一个buffer没有flush完,另一个buffer如果满了会阻塞,可以使用最新版本试试。

@hearto1314
你说的阻塞式等待 std::unique_lockstd::mutex flush_lock(flush_mutex_);这个锁吗,这个时候可能Flush线程也在等这个锁,两个线程谁抢到锁是不一定的,如果还是WriteMessage这个线程抢到了,不就会连续两次swap吗?
我们用的代码都是record/下的,这部分已经好几个月没动了,新版本应该没啥改变

@FlyingMusic
Copy link
Author

FlyingMusic commented Dec 19, 2024

我的描述可能有误,Flush线程不是也在等这个锁;
因为它在wait时是解开锁等的,极限条件下,Flush可能永远也得不到CPU,所以连尝试获取锁的机会都没有,而WriteMessage可能一直获取到CPU,也能获取锁,从而连续进行swap @hearto1314

@hearto1314
Copy link
Contributor

10.0里面加了一个in_writing开关优化可能存在录制数据丢失的问题,我们平时确实没遇到乱序的情况。
进程没有设置nice值,cpu调度理论上不会存在一个进程一直获取不到cpu而另一个能一直获取。

@FlyingMusic
Copy link
Author

10.0里面加了一个in_writing开关优化可能存在录制数据丢失的问题,我们平时确实没遇到乱序的情况。 进程没有设置nice值,cpu调度理论上不会存在一个进程一直获取不到cpu而另一个能一直获取。

是的,这就是个概率问题,我们是自己缓存一段数据,然后快速频繁调用WriteMessage,所以出现的概率比较大,但也不是必现的,如果是cyber_recorder录数据,是不会出现的,因为调用WriteMessage的频率没那么高,Flush大概率是可以执行到的

@FlyingMusic
Copy link
Author

这就是个生产者消费者模式嘛,生产-消费的过程并不能保证是严格交替执行的,但是现在由于生产者速度比较慢(有个缓存数据的时间),所以大多数情况都是交替执行的,我们的应用场景也是比较苛刻,所以计划先本地改了,你们再帮忙再评估下看看有没有修改的必要吧 @hearto1314

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants