发表于: 2017-08-09 22:08:15

2 1103


一.今天完成的事情

1.学习memcached相关的知识

自己的理解就是,memcached可以先将常用的数据放在内存中,当客户端请求数据时先从缓存中寻找,找不到了以后再去访问数据库,从数据库中找到之后会将数据放进缓存,以后查询该数据时,可以从内存中找,因为内存的读取速度远快于数据库,所以这样能够提高查询效率.

memcached不仅可以作为简单的缓存,还可以做分布式,但是这要求我们在代码中体现出来.memcached将分配给它的内存分为一个一个slab_class,每个slab_class又可以分为若干个slab,每个slab又可以分为若干个page,每个page中又分为trunk,trunk就是memcached最小的存取单位,在存放数据时,memcached会根据数据的大小分配创建和该数据相近的trunk,而且会创建相应的page,以及slab,所以在刚刚安装好memcached时,通过stats slab是没有结果的,必须要放入一个数据才可以,这样memcached实际上是会对内存产生一定的浪费,memcached的分布式是简单的通过增加节点实现的,可以在程序中配置,但是没有主从关系,所以一旦服务器重启,缓存中的数据就会丢失.

2.使用memcached缓存数据

首先,安装memcached客户端,注意要先安装libevent

其次,启动memcached服务,加参数,几个常用的参数有-m 占用内存大小,默认为64M,-p 为端口号, -l 为服务器ip,-u 为以什么用户执行,必须是root才有作用,-d start是启动

如:/usr/local/bin/memcached -d start -p 9006 -m 128 -u root

意思是启动服务,ip默认本机,端口号为9006,占用内存128M,以root身份运行

接着可以用telnet ip 端口号链接至memcache服务

之后用stats可以查看memcacahed基本状态信息,用stats slab查看slab信息,其中比较重要的参数有

用这两个参数计算缓存命中率.

然后就是选择一个java memcached客户端(目前有三种,java官方传统客户端,spymemcached,XMemcached)

编写demo测试


package com.putaoteng.task5.utils;

import java.io.IOException;

import java.util.concurrent.TimeoutException;

import net.rubyeye.xmemcached.GetsResponse;

import net.rubyeye.xmemcached.MemcachedClient;

import net.rubyeye.xmemcached.MemcachedClientBuilder;

import net.rubyeye.xmemcached.XMemcachedClientBuilder;

import net.rubyeye.xmemcached.command.BinaryCommandFactory;

import net.rubyeye.xmemcached.exception.MemcachedException;

import net.rubyeye.xmemcached.utils.AddrUtil;

public class Cache {

private MemcachedClientBuilder builder = null;

private MemcachedClient client = null;

// 构造方法,参数为memcached的ip地址以及权重值

public Cache(String address, int[] weight) {

builder = new XMemcachedClientBuilder(AddrUtil.getAddresses(address), weight);

// 设置连接池大小,即客户端个数

builder.setConnectionPoolSize(50);

//宕机报警

builder.setFailureMode(true);

//使用二进制文件

builder.setCommandFactory(new BinaryCommandFactory());

try {

this.client = builder.build();

} catch (IOException e) {

Log.loggerCreate(LogLevel.ERROR, "创建Memcached客户端失败:" + e.getMessage());

e.printStackTrace();

}

}

// 添加方法

public void set(String key, int exp, Object value) {

try {

if (!client.set(key, exp, value)) {

System.err.println("set error, key is" + key + "value is" + value);

}

} catch (TimeoutException e) {

Log.loggerCreate(LogLevel.ERROR, "MemcachedClient operation timeout-----(set)" + e.getMessage());

e.printStackTrace();

} catch (InterruptedException e) {

Log.loggerCreate(LogLevel.ERROR, "MemcachedClient operation interrupted-----(set)" + e.getMessage());

e.printStackTrace();

} catch (MemcachedException e) {

Log.loggerCreate(LogLevel.ERROR, "MemcachedClient operation failed-----(set)" + e.getMessage());

e.printStackTrace();

}

}

// 删除一个key

public void delete(String key) {

try {

client.delete(key);

} catch (TimeoutException e) {

Log.loggerCreate(LogLevel.ERROR, "MemcachedClient operation timeout-----(delete)" + e.getMessage());

e.printStackTrace();

} catch (InterruptedException e) {

Log.loggerCreate(LogLevel.ERROR, "MemcachedClient operation interrupted-----(delete)" + e.getMessage());

e.printStackTrace();

} catch (MemcachedException e) {

Log.loggerCreate(LogLevel.ERROR, "MemcachedClient operation failed-----(delete)" + e.getMessage());

e.printStackTrace();

}

}

//原子更新,将比较和更新绑定为一个原子的操作

public boolean update(String key, Object value) {

try {

GetsResponse<Integer> result =  client.gets(key);

long cas = result.getCas();

if (!client.cas(key, 0, value, cas)){

return false;

}

} catch (TimeoutException e) {

Log.loggerCreate(LogLevel.ERROR, "MemcachedClient operation timeout-----(update)" + e.getMessage());

e.printStackTrace();

} catch (InterruptedException e) {

Log.loggerCreate(LogLevel.ERROR, "MemcachedClient operation interrupted-----(update)" + e.getMessage());

e.printStackTrace();

} catch (MemcachedException e) {

Log.loggerCreate(LogLevel.ERROR, "MemcachedClient operation failed-----(update)" + e.getMessage());

e.printStackTrace();

}

return true;

}

//根据key,获取值

public Object get(String key){

try {

return client.get(key);

} catch (TimeoutException e) {

Log.loggerCreate(LogLevel.ERROR, "MemcachedClient operation timeout-----(get)" + e.getMessage());

e.printStackTrace();

} catch (InterruptedException e) {

Log.loggerCreate(LogLevel.ERROR, "MemcachedClient operation interrupted-----(get)" + e.getMessage());

e.printStackTrace();

} catch (MemcachedException e) {

Log.loggerCreate(LogLevel.ERROR, "MemcachedClient operation failed-----(get)" + e.getMessage());

e.printStackTrace();

}

return null;

}

//额外添加服务

public void addServer(String server, int port, int weight){

try {

client.addServer(server, port, weight);

} catch (IOException e) {

Log.loggerCreate(LogLevel.ERROR, "添加Memcacahed失败:" + e.getMessage());

e.printStackTrace();

}

}

//移除一个服务

public void removeServer(String hostList){

client.removeServer(hostList);

}

}

该类就是主要的执行增加,更新,删除数据的操作,其中更新是将比较和更新绑定在一起原子操作,同时捕捉各种异常,记录日志服务.

编写测试类,测试该类的结果

测试代码,设置在缓存中保存10分钟:

结果:

最后,就是在task5中使用,今天没有用spring整合memcachend,使用简单的定义类的方式,以home页面为例

添加日志是为了查看结果,逻辑很简单,当有请求时先查询缓存中的key为list的值,该值若为空,则从数据库中获取数据,然后将该数据放入缓存,设置有效时间为30天,以后读取时从缓存读取.

3.测试增加缓存之后的结果

在这点上遇到了一个问题,即我从日志中看,缓存确实起到了作用,除第一次是从数据库中获取数据,其余均是从缓存获取数据,从日志可以看到,执行一个controller,包括逻辑和读取数据,大部分时间仅用几毫秒,少数数据用20毫秒左右

缓存命中率也还行

在缓存中查找数据也可以找到

但是压力测试的结果就很一般,我用的还是单线程,无限循环测试,结果如下

基本都是平均95毫秒左右,

不用缓存的测试结果,基本相同

今天没时间了,明天解决它

二.明天的计划

1.解决今天的 问题

2.将memcached和spring整合在一起,有的部分可以用spring AOP实现,减少冗余代码

3.如果有时间,尽量完成这一步骤

三.问题

以上

四,收获

memcached相关知识,具体见以上

五.进度

预计用一周的时间完成任务六,今天一过就剩下六天了,应该可以完成.


返回列表 返回列表
评论

    分享到