原子计数器是将列当成一个原子计数器来使用,便于为某些在线应用提供实时统计功能,例如统计帖子的PV(实时浏览量)等。

原子计数器可以解决由强一致性导致的写入性能开销的问题。一个RMW(Read-Modify-Write)操作,通过一次网络请求发送到后端服务器,后端服务器使用内部行锁机制在本地完成RMW的操作。通过原子计数器将分布式计算器的计算逻辑下推到后端服务器,在保证强一致性的情况下,提升原子计数器的写入性能。

接口说明

RowUpdateChange类新增原子计数器接口:

  • RowUpdateChange increment(Column column):对列执行增量变更(如:+X,-X等)。
  • void addReturnColumn(String columnName):对于涉及原子加的列,设置需要返回列值的列名。
  • void setReturnType(ReturnType.RT_AFTER_MODIFY):设置返回类型,返回指定的原子加列的新值。

写入数据时,使用RowUpdateChange接口对整型列做列值的增量变更,如下所示:

private static void incrementByUpdateRowApi(SyncClient client) {
        // 构造主键
        PrimaryKeyBuilder primaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
        primaryKeyBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME, PrimaryKeyValue.fromString("pk0"));
        PrimaryKey primaryKey = primaryKeyBuilder.build();

        RowUpdateChange rowUpdateChange = new RowUpdateChange(TABLE_NAME, primaryKey);

        // 将price列值+10,不允许设置时间戳
        rowUpdateChange.increment(new Column("price", ColumnValue.fromLong(10)));

        // 设置ReturnType将原子计数器的结果返回
        rowUpdateChange.addReturnColumn("price");
        rowUpdateChange.setReturnType(ReturnType.RT_AFTER_MODIFY);

        // 对price列发起原子计数器操作
        UpdateRowResponse response = client.updateRow(new UpdateRowRequest(rowUpdateChange));

        // 打印出更新后的新值
        Row row = response.getRow();
        System.out.println(row);
    }
说明
  • RowUpdateChange.addReturnColumn(列名):设置需要返回的列。
  • RowUpdateChange.setReturnType(RT_AFTER_MODIFY:指定本次修改需要返回上述设定的列值。

使用场景

您可以使用原子计数器对某一行中的数据做实时统计。假设某一用户需要使用表格存储图片元信息并统计图片数信息,表格内每一行对应某用户ID,行上的其中一列用于存储上传的图片, 另一列用于实时统计上传的图片数。

  • UpdateRow:增加一张新图片,原子计数器+1。
  • UpdateRow:删除一张旧图片,原子计数器-1。
  • GetRow:读取原子计数器的值,获取当前用户的图片数。

上述行为具有强一致性,即当您增加一张新图片时,原子计数器会相应+1,而不会出现-1的情况。

限制

原子计数器主要存在以下几方面的限制:

  • 仅支持Integer类型。
  • 作为原子计数器的列,若写入前该列不存在,则默认值为0。若写入前该列已存在且列值为非Integer类型,则抛出OTSParameterInvalid错误。
  • 增量值可以是正数或负数,但不允许计算溢出。若出现计算溢出,则抛出OTSParameterInvalid错误。
  • 默认不返回原子加列的结果。可以通过addReturnColumn() + setReturnType()接口,指定返回哪些原子加列的结果。
  • 在单次更新请求时,不能对某一列同时进行更新和原子计数的操作。假设列A已经执行原子计数器操作,则列A不能再执行其他操作(如列的覆盖写,列删除等)。
  • 在一次 BatchWriteRow 请求中,可以支持对同一行的多次更新操作。但若某一行已执行原子计数器操作,则该行在此批量请求中只能出现一次。
  • 列上的原子计数器只作用在最新版本上,不支持对列的特定版本做原子计数器。更新完成后,原子计数器会插入一个新的版本。
  • 原子计数器操作可能会由于网络超时、系统错误等导致失败。此时,该应用程序只需重试该操作即可。这会产生更新两次计数器的风险,导致计数有可能偏多或偏少。针对此类异常场景,建议使用条件更新精确变更列值。