文章目录
一、了解NoSQL
1.1 概念简介
NoSQL 是以大数据应用为背景发展起来的分布式数据库管理系统。它的产生就是为了解决大规模数据集合,多重数据种类带来的挑战,尤其是大数据应用难题。
NoSQL,泛指非关系型数据库,区别于关系数据库,它们不保证关系数据的ACID特性。它的流行解释是 Not Only SQL,即数据管理不仅是SQL。
ACID特性: 是数据库事务 4 个特性,即原子性、一致性、隔离性、持续性(永久性)
事务是用户定义的一个数据库操作序列,这些操作要么全做,要么都不做,是数据库不可分割的逻辑工作单位。
1.2 NoSql支持的数据模型
- Key-Value 模型
每个 Key 值对应一个 Value,这个 Value 可以是任意类型的数据值,按 Key 值存储、提取。 Value
值是无结构的二进制码或纯字符串,通常需在应用层解析相应结构。
- Big Table 模型
也叫 Columns Oriented 模型。支持结构化的数据,包括列、列簇、时间戳、版本控制等元数据存储。
该模型特点是列簇式,即按列存储,每行数据的各项被存在不同列中,而这些列的集合叫列簇。每列的每个数据项都含一个时间戳属性,以便保存同一数据项的多个版本。
- 文档模型
Value 值支持复杂的结构定义,通常是被转成 JSON 或 类似 JSON
格式的结构化文档;支持数据库索引的定义,其索引主要按字段名组织
- 图模型
记为 G(V,E),V 是点集,E 是边集。V、E 都可以有若干属性。该模型支持图结构的各种基本算法。
1.3 NoSql数据库的优势
现在网站的特点:
- 高并发读写 数据库并发负载非常高,往往达到每秒上万次的读写请求
- 高容量存储和高效存储 通常需要在后台数据库中存储海量数据,如何存储海量数据并进行高效的查询往往是个挑战
- 高扩展性和高可用性 随着系统的用户量和访问量与日俱增,需要数据库能够很方便的进行扩展、维护
优势:
- 易扩展
NoSQL数据库种类繁多,但是一个共同的特点都是去掉关系数据库的关系型特性。数据之间无关系,极易扩展,也无形之间,在架构的层面上带来了可扩展能力。
- 大数据量,高性能
NoSQL 数据库都具有非常高的读写性能,尤其在大数据量下,同样表现优秀。这得益于它的无关系性, 数据库结构简单。
一般MySQL使用 Query Cache,每次表的更新 Cache 就失效,是一种大粒度 Cache,针对 web 交互频繁的应用,Cache 性能不高。而 NoSQL 的 Cache 是记录级的,是一种细粒度 Cache,所以 NoSQL 在这个层面上来说性能高很多。
- 灵活的数据模型
NoSQL 无需事先为要存储的数据建立字段,可随时存储自定义数据格式。而在关系数据库里,增删字段非常麻烦,如果是非常大数据量的表,增加字段简直就是一个噩梦。
- 高可用
NoSQL在不太影响性能的情况,就可以方便的实现高可用的架构。比如Cassandra,HBase模型,通过复制模型也能实现高可用。
1.4 常见的 NoSQL产品
各产品区别,基本按存储格式分
二、Redis介绍(了解就行)
2.1 概念简介
全称:REmote DIctionary Server(远程字典服务器)。是完全开源免费的,用 C 语言编写的, 遵守 BCD 协议。是一个高性能的(key/value)分布式内存数据库,基于内存运行并支持持久化的NoSQL数据库,是当前热门的NoSql数据库之一,也被人们称为数据结构服务器。
Redis 与其他 key - value 缓存产品相比,有以下三个特点
(1) Redis支持数据的持久化,可将内存中的数据保持在磁盘中,重启时可再次加载并使用
(2) Redis不仅支持简单的 key-value 类型的数据,同时还提供 list,set,zset,hash等数据结构的存储
(3) Redis支持数据备份,即 master-slave (主从)模式的数据备份
补充:zset 是 set 的升级,在 set 基础上增加了一个权重参数 score,使得集合中的元素能按 score 进行有序排列。
2.2 Redis优势
(1)性能极高
Redis能读的速度是110000次/s,写的速度是81000次/s 。
(2)数据类型丰富
Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。
(3)原子
Redis的所有操作都是原子性的,同时 Redis 支持对几个操作全并后的原子性执行。
(4)特性丰富
Redis支持 publish/subscribe, 通知, key 过期等等特性
(5) 采用单线程
避免了不必要的上下文切换和竞争条件,不存在多进程或多线程导致的切换而消耗 CPU,不用考虑各种锁的问题,不存在加锁释放锁操作,没有因可能出现死锁而导致的性能消耗;
(6)使用多路 I/O 复用模型,非阻塞 IO;
2.3 Redis应用场景
(1) 缓存(数据查询,短连接,新闻内容,商品内容等),使用最多
(2) 聊天室在线好友列表
(3) 任务队列(秒杀,抢购,12306等)
(4) 应用排行榜
(5) 网站访问统计
(6) 数据过期处理(可以精确到毫秒)
(7) 分布式集群架构中的 session 问题
三、Redis下载与安装(centos7)
3.1 下载
3.2 环境准备
- VMWare
- Linux系统:CentOS7
- 远程命令端xshell,有其他的也行
- 文件传输工具
3.3 安装Redis的编译环境
Redis 是 C 语言开发的,安装 redis 需要先去官网下载源码进行编译,编译需要依赖于 GCC 编译环境,如果 CentOS 上没有安装 gcc 编译环境,需要提前安装,安装命令如下:(这里得用 root 权限处理这些操作)
[root@centos01 ~]# yum install gcc-c++
#记得询问是否下载、是否安装时,输入 y
出现 Complete! 即安装成功。
TCL(Tool Command Language)工具脚本语言,是Linux内的一种语言包。
查看安装命令: whereis gcc tcl
安装命令: yum -y install gcc tcl
3.4 centos7 安装 Redis7.0.0
(1) 用文件传输工具,上传 Redis 安装文件到 Linux 目录。这边上传成功后,在终端输入命令,查看文件是否已存在。(我上传到了自建文件夹 /mysoft/redis)
(2)在当前文件夹下,解压 redis 文件,
[root@centos01 redis]# tar -zxvf redis-x.x.x.tar.gz
ll
看一下,确实解压上了,就 OK 了。
(3)编译Redis(编译,将.c文件编译为.o文件)
进入解压文件夹,执行 make,出现下图,说明编译成功了。
如果编译过程中出错,先删除安装文件目录,后解压重新编译。
(4)安装 Redis7.0.0
[root@centos01 redis-7.0.0]# make PREFIX=/mysoft/redis/soft install
说明:这里的 /mysoft/redis/soft 是自定义的redis安装路径
出现上图后,cd 到 /mysoft/redis/soft,ll 看一下,就是在 redis 的安装位置下出现这个 bin ,就算装好了。
装好后,cd 到 bin 文件夹下,ll ,可发现有这样几个可执行文件。
- redis-benchmark 性能测试工具
- redis-check-aof AOF文件修复工具
- redis-check-rdb RDB文件检查工具(快照持久化文件)
- redis-cli 命令行客户端
- redis-sentinel 监控、通知和自动故障转移
- redis-server redis服务器启动命令
(5)Copy文件
Redis启动需要一个配置文件,可以修改端口号信息。将redis解压的文件夹中的 redis.conf 文件复制到安装目录
cp redis.conf /mysoft/redis/soft
3.5 启动 Redis
3.5.1 Redis的前端启动
cd 至安装目录下的 bin文件,输入命令
./redis-server
下面是启动界面(这个界面只能启动,启动后不能进行其他操作。 ctrl+c 退出前端启动。)
前端模式启动的缺点是启动完成后,不能再进行其他操作,如果要操作必须使用 ctrl+c,同时 redis-server 程序结束,不推荐此方法。
3.5.2 Redis的后端启动
vi ./redis.conf
修改安装目录下的 redis.conf 配置文件。翻到 GENERAL 或 按 /daemonize 搜索,输入 i 进入编辑模式,设置 daemonize yes
,配置 redis 为后台启动。:wq 保存退出
服务启动时指定配置文件(我是在安装目录下输入的这个命令)
./bin/redis-server ./redis.conf
Redis默认端口:6379,通过当前服务进行查看
ps -ef | grep -i redis
#下面弹出redis-server服务信息,说明已启动redis
3.5.3 客户端访问 redis
cd 到 redis 安装目录下,输入命令 ./bin/redis-server ./redis.conf
可通过命令查看 redis 是否已启动
ps -ef | grep -i redis
#下面弹出redis-server服务信息,说明已启动redis
cd 到 bin 文件夹,输入命令 ./redis-cli
,该指令默认连接 ip 地址为 127.0.0.1 ,默认端口号是 6379
输入 ping,测试客户端与 Redis 的连接是否正常,如果连接正常,回收到 pong。输入 quit,退出客户端。
若要连接指定的 ip地址 及 端口号,则需要按照如下语法结构进行连接。 在bin下:./redis-cli -h ip地址 -p 端口号
redis.conf 属性改动:
- daemonize yes #是否要用守护线程的方式启动
yes : redis将一直运行,除非手动kill该进程
no :进入redis的命令行界面,exit 强制退出或关闭连接工具(putty,xshell等)都会导致redis进程退出。- pretected-mode yes
3.5.4 Redis 服务的停止
(1) 强制结束程序。强制终止Redis进程可能会导致redis持久化数据丢失。语法为 kill -9 pid
在安装目录 bin 文件下,输入命令 ps aux|grep -i redis
,查看当前 redis-server 的进程 id —— 可看到是 3614 ,kill -9 3614 可以终止 redis,但不推荐
(2)正确停止Redis
向 Redis 发送 SHUTDOWN 命令
方法为(关闭默认的端口),在安装目录 bin 下,输入命令./redis-cli shutdown
。再查看一下进程,可发现进程 id 为 3614 的redis服务进程已关闭
如果后面开了主从机,还需密码验证,则用下面这条指令关闭
#-a后面是密码
./bin/redis-cli -h 192.168.xxx.xxx -p xxxx -a xxx shutdown
服务启动到终止命令总结如下(按自己的安装目录来)
cd /mysoft/redis/soft/bin
vi ../redis.conf
./redis-server ../redis.conf
ps -ef | grep -i redis
#ps aux|grep -i redis
./redis-cli
#ping
#./redis-cli -h 192.168.xxx.xxx -p 6379
#./redis-cli -h ip地址 -p 端口号
./redis-cli shutdown
3.5.5 第三方工具(redis-desktop-manager)操作redis
(1)关闭 linux 防火墙,
- 关闭防火墙
systemctl stop firewalld
- 查看防火墙状态
systemctl status firewalld
- 启动防火墙
systemctl start firewalld
(2)改 redis.conf 参数
- bind linux的ip地址
- daemonize yes #是否要用守护线程的方式启动
- pretected-mode yes
- requirepass xxx # 密码自定义
在客户端(linux终端)输入如下命令
ps -ef | grep -i redis
kill -9 进程号 #把redis-server的进程关掉
vi ../redis.conf # 改文件参数
./redis-server ../redis.conf #启动服务
ps -ef | grep -i redis #会发现多了一个虚拟机地址的redis服务
./redis-cli -h 192.168.xxx.xxx -p 6379
auth xxx #密码
ping # 可以 ping通
打开后,点击绿色加号进行连接
输入 linux ip地址,密码,随便输个名字,点ok,就能连上了。双击左侧连好的redis,就能看到16个默认数据库
四、Redis 的数据结构
Redis是一种基于内存的数据库,并提供一定的持久化功能,是一种键值(key-value)数据库,用 key 作索引找到当前缓存的数据,并返回给程序调用者。
当前的 Redis 支持 6 种数据类型,它们分别是字符串(String)、列表(List)、集合(set)、哈希结构(hash)、有序集合(zset)和基数(HyperLogLog)
注意 set 时无序的,与 Java 类似,重点在五种,而基数类型用的比较少
五、常用命令
5.1 String 类型
存单个值 set key value
存多个值 mset key1 value1 key2 value2
取 get key
删除 del key
,成功返回1 ,失败返回0
5.2 字符串数字的递增与递减
- 递增
incr key
# 默认从0起,每执行一次自增1
- 递减
decr key
- 增减指定步长 (了解)
自增指定步长incrby key x
,# 默认从0起,执行一次自增 x
自减指定步长decrby key x
5.3 Hash散列 (了解)
hash叫散列类型,它提供了字段和字段值的映射。字段值只能是字符串类型,不支持散列类型、集合类型等其它类型。相当于是对象 (类似Java> 对象)格式的存储
-
设置一个字段值,语法 :
hash key field value
, HSET命令不区分插入和更新操作,当执行插入操作时HSET命令返回1,当执行更新操作时
返回0.
-
取值语法 :
hget key field
-
设置多个字段语法:
hmset key field value [field value ...]
-
取多个值语法:
hmget key field [field ...]
-
获取所有字段值语法:
hgetall key
-
删除字段语法:
hdel key field [field ...]
5.4 队列类型
Redis 的 list 是采用来链表来存储,双向链表存储数据。
特点:增删快、查询慢(Linkedlist)、队列有序
向列表左边增加元素: lpush key value [value ...]
从列表左边弹出元素: lpop key
(临时存储,弹出后,从队列中清除)
向列表右边增加元素 : rpush key value [value ...]
从列表右边弹出元素: rpop key
获取列表中元素的个数: llen key
查看列表语法:lrange key start stop
返回start、stop之间的所有元素(包含两端的元素),索引从0开始,可以是负数,如:“-1”代表最后的一个元素。
5.5 Set集合
Set集合类型:无序、不可重复
增加元素语法:sadd key member [member ...]
删除元素语法: srem key member [member ...]
获得集合中的所有元素 : smembers key
判断元素是否在集合中: sismember key member
5.6 Zset有序集合
Sortedset 又叫zset,是有序集合,可排序的,但是唯一。 Sortedset 和 set 的区别是会给 set 中的元素添加一个分数,然后通过这个分数进行排序。(不是指数值上的分数,类似学生成绩、销量数据这些)
- 向有序集合中加入一个元素和该元素的分数(score),如果该元素已经存在则会用新的分数替换原有的分数。
增加元素:zadd key score member [score member ...]
在上面这个例子是为 num1 这个有序集合,加了 stu1 、stu2 、 stu3 共 3 个元素,其分数分别为 20、30、40
添加带分数(可用学生成绩,销售数量等来做分数,方便计算排序):
- 获得排名在某个范围的元素列表,并按照元素分数降序返回
语法:zrevrange key start stop [withscores]
- 获取元素的分数 :
zscore key member
- 删除元素
zrem key member [member ...]
- 获得元素的分数的可以在命令尾部加上 withscores 参数
5.7 HyoperLogLog命令
HyperLogLog 是一种使用随机化的算法,以少量内存提供集合中唯一元素数量的近似值。可以接受多个元素作为输入,并给出输入元素的基数估算值。
- 基数:集合中不同元素的数量。比如 {‘apple’, ‘banana’, ‘cherry’, ‘banana’, ‘apple’} 的基数就是 3
- 估算值:算法给出的基数并不精确,可能会比实际稍多一些或稍少一些,但会控制在合理范围内
HyperLogLog 的优点是,即使输入元素的数量或者体积非常非常大,计算基数所需的空间总是固定的、并且是很小的。
Redis 里面,每个 HyperLogLog 键只需 12 KB 内存,就可以计算接近 2^64 个不同元素的基数。这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比。
但是,因为 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能像集合那样,返回输入的各个元素。
相关指令:
5.8 其他命令
(1) keys 返回满足给定 pattern 的所有key
keys user* //查询以user开头的key
keys * //查询所有的key
(2)exists 确认一个 key 是否存在,存在返回1
127.0.0.1:6379> exists num2 //语法:exists key
(integer) 1
127.0.0.1:6379> exists num23
(integer) 0
(3) del 删除一个 key
127.0.0.1:6379> del num1 //语法: del key 删除存在的key返回1,不存在的key返回0
(integer) 1
127.0.0.1:6379> del num23
(integer) 0
(4) rename 重命名 key:rename oldkey newkey
127.0.0.1:6379> rename k1 k11
OK
127.0.0.1:6379> keys *
1) "ulist"
2) "k2"
3) "user1"
4) "num2"
5) "clist"
6) "k11"
(5) type 返回值的类型: type key
127.0.0.1:6379> type ulist
set
127.0.0.1:6379> type k11
string
127.0.0.1:6379> type alist
list
设置 key 的生存时间:缓存的数据一般都是需要设置生存时间的,即:到期后数据销毁。
(6) expire key seconds
设置 key 的生存时间(单位:秒)key在多少秒后会自动删除
ttl key
查看key剩余的生存时间
persist key
清除生存时间
127.0.0.1:6379> set a1 123
OK
127.0.0.1:6379> get a1
"123"
127.0.0.1:6379> expire a1 60
(integer) 1
127.0.0.1:6379> ttl a1
(integer) 56
127.0.0.1:6379> ttl a1
(integer) 51
127.0.0.1:6379> ttl a1
(integer) 47
(7) 获取服务器信息和统计:info
(8)删除当前选择数据库中的所有key:flushdb
(9)删除所有数据库中的所有 key:flushall
5.9 Redis的多数据库
一个redis实例key包括多个数据库,客户端可以指定连接某个redis实例的哪个数据库,就好比一个mysql中创建多个数据库,客户端连接时指定连接哪个数据库。
一个redis实例最多可提供16个数据库,下标从0-15,客户端默认连接第0号数据库,也可以通过select选择连接哪个数据库,如下连接1号库:
切换至 0数据库下面
将 key 的数据移动到1号数据库: move key 数据库编号
六、Redis的事务管理
Redis 事务可以一次执行多个命令。
事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
事务是一个原子操作:事务中的命令要么全部被执行,要么全部都不执行。
一个事务从开始到执行会经历以下三个阶段:
- 开始事务
- 命令入队
- 执行事务
以下是一个事务的例子, 它先以 MULTI 开始一个事务, 然后将多个命令入队到事务中, 最后由 EXEC 命令触发事务, 一并执行事务中的所有命令:
示例1:
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set bookname java
QUEUED
127.0.0.1:6379> set bookname c++
QUEUED
127.0.0.1:6379> set bookname html
QUEUED
127.0.0.1:6379> exec
1) OK
2) OK
3) OK
示例2:
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set u1 user1
QUEUED
127.0.0.1:6379> get u1
QUEUED
127.0.0.1:6379> sadd tag c++ html java
QUEUED
127.0.0.1:6379> smembers tag
QUEUED
127.0.0.1:6379> exec
1) OK
2) "user1"
3) (integer) 3
4) 1) "java"
2) "html"
3) "c++"
七、Redis发布订阅模式
Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。
Redis 客户端可以订阅任意数量的频道。
下图展示了频道 channel1 , 以及订阅这个频道的三个客户端 —— client2 、 client5 和 client1 之间的关系:
当有新消息通过 PUBLISH 命令发送给频道 channel1 时, 这个消息就会被发送给订阅它的三个客户端:
样例:
(1)在实例中创建一个名为 redisMessage 的订阅频道
127.0.0.1:6379> subscribe redisMessage
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "redisMessage"
3) (integer) 1
(2)重新开启一个 redis 客户端,然后在同一个频道 redisMessage 发布两次消息,订阅者就能接收到消息。
127.0.0.1:6379> publish redisMessage "demo1 test"
(integer) 1
127.0.0.1:6379> publish redisMessage "demo2 test"
(integer) 1
127.0.0.1:6379> publish redisMessage "demo3 test"
(integer) 1
订阅者的客户端会显示如下消息
127.0.0.1:6379> subscribe redisMessage
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "redisMessage"
3) (integer) 1
1) "message"
2) "redisMessage"
3) "demo1 test"
1) "message"
2) "redisMessage"
3) "demo2 test"
1) "message"
2) "redisMessage"
3) "demo3 test"
八、Jedis 连接 Redis
8.1 版本问题
我用的 redis 7.0.0 ,目前看最新的 Jedis 版本 为 5.1.2(24/04 )
github redis
github redis readme 这个可能打不开,先开前面那个,打开后找 readme 文档
jedis guide 这是 Redis 官网的 Jedis 手册
8.2 确认网络并关闭虚拟机防火墙
(1)确认远程服务器(就是 windows终端)是否可以 ping 通虚拟机的 ip 地址
(2)确认虚拟机防火墙是否关闭
systemctl status firewalld
systemctl stop firewalld
(3)开启 redis 服务
cd /mysoft/redis/soft/bin
ps -ef | grep -i redis
./redis-server ../redis.conf
ps -ef | grep -i redis #看到开启了redis服务就可以了
8.3 idea2023 创建项目,导入依赖
创建 maven 项目,选那个webapp,在 pom 文件里加上以下代码:
<dependencys> // 加在这对标签里面
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>5.1.2</version>
</dependency>
</dependencys>
第一次用会报错 :
Dependency ‘redis.clients:jedis:5.1.2’ not found
就需要同步依赖,点右侧 maven 工具栏的刷新图标(Reload all maven projects)。同步依赖后需要重构项目以使其生效,右键点击项目,点 Rebuild Project 。
8.4 链接服务器
注意 第一次弄之前,要先把 redis.conf 跟着前面 3.5.5 改好,尤其 bind 虚拟机ip地址
改好,不然连不上。
另外,连接前:
- 关防火墙
- cd 到 bin,
./redis-server ../redis.conf
把服务启来。 - 检查一下开了没
ps -ef | grep -i redis
8.4.1 方法 1 —— 单实例链接
public static void main(String[] args){
//建立链接
Jedis jedis=new Jedis("192.168.xxx.xxx",6379);
// 如果 Redis 服务器设置了密码,使用 auth 方法进行认证
String password = "xxxx";
jedis.auth(password);
//设置值 set = key - value 的存值
jedis.set("key1","java工程师");
//get = 通过 key 进行取值
String key1 = jedis.get("key1");
System.out.println(key1);
}
有一个问题,输出中文乱码:
照着下面这两位博主的博文改的
夏丶微凉 解决办法:IDEA 控制台中文乱码的几种解决方案
——这个改了没成
算法与编程之美 腾讯云开发社区 —— 又按这个更改的,成了。
8.4.2 方法 2 —— 连接池
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
public class Demo2_ConnectionPool {
public static void main(String[] args){
//初始化连接池
//1. 创建连接池配置的工具类对象,设置配置项
JedisPoolConfig config = new JedisPoolConfig();
//1.1 Jedis最大的连接数
config.setMaxTotal(20);
//1.2 Jedis最大的连接空闲
config.setMaxIdle(10);
//声明 Jedis 对象
JedisPool jedisPool = null;
Jedis jedis = null;
try {
//2.创建连接池对象
// 如果Redis服务器设置了密码,就在端口号后面加上 timeout、password参数
jedisPool = new JedisPool(config, "192.168.xxx.xxx", 6379,2000,"xxx");
//3.获得 Jedis 资源
jedis = jedisPool.getResource();
//4.设置数据
jedis.set("name", "张三");
//获取对应值
String name = jedis.get("name");
System.out.println("name = " + name);
} catch (Exception e) {
e.printStackTrace();
} finally {
//关闭资源
if (jedis != null) {
jedis.close();
}
// 虚拟机关闭的时候,释放资源
if (jedisPool != null) {
jedisPool.close();
}
} //finally
} //main()
}//class Demo2_ConnectionPool
报错了!(#°Д°)
感觉重点在这块:
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
redis.clients.jedis.exceptions.JedisConnectionException: Failed to connect to any host resolved for DNS name.
Suppressed: java.net.SocketTimeoutException: connect timed out
突然想起来,没关防火墙,去关了之后,能输出了,但还是报错
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
org.slf4j.impl.StaticLoggerBinder
是SLF4J内部使用的类,当系统找不到这个类时,就意味着SLF4J的相关库没有被正确地添加到项目中。可能由以下原因造成:
1、缺少依赖(我是这个原因,添上后就成了)
在pom.xml文件中添加下面的依赖,加上后记得点maven的刷新小图标,就是那个 reload all maven projects
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.30</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.30</version>
</dependency>
成功了
2、版本冲突:可能在项目中用了不同版本的SLF4J库,导致冲突。确保项目中所有SLF4J相关库都是同一版本。
3、类路径问题:可能类路径(CLASSPATH)设置不正确,导致SLF4J库没有被正确加载。检查项目设置,确保SLF4J库在类路径中。
4、IDE问题:如果你在使用IDE(如Eclipse或IntelliJ IDEA),可能是IDE缓存的问题。尝试重启,或者清理并重建项目。
5、其他库的干扰:项目中可能包含一些与SLF4J冲突的库。检查项目依赖,尝试排除这些冲突的库。
若以上方法都不能解决问题,就进一步检查项目配置和环境设置,或者考虑使用其他日志框架,如 Logback 或 Log4j
8.4.3 服务端存储确认
打开 redis 桌面管理工具,连好redis所用 ip,打开 db0,可以发现存好的值
方法 1 存上的 key1
方法 2 存上的 name
九、redis 持久化存储方式
关闭电脑后,开启,再次启动 redis,可以发现这些数据依然存在,这是因为redis的值放在内存中。
为防止突然断电等特殊情况的发生,需要对数据进行持久化备份。即将内存数据保存到硬盘,跟数据库是一样的。
9.1 RDB持久化
RDB 是一个二进制文件,在某个时间点将数据写入一个临时文件,持久化结束后,用这个临时文件替换上次持久化的文件,达到数据恢复。
优点:使用单独子进程来进行持久化,主进程不会进行任何 IO 操作,保证了 redis 的高性能。
缺点:RDB 是间隔一段时间进行持久化,如果持久化之间,就是他间隔的这段时间里, redis 发生故障,就会发生数据丢失。所以这种方式更适合数据要求不严谨的时候。
这个执行数据写入到临时文件的时间点 ,是可以通过配置来自己确定的,通过配置redis ,在 n 秒内如果超过 m 个 key 被修改,就执行一次 RDB 操作。
这个操作就类似于在这个时间点来保存一次 Redis 的所有数据。所有这个持久化方法也通常叫做 snapshots。
RDB 默认开启,redis.conf 中的具体配置参数如下;
#dbfilename:持久化数据存储在本地的文件
dbfilename dump.rdb
#dir:持久化数据存储在本地的路径,如果是在/redis/redis-5.0.5/src下启动的redis-cli,则数据会存储在当前src目录下 dir ./
#snapshot触发的时机,save
#如下为900秒后,至少有一个变更操作,才会snapshot
#对于此值的设置,需要谨慎,评估系统的变更操作密集程度
#可以通过“save”来关闭snapshot功能
#save时间,以下分别表示更改了 1个key,隔 900s进行持久化存储;更改了10个key,隔300s进行存储;更改10000个key隔60s进行存储。
save 900 1
save 300 10
save 60 10000
#当snapshot时出现错误无法继续时,是否阻塞客户端“变更操作”,“错误”可能因为磁盘已满/磁盘故障/OS级别异常等
stop-writes-on-bgsave-error yes
##是否启用rdb文件压缩,默认为“yes”。但压缩了就会造成“额外的cpu消耗”,同时也意味这较小的文件尺寸以及较短的网络传输时间
rdbcompression yes
因为前面用 redis 练习过,再打开安装目录时,能看到多出来一个 dump.rdb 文件
关闭服务后,把这个删了,再去 bin 下确认没有这个文件后,重新开启服务,登录虚拟机ip、 端口6379,查询之前存过的值,就会发现空了,没有了。(测试时使用root用户操作)
用到的相关命令罗列如下
cd /mysoft/redis/soft/bin
./redis-server ../redis.conf
./redis-cli -h 192.168.xxx.xxx -p 6379
auth xxx #密码
keys *
set u1 stu1
set u2 stu2
key *
shutdown #再按ctrl + c
ps -ef|grep -i redis
ls #在bin里
rm -rf dump.rdb
ls
cd ../ #到安装目录,即bin的父目录
ls # soft里
rm -rf dump.rdb
ls # 备份删除完毕
#重启服务
cd bin
./redis-server ../redis.conf
./redis-cli -h 192.168.xxx.xxx -p 6379
auth xxx #密码
keys * #可发现,空了
9.2 AOF持久化
这个更可靠,但是默认关闭,要修改配置文件 redis.conf 的属性为 appendonly yes
才能打开。(只有在“yes”下,aof 重写/文件同步等特性才会生效)
Append-Only File,将“操作 + 数据”以格式化指令的方式追加到操作日志文件的尾部,在 append 操作返回后(已经写入到文件或者将要写入),才进行实际的数据变更,“日志文件”保存了历史所有的操作过程。
当需要数据恢复时,可直接 replay 此日志文件,即可还原所有操作。
优点: 可保持更高的数据完整性,如果设置追加 file 的时间是 1s,如果 redis 发生故障,最多丢失 1s 的数据;
且如果日志写入不完整,支持 redis-check-aof 来进行日志修复; AOF 文件没被 rewrite
之前(文件过大时会对命令进行合并重写),可以删除其中的某些命令(比如误操作的 flushall)。缺点:AOF 文件比 RDB 文件大,且恢复速度慢。
AOF文件只记录“变更操作”(如:set/del 等),如果 server 中持续的大量变更操作,会导致 AOF 文件非常庞大。当 server 失效后,数据恢复的过程将会很长;事实上,一条数据经多次变更,会产生多条 AOF 记录,其实只保存当前状态,历史操作记录是可抛弃的。
若期望数据更少的丢失,则可采用 AOF 模式。 如果 AOF 文件正在被写入时,突然 server
失效,则可能导致文件的最后一次记录不完整,可通过手工或程序去检测并修正不完整记录,以便通过 AOF 文件恢复能够正常。若 redis
持久化手段中有 aof,那么在server 故障失效后再次启动前,需要检测 aof 文件的完整性。
测试:
1、先把安装目录及其bin文件下的 dump.rdb 删掉。 rm -rf dump.rdb
2、修改redis.conf 的属性,保存退出后,启动一下配置服务。 ./bin/redis-server redis.conf
3、通过客户端访问一下 redis 服务。 ./bin/redis-cli -h 192.168.xxx.xxx -p 6379
4、auth password
5、查询一下之前存的值,会发现都删掉为空了。 keys *
6、存几个值,看前面的 五、常用命令 ,存完查一下,确认存好后, quit 退出
7、在安装目录下 ll ,可看到生成了一个 appendonlydir目录,cd 进去后有三个文件,其中 appendonly.aof.1.incr.aof 保存了我们刚刚的设值操作
十、 Redis 主从复制(重点)
为在单台服务器故障下,保证服务的高可用,采用 主从复制机制 ——主:主机 master; 从:从机 slave
主 redis 中的数据和从上的数据保持实时同步,当主 redis 写入数据时,通过主从复制机制,复制到两个从服务上。 主从复制不会阻塞 master,在同步数据时,master 可以继续处理 client 请求。
![](https://i-blog.csdnimg.cn/blog_migrate/30f6099ba14338115c0ce1299907c745.png)
数据会同步到从服务器。在这个集群中的几台服务器上都有同样的数据。
工作中一般选用:一主两从 或 一主一从
单机版主从搭建步骤(用 root 权限):
主机:不用配置。仅需配置从机,从机 slave 配置:(这里是伪集群)
为方便远程redis连接,先关防火墙 systemctl stop firewalld
step 1:复制出一个从机。在 redis 的安装位置下复制它的安装文件夹,像下面这样
#前面那个redis是我们配置好了的redis安装文件夹,后面的那个是要复制出来的从机名字
[root@localhost myapps]# cp redis/ redis1 -r
[root@localhost myapps]# ll
总用量 40
drwxr-xr-x. 3 root root 4096 2月 1 09:26 redis
drwxr-xr-x. 3 root root 4096 2月 1 09:27 redis1
step 2:修改从机的 redis.conf
- 打开文件后,输入/replicaof 检索这个属性,当前页面找不到,就按 n ,找下一页。找下面这个,把前面的 # 去了,后面那两个修改为 主机IP(就是虚拟机的IP)、主机端口号 6379
![](https://i-blog.csdnimg.cn/blog_migrate/1143691e02bc2af02121f15f656aee08.png)
- 修改从机端口号
检索 port 6379 ,端口号改成 6380,保存退出
step 3:删除对应的持久化文件 rm -rf appendonlydir dump.rdb
step 4:启动从机 ./bin/redis-server ./redis.conf
step 5:启动从机 6380客户端 ./bin/redis-cli -h 192.168.xx.xxx -p 6380
记得 auth 密码 验证。
最好有密码,我这里不改上密码,就无法在客户端操作。改密码操作看前面 3.5.5 (引用文本框里最后一条)
ping 一下,看能否收到 pong;
把主机的 redis 6379客户端服务也启开,看能否 ping 通,主、从都必须能 ping 通 。
主从机连不上的试一下:
- 主、从机的 redis.conf 中, protected-mode 都改成 no
- 从机的 redis.conf 中,masterauth属性去# ,后面改上主机密码
好吧,我的主从机还是没连上,不知道是不是没重启的原因。太晚了,明天再改。 改好了!!连不上的试试重启虚拟机,关防火墙。
主机的6379客户端输入 info replication,会显示
在从机的 redis 6380客户端:
输入info replication,会出现 role:slave。看到下面这条信息,显示 up ,说明主从机已连好;若没连上,则显示 down。
停止客户端 ./bin/redis-cli -h 192.168.xxx.xxx -p 6380 shutdown
主机一般用于存储数据,从机只能读数据,无法写入。
主Redis每当接收到写命令时,会将命令发给 从Redis,保证数据的一致。—— 内部完成,所以不支持客户端在 从机 人为写数据。
在主机增删改数据,从机会自动同步数据。
——到此,一主一从的主从复制已搭建完毕!
复制架构中出现宕机情况:
从Redis宕机:重启就好
要是主的那个不行了,看下面
十一、哨兵模式(重点)
哨兵是一个独立进程,监控 redis 系统运行情况。主要作用如下:
- 监控 主数据库 和 从数据库 是否运行正常;
- 主数据 出现故障后,自动将 从数据库 转为 主数据库;
如果主机宕机,开启选举工作,选一个从机做主机。
![](https://i-blog.csdnimg.cn/blog_migrate/cd61ab7bc3619b37e5b23a1bc3da8c54.png)
11.1 搭建单机版的一主两从
下面,先准备一主两从,在启动任一从机时,启动哨兵模式。因为前面弄了一个从机,这里再搞一个就 OK
step1:跟前面主从复制的搭建一样,把从机复制一份:cp redis1/ redis2 -r
step2:打开 redis.conf,修改属性
- 改端口号为 port 6381
- 改 replicaof 主机ip 主机端口号6379
- :wq 保存退出
step3:清除持久化文件,安装文件夹下以及其 bin文件下的 dump.rdb、appendonlydir下所有文件。
step4:确认关闭所有 redis 进程后:
- 逐个启动 Redis 服务
./bin/redis-server ./redis.conf
- 访问客户端
./bin/redis-cli -h 192.168.xxx.xxx -p 63xx
- ping一下,能通就 ok
- 查看各自的主从关系是否正确
info replication
看一下显示的角色、从机数量、端口号、连接状态是否正确。
至此,一主两从搭建完毕。
搭建单机版 一主两从三哨兵模式:
大林子先森的博客
十二、redis 集群
12.1 redis-cluster 架构图
(1) 所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽;
(2) 节点的fail是通过集群中超过半数的节点检测有效时整个集群才生效;
(3) 客户端与redis节点直连,不需要中间proxy层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可;
(4) redis-cluster把所有的物理节点映射到[0-16383]slot上,cluster 负责维护 node<->slot<->value
Redis 集群中内置了 16384 个哈希槽,当需要在 Redis 集群中放置一个 key-value 时,redis 先对 key 使用 crc16 算法算出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,redis 会根据节点数量大致均等的将哈希槽映射到不同的节点。
示例:
12.2 redis-cluster 投票:容错
心跳机制:
(1) 集群中所有 master 参与投票,如果半数以上 master 节点与其中一个 master 节点通信超过(cluster-node-timeout),认为该 master 节点挂掉;
(2) 什么时候整个集群不可用 (cluster_state:fail) ?
- 如果集群任意 master 挂掉,且当前 master 没有 slave,则集群进入fail状态。也可以理解成集群的 [0-16383] slot 映射不完全时进入 fail 状态。
- 如果集群超过半数以上 master 挂掉,无论是否有 slave,集群进入 fail 状态
12.3 集群命令
启动所有的实例: ./startall.sh
startall.sh 自定义的 启动端口为 7001-7006 六台机器的启动命令的 shell 脚本,写完记得改权限
chmod u+x startall.sh
创建集群(关闭防火墙)
在任意一台上运行,redis-cli --cluster create ip:port ip:port --cluster-replicas 1
./redis-cli --cluster create 192.168.xxx.xxx:7001 192.168.xxx.xxx:7002
192.168.xxx.xxx:7003 192.168.xxx.xxx:7004 192.168.xxx.xxx:7005 192.168.xxx.xxx:7006 --cluster- replicas 1 -a xxx # -a后是密码,没有密码的不用加这个
连接集群 ./bin/redis-cli -h 127.0.0.1 -p 7001 -a xxx -c
( -c:指定是集群连接 )
7001客户端输入 set username aaa ,后面会跳到 7003 ,在 7003 客户端中可以查询到这个信息 get username
cluster info
# 查看集群信息
cluster nodes
# 查看集群中节点信息
最好别设密码,不用密码也能连redis,有密码时,java 连它不方便
把 redis.conf 中,requirepass xxx 以及 masterauth xxx 注释掉即可
12.4 Jedis连接集群
(1) 关闭防火墙
如果redis重启,需要将 redis 中生成的dump.rdb和nodes.conf文件删除,然后再重启。
(2) 代码实现 —— 版本问题看 8.1
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>5.1.2</version>
</dependency>
public static void main(String[] args) throws IOException {
// 创建一连接,JedisCluster对象,在系统中是单例存在
Set<HostAndPort> nodes = new HashSet<HostAndPort>();
nodes.add(new HostAndPort("192.168.xxx.xxx", 7001));
nodes.add(new HostAndPort("192.168.xxx.xxx", 7002));
nodes.add(new HostAndPort("192.168.xxx.xxx", 7003));
nodes.add(new HostAndPort("192.168.xxx.xxx", 7004));
nodes.add(new HostAndPort("192.168.xxx.xxx", 7005));
nodes.add(new HostAndPort("192.168.xxx.xxx", 7006));
JedisCluster cluster = new JedisCluster(nodes);
// 执行JedisCluster对象中的方法,方法和redis指令一一对应。
cluster.set("test", "hahaha");
String result = cluster.get("test");
System.out.println(result);
//存储List数据到列表中
cluster.lpush("site-list", "python");
cluster.lpush("site-list", "java");
cluster.lpush("site-list", "sql");
// 获取存储的数据并输出
List<String> list = cluster.lrange("site-list", 0 ,2);
for(int i=0; i<list.size(); i++) {
System.out.println("列表项为: "+list.get(i));
}
// 程序结束时需要关闭JedisCluster对象
cluster.close();
System.out.println("集群测试成功!");
}
十三、缓存
广义的缓存:
第一次加载某些可能会复用的数据时,在加载数据的同时,将数据保存到一个指定地点。下次加载时,从该地点取数据。(前提:从这个地方取数据,比从数据源取数据要快的多)
Java缓存大概分类(正常来说,速度由上到下依次减慢)
- 本地缓存(虚拟机缓存)—— ehcache,JBoss Cache
- 分布式缓存 —— redis,memcache
- 数据库缓存