NoSQL数据库之:Redis

一、什么是Redis?

Redis是基于内存的NoSQL数据库。前身是memcached,但是memcached不支持持久化,没有丰富的数据类型。Redis存放的数据是key-values键值对。

二、安装Redis、命令脚本

1、解压

tar -zxvf redis-3.0.5.tar.gz 

注意:这里下载是源码。
2、安装

//预编译,需要gcc环境。
apt-get install gcc
apt-get install make
make
//PREFIX指定安装目录
make PREFIX=/usr/local/redis install

3、Redis的脚本命令

└── bin
		├── redis-benchmark		压力测试工具
		├── redis-check-aof		检查AOF文件
		├── redis-check-dump	检查RDB文件
		├── redis-cli			客户端命令行
		├── redis-sentinel -> redis-server  哨兵(HA的实现)
		└── redis-server		服务器

4、核心配置文件:redis.conf(在源码的目录)

mkdir conf
cp ~/tools/redis-3.0.5/redis.conf conf/

5、参数

daemonize no ----> yes:表示redis在后台运行
port 6379

6、启动Redis服务器

bin/redis-server conf/redis.conf
	
[root@bigdata111 redis]# ps -ef | grep redis-server
root      15608      1  0 20:38 ?        00:00:00 bin/redis-server *:6379

7、启动Redis客服端

bin/redis-cli   -h 列举所有的参数。默认是连接本机Redis。

三、操作Redis(命令行、Java程序)

1、设置键

expire  key   设置key的过期时间

2、数据类型(命令行)

以下删除数据  del  <name>

2.1、字符串
set 、get 、append在字符串后追加

set key1 "hello world"
get key1
append key1 "**********"
get key1
输出:hello world***********

mset(设置多个字符) 、mget (获取多个字符)、 incr (自增1)、 decr(自减1)

mset key2 "abcd" key3 "xyz"
mget key2 key3
set key4 100
incr key4
decr key4
decrby key4 10
incrby key4 10

2.2 、 链表(就是一个双端队列)对表头和表尾操作
lpush 、 lrange 、 lpop -----> 左:链表的头部

lpush list1 11 22 33 44 
lrange list1 0 2 
lrange list 0 -1  表示列出所有的元素
lpop list1 从链表的头部取一个值

rpush、rpop、--------> 右:链表的尾部

rpush list2 11 22 33 44 55 
rpop list2

2.3、Hash(列式存储)
hset 、 hget

hset hashkey name zhangsan
hset hashkey age 10

hmset 、hmget

hmset  user1 name zhangsan age 10
hmset user2 name lisi age 11
hgetall user1  //获取所有user1的所有信息
hget user1 name //获取一列值 

3、数据类型(Java程序)

在项目中导入jedis的jar包
3.1、操作数据

	 public static void main(String[] args) {
        Jedis jedis = new Jedis("192.168.92.111",6379);
        //1、字符类型
        //添加数据
        jedis.mset("key1","1","key2","2");
        String key1=jedis.get("key1");
        System.out.println("key1:"+key1);

        System.out.println("********************************");
//        jedis.lpush("list","1" , "2" ,"3","4");
        List list = jedis.lrange("list",0 , -1);
        Iterator it = list.iterator();
        while (it.hasNext()){
            Object o= it.next();
            System.out.println(o);
        }
        System.out.println("***************************");
        Map<String,String> map = new HashMap<String, String>();
        map.put("name","吴明辉");
        map.put("age" , "20");
        jedis.hmset("user001",map);

        List user001 = jedis.hmget("user001","name" , "age");
        for (Object o : user001) {
            System.out.println(o);
        }


        jedis.disconnect();


    }

3.2、Redis连接池
再导入一个jar包,commonts-pool2.jar,注意版本问题。

public class RedisUtils {
    private static JedisPool jedisPool = null;
    static {
        try {
            JedisPoolConfig config = new JedisPoolConfig();
            // 可用连接实例最大数目,默认为8,如果为-1,表示不限制;
            config.setMaxActive(1024);
            // 控制一个pool最多有多少个状态为idle(空闲的)的jedis实例,默认值为8
            config.setMaxIdle(200);
            // 等待可用连接最大时间,单位毫秒,默认值-1,表示永不超时
            config.setMaxWait(10000);
            // 在borrow一个jedis实例时,是否提前进行validate操作,如果为true,则得到的jedis实例均是可用的
            config.setTestOnBorrow(true);

            jedisPool = new JedisPool(config , "192.168.92.111",6379);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
    public synchronized static Jedis getJedis(){
        if(jedisPool != null){
            return jedisPool.getResource();
        }
        return null;
    }

    public static void returnResource(final  Jedis jedis){
        if (jedis != null) {
            jedisPool.returnResource(jedis);
        }
    }
}

四、Redis的事务和锁机制

1、什么是事务?具备ACID属性

 MySQL:start transaction;
	        insert
			update
			insert
			delete
			commit; (rollback;)

2、对比:MySQL(Oracle)跟Redis的事务

		MySQL(Oracle)				        Redis
		事务本质:将操作写入日志				将操作放入队列(批处理)
		开启事务:start transaction;			multi;
		事务操作:insert update delete			操作命令
		          (DML)
		提交事务:commit						exec
		回滚事务:rollback						disacard

3、举例:银行转账

set tom 1000
set mike 1000
multi
decrby tom 100  -----> 放入队列
incrby mike 100 -----> 放入队列
exec

4、锁机制:在事务执行的过程中,如果某些值发生了变化,自动回滚;

相当于给值加上锁(监听)----> watch,是一个乐观锁

  • 悲观锁
    总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁(共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程)
  • 乐观锁
    总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,

Demo:买票


set ticket 1
set tom 1000
watch ticket		
multi
decrby tom 100
decrby ticket 1
exec  -------> 提交时候,票已经被别人买走

在最后执行时,会检查ticket的值是否发生变化,发生变化就回滚。

Java代码实现事务与锁:

	@Test
    public void testLock(){
        Jedis jedis = new Jedis("192.168.92.111",6379);
        jedis.watch("ticket");
        Transaction tc = null;
        try {
            tc = jedis.multi();
            tc.decrBy("ticket" , 1);
            Thread.sleep(5000);
            tc.decrBy("tom",100);
            tc.exec();
        } catch (InterruptedException e) {
            //回滚事务
            tc.discard();
            e.printStackTrace();
        }
        jedis.disconnect();
    }

五、Redis的消息机制(只支持Topic类型(广播)的消息)

1、消息:可以是字符串、也可以是对象(序列化)
消息类型:

  • Queue队列:点对点
  • Topic主题:广播(群发): 订阅(接收消息)
    Kafka、Redis只支持Topic

消息系统:

  • 同步消息系统:必须等待对方的回答(ATM机)
  • 异步消息系统:不需要等待对方的回答(微信)

2、Redis消息机制的架构:核心定义一个Channel(频道、主题Topic)
3、消息命令

发布消息:publish
订阅消息:subscribe
使用通配符订阅消息:psubscribe

先订阅后发布信息

命令行实现:

开通3个窗口:窗口1、窗口2、窗口3
窗口2:subscribe c1
窗口3:subscribe c1
窗口1:publish c1
窗口2与窗口3订阅窗口1的信息
在这里插入图片描述
注意:订阅消息会产生阻塞。
订阅也可以使用通配符,命令如下:

psubscribe c*

Java代码实现:

订阅代码展示

	@Test
    public void TestRedisSubscribe(){
        Jedis jedis = new Jedis("192.168.92.111",6379);

        jedis.subscribe(new JedisPubSub() {
            @Override
            public void onMessage(String channel, String message) {
                System.out.println("moMessage channel is "+ channel +"message is "+ message);
            }

            @Override
            public void onPMessage(String pattern, String channel, String message) {
                // 通配符进行匹配,在这里进行输出
            }

            @Override
            public void onSubscribe(String s, int i) {

            }

            @Override
            public void onUnsubscribe(String s, int i) {

            }

            @Override
            public void onPUnsubscribe(String s, int i) {

            }

            @Override
            public void onPSubscribe(String s, int i) {

            }
        } , "c1");
        // 通配符,用psubscribe函数,“c1”可以换成“c*”


        // 产生阻塞,不关闭连接
        //jedis.disconnect();

    }

六、Redis的持久化:把内存中的数据写到文件

利用RDB和AOF:实现数据的迁移。

1、RDB

是一种快照,每隔一段时间将Redis内存中的所有数据写到文件(dump.rdb)上,默认的持久化
优点:恢复速度快
缺点:两次RDB之间,数据可能丢失

命令

save <seconds> <changes>		
save ------- 阻塞当前的工作线程
bgsave ----- 单起一个线程来执行RDB,本质是把内存copy一份,再执行RDB

参数:

	 秒  发生变化的value
save 900 1      在15分钟内,如果有1个value发生了变化,就执行RDB
save 300 10     在5分钟内,如果有10个value发生了变化,就执行RDB
save 60  10000	在1分钟内,如果有1w个value发生了变化,就执行RDB
stop-writes-on-bgsave-error yes 当执行RDB出错的时候,禁止写入新的数据
rdbcompression yes  RDB文件是否压缩;建议改no
dbfilename dump.rdb
dir ./ 当前目录

2、AOF:append only file -----> 日志

#开启aof
appendonly yes
# 有操作系统决定什么写入日志
appendfsync no
# 每条操作都写入
appendfsync always
# 每秒写入一次
appendfsync everysec
# 生成aof的时候,是否不写入aof
no-appendfsync-on-rewrite yes
# aof 文件比上次重写时,超过的百分比
auto-aof-rewrite-percentage 100
# aof发生重写的最小文件大小
auto-aof-rewrite-min-size 64mb
#aof日志重写就是文件进行压缩。 

如果aof和rdb都有,默认使用aof进行恢复。

七、Redis主从复制

1、目的:

  • 实现读写分离
  • 实现任务分离:由从节点负责生成RDB、AOF

2、实现的架构:

  • 星型模型:优点:同步效率高 缺点:HA较麻烦
    在这里插入图片描述

  • 线型模型:优点:HA简单 缺点:效率低
    在这里插入图片描述

3、搭建

以星型模型为例:

Master:6379
Slave1:6380
Slave2:6381

修改两部分:
从节点:
1、slaveof 指定从节点的主节点地址。

slaveof bigdata111 6379

从节点默认情况下是只读的

slave-read-only yes

2、修改生成rdb文件名,以便观察

dbfilename dump6380.rdb

3、指定端口

port 6380

同样配置 slave2

主节点:禁用主节点的RDB和AOF(并不意味着:不产生RDB和AOF的信息,只是这样的信息不由主节点写到文件),禁用下面三行代码。

#save 900 1
#save 300 10
#save 60 10000

appendonly no

启动:

bin/redis-server conf/redis6379.conf
bin/redis-server conf/redis6380.conf
bin/redis-server conf/redis6381.conf

注意:不要一次性的启动很多的从节点,容易造成主节点的崩溃。

4、主从复制的原理

在这里插入图片描述

分两步
第一步:主节点-从节点-----> 同步的是RDB
从第二次开始:同步就是AOF

八、Redis代理分片:负载均衡

在这里插入图片描述
我们使用nutcracker做一个读数据负载均衡

1、首先搭建主从复制环境

2、解压

tar -zxvf nutcracker-0.3.0.tar.gz

3、安装

// prefix指定安装路径
./configure --prefix=/usr/local/proxy
make
make install

4、配置

核心配置文件:nutcracker.yml ,这个文件需要我们在刚才解压的文件里copy一下

cp /tools/nutcracker-0.3.0/conf/nutcracker.yml /usr/local/proxy/conf/

然后编辑这个文件,nutcracker可以配置多个Redis集群
vi nutcracker.yaml ,只保留一个就行。

alpha:
  listen: 127.0.0.1:22121
  hash: fnv1a_64
  distribution: ketama
  auto_eject_hosts: true
  redis: true
  server_retry_timeout: 2000
  server_failure_limit: 1
  servers:
   - 127.0.0.1:6380:1
   - 127.0.0.1:6381:1

listen:nutcracker的IP地址与端口
servers:“-”与后面的IP存在一个空格,IP地址:端口:权重

5、启动

  • 检查配置文件是否正确
sbin/nutcracker -t conf/nutcracker.yml
  • 启动服务器
sbin/nutcracker -d conf/nutcracker.yml
  • 测试
    进入Redis的home目录下执行:
bin/Redis-cli -p <nutcracker的端口>

九、Redis的HA:high availablity-------哨兵

功能:主节点宕机,从节点补上。
在这里插入图片描述

1、配置核心文件sentinel.conf

这个文件也需要我们从源码(刚开始解压的文件)中拷贝

cp /tools/redis-3.0.5/sentinel.conf conf/

2、修改参数

监听的是主节点

                    别名   主节点的地址  如果有2个哨兵没有收到心跳,就进行切换
sentinel monitor mymaster 127.0.0.1 6379 1

sentinel auth-pass <master-name> <password>

sentinel down-after-milliseconds mymaster 30000
表示多少秒没,没有收到主节点的心跳,哨兵就认为主节点down

sentinel parallel-syncs mymaster 1
选出新的主节点后,可以同时连接其他从节点的个数

sentinel failover-timeout mymaster 18000
失败切换时,允许的最大时间

3、启动哨兵

在Redis 的home目录下

bin/redis-sentinel conf/sentinel.conf

当主节点宕机时,看日志选出的新的主节点。
当杀死主节点时,sentinel 日志:在这里插入图片描述

十、Redis Cluster----数据的分布式存储

本质就是Hash分区,Redis Cluster中,Hash值叫做槽号 slot,根据数据的key,来计算槽号。如果槽号相同,数据就被放到同一个Redis的节点上,槽号的范围0~16383。Redis是去中心化

安装部署

我们以6个节点为例,体系架构如下
在这里插入图片描述

1、安装ruby的运行环境

apt-get install ruby

2、安装Redis与ruby的接口

首先上传redis-3.0.5.gem
在此文件目录下:

gem install redis-3.0.5.gem

3、手动安装

配置六个文件,需要修改的参数,其中黄色字体需要每个实例修改
提前创建好 nodes文件夹

daemonize yes
port 6379
cluster-enabled yes
#每个节点存放集群信息位置
cluster-config-file nodes/nodes-6379.conf
cluster-node-timeout 15000
dbfilename dump6379.rdb
appendonly yes
appendfilename “appendonly6379.aof”

配置文件共六个:

redis6379.conf
redis6380.conf
redis6381.conf
redis6382.conf
redis6383.conf
redis6384.conf

启动Redis实例

bin/redis-server cluster/redis6379.conf
bin/redis-server cluster/redis6380.conf
bin/redis-server cluster/redis6381.conf
bin/redis-server cluster/redis6382.conf
bin/redis-server cluster/redis6383.conf
bin/redis-server cluster/redis6384.conf

进行初始化

  • 把redis-trib.rb 复制到Redis的home目录下的 bin/
cp /tools/redis-3.0.5/src/redis-trib.rb bin/
  • 启动
bin/redis-trib.rb create --replicas 1 192.168.92.111:6379 192.168.92.111:6380 192.168.92.111:6381 192.168.92.111:6382 192.168.92.111:6383 192.168.92.111:6384

replicas 1 表示冗余度为1,即6个节点,3个主节点和3个从节点

4、自动安装

1、cp ~/tools/redis-3.0.5/utils/create-cluster/create-cluster bin/
2、修改create-cluster里面的路径 , 全部修改成bin目录下
3、启动节点

bin/create-cluster  start

4、配置主从

bin/create-cluster  create

5、测试:

bin/redis-cli -c -p 6380
-c 表示集群登录
cluster nodes 查看cluster节点的信息。
在这里插入图片描述

十一、故障诊断和优化

1、Redis的日志

是Redis系统本身的日志,不是AOF,AOF是记录客户端的操作
默认是禁用的,需要在配置文件中打开。

97 # Specify the server verbosity level.
98 # This can be one of:
99 # debug (大量的信息,对开发/测试有用)
100 # verbose (许多很少有用的信息,但不像调试级别那样混乱)
101 # notice (比较冗长,这可能是生产中需要的)
102 # warning (只有非常重要/关键的消息被记录)
103 loglevel notice
105 # Specify the log file name. Also the empty string can be used to force
106 # Redis to log on the standard output. Note that if you use standard
107 # output for logging but daemonize, logs will be sent to /dev/null
108 # 配置生成日志文件的路径
108 logfile "/usr/local/redis/redis.log"

2、Redis的内存监控

2.1、bin/redis-cli info ----> 输出Redis的统计信息
2.2、bin/redis-cli info | grep mem

used_memory:816000				数据总量占用的内存
used_memory_human:796.88K		数据总量占用的内存(带有单位)
used_memory_rss:2060288			Redis进程本身占用的内存
used_memory_peak:816000			数据占用的内存的峰值
used_memory_peak_human:796.88K  数据占用的内存的峰值(带有单位)
used_memory_lua:36864
mem_fragmentation_ratio:2.52	内存碎片率
mem_allocator:jemalloc-3.6.0

3、数据过期的策略

  • 定时删除
    含义:设置key的过期时间的同时,为该key创建一个定时器,达到时间时,删除可以
    优点:保证没存尽快释放
    缺点:消耗内存
127.0.0.1:6379> help set

  SET key value [EX seconds] [PX milliseconds] [NX|XX]
EX -----> 是秒
PX -----> 是毫秒
127.0.0.1:6379> set key1 heolloworld ex 10
OK
127.0.0.1:6379> get key1
"heolloworld"
127.0.0.1:6379> get key1

  • 惰性删除
    含义:key过期时,不进行删除,当用户再次访问这个key时,先进行判断是否过期,假如过期了,再进行删除。
    优点:对CPU的占用少。
    缺点:无用的垃圾占用大量的内存。
  • 定期删除
    含义:设置每隔一段时间执行一次删除(在redis.conf配置文件设置hz,1s刷新的频率)。
    优点:限制删除操作的时长和频率。
    缺点:在内存方面不如定时删除,在cup时间友好方面,不如惰性删除。

4、PipeLine:管道

批处理,减少网络上的开销,提高性能
在这里插入图片描述
管道就是指,将命令打包一块处理。

  • Java测试代码如下
	@Test
    public void normal(){
        Jedis client = new Jedis("192.168.92.111",6379);

        //记录开始操作
        long startTime = System.currentTimeMillis();

        //插入10000条数据
        for (int i = 0; i < 10000; i++) {
            client.set("key"+i , "value"+i);
        }

        client.disconnect();

        long endTime = System.currentTimeMillis();

        System.out.println("程序执行时间"+(endTime-startTime));
    }

    @Test
    public void pipeLine(){
        Jedis client = new Jedis("192.168.92.111",6379);

        //记录开始操作
        long startTime = System.currentTimeMillis();

        Pipeline pipeline = client.pipelined();

        //插入10000条数据
        for (int i = 0; i < 10000; i++) {
            pipeline.set("key"+i , "value"+i);
        }
        pipeline.sync();

        long endTime = System.currentTimeMillis();

        System.out.println("程序执行时间"+(endTime-startTime));
        client.disconnect();
    }

5、慢查询日志

(1)什么是慢查询:查询语句执行的时间比较长,超过了我们预先设定的阈值。注意:慢查询日志只记录语句执行的时间
(2)相关参数设置

127.0.0.1:6379> CONFIG GET slow*
1) "slowlog-log-slower-than"  默认的语句执行时间的阈值,默认10000微秒
2) "10000"
3) "slowlog-max-len"	      最多记录多少条慢查询日志,默认是:最新的128条慢查询日志
4) "128"

(3)Demo

27.0.0.1:6379> CONFIG SET slowlog-log-slower-than 1  设置阈值:1微秒
OK
127.0.0.1:6379> set mykey001 helloworld 执行操作(没有超过10微秒)
OK
127.0.0.1:6379> slowlog get 5  获取最新的5条慢查询日志
1)	1) (integer) 1
	2) (integer) 1601902695
	3) (integer) 10
	4)  1) "CONFIG"
		2) "SET"
		3) "slowlog-log-slower-than"
		4) "10"
2)  1) (integer) 0              慢查询日志的ID
	2) (integer) 1601902129	   时间戳
	3) (integer) 63009		   执行的时间
	4)  1) "SET"					执行的指令和相关的参数
		2) "key8192"
		3) "value8192"

6、Redis监控命令

(1)监控:内存、RDB、AOF

bin/redis-cli info | grep mem
[root@bigdata111 redis]# bin/redis-cli info | grep rdb
rdb_changes_since_last_save:1    表示上次RDB以来,发生变化的key的个数
rdb_bgsave_in_progress:0		  当前RDB是否正在执行,1--在执行  0---没有执行
rdb_last_save_time:1601902189	  上次RDB执行的时间戳
rdb_last_bgsave_status:ok		  上次RDB执行的状态
rdb_last_bgsave_time_sec:0		  上次RDB执行花费的时间
rdb_current_bgsave_time_sec:-1	  当前RDB花费的时间
[root@bigdata111 redis]# bin/redis-cli info | grep aof
aof_enabled:1						是否启用了AOF
aof_rewrite_in_progress:0			是否正在执行AOF的重写
aof_rewrite_scheduled:0
aof_last_rewrite_time_sec:-1		AOF重写的时间戳
aof_current_rewrite_time_sec:-1
aof_last_bgrewrite_status:ok        上次AOF重写的状态
aof_last_write_status:ok
aof_current_size:865606
aof_base_size:0
aof_pending_rewrite:0
aof_buffer_length:0
aof_rewrite_buffer_length:0
aof_pending_bio_fsync:0
aof_delayed_fsync:0

(2)监控Redis的吞吐量

bin/redis-cli info | grep -e "connected_clients" -e "blocked_clients" -e "used_memory_human" -e "used_memory_peak_human" -e "rejected_connections" -e "evicted_keys" -e "instantaneous"
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值