【分布式架构之旅 理论篇】Redis入门

###前言redis

昨天和室友去包夜,玩了一夜的LOL,跪了一整夜,可是很开心。从S1末开始玩LOL的我,到如今仍是青铜,真是菜的抠脚。最近负能力满满的,惟有睡觉和学习才可解忧愁。今天也看了慕课网上面的《Redis入门》,来记一下学习笔记。(写这篇文章开头的时候应该是一个星期以前)算法

DNA.png


###NoSQL概述shell

  • NoSQL就是Not Only SQL的意思,是非关系型数据库。数据库

  • 为何须要NoSQL?vim

    • High performance - 高并发读写数组

    • Huge Storage - 海量数据的高效率存储和访问缓存

    • High Scalability & High Availability - 高可扩展性和高可用性安全

  • NoSQL数据库的四大分类bash

    • 键值(Key - Value)存储:优势是快速查询,缺点存储的数据缺乏结构化。服务器

    • 列存储:优势是查询比较快,扩展性比较强,缺点是功能相对局限。

    • 文档数据库:对应的产品就是MongoDB。对数据结构要求不是特别严格,查询性能不能特别高,缺乏统一查询的语法。

    • 图形数据库:优势是利用图结构相关的算法,缺点是须要对整个图进行结算才能得出结果,不能做为分布式的解决方案。

image.png

  • 如今来讲说NoSQL的特色,美滋滋。
    • 易扩展
    • 灵活的数据模型
    • 高可用
    • 大数据量,高性能

###Redis的概述

  • 高性能键值对数据库,支持的键值数据类型:

    • 字符串类型 - String

    • 列表类型 - Set

    • 有序集合类型 - Sorted Set

    • 散列类型 - Hash

    • 集合类型 - List

  • Redis的应用场景

    • 缓存

    • 任务队列

    • 网站访问统计

    • 应用排行榜

    • 分布式集群架构中的session分离


###Redis在Linux上的使用 能够看我这篇文章【Linux学习】 Redis经常使用的一些指令


###Jedis的入门

  • 咱们要在Java平台上使用redis,确定须要Jedis这个客户端。首先在pom文件中引入Jedis的依赖
<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
		<dependency>
			<groupId>redis.clients</groupId>
			<artifactId>jedis</artifactId>
			<version>2.9.0</version>
		</dependency>
复制代码
  • 普通方式建立Jedis对象。
public void methodOne() {
        Jedis jedis = new Jedis("100.64.84.47", 6379);
        jedis.set("name", "cmazxiaoma");
        String value = jedis.get("name");
        System.out.println(value);
        jedis.close();
    }
复制代码
  • 经过线程安全的链接池来建立Jedis对象。
public void methodTwo() {
        //得到链接池的配置对象
        JedisPoolConfig config = new JedisPoolConfig();
        //设置最大链接数
        config.setMaxTotal(30);
        //设置最大空闲链接数
        config.setMaxIdle(10);
        //得到链接池
        JedisPool jedisPool = new JedisPool(config, "100.64.84.47", 6379);

        Jedis jedis = null;

        try {
            jedis = jedisPool.getResource();
            String value = jedis.get("name");
            System.out.println(value);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (jedis != null) {
                jedis.close();
            }

            jedisPool.close();
        }
    }
}
复制代码
  • 编写测试类。
public class JedisDemo1Test {
    private JedisDemo1 demo;

    @Before
    public void setUp() {
        demo = new JedisDemo1();
    }

    @Test
    public void methodOne() throws Exception {
        demo.methodOne();
    }

    @Test
    public void methodTwo() throws Exception {
        demo.methodTwo();
    }

}
复制代码
  • 运行Test Case,测试成功。

    image.png

  • 咱们在Xshell软件,输入get name指令,也能够看到输出cmazxiaoma

    image.png


###Redis的数据结构

####String

  • Key定义的注意点:

    • 不要过长。
    • 不要太短。
    • 统一的命名规范。
  • 存储String

    • 二进制安全的,存入和获取的数据相同。
    • Value最多能够容纳的数据长度是512M
  • 存储String经常使用的命令:

    • 赋值

      image.png

    • 取值

      image.png

    • 删除

      image.png

    • 数值增减

若是属性不存在的话,那么integer类型默认为0

image.png

若是name属性的值不能转换成integer类型,那么会抛出ERR is not an integer or out of range异常。

image.png

decr指令也是同样的。

image.png

  • 扩展命令 incrbydecrby也是同样的,很简单。
    image.png

append指令能够拼接字符串。

image.png

若是append key cmazxiaoma。这个key不存在的话,首先会建立这个key,而后存入cmazxiaoma内容,接着输出cmazxiaoma

image.png


####Hash

  • 赋值,可使用hset myhash key value单一赋值、hmset myhash key value key value屡次赋值。

    image.png

  • 取值,能够用hget myhash key单一取值、hmget myhash key key 多个取值、hgetall取出全部key所对应的值。

    image.png

  • 删除 ,能够用hdel myhash key删除单一的key

    image.png

hdel myhash key key删除多个的key

image.png

del myhash删除myhash中全部的key

image.png

  • 数值增减,hincrby myhash key 100

    image.png

  • 使用hexists myhash key 判断key是否在myhash中存在,存在返回1,不存在返回0

    image.png

  • hlen myhash获取myhash中存在key的数量。

    image.png

  • hkeys myhash获取myhash中全部的key

    image.png

  • hvals myhash获取myhash中全部的values

    image.png


####List

  • 存储list:

    • ArrayList使用数组方式
    • LinkedList使用双向链表方式
  • 两端添加

    • 使用lpush a b c 命令在左端添加,那么c确定是在最左端。
      image.png
    • 使用rpush a b c命令在右端添加,那么c确定是在最右端。
      image.png
  • 两端弹出

    • 使用lpop mylist弹出mylist中头部元素、rpop mylist2弹出mylist2尾部中的元素。它们都是3
      image.png
    • 咱们接着来查看mylistmylist2
      image.png
  • 查看列表

    • 使用lrange mylist 0 5来查看mylist列表,mylist插入的方式从头结点开始添加的,那么输出确定是321abc
      image.png
    • 使用lrange mylist2 0 5查看mylist2列表,mylist2插入的方式是从最右端添加的,那么输出确定是abc123
      image.png

image.png

  • 获取列表元素的个数

    • 使用llen mylist命令
      image.png
  • 扩展命令

    • 使用lpushx mylist x,使插入的元素在头部位置。

      image.png

    • 使用rpushx mylist x,使插入的元素在尾部位置。

      image.png

    • 使用lrem mylist count elementcount表明是删除的次数,element表明是须要删除的元素。若是count > 0 表明删除的方式从头至尾,删除countelementcount < 0表明删除的方式从尾到头,删除countelement。若是count = 0,删除mylist中全部和element相同的元素。

      image.png
      image.png

    • lrem mylist 2 test1

      image.png

    • lrem mylist -2 test1

      image.png

    • lrem mylist 0 cmazxiaoma

      image.png

    • 在某一个下标位置插入元素。lset mylist index element

      image.png

    • 在目标元素以前插入指定的元素。linsert mylist before helloworl before_helloworld

      image.png
      image.png

    • 在目标元素以后插入指定的元素。linsert mylist helloworld after after_helloworld

      image.png

    • 弹出mylist中最后一个元素,并插入到mylist中的头部。rpoplpush mylist mylist

      image.png

    • rpoplpush使用场景

      image.png


####Set 和List类型不一样的是,Set集合中不容许出现重复的元素。

  • 添加/删除元素

    • 添加 sadd myset a b c,若是咱们重复添加相同的元素,确定是不成功的。好比sadd myset a
      image.png
    • 删除 srem myset a,删除myset中的a元素。
      image.png
    • 查看myset中的元素。smembers myset
      image.png
    • 查看指定元素是不是myset中的成员。sismember myset a,返回0表明不存在,返回1表明存在。
      image.png
  • 得到集合中的元素, smembers myset

  • 集合中的差集运算,sdiff myset2 mysetmyset2中元素有b,c,dmyset中元素有b,c。它们之间的差集运算结果应该为d

    image.png

    • 集合中的交集运算,sinter myset2 myset,应该输出cb

      image.png

    • 集合中的并集运算,sunion myset2 myset,应该输出cbd

      image.png

  • 扩展命令

    • scard myset 查看myset有多少个元素。

      image.png

    • srandmember myset 随机返回myset中的一个元素。

      image.png

    • sdiffstore new_myset myset2 mysetmysetmyset2差集元素的结果存储到new_myset中。(sinterstore, sunionstore也是同样的用法)

      image.png

  • Set使用场景

    • 跟踪一些惟一性的数据。
    • 用于维护数据对象之间的关联关系。

####SortedSet SortedSet中的成员在集合中的位置是有序的。

  • 添加元素 zadd mysort 70 cmazxiaoma 80 xiaoma 100 doudou

    image.png

  • 得到元素

    • zcard mysort 得到mysort中全部元素的个数

      image.png

    • 得到mysortnamecmazxiaoma对应的成绩。zscore mysort cmazxiaoma

      image.png

  • 删除元素,zrem mysort cmazxiaoma deli doudou xiaoma

    image.png

  • 范围查询 zrange mysort 0 -1,输出的key是按成绩正序排列。

    image.png

    • 若是输出的数据项要带上成绩的话,指令应该是zrange mysort 0 -1 withscores

      image.png

    • 若是输出的数据项想按成绩逆序排序,那么就应该zrevrange mysort 0 -1 withscores

      image.png

    • 若是想按排名范围进行删除的话,那么应该zremrangebyrank mysort 0 2

      image.png

    • 若是想按成绩范围进行删除的话,那么应该zremrangebyscore mysort 0 10。顾名思义删除成绩在0-10以内的数据项。

      image.png

  • 扩展命令

    • 查看分数在0-10以内的学生信息,zrangebyscore mysort 0 10 withscores

      image.png

    • 查看分数在0-100以内且在第1行-第2行的学生信息。zrangebyscore mysort 0 100 withiscores limit 0 2

      image.png

    • cmazxiaoma的成绩加100分。zincrby mysort cmazxiaoma 100

      image.png

    • 查当作绩0-10之间的学生的个数。zcount mysort 0 10

      image.png

  • Sorted Set使用场景

    • 如大型在线游戏积分排行榜

    • 构建索引数据


###Redis中的通用命令

  • key * 获取全部redis中的key

    image.png

  • keys my* 获取全部redis中以my开头的key

    image.png

  • exists mylist 查看redis中是否存在mylist,0表明不存在,1表明存在。

    image.png

  • rename name new_name 给名字为name的数据结构重命名为new_name

    image.png

  • expire new_name 10 设置redisnew_name过时时间,经过ttl new_name看到其距离过时的时间。

    image.png

  • type mylist,能够查看mylist对应的数据结构类型。

    image.png


###Redis的事务

  • Redis相关的特性:

    • 多数据库

    • Redis事务

  • 一个Redis最多能够提供16个数据库,下标分别是0-15。客户端默认链接的是第0号数据。咱们能够经过select index来选择数据库。

    image.png

  • 咱们想把第0号的数据库中某些key移动到第1号数据库里面,那么咱们该怎么作呢。经过move cmazxiaoma_test_mayday_5 1就能够完成。

    image.png

  • 咱们能够经过multiexecdiscard来完成事务操做。事务执行期间,Redis不会为其余客户端提供任何服务,以保证事务中的全部命令原子执行。multi至关于开启事务,exec至关于提交,discard至关于回滚。

  • 首先咱们在第一个客户端进行以下操做。咱们在第一个客户端开启了事务,在事务中咱们incr num 2次,按理来讲,get num 应该等于4

    redis第一个客户端.png

  • 咱们在第二个客户端输入get num,发现num仍是2。那么证实了咱们的结论:事务执行期间,Redis不会为其余客户端提供任何服务,以保证事务中的全部命令原子执行。

    image.png

  • 若是咱们在第一个客户端提交了事务。

    image.png

  • 接着咱们在第二个客户端get num,发现能够num的值获得了更新。

    image.png

  • 咱们能够演示一下回滚操做,首先set user cmazxiaoma,接着开启事务,在事务中set user xiaoma,而后进行回滚操做,发现 get user 依然是cmazxiaoma

    image.png


###Redis的持久化 Redis的性能体如今它把数据都保存在内存当中。咱们把内存中的数据同步到硬盘当中的操做称之为持久化。

  • Redis持久化方式:

    • RDB方式,在指定的时间内,把内存中的数据快照写入到硬盘当中。

    • AOF方式,将以日志的形式记录服务器所处理的每个操做。当Redis服务器启动之初,它会读取该aof文件,会从新构建咱们的数据库。保证咱们启动以后,保证数据的完整性。

    • 无持久化,咱们能够经过配置禁止Redis服务器的持久化,咱们认为Redis就是缓存的一种机制了。

    • 同时使用。

  • RDB

    • 默认状况下,每隔一段时间redis服务器程序会自动对数据库作一次遍历,把内存快照写在一个叫作"dump.rdb"的文件里,这个持久化机制叫作SNAPSHOT。有了SNAPSHOT后,若是服务器宕机,从新启动redis服务器时,redis会自动加载"dump.rdb",将数据库状态恢复上一次SNAPSHOT的状态。

    • Redis服务器初始化过程当中,设定了定时时间,每隔一段时间就会触发持久化操做,进入定时事件处理程序中,就会fork出子进程来进行持久化操做。

    • Redis服务器预设了save指令,客户端可要求服务器进程中断服务,执行持久化操做。

    • 咱们能够经过vim /etc/redis.conf打开配置文件,能够看到如下配置。

      image.png

    • 同时咱们还能够看到内存快照输出在file文件名。

      image.png

    优缺点:

    • 若是数据集很大,RDB相对于AOF启动效率很更高。

    • 若是想保证数据的高可用性,最大限度的避免数据的丢失,RDB将不是一个好的选择。由于系统在定时持久化操做以前,还没来得及在硬盘写入数据就发生宕机的话,就形成了数据的丢失。

    • RDB经过fork出子线程来完成数据持久化操做,若是当数据集很大的时候,可能会致使服务器中止几百ms,或者几s

RDB.png

  • AOF(append only file):

  • 对于Redis服务器而言,其缺省的机制是RDB,若是须要使用AOF,则须要修改appendonly no改为appendonly yesRedis在每一次收到数据修改的命令以后,都会将其追加到AOF文件中。在Redis下一次从新启动时,须要加载AOF文件中的信息来构建最新的数据到内存中。

    image.png
    image.png

  • 能够记录服务器的全部写操做。在服务器从新启动时,会把全部的写操做从新执行一遍从而实现数据的备份。当写操做集过大(比原有的数据集还大),Redis会重写写操做集。

  • 带来更好的数据安全性,有3种同步策略,每秒同步,每修改同步,不一样步。 每秒同步也是异步完成的,效率也很是高。缺点是一旦系统发生宕机的现象,那么这一秒中的修改的数据就会发生丢失。每修改同步,咱们能够视为同步持久化。每一次发生数据的变化,就会当即的记录在磁盘,这种效率很低,可是很安全。

  • 采用append追加的模式,就算系统发生宕机,也不会影响咱们日志文件中已经存在的内容。然而咱们本次操做中,只写入了一半数据就出现了系统崩溃的问题。在Redis下一次启动以前,咱们能够经过"redis-check-aof --fix <filename>"命令来修复坏损的AOF文件,解决数据一致性的问题。

  • 对于相同数量的数据集而言,AOF文件一般要大于RDB文件。

  • AOF在运行效率上每每会慢于RDB

AOF.png

  • RDBAOF的区别 前者是保存了数据自己,然后者是记录了数据的变动。

###尾言

这篇文章最后在网吧完成的,勿以善小而不为。

相关文章
相关标签/搜索