Redis 学习心得

Redis学习心得

没看redis入门指南这本书之前,我是通过别人的博客和手册来学习redis的,所得到的知识零零碎碎,最近两个星期看完了入门指南这本书get到了许多知识,于是打算分享一篇学习笔记。

redis的key键你真的会命名吗?

提示 Redis 对于键的命名并没有强制的要求,但比较好的实践是用“对象类型:对象ID:对象属性”来命名一个键,如使用键user:1:friends来存储ID为1的用户的好友列表。对于多个单词则推荐使用“.”分隔,一方面是沿用以前的习惯(Redis以前版本的键名不能包含空格等特殊字符),另一方面是在 redis-cli 中容易输入,无需使用双引号包裹。另外为了日后维护方便,键的命名一定要有意义,如 u:1:f的可读性显然不如user:1:friends好.

例如:文章ID为1的这篇文章的观看量要如何命名?

$key = "article:1:view";

ps:虽然采用较短的名称可以节省存储空间,但由于键值的长度往往远远大于键名的长度,所以这部分的节省大部分情况下并不如可读性来得重要。

redis几条命令一起执行的时候如何保证原子性?

1.事务

Redis中的事务(transaction)是一组命令的集合。事务同命令一样都是 Redis 的最小执行单位,一个事务中的命令要么都执行,要么都不执行。事务的应用非常普遍,如银行转账过程中A给B汇款,首先系统从A的账户中将钱划走,然后向B的账户增加相应的金额。这两个步骤必须属于同一个事务,要么全执行,要么全不执行。否则只执行第一步,钱就凭空消失了,这显然让人无法接受。


redis> MULTI

OK

redis> SADD "user:1:following" 2

QUEUED

redis> SADD "user:2:followers" 1

QUEUED

redis> EXEC

1) (integer) 1

2) (integer) 1

上面的代码演示了事务的使用方式。首先使用MULTI命令告诉Redis:“下面我发给你的命令属于同一个事务,你先不要执行,而是把它们暂时存起来。”Redis回答:“OK。”

而后我们发送了两个 SADD命令来实现关注和被关注操作,可以看到 Redis 遵守了承诺,没有执行这些命令,而是返回QUEUED表示这两条命令已经进入等待执行的事务队列中了。

当把所有要在同一个事务中执行的命令都发给 Redis 后,我们使用 EXEC 命令告诉Redis将等待执行的事务队列中的所有命令(即刚才所有返回QUEUED的命令)按照发送顺序依次执行。EXEC 命令的返回值就是这些命令的返回值组成的列表,返回值顺序和命令的顺序相同。

Redis保证一个事务中的所有命令要么都执行,要么都不执行。如果在发送EXEC命令前客户端断线了,则 Redis 会清空事务队列,事务中的所有命令都不会执行。而一旦客户端发送了EXEC命令,所有的命令就都会被执行,即使此后客户端断线也没关系,因为Redis中已经记录了所有要执行的命令。

2.脚本

有些情况下会不适合使用事务来保证数据操作的原子性,这时候就要用到脚本。

使用脚本的好处有如下几点:
(1)减少网络开销:如果五条命令最多需要向Redis发送5次请求,而使用脚本功能完成同样的操作只需要发送一个请求即可,减少了网络往返时延。

(2)原子操作:Redis 会将整个脚本作为一个整体执行,中间不会被其他命令插入。换句话说在编写脚本的过程中无需担心会出现竞态条件,也就无需使用事务。事务可以完成的所有功能都可以用脚本来实现。

(3)复用:客户端发送的脚本会永久存储在 Redis 中,这就意味着其他客户端(可以是其他语言开发的项目)可以复用这一脚本而不需要使用代码完成同样的逻辑。

redis的持久化

AOF

当使用Redis存储非临时数据时,一般需要打开AOF持久化来降低进程中止导致的数据丢失。AOF可以将Redis执行的每一条写命令追加到硬盘文件中,这一过程显然会降低Redis 的性能,但是大部分情况下这个影响是可以接受的,另外使用较快的硬盘可以提高AOF的性能。

虽然每次执行更改数据库内容的操作时,AOF都会将命令记录在AOF文件中,但是事实上,由于操作系统的缓存机制,数据并没有真正地写入硬盘,而是进入了系统的硬盘缓存。在默认情况下系统每30秒会执行一次同步操作,以便将硬盘缓存中的内容真正地写入硬盘,在这30秒的过程中如果系统异常退出则会导致硬盘缓存中的数据丢失。一般来讲启用AOF持久化的应用都无法容忍这样的损失,这就需要Redis在写入AOF文件后主动要求系统将缓存内容同步到硬盘中。在 Redis 中我们可以通过 appendfsync 参数设置同步的时机:

# appendfsync always

appendfsync everysec

# appendfsync no

默认情况下Redis采用everysec规则,即每秒执行一次同步操作。always表示每次执行写入都会执行同步,这是最安全也是最慢的方式。no表示不主动进行同步操作,而是完全交由操作系统来做(即每30秒一次),这是最快但最不安全的方式。一般情况下使用默认值everysec就足够了,既兼顾了性能又保证了安全。

结语

看完书中的redis内部编码优化,我还是挺不解的,直到看到一篇博客才恍然大悟。

博客地址:https://sunznx.com/redis/instagram-redis-p...

本作品采用《CC 协议》,转载必须注明作者和本文链接
本帖由系统于 4年前 自动加精
讨论数量: 2

成长从记录开始。

4年前 评论

关于Redis的事务的原子性我觉得需要考证:保证事务性可以让Redis在执行时将这一组的命令按顺序执行而不会被其他的命令插队。但是却不能保证原子性。假设我在事务里面起了10个命令,但是其中某一个失败了,只会在exec后告诉你某一条失败了,而其他的命令却都是执行成功的。

我做了一个实验,截图如下:
首先查看key和hkey的类型,分别是StringHASH。并且查看原来的hkey的值是:value(不截图了)。

PHP
然后在另外开启一个窗口,执行事务:

PHP

最后在查看下hkey的值:

PHP

可见:开启事务后,无法保证原子性操作。

3年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!