A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

攻克Redis基本知识

    摘要: 【攻克Redis】Redis基本知识 发展史 Redis是一种基于键值对的Nosql数据库,Redis值可以是string(字符串)、hash(哈希)、list(列表)、set(集合)、zset(有序集合)、Bitmaps(位图)、 HyperLogLog、GEO(地理信息定位)等多种数据结构和算法组成 Redis会将所有数据都存放在内存 中,所以它的读写性能非常惊人。

1.发展史

    Redis是一种基于键值对的Nosql数据库,Redis值可以是string(字符串)、hash(哈希)、list(列表)、set(集合)、zset(有序集合)、Bitmaps(位图)、 HyperLogLog、GEO(地理信息定位)等多种数据结构和算法组成
    Redis会将所有数据都存放在内存 中,所以它的读写性能非常惊人。不仅如此,Redis还可以将内存的数据利 用快照和日志的形式保存到硬盘上,这样在发生类似断电或者机器故障的时 候,内存中的数据不会“丢失”
    Redis提供了键过期、发布订阅、事务、流水线、Lua脚本等附加功能

2.特性

1.速度快(10万/秒)
所有数据存放在内存中
C语言实现,C语言“距离”操作系统更近       
单线程架构,防止多线程可能产生的问题
2.基于键值对的数据结构服务器
主要提供了5种数据结构:字符串、哈希、列表、集合、有序集合
在字符串的基础之上演变 出了位图(Bitmaps)和HyperLogLog两种神奇的“数据结构”
Redis3.2版本中 加入有关GEO(地理信息定位)的功能
3.丰富的功能
提供了键过期功能,可以用来实现缓存。
提供了发布订阅功能,可以用来实现消息系统。
支持Lua脚本功能,可以利用Lua创造出新的Redis命令。
提供了简单的事务功能,能在一定程度上保证事务特性。
提供了流水线(Pipeline)功能,这样客户端能将一批命令一次性传到 Redis,减少了网络的开销。
4.简单稳定
源码代码量少
单线程模型开发简单
不需要依赖操作系统类库
5.客户端语言多
Redis提供了简单的TCP通信协议,很多编程语言可以很方便地接入到 Redis
6.持久化
两种持久化方式:RDB和 AOF
7.主从复制
Redis提供了复制功能,实现了多个相同数据的Redis副本,复制功能是分布式Redis的基础
8.高可用和分布式

3.使用场景

可以做1. 缓存缓存提高访问速度,降低后端数据库压力,可以设置过期时间,对存储数据进行淘汰。2.排行榜系统Redis提供了列表和有序集合数据结构,合理地使用这些数据结构可以很方便地构建各种排行榜系统。3.计数器应用视频网站有播放数、电商网站有 浏览数,为了保证数据的实时性,每一次播放和浏览都要做加1的操作4. 社交网络/踩、粉丝、共同好友/喜好、推送、下拉刷新等
5. 消息队列系统
Redis提供了发布订阅功能和阻塞队列的功能,虽然和专业的消息队列比还不够足够强大,但是对于一般的消息队列功能基本可以满足。

4.五种数据结构详解

    Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。
    String——字符串Hash——字典List——列表Set——集合Sorted Set——有序集合
    下面我们就来简单说明一下它们各自的使用场景:
1Redis String类型
    string类型的数据存储是最简单的key-value存储;
[Java] 纯文本查看 复制代码
   public function testRedis(){
        //string类型的数据结构
        app()->redis->set('1', 'aa');
    //根据key取出value值
    $string = app()->redis->get('1');
    }
  1-2.redis客户端查看结果:
  1-3.string字符串的其他redis操作方法:
//普通set/get操作$redis->set('library', 'predis');​redis->get('library');echo $retval; //显示 'predis'
//setex set一个存储时效$redis->setex('str', 10, 'bar'); //表示存储有效期为10秒
//setnx/msetnx相当于add操作,不会覆盖已有值$redis->setnx('foo',12); //true$redis->setnx('foo',34); //false
//getset操作,set的变种,结果返回替换前的值$redis->getset('foo',56);//返回34
// incrby/incr/decrby/decr 对值的递增和递减$redis->incr('foo'); //foo为57$redis->incrby('foo',2); //foo为59
//exists检测是否存在某值$redis->exists('foo');//true
//del 删除$redis->del('foo');//true
//type 类型检测,字符串返回string,列表返回 list,set表返回set/zset,hash表返回hash$redis->type('foo');//不存在,返回none$redis->set('str','test');$redis->type('str'); //字符串,返回string
//append 连接到已存在字符串$redis->append('str','_123'); //返回累加后的字符串长度8,此进str为 'test_123'
//setrange 部分替换操作$redis->setrange('str',0,'abc'); //返回3,参数2为0时等同于set操作$redis->setrange('str',2,'cd');//返回4,表示从第2个字符后替换,这时'str'为'abcd'
//substr 部分获取操作$redis->substr('str',0,2);//表示从第0个起,取到第2个字符,共3个,返回'abc'
//strlen 获取字符串长度$redis->strlen('str'); //返回4
//setbit/getbit 位存储和获取$redis->setbit('binary',31,1); //表示在第31位存入1,这边可能会有大小端问题?不过没关系,getbit 应该不会有问题$redis->getbit('binary',31); //返回1
//keys 模糊查找功能,支持*号以及?号(匹配一个字符)$redis->set('foo1',123);$redis->set('foo2',456);$redis->keys('foo*'); //返回foo1和foo2的array$redis->keys('f?o?'); //同上
//randomkey 随机返回一个key$redis->randomkey(); //可能是返回 'foo1'或者是'foo2'及其它任何一存在redis的key
//rename/renamenx 对key进行改名,所不同的是renamenx不允许改成已存在的key$redis->rename('str','str2'); //把原先命名为'str'的key改成了'str2'
//expire 设置key-value的时效性,ttl 获取剩余有效期,persist 重新设置为永久存储$redis->expire('foo', 1); //设置有效期为1秒$redis->ttl('foo'); //返回有效期值1s$redis->expire('foo'); //取消expire行为
//dbsize 返回redis当前数据库的记录总数$redis->dbsize();
2、Redis Hash表    redis中hash表存储数据,比较类似数据库中表的一条记录;2-1.hash读写实现方式:
[Java] 纯文本查看 复制代码
 public function testRedis()
    {//存储 hash类型 数据结构
        app()->redis->hset('goods', 'apple', '苹果');
​
        //取出 hash表中的数据
        $hash = app()->redis->hget('goods', 'apple');
        print_r($hash);
        echo "\n";
        
        die();
    }

3、Redis list列表
    List数据结构是链表结构,是双向的,可以在链表左,右两边分别操作;
    也可以把list看成一种队列,所以在很多时候可以用redis用作消息队列,这个时候它的作用就类似于activeMq啦;
    应用案例有时间轴数据,评论列表,消息传递等等,它可以提供简便的分页,读写操作。
3-1.list 读写实现方式:
[Java] 纯文本查看 复制代码
public function testRedis()
    {//存储 list
        app()->redis->lpush('news', 'cc'); //从队列前面插入元素
        app()->redis->lpush('news', 'ee'); //从队列前面插入元素
        app()->redis->rpush('news', 'dd');//从队列后面插入元素
        $list = app()->redis->lrange('news', 0, -1);//取出list所有元素
        print_r($list);
        echo "\n";
​
        die();
    }

4、Redis Set集合
    Set 就是一个集合,集合的概念就是一堆不重复值的组合。利用 Redis 提供的 Set 数据结构,可以存储一些集合性的数据。
    比如在微博应用中,可以将一个用户所有的关注人存在一个集合中,将其所有粉丝存在一个集合。
    因为 Redis 非常人性化的为集合提供了求交集、并集、差集等操作,那么就可以非常方便的实现如共同关注、共同喜好、二度好友等功能,对上面的所有集合操作,你还可以使用不同的命令选择将结果返回给客户端还是存集到一个新的集合中。
1.共同好友、二度好友2.利用唯一性,可以统计访问网站的所有独立 IP3.好友推荐的时候,根据 tag 求交集,大于某个 threshold 就可以推荐
4-1.set 读写实现方式:
[Java] 纯文本查看 复制代码
  public function testRedis()
    {//存储 set
        $fans = app()->redis->sadd('fans', 'ff');
        if($fans){
            print_r('set add ff success');
        }else{
            print_r('set add ff fail');
        }
        $fans = app()->redis->sadd('fans', 'gg'); //不存在返回true
        if($fans){
            print_r('set add gg success');
        }else{
            print_r('set add gg fail');
        }
        $fans = app()->redis->sadd('fans', 'gg'); //不存在返回false
        if($fans){
            print_r('set add gg success');
        }else{
            print_r('set add gg fail');
        }
        //取出set
        $fans = app()->redis->smembers('fans');
        print_r($fans);
        echo "\n";
    }

5、Redis Zset集合(Sorted Sets)
    zset是set的一个升级版本,他在set的基础上增加了一个顺序属性,这一属性在添加修改元素的时候可以指定,每次指定后,zset会自动重新按新的值调整顺序。 可以对指定键的值进行排序权重的设定,它应用排名模块比较多。
    比如一个存储全班同学成绩的 Sorted Sets,其集合 value 可以是同学的学号,而 score 就可以是其考试得分,这样在数据插入集合的时候,就已经进行了天然的排序。另外还可以用 Sorted Sets 来做带权重的队列,比如普通消息的 score 为1,重要消息的 score 为2,然后工作线程可以选择按 score 的倒序来获取工作任务,让重要的任务优先执行。
    zset集合可以完成有序执行、按照优先级执行的情况;
1.zset 读写实现方式:
[Java] 纯文本查看 复制代码
 public function testRedis()
    {//zset 添加元素
        app()->redis->zadd('students', '1', '90');
        app()->redis->zadd('students', '2', '80');
        app()->redis->zadd('students', '3', '95');
        app()->redis->zadd('students', '7', '75');
        app()->redis->zadd('students', '5', '55');
        //取出 zset
        $zset = app()->redis->zrange('students', 0, -1);
        print_r($zset);
        echo "\n";
    }

4.集群
    Redis 集群是Redis 的一个分布式实现,它是一个网状结构,每个节点都通过 TCP 连接跟其他每个节点连接。现在来看看Redis集群实现了哪些目标?
    在1000个节点的时候仍能表现得很好并且可扩展性(scalability)是线性的。集群之间使用异步复制,并且没有合并的操作。
    可接受的写入安全(Write safety)级别:那些与大多数节点相连的客户端所做的写入操作,系统尝试全部都保存下来。不过还是会有小部分写入会丢失。
    可用性(Availability):在绝大多数的主节点(master node)是可达的,并且对于每一个不可达的主节点都至少有一个它的从节点(slave)可达的情况下,Redis 集群仍能进行分区(partitions)操作。
    那么Redis集群环境与非分布式Redis环境在功能上有没有什么不同的呢?
    集群的数据库只有0,且不支持SELECT
    由于集群将键分布在不同的槽(slot)中,所以涉及到多键值的复制操作也是不支持的,像set里的并集(unions)和交集(intersections)操作
1 集群环境介绍
    本文搭建的集群环境有3个主节点,每个主节点都有两个从节点,架构图如下
2 修改配置文件
    关于集群的配置如下:
[Java] 纯文本查看 复制代码
################################ REDIS CLUSTER ###############################
​
cluster-enabled yes
​
cluster-config-file nodes-6379.conf
​
cluster-node-timeout 5000
cluster-enabled表示是否开启集群模式
cluster-conf-file 表示保存节点配置文件的路径
cluster-node-timeout表示节点超时时间
完整的配置文件在https://github.com/rainbowda/learnWay/tree/master/learnRedis/cluster ,有需要的可以去下载
3 节点配置及启动
    由于采用一个服务器运行三个Redis实例,所以每个节点的配置有些许不同,像端口号、文件位置、文件名称等等。这里就不将每个配置文件贴出来了,Github上有主节点和两个从节点的配置文件。
    我在redis文件夹下创建一个cluster文件夹,然后在cluster文件夹下创建一个master文件,存放主节点的配置文件master.conf和一些其他文件;再然后创建两个从节点文件7001和7002,也是存放配置文件等。

    mkdir cluster
    cd cluster
    mkdir master 7001 7002
    将配置文件拷贝到相应文件夹后,根据配置文件启动Redis,这里就不在说明了。



4 个回复

倒序浏览
可以可以
回复 使用道具 举报
回复 使用道具 举报
奈斯加油加油
回复 使用道具 举报
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马