1.NoSQL
noSQL意味不仅仅是sql,泛指非关系型数据库。noSQL不依赖于业务的逻辑关系存储,而以简单的key-value形式存储,因此大大的增加了数据库的扩展能力。
noSQL适用于数据的高并发读写,海量数据的读写,对数据的高扩展。
2.Redis
redis是一个开源的key-value存储系统,和Memcached类似,但是他支持存储的value的类型更多,包括String、list、set、hash、zset。
redis可以配合关系型数据库做高速缓存,因为其数据是存放在内存中的,可以降低数据库的IO次数。
redis具有持久化的能力,利用其多样性的数据结构可以存储特定的数据。
最新N个数据 通过List实现按自然时间排序的数据
做排行榜,top N 利用zset(有序集合)
时效性的数据,比如手机验证码 Expire过期
计数器,秒杀 原子性,自增方法incr
去除大量数据中的重复数据 利用Set集合
构建队列 利用list集合
发送订阅消息系统 pub/sub模式
3.Redis的安装
解压后在目录中make。如果没有c++语言环境需要先运行yum install gcc-c++,然后makedistclean、make、makeinstall即可
默认安装目录:usr/local/bin
启动是需要将redis.conf文件里面的daemonize no 改为yes,让服务后台运行。
启动命令:redis-server /myredis/redis.conf 关闭命令:redis-cli shutdown
redis是单线程+多路IO复用技术
4.Redis的常用命令
基本:keys * exists key type key del key expire key seconds ttl key (-1表示永不过期,-2表示已过期) dbsize falushdb flushall
String:get set append strlen setnx incr decr incrby/decrby key 步长 mget mset msetnx getrange setrange setex getset
List:lpush/rpush lpop/rpop rpoplpush lrange lindex llen linsert lrem
Set:sadd smembers sismember scard srem spop srandmember sinter sunion sdiff
Hash:hset hget hmset hesists hkeys hvals hincrby hsetnx
Zset:zadd zrange zrangebyscore zrevrangebyscore zincrby zrem zcount zrank
5.Redis的相关配置
include:类似于jsp中的include
bind:ip地址的绑定,默认为127.0.0.1,不写的情况下,无限制接收任何ip地址的访问,如果开启了protected-mode,name在没有设定bind ip 且没有设置密码的情况下,redis只允许接收本机的响应
tcp-backlog:可以理解是一个请求到达后至到接收进程处理前的队列数。backlog队列总和=未完成三次握手队列+已经燃车鞥三次握手队列
timeout:一个空闲的客户端维持多少秒会关闭,0为永不关闭
TCP keepalive:对访问客户端的一种心跳检测,每个n秒检测一次,官方推荐设置为60秒
daemonize:是否为后台进程
pidfile:存放pid文件的位置,每个实例会产生一个不同的pid文件
log level:四个级别根据使用阶段来选择,生产换将选择notice或者warning
logfile:日志文件名称
syslog:是否将redis日志输送到linux系统日志服务中
security:在命令行中设置密码
maxclient:最大客户端连接数
maxmemory:设置redis可以使用的内存量
6.Java对Redis 的支持
需要的jar包:Commons-pool-1.6.jar Jedis-2.1.0.jar
注意事项:开放端口,注释掉bind protect-mode no
7.redis事务
redis事务是一个单独的隔离操作,事务中的所有命令都会序列化,被顺序的执行,事务在执行过程中,不会被其他的客户端发来的命令请求所打断。
Multi、Exec、discard:从输入multi开始,输入的命令就都会一次进入命令队列中,但不会真正的执行,直到输入exec后,redis会将之前的命令队列中的命令依次执行。组队的过程中可以通过discard来放弃组队。
如果组队的过程中某个命令出现了报告错误(类似于编译时期异常),执行的整个队列都会被取消,如果exec后某个命令报出了错(类似于运行时异常),则只有报错的命令不会被执行,而其他的命令都会执行。
Watch:在执行multi之前,先执行watch key 可以监视一个或多个key,如果在事务执行之前这个key被其他命令锁改动,那么事务将被打断。unwatch可以取消监视。如果在执行watch命令后,exec命令或者discard命令执行了的话,那么就不需要执行unwatch了。
redis的三个特性:
单独的隔离操作:事务中的所有命令都会序列化,按顺序的执行,事务在执行的过程中,不会被其他客户端发送来的命令所打断
没有隔离级别的概念:队列中的命令没有提交之前都不会实际的执行,也就不存在是事务内的查询要看到事务里的更新,在事务外查询不能看到这个让人头痛的问题。
不保证原子性:redis的一个事务中如果有一条命令执行失败,其后的命令仍然会被执行,没有回滚。
8.Redis的持久化
redis提供了两个不同形式的持久化方式:RDB(Redis DataBase) AOF(Append Of File)
RDB:在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是行话讲的Snapshot快照。它恢复时是将快照文件直接读到内存里。Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到一个临时文件中,带持久化过程都结束了,在用这个临时文件替换上次持久化好的文件。整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能,如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那么RDB要比AOF方式更加的高效。RDB的缺点是最后一次持久化的数据可能丢失
在redis.conf中配置的临时文件名默认为dbfilename dump.rdb。默认的文件保存路径为redis启动时命令行所在的目录下
保存策略:900 1 300 10 60 10000
手动保存快照:save
rdb的备份:先通过config get dir 查询rdb文件的目录 再将*.rdb的文件拷贝到别的地方
rdb的恢复:关闭redis后直接将备份的文件拷贝到工作目录系,启动redis,备份就会被加载
AOF:以日志的形式来记录每个写操作,将Redis执行过的所有写指令记录下来,只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis重启的话就是根据日志文件的内容将写指令从头到尾执行一次以完成恢复工作。
AOF默认不开启,需要手动在配置文件中配置。可以在redis.conf中配置文件名称,默认为appendonly.aof。AOF文件的保存路径同RBD的路径一致。
AOF文件的故障备份:拷贝备份文件,需要回复是在拷贝到工作目录下。
AOF和RDB同时开启,系统默认取AOF得数据
AOF文件故障恢复:如果遇到AOF文件损坏,可用redis-check-aof --fix appendonly.aof 进行恢复
AOF文件的Rewrite:当AOF文件持续增长而过大时,会fork出一条新进程来将文件重写(也是先临时文件最后rename),重写时并不会读取旧的aof文件,而是将整个内存中的数据库内容用命令的方式重写了一个aof文件。当当前aof文件是上次记录是的两倍大小且总大小大于等于64mb的情况下,redis会对aof进行重写
AOF:可读的日志文本,通过操作AOF文件,可以处理误操作。占用更多的磁盘空间,恢复慢,有个别BUG,造成恢复不能。
官方推荐两个都启用,如果对数据不敏感,可以单独启用RDB,不建议单独用AOF
9.redis 的主从复制
配从不配主:拷贝多个redis.conff文件、开启daemonize yes、pid文件名字、指定端口、log文件名字、dump.rdb名字、Appendonly关掉或换名字
include /myredis/redis.conf
port 6379
pidfile /var/run/redis_6379.pid
dbfilename dump6379.rdb
slave-priority 100 设置从机生主机优先级,越小越高
:%s/6379/6380(vim中的全部替换命令)
info replication:打印主从复制的相关信息
slaveof ip port:成为某个实例的从服务器。 slaveof no one:翻身成老大
复制原理:每次从机连通后,都会给主机发送sync指令,主机立刻进行存盘操作,发送RBD文件给从机,从机收到RDB文件后,进行全盘加载,之后每次主机的写操作会立刻发送给从机,从机执行相同的命令
哨兵模式:在工作目录中新建sentinel.conf,在文件中填写内容:sentinel monitor mymaster 127.0.0.1 6379 1(其中mymaster为监控对象起的服务器名称,1为至少有多少个哨兵同意更改主机的数量)
启动哨兵:执行redis-sentinel /myredis/sentinel.conf
故障恢复:从下线的主服务器的所有从服务器中挑选一个从服务器,将其转成主服务器,选择的条件依次为:1.选择优先级靠前的2.选择偏移量最大的3.选择runid最小的从服务器(每个节点都会有一个32为的随机runid)。选择出新的主服务器之后,sentinel向原主服务器的从服务器发送slaveof新主服务器的的命令,复制新的master。当已下线的服务重新上线,sentinel会向其发送slaveof命令,让其成为新主的从
10.redis集群
redis的集群实现了对redis的水平扩容,即启动了N个redis节点,将整个数据库分步存储在这N个节点中,每个节点存储的总数据的1/N。redis集群通过分区来提供一定程度的可用性:即使集群中有一部分节点失效或者无法进行通讯,集群也可以继续处理命令请求。
使用代理中间件维护一个表来维护集群中节点与数据之间的位置关系
redis官方解决方案:redis-cluster3.0。无中心化结构。将集群中的每个节点关联起来,让节点自己去找兄弟节点,只要找到一个节点,就相当于找到了所有的节点。
使用官方的集群搭建脚本需要安装ruby环境。ruby需要一个redis插件来操作集群,插件名为:redis-3.2.0.gem。然后执行 gem install --local redis-3.2.0.gem
然后编写配置文件:、
include /myredis/redis.conf
port 6379
pidfile /var/run/redis_6379.pid
dbfilename dump6379.rdb
cluster-enabled yes 集群开关
cluster-config-file nodes-6379.conf 设定节点配置文件名
cluster-node-timeout 15000 节点失联时间,单位毫秒
配置好配置文件后启动所有服务,这时的所有节点都已经都了集群的能力,但是还没有形成集群。然后在安装目录的src目录下使用redis-trib.rb执行rube脚本
脚本命令为:./redis-trib.rb create --replicas 1 192.168.148.128 :6379 192.168.148.128 :6380 192.168.148.128 :6381(有多少个节点就写多少,理论上至少6个)
使用cluster nodes来查看集群信息。
集群原则:一个集群至少有三个主节点;选项 --replicas 1 表示我们希望为集群的每个主节点创建一个从节点;分配原则尽量保证每个主数据库运行在不同的IP地址,每个从库和主库不在一个IP地址上。
如果在某个节点进行插入,有可能失败,因为key可能不会存储在当前节点上。可以通过redis -cli -c客户端来自动重定向存储和获取。不在一个solt下的键值,是不能使用mget,mset等多件操作。但是可以使用mset k1{customer} v1 k2{customer} v2 来指定存储,这时就不用key来计算位置,而是用大括号中的值来计算位置。
slots:一个redis集群包含16384个插槽,数据库中的每个键都属于这16384个插槽中的其中一个,集群使用公式CRC16(key)%16384来计算键key属于哪个槽,其中CRC16(key)语句用于计算键key的CRC16校验和。集群中的每个节点负责处理一部分插槽。
命令:
cluster keyslot key 查看key应该在哪个槽中
cluster countkeysinslot slot 返回槽 slot 目前包含的键值对数量
cluster getkeysinslot slot count 返回count个slot槽中的键
主节点下线后,从节点自动升为主节点。主节点回复后,自动变为从节点,如果某一段插槽的主从节点都当掉,就看redis.conf中的参数 cluster-require-full-coverage 如果为yes,说明对数据完整性要求高,全停,否则就凑合着继续用
在java中使用:
Set<HostAndPort> set = new HashSet<HostAndPort>();
set.add(new HostAndPort("192.168.148.128",6379));
JedisCluster jedisCluster = new JedisCluster(set);
jedisCluster.set("k1","v1");
System.out.println(jedisCluster.get("k1"));
redis集群的好处:实现扩容;分摊压力;无中心配置相对简单;
redis集群的不足:多键操作不被支持;多件的Redis事务不被支持。lua脚本不被支持;出现较晚