Redis-全面详解(学习总结---从入门到深化)

227 阅读1小时+

目录

Redis概述_为什么要用NoSQL

 单机Mysql的美好年代

 Tomcat与数据库分开部署

 引入本地缓存和分布式缓存

 引入反向代理实现负载均衡

 数据库读写分离

 数据库按业务分库

为什么用NoSQL

 Redis概述_什么是NoSQL

 什么是NoSQL

 结构化数据和非结构化数据

 NoSQL的四大分类

 KV型NoSql(代表----Redis)

 列式NoSql(代表----HBase)

 文档型NoSql(代表----MongoDB)

 搜索型NoSql(代表----ElasticSearch)

 关系型数据库和非关系型数据及其区别

关系型数据库

 非关系型数据库

 Redis概述_当下NoSQL经典应用

 当下应用是SQL和NoSQL一起使用

 淘宝商品信息如何存放

 商品基本信息

 商品描述、详情、评论

 商品的图片

 商品关键字

 商品热门的波段信息

 发现问题

 解决问题

UDSL统一数据服务平台

 UDSL热点缓存设计

 Redis概述_Redis是什么

Redis是什么 

 谁在用Redis

 Redis安装_Linux下安装Redis

 下载地址

 下载Redis

 安装GCC

 安装Redis

编译Redis

 安装Redis

服务启动

后台启动

客户端启动

 Redis安装_Docker下安装Redis

 下载最新Redis镜像

 启动Redis容器

观察Redis启动效果

 查看Redis的版本

Redis服务器和客户端

Redis安装_基本知识

 默认16数据库

 Redis 使用的到底是多线程还是单线程?

 IO多路复用技术

 切换数据库

 清空当前库

 通杀全部库

 为什么默认端口6379

 Redis数据类型_key键

 keys

 exists

 type

 del

expire 

ttl 

persist 

 Redis数据类型_String

 简介

 常用命令

set

 get

 使用场景

 Redis数据类型_List

 简介

 常用命令

lpush/rpush

 lrange

 lpop/rpop

 lindex

 llen

 lrem

 linsert

 lset

 使用场景

 Redis数据类型_Set

 简介

 常用命令

sadd

 smembers

 sismember

 scard

 srem

 spop

srandmember 

 smove

 sinter

 sunion

 sdiff

Redis数据类型_Hash 

 简介

常用命令 

hset

 hget

 hmset

 hexists

 hkeys

 hvals key

 hincrby

 hdel

hsetnx 

 Redis数据类型_Zset

 简介

 常用命令

zadd

 zrange

 zrangebyscore

 zincrby

zrem 

zcount 

 zrank

 Redis数据类型_Bitmaps

 简介

 常用命令

setbit

 getbit

 bitcount

 bitop

Redis数据类型_Geospatia 

 简介

 常用命令

geoadd

 geopos

 geodist

 georadius

 Redis数据类型_Hyperloglog

 简介

 什么是基数

 常用命令

pfadd

 pfcount

 pfmerge

使用场景 

 Redis可视化工具_安装Redis_Desktop_Manager

 下载Redis Desktop Manager

 选择安装路径

 连接Redis服务

关闭防火墙

关闭保护模式

开启远程访问

 配置连接服务

 配置信息

 Java整合Redis_Jedis操作

什么是Jedis 

引入Jedis

创建maven工程

引入maven依赖 

Jedis连接到redis

测试相关数据类型 

连接Redis服务

Jedis-API:String

Jedis-API:Keys

Jedis-API:List

Jedis-API:Set

Jedis-API:Hash

Jedis-API:Zset

Jedis-API:Bitmaps

Jedis-API:Geospatia

Jedis-API:Hyperloglog

Java整合Redis_Spring-Data-Redis 

简介 

RedisTemplate介绍

 RedisTemplate中定义了对5种数据结构操作

StringRedisTemplate与RedisTemplate

 pom.xml添加依赖

在application.properties中配置

自定义序列化

使用redisTemplate进行各类型的CURD操作

String数据类型操作

Hash类型的操作

set类型的操作

zset类型的操作

list类型的操作

Redis构建web应用实践_网页缓存

创建springboot项目 

选择组件 

编写配置文件 

创建表

 编写持久层

编写业务层

编写控制层

下载压测工具

启动Jmeter工具 

修改语言 

创建压测任务 

 添加HTTP请求

 配置HTT请求

 添加压测结果报告

 没有加缓存的吞吐量

​编辑 添加Redis缓存

继续压力测试

 Redis配置文件详解

units单位 

 INCLUDES

NETWORK 

GENERAL 

 SNAPSHOTTING

REPLICATION 

SECURITY 

CLIENTS 

 MEMORY MANAGEMENT

APPEND ONLY MODE 

​编辑 LUA SCRIPTING

REDIS CLUSTER 

 Redis其他功能_发布与订阅

什么是发布与订阅 

 什么时候用发布订阅

Redis的发布与订阅 

发布订阅命令行实现 

订阅

 发布命令

Redis其他功能_慢查询 

什么是慢查询 

Redis命令执行的整个过程

什么是慢查询日志 

如何获取慢查询日志 

 如何获取慢查询日志的长度

怎么配置慢查询的参数 

如何进行配置 

查看慢日志配置

 修改Redis配置文件

使用 config set 命令动态修改。 

 Redis其他功能_流水线pipeline

1次网络命令通信模型 

批量网络命令通信模型 

什么是流水线? 

案例展示 

pipeline-Jedis实现 

首先,引入jedis依赖包:

没有pipeline的命令执行

使用pipeline 

Redis数据安全_持久化机制概述 

持久化机制概述 

持久化机制的意义 

Redis提供了两个不同形式的持久化方式 

Redis数据安全_RDB持久化机制实战 

RDB是什么 

配置dump.rdb文件 

触发机制-主要三种方式 

RDB配置

配置新的保存规则 

 flushall

save与bgsave 

高级配置 

stop-writes-on-bgsave-error

rdbcompression 

rdbchecksum 

恢复数据 

 Redis数据安全_AOF持久化机制实战

 AOF是什么

 AOF默认不开启

 AOF启动/修复/恢复

开启AOF

AOF同步频率设置 

 Redis数据安全_如何选用持久化方式

 不要仅仅使用RDB

 也不要仅仅使用AOF

 综合使用AOF和RDB两种持久化机制

 Redis事务_事务的概念与ACID特性

 数据库层面事务

 数据库事务的四大特性

 Redis事务

 Redis事务三大特性

 Redis事务执行的三个阶段

Redis事务_Redis事务基本操作 

Multi、Exec、discard

 例子

 Redis集群_主从复制

 概述

 解决办法

 什么是主从复制

 Redis集群_主从复制环境搭建

 编写配置文件

新建redis6379.conf

新建redis6380.conf

新建redis6381.conf

启动三台redis服务器

查看系统进程

查看三台主机运行情况

配从库不配主库

 在主机上写,在从机上可以读取数据

Redis集群_主从复制原理剖析

 主从复制可以分为3个阶段

 复制过程大致分为6个过程

 主从同步策略

 Redis集群_ 哨兵监控概述

 Redis主从复制缺点

 主从切换技术

 哨兵概述

 Redis集群_哨兵监控环境搭建

 新建sentinel-26379.conf文件

 新建sentinel-26380.conf文件

新建sentinel-26381.conf文件

哨兵节点的启动两种方式

查看哨兵节点状态

Redis集群_哨兵工作原理详解

 监控阶段

 通知阶段

故障转移阶段

 投票方式

 Redis集群_故障转移

 概述

演示故障转移

使用kill命令杀掉主节点

查看哨兵节点信息

 重启6379节点

配置文件都会被改写

 Redis集群_Cluster模式概述

 Redis有三种集群模式

 哨兵模式的缺点

 Cluster模式概述

 Redis集群的优点

Redis集群_Cluster模式搭建 

 环境准备

 创建文件夹

拷贝配置文件

验证集群 

查看集群的信息 

 Redis集群_Cluster模式原理分析

 命令执行

故障恢复 

查看节点

 杀死Master节点

观察节点信息

 Redis集群_Java操作Redis集群

 Jedis整合Redis

引入jedis的maven坐标

Java编写的代码

SpringBoot 整合 Redis

引入maven坐标

配置文件

java代码

Redis企业级解决方案_Redis脑裂

 什么是Redis的集群脑裂

 解决方案

 Redis企业级解决方案_缓存预热

 缓存冷启动

 缓存冷启动场景

 Redis企业级解决方案_缓存穿透

 概念

布隆过滤器 

什么是布隆过滤器

 代码实现

Redis企业级解决方案_缓存击穿

 ​编辑

 Redis企业级解决方案_缓存雪崩

 概念

 Redis企业级解决方案_Redis开发规范

 value设计

拒绝bigkey

 命令使用

 客户端使用

Redis企业级解决方案_数据一致性 


  

Redis概述_为什么要用NoSQL

 

 单机Mysql的美好年代

在90年代,一个网站的访问量一般都不大,用单个数据库完全可以轻松应付。在那个时候,更多的都是 静态网页,动态交互类型的网站不多。

遇到问题:

随着用户数的增长,Tomcat和数据库之间竞争资源,单机性能不足以支撑业务。

 Tomcat与数据库分开部署

 Tomcat和数据库分别独占服务器资源,显著提高两者各自性能。

新的问题: 随着用户数的增长,并发读写数据库成为瓶颈。

 引入本地缓存和分布式缓存

通过缓存能把绝大多数请求在读写数据库前拦截掉,大大降低数据库压力。其中涉及的技术包括:使用 memcached作为本地缓存,使用Redis作为分布式缓存。

注意:

缓存抗住了大部分的访问请求,随着用户数的增长,并发压力主要落在单机的Tomcat上,响应逐渐变慢。

 引入反向代理实现负载均衡

在多台服务器上分别部署Tomcat,使用反向代理软件(Nginx)把请求均匀分发到每个Tomcat中。

 

新的挑战:

反向代理使应用服务器可支持的并发量大大增加,但并发量的增长也意味着更多请求穿透到数据库,单机的数据库最终成为瓶颈。

 数据库读写分离

由于数据库的写入压力增加,Memcached只能缓解数据库的读取压力。读写集中在一个数据库上让数 据库不堪重负,大部分网站开始使用主从复制技术来达到读写分离,以提高读写性能和读库的可扩展 性。Mysql的master-slave模式成为这个时候的网站标配了

 ​​​​​​

新的挑战:

业务逐渐变多,不同业务之间的访问量差距较大,不同业务直接竞争数据库,相互影响性能。

 数据库按业务分库

把不同业务的数据保存到不同的数据库中,使业务之间的资源竞争降低,对于访问量大的业务,可以部署更多的服务器来支撑。

 ​​​​​​

为什么用NoSQL

 用户的个人信息,社交网络,地理位置,用户生成的数据和用户操作日志已经成倍的增加。我们如果要对这些用户数据进行挖掘,那SQL数据库已经不适合这些应用了, NoSQL数据库的发展也却能很好的处理这些大的数据。

 ​​​​​

 1. 单机Mysql的架构,随着用户数的增长,并发读写数据库成为瓶颈如何解决。 

引入本地缓存和分布式缓存

2. 单机Tomcat压力大,响应逐渐变慢如何解决。 引入反向代理实现负载均衡

 Redis概述_什么是NoSQL

 什么是NoSQL

 结构化数据和非结构化数据

 NoSQL的四大分类

 KV型NoSql(代表----Redis)

KV型NoSql顾名思义就是以键值对形式存储的非关系型数据库,是最简单、最容易理解也是大家最熟悉 的一种NoSql,因此比较快地带过。

注意:

KV型NoSql最大的优点就是高性能,利用Redis自带的BenchMark做基准测试,TPS可达到10万的级别,性能非常强劲。 

 列式NoSql(代表----HBase)

列式NoSql,大数据时代最具代表性的技术之一了,以HBase为代表。

关系行数据库数据

注意:

看到每行有name、phone、address三个字段,这是行式存储的方式,且可以观察id = 2的这条数 据,即使phone字段没有,它也是占空间的。

列式数据库数据

 文档型NoSql(代表----MongoDB)

 什么是文档型NoSql呢,文档型NoSql指的是将半结构化数据存储为文档的一种NoSql,文档型NoSql通 常以JSON或者XML格式存储数据。

注意:

关系型数据库是按部就班地每个字段一列存,在MongDB里面就是一个JSON字符串存储。

 搜索型NoSql(代表----ElasticSearch)

 传统关系型数据库主要通过索引来达到快速查询的目的,但是在全文搜索的场景下,索引是无能为力 的,like查询一来无法满足所有模糊匹配需求,二来使用限制太大且使用不当容易造成慢查询,搜索型 NoSql的诞生正是为了解决关系型数据库全文搜索能力较弱的问题,ElasticSearch是搜索型NoSql的代表产品。

 关系型数据库和非关系型数据及其区别

关系型数据库

 非关系型数据库

 

 1. 为什么使用NoSQL技术说法正确的是___。 解决数据量大,种类繁多出现性能问题

 2. 如下针对NoSQL特点不正确的是___。 支持事务

 Redis概述_当下NoSQL经典应用

 当下应用是SQL和NoSQL一起使用

 淘宝商品信息如何存放

 商品基本信息

名称、价格、出厂信息、生产厂商,商家信息等, 关系型数据库就可以解决。

注意:

淘宝内部用的Mysql是里面的大牛自己改造过的。

 商品描述、详情、评论

 多文件信息描述类,IO读写性能变差不能使用Mysql数据库,使用MongDB。

 商品的图片

 分布式文件系统:

1. 淘宝自己的TFS

2. Google的GFS

3. Hadoop的HDFS

4. 阿里云的OSS

 商品关键字

搜索引擎 elasticsearch 或者 ISerach 

 商品热门的波段信息

内存数据库 Redis Tair Memache

 发现问题

 ​​​​​​

 解决问题

UDSL统一数据服务平台

 UDSL热点缓存设计

1. 淘宝第五代架构升级解决___问题。语言多不兼容

 Redis概述_Redis是什么

Redis是什么 

Redis是一个使用ANSI C编写的开源、包含多种数据结构、支持网络、基于内存、可选持久性的键值对存储数据库。

 谁在用Redis

 1. Redis是__。 分布式缓存

2. Redis采用的是___的存储形式。 键值对

 Redis安装_Linux下安装Redis

 下载地址

Redis官方网址:redis.io/

 下载Redis

 ​​​

 redis-6.2.4.tar.gz上传至CentOS并解压,解压后得到redis-6.2.4目录

 解压命令:

tar -zxvf redis-6.2.4.tar.gz

 安装GCC

安装C语言编译环境

yum install -y gcc

 通过使用 gcc --version 命令打印 GCC 版本,来验证 GCC 编译器是否被成功安装:

gcc --version

 安装Redis

编译Redis

在redis-6.2.4目录下执行:

make

 安装Redis

在redis-6.2.4目录下执行:

make install

 安装目录: /usr/local/bin

服务启动

前台启动:/usr/local/bin下执行

./redis-server

后台启动

修改redis.conf文件

daemonize yes #由no改为yes

启动服务

./redis-server ../redis.conf

客户端启动

/usr/local/bin下执行

./redis-cli

ping命令可以检测服务器是否正常(服务器返回PONG)

127.0.0.1:6379> ping
PONG

 Redis安装_Docker下安装Redis

 下载最新Redis镜像

docker pull redis

注意:

可以用docker pull redis命令下载最新版本的Redis镜像,也可 以用“docker pull redis:标签”命令下载指定版本的Redis。

 启动Redis容器

docker run -itd --name myFirstRedis -p 6379:6379
redis:latest

观察Redis启动效果

docker logs myFirstRedis

注意: 如果直接在Linux等环境上启动Redis服务器,就能直接看到启动后的效果。

 查看Redis的版本

先确保myFirstRedis容器处于Up状态。进入容器的命令行交互窗口。

docker exec -it myFirstRedis /bin/bash
redis-server --version

Redis服务器和客户端

Redis是基于键值对存储的NoSQL数据库,其中的数据是存储在 Redis服务器里的。和传统的MySQL数据库服务器相似,一个Redis服务器可以同多个客户端创建连接。

docker exec -it myFirstRedis /bin/bash
redis-cli

Redis安装_基本知识

 默认16数据库

Redis是一个字典结构的存储服务器,一个Redis实例提供了多个用来存储数据的字典,客户端可以指定 将数据存储在哪个字典中。 这与在一个关系数据库实例中可以创建多个数据库类似(如下图所示),所以可以将其中的每个字典都 理解成一个独立的数据库。

 

 Redis默认支持16个数据库,可以通过调整Redis的配置文件redis/redis.conf中的databases来修改这一 个值,设置完毕后重启Redis便完成配置。

 Redis 使用的到底是多线程还是单线程?

因为Redis是基于内存的操作,CPU不是Redis的瓶颈,Redis的瓶颈最有可能是机器内存的大小或者网络带宽。既然单线程容易实现,而且CPU不会成为瓶颈,那就顺理成章地采用单线程的方案了。

 IO多路复用技术

 redis 采用网络IO多路复用技术来保证在多连接的时候, 系统的高吞吐量。

大白话解释

假设你是一个机场的空管, 你需要管理到你机场的所有的航线, 包括进港,出港, 有些航班需要放到 停机坪等待,有些航班需要去登机口接乘客。

最简单的做法,就是你去招一大批空管员,然后每人盯一架飞机, 从进港,接客,排位,出港,航线监 控,直至交接给下一个空港,全程监控。

怎么解决

这个东西叫flight progress strip. 每一个块代表一个航班,不同的槽代表不同的状态,然后一个空管员可 以管理一组这样的块(一组航班),而他的工作,就是在航班信息有新的更新的时候,把对应的块放到 不同的槽子里面。

结论

 这里“多路”指的是多个网络连接,“复用”指的是复用同一个线程。采用多路 I/O 复用技术可以让单个线程 高效的处理多个连接请求(尽量减少网络IO的时间消耗),且Redis在内存中操作数据的速度非常快(内存内的操作不会成为这里的性能瓶颈),主要以上两点造就了Redis具有很高的吞吐量。

 切换数据库

语法结构:

select number

示例:

# 默认使用 0 号数据库
redis 127.0.0.1:6379> SET db_number 0
OK
# 使用 1 号数据库
redis 127.0.0.1:6379> SELECT 1
OK

 清空当前库

Redis Flushdb 命令用于清空当前数据库中的所有 key。

语法结构:

127.0.0.1:6379> FLUSHDB

示例:

127.0.0.1:6379> FLUSHDB

 通杀全部库

Redis Flushall 命令用于清空整个 Redis 服务器的数据(删除所有数据库的所有 key )。

语法结构:

redis 127.0.0.1:6379> FLUSHALL

示例:

# 清空所有数据库的所有 key
redis 127.0.0.1:6379>flushall
OK

 为什么默认端口6379

意大利的一位广告女郎名字叫Merz全名Alessia Merz。

 1. Redis采用____模型。 多路I/O复用

 2.Redis默认___数据库。16

 Redis数据类型_key键

 

 keys

查看当前库中所有的key 。

语法结构:

keys *

示例:

keys *

 新版本也进行了替代:

root@6c068b3fbf29:/data# redis-cli --scan "u*"
"user1"
"user"

 exists

判断某个key是否存在,返回1表示存在,0不存在。

语法结构:

exists key

示例:

#查看k1是否存在,如果存在返回1
exists k1
# 查看k1 k2 k3是否存在,如果k1 k2存在,k3不存在,则返回2
exists k1 k2 k3

 type

查看当前key 所储存的值的类型。返回当前key所储存的值的类型,如string 、list等。

语法结构:

type key

示例:

type k1

del

删除已存在的key,不存在的 key 会被忽略。

语法结构:

del key

示例: 可以设置多个key,返回删除成功的个数。

expire 

给key设置time秒的过期时间。设置成功返回 1 。 当 key 不存在返回 0。

语法结构:

expire key time

示例:

# 给k1设置10秒后过期
expire k1 10

ttl 

以秒为单位返回 key 的剩余过期时间。

语法结构:

ttl key

示例:

ttl k1

persist 

移除给定 key 的过期时间,使得 key 永不过期。

语法结构:

persist key

示例:

persist k1

 1. Redis技术中查看当前库中所有的key的命令___。 keys

 2. Redis技术中如何删除已存在的key。del

 Redis数据类型_String

 简介

String是Redis最基本的类型,一个key对应一个value。String是二进制安全的,意味着String可以包含任何数据,比如序列化对象或者一张图片。String最多可以放512M的数据

 常用命令

set

用于设置给定 key 的值。如果 key 已经存储其他值, set 就重写旧值,且无视类型。

语法格式:

set key value

示例:

127.0.0.1:6379> set k1 v1
OK

 get

用于获取指定 key 的值。如果 key 不存在,返回 nil 。

语法格式:

get key

示例:

127.0.0.1:6379> get k1
"v1"

append

 将给定的value追加到key原值末尾。

语法格式:

append key value

示例:

127.0.0.1:6379> APPEND k1 k1
(integer) 4
127.0.0.1:6379> APPEND k1 k2
(integer) 6

strlen

获取指定 key 所储存的字符串值的长度。当 key 储存的不是字符串值时,返回一个错误。

语法格式:

strlen key

示例:

127.0.0.1:6379> strlen k1
(integer) 6

setex

给指定的 key 设置值及time 秒的过期时间。如果 key 已经存在, setex命令将会替换旧的值,并设置过期时间。

语法格式:

setex key time value

示例:

#向Redis中设置一个k1的键值对并且10秒后过期
127.0.0.1:6379> setex k1 10 v1
OK

setnx

只有在key不存在时设置key的值

语法格式:

setnx key value

示例:

127.0.0.1:6379> setnx k1 v1
(integer) 0
127.0.0.1:6379> setnx k4 v4
(integer) 1

getrange

获取指定区间范围内的值,类似between........and 的关系

语法格式:

getrange key start end

示例:

127.0.0.1:6379> set k5 abcd123xxx
OK
127.0.0.1:6379> getrange k5 2 4
"cd1"

setrange

获取指定区间范围内的值,类似between........and 的关系

语法结构:

setrange key offset value

示例:

127.0.0.1:6379> set k6 abcd1234
OK
127.0.0.1:6379> setrange k6 1 xxx
(integer) 8
127.0.0.1:6379> get k6
"axxx1234"

incr

将 key 中储存的数字值增一。

语法格式:

incr key

示例:

#因为Redis中不存在k1,所以先初始化为0,再递增,值为1
127.0.0.1:6379> incr k1
(integer) 1
# incr k1 存在k1,递增后k1的值为2
127.0.0.1:6379> incr k1
(integer) 2
# 如果value不是数字就会报错
127.0.0.1:6379> set k2 v2
OK
127.0.0.1:6379> INCR k2
(error) ERR value is not an integer or out of range

decr

将 key 中储存的数字值减一。

语法格式:

decr key

示例:

127.0.0.1:6379> decr k1
(integer) 1
127.0.0.1:6379> decr k1
(integer) 0
127.0.0.1:6379> decr k1
(integer) -1
127.0.0.1:6379> decr k1
(integer) -2
#如果
set k2 v2
decr k2 因为k2不为数值,Redis返回一个错误

incrby/decrby key step

将key存储的数字值按照step进行增减。

127.0.0.1:6379> incrby k1 10
(integer) 20

mset

同时设置一个或多个 key-value 。

语法格式:

mset key1 value1 key2 value2

示例:

127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3
OK

mget

返回所有(一个或多个)给定 key 的值。

语法格式:

mget key1 key2

示例:

127.0.0.1:6379> mget k1 k2 k3
1) "v1"
2) "v2"
3) "v3"

getset

将给定key值设为value,并返回key的旧值(old value),简单一句话(先get然后立即set)。

语法格式:

getset key value

示例:

127.0.0.1:6379> getset k1 wcc
"v1"
127.0.0.1:6379> get k1
"wcc"

 使用场景

 1.Redis技术String数据类型中如何设置给定 key 的值。 set

 2. Redis技术String数据类型中如何只有在key不存在时设置key的值。 setnx

 Redis数据类型_List

 简介

 List是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。底层是一个双向链表,对两段操作性能极高,通过索引操作中间的节点性能较差。

 一个List最多可以包含 $2^{32}-1$个元素 ( 每个列表超过40亿个元素)。

 常用命令

lpush/rpush

从左边(头部)/右边(尾部)插入一个或多个值。

语法结构:

lpush/rpush key1 value1 value2 value3……

示例:

#从左边放入v1 v2 v3
127.0.0.1:6379> lpush k1 v1 v2 v3
(integer) 3

#从右边放入v4 v5 v6
127.0.0.1:6379> rpush k1 v4 v5 v6
(integer) 6

 lrange

返回key列表中的start和end之间的元素(包含start和end)。 其中 0 表示列表的第一个元素,-1表示最后一个元素。

语法结构:

lrange key start end

示例:

#取出列表里前3个值,结果为v3 v2 v1
127.0.0.1:6379> lrange k1 0 2
#取出列表里全部值,结果为v3 v2 v1 v4 v5 v6
127.0.0.1:6379> lrange k1 0 -1

 lpop/rpop

移除并返回第一个值或最后一个值。

语法格式:

lpop/rpop key

示例:

lpop k1 从列表中删除v3,并返回,当前列表全部值v2 v1 v4 v5 v6
rpop k1 从列表中删除v6,并返回,当前列表全部值v2 v1 v4 v5

 lindex

获取列表index位置的值(从左开始)。

语法结构:

lindex key index

示例:

lindex k1 0

 llen

获取列表长度。

语法结构:

llen key

示例:

127.0.0.1:6379> llen k1
(integer) 6

 lrem

从左边开始删除与value相同的count个元素。

语法结构:

lrem key count value

示例:

#从左边开始删除k1列表中2个v1元素
lrem k1 2 v1

 linsert

在列表中value值的前边/后边插入一个new value值(从左开始)。

语法结构:

linsert key before/after value newvalue

示例:

linsert k1 before v1 v5 在v1前面插入一个v5

 lset

将索引为index的值设置为value

语法结构:

lset key index value

示例:

lset key index value

 使用场景

 1. Redis技术List数据类型中如何插入一个或多个值。 lpush/rpush

2. Redis技术List数据类型中如何移除并返回第一个值或者最后一个值。lpop/rpop

 Redis数据类型_Set

 简介

与List类似是一个列表功能,但Set是自动排重的,当需要存储一个列表数据,又不希望出现重复数据 时,Set是一个很好的选择。

Set是String类型的无序集合,它底层其实是一个value为null的hash表,所以添加、删除、查找的时间复杂度都是O(1)。

 常用命令

sadd

将一个或多个元素添加到集合key中,已经存在的元素将被忽略。

语法结构:

sadd key value1 value2……

示例:

#向集合中添加值,最终只有v1 v2 v3 v4 v5 v6
127.0.0.1:6379> sadd k1 v1 v2 v2 v3 v4 v5 v6

 smembers

取出该集合的所有元素。

语法结构:

smembers key

示例:

127.0.0.1:6379> smembers k1

 sismember

判断集合key中是否含有value元素,如有返回1,否则返回0。

语法结构:

sismember key value

示例:

sismember k1 v1

 scard

返回该集合的元素个数。

语法结构:

scard key

示例:

scard k1

 srem

删除集合中的一个或多个成员元素,不存在的成员元素会被忽略。

语法结构:

srem key value1 value2……

示例:

# 删除v1 v2
srem k1 v1 v2

 spop

随机删除集合中一个元素并返回该元素。

语法结构:

spop key

示例:

spop k1 随机删除一个元素,并返回

srandmember 

随机取出集合中count个元素,但不会删除。

语法结构:

srandmember key count

示例:

#随机取出集合中的2个元素
srandmember k1 2

 smove

将value元素从sourcekey集合移动到destinationkey集合中。

语法结构:

smove sourcekey destinationkey value

示例:

smove k1 k2 v5 将元素v5从集合k1中移动到集合k2

 sinter

返回两个集合的交集元素。

语法结构:

sinter key1 key2

示例:

sinter key1 key2

 sunion

返回两个集合的并集元素。

语法结构:

sunion key1 key2

示例:

sunion k1 k2

 sdiff

返回两个集合的差集元素(key1中的,不包含key2)

语法结构:

sdiff key1 key2

示例:

sdiff k1 k2

 

 1. Redis技术Set数据类型中将一个或多个元素添加到集合key中。sadd

 2. Redis技术Set数据类型中如何取出该集合的所有元素。 smembers

Redis数据类型_Hash 

 简介

Hash是一个键值对的集合。Hash 是一个 String 类型的 field(字段) 和 value(值) 的映射表,hash 特别适合用于存储对象。

常用命令 

hset

给key集合中的field赋值value。

语法结构:

hset key field value

示例:

127.0.0.1:6379> hset user name xiaoton
(integer) 1
127.0.0.1:6379> hset user age 3
(integer) 1

 hget

从key哈希中,取出field字段的值。

语法结构:

hget key field

示例:

127.0.0.1:6379> hget user name
"xiaoton"

 hmset

批量设置哈希的字段及值。

语法结构:

hmset key field1 value1 field2 value2……

示例:

127.0.0.1:6379> hmset user1 name xiaoton age 15
OK

 hexists

判断指定key中是否存在field

语法结构:

hexists key field

示例:

127.0.0.1:6379> hexists user1 name
(integer) 1
127.0.0.1:6379> hexists user1 xxx
(integer) 0

 hkeys

获取该哈希中所有的field。

语法结构:

hkeys key

示例:

127.0.0.1:6379> hkeys user1
1) "name"
2) "age"

 hvals key

获取该哈希中所有的value。

语法结构:

hvals key

示例:

127.0.0.1:6379> hvals user1
1) "xiaoton"
2) "15"

 hincrby

为哈希表key中的field字段的值加上增量increment。

语法结构:

hincrby key field increment

示例:

127.0.0.1:6379> hincrby user1 age 10
(integer) 25

 hdel

删除哈希表 key 中的一个或多个指定字段,不存在的字段将被忽略。

语法结构:

hdel key field1 field2……

示例:

127.0.0.1:6379> hdel user1 age
(integer) 1

hsetnx 

给key哈希表中不存在的的字段赋值 。

语法结构:

hsetnx key field value

示例:

127.0.0.1:6379> hsetnx user1 age 10
(integer) 1

使用场景

     1、购物车

     2、存储对象

 1. Redis技术Hash数据类型中如何给key集合中的field赋值value。  hset

 2. Redis技术Hash数据类型中如何从key哈希中,取出field字段的值。 hget

 Redis数据类型_Zset

 简介

Zset与Set非常相似,是一个没有重复元素的String集合。不同之处是Zset的每个元素都关联了一个分数 (score),这个分数被用来按照从低分到高分的方式排序集合中的元素。集合的元素是唯一的,但分数可以重复。

 常用命令

zadd

将一个或多个元素(value)及分数(score)加入到有序集key中。

语法结构:

zadd key score1 value1 score2 value2……

示例:

zadd k1 100 java 200 c++ 300 python 400 php

 zrange

返回key集合中的索引start和索引end之间的元素(包含start和end)。

语法结构:

zrange key start end [withscores]

示例:

zrange k1 0 -1 返回集合中所有元素
zrange k1 0 -1 withscores 返回集合中所有元素,并携带元素分数

 zrangebyscore

返回key集合中的分数minscore 和分数maxscore 之间的元素(包含minscore 和maxscore )。其中元素的位置按分数值递增(从小到大)来排序。

语法结构:

zrangebyscore key minscore maxscore [withscores]

示例:

zrangebyscore k1 200 400 返回200-400分之间的元素递增排序

 zincrby

 为元素value的score加上increment的值。

语法结构:

zincrby key increment value

示例:

zincrby k1 50 java 给java元素加上50分

zrem 

删除该集合下value的元素。

语法结构:

zrem k1 php 删除php

zcount 

统计该集合在minscore 到maxscore分数区间中元素的个数。

语法结构:

zcount key minscore maxscore

示例:

zcount k1 100 300 统计100分到300分中间元素的个数

 zrank

返回value在集合中的排名,从0开始。

语法结构:

zrank key value

示例:

zrank k1 c++ 返回c++排名

 1. Redis技术Zset数据类型中如何给将一个或多个元素(value)及分数(score)加入到有序集key 中。 zadd

2. Redis技术Zset数据类型中如何返回key集合中的索引start和索引end之间的元素。zrange  

 Redis数据类型_Bitmaps

 简介

在计算机中,用二进制(位)作为存储信息的基本单位,1个字节等于8位。 例如 "abc" 字符串是由 3 个字节组成,计算机存储时使用其二进制表示,"abc"分别对应的ASCII码是 97、98、99,对应的二进制是01100001、01100010、01100011,在内存中表示如下:

 

 合理地使用位能够有效地提高内存使用率和开发效率。

 Redis提供了Bitmaps这个 “数据结构” 可以实现对位的操作:

 常用命令

setbit

设置Bitmaps中某个偏移量的值。

语法结构:

setbit key offset value

示例:

redis中bitmaps可以用来统计用户信息,eg:活跃天数、打卡天数、登录天数 bitmaps位图,都是操作二进制来进行记录,就只有0和1两个状态

127.0.0.1:6379> getbit sign 1 # 获取第一天的打卡状态
(integer) 1
127.0.0.1:6379> BITCOUNT sign # 统计所有打卡天数
(integer) 4127.0.0.1:6379> setbit zhangsan:3 1 1 # 往sign中添加数据,第1天打卡
(integer) 1
127.0.0.1:6379> setbit zhangsan:3 2 0 # 第2天未打卡
(integer) 0
127.0.0.1:6379> setbit zhangsan:3 3 1 # 第3天打卡
(integer) 0
127.0.0.1:6379> setbit zhangsan:3 4 0 # 第4天未打卡
(integer) 0
127.0.0.1:6379> setbit zhangsan:3 5 1 # 第5天打卡
(integer) 0
127.0.0.1:6379> setbit zhangsan:3 6 0 # 第6天未打卡
(integer) 0
127.0.0.1:6379> setbit zhangsan:3 7 1 # 第7天打卡
(integer) 0 127.0.0.1:6379> getbit sign 1 # 获取第一天的打卡状态
(integer) 1
127.0.0.1:6379> BITCOUNT sign # 统计所有打卡天数
(integer) 4
127.0.0.1:6379> getbit sign 1 # 获取第一天的打卡状态
(integer) 1

 getbit

获取Bitmaps中某个偏移量的值。

语法结构:

getbit key offset

示例: 获取key的offset 的值。

getbit sign 3 获取偏移量为1的值,结果为1

如果偏移量未设置值,则也返回0。

getbit sign 99 获取偏移量为99的值,结果为0

 bitcount

统计字符串被设置为1的bit数量。一般情况下,给定的整个字符串都会被进行统计,可以选择通过额外 的start和end参数,指定字节组范围内进行统计(包括start和end),0表示第一个元素,-1表示最后一 个元素。

语法结构:

bitcount key [start end]

示例:

bitcount sign 获取整个字符串被设置为1的bit数量,结果为3

如:当前存在一个key为k1的bitmaps存储着[00000001,00000001,00000010,00000011],分别对应 [1,1,2,3]。

setbit num 7 1
setbit num 15 1
setbit num 22 1
setbit num 30 1
setbit num 31 1
bitcount num 1 2 统计索引1、2两个字节组中bit=1的数量,即统计00000001,00000010中bit=1的数
量,结果为2
bitcount num 1 3 统计索引1、2、3三个字节组中bit=1的数量,即统计
00000001,00000010,00000011中bit=1的数量,结果为4
bitcount num 0 -1 统计所有的字节组中bit=1的数量,结果为5

setbit设置或获取的是bit(位)的位置,bitcount计算的是byte(字节)位置。

 bitop

将多个bitmaps通过求交集/并集方式合并成一个新的bitmaps。

语法结构:

bitop and/or destkey sourcekey1 sourcekey2……

示例:

bitop and k3 k1 k2 通过求交集将k1 k2合并成k3
bitop or k3 k1 k2 通过求并集将k1 k2合并成k3

 

 1. Redis技术Bitmaps数据类型中如何设置Bitmaps中某个偏移量的值。setbit

 2. Redis技术Bitmaps数据类型中如何获取Bitmaps中某个偏移量的值。getbit

Redis数据类型_Geospatia 

 简介

GEO,Geographic,地理信息的缩写。该类型就是元素的二维坐标,在地图上就是经纬度。Redis基于该 类型,提供了经纬度设置、查询、范围查询、距离查询、经纬度Hash等常见操作。

 常用命令

geoadd

用于存储指定的地理空间位置,可以将一个或多个经度(longitude)、纬度(latitude)、位置名称 (member)添加到指定的 key 中。

语法结构:

geoadd key longitude latitude member

示例:

# 将北京的经纬度和名称添加到china
geoadd china 116.405285 39.904989 beijing
# 将成都和上海的经纬度、名称添加到china
geoadd china 104.065735 30.659462 chengdu 121.472644 31.231706 shanghai

 geopos

从给定的 key 里返回所有指定名称(member)的位置(经度和纬度),不存在的返回 nil。

语法结构:

geopos key member [member ……]

示例: 返回china中名称为shanghai和beijing的经纬度

geopos chinacity shanghai beijing

 geodist

用于返回两个给定位置之间的距离。

语法结构:

geodist key member1 member2 [m|km|ft|mi]

示例:

# 返回shanghai和beijing之间的距离,结果1067597.9668,单位米
geodist chinacity shanghai beijing
# 返回shanghai和chengdu之间的距离,结果1660.0198,单位是千米
geodist chinacity shanghai chengdu km

 georadius

以给定的经纬度(longitude latitude)为中心, 返回键包含的位置元素当中, 与中心的距离不超过给 定最大距离(radius )的所有位置元素。

 

语法结构:

georadius key longitude latitude radius m|km|ft|mi

示例:

#获取经纬度110 30为中心,在china内1200公里范围内的所有元素。
georadius china 110 30 1200 km

1. Redis技术Geospatia数据类型中如何存储指定的地理空间位置。 geoadd

2. Redis技术Geospatia数据类型中如何计算两个给定位置之间的距离。 geodist

 Redis数据类型_Hyperloglog

简介

在我们做站点流量统计的时候一般会统计页面UV(独立访客:unique visitor)和PV(即页面浏览量:page view)。redis HyperLogLog是用来做基数统计的算法,HyperLogLog的优点是:在输入元素的数量或者 体积非常非常大时,计算基数所需的空间总是固定的、并且使很小的。

 什么是基数

比如数据集{1,3,5,7,5,7,8},那么这个数据集的基数集为{1,3,5,7,8},基数(不重复元素)为5.基数估计就是在 误差可接受的范围内,快速计算基数。

 常用命令

pfadd

将所有元素参数添加到 Hyperloglog 数据结构中。

语法结构:

pfadd key element1 element2……

示例:

如果至少有个元素被添加返回 1, 否则返回 0。

pfadd book1 uid1 uid2 uid

注意:

添加元素到HyperLogLog中,如果内部有变动返回1,没有返回0。

 pfcount

计算Hyperloglog 近似基数,可以计算多个Hyperloglog ,统计基数总数。

语法结构:

pfcount key1 key2……

示例:

pfcount book1 #计算book1的基数,结果为3
pfadd book2 uid3 uid4 #添加两个元素到book2中
pfcount book1 book2 #统计两个key的基数总数,结果为5

 pfmerge

将一个或多个Hyperloglog(sourcekey1) 合并成一个Hyperloglog (destkey )。

语法结构:

pfmerge destkey sourcekey1 sourcekey2……

示例: 比如每月活跃用户可用每天活跃用户合并后计算。

#将book1和book2合并成book,结果为5
pfmerge book book1 book2

使用场景 

基数不大,数据量不大就用不上,会有点大材小用浪费空间,有局限性,就是只能统计基数数量,而没 办法去知道具体的内容是什么,和bitmap相比,属于两种特定统计情况,简单来说,HyperLogLog 去重比 bitmaps 方便很多,一般可以bitmap和hyperloglog配合使用,bitmap标识哪些用户活跃。

1.Redis HyperLogLog 是用来做____的算法。 统计基数

 Redis可视化工具_安装Redis_Desktop_Manager

 下载Redis Desktop Manager

 注意: 官网https://rdm.dev/pricing

 

 选择安装路径

 连接Redis服务

关闭防火墙

systemctl stop firewalld.service

关闭保护模式

protected-mode no

开启远程访问

redis默认只允许本地访问,要使redis可以远程访问可以修改redis.conf。

注释掉bind 127.0.0.1 可以使所有的ip访问redis

 配置连接服务

 配置信息

 Java整合Redis_Jedis操作

什么是Jedis 

Jedis是Redis官方推荐的Java连接开发工具。

引入Jedis

创建maven工程

引入maven依赖 

<dependency>
      <groupId>redis.clients</groupId>
      <artifactId>jedis</artifactId>
      <version>3.6.0</version>
</dependency>
<dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
</dependency>

Jedis连接到redis

//第一个参数是ip地址,第二个参数是端口
Jedis jedis = new Jedis("192.168.56.31",6379);

测试相关数据类型 

连接Redis服务

Jedis jedis = new Jedis("192.168.56.31",6379);
//通过ping()方法向redis发送一个ping命令,服务器返回一个Pong
String msg = jedis.ping();
System.out.println(msg);
//jedis使用完毕需要关闭
jedis.close();

Jedis-API:String

//设置一个key
jedis.set("k1","v1");
//设置一个key
jedis.set("k2","1");
//获取一个key
String res = jedis.get("k1");
//对某一个key自增
Long ires = jedis.incr("k2");

Jedis-API:Keys

//返回所有的key
Set<String> keys = jedis.keys("*");
//返回该key剩余过期时间
Long time = jedis.ttl("k1");

Jedis-API:List

//向list中添加数据
jedis.lpush("list1","v1","v2","v3");
//返回list全部数据
List<String> list = jedis.lrange("list1",0,-1 );

Jedis-API:Set

//向set中添加数据
jedis.sadd("set1" ,"v1","v2","v2","v3");
//查看该集合中有多少个元素
jedis.smembers("set1");

Jedis-API:Hash

//设置一个hash
jedis.hset("user","age","25");
//获取该key的所有value
jedis.hvals("user");

Jedis-API:Zset

//向zset中添加一条数据
jedis.zadd("zset1",100,"java");
//获取所有的值
jedis.zrange("zset1",0,-1);

Jedis-API:Bitmaps

//将b1偏移量为0的位设置为1
jedis.setbit("b1",0, "1");
//获取b1偏移量为0的位
jedis.getbit("b1",0);

Jedis-API:Geospatia

//添加一条地理信息数据
jedis.geoadd("chinacity",130,110,"xiaotong");

Jedis-API:Hyperloglog

//将所有元素参数添加到 Hyperloglog 数据结构中。
jedis.pfadd("book","c++","java","php");

Java整合Redis_Spring-Data-Redis 

简介 

Spring-Data-Redis是spring大家族的一部分,通过简单的配置访问Redis服务,对Reids底层开发包 (Jedis, JRedis, and RJC)进行了高度封装,RedisTemplate提供了Redis各种操作、异常处理及序列化,支持发布订阅。

RedisTemplate介绍

Spring封装了RedisTemplate对象来进行对Redis的各种操作,它支持所有的Redis原生的api。

org.springframework.data.redis.core
Class RedisTemplate<K,V>

 RedisTemplate中定义了对5种数据结构操作

redisTemplate.opsForValue();//操作字符串
redisTemplate.opsForHash();//操作hash
redisTemplate.opsForList();//操作list
redisTemplate.opsForSet();//操作set
redisTemplate.opsForZSet();//操作有序set

StringRedisTemplate与RedisTemplate

 pom.xml添加依赖

<dependencies>
       <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
      </dependency>
      <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-web</artifactId>
     </dependency>
     <dependency>
             <groupId>org.projectlombok</groupId>
             <artifactId>lombok</artifactId>
             <optional>true</optional>
    </dependency>
    <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
    </dependency>
    <dependency>
            <groupId>io.projectreactor</groupId>
            <artifactId>reactor-test</artifactId>
            <scope>test</scope>
    </dependency>
</dependencies>

在application.properties中配置

#Redis服务器连接地址
spring.redis.host=192.168.56.31
#Redis服务器连接端口
spring.redis.port=6379
#连接池最大连接数(使用负值表示没有限制)
spring.redis.pool.max-active=8
#连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.pool.max-wait=-1
#连接池中的最大空闲连接
spring.redis.pool.max-idle=8
#连接池中的最小空闲连接
spring.redis.pool.min-idle=0
#连接超时时间(毫秒)
spring.redis.timeout=30000

自定义序列化

/**
* 自定义序列化方式
*/
@Configuration
public class RedisConfig {
     @Bean
     public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
            RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
            redisTemplate.setKeySerializer(new StringRedisSerializer());
            redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
            redisTemplate.setHashKeySerializer(new StringRedisSerializer());
            redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
            redisTemplate.setConnectionFactory(redisConnectionFactory);
            return redisTemplate;
     }
}

使用redisTemplate进行各类型的CURD操作

String数据类型操作

添加元素

public boolean set(String key,Object value){
     try{
     redisTemplate.opsForValue().set(key,value);
             return true;
      }catch (Exception e){
             log.error("redis set value exception:{}",e);
             return false;
     }
}

获取元素

public Object get(String key){
         return key == null ? null : redisTemplate.opsForValue().get(key);
}

添加元素并设置过期时间

public boolean setex(String key,Object value,long expire){
      try{
          //TimeUnit.SECONDS指定类型为秒
          redisTemplate.opsForValue().set(key,value,expire,TimeUnit.SECONDS);
          return true;
        }catch (Exception e){
              log.error("redis set value and expire exception:{}",e);
              return false;
     }
}

Hash类型的操作

添加元素

public boolean hset(String key, String field, Object value,long seconds) {
      try {
              redisTemplate.opsForHash().put(key, field, value);
              expire(key,seconds);//调用通用方法设置过期时间
              return true;
          }catch (Exception e){
              log.error("redis hset and expire eror,key:{},field:{},value: {},exception:{}",key,field,value,e);
                  return false;
    }
}

获取数据

public Object hget(String key,String field){
      return redisTemplate.opsForHash().get(key,field);
}

set类型的操作

添加元素

public long sset(String key ,Object...values){
    try {
          return redisTemplate.opsForSet().add(key,values);
        }catch (Exception e){
          log.error("redis sset error,key:{},value:{},values:{},exception:
{}",key,values,e);
          return 0;
    }
}

获取set的长度

public long sgetSize(String key){
      try {
            return redisTemplate.opsForSet().size(key);
          }catch (Exception e){
            log.error("redis sgetSize error,key:{},exception:{}",key,e);
            return 0;
     }
}

获取元素

public Set<Object> sgetAll(String key){
     try {
           return redisTemplate.opsForSet().members(key);
         }catch (Exception e){
           log.error("redis sgetAll error,key:{},exception:{}",key,e);
           return null;
    }
}

zset类型的操作

添加元素

public boolean zadd(String key,Object member,double score){
    try {
          return redisTemplate.opsForZSet().add(key,member,score);
        } catch (Exception e) {
         log.error("redis zadd error,key:{},value:{},score:{},exception:
{}",key,member,score,e);
          return false;
    }
}

获取元素

public Set<String> zrange(String key,int start,int end){
     try {
        Set<Object> range = redisTemplate.opsForZSet().range(key, start, end);
        if(range==null||range.size()==0) return null;
              return range.stream().
              map(o->(String)o).collect(Collectors.toSet());
         } catch (Exception e) {
             log.error("redis zrange error,key:{},start:{},end:{},exception:{}",key,start,end,e);
             return null;
     }
}

list类型的操作

添加元素

public boolean lrpush(String key, Object value) {
   try {
         redisTemplate.opsForList().rightPush(key, value);
         return true;
     } catch (Exception e) {
         log.error("redis lrpush error,key:{},value:{}exception:
{}",key,value,e);
        return false;
    }
}

获取元素

public List<Object> getList(String key,int start,int end) {
     try {
           List<Object> o = redisTemplate.opsForList().range(key,start,end);
           return o;
        } catch (Exception e) {
          return null;
     }
}

Redis构建web应用实践_网页缓存

创建springboot项目 

选择组件 

Lombok

spring mvc

spring data redis

spring data jpa

编写配置文件 

########################################################
### 配置连接池数据库访问配置
########################################################
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://47.104.210.57:3306/zhonglian?
characterEncoding=utf-8&&useSSL=false
spring.datasource.username=root
spring.datasource.password=mytest
# 初始化大小,最小,最大
spring.datasource.initialSize=5
spring.datasource.minIdle=5
spring.datasource.maxActive=20
# 配置获取连接等待超时的时间
spring.datasource.maxWait=60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
spring.datasource.timeBetweenEvictionRunsMillis=60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
spring.datasource.minEvictableIdleTimeMillis=300000
spring.datasource.validationQuery=SELECT 1 FROM DUAL
spring.datasource.testWhileIdle=true
spring.datasource.testOnBorrow=false
spring.datasource.testOnReturn=false
# 打开PSCache,并且指定每个连接上PSCache的大小
spring.datasource.poolPreparedStatements=true
spring.datasource.maxPoolPreparedStatementPerConnectionSize=20
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
spring.datasource.filters=stat,wall,log4j
# 通过connectProperties属性来打开mergeSql功能;慢SQL记录
spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowS
qlMillis=5000
# 合并多个DruidDataSource的监控数据
#spring.datasource.useGlobalDataSourceStat=true
########################################################
### Java Persistence Api --y
########################################################
# Specify the DBMS
spring.jpa.database = MYSQL
# Show or not log for each sql query
spring.jpa.show-sql = true
# Hibernate ddl auto (create, create-drop, update)
spring.jpa.hibernate.ddl-auto = update
# Naming strategy
#[org.hibernate.cfg.ImprovedNamingStrategy
#org.hibernate.cfg.DefaultNamingStrategy]
spring.jpa.hibernate.naming-strategy = org.hibernate.cfg.ImprovedNamingStrategy
# stripped before adding them to the entity manager)
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect
########################################################
### 配置连接池数据库访问配置
########################################################
#Redis服务器连接地址
spring.redis.host=192.168.56.31
#Redis服务器连接端口
spring.redis.port=6379
#连接池最大连接数(使用负值表示没有限制)
spring.redis.pool.max-active=8
#连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.pool.max-wait=-1
#连接池中的最大空闲连接
spring.redis.pool.max-idle=8
#连接池中的最小空闲连接
spring.redis.pool.min-idle=0
#连接超时时间(毫秒)
spring.redis.timeout=30000
logging.pattern.console=%d{MM/dd HH:mm:ss.SSS} %clr(%-5level) --- [%-15thread]
%cyan(%-50logger{50}):%msg%n

创建表

@Data
@Entity
@Table(name = "goods")
public class GoodsEntity {
     //自增ID
     @Id
     @GeneratedValue(strategy=GenerationType.IDENTITY)//自增
     private Long id;
     // 商品名字
     private String goodsName;
     // 订单id
     private String orderId;
     // 商品数量
     private Integer goodsNum;
     // 商品价格
     private Double price;
}

 编写持久层

public interface GoodsRepository extends JpaRepository<GoodsEntity,Long> {
}

编写业务层

@Repository
@Service
public class GoodsService {
      //商品
      @Autowired
      private GoodsRepository goodsRepository;
      /**
       * 根据id获取商品信息
       * @param id
       * @return
       */
      public GoodsEntity getId(Long id){
           //根据id查询商品信息
           Optional<GoodsEntity> goodsEntity = goodsRepository.findById(id);
           if (goodsEntity.isPresent()){
                return goodsEntity.get();
             }else {
                  return null;
            }
      }
}

编写控制层

/**
* 商品控制层
*/
@RequestMapping("/goods")
@RestController
public class GoodsController {
      @Autowired
      private GoodsService goodsService;
      /**
       * 根据id查询商品信息
       * @param id
       * @return
       */
@GetMapping("/getById/{id}")
public GoodsEntity getById(@PathVariable String id){
       return goodsService.getId(Long.valueOf(id));
   }
}

下载压测工具

登录官网Jmeter下载,得到压缩包 jmeter-5.0.zip

启动Jmeter工具 

D:\apache-jmeter-5.4.3\bin\jmeter.bat文件双击运行。

修改语言 

创建压测任务 

 添加HTTP请求

 配置HTT请求

 添加压测结果报告

 没有加缓存的吞吐量

 添加Redis缓存

@Repository
@Service
public class GoodsService {
     //商品
     @Autowired
    private GoodsRepository goodsRepository;
    @Autowired
    private StringRedisTemplate redisTemplate;
    
    /**
     * 根据id获取商品信息
     * @param id
     * @return
     */
    public GoodsEntity getId(Long id){
        // 从Redis中获取缓存
        String goodsStr = redisTemplate.opsForValue().get("goods:id:"+ id);
       // 判断是否有缓存
       if (StringUtils.isEmpty(goodsStr)){
            //根据id查询商品信息
            GoodsEntity goodsEntity = goodsRepository.getById(id);
            //添加缓存
            redisTemplate.opsForValue().set("goods:id:"+ id,JSON.toJSONString(goodsEntity));
            return goodsEntity;
          }else {
             // 把json数据转为goods对象
             return JSON.parseObject(goodsStr,GoodsEntity.class);
         }
     }
}

继续压力测试

 Redis配置文件详解

 在Redis的解压目录下有个很重要的配置文件 redis.conf ,关于Redis的很多功能的配置都在此文件中完 成的,一般为了不破坏安装的文件,出厂默认配置最好不要去改。

units单位 

配置大小单位,开头定义基本度量单位,只支持bytes,大小写不敏感。

 INCLUDES

Redis只有一个配置文件,如果多个人进行开发维护,那么就需要多个这样的配置文件,这时候多个配置 文件就可以在此通过 include /path/to/local.conf 配置进来,而原本的 redis.conf 配置文件就作为一个总闸。 

NETWORK 

GENERAL 

 ​​​​​

 SNAPSHOTTING

这里的配置主要用来做持久化操作。

REPLICATION 

SECURITY 

requirepass:设置redis连接密码。

比如: requirepass 123 表示redis的连接密码为123。 

CLIENTS 

 MEMORY MANAGEMENT

APPEND ONLY MODE 

 LUA SCRIPTING

参数:

lua-time-limit:一个lua脚本执行的最大时间,单位为ms。默认值为5000. 

REDIS CLUSTER 

 

1. Redis核心配置文件中修改那个参数可以开启远程连接。 bind

2. Redis核心配置文件中如何修改Redis的端口号。port

 Redis其他功能_发布与订阅

什么是发布与订阅 

Redis 发布订阅 (pub/sub) 是一种消息通信模式:发送者 (pub) 发送消息,订阅者 (sub) 接收消息。

 什么时候用发布订阅

看到发布订阅的特性,用来做一个简单的实时聊天系统再适合不过了。再比如,在一个博客网站中,有 100个粉丝订阅了你,当你发布新文章,就可以推送消息给粉丝们拉。

Redis的发布与订阅 

发布订阅命令行实现 

订阅

语法格式:

subcribe 主题名字

示例:

127.0.0.1:6379> SUBSCRIBE channel-1
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "channel-1"
3) (integer) 1

 发布命令

语法格式:

publish channel-1 hello

示例: 打开另一个客户端,给channel1发布消息hello

127.0.0.1:6379> PUBLISH channel-1 hello
(integer) 1

打开第一个客户端可以看到发送的消息

127.0.0.1:6379> SUBSCRIBE channel-1
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "channel-1"
3) (integer) 1
1) "message"
2) "channel-1"
3) "hello"

 

1. Redis技术中如何订阅一个主题。 add

Redis其他功能_慢查询 

什么是慢查询 

慢查询,顾名思义就是比较慢的查询,但是究竟是哪里慢呢?

Redis命令执行的整个过程

 

什么是慢查询日志 

慢查询日志是Redis服务端在命令执行前后计算每条命令的执行时长,当超过某个阈值是记录下来的日志。日志中记录了慢查询发生的时间,还有执行时长、具体什么命令等信息,它可以用来帮助开发和运维人员定位系统中存在的慢查询。

如何获取慢查询日志

可以使用 slowlog get 命令获取慢查询日志,在 slowlog get 后面还可以加一个数字,用于指定获取 慢查询日志的条数,比如,获取3条慢查询日志:

127.0.0.1:6379> SLOWLOG get 3
1) 1) (integer) 0
2) (integer) 1640056567
3) (integer) 11780
4) 1) "FLUSHALL"
5) "127.0.0.1:43406"
6) ""

 如何获取慢查询日志的长度

可以使用 slowlog len 命令获取慢查询日志的长度。

> slowlog len
(integer) 121

 

怎么配置慢查询的参数 

如何进行配置 

查看慢日志配置

查看redis慢日志配置,登陆redis服务器,使用redis-cli客户端连接redis server

127.0.0.1:6379> config get slow*
1) "slowlog-max-len"
2) "128"
3) "slowlog-log-slower-than"
4) "10000"

 修改Redis配置文件

比如,把slowlog-log-slower-than设置为1000,slowlog-max-len设置为1200:

slowlog-log-slower-than 1000
slowlog-max-len 1200

使用 config set 命令动态修改。 

 比如,还是把slowlog-log-slower-than设置为1000,slowlog-max-len设置为1200:

> config set slowlog-log-slower-than 1000
OK
> config set slowlog-max-len 1200
OK
> config rewrite
OK

1. Redis技术中慢查询主要作用___。定位系统存在的慢操作

2. Redis慢查询技术中通过修改___预设阈值。 slowlog-log-slower-than

 Redis其他功能_流水线pipeline

1次网络命令通信模型 

 

 经历了1次时间 = 1次网络时间 + 1次命令时间。

批量网络命令通信模型 

什么是流水线? 

案例展示 

从北京到上海的一条命令的生命周期有多长?

执行一条命令在redis端可能需要几百微秒,而在网络光纤中传输只花费了13毫秒。

pipeline-Jedis实现 

首先,引入jedis依赖包:

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

没有pipeline的命令执行

Jedis jedis - new Jedis("127.0.0.1",6379);
      for ( int i = 0 ; i < 10000 ; i ++ ){
         jedis.hset("hashkey:" + i , "field" + i , "value" + i);
}

使用pipeline 

Jedis jedis = new Jedis("127.0.0.1",6379);
     for ( int i = 0; i < 100 ; i++) {
         Pipeline pipeline = jedis.ppipelined();
         for (int j = i * 100 ; j < (i + 1) * 100 ; j++) {
              pipeline.hset("hashkey:" + j,"field" + j, "value" + j);
      }
    pipeline.syncAndReturnAll();
}

1. Redis技术中Pipeline主要作用是。 减少了网络时间的开销

Redis数据安全_持久化机制概述 

由于Redis的数据都存放在内存中,如果没有配置持久化,Redis重启后数据就全丢失了,于是需要开启 Redis的持久化功能,将数据保存到磁盘上,当Redis重启后,可以从磁盘中恢复数据。 

持久化机制概述

对于Redis而言,持久化机制是指把内存中的数据存为硬盘文件, 这样当Redis重启或服务器故障时能根 据持久化后的硬盘文件恢复数据。

持久化机制的意义 

redis持久化的意义,在于故障恢复。比如部署了一个redis,作为cache缓存,同时也可以保存一些比较 重要的数据。

 

Redis提供了两个不同形式的持久化方式 

1. Redis持久化机制主要解决___问题。 数据丢失 

2. 开启Redis的持久化功能,将数据保存到____上。 磁盘

Redis数据安全_RDB持久化机制实战 

RDB是什么 

在指定的时间间隔内将内存的数据集快照写入磁盘,也就是行话讲的快照,它恢复时是将快照文件直接读到内存里。

 

配置dump.rdb文件 

RDB保存的文件,在redis.conf中配置文件名称,默认为dump.rdb。

 rdb文件的保存位置,也可以修改。默认在Redis启动时命令行所在的目录下。

rdb文件的保存路径,也可以修改。默认为Redis启动时命令行所在的目录下

dir ./

触发机制-主要三种方式 

RDB配置

 

配置新的保存规则 

给redis.conf添加新的快照策略,30秒内如果有5次key的变化,则触发快照。配置修改后,需要重启 Redis服务。

save 3600 1
save 300 100
save 60 10000
save 30 5

 flushall

执行flushall命令,也会触发rdb规则。

save与bgsave 

高级配置 

stop-writes-on-bgsave-error

默认值是yes。当Redis无法写入磁盘的话,直接关闭Redis的写操作。

rdbcompression 

默认值是yes。对于存储到磁盘中的快照,可以设置是否进行压缩存储。如果是的话,redis会采用LZF算 法进行压缩。如果你不想消耗CPU来进行压缩的话,可以设置为关闭此功能,但是存储在磁盘上的快照 会比较大。

rdbchecksum 

默认值是yes。在存储快照后,我们还可以让redis使用CRC64算法来进行数据校验,但是这样做会增加 大约10%的性能消耗,如果希望获取到最大的性能提升,可以关闭此功能。

恢复数据 

只需要将rdb文件放在Redis的启动目录,Redis启动时会自动加载dump.rdb并恢复数据。

1. Redis技术中下列____是RDB缺点。 会丢失最后一次快照后的所有修改 

2. Redis技术中RDB持久化如何表示30秒内如果至少有100个 key的值变化,则保存。 

save 30 100

 Redis数据安全_AOF持久化机制实战

 AOF是什么

以日志的形式来记录每个写操作,将Redis执行过的所有写指令记录下来。

 AOF默认不开启

可以在redis.conf中配置文件名称,默认为appendonly.aof。

 

 AOF启动/修复/恢复

开启AOF

设置Yes:修改默认的appendonly no,改为yes

appendonly yes

 设置数据。

set k11 v11
set k12 v12
set k13 v13
set k14 v14
set k15 v15

AOF同步频率设置 

 1. Redis技术中AOF持久化主要解决___问题。 数据丢失

2.Redis技术中AOF同步频率设置每秒记录日志一次。 appendfsync everysec

 Redis数据安全_如何选用持久化方式

 不要仅仅使用RDB

RDB数据快照文件,都是每隔5分钟,或者更长时间生成一次,这个时候就得接受一旦redis进程宕机, 那么会丢失最近5分钟的数据。

 也不要仅仅使用AOF

1. 你通过AOF做冷备,没有RDB做冷备,来的恢复速度更快。

2. RDB每次简单粗暴生成数据快照,更加健壮,可以避免AOF这种复杂的备份和恢复机制的bug。

 综合使用AOF和RDB两种持久化机制

用AOF来保证数据不丢失,作为数据恢复的第一选择,用RDB来做不同程度的冷备,在AOF文件都丢失或损坏不可用的时候,还可以使用RDB来进行快速的数据恢复。

 

 1. Redis技术中企业中该如何选择持久化机制。

综合使用AOF和RDB两种持久化机制

 Redis事务_事务的概念与ACID特性

 数据库层面事务

在数据库层面,事务是指一组操作,这些操作要么全都被成功执行,要么全都不执行。

 数据库事务的四大特性

 Redis事务

Redis事务是一组命令的集合,一个事务中的所有命令都将被序列化,按照一次性、顺序性、排他性的执行一系列的命令。

 

 Redis事务三大特性

 Redis事务执行的三个阶段

 1. Redis事务说法错误的是__。 保证原子性

 2. Redis实现事务,是基于__队列

Redis事务_Redis事务基本操作 

Multi、Exec、discard

事务从输入Multi命令开始,输入的命令都会依次压入命令缓冲队列中,并不会执行,直到输入Exec后, Redis会将之前的命令缓冲队列中的命令依次执行。组队过程中,可以通过discard来放弃组队。

 例子

正常执行

127.0.0.1:6379> set t1 1
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> set id 12
QUEUED
127.0.0.1:6379(TX)> get id
QUEUED
127.0.0.1:6379(TX)> incr t1
QUEUED
127.0.0.1:6379(TX)> incr t1
QUEUED
127.0.0.1:6379(TX)> get t1
QUEUED
127.0.0.1:6379(TX)> EXEC
1) OK
2) "12"
3) (integer) 2
4) (integer) 3
5) "3"

放弃事务

127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> set name z3
QUEUED
127.0.0.1:6379(TX)> set age 29
QUEUED
127.0.0.1:6379(TX)> incr t1
QUEUED
127.0.0.1:6379(TX)> DISCARD
OK

全体连坐

127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> set name z3
QUEUED
127.0.0.1:6379(TX)> get name
QUEUED
127.0.0.1:6379(TX)> incr t1
QUEUED
127.0.0.1:6379(TX)> get t1
QUEUED
127.0.0.1:6379(TX)> set email
(error) ERR wrong number of arguments for 'set' command
127.0.0.1:6379(TX)> exec
(error) EXECABORT Transaction discarded because of previous errors.

 冤有头,债有主

127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> set age 11
QUEUED
127.0.0.1:6379(TX)> incr t1
QUEUED
127.0.0.1:6379(TX)> set email abc@163.com
QUEUED
127.0.0.1:6379(TX)> incr email
QUEUED
127.0.0.1:6379(TX)> get age
QUEUED
127.0.0.1:6379(TX)> exec
1) OK
2) (integer) 5
3) OK
4) (error) ERR value is not an integer or out of range
5) "11"

注意: 运行时错误,即非语法错误,正确命令都会执行,错误命令返回错误。

 1. Redis技术中如何开启一个事务。multi

 Redis集群_主从复制

 概述

在现有企业中80%公司大部分使用的是redis单机服务,在实际的场景当中单一节点的redis容易面临风险。 

 解决办法

要实现分布式数据库的更大的存储容量和承受高并发访问量,我们会将原来集中式数据库的数据分别存储到其他多个网络节点上。

 

 什么是主从复制

 

 

 1.单机Redis会遇到____问题。容量

 2. 下列不是Redis主从复制作用的是__兼容性

 Redis集群_主从复制环境搭建

 编写配置文件

新建redis6379.conf

include /usr/local/redis/redis.conf
pidfile /var/run/redis_6379.pid
port 6379
dbfilename dump6379.rdb

新建redis6380.conf

include /usr/local/redis/redis.conf
pidfile /var/run/redis_6380.pid
port 6380
dbfilename dump6380.rdb

新建redis6381.conf

include /usr/local/redis/redis.conf
pidfile /var/run/redis_6381.pid
port 6381
dbfilename dump6381.rdb

启动三台redis服务器

./redis-server ../redis6379.conf
./redis-server ../redis6380.conf
./redis-server ../redis6381.conf

查看系统进程

[root@localhost src]# ps -ef |grep redis
root 40737 1 0 22:05 ? 00:00:00 ./redis-server *:6379
root 40743 1 0 22:05 ? 00:00:00 ./redis-server *:6380
root 40750 1 0 22:05 ? 00:00:00 ./redis-server *:6381
root 40758 40631 0 22:05 pts/0 00:00:00 grep --color=auto redis

查看三台主机运行情况

#打印主从复制的相关信息
./redis-cli -p 6379
./redis-cli -p 6380
./redis-cli -p 6381
127.0.0.1:6379> info replication
127.0.0.1:6380> info replication
127.0.0.1:6381> info replication

配从库不配主库

语法格式:

slaveof <ip> <port>

示例: 在6380和6381上执行。

127.0.0.1:6380> SLAVEOF 127.0.0.1 6379
OK

 在主机上写,在从机上可以读取数据

set k1 v1

Redis集群_主从复制原理剖析

 主从复制可以分为3个阶段

1、连接建立阶段(即准备阶段)

2、数据同步阶段

3、命令传播阶段

 复制过程大致分为6个过程

 1、保存主节点(master)信息。

      执行 slaveof 后 查看状态信息

info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6379
master_link_status:up

2、从节点(slave)内部通过每秒运行的定时任务维护复制相关逻辑,当定时任务发现存在新的主 节点后,会尝试与该节点建立网络连接

 3、从节点与主节点建立网络连接

从节点会建立一个 socket 套接字,从节点建立了一个端口为51234的套接字,专门用于接受主节点发送 的复制命令。

 4、发送ping命令

连接建立成功后从节点发送 ping 请求进行首次通信。

 

 4、权限验证。

如果主节点设置了 requirepass 参数,则需要密码验证,从节点必须配置 masterauth 参数保证与主节 点相同的密码才能通过验证;如果验证失败复制将终止,从节点重新发起复制流程。

5、同步数据集。

主从复制连接正常通信后,对于首次建立复制的场景,主节点会把持有的数据全部发送给从节点,这部分操作是耗时最长的步骤。

 主从同步策略

主从刚刚连接的时候,进行全量同步;全同步结束后,进行增量同步。当然,如果有需要,slave 在任何 时候都可以发起全量同步。redis 策略是,无论如何,首先会尝试进行增量同步,如不成功,要求从机进 行全量同步。

 例如

保存一个缓存

set name baizhan

记录命令为

$3 \r \n
set \r \n
$4 \r \n
name \r \n
$5 \r \n
baizhan \r \n

 

6、命令持续复制。

当主节点把当前的数据同步给从节点后,便完成了复制的建立流程。接下来主节点会持续地把写命令发送给从节点,保证主从数据一致性。

 1.Redis技术中如何设置Redis密码。requirepass

2. Redis主从复制技术中主从刚刚连接的时候,进行___同步。全量

 Redis集群_ 哨兵监控概述

 Redis主从复制缺点

当主机 Master 宕机以后,我们需要人工解决切换。

 

 主从切换技术

当主服务器宕机后,需要手动把一台从服务器切换为主服务器,这就需要人工干预,费事费力,还会造 成一段时间内服务不可用。这不是一种推荐的方式,更多时候,我们优先考虑哨兵模式

 哨兵概述

哨兵模式是一种特殊的模式,首先Redis提供了哨兵的命令,哨兵是一个独立的进程,作为进程,它会独 立运行。其原理是哨兵通过发送命令,等待Redis服务器响应,从而监控运行的多个Redis实例。

 

 

 1.Redis技术中哨兵模式解决____问题。 主从切换

 Redis集群_哨兵监控环境搭建

 新建sentinel-26379.conf文件

#端口
port 26379
#守护进程运行
daemonize yes
#日志文件
logfile "26379.log"
sentinel monitor mymaster 192.168.92.128 6379 2

 新建sentinel-26380.conf文件

#端口
port 26380
#守护进程运行
daemonize yes
#日志文件
logfile "26380.log"
sentinel monitor mymaster 192.168.66.100 6379 2

新建sentinel-26381.conf文件

#端口
port 26381
#守护进程运行
daemonize yes
#日志文件
logfile "26381.log"
sentinel monitor mymaster 192.168.66.100 6379 2

哨兵节点的启动两种方式

redis-sentinel sentinel-26379.conf

查看哨兵节点状态

[root@localhost src]# ./redis-cli -p 26379
127.0.0.1:26379>
127.0.0.1:26379>
127.0.0.1:26379> info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=192.168.66.100:6379,slaves=2,sentinels=3

Redis集群_哨兵工作原理详解

 监控阶段

 

 通知阶段

sentinel不断的向master和slave发起通知,收集信息。

故障转移阶段

通知阶段sentinel发送的通知没得到master的回应,就会把master标记为SRI_S_DOWN,并且把master 的状态发给各个sentinel,其他sentinel听到master挂了,说我不信,我也去看看,并把结果共享给各 个sentinel,当有一半的sentinel都认为master挂了的时候,就会把master标记为SRI_0_DOWN。

 

 

 投票方式

方式: 自己最先接到哪个sentinel的竞选通知就会把票投给它。

剔除一些情况:

1. 不在线的

2. 响应慢的

3. 与原来master断开时间久的

4. 优先级原则

 

 1.Redis哨兵模式是Redis的___架构的一种方式。高可用

 Redis集群_故障转移

 概述

演示当主节点发生故障时,哨兵的监控和自动故障转移功能。

演示故障转移

使用kill命令杀掉主节点

ps aux |grep redis
kill -9 pid

查看哨兵节点信息

如果此时立即在哨兵节点中使用info Sentinel命令查看。

[root@localhost src]# ./redis-cli -p 26379
127.0.0.1:26379> info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=127.0.0.1:6381,slaves=5,sentinels=3

注意: 会发现主节点还没有切换过来,因为哨兵发现主节点故障并转移,需要一段时间。

 重启6379节点

[root@localhost src]# ./redis-cli info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6381
master_link_status:down

配置文件都会被改写

故障转移阶段,哨兵和主从节点的配置文件都会被改写

include /usr/local/redis/redis.conf
pidfile "/var/run/redis_6379.pid"
port 6379
dbfilename "dump6379.rdb"
# Generated by CONFIG REWRITE
daemonize yes
protected-mode no
appendonly yes
slowlog-max-len 1200
slowlog-log-slower-than 1000
save 5 1
user default on nopass ~* &* +@all
dir "/usr/local/redis"
replicaof 127.0.0.1 6381

 Redis集群_Cluster模式概述

 Redis有三种集群模式

 哨兵模式的缺点

 

 Cluster模式概述

 Redis集群是一个由多个主从节点群组成的分布式服务集群,它具有复制、高可用和分片特性。

 Redis集群的优点

 1.Redis集群是一个由__节点群组成的分布式服务集群。多个主从

 2.Redis哨兵模式的缺点是__哨兵选举期间,不能对外提供服务

Redis集群_Cluster模式搭建 

 Redis的集群搭建最少需要3个master节点,我们这里搭建3个master,每个下面挂一个slave节点,总 共6个Redis节点;

环境准备

第1台机器: 192.168.66.101 8001端口 8002端口

第2台机器: 192.168.66.102 8001端口 8002端口

第3台机器: 192.168.66.103 8001端口 8002端口

 创建文件夹

mkdir -p /usr/local/redis/redis-cluster/8001 /usr/local/redis/redis-cluster/8002

拷贝配置文件

将redis安装目录下的 redis.conf 文件分别拷贝到8001目录下

cp /usr/local/redis/redis.conf /usr/local/redis/redis-cluster/8001

修改redis.conf文件以下内容

port 8001
daemonize yes
pidfile "/var/run/redis_8001.pid"
#指定数据文件存放位置,必须要指定不同的目录位置,不然会丢失数据
dir /usr/local/redis/redis-cluster/8001/
#启动集群模式
cluster-enabled yes
#集群节点信息文件,这里800x最好和port对应上
cluster-config-file nodes-8001.conf
# 节点离线的超时时间
cluster-node-timeout 5000
#去掉bind绑定访问ip信息
#bind 127.0.0.1
#关闭保护模式
protected-mode no
#启动AOF文件
appendonly yes
#如果要设置密码需要增加如下配置:
#设置redis访问密码
#requirepass xiaoton
#设置集群节点间访问密码,跟上面一致
#masterauth xiaoton

文件拷贝到8002文件夹

#将8001修改为8002:
cp /usr/local/redis/redis-cluster/8001/redis.conf /usr/local/redis/rediscluster/8002
# 批量修改字符串
:%s/8001/8002/g

将本机机器上的文件拷贝到另外两台机器上

# 第二台机器
scp /usr1/redis/redis-cluster/8001/redis.conf
root@192.168.66.102:/usr1/redis/redis-cluster/8001/
scp /usr1/redis/redis-cluster/8002/redis.conf
root@192.168.66.102:/usr1/redis/redis-cluster/8002/
# 第三台机器
scp /usr1/redis/redis-cluster/8001/redis.conf
root@192.168.66.103:/usr1/redis/redis-cluster/8001/
scp /usr1/redis/redis-cluster/8002/redis.conf
root@192.168.66.103:/usr1/redis/redis-cluster/8002/

分别启动这6个redis实例

/usr/local/redis/src/redis-server /usr/local/redis/redis-cluster/8001/redis.conf
/usr/local/redis/src/redis-server /usr/local/redis/redis-cluster/8002/redis.conf

检查是否启动成功

ps -ef |grep redis

使用redis-cli创建整个redis集群

/usr/local/redis/src/redis-cli -a redis-pw --cluster create --cluster-replicas 1
192.168.66.101:8001 192.168.66.101:8002 192.168.66.102:8001 192.168.66.102:8002
192.168.66.103:8001 192.168.66.103:8002

查看帮助命令

src/redis‐cli --cluster help

验证集群 

连接任意一个客户端

/usr/local/redisd/src/redis-cli -a redis-pw -c -h 192.168.66.101 -p 8001

查看集群的信息 

cluster info

 Redis集群_Cluster模式原理分析

 Redis Cluster将所有数据划分为16384个slots(槽位),每个节点负责其中一部分槽位。槽位的信息存储 于每个节点中。只有master节点会被分配槽位,slave节点不会分配槽位。

HASH_SLOT = CRC16(key) % 16384

 命令执行

set k1 v1

 

 可以通过{}来定义组的概念,从而是key中{}内相同内容的键值对放到同一个slot中。

mset k1{test} v1 k2{test} v2 k3{test} v3

故障恢复 

查看节点

192.168.66.103:8001> cluster nodes

 杀死Master节点

lsof -i:8001
kill -9 pid

观察节点信息

 1. Redis Cluster模式默认会对key值使用__算法进行hash得到一个整数值,然后用这个整数值对16384 进行取模来得到具体槽位。crc-16

 Redis集群_Java操作Redis集群

 Jedis整合Redis

引入jedis的maven坐标

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

Java编写的代码

public class JedisClusterTest {
    public static void main(String[] args) throws IOException {
         JedisPoolConfig config = new JedisPoolConfig();
         config.setMaxTotal(20);
         config.setMaxIdle(10);
         config.setMinIdle(5);
         Set<HostAndPort> jedisClusterNode = new HashSet<HostAndPort>();
         jedisClusterNode.add(new HostAndPort("192.168.66.101", 8001));
         jedisClusterNode.add(new HostAndPort("192.168.66.102", 8002));
         jedisClusterNode.add(new HostAndPort("192.168.66.103", 8001));
         JedisCluster jedisCluster = null;
         try {
               //connectionTimeout:指的是连接一个url的连接等待时间
               //soTimeout:指的是连接上一个url,获取response的返回等待时间
               jedisCluster = new JedisCluster(jedisClusterNode, 6000, 5000, 10, "redis-pw", config);
               System.out.println(jedisCluster.set("name", "zhangsan"));
               System.out.println(jedisCluster.get("name"));
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (jedisCluster != null) {
                        jedisCluster.close();
            }
        }
    }
}

SpringBoot 整合 Redis

引入maven坐标

<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring‐boot‐starter‐data‐redis</artifactId>
</dependency>

配置文件

##单服务器
spring.redis.cluster.nodes=192.168.159.129:7001,192.168.159.129:7002,192.168.159
.129:7003,192.168.159.129:7004,192.168.159.129:7005,192.168.159.129:7006
## 连接池最大连接数(使用负值表示没有限制)
spring.redis.pool.max-active=300
## Redis数据库索引(默认为0)
spring.redis.database=0
## 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.pool.max-wait=-1
## 连接池中的最大空闲连接
spring.redis.pool.max-idle=100
## 连接池中的最小空闲连接
spring.redis.pool.min-idle=20
## 连接超时时间(毫秒)
spring.redis.timeout=60000

java代码

@RestController
public class TestController {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @RequestMapping("/test_cluster")
    public void testCluster() throws InterruptedException {
        stringRedisTemplate.opsForValue().set("user:name", "xiaoton");
        System.out.println(stringRedisTemplate.opsForValue().get("user:name"));
    }
}

Redis企业级解决方案_Redis脑裂

 什么是Redis的集群脑裂

Redis的集群脑裂是指因为网络问题,导致Redis Master节点跟Redis slave节点和Sentinel集群处于不同 的网络分区,此时因为sentinel集群无法感知到master的存在,所以将slave节点提升为master节点。

 

注意:

此时存在两个不同的master节点,就像一个大脑分裂成了两个。集群脑裂问题中,如果客户端还在基于原来的master节点继续写入数据,那么新的Master节点将无法同步这些数据,当网络问题 解决之后,sentinel集群将原先的Master节点降为slave节点,此时再从新的master中同步数据, 将会造成大量的数据丢失。

 解决方案

redis.conf配置参数:

min-replicas-to-write 1
min-replicas-max-lag 5

 1.Redis的集群脑裂是指___问题。网络

 2.Redis的集群脑裂通过配置____命令解决。min-replicas-max-lag

 Redis企业级解决方案_缓存预热

 缓存冷启动

缓存中没有数据,由于缓存冷启动一点数据都没有,如果直接就对外提供服务了,那么并发量上来 Mysql就裸奔挂掉了。

 

 缓存冷启动场景

新启动的系统没有任何缓存数据,在缓存重建数据的过程中,系统性能和数据库负载都不太好,所以最好是在系统上线之前就把要缓存的热点数据加载到缓存中,这种缓存预加载手段就是缓存预热。

 

 

 1.Redis技术中缓存预热主要解决____问题。 缓存冷启动

 Redis企业级解决方案_缓存穿透

 概念

缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,如发起为id为“-1”的数据或id为特别 大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大。

 

 

解决方案

1. 对空值缓存: 如果一个查询返回的数据为空(不管数据是否存在),我们仍然把这个空结果缓存, 设置空结果的过期时间会很短,最长不超过5分钟。

2. 布隆过滤器: 如果想判断一个元素是不是在一个集合里,一般想到的是将集合中所有元素保存起 来,然后通过比较确定。

布隆过滤器 

什么是布隆过滤器

布隆过滤器是一种数据结构,比较巧妙的概率型数据结构(probabilistic data structure),特点是高效 地插入和查询,可以用来告诉你 “某样东西一定不存在或者可能存在”。

 

 

 代码实现

引入hutool包

<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.7.17</version>
</dependency>

java代码实现

// 初始化 注意 构造方法的参数大小10 决定了布隆过滤器BitMap的大小
BitMapBloomFilter filter = new BitMapBloomFilter(10);
filter.add("123");
filter.add("abc");
filter.add("ddd");

boolean abc = filter.contains("abc");
System.out.println(abc);

1.布隆过滤器是一种数据库结构,底层是___。 bit数组

2.Redis技术中缓存穿透主要指____问题。 缓存和数据库中都没有的数据

Redis企业级解决方案_缓存击穿

 

概念

某一个热点 key,在缓存过期的一瞬间,同时有大量的请求打进来,由于此时缓存过期了,所以请求最 终都会走到数据库,造成瞬时数据库请求量大、压力骤增,甚至可能打垮数据库

 

解决方案

代码实现

public String get(String key) throws InterruptedException {

    String value = jedis.get(key);
    // 缓存过期
    if (value == null){
        // 设置3分钟超时,防止删除操作失败的时候 下一次缓存不能load db
        Long setnx = jedis.setnx(key + "mutex", "1");
        jedis.pexpire(key + "mutex", 3 * 60);
        // 代表设置成功
        if (setnx == 1){
            // 数据库查询
            //value = db.get(key);
            //保存缓存
            jedis.setex(key,3*60,"");
            jedis.del(key + "mutex");
            return value;
    }else {
            // 这个时候代表同时操作的其他线程已经load db并设置缓存了。 需要重新重新获取缓存
            Thread.sleep(50);
            // 重试
            return get(key);
        }
    }else {
            return value;
     }
}

 1.Redis技术中缓存击穿指____问题。 缓存中没有但数据库中有的数据

 2.Redis技术中缓存击穿如何解决。加互斥锁

 Redis企业级解决方案_缓存雪崩

 概念

缓存雪崩是指在我们设置缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效,请求全部转发 到DB,DB瞬时压力过重雪崩。

缓存正常从Redis中获取,示意图如下:

缓存失效瞬间示意图如下:

解决方案

过期时间打散: 既然是大量缓存集中失效,那最容易想到就是让他们不集中生效。可以给缓存的过期时间时加上一个随机值时间,使得每个 key 的过期时间分布开来,不会集中在同一时刻失效。

热点数据不过期: 该方式和缓存击穿一样,也是要着重考虑刷新的时间间隔和数据异常如何处理的情况。

加互斥锁: 该方式和缓存击穿一样,按 key 维度加锁,对于同一个 key,只允许一个线程去计算, 其他线程原地阻塞等待第一个线程的计算结果,然后直接走缓存即可。

加锁排队代码如下:

public Object GetProductListNew(String cacheKey) {
        int cacheTime = 30;
        String lockKey = cacheKey;
        // 获取key的缓存
        String cacheValue = jedis.get(cacheKey);
        // 缓存未失效返回缓存
        if (cacheValue != null) {
                return cacheValue;
            } else {
                // 枷锁
                synchronized(lockKey) {
                // 获取key的value值
                cacheValue = jedis.get(cacheKey);
                if (cacheValue != null) {
                        return cacheValue;
                } else {
                //这里一般是sql查询数据
                // db.set(key)
                // 添加缓存
                jedis.set(cacheKey,"");
            }
        }
        return cacheValue;
    }
}

注意: 加锁排队只是为了减轻数据库的压力,并没有提高系统吞吐量。

 1.Redis技术中缓存雪崩指____问题。缓存中数据大批量到过期时间

****2.Redis技术中缓存雪崩____解决。 缓存数据的过期时间设置随机

 Redis企业级解决方案_Redis开发规范

 

示例

# 表名 主键 主键值 存储列名字
set user:user_id:1:name xiaoton
set user:user_id:1:age 20
#查询这个用户
keys user:user_id:9*

 value设计

拒绝bigkey

防止网卡流量、慢查询,string类型控制在10KB以内,hash、list、set、zset元素个数不要超过5000。

 命令使用

1、禁用命令

禁止线上使用keys、flushall、flushdb等,通过redis的rename机制禁掉命令,或者使用scan的方式渐 进式处理。

2、合理使用select

redis的多数据库较弱,使用数字进行区分,很多客户端支持较差,同时多业务用多数据库实际还是单线 程处理,会有干扰。

3、使用批量操作提高效率

4、不建议过多使用Redis事务功能

Redis的事务功能较弱(不支持回滚),而且集群版本(自研和官方)要求一次事务操作的key必须在一个slot 上。

 客户端使用

1. Jedis : github.com/xetorthio/j… 重点推荐

2. Spring Data redis : github.com/spring-proj… 使用Spring框架时推荐

3. Redisson : github.com/mrniko/redi… 分布式锁、阻塞队列的时重点推荐

1、避免多个应用使用一个Redis实例

不相干的业务拆分,公共数据做服务化。

2、使用连接池

可以有效控制连接,同时提高效率,标准使用方式:

执行命令如下:
Jedis jedis = null;
try {
        jedis = jedisPool.getResource();
        //具体的命令
        jedis.executeCommand()
    } catch (Exception e) {
        logger.error("op key {} error: " + e.getMessage(), key, e);
    } finally {
        //注意这里不是关闭连接,在JedisPool模式下,Jedis会被归还给资源池。
        if (jedis != null)
                jedis.close();
    }

 1.Redis技术中下列符合key设计__。user:id.1.age

Redis企业级解决方案_数据一致性 

 缓存已经在项目中被广泛使用,在读取缓存方面,大家没啥疑问,都是按照下图的流程来进行业务操作。

 

缓存说明: 从理论上来说,给缓存设置过期时间,是保证最终一致性的解决方案。

三种更新策略

      1. 先更新数据库,再更新缓存

      2. 先删除缓存,再更新数据库

      3. 先更新数据库,再删除缓存

先更新数据库,再更新缓存

这套方案,大家是普遍反对的。为什么呢?

线程安全角度

        同时有请求A和请求B进行更新操作,那么会出现

          (1)线程A更新了数据库

          (2)线程B更新了数据库

          (3)线程B更新了缓存

          (4)线程A更新了缓存 这就出现请求A更新缓存应该比请求B更新缓存早才对,但是因为网络等原因,B却比A更早更新了缓存。 这就导致了脏数据,因此不考虑。

先删缓存,再更新数据库

先更新数据库,再延时删缓存

 

 1.Redis技术中哪一种保证数据一致性最合理。设置过期时间