优化的一些建议

1、尽量使用短的key

当然在精简的同时,不要完了key的“见名知意”。对于value有些也可精简,比如性别使用0、1。

**2、避免使用keys ***

keys *, 这个命令是阻塞的,即操作执行期间,其它任何命令在你的实例中都无法执行。当redis中key数据量小时到无所谓,数据量大就很糟糕了。所以我们应该避免去使用这个命令。可以去使用SCAN,来代替。

3、在存到Redis之前先把你的数据压缩下

redis为每种数据类型都提供了两种内部编码方式,在不同的情况下redis会自动调整合适的编码方式。

4、设置 key 有效期

我们应该尽可能的利用key有效期。比如一些临时数据(短信校验码),过了有效期Redis就会自动为你清除!

5、选择回收策略(maxmemory-policy)

当 Redis 的实例空间被填满了之后,将会尝试回收一部分key。根据你的使用方式,强烈建议使用 volatile-lru(默认) 策略——前提是你对key已经设置了超时。但如果你运行的是一些类似于 cache 的东西,并且没有对 key 设置超时机制,可以考虑使用 allkeys-lru 回收机制,具体讲解查看 。maxmemory-samples 3 是说每次进行淘汰的时候 会随机抽取3个key 从里面淘汰最不经常使用的(默认选项)

maxmemory-policy 六种方式 :

  • volatile-lru:只对设置了过期时间的key进行LRU(默认值)
  • allkeys-lru : 是从所有key里 删除 不经常使用的key
  • volatile-random:随机删除即将过期key
  • allkeys-random:随机删除
  • volatile-ttl : 删除即将过期的
  • noeviction : 永不过期,返回错误

6、使用bit位级别操作和byte字节级别操作来减少不必要的内存使用。

  • bit位级别操作:GETRANGE, SETRANGE, GETBIT and SETBIT
  • byte字节级别操作:GETRANGE and SETRANGE

7、尽可能地使用hashes哈希存储。

8、当业务场景不需要数据持久化时,关闭所有的持久化方式可以获得最佳的性能。

9、想要一次添加多条数据的时候可以使用管道。

10、限制redis的内存大小(64位系统不限制内存,32位系统默认最多使用3GB内存)

数据量不可预估,并且内存也有限的话,尽量限制下redis使用的内存大小,这样可以避免redis使用swap分区或者出现OOM错误。(使用swap分区,性能较低,如果限制了内存,当到达指定内存之后就不能添加数据了,否则会报OOM错误。可以设置maxmemory-policy,内存不足时删除数据。)

11、SLOWLOG [get/reset/len]

  • slowlog-log-slower-than 它决定要对执行时间大于多少微秒(microsecond,1秒 = 1,000,000 微秒)的命令进行记录。
  • slowlog-max-len 它决定 slowlog 最多能保存多少条日志,当发现redis性能下降的时候可以查看下是哪些命令导致的。

优化实例分析

管道性能测试

redis的管道功能在命令行中没有,但是redis是支持管道的,在java的客户端(jedis)中是可以使用的:

示例代码

    //注:具体耗时,和自身电脑有关(博主是在虚拟机中运行的数据)
/**
* 不使用管道初始化1W条数据
* 耗时:3079毫秒
* @throws Exception
*/
@Test
public void NOTUsePipeline() throws Exception {
Jedis jedis = JedisUtil.getJedis();
long start_time = System.currentTimeMillis();
for (int i = 0; i < 10000; i++) {
jedis.set("aa_"+i, i+"");
}
System.out.println(System.currentTimeMillis()-start_time);
} /**
* 使用管道初始化1W条数据
* 耗时:255毫秒
* @throws Exception
*/
@Test
public void usePipeline() throws Exception {
Jedis jedis = JedisUtil.getJedis(); long start_time = System.currentTimeMillis();
Pipeline pipelined = jedis.pipelined();
for (int i = 0; i < 10000; i++) {
pipelined.set("cc_"+i, i+"");
}
pipelined.sync();//执行管道中的命令
System.out.println(System.currentTimeMillis()-start_time);
}

hash的应用

示例:我们要存储一个用户信息对象数据,包含以下信息:

key为用户ID,value为用户对象(姓名,年龄,生日等)如果用普通的key/value结构来存储,主要有以下2种存储方式:

  • 将用户ID作为查找key,把其他信息封装成一个对象以序列化的方式存储

    缺点:增加了序列化/反序列化的开销,引入复杂适应系统(Complex adaptive system,简称CAS)修改其中一项信息时,需要把整个对象取回,并且修改操作需要对并发进行保护。

  • 用户信息对象有多少成员就存成多少个key-value对

    虽然省去了序列化开销和并发问题,但是用户ID为重复存储。

  • Redis提供的Hash很好的解决了这个问题,提供了直接存取这个Map成员的接口。Key仍然是用户ID, value是一个Map,这个Map的key是成员的属性名,value是属性值。( 内部实现:Redis Hashd的Value内部有2种不同实现,Hash的成员比较少时Redis为了节省内存会采用类似一维数组的方式来紧凑存储,而不会采用真正的HashMap结构,对应的value redisObject的encoding为zipmap,当成员数量增大时会自动转成真正的HashMap,此时encoding为ht )。

Instagram内存优化

Instagram可能大家都已熟悉,当前火热的拍照App,月活跃用户3亿。四年前Instagram所存图片3亿多时需要解决一个问题:想知道每一张照片的作者是谁(通过图片ID反查用户UID),并且要求查询速度要相当的块,如果把它放到内存中使用String结构做key-value:

HSET "mediabucket:1155" "1155315" "939"
HGET "mediabucket:1155" "1155315"
"939"

测试:1百万数据会用掉70MB内存,3亿张照片就会用掉21GB的内存。当时(四年前)最好是一台EC2的 high-memory 机型就能存储(17GB或者34GB的,68GB的太浪费了),想把它放到16G机型中还是不行的。

Instagram的开发者向Redis的开发者之一Pieter Noordhuis询问优化方案,得到的回复是使用Hash结构。具体的做法就是将数据分段,每一段使用一个Hash结构存储.

由于Hash结构会在单个Hash元素在不足一定数量时进行压缩存储,所以可以大量节约内存。这一点在上面的String结构里是不存在的。而这个一定数量是由配置文件中的hash-zipmap-max-entries参数来控制的。经过实验,将hash-zipmap-max-entries设置为1000时,性能比较好,超过1000后HSET命令就会导致CPU消耗变得非常大。

HSET "mediabucket:1155" "1155315" "939"
HGET "mediabucket:1155" "1155315"
"939"

测试:1百万消耗16MB的内存。总内存使用也降到了5GB。当然我们还可以优化,去掉mediabucket:key长度减少了12个字节。

HSET "1155" "315" "939"
HGET "1155" "315"
"939"

启动时WARNING优化

在我们启动redis时,默认会出现如下三个警告:

  • 一、修改linux中TCP监听的最大容纳数量
WARNING: The TCP backlog setting of 511 cannot be enforced because
/proc/sys/net/core/somaxconn is set to the lower value of 128.

在高并发环境下你需要一个高backlog值来避免慢客户端连接问题。注意Linux内核默默地将这个值减小到/proc/sys/net/core/somaxconn的值,所以需要确认增大somaxconn和tcp_max_syn_backlog两个值来达到想要的效果。

echo 511 > /proc/sys/net/core/somaxconn

注意:这个参数并不是限制redis的最大链接数。如果想限制redis的最大连接数需要修改maxclients,默认最大连接数为10000

  • 二、修改linux内核内存分配策略
错误日志:WARNING overcommit_memory is set to 0! Background save may fail under low memory condition.
To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or
run the command 'sysctl vm.overcommit_memory=1'

原因:

redis在备份数据的时候,会fork出一个子进程,理论上child进程所占用的内存和parent是一样的,比如parent占用的内存为8G,这个时候也要同样分配8G的内存给child,如果内存无法负担,往往会造成redis服务器的down机或者IO负载过高,效率下降。所以内存分配策略应该设置为 1(表示内核允许分配所有的物理内存,而不管当前的内存状态如何)。

内存分配策略有三种

可选值:0、1、2。

  • 0, 表示内核将检查是否有足够的可用内存供应用进程使用;如果有足够的可用内存,内存申请允许;否则,内存申请失败,并把错误返回给应用进程。

  • 1, 不管需要多少内存,都允许申请。

  • 2, 只允许分配物理内存和交换内存的大小(交换内存一般是物理内存的一半)。

  • 三、关闭Transparent Huge Pages(THP)

THP会造成内存锁影响redis性能,建议关闭

Transparent HugePages :用来提高内存管理的性能
Transparent Huge Pages在32位的RHEL 6中是不支持的
执行命令 echo never > /sys/kernel/mm/transparent_hugepage/enabled
把这条命令添加到这个文件中/etc/rc.local

原文出处

xiaoxiaomo -> http://blog.xiaoxiaomo.com/2016/05/02/Redis-%E4%BC%98%E5%8C%96%E8%AF%A6%E8%A7%A3/

Redis优化建议的更多相关文章

  1. Redis系列--内存淘汰机制(含单机版内存优化建议)

    https://blog.csdn.net/Jack__Frost/article/details/72478400?locationNum=13&fps=1 每台redis的服务器的内存都是 ...

  2. Redis 优化查询性能

    一次使用 Redis 优化查询性能的实践   应用背景 有一个应用需要上传一组ID到服务器来查询这些ID所对应的数据,数据库中存储的数据量是7千万,每次上传的ID数量一般都是几百至上千数量级别. 以前 ...

  3. 一次使用 Redis 优化查询性能的实践

    因为我的个人网站 restran.net 已经启用,博客园的内容已经不再更新.请访问我的个人网站获取这篇文章的最新内容,一次使用 Redis 优化查询性能的实践 应用背景 有一个应用需要上传一组ID到 ...

  4. mysql锁机制总结,以及优化建议

    一.锁概述和分类 二.表锁 偏向MyISAM存储引擎,开销小,加锁快:无死锁:锁定粒度大,发生锁冲突的概率最高,并发度最低. [手动增加表锁] lock table 表名字1 read(write), ...

  5. .NET程序的性能要领和优化建议

    前几天在老赵的博客上看到,Bill Chiles (Roslyn 编译器的Program Manager)写了一篇文章叫做<Essential Performance Facts and .NE ...

  6. Unity 几种优化建议

    转: http://user.qzone.qq.com/289422269/blog/1453815561?ptlang=2052 Unity 几种优化建议 最简单的优化建议: 1.PC平台的话保持场 ...

  7. Unity开发-你必须知道的优化建议

    转自:http://blog.csdn.net/leonwei/article/details/18042603 最近研究U3D开发,个人认为,精通一种新的技术,最快最好的方法就是看它的documen ...

  8. mysql性能优化学习笔记-参数介绍及优化建议

    MySQL服务器参数介绍 mysql参数介绍(客户端中执行),尽量只修改session级别的参数. 全局参数(新连接的session才会生效,原有已经连接的session不生效) set global ...

  9. Jquery学习笔记--性能优化建议

    一.选择器性能优化建议 1. 总是从#id选择器来继承 这是jQuery选择器的一条黄金法则.jQuery选择一个元素最快的方法就是用ID来选择了. 1 $('#content').hide(); 或 ...

随机推荐

  1. c# 自己实现可迭代的容器

    在c#中我们经常使用到foreach语句来遍历容器,如数组,List,为什么使用foreach语句能够遍历一个这些容器呢,首先的一个前提是这些容器都实现了IEnumerable接口,通过IEnumer ...

  2. 为什么现在这么多人开始学习Python?

    近几年Python编程语言在国内引起不小的轰动,有超越JAVA之势,本来在美国这个编程语言就是最火的,应用的非常非常的广泛,而Python的整体语言难度来讲又比JAVA简单的很多.尤其在运维的应用中非 ...

  3. Visual Studio Code配置

    Visual Studio Code 从1.23.0开始VS Code就不再默认提供各语言版本, 而是改为使用插件的方式提供语言包. 在插件商店搜索Chinese (Simplified), 安装. ...

  4. java内存管理机制剖析(一)

    最近利用工作之余学习研究了一下java的内存管理机制,在这里记录总结一下. 1-1.java内存区域 当java程序运行时,java虚拟机会将内存划分为若干个不同的数据区域,这些内存区域创建和销毁的时 ...

  5. redhat6.0下配置DNS

    最近操作系统要结课,老师要求在redhat上配置各种服务器角色,包括dhcp.ftp.web.dns.前三个都还好,但就dns,被折磨的死去活来的,真让人头大.还好在同学的帮助下最后配置成功,实现了正 ...

  6. 微服务-springboot打包

    idea打包方式: 打包前确认项目可以正常运行 一.File->Project Structure->Artifacts->点击 + ->JAR->From module ...

  7. POJ 1651:Multiplication Puzzle(区间DP)

    http://poj.org/problem?id=1651 题意:给出n个数字,每取中间一个数,就会使得权值加上中间这个数和两边的乘积,求取剩两个数最少的权值是多少. 思路:区间dp. 一开始想了挺 ...

  8. 利用os模块生成 文件夹和文件

    需求: 使用os模块创建如下目录结构 glance/ ├── __init__.py ├── api │ ├── __init__.py │ ├── policy.py │ └── versions. ...

  9. C# 中奇妙的函数–6. 五个序列聚合运算(Sum, Average, Min, Max,Aggregate)

    今天,我们将着眼于五个用于序列的聚合运算.很多时候当我们在对序列进行操作时,我们想要做基于这些序列执行某种汇总然后,计算结果. Enumerable 静态类的LINQ扩展方法可以做到这一点 .就像之前 ...

  10. 《ElasticSearch6.x实战教程》之简单的API

    第三章-简单的API 万丈高楼平地起 ES提供了多种操作数据的方式,其中较为常见的方式就是RESTful风格的API. 简单的体验 利用Postman发起HTTP请求(当然也可以在命令行中使用curl ...