《Write-Ahead Log》中文翻译

本文探讨了预写日志在分布式数据库中的关键作用,如何通过序列化操作、日志持久化和错误恢复机制确保数据完整性。详解了WALEntry结构、KVStore示例和实现注意事项,以及预写日志在一致性算法和数据库系统中的广泛应用。

注:文章来自于 Write-Ahead Log,作者是在Thoughtworks工作的 Martin Fowler文章主要写了「预写日志」这一在现代分布式数据库中的常用技术。

预写日志

通过将每个状态更改以命令的形式持久化到日志中,而无需将数据结构刷新到磁盘,来提供持久性保证。

也就是:操作日志。

问题

即时在存储数据的服务器出故障的情况下,也需要数据强完整性的保证。一旦服务器同意执行一个操作,他就应该能执行下去,就算服务器失败重启,丢失所有的内存信心。

解决方案

Figure 1: Write Ahead Log

 将每个状态变更以命令的形式存储到硬盘文件中。为每个服务器进程维护一个日志,并按顺序追加。单个日志的顺序追加操作简化了服务重启后的日志处理和后续联机处理工作。每个日志条目都有唯一的标志符。唯一日志标识符有助于在日志上执行某些其他操作,如分段日志( Segmented Log ) 或使用低水位线( Low-Water Mark )清理日志等。日志更新可以使用单一更新队列( Singular Update Queue)来实现。

典型的日志条目结构如下所示:

class WALEntry…

  private final Long entryId;
  private final byte[] data;
  private final EntryType entryType;
  private long timeStamp;

每次重新启动时都可以读取该文件,并且可以通过重放所有日志条目来恢复状态。

考虑一个简单的内存kv存储:

class KVStore…

  private Map<String, String> kv = new HashMap<>();

  public String get(String key) {
      return kv.get(key);
  }

  public void put(String key, String value) {
      appendLog(key, value);
      kv.put(key, value);
  }

  private Long appendLog(String key, String value) {
      return wal.writeEntry(new SetValueCommand(key, value).serialize());
  }

put操作表示为命令,该命令在更新内存哈希映射之前被序列化并存储在日志中。

class SetValueCommand…

  final String key;
  final String value;
  final String attachLease;
  public SetValueCommand(String key, String value) {
      this(key, value, "");
  }
  public SetValueCommand(String key, String value, String attachLease) {
      this.key = key;
      this.value = value;
      this.attachLease = attachLease;
  }

  @Override
  public void serialize(DataOutputStream os) throws IOException {
      os.writeInt(Command.SetValueType);
      os.writeUTF(key);
      os.writeUTF(value);
      os.writeUTF(attachLease);
  }

  public static SetValueCommand deserialize(InputStream is) {
      try {
          DataInputStream dataInputStream = new DataInputStream(is);
          return new SetValueCommand(dataInputStream.readUTF(), dataInputStream.readUTF(), dataInputStream.readUTF());
      } catch (IOException e) {
          throw new RuntimeException(e);
      }
  }

这可以确保一旦put方法成功返回,即使持有KVStore的进程崩溃,也可以通过在启动时读取日志文件来恢复其状态。

class KVStore…

  public KVStore(Config config) {
      this.config = config;
      this.wal = WriteAheadLog.openWAL(config);
      this.applyLog();
  }

  public void applyLog() {
      List<WALEntry> walEntries = wal.readAll();
      applyEntries(walEntries);
  }

  private void applyEntries(List<WALEntry> walEntries) {
      for (WALEntry walEntry : walEntries) {
          Command command = deserialize(walEntry);
          if (command instanceof SetValueCommand) {
              SetValueCommand setValueCommand = (SetValueCommand)command;
              kv.put(setValueCommand.key, setValueCommand.value);
          }
      }
  }

  public void initialiseFromSnapshot(SnapShot snapShot) {
      kv.putAll(snapShot.deserializeState());
  }

实现考虑

在实现预写日志时,有一些重要的注意事项。最重要的是要确保写入日志文件的条目实际上保存在物理介质上。所有编程语言中提供的文件处理库都提供了一种机制,强制操作系统“刷新”对物理介质的文件更改。在使用冲洗机制时,需要考虑权衡。

刷新磁盘上的每一个日志写操作可以提供很强的持久性保证(这是拥有日志的首要目的),但这严重限制了性能,并可能很快成为瓶颈。如果刷新延迟或异步完成,则会提高性能,但如果服务器在刷新条目之前崩溃,则有可能丢失日志中的条目。大多数实现使用批处理等技术来限制刷新操作的影响。

另一个注意事项是确保在读取日志时检测到损坏的日志文件。为了处理这个问题,日志条目通常使用CRC记录写入,然后在读取文件时可以验证CRC记录。

单个日志文件可能变得难以管理,并且可能会快速占用所有存储空间。为了解决这个问题,使用了分段日志和低水位线等技术。

预写日志仅支持追加的。由于这种行为,在客户端通信失败和重试的情况下,日志可能包含重复的条目。应用日志条目时,需要确保忽略重复项。如果最终状态类似于HashMap,其中对同一密钥的更新是幂等的,则不需要特殊的机制。如果不是,则需要实现某种机制,用唯一标识符标记每个请求并检测重复项。

例子

  • 所有一致性算法服务如zookeeper和raft中的日志实现都类似于预写日志
  • kafka中的存储实现
  • 所有数据库,包括像Cassandra这样的nosql数据库,都使用预写日志技术来保证持久性

发现还有一些人进行了翻译,罗列如下:

分布式系统设计模式 - 预写日志(Write Ahead Log)_张哈希的博客-优快云博客

分布式系统模式2-Write-Ahead Log_XMEHB的博客-优快云博客

<think>好的,我现在需要帮助用户解决他们在HBase安装过程中遇到的问题。根据用户提供的日志,他们在执行`hbase.cmd`时出现了使用提示,而没有成功启动HBase服务。用户可能不太清楚如何正确使用这些命令,特别是如何启动HMaster或RegionServer。 首先,我需要回顾之前的对话历史,确保我的回答与之前的指导一致。之前的指南中,用户被引导到HBase的bin目录下执行`hbase.cmd start`来启动服务。然而,用户现在直接运行`hbase.cmd`,导致输出了命令列表,而不是启动服务。这可能意味着用户没有正确输入启动命令,或者可能存在其他配置问题。 接下来,我需要分析用户提供的错误信息。用户输入的是`PS D:\hbase-2.4.11\bin> .\hbase.cmd`,而正确的启动命令应该是`hbase.cmd start`。因此,用户可能漏掉了`start`参数,导致HBase只是显示帮助信息而没有启动服务。这是最常见的问题之一,特别是对于新用户来说,可能会忽略必要的参数。 另外,我还需要检查用户是否按照之前的步骤正确配置了环境变量和依赖项。例如,Java环境变量是否正确设置,Hadoop的winutils和dll文件是否放置正确,以及HBase的配置文件是否有误。用户可能遇到了环境配置问题,例如JAVA_HOME未正确设置,或者Hadoop组件缺失,导致HBase无法启动。 此外,用户可能在启动HBase时遇到了端口冲突,或者文件权限问题,这也会导致服务启动失败。需要提醒用户检查端口占用情况,并确保有足够的权限访问相关目录。 在回答中,我需要分步骤指导用户正确输入命令,并验证他们的配置是否正确。同时,要提供常见问题的解决方法,帮助用户排查可能遇到的错误,例如检查日志文件,确认Java版本兼容性,以及确保Hadoop依赖项的存在。 最后,确保回答结构清晰,语言简洁,避免技术术语过多,方便用户理解和跟随操作步骤。需要强调正确使用命令参数的重要性,并提供验证服务是否成功启动的方法,例如访问Web UI或检查日志。</think>以下是针对你执行 `hbase.cmd` 后显示命令列表的详细解释与操作指导: --- ### **一、问题分析** 你直接运行了 `hbase.cmd` 但未添加子命令,因此系统输出了所有可用的命令选项。要启动HBase服务或执行操作,需在 `hbase.cmd` 后附加具体命令(如 `start`、`shell` 等)。 --- ### **二、核心命令说明** #### 1. **启动HBase服务** - 启动HMaster(主节点)和RegionServer(区域服务器): ```cmd .\hbase.cmd start ``` - 成功启动后,会显示 `HMaster` 和 `HRegionServer` 进程信息。 - 验证服务: - 访问Web UI:`http://localhost:16010` - 检查日志文件:`D:\hbase-2.4.11\logs\hbase-*.log` #### 2. **进入HBase Shell(交互式命令行)** - 执行以下命令启动HBase Shell: ```cmd .\hbase.cmd shell ``` - 进入后可以操作HBase数据库,例如: ```shell create 'test_table', 'cf' # 创建表 list # 查看所有表 ``` #### 3. **其他常用命令** - 启动ZooKeeper(独立模式): ```cmd .\hbase.cmd zookeeper ``` - 查看版本信息: ```cmd .\hbase.cmd version ``` --- ### **三、操作示例** #### **场景:单机模式启动并测试** 1. **启动HBase服务**: ```cmd .\hbase.cmd start ``` - 若输出 `Master is running` 且无报错,则启动成功。 2. **进入Shell操作**: ```cmd .\hbase.cmd shell ``` - 创建表并插入数据: ```shell create 'user', 'details' put 'user', 'row1', 'details:name', 'John' scan 'user' ``` 3. **关闭服务**: - 在Shell外按 `Ctrl+C` 终止服务进程,或直接关闭命令行窗口。 --- ### **四、常见错误排查** #### 1. **启动失败:`JAVA_HOME not set`** - **解决**:检查 `conf\hbase-env.cmd` 中 `JAVA_HOME` 路径是否指向JDK安装目录(如 `C:\Program Files\Java\jdk1.8.0_301`)。 #### 2. **端口冲突** - **现象**:`Address already in use` - **解决**: 1. 修改 `conf\hbase-site.xml` 中的端口号: ```xml <property> <name>hbase.master.port</name> <value>16000</value> <!-- 替换为未占用端口 --> </property> ``` #### 3. **Hadoop依赖缺失** - **现象**:`java.io.IOException: Could not locate executable null\bin\winutils.exe` - **解决**: - 确保已下载 `winutils.exe` 和 `hadoop.dll`,并配置 `HADOOP_HOME` 环境变量指向其父目录(如 `C:\hadoop`)。 --- ### **五、注意事项** - **路径规范**:HBase路径中避免使用空格(如 `Program Files` 可能引发问题)。 - **版本兼容**:HBase 2.4.x 需搭配JDK 8或11,更高版本JDK可能不兼容。 --- 通过上述步骤,可正确使用 `hbase.cmd` 命令操作HBase。若仍有问题,请提供具体报错信息进一步分析!
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值