Redis 从搭建到集群实践

 

第一章 安装

1.1.windows 安装

1.1.1下载

   下载地址: https://github.com/MSOpenTech/redis/releases

    Redis 支持 32 位和 64 位。这个需要根据你系统平台的实际情况选择,这里我们下载 Redis-x64-xxx.zip压缩包到 C 盘,解压后,将文件夹重新命名为 redis

     打开一个 cmd 窗口 使用cd命令切换目录到 C:\redis 运行 redis-server.exe redis.windows.conf 。

     如果想方便的话,可以把 redis 的路径加到系统的环境变量里,这样就省得再输路径了,后面的那个 redis.windows.conf 可以省略,如果省略,会启用默认的。输入之后,会显示如下界面:

这时候另启一个cmd窗口,原来的不要关闭,不然就无法访问服务端了。

切换到redis目录下运行 redis-cli.exe -h 127.0.0.1 -p 6379 。

设置键值对 set myKey abc 取出键值对 get myKey

1.2 Linux安装

1.2.1下载: 

      从官网http://download.redis.io/releases/readis-3.0.6.tar.gz 下载,         

1.2.2.安装:

      将下载的redis传送到虚拟机中,因为比较小,通过xshell传输 cd /usr/local/src

      mkdir redis    

 (1) 传输:rz   -E

 (2) 解压: tar -xzvf redis...

 (3) 进入 cd  redis-3.2.6

    (4) 编译: make

    (5) 安装:make install

    (6) 查看  ll / ls

 

1.2.3 启动 redis-server

 

在命令里面不能退出来,所以得在开启一个窗口

  查看进程 ps -ef |grep redis

1.2.4 开启redis客户端口

SUCCESS!

启动配置

1.3 Redis配置 

  redis实例配置配置文件:redis.conf

       redis最多启用6个实例

1.3.1 单机多实例配置  

   (1)在redis目录下,cp一份redis.conf

             

   (2) 编辑redis2.config即可

             

   (3) port修改,如果设为0,redis将不在socket上监听任何客户端连接。

                      

   (4) 守护进程模式: 默认情况下redis不是作为守护进程运行的,如果想改为后台运行,就需要改成yes.

                           

   (5) 设置最大内存空间,默认情况下整个物理内存就是默认内存空间,风险太大

 必须带上单位,通常是 1k 1gb  4m等这样,不区分大小写。

 

    (6) 默认情况下,redis在server上所有有效的网络接口上监听客户端连接。如果只想让它在一个网络接口上监听,那就绑定一个IP或者多个IP.

             

     (7) 可以设置密码

 

     (8) 启动实例

    (9) redis客户端服务关闭

            redis-cli -h 127.0.0.1 -p 6380 shutdown     / kill 进程号

    (10) 插入数据

                

    (11) 读取缓存数据

                      

     (12) 可以设置密码,在配置文件(redis*.conf)

                       

     (13) 访问需要密码:auth 密码

                         

1.3.2注释:

(1) 设置模式,修改redis.conf

daemonize yes #默认为no

(2) 端口配置:

   默认6379

 (3) 配置数据库数量:

Redis默认开启16个数据库,不能像mysql自定义数据库名称,只能是数值,不能修改。

 (4) 配置内存大小:

会生成一个和内存大小一样的文件。maxmemory 200mb #在真实环境必须部署,否则物理内存会被耗尽。一般配置200mb/500mb/1gb/2gb。可以分散到多台服务器,和其它业务共享服务器,以充分利用资源。同时因为分散,防止单点故障,造成大量缓存失效。

maxmemory 200mb

1.3.3启动

redis-server #默认找redis.conf配置文件

(1)  redis-server redis6380.conf #指定配置文件,这样可以启动多个实例

(2)  redis-cli的使用之发送命令  redis-cli 默认连接:IP 127.0.0.1 端口 6379

(3)  指定IP端口:redis-cli -h 实例ip -p 实例端口

eg:  redis-cli –h 127.0.0.1 –p 6379

(4) 使用ping命令测试与客户端和服务器链接是否正常

redis-cli ping或redis-cli

redis 127.0.0.1:6379>ping

PONG

redis-cli的使用之命令返回值,状态回复(最简单的回复-redis提供的测试命令)

错误回复(以error开头,后面跟着错误信息)

eg:127.0.0.1:6379>TEST

(error) ERR unknown command 'TEST'

  a. 整数回复

    127.0.0.1:6379>INCR test_incr

    (integer) 1

  b. 字符串回复(最长久的一种回复,双引号包裹)

    127.0.0.1:6379>get test

    “123”

  c. 多行字符串回复

    127.0.0.1:6379>KEYS *

   1) "test_incr"

   2) "test"

(5)  redis数据库切换SELECT

redis默认支持16个数据库,对外都是以一个从0开始的递增数字命名,可以通过参数database来修改默认数据库个数。客户端连接redis服务后会自动选择0号数据库,可以通过select命令更换数据库,例如选择1号数据库:

127.0.0.1:6379>SELECT 1

OK

127.0.0.1:6379>GET test

(nil)

说明:

Redis不支持自定义数据库名称。

Redis不支持为每个数据库设置访问密码。

Redis的多个数据库之间不是安全隔离的,FLUSHALL命令会清空所有数据库的数据

1.3.4 安装两个服务

复制改端口无需再次安装

只需要复制配置文件,启动时选择配置文件即可。

#cd  /usr/local/src/redis/redis.2.8.17

#cp  redis.conf redis6380.conf

#vi  redis6380.conf    #修改端口为6380

#redis-server redis6380.conf

注意:启动后,会残留些数据,不完全,必须flushall清除掉。

1.4 外部编码访问配置

1.4.1 多机多实例配置

     克隆redis虚拟机1,配置redis1的三个redis实例

 

1.4.2 pom依赖

  <!-- jedis -->
<dependency>
   <groupId>redis.clients</groupId>
   <artifactId>jedis</artifactId>
   <version>2.9.0</version>
</dependency>

1.4.3 连接测试

1.4.4 与外界java连接

(1) 需要开放端口

a . 打开6379端口(Centeros 7之前版本)

/sbin/iptables -I INPUT -p tcp --dport 6379 -j ACCEPT

/etc/rc.d/init.d/iptables save #修改生效

/etc/init.d/iptables status #查看配置

 b. CenterOS 7版本,本次所有测试均使用CenterOS 7

systemctl start firewalld   开启防火墙

firewall-cmd --zone=public --add-port=6379/tcp --permanent 开启6379端口(permanent永久生效,没有此参数,重启后失效)

firewall-cmd --reload 重新载入

firewall-cmd --zone=public --query-port=6379/tcp 查看

(1)  错误处理:

解决:redis服务没启动。。。。

                 

 (2) 进入redis中,设置保护模式no.

                   

 (3) 访问redis的驱动包。

 

使用最为广泛的是Jedis和Redisson(官方推荐),在企业中采用最多的是Jedis。 Jedis官网地址:https://github.com/xetorthio/jedis

 

(5)  Jedis测试

@Test
public void jedis() {
    Jedis jedis = new Jedis("192.168.88.110", 6379);
    jedis.set("test", "456789"); //设置值
    System.out.println(jedis.get("test")); //获取值
    /*设置多个值*/
    jedis.mset("test1", "1", "test2", "2");
    List<String> olist = jedis.mget("test1", "test2");
    for (String s : olist) {
        System.out.println(s);
    }
    jedis.close();  //关闭
}

Jedis连接池示例:

public static void main(String[] args) {
    /*构建连接池配置信息*/
    JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
    /*设置最大连接数*/
    jedisPoolConfig.setMaxTotal(200);
    /*构建连接池*/
    JedisPool jedisPool = new JedisPool(jedisPoolConfig, "192.168.88.110",
        6379);
    /*从池中获取连接*/
    Jedis jedis = jedisPool.getResource();
    /*读取数据*/
    System.out.println(jedis.get("name"));
    /*将连接还回池中*/
    //jedisPool.returnResource(jedis); //被废弃了,重写了close()
    jedis.close();
    jedisPool.close();
}

1.5 Reids分片:集群搭建

1.5.1分片代码示例

/**
 * 集群式连接池配置
 */
public class ShardedJedisPoolDemo {
    public static void main(String[] args) {
        /*构建连接池的配置信息*/
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        /*设置最大连接数*/
        jedisPoolConfig.setMaxTotal(200);
        /*定义集群信息*/
        List<JedisShardInfo> shards = new ArrayList<JedisShardInfo>();
        shards.add(new JedisShardInfo("192.168.88.110", 6379));
        shards.add(new JedisShardInfo("192.168.88.110", 6380));
        shards.add(new JedisShardInfo("192.168.88.110", 6381));
        /*定义集群连接池*/
        ShardedJedisPool shardedJedisPool = new ShardedJedisPool(
            jedisPoolConfig, shards);
        ShardedJedis shardedJedis = null;

        try {
            /*从连接池中获取分片对象*/
            shardedJedis = shardedJedisPool.getResource();
            /*存数据*/
            for (int i = 0; i < 100; i++) {
                shardedJedis.set("name_" + i, "tom_" + i);
            }
            /*从池中获取数据*/
            String value = shardedJedis.get("name_32");
            System.out.println(value);
            value = shardedJedis.get("name_88");
            System.out.println(value);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (null != shardedJedis) {
                /*关闭,检测连接是否有效,有效放回连接池中,无效则重置*/
                shardedJedis.close();
            }
        }
        /*关闭连接池*/
        shardedJedisPool.close();
    }
}

1.5.2 Redis多个节点的透明访问:

在6379上执行:

redis-cli -h 192.168.88.110 -p 6379

192.168.88.110:6379> keys *

 1) "name_53"

 2) "name_7"

 3) "name_99"

 4) "name_87"

 5) "name_18

.........

在6380上执行:

redis-cli -h 192.168.88.110 -p 6379

192.168.88.110:6380> keys *

  1) "name_75"

  2) "name_14"

  3) "name_89"

  4) "name_56"

  5) "name_0"

   ......

1.6  Redis 主从复制

1.6.1  查看全部信息

        

1.6.2  默认是主

        

1.6.3 配置从服务器,挂载到从服务器上

         

 

1.7  哨兵

Sentinel 总结

 

1.7.1 Sentinel的作用:

A、Master 状态监测

B、如果Master 异常,则会进行Master-slave 转换,将其中一个Slave作为Master,将之前的Master作为Slave 

C、Master-Slave切换后,master_redis.conf、slave_redis.conf和sentinel.conf的内容都会发生改变,即master_redis.conf中会多一行slaveof的配置,sentinel.conf的监控目标会随之调换 

 

 

1.7.2 Sentinel的工作方式:

1):每个Sentinel以每秒钟一次的频率向它所知的Master,Slave以及其他 Sentinel 实例发送一个 PING 命令 
2):如果一个实例(instance)距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所指定的值, 则这个实例会被 Sentinel 标记为主观下线。 
3):如果一个Master被标记为主观下线,则正在监视这个Master的所有 Sentinel 要以每秒一次的频率确认Master的确进入了主观下线状态。 
4):当有足够数量的 Sentinel(大于等于配置文件指定的值)在指定的时间范围内确认Master的确进入了主观下线状态, 则Master会被标记为客观下线 
5):在一般情况下, 每个 Sentinel 会以每 10 秒一次的频率向它已知的所有Master,Slave发送 INFO 命令 
6):当Master被 Sentinel 标记为客观下线时,Sentinel 向下线的 Master 的所有 Slave 发送 INFO 命令的频率会从 10 秒一次改为每秒一次 
7):若没有足够数量的 Sentinel 同意 Master 已经下线, Master 的客观下线状态就会被移除。 
若 Master 重新向 Sentinel 的 PING 命令返回有效回复, Master 的主观下线状态就会被移除。

1.7.3 故障转移

一次故障转移操作由以下步骤组成:  

  1. 发现主服务器已经进入客观下线状态。  
  2. 对我们的当前纪元进行自增(详情请参考 Raft leader election ), 并尝试在这个纪元中当选。  
  3. 如果当选失败, 那么在设定的故障迁移超时时间的两倍之后, 重新尝试当选。 如果当选成功, 那么执行以下步骤。  
  4. 选出一个从服务器,并将它升级为主服务器。  
  5. 向被选中的从服务器发送 SLAVEOF NO ONE 命令,让它转变为主服务器。  
  6. 通过发布与订阅功能, 将更新后的配置传播给所有其他 Sentinel , 其他 Sentinel 对它们自己的配置进行更新。  
  7. 向已下线主服务器的从服务器发送 SLAVEOF 命令, 让它们去复制新的主服务器。  
  8. 当所有从服务器都已经开始复制新的主服务器时, 领头 Sentinel 终止这次故障迁移操作。    
  9. 故障转移(failover)的第一步,就是选出新的master,大致的筛选流程为:  
  10. 1. 删除列表中所有处于下线或者断线状态的slave  
  11. 2. 删除列表中所有最近五秒内没有回复过领头sentinel的INFO命令的slave  
  12. 3. 删除所有与已下线主服务器连接断开超过down-after-milliseconds * 10毫秒的slave(确保slave没有过早与master断开,副本比较新)  
  13. 4. 根据slave优先级选择  
  14. 5. 如果优先级相同,选择复制偏移量最大的slave  
  15. 6. 如果都相同,按照run_id排序,选出run_id最小的slave  

 

哨兵监控主从redis,当master节点宕机,sentinel一直监控,如果发现master不能正常工作,sentinel从新选举,从多个从节点中选举出一个节点,把它改成主,其它slave节点,挂接到新的主上。旧的master进行修理,修理好,可以重新加入集群中(动态),连接到新的master,它就变成一个slave。旧的主会自动全量从master上获取数据(如果主的数据量很大,同步过程会稍长)

 

1.7.1 修改端口:

                           

1.7.2 配置监控的主服务器:

    

 

第一行配置指示 Sentinel 去监视一个名为 mymaster 的主服务器, 这个主服务器的 IP 地址为 127.0.0.1 , 端口号为 6381 , 默认是2表示在sentinel集群中只要有两个节点检测到redis主节点出故障就进行切换,单sentinel节点无效(自己测试发现的),改为1,1表示宕机1个节点以后,就开始选举  

 

1.7.3 其他配置使用默认配置,实际有需要再做相应配置,网上可以找到。

1.7.4 启动:redis-sentinel sentinel.conf &

1.7.5 主节点挂掉,从节点自动选举主节点,消息如下:

 

1.7.6  客户端连接需要关闭保护模式(sentienl.conf)

  protected-mode no  

 

1.7.7 哨兵实例:

public class JedisSentinelDemo {
    public static void main(String[] args) {
        Set sentinels = new HashSet();
        sentinels.add(new HostAndPort("192.168.88.120", 26379).toString());
        sentinels.add(new HostAndPort("192.168.88.120", 26380).toString());
        JedisSentinelPool sentinelPool = new JedisSentinelPool("mymaster",
            sentinels);
        System.out.println("Current master: "
            + sentinelPool.getCurrentHostMaster().toString());
        Jedis master = sentinelPool.getResource();
        master.set("username", "wangqiulin");
        //sentinelPool.returnResource(master);
        Jedis master2 = sentinelPool.getResource();
        String value = master2.get("username");
        System.out.println("username: " + value);
        master2.close();
        sentinelPool.close();
        sentinelPool.destroy();
    }

}

1.8 Redis集群官方推荐方案 Redis-Cluster 

Redis3.0版本之后,官方推荐集群方案

1.8.1 redis使用中遇到的瓶颈

  我们日常在对于redis的使用中,经常会遇到一些问题

1、高可用问题,如何保证redis的持续高可用性。

2、容量问题,单实例redis内存无法无限扩充,达到32G后就进入了64位世界,性能下降。

3、并发性能问题,redis号称单实例10万并发,但也是有尽头的。

1.8.2 redis-cluster的优势  

1、官方推荐,毋庸置疑。

2、去中心化,集群最大可增加1000个节点,性能随节点增加而线性扩展。

3、管理方便,后续可自行增加或摘除节点,移动分槽等等。

4、简单,易上手。

1.8.3 redis-cluster名词介绍

1、master  主节点、

2、slave   从节点

3、slot    槽,一共有16384数据分槽,分布在集群的所有主节点中。=

1.8.4 redis-cluster简介

 

图中描述的是六个redis实例构成的集群

6379端口为客户端通讯端口

16379端口为集群总线端口

集群内部划分为16384个数据分槽,分布在三个主redis中。

从redis中没有分槽,不会参与集群投票,也不会帮忙加快读取数据,仅仅作为主机的备份。

三个主节点中平均分布着16384数据分槽的三分之一,每个节点中不会存有有重复数据,仅仅有自己的从机帮忙冗余。

1.8.5 集群部署

测试部署方式,一台测试机多实例启动部署。

(1) 安装redis

$ wget http://download.redis.io/releases/redis-3.2.8.tar.gz

$ tar xzf redis-3.2.8.tar.gz

$ cd redis-3.2.8

$ make

(2) 修改配置文件 redis.conf

port 7000

cluster-enabled yes

cluster-config-file nodes.conf

cluster-node-timeout 5000

appendonly yes

cluster-enabled yes

cluster-config-file /opt/redis/7000/nodes.conf   #多实例情况下需要修改,例如/7000/

cluster-node-timeout 5000

首先, 让我们进入一个新目录, 并创建六个以端口号为名字的子目录, 稍后我们在将每个目录中运行一个 Redis 实例: 命令如下:

mkdir cluster-test

cd cluster-test

mkdir 7000 7001 7002 7003 7004 7005

在文件夹 7000 至 7005 中, 各创建一个 redis.conf 文件, 文件的内容可以使用上面的示例配置文件, 但记得将配置中的端口号从 7000 改为与文件夹名字相同的号码。

(3)  启动六个实例:

/编译安装目录/src/redis-server redis.conf

注意,redis.conf应为6个不同的修改过的多实例配置文件。 

注意,配置文件复制六分后,有许多需要你修改的地方。

(4) 创建redis-cluster

在src下运行集群命令

redis-trib.rb命令与redis-cli命令放置在同一个目录中,可全路径执行或者创建别名。

./redis-trib.rb create --replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005

1.8.6 安装问题

注意:  redis的集群,redis官方提供了redis-trib.rb工具,但是在使用之前 需要安装ruby,以及redis和ruby连接:

yum -y install ruby ruby-devel rubygems rpm-build

gem install redis

其中 gem install redis命令执行时出现了:

 redis requires Ruby version >= 2.2.2的报错,查了资料发现是Centos默认支持ruby到2.0.0,可gem 安装redis需要最低是2.2.2

解决办法是 先安装rvm,再把ruby版本提升至2.3.3

1.安装curl

sudo yum install curl

2. 安装RVM

curl -L get.rvm.io | bash -s stable 

3. 

source /usr/local/rvm/scripts/rvm

4. 查看rvm库中已知的ruby版本

rvm list known

5. 安装一个ruby版本

rvm install 2.3.3

6. 使用一个ruby版本

rvm use 2.3.3

7. 设置默认版本

rvm remove 2.0.0

8. 卸载一个已知版本

ruby --version

9. 再安装redis就可以了

gem install redis

10.在redis/src中编译

./redis-trib.rb create --replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005

11.为了方便,可以写脚本 start-cluster-all.sh

内容:

#!/bin/sh

#启动实例

redis-server cluster/7000/redis.conf &

redis-server cluster/7001/redis.conf &

redis-server cluster/7002/redis.conf &

redis-server cluster/7003/redis.conf &

redis-server cluster/7004/redis.conf &

redis-server cluster/7005/redis.conf &

#创建集群

cd  src

./redis-trib.rb create --replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005

授权 chmod 777 start-cluster-all.sh

12. 运行

 

6个实例,默认配置3主3从,yes完成主从配置。

 

1.8.7 集群命令

1.8.7.创建redis-cluster

./start-all.sh  

1.8.7.1移动槽

redis-trib.rb reshard 127.0.0.1:7000

执行集群reshard操作,通过集群中127.0.0.1:7000这一台机器

[OK] All 16384 slots covered.

How many slots do you want to move (from 1 to 16384)? 2731

输入需要移动的槽数量

What is the receiving node ID? 21c93aa709e10f7a9064faa04539b3ecd

输入接收的节点的ID

How many slots do you want to move (from 1 to 16384)? 2731

What is the receiving node ID? 0abf4ca21c93aa709e10f7a9064faa04539b3ecd

Please enter all the source node IDs.

  Type 'all' to use all the nodes as source nodes for the hash slots.

  Type 'done' once you entered all the source nodes IDs.

Source node #1:0ddb4e430dda8778ac873dd169951c7d71b8235e

Source node #2:done

输入所有被移动的节点ID,确认后输入done

    Moving slot 5460 from 0ddb4e430dda8778ac873dd169951c7d71b8235e

    Moving slot 13653 from 0ddb4e430dda8778ac873dd169951c7d71b8235e

Do you want to proceed with the proposed reshard plan (yes/no)?

检查后输入yes进行移动分槽

至此,分槽移动完毕。

1.8.7.2 删除节点 

redis-trib.rb del-node 127.0.0.1:6360 'f24c0c1ecf629b5413cbca632d389efcad7c8346'

最后跟着的是这个节点的ID,可在redis-cli终端中使用CLUSTER NODES查看

必要条件,此节点所有分槽均已移除。

1.8.7.3 添加master节点

redis-trib.rb add-node 127.0.0.1:6360 127.0.0.1:6350

新节点必须是空的,不能包含任何数据。请把之前aof和dump文件删掉,并且若有nodes.conf也需要删除。

add-node  将一个节点添加到集群里面, 第一个是新节点ip:port, 第二个是任意一个已存在节点ip:port

node:新节点没有包含任何数据, 因为它没有包含任何slot。新加入的加点是一个主节点, 当集群需要将某个从节点升级为新的主节点时, 这个新节点不会被选中,同时新的主节点因为没有包含任何slot,不参加选举和failover。

1.8.7.4 添加一个从节点

前三步操作同添加master一样

第四步:redis-cli连接上新节点shell,输入命令:cluster replicate 对应master的node-id

 

1.8.8 客户端javaDemo

 @Test
public void testJedis() {
    String clusterNodes = "192.168.88.120:7000,192.168.88.120:7001,192.168.88.120:7002,192.168.88.120:7003,192.168.88.120:7004,192.168.88.120:7005";

    String[] nodelist = clusterNodes.split(",");
    Set<HostAndPort> nodes = new HashSet<>();
    for (String ipPort : nodelist) {
        String[] ipPortPair = ipPort.split(":");
        nodes.add(new HostAndPort(ipPortPair[0].trim(),
            Integer.valueOf(ipPortPair[1].trim())));
    }
    JedisCluster jedisCluster = new JedisCluster(nodes);
    jedisCluster.set("test_cluster", "7000");
    Assert.assertEquals("7000", jedisCluster.get("test_cluster"));
    jedisCluster.del("test_cluster");
   
} 

问题1:

通过jedis连接redis单机成功,使用JedisCluster连接redis集群一直报Could not get a resource from the pool,如下图:

断点调试:

 

解决:

   修改 start-cluster-all.sh

./redis-trib.rb create --replicas 1 192.168.88.120:7000 192.168.88.120:7001 192.168.88.120:7002 192.168.88.120:7003 192.168.88.120:7004 192.168.88.120:7005

   删除 各个文件夹下所有nodes文件和dump文件,重启即可。

   (1) 清空数据 redis-cli -c -p 7000   -> flushdb

   (2) rm -rf cluster/700*/nodes*

   (3) rm -rf dump.700*

   (4) ./start-cluster-all.sh

附录一: Redis配置参数表

属性

说明

daemonize no

# 默认值no,该参数用于定制redis服务是否以守护模式运行。

pidfile /var/run/redis.pid

# 默认值/var/run/redis.pid,指定redis服务的进程号文件路径,以守护模式运行时需要配置本参数;

port 6379

# 默认值6379,指定redis服务的端口

tcp-backlog 511

# 在高并发的环境中,为避免慢客户端的连接问题,需要设置一个高速后台日志

timeout 0

设置客户端连接时的超时时间,单位为秒。当客户端在这段时间内没有发出任何指令,那么关闭该连接

# 0是关闭此设置

tcp-keepalive 0

# TCP keepalive

 Linux上,指定值(秒)用于发送 ACKs的时间。注意关闭连接需要双倍的时间。默认为 0

loglevel notice

指定日志记录级别,生产环境推荐 notice

# Redis总共支持四个级别: debugverbosenoticewarning,默认为 verbose

# debug    记录很多信息,用于开发和测试

# varbose  有用的信息,不像 debug会记录那么多

# notice   普通的 verbose,常用于生产环境

# warning  只有非常重要或者严重的信息会记录到日志

logfile ""

配置 log文件地址

默认值为 stdout,标准输出,若后台模式会输出到 /dev/null

databases 16

# 可用数据库数,默认值为 16,默认数据库为 0,数据库范围在 0- database-1)之间

快照

stop-writes-on-bgsave-error yes

保存数据到磁盘,格式如下 :

#  save <seconds> <changes>

指出在多长时间内,有多少次更新操作,就将数据同步到数据文件rdb

相当于条件触发抓取快照,这个可以多个条件配合

比如默认配置文件中的设置,就设置了三个条件

#   save 900 1  900秒内至少有 1 key被改变

#   save 300 10  300秒内至少有 300 key被改变

#   save 60 10000  60秒内至少有 10000 key被改变

#   save 900 1

#   save 300 10

#   save 60 10000

 

stop-writes-on-bgsave-error yes

后台存储错误停止写。

rdbcompression yes

存储至本地数据库时(持久化到 rdb文件)是否压缩数据,默认为 yes

rdbchecksum yes

#  RDB文件的是否直接偶像 chcksum

dbfilename dump.rdb

本地持久化数据库文件名,默认值为 dump.rdb

dir /var/lib/redis-server/

工作目录

数据库镜像备份的文件放置的路径。

这里的路径跟文件名要分开配置是因为 redis在进行备份时,先会将当前数据库的状态写入到一个临时文件中,等备份完成,

再把该该临时文件替换为上面所指定的文件,而这里的临时文件和上面所配置的备份文件都会放在这个指定的路径当中。

# AOF文件也会存放在这个目录下面

注意这里必须制定一个目录而不是文件

slave-serve-stale-data yes

主从复制 .设置该数据库为其他数据库的从数据库 .

设置当本机为 slav服务时,设置 master服务的 IP地址及端口,在 Redis启动时,它会自动从 master进行数据同步

# slaveof <masterip><masterport>

 master服务设置了密码保护时 ( requirepass制定的密码 )

# slave服务连接 master的密码

# masterauth <master-password>

当从库同主机失去连接或者复制正在进行,从机库有两种运行方式:

# 1) 如果 slave-serve-stale-data设置为 yes(默认设置 ),从库会继续响应客户端的请求

# 2) 如果 slave-serve-stale-data是指为 no,出去 INFO SLAVOF命令之外的任何请求都会返回一个

#    错误 "SYNC with master in progress"

slaveread-only yes

配置 slave实例是否接受写。写 slave对存储短暂数据(在同 master数据同步后可以很容易地被删除)是有用的,但未配置的情况下,客户端写可能会发送问题。

 Redis2.6后,默认 slave read-only

repl-disable-tcp-nodelay no

从库会按照一个时间间隔向主库发送 PINGs.可以通过 repl-ping-slave-period设置这个时间间隔,默认是 10

# repl-ping-slave-period 10

# repl-timeout 设置主库批量数据传输时间或者 ping回复时间间隔,默认值是 60

一定要确保 repl-timeout大于 repl-ping-slave-period

# repl-timeout 60

slave socket SYNC后禁用 TCP_NODELAY

如果选择“ yes ,Redis将使用一个较小的数字 TCP数据包和更少的带宽将数据发送到 slave,但是这可能导致数据发送到 slave端会有延迟 ,如果是 Linux kernel的默认配置,会达到 40毫秒 .

如果选择 "no",则发送数据到 slave端的延迟会降低,但将使用更多的带宽用于复制 .

slave-priority 100

如果少于 N slave连接,且延迟时间 <=M秒,则 master可配置停止接受写操作。

例如需要至少 3 slave连接,且延迟 <=10秒的配置:

#  min-slaves-to-write 3

#  min-slaves-max-lag 10

设置 0为禁用

#  默认 min-slaves-to-write 0(禁用), min-slaves-max-lag 10

AOF数据备份

appendonly no

# AOF文件名称  (默认 : "appendonly.aof")

# appendfilename appendonly.aof

# Redis支持三种同步 AOF文件的策略 :

# no: 不进行同步,系统去操作  . Faster.

# always: always表示每次有写操作都进行同步 . Slow, Safest.

# everysec: 表示对写操作进行累积,每秒同步一次 . Compromise.

默认是 "everysec",按照速度和安全折中这是最好的。

如果想让 Redis能更高效的运行,你也可以设置为 "no",让操作系统决定什么时候去执行

或者相反想让数据更安全你也可以设置为 "always"

如果不确定就用  "everysec".

# appendfsync always

appendfsync everysec

# appendfsync no

# AOF策略设置为 always或者 everysec时,后台处理进程 (后台保存或者 AOF日志重写 )会执行大量的 I/O操作

在某些 Linux配置中会阻止过长的 fsync()请求。注意现在没有任何修复,即使 fsync在另外一个线程进行处理

为了减缓这个问题,可以设置下面这个参数 no-appendfsync-on-rewrite

no-appendfsync-on-rewrite no

# AOF 自动重写

 AOF文件增长到一定大小的时候 Redis能够调用  BGREWRITEAOF 对日志文件进行重写

它是这样工作的: Redis会记住上次进行写日志后文件的大小 (如果从开机以来还没进行过重写,那日志大小在开机的时候确定 )

基础大小会同现在的大小进行比较。如果现在的大小比基础大小大制定的百分比,重写功能将启动

同时需要指定一个最小大小用于 AOF重写,这个用于阻止即使文件很小但是增长幅度很大也去重写 AOF文件的情况

设置  percentage 0就关闭这个特性

auto-aof-rewrite-percentage 100

auto-aof-rewrite-min-size 64mb

aof-rewrite-incremental-fsync yes

当一个子节点重写 AOF文件时,如果启用下面的选项,则文件每生成 32M数据进行同步。

Lua脚本

lua-time-limit 5000

# 一个 Lua脚本最长的执行时间为 5000毫秒( 5秒),如果为 0或负数表示无限执行时间。

Log日志

slowlog-log-slower-than 10000

# Redis Slow Log 记录超过特定执行时间的命令。执行时间不包括 I/O计算比如连接客户端,返回结果等,只是命令执行时间

可以通过两个参数设置 slow log:一个是告诉 Redis执行超过多少时间被记录的参数 slowlog-log-slower-than(微妙 )

另一个是 slow log的长度。当一个新命令被记录的时候最早的命令将被从队列中移除

下面的时间以微妙为单位,因此 1000000代表一秒。

注意指定一个负数将关闭慢日志,而设置为 0将强制每个命令都会记录

slowlog-max-len 128

对日志长度没有限制,只是要注意它会消耗内存

可以通过  SLOWLOG RESET回收被慢日志消耗的内存

推荐使用默认值 128,当慢日志超过 128时,最先进入队列的记录会被踢出

事件通知

notify-keyspace-events ""

当事件发生时, Redis可以通知 Pub/Sub客户端。

可以在下表中选择 Redis要通知的事件类型。事件类型由单个字符来标识:

# K     Keyspace事件,以 _keyspace@<db>_的前缀方式发布

# E     Keyevent事件,以 _keysevent@<db>_的前缀方式发布

# g    通用事件(不指定类型),像 DEL, EXPIRE, RENAME,

# $     String命令

# s     Set命令

# h     Hash命令

# z    有序集合命令

# x    过期事件(每次 key过期时生成)

# e    清除事件(当 key在内存被清除时生成)

# A     g$lshzxe的别称,因此”AKE”意味着所有的事件

# notify-keyspace-events带一个由 0到多个字符组成的字符串参数。空字符串意思是通知被禁用。

例子:启用 list和通用事件:

# notify-keyspace-events Elg

默认所用的通知被禁用,因为用户通常不需要改特性,并且该特性会有性能损耗。

注意如果你不指定至少 K E之一,不会发送任何事件。

高级配置

 

hash-max-zipmap-entries 512

 

hash-max-zipmap-value 64 

 hash中包含超过指定元素个数并且最大的元素没有超过临界时,

# hash将以一种特殊的编码方式(大大减少内存使用)来存储,这里可以设置这两个临界值

# Redis Hash对应 Value内部实际就是一个 HashMap,实际这里会有 2种不同实现,

这个 Hash的成员比较少时 Redis为了节省内存会采用类似一维数组的方式来紧凑存储,而不会采用真正的 HashMap结构,对应的 valueredisObject encoding zipmap,

当成员数量增大时会自动转成真正的 HashMap,此时 encoding ht

list-max-ziplist-entries 512

list-max-ziplist-value 64

 Hash一样,多个小的 list以特定的方式编码来节省空间。

#  list数据类型节点值大小小于多少字节会采用紧凑存储格式。

set-max-intset-entries 512

# set数据类型内部数据如果全部是数值型,且包含多少节点以下会采用紧凑格式存储。

zset-max-ziplist-entries 128

zset-max-ziplist-value 64

 hashe list一样 ,排序的 set在指定的长度内以指定编码方式存储以节省空间

#  zsort数据类型节点值大小小于多少字节会采用紧凑存储格式。

activerehashing yes

# Redis将在每 100毫秒时使用 1毫秒的 CPU时间来对 redis hash表进行重新 hash,可以降低内存的使用

当你的使用场景中,有非常严格的实时性需要,不能够接受 Redis时不时的对请求有 2毫秒的延迟的话,把这项配置为 no

如果没有这么严格的实时性要求,可以设置为 yes,以便能够尽可能快的释放内存。

client-output-buffer-limit normal 0 0 0

client-output-buffer-limit slave 256mb 64mb60

client-output-buffer-limit pubsub 32mb 8mb60

# 客户端的输出缓冲区的限制,因为某种原因客户端从服务器读取数据的速度不够快,

# 可用于强制断开连接(一个常见的原因是一个发布 /订阅客户端消费消息的速度无法赶上生产它们的速度)。

可以三种不同客户端的方式进行设置:

# normal -> 正常客户端

# slave  -> slave MONITOR客户端

# pubsub -> 至少订阅了一个 pubsub channel pattern的客户端

每个 client-output-buffer-limit语法 :

# client-output-buffer-limit <class><hard limit> <soft limit> <soft seconds>

一旦达到硬限制客户端会立即断开,或者达到软限制并保持达成的指定秒数(连续)。

例如,如果硬限制为 32兆字节和软限制为 16兆字节 /10秒,客户端将会立即断开

如果输出缓冲区的大小达到 32兆字节,客户端达到 16兆字节和连续超过了限制 10秒,也将断开连接。

默认 normal客户端不做限制,因为他们在一个请求后未要求时(以推的方式)不接收数据,

只有异步客户端可能会出现请求数据的速度比它可以读取的速度快的场景。

把硬限制和软限制都设置为 0来禁用该特性

hz 10

# Redis调用内部函数来执行许多后台任务,如关闭客户端超时的连接,清除过期的 Key,等等。

不是所有的任务都以相同的频率执行,但 Redis依照指定的“Hz”值来执行检查任务。

默认情况下,“ Hz”的被设定为 10

提高该值将在 Redis空闲时使用更多的 CPU时,但同时当有多个 key同时到期会使 Redis的反应更灵敏,以及超时可以更精确地处理。

范围是 1 500之间,但是值超过 100通常不是一个好主意。

大多数用户应该使用 10这个预设值,只有在非常低的延迟的情况下有必要提高最大到 100

附录二: Redis命令

1. 对value操作的命令

exists(key):确认一个key是否存在

del(key):删除一个key

type(key):返回值的类型

keys(pattern):返回满足给定pattern的所有key

randomkey:随机返回key空间的一个key

rename(oldname, newname):将key由oldname重命名为newname,若newname存在则删除newname表示的key

dbsize:返回当前数据库中key的数目

expire:设定一个key的活动时间(s)

ttl:获得一个key的活动时间

select(index):按索引查询

move(key, dbindex):将当前数据库中的key转移到有dbindex索引的数据库

flushdb:删除当前选择数据库中的所有key

flushall:删除所有数据库中的所有key

2、对String操作的命令

set(key, value):给数据库中名称为key的string赋予值value

get(key):返回数据库中名称为key的string的value

getset(key, value):给名称为key的string赋予上一次的value

mget(key1, key2,…, key N):返回库中多个string(它们的名称为key1,key2…)的value

setnx(key, value):如果不存在名称为key的string,则向库中添加string,名称为key,值为value

setex(key, time, value):向库中添加string(名称为key,值为value)同时,设定过期时间time

mset(key1, value1, key2, value2,…key N, value N):同时给多个string赋值,名称为key i的string赋值value i

msetnx(key1, value1, key2, value2,…key N, value N):如果所有名称为key i的string都不存在,则向库中添加string,名称key i赋值为value i

incr(key):名称为key的string增1操作

incrby(key, integer):名称为key的string增加integer

decr(key):名称为key的string减1操作

decrby(key, integer):名称为key的string减少integer

append(key, value):名称为key的string的值附加value

substr(key, start, end):返回名称为key的string的value的子串

3、对List操作的命令

rpush(key, value):在名称为key的list尾添加一个值为value的元素

lpush(key, value):在名称为key的list头添加一个值为value的 元素

llen(key):返回名称为key的list的长度

lrange(key, start, end):返回名称为key的list中start至end之间的元素(下标从0开始,下同)

ltrim(key, start, end):截取名称为key的list,保留start至end之间的元素

lindex(key, index):返回名称为key的list中index位置的元素

lset(key, index, value):给名称为key的list中index位置的元素赋值为value

lrem(key, count, value):删除count个名称为key的list中值为value的元素。count为0,删除所有值为value的元素,count>0从头至尾删除count个值为value的元素,count<0从尾到头删除|count|个值为value的元素。 lpop(key):返回并删除名称为key的list中的首元素 rpop(key):返回并删除名称为key的list中的尾元素 blpop(key1, key2,… key N, timeout):lpop命令的block版本。即当timeout为0时,若遇到名称为key i的list不存在或该list为空,则命令结束。如果timeout>0,则遇到上述情况时,等待timeout秒,如果问题没有解决,则对keyi+1开始的list执行pop操作。

brpop(key1, key2,… key N, timeout):rpop的block版本。参考上一命令。

rpoplpush(srckey, dstkey):返回并删除名称为srckey的list的尾元素,并将该元素添加到名称为dstkey的list的头部

4、对Set操作的命令

sadd(key, member):向名称为key的set中添加元素member

srem(key, member) :删除名称为key的set中的元素member

spop(key) :随机返回并删除名称为key的set中一个元素

smove(srckey, dstkey, member) :将member元素从名称为srckey的集合移到名称为dstkey的集合

scard(key) :返回名称为key的set的基数

sismember(key, member) :测试member是否是名称为key的set的元素

sinter(key1, key2,…key N) :求交集

sinterstore(dstkey, key1, key2,…key N) :求交集并将交集保存到dstkey的集合

sunion(key1, key2,…key N) :求并集

sunionstore(dstkey, key1, key2,…key N) :求并集并将并集保存到dstkey的集合

sdiff(key1, key2,…key N) :求差集

sdiffstore(dstkey, key1, key2,…key N) :求差集并将差集保存到dstkey的集合

smembers(key) :返回名称为key的set的所有元素

srandmember(key) :随机返回名称为key的set的一个元素

5、对zset(sorted set)操作的命令

zadd(key, score, member):向名称为key的zset中添加元素member,score用于排序。如果该元素已经存在,则根据score更新该元素的顺序。

zrem(key, member) :删除名称为key的zset中的元素member

zincrby(key, increment, member) :如果在名称为key的zset中已经存在元素member,则该元素的score增加increment;否则向集合中添加该元素,其score的值为increment

zrank(key, member) :返回名称为key的zset(元素已按score从小到大排序)中member元素的rank(即index,从0开始),若没有member元素,返回“nil”

zrevrank(key, member) :返回名称为key的zset(元素已按score从大到小排序)中member元素的rank(即index,从0开始),若没有member元素,返回“nil”

zrange(key, start, end):返回名称为key的zset(元素已按score从小到大排序)中的index从start到end的所有元素

zrevrange(key, start, end):返回名称为key的zset(元素已按score从大到小排序)中的index从start到end的所有元素

zrangebyscore(key, min, max):返回名称为key的zset中score >= min且score <= max的所有元素 zcard(key):返回名称为key的zset的基数 zscore(key, element):返回名称为key的zset中元素element的score zremrangebyrank(key, min, max):删除名称为key的zset中rank >= min且rank <= max的所有元素 zremrangebyscore(key, min, max) :删除名称为key的zset中score >= min且score <= max的所有元素

zunionstore / zinterstore(dstkeyN, key1,…,keyN, WEIGHTS w1,…wN, AGGREGATE SUM|MIN|MAX):对N个zset求并集和交集,并将最后的集合保存在dstkeyN中。对于集合中每一个元素的score,在进行AGGREGATE运算前,都要乘以对于的WEIGHT参数。如果没有提供WEIGHT,默认为1。默认的AGGREGATE是SUM,即结果集合中元素的score是所有集合对应元素进行SUM运算的值,而MIN和MAX是指,结果集合中元素的score是所有集合对应元素中最小值和最大值。

6、对Hash操作的命令

hset(key, field, value):向名称为key的hash中添加元素field<—>value

hget(key, field):返回名称为key的hash中field对应的value

hmget(key, field1, …,field N):返回名称为key的hash中field i对应的value

hmset(key, field1, value1,…,field N, value N):向名称为key的hash中添加元素field i<—>value i

hincrby(key, field, integer):将名称为key的hash中field的value增加integer

hexists(key, field):名称为key的hash中是否存在键为field的域

hdel(key, field):删除名称为key的hash中键为field的域

hlen(key):返回名称为key的hash中元素个数

hkeys(key):返回名称为key的hash中所有键

hvals(key):返回名称为key的hash中所有键对应的value

hgetall(key):返回名称为key的hash中所有的键(field)及其对应的value

附录三:集群客户端命令(redis-cli -c -p port)

集群
cluster info :打印集群的信息
cluster nodes :列出集群当前已知的所有节点( node),以及这些节点的相关信息。
节点
cluster meet <ip> <port> :将 ip 和 port 所指定的节点添加到集群当中,让它成为集群的一份子。
cluster forget <node_id> :从集群中移除 node_id 指定的节点。
cluster replicate <node_id> :将当前节点设置为 node_id 指定的节点的从节点。
cluster saveconfig :将节点的配置文件保存到硬盘里面。
槽(slot)
cluster addslots <slot> [slot ...] :将一个或多个槽( slot)指派( assign)给当前节点。
cluster delslots <slot> [slot ...] :移除一个或多个槽对当前节点的指派。
cluster flushslots :移除指派给当前节点的所有槽,让当前节点变成一个没有指派任何槽的节点。
cluster setslot <slot> node <node_id> :将槽 slot 指派给 node_id 指定的节点,如果槽已经指派给另一个节点,那么先让另一个节点删除该槽>,然后再进行指派。
cluster setslot <slot> migrating <node_id> :将本节点的槽 slot 迁移到 node_id 指定的节点中。
cluster setslot <slot> importing <node_id> :从 node_id 指定的节点中导入槽 slot 到本节点。
cluster setslot <slot> stable :取消对槽 slot 的导入( import)或者迁移( migrate)。

cluster keyslot <key> :计算键 key 应该被放置在哪个槽上。
cluster countkeysinslot <slot> :返回槽 slot 目前包含的键值对数量。
cluster getkeysinslot <slot> <count> :返回 count 个 slot 槽中的键  

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章