千亿数据规模下,数据查询系统的性能与储存成本成正比,要达到满意的查询性能需要昂贵的存储设备来存储海量的数据,反之廉价的存储设备会降低查询速度,所以需要一种兼顾性能与成本的分级存储方法。
目前主流存储设备按照读取速度从快到慢的顺序,有内存、SSD固态硬盘、SAS机械硬盘、SATA机械硬盘,其价格也与之成正比。从稳定可靠的性能看,正好反之,速度越慢的设备越不容易损坏,内存容易丢失数据,在断电的情况下就会丢失数据。
除了存储设备分级外,数据也是分级的,数据可以根据保存时间分级、可以根据重要程度分级、可以根据即时性分级,并且这些级别会随着时间的变化而变化。
现有方案
虽然目前业界采用一定的方式解决了数据分级的问题,但功能很受限。不能从根本上降低存储成本。并且在性能上也存在很多硬伤。
首先存储方式上,一张数据表,只能存储在同一种类的存储设备中,这种方式对本地磁盘要求比较高,一旦磁盘损坏,则该表无法使用,服务会受到影响。另外一种情况是如果数据由多备份或副本组成,其中一份副本所对应的磁盘故障,或当前正在进行大IO操作等因素导致这块磁盘读的速度很慢,系统不会自动识别切换到另外一块磁盘上进行读写,从而拖累整体的查询速度。
其次业界采用的这种方式只能作用到具体某张表上,不能细化到具体的某个数据列上面,这不够灵活,存储也不够精细化。因此对于同一张数据表的不同数据列之间有诸多限制。比如:
① 同一张表的数据列必须是相同的生命周期,保存的天数必须相同。
② 同一张表的数据列必须存储在同一个存储设备上,不能按列分数据级别后分别存储在不同的存储设备上。
③ 同一张表的数据列不会随着时间的改变变换存储级别,从而变换存储设备。
④ 同一张表的数据列只能存储在同一台计算机上,不能将不同的数据列分散存储在不同的计算机上。不同的列之间不可以通过存储设备的不同,做到列和列之间的资源隔离。在同一台计算机上读取时会相互影响。比如读取A列数据,B列数据也要一起随同读取进来,但是并不需要B列,故而浪费了磁盘IO资源,和用于解压的CPU资源。尤其在A列是小体积数据而B列是大体积数据的时候,比如图片文件之类的,更会严重影响性能。
列簇存储
列簇功能是一个较典型的存储需求。从名字中就可以看出其作用——将一张表中的不同的列的存储隔离开来,不同的列拥有不同的存储目录。在开源方案中列簇并不少见,常见的支持列簇的存储产品有HBase、RocksDB(columnfamily)等,列簇功能其实也成为了大数据存储组件的一个典型功能。
LSQL的列簇用于管理不同列保存不同的周期。列簇存储适合只是追加,并不需要修改的数据,如:日志数据。LSQL的列簇存储是将行存数据直接存储在HDFS上,通过减少了索引合并,从而提升创建索引的效率。不同的列簇可以设置不同的生命周期,不同的存储介质,具体原理如下图所示:
不同列簇可以存储到不同磁盘, 具备混合使用不同磁盘的能力。
列簇可以根据时间变更存储设备,自动迁移。
不同列簇可以有不同的存储生命周期。
同一个数据列能综合使用多种存储设备。
不同列簇不同存储格式,不同压缩算法。支持行存,列存,混合存,多值列,汇聚存储均支持。
对于一张宽表可以有多种数据融合方案,如下所示:
假设一张宽表共300个列:
前100个列,都是图片,文件存储,比较大,保存10天,存储在SATA盘上; 中间100列,都是文本内容,经常全文检索,保存30天,一份副本存SSD,其他副本存储SATA; 后100个列,都是轨迹与关系数据,占存储空间相对较少,但需要进行统计分析,故存储90天,近7天一份副本存在内存里,7天外存储在SSD,另外一份副本存储在SATA做备份。
将一张数据表按照分为不同的列簇,可以是每列一个列簇,也可以是多列一个列簇。每个列簇根据其数据等级的特点选择适合的存储设备,提升性能的同时,高可以节省90%存储成本。HDFS的异构存储在一定程度上降低了成本,但是使用上列簇存储则可将硬件的性价比发挥到。
列簇使用
1. 两种列簇存储方式
启用行存数据-索引外的-列簇存储='store@true' 启用索引内-索引数据-列簇存储='index@true'
2. 列簇使用语法
(1)旧版创建方式
create columnfamily physical_table_name (
default at 'index@true' 'store@true' 'ssdindex@tim,doc' 'ssdindex2@fdt,fdx' 'cleanday@200,yyyyMMdd',
cf_name_01 at 'fields@col_001,col_002' index@false' 'cleanday@150,yyyyMMdd',
cf_name_02 at 'fields@col_003,col_004,col_005' 'store@false' 'cleanday@100,yyyyMMdd',
cf_name_03 at 'fields@col_006,col_007,col_008' 'cleanday@60,yyyyMMdd'
);
create columnfamily:语法关键字。
physical_table_name: 物理表名称,可变。
cf_name_0*:列簇名称,可变。
default:默认列簇管理策略。
fields:字段列表,物理表中的字段;不能对MAPPING对象(映射表)做列簇管理。
index:索引列簇,true代表需要索引列簇管理,false代表不需要索引列簇管理;不写默认为true。
store:数据列簇(行存储列簇),true代表需要数据列簇管理,false代表不需要数据列簇管理;不写默认为true。store只对行存数据起作用,列存数据不可用。
ssdindex、ssdindex2、ssdindex3:异构特性设置,参考Hadoop异构存储介绍。
cleanday:列簇保存周期,用作数据清理淘汰。
(2)新版创建方式
create table lsql_column(col1 y_string_is,col2 y_string_is,col3 y_string_is,col4 y_string_is)tableproperties(
columnfamily='default at index@true store@true ssdindex@tim,doc ssdindex2@fdt,fdx cleanday@200,yyyyMMdd'
,columnfamily='cf1 at fields@col1 index@false cleanday@150,yyyyMMdd'
,columnfamily='cf2 at fields@col2,col3 store@false cleanday@100,yyyyMMdd'
,columnfamily='cf3 at fields@col4 cleanday@60,yyyyMMdd');
同时兼容旧版列簇创建方式。
进入lsql所在节点:
# cd /opt/software/lsql/bin
# ./beeline.sh
创建物理表“physical_table_test”:
create table physical_table_test(
col_001 y_string_id,
col_002 y_string_id,
col_003 y_string_id,
col_004 y_string_id,
col_005 y_string_id,
col_006 y_string_id,
col_007 y_string_id,
col_008 y_string_id,
col_009 y_string_id,
col_010 y_string_id
);
(2)创建物理表“physical_table_test”的列簇
create columnfamily physical_table_test (
default at 'index@false' 'store@false' 'ssdindex@tim,doc' 'ssdindex2@fdt,fdx' 'cleanday@200,yyyyMMdd',
cf1_2 at 'fields@col_001,col_002' 'ssdindex@tim,tip' 'ssdindex2@doc' 'cleanday@150,yyyyMMdd',
cf3_5 at 'fields@col_003,col_004,col_005' 'index@false' 'cleanday@100,yyyyMMdd',
cf6_8 at 'fields@col_006,col_007,col_008' 'store@false' 'cleanday@60,yyyyMMdd',
cf9_10 at 'fields@col_009,col_010' 'cleanday@20,yyyyMMdd'
);
列簇cf1_2:“col_001,col_002”字段做一个列簇,其中索引的“tim,tip,doc”做异构存储;列簇存储周期为150天。
列簇cf3_5:“col_003,col_004,col_005”字段做一个列簇,数据进行列簇,索引不做列簇管理;列簇存储周期为100天。
列簇cf6_8:“col_006,col_007,col_008”字段做一个列簇,数据不做列簇管理,索引进行列簇管理;列簇存储周期为60天。
列簇cf9_10:“col_009,col_010”字段做一个列簇;数据存储周期为60天。
列簇default:数据不做列簇,索引不做列簇,其中索引的“tim,doc,fdt,fdx”做异构存储;列簇存储周期为200天。
1. 设置行存储是否启用压缩
可以在default属性上设置compress@false,禁止进行压缩,默认不设置则索引内存储采用lz4压缩,索引外列簇采用zip。
具体使用方法如下:
--启用索引列簇存储,行存储不启用压缩:
create columnfamily common_performance (
default at 'index@true' 'store@false' 'compress@false'
);
--启用索引列簇存储、行存储列簇存储,行存储不启用压缩:
create columnfamily common_performance (
default at 'index@true' 'store@true' 'compress@false'
);
2. 列簇名更换后如何使用
(1)种情形-先在配置文件配置列簇(这个方式已经被废弃,没有按照表进行区分),更改为通过create columnfamily方式
cl.column.family.store=true
cl.rowstore.column.family=cf
cl.rowstore.column.family.alltable.s_mod_10=hl
cl.rowstore.column.family.alltable.s_mod_100=hl
--变更为create方式后就读不到列簇的值了
create columnfamily common_performance (
default at 'index@true' 'store@true'
,sss at 'fields@s_mod_10,s_mod_100' 'index@true' 'store@true'
)
--添加 'cf_old_site@cf'就可以读到之前在配置文件中配置的的列簇的值了
create columnfamily common_performance (
default at 'index@true' 'store@true' 'cf_old_site@cf'
,sss at 'fields@s_mod_10,s_mod_100' 'index@true' 'store@true' 'cf_old_site@hl'
)
--原先是 sss列簇:
create columnfamily common_performance (
default at 'index@true' 'store@true'
,sss at 'fields@s_mod_10,s_mod_100' 'index@true' 'store@true'
);
--sss列簇变更为mmm列簇,无法再读取到之前sss列簇的值:
create columnfamily common_performance (
default at 'index@true' 'store@true'
,mmm at 'fields@s_mod_10,s_mod_100' 'index@true' 'store@true'
);
--添加 'cf_old@sss',可以继续读取之前设置过的 sss 列簇,即兼容旧列簇的数据:
create columnfamily common_performance (
default at 'index@true' 'store@true'
,mmm at 'fields@s_mod_10,s_mod_100' 'index@true' 'store@true' 'cf_old@sss'
);
--用来查看系统中的列簇:
show columnfamilys;
--用来查看系统中的列簇:
drop columnfamily XXX;
--用来查看创建列簇的语句(取消show create columnfamily语法支持):
show create table XXX;
LSQL的列簇功能将一张数据表按照分为不同的列簇,可以是每列一个列簇,也可以是多列一个列簇。每个列簇根据其数据等级的特点选择适合的存储设备。从而达到性能与成本的佳性价比,增强系统的灵活性,并显著提升系统的整体性能。
来源:https://mp.weixin.qq.com/s/YhjHod9Zk54r7LPLBF3kQA