zero's Blog

持续迭代

  • 基于内存的数据库。完全基于内存,绝大部分请求是纯粹的内存操作,非常快速。数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1);

  • 多路I/O复用模型:对于服务端接收到的大量请求,redis使用I/O多路复用程序同时监听多个套接字,并且将这些事件push到同一个队列中逐步执行,最终再将结果返回给客户端。

  • 高效的数据结构: sds (simple dynamic string) 简单动态字符串

    O(1) 复杂度的长度计算:在 C 语言中,要计算一个字符串的长度,需要遍历整个字符串,时间复杂度为 O(n)。而 SDS 中的 len 属性记录了字符串的长度,因此可以在 O(1) 时间内获取字符串的长度。

    二进制安全:C 语言中的普通字符串使用 ‘\0’ 字节作为字符串的结束符,因此不支持存储二进制数据和包含空字符的字符串。而 SDS 使用 buf 和 len 属性来表示字符串,因此可以存储任何二进制数据,同时也支持存储包含空字符的字符串。

    减少缓冲区溢出的风险:在 C 语言中,如果使用 char 数组来存储字符串,当字符串的长度超过数组大小时,就会发生缓冲区溢出的错误。而 SDS 在扩展缓冲区时,会通过预留额外的空间来避免缓冲区溢出的风险。

    支持快速增长和缩短:在 C 语言中,如果要对字符串进行增长或缩短操作,需要重新分配内存并复制数据。而 SDS 的 buf 属性可以支持快速增长和缩短,因为它是一个可修改大小的空间,不需要分配新的空间。

    兼容部分 C 字符串库:SDS 一些 API 与标准 C 库中字符串操作函数(如 strlen、strcat)类似,因此可以兼容一些 C 字符串库的使用,同时也提高了代码的可读性和易维护性。

  • 单线程模式:Redis基于Reactor模式开发了网络事件处理器,这个处理器被称为文件事件处理器。它的组成结构为4部分:多个套接字、IO多路复用程序、文件事件分派器、事件处理器。因为文件事件分派器队列的消费是单线程的,所以Redis才叫单线程模型。为什么redis会使用单线程?因为一般来说,redis比较少会有计算密集型的操作,所以cpu不会有瓶颈。redis的瓶颈,一般是在没存大小与网络IO。实际中我们为了使用cpu的多核,都是采用搭建多个redis实例来解决。在redis6.0以后的新版本中,网络IO处理模块已经使用了多线程,比如网络数据的读写与协议解析等等。但是,执行命令的模块,即文件事件分派器仍然是单线程,所以我们还是可以说redis是单线程模型。单线程模式可以使得redis变快,原因主要在于单线程在执行的过程中不需要进行上下文的切换,从而减少了耗时提高了处理速度。

​ Redis客户端对服务端的每次调用都经历了发送命令,执行命令,返回结果三个过程。其中执行命令阶段,由于Redis是单线程来处理命令的,所有每一条到达服务端的命令不会立刻执行,所有的命令都会进入一个队列中,然后逐个被执行。并且多个客户端发送的命令的执行顺序是不确定的。但是可以确定的是不会有两条命令被同时执行,不会产生并发问题,这就是Redis的单线程基本模型。

  Redis为了解决单点数据库问题,会把数据复制多个副本部署到其他节点上,通过复制,实现Redis的高可用性,实现对数据的冗余备份,保证数据和服务的高度可靠性。

一. 旧版复制

  Redis 的复制功能分为 同步(sync)命令传播(command propagate) 两个操作。

  同步是从服务器对主服务器发送 SYNC 命令来完成, 以下是 SYNC 命令的执行步骤:

从服务器连接主服务器,发送SYNC命令;
主服务器接收到SYNC命名后,开始执行BGSAVE命令生成RDB文件并使用缓冲区记录此后执行的所有写命令;
主服务器BGSAVE执行完后,向所有从服务器发送快照文件,并在发送期间继续记录被执行的写命令;
从服务器收到快照文件后丢弃所有旧数据,载入收到的快照;
主服务器快照发送完毕后开始向从服务器发送缓冲区中的写命令;
从服务器完成对快照的载入,开始接收命令请求,并执行来自主服务器缓冲区的写命令;

  命令传播,也可以说是增量复制,主要是指主服务器每执行一个写命令就会向从服务器发送相同的写命令,从服务器接收并执行收到的写命令。当从服务器执行了相同的写命令之后, 主从服务器将再次回到一致状态。

Read more »

Redis提供了INFO这个命令,能够随时监控服务器的状态,只用telnet到对应服务器的端口,执行命令即可:

1
2
telnet localhost 6379
info

在输出的信息里面有这几项和缓存的状态比较有关系:

1
2
3
4
5
keyspace_hits:14414110
keyspace_misses:3228654
used_memory:433264648
expired_keys:1333536
evicted_keys:1547380

通过计算hits和miss,我们可以得到缓存的命中率:14414110 / (14414110 + 3228654) = 81% ,一个缓存失效机制,和过期时间设计良好的系统,命中率可以做到95%以上

有个ruby gem叫redis-stat,它利用INFO命令展现出更直观的信息报表,推荐:
https://github.com/junegunn/redis-stat

前言

前几天有读者说自己面试被问到Redis的事务,虽然不常用,但是面试竟然被问到,平时自己没有注意Redis的事务这一块,面试的时候被问到非常不好受。

虽然,这位读者面试最后算是过了,但是薪资方面没有拿到自己理想的薪资。

其实这个也是正常的,一般面试被问到烂大街的,谁还问你啊,专门挑一些不常见的来问你,就是为了压你的薪资。

所以在这里写一篇文章对Redis的事务进行详细的讲解,估计对Redis事务从理解到原理深入这一篇就够了。

以后面试都不用担心了再被问道Redis的事务了,这一篇主要讲解Redis事务原理和实操的演练,理解理论的同时也通过实操来证实理论。

Read more »

[toc]
  Redis的强劲性能很大程度上是由于其将所有数据都存储在了内存中,为了使Redis在重启之后仍能保证数据不丢失,需要将数据从内存中以某种形式同步到硬盘中,这一过程就是持久化。
  Redis支持两种方式的持久化,一种是RDB(Redis DataBase)方式,一种是AOF(Append Only File)方式。可以单独使用其中一种或将二者结合使用。RDB可以理解是基于全量模式的持久化,AOF是基于增量模式的持久化。

Read more »

我们在使用redis时,一般会设置一个过期时间,当然也有不设置过期时间的,也就是永久不过期。
当我们设置了过期时间,redis是如何判断是否过期,以及根据什么策略来进行删除的。

1.redis设置过期时间:expire 只针对顶级key有效,即哈希结构不支持过期

1
2
3
expire key time(以秒为单位)--这是最常用的方式

setex(String key, int seconds, String value)--字符串独有的方式

注:
除了字符串自己独有设置过期时间的方法外,其他方法都需要依靠expire方法来设置时间;
如果没有设置时间,那缓存就是永不过期;
如果设置了过期时间,之后又想让缓存永不过期,使用persist key;

Read more »

[toc]

Redis 如何才能做到高并发

redis 主从架构

单机的 redis,能够承载的 QPS 大概就在上万到几万不等。对于缓存来说,一般都是用来支撑读高并发的。因此架构做成主从(master-slave)架构,一主多从,主负责写,并且将数据复制到其它的 slave 节点,从节点负责读。所有的读请求全部走从节点。这样也可以很轻松实现水平扩容,支撑读高并发。

Read more »

[toc]

什么是redis sentinel

哨兵在redis集群架构中是一个非常重要的组件,其主要功能有下面这些:

  • 集群监控,即时刻监控着redis的master和slave进程是否是在正常工作。
  • 消息通知,就是说当它发现有redis实例有故障的话,就会发送消息给管理员
  • 故障自动转移,如果redis master 节点宕机了的话,它就会将请求转到slave 节点上,slave升为master。
  • 充当配置中心,如果发生了故障转移,它会通知将master的新地址写在配置中心告诉客户端。

  
sentinel 本身也是分布式部署的,是一个集群去运行的并且节点间相互协调工作,那它是怎么来监控redis的呢?

  1. 当发生故障转移的时候,只有大部分哨兵节点同意(选主)才会判断你这个master是真的宕机
  2. 如果哨兵部分节点挂了的话,整个哨兵集群依然能工作,这也是确保自身能高可用

哨兵集群至少要 3 个节点,来确保自己的健壮性;redis主从 + sentinel的架构,是不会保证数据的零丢失的,它是为了保证redis集群的高可用。

Read more »

[toc]

什么是MVVC

  MVCC (Multi-Version Concurrency Control) 是一种基于多版本的并发控制协议,只有在InnoDB引擎下存在。MVCC是为了实现事务的隔离性,通过版本号,避免同一数据在不同事务间的竞争,可以把它当成基于多版本号的一种乐观锁。当然,这种乐观锁只在事务级别未提交锁和已提交锁时才会生效。MVCC最大的好处,读不加锁,读写不冲突。在读多写少的OLTP应用中,读写不冲突是非常重要的,极大的增加了系统的并发性能。

  可以认为MVCC是行级锁的一个变种,但是它在很多情况下避免了加锁操作,因此开销更低。虽然实现机制有所不同,但大都实现了非阻塞的读操作,写操作也只锁定必要的行。

  MVCC只在 READ COMMITTED 和 REPEATABLE READ 两个隔离级别下工作。

Read more »

[toc]
  InnoDB与MyISAM的最大不同有两点:一是支持事务(TRANSACTION);二是采用了行级锁。(还有一个支持外键)

获取InnoDB行锁争用情况

  可以通过检查InnoDB_row_lock状态变量来分析系统上的行锁的争夺情况:

1
mysql> show status like 'innodb_row_lock%';

  如果发现锁争用比较严重,如InnoDB_row_lock_waits和InnoDB_row_lock_time_avg的值比较高,还可以通过设置InnoDB Monitors来进一步观察发生锁冲突的表、数据行等,并分析锁争用的原因。

InnoDB的行锁模式及加锁方法

  InnoDB实现了以下两种类型的行锁。

  • 共享锁(S, shared locks):允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁。
  • 排他锁(X, exclusive locks):允许获得排他锁的事务更新数据,阻止其他事务取得相同数据集的共享读锁和排他写锁。

  InnoDB支持多粒度的锁,也即,除了行锁外还支持表锁,表锁通过意向锁实现,用以提示事务即将对表中的行添加什么样的锁。InnoDB有两种内部使用的意向锁(Intention Locks):

  • 意向共享锁(IS):事务打算给数据行加行共享锁,事务在给一个数据行加共享锁前必须先取得该表的IS锁。
  • 意向排他锁(IX):事务打算给数据行加行排他锁,事务在给一个数据行加排他锁前必须先取得该表的IX锁。

  上述锁模式的兼容情况具体如表:

Read more »
0%