热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

内存缓存与硬盘缓存访问速度的比较

   这两天在为一个应用做solr搜索方案定制的过程中,需要用到solr的fieldcache,在估算fieldcache需要的内存容量,缓存中key是int,value是两个64

      这两天在为一个应用做solr搜索方案定制的过程中,需要用到solr的fieldcache,在估算fieldcache需要的内存容量,缓存中key是int,value是两个64bit大小的long类型数组,数据量大约是8100w,64×8100w/1024/1024,大致需要10G的容量,

 然而服务器总共也只有8G内存,实在无法支持这么大容量的缓存数据。

         

    于是开始想是不是可以有其他的替换的方案,可以不需要使用这么大的缓存容量,有能满足缓存的需要。考虑是不是可以将fieldcache中的数据内存存放到硬盘中去,在调用的时候可以通过key值快速计算出文档中的偏移量从而量数据取出,因为直观感觉只要知道一个文件偏移量而取内存应该是很快的。

          

    光有感觉是不行的,还需要实际测试一下,测试硬盘访问速度到底和内存访问速度相差多大。

 

  初始化测试数据       

    分别写一个向内存中和向硬盘中写数据的代码,内容如下:

  1. 向内存中写

    Map data = new HashMap();
    for (int i = 0; i <2000000; i++) {
    data.put(i, new Long[] { (long) (i + 1), (long) (i + 2) });
    }

     

  2. 向硬盘中写

    import java.io.File;
    import java.io.RandomAccessFile;
    import org.apache.lucene.analysis.Analyzer;
    import org.apache.lucene.analysis.payloads.PayloadHelper;
    import org.apache.lucene.analysis.standard.StandardAnalyzer;
    import org.apache.lucene.document.Document;
    import org.apache.lucene.document.Field;
    import org.apache.lucene.index.IndexWriter;
    import org.apache.lucene.index.IndexWriterConfig;
    import org.apache.lucene.index.IndexWriterConfig.OpenMode;
    import org.apache.lucene.store.Directory;
    import org.apache.lucene.store.SimpleFSDirectory;
    import org.apache.lucene.util.Version;
    public class DocReplication {
    public static Analyzer analyzer;
    static {
    analyzer = new StandardAnalyzer(Version.LUCENE_34);
    }
    public static void main(String[] arg) throws Exception {
    RandomAccessFile randomFile = new RandomAccessFile(new File(
    "DocReplication.text"), "rw");
    Directory dir = new SimpleFSDirectory(new File("indexdir"));
    IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE_34,
    analyzer);
    iwc.setOpenMode(OpenMode.CREATE_OR_APPEND);
    IndexWriter writer = new IndexWriter(dir, iwc);
    for (int i = 0; i <2000000; i++) {
    // 向一个随机访问文件中写
    randomFile.write(PayloadHelper.encodeInt(i));
    randomFile.write(long2Array(i + 1));
    randomFile.write(long2Array(i + 2));
    // 向lucene中document中写
    Document doc = new Document();
    doc.add(new Field("id", String.valueOf(i), Field.Store.YES,
    Field.Index.NOT_ANALYZED_NO_NORMS));
    doc.add(new Field("id2", String.valueOf(i), Field.Store.YES,
    Field.Index.NOT_ANALYZED_NO_NORMS));
    writer.addDocument(doc);
    System.out.println("point:" + randomFile.getFilePointer());
    }
    writer.commit();
    writer.close();
    randomFile.close();
    }
    static byte[] long2Array(long val) {
    int off = 0;
    byte[] b = new byte[8];
    b[off + 7] = (byte) (val >>> 0);
    b[off + 6] = (byte) (val >>> 8);
    b[off + 5] = (byte) (val >>> 16);
    b[off + 4] = (byte) (val >>> 24);
    b[off + 3] = (byte) (val >>> 32);
    b[off + 2] = (byte) (val >>> 40);
    b[off + 1] = (byte) (val >>> 48);
    b[off + 0] = (byte) (val >>> 56);
    return b;
    }
    }

     以上向内存中和向硬盘中写都是写200w条数据,在执行向硬盘中写的过程中分别是向lucene的索引文件和向RandomAccessFile随机文件中写,下面介绍一下用RandomAccessFile写的文件结构,文件中一条记录的数据结构,如图:
    《内存缓存与硬盘缓存访问速度的比较》
     一条记录的长度为20字节,只要拿到docid也就是key值就能计算出
    RandomAccessFile的文件偏移量=docid × 20。

     至于为什么要向lucene索引文件中写的原因是,想比较一下通过lucene的 indexread.get(docid) 方法取得到document的fieldvalue 的访问速度,和用RandomAccessFile访问缓存值的速度到底谁更快。

 

编写读数据测试案例

  1. 从自定义随机文件中读取

    public static void main(String[] args) throws Exception {
    RandomAccessFile randomFile = new RandomAccessFile(new File(
    "DocReplication.text"), "rw");
    long current = System.currentTimeMillis();
    for (int i = 0; i <100000; i++) {
    int docid = (int) (Math.random() * 2000000);
    randomFile.seek(docid * 20 + 4);
    randomFile.readLong();
    randomFile.readLong();
    }
    System.out.println((System.currentTimeMillis() - current) / 1000);
    randomFile.close();
    }

     

  2. 从内存中读取

    public static void main(String[] args) {
    Map data = new HashMap();
    for (int i = 0; i <2000000; i++) {
    data.put(i, new Long[] { (long) (i + 1), (long) (i + 2) });
    }
    long start = System.currentTimeMillis();
    Long[] row = null;
    long tmp = 0;
    for (int i = 0; i <100000; i++) {
    int doc = (int) (Math.random() * 2000000);
    row = data.get(doc);
    tmp = row[0];
    tmp = row[1];
    }
    System.out.println((System.currentTimeMillis() - start) );
    }

     

  3. 从lucene索引文件中随机访问

    public static void main(String[] args) throws Exception {
    Directory dir = new SimpleFSDirectory(new File("indexdir"));
    long start = System.currentTimeMillis();
    IndexReader reader = IndexReader.open(dir);
    Document doc = null;
    for (int i = 0; i <100000; i++) {
    int docid = (int) (Math.random() * 2000000);
    doc = reader.document(docid);
    doc.get("id");
    doc.get("id2");
    }
    System.out.println("consume:" + (System.currentTimeMillis() - start)/ 1000);
    }

     三个测试案例,都是从目标存储中从有200w数据量的cache中随机取出一个key,通过key取到value,这样的过程重复10w次,看看需要花费多少时间。

测试结果:

  从自定义随机文件中读取 从内存中读取 从lucene索引文件中随机访问
 总耗时 3717ms 75ms 1673ms

 

    从测试结果看,通过内存读cache是最快的,无疑和预想的结果是一致的,但是本来以为从自定义的随机文件中读取速度要比从lucene的indexreader来取要快些,但从测试结果看恰恰相反,从lucene的indexreader要比自定义随机文件快差不多一倍。

   比较之下,内存和磁盘的访问速度比是75比1673=1比22,速度还是相差挺大的,我很好奇,要是将磁盘改成SSD存储介质的话,磁盘访问速度会有多大提升,无奈现在测试环境中还没有SSD的服务器,改天找一台来测试一下,到时候再将测试结果公布一下。


推荐阅读
  • 本文详细介绍了Java编程语言中的核心概念和常见面试问题,包括集合类、数据结构、线程处理、Java虚拟机(JVM)、HTTP协议以及Git操作等方面的内容。通过深入分析每个主题,帮助读者更好地理解Java的关键特性和最佳实践。 ... [详细]
  • 从 .NET 转 Java 的自学之路:IO 流基础篇
    本文详细介绍了 Java 中的 IO 流,包括字节流和字符流的基本概念及其操作方式。探讨了如何处理不同类型的文件数据,并结合编码机制确保字符数据的正确读写。同时,文中还涵盖了装饰设计模式的应用,以及多种常见的 IO 操作实例。 ... [详细]
  • golang常用库:配置文件解析库/管理工具viper使用
    golang常用库:配置文件解析库管理工具-viper使用-一、viper简介viper配置管理解析库,是由大神SteveFrancia开发,他在google领导着golang的 ... [详细]
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • 网络攻防实战:从HTTP到HTTPS的演变
    本文通过一系列日记记录了从发现漏洞到逐步加强安全措施的过程,探讨了如何应对网络攻击并最终实现全面的安全防护。 ... [详细]
  • 本文详细解析了Python中的os和sys模块,介绍了它们的功能、常用方法及其在实际编程中的应用。 ... [详细]
  • 掌握远程执行Linux脚本和命令的技巧
    本文将详细介绍如何利用Python的Paramiko库实现远程执行Linux脚本和命令,帮助读者快速掌握这一实用技能。通过具体的示例和详尽的解释,让初学者也能轻松上手。 ... [详细]
  • 本文详细介绍了Java中org.neo4j.helpers.collection.Iterators.single()方法的功能、使用场景及代码示例,帮助开发者更好地理解和应用该方法。 ... [详细]
  • 本文将介绍如何编写一些有趣的VBScript脚本,这些脚本可以在朋友之间进行无害的恶作剧。通过简单的代码示例,帮助您了解VBScript的基本语法和功能。 ... [详细]
  • 技术分享:从动态网站提取站点密钥的解决方案
    本文探讨了如何从动态网站中提取站点密钥,特别是针对验证码(reCAPTCHA)的处理方法。通过结合Selenium和requests库,提供了详细的代码示例和优化建议。 ... [详细]
  • 1:有如下一段程序:packagea.b.c;publicclassTest{privatestaticinti0;publicintgetNext(){return ... [详细]
  • 1.如何在运行状态查看源代码?查看函数的源代码,我们通常会使用IDE来完成。比如在PyCharm中,你可以Ctrl+鼠标点击进入函数的源代码。那如果没有IDE呢?当我们想使用一个函 ... [详细]
  • MQTT技术周报:硬件连接与协议解析
    本周开发笔记重点介绍了在新项目中使用MQTT协议进行硬件连接的技术细节,涵盖其特性、原理及实现步骤。 ... [详细]
  • 本文详细介绍了 MySQL 的查询处理流程,包括从客户端连接到服务器、查询缓存检查、语句解析、查询优化及执行等步骤。同时,深入探讨了 MySQL 中的乐观锁机制及其在并发控制中的应用。 ... [详细]
  • MySQL缓存机制深度解析
    本文详细探讨了MySQL的缓存机制,包括主从复制、读写分离以及缓存同步策略等内容。通过理解这些概念和技术,读者可以更好地优化数据库性能。 ... [详细]
author-avatar
凌彩霞_685
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有