码迷,mamicode.com
首页 > 其他好文 > 详细

redis优化秒杀系统

时间:2016-08-24 17:00:18      阅读:480      评论:0      收藏:0      [点我收藏+]

标签:

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

使用背景:

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

redis服务器的下载:

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

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

maven项目中引入redis的依赖:

<dependency>

   <groupId>redis.client</groupId>

   <artifactId>jedis</artifactId>

   <version>2.7.3</version>

</dependency>

redis核心类:

Jedis jedis = jedisPool.getResource();

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

   如以上所说,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;
}
}
如有什么不足或者错误的地方希望大家留言指出,转载的话请标明出处;

redis优化秒杀系统

标签:

原文地址:http://www.cnblogs.com/onedaylin/p/5801419.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!