知识大全 Java在处理大数据的时候一些小技巧

Posted

篇首语:不担三分险,难练一身胆。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 Java在处理大数据的时候一些小技巧相关的知识,希望对你有一定的参考价值。

Java在处理大数据的时候一些小技巧  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

  众所周知 java在处理数据量比较大的时候 加载到内存必然会导致内存溢出 而在一些数据处理中我们不得不去处理海量数据 在做数据处理中 我们常见的手段是分解 压缩 并行 临时文件等方法

  例如 我们要将数据库(不论是什么数据库)的数据导出到一个文件 一般是Excel或文本格式的CSV 对于Excel来讲 对于POI和JXL的接口 你很多时候没有办法去控制内存什么时候向磁盘写入 很恶心 而且这些API在内存构造的对象大小将比数据原有的大小要大很多倍数 所以你不得不去拆分Excel 还好 POI开始意识到这个问题 在 的版本后 开始提供cache的行数 提供了SXSSFWorkbook的接口 可以设置在内存中的行数 不过可惜的是 他当你超过这个行数 每添加一行 它就将相对行数前面的一行写入磁盘(如你设置 行的话 当你写第 行的时候 他会将第一行写入磁盘) 其实这个时候他些的临时文件 以至于不消耗内存 不过这样你会发现 刷磁盘的频率会非常高 我们的确不想这样 因为我们想让他达到一个范围一次性将数据刷如磁盘 比如一次刷 M之类的做法 可惜现在还没有这种API 很痛苦 我自己做过测试 通过写小的Excel比使用目前提供刷磁盘的API来写大文件 效率要高一些 而且这样如果访问的人稍微多一些磁盘IO可能会扛不住 因为IO资源是非常有限的 所以还是拆文件才是上策 而当我们写CSV 也就是文本类型的文件 我们很多时候是可以自己控制的 不过你不要用CSV自己提供的API 也是不太可控的 CSV本身就是文本文件 你按照文本格式写入即可被CSV识别出来 如何写入呢?下面来说说

  在处理数据层面 如从数据库中读取数据 生成本地文件 写代码为了方便 我们未必要 M怎么来处理 这个交给底层的驱动程序去拆分 对于我们的程序来讲我们认为它是连续写即可 我们比如想将一个 W数据的数据库表 导出到文件 此时 你要么进行分页 oracle当然用三层包装即可 mysql用limit 不过分页每次都会新的查询 而且随着翻页 会越来越慢 其实我们想拿到一个句柄 然后向下游动 编译一部分数据(如 行)将写文件一次(写文件细节不多说了 这个是最基本的) 需要注意的时候每次buffer的数据 在用outputstream写入的时候 最好flush一下 将缓冲区清空下 接下来 执行一个没有where条件的SQL 会不会将内存撑爆?是的 这个问题我们值得去思考下 通过API发现可以对SQL进行一些操作 例如 通过 PreparedStatement statement = connection prepareStatement(sql) 这是默认得到的预编译 还可以通过设置

  PreparedStatement statement = connection prepareStatement(sql ResultSet TYPE_FORWARD_ONLY ResultSet CONCUR_READ_ONLY)

  来设置游标的方式 以至于游标不是将数据直接cache到本地内存 然后通过设置statement setFetchSize( ) 设置游标每次遍历的大小 OK 这个其实我用过 oracle用了和没用没区别 因为oracle的jdbc API默认就是不会将数据cache到java的内存中的 而mysql里头设置根本无效 我上面说了一堆废话 呵呵 我只是想说 java提供的标准API也未必有效 很多时候要看厂商的实现机制 还有这个设置是很多网上说有效的 但是这纯属抄袭 对于oracle上面说了不用关心 他本身就不是cache到内存 所以java内存不会导致什么问题 如果是mysql 首先必须使用 以上的版本 然后在连接参数上加上useCursorFetch=true这个参数 至于游标大小可以通过连接参数上加上 defaultFetchSize= 来设置 例如

  jdbc mysql //xxx xxx xxx xxx /abc?zeroDateTimeconvertToNull&useCursorFetch=true&defaultFetchSize= < /span>

  上次被这个问题纠结了很久(mysql的数据老导致程序内存膨胀 并行 个直接系统就宕了) 还去看了很多源码才发现奇迹竟然在这里 最后经过mysql文档的确认 然后进行测试 并行多个 而且数据量都是 W以上的 都不会导致内存膨胀 GC一切正常 这个问题终于完结了

  我们再聊聊其他的 数据拆分和合并 当数据文件多的时候我们想合并 当文件太大想要拆分 合并和拆分的过程也会遇到类似的问题 还好 这个在我们可控制的范围内 如果文件中的数据最终是可以组织的 那么在拆分和合并的时候 此时就不要按照数据逻辑行数来做了 因为行数最终你需要解释数据本身来判定 但是只是做拆分是没有必要的 你需要的是做二进制处理 在这个二进制处理过程 你要注意了 和平时read文件不要使用一样的方式 平时大多对一个文件读取只是用一次read操作 如果对于大文件内存肯定直接挂掉了 不用多说 你此时因该每次读取一个可控范围的数据 read方法提供了重载的offset和length的范围 这个在循环过程中自己可以计算出来 写入大文件和上面一样 不要读取到一定程序就要通过写入流flush到磁盘 其实对于小数据量的处理在现代的NIO技术的中也有用到 例如多个终端同时请求一个大文件下载 例如视频下载吧 在常规的情况下 如果用java的容器来处理 一般会发生两种情况

  其一为内存溢出 因为每个请求都要加载一个文件大小的内存甚至于更多 因为java包装的时候会产生很多其他的内存开销 如果使用二进制会产生得少一些 而且在经过输入输出流的过程中还会经历几次内存拷贝 当然如果有你类似nginx之类的中间件 那么你可以通过send_file模式发送出去 但是如果你要用程序来处理的时候 内存除非你足够大 但是java内存再大也会有GC的时候 如果你内存真的很大 GC的时候死定了 当然这个地方也可以考虑自己通过直接内存的调用和释放来实现 不过要求剩余的物理内存也足够大才行 那么足够大是多大呢?这个不好说 要看文件本身的大小和访问的频率

  其二为假如内存足够大 无限制大 那么此时的限制就是线程 传统的IO模型是线程是一个请求一个线程 这个线程从主线程从线程池中分配后 就开始工作 经过你的Context包装 Filter 拦截器 业务代码各个层次和业务逻辑 访问数据库 访问文件 渲染结果等等 其实整个过程线程都是被挂住的 所以这部分资源非常有限 而且如果是大文件操作是属于IO密集型的操作 大量的CPU时间是空余的 方法最直接当然是增加线程数来控制 当然内存足够大也有足够的空间来申请线程池 不过一般来讲一个进程的线程池一般会受到限制也不建议太多的 而在有限的系统资源下 要提高性能 我们开始有了new IO技术 也就是NIO技术 新版的里面又有了AIO技术 NIO只能算是异步IO 但是在中间读写过程仍然是阻塞的(也就是在真正的读写过程 但是不会去关心中途的响应) 还未做到真正的异步IO 在监听connect的时候他是不需要很多线程参与的 有单独的线程去处理 连接也又传统的socket变成了selector 对于不需要进行数据处理的是无需分配线程处理的 而AIO通过了一种所谓的回调注册来完成 当然还需要OS的支持 当会掉的时候会去分配线程 目前还不是很成熟 性能最多和NIO吃平 不过随着技术发展 AIO必然会超越NIO 目前谷歌V 虚拟机引擎所驱动的node js就是类似的模式 有关这种技术不是本文的说明重点

  将上面两者结合起来就是要解决大文件 还要并行度 最土的方法是将文件每次请求的大小降低到一定程度 如 K(这个大小是经过测试后网络传输较为适宜的大小 本地读取文件并不需要这么小) 如果再做深入一些 可以做一定程度的cache 将多个请求的一样的文件 cache在内存或分布式缓存中 你不用将整个文件cache在内存中 将近期使用的cache几秒左右即可 或你可以采用一些热点的算法来配合 类似迅雷下载的断点传送中(不过迅雷的网络协议不太一样) 它在处理下载数据的时候未必是连续的 只要最终能合并即可 在服务器端可以反过来 谁正好需要这块的数据 就给它就可以 才用NIO后 可以支持很大的连接和并发 本地通过NIO做socket连接测试 个终端同时请求一个线程的服务器 正常的WEB应用是第一个文件没有发送完成 第二个请求要么等待 要么超时 要么直接拒绝得不到连接 改成NIO后此时 个请求都能连接上服务器端 服务端只需要 个线程来处理数据就可以 将很多数据传递给这些连接请求资源 每次读取一部分数据传递出去 不过可以计算的是 在总体长连接传输过程中总体效率并不会提升 只是相对相应和所开销的内存得到量化控制 这就是技术的魅力 也许不要太多的算法 不过你得懂他

cha138/Article/program/Java/hx/201311/26253

相关参考

知识大全 java中对于复杂对象排序的模型及其实现

  排序是编程中经常要碰到的问题如果只是一般的数据库数据那么我们完全可以用数据sql语言来排序但有的时候情况并不是这样在一些特殊情况下我们不得不自己在java中写一些排序而通常排序是一件让程序员非常恼

知识大全 用句柄操纵对象

  每种编程语言都有自己的数据处理方式有些时候程序员必须时刻留意准备处理的是什么类型您曾利用一些特殊语法直接操作过对象或处理过一些间接表示的对象吗(C或C++里的指针)?  所有这些在Java里都得到

知识大全 hibernate大数据性能处理

   在项目中使用Hibernate进行大数据量的性能测试有一些总结   )在处理大数据量时会有大量的数据缓冲保存在Session的一级缓存

知识大全 java操作word

  最近在做项目的时候需要这么一个功能客户有一大堆word格式的模板需要我们用程序向模板里面填充一些数据如果是直接重新写一个Word用POI或Itext都可以搞定关键是读取并解析而且Word里有表格图

知识大全 Java线程模型如何完善相关的数据处理

Java线程模型如何完善相关的数据处理  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  Java线

知识大全 关于oracle中大对象处理的一些方法和实例

  在oracle中有个大对象(lobs)类型可用分别是blobclobbfilenclob  下面是对lob数据类型的简单介绍  lblob:二进制lob为二进制数据最长可达GB存贮在数据库中  l

知识大全 我是传播学的研究生,想找一些在线的数据分析工具,写论文的时候可以填一些数据。

我是传播学的研究生,想找一些在线的数据分析工具,写论文的时候可以填一些数据。我也是传播学研究生毕业的。主要还是看你要拿来做什么用吧。我经常用的一个在线数据分析平台叫BlueMC在数据分析的时候可以用到

知识大全 java 解析json格式数据

  有时候可能会用到json格式进行数据的传输那么怎么把接收到的数据解析出来呢?下面介绍两种解析json数据的方法      通过谷歌的Gs

知识大全 数据库连接池java实现小结

  因为工作需要要使用到连接池所以拜读了互联网上众多前辈的文章学了不少经验这里想做一个小结加上自己的想法和在一起希望能给大家一些帮助    目的  消除数据库频繁连接带来的开销和瓶颈  解决方案  不

知识大全 java连接mysql数据库乱码的解决方案

  解决方法一:  mysql安装时候的编码  看下myini有无  [mysql]  defaultcharacterset=utf  [client]defaultcharacterset=utf