Redis实现高效运行的奥秘
Redis是一个开源的高性能键值存储数据库。它可以实现多种数据结构,如哈希表、字符串、列表等,同时也支持多种数据操作,如过期设置、事务等。Redis之所以能够高效运行,最主要的原因就是它采用了内存数据库的设计思想。
内存数据库是指将数据存储在内存中的数据库系统。相对于传统的关系型数据库,内存数据库在读写速度、并发性能上有着极大的优势。但是也由于内存数据易丢失,且成本较高,因此内存数据库通常会与磁盘数据库结合使用,以保证数据的安全性和稳定性。
Redis作为一个内存数据库,其底层数据结构和算法设计非常精妙。下面我们将重点介绍一些Redis的核心设计和实现原理。
1. 数据结构
Redis支持多种数据结构,其中最主要的有五种:字符串、哈希表、链表、集合和有序集合。这些数据结构都可以在内存中直接使用,因此读写速度非常快。
– 字符串:字符串是Redis最基本的数据结构,但也是最常用的。它的底层实现采用了简单动态字符串(SDS)的结构,能够快速进行插入、删除和修改等操作。
– 哈希表:哈希表是一种键值对存储结构,Redis内部采用了多个小哈希表来实现大哈希表存储。这样可以提高哈希表的查找效率,同时也可以减少哈希表的扩容频率。
– 链表:链表是一种支持插入和删除操作的基本数据结构。Redis的链表实现采用了前驱指针和后继指针的方式存储,能够快速进行插入和删除操作。
– 集合:集合是一种无序的唯一元素集合。Redis内部采用了哈希表存储数据,能够快速进行添加、删除和查找等操作。
– 有序集合:有序集合是一种有序的唯一元素集合。Redis内部采用了跳跃表(SkipList)结构存储数据,能够快速进行元素的查找、插入、删除和有序遍历。
2. 算法设计
Redis采用了多种算法来优化数据的存储和访问效率,其中最为重要的两个算法是LRU算法和持久化算法。
– LRU算法:LRU(Least Recently Used)算法是一种缓存淘汰策略,其原理是根据数据的访问时间来判断哪些数据应该更频繁地被访问。Redis的LRU算法是通过利用哈希表和双向链表实现的。哈希表用来存储数据的键值对,双向链表用来记录哈希表表项的使用情况。当数据被访问时,Redis会将该数据对应的表项插入双向链表的表头位置。当缓存满了之后,Redis会从链表的尾部开始遍历,将最久未被访问的数据淘汰掉。
– 持久化算法:持久化是指将数据存储到磁盘中,以便在Redis重启或崩溃时能够重新加载数据。Redis支持两种持久化方式:RDB和AOF。RDB是在指定的时间间隔内生成快照文件,将数据保存到磁盘上。AOF(Append Only File)是将每个写操作操作以追加的方式写入到磁盘文件里。Redis支持这两种持久化方式的选择和切换,能够保证数据的准确性和一致性。
3. 多线程并发控制
多线程并发控制是Redis实现高效运行的关键。Redis采用了Golang编程语言的协程模型,每个操作都会在一个协程中运行。这样就可以充分利用现代多核处理器的能力,提高并发访问性能。
Redis还使用多种优化技巧来提高并发访问的效率。例如,Redis内部采用了基于事件的异步网络模型,并且使用了多路复用技术。这样就可以在一次事件循环中处理多个网络连接,避免了频繁地创建和销毁网络连接的开销。
总结
Redis实现高效运行的奥秘主要体现在其优秀的数据结构和算法设计以及多线程并发控制的实现上。除此之外,Redis还具有丰富的命令集、高效的过期机制、可配置的持久化方案等特点,使其成为一款著名的开源内存数据库。
香港服务器首选树叶云,2H2G首月10元开通。树叶云(shuyeidc.com)提供简单好用,价格厚道的香港/美国云 服务器 和独立服务器。IDC+ISP+ICP资质。ARIN和APNIC会员。成熟技术团队15年行业经验。
Redis源码解析:一条Redis命令是如何执行的?
一条Redis命令的执行过程如下:
重点内容: redisServer:服务端运行的核心结构,包括监听socket、数据存储的redisDb列表和客户端连接信息。 redisClient:客户端连接状态的存储,包括命令处理缓冲区和回复数据列表等。 命令解析与执行:服务器接收并解析客户端命令,然后调用相应的命令处理函数执行命令。 结果返回:命令处理完毕后,服务器构建回复数据并返回给客户端。
缓存-redis 三种模式搭建和运行原理
本文简单的介绍redis三种模式在linux的安装部署和数据存储的总结,希望可以相互交流相互提升。
对于Centos7在安装redis之前需要进行一些常用工具的安装:
关闭防火墙
正式安装redis
在redis进行maketest时候会出现一系列的异常,有如下解决方案:
用redis-server启动一下redis,做一些实验没什么意义。
要把redis作为一个系统的daemon进程去运行的,每次系统启动,redis进程一起启动,操作不走如下:
RDB和AOF是redis的一种数据持久化的机制。 持久化 是为了避免系统在发生灾难性的系统故障时导致的系统数据丢失。 我们一般会将数据存放在本地磁盘,还会定期的将数据上传到云服务器。 RDB是redis的snapshotting,通过中的save配置进行设置,如 save 60 1000:
AOF是以appendonly方式进行数据的储存的,开启AOF模式后,所有存进redis内存的数据都会进入os cache中,然后默认1秒执行一次fsync写入追加到文件中。一般我们配置中的一下指令:
AOF和RDB模式我们一般在生产环境都会打开,一般而言,redis服务挂掉后进行重启会优先家在aof中的文件。
当启动一个slave node的时候,它会发送一个PSYNC命令给master node,如果这是slave node重新连接master node,那么master node仅仅会复制给slave部分缺少的数据;否则如果是slave node第一次连接master node,那么会触发一次full resynchronization; 开始full resynchronization的时候,master会启动一个后台线程,开始生成一份RDB快照文件,同时还会将从客户端收到的所有写命令缓存在内存中。 RDB文件生成完毕之后,master会将这个RDB发送给slave,slave会先写入本地磁盘,然后再从本地磁盘加载到内存中。 然后master会将内存中缓存的写命令发送给slave,slave也会同步这些数据。 slave node如果跟master node有网络故障,断开了连接,会自动重连。 master如果发现有多个slave node都来重新连接,仅仅会启动一个rdb save操作,用一份数据服务所有slave node。
从redis 2.8开始,就支持主从复制的断点续传,如果主从复制过程中,网络连接断掉了,那么可以接着上次复制的地方,继续复制下去,而不是从头开始复制一份。
master node会在内存中常见一个backlog,master和slave都会保存一个replica offset还有一个master id,offset就是保存在backlog中的。 如果master和slave网络连接断掉了,slave会让master从上次的replica offset开始继续复制,但是如果没有找到对应的offset,那么就会执行一次resynchronization。
master在内存中直接创建rdb,然后发送给slave,不会在自己本地落地磁盘了,可以有如下配置:
slave不会过期KEY,只会等待master过期key。 如果master过期了一个key,或者通过LRU淘汰了一个key,那么会模拟一条del命令发送给slave。
在配置文件中,上面的参数代表至少需要3个slaves节点与master节点进行连接,并且master和每个slave的数据同步延迟不能超过10秒。 一旦上面的设定没有匹配上,则master不在提供相应的服务。
sdown达成的条件很简单,如果一个哨兵ping一个master,超过了 is-master-down-after-milliseconds 指定的毫秒数之后,就主观认为master宕机 sdown到odown转换的条件很简单,如果一个哨兵在指定时间内,收到了 quorum 指定数量的其他哨兵也认为那个master是sdown了,那么就认为是odown了,客观认为master宕机
如果一个slave跟master断开连接已经超过了down-after-milliseconds的10倍,外加master宕机的时长,那么slave就被认为不适合选举为master (down-after-milliseconds * 10) + milliseconds_since_master_is_in_SDOWN_state
每次一个哨兵要做主备切换,首先需要quorum数量的哨兵认为odown,然后选举出一个slave来做切换,这个slave还得得到majority哨兵的授权,才能正式执行切换;
(2)SENTINEL RESET *,在所有sentinal上执行,清理所有的master状态 (3)SENTINEL MASTER mastername,在所有sentinal上执行,查看所有sentinal对数量是否达成了一致
4.3.2 slave的永久下线
让master摘除某个已经下线的slave:SENTINEL RESETmastername,在所有的哨兵上面执行.
redis的集群模式为了解决系统的横向扩展以及海量数据的存储问题,如果你的数据量很大,那么就可以用redis cluster。 redis cluster可以支撑N个redis master,一个master上面可以挂载多个slave,一般情况我门挂载一个到两个slave,master在挂掉以后会主动切换到slave上面,或者当一个master上面的slave都挂掉后,集群会从其他master上面找到冗余的slave挂载到这个master上面,达到了系统的高可用性。
2.1 redis cluster的重要配置
2.2 在三台机器上启动6个redis实例
将上面的配置文件,在/etc/redis下放6个,分别为: ,,,,,
每个启动脚本内,都修改对应的端口号
2.3 创建集群
解决办法是 先安装rvm,再把ruby版本提升至2.3.3
使用命令创建集群
--replicas: 表示每个master有几个slave
check 192.168.31.187:7001查看状体
3.1 加入新master
以上相同配置完成后,设置启动脚本进行启动;然后用如下命令进行node节点添加:
3.2 reshard一些数据过去
3.3 添加node作为slave
3.4 删除node
redis是如何执行的
对于任何一门技术,如果你只停留在「会用」的阶段,那就很难有所成就,甚至还有被裁员和找不到工作的风险,我相信能看此篇文章的你,一定是积极上进想有所作为的人,那么借此机会,我们来深入的解一下 Redis 的执行细节。
一条命令的执行过程有很多细节,但大体可分为:客户端先将用户输入的命令,转化为 Redis 相关的通讯协议,再用 socket 连接的方式将内容发送给服务器端,服务器端在接收到相关内容之后,先将内容转化为具体的执行命令,再判断用户授权信息和其他相关信息,当验证通过之后会执行最终命令,命令执行完之后,会进行相关的信息记录和数据统计,然后再把执行结果发送给客户端,这样一条命令的执行流程就结束了。 如果是集群模式的话,主节点还会将命令同步至子节点,下面我们一起来看更加具体的执行流程。
步骤二:客户端先将命令转换成 Redis 协议,然后再通过 socket 连接发送给服务器端
客户端和服务器端是基于 socket 通信的,服务器端在初始化时会创建了一个 socket 监听,用于监测链接客户端的 socket 链接,源码如下:
当 socket 成功连接之后,客户端会先把命令转换成 Redis 通讯协议(RESP 协议,REdis Serialization Protocol)发送给服务器端,这个通信协议是为了保障服务器能最快速的理解命令的含义而制定的,如果没有这个通讯协议,那么 Redis 服务器端要遍历所有的空格以确认此条命令的含义,这样会加大服务器的运算量,而直接发送通讯协议,相当于把服务器端的解析工作交给了每一个客户端,这样会很大程度的提高 Redis 的运行速度。 例如,当我们输入set key val命令时,客户端会把这个命令转换为*3\r\n$3\r\nSET\r\n$4\r\nKEY\r\n$4\r\nVAL\r\n协议发送给服务器端。 更多通讯协议,可访问官方文档:
扩展知识:I/O 多路复用
Redis 使用的是 I/O 多路复用功能来监听多 socket 链接的,这样就可以使用一个线程链接来处理多个请求,减少线程切换带来的开销,同时也避免了 I/O 阻塞操作,从而大大提高了 Redis 的运行效率。
综合来说,此步骤的执行流程如下:
步骤三:服务器端接收到命令
当数据大小验证通过之后,服务器端会对输入缓冲区中的请求命令进行分析,提取命令请求中包含的命令参数,存储在 client 对象(服务器端会为每个链接创建一个 Client 对象)的属性中。
步骤四:执行前准备
① 判断是否为退出命令,如果是则直接返回;
② 非 null 判断,检查 client 对象是否为 null,如果是返回错误信息;
③ 获取执行命令,根据 client 对象存储的属性信息去 redisCommand 结构中查询执行命令;
④ 用户权限效验,未通过身份验证的客户端只能执行 AUTH(授权) 命令,未通过身份验证的客户端执行了 AUTH 之外的命令则返回错误信息;
⑤ 集群相关操作,如果是集群模式,把命令重定向到目标节点,如果是 master(主节点) 则不需要重定向;
⑥ 检查服务器端最大内存限制,如果服务器端开启了最大内存限制,会先检查内存大小,如果内存超过了最大值会对内存进行回收操作;
⑦ 持久化检测,检查服务器是否开启了持久化和持久化出错停止写入配置,如果开启了此配置并且有持久化失败的情况,禁止执行写命令;
⑧ 集群模式最少从节点(slave)验证,如果是集群模式并且配置了 repl min slaves to write(最小从节点写入),当从节点的数量少于配置项时,禁止执行写命令;
⑨ 只读从节点验证,当此服务器为只读从节点时,只接受 master 的写命令;

⑩ 客户端订阅判断,当客户端正在订阅频道时,只会执行部分命令(只会执行 SUBSCRIBE、PSUBSCRIBE、UNSUBSCRIBE、PUNSUBSCRIBE,其他命令都会被拒绝)。
⑪ 从节点状态效验,当服务器为 slave 并且没有连接 master 时,只会执行状态查询相关的命令,如 info 等;
⑫ 服务器初始化效验,当服务器正在启动时,只会执行 loading 标志的命令,其他的命令都会被拒绝;
⑬ lua 脚本阻塞效验,当服务器因为执行 lua 脚本阻塞时,只会执行部分命令;
⑭ 事务命令效验,如果执行的是事务命令,则开启事务把命令放入等待队列;
⑮ 监视器 (monitor) 判断,如果服务器打开了监视器功能,那么服务器也会把执行命令和相关参数发送给监视器 (监视器是用于监控服务器运行状态的)。
当服务器经过以上操作之后,就可以执行真正的操作命令了。
步骤五:执行最终命令,调用 redisCommand 中的 proc 函数执行命令。
步骤六:执行完后相关记录和统计① 检查慢查询是否开启,如果开启会记录慢查询日志; ② 检查统计信息是否开启,如果开启会记录一些统计信息,例如执行命令所耗费时长和计数器(calls)加1; ③ 检查持久化功能是否开启,如果开启则会记录持久化信息; ④ 如果有其它从服务器正在复制当前服务器,则会将刚刚执行的命令传播给其他从服务器。
步骤七:返回结果给客户端命令执行完之后,服务器会通过 socket 的方式把执行结果发送给客户端,客户端再把结果展示给用户,至此一条命令的执行就结束了。
小结 当用户输入一条命令之后,客户端会以 socket 的方式把数据转换成 Redis 协议,并发送至服务器端,服务器端在接受到数据之后,会先将协议转换为真正的执行命令,在经过各种验证以保证命令能够正确并安全的执行,但验证处理完之后,会调用具体的方法执行此条命令,执行完成之后会进行相关的统计和记录,然后再把执行结果返回给客户端。
发表评论