最近在大量使用Redis来进行数据统计前的清洗和整理,每天的数据量超5千万+,在开发过程中,数据量小,着重注意业务规则的处理,在上线基本测试后发现了大量的问题,其中之一就是Redis存储数据过多,内存的使用量大大增加。进过简单分析,对存储非常频繁的实体类进行了改进,字段名字进行缩写处理,一下子就减少了很多内存使用量。在对Redis的研究过程中,发现了以下这篇文章:Redis上踩过的一些坑-美团 ,发现其中 有一节内容:“四、redis内存使用优化 ”,对Redis不同的存储结构的使用量进行了对比,对此很敢兴趣,也发现自己在使用过程中可能存储误区,所以就根据自己的业务情况进行了同样的测试,看看有没有优化的余地。

1.测试环境和对比项目

C# 4.0 +  ServiceStack.Redis 3.9 + Windows Redis 2.6.2

测试同样数据结构下,测试存储的Key 的个数100万:

1) 普通K-V结构存储

2) 列表结构存储

3) 独立哈希结构存储

4) 多个哈希结构存储

下面看看简单的代码和结果,为了简单起见,我们使用同一个实体结构和同样的数据,这个实体是业务中用到的,对字段值进行了模糊处理。

由于上述美团的文章的存储结构比较简单,所以我选择了一个比较接近实际使用的实体结构。7个字段,值类型也基本都有。

static SendScanMsg GetEntity()
{
return new SendScanMsg()
{
SN = "测试测试",
NN = "测试",
SM = "颜色身高7",
SC = "123445.888",
P = "A59115901094",
ST = Convert.ToDateTime("2016-01-18 09:54:53"),
RT = Convert.ToDateTime("2016-01-18 10:59:44")
};
}

2.单独的Key-Value存储

简单代码,其中的redis操作经过了封装,看懂意思即可。K-V存储可以想象肯定存储空间是最大的,因为到了一定数量级,Key的长度很关键,也很占内存。

public static void TestKeyMemorySingle()
{
String key = "701183714183_8801_6222";
var model = GetEntity();
Int32 N = 1000000;
for (int i = 0; i < N; i++)
{
MsgRedis.RedisHelper.Item_Set<SendScanMsg>(key + i.ToString(), model, new TimeSpan(10, 0, 0));
}
}

结果如下:

# Memory
used_memory:317253140
used_memory_human:302.56M
used_memory_rss:317253140
used_memory_peak:317253324
used_memory_peak_human:302.56M
used_memory_lua:31744
mem_fragmentation_ratio:1.00
mem_allocator:libc

3. List列表结构存储

看看代码,List结构只数组类型,理论上也是最节省空间的,因为只有1个Key,看看结果:

public static void TestKeyMemoryList()
{
String key = "701183714183_8801_6222";
var model = GetEntity();
Int32 N = 1000000;
for (int i = 0; i < N; i++)
{
MsgRedis.RedisHelper.List_Add<SendScanMsg>(key, model);
}
}

结果如下:

# Memory
used_memory:220861160
used_memory_human:210.63M
used_memory_rss:220861160
used_memory_peak:410351028
used_memory_peak_human:391.34M
used_memory_lua:31744
mem_fragmentation_ratio:1.00
mem_allocator:libc

4.单独哈希结构

代码如下,原理和上面类似。实际使用中,哈希结构使用还是很频繁的,但是也有一些相应的不方便,比如不能针对单个Key设置过期时间,只能对整体的哈希Key设置过期时间,不能分页获取等,具体使用根据情况选择即可。

public static void TestKeyMemoryHash()
{
String key = "701183714183_8801_6222";
var model = GetEntity();
Int32 N = 1000000;
for (int i = 0; i < N; i++)
{
MsgRedis.RedisHelper.Hash_Set<SendScanMsg>(key,i.ToString(), model);
}
}

结果如下,可以看到结果比列表多了不多,应该是Key的原因导致的:

# Memory
used_memory:253009020
used_memory_human:241.29M
used_memory_rss:253009020
used_memory_peak:471307216
used_memory_peak_human:449.47M
used_memory_lua:31744
mem_fragmentation_ratio:1.00
mem_allocator:libc

5.多个哈希结构存储

根据上面那篇文章提供的信息,多个哈希结构存储要比单个哈希更节省空间。所以我也特意对比了一下,我们将哈希的ID分为用0-100的队列,取余实现:

public static void TestKeyMemorySplitHash()
{
String key = "701183714183_8801_6222";
var model = GetEntity();
Int32 N = 1000000;
for (int i = 0; i < N; i++)
{
MsgRedis.RedisHelper.Hash_Set<SendScanMsg>(key+(i%100).ToString(),i.ToString(), model);
}
}

结果如下,其实和单个哈希相差不大,分析原因,可能和具体的使用实体类的Key有关系。并不是所有的情况都是差距好几倍。这也是我测试的真正目的,看看真的差距是不是有这么多。

# Memory
used_memory:264309588
used_memory_human:252.07M
used_memory_rss:264309588
used_memory_peak:266261980
used_memory_peak_human:253.93M
used_memory_lua:31744
mem_fragmentation_ratio:1.00
mem_allocator:libc

6.结论

    上述结果的直接对比如下图,由于实际使用的实体结构和上述提到的文章不一样,所以结果没有对比性,大家也不能完全迷信我的结果,具体问题,具体分析,我们只能从测试中发现大概的趋势,至于具体的差距会根据实际情况不同而不同:

Redis使用上对Key的存储和具体业务要相关,至于是列表还是哈希搞清楚其特点也不难,至于独立的哈希结构和多个哈希节省空间的问题,大部分差不多,也需要在使用上根据业务划分为好,也不能单独的为了节省内存空间丢失业务的灵活性。下面简单说说几种数据结构的区别:

  1. 独立的K-V结构:好处是单个存储可以灵活设置过期时间,同时同一种数据类型内存占有量会增加;在Redis中结构性不明显;

  2. List结构:List结构好处是可以很灵活的获取一定范围的数据,或者分页,同时也是最省内存的,但是实体独立查找比较困难;只能对整个List结构设置过期时间;

  3. 哈希结构:最大的好处是元素的查找效率高,很灵活,但缺点是不能像List那样按照范围获取,也只能设置过期时间;

在经过一段时间的开发后,对数据分析过程中的不同问题和业务采样合适的结构也有了很深的理解。每种结构的优缺点其实是互补的,只要耐心,仔细分析,其实这几种结构非常强大。时间进展,至于Redis的使用经验,个人还有很多不足,如有问题,还请指正。

C#中使用Redis不同数据结构的内存占有量的疑问和对比测试的更多相关文章

  1. Java面试题中的Redis大合集,所有你想找的都在这里!

    概述 Redis 是一个开源的,基于内存的结构化数据存储媒介,可以作为数据库.缓存服务或消息服务使用.``` Redis 支持多种数据结构,包括字符串.哈希表.链表.集合.有序集合.位图.Hyperl ...

  2. redis内部数据结构深入浅出

    最大感受,无论从设计还是源码,Redis都尽量做到简单,其中运用到的原理也通俗易懂.特别是源码,简洁易读,真正做到clean and clear, 这篇文章以unstable分支的源码为基准,先从大体 ...

  3. Redis(三)内存模型

    本文转载自编程迷思,原文链接 深入学习Redis(1):Redis内存模型 前言 Redis是目前最火爆的内存数据库之一,通过在内存中读写数据,大大提高了读写速度,可以说Redis是实现网站高并发不可 ...

  4. 探索Redis设计与实现2:Redis内部数据结构详解——dict

    本文转自互联网 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial ...

  5. Redis 数据结构与内存管理策略(上)

    Redis 数据结构与内存管理策略(上) 标签: Redis Redis数据结构 Redis内存管理策略 Redis数据类型 Redis类型映射 Redis 数据类型特点与使用场景 String.Li ...

  6. Redis 数据结构与内存管理策略(下)

    Redis 数据结构与内存管理策略(下) 标签: Redis Redis数据结构 Redis内存管理策略 Redis数据类型 Redis类型映射 Redis 数据类型特点与使用场景 String.Li ...

  7. Redis 中的过期删除策略和内存淘汰机制

    Redis 中 key 的过期删除策略 前言 Redis 中 key 的过期删除策略 1.定时删除 2.惰性删除 3.定期删除 Redis 中过期删除策略 从库是否会脏读主库创建的过期键 内存淘汰机制 ...

  8. 如何在ASP.NET Core中使用Redis

    注:本文提到的代码示例下载地址> https://code.msdn.microsoft.com/How-to-use-Redis-in-ASPNET-0d826418 Redis是一个开源的内 ...

  9. NET Core中使用Redis

    NET Core中使用Redis 注:本文提到的代码示例下载地址> https://code.msdn.microsoft.com/How-to-use-Redis-in-ASPNET-0d82 ...

随机推荐

  1. 分布式系统:怎么简单地解释Paxos算法?从二段提交、三段提交讲到Paxos

    原文:https://www.quora.com/Distributed-Systems/What-is-a-simple-explanation-of-the-Paxos-algorithm 作者: ...

  2. linux(centos)下挂载ntfs文件系统

    在将硬盘插到Linux系统上,打开硬盘时一直提示:unknown filesystem type 'ntfs'.在尝试网上的方法也遇到了一些问题. 下面按照遇到的问题,按照正确的方式注意操作从而避免问 ...

  3. 20155315庄艺霖--对做中学的理解及对c语言和Java的看法

    关于做中学的理解及技能训练的思考 在写这篇博客之前,我首先阅读了娄老师的博客,对做中学的概念很感兴趣.我们常说知识要学以致用,做中学强调的是在用的过程中有新的收获和体会来进一步巩固学习.细数我学过的课 ...

  4. Php:学习笔记(一):版本选择

    (注:本文来自网络) 超过75%的网站使用了PHP作为开发语言,wordpress,phpmyadmin和其他一些开源项目的盛行,带来了一大批的长尾用户.然而,他们一般安装之后却很少升级.下图是目前P ...

  5. HTML元素基础学习

    HTML元素 HTML文档是由HTML元素定义的.HTML元素是指从start tag(opening tag)到end tag(closing tag)的所有代码,即start tag + cont ...

  6. JavaScript摇股子

    摇股子就是用javascript实现的一个简单的小特效. 下面来看一下我自己做的一个用javascript实现的摇股子. 效果图如下: 我做的股子是由6张图片,点击股子它自己会随机晃动. 代码如下: ...

  7. Probe在性能测试中的使用方式简介

    简介: Lambda Probe(以前称为Tomcat Probe)是一款实时监控和管理的Apache Tomcat实例的基本工具. Lambda Probe 是基于 Web + AJAX 的强大的免 ...

  8. SpringMVC4 实例

    之前我先创建普通web项目,再直接添加maven框架.结果springMVC框架一直不能正确的访问控制器. 但通过以下方式创建maven web项目就能获得正确的架构路径. 1.新建一个maven项目 ...

  9. javascript 执行上下文的理解

    首先,为什么某些函数以及变量在没有被声明以前就可以被使用,javascript引擎内部在执行代码以前到底做了些什么?这里,想信大家都会想到,变量声明提前这个概念: 但是,以下我要讲的是,声明提前的这个 ...

  10. apache rewrite_mod 经典疑问解答

    1.RewriteRule ^(com\/.*)$ index.php?do=$1 问:上面的规则匹配表达式 "^(.*)$" 匹配的内容是什么 答:匹配内容是URI站点目录:/d ...