5

《Redis深度历险》学习笔记:管道&事务

 2 years ago
source link: https://acuario.xyz/posts/redis-deep-adventure-pipeline-and-transaction/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

《Redis深度历险》学习笔记:管道&事务

 2020.8.11 2020.8.11  学习笔记/Redis  1151  3 分钟

管道

  • Redis 的管道特性由 Redis 客户端提供,客户端通过改变了读写的顺序带来性能的巨大提升。
  • Redis 的管道命令让客户端通过对管道中的指令列表改变读写顺序就可以大幅节省 IO 时间。
  • 管道中指令越多,效果越好。
  • 管道的本质:操作系统内核从为套接字分配的缓冲区(发送缓冲 send buffer / 接收缓冲 recv buffer)中读写数据。
  • 执行命令时,系统会调用 write 和 read 进行 IO 操作:
    • write 操作只负责将数据写到本地操作系统内核的发送缓冲,如果发送缓冲满了,则等待缓冲相应就是写操作 IO 操作的真正耗时。
    • read 操作只负责将数据从本地操作系统内核的接收缓冲中取出,如果接收缓冲是空的,则等待数据到来就是读操作 IO 操作的真正耗时。
  • 对于管道来说,连续的 write 操作根本就没有耗时,之后第一个 read 操作会等待一个网络的来回开销,然后所有的响应消息就都已经回送到内核的读缓冲了,后续的 read 操作直接就可以从缓冲拿到结果,瞬间返回。
  • 管道不仅减少了 RTT,同时也减少了 IO 调用次数(IO 调用涉及到用户态到内核态之间的切换)
传统请求相应模式
(Source: 被遗忘的站点)
管道模式
(Source: 被遗忘的站点)

下面分别对比了传统模式、管道模式、事务批量执行模式在命令时序方面的差异,可以看到利用 批量执行事务+管道 可以实现很大的性能优化:

传统模式
(Source: Taswar BhattiTaswar Bhatti)
管道模式
(Source: Taswar BhattiTaswar Bhatti)
批量执行模式
(Source: Taswar BhattiTaswar Bhatti)

事务

  • Redis 的事务模型很不严格,这要求我们不能像使用关系数据库的事务一样来使用 Redis。

  • Redis 的事务命令分别是:

    • multi:开始事务,相当于 begin
    • exec:执行事务,相当于 commit
    • discard:丢弃事务,不执行前序事务
  • Redis 的事务仅仅是满足了事务的「隔离性」,隔离性中的串行化——当前执行的事务有着不被其它事务打断的权利:

    > multi # 开始事务
    OK
    > set books iamastring
    QUEUED
    > incr books
    QUEUED
    > set poorman iamdesperate
    QUEUED
    > exec # 执行事务
    1) OK
    2) (error) ERR value is not an integer or out of range # 执行错误但会继续执行后续命令,并生效
    3) OK
    > get books
    "iamastring"
    > get poorman
    "iamdesperate
    
    > get books
    (nil)
    > multi # 开始事务
    OK
    > incr books
    QUEUED
    > incr books
    QUEUED
    > discard # 丢弃事务
    OK
    > get books
    (nil)
    
  • 使用 Redis 事务时通常需要执行较多的命令,一半会配合管道进行使用,以提高性能。

  • Redis 提供 watch 命令处理并发产生的竞争条件问题: 事务只能在所有被监视键都没有被修改的前提下执行,如不满足则不执行事务。

  • watch 命令是乐观锁,在 watch 执行后,exec 执行前,如果被监视键的值改变,则事务执行失败。此时可重试事务操作,直到没有发生碰撞为止。大多数情况下,变量碰撞的情况很少,所以通常并不需要进行重试。

    WATCH mykey
    
    val = GET mykey
    val = val + 1
    
    MULTI
    SET mykey $val
    EXEC  # 如果 mykey 改变,则返回 null
    
  • Redis 不支持事务回滚 rollback,原因如下:

    • Redis 是单线程服务,事务仅会因错误命令而执行失败。错误的命令应在开发的过程中被发现,而不应该出现在生产环境中。
    • 实现回滚需要付出额外的开销和成本,这违背了 Redis 的设计哲学和生态。

延伸阅读:


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK