目录
Redis可视化工具_安装Redis_Desktop_Manager
StringRedisTemplate与RedisTemplate
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-cliping命令可以检测服务器是否正常(服务器返回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的数量,结果为5setbit设置或获取的是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:up2、从节点(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技术中哪一种保证数据一致性最合理。设置过期时间