Redis NoSQL数据库(version 3.0)

  • NOSQL类型简介

    • 键值对:会使用到一个哈希表,表中有一个特定的键和一个指针指向特定的数据,如redis,voldemort,oracle bdb
    • 列存储数据库,应对分布式存储的海量数据,键仍然在,但是指向了多个列,如HBase,Riak
    • 文档型数据库:数据模型是版本化的文档,半结构化的文档以特定的格式存储,如json,文档型数据库可以看成是键值型数据的升级版,允许之间嵌套键值,而且文档型数据库比键值数据库的查询效率更高,如CouchDB,MongoDb
    • 图形数据库,使用灵活的图形模型,并且能扩展到多个服务器上,Neo4J,InfoGrid,InfiniteGraph
  • NOSQL特点

    • 数据模型简单
    • 性能较高
    • 不需要高度的数据一致性
  • 优缺点

    • 优点
      • 对数据的高并发读写
      • 对海量数据的高效率存储和访问
      • 对数据的高扩展性和高可用性
    • 缺点
      • redis的acid关系非常简单,无法做到太复杂的关系数据库模型
  • 可扩展性和可用性

    • 可扩展性
      • 垂直扩展(容量不够了加内存)
      • 水平扩展(容量不够了往集群里加机器)
    • 可用性
      • 单节点挂了,节点之间迅速切换
    • 可靠性
      • 只要刷盘了,数据不丢失
  • redis以key-value形式存储,data structure service 数据结构服务器,支持各种不同方式的排序,数据都是缓存在内存中,它也可以周期性的将更新的数据写入到磁盘或者把修改操作写入追加到文件。redis的数据持久化主要是rdb和aof

    • rdb,周期性的将数据刷入到磁盘(默认开启rdb)
    • aof,将更改操作写入到日志文件,相当于数据库的undo日志,开aof,多线程并发的去访问redis集群,redis的写的性能大大降低,怎么解决呢?
      • 1.多几个主节点,分担写压力
      • 2.使用ssdb(写性能高)写,用redis读,技术的合并
  • redis的三种集群方式

    • 主从模式
      • 主节点可写,其他节点均高并发可读,如果主节点挂了,那么整个redis服务不可用,主从节点数据完全一致
    • 哨兵模式
      • 主从模式上另加一个哨兵进行监控,如果主节点挂了,哨兵服务会对从节点之间进行选举出一个主节点 实现高可用,自动切换主从,如果主节点再次加入进来,成为一个从节点。也就是说任意时间内,只有一个主节点,主从节点数据完全一致
    • 集群模式
      • 多主节点,并对数据进行分布式存储,主从节点数据不一样
  • reids和memcache

    • redis多实例化是串行化执行,多实例化性能比较高,群狼战猛虎
    • memcache多实例是并行化执行,单节点性能比较高
  • 简单安装

    • 编译安装make && make install(请先安装gcc,如果出现jemalloc/jemalloc.h: No such file or directory,请使用make MALLOC=libc && make install)
    • mkdir -p /usr/local/redis/etc
    • mkdir -p /usr/local/redis/bin
    • cp redis源码目录/redis.conf /usr/localredis/etc
    • cp redis源码目录/src mkreleasehdr.sh redis-cli redis-server /usr/local/redis/bin
    • 修改/usr/local/reids/etc/redis.conf里 daemonize改为 yes
    • 启动 /usr/local/redis/bin/redis-server /usr/local/reids/etc/redis.conf
    • netstat -tunpl | grep 6379
    • 停止redis:/usr/local/redis/bin/redis-cli shutdown 或者pkill redis-server,或者直接kill redis 进程号
    • 只要dump.rdb文件不删,关闭操作之前的数据还存在
  • 基础数据类型

    • String
      • 键和值都是字符串
      • set key value 不用加双引号
      • get key 获取值
      • 多次设置同key的value会覆盖
      • setnx key value 不存在则设置值
      • del key 删除键值
      • setex key 有效期时间(单位:秒) value,键值有效期之后自动失效
      • setrange key 第几个位置开始替换(索引从0开始) 替换字符串,从索引位开始替换成替换字符串长度的替换字符串
      • mset key1 key1value key2 keyn valuen 多次 设置值
      • mget key1 key2 keyn 多次获取值
      • getset key value 返回key的旧值并将该key设置为新值
      • incr | decr key 对一个值进行自增和递减
      • incrby | decrby key 步长 对一个值进行步长自增和递减
      • append key val 给key的value追加val的字符串
      • strlen key 返回key对于的字符串长度
    • Hash
      • 非常常用适合存储对象,将一个对象类型存储在hash要比存储在string类型里占用更小的内存空间
      • hset hash_name key value 存一个键值对到名为hash_name的Hash里
      • hget hash_name key 从hash_name的hash里取key的value
      • hmget | hmset hash_name key1 key1value key2 keyn valuen 多次 获取或设置值
      • hsetnx hash_name key val 不存在则设置为val值
      • hincrby | hdecrby hash_name 步长 集合的步长递增和递减
      • hexists hash_name key 集合里是否存在key,不存在返回0
      • hlen hash_name 集合里的所有键的数量
      • hdel hash_name key 删除名称为hash_name 的hash里的key对应的键值
      • hkeys hash_name 获取hash里的所有key
      • hvals hash_name 获取hash里的所有value
      • hgetall hash_name 获取hash里的所有key,value
    • List
      • 链表结构,双端链表,既可以成为栈,也可以成为队列,元素可以重复
      • lpush 从头部加入元素,先进后出,lpush list_name value
      • rpush 从尾部加入元素,先进先出,rpush list_name value
      • Irange list_name 0 -1 到名为list_name的list里从0开始,取出所有元素,-1为取出所有,即到直到没有元素位置
      • linsert list_name before "value" "insert_value" 在value值之前插入insert_value
      • lset list_name 下标 "value" 将指定下标的值替换为value
      • lrem list_name 删除个数 "value" 从指定下标开始,删除n个 值为value的元素
      • ltrim list_name 下标 上标 保留从下标到上标的元素
      • lpop list_name 从list的头部删除元素,并返回删除元素
      • rpop list_name 从list的尾部删除元素,并返回删除元素
      • rpoplpush list_name_1 list_name_2 value 先从list_name_1中移除元素,再往list_name_2中的头部添加元素
      • lindex list_name index 返回index处的元素、
      • llen list_name 返回元素的个数
    • Set
      • 元素不能重复,string类型的无序集合,通过hashtable实现,集合我们可以取交集并集和差集
      • sadd set_name value 向set_name的set中添加value元素
      • srem set_name value 移除set_name中的value元素
      • spop set_name 移除并返回集合中的一个随机元素
      • smembers set_name 查看set里的所有元素
      • sdiff set_name1 set_name2 取俩个集合的差集,那个集合在前面就以那个为标准
      • sdiffstore set_name3 set_name1 set_name2 取set1和set2的差集并存储到set3
      • sinter key1 [key2] 返回给定所有集合的交集
      • sinterstore set_name3 set_name1 set_name2 取set1和set2的交集并存储到set3
      • sunion key1 [key2] 返回给定所有集合的并集
      • sunionstore set_name3 set_name1 set_name2 取set1和set2的并集并存储到set3
      • smove set_name1 set_name2 value 将set_name1中的元素value移动到set_name2中
      • scard set_name 查看集合的元素个数
      • sismember set_name value 查看value 是否在set中
      • srandmember set_name 随机返回一个set中的元素
    • ZSet
      • 有序的集合,
      • zadd zset_name n value 向zset中的索引n中添加元素(value)
      • zrange zset_name 0 -1 withscores 列出所有元素,索引从0开始到-1(所有),并显示索引
      • zrem set_name value 删除zset中的元素value
      • zincrby set_name 步长,以指定步长去自动递增或递减
      • zrangebyscore set_name (1 5 返回所有符合条件 1 < score <= 5 的成员
      • zremrangebyrank key start stop 移除有序集key中,指定排名(rank)区间内的所有成员。下标参数start和stop都以0为底,0处是分数最小的那个元素。这些索引也可是负数,表示位移从最高分处开始数。例如,-1是分数最高的元素,-2是分数第二高的,依次类推。
      • zremrangebyscore set_name (start stop 删除所有符合条件 start< score <= stop 的成员
      • zrank set_name value 如果成员在有序集合存在,返回整数:成员的权重。如果成员在有序集合不存在或键不存在,字符串返回nil。
      • zrevrank set_name value 返回有序集key中成员member的排名,其中有序集成员按score值从大到小排列。排名以0为底,也就是说,score值最大的成员排名为0。
        使用ZRANK命令可以获得成员按score值递增(从小到大)排列的排名(顺序)。
      • zcard set_name 返回集合里所有元素的个数
      • zcount set_name (1 5 返回所有符合条件 1 < score <= 5 的成员个数
  • redis高级命令

    • 所有的键: keys * 支持模糊查询
    • 是否存在指定键 exists key
    • expire key time_out 设置某个key的过期时间,单位为秒,使用ttl key查看剩余时间,-2代表过期
    • persist key 取消过期时间,执行之后再执行ttl返回-1
    • select 选择数据库,数据库为0-15(默认共16个库),默认进入0库,早期16个库是为了安全,可以使用8个库用作备份,看你怎么拆分,或者不同的数据类型放到不同的数据库,现在已经不考虑,redis已经有集群实现
      +move [key] [数据库下标] 移动数据到其他库
    • randomkey随机返回数据库里的一个key
    • rename key newkey 重命名key
    • echo 打印命令
    • dbsize 查看数据库的key数量
    • info 获取数据库信息
    • config get key 实时传储收到的请求,返回相关的配置信息,
    • config get * 返回所有配置
    • flushdb 清空当前数据库,
    • flushall 清空所有数据库
  • 安全性
    requirepass password 设置密码后能登陆redis,但是访问不了任何数据,登陆redis后如果要使用密码,使用auth password,才能正常操作数据,或者使用redis-cli加上参数-a password 登陆

  • redis主从复制

    • 概念
      • 一个Master可以拥有多个slave
      • 多个slave可以连接同一个master,还可以连接其他slave,子节点的子节点
      • 主从复制不会阻塞master,在同步数据时,master可以继续处理client请求
      • 提供系统的伸缩性
    • 主从复制过程
      • slave 与master建立连接之后,发送sync同步命令
      • master会开启一个后台进程,将数据库快照保存到文件中,同时master主进程会开始收集新的写命令并缓存
      • 后台完成保存后,将文件发送给slave
      • slave将文件保存到磁盘上
    • 主从复制配置
      • 如果机器架构一致,可以clone master上的redis
      • 修改从服务器的redis配置文件/usr/local/redis/etc/redis.conf
        • slaveof <masterip> <mastport>
        • 如果主服务器有密码:masterauth <master-password>
      • 启动master和slave
      • 使用info查看role角色即可知道谁是主服务或从服务
      • slave是不能执行写操作的(set 操作),他是readonly的,slave的数据和master一致,在应用中,你只要创建一个master redis连接,写在master,读操作会自动负载到从节点
      • 主节点挂了,整个集群不可用
  • redis 哨兵模式

    • 功能有俩点
      • 监控主数据库和从数据库是否正常运行
      • 主数据库出现故障时,自动选举一个从数据库为主数据库,实现自动切换
      • 实现高可用性,没有单点问题,挂了就挂了,可以自动切换
    • 实现步骤
      • copy redis源码中的sentinel.conf 到一台从数据库服务器的/usr/local/redis/etc中
      • 修改sentinel.conf
        • sentinel monitor master_name ip port n 设置master的名称,ip,端口,投票选举次数,n票通过之后选举为主节点
        • sentinel down-after-milliseconds master_name 5000 默认是1s检测一次,这里配置超时5000ms为宕机
        • sentinel failover-timeout master_name 900000
        • sentinel parallel-syncs master_name n 从节点数量
        • sentinel can-failover master_name yes
      • 启动sentinel哨兵 /usr/local/redis/bin/redis-server /usr/local/redis/etc/sentinel.conf --sentinel &
      • 查看哨兵相关信息 /usr/local/redis/bin/redis-cli -h sentinel_ip -p sentinel_port info Sentinel
      • 哨兵服务可以放到主或从中,或者一台单独的机器,或者多个机器,避免单点故障
      • 可以通过redis-cli shutdown将主节点down掉,再查看哨兵相关信息,可以查看到主节点已近切换了
      • 将down掉的主节点重新启动,连接redis-cli,执行info命令,可以看到角色已经变成了slave
  • redis的简单事务 (一般不使用)

    • 使用multi 命令打开事务
    • 执行crud操作
    • exec命令执行,存储到redis
    • discard 命令回滚
    • 注意reids事务里的操作如果出错了,并不会自动回滚
  • 持久化机制

    • 默认是快照方式
      • 将内存中的数据以快照的方式写入到二进制文件中,默认为dump.rdb,可以通过配置设置自动做快照持久化的方式,我们可以配置redis在n秒内如果超过m个key被修改就自动做快照
        • 快照设置
        • save 900 1 900秒内如果有超过1个key被修改,则发起快照保存
        • save 300 10 300秒内如果有超过10个key被修改,则发起快照保存
    • append-only file (aof)
      • 由于快照方式是在一定时间间隔之后做一次,所以有可能redis意外down掉之后,有可能会丢失一部分数据,aof方式有点像oracle 数据库的undo日志,aof比快照方式有更好的持久化性,在使用aof的时候,redis会将每一次写操作(除了查询,其他有更改数据的操作)都通过write函数追加到命令中,当redis重新启动的时候会重新执行aof文件中的写命令重建数据库内容,appendonly.aof,aof并不是立即写在硬盘上,可以通过配置文件修改强制写到硬盘中
      • aof设置(生产环境推荐使用)
        • appendonly yes //启动aof持久化方式有三种方式
        • # appendfsync always//收到写命令就立即写入磁盘,效率最慢,但是保证完全的持久化(生产使用)
        • # appendfsync everysec //每秒钟写入磁盘一次
        • # appendfsync no //完全依赖os,性能最好,持久化没保证
  • redis 发布与订阅信息

    • redis提供了简单的发布订阅功能
    • 使用subscribe [频道] 进行订阅监听
    • 使用publish [频道] [发布内容] 进行发布消息广播
  • redis与java的使用

    • 在jedis的jar中,有Jedis对象,
    • Jedis对象
          import java.util.HashMap;
          import java.util.Iterator;
          import java.util.List;
          import java.util.Map;
          
          import org.junit.Test;
          
          import redis.clients.jedis.Jedis;
          
          public class testRedis {
          
          private static Jedis jedis = new Jedis("192.168.1.101",6379);
          
          /**
           * @param args
           */
          @Test
          public void test() {
              // TODO Auto-generated method stub
          //      jedis.set("sex","man");
          //      System.out.println(jedis);
          //      
          //      List<String> list = jedis.mget("name","age","sex");
          //        for (Iterator iterator = list.iterator(); iterator.hasNext();) {
          //          String string = (String) iterator.next();
          //          System.out.println(string);
          //      }
          //        
          //        Map<String, String> user = new HashMap<String, String>();
          //        user.put("name","huangyuxuan");
          //        user.put("age", "0.5");
          //        user.put("sex","男");
          //        jedis.hmset("user",user);
          
              //
          //        List<String> rsmap = jedis.hmget("user", "name", "age","sex");
          //        System.out.println(rsmap);  
              //
          //        jedis.hdel("user","age");
          //        System.out.println(jedis.hmget("user", "age")); //因为删除了,所以返回的是null  
          //        System.out.println(jedis.hlen("user")); //返回key为user的键中存放的值的个数2 
          //        System.out.println(jedis.exists("user"));//是否存在key为user的记录 返回true  
          //        System.out.println(jedis.hkeys("user"));//返回map对象中的所有key  
          //        System.out.println(jedis.hvals("user"));//返回map对象中的所有value 
              //
              //testStr();
              //testList();
              testSet();
          
          
          //        Iterator<String> iter=jedis.hkeys("user").iterator();  
          //        while (iter.hasNext()){  
          //            String key = iter.next();  
          //            System.out.println(key+":"+jedis.hmget("user",key));  
          //        }  
          }
          
          public static void testStr(){
              //-----添加数据----------  
              jedis.set("name","bhz");//向key-->name中放入了value-->xinxin  
              System.out.println(jedis.get("name"));//执行结果:xinxin  
          
              jedis.append("name", " is my lover"); //拼接
              System.out.println(jedis.get("name"));
          
              jedis.del("name");  //删除某个键
              System.out.println(jedis.get("name"));
              //设置多个键值对
              jedis.mset("name","bhz","age","27","qq","174754613");
              jedis.incr("age"); //进行加1操作
              System.out.println(jedis.get("name") + "-" + jedis.get("age") + "-" + jedis.get("qq"));
          
          }
          
          public static void testList(){
              //开始前,先移除所有的内容  
              jedis.del("java framework");
              System.out.println(jedis.lrange("java framework",0,-1));
              //先向key java framework中存放三条数据  
              jedis.lpush("java framework","spring");
              jedis.lpush("java framework","struts");
              jedis.lpush("java framework","hibernate");
              //再取出所有数据jedis.lrange是按范围取出,  
              // 第一个是key,第二个是起始位置,第三个是结束位置,jedis.llen获取长度 -1表示取得所有  
              System.out.println(jedis.lrange("java framework",0,-1));
          
              jedis.del("java framework");
              jedis.rpush("java framework","spring");
              jedis.rpush("java framework","struts");
              jedis.rpush("java framework","hibernate");
              System.out.println(jedis.lrange("java framework",0,-1));
          }
          
          
          public static void testSet(){
              //添加  
              jedis.sadd("user1","liuling");
              jedis.sadd("user1","xinxin");
              jedis.sadd("user1","ling");
              jedis.sadd("user1","zhangxinxin");
              jedis.sadd("user1","who");
              //移除noname  
              jedis.srem("user1","who");
              System.out.println(jedis.smembers("user1"));//获取所有加入的value  
              System.out.println(jedis.sismember("user1", "who"));//判断 who 是否是user集合的元素  
              System.out.println(jedis.srandmember("user1"));
              System.out.println(jedis.scard("user1"));//返回集合的元素个数  
          }
          
          }
      
  • redis 集群搭建(哨兵模式的问题是在选举程序执行时,redis不可写)

    • redis3.0开始支持集群容错功能,集群至少要三个master,3个slave
    • 此处是同一台机器开6个redis,模拟集群
    • 创建文件夹:mkdir -p /usr/local/redis-cluster
    • cd /usr/local/redis-cluster
    • mkdir 7001,mkdir 7002,mkdir 7003,mkdir 7004,mkdir 7005,mkdir 7006,
    • 拷贝redis配置文件到7001到7006文件夹,修改配置:
      • daemonize yes
      • port 700*
      • bind 当前机器ip
      • dir /usr/local/redis-cluster/700* 必须指定,分布式的数据每台机器存的数据都不一样的
      • cluster-enabled yes
      • cluster-config-file nodes-700*.conf
      • cluster-node-timeout 5000
      • appendonly yes
    • 由于redis集群需要使用ruby命令,所以要安装ruby,yum install ruby
    • yum install rubygems
    • gem install redis 安装redis和ruby的接口
    • 启动redis实例,/usr/local/redis/bin/redis-server /usr/local/redis-cluster/700*/redis.conf
    • ps -ef | grep redis 看6个redis是否启动成功
    • 切换到redis源码目录,拷贝redis源码目录下的redis-trib.rb到/usr/local/redis/bin/,cp redis-trib.rb /usr/local/redis/bin/
    • /usr/local/redis/bin/redis-trib.rb create --replicas 1 ip:7001 ip:7002 ip:7003 ip:7004 ip:7005 ip:7006
    • redis-trib.rb的更多信息请执行/usr/local/redis/bin/redis-trib.rb --help ,--replicas参数后面跟的1是指主节点数/从节点数的比值,比如6个master,12个slave,这个值就应该是0.5,假设有m个节点,比值为k,a为master的个数,b为slave的个数,即a/b = k, a+b= m,所以a=bk,bk+b=m,(k+1)b=m,所以b=m/(k+1),a=m-b,则命令行参数中的前a个为master,后m-a个为slave,slave依据比值,比如0.5,那么就先给第一个master分配俩台slave,剩余的分配给下面的master,集群中每个master都有slots(槽),slave没有,说明不可写
    • 至此集群环境已经搭建好了,如何验证?连接任意一客户端:/usr/local/redis/bin/redis-cli -c -h ip -p port (-c 代表集群模式,指定ip和端口),验证命令:cluster info (查看集群信息) cluster nodes(查看节点列表)
    • 数据操作验证,往redis集群中的一个节点放一条数据,数据放的地方不一定redis-cli是登陆的机器,具体存放在哪,在你set的时候,会有信息提示被定向到哪了,读数据会自动定向到所在的节点,但是你在执行flushall的时候要去每个主节点执行该命令,集群中所有的数据才会删除
    • 关闭集群需要逐个进行关闭,使用命令:/usr/local/redis/bin/redis-cli -c -h ip -p port shutdown ,如果要重新启动集群,将redis逐个启动就好
    • 如果出现集群无法启动时,删除cluster-config-file文件(集群配置文件),注意redis.conf,.rdb,.aof不能删,再次重新启动每一个redis 服务,重新构建集群环境
    • 更多参考redis-trib.rb,推荐博客
  • redis-trib 命令详解

    • /usr/local/redis/bin/redis-trib.rb create --replicas 1 ip:port ip:port ... 命令会创建集群信息,并将集群信息存储到cluster-config-file
    • 关闭集群需要逐个进行关闭,使用命令:/usr/local/redis/bin/redis-cli -c -h ip -p port shutdown ,如果要重新启动集群,将redis逐个启动就好
    • 查看集群节点信息:/usr/local/redis/bin/redis-cli cluster nodes
    • 查看集群信息:/usr/local/redis/bin/redis-cli cluster info
    • redis-trib 添加节点
      • 我们新建俩个服务,按照之前搭建的集群方式新增俩个节点:(一主一从 master、slave) Master:7007,Slave:7008
      • cd /usr/local/redis-cluster
      • mkdir 7007,mkdir 7008
      • 拷贝redis配置文件到7007到7008文件夹,修改配置:
      • daemonize yes
      • port 700*
      • bind 当前机器ip
      • dir /usr/local/redis-cluster/700* 必须指定,分布式的数据每台机器存的数据都不一样的
      • cluster-enabled yes
      • cluster-config-file nodes-700*.conf
      • cluster-node-timeout 5000
      • appendonly yes
      • 启动7007和7008,/usr/local/redis/bin/redis-server /usr/local/redis-cluster/700*(7和8)/redis.conf
      • redis-trib 命令:
        • create:创建一个集群环境host1:port1 ... hostN:portN(集群中的主从节点比例)
        • call:可以执行redis命令
        • add-node:将一个节点添加到集群里,第一个参数为新节点的ip:port,第二个参数为集群中任意一个已经存在的节点的ip:port
        • del-node:移除一个节点
        • reshard:重新分片
        • check:检查集群状态
      • 新增一个主节点7007(master)
        • /usr/local/redis3.0/src/redis-trib.rb add-node 192.168.1.171:7007(要加的master的ip:port) 192.168.1.171:7001(集群内已知的任意一master的ip:port)
        • 查看集群信息:/usr/local/redis/bin/redis-cli cluster nodes,记录下新的节点的node id
        • 新增的节点不会有任何数据,因为它没有分配任何的slots,槽,需要手工分配
        • 分配槽,/usr/local/redis3.0/src/redis-trib.rb reshard 192.168.1.171:7001(集群内的任意一master),命令执行时会询问要分配多少个槽到新的master:How many slots do you want to move (from 1 to 16384)?可以自己设置,比如200,或者更多,接下来会询问What is the receiving node ID?,输入上个命令记录下的新节点的node id,下面会要求输入source node,可以输入all,意思是从所有的主节点中抽取相应的槽数到指定的新节点中,Do you want to proceed with the proposed reshard plan (yes/no)?直接输入yes,执行分片计划
        • 查看集群信息:/usr/local/redis/bin/redis-cli cluster nodes,可以看见新的master已经有槽数了
      • 添加从节点(7008)
        • /usr/local/redis3.0/src/redis-trib.rb add-node 192.168.1.171:7008(要加的slave) 192.168.1.171:7001(集群内的任意一master)
        • 查看集群信息:/usr/local/redis/bin/redis-cli cluster nodes,记录下7008要slave的节点的node id,即7008的master 节点(7007)的节点id,另外还可以看到这还是一个master,没有分配任何的槽,
        • 主节点转换为从节点:
            首先需要登录新加的7008节点的客户端,然后使用集群命令进行操作,把当前的
          7008(slave)节点指定到一个主节点下(这里使用之前创建的7007主节点)
          
          [root@micocube ~]# /usr/local/redis/bin/redis-cli -c -h 192.168.1.171 -p 7008
          192.168.1.171:7008> cluster replicate master(7007)节点id
          192.168.1.171:7008> OK(提示OK则操作成功)
          
        • 查看集群信息:/usr/local/redis/bin/redis-cli cluster nodes,可以看到7008已经变成slave了,我们可以对集群进行操作,来验证下是否可以进行读写(当然可以)。
    • redis-trib 删除节点
      • 移除从节点
        • /usr/local/redis3.0/src/redis-trib.rb
          del-node 192.168.1.171:7008 node_id(7008的节点id),执行命令之后,7008会从集群中移除,7008的服务也会被销毁,ps -ef | grep redis是看不到7008的redis的
      • 移除主节点
        • 主节点稍微麻烦一点,因为我们给它分配了slots(槽),所以我们这里必须先把7007里的slot槽放入到其他的可用主节点中去,然后再进行移除节点操作才行,不然会出现数据丢失问题.
        • 删除7007(master)节点之前,我们需要先把其全部的数据(slot槽)移动到其他节点上去(目前只能把master的数据迁移到一个节点上,暂时做不了平均分配功能),/usr/local/redis3.0/src/redis-trib.rb reshard 192.168.1.171:7007输出如下
        [root@micocube 7001]# /usr/local/redis3.0/src/redis-trib.rb reshard 192.168.1.171:7007
        
        >>> Performing Cluster Check (using node 192.168.1.171:7007)
        M: 382634a4025778c040b7213453fd42a709f79e28 192.168.1.171:7007
           slots:0-65,5461-5527,10923-10988 (199 slots)[注意这里,7007只有199个槽] master
           0 additional replica(s)
        S: fa299e41c173fa807ba04684c2f5e5e185d5f7d0 192.168.1.171:7006
           slots: (0 slots) slave
           replicates 83df08875c7707878756364039df0a4c8658f272
        S: a69b98937844c6050ee5885266ccccb185a3f36a 192.168.1.171:7004
           slots: (0 slots) slave
           replicates 614d0def75663f2620b6402a017014b57c912dad
        M: 614d0def75663f2620b6402a017014b57c912dad 192.168.1.171:7001
           slots:66-5460 (5395 slots) master
           1 additional replica(s)
        M: 8aac82b63d42a1989528cd3906579863a5774e77 192.168.1.171:7002
           slots:5528-10922 (5395 slots) master
           1 additional replica(s)
        S: adb99506ddccad332e09258565f2e5f4f456a150 192.168.1.171:7005
           slots: (0 slots) slave
           replicates 8aac82b63d42a1989528cd3906579863a5774e77
        M: 83df08875c7707878756364039df0a4c8658f272 192.168.1.171:7003
           slots:10989-16383 (5395 slots) master
           1 additional replica(s)
        [OK] All nodes agree about slots configuration.
        >>> Check for open slots...
        >>> Check slots coverage...
        [OK] All 16384 slots covered.
        How many slots do you want to move (from 1 to 16384)? 199
        (注释:这里不会是正好200个槽)
        What is the receiving node ID? 614d0def75663f2620b6402a017014b57c912dad
        (注释:这里是需要把数据移动到哪?7001的主节点id)
        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:382634a4025778c040b7213453fd42a709f79e28
        (注释:这里是需要数据源,也就是我们的7007节点id)
        Source node #2:done
        (注释:这里直接输入done 开始生成迁移计划)
        
        Ready to move 199 slots.
          Source nodes:
            M: 382634a4025778c040b7213453fd42a709f79e28 192.168.1.171:7007
           slots:0-65,5461-5527,10923-10988 (199 slots) master
           0 additional replica(s)
          Destination node:
            M: 614d0def75663f2620b6402a017014b57c912dad 192.168.1.171:7001
           slots:66-5460 (5395 slots) master
           1 additional replica(s)
          Resharding plan:
        Moving slot 0 from 382634a4025778c040b7213453fd42a709f79e28
        ...
        Do you want to proceed with the proposed reshard plan (yes/no)? Yes
        (注释:这里输入yes开始迁移)
        Moving slot 0 from 192.168.1.171:7007 to 192.168.1.171:7001: 
        ...
        
        • 到此为止我们已经成功的把7007主节点的数据迁移到7001上去了,我们可以看一下现在的集群状态如下图,你会发现7007下面已经没有任何数据(slot)槽了,证明迁移成功!
        • 最后我们直接使用del-node命令删除7007主节点即可。
          [root@micocube 7001]# /usr/local/redis3.0/src/redis-trib.rb del-node
          192.168.1.171:7007 382634a4025778c040b7213453fd42a709f79e28(7007的node id)
  • java 操作redis集群
      import java.util.HashSet;
      import java.util.Set;
    
      import redis.clients.jedis.HostAndPort;
      import redis.clients.jedis.JedisCluster;
      import redis.clients.jedis.JedisPoolConfig;
    
      public class TestClusterRedis {
    
          public static void main(String[] args) {
              
              Set<HostAndPort> jedisClusterNode = new HashSet<HostAndPort>();
                          //下面是集群中各个节点的ip和端口,如果连不上关闭redis服务器的防火墙
              jedisClusterNode.add(new HostAndPort("192.168.1.171", 7001));
              jedisClusterNode.add(new HostAndPort("192.168.1.171", 7002));
              jedisClusterNode.add(new HostAndPort("192.168.1.171", 7003));
              jedisClusterNode.add(new HostAndPort("192.168.1.171", 7004));
              jedisClusterNode.add(new HostAndPort("192.168.1.171", 7005));
              jedisClusterNode.add(new HostAndPort("192.168.1.171", 7006));
              //GenericObjectPoolConfig goConfig = new GenericObjectPoolConfig();
              //JedisCluster jc = new JedisCluster(jedisClusterNode,2000,100, goConfig);
              JedisPoolConfig cfg = new JedisPoolConfig();
              cfg.setMaxTotal(100);
              cfg.setMaxIdle(20);
              cfg.setMaxWaitMillis(-1);
              cfg.setTestOnBorrow(true); 
              JedisCluster jc = new JedisCluster(jedisClusterNode,6000,1000,cfg);     
              
              System.out.println(jc.set("age","20"));
              System.out.println(jc.set("sex","男"));
              System.out.println(jc.get("name"));
              System.out.println(jc.get("name"));
              System.out.println(jc.get("name"));
              System.out.println(jc.get("name"));
              System.out.println(jc.get("name"));
              System.out.println(jc.get("name"));
              System.out.println(jc.get("name"));
              System.out.println(jc.get("name"));
              System.out.println(jc.get("age"));
              System.out.println(jc.get("sex"));
              jc.close();
              
              
          }
          
      }
    
  • redis与spring的整合(applicationContext-cluster.xml)
      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
          xmlns:context="http://www.springframework.org/schema/context"
          xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
          xmlns:aop="http://www.springframework.org/schema/aop"
          xsi:schemaLocation="  
                  http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd  
                  http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    
          <context:property-placeholder location="classpath:redis.properties" />
          <context:component-scan base-package="com.x.redis.dao">
          </context:component-scan>
          <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
              <property name="maxIdle" value="${redis.maxIdle}" />
              <property name="maxTotal" value="${redis.maxActive}" />
              <property name="maxWaitMillis" value="${redis.maxWait}" />
              <property name="testOnBorrow" value="${redis.testOnBorrow}" />
          </bean>
    
          <bean id="hostport1" class="redis.clients.jedis.HostAndPort">
              <constructor-arg name="host" value="10.16.68.92" />
              <constructor-arg name="port" value="7770" />
          </bean>
          <bean id="hostport2" class="redis.clients.jedis.HostAndPort">
              <constructor-arg name="host" value="10.16.68.92" />
              <constructor-arg name="port" value="7771" />
          </bean>
          <bean id="hostport3" class="redis.clients.jedis.HostAndPort">
              <constructor-arg name="host" value="10.16.68.92" />
              <constructor-arg name="port" value="7772" />
          </bean>
          <bean id="hostport4" class="redis.clients.jedis.HostAndPort">
              <constructor-arg name="host" value="10.16.68.92" />
              <constructor-arg name="port" value="7773" />
          </bean>
          <bean id="hostport5" class="redis.clients.jedis.HostAndPort">
              <constructor-arg name="host" value="10.16.68.92" />
              <constructor-arg name="port" value="7774" />
          </bean>
          <bean id="hostport6" class="redis.clients.jedis.HostAndPort">
              <constructor-arg name="host" value="10.16.68.92" />
              <constructor-arg name="port" value="7775" />
          </bean>
    
          <bean id="redisCluster" class="redis.clients.jedis.JedisCluster">
              <constructor-arg name="nodes">
                  <set>
                      <ref bean="hostport1" />
                      <ref bean="hostport2" />
                      <ref bean="hostport3" />
                      <ref bean="hostport4" />
                      <ref bean="hostport5" />
                      <ref bean="hostport6" />
                  </set>
              </constructor-arg>
              <constructor-arg name="timeout" value="6000" />
              <constructor-arg name="poolConfig">
                  <ref bean="jedisPoolConfig" />
              </constructor-arg>
          </bean>
      </beans>
    
  • Redis配置文件详解
      # Redis 配置文件
    
      # 当配置中需要配置内存大小时,可以使用 1k, 5GB, 4M 等类似的格式,其转换方式如下(不区分大小写)
      #
      # 1k =>
      1000 bytes
      # 1kb => 1024 bytes
      # 1m => 1000000 bytes
      # 1mb =>
      1024*1024 bytes
      # 1g => 1000000000 bytes
      # 1gb => 1024*1024*1024
      bytes
      #
      # 内存配置大小写是一样的.比如 1gb 1Gb 1GB 1gB
    
      # daemonize no 默认情况下,redis不是在后台运行的,如果需要在后台运行,把该项的值更改为yes
      daemonize
      yes
    
      # 当redis在后台运行的时候,Redis默认会把pid文件放在/var/run/redis.pid,你可以配置到其他地址。
      #
      当运行多个redis服务时,需要指定不同的pid文件和端口
      pidfile /var/run/redis.pid
    
      # 指定redis运行的端口,默认是6379
      port 6379
    
      # 指定redis只接收来自于该IP地址的请求,如果不进行设置,那么将处理所有请求,
      # 在生产环境中最好设置该项
      # bind
      127.0.0.1
    
      # Specify the path for the unix socket that will be used to listen for
      #
      incoming connections. There is no default, so Redis will not listen
      # on a
      unix socket when not specified.
      #
      # unixsocket /tmp/redis.sock
      #
      unixsocketperm 755
    
      # 设置客户端连接时的超时时间,单位为秒。当客户端在这段时间内没有发出任何指令,那么关闭该连接
      # 0是关闭此设置
      timeout
      0
    
      # 指定日志记录级别
      # Redis总共支持四个级别:debug、verbose、notice、warning,默认为verbose
      #
      debug  记录很多信息,用于开发和测试
      # varbose 有用的信息,不像debug会记录那么多
      #
      notice 普通的verbose,常用于生产环境
      # warning 只有非常重要或者严重的信息会记录到日志
      loglevel
      debug
    
      # 配置log文件地址
      # 默认值为stdout,标准输出,若后台模式会输出到/dev/null
      #logfile
      stdout
      logfile /var/log/redis/redis.log
    
      # To enable logging to the system logger, just set 'syslog-enabled' to
      yes,
      # and optionally update the other syslog parameters to suit your
      needs.
      # syslog-enabled no
    
      # Specify the syslog identity.
      # syslog-ident redis
    
      # Specify the syslog facility.  Must be USER or between LOCAL0-LOCAL7.
      #
      syslog-facility local0
    
      # 可用数据库数
      # 默认值为16,默认数据库为0,数据库范围在0-(database-1)之间
      databases 16
    
      ################################ 快照  
      #################################
      #
      # 保存数据到磁盘,格式如下:
      #
      #   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
    
      # 存储至本地数据库时(持久化到rdb文件)是否压缩数据,默认为yes
      rdbcompression yes
    
      # 本地持久化数据库文件名,默认值为dump.rdb
      dbfilename dump.rdb
    
      # 工作目录
      #
      # 数据库镜像备份的文件放置的路径。
      #
      这里的路径跟文件名要分开配置是因为redis在进行备份时,先会将当前数据库的状态写入到一个临时文件中,等备份完成时,
      #
      再把该该临时文件替换为上面所指定的文件,而这里的临时文件和上面所配置的备份文件都会放在这个指定的路径当中。
      #
      #
      AOF文件也会存放在这个目录下面
      #
      # 注意这里必须制定一个目录而不是文件
      dir ./
    
      ################################# 复制
      #################################
    
      # 主从复制. 设置该数据库为其他数据库的从数据库.
      #
      设置当本机为slav服务时,设置master服务的IP地址及端口,在Redis启动时,它会自动从master进行数据同步
      #
      # slaveof
      <masterip> <masterport>
    
      # 当master服务设置了密码保护时(用requirepass制定的密码)
      # slav服务连接master的密码
      #
      #
      masterauth <master-password>
    
    
      # 当从库同主机失去连接或者复制正在进行,从机库有两种运行方式:
      #
      # 1)
      如果slave-serve-stale-data设置为yes(默认设置),从库会继续相应客户端的请求
      #
      # 2)
      如果slave-serve-stale-data是指为no,出去INFO和SLAVOF命令之外的任何请求都会返回一个
      #    错误"SYNC with
      master in progress"
      #
      slave-serve-stale-data yes
    
      # 从库会按照一个时间间隔向主库发送PINGs.可以通过repl-ping-slave-period设置这个时间间隔,默认是10秒
      #
      #
      repl-ping-slave-period 10
    
      # repl-timeout 设置主库批量数据传输时间或者ping回复时间间隔,默认值是60秒
      #
      一定要确保repl-timeout大于repl-ping-slave-period
      # repl-timeout 60
    
      ################################## 安全
      ###################################
    
      # 设置客户端连接后进行任何其他指定前需要使用的密码。
      #
      警告:因为redis速度相当快,所以在一台比较好的服务器下,一个外部的用户可以在一秒钟进行150K次的密码尝试,这意味着你需要指定非常非常强大的密码来防止暴力破解
      #
      #
      requirepass foobared
    
      # 命令重命名.
      #
      # 在一个共享环境下可以重命名相对危险的命令。比如把CONFIG重名为一个不容易猜测的字符。
      #
      #
      举例:
      #
      # rename-command CONFIG
      b840fc02d524045429941cc15f59e41cb7be6c52
      #
      #
      如果想删除一个命令,直接把它重命名为一个空字符""即可,如下:
      #
      # rename-command CONFIG ""
    
      ################################### 约束
      ####################################
    
      # 设置同一时间最大客户端连接数,默认无限制,Redis可以同时打开的客户端连接数为Redis进程可以打开的最大文件描述符数,
      # 如果设置
      maxclients 0,表示不作限制。
      # 当客户端连接数到达限制时,Redis会关闭新的连接并向客户端返回max number of clients
      reached错误信息
      #
      # maxclients 128
    
      # 指定Redis最大内存限制,Redis在启动时会把数据加载到内存中,达到最大内存后,Redis会先尝试清除已到期或即将到期的Key
      #
      Redis同时也会移除空的list对象
      #
      #
      当此方法处理后,仍然到达最大内存设置,将无法再进行写入操作,但仍然可以进行读取操作
      #
      #
      注意:Redis新的vm机制,会把Key存放内存,Value会存放在swap区
      #
      #
      maxmemory的设置比较适合于把redis当作于类似memcached的缓存来使用,而不适合当做一个真实的DB。
      #
      当把Redis当做一个真实的数据库使用的时候,内存使用将是一个很大的开销
      # maxmemory <bytes>
    
      # 当内存达到最大值的时候Redis会选择删除哪些数据?有五种方式可供选择
      #
      # volatile-lru ->
      利用LRU算法移除设置过过期时间的key (LRU:最近使用 Least Recently Used )
      # allkeys-lru ->
      利用LRU算法移除任何key
      # volatile-random -> 移除设置过过期时间的随机key
      #
      allkeys->random -> remove a random key, any key
      # volatile-ttl ->
      移除即将过期的key(minor TTL)
      # noeviction -> 不移除任何可以,只是返回一个写错误
      #
      #
      注意:对于上面的策略,如果没有合适的key可以移除,当写的时候Redis会返回一个错误
      #
      #       写命令包括: set setnx
      setex append
      #       incr decr rpush lpush rpushx lpushx linsert lset
      rpoplpush sadd
      #       sinter sinterstore sunion sunionstore sdiff sdiffstore
      zadd zincrby
      #       zunionstore zinterstore hset hsetnx hmset hincrby incrby
      decrby
      #       getset mset msetnx exec sort
      #
      # 默认是:
      #
      #
      maxmemory-policy volatile-lru
    
      # LRU 和 minimal TTL 算法都不是精准的算法,但是相对精确的算法(为了节省内存),随意你可以选择样本大小进行检测。
      #
      Redis默认的灰选择3个样本进行检测,你可以通过maxmemory-samples进行设置
      #
      # maxmemory-samples
      3
    
      ############################## AOF ###############################
    
    
      #
      默认情况下,redis会在后台异步的把数据库镜像备份到磁盘,但是该备份是非常耗时的,而且备份也不能很频繁,如果发生诸如拉闸限电、拔插头等状况,那么将造成比较大范围的数据丢失。
      #
      所以redis提供了另外一种更加高效的数据库备份及灾难恢复方式。
      # 开启append
      only模式之后,redis会把所接收到的每一次写操作请求都追加到appendonly.aof文件中,当redis重新启动时,会从该文件恢复出之前的状态。
      #
      但是这样会造成appendonly.aof文件过大,所以redis还支持了BGREWRITEAOF指令,对appendonly.aof 进行重新整理。
      #
      你可以同时开启asynchronous dumps 和 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
      #
      # This means that while
      another child is saving the durability of Redis is
      # the same as "appendfsync
      none", that in pratical terms means that it is
      # possible to lost up to 30
      seconds of log in the worst scenario (with the
      # default Linux
      settings).
      #
      # If you have latency problems turn this to "yes". Otherwise
      leave it as
      # "no" that is the safest pick from the point of view of
      durability.
      no-appendfsync-on-rewrite no
    
      # Automatic rewrite of the append only file.
      # AOF 自动重写
      #
      当AOF文件增长到一定大小的时候Redis能够调用 BGREWRITEAOF 对日志文件进行重写
      #
      #
      它是这样工作的:Redis会记住上次进行些日志后文件的大小(如果从开机以来还没进行过重写,那日子大小在开机的时候确定)
      #
      #
      基础大小会同现在的大小进行比较。如果现在的大小比基础大小大制定的百分比,重写功能将启动
      #
      同时需要指定一个最小大小用于AOF重写,这个用于阻止即使文件很小但是增长幅度很大也去重写AOF文件的情况
      # 设置 percentage
      为0就关闭这个特性
    
      auto-aof-rewrite-percentage 100
      auto-aof-rewrite-min-size 64mb
    
      ################################## SLOW LOG
      ###################################
    
      # Redis Slow Log 记录超过特定执行时间的命令。执行时间不包括I/O计算比如连接客户端,返回结果等,只是命令执行时间
      #
      #
      可以通过两个参数设置slow log:一个是告诉Redis执行超过多少时间被记录的参数slowlog-log-slower-than(微妙),
      #
      另一个是slow log 的长度。当一个新命令被记录的时候最早的命令将被从队列中移除
    
      # 下面的时间以微妙微单位,因此1000000代表一分钟。
      #
      注意制定一个负数将关闭慢日志,而设置为0将强制每个命令都会记录
      slowlog-log-slower-than 10000
    
      # 对日志长度没有限制,只是要注意它会消耗内存
      # 可以通过 SLOWLOG RESET
      回收被慢日志消耗的内存
      slowlog-max-len 1024
    
      ################################ VM ###############################
    
      ### WARNING! Virtual Memory is deprecated in Redis 2.4
      ### The use of
      Virtual Memory is strongly discouraged.
    
      # Virtual Memory allows Redis to work with datasets bigger than the
      actual
      # amount of RAM needed to hold the whole dataset in memory.
      # In
      order to do so very used keys are taken in memory while the other keys
      # are
      swapped into a swap file, similarly to what operating systems do
      # with
      memory pages.
      #
      # To enable VM just set 'vm-enabled' to yes, and set the
      following three
      # VM parameters accordingly to your needs.
    
      vm-enabled no
      # vm-enabled yes
    
      # This is the path of the Redis swap file. As you can guess, swap
      files
      # can't be shared by different Redis instances, so make sure to use a
      swap
      # file for every redis process you are running. Redis will complain if
      the
      # swap file is already in use.
      #
      # The best kind of storage for the
      Redis swap file (that's accessed at random)
      # is a Solid State Disk
      (SSD).
      #
      # *** WARNING *** if you are using a shared hosting the default
      of putting
      # the swap file under /tmp is not secure. Create a dir with access
      granted
      # only to Redis user and configure Redis to create the swap file
      there.
      vm-swap-file /tmp/redis.swap
    
      # vm-max-memory configures the VM to use at max the specified amount
      of
      # RAM. Everything that deos not fit will be swapped on disk *if* possible,
      that
      # is, if there is still enough contiguous space in the swap
      file.
      #
      # With vm-max-memory 0 the system will swap everything it can. Not
      a good
      # default, just specify the max amount of RAM you can in bytes, but
      it's
      # better to leave some margin. For instance specify an amount of
      RAM
      # that's more or less between 60 and 80% of your free
      RAM.
      vm-max-memory 0
    
      # Redis swap files is split into pages. An object can be saved using
      multiple
      # contiguous pages, but pages can't be shared between different
      objects.
      # So if your page is too big, small objects swapped out on disk will
      waste
      # a lot of space. If you page is too small, there is less space in the
      swap
      # file (assuming you configured the same number of total swap file
      pages).
      #
      # If you use a lot of small objects, use a page size of 64 or 32
      bytes.
      # If you use a lot of big objects, use a bigger page size.
      # If
      unsure, use the default :)
      vm-page-size 32
    
      # Number of total memory pages in the swap file.
      # Given that the page
      table (a bitmap of free/used pages) is taken in memory,
      # every 8 pages on
      disk will consume 1 byte of RAM.
      #
      # The total swap size is vm-page-size *
      vm-pages
      #
      # With the default of 32-bytes memory pages and 134217728 pages
      Redis will
      # use a 4 GB swap file, that will use 16 MB of RAM for the page
      table.
      #
      # It's better to use the smallest acceptable value for your
      application,
      # but the default is large in order to work in most
      conditions.
      vm-pages 134217728
    
      # Max number of VM I/O threads running at the same time.
      # This threads
      are used to read/write data from/to swap file, since they
      # also encode and
      decode objects from disk to memory or the reverse, a bigger
      # number of
      threads can help with big objects even if they can't help with
      # I/O itself
      as the physical device may not be able to couple with many
      # reads/writes
      operations at the same time.
      #
      # The special value of 0 turn off threaded
      I/O and enables the blocking
      # Virtual Memory
      implementation.
      vm-max-threads 4
    
      ############################### ADVANCED CONFIG
      ###############################
    
      # 当hash中包含超过指定元素个数并且最大的元素没有超过临界时,
      #
      hash将以一种特殊的编码方式(大大减少内存使用)来存储,这里可以设置这两个临界值
      # Redis
      Hash对应Value内部实际就是一个HashMap,实际这里会有2种不同实现,
      #
      这个Hash的成员比较少时Redis为了节省内存会采用类似一维数组的方式来紧凑存储,而不会采用真正的HashMap结构,对应的value
      redisObject的encoding为zipmap,
      #
      当成员数量增大时会自动转成真正的HashMap,此时encoding为ht。
      hash-max-zipmap-entries
      512
      hash-max-zipmap-value 64
    
      # list数据类型多少节点以下会采用去指针的紧凑存储格式。
      #
      list数据类型节点值大小小于多少字节会采用紧凑存储格式。
      list-max-ziplist-entries
      512
      list-max-ziplist-value 64
    
      # set数据类型内部数据如果全部是数值型,且包含多少节点以下会采用紧凑格式存储。
      set-max-intset-entries
      512
    
      # zsort数据类型多少节点以下会采用去指针的紧凑存储格式。
      #
      zsort数据类型节点值大小小于多少字节会采用紧凑存储格式。
      zset-max-ziplist-entries
      128
      zset-max-ziplist-value 64
    
      # Redis将在每100毫秒时使用1毫秒的CPU时间来对redis的hash表进行重新hash,可以降低内存的使用
      #
      #
      当你的使用场景中,有非常严格的实时性需要,不能够接受Redis时不时的对请求有2毫秒的延迟的话,把这项配置为no。
      #
      #
      如果没有这么严格的实时性要求,可以设置为yes,以便能够尽可能快的释放内存
      activerehashing yes
    
      ################################## INCLUDES 
      ###################################
    
      # 指定包含其它的配置文件,可以在同一主机上多个Redis实例之间使用同一份配置文件,而同时各个实例又拥有自己的特定配置文件
      #
      include /path/to/local.conf
      # include /path/to/other.conf
    
  • TomcatRedis 的session共享,一般不使用,只作为知识扩展,一般都会使用cas,而不是redis的session共享