大数据技术之_21_Redis学习_02_解析 Redis 配置文件 redis.conf + Redis 的持久化 + Redis 的事务 + Redis 的复制(Master/Slave)+ Redis 的 Java 客户端 Jedis

第四章 解析 Redis 配置文件 redis.conf4.1 Units 单位4.2 INCLUDES 包含4.3 GENERAL 通用4.4 SNAPSHOTTING 快照4.5 SECURITY 安全4.6 LIMITS 限制4.7 APPEND ONLY MODE 追加4.8 常见配置 redis.conf 介绍第五章 Redis 的持久化第六章 Redis 的事务第七章 Redis 的复制(Master/Slave)第八章 Redis 的 Java 客户端 Jedis


第四章 解析 Redis 配置文件 redis.conf

4.1 Units 单位


1、配置大小单位,开头定义了一些基本的度量单位,只支持 bytes(字节),不支持 bit(位数)。
2、对大小写不敏感。

4.2 INCLUDES 包含


指定包含其它的配置文件,可以在同一主机上多个 Redis 实例之间使用同一份配置文件,而同时各个实例又拥有自己的特定配置文件。
include /path/to/local.conf

4.3 GENERAL 通用

daemonize
pidfile
port


bind
timeout

loglevel
logfile
databases

4.4 SNAPSHOTTING 快照

sava

RDB是整个内存的压缩过的Snapshot,RDB的数据结构,可以配置复合的快照触发条件。
默认
save 900 1
save 300 10
save 60 10000

15分钟内改了1次,就保存一次快照
或5分钟内改了10次,就保存一次快照
或1分钟内改了1万次,就保存一次快照

注意:实际开发中 30 分钟保存一次快照。

如果想禁用RDB持久化的策略,只要不设置任何save指令,或者给save传入一个空字符串参数也可以。
sava ""

stop-writes-on-bgsave-error 默认配置是yes,表示在使用bgsave命令备份的时候出现错误则停止外界写入操作,
如果配置成no,表示你不在乎数据不一致或者有其他的手段发现和控制。
dbfilename
dir dump.rdb存储的目录,即启动redis时的目录

4.5 SECURITY 安全


具体操作如下:

4.6 LIMITS 限制

maxclients

  设置 redis 同时可以与多少个客户端进行连接。默认情况下为 10000 个客户端。当你无法设置进程文件句柄限制时,redis 会设置为当前的文件句柄限制值减去 32,因为 redis 会为自身内部处理逻辑留一些句柄出来。如果达到了此限制,redis 则会拒绝新的连接请求,并且向这些连接请求方发出 “max number of clients reached” 以作回应。
maxmemory
  设置 redis 可以使用的内存量。一旦到达内存使用上限,redis 将会试图移除内部数据,移除规则可以通过 maxmemory-policy 来指定。如果 redis 无法根据移除规则来移除内存中的数据,或者设置了“不允许移除”,那么 redis 则会针对那些需要申请内存的指令返回错误信息,比如 SET、LPUSH 等。
  但是对于无内存申请的指令,仍然会正常响应,比如 GET 等。如果你的 redis 是主 redis(说明你的 redis 有从 redis),那么在设置内存使用上限时,需要在系统中留出一些内存空间给同步队列缓存,只有在你设置的是“不移除”的情况下,才不用考虑这个因素。
maxmemory-policy
  •(1)volatile-lru:使用 LRU 算法移除 key,只对设置了过期时间的键
  •(2)allkeys-lru:使用 LRU 算法移除 key
  •(3)volatile-random:在过期集合中移除随机的 key,只对设置了过期时间的键
  •(4)allkeys-random:移除随机的 key
  •(5)volatile-ttl:移除那些 TTL 值最小的 key,即那些最近要过期的 key
  •(6)noeviction:不进行移除。针对写操作,只是返回错误信息,实际开发中不使用这个配置。

4.7 APPEND ONLY MODE 追加

appendonly
appendfilename
appendfsync
  always:同步持久化,每次发生数据变更会被立即记录到磁盘,性能较差但数据完整性比较好。
  everysec:出厂默认推荐,异步操作,每秒记录,如果一秒内宕机,有数据丢失,实际开发中推荐
  no

4.8 常见配置 redis.conf 介绍

参数说明:

redis.conf 配置项说明如下:
1. Redis 默认不是以守护进程的方式运行,可以通过该配置项修改,使用 yes 启用守护进程
  daemonize no
2. 当 Redis 以守护进程方式运行时,Redis 默认会把 pid 写入 /var/run/redis.pid 文件,可以通过 pidfile 指定
  pidfile /var/run/redis.pid
3. 指定 Redis 监听端口,默认端口为 6379,作者在自己的一篇博文中解释了为什么选用 6379 作为默认端口,因为 6379 在手机按键上是 MERZ 对应的号码,而 MERZ 取自意大利歌女 Alessia Merz 的名字
  port 6379
4. 绑定的主机地址
  bind 127.0.0.1
5.当客户端闲置多长时间后关闭连接,如果指定为0,表示关闭该功能
  timeout 300
6. 指定日志记录级别,Redis 总共支持四个级别:debug、verbose、notice、warning,默认为 verbose
  loglevel verbose
7. 日志记录方式,默认为标准输出,如果配置 Redis 为守护进程方式运行,而这里又配置为日志记录方式为标准输出,则日志将会发送给 /dev/null
  logfile stdout
8. 设置数据库的数量,默认数据库为 0,可以使用 SELECT <dbid> 命令在连接上指定数据库 id
  databases 16
9. 指定在多长时间内,有多少次更新操作,就将数据同步到数据文件,可以多个条件配合
  save <seconds> <changes>
  Redis 默认配置文件中提供了三个条件:
  save 900 1
  save 300 10
  save 60 10000
  分别表示 900 秒(15分钟)内有 1 个更改,300 秒(5分钟)内有 10 个更改以及 60 秒内有 10000 个更改。
10. 指定存储至本地数据库时是否压缩数据,默认为 yes,Redis 采用 LZF 压缩,如果为了节省 CPU 时间,可以关闭该选项,但会导致数据库文件变的巨大
  rdbcompression yes
11. 指定本地数据库文件名,默认值为 dump.rdb
  dbfilename dump.rdb
12. 指定本地数据库存放目录
  dir ./
13. 设置当本机为 slave 服务时,设置 master 服务的 IP 地址及端口,在 Redis 启动时,它会自动从 master 进行数据同步
  slaveof <masterip> <masterport>
14. 当 master 服务设置了密码保护时,slave 服务连接 master 的密码
  masterauth <master-password>
15. 设置 Redis 连接密码,如果配置了连接密码,客户端在连接 Redis 时需要通过 AUTH <password> 命令提供密码,默认关闭
  requirepass foobared
16. 设置同一时间最大客户端连接数,默认无限制,Redis 可以同时打开的客户端连接数为 Redis 进程可以打开的最大文件描述符数,如果设置 maxclients 0,表示不作限制。当客户端连接数到达限制时,Redis 会关闭新的连接并向客户端返回 max number of clients reached 错误信息
  maxclients 128
17. 指定 Redis 最大内存限制,Redis 在启动时会把数据加载到内存中,达到最大内存后,Redis 会先尝试清除已到期或即将到期的 key,当此方法处理 后,仍然到达最大内存设置,将无法再进行写入操作,但仍然可以进行读取操作。Redis 新的 vm 机制,会把 key 存放内存,value 会存放在 swap 区
  maxmemory <bytes>
18. 指定是否在每次更新操作后进行日志记录,Redis 在默认情况下是异步的把数据写入磁盘,如果不开启,可能会在断电时导致一段时间内的数据丢失。因为 redis 本身同步数据文件是按上面 save 条件来同步的,所以有的数据会在一段时间内只存在于内存中。默认为 no
  appendonly no
19. 指定更新日志文件名,默认为 appendonly.aof
   appendfilename appendonly.aof
20. 指定更新日志条件,共有3个可选值: 
  no:表示等操作系统进行数据缓存同步到磁盘(快) 
  always:表示每次更新操作后手动调用fsync()将数据写到磁盘(慢,安全) 
  everysec:表示每秒同步一次(折衷,默认值)
  appendfsync everysec
21. 指定是否启用虚拟内存机制,默认值为 no,简单的介绍一下,VM机制将数据分页存放,由Redis将访问量较少的页即冷数据swap到磁盘上,访问多的页面由磁盘自动换出到内存中(在后面的文章会仔细分析 Redis 的 VM 机制)
  vm-enabled no
22. 虚拟内存文件路径,默认值为 /tmp/redis.swap,不可多个 Redis 实例共享
  vm-swap-file /tmp/redis.swap
23. 将所有大于 vm-max-memory 的数据存入虚拟内存,无论 vm-max-memory 设置多小,所有索引数据都是内存存储的(Redis的索引数据 就是 keys),也就是说,当 vm-max-memory 设置为0的时候,其实是所有 value 都存在于磁盘。默认值为 0
  vm-max-memory 0
24. Redis swap 文件分成了很多的 page,一个对象可以保存在多个 page 上面,但一个 page 上不能被多个对象共享,vm-page-size 是要根据存储的 数据大小来设定的,作者建议如果存储很多小对象,page 大小最好设置为 32 或者 64bytes;如果存储很大大对象,则可以使用更大的 page,如果不确定,就使用默认值
  vm-page-size 32
25. 设置 swap 文件中的 page 数量,由于页表(一种表示页面空闲或使用的 bitmap)是在放在内存中的,,在磁盘上每 8 个 pages 将消耗 1byte 的内存。
  vm-pages 134217728
26. 设置访问 swap 文件的线程数,最好不要超过机器的核数,如果设置为 0,那么所有对 swap 文件的操作都是串行的,可能会造成比较长时间的延迟。默认值为 4
  vm-max-threads 4
27. 设置在向客户端应答时,是否把较小的包合并为一个包发送,默认为开启
  glueoutputbuf yes
28. 指定在超过一定的数量或者最大的元素超过某一临界值时,采用一种特殊的哈希算法
  hash-max-zipmap-entries 64
  hash-max-zipmap-value 512
29. 指定是否激活重置哈希,默认为开启(后面在介绍 Redis 的哈希算法时具体介绍)
  activerehashing yes
30. 指定包含其它的配置文件,可以在同一主机上多个 Redis 实例之间使用同一份配置文件,而同时各个实例又拥有自己的特定配置文件
  include /path/to/local.conf

第五章 Redis 的持久化


RBD小结

AOF小结

第六章 Redis 的事务

Redis 事务常用命令:


Redis 的事务脑图

第七章 Redis 的复制(Master/Slave)

第八章 Redis 的 Java 客户端 Jedis


测试连通性
package com.atguigu.test;

import redis.clients.jedis.Jedis;

public class HelloRedis {

    public static void main(String[] args) {
        Jedis jedis = new Jedis("192.168.25.102"6379);

        String result = jedis.ping();

        System.out.println("**********" + result);

        // Connection
    }
}

五大数据类型 + 1个 key

package com.atguigu.test;

import java.util.Set;

import redis.clients.jedis.Jedis;

public class APIRedis {

    public static void main(String[] args) {
        Jedis jedis = new Jedis("192.168.22.167"6379);

        Set<String> set = jedis.keys("*");
        System.out.println(set.size());

        jedis.set("k3""v3");

        System.out.println(jedis.get("k3"));
    }
}

事务提交

package com.atguigu.test;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;

public class TXRedis {

    public boolean transMethod() throws InterruptedException {
        Jedis jedis = new Jedis("192.168.25.102"6379);

        int balance;// 可用余额
        int debt;// 欠额
        int amtToSubtract = 10;// 实刷额度

        jedis.watch("balance");
        Thread.sleep(8000); // 停止程序一小段时间,外面先修改balance数据后看效果
        balance = Integer.parseInt(jedis.get("balance"));

        if (balance < amtToSubtract) {
            jedis.unwatch();
            System.out.println("The Data has been updated before you commit or balance < amtToSubtract");
            return false;
        } else {
            System.out.println("***********transaction");

            Transaction transaction = jedis.multi();
            transaction.decrBy("balance", amtToSubtract);
            transaction.incrBy("debt", amtToSubtract);
            transaction.exec();

            balance = Integer.parseInt(jedis.get("balance"));
            debt = Integer.parseInt(jedis.get("debt"));

            System.out.println("*******" + balance);
            System.out.println("*******" + debt);
            return true;
        }
    }

    /**
     * 伪代码如下: 通俗点讲,watch 命令就是标记一个键,如果标记了一个键:
     * 
     * 在提交事务前如果该键被别人修改过,那事务就会失败,这种情况通常可以在程序中重新再尝试一次。
     * 首先标记了键balance,然后检查余额是否足够,不足就取消标记,并不做扣减; 足够的话,就启动事务进行更新操作,
     * 如果在此期间键balance被其它人修改, 那在提交事务(执行exec)时就会报错, 程序中通常可以捕获这类错误再重新执行一次,直到成功。
     * 
     * @throws InterruptedException
     */

    public static void main(String[] args) throws InterruptedException {
        TXRedis test = new TXRedis();
        boolean retValue = test.transMethod();
        System.out.println("main retValue-------: " + retValue);
    }
}

主从复制

package com.atguigu.test;

import redis.clients.jedis.Jedis;

public class ReplicationRedis {

    public static void main(String[] args) {
        Jedis jedisM = new Jedis("192.168.25.102"6379);
        Jedis jedisS = new Jedis("192.168.25.102"6380);

        jedisS.slaveof("192.168.25.102"6379);

        jedisM.set("k3""v3");

        String result = jedisS.get("k3");

        System.out.println("############# result: " + result);
    }
}

JedisPoolUtils.java

package com.atguigu.test;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

public class JedisPoolUtils {
    private static volatile JedisPool jedisPool = null;

    private JedisPoolUtils() {
    }

    // DCL(double check lock)
    public static JedisPool getInstance() {
        if (null == jedisPool) {
            synchronized (JedisPoolUtils.class) {
                if (null == jedisPool) {
                    JedisPoolConfig poolConfig = new JedisPoolConfig();
                    poolConfig.setMaxActive(100);
                    poolConfig.setMaxIdle(32);
                    poolConfig.setMaxWait(100 * 1000);
                    poolConfig.setTestOnBorrow(true);

                    jedisPool = new JedisPool(poolConfig, "192.168.25.102"6379);
                }
            }
        }
        return jedisPool;
    }

    public static void close(JedisPool jedisPool, Jedis jedis) {
        if (null != jedis) {
            jedisPool.returnResourceObject(jedis);
        }
    }
}

JedisPoolRedis.java

package com.atguigu.test;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

public class JedisPoolRedis {

    public static void main(String[] args) {
        JedisPool jedisPool = JedisPoolUtils.getInstance();
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            jedis.set("k5""0508good");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JedisPoolUtils.close(jedisPool, jedis);
        }
    }
}

配置总结

JedisPool 的配置参数大部分是由 JedisPoolConfig 的对应项来赋值的。

maxActive:控制一个 pool 可分配多少个 jedis 实例,通过 pool.getResource() 来获取;如果赋值为 -1,则表示不限制;如果  pool 已经分配了 maxActive 个 jedis 实例,则此时 pool 的状态为 exhausted。

maxIdle:控制一个 pool 最多有多少个状态为 idle(空闲) 的 jedis 实例。

whenExhaustedAction:表示当 pool 中的 jedis 实例都被 allocated 完时,pool 要采取的操作,默认有三种:
   WHEN_EXHAUSTED_FAIL  --> 表示无 jedis 实例时,直接抛出 NoSuchElementException
   WHEN_EXHAUSTED_BLOCK --> 则表示阻塞住,或者达到 maxWait 时抛出 JedisConnectionException
   WHEN_EXHAUSTED_GROW --> 则表示新建一个 jedis 实例,也就说设置的 maxActive 无用

maxWait:表示当 borrow 一个 jedis 实例时,最大的等待时间,如果超过等待时间,则直接抛 JedisConnectionException;

testOnBorrow:在 borrow 一个 jedis 实例时,是否提前进行 validate 操作;如果为 true,则得到的 jedis 实例均是可用的;

testOnReturn:在 return 给 pool 时,是否提前进行 validate 操作;

testWhileIdle:如果为 true,表示有一个 idle object evitor 线程对 idle object 进行扫描,如果 validate 失败,此 object 会被从 pool 中 drop 掉;这一项只有在 timeBetweenEvictionRunsMillis 大于0时才有意义;

timeBetweenEvictionRunsMillis:表示 idle object evitor 两次扫描之间要 sleep 的毫秒数;

numTestsPerEvictionRun:表示 idle object evitor 每次扫描的最多的对象数;

minEvictableIdleTimeMillis:表示一个对象至少停留在 idle 状态的最短时间,然后才能被 idle object evitor 扫描并驱逐;这一项只有在 timeBetweenEvictionRunsMillis 大于0时才有意义;

softMinEvictableIdleTimeMillis:在 minEvictableIdleTimeMillis 基础上,加入了至少 minIdle 个对象已经在 pool 里面了。如果为 -1,evicted 不会根据 idle time 驱逐任何对象。如果 minEvictableIdleTimeMillis > 0,则此项设置无意义,且只有在 timeBetweenEvictionRunsMillis > 0 时才有意义;

lifo:borrowObject 返回对象时,是采用 DEFAULT_LIFO(last in first out,即类似 cache 的最频繁使用队列),如果为 False,则表示 FIFO 队列;

=================================================
其中 JedisPoolConfig 对一些参数的默认设置如下:

testWhileIdle=true
minEvictableIdleTimeMills=60000
timeBetweenEvictionRunsMillis=30000
numTestsPerEvictionRun=-1
posted @ 2019-05-08 15:32  黑泽君  阅读(433)  评论(0编辑  收藏  举报