持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第13天,点击查看活动详情
Redis的key和value大小限制
redis官方所定义各个数据结构KEY允许的数据大小:
最多容纳 2^32 个key
redis的key和string类型value限制均为512MB。
String类型:一个String类型的value最大可以存储512M
List类型:list的元素个数最多为2^32-1个,也就是4294967295个。
Set类型:元素个数最多为2^32-1个,也就是4294967295个。
Hash类型:键值对个数最多为2^32-1个,也就是4294967295个。
Sorted set类型:跟Set类型相似。
redis中大Value问题的解决
1、压缩
日常在使用redis的时候, 有时会碰到大Value的问题, 超级大的一个Value存到redis中去, 这样其实不好, 我们可以把value进行压缩.
下面我们使用java自带的压缩, 对字符串进行压缩。
/**
* 使用gzip压缩字符串
*
* @param originString 要压缩的字符串
* @return 压缩后的字符串
*/
public static String compress(String originString) {
if (originString == null || originString.length() == 0) {
return originString;
}
ByteArrayOutputStream out = new ByteArrayOutputStream();
try (
GZIPOutputStream gzip = new GZIPOutputStream(out);
) {
gzip.write(originString.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
return new sun.misc.BASE64Encoder().encode(out.toByteArray());
}
/**
* 使用gzip解压缩
*
* @param compressedString 压缩字符串
* @return
*/
public static String uncompress(String compressedString) {
if (compressedString == null || compressedString.length() == 0) {
return null;
}
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] compressedByte = new byte[0];
try {
compressedByte = new sun.misc.BASE64Decoder().decodeBuffer(compressedString);
} catch (IOException e) {
e.printStackTrace();
}
String originString = null;
try (
ByteArrayInputStream in = new ByteArrayInputStream(compressedByte);
GZIPInputStream ginzip = new GZIPInputStream(in);
) {
byte[] buffer = new byte[1024];
int offset = -1;
while ((offset = ginzip.read(buffer)) != -1) {
out.write(buffer, 0, offset);
}
originString = out.toString();
} catch (IOException e) {
e.printStackTrace();
}
return originString;
}
2、拆解几个key-value
如果对象需要每次都整存整取,可以尝试将对象分拆成几个key-value, 使用multiGet获取值,这样分拆的意义在于分拆单次操作的压力,将操作压力平摊到多个redis实例中,降低对单个redis的IO影响;
由于redis是单线程运行的,如果一次操作的value很大会对整个redis的响应时间造成负面影响,所以,业务上能拆则拆,下面举几个典型的分拆方案。
3、换数据格式——hash 可以将这个存储在一个hash中,每个field代表一个具体的属性,使用hget,hmget来获取部分的value,使用hset,hmset来更新部分属性。
4、hash, set,zset,list 中存储过多的元素——元素分拆
以hash为例,原先的正常存取流程是 hget(hashKey, field) ; hset(hashKey, field, value)
现在,固定一个桶的数量,比如 10000, 每次存取的时候,先在本地计算field的hash值,模除 10000, 确定了该field落在哪个key上,再根据对应的hashkey取值。
Redis大Key问题
数据量大的 key ,由于其数据大小远大于其他key,导致经过分片之后,某个具体存储这个 big key 的实例内存使用量远大于其他实例,造成内存不足,拖累整个集群的使用。
什么是 big key
- 字符串类型:一般认为超过 10k 的就是 bigkey,但是这个值和具体的 OPS 相关。
- 非字符串类型:体现在哈希,列表,集合类型元素过多。
带来的问题
bigkey 通常会导致内存空间不平衡,超时阻塞,如果 key 较大,redis 又是单线程,操作 bigkey 比较耗时,那么阻塞 redis 的可能性增大。每次获取 bigKey 的网络流量较大,假设一个 bigkey 为 1MB,每秒访问量为 1000,那么每秒产生 1000MB 的流量,对于普通千兆网卡,按照字节算 128M/S 的服务器来说可能扛不住。
优化big key
当存储量特别大的时候,可以将key进行hash分散处理,可以减少存储内存。
优化big key的原则就是string减少字符串长度,list、hash、set、zset等减少成员数。