NoSQL

NoSQL概述

NoSOL:Not Only SQL
NoSQL不依赖业务逻辑方式存储,而是以简单的key-value模式存储。因此大大的增加了数据库扩展能力
不遵循SQL标准
不支持ACID(原子性、隔离性、一致性、持久性)
远超于SQL业务能力

NoSQL适用场景

对数据高并发的读写
海量数据的读写
对数据高可扩展性的

NoSQL不适用的场景

需要事务支持
基于sql的结构化查询存储,处理复杂关系,需要即席查询(立即就要的查询)
用不到SQL和用了SQL也不可以的情况可以考虑NoSQL

NoSQL兄弟会
Menmcached
  • 很早之前出现的NoSQL数据库
  • 数据都在内存中,一般不持久化
  • 支持简单的key-value模式
  • 一般是作为缓存数据库辅助持久化的数据库
Redis
  • 几乎覆盖了Memecached绝大部分功能
  • 数据都在内存中、支持格式化,主要用作备份恢复e
  • 除了支持简单的key-value模式,还支持多种数据结构的存储,如:list、set、hash、zset
  • 一般是作为缓存数据库辅助持久化的数据库
Redis

Redis是一个开源的key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,Redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是Redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步

应用场景

1.配合关系型数据库做高速缓存
2.拥有持久化能力,利用其多样性的数据结构存储特定的数据
例如:

  • 最新N个数据 :通过List按自然时间顺序排序
  • 排行榜,TOP N:利用zset集合
  • 时效性的数据,例如手机验证码:Expire过期
  • 计数器、秒杀:原子性,自增方法INCR、DECR
  • 去除大量数据中的重复数据:利用set集合
  • 构建队列:利用list集合
  • 发布订阅消息系统:pub/sub模式
安装

1.下载安装包后放入Linux的/opt
2.解压
3.进入redis-3.2.5
运行make发现错误
解决:

  • yum install gcc
  • yum install gcc-c++

之后make发现
Jemalloc/jemalloc.h:没有那个文件
解决:
make distclean之后再 make
继续执行make install
进入usr/local/bin/
ll查看命令

  • redis-benchmark:性能测试工具,可以在自己本子运行,看看自己本子性能如何(服务启动起来后执行)
  • redis-check-aof:修复有问题的AOF文件
  • redis-check-dump:修复有问题的dump.rdb文件
  • redis-sentinel:Redis集群使用
  • redis-server:Redis服务器启动命令
  • redis-cli:客户端,操作入口
    运行 redis-server
启动

在redis的目录下复制redis.conf到root的一个目录下,并且修改一下里面的内容

daemonize no 改成 yes,让服务在后台启动

之后启动方式就变得简单了

redis-server /root/myredis/redis.conf

客户端访问:
redis -cli
多端口:
redis-cli -p 6379
启动后默认进入零号库
一共有16个库
可以根据命令
select 6切换

关闭

进入客户端关闭
在这里插入图片描述
进入终端关闭
在这里插入图片描述

Redis单线程+多路IO复用技术

多路复用是指使用一个线程来检查多个文件描述符(Socket)的就绪状态,比如调用select和poll函数,传入多个文件描述符,如果有一个文件描述符就绪,就返回,否则阻塞直到超时。得到就绪状态后进行真正的操作就可以在同一个线程里执行,也可以启动线程执行(例如线程池)。
串行 vs 多线程+锁(Menmcached) vs 单线程+多路IO复用(Redis)

Redis和Menmcached三个区别

Menmcached是多线程的,Redis使单线程+IO多路复用
另外两个分别是关于持久化和支持数据结构存储

Redis对key的操作

查询当前库中所有键

keys *

判断某个键是否存在

exists <key>

查看键的类型

type <key>

删除某个键

del <key>

为键设置过期时间,单位为秒

expire <key> <seconds>

查看一个键还有多晒秒过期
-1 表示永不过期,-2表示已过期

ttl <key>

查看当前数据库中的key数量

dbsize

清空当前库

flushdb

通杀全部库

flushall

Redis五大数据类型-String
命令

获取对应键值

get <key>

添加键值对

set <key> <value>

将给定的<value>追加到原值的末尾

append <key> <value>

获取值的长度

strlen <keys>

只有在key不存在时设置key的值

setnx <key> <value>

将key中对应键值增加1
只能对数字值进行操作,如果为空,新增值为1

incr <key>

将key中对应键值减1
只能对数字值进行操作,如果为空,新增值为-1

decr <key>

将key中对应键值增减,自定义步长

incrby/decrby <key> <步长>

同时设置一个或多个键值对

mset <key1> <value1> <key2> <value2>...

同时获取一个或多个value

mset <key1> <key2>...

同时设置一个或多个键值对,前提是当且仅当所有给定的key都不存在

msetnx <key1> <value1> <key2> <value2>

获取值的范围,类似java中的substring

getrange <key> <起始位置> <结束位置>

<value>覆写<key>所对象的字符串值,从<起始位置>开始

setrange <key> <起始位置> <value>

设置键的同时,设置过期时间

setex <key> <过期时间> <value>

设置了新值同时获得旧值

getset <key> <value>
原子性

所谓原子性操作是指不会被线程调度机制打断的操作,这种操作一旦开始,就一直运行到结束,中间不会切换到另一种线程
1.在单线程中,能够在单条指令中完成的操作都可以认为是“原子性操作”,因为终端只能发生于指令之间
2.在多线程中,不能被其他线程(进程)打断的操作都叫原子操作
Redis但命令的原子性主要得益于Redis的单线程


Redis数据类型-List
  • 单键多值
  • Redis列表是简单的字符串链表,按照插入顺序,你可以添加一个元素从列表头部(左边)到列表尾部(右边)
  • 它的底层是一个双向链表,对两端的操作性能很高,通过索引下标的操作中间节点的性能较差
命令

从左面/右面插入一个或多个值

lpush/rpush <key> <value1> <value2>

从左面/右面吐出一个值
值在健在,值亡键亡

lpop/rpop <key>

<key1> 列表右边吐出一个值,插入到<key2>左边

ropolpush <key1> <key2>

按照索引下标获得元素(从左到右)

lrange <key> <start> <stop>

按照索引下标获得元素

lindex<key> <index>

获得列表长度

llen<key>

<value>前插入<newvalue>

linsert <key> before <value> <newvalue>

从左面删除n个value(从左到右)

lrem <key> <n> <value>

Redis数据类型-set

Redis set对外提供的功能与list类似,是一个列表功能,特殊之处在于set是可以自动重排,当你需要存储一个列表数据,又不希望出现重复数据,set是一个很好的选择,并且set提供了判断某个成员是否在一个set集合内的重要接口,而list并不提供。
Redis set是String类型的无序集合,**它的底层是一个value为null的hash表,**所以,添加、查找、删除的复杂度都为O(1)。

命令:

将一个或多个member元素加入到集合key中,已经存在于集合的member元素将会被忽略。

SADD <key> <value1> <value2>

获取该集合所有值

SMEMBERS <key>

判断集合<key>是否含该<value>值,如果有返回1,否则返回0

 SISMEMBER <key> <value>

返回该集合元素个数

scard <key>

删除集合中某些元素

srem <key> <value1> <value2>

随机从该集合中吐出一个值(吐出后即从该集合中删除)

spop <key>

随机从该集合中取出n个元素(不会从该集合中删除)

srandmenmber <key> <n>

返回两个集合交集元素

sinter <key1> <key2>

返回两个集合并集元素

sunion <key1> <key2>

返回两个集合的差集

sdiff <keyy1> <key2>
Redis 数据类型-hash

Redis hash 是一个键值对集合
Redis hash是一个string类型的field和value的映射表,hash特别适合用于存储对象
类似于Java中的Map<String ,Object >

假设用户ID为查找的key,存储的value用户对象包含姓名、年龄、升入等信息,如果用普通的key-value结构存储,主要有两种形式:
第一种
在这里插入图片描述
每次修改用户的某个属性(年龄等等),需要先序列化修改好后再反序列化,开销较大

第二种
在这里插入图片描述
这会造成用户ID数据冗余
如果我们用hash来存储
在这里插入图片描述
相当于KEY 存储用户ID,key存储属性标签,就可以操作对应属性数据,既不需要重读存储数据,也不会带来序列化和并发修改控制的问题

命令

<key>集合中的<filed>键赋值<value>

hset <key> <field> <value>

<key>集合<field>取出<value>

hget <key> <field>

批量设置hash的值

hmset <key1> <field1> <value1> <field2> <value2>

查看哈希表key中,给定域field是否存在

hexists key <field>

列出该hash集合所有field

hkeys <key>

列出该hash集合所有的value

hvals <key>

为哈希表中的域field的值加上增量increment

hincrby <key> <field> <increment>

将哈希表key中的域field的值设置为value,当且仅当域field不存在

hsetnx <key> <field> <value>
Redis数据类型-zset

Redis中有序集合zset与普通集合set非常相似,是一个没有重复元素的字符串集合,不同之处在于有序集合的所有成员都关联了一个评分(score),这个评分被用来按照从最低分到最高分的方式排序结合中的成员,集合成员是唯一的,但是评分可以充分。
因为元素是有序的,所以你也可以很快的根据评分或者次序来获取一个范围的元素,访问有序集合的中间元素也是非常快的,因此你能够使用有序集合作为一个没有重复成员的只能列表

命令

将一个或多个member元素及其score值加入到有序集key中

zadd <key> <score1> <value1> <score2> <value2>

返回有序集key中,下标在<start> <stop>之间的元素,带WITHSCORES可以连同分数一起返回

zrange <key> <start> <stop> [WITHSCORE]

返回有序集key中,所有score值介于min和max之间(包括等于)的成员,有序集成员按照score值递增(从小到大)次序排列

zrangebyscore key min max [witgscore] 

返回有序集key中,所有score值介于min和max之间(包括等于)的成员,有序集成员按照score值递减(从大到小)次序排列

zrevrangebyscore key max min [withscore] 

给元素的score加上增量

zincrby <key> <increment> <value>

删除该集合下,指定值的元素

zrem <key> <value>

统计该集合,分数区间内的元素个数

zcount <key> <min> <max>

返回该值再集合中的排名,从0开始

zrank <key> <value>
Redis的java客户端Jedis

用Windows的IDEA连接虚拟机中Redis注意事项

禁用Linux防火墙
redis.conf中注释掉bind 127.0.0.1,然后protect-mode 设置为no
虚拟机后台必须启动redis

导入jar包之后,即可连接

package com.yyx.jedis;

import redis.clients.jedis.Jedis;

import java.util.Set;

public class TestJedis {
    // @SuppressWarnings("resource") 注释掉记得关闭
    public static void main(String[] args) {
        // 创建Jedis对象
        Jedis jedis = new Jedis("192.168.111.114", 6379);
        // 测试连接
        String ping = jedis.ping();
        System.out.println(ping);
        // 向Redis中添加String类型数据
        String set = jedis.set("javakey", "valueJava");
        System.out.println(set);
        // 获取Redis中javakey对应的值
        String javakey = jedis.get("javakey");
        System.out.println(javakey);
        // 获取Redis中所有的key
        Set<String> keys = jedis.keys("*");
        // 遍历
        for (String key : keys
             ) {
            System.out.println(key);
        }
        jedis.close();
    }
}

Redis的事务

Redis是一个单独的隔离操作,属物种的所有命令都会序列化,按顺序的执行,事务在执行过程中,不会被其他客户端发送的请求打断。
Redis 事务的主要作用是串联多个命令防止其他命令插队

Multi、Exec、discard
Multi:从输入Multi开始,输入的命令会依次进入命令队列中,但不会执行,知道输入Exec后,Redis会将之前的命令依次执行。
组队过程中可以通过discard来放弃组队
组队中某个命令出现了错误,执行时整个的所有队列都会被取消
如果执行阶段某个命令出现了错误,则只有报错的命令不会执行,而其他的命令都会被执行,不会回滚

事务冲突问题

例如:你的支付账号不只有你自己用,假设余额一万,那么如果双十一有三个请求,一个是想给金额减8000,一个是想给金额减2000,还有一个想给金额减1000,肯定不能都完成,这就涉及到了乐观锁悲观锁

乐观锁:

每次去取数据时都认为别人不会修改数据,也就不会上锁,但是在更新的时候会判断一下这期间有没有人更新了这个数据,乐观锁适用于多读类型,这样可以提高吞吐量,Redis就是利用这种check-and-set机制实现事务。

悲观锁:

每次去拿数据的时候都会认为别人想修改数据,所以每次拿数据时都会上锁,这样别人想那这个数据就会block直到它拿到锁,传统的关系型数据库中就用到了很多悲观锁的机制,比如行锁,表锁,读锁,写锁等

WATCH key 【key2】…

综上,在执行multi之前,可以先执行watch key 【key2】…,可以监视一个/多个key,如果在事务执行之前这个key被其他命令所改动,那么事务会被打断。
例如:
启动两个Xshell
同时watch同一个key
当其中一个执行事务时,另一个将该key对应数据修改
那么exec事务时就会报错

如何取消监视unwatch

取消watch命令对所有key的监视
如果在执行了Watch之后,exce命令或discard命令先被执行,那么就不需要unwatch

Redis事务的三特性
  1. 单独的隔离操作:事务中所有命令都会序列化、按顺序的执行,事务在执行的过程中,不会被其他客户端发送来的命令请求打断
  2. 没有隔离级别的概念:队列中的命令没有提交之前都不会实际的被执行,因为事务提交前,任何指令都不会被实际执行,也就不存在“事务内的查询要看到事务里的更新,在事务外查询不能看到”
  3. 不保证原子性:Redis同一个事物中如果有一条命令执行失败,其后的命令仍会执行,没有回滚
Redis持久化
RDB

在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是Snapsjot快照,它恢复时是将快照文件直接读到内存里

备份是如何执行的

Redis会单独创建一个子进程(fork)来进行持久化,会先将数据写入一个临时文件中,待持久化过程结束,在用这个临时文件替换上次持久化好的文件。整个过程中,主进程不进行任何IO操作。如果需要进行大规模数据的恢复,这就确保了极高的性能,且对于数据回复的完整性并不是很非常敏感,RDB的缺点是最后一次持久化后数据可能丢失。优点是RDB比AOF更加高效

fork进程会产生一个和父进程完全相同的子进程,但子进程在此后夺回exec系统调用,处于效率考虑,Linux中引入了 写时复制一般情况下父进程和子进程会共用同一段物理内存,只有进程空间的各段内容要发生变化时,才会将父进程的内容复制一份给子进程

RDB保存文件

在redis.conf中,默认名为dump.rdb
rdb默认保存路径为Redis启动时命令行所在目录
手动保存快照:bgsave

RDB优缺点:

优点:节省磁盘空间,恢复速度快
缺点:数据庞大时耗性能,在备份周期一定间隔时间做一次备份,如果Redis意外down,就会丢失最后一次快照后的所有修改

AOF

以日志的形式来记录每个写操作,将Redis执行过的所有写指令记录下来,只允许追加文件但不可以改写文件,Redis启动之初会读取该文件重新构建数据,Redis重启的话就根据日志文件的内容将写指令从前到后执行一次已完成数据的恢复
默认是不开启的,需要在配置文件中配置(redis.conf中配置文件名称,默认为appendonly.aof)
AOF文件保存路径和RDB路径一致

如果遇到AOF文件损坏,可通过
redis-check-aof --fix appendonly.aof恢复

AOF同步频率设置
  • 始终同步,每次Redis的写入都会立刻计入日志
  • 每秒同步,每秒计入日志依次,如果待机,本秒数据可能丢失
  • 如果不主动进行同步,把同步时机交给操作系统 在这里插入图片描述
Rewrite

AOF采用文件追加方式,文件会越来越大,为了避免这种情况,新增了重写机制,当AOF文件大小超过设定的阈值时,Redis就会启动AOF文件的内容压缩,只保留可以恢复数据的最小指令集,可以使用命令bgrewriteaof。
重写于之前的不同
例如:
incby k 1000
incby k 1000
incby k 1000
重写后
incby k 3000

Redis如何实现重写

AOF文件持续增长而过大时,会fork出一条新的进程来将文件重写,(也是先写临时文件最后在rename),遍历新进程的内存中数据,每条记录都有一个Set语句。重写aof文件的操作,并没有读取旧的aof文件,而是将整个内存中的数据库内容用命令的方式重写了一个新的aof文件,与快照类似。

何时重写?

auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
系统在载入时,或者上次重写完毕时,都会记录AOF大小,设为base_size,如果Redis中AOF当前大小>=base_size+base_size*100(默认)%且当前大小>=64(默认)mb,Redis会对AOF进行重写

AOF优点

备份机制更加稳健,丢失数据概率低
可读的日志文件,通过操作AOF文件,可以处理错误操作

AOF缺点

比RDB占用更多磁盘空间
恢复备份速度慢
每次读写都同步的话,会影响性能

如果两个持久化方式都开启,默认听AOF的

AOF的数据更准确
官方建议都启用,对数据不敏感可只用RDB,不建议单独用AOF,可能会出现BUG,如果只是做纯内存缓存,可以都不用

Redis主从复制

就是主机更新数据后根据配置和策略,自动同步到备机的master/slaver机制Master以写为主,Slaver以读为主
用处:读写分离、性能扩展,容灾快速恢复

主从复制模式搭建

创建新的redis.conf文件并且修改:
从机2:

include /root/myredis/redis.conf
pidfile /var/run/redis_6381.pid
port 6381
dbfilename dump6381.rdb                       

从机1:

include /root/myredis/redis.conf
pidfile /var/run/redis_6380.pid
port 6380
dbfilename dump6380.rdb

主机的conf文件直接复制原本的conf文件就好(daemonize yes)
之后启动时要按端口号启动

redis-cli -p 6379
redis-cli -p 6380
redis-cli -p 6381


主机:

127.0.0.1:6379> INFO replication
# Replication
role:master
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
127.0.0.1:6379> INFO replication
# Replication
role:master
connected_slaves:2
slave0:ip=127.0.0.1,port=6380,state=online,offset=29,lag=1
slave1:ip=127.0.0.1,port=6381,state=online,offset=29,lag=0
master_repl_offset:29
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:28
127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379> set key1 v1
OK
127.0.0.1:6379> get key1
"v1"
127.0.0.1:6379> 

从机1:

127.0.0.1:6380> INFO replication
# Replication
role:master
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
127.0.0.1:6380> SLAVEOF 127.0.0.1 6379 这句命令表示成为从机
OK
127.0.0.1:6380> INFO replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6379
master_link_status:up
master_last_io_seconds_ago:4
master_sync_in_progress:0
slave_repl_offset:29
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
127.0.0.1:6380> get key1
"v1"
127.0.0.1:6380> 

从机2:

127.0.0.1:6381> INFO replication
# Replication
role:master
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
127.0.0.1:6381> SLAVEOF 127.0.0.2 6379
OK
127.0.0.1:6381> INFO replication
# Replication
role:slave
master_host:127.0.0.2
master_port:6379
master_link_status:up
master_last_io_seconds_ago:2
master_sync_in_progress:0
slave_repl_offset:15
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
127.0.0.1:6381> get key1
"v1"
127.0.0.1:6381> set key2 v2
(error) READONLY You can't write against a read only slave.
127.0.0.1:6381> 

一主二仆模式演示
切入点问题:slave1、slave2、是从头开始复制还是从切入点开始复制?比如从key4进来,那么之前的key123是否可以复制?

从头开始复制

从机是否可以写入?set可否?

不可

主机shutdown之后从机情况如何?

原地待命

主机回来后新增记录,从机能否顺利复制?

可以顺利复制

其中一台从机shutdown后情况如何?

重新启动后变为主机,要重新命令变为从机。

薪火相传(一主二仆中仆人再收仆人)

上一个slave可以是下一个slave的Master,slave同样可以接受其他的slaves的连接和同步请求,那么该slave作为了链条中下一个master,可以有效减轻master的压力,中心化降低风险
用slaveof <ip> <port>
中途变更转向:会清除之前的数据,重新建立拷贝最新的
风险:一旦某个slave宕机,后面的slave都无法备份

反客为主

当一个master宕机后,后面的slave可以立刻升为master,后面的slave不用改
slaveof no one将从机变为主机

哨兵模式

反客为主的自动版,能够从后台监控主机是否故障,如果故障了,根据投票数自动将从机转为主机

配置哨兵:
  • 调整为一主二仆模式
  • 自定义/myredis目录下新建sentinel.conf文件
  • 在配置文件中填写内容:sentinel monitor mymaster 127.0.0.1 6379 1
  • 其中mymaster为监控对象起的服务器名称,1为至少有多少个哨兵同意迁移的数量
    启动哨兵:redis-sentinel /myredis/sentinel.conf
故障恢复

新主登基:从下线的主机的所有从机里面挑选一个从机,将其转为主机,选择条件依次为:

  • 选择优先级靠前的(优先级在redis.conf中slave-priority 100(越大优先级越低)、偏移量是指获取原主数据最多的、每个redis实例启动后都会随机生成一个40位的runid)
  • 选择偏移量大的
  • 选择runid最小的从机
    群仆俯首:选出新的主机之后,sentinel向原主机的从机发送slaveof新主机 命令,复制master
    旧主俯首:当已下线的服务重新上线,sentinel会向其发送slaveof命令,让其称为新主机的从机
Redis集群

Redis集群实现了对Redis水平的扩容,即启动n个redis节点,将整个数据库分布存储在这N个节点中。每个节点存储总数据的1/N
Redis集群通过分区(partition)来提供一定程度的可用性,即使集群中一部分节点失效或无法进行通讯,集群也可以继续处理命令请求

集群搭建

1.安装ruby环境

yum install ruby
yum install rubygems

2.拷贝redis-3.2.0.gem到/opt下
用xftp传输文件报错的话将/opt权限改为777
3.执行命令

gem install --local reids-3.2.0.gem

4.开始制作实例:
6379、6380、6381、6389、6390、6391

  • 拷贝多个redis.conf文件
  • 开启daemonize yes
  • Pid文件名
  • 指定端口
  • Log文件名
  • Dump.rdb名
  • Appendonly 关掉或者换名
    这部分和主从复制一样
    添加配置:
  • cluster-enabled yes 打开集群模式
  • cluster-config-file node-6379.conf 设定节点配置文件名
  • cluster-node-timeout 15000 设置节点失联时间超过改时间(毫秒),集群自从进行主从切换
include /root/myredis/redis.conf
pidfile "/var/run/redis_6379.pid"
port 6379
dbfilename "dump6379.rdb"
#集群
cluster-enabled yes
cluster-config-file node-6379.conf
cluster-node-timeout 15000
~                           

之后复制覆盖

[root@hadoop04 myredis]# cp redis6379.conf redis6380.conf 
cp:是否覆盖"redis6380.conf"? y
[root@hadoop04 myredis]# cp redis6379.conf redis6381.conf 
cp:是否覆盖"redis6381.conf"? y
[root@hadoop04 myredis]# cp redis6379.conf redis6389.conf
[root@hadoop04 myredis]# cp redis6379.conf redis6390.conf
[root@hadoop04 myredis]# cp redis6379.conf redis6391.conf

修改端口号

vim redis6380.conf 

替换

:%s/6379/6380

以下同理
启动所有的redis
发现以下文件表示成功:
在这里插入图片描述
将六个节点合成一个集群:
进入src目录后./运行以下代码(用本机的ip)

[root@hadoop04 redis-3.2.5]# cd /opt/software/redis-3.2.5/src
[root@hadoop04 src]# ./redis-trib.rb create --replicas 1 192.168.111.114:6379 192.168.111.114:6380 192.168.111.114:6381 192.168.111.114:6389 192.168.111.114:6390 192.168.111.114:6391

输出以下信息表示成功

>>> Creating cluster
>>> Performing hash slots allocation on 6 nodes...
Using 3 masters:
192.168.111.114:6379
192.168.111.114:6380
192.168.111.114:6381
Adding replica 192.168.111.114:6389 to 192.168.111.114:6379
Adding replica 192.168.111.114:6390 to 192.168.111.114:6380
Adding replica 192.168.111.114:6391 to 192.168.111.114:6381
M: 64800cded9c6a7a3e3477d6996526efdb318deab 192.168.111.114:6379
   slots:0-5460 (5461 slots) master
M: 5d691cc1c98118fb7d292882e1d5c5ccaeb3476a 192.168.111.114:6380
   slots:5461-10922 (5462 slots) master
M: c4ed24f5e1222883e3da52ee970bea26d0aa0135 192.168.111.114:6381
   slots:10923-16383 (5461 slots) master
S: 03e0b8a2395d61f5bf2648c4407ec190bf57bb2b 192.168.111.114:6389
   replicates 64800cded9c6a7a3e3477d6996526efdb318deab
S: 59cf3ce1e44290803fd8f143b245a4af4b3a0ff7 192.168.111.114:6390
   replicates 5d691cc1c98118fb7d292882e1d5c5ccaeb3476a
S: fba7d1ac01c76edd783e7be20abecaa058b07bd5 192.168.111.114:6391
   replicates c4ed24f5e1222883e3da52ee970bea26d0aa0135
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join..
>>> Performing Cluster Check (using node 192.168.111.114:6379)
M: 64800cded9c6a7a3e3477d6996526efdb318deab 192.168.111.114:6379
   slots:0-5460 (5461 slots) master
   1 additional replica(s)
S: fba7d1ac01c76edd783e7be20abecaa058b07bd5 192.168.111.114:6391
   slots: (0 slots) slave
   replicates c4ed24f5e1222883e3da52ee970bea26d0aa0135
M: 5d691cc1c98118fb7d292882e1d5c5ccaeb3476a 192.168.111.114:6380
   slots:5461-10922 (5462 slots) master
   1 additional replica(s)
M: c4ed24f5e1222883e3da52ee970bea26d0aa0135 192.168.111.114:6381
   slots:10923-16383 (5461 slots) master
   1 additional replica(s)
S: 59cf3ce1e44290803fd8f143b245a4af4b3a0ff7 192.168.111.114:6390
   slots: (0 slots) slave
   replicates 5d691cc1c98118fb7d292882e1d5c5ccaeb3476a
S: 03e0b8a2395d61f5bf2648c4407ec190bf57bb2b 192.168.111.114:6389
   slots: (0 slots) slave
   replicates 64800cded9c6a7a3e3477d6996526efdb318deab
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

16384表示插槽数

一个 Redis 集群包含 16384 个插槽(hash slot), 数据库中的每个键都属于这 16384 个插槽的其中一个, 集群使用公式 CRC16(key) % 16384 来计算键 key 属于哪个槽, 其中 CRC16(key) 语句用于计算键 key 的CRC16 校验和 。
集群中的每个节点负责处理一部分插槽。 举个例子, 如果一个集群可以有主节点, 其中:
节点 A 负责处理 0 号至 5500 号插槽。
节点 B 负责处理 5501 号至 11000 号插槽。
节点 C 负责处理 11001 号至 16383 号插槽。

进入集群命令:

[root@hadoop04 src]# redis-cli -c -p 6379

如果不添加-c就会出现redis集群不能自动重定向的情况
不在一个slot下的键值,是不能使用mget,mgset等多键操作
可以通过{}来定义组的概念,从而使key中{}内相同内容的键值对放到一个slot中

查询集群中的值

CLUSTER KEYSLOT 计算键 key 应该被放置在哪个槽上。
CLUSTER COUNTKEYSINSLOT 返回槽 slot 目前包含的键值对数量。
CLUSTER GETKEYSINSLOT 返回 count 个 slot 槽中的键。

使用Java连接集群
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;

import java.util.HashSet;
import java.util.Set;

public class JedisClusterTest {
    public static void main(String[] args) {
        Set<HostAndPort> set =new HashSet<>();//创建存储 HostAndPort的哈希表
        set.add(new HostAndPort("192.168.111.114",6379));
        JedisCluster jedisCluster=new JedisCluster(set);
        jedisCluster.set("k1", "v1");
        System.out.println(jedisCluster.get("k1"));
    }
}

Redis集群优缺点

优点:

实现扩容
分摊压力
无中心配置相对简单

缺点:

多键操作是不被支持的
多键的Redis事务是不被支持的。lua脚本不被支持。
由于集群方案出现较晚,很多公司已经采用了其他的集群方案,而代理或者客户端分片的方案想要迁移至redis cluster,需要整体迁移而不是逐步过渡,复杂度较大。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值