You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

并发fwrite写入WekaFS时read读取全0异常问题排查

实时读写WekaFS文件时读取缓冲区全0的问题分析与解决

问题描述

我有两个进程:一个通过fwrite循环写入文件,另一个通过read循环实时读取该文件。读取进程使用O_DIRECT标志打开文件,偶尔会出现read()返回正的读取字节数,但缓冲区内容全为0x00的情况,重试读取后即可恢复正常。文件存储在WekaFS网络文件系统上,读取操作在写入进程持续写入时实时进行。

读取进程代码如下:

#include <iostream>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

int main() {
    const char* filename = "<my file>";
    
    // Open the file for reading
    int fd = open(filename, O_DIRECT | O_RDONLY);
    if (fd < 0) {
        perror("Failed to open file for reading");
        return 1;
    }

    size_t sz = 40000;
    char *read_data;
    if (posix_memalign((void**)&read_data, 512, sz) != 0) {
        perror("Failed to allocate aligned memory");
        return 1;
    }

    bool loop = true;
    size_t total_bytes = 0;

    while (loop) {
        ssize_t bytes_read = read(fd, read_data, sz);
        if (bytes_read < 0) {
            perror("Failed to read from file");
            break;
        } else if (bytes_read == 0) {
            std::cout << "End of file reached." << std::endl;
            break;
        } else {
            total_bytes += bytes_read;
            std::cout << "Read " << bytes_read << " bytes, total so far: " << total_bytes << std::endl;
        }
    }

    // Clean up
    free(read_data);
    close(fd);

    return 0;
}

问题原因分析

这个问题和网络文件系统的一致性机制、读写同步缺失都有关系:

  1. O_DIRECT的特性与WekaFS的延迟同步:O_DIRECT绕过了操作系统页缓存,直接和存储设备交互。但WekaFS作为分布式文件系统,写入进程的fwrite返回后,数据可能还在同步到存储节点的过程中,此时用O_DIRECT读取会拿到未填充数据的块(默认用0填充),重试时数据已完成同步,就能读到正确内容。
  2. 无同步的异步读写:当前读写进程没有任何同步机制,写入操作和读取操作完全独立,无法保证读取时目标区域的写入已经完成持久化。
  3. WekaFS的并发读写处理:部分分布式文件系统为了性能,会对未完全持久化的块返回占位数据(比如0),直到数据完成副本同步或持久化。

解决方案

1. 强化写入进程的同步策略

在写入进程的fwrite之后,强制刷写数据到存储设备,确保写入完成后数据才对读取进程可见:

// 写入进程中每次fwrite后添加
fwrite(buffer, size, count, fp);
fflush(fp);       // 刷新用户空间缓存到内核
fsync(fileno(fp));// 确保内核数据刷到WekaFS存储节点

2. 调整读取进程的打开标志

如果业务允许使用操作系统页缓存,可以移除O_DIRECT,让内核自动处理缓存一致性:

// 去掉O_DIRECT标志
int fd = open(filename, O_RDONLY);

页缓存会自动维护读写的可见性,大幅减少未同步导致的全0问题。如果必须保留O_DIRECT,则需要在读取前确保目标区域的数据已经完成写入同步。

3. 增加读写进程的同步机制

通过文件锁实现读写互斥,确保读取时写入操作已经完成:

  • 读取进程使用共享锁(F_RDLCK)
  • 写入进程使用独占锁(F_WRLCK)

读取进程修改示例:

// 在read前添加锁逻辑
struct flock lock;
lock.l_type = F_RDLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0; // 锁定整个文件
lock.l_pid = getpid();

// 阻塞等待获取共享锁
if (fcntl(fd, F_SETLKW, &lock) == -1) {
    perror("Failed to acquire read lock");
    // 错误处理
}

ssize_t bytes_read = read(fd, read_data, sz);

// 释放锁
lock.l_type = F_UNLCK;
if (fcntl(fd, F_SETLK, &lock) == -1) {
    perror("Failed to release lock");
}

4. WekaFS专属优化

查看WekaFS官方文档,调整文件的一致性级别(比如启用强一致性模式),或配置客户端缓存策略,确保读取请求能获取到最新的已持久化数据。

内容的提问来源于stack exchange,提问作者rishi jain

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 01:57:09