"缓存"问题

Submitted by Lizhe on Thu, 06/08/2017 - 10:27

 

cache everything you can

缓存 实际上仍然是一种通过 消耗硬件资源和存储空间 换取 运行速度的手段

通过将数据转移到高速载体或者预先完成初始化动作来保证程序运行期间的速度

  • 数据库连接池
  • 线程池
  • spring 对象容器

等都是缓存技术的一种实现

我们来看几种典型应用

1. 使用静态块或静态变量

想象一下你的"商城"应用中有一个<select>选项, 用于让用户选择商品类别, 这些类别可能几年都不会更新一次, 它们被存储在文件或者数据库中, 当用户打开页面时每次都从文件系统或数据加载一遍这些数据显然不合适

最简单的做法是通过 静态变量 , 静态变量的生命周期与class在类加载器中的生命周期是一样的,所以很难被回收掉, 这个对象会一直存储在java 堆中,也就构成了一个简单的构建在堆内存上的缓存

private static List<String> types = getTypes();

2. 使用Spring对象池中的单例对象

spring容器启动之后会一直持有一个保存单例对象的hashmap(猜测是静态的,跟上面原理一样) , 每个单例对象在容器容器启动时初始化, 也就是说每个单例对象自有的类成员变量不会被销毁, 通过这些成员变量很容易做出一种懒汉式的缓存机制, 用户第一次调用时,或者启动应用时通过其他手段调用一次(比如构造函数,当对象被new出来时候就调用一下), 之后就可以一直返回这个已经处理过的对象

例如

public List<String> getTypes(){

    if(types==null){

        return initTypes();

    }else{

        return types

    }

}

Spring的对象容器本身就是一个用于缓存对象的缓存, 这也是"我们为什么要使用spring的一个重要原因之一"

3. 使用memcache

memcache可以将文本或者可序列化对象直接存储在其他server的内存中, 这种模型甚至可以超出一般缓存的定义转而成为共享数据的方式 ( 比如tomcat集群中它可以解决session共享问题 )

4. get请求

不要诧异, get请求实际上也使用了缓存, 对于一些 通知, 文本内容的信息, 完全可以避免使用post方法转而使用get, get方法会充分利用浏览器本地缓存, 减少对服务器的依赖

5. 只读缓存

典型的只读缓存实际上是爬虫产生的搜索index, 这些结果集并不需要实时更新, 你可能需要准备一个batch(springbatch是一个不错的选择,或者直接使用cron调用脚本也可以处理简单的更新), 如果产生的缓存数据量特别大的话你甚至可以考虑使用Hadoop的HDFS文件系统或者使用HBase或者其他NoSql数据库