redis 读书笔记

来源:互联网 发布:单簧管 笛头 知乎 编辑:程序博客网 时间:2024/06/10 15:07
1、通过复制、持久化和客户端分片等特性,用户可以很方便将redis扩展成一个能够包含数百GB数据,每秒处理上百万次请求的系统。
   redis是一种nosql数据库,redis不使用表,它的数据库也不会预订以或者强制去要求用户对redis存储的不同数据进行关联。

2、高性能键值缓存服务器memcached也经常被拿来与redis进行比较,都可以存储键值映射,彼此的性能也相差无几,但redis能够自动以两种不同方式将数据
   写入硬盘,并且redis除了能够存储普通字符串键之外,还可以存储其他4中数据结构,而memcached只能存储普通字符串键。

3、redis拥有两种不同形式的持久化方法,他们都可以用小而紧凑的格式将存储在内存中的数据写入硬盘:
    #第一种持久化方法为时间点转储(point-in-time dump),
        指定时间段内有指定数量的写操作执行,此时可以执行转储
        调用两条转储命令的任何一条来执行(dump-to-disk)
    #第二种持久化方法将所有修改了数据库的命令都写入一个只追加(append-only)文件里面,用户可以更具数据的重要程度,将只追加写入设置为不同步、
    每秒同步一次或者每写入一个命令就同步一次。

4、redis实现了主从复制特定:
    执行复制的从服务器会连接上主服务器,接受主服务器发送的整个数据库的初始副本;
    之后服务器执行写命令,都会被发送给所有连接着的从服务器去执行,从而实时的更新从服务器的数据集。

5、redis支持5种数据结构类型:
    #STRING(字符串)
        GET
        SET
        DEL:适用于所有
        INCR:自增1
        DECR:自减1
        INCRBY:INCRBY NAME AMOUNT,将键存储的值加上整数amount
        DECRBY:
        INCRBYFLOAT:INCRBY NAME AMOUNT,将键存储的值加上浮点数数amount
    字符串相关:
        APPEND:APPEND NAME value,value追加到键值name后面
        GETRANGE:GETRANGE name start end,获取name字符串start到end之间子串,包括start和end
        SETRANGE:SETRANGE name offset value,将name字符串从offset开始以后的子串用value串替代,一个value串位置代替一个offset后面的串位置
    二进制相关:
        GETBIT:GETBIT name offset,将name串看作二进制位串,获取offset处二进制值(0或1)
        SETBIT:SETBIT name offset value,将offset处二进制值(0或1)重新设置为(0或1)
        BITCOUNT:BITCOUNT name [start end],统计name(可以有范围)位串中1的数量
        BITOP:BITOP operation[AND|OR|XOR|NOT] dest-key keyname [keyname2,keyname3...],将一个或者多个串进行位运算,结果保存到dest-key中
    #LIST  (列表)链表
        LPUSH
        RPUSH
        LRANGE:获取列表在给定范围的所有值
        LINDEX:获取列表在给定位置上的单个元素
        LPOP:从列表左端弹出一个值,并返回被弹出的值
        RPOP
        LTRIM:LTRIM name start end,对列表进行裁剪,只保留start到end的元素,start和end会被保留。    
    阻塞式弹出命令以及在列表之间移动命令
        BLPOP:BLPOP name [key-name] timeout ,从第一个非空列表中弹出位于最左端的元素,或者在timeout秒内阻塞病等代可弹出元素的出现,意思就是可以多个
        列表,同时也能够弹出多个值。
        BRPOP:                                                         右
        RPOPLPUSH:RPOPLPUSH source-key dest-key,从source-key列表弹出最右端元素,然后将这个元素推入dest-key列表的最左端,并向用户返回这个元素。
        BRPOPLPUSH:BRPOPLPUSH source-key dest-key timeout,基本操作和上一条一样,就是当source-key为空时,那么在timeout秒之内阻塞并等待可弹出元素
                出现。
    #SET   (集合)无序集合,redis的集合和列表都可以存储多个字符串,它们之间不同之处在于,列表可以存储多个相同字符串,而集合则是通过散列表来保证自己
        存储的每个字符串都是各不相同的(这些散列表只有键,没有与之对应的值)
        SADD:将给定元素添加到集合
        SMEMBERS:返回集合包含的所有元素
        SISMEMBER:检查给定元素是否存在于集合中
        SREM:如果给定元素存在与集合中,那么就移除这个元素
        SCARD:SCARD name,返回包含元素的数量
        SPOP:随机移除
        SMOVE:SMOVE source-key dest-key item,将source-key中item移除并放入dest-key中,成功返回1,失败返回0.
        SRANDMEMBER:SRANDMEMBER key-name [count],随机返回count个元素,且不重复,当count为负数时,返回的元素可能出现重复。
        SINTER:交集
        SINTERSTORE
        SUNION:并集
        SUNIONSTORE
        SDIFF:差集
        SDIFFSTORE:SDIFFSTORE dest-key keyname[key-name2....]求差集(存在于keyname,但是不存在与key-name2(或更多),存储到dest-key中)并存储
    #HASH  (散列)hash集合:散列可以存储多个键值对之间的映射,散列存储的值可以是字符串或者数字
        HSET
        HGET
        HGETALL
        HDEL
        HEXISTS :HEXISTS key-name key,检查给定的键是否存在于散列中
        HKEYS:获取所有的键
        HVALS:获取所有的值
        HGETALL:获取所有的键值对
        HINCRBYFLOAT:HINCRBYFLOAT key-name key increment,将键key保存的值加上浮点数increment。
    #ZSET  (有序集合)按照分值大小排序。和散列一样,都用于存储字符串,有序集合的键被称为成员(member),每个成员都是独一无二的,而有序的值则成为
        分值(score),分值必须为浮点数。有序集合是redis里面唯一一个既可以根据成员访问元素(和散列一样),又可以根据分值以及分值排列顺序访问元素
        的结构。
        ZADD
        ZCARD
        ZINCRBY
        ZSCORE:ZSCORE key-name member 返回成员member的分值
        ZCOUNT:ZCOUNT key-name min max,返回分值介于min和max之间的成员数量
        ZRANK:ZRANK key-name member,返回成员member在有序集合中的排名。
        ZREVRANK:        
        ZRANGE:ZRANGE key-name start end [withscores]根据元素在有序排列中所处的位置,从有序集合里面获取多个member,如果有withscores,则会把分值
            一并返回。
        ZREVRANGE:
        ZREMRANGEBYRANK:移除有序集合中排名介于min和max之间的所有成员
        ZREMRANGEBYSCORE:            分值
        ZRANGEBYSCORE:获取有序集合在给定分值范围内的所有元素
        ZREM:如果给定成员存在于有序集合,那么移除这个成员
        ZINTERSTORE:可以指定交集后的分值如何取,默认为相加
        ZUNIONSTORE:同上
        ZREV*,也就是逆序中的操作,逆序也就是分值从大到小排列。

6、redis中STRING小操作:
    anla7856@anLA7856:/usr/redis2.8.3/myBin$ ./redis-cli
    127.0.0.1:6379> set hello world
    OK
    127.0.0.1:6379> get hello
    "world"
    127.0.0.1:6379> del hello
    (integer) 1
    127.0.0.1:6379> get hello
    (nil)
    127.0.0.1:6379>

7、redis中LIST小操作
    127.0.0.1:6379> rpush list item1
    (integer) 1
    127.0.0.1:6379> rpush list item2
    (integer) 2
    127.0.0.1:6379> rpush list item3
    (integer) 3
    127.0.0.1:6379> lrange list 0 -1
    1) "item1"
    2) "item2"
    3) "item3"

8、redis中HASH小操作:
    127.0.0.1:6379> hset hash key1 value1
    (integer) 1
    127.0.0.1:6379> hset hash key1 value2
    (integer) 0
    127.0.0.1:6379> smenbers
    (error) ERR unknown command 'smenbers'
    127.0.0.1:6379> smembers
    (error) ERR wrong number of arguments for 'smembers' command
    127.0.0.1:6379> hgetall hash
    1) "key1"
    2) "value2"
    127.0.0.1:6379> hset hash key2 value2
    (integer) 1
    127.0.0.1:6379> hgetall hash
    1) "key1"
    2) "value2"
    3) "key2"
    4) "value2"
    127.0.0.1:6379> hget hash key1
    "value2"
    127.0.0.1:6379> hdel hash key1
    (integer) 1
    127.0.0.1:6379> hdel hash key1
    (integer) 0
    127.0.0.1:6379> hget hash key1
    (nil)
    127.0.0.1:6379> hget hash key2
    "value2"

9、对于用来登录的cookie,有两种常见的方法可以将登录信息存储在cookie里面:
    #一种是签名(signed)cookie
    #另一种是令牌(token)cookie
    #两者之间异同,一个大一个小

10、因为浏览器每次发送请求时都会连cookie一起发送,所以如果购物车cookie的体积比较大,那么请求发送和处理的速度可能会有所降低。

11、redis字符串可以存储一下3中类型的值:
    #字符串
    #整数
    #浮点数

12、发布与订阅(又称为pub/sub)的特点是订阅者(listener)负责订阅频道(channel),发送者(publisher)负责想频道发送二进制字符串信息,每当有消息被发送至给定
   频道时,频道的所有订阅者都会收到消息。
    SUBSCRIBE:SUBSCRIBE channel [channel1...],订阅给定的一个或者多个频道
    UNSUBSCRIBE:UNSUBSCRIBE [channel1 ...],退订一个或者多个频道,如果没有参数,就会退订所有频道
    PUBLISH:PUBLISH channel message,向给定频道发送消息
    PSUBSCRIBE:PSUBSCRIBE pattern [pattern1 ...]订阅与给定模式相匹配的所有频道
    PUNSUBSCRIBE: PUNSUBSCRIBE [pattern ...]退订给定的模式,如果执行时没有任何参数,就退订所有模式。

13、redis支持的其他命令
    #SORT排序

14、redis有5个命令可以让用户在不被打断的情况下对多个键执行操作:
    #WATCH
    #MULTI
    #EXEC
    #UNWATCH
    #DISCARD
   在redis里面,被MULTI命令和EXEC命令包围的所有命令会一个接一个执行,直到所有命令执行完毕,才会去处理其他客户端命令。在执行MULTI命令时,redis会把它之后的
   所有命令都放到一个队列里面,知道遇到EXEC命令位置,然后redis就会在不被打断情况下,一个个执行队列离的命令。只有接受EXEC,才会开始执行队列中的命令。

15、键的过期时间:
    #PERSIST:PERSIST key-name,移除键的过期时间
    #TTL:TTL key-name,查看给定键距离过期时间还有多少秒
    #EXPIRE:EXPIRE key-name second,让给定键在指定的秒数之后过期
    #PTTL:同TTL
    #PEXPIRE:PEXPIRE key-name milliseconds,让键给定键在指定的毫秒数之后过期
    #PEXPIREAT PEXPIREAT key-name timestamp-milliseconds,用毫秒级来指定过期时间

16、快照持久化只适用于哪些即使丢失一部分数据也不会造成问题的应用程序,而不能接受这种数据损失的可以考虑AOF持久化(只追加文件append-only file)
    AOF持久化有三个选项:
        #always:每个命令都要同步到硬盘
        #everysec
        #no:让操作系统来决定何时进行同步
    AOF持久化也有缺点,就是AOF体积的大小,可能越来越大,可能会用完硬盘所有空间。
    用户可以通过发送BGREWRITEAOF来对AOF文件进行优化,尽可能减少大小,这个与BGSAVE创建快照的工作原理非常相似

17、关系数据库通常会使用一个主服务器向多个从服务器发送更新,并使用从服务器来处理所有请求,redis也采用了同样的方法来实现复制特性,并将其作为扩展
   性能的一种手段。从服务器连接一个主服务器的时候,主服务器会创建一个快照文件并将其发送给从服务器。
   #从服务器也可以拥有自己的从服务器,并由此形成主从链。但是有一个问题,当从服务器与主服务器进行连接操作时,会断开此从服务器与自己的从服务器的连接并且
   需要重新同步。
   #检查INFO命令的输出结果中aof_pending_bio_fsync属性是否为0,如果是的话,那么表示服务器已经将所有数据都保存到硬盘。
   #INFO命令提供了大量与redis服务器当前状态有关的信息,比如内存占用凉,客户端连接数,每个数据库包含的键的数量,上一次创建快照文件之后执行的命令数量等等,
    INFO命令对了解redis服务器的综合状态非常有帮助。

18、更换故障服务器,如果a,b,c三台服务器,a是主,b是从,如果a坏了,那么就要更换a,首先向机器b发送一条SAVE命令,让它创建一个新的快照文件,接着把这个快照文件
   发送给机器c,并且在机器c上启动redis,最后,让机器b成为机器c的从服务器。SLAVEOF machine-c.vpn 6379,在机器b上运行该命令,将c作为作为redis主服务器。

19、包括python在内的很多redis客户端,在处理事务的时候,都是会等到所有命令都出现后,才一次性的将所有MULTI命令,待执行的命令,EXEC命令一次性发送给redis。

20、通过使用WATCH、MULTI/EXEC、UNWATCH/DISCARD等命令,程序可以在执行某些重要操作时,通过确保自己正在使用的数据没有发生变化来避免数据出错。
    UNWATCH可以在WATCH命令执行之后,MULTI命令执行之前对连接进行重置。
    DISCARD命令也可以在MULTI命令之后,EXEC命令之前对连接进行重置。
    这也就是说,用户在使用WATCH监视一个或者多个键,接着使用MULTI开始一个新的事务,并将多个命令入队到队列之后,仍然可以通过DISCARD命令来取消WATCH命令并
         清空原有入队命令。

21、非事务型流水线:
    pipe = conn.pipeline();
   如果用户需要向redis发送多条命令,并且对于这些命令来说,一个命令的执行结果并不会影响到另一个命令的输入,而且这些命令也不需要以事务的方式来执行的话
   ,就可以通过pipeline()方法传入false来进一步提升redis的整体性能。    

22、如何构建两个前缀自动补全程序,在web领域自动补全(autocomplete)是一种能够让用户在不进行搜索的情况下,快速找到所需技术。
   用redis列表来实现。保证列表只有特地数量的人。然后每次搜索时获取全部联系人,如何实现自动补全呢?也就是如何查找所需要字符串呢?
   比如查找abc,我们可以用zrange查找abbz之后和abd之前的。通过WATCH,MULTI,EXEC来确保在查找过程中,有序集合不会发生变化。
   #在自动补全程序向有序集合里面添加起始元素和结束元素的时候,我们需要谨慎的处理其他正在执行的自动补全操作,这样是程序里面用到watch命令的原因,但是随着
    负载增加,程序在进行重试次数可能越来越多,导致资源被白白浪费,所以此时用锁来减少对watch命令的使用,甚至用锁来替代watch命令,从而达到避免重试,提升
    性能并在某些情况下简化代码的效果。

23、一般来说,对数据进行加锁时,程序首先需要通过获取锁来对数据进行排他性的访问能力,然后才能对数据进行一系列操作,最后还要将锁释放给其他程序。对于能够被
   多个线程访问的共享内存数据结构来说,这种“先获取锁,然后执行操作,最后释放锁”的动作非常常见,redis使用watch命令来代替数据进行加锁,因为watch只会在数据被
   其他客户端抢先修改的情况下通知执行了这个命令的客户端,而不会阻止客户端对数据进行修改,所以这个命令称为乐观锁。
   #分布式锁也有类似“先获取,然后执行操作,最后释放锁”动作,但这种锁既不是给同一个进程多个线程使用,也不是给同一台机器上多个进程使用,而是由不同机器上的
    不同redis客户端进行获取和释放的。

24、redis来构建锁:而不是简易锁(lock,locking,locking timeouts)
        #为了对数据进行排他性访问,程序首先就是要获取锁,SETNX命令天生就是适合用来实现锁的获取功能,这个命令只会在键不存在情况下为键设置值,而锁要做的就是
   将一个随机生成的UUID设置为键的值,并使用这个值来防止锁被其他进程获取到。如果程序在尝试获取锁的时候失败,那么它将会不断的进行重试,知道成功的取得锁或者
   超过给定的时限,键不存在才能为它设置值,键存在,就说明有人为他设置,有人获取了它的锁,所以你不能获取。
        #当释放这样的锁时,需要小心,因为你加锁可能是一个客户端才能够进行,但是释放也就是删除这个UUID时,就可能有多个键可以进行,所以这样:
    首先使用watch命令监视代表锁的键,接着检查目的值是否和加锁时设定相同的值,确认相同后删除该键。
        #在高负载的情况下,使用锁可以减少重试次数,降低延迟时间,提升性能并将加锁的粒度调整至合适大小。
        #如何构造一个带有超时限制的锁呢?
    为了给锁加上超时限制特性,程序将在取得锁后,调用expire命令来为锁设置过期时间,使得redis可以自动删除超时的锁,为了确保锁在客户端已经崩溃的情况下仍然能够
    自动释放,客户端会尝试获取做失败后,检查锁的超时时间,并为未设置超时时间的锁设置超时时间,因此锁总会带有超时时间,并且最终因为草食而自动释放。这样由于
    总会有超时时间,所以也就不存在,锁超时被释放了,但是另一方面锁手动还没释放?可能有,

25、计数信号量:是一种锁,它可以让用户限制一项资源最多能够同时被多少个进程访问,通常限定与能够同时使用的资源数量。
        #使用redis来实现超时限制特性通常有两种方法可以选,一种是使用expire命令,另一种就是使用有序集合,即存储唯一标识和unix时间戳。
        #程序为每个尝试获取信号量的进程生成一个唯一标识符,并将这个标识符用作有序集合的成员,而成员对应的分值则是进程尝试获取信号量时的unix时间戳
        #每当进程尝试获取信号量,就会生成一个标识符,并使用当前时间戳为分值,将标识符添加到有序集合里面,接着进程会检查自己的标识符在有序集合里面的
    排名,如果排名低于可获取的信号量总数(0开始),那么就表示进程成功的获取了信号量,反之则未获去信号量,它必须从有序集合里面移除自己的标识符。为了处理
    过期的信号量,程序在将标识符加到有序集合之前,会先清理有序集合中所有时间戳大于超时数值的标识符。
        #每当锁或者信号量因为系统始终的细微不同而导致锁的获取结果出现剧烈变化时,这个锁或者信号量就是不公平的。
        #所谓redis里面实现的公平信号量,就是给信号量添加一个计数器timer类似,然后每次不是通过获取unix时间戳,而是获取timer返回的时间来作为分值。

26、任务队列:

27、简单来说,publish和subscribe的缺陷在于客户端必须一直在线才能接受到消息,断线可能会导致客户端丢失信息。除此之外,旧版redis可能会因为订阅者处理消息速度
    不够块而变得不稳定甚至崩溃,又或者被管理员杀死。

28、使用redis来进行文件分发:
        #利用Rsync软件,旨在解决网络不稳定时,让单个文件或者多个文件可以部分的进行传送续传。
        #利用bittorrent
        
29、redis还特别适用解决搜索的问题,这类问题通常需要使用集合以及有序集合的交集,并集和差集操作查找符合指定要求的元素。

30、为了获得比扫描文件更快的搜索速度,需要对文档进行预处理,也就是建立索引,而所需要创建索引的结构被成为反向索引。具体来说,反向索引会从每个被索引的文档里面
   提取一些但此,并创建集合来记录每篇文章包含了哪些但此,例如一篇文章doca是 hello world,另一篇文章docb是hello java,程序就会在redis里面为hello这个但此创建
   一个集合,并在集合里面包含doca和docb。

31、广告定向,广告服务器需要接受一系列定向参数以便挑选出具体的广告,这些参数至少需要包含浏览者基本位置信息
    广告定向系统也会使用由集合和有序集合构成的反向索引来存储广告id

32、职位搜索,通过并集来将和相关信息相同的职位都收集起来。

33、构建简单的社交网站
        #用户和状态
        #主页时间线
        #关注者列表和正在关注列表
        #状态消息的发布与删除
        #流API
            :流API的作用就是随着时间的推移,产生一个由事件组成的序列,以此来让整个网络上的客户端和其他服务及时了解到网站目前正在发生的事。
            :每当新诞生的状态消息与过滤器相匹配的时候,流API就将会把这条消息返回给客户端,服务器会告知客户端,并将实际的过滤器传递给生成器,
            然后由生成器产生符合过滤标准的消息序列。
            :pub/sub模式
原创粉丝点击