Redis性能调优,影响Redis性能的因素

头像

👁 关注微信公众号:非典型理科男 回复:redis获取redis三本经典著做html

序言

上一篇文章《Redis为何这么快》介绍了Redis性能评估工具,以及Redis高性能的缘由。详细请见: 这篇咱们将从业务的视角,讲解下影响Redis性能的因素以及如何提高Redis使用的性能。redis

从用户到Redis请求过程分析

以最经常使用场景缓存为例,流量从用户到Redis Server的过程以下所示:后端

  1. 用户访问后端服务器,调用对应的Controller
  2. Controller命中缓存记录,经过Jedis客户端调用Reids从缓存获取记录。 若是使用的Jedis链接池获取Jedis对象,从Jedis链接池获取一个Jedis链接实例。
  3. Jedis使用Redis序列化协议(RESP)将命令编码,放到Redis Server输入缓冲区中。
  4. Redis Server从输入缓冲区获取命令并执行。
  5. 执行结束后将执行结果放入到输出缓冲区。
  6. Jedis客户端从输出缓冲区获取执行结果并返回给Controller。
  7. Controller执行完业务逻辑相应用户的请求。

从上面时序图能够看出,用户请求经过Redis client经由网路到达Redis Server。缓存

所以在考虑使用Redis性能的时候要从客户端和服务端两个角度考虑。 对于业务方来讲, 合理使用Redis特性比Redis服务器的优化可操做性更强,也更容易得到好的效果。bash

下面将从业务优化和服务器优化两个方面介绍Redis的优化。服务器

业务优化

查询本地redis的延迟一般低于1毫秒,而查询同一个数据中心的redis的延迟一般低于5毫秒。也就是说,网络传输的损耗为实际操做用时的5倍。微信

所以,从客户端角度,如何减小网络耗时相当重要。网络

使用链接池减小创建链接和销毁链接的时间开销

Jedis是Java语言使用最多的Redis客户端。 Jedis支持直连和链接池的两种方式。并发

直连的方式:运维

# 1. 生成一个Jedis对象,这个对象负责和指定Redis实例进行通讯 
Jedis jedis = new Jedis("127.0.0.1", 6379); 
# 2. jedis执行set操做 
jedis.set("hello", "world"); 
# 3. jedis执行get操做 value="world" 
String value = jedis.get("hello");
复制代码

所谓直连是指Jedis每次都会新建TCP 链接,使用后再断开链接。 咱们都知道新建TCP链接通过3次握手,释放TCP链接通过4次挥手,新建和回收是很是耗时操做。对于频繁访问Redis的场景显然不是高效的使用方式。

Jedis也提供了链接池的方式。

节选自:《Redis开发和运维》

节选自:《Redis开发和运维》
// common-pool链接池配置,这里使用默认配置
GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig(); // 初始化Jedis链接池 
JedisPool jedisPool = new JedisPool(poolConfig, "127.0.0.1", 6379);
Jedis jedis = null; try {
  // 1. 从链接池获取jedis对象 
  jedis = jedisPool.getResource(); 
  // 2. 执行操做 
  jedis.get("hello"); 
} catch (Exception e) { 
    logger.error(e.getMessage(),e); 
} finally { 
  if (jedis != null) { 
  // 若是使用JedisPool,close操做不是关闭链接,表明归还链接池 
  jedis.close(); 
  } 
}
复制代码

使用Pipeline或者Lua脚本减小请求次数

经过链接池,减小创建和断开TCP链接的时间开销。 另外,redis提供了其余三种方式,经过减小请求次数提高性能。 (1) 批量操做的命令,如mget,mset等 (2) pipeline方式 (3) Lua脚本

pipeline方式

使用redis-benchmark在Intel(R) Xeon(R) CPU E5520 @ 2.27GHz对比pipeline(每次16个命令)和普通请求。

使用pipeline的状况:

$ ./redis-benchmark -r 1000000 -n 2000000 -t get,set,lpush,lpop -P 16 -q
SET: 552028.75 requests per second
GET: 707463.75 requests per second
LPUSH: 767459.75 requests per second
LPOP: 770119.38 requests per second
Intel(R) Xeon(R) CPU E5520 @ 2.27GHz (without pipelining)
复制代码

无pipeline的状况:

$ ./redis-benchmark -r 1000000 -n 2000000 -t get,set,lpush,lpop -q
SET: 122556.53 requests per second
GET: 123601.76 requests per second
LPUSH: 136752.14 requests per second
LPOP: 132424.03 requests per second
复制代码

从benchmark的结果能够看出,使用pipeline技术比没有使用性能提高5-10倍左右。

Jedis支持Pipeline特性,咱们知道 Redis提供了mget、mset方法,可是并无提供mdel方法,若是想实现这个功 能,能够借助Pipeline来模拟批量删除,虽然不会像mget和mset那样是一个原 子命令,可是在绝大数场景下可使用。

public void mdel(List<String> keys) { 
  Jedis jedis = new Jedis("127.0.0.1"); 
  // 1)生成pipeline对象 Pipe   
  line pipeline = jedis.pipelined(); 
  // 2)pipeline执行命令,注意此时命令并未真正执行 
  for (String key : keys) { 
      pipeline.del(key);
  }
  // 3)执行命令 
  pipeline.sync(); 
}
复制代码

将del命令封装到pipeline中,能够调用pipeline.del(String key),此时不会真正的 执行命令。

使用pipeline.sync()完成这次pipeline对象的调用。

除了pipeline.sync(),还可使用pipeline.syncAndReturnAll()将 pipeline的命令进行返回。

pipeline提高性能的缘由

pipeline提高性能的一个缘由是减小了命令总的RTT时间(往返时延), 另一方面减小 总的系统调用的次数。

RTT(Round-Trip Time): 往返时延。在计算机网络中它是一个重要的性能指标,表示从发送端发送数据开始,到发送端收到来自接收端的确认(接收端收到数据后便当即发送确认),总共经历的时延。往返延时(RTT)由三个部分决定:即链路的传播时间、末端系统的处理时间以及路由器的缓存中的排队和处理时间。其中,前面两个部分的值做为一个TCP链接相对固定,路由器的缓存中的排队和处理时间会随着整个网络拥塞程度的变化而变化。因此RTT的变化在必定程度上反映了网络拥塞程度的变化。简单来讲就是发送方从发送数据开始,到收到来自接受方的确认信息所经历的时间。

pipline和lua脚本的不一样

Redis原生支持Lua语言,而且提供了经过客戶端执行lua脚本的命令。

Redis Lua脚本相关命令脑图

好比咱们能够用Lua脚本在低版本的Redis上实现分布式锁。

local current current = redis.call('incr',KEYS[1]) 

if tonumber(current) == 1 
then 
redis.call('expire',KEYS[1], ARGV[1]) 
end 

return current
复制代码

调用EVAL命令能够传入不定的KEY和ARGS的值, 这些值被能够经过KEY[i]和ARGV[i]访问对应的入参,而且经过return返回执行结果。

更多的Lua脚本,会在其余文章中介绍。

能够关注微信公众号:非典型理科男,查看所有文章列表阅读Lua脚本相关的文章。

pipeline和Lua比较:

(1) 返回结果不一样: pipeline会把命令执行结果都返回出来, lua脚本只有一个返回结果。

(2) 使用场景不一样: lua脚本能够提供复杂逻辑运算而且提供了缓存脚本的功能,提高像原生命令同样的性能体验。 所以lua脚本能够用在处理逻辑复杂,不须要返回或者只返回操做结果的场景。 pipeline用在合并命令减小执行开销和redis server压力的场景下。

在使用pipeline时有几个注意事项:

(1) pipeline执行命令虽然没有明确的执行命令数量的限制,可是建议限制执行命令数量。 执行命令数量过多一方面占用网络带宽,另外一方面会阻塞客户端。

Redis Server性能影响因素

影响Redis Server性能主要有硬件、数据分布和配置有关。

硬件因素

Redis喜欢下面的硬件条件:

  1. 高带宽,低延迟的网络: Redis的性能中网络带宽和延迟一般是最大短板。所以,须要选择高带宽,低延迟的网络。
  2. 大缓存快速 CPU: 而不是多核。这种场景下面,比较推荐 Intel CPU。AMD CPU 可能只有 Intel CPU 的一半性能(经过对 Nehalem EP/Westmere EP/Sandy 平台的对比)。 当其余条件至关时候,CPU 就成了 redis-benchmark 的限制因素。
  3. 大对象(>10k)存储时内存和带宽显得尤为重要。 可是更重要是优化大对象的存储。
  4. 将Redis运行在物理机器上:Redis 在 VM 上会变慢。虚拟化对普通操做会有额外的消耗,Redis 对系统调用和网络终端不会有太多的 overhead。建议把 Redis 运行在物理机器上。

大Value的影响

包大小影响Redis的相应速度。 以太网网数据包在 1500 bytes 如下时, 将多条命令包装成 pipelining 能够大大提升效率。事实上,处理 10 bytes,100 bytes, 1000 bytes 的请求时候,吞吐量是差很少的,详细能够见下图。

不一样数据包大小下的并发量

因此,当大value(>10k)存在时要及时优化掉。

参考文档:

  1. Redis Benchmark
  2. Redis 命令合集

头像
👁 关注微信公众号:非典型理科男 回复:redis获取redis三本经典著做

本文由博客群发一文多发等运营工具平台 OpenWrite 发布

相关文章
相关标签/搜索