您的位置:首页 > 数据库 > Redis

Redis笔记

2015-06-24 15:26 344 查看
【1】redis是什么

    Redis是一个开源的高性能键值对数据库。它通过提供多种键值数据类型来适应不同场景下的存储需求,并借助许多高层级的接口使其

    可以胜任如缓存、队列系统等不同的角色

【2】特性

    {

        1.存储结构:    Redis是REmote DIctionary Server(远程字典服务器)的缩写,它以字典结构存储数据,并允许其他应用

        通过TCP协议读写字典中的内容(dict['key'] = 'value')

        

        2.内存存储和持久化

        {

            所有数据都存储在内存中,速度快

            内存中的数据异步写入硬盘,永久保存

        }

        

        

        3.功能丰富

        {

            1.缓存系统

            2.队列系统

        }

        

        4.简单稳定

    

    }

【3】安装



    1.在POSIX系统中安装

    {

        wget http://download.redis.io/redis-stable.tar.gz
        tar xzf redis-stable.tar.gz

        cd redis-stable

        make    

        

        最好在编译后直接执行make install命令来将这些可执行程序复制到/usr/local/bin目录中以便以后执行程序时可以不用

        输入完整的路径

    }       



【4】启动和停止Redis



    1.运行文件

    {

        1.redis-server  redis服务器

        2.redis-cli redis客户端

        3.redis-benchmark   redis性能测试工具

        4.redis-check-aof   AOF文件修复工具

        5.redis-check-dump  RDB文件检查工具

    }

    

    2.启动redis

    {

        1.直接启动  redis-server(通过--port可以自定义端口号)

        

        2.脚本启动(生产环境推荐)

        {

            1.首先将初始化脚本redis_init_script复制到/etc/init.d目录中,文件名为redis_端口号

            2.建立需要的文件夹

            {

                /etc/redis  存放redis的配置文件

                /var/redis/端口号   存放redis的持久话文件

            }

            3.修改配置文件,首先将配置模板文件redis.conf复制到/etc/redis目录中,以端口号命名文件如6379.conf

            {

                1.daemonize yes 是redis以守护进程的模式运行

                2.pidfile   /var/run/redis_端口号.pid   设置Redis的PID文件位置

                3.port  

                4.dir   /var/redis/端口号   设置持久化文件存放位置

            }

            

            

            手动脚本启动    /etc/init.d/redis_端口号 start

        

            随系统自动启动 sudo update-rc.d redis_端口号 defaults

        }

        

        3.停止redis: redis-cli SHUTDOWN

        {

            当Redis收到SHUTDOWN命令后,会先断开所有客户端连接,然后根据配置执行持久化,最后完成退出。

            Redis可以妥善处理SIGTERM信号,所以使用“kill Redis进程的PID”也可以正常结束Redis,效果与发送SHUTDOWN

            命令一样

        }

        

        

    }

    

    3.命令行客户端

    {

        1.发送命令

        {

            1.将命令作为redis的参数执行: redis ping

            2.不附带参数运行的redis:    ping(新登录redis进入交互模式)

        }

        

        2.命令返回值

        {

            1.状态回复

            2.错误回复

            3.整数回复

            4.字符串回复

            5.多行字符串回复            

        }

                    

    }

    

    4.多数据库配置

    {

        1.一个实例提供多个存储数据的字典(数据库),默认支持16个。

        2.数据库以一个从0开始的数据命名(0-15)

        3.通过select 1来切换数据库

        4.不支持修改数据库的名字,不支持为每个数据库设置不同的访问密码

        5.不同的应用应使用不同的实例来存储

    }



【5】数据类型



    1.基础命令

    {

        1. keys pattern 获得符合规则的键名列表

        {

            1.?     任一个字符

            2.*    0到多个字符

            3.[]  一个字符[a-z]   

            4.\x    用于转义字符

            

            KEYS命令需要遍历Redis中的所有键,当键的数量较多时会影响性能,不建议在生产环境中使用

        }

        

        2.exists key    如果键存在则返回整数类型1,否则返回0

        

        3.DEL key [key ...] 可以删除一个或多个键

        {

            1.可以结合Linux 的管道和xargs 命令自己实现删除所有符合规则的键

            

                redis-cli KEYS "user:*" | xargs redis-cli DEL                

                redis-cli DEL 'redis-cli KEYS"user:*"'  //删除不了,待研究

        }

        

        4.TYPE key  获得键值的数据类型

        {

            1.string    字符串类型

            2.hash  散列类型

            3.list  列表类型

            4.set   集合类型

            5.zset  有序集合类型

        }

    }

    

    2.字符串类型    redis最基本的数据类型

    {

        1.命令

        {

            1.SET key value

            2.GET key

            3.INCR key  递增数字

            

            命令拾遗

            4.INCRBY key increment  增加指定的整数

            5.DECR key  递减数字

            6.DECRBY key decrement  减少指定的整数

            7.INCRBYFLOAT key increment 增加指定浮点数

            8.APPEND key value  向尾部追加值(类似字符串连接)

            9.STRLEN key    获取字符串长度

            10. 同时获得/设置多个键值

            {

                MGET key [key ...]

                MSET key value [key value ...]

            }

        }

        

        2.键名规则

        {

            Redis对于键的命名并没有强制的要求,但比较好的实践是用“对象类型:对象ID:对象属性”来命名一个键

        }

    }

    

    3.散列类型(hash,字段和字段值的映射,key,fields,value)

    {

        1.定义:    散列类型(hash)的键值也是一种字典结构,其存储了字段(field)和字段值的映射,但字段值只能是字符串

                    (基本数据类型),不支持其他数据类型

                    

        2.用途:    散列类型适合存储对象:使用对象类别和ID构成键名,使用字段表示对象的属性,而字段值则存储属性值

        

        3.特点:    可以自由地为任何键增减字段而不影响其他键

        

        4.命令

        {

            1.HSET key field value

            2.HGET key field

            3.HMSET key field value [field value ...]

            4.HMGET key field [field ...]

            5.HGETALL key

            

            6.HEXISTS key field //hexists car name

            7.HSETNX key field value    当字段不存在时赋值

            8.HINCRBY key field increment   

            9.HDEL key field [field ...]

        }

        

        

        5.命令拾遗

        {

            1.只获取字段名或字段值

            {

                HKEYS key

                HVALS key

            }

            

            2.获得字段数量

                HLEN key

        }

    }

    

    4.列表类型

    {

        1.定义:列表类型(list)可以存储一个有序的字符串列表,常用的操作是向列表两端添加元素,或者获得列表的某一个片段

        

        2.特定:

        {

            1.列表类型内部是使用双向链表(double linked list)实现的,所以向列表两端添加元素的时间复杂度为0(1),

              获取越接近两端的元素速度就越快

            

            2.使用列表类型来模拟栈和队列的操作:如果想把列表当做栈,则搭配使用LPUSH和LPOP或RPUSH和RPOP,如果想

              当成队列,则搭配使用LPUSH和RPOP或RPUSH和LPOP

        }

                       

        3.命令

        {

            1.向列表两端增加元素

            {

                LPUSH key value [value ...]

                RPUSH key value [value ...]

            }

            

            2.从列表两端弹出元素

            {

                LPOP key

                RPOP key

            }

            

            3.获取列表中元素的个数  LLEN key

            

            4.获得列表片段

            {

                1.LRANGE key start stop

                2.LRANGE命令也支持负索引,表示从右边开始计算序数,如"-1"表示最右边第一个元素,"-2"表示最右边第二个

                  元素,依次类推

                  

                3.LRANGE numbers 0 -1可以获取列表中的所有元素

            }

            

            5.删除列表中指定的值

            {

                1.LREM key count value

                

                ●当count>0时LREM命令会从列表左边开始删除前count个值为value的元素;

                ●当count<0时LREM 命令会从列表右边开始删除前|count|个值为value的元素;

                ●当count=0是LREM命令会删除所有值为value的元素。

            }

        }

        

        4.命令拾遗

        {

            1.获得/设置指定索引的元素值

            {

                如果index是负数则表示从右边开始计算的索引,最右边元素的索引是-1

                LINDEX key index

                LSET key index value

            }

            

            2.只保留列表指定片段

            {

                ●LTRIM key start end

                ●LTRIM命令可以删除指定索引范围之外的所有元素,其指定列表范围的方法和LRANGE命令相同

                ●LTRIM命令常和LPUSH命令一起使用来限制列表中元素的数量(ltrim logs 0 99)

            }

            

            3.向列表中插入元素

            {

                ●LINSERT key BEFORE|AFTER pivot value

            }

            

            4.将元素从一个列表转到另一个列表

            {

                ●RPOPLPUSH source destination

                ●先执行RPOP命令再执行LPUSH 命令。RPOPLPUSH命令会先从source列表类型键的右边弹出一个元素,然后将其

                加入到destination列表类型键的左边,并返回这个元素的值,整个过程是原子的

                ●RPOPLPUSH命令可以很直观地在多个队列中传递数据。当source和destination相同时,RPOPLPUSH命令会不断

                地将队尾的元素移到队首,形成队列循环

            }

        }

    }

    

    5.集合类型

    {

        1.定义:在集合中的每个元素都是不同的,且没有顺序。集合类型在Redis内部是使用值为空的散列表(hash table)实现的

               (列表类型是有序,不唯一)

        2.特定:并集、交集和差集运算

        

        3.命令

        {

            1.增加/删除元素

            {

                    SADD
146bf
key member [member ...]

                    SREM key member [member ...]

            }

            

            2.获得集合中的所有元素

            {

                    SMEMBERS key

            }

            

            3.判断元素是否在集合中

            {

                    SISMEMBER key member

            }

            

            4.集合间运算

            {

                    SDIFF key [key ...] 差集

                    SINTER key [key ...]    交集

                    SUNION key [key ...]    合集

            }

            

            5.获得集合中元素个数    SCARD key

            6.进行集合运算并将结果存储

            {

                SDIFFSTORE destination key [key ...]

                SINTERSTORE destination key [key ...]

                SUNIONSTORE destination key [key ...]

            }

            7.随机获得集合中的元素

            {

                SRANDMEMBER key [count]

                (1)当count为正数时,SRANDMEMBER会随机从集合里获得count个不重复的元素。如果count的值大于集合中的

                   元素个数,则SRANDMEMBER会返回集合中的全部元素。

                (2)当count为负数时,SRANDMEMBER会随机从集合里获得|count|个的元素,这些元素有可能相同。

            }

            

            8.从集合中弹出一个元素  SPOP key

            

        }

               

        

    }

    

    6.有序集合

    {

        1.特点:在集合类型的基础上有序集合类型为集合中的每个元素都关联了一个分数

        

        2.有序集合和列表类型的区别

        {

            (1)列表类型是通过链表实现的,获取靠近两端的数据速度极快,而当元素增多后,访问中间数据的速度会较慢,所以它更

               加适合实现如“新鲜事”或“日志”这样很少访问中间元素的应用。

            

            (2)有序集合类型是使用散列表和跳跃表(Skip list)实现的,所以即使读取位于中间部分的数据速度也很快(时间复杂

               度是O(log(N)))。

            (3)列表中不能简单地调整某个元素的位置,但是有序集合可以(通过更改这个元素的分数)。

            (4)有序集合要比列表类型更耗费内存。

        }

        

        3.命令

        {

            1.增加元素

            {

                ZADD key score member [score member ...]

                ZADD命令用来向有序集合中加入一个元素和该元素的分数,如果该元素已经存在则会用新的分数替换原有的分数

                分数不仅可以是整数,还支持双精度浮点数

            }

            

            2.获得元素的分数    ZSCORE key member

            3.获得排名在某个范围的元素列表

            {

                ZRANGE key start stop [WITHSCORES]

                ZRANGE命令会按照元素分数从小到大的顺序返回索引从start到stop之间的所有元素(包含两端的元素)

                

                ZREVRANGE key start stop [WITHSCORES]

                ZREVRANGE命令和ZRANGE的唯一不同在于ZREVRANGE命令是按照元素分数从大到小的顺序给出结果的。

            }

            

            4.获得指定分数范围的元素

            {

                ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]

                如果希望分数范围不包含端点值,可以在分数前加上“(”符号(如不包含100分,则是‘(100’  )

            }

            

            5.增加某个元素的分数

            {

                ZINCRBY key increment member

                increment是个正数表示加分

                increment也可以是个负数表示减分

            }

            

            6.获得集合中元素的数量 ZCARD key

            7.获得指定分数范围內的元素个数  ZCOUNT key min max

            8.删除一个或多个元素    ZREM key member [member ...]

            9.按照排名范围删除元素  ZREMRANGEBYRANK key start stop

            10按照分数范围删除元素  ZREMRANGEBYSCORE key min max

            11.获得元素的排名

            {

                ZRANK key member

                ZREVRANK key member

            }

            

            12.计算有序集合的交集

            {

                ZINTERSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]]

                [AGREGATE SUM|MIN|MAX]

                

                

                ZINTERSTORE命令用来计算多个有序集合的交集并将结果存储在destination键中(同样以有序集合类型存储),

                返回值为destination键中的元素个数

            }

            

        }

    }



【6】进阶



    1.事务

    {

        1.定义:事务同命令一样都是Redis的最小执行单位,一个事务中的命令要么都执行,要么都不执行

        

        2.错误处理

        {

            (1)语法错误。语法错误指命令不存在或者命令参数的个数不对

            只要有一个命令有语法错误,执行EXEC命令后Redis就会直接返回错误,连语法正确的命令也不会执行

            

            (2)运行错误。运行错误指在命令执行时出现的错误

            如果事务里的一条命令出现了运行错误,事务里其他的命令依然会继续执行(包括出错命令之后的命令)

        }

        

        3.WATCH

        {

            WATCH命令可以监控一个或多个键,一旦其中有一个键被修改(或删除),之后的事务就不会执行,监控一直持续到EXEC命令

            

            由于WATCH命令的作用只是当被监控的键值被修改后阻止之后一个事务的执行,而不能保证其他客户端不修改这一键值,

            所以我们需要在EXEC执行失败后重新执行整个函数

            

            UNWATCH命令来取消监控

        }

    }

    

    2.生存时间

    {

    

        1.EXPIRE:设置一个键的生存时间,到时间后Redis会自动删除它(也可以重新设置键的生存时间)

        2.EXPIRE key seconds

        3.TTL

        {

            1.返回值是键的剩余时间

            2.实际测试中,键值不存在后返回-2

            3.没有为键设置生存时间(默认情况),返回值是-1            

        }

        

        4.persist:取消键的生存时间设置(即将键恢复成永久的)

        {

            生存时间被成功清除则返回-1

        }

        

        5.set或者getset命令为键赋值也会同时清除键的生存时间,其他只对键值进行操作的命令(如INCR、LPUSH、HSET、ZREM)

        均不会影响键的生存时间

        

        6.PEXPIRE 单位是毫秒

        7.如果使用WATCH命令监测了一个拥有生存时间的键,该键时间到期自动删除并不会被WATCH命令认为该键被改变

        8.EXPIREAT  参数为unix时间戳

        

        9.实现缓存

        {

            可以限制Redis能够使用的最大内存,并让Redis按照一定的规则淘汰不需要的缓存键,这种方式在只将Redis用作缓存系统

            时非常实用

            

            具体的设置方法为:修改配置文件的maxmemory参数,限制Redis最大可用内存大小(单位是字节),当超出了这个限制时

            Redis会依据maxmemory-policy参数指定的策略来删除不需要的键,直到Redis占用的内存小于指定内存

            (/etc/redis/6379.conf)

            

            表4-1 Redis支持的淘汰键的规则续表如当maxmemory-policy设置为allkeys-lru时,一旦Redis占用的内存超过了

            限制值,Redis会不断地删除数据库中最近最少使用的键1 ,直到占用的内存小于限制值

        }

        

    }

    

    3.排序

    {

        a.  SORT

        {

            1). SORT命令可以对列表类型、集合类型和有序集合类型键进行排序

            2). SORT命令还可以通过ALPHA参数实现按照字典顺序排列非数字元素

            3). SORT命令的 DESC参数可以实现将元素按照从大到小的顺序排列

            4). SORT命令还支持LIMIT参数来返回指定范围的结果。用法和SQL语句一样,LIMIT offset count

        }

        

        b.  BY参数

        {

            1). BY 参数的语法为“BY参考键”。其中参考键可以是字符串类型键或者是散列类型键的某个字段(表示为键名->字段名)。

                如果提供了BY参数,SORT命令将不再依据元素自身的值进行排序,而是对每个元素使用元素的值替换参考键中的第一个

                “*”并获取其值,然后依据该值对元素排序

                

            2). 当参考键名不包含“*”时(即常量键名,与元素值无关),SORT命令将不会执行排序操作,因为Redis认为这种情况是没有

                意义的(因为所有要比较的值都一样)

                

            3).在不需要排序但需要借助SORT命令获得与元素相关联的数据时(见4.3.4节),常量键名是很有用的

            4).如果几个元素的参考键值相同,则SORT命令会再比较元素本身的值来决定元素的顺序

            5).当某个元素的参考键不存在时,会默认参考键的值为0

        }

        

        c.  GET参数

        {

            1).GET参数不影响排序,它的作用是使SORT命令的返回结果不再是元素自身的值,而是GET参数中指定的键值

            2).GET参数的规则和BY参数一样,GET参数也支持字符串类型和散列类型的键,并使用“*”作为占位符

                redis>SORT tag:ruby:posts BY post:*->time DESC GET post:*->title

                

            3).在一个SORT命令中可以有多个GET参数(而BY参数只能有一个)

                redis>SORT tag:ruby:posts BY post:*->time DESC GET post:*->title GET post:*->time

                

            4).GET #会返回元素本身的值

        }

        

        d. STORE参数

        {

            1). 默认情况下SORT会直接返回排序结果,如果希望保存排序结果,可以使用STORE参数

            2). 保存后的键的类型为列表类型,如果键已经存在则会覆盖它

            3). STORE参数常用来结合EXPIRE命令缓存排序结果

        }

        

        e. 开发中使用SORT命令时需要注意以下几点。

        {            

            (1)尽可能减少待排序键中元素的数量(使n尽可能小)。

            (2)使用LIMIT参数只获取需要的数据(使m尽可能小)。

            (3)如果要排序的数据数量较大,尽可能使用STORE参数将结果缓存。

        }

            

    }

    

    4.消息通知

    {

        a.  任务队列

        {

            1).松耦合

            2).易于扩展消费者可以有多个,可以分布在不同的服务器上

        }

        

        b.  使用redis实现任务队列

        {

            1).如果要实现任务队列,只需要让生产者将任务使用LPUSH命令加入到某个键中,另一边让消费者不断地使用RPOP命令从

                该键中取出任务即可

                

            2).BRPOP命令和RPOP命令相似,唯一的区别是当列表中没有元素时BRPOP命令会一直阻塞住连接,直到有新元素加入(BLPOP)

        }

        

        c.  优先级队列

        {

            1).BRPOP命令可以同时接收多个键,其完整的命令格式为BLPOP key [key ...]timeout,

               如BRPOP queue:1 queue:2 0。意义是同时检测多个键,如果所有键都没有元素则阻塞,如果其中有一个键有元素

               则会从该键中弹出元素

               

            2).如果多个键都有元素则按照从左到右的顺序取第一个键中的一个元素

        }

        

        d.  发布订阅模式

        {

            1).定义:“发布/订阅”模式中包含两种角色,分别是发布者和订阅者。订阅者可以订阅一个或若干个频道(channel),

               而发布者可以向指定的频道发送消息,所有订阅此频道的订阅者都会收到此消息

               

            2).发布者发布消息的命令是PUBLISH,用法是PUBLISH channel message.发出去的消息不会被持久化,也就是说当有客户

               端订阅channel.1后只能收到后续发布到该频道的消息,之前发送的就收不到了

            

            3).订阅频道的命令是SUBSCRIBE,可以同时订阅多个频道,用法是SUBSCRIBE channel[channel ...]

               执行SUBSCRIBE命令后客户端会进入订阅状态,处于此状态下客户端不能使用除

               SUBSCRIBE/UNSUBSCRIBE/PSUBSCRIBE/PUNSUBSCRIBE这4个属于“发布/订阅”模式的命令之外的命令,否则会报错

               

            4).进入订阅状态后客户端可能收到三种类型的回复

            {

                [1].Subscribe

                [2].message

                [3].unsubscribe

            }

        }

    }

    

    5.按照规则订阅

    {

        a.  使用PSUBSCRIBE命令订阅指定的规则。规则支持glob风格通配符格式

            如:PSUBSCRIBE channel.?*

            

        b.  使用PSUBSCRIBE命令可以重复订阅一个频道,如某客户端执行了PSUBSCRIBE channel.? channel.?*

        

        c.  PUNSUBSCRIBE命令可以退订指定的规则,用法是PUNSUBSCRIBE [pattern[pattern ...]],

            如果没有参数则会退订所有规则

            

        d.  使用PUNSUBSCRIBE命令只能退订通过PSUBSCRIBE命令订阅的规则,不会影响直接通过SUBSCRIBE命令订阅的频道;

            同样UNSUBSCRIBE命令也不会影响通过PSUBSCRIBE命令订阅的规则

            

        e.  使用PUNSUBSCRIBE命令退订某个规则时不会将其中的通配符展开,而是进行严格的字符串匹配,所以PUNSUBSCRIBE*

            无法退订channel.*规则,而是必须使用PUNSUBSCRIBE channel.*才能退订

    }

    

    6.管道命令

    {

        作用:管道通过减少客户端与Redis的通信次数来实现降低往返时延累计值的目的

        用法:通过管道可以一次性发送多条命令并在执行完后一次性将结果返回,当一组命令中每条命令都不依赖于之前命令的执行结果

             时就可以将这组命令一起通过管道发出

    }

    

    7.节省空间

    {

        原因:Redis是一个基于内存的数据库,所有的数据都存储在内存中,所以如何优化存储,减少内存空间占用对成本控制来说是

             一个非常重要的话题

             

        a.  精简键名和键值是最直观的减少内存占用的方式

        b.  内部编码转换减少存储空间

        {

            1). Redis的每个键值都是使用一个redisObject结构体保存的

            

            2). 字符串类型

            {

                [1]   Redis使用一个sdshdr类型的变量来存储字符串,而redisObject的ptr字段指向的是该变量的地址

                

                [2]   redisObject中的refcount字段存储的是该键值被引用数量,即一个键值可以被多个键引用。Redis启动

                       后会预先建立10000个分别存储从0到9999这些数字的redisObject类型变量作为共享对象,如果要设置的

                       字符串键值在这10000个数字内(如SET key1 123)则可以直接引用共享对象而不用再建立一个

                       redisObject了,也就是说存储键值占用的空间是0字节.由此可见,使用字符串类型键存储对象ID这种小数字

                       是非常节省存储空间的,Redis只需存储键名和一个对共享对象的引用即可

            }

            

            3). 散列类型

            {

                [1]   散列类型的内部编码方式可能是REDIS_ENCODING_HT或REDIS_ENCODING_ZIPLIST

                

                [2]   当散列类型键的字段个数少于hash-max-ziplist-entries参数值且每个字段名和字段值的长度都小于

                       hash-max-ziplist-value参数值(单位为字节)时,Redis就会使用REDIS_ENCODING_ZIPLIST来存储

                       该键,否则就会使用REDIS_ENCODING_HT

                       

                [3]   REDIS_ENCODING_HT编码即散列表,可以实现O(1)时间复杂度的赋值取值等操作,其字段和字段值都是使用

                       redisObject存储的,所以前面讲到的字符串类型键值的优化方法同样适用于散列类型键的字段和字段值

                       

                [4]   REDIS_ENCODING_ZIPLIST编码类型是一种紧凑的编码格式,它牺牲了部分读取性能以换取极高的空间

                       利用率,适合在元素较少时使用

            }

            

            4). 列表类型

            {

                [1] 列表类型的内部编码方式可能是REDIS_ENCODING_LINKEDLIST或REDISENCODINGZIPLIST

                    

                [2] REDIS_ENCODING_LINKEDLIST编码方式即双向链表,链表中的每个元素是用redisObject存储的,所以此种

                    编码方式下元素值的优化方法与字符串类型的键值相同                                        

            

            }

            

            5.  集合类型

            {

                [1]   集合类型的内部编码方式可能是REDIS_ENCODING_HT或REDIS_ENCODING_INTSET

                

                [2]   当集合中的所有元素都是整数且元素的个数小于配置文件中的set-max-intset-entries参数指定值

                        (默认是512)时Redis会使用REDIS_ENCODING_INTSET编码存储该集合,否则会使用REDIS_ENCODING_HT来存储

                

                [3]   REDIS_ENCODING_INTSET编码以有序的方式存储元素(所以使用SMEMBERS命令获得的结果是有序的),使得

                        可以使用二分算法查找元素。然而无论是添加还是删除元素,Redis都需要调整后面元素的内存位置,所以当

                        集合中的元素太多时性能较差

            }

            

            6.  有序集合类型

            {

                [1]   有序集合类型的内部编码方式可能是REDIS_ENCODING_SKIPLIST或REDIS_ENCODING_ZIPLIST

                

                [2]   当编码方式是REDIS_ENCODING_SKIPLIST时,Redis使用散列表和跳跃列表(skiplist)两种数据结构来

                        存储有序集合类型键值,其中散列表用来存储元素值与元素分数的映射关系以实现0(1)时间复杂度的ZSCORE

                        等命令。跳跃列表用来存储元素的分数及其到元素值的映射以实现排序的功能。Redis对跳跃列表的实现进行

                        了几点修改,其中包括允许跳跃列表中的元素(即分数)相同,还有为跳跃链表每个节点增加了指向前一个元素的

                        指针以实现倒序查找

            }

        

        }

    }



【7】实践



    1. PHP和Redis

    {

    

        a.  Redis官方推荐的PHP客户端是Predis1 和phpredis2 

        b.  安装

        {

            1). 下载predis, 解压并将整个文件夹复制到项目目录中即可使用

            2). require './predis/autoload.php';    

                如果你的项目使用的PHP框架已经支持了通过定义PHP的自动加载函数实现了该标准那么就无需再次引入autoload.php了

                

            3). $redis=new Predis\Client(array(

                    'scheme'=>'tcp',

                    'host'=>'127.0.0.1',

                    'port'=>6379,

                ));

        }

    }



【8】管理



    1.持久化    将数据从内存中以某种形式同步到硬盘中

    {

        a.  RDB方式

        {

        

            1). RDB方式的持久化是通过快照(snapshotting)完成的,当符合一定条件时Redis会自动将内存中的所有数据进行快照

                并存储在硬盘上

                

            2). 进行快照的条件可以由用户在配置文件中自定义,由两个参数构成:时间和改动的键的个数。当在指定的时间内被更改

                的键的个数大于指定的数值时就会进行快照。RDB是Redis默认采用的持久化方式,在配置文件中已经预置了3个条件:

                save 900 1

                save 300 10

                save 60 10000

                save参数指定了快照条件,可以存在多个条件,条件之间是“或”的关系

                

            3). Redis默认会将快照文件存储在当前目录的dump.rdb文件中,可以通过配置dir和dbfilename两个参数分别指定

                快照文件的存储路径和文件名

                

            4). Redis在进行快照的过程中不会修改RDB文件,只有快照结束后才会将旧的文件替换成新的,也就是说任何时候RDB文件

                都是完整的。这使得我们可以通过定时备份RDB文件来实现Redis数据库备份

                

            5). 手动发送SAVE或BGSAVE命令让Redis执行快照,两个命令的区别在于,前者是由主进程进行快照操作,会阻塞住其他

                请求,后者会通过fork子进程进行快照操作

                

            6). 通过RDB方式实现持久化,一旦Redis异常退出,就会丢失最后一次快照以后更改的所有数据

        }

        

        b.  AOF方式

        {

            1). 默认情况下Redis没有开启AOF(append only file)方式的持久化,可以通过appendonly参数开启:appendonly yes

            

            2). 开启AOF持久化后每执行一条会更改Redis中的数据的命令,Redis就会将该命令写入硬盘中的AOF文件

            

            3). AOF文件的保存位置和RDB文件的位置相同,都是通过dir参数设置的,默认的文件名是appendonly.aof,可以通过

                appendfilename参数修改:appendfilename appendonly.aof

                

            4). 每当达到一定条件时Redis就会自动重写AOF文件,这个条件可以在配置文件中设置:

                auto-aof-rewrite-percentage 100

                auto-aof-rewrite-min-size 64mb

                可以主动使用BGREWRITEAOF命令手动执行AOF重写

                

            5). 在启动时Redis会逐个执行AOF文件中的命令来将硬盘中的数据载入到内存中,载入的速度相较RDB会慢一些

            

            6). 在Redis中我们可以通过appendfsync参数设置同步的时机:

                # appendfsync always

                appendfsync everysec

                # appendfsync no

                默认情况下Redis采用everysec 规则,即每秒执行一次同步操作。always表示每次执行写入都会执行同步,这是

                最安全也是最慢的方式。no表示不主动进行同步操作,而是完全交由操作系统来做(即每30秒一次),这是最快但最不安全

                的方式。一般情况下使用默认值everysec就足够了,既兼顾了性能又保证了安全

                

            7). Redis允许同时开启AOF和RDB,既保证了数据安全又使得进行备份等操作十分容易。此时重新启动Redis后Redis会

                使用AOF文件来恢复数据,因为AOF方式的持久化可能丢失的数据更少

            

        }

    

    }

    

    2.Redis提供了复制(replication)功能可以自动实现同步的过程

    {

    

        a.  配置

        {

            1). 同步后的数据库分为两类,一类是主数据库(master),一类是从数据库(slave)。主数据库可以进行读写操作,当发生写

                操作时自动将数据同步给从数据库。而从数据库一般是只读的,并接受主数据库同步过来的数据

            

            2). 在从数据库的配置文件中加入“slaveof主数据库IP主数据库端口”即可实现复制功能

            3). 除了通过配置文件或命令行参数设置slaveof参数,还可以在运行时使用SLAVEOF命令修改:

                redis>SLAVEOF 127.0.0.1 6379

                如果该数据库已经是其他主数据库的从数据库了,SLAVEOF命令会停止和原来数据库的同步转而和新数据库同步。

            4). 使用SLAVEOF NO ONE来使当前数据库停止接收其他数据库的同步转成主数据库

        }

        

        

        b.  原理

        {

            1). 当一个从数据库启动后,会向主数据库发送SYNC命令,主数据库接收到SYNC命令后会开始在后台保存快照

                (即RDB持久化的过程),并将保存期间接收到的命令缓存起来。当快照完成后,Redis会将快照文件和所有缓存的命令

                发送给从数据库。从数据库收到后,会载入快照文件并执行收到的缓存的命令。当主从数据库断开重连后会重新执行

                上述操作,不支持断点续传

                

            2). 在同步的过程中从数据库并不会阻塞,而是可以继续处理客户端发来的命令。默认情况下,从数据库会用同步前的数据

                对命令进行响应。可以配置slave-serve-stale-data参数为no来使从数据库在同步完成前对所有命令(除了INFO

                和SLAVEOF)都回复错误:“SYNC with master in progress.

        }

        

        c.  读写分离

        {

            通过复制可以实现读写分离以提高服务器的负载能力。在常见的场景中,读的频率大于写,当单机的Redis无法应付大量的读

            请求时(尤其是较耗资源的请求,比如SORT命令等)可以通过复制功能建立多个从数据库,主数据库只进行写操作,而从数据库

            负责读操作

        }

        

        d.  从数据库持久化

        {

            另一个相对耗时的操作是持久化,为了提高性能,可以通过复制功能建立一个(或若干个)从数据库,并在从数据库中启用持久化,

            同时在主数据库禁用持久化。当从数据库崩溃时重启后主数据库会自动将数据同步过来,所以无需担心数据丢失。而当主数据库

            崩溃时,需要在从数据库中使用SLAVEOF NO ONE命令将从数据库提升成主数据库继续服务,并在原来的主数据库启动后使用

            SLAVEOF命令将其设置成新的主数据库的从数据库,即可将数据同步回来

        }

        

    }

    

    

    【9】安全

    {

        1.  可信的环境

        {

            a.  在生产环境运行时不能允许外界直接连接到Redis服务器上,而应该通过应用程序进行中转,运行在可信的环境中是保证

                Redis安全的最重要方法

            

            b.  在配置文件中修改bind参数,如只允许本机应用连接Redis,可以将bind参数改成:bind 127.0.0.1

        }

        

        2.  数据库密码

        {

            a.  配置文件中的requirepass参数为Redis设置一个密码。一定要选择复杂的密码,否则可以通过穷举法破解

                例如:requirepass TAFK(@~!ji^XALQ(sYh5xIwTn5D s7JF

            

            b.  客户端每次连接到Redis时都需要发送密码,发送密码需要使用AUTH命令

                redis>AUTH TAFK(@~!ji^XALQ(sYh5xIwTn5D s7JF

            

                

            c.  配置Redis复制的时候如果主数据库设置了密码,需要在从数据库的配置文件中通过masterauth参数设置主数据库的

                密码,以使从数据库连接主数据库时自动使用AUTH命令认证

            

        }

        

        3.  命名命令

        {

        

            a.  Redis支持在配置文件中将命令重命名

                rename-command FLUSHALL oyfekmjvmwxq5a9c8usofuo369x0it2k

                

            b.  如果希望直接禁用某个命令可以将命令重命名成空字符串:

                rename-command FLUSHALL ""

        }

        

        

    }

    

    

    【10】通信协议

    {

    

        1.  Redis通信协议是Redis客户端与Redis之间交流的语言,通信协议规定了命令和返回值的格式

        

        2.  Redis支持两种通信协议,一种是二进制安全的统一请求协议(unified request protocol),一种是比较直观的便于在

            telnet程序中输入的简单协议。这两种协议只是命令的格式有区别,命令返回值的格式是一样的

            

        3.  简单协议

        {

            a.  简单协议适合在telnet程序中和Redis通信。简单协议的命令格式就是将命令和各个参数使用空格分隔开

            

            b.  由于Redis解析简单协议时只是简单地以空格分隔参数,所以无法输入二进制字符

        }

        

        4.  Redis的5种返回值类型的格式

        {

            a.  错误回复(error reply)以-开头,并在后面跟上错误信息,最后以\r\n结尾

            b.  状态回复(status reply)以+开头,并在后面跟上状态信息,最后以\r\n结尾

            c.  整数回复(integer reply)以:开头,并在后面跟上数字,最后以\r\n结尾

            d.  字符串回复(bulk reply)以$开头,并在后面跟上字符串的长度,并以\r\n分隔,接着是字符串的内容和\r\n

            f.  多行字符串回复(multi-bulk reply)以*开头,并在后面跟上字符串回复的组数,并以\r\n分隔。接着后面跟的

                就是字符串回复的具体内容

        }

        

        5.  统一请求协议

        {

            a.  统一请求协议是从Redis 1.2开始加入的,其命令格式和多行字符串回复的格式很类似,如SET foo bar的统一请求

                协议写法是“*3\r\n 3\r\nSET\r\n 3\r\nfoo\r\n 3\r\nbar\r\n”。

        }

        

        

        6.  Redis的AOF文件和主从复制时主数据库向从数据库发送的内容都使用了统一请求协议。如果要开发一个和Redis直接通信

            的客户端,推荐使用此协议。如果只是想通过telnet向Redis服务器发送命令则使用简单协议就可以了

        

    }

    

    

    【11】管理工具

    {

        1.  redis-cli

        {

            a.  耗时命令日志

            {

                1). 当一条命令执行时间超过限制时,Redis会将该命令的执行时间等信息加入耗时命令日志(slow log)以供开发者

                    查看。可以通过配置文件的slowlog-log-slower-than参数设置这一限制,要注意单位是微秒(1000000微秒

                    相当于1秒),默认值是10000。耗时命令日志存储在内存中,可以通过配置文件的slowlog-max-len参数来限制

                    记录的条数

                    

                2). 使用SLOWLOG GET命令来获得当前的耗时命令日志

                

                3)

                {

                    每条日志都由以下4个部分组成:

                    (1)该日志唯一ID;

                    (2)该命令执行的UNIX时间;

                    (3)该命令的耗时时间,单位是微秒;

                    (4)命令及其参数。

                }

            }

            

            b.  命令监控

            {

                1). MONITOR命令来监控Redis执行的所有命令

                

                2). MONITOR命令非常影响Redis的性能,一个客户端使用MONITOR命令会降低 Redis将近一半的负载能力。

                    所以MONITOR命令只适合用来调试和纠错。

            }

        }

        

        

        2.  phpRedisAdmin

        {

            a.  安装phpRedisAdmin

            {

                1). git clone https://github.com/ErikDubbelboer/phpRedisAdmin.git
                2). cd phpRedisAdmin

                3). git clone https://github.com/nrk/predis.git vendor

                4). git submodule init

                5). git submodule update

                6). sudo /user/local/bin/redis-server   must to start redis service before using phpReidsAdmin

            }

            

            b.  配置数据库连接

            {

                默认phpRedisAdmin会连接到127.0.0.1,端口6379,如果需要更改或者添加数据库信息可以编辑includes文件夹

                中的config.inc. php文件

            }

            

            c.  性能

            {

                phpRedisAdmin在获取键列表时使用的是KEYS*命令,然后对所有的键使用TYPE命令来获取其数据类型,所以当键非常

                多的时候性能并不高(对于一个有一百万个键的Redis数据库,在一台普通个人计算机上使用KEYS*命令大约会花费几十

                毫秒)。由于Redis使用单线程处理命令,所以对生产环境下拥有大数据量的数据库来说不适宜使用phpRedisAdmin管理

            }

        }

        

        3.  Rdbtools

        {

            a.  Rdbtools是一个Redis的快照文件解析器,它可以根据快照文件导出JSON数据文件、分析Redis中每个键的占用空间

                情况等

        }

    }

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  reids