天道酬勤

坚持,努力,让好事发生

0%

通过 info命令可以查看Redis Server的基本信息、CPU、内存、持久化、客户端连接信息等等;
通过 info memory 可以查看Redis Server的内存相关信息。

(1) 从 info memory 看Redis内存使用情况

Redis Server info memory

阅读全文 »

通过源代码编译来安装 Redis ,在自己的机器上搭建一套可以 Debug 的 Redis 源码环境。
推荐在 Linux 或者 MacOS 上Debug。

redis-server调试-启动

redis-server调试截图

阅读全文 »

我们经常会计算我们有多少钱,每个月吃饭开销多少,交通开销多少,以及其它开销多少,方便管理,避免透支。

在使用Redis时也要有同样的意识,各种数据占用多少内存,要做到心中有数,避免Redis内存不够用,造成问题。

Redis整体内存结构-主要

(1) 2012年微博是怎么用缓存支撑千亿级数据存储的

[WeiDesign]微博计数器的设计(下)

(1.1) 背景

当时(2012年)微博总数量,千亿级而且每秒都在飞速增长中。每条微博都有一个64位的唯一id。

访问量 每秒百万级 还在稳步增长中。根据微博的id来访问。

主要接口 获取评论数 + 获取转发数 。

阅读全文 »

像大家原来使用纸币,平时用的纸币只有 1元 5元 10元 20元 50元 100元,为什么没有 1.5元 3元 ?
因为有了 3元 人们使用不方便,也不方便管理。

(1) Redis内存分配器

Redis在内存使用时也是类似纸币,为了方便管理,Redis在分配内存时按照设计的大小分配。

(1.1) 为什么要设置内存分配器

举个简单的例子,你找妈妈要零花钱,你想要1.5元,但是她没有1.5元,给了个你5元。

  1. 内存分配器的目标主要有2个:
    1.1 减少内存碎片,包括内部碎片和外部碎片:
    内部碎片:分配出去的但没有使用到的内存,比如需要 32 字节,分配了 40 字节,多余的 8 字节就是内部碎片。
    外部碎片:大小不合适导致无法分配出去的内存,比如一直申请 16 字节的内存,但是内存分配器中保存着部分 8 字节的内存,一直分配不出去。
  2. 提高性能:
  3. 1 单线程性能
  4. 2 多线程性能

(1.2) 内存分配器配置

Linux上默认内存分配器是jemalloc

Mac OS 系统Redis默认内存分配器是libc,可以通过 info memory 结果里的 mem_allocator指标 查看;
如果需要使用 jemalloc 内存分配器,在执行make命令时通过 MALLOC=jemalloc 指定

jemalloc 和 tcmalloc 都是对 glibc 中的优化,目的也是为了减少内存碎片和提高性能。


(2) 内存分配的原理

类似于人民币有 1元、5元、10元、100元

jemalloc 将对象按大小分为3类,不同大小类别的分配算法不同:
small: 从对应 bin 管理的 run 中返回一个 region
large: 大小比 chunk 小,比 page 大,会单独返回一个 run
huge: 大小为 chunk 倍数,会分配 chunk

每个 size_class 代表 jemalloc 分配的内存大小。
共有 NSIZES(232)个小类(如果用户申请的大小位于两个小类之间,会取较大的,比如申请14字节,位于8和16字节之间,按16字节分配。

在 2MiB chunk,4KiB page 的64位系统上,size classes 如下

+---------+---------+--------------------------------------+
|Category | Spacing | Size                                 |
+---------+---------+--------------------------------------+
|         |       8 | [8]                                  |
|         +---------+--------------------------------------+
|         |      16 | [16, 32, 48, 64, 80, 96, 112, 128]   |
|         +---------+--------------------------------------+
|         |      32 | [160, 192, 224, 256]                 |
|         +---------+--------------------------------------+
|         |      64 | [320, 384, 448, 512]                 |
|         +---------+--------------------------------------+
|Small    |     128 | [640, 768, 896, 1024]                |
|         +---------+--------------------------------------+
|         |     256 | [1280, 1536, 1792, 2048]             |
|         +---------+--------------------------------------+
|         |     512 | [2560, 3072, 3584, 4096]             |
|         +---------+--------------------------------------+
|         |   1 KiB | [5 KiB, 6 KiB, 7 KiB, 8 KiB]         |
|         +---------+--------------------------------------+
|         |   2 KiB | [10 KiB, 12 KiB, 14 KiB]             |
+---------+---------+--------------------------------------+
|         |   2 KiB | [16 KiB]                             |
|         +---------+--------------------------------------+
|         |   4 KiB | [20 KiB, 24 KiB, 28 KiB, 32 KiB]     |
|         +---------+--------------------------------------+
|         |   8 KiB | [40 KiB, 48 KiB, 54 KiB, 64 KiB]     |
|         +---------+--------------------------------------+
|         |  16 KiB | [80 KiB, 96 KiB, 112 KiB, 128 KiB]   |
|Large    +---------+--------------------------------------+
|         |  32 KiB | [160 KiB, 192 KiB, 224 KiB, 256 KiB] |
|         +---------+--------------------------------------+
|         |  64 KiB | [320 KiB, 384 KiB, 448 KiB, 512 KiB] |
|         +---------+--------------------------------------+
|         | 128 KiB | [640 KiB, 768 KiB, 896 KiB, 1 MiB]   |
|         +---------+--------------------------------------+
|         | 256 KiB | [1280 KiB, 1536 KiB, 1792 KiB]       |
+---------+---------+--------------------------------------+
|         | 256 KiB | [2 MiB]                              |
|         +---------+--------------------------------------+
|         | 512 KiB | [2560 KiB, 3 MiB, 3584 KiB, 4 MiB]   |
|         +---------+--------------------------------------+
|         |   1 MiB | [5 MiB, 6 MiB, 7 MiB, 8 MiB]         |
|         +---------+--------------------------------------+
|Huge     |   2 MiB | [10 MiB, 12 MiB, 14 MiB, 16 MiB]     |
|         +---------+--------------------------------------+
|         |   4 MiB | [20 MiB, 24 MiB, 28 MiB, 32 MiB]     |
|         +---------+--------------------------------------+
|         |   8 MiB | [40 MiB, 48 MiB, 56 MiB, 64 MiB]     |
|         +---------+--------------------------------------+
|         |     ... | ...                                  |
+---------+---------+--------------------------------------+
阅读全文 »

# Redis配置文件

# 启用AOF持久化
appendonly yes

# 当AOF文件增长 100% 时重写AOF文件
auto-aof-rewrite-percentage 100

# 当AOF文件大于 64M 时重写AOF文件
auto-aof-rewrite-min-size 64mb
阅读全文 »

Redis Serialization ProtocolRESP)是Redis客户端服务器之间使用的通信协议。它是一种简单、高效的文本协议,易于实现和解析。

阅读全文 »

有一个常见的问题,Redis是如何实现高可用的?

(1) 如何实现高可用

在分布式环境中,有可能出现某台机器挂了,为了保障高可用,首先要提高服务的分区容错性,一般都会通过冗余来实现。

图片

Redis主从是冗余的一种体现。

Redis的高可用是通过主从哨兵来保障的。在主库挂了以后,哨兵可以把流量切到从库,让从库顶上去,来保障服务可用。

那就有一个问题了,顶上去的从库的数据和主库数据一样吗?还有Redis是如何实现主从数据同步的?


(2) Redis主从数据同步

Redis多个副本(主库和从库)之间的数据如何保持一致呢?
数据读写操作可以发给所有的实例吗?

(2.1) 新增数据是如何保存到Redis副本

Redis是通过读写分离的方式,通过主从库模式来保障多个副本数据一致。 (MySQL、Kafka也是类似)

为什么要采用读写分离的方式呢?
set key v1
set key v2

Redis主从分离

如果允许所有副本接收写操作(新增 修改 删除),数据在这多个副本可能就不一致了(分别是 v1 和 v2)。

如果必须保障新增的数据在多个副本上一致,就要涉及到加锁实例间协商是否完成修改等一系列操作,但这会带来巨额的开销,当然是不太能接受的。

阅读全文 »

在2020年5月推出的 Redis 6.0 版本中,Redis 在执行模型中使用了多线程来处理 IO 任务,这样是为了充分利用当前服务器的多核特性,使用多核运行多线程,让多线程帮助加速数据读取、命令解析以及数据写回的速度,提升 Redis 整体性能。

那么,这些多线程具体是在什么时候启动,又是通过什么方式来处理 IO 请求的呢?

(1) IO多线程

Redis里的IO多线程是指Redis Server读取客户端请求或者向客户端写数据时,使用多个线程,利用CPU资源,加快整体读写速度。

阅读全文 »

无论是 LRU 算法还是 LFU 算法,它们在删除淘汰数据时,实际上都会根据 Redis server 的 lazyfree-lazy-eviction 配置项,来决定是否使用 Lazy Free,也就是惰性删除。

(1) 惰性删除是什么

惰性删除是 Redis 4.0 版本后提供的功能,它会使用后台线程来执行删除数据的任务

(2) 为什么要用惰性删除

可以避免了删除操作对主线程的阻塞。

阅读全文 »

Redis的执行模型,是指 Redis 运行时使用的进程、子进程和线程的个数,以及它们各自负责的工作任务。

我们经常会听到一个问题: Redis 到底是不是一个单线程的程序?

先来看 Redis server 启动时的进程运行。

(1) Redis进程创建

在启动 Redis 实例时

./redis-server ../redis.conf

这个命令后,它实际会调用fork系统调用函数,最终会调用Redis Servermain函数,来新建一个进程。
运行 Redis server 后,我们会看到 Redis server 启动后的日志输出会打印到终端屏幕上

阅读全文 »