zoukankan      html  css  js  c++  java
  • Redis Installation、Configuration、Program Based On Redis Learning

    目录

    1. Redis 简介
    2. Redis安装配置
    3. 编程使用Redis
    4. 使用Lua脚本

    1. Redis 简介

    0x1: Redis是什么

    Redis是一款Nosql类型的基于key-value的高速缓存系统,

    从架构上看,redis有3种特性

    1. key value store
    是一个以key-value形式存储的数据库,定位直指MySQL,用来作为唯一的存储系统
    
    2. memory cache
    是一个把数据存储在内存中的高速缓存,用来在应用和数据库间提供缓冲,替代memcachd
    
    3. data structrue server
    把它支持对复杂数据结构的高速操作作为卖点,提供某些特殊业务场景的计算和展现需求。比如排行榜应用,Top 10之类的

    在redis的键值的"值"中,它所支持的数据结构有:

    1. String
        1) 常用命令
          setget、decr、incr、mget等
          2) 应用场景
          String是最常用的一种数据类型,普通的key/value存储都可以归为此类 
          3) 实现方式
          String在redis内部存储默认就是一个字符串,被redisObject所引用,当遇到incr、decr等操作时会转成数值型进行计算,此时redisObject的encoding字段为int
    
    2. Hash
        1) 常用命令
          hget、hset、hgetall等
          2) 应用场景
        3) 实现方式
          Redis Hash对应Value内部实际就是一个HashMap,实际这里会有2种不同实现
            3.1) 这个Hash的成员比较少时Redis为了节省内存会采用类似一维数组的方式来紧凑存储,而不会采用真正的HashMap结构,对应的value redisObject的encoding为zipmap
            3.2) 当成员数量增大时会自动转成真正的HashMap,此时encoding为ht
    
    3. List
        1) 常用命令
          lpush、rpush、lpop、rpop、lrange等
          2) 应用场景
          Redis list的应用场景非常多,也是Redis最重要的数据结构之一,比如twitter的关注列表,粉丝列表等都可以用Redis的list结构来实现 
          3) 实现方式
          Redis list的实现为一个双向链表,即可以支持反向查找和遍历,更方便操作,不过带来了部分额外的内存开销,Redis内部的很多实现,包括发送缓冲队列等也都是用的这个数据结构
    
    4. Set
        1) 常用命令
          sadd、spop、smembers、sunion等 
          2) 应用场景
          Redis set对外提供的功能与list类似是一个列表的功能,特殊之处在于set是可以自动排重的,当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择,并且set提供了判断某个成员是否在一个set集
    合内的重要接口,这个也是list所不能提供的   
    3) 实现方式:    set的内部实现是一个value永远为null的HashMap,实际就是通过计算hash的方式来快速排重的,这也是set能提供判断一个成员是否在集合内的原因 5. Sorted set 1) 常用命令    zadd、zrange、zrem、zcard等    2) 使用场景    Redis sorted set的使用场景与set类似,区别是set不是自动有序的,而sorted set可以通过用户额外提供一个优先级(score)的参数来为成员排序,并且是插入有序的,即自动排序。当你需要一个有序的并且不重复的集
    合列表,那么可以选择sorted set数据结构,比如twitter 的public timeline可以以发表时间作为score来存储,这样获取时就是自动按时间排好序的   
    3) 实现方式    Redis sorted set的内部使用HashMap和跳跃表(SkipList)来保证数据的存储和有序,HashMap里放的是成员到score的映射,而跳跃表里存放的是所有的成员,排序依据是HashMap里存的score,使用跳跃表的结构可以获
    得比较高的查找效率,并且在实现上比较简单

    Redis内部使用一个redisObject对象来表示所有的key和value

    1. type
    代表一个value对象具体是何种数据类型
    2. encoding
    不同数据类型在redis内部的存储方式,比如:type=string代表value存储的是一个普通字符串,那么对应的encoding可以是raw或者是int,如果是int则代表实际redis内部是按数值型类存储和表示这个字符串的,当然前提是这个
    字符串本身可以用数值表示,比如:"123" "456"这样的字符串 3. ptr 数据指针 4. vm 只有打开了Redis的虚拟内存功能,此字段才会真正的分配内存,该功能默认是关闭状态的

    我们可以发现Redis使用redisObject来表示所有的key/value数据是比较浪费内存的,当然这些内存管理成本的付出主要也是为了给Redis不同数据类型提供一个统一的管理接口

    0x2: Redis支持的指令集

    Redis提供了丰富的命令(command)对数据库和各种数据类型进行操作,这些command可以在Linux终端使用(redis-cli)。也可以在编程时通过API方式使用,比如使用Redis 的Java语言包

    1. 连接操作相关的命令
        1) QUIT: 关闭连接(connection)
        2) AUTH: 简单密码认证
    
    2. 适合全体类型的命令
        1) EXISTS(key) 确认一个 key 是否存在 
        2) DEL(key) 删除一个 key 
        3) TYPE(key) 返回值的类型 
        4) KEYS(pattern) 返回满足给定 pattern 的所有 key 
        5) RANDOMKEY:随机返回 key 空间的一个key 
        6) RENAME(oldname, newname) 将 key 由 oldname 重命名为 newname,若 newname 存在则删除 newname 表示的 key 
        7) DBSIZE:返回当前数据库中 key 的数目 
        8) EXPIRE(key,ttl) 设定一个 key 的生存时间 ttl(s) 
        9) TTL(key) 获得一个 key 的活动时间 
        10) SELECT(index) 按索引查询;
        11) MOVE(key, dbindex) 将当前数据库中的 key 转移到有 dbindex 索引的数据库 
        12) FLUSHDB:删除当前选择数据库中的所有 key 
        13) FLUSHALL:删除所有数据库中的所有 key
    
    3. 自定义扩展指令相关的指令
        1) EVAL: EVAL script numkeys key [key ...] arg [arg ...]
        EVAL 和 EVALSHA 命令是从 Redis 2.6.0 版本开始的,使用内置的 Lua 解释器,可以对 Lua 脚本进行求值
    
    3、对 STRING 操作的命令
        1) SET(key, value) 给数据库中名称为 key 的 string 赋予值 value 
        2) GET(key) 返回数据库中名称为 key 的 string 的 value 
        3) GETSET(key, value) 给名称为 key 的 string 赋予上一次的value 
        4) MGET(key1, key2,…, key{$n}) 返回库中多个 string(它们的名称为key1,key2...)的value 
        5) SETNX(key, value) 如果不存在名称为 key 的 string,则向库中添加 string,名称为 key,值为 value;
        6) SETEX(key, time, value) 向库中添加 string(名称为key,值为value)同时,设定过期时间time;
        7) MSET(key1, value1, key2, value2,…key{$n}, value{$n}) 同时给多个 string 赋值,名称为 key{$i} 的 string 赋值 value{$i};
        8) MSETNX(key1, value1, key2, value2,…key{$n}, value{$n}) 如果所有名称为 key{$i} 的 string 都不存在,则向库中添加 string,名称 key{$i} 赋值为 value{$i};
        9) INCR(key) 名称为 key 的 string 增1操作;
        10) INCRBY(key, integer) 名称为 key 的 string 增加 integer;
        11) DECR(key) 名称为 key 的 string 减1操作;
        12) DECRBY(key, integer) 名称为 key 的 string 减少 integer;
        13) APPEND(key, value) 名称为 key的 string 的值附加 value;
        14) SUBSTR(key, start, end) 返回名称为 key 的 string 的 value 的子串
    
    4、对无索引序列 LIST 操作的命令
        1) RPUSH(key, value) 在名称为 key 的 list 尾添加一个值为 value 的元素;
        2) LPUSH(key, value) 在名称为 key 的 list 头添加一个值为 value 的 元素;
        3) LLEN(key) 返回名称为 key 的 list 的长度;
        4) LRANGE(key, start, end) 返回名称为 key 的 list 中 start 至 end 之间的元素(下标从0开始,下同)
        5) LTRIM(key, start, end) 截取名称为 key 的 list,保留 start 至 end 之间的元素;
        6) LINDEX(key, index) 返回名称为 key 的 list 中 index 位置的元素;
        7) LSET(key, index, value) 给名称为 key 的 list 中 index 位置的元素赋值为 value;
        8) LREM(key, count, value) 删除 count 个名称为 key 的 list 中值为value的元素。count 为0,删除所有值为 value 的元素,count>0从 头至尾删除 count 个值为 value 的元素,count<0从尾到头删除|count|个值为value的元素;
        9) LPOP(key) 返回并删除名称为key的list中的首元素;
        10) RPOP(key) 返回并删除名称为key的list中的尾元素;
        11) BLPOP(key1, key2,… key{$n}, timeout) LPOP 命令的 block 版本。即当 timeout 为0时,若遇到名称为 key{$i} 的 list 不存在或该 list 为空,则命令结束。如果 timeout>0,则遇到上述情况时,等待 timeout 秒,如果问题没有解决,则对 key{$i}+1 开始的 list 执行 pop 操作;
        12) BRPOP(key1, key2,… key{$n}, timeout) RPOP 的 block 版本。参考上一命令;
        13) RPOPLPUSH(srckey, dstkey) 返回并删除名称为 srckey 的 list 的尾元素,并将该元素添加到名称为 dstkey 的 list 的头部。
    
    5、对有索引无序集合 SET 操作的命令
        1) SADD(key, member) 向名称为 key 的 set 中添加元素 member;
        2) SREM(key, member) 删除名称为 key 的 set 中的元素 member;
        3) SPOP(key) 随机返回并删除名称为 key 的 set 中一个元素;
        4) SMOVE(srckey, dstkey, member) 将 member 元素从名称为 srckey 的集合移到名称为 dstkey 的集合;
        5) SCARD(key) 返回名称为 key 的 set 的基数;
        6) SISMEMBER(key, member) 测试 member 是否是名称为 key 的 set 的元素;
        7) SINTER(key1, key2,…key{$n}) 求交集;
        8) SINTERSTORE(dstkey, key1, key2,…key{$n}) 求交集并将交集保存到 dstkey 的集合;
        9) SUNION(key1, key2,…key{$n}) 求并集;
        10) SUNIONSTORE(dstkey, key1, key2,…key{$n}) 求并集并将并集保存到 dstkey 的集合;
        11) SDIFF(key1, key2,…key{$n}) 求差集;
        12) SDIFFSTORE(dstkey, key1, key2,…key{$n}) 求差集并将差集保存到 dstkey 的集合;
        13) SMEMBERS(key) 返回名称为 key 的 set 的所有元素;
        14) SRANDMEMBER(key) 随机返回名称为 key 的 set 的一个元素。
     
    6、持久化
        1) SAVE:将数据同步保存到磁盘;
        2) BGSAVE:将数据异步保存到磁盘;
        3) LASTSAVE:返回上次成功将数据保存到磁盘的 UNIX 时戳;
        4) SHUNDOWN:将数据同步保存到磁盘,然后关闭服务
    
    7、远程服务控制
        1) INFO:提供服务器的信息和统计;
        2) MONITOR:实时转储收到的请求;
        3) SLAVEOF:改变复制策略设置;
        4) CONFIG:在运行时配置 Redis 服务器 

    0x3: 配置密码登录

    关于密码验证

    1. 如果redis监听回环IP之外的地址 任何人都可以读取其信息,所以安全问题需要考虑,即redis是默认未授权可任意访问的
    2. 即使显式设置了密码验证,但是redis服务器的login响应速度极快,因此官方文件中提醒设置比较复杂的密码,防止机器破解

    redis配置密码

    1. vim /etc/redis.conf
    2. requirepass littlehann 
    //littlehann是设置的密码
    3. 重启redis
    sudo service redis restart  
    #或者  
    sudo service redis stop  
    sudo redis-server /etc/redis.conf  
    
    4. 尝试登录redis,在没有进行身份认证的情况下
    (error) ERR operation not permitted
    
    5. 进行身份认证
    redis-cli -h 127.0.0.1 -p 6379 -a littlehann  
    #或者
    redis-cli 
    auth littlehann

    除了使用这种修改配置文件并重启的方式进行redis密码配置之外,还可以通过指令,动态地对redis进行密码配置(重启后失效)

    1. config set requirepass my_redis  
    2. config get requirepass  
    //无需重启redis,之前配置的老密码会失效(只在本次启动声明周期内有效) 

    Relevant Link:

    http://try.redis.io/
    http://www.redis.cn/
    http://jandyu.diandian.com/post/2012-03-15/16145594
    http://tech.it168.com/a2011/0818/1234/000001234478_all.shtml
    http://hedatou.com/archives/introduction_to_redis.html
    http://blog.csdn.net/tianmohust/article/details/7739739
    http://www.redis.cn/commands.html
    http://www.lvtao.net/content/book/redis.htm 
    http://blog.csdn.net/zyz511919766/article/details/4226821

    2. Redis安装配置

    0x1: 主程序安装

    cd /usr/local
    wget http://download.redis.io/releases/redis-2.8.13.tar.gz
    tar xzf redis-2.8.13.tar.gz
    cd redis-2.8.13
    make
    /*make命令执行完成后,会在当前src目录(/usr/local/redis-2.8.13/src)下生成本个可执行文件如下:
    1. redis-server:Redis服务器的daemon启动程序
    2. redis-cli:Redis命令行操作工具。当然,你也可以用telnet根据其纯文本协议来操作
    3. redis-benchmark:Redis性能测试工具,测试Redis在你的系统及你的配置下的读写性能
    4. redis-stat:Redis状态检测工具,可以检测Redis当前状态参数及延迟状况 
    */

    0x2: 命令测试

    //启动server
    ./redis-server
    //测试benchmark
    ./redis-benchmark
    //使用内置的客户端连接Redis
    ./redis-cli
    127.0.0.1:6379> set foo bar
    OK
    127.0.0.1:6379> get foo
    "bar"
    127.0.0.1:6379>

    0x3: 运行Redis所需要的内核参数优化

    /*
    1. overcommit_memory
    指定了内核针对内存分配的策略,其值可以是0、1、2。
    0: 表示内核将检查是否有足够的可用内存供应用进程使用
        1) 如果有足够的可用内存,内存申请允许
        2) 否则,内存申请失败,并把错误返回给应用进程
    1: 表示内核允许分配所有的物理内存,而不管当前的内存状态如何
    2: 表示内核允许分配超过所有物理内存和交换空间总和的内存
    */
    vim /etc/sysctl.conf
    //添加
    vm.overcommit_memory=1
    //刷新配置使之生效
    sysctl vm.overcommit_memory=1 

    0x4: Redis配置文件

    vim /usr/local/redis-2.8.13/redis.conf
    //1. 开启守护进程
    daemonize yes 
    //2. 每隔5秒输出一行监控信息(默认)
    daemonize no
    
    //3. 减小改变次数,这个参数可以根据情况进行指定
    save 60 1000 
    
    //4. 分配256M内存
    maxmemory 256000000  
     
    //5. pid文件位置
    pidfile /var/run/redis.pid 
    
    //6. 监听的端口号
    port 6379
    
    //7. 请求超时时间
    timeout 0
    
    //8. log信息级别
    loglevel notice
    
    //9. 开启数据库的数量
    databases 16
    
    /*
    10. 保存快照的频率
        1) 第一个*表示多长时间
        2) 第二个*表示执行多少次写操作
    在一定时间内执行一定数量的写操作时,自动保存快照。可设置多个条件
    */
    save * *
    
    //11. 是否使用压缩
    rdbcompression yese
    
    //12. 数据快照文件名(只是文件名,不包括目录)
    dbfilename dump.rdb
    
    //13. 数据快照的保存目录(这个是目录)
    dir ./
    
    //14. 是否开启appendonlylog,开启的话每次写操作会记一条log,这会提高数据抗风险能力,但影响效率
    appendonly no
    
    /*
    15. appendonlylog如何同步到磁盘
        1) always: 每次写都强制调用fsync
        2) everysec: 每秒启用一次fsync
        3) no: 不调用fsync等待系统自己同步
    */ 
    appendfsync everysec

    配置好保存,重启redis,就可以正常启动了,和mysql一样,redis是基于socket监听端口的方式提供服务的,我们可以使用telnet、或者socket方式进行连接

    Relevant Link:

    http://www.redis.cn/documentation.html
    http://www.redis.cn/download.html
    http://www.php100.com/html/webkaifa/PHP/PHPyingyong/2011/0406/7873.html

    3. 编程使用Redis

    0x1: PHP连接Redis

    使用php连接redis需要安装php的扩展

    下载redis扩展源代码
    http://pecl.php.net/package/redis
    解压缩后进行编译
    phpize
    ./configure --enable-hello
    make
    关于php扩展的原理以及编译过程请参阅另一篇文章
    http://www.cnblogs.com/LittleHann/p/3562259.html
    将编译好的.so文件复制到php的扩展目录中
    cp redis.so /usr/lib/php/modules/
    修改php.ini中的extension,增加redis扩展的自动启动
    重启apache即可

    Code

    <?php  
        $redis = new redis();  
        $result = $redis->connect('192.168.207.128', 6379);  
        var_dump($result); //结果:bool(true)  
    
        $result = $redis->set('name',"LittleHann");  
        var_dump($result); //结果:bool(true)  
    
        $result = $redis->get('name'); 
        var_dump($result); //结果:LittleHann 
    
        $redis->delete('name');  
        var_dump($result); //结果:bool(true)  
    ?>  

    Relevant Link:

    https://github.com/nrk/predis
    https://github.com/Shumkov/Rediska
    https://github.com/jdp/redisent
    http://www.cnblogs.com/ikodota/archive/2012/03/05/php_redis_cn.html
    http://blog.51yip.com/cache/1439.html
    http://www.cnblogs.com/jackluo/p/3412670.html

    0x2: Java连接Redis

    Relevant Link:

    http://outofmemory.cn/code-snippet/128/java-usage-redis-jiandan-usage
    http://www.cnblogs.com/edisonfeng/p/3571870.html

    4. 使用Lua脚本(Redis将lua引擎静态编译包含使redis具备解析lua脚本的能力)

    0x1: 初始化 Lua 环境

    在初始化 Redis 服务器时, 对 Lua 环境的初始化也会一并进行,为了让 Lua 环境符合 Redis 脚本功能的需求, Redis 对 Lua 环境进行了一系列的修改, 包括添加函数库、更换随机函数、保护全局变量, 等等
    整个初始化 Lua 环境的步骤如下

    1. 调用 lua_open 函数,创建一个新的 Lua 环境 
    2. 载入指定的 Lua 函数库,包括:
        1) 基础库(base lib)
        2) 表格库(table lib)
        3) 字符串库(string lib)
        4) 数学库(math lib)
        5) 调试库(debug lib)
        6) 用于处理 JSON 对象的 cjson 库
        7) 在 Lua 值和 C 结构(struct)之间进行转换的 struct8) 处理 MessagePack 数据的 cmsgpack 库 
    3. 屏蔽一些可能对 Lua 环境产生安全问题的函数,比如 loadfile
    4. 创建一个 Redis 字典,保存 Lua 脚本,并在复制(replication)脚本时使用。字典的键为 SHA1 校验和,字典的值为 Lua 脚本 
    5. 创建一个 redis 全局表格到 Lua 环境,表格中包含了各种对 Redis 进行操作的函数,包括 
        1) 用于执行 Redis 命令的 redis.call 和 redis.pcall 函数 
        2) 用于发送日志(log)的 redis.log 函数,以及相应的日志级别(level)
            redis.LOG_DEBUG
            redis.LOG_VERBOSE
            redis.LOG_NOTICE
            redis.LOG_WARNING
        3) 用于计算 SHA1 校验和的 redis.sha1hex 函数 
        4) 用于返回错误信息的 redis.error_reply 函数和 redis.status_reply 函数 
    6. 用 Redis 自己定义的随机生成函数,替换 math 表原有的 math.random 函数和 math.randomseed 函数,新的函数具有这样的性质:每次执行 Lua 脚本时,除非显式地调用 math.randomseed ,否则 math.random 生成的伪随机数序列总是相同的 
    7. 创建一个对 Redis 多批量回复(multi bulk reply)进行排序的辅助函数 
    8. 对 Lua 环境中的全局变量进行保护,以免被传入的脚本修改 
    9. 因为 Redis 命令必须通过客户端来执行,所以需要在服务器状态中创建一个无网络连接的伪客户端(fake client),专门用于执行 Lua 脚本中包含的 Redis 命令:当 Lua 脚本需要执行 Redis 命令时,它通过伪客户端来向服务器发送命令请求,服务器在执行完命令之后,将结果返回给伪客户端,而伪客户端又转而将命令结果返回给 Lua 脚本 
    10. 将 Lua 环境的指针记录到 Redis 服务器的全局状态中,等候 Redis 的调用 

    这些步骤都执行完之后, Redis 就可以使用 Lua 环境来处理脚本了

    0x2: 脚本的安全性

    Redis 对 Lua 环境所能执行的脚本做了一个严格的限制 —— 所有脚本都必须是无副作用的纯函数(pure function)
    为此,Redis 对 Lua 环境做了一些列相应的措施

    1. 不提供访问系统状态状态的库(比如系统时间库)
    2. 禁止使用 loadfile 函数
    3. 如果脚本在执行带有随机性质的命令(比如 RANDOMKEY ),或者带有副作用的命令(比如 TIME )之后,试图执行一个写入命令(比如 SET ),那么 Redis 将阻止这个脚本继续运行,并返回一个错误 
    4. 如果脚本执行了带有随机性质的读命令(比如 SMEMBERS ),那么在脚本的输出返回给 Redis 之前,会先被执行一个自动的字典序排序,从而确保输出结果是有序的 
    5. 用 Redis 自己定义的随机生成函数,替换 Lua 环境中 math 表原有的 math.random 函数和 math.randomseed 函数,新的函数具有这样的性质:每次执行 Lua 脚本时,除非显式地调用 math.randomseed ,否则 math.random 生成的伪随机数序列总是相同的 

    经过这一系列的调整之后, Redis 可以保证被执行的脚本

    1. 无副作用
    2. 没有有害的随机性
    3. 对于同样的输入参数和数据集,总是产生相同的写入命令

    0x3: 脚本的执行

    在脚本环境的初始化工作完成以后, Redis 就可以通过 EVAL 命令或 EVALSHA 命令执行 Lua 脚本了

    1. EVAL(对输入的脚本代码体进行求值)

    EVAL "return 'hello world'" 0

    由于redis替换了lua中的基本库全局变量,产生了sandbox的效果,所以很多提权操作是不允许的

    eval "return io.popen('ifconfig')" 0

    2. EVALSHA 则要求输入某个脚本的 SHA1 校验和, 这个校验和所对应的脚本必须至少被 EVAL 执行过一次

    Relevant Link:

    http://www.redis.cn/commands/eval.html
    http://origin.redisbook.com/feature/scripting.html

    Copyright (c) 2014 LittleHann All rights reserved

  • 相关阅读:
    centos下部署启动elasticsearch错误集合与解决方案
    rpm和yum的区别
    centos7 安装Jdk1.8.0
    nvm-windows安装
    linux运行.sh命令
    centos7 安装 nvm
    centos7 安装、使用git
    转载:centos安装redis
    centos7 安装Node.js并配置为全局可用
    前端代码tomcat下简单部署
  • 原文地址:https://www.cnblogs.com/LittleHann/p/3901588.html
Copyright © 2011-2022 走看看