Redis_00
Redis_00
1.NoSQL入门和概述
1.1 NoSQL的定义
NoSQL(Not only SQL),泛指非关系型的数据库。随着互联网web2.0网站的兴起,传统的关系数据库在应付web2.0网站,特别是超大规模和高并发的SNS类型的web2.0纯动态网站已经显得力不从心,暴露了很多难以克服的问题,而非关系型的数据库则由于其本身的特点得到了非常迅速的发展。NoSQL数据库的产生就是为了解决大规模数据集合多重数据种类带来的挑战,尤其是大数据应用难题。
1.2 NoSQL的数据模型(聚合模型)
- KV
- BSON
- 列族
- 图形
1.3 NoSQL数据库的四大分类
- KV键值
- 文档型数据库(BSON格式比较多)
- 列存储数据库
- 图关系数据库
1.4 分布式数据库中CAP原理
C | A | P |
---|---|---|
Consistency | Availability | Partition tolerance |
强一致性 | 高可用性 | 分布式容忍性 |
CAP理论的核心是: 一个分布式系统不可能同时很好地满足一致性、可用性和分区容错性这三个需求,最多只能同时较好地满足两个。
因此,根据CAP原理将NoSQL数据库分成了满足CA原则、CP原则和AP原则三大类。而由于当前的网络硬件肯定会出现延迟丢包等问题,所以,分区容忍性事我们必须要实现的。以至于,我们只能在一致性和可用性之间进行权衡,没有NoSQL系统能同时保证这三点。
原则 | 解释 |
---|---|
CA | 单点集群,满足一致性,可用性的系统,通常在可扩展性上不太强大 |
CP | 满足一致性,分区容忍性的系统,通常性能不是特别高 |
AP | 满足可用性,分区容忍性的系统,通常可能对一致性要求低一些 |
1.5 BASE
为了解决关系数据强一致性引起的问题而引起的可用性降低而提出的解决方案
- 基本可用: Basically Available
- 软状态: Soft state
- 最终一致: Eventually consistent
它的思想是通过让系统放松对某一时刻数据一致性的要求来换取系统整体伸缩性和性能上改观。大型系统往往由于地域分布和极高性能的要求,不可能采用分布式事务来完成这些指标,要想获得这些指标,我们必须采用另外一种方式来完成,这里BASE就是解决这个问题的办法。
1.6 分布式系统(distributed system)
由多台计算机和通信的软件组件通过计算机网络连接(本地网络或广域网)组成。分布式系统是建立在网络之上的软件系统。正是因为软件的特性,所以分布式系统具有高度的内聚性和透明性。因此,网络和分布式系统之间的区别更多的在于高层软件(特别是操作系统),而不是硬件。分布式系统可以应用在不同的平台上如:PC、工作站、局域网和广域网上等。
简单来讲:
- 分布式: 不同的多台服务器上面部署不同的服务模块(工程),他们之间通过RPC/RMI之间通信和调用,对外提供服务和组内协作。
- 集群: 不同的多台服务器上面部署相同的服务模块,通过分布式调度软件进行统一的调度,对外提供服务和访问。
2.Redis从安装到卸载
Remote dictionary server: 远程字典服务器;是完全开源免费的,用C语言编写的,遵守BSD协议,是一个高性能的(key/value)分布式内存数据库,基于内存运行并支持持久化的NoSQL数据库,是当前最热门的NoSQL数据库之一,也被人们称为数据结构服务器。
2.1 Redis的特点
- Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用;
- Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储;
- Redis支持数据的备份,即master-slave模式的数据备份;
2.2 Redis的官网
- 英文版(推荐): http://www.redis.io/
- 中文版: http://www.redis.cn/
- 命令参考: http://redisdoc.com/
2.3 Redis的安装和部署
- 首先,需要获取Redis的安装包,已经在Windows上有的话,可以用Xftp等工具传到Linux上,也可以直接在Linux上下载:
wget http://download.redis.io/releases/redis-5.0.3.tar.gz
- 解压
tar -zxvf redis-5.0.3.tar.gz
- 进入解压后的目录
cd redis-5.0.3
- 执行编译命令
make
注意: 可能会出现你本机的GCC未安装情况,这时应该进行安装(参考:https://blog.****.net/fanwenyuan_fwy/article/details/82225142)。同时,在第二次make的时候需要进行make distclean清除一些不必要的文件,然后再次make。
- 到src目录下执行安装命令
make install
注意: 如果未执行此步骤,在/usr/local/bin/目录是看不到redis-server等可执行文件。
- 测试
- 安装TCL(不是电视那个)
wget http://downloads.sourceforge.net/tcl/tcl8.6.1-src.tar.gz
tar -xzvf tcl8.6.1-src.tar.gz -C /usr/local/
cd /usr/local/tcl8.6.1/unix
./configure
make
make install
- 执行测试命令
make test
2.4 Redis的HelloWorld
- 查看后台redis的进程是否开启
ps -ef | grep redis
- 修改redis.conf文件
[[email protected] redis-5.0.3]# cp redis.conf /myRedis/
[[email protected] redis-5.0.3]# vim redis.conf
# 将GENERAL模块下的daemonize no改为daemonize yes,wq保存退出
- 运行配置
cd /usr/local/bin/
ls -l
[[email protected] bin]# redis-server /myRedis/redis.conf
[[email protected] bin]# redis-cli -p 6379
- 测试运行
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> set k1 hello
OK
127.0.0.1:6379> get k1
"hello"
此时,再检测redis的启动状态(ps -ef | grep redis)会发现
[[email protected] redis-5.0.3]# ps -ef | grep redis
root 112724 1 0 02:25 ? 00:00:01 redis-server 127.0.0.1:6379
root 112728 74127 0 02:26 pts/0 00:00:00 redis-cli -p 6379
root 112928 112789 0 02:35 pts/1 00:00:00 grep --color=auto redis
- 关闭redis
127.0.0.1:6379> shutdown
not connected> exit
2.5 Redis的卸载
先利用kill -9 PID停止redis服务,此处PID是通过ps aux | grep redis查看的redis的进程号。然后到redis的安装目录,比如/usr/local/redis目录,将所有的文件删除。或者直接将redis目录删除。
3.Redis的琐碎知识点
3.1 单进程
单进程模型来处理客户端的请求,对读写等事件的响应是通过对epoll函数的包装来做到的;Redis的实际处理速度完全依靠主进程的执行效率。Epoll是Linux内核为处理大批量文件描述符而作了改进的epoll,是Linux下多路复用IO接口select/poll的增强版本,它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率。
3.2 默认16个数据库
下标从0开始,可从redis.conf文件中查询
# 切换至第1个数据库
127.0.0.1:6379> select 0
OK
# 切换至第6个数据库
127.0.0.1:6379> select 7
OK
127.0.0.1:6379[7]>
3.3 dbsize查看当前数据库的key的数量
# 可以输入命令的前三个后用Tab键补全
127.0.0.1:6379> DBSIZE
(integer) 1
# 列出当前数据库中所有的key值
127.0.0.1:6379> keys *
1) "k1"
127.0.0.1:6379> set k2 v2
OK
127.0.0.1:6379> keys *
1) "k2"
2) "k1"
# 匹配模式的列出
127.0.0.1:6379> keys k?
1) "k2"
2) "k1"
127.0.0.1:6379>
# 判断key是否存在
127.0.0.1:6379> exists k1
(integer) 1
127.0.0.1:6379> exists k1 k2
(integer) 2
#
3.4 清库命令(千万不要用!!!)
- FLUSHDB : 清空当前库
- FLUSHALL : 清空所有库
3.5 密码管理
4.Redis的常用数据类型简介
Redis 命令参考:http://redisdoc.com/
4.1 String
- set
- get
- incr
- decr
- strlen
- getrange
- setrange
- mset
- gset
4.2 hash
- hset
- hget
- hmset
- hmget
- hgetall
- hdel
- hkeys
- hvals
- hexists
4.3 list
- lpush
- rpush
- lrange
- lindex
- llen
- lrem
- lset
- linsert
4.4 set
- sadd
- smembers
- sismember
- scard
- srem
- srandmember
- spop
4.5 zset
- zadd
- zrange
- zrevrange
- zrem
- zcard
- zrangebyscore
- zrevrangebyscore
- zcount
5.事务
- multi: 开始事务
- exec: 执行事务
- discard: 放弃事务
- watch: 监视key
- unwatch: 取消监视key
6.持久化
7.主从复制
通过持久化功能,Redis保证了即使在服务器重启的情况下也不会丢失(或少量丢失)数据,但是由于数据是存储在一台服务器上的,如果这台服务器出现故障,比如硬盘坏了,也会导致数据丢失。
为了避免单点故障,我们需要将数据复制多份部署在多台不同的服务器上,即使有一台服务器出现故障,其他服务器依然可以继续提供服务。
这就要求一台服务器上的数据更新后,自动将更新的数据同步到其他服务器上,那该如何实现呢?
Redis提供了复制(replication)功能自动实现多台redis服务器的数据同步。我们可以通过部署多台redis,并在配置文件中指定这几台redis之间的主从关系,主负责写入数据,同时把写入的数据实时同步到从机器,这种模式叫做主从复制,即master/slave,并且redis默认master用于写,slave用于读,向slave写数据会导致错误。
7.1 Redis主从复制实现
- 方式一: 修改配置文件,启动时,服务器读取配置文件,并自动成为指定服务器的从服务器,从而构成主从复制的关系。
方式一的具体操作
- 新建三个Redis的配置文件,如果Redis启动,先停止,作为master的redis端口是6380,作为slave的redis端口分别是6382,6384,从原有的redis.conf拷贝三份,分别命名为redis6380.conf,redis6382.conf,redis6384.conf;
- 编辑master的配置文件redis6380.conf
include /usr/local/redis-3.2.9/redis.conf
daemonize yes
port 6380
pidfile /var/run/redis_6380.pid
logfile 6380.log
dbfilename dump6380.rdb
- 编辑slave配置文件redis6382.conf和redis6384.conf
- redis6382.conf
include /usr/local/redis-3.2.9/redis.conf
daemonize yes
port 6382
pidfile /var/run/redis_6382.pid
logfile 6382.log
dbfilename dump6382.rdb
slaveof 127.0.0.1 6380
- redis6384.conf
include /usr/local/redis-3.2.9/redis.conf
daemonize yes
port 6384
pidfile /var/run/redis_6384.pid
logfile 6384.log
dbfilename dump6384.rdb
slaveof 127.0.0.1 6380
- 启动redis服务器
# ./redis-server ../redis6380.conf
# ./redis-server ../redis6382.conf
# ./redis-server ../redis6384.conf
# ps -ef | grep redis
# ./redis-cli -p 6380
# info replication
- 方式二: ./redis-server --slaveof ,在启动redis时指定当前服务器成为某个主Redis服务的从Slave。
7.2 容灾处理
当master服务器出现故障时,需要手动将slave中的一个提升为master,剩下的slave挂至新的master上(冷处理,机器挂掉了,再处理)。
- slaveof no one : 将一台slave服务器提升为master
- slaveof 127.0.0.1 6381 : 将slave挂至新的master上
7.2.1 执行步骤
- 停止运行故障的master6380
- 在6382执行命令slaveof no one
- 在6384执行命令slaveof 127.0.0.1 6282
7.2.2 原来的服务器重新添加到主从结构中
- 启动6380的redis服务
# ./redis-server ../redis6380.conf
- 连接到6380端口
# ./redis-cli -p 6380
# info replication
- 将主降为从
# slaveof 127.0.0.1 6382
7.3 高可用Sentinel哨兵
Sentinel哨兵是redis官方提供的高可用方案,可以用它来监视多个Redis服务实例的运行情况。Redis Sentinel是一个运行在特殊模式下的Redis服务器。Redis Sentinel是在多个Sentinel进程环境下互相协作工作的。
7.3.1 Sentinel系统有三个主要任务
- 监控: Sentinel不断地检查主服务器和从服务器是否按照预期正常工作
- 提醒: 被监控的Redis出现问题时,Sentinel会通知管理员或其他应用程序
- 自动故障转移: 监控的主Redis不能正常工作,Sentinel会开始进行故障迁移操作,将一个从服务器升级新的主服务器,让其他从服务器挂到新的主服务器,同时向客户端提供新的主服务器地址。
9.安全设置
9.1 设置密码
访问Redis默认是没有密码的,这样不安全,任意用户都可以访问。可以启用使用密码才能访问Redis。设置Redis的访问密码,修改redis.conf中这行requirepass密码。密码需比较复杂,不容易**,而且需要定期修改。因为redis速度相当快,所以在一台比较好的服务器下,一个外部的用户可以在一秒钟进行150k次的密码尝试,需要指定非常非常强大的密码来防止暴力**。
- 修改redis.conf,找到requirepass行去掉注释,requirepass空格后就是密码
- 绑定ip,修改redis.conf,将# bind 127.0.0.1前面的注释去掉,然后把127.0.0.1改成允许访问你redis服务器的ip地址,表示只允许该ip进行访问,多个ip使用空格分隔。
- 修改redis的端口,这一点很重要,使用默认的端口很危险,redis.conf中修改port 6379 将其修改为自己指定的端口(可随意),端口1024是保留给操作系统使用的,用户可以使用的范围是1024-65535。使用-p参数指定端口,例如: ./redis-cli -p 端口号。
10.使用Jedis操作Redis
Jedis几乎涵盖了Redis的所有命令,操作Redis的命令在Jedis中以方法的形式出现,Jedis完全兼容Redis 2.8.x 和 3.x.x。
- Jedis源码: https://github.com/xetorthio/jedis
10.1 单独使用redis
<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
public class RedisString {
public static void main(String[] args) {
/*
* 通过网络,访问redis服务器
* 1. 修改redis.conf,启动redis需要指定redis.conf的位置
* 2. 关闭Linux防火墙,或者让redis的端口通过防火墙
*/
//创建Jedis对象,指定连接的Redis服务器的IP,端口
/*
* String host: redis所在的Linux服务器的IP
* int port: redis运行的端口号
*/
String host = "192.168.31.128";
int port = 6379;
Jedis jedis = new Jedis(host, port);
//设置访问密码
jedis.auth("123456");
//调用Jedis对象的方法,操作Redis数据
jedis.set("breakfast", "豆浆油条");
//获取key的值
String value = jedis.get("breakfast");
System.out.println("breakfast: " + value);
}
}
10.2 jedis+commons-pool2
jedis单独使用会有线程安全问题
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-pool2 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.4.2</version>
</dependency>
- RedisUtils
public class RedisUtils {
private static JedisPool pool;
/**
* 创建JedisPool对象
*
* @param ip
* @param port
* @return
*/
public static JedisPool open(String ip, int port) {
if (pool == null) {
//创建JedisPoolConfig,给config设置连接池的参数,使用config对象创建JedisPool
JedisPoolConfig config = new JedisPoolConfig();
//设置最大的线程数,一个线程就是一个Jedis
config.setMaxTotal(20);
//设置最大空闲数
config.setMaxIdle(2);
//设置检查项为true,表示从线程池中获取的对象一定是经过检查可用
config.setTestOnBorrow(true);
//创建Pool对象
pool = new JedisPool(config, ip, port, 6000, "123456");
}
return pool;
}
/**
* 关闭pool对象
*/
public static void close() {
if (pool != null) {
pool.close();
}
}
}
- RedisStringPool
public class RedisStringPool {
public static void main(String[] args) {
/*
* 通过网络,访问redis服务器
* 1. 修改redis.conf,启动redis需要指定redis.conf的位置
* 2. 关闭Linux防火墙,或者让redis的端口通过防火墙
*/
//创建Jedis对象,指定连接的Redis服务器的IP,端口
/*
* String host: redis所在的Linux服务器的IP
* int port: redis运行的端口号
*/
String host = "192.168.31.128";
int port = 6379;
//创建JedisPool对象,从JedisPool中获取Jedis
JedisPool pool;
Jedis jedis = null;
try {
pool = RedisUtils.open(host,port);
//从pool中获取Jedis
jedis = pool.getResource();
//调用Jedis对象的方法,操作Redis数据
jedis.set("breakfast", "豆浆油条");
//获取key的值
String value = jedis.get("breakfast");
System.out.println("breakfast: " + value);
}finally {
if (jedis != null){
jedis.close();
}
}
}
}