zoukankan      html  css  js  c++  java
  • redis学习笔记

    原文

    Redis提供了5种数据结构,但除此之外,Redis还提供了注入慢查询分析,Redis Shell、Pipeline、事务、与Lua脚本、Bitmaps、HyperLogLog、PubSub、GEO等附加功能,这些功能可以在某些场景发挥很重要的作用.

    Pipeline

    1. Pipeline概念

    Redis客户端执行一条命令分为以下四个步骤:

    1.发送命令
    2.命令排队
    3.命令执行
    4.返回结果

    其中,第一步+第四步称为Round Trip Time(RTT,往返时间).

    Redis提供了批量操作命令(例如mget,mset等),有效的节约RTT.但大部分命令是不支持批量操作的,例如要执行nhgetall命令,并没有mhgetall存在,需要消耗nRTT.Redis的客户端和服务端可能不是在不同的机器上.例如客户端在北京,Redis服务端在上海,两地直线距离为1300公里,那么1次RTT时间=1300×2/(300000×2/3)=13毫秒(光在真空中传输速度为每秒30万公里,这里假设光纤的速度为光速的2/3),那么客户端在1秒内大约只能执行80次左右的命令,这个和Redis的高并发高吞吐背道而驰.

    Pipeline(流水线)机制能改善上面这类问题,它能将一组Redis命令进行组装,通过一次RTT传输给Redis,再将这组Redis命令按照顺序执行并装填结果返回给客户端.图1.1中未使用Pipeline执行了n次命令,整个过程需要n个RTT.

    Pipeline并不是什么新的技术和机制,很多技术上都使用过.而且RTT在不同网络环境下会有不同,例如同机房和同机器会比较快,跨机房跨地区会比较慢.Redis命令真正执行的时间通常在微秒级别,所以才会有Redis性能瓶颈是网络这样的说法.

    2. 原生批量命令与Pipeline对比

    可以使用Pipeline模拟出批量操作的效果,但是在使用时需要质疑它与原生批量命令的区别,具体包含几点:

    • 原生批量命令是原子性,Pipeline是非原子性的.
    • 原生批量命令是一个命令对应多个key,Pipeline支持多个命令.
    • 原生批量命令是Redis服务端支持实现的,而Pipeline需要服务端与客户端的共同实现.

    3. Pipeline总结

    Pipeline虽然好用,但是每次Pipeline组装的命令个数不能没有节制,否则一次组装Pipeline数据量过大,一方面会增加客户端的等待时机,另一方面会造成一定的网络阻塞,可以将一次包含大量命令的Pipeline拆分成多次较小的Pipeline来完成.

    Pipeline只能操作一个Redis实例,但即使在分布式Redis场景中,也可以作为批量操作的重要优化方法.

    事务

    为了保证多条命令组合的原子性,Redis提供了简单的事务以及集成Lua脚本来解决这个问题.

    熟悉关系型数据库的开发者应该对事务比较了解,简单地说,事务表示一组动作,要么全部成功,要不全部不成功.例如在在电商网站中用户购买商品A那么需要将商品A的库存-1,并创建一个订单.这两个操作要么远不执行成功,要么全部执行不成功,否则会出现数据不一致的情况.

    Redis提供了简单的功能,将一组需要一起执行的命令放到multiexec两个命令之间.multi命令代表事务的开始,exec命令代表事务结束,他们之间的命令是原子顺序执行的.
    例如上述的用户购买商品问题:

        127.0.0.1:6379> multi
        OK
        127.0.0.1:6379> hincrby commodity:a:detail stock -1
        QUEUE
        127.0.0.1:6379> rpush user:1:orders {"commodity":'a',..}
        QUEUE

    可以看到数据操作命令返回的结果是QUEUE,代表命令并没有真正执行,而是暂时保存在Redis中.如果此时另一个客户端执行llen user:1:orders返回结果为0.

        127.0.0.1:6379> llen user:1:orders
        (integer) 0

    只有当exec执行后,用户购买商品的行为才算完成,如下两个结果对应hincrbyrpush命令.

        127.0.0.1:6379> exec
        1) (integer) 4  # 商品原库存为5
        2) (integer) 1
        127.0.0.1:6379> llen user:1:orders
        (integer) 1

    如果要停止事务的执行,可以使用discard命令替代exec命令即可.

        127.0.0.1:6379> discard
        OK
        127.0.0.1:6379> llen user:1:orders
        (integer) 0

    如果事务中的命令出现错误,Redis的处理机制也不尽相同.

    1.命令错误
    例如下面操作错将set写成了sett,属于语法错误,会造成整个事务无法执行,keycounter的值未发生变化:

        127.0.0.1:6379> mget key counter
        1) "hello"
        2) "100"
        127.0.0.1:6379> multi
        OK
        127.0.0.1:6379> sett key world
        (error) ERR unknown command 'sett'
        127.0.0.1:6379> incr counter
        QUEUE
        127.0.0.1:6379> exec
        (error) EXECABORT Transaction discarded because of previous errors.
        127.0.0.1:6379> mget key counter
        1) "hello"
        2) "100"

    2.运行时错误
    例如用户购买商品,误把rpush写成了zadd

        127.0.0.1:6379> multi
        OK
        127.0.0.1:6379> hincrby commodity:a:detail stock -1
        QUEUED
        127.0.0.1:6379> zadd user:1:orders {"commodity":'a',..}
        QUEUED
        127.0.0.1:6379> exec
        1) (integer) 1
        2) (error) WRONGTYPE Operation against a key holding the wrong kind of value.
        127.0.0.1:6379> hget commodity:a:detail stack
        (integer) 3

    可以看到Redis并不支持回滚功能,hincrby commodity:a:detail stock -1命令已经执行成功,开发者需要自己修改这类问题.

  • 相关阅读:
    DOM解析和SAX解析对比
    SAX解析示例代码和原理
    xPath技术
    dom4j工具对XML写入修改删除操作实现
    Dom4j工具j解析XML原理和示例代码
    Servlet的多线程并发问题
    Servlet的自动加载
    servlet缺省路径
    线程安全问题出现 的根本原因和解决方案
    9.12測试(四)——測试笔
  • 原文地址:https://www.cnblogs.com/yixianyixian/p/8353563.html
Copyright © 2011-2022 走看看