hbase时间戳修改带来的问题总结

本文探讨了HBase中时间戳(ts)的使用方法及注意事项,包括如何利用时间戳实现数据提前失效,以及在手动设置时间戳时可能遇到的问题与解决办法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转自:https://my.oschina.net/u/2293326/blog/750112

 

公司业务:数据录入的时候,同一时刻,一条数据的某个字段存在多版本情况。
根据资料,hbase 插入数据的时候可以手动设置时间戳,这样把多个版本的时间戳区别开,但是发现hbase数据不能删除。

经过分析,这是由于:插入数据时候,人为设定的时间戳大于,删除的时间戳。 当client端系统时间大于集群系统时间,就会可能出现这种情况。

作结,hbase java代码部署的client服务器,最好和集群hbase服务器时间做同步,就会避免以上问题。

 

大家知道,像OB,HBase这种存储系统,插入数据的时候,一般数据上都会有一个时间戳(ts)。

Hbase有一个TTL(time to live),可以标识数据的有效期,比如,可以把TTL设置成86400*1000,也就是说数据将于1天后过期。这是一个表级的设置,必须在建表时指定。

但是如果说你需要存储某一天内的数据,到第二天0点失效。这种情况TTL是没法控制的,因为TTL只能控制数据在一段时间后失效,而不能控制在特定的时间点失效。

TTL的本质是通过对比数据的ts,与当前系统时间,然后确定是否应该失效,于是,我们可以通过ts来hack一下。

假设数据的TTL是1天,如果我在凌晨1点插入数据,那么正常情况,它会到第二天凌晨1点失效。实际上就是判断:currentMilliseconds - ts > 86400*1000,如果满足,数据就失效了。

这时如果要控制数据在第二天0点就失效,我们把插入数据的ts往后推一小时就可以了,它就会提前失效。

 

这个方案理论上看起来没有问题,但是如果你的表涉及到删除数据,那么,坑就来了。

 

HBase普通的操作,都会写入WAL(Write ahead log),累积到一定数量后(或者根据时间),根据操作的ts,进行merge,然后对真实的数据做commit,这个跟数据库的log是有点类似的。

 

这里面隐含的一点是,hbase中的操作,是需要ts比当前数据中的ts大,操作才会有效,否则就无效(正常的都是这样的,因为时间是不断变大的嘛)。

 

比如当前有2个操作:

put 'key', 'value', ts=1

put 'key', 'value', ts=2

那么经过合并后,实际上只会有一个操作:

put 'key', 'value', ts=2(因为这个时间戳比较大嘛)

 

接着来,如果有3个操作:

put 'key', 'value', ts=1

put 'key', 'value', ts=2

del 'key', 'value', ts=3

那么,合并后,就只有delete的操作了。

坑就在这里,因为我们是手动设置插入数据的ts的。这就意味着,如果要删除数据,那必须要将删除操作的ts设置得比原来的数据的ts要大(在我们的情况中,两个时间都是未来)。

 

如果删除操作,使用了系统默认的ts,那么造成的结果是:数据无法被删除。

 

OK,那我们就知道,会将删除的ts设大。可是这时,如果你再插入数据,就必须将插入数据的ts设置得比删除操作的ts还要大。。。其实就是,对同一个cell的操作,要想你的操作有效,你必须将它的ts设置为比当前操作序列中最大的还要大。。。

 

然后,如果一不小心,你想当然地把删除的ts设置成了Long.MAX_VALUE,你就会发现,你永远也插入不了数据了。。。。(其实不是永远啦,要到下一次major compact)。

 

最后的总结:谨慎修改数据的ts。。。

 

HBase中插入数据主要通过Put操作实现,每次插入的数据会对应一个特定的行键(RowKey)、族(ColumnFamily)、限定符(ColumnQualifier)和时间戳(Timestamp)。HBase支持显式指定时间戳,也可以使用系统自动生成的时间戳。以下是关于HBase插入数据及处理时间戳的具体方法: 在HBase Shell中插入数据可以使用`put`命令。基本语法为: ```shell put '<table name>', '<row key>', '<column family>:<column qualifier>', '<value>' ``` 例如,向表`users`中插入一行数据,行键为`user1`,族为`info`,限定符为`name`,值为`John Doe`: ```shell put 'users', 'user1', 'info:name', 'John Doe' ``` 此操作将使用服务器当前时间作为时间戳[^1]。 若希望显式指定时间戳,在`put`命令中添加时间戳参数即可: ```shell put '<table name>', '<row key>', '<column family>:<column qualifier>', <timestamp>, '<value>' ``` 例如,指定时间为`20230101000000`: ```shell put 'users', 'user1', 'info:name', 20230101000000, 'John Doe' ``` 这种方式适用于需要精确控制数据版本的场景[^1]。 对于编程接口(如Java API),插入数据需构建`Put`对象,并调用`addColumn`或`addImmutable`方法添加单元格数据。若要指定时间戳,可在`addColumn`方法中传入时间戳参数: ```java Put put = new Put(Bytes.toBytes("user1")); put.addColumn(Bytes.toBytes("info"), Bytes.toBytes("name"), System.currentTimeMillis(), Bytes.toBytes("John Doe")); table.put(put); ``` 上述代码展示了如何使用HBase Java客户端API插入带有自定义时间戳的数据[^1]。 HBase中的时间戳不仅用于标识数据插入时刻,还决定了多个版本数据之间的优先级。默认情况下,HBase保留每个单元格的三个版本数据。可通过修改族属性调整最大版本数: ```shell alter 'users', {NAME => 'info', VERSIONS => 5} ``` 该配置确保每个单元格最多保留五个不同时间戳的数据版本[^1]。 此外,HBase提供了TTL(Time To Live)机制,允许设置数据的有效期。当数据的时间戳加上TTL值小于当前时间时,该数据将在下一次Compaction过程中被删除。配置TTL的方式如下: ```shell alter 'users', {NAME => 'info', TTL => 86400} # 设置数据存活时间为一天(单位:秒) ``` 此功能有助于自动清理过期数据,减少存储负担。 ### 数据版本与查询 HBase在读取数据时,默认返回最新版本的数据(即时间戳最大的记录)。如果需要获取特定时间范围内的数据,可以通过Scan操作结合时间戳区间进行筛选: ```java Scan scan = new Scan(); scan.setTimeRange(startTimestamp, endTimestamp); // 设置时间范围 ResultScanner results = table.getScanner(scan); ``` 此方法可用于分析历史数据变化趋势等复杂业务场景[^1]。 ### 总结 HBase通过灵活的时间戳机制支持多版本数据管理,既可利用系统自动生成的时间戳简化开发流程,也可手动指定时间戳以满足特殊需求。同时,配合TTL和版本控制策略,能够有效平衡数据新鲜度与存储成本之间的关系。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值