关于海量数据存储与查询的思考
前段时间我做了一个SCA日志分析服务,该功能主要是从多台生产服务器上下载当天的日志数据,并且存在数据库中。日志数据主要用于支持维护组查询异常信息以及进行一些统计工作。
开始方案是通过ORACLE+Spring JDBCTemplate来实现,代码实现后发现一个可怕的问题,日志解析入库耗费的时间非常大,查看了一下数据库数据解析1w条日志 用时10min左右 数据库就有将近20w条数据,但是一般一个日志文件一天就是3w-4w条数据,所以数据库中有应该有将近 20w *4 =80w条数据左右,这还是一台服务器的当天日志,如果是3台服务器 那么一天将近240w条日志 4天左右就有近1000w条数据,那么一个月将近上亿条日志数据,但是我们最少数据库中要保存2-3个月的日志数据,所以这种方案入库是根本行不通的,服务器也会被卡死,性能消耗可想而知。
继续思考上面的问题,想什么办法可以提高日志入库的时间呢,主要考虑过三种方式:第一种,用Oracle自带的大数据导入工具sqlldr,将数据导入到一张临时表中,在数据库中解析日志后在分别插入到相关表中,这种方案可以行吧,效率肯定非常高,因为是在数据库中直接操作,摒弃了jdbctemplate操作数据库。第二种,减少jdbctemplate建立连接的次数,因为用的存储过程,我们可以把参数改成数组的形式,可以提高上百倍的效率,但是这种方式有个问题,我们数据库中对大对象用到了CLOB参数类型,这种类型会超出varchar2 4000字节的长度,我们在对字符串数组进行分离的时候可能会导致数据丢失,而且CLOB类型也不能转换为varchar2类型,所以这种方式也不太可行。第三种,去掉存储过程,直接对表进行操作,采用一些ORM框架,用事务提交,这种方式还没有验证过是否可以大幅的提高日志入库的效率。既然Oracle都提供了一个工具专门解决大数据入库的性能问题,我想这个应该会起其它两种方式都更简便,效率也更可观一些。当然口说无凭,这些方式都需要我们手动去验证了才能证明它才是真理。
通过上面的分析,好像sqlldr可以解决我们数据入库的问题,但是问题又来了,上亿的数据量,按照我们传统的方式进行模糊查询只能接近龟速,这也是关系型数据库的一大弊端,不支持全文索引,数据库的索引不是为全文索引设计的,在使用Like查询时,搜索过程又变成类似一页一页翻书的过程,所以使用Like对关系型数据来说是一个性能杀手。这时Lucene上场了,Lucence最核心的特征是通过特殊的索引结构实现了传统数据库不擅长的全文索引机制,请提供了扩展接口,以方便针对不同应用的定制。据我了解,Lucence主要用到了倒排索引和折半查找,所以Lucence无疑是全文索引的一个好帮手。
综合上面的观点,好像目前最佳的解决方案是sqlldr+Lucence。由于主要是日志入库和查询,所以这种方案理论上应该是可行的。我们衍生一下,假如是一个海量数据,且存在上万次并发请求情况呢?关系数据库应付上万次SQL查询还勉强顶得住,但是应付上万次SQL写数据请求,硬盘IO就已经无法承受了。其实对于普通的BBS网站,往往也存在对高并发写请求的需求。 当一个应用系统的用户量和访问量与日俱增的时候,你的数据库却没有办法像web server和app server那样简单的通过添加更多的硬件和服务节点来扩展性能和负载能力,数据库是最难横向扩展的。这时候我们可以考虑用NoSQL。
Nosql有很多优点,可以运行在便宜的PC集群上,NoSQL架构可以省去将Web或Java应用和数据转换成SQL格式的时间,使执行速度变得更快,具有灵活的数据模型,可以非常方便的添加字段等。我们常用的一些NOSQL主要有:CouchDB、Redis、MongoDB、Hbase等,可能MongoDB是我们最好理解的nosql,UACD时主要用到了JSON格式。所以我们在处理高并发+海量数据时一般采用的是NOSQL存储架构。
当然我们不能杀鸡用牛刀,应具体应用具体分析。欢迎大家来指正~,提更多更好的观点。