`
mozhenghua
  • 浏览: 324496 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

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

阅读更多

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

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

         

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

          

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

 

  初始化测试数据       

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

  1. 向内存中写
    Map<Integer, Long[]> data = new HashMap<Integer, Long[]>();
    
    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<Integer, Long[]> data = new HashMap<Integer, Long[]>();
    
    		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的服务器,改天找一台来测试一下,到时候再将测试结果公布一下。

  • 大小: 14.1 KB
分享到:
评论

相关推荐

    使用 内存缓存与硬盘缓存异步下载图片

    "使用内存缓存与硬盘缓存异步下载图片"这一主题涉及到的关键技术主要包括内存缓存、硬盘缓存、AsyncTask以及GridView。下面将详细阐述这些知识点。 1. **内存缓存**: 内存缓存是一种快速的数据存储机制,它将经常...

    老硬盘使用内存做缓存的程序

    1. **速度提升**:内存的读写速度远快于硬盘,因此使用内存作为缓存能显著加快数据访问速度。 2. **减少硬盘磨损**:频繁的硬盘读写会导致硬盘寿命缩短,缓存技术可以减少硬盘的物理操作,延长其使用寿命。 3. **...

    图片二级缓存

    二、内存缓存与磁盘缓存 1. 内存缓存:内存缓存(也称为LRU缓存)将图片存储在应用程序的内存中。由于内存读写速度快,图片加载迅速,但内存资源有限,当系统需要更多内存时,可能会清除部分缓存以释放空间。因此,...

    Fuse,用kotlin编写的android的简单通用lru内存/磁盘缓存.zip

    1. **多层缓存**:`Fuse`结合了内存和磁盘两层缓存,内存缓存提供快速的读写速度,而磁盘缓存则用于持久化数据,即使应用关闭也能恢复。 2. **Kotlin实现**:利用Kotlin的现代特性,`Fuse`提供了简洁易用的API,使得...

    基与LruCache(内存缓存)和 DiskLruCache(硬盘缓存)的图片三级缓存工具类

    相比于内存缓存,硬盘缓存不会占用宝贵的运行内存,但访问速度相对较慢。DiskLruCache同样限制了总的存储空间,以防止磁盘空间被过度消耗。 构建一个基于LruCache和DiskLruCache的图片三级缓存工具类,通常会包括...

    磁盘高速缓存程序

    这种技术通过预读取和存储频繁访问的数据到内存中,避免了反复访问速度较慢的硬盘,从而显著加快了数据读取速度。在早期的个人电脑系统中,由于硬盘读写速度相对较慢,这类缓存程序尤为重要。 SMARTDRV.EXE 是一个...

    PHP内存缓存的配置及使用

    PHP内存缓存是提高Web应用程序性能的关键技术之一,它通过存储经常访问的数据在内存中,避免了反复从数据库读取,从而显著提升了网站的响应速度。本文将详细介绍如何在Windows环境下配置和使用PHP的内存缓存系统——...

    Android内存缓存图片的标准方法

    内存缓存是一种将常用数据存储在内存中以便快速访问的技术。在Android中,内存缓存可以显著提高应用程序的响应速度,特别是对于图片这种频繁读取的数据。通过将图片缓存在内存中,应用可以快速获取图片,而无需每次...

    ListView加载网络图片“内存双缓存”+硬盘缓存

    内存缓存的优势在于访问速度快,但容量有限,因此需要合理管理,防止内存溢出。 2. **双缓存** “内存双缓存”是指在内存中维护两层缓存,一层是强引用缓存,另一层是弱引用缓存。强引用缓存中的图片不会被垃圾...

    iOS开发缓存机制之—内存缓存机制

    在iOS应用开发中,缓存机制扮演着至关重要的角色,它可以显著提高用户体验,减少网络延迟,避免不必要的数据传输。...在下一篇文章中,将会介绍iOS的磁盘缓存机制,这将进一步增强缓存系统的功能和持久性。

    存储系统-缓存-磁盘学习

    DRAM(动态随机存取内存)是一种常见的系统内存类型,相比硬盘,其访问速度更快。在存储系统中,DRAM常作为CPU和硬盘之间的缓存层,被称为二级缓存或L2 Cache。当CPU需要数据时,会首先查找L2 Cache,如果找到则直接...

    FancyCache 将系统内存或闪存虚拟成硬盘缓存的软件

    它把从硬盘中读取的数据存入系统内存或闪存,使系统在下次访问该数据时可以很快从内存读取,避免再次读取速度较慢的硬盘,从而突破硬盘瓶颈,提升系统性能。 FancyCache还具有检测和利用系统未识别内存的功能,解决...

    将固态作为机械硬盘缓存工具,类似Intel快速储存驱动

    固态硬盘因为其快速的读写速度,可以作为临时存储区域,存储那些频繁访问的数据,当这些数据被请求时,可以从SSD缓存中快速获取,而不是等待较慢的HDD查找。此外,提到“绿色无毒,亲测可用”,这通常是指该软件是...

    报表性能优化方案之数据集缓存与共享

    综上所述,FineReport提供的数据集缓存与共享机制,结合了内存缓存和磁盘缓存的各自优势,并通过合理设置缓存参数,优化报表性能。在实际应用中,需要根据报表的具体使用场景和数据特性,选择合适的缓存策略,以达到...

    磁盘缓存优化版

    磁盘缓存,也称为内存缓冲区或页面缓存,是操作系统为了提高硬盘读写速度而设立的一块内存空间。当数据被请求时,如果已经在缓存中,操作系统会直接从缓存读取,而不是等待较慢的硬盘响应,这大大提高了数据访问的...

    Bitmap图片的三级缓存DEMO 三层缓存 强引用 软引用DEMO

    2. **磁盘缓存**:一般选择SQLite数据库或文件系统进行存储,虽然访问速度较慢,但容量大,可持久化数据。磁盘缓存通常会进行文件系统的优化,如使用LRU策略清理旧的或不常访问的文件。 3. **网络缓存**:通常指的...

    LRU页面缓存-磁盘

    磁盘缓存的工作流程大致如下: 1. **初始化**:创建一个大小固定的哈希表,并设定一个最大缓存容量。 2. **缓存命中**:当需要访问的数据在缓存中,直接返回,减少磁盘I/O。 3. **缓存未命中**:如果数据不在缓存中...

    CacheXset磁盘缓存

    这种技术借鉴了计算机硬件中的缓存层次结构,通过在CPU与硬盘之间构建一个高速的数据缓冲层,实现了数据访问速度的显著提升。 CacheXset的使用方法在“CacheXset官方使用说明.doc”文档中会有详细介绍,一般包括...

    Android仿今日头条新闻缓存加载功能实现和DiskLruCache硬盘缓存学习

    总之,通过以上步骤,我们可以实现类似今日头条的新闻缓存加载功能,结合内存和硬盘缓存,既提高了用户体验,又降低了服务器压力。在实际项目中,还可以根据需求调整缓存策略,比如添加优先级、使用更复杂的缓存淘汰...

    DiskLruCache磁盘缓存java源码

    在磁盘缓存中,LRU策略通过记录每个文件的访问时间来决定何时删除某个文件。 2. **结构设计** DiskLruCache的结构包含一个主目录,每个缓存项都在该目录下拥有自己的子目录。每个子目录下有四个文件,分别存储键、...

Global site tag (gtag.js) - Google Analytics