redis存储对象大小2m
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了redis存储对象大小2m相关的知识,希望对你有一定的参考价值。
redis存储对象大小2m
参考技术A Redis 存储字符串和对象1 测试类
import redis.clients.RedisClinet;
import redis.clients.SerializeUtil;
import redis.clients.jedis.Jedis;
public class Test
/**
* Administrator
* @param args
*/
public static void main(String[] args)
// 操作单独的文本串
Jedis redis= new Jedis( "10.2.31.38", 6379);
redis.set( "key", "value");
System. out.println(redis.get( "key"));
System. out.println(redis.del( "key"));
// 操作实体类对象
Goods good= new Goods(); // 这个Goods实体我就不写了啊
good.setName( "洗衣机" );
good.setNum(400);
good.setPrice(19l);
redis.set( "good".getBytes(), SerializeUtil. serialize(good));
byte[] value = redis.get( "good".getBytes());
Object object = SerializeUtil. unserialize(value);
if(object!= null)
Goods goods=(Goods) object;
System. out.println(goods.getName());
System. out.println(goods.getNum());
System. out.println(goods.getPrice());
System. out.println(redis.del( "good".getBytes()));
// 操作实体类对象2(实际上和上面是一样的)
String key= "goods-key";
Goods g= new Goods();
g.setName( "电风扇--d" );
g.setNum(200);
String temp=RedisClinet. getInstance().set(g, key);
System. out.println(temp);
Object o=RedisClinet. getInstance().get(key);
if(o!= null)
Goods g1=(Goods)o;
System. out.println(g1.getName());
System. out.println(g1.getNum());
System. out.println(RedisClinet. getInstance().del(key));
2 RedisClinet 客户端类
package redis.clients;
import redis.clients.jedis.Jedis;
/**
*
* @author ajun
*
*/
public class RedisClinet
private static final String ip= "10.2.31.38";
private static final int port=6379;
protected static RedisClinet redis = new RedisClinet ();
protected static Jedis jedis = new Jedis( ip, port);;
static
protected RedisClinet()
System. out.println( " init Redis ");
public static RedisClinet getInstance()
return redis;
/**set Object*/
public String set(Object object,String key)
return jedis.set(key.getBytes(), SerializeUtil.serialize(object));
/**get Object*/
public Object get(String key)
byte[] value = jedis.get(key.getBytes());
return SerializeUtil. unserialize(value);
/**delete a key**/
public boolean del(String key)
return jedis.del(key.getBytes())>0;
3 序列化工具类
/**
*
*/
package redis.clients;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
/**
* @author Administrator
*
*/
public class SerializeUtil
public static byte[] serialize(Object object)
ObjectOutputStream oos = null;
ByteArrayOutputStream baos = null;
try
// 序列化
baos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(baos);
oos.writeObject(object);
byte[] bytes = baos.toByteArray();
return bytes;
catch (Exception e)
return null;
public static Object unserialize( byte[] bytes)
ByteArrayInputStream bais = null;
try
// 反序列化
bais = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bais);
return ois.readObject();
catch (Exception e)
return null;
Redis 存储压缩实战
参考技术Axx的模型分计算,由于客户对响应要求比较高,要求在20ms内就需要返回, 同时QPS要求为60W .
所以存储这一块的选则就是使用的Redis的集群(无主从,更多资源用来存储,同时高可用要求不高)
一开始使用最直接使用了String的Key-Value入库 ; 结果,才入了八亿的数据,内存就去到了140g .对单点分析之后得出对象数量3000w, 数据内存消耗:2.72g,大约一条记录数据大小是97字节,但实际节点占用内存:5.13g . 运维给出来的答复是 :
数据量: 50亿+
数据格式: MD5(imei) :Score1(double),Score2(double)
单条纯数据量: 32字节
首先ZipList是作为Redis的一种底层数据结构, 在一定条件下可作用于HashTable,List,Set的底层实现,
由于其设定是使用一整块的连续内存 (可看似数组结构) ,减少了内存碎片的产生,同时在提供了较高的效率 .
由于ZipList的初始是申请一个连续的长度为zlbytes的内存 , 所以正常情况下对ZipList的修改都会触发内存的重分配, 同时有可能发生数据的复制开销比较大.
这也是ZipList不适合用于存放过大量数据.
以下是HashTable底层使用ZipList的相关配置:
要使用ZipList作为存储结构,所以使用HashTable的时候要将entry的数量控制在ZipList的hash-max-ziplist-entries阈值内 ( 极光这里配置的是256 先不做修改,按这个条件来 )
根据上面的需要将entry数量控制再256以内 , 所以按照50亿的总数量计算的话那么, Redis Key 的KeyNum应该是:
这里的KeyNum根据实际情况可以预估大一点以备数据量增加
通过上一步我们确定了KeyNum的范围 ,那么这一步就要考虑如何将要做的就是找到一个确定的数量使得我们50亿的数据可以均匀的分布再这 KeyNum 个HashTable里
如下图所示,我们的Key是32位的MD5(imei), 为了达到更好的内存合理使用,所以这里考虑将这32位的十六进制拆分成两部分, 一部分作为Redis的Key,一部分作为HashTable的field.
如果 使用六位的 十六进制作为Redis Key那么他的KeyNum为:
2^24 = 16,777,216
同理 七位 :
2^28 = 268,435,456
同理 八位 :
2^32 = 4,294,967,296
与上面 计算出来的 19,531,250比较, 使用七位的十六进制作为Key 的话,那么理论上他的每个HashTable的Entries数量就是大概20个左右. 所以直接选择了7位的十六进制
这里六位的十六进制也可以选择的,只需要将上述的hash-max-ziplist-entries 配置的稍微大一点,但是带来的就是hget的时候会比七位十六进制的慢. 由于没有做过hget差异实验 ,所以就保险的先选择7位.
如下图所示,进行拆分,由于七位的十六进制 只有3.5个字节,所以这里需要补一个十六进制的 \'0\' 凑整4个字节.
为了使切分七位十六进制后的数据更均匀分布,应该对选择的目标七位十六进制进行groupBy,然后看看,数据分布的是不是足够的均匀. 假设,如果有大量MD5(imei) 的前七位都是零,那么就会造成 key为00000000的这个HashTable 过于庞大,而没法使用ZipList . 经过对玖富的数据进行分析,最终选取后七位
1.可以通过减少RedisKey的数量, 达到增加每个HashTable的Entry的数量,达到内存缩减
以上是关于redis存储对象大小2m的主要内容,如果未能解决你的问题,请参考以下文章