redis优化秒杀系统

用redis提升基于mss的秒杀系统

使用背景:

      普通的基于mss框架的系统在并发量不是很高的状况下,对redis的需求不是很高。redis在系统中的角色至关于一个对象缓存器,在高并发的系统中(好比秒杀系统),在某一刻对数据库中的一条数据多是成千上万的用户同时去访问,系统的用户体验度直接受到数据库的性能的影响。为了保证数据的完整性,用户只能串行访问数据库中的某一条记录。redis则是把记录对应的对象序列化存储在自身的容器中,减小数据库的压力。废话很少说,接下来简单介绍redis的使用。html

redis服务器的下载:

http://www.newasp.net/soft/67186.html#downloadedredis

该地址有redis的介绍,安装以及启动。数据库

maven项目中引入redis的依赖:

<dependency>数组

   <groupId>redis.client</groupId>缓存

   <artifactId>jedis</artifactId>服务器

   <version>2.7.3</version>并发

</dependency>框架

redis核心类:

Jedis jedis = jedisPool.getResource();asp.net

    返回一个操做redis对象池的对象,该对象的存储方式相似于map同样也是采用键值对来存储对象的。jedisPool的初始化采用构造函数指明redis服务器所在的ip地址跟监听的接口,若是实验的redis服务器在本机则ip地址填写localhost便可。maven

   如以上所说,redis服务器以键值对来存储对象,可是值得存储方式是将对象序列化再进行存储。jdk为用户提供了一套对象序列化API,此时你们想到的应该是让被序列化类去实现Serializable接口。这种方法是可行的,可是缺点在与sun提供的这套API是比较低效率的,并且压缩以后的对象仍是比较占空间的。此时咱们能够采用Protostuff对象提供的序列化API,测试证实了这套API的序列化效率更高切压缩空间更小。

Protostuff依赖:

<dependency>
  <groupId>com.dyuproject.protostuff</groupId>
  <artifactId>protostuff-core</artifactId>
  <version>1.0.8</version>
</dependency>
<dependency>
  <groupId>com.dyuproject.protostuff</groupId>
  <artifactId>protostuff-runtime</artifactId>
  <version>1.0.8</version>
</dependency>
<dependency>
<groupId>velocity</groupId>
  <artifactId>velocity</artifactId>
  <version>1.4</version>
  <scope>test</scope>
</dependency>
<dependency>
  <groupId>commons-collections</groupId>
  <artifactId>commons-collections</artifactId>
  <version>3.2</version>
</dependency>

protostuffIOUtil使用:

序列化:

RuntimeSchema<T> schema = RuntimeSchema.createFrom(T.class);

首先是告知protostuffIOUtil即将要序列化的对象的序列化规则。

byte[] bytes = ProtostuffIOUtil.toByteArray(Object, schema,LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE));

将Object对象进行序列化,schema则是序列化规则,参数三是序列过过程当中使用到的缓冲区。

反序列化:

  如上面提到的,schema表明序列化规则,因此经过Object object = schema.newMessage();可让容器按规则生成一个空对象,在根据冲redis中拿到的序列值进行反化

ProtostuffIOUtil.mergeFrom(bytes,object,schema);

该方法是根据参数三的对象序列化规则,对参数一的序列值进行操做,而后将对象封装在空对象object中。

redis的存取:

  讲了这么对先在该说说redis的存取方法了,如同上面我所说的同样,跟map集合很类似的是redis的取值也是使用get(“key”)方法。不过传入的参数必须是字节数组,并且方法的返回值也是一个字节数组,因此只要将返回的字节数组使用Protostuff的反序列化便可获得所要的对象。

  byte[] bytes = jedis.get(key.getBytes());

  不一样的是redis的存储并非使用put()方法,而是setex(key.getBytes(), timeout, bytes);方法。方法中的参数一是键值对中的键,参数三是序列化后的对象字节数组,参数二是指明该对象在redis服务器中缓存多长时间,它的单位是秒。

int timeout = 60 * 60;
String result = jedis.setex(key.getBytes(), timeout, bytes);

实战案例:

package org.seckill.dao.cache;import com.dyuproject.protostuff.LinkedBuffer;import com.dyuproject.protostuff.ProtostuffIOUtil;import com.dyuproject.protostuff.runtime.RuntimeSchema;import org.seckill.entity.Seckill;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import redis.clients.jedis.Jedis;import redis.clients.jedis.JedisPool;/** * Created by Administrator on 2016/8/10 0010. */public class RedisDao{    private final Logger logger = LoggerFactory.getLogger(this.getClass());    private JedisPool jedisPool;    //序列化工具类,泛型指明该类序列化的规则    private RuntimeSchema<Seckill> schema = RuntimeSchema.createFrom(Seckill.class);    public RedisDao(String ip,int port){        jedisPool = new JedisPool(ip,port);    }    public Seckill getSeckill(long seckillId){        //redis操做逻辑        try {            Jedis jedis = jedisPool.getResource();            try {                String key = "seckill:" + seckillId;                //并无实现内部序列化操做                //get->byte[]->反序列化->Object(Seckill)                //采用自定义序列化                byte[] bytes = jedis.get(key.getBytes());                //缓存从新取到                if(bytes != null){                    //空对象                    Seckill seckill = schema.newMessage();                    ProtostuffIOUtil.mergeFrom(bytes,seckill,schema);                    //seckill 被反序列了                    return seckill;                }            }finally {                jedis.close();            }        }catch (Exception e){            logger.error(e.getMessage(),e);        }        return null;    }    public String putSeckill(Seckill seckill){        //set Object(Seckill)->序列化->byte[]        try{            Jedis jedis = jedisPool.getResource();            try {                String key = "seckill:" + seckill.getSeckillId();                byte[] bytes = ProtostuffIOUtil.toByteArray(seckill, schema,                        LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE));                //超时缓存                int timeout = 60 * 60;                String result = jedis.setex(key.getBytes(), timeout, bytes);                return result;            }finally{                jedis.close();            }        }catch (Exception e){            logger.error(e.getMessage(),e);        }        return null;    }}若有什么不足或者错误的地方但愿你们留言指出,转载的话请标明出处;
相关文章
相关标签/搜索