求一个大数据存储查询的方案?

理由
举报 取消

目前数据有如下特征:1.数据量大,每日达到上亿条记录,至少需要保存两年以上的记录2.写入频繁,每日需要将上亿条记录写入数据库3.读的并发性不高,最多上千个访问同时在线,但有实时性要求,延时不能超过5秒该数据特征与百度统计、CNZZ统计比较相似。求推荐数据库方案比如传统的关系型数据库:MYSQL?还是NOSQL数据库:mongodb?还是:HBASE、HIVE?还是其他?多谢!

2017年8月27日 10 条回复 1512 次浏览

回复 ( 10 )

  1. 杨东东
    理由
    举报 取消

    目前数据有如下特征:

    1.数据量大,每日达到上亿条记录,至少需要保存两年以上的记录

    2.写入频繁,每日需要将上亿条记录写入数据库

    3.读的并发性不高,最多上千个访问同时在线,但有实时性要求,延时不能超过5秒

    看楼主似乎是收集日志作分析,偶尔前面有人工查询的需求。

    1, 先看下数据量:每日一亿条,每条100B,则数据量是0.1G*100B= 10G,那么一年是365*10G=3.65T数据。如果楼主保存两年,那么至少有7.3T数据,而且这是假设业务平稳、中间数据很少的情况下,如果迅速增长或者需要保留更多的中间结果,那么数据量会大得多;

    2. 写入要求很高,假设写入了是平均的,那么每秒写入1亿/(3600*24)=1150条,如果峰值是均值的10倍,那么峰值每秒1万条写入,当然如果前端可以使用队列控制缓冲,控制写入速度1000-2000条/秒;

    3. 读要求确实不高,看起来是读得出来就行;

    从上面看,数据量逐渐增大单机已经很难搞定,即使能搞定你也不敢只使用单机,一旦坏了,数据全没了;而且你要分析计算,单机的计算能力有限,未必满足计算需求,即使一主一备也未必有足够的计算能力。

    MySQL、MongoDB都有集群方案,不过要稳定可用得付出不少精力,比如扩容时候数据重新分片就够头痛的。HBase将数据存储在HDFS中,天生具有很强的扩容能力,机器不够,直接加入新机器,一个命令做个再平衡就可以。一般场景下,HBase的写入能力也强过MySQL、MongoDB,这个涉及到各自的存储引擎结构不同,楼主可用找各自的技术文档来了解。当然,各个DB的存储引擎都在进步,性能这块不能一锤定音。

  2. 周工
    理由
    举报 取消

    你给的信息太少了,从你的问题描述中,先理一些关键因素出来:

    1. 每日写入行数:1亿(每日上亿我姑且认为是1亿),平均下来每秒写入1157行。因为不清楚写入的模式,姑且峰值算两倍的话就是2314行/秒。如果对写入速度没什么要求,可以把峰值给平均掉,控制写入压力。

    2. 每日新增数据量:一行按1KB来算的话,日新增100GB

    3. 总的存储量:保存两年数据,总的数据量就是 100G * 365 * 2 = 73T

    4. 读写场景:写多读少。如何读没描述清楚,每次读的数据量没描述清楚。

    5. 功能性需求:数据过期(超过两年的数据自动过期)

    6. 业务增长:一年或两年后,日增数据会增长到多少?

    这写入量,这数据规模,就不用考虑用mysql了。

    考虑数据规模和业务的发展,数据库同样需要有横向扩展的能力,HBase和MongoDB是比较合适的。

    我对MongoDB不是非常熟悉,所以详细讨论下HBase如何应用在你的场景。

    Hbase天然具备横向扩展的能力,所以只要你机器规模够(机型需要考虑使用SSD、SATA或混合存储?读写比例多少?缓存命中率多少?如果你够土豪,上个几十台的SSD机器。)、有能力运维(技术能力是否足够玩得起HBase?是否能够运维这么多机器?),支撑这么大量数据写入并且提供低延迟的在线读完全没有问题。

    再回答下你在「杨东东」的评论里问的问题:

    『目前使用python操作hbase,但遇到另外一个问题,比如rowkey设计成111_333_222的格式,如何快速查询两个_之间值为333的记录呢?』

    这种只能靠索引:

    表A的RowKey为:111_333_222

    表B的RowKey为:333_111_222

    日志数据可以在两张表内各存一份,这样会导致数据量翻番,一行的写入速度变慢,需要处理两张表的一致性问题等,但是能提升查询速度。

    或者查询较少的那张表(例如表B)存储一份表A的rowkey,查询就是先查表B,拿到表A的rowkey,再查表A,这样好处是节省存储空间,坏处是查询变慢。

    以上方案的假设是:你已经写入的行不会改或者改动很少,你能处理数据一致性问题。

  3. itlr
    理由
    举报 取消
    • MYSQL或者其他RDBMS,读优化容易,写优化难,维护成本高
    • MongoDB,比RDBMS易扩展,但有Database Lock,单点写入,对你的应用仍然是潜在瓶颈
    • HIVE,延迟高,适合做线下数据分析,不适合实时系统
    • HBASE,是可能的方案,但维护门槛高,架构上仍有master节点,写扩展能力仍有限

    —–

    Apache Cassandra

    • 节点平等,读写性能均可水平扩展,节点间数据自动replicate,跨地域部署容易,高容错
    • 单节点写入性能作了特别优化,不用太多节点也可以支持相当吞吐量的写入
    • 部署容易,相对HBASE,不用zookeeper这样的东西,admin门槛低,好用
    • 市场上众多对写入有很高要求的应用的验证 Companies Using NoSQL Apache Cassandra

    —–

    Youtube上关于Cassandra在time series(你的情况)应用的讨论,也有Cassandra配合Spark的讨论。 知乎上有Cassandra经验的人的回答。

    —–

    • Learning Apache Cassandra
    • Big Data: Principles and Best Practices of Scalable Realtime Data Systems
  4. 匿名用户
    理由
    举报 取消

    首先从你的需求来看必须要选Nosql类型的数据库了,推荐Hbase 和Mongodb.我对mongodb不了解,所以只好大致讲一下hbase了。

    Hbase读的性能比较强,官方定义为适合PB级数据的秒级查询,就是说在巨海量的数据中查询,响应速度非常快。写的速度和程序员及硬件的关系较大,具体如下:

    在此之前,请检查硬件状况。硬盘推荐SSD,一般SATA即可。网络千兆以上。可以安装Ganglia等工具,检查各节点的各硬件的运作状态:CPU,Memo,网络等等。

    一、调整参数

    入门级的调优可以从调整参数开始。投入小,回报快。

    1. Write Buffer Size快速配置

    Java代码

    1. HTable htable = new HTable(config, tablename);
    2. htable.setWriteBufferSize(6 * 1024 * 1024);
    3. htable.setAutoFlush(false);

    设置buffer的容量,例子中设置了6MB的buffer容量。

    * 必须禁止auto flush。

    * 6MB是经验值,可以上下微调以适应不同的写场景。

    原理

    HBase Client会在数据累积到设置的阈值后才提交Region Server。这样做的好处在于可以减少RPC连接次数。同时,我们得计算一下服务端因此而消耗的内存:hbase.client.write.buffer * hbase.regionserver.handler.count。在减少PRC次数和增加服务器端内存之间找到平衡点。

    2. RPC Handler快速配置

    修改hbase-site.xml的hbase.regionserver.handler.count配置项:

    Xml代码

    1. <property>
    2. <name>hbase.regionserver.handler.count</name>
    3. <value>100</value>
    4. </property>

    原理

    该配置定义了每个Region Server上的RPC Handler的数量。Region Server通过RPC Handler接收外部请求并加以处理。所以提升RPC Handler的数量可以一定程度上提高HBase接收请求的能力。当然,handler数量也不是越大越好,这要取决于节点的硬件情况。

    3. Compression 压缩快速配置

    Java代码

    1. HColumnDescriptor hcd = new HColumnDescriptor(familyName);
    2. hcd.setCompressionType(Algorithm.SNAPPY);

    原理

    数据量大,边压边写也会提升性能的,毕竟IO是大数据的最严重的瓶颈,哪怕使用了SSD也是一样。众多的压缩方式中,推荐使用SNAPPY。从压缩率和压缩速度来看,性价比最高。

    4. WAL快速配置

    Java代码

    1. Put put = new Put(rowKey);
    2. put.setWriteToWAL(false);

    原理

    其实不推荐关闭WAL,不过关了的确可以提升性能…因为HBase在写数据前会先写WAL,以保证在异常情况下,HBase可以按照WAL的记录来恢复还未持久化的数据。

    5. Replication

    虽然推荐replica=3,不过当数据量很夸张的时候,一般会把replica降低到2。当然也不推荐随便降低replica。

    6. Compaction

    在插数据时,打开HMaster的web界面,查看每个region server的request数量。确保大部分时间,写请求在region server层面大致平均分布。

    在此前提下,我们再考虑compaction的问题。继续观察request数量,你会发现在某个时间段,若干region server接收的请求数为0(当然这也可能是client根本没有向这个region server写数据,所以之前说,要确保请求在各region server大致平均分布)。这很有可能是region server在做compaction导致。compaction的过程会block写。

    优化的思路有两种,一是提高compaction的效率,二是减少compaction发生的频率。

    提高以下两个属性的值,以增加执行compaction的线程数:

    Xml代码

    1. hbase.regionserver.thread.compaction.large
    2. hbase.regionserver.thread.compaction.small

    推荐设置为2。

    7. 减少Region Split次数

    region split是提升写性能的一大障碍。减少region split次数可以从两方面入手,一是预分配region(该内容会在下章节表设计优化里详述)。其二是适当提升hbase.hregion.max.filesize

    提升region的file容量也可以减少split的次数。具体的值需要按照你的数据量,region数量,row key分布等情况具体考量。一般来说,3~4G是不错的选择。

    8. HFile format version

    0.92.0后的version都应该是2。v2比v1支持更大的region大小。一般经验是Region越大越少,性能更好(当然也不能过分大,否则major compaction的时候时间长的吃不消)。所以推荐把hfile.format.version改成2,并提高hfile大小。对于使用v1 format的用户,不用担心,数据迁移到v2上是有工具的。具体参见HBASE-1621。

    9. hbase.ipc.client.tcpnodelay

    设置成True。关闭Nagle,可能提高latency。当然HDFS也关掉TPC Nagle。

    A TCP/IP optimization called the Nagle Algorithm can also limit data transfer speed on a connection. The Nagle Algorithm is designed to reduce protocol overhead for applications that send small amounts of data, such as Telnet, which sends a single character at a time. Rather than immediately send a packet with lots of header and little data, the stack waits for more data from the application, or an acknowledgment, before proceeding.

    二、表设计优化1. 预分配Region

    之前有说防止region split的两大手段其中之一就是预分配region。

    在此不重复region split的原理,请参见HBase自动分区(Auto-Sharding)_学步。按数据量,row key的规则预先设计并分配好region,可以大幅降低region split的次数, 甚至不split。这点非常重要。

    2. Column Family的数量

    实测发现column family的数量对性能会有直接影响。建议减少column family的数量。单个cf是最好

    3. Column Family MAX_VERSIONS/MAX_LENGTH

    前者确定保存一个cell的最大历史份数,后者确定多少byte可以存进一个cell 历史记录。所以我们可以减低这些值。

    4. Row Key的设计

    Region的数据边界是start key和end key。如果记录的row key落在某个region的start key和end key的范围之内,该数据就会存储到这个region上。在写数据的时候,尤其是导入客户原有数据的时候,如果row key设计不当,很可能导致性能问题。之前我们也介绍了row key和region的关系。如果在某个时段内,很多数据的row key都处在某个特定的row key范围内。那这个特定范围row key对应的region会非常繁忙,而其他的region很可能非常的空闲,导致资源浪费。

    那么,如何设计row key呢?举个比较实际的例子,如果有张HBase表来记录每天某城市的通话记录, 常规思路下的row key是由电话号码 + yyyyMMddHHmmSS(通话开始时间) + … 组成。按电话号码的规律来划分region。但是这样很容易导致某时段row key极其不均匀(因为电话通话呈随机性)。但是,如果把电话号码倒序,数据在region层面的分布情况就大有改观。

    设计row key的方法千变万化,宗旨只有一条,尽量保证单位时间内写入数据的row key对于region呈均匀分布。

    三、优化Client设计

    实践发现,写性能差大部分情况是源于Client端的糟糕设计。接下来分享一些Client设计的思路。

    1. 均匀分布每个Region Server的写压力

    之前也提到了RPC Handler的概念。好的Data Loader需要保证每个RPC Handlder都有活干,每个handler忙,但不至超载。注意region的压力不能过大,否则会导致反复重试,并伴有超时异常(可以提高超时的时间设置)。

    如何保证每个Region Server的压力均衡呢?这和region 数量,row key的设计 和client数据的插入顺序有关。设计者需要根据用户数据的情况,集群情况来综合考虑。

    2. 并行的数据插入框架

    多线程是最简单的解决方案。要点是让每个线程负责一部分的row key范围,而row key范围又和region相关,所以可以在数据插入时,程序控制每个region的压力,不至于有些region闲着没事干。由于相对简单,不再赘述。

    即使使用多线程,也受限于单节点的硬件资源,写入速度不可能很快。典型的思路是将客户端部署在多个节点上运行,提高写的并发度。MapReduce是个很好的选择。使用MapReduce把写入程序分布到集群的各个节点上,并在每个mapper中运行多线程的插入程序。这样可以很好的提高写并发度。

    注意,不要使用reducer。mapper到reducer需要走网络,受限于集群带宽。其次,实际的应用场景一般是用户从关系型数据库中导出了文本类型的数据,然后希望能把导出的数据写到HBase里。在这种情况下,需要小心谨慎地设计和实现FileInputFormat的file split逻辑。

    3. BulkLoad

    请拿出HBase的API读读,HFileOutputFomart里有个叫configureIncrementalLoad的方法。API是这么介绍的:

    Configure a MapReduce Job to perform an incremental load into the given table. This

    Inspects the table to configure a total order partitioner

    Uploads the partitions file to the cluster and adds it to the DistributedCache

    Sets the number of reduce tasks to match the current number of regions

    Sets the output key/value class to match HFileOutputFormat’s requirements

    Sets the reducer up to perform the appropriate sorting (either KeyValueSortReducer or PutSortReducer)

    The user should be sure to set the map output value class to either KeyValue or Put before running this function.

    这是HBase提供的一种基于MapReduce的数据导入方案,完美地绕过了HBase Client(上一节的分布式插入方法也是用mapreduce实现的,不过本质上还是用hbase client来写数据)

    网上有不少文章叙述了使用命令行方式运行BulkLoad,google一下你就知道…

    但是,不得不说,实际生产环境上很难使用这种方式。毕竟源数据不可能直接用来写HBase。在数据迁移的过程中会涉及到数据清洗、整理归并等许多额外的工作。这显然不是命令行可以做到的事情。按照API的描述, 可行的方案是自定义一个Mapper在mapper中清洗数据,Mapper的输出value为HBase的Put类型,Reducer选用PutSortReducer。然后使用HFileOutputFormat#configureIncrementalLoad(Job, HTable);解决剩余工作。

    不过,这种实现也存在局限性。毕竟Mapper到Reducer比较吃网络。

    四、写在后面的话

    至此,介绍了三种HBase数据写入的方法(1种多线程,2种mapreduce),并介绍了各类性能调优的方法。希望有所帮助。如果有大家有更好的方法,不妨留言讨论,共同进步。

  5. 吴迪
    理由
    举报 取消

    条件不太充分,建议从业务角度描述清楚数据模型,以及查询分析的场景。

  6. 陶云峰
    理由
    举报 取消

    阿里云的OTS。不用管运维,不用担心jvm gc带来的毛刺,也不用手工分区。

    利用相关:OTS开发

  7. JingSQ
    理由
    举报 取消

    场景:

    1. 数据量大,未来可能还会增加:那就只能用分布式系统,且必须要扩展容易
    2. 写多读少:那就最好不要单独用ElasticSearch了。

    结论:

    1. 如果查询条件简单:那就Hbase,如果想用云产品,那就阿里云的开放结构化数据服务OTS_海量数据存储
    2. 如果查询条件复杂,且有文本查询,那就Hbase + ElasticSearch;如果用云产品,那就是阿里云的OTS + OpenSearch。
    3. 如果很久之前的数据也不想删除,可以用阿里云的归档服务归档几年前的冷数据,价格十分低廉。
  8. WJWJ
    理由
    举报 取消

    Elasticsearch

  9. 陈鑫
    理由
    举报 取消

    我信奉,稳定压倒一切。

    每秒2000多次单行写入,现在的主流关系型数据库都能接受。数据量大,可以分表切片做冷热,这个量级我认为没有存储及并发压力。没必要选hbase或mongodb之类的数据库,它们都还有一些坑要踩(我从2.x踩到3.x)。在现在大数据方案百花齐放但未出现王者前,选型尽量慎重。重点是你的数据关系或存储关系优化,做好了,绝逼没问题。

    而且你好像是做离线分析。

  10. 用户头像
    理由
    举报 取消

    首先,这个量级的的数据必须是上nosql了。

    其次,关于选型,假如这部分数据只是持久化,不考虑查询性能、并行度等因素(或者这方面要求不高),建议hbase即可,毕竟基于hbase还可以方便的进行mr或者hive端的离线分析工作,形成最终的数据仓库;假如该数据已经经过了ETL过程,直接需要用于OLAP的话,Mongodb,Cassandra等都可作为选择项,但nosql种类众多,侧重点也不同,建议根据实际业务背景充分调研后再决定使用何种nosql,并需考虑相关运维成本。

我来回答

Captcha 点击图片更换验证码