行将开播:5月14日,Jenkins在K8S下的三种部署流程和实战演示
在一些网络效劳的系统中,Redis 的功用,能够是比 MySQL 等硬盘数据库的功用更重要的课题。比如微博,把热点微博[1],最新的用户关系,都存储在 Redis 中,少量的查询击中 Redis,而不走 MySQL。
那么,针对 Redis 效劳,我们能做哪些功用优化呢?或许说,应该避免哪些功用糜费呢?
Redis 功用的基本面在讨论优化之前,我们需求知道,Redis 效劳本身就有一些特性,比如单线程运转。除非修正 Redis 的源代码,不然这些特性,就是我们思索功用优化的基本面。
那么,有哪些 Redis 基本特性需求我们思索呢?Redis 的项目引见中概括了它特性:
Redis is an in-memory database that persists on disk. The data model is key-value, but many different kind of values are supported.
首先,Redis 运用操作系统提供的虚拟内存来存储数据。而且,这个操作系统普通就是指 Unix。Windows 上也能运转 Redis,但是需求特殊处置。假设你的操作系统运用交流空间,那么 Redis 的数据能够会被实践保存在硬盘上。
其次,Redis 支持耐久化,可以把数据保存在硬盘上。很多时分,我们也确实有必要停止耐久化来完成备份,数据恢复等需求。但耐久化不会凭空发作,它也会占用一部分资源。
第三,Redis 是用 key-value 的方式来读写的,而 value 中又可以是很多不同种类的数据;更进一步,一个数据类型的底层还有被存储为不同的结构。不同的存储结构决议了数据增删改查的复杂度以及功用开支。
最后,在下面的引见中没有提到的是,Redis 大少数时分是单线程运转[2]的(single-threaded),即同一时间只占用一个 CPU,只能有一个指令在运转,并行读写是不存在的。很多操作带来的延迟成绩,都可以在这里找到答案。
关于最后这个特性,为什么 Redis 是单线程的,却能有很好的功用(依据 Amdahl’s Law,优化耗时占比大的进程,才更有意义),两句话概括是:Redis 应用了多路 I/O 复用机制[3],处置客户端央求时,不会阻塞主线程;Redis 单纯执行(大少数指令)一个指令不到 1 微秒[4],如此,单核 CPU 一秒就能处置 1 百万个指令(大约对应着几十万个央求吧),用不着完成多线程(网络才是瓶颈[5])。
优化网络延时Redis 的官方博客在几个中央都说,功用瓶颈更能够是网络[6],那么我们如何优化网络上的延时呢?
首先,假设你们运用单机部署(运用效劳和 Redis 在同一台机器上)的话,运用 Unix 进程间通讯来央求 Redis 效劳,速度比 localhost 局域网(学名 loopback)更快。官方文档[7]是这么说的,想一想,实际上也应该是这样的。
但很多公司的业务规模不是单机部署能支撑的,所以还是得用 TCP。
Redis 客户端和效劳器的通讯普通运用 TCP 长链接。假设客户端发送央求后需求等候 Redis 前往结果再发送下一个指令,客户端和 Redis 的多个央求就构成下面的关系:
(备注:假设不是你要发送的 key 特别长,一个 TCP 包完全能放下 Redis 指令,所以只画了一个 push 包)
这样这两次央求中,客户端都需求阅历一段网络传输时间。
但假设有能够,完全可以运用 multi-key 类的指令来兼并央求,比如两个 GET key可以用MGET key1 key2兼并。这样在实践通讯中,央求数也增加了,延时自然失掉好转。
假设不能用 multi-key 指令来兼并,比如一个 SET,一个GET无法兼并。怎样办?
Redis 中有至少这样两个办法能兼并多个指令到一个 request 中,一个是 MULTI/EXEC,一个是 script。前者本来是构建 Redis 事务的办法,但确实可以兼并多个指令为一个 request,它到通讯进程如下。至于 script,最好应用缓存脚本的 sha1 hash key 来调起脚本,这样通讯量更小。
这样确实更能增加网络传输时间,不是么?但如此以来,就必需要求这个 transaction / script 中触及的 key 在同一个 node 上,所以要酌情思索。
假设下面的办法我们都思索过了,还是没有办法兼并多个央求,我们还可以思索兼并多个 responses。比如把 2 个回复信息兼并:
这样,实际上可以省去 1 次回复所用的网络传输时间。这就是 pipeline 做的事情。举个 ruby 客户端运用 pipeline 的例子:
require 'redis'
@redis = Redis.new
@redis.pipelined do
@redis.get 'key1'
@redis.set 'key2' 'some value'
end
# => [1, 2]
听说,有些言语的客户端,甚至默许就运用 pipeline 来优化延时成绩,比如 node_redis。
另外,不是恣意多个回复信息都可以放进一个 TCP 包中,假设央求数太多,回复的数据很长(比如 get 一个长字符串),TCP 还是会分包传输,但运用 pipeline,依然可以增加传输次数。
pipeline 和下面的其他办法都不一样的是,它不具有原子性。所以在 cluster 形状下的集群上,完成 pipeline 比那些原子性的办法更有能够。
小结一下:
运用 unix 进程间通讯,假设单机部署
运用 multi-key 指令兼并多个指令,增加央求数,假设有能够的话
运用 transaction、script 兼并 requests 以及 responses
运用 pipeline 兼并 response
警觉执行时间长的操作 (责任编辑:admin)