Redis入门到精通

NoSql概述

为什么要用NoSql

现在处于数据量爆炸的年代,传统数据库性能已经不能满足与当下的业务。

什么是NoSql

NoSql=Not only SQL ( 不仅仅是SQL )

关系型数据库:表 行 列

泛指非关系型数据库的,随着web2.0互联网的诞生!传统的关系型数据库很难对付web2.0时代。尤其是超大规模的高并发的社区!爆露出来很多难以克服的问题,NoSql在当今大环境数据环境下发展的十分迅速,Redis是发展最快的,而且是我们当下必须要掌握的技术!

很多的数据类型用户的个人信息,社交网络,地理位置。这些数据类型的存储不需要一个固定的格式!不需要多余的操作就可以实现横向扩展!

NoSql特点

1、方便扩展(数据之间没有关系,很好扩展)

2、大数据量高性能(Redis一秒写8万次,读取11万,NoSql的缓存记录是一种细粒度的缓存,性能会比较高)

3、数据类型是多样型的!(不需要事先设计数据库!随取随用!)

4、传统的RDBMS(关系型数据库)和NoSql

传统的RDBMS
- 结构化组织
- SQL
- 数据和关系都存在单独的表中 row col
- 严格的一致性
- 基础的事务
NoSql
- 不仅仅是数据
- 没有固定的查询语言
- 键值对存储,列存储,文档存储,图形数据库(社交关系)
- 最终一致性
- 高性能,高可用,高扩展

了解3V+3高

大数据的时代的3v:主要描述的问题

1.海量Volume

2.多样Variety

3.实时Velocity

大数据的时代的3高:主要描述的问题

1.高并发

2.高扩展

3.高性能

NoSql的四大分类

KV键值对:

  • 新浪: Redis
  • 美团:Redis+tair
  • 阿里、百度:Redis+Memecahe

文档形数据库(bson格式和json一样)

  • MongoDB

    • 主要存储文档文档类型

    • MongoDB是一个基于分布式文件存储的数据库,c++编写,主要用来处理大量的文档

    • MongoDB是介于关系型数据库和非关系型数据库的中间产品,是非关系型数据库功能能最丰富的

列存储数据库

  • HBase
  • 分布式文件系统

图关系型数据库

主要是用来梳理各个节点之间的关系,推荐系统,构建关系图谱会用到

  • Neo4J
  • InfoGrid

Redis入门

什么是Redis

Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。

Redis能干吗

1、内存存储,持久化,内存是断电即失,所以说持久化很重要(rdb、aof)

2、效率高可用于缓存

3、发布定域系统

4、地图信息分析

5、计时器、计数器

Redis的特性

1、多样的存储数据类型

2、持久化

3、集群

4、事务

Windows安装

自行百度

Linux安装

# 1官网下载https://redis.io/download 最新redis.tar.gzip安装包上传至服务器并压缩
# 2进入解压后的目录执行下面命令
[root@pinyoyougou-docker redis-6.2.4]# yum install gcc-c++
[root@pinyoyougou-docker redis-6.2.4]# make
[root@pinyoyougou-docker redis-6.2.4]# make install
# 3进入到/usr/local/bin目录就能找到安装的Redis
# 4将redis配置文件保存到bin目录下
[root@pinyoyougou-docker redis-6.2.4]# cp -a redis.conf ../bin
# redis默认不是后台启动的,修改配置文件 将daemonize 改为yes
[root@pinyoyougou-docker redis-6.2.4]# vim redis.conf
# 启动redis服务 如果启动报错就把配置文件删了再重新copy一下
[root@pinyoyougou-docker redis-6.2.4]# redis-server redis.conf

基础的知识

Redis默认有16个数据库

默认使用的是第0个数据库

可以使用select进行切换

[root@pinyoyougou-docker bin]# redis-cli
127.0.0.1:6379> select 3
OK
#显示数据库的存储大小
127.0.0.1:6379[3]> DBSIZE
#显示所有的key
127.0.0.1:6379[3]> keys *
#清空所有数据库的数据
127.0.0.1:6379[3]> flushall
#清空当前数据库
127.0.0.1:6379[3]> flushdb

Redis是单线程的

因为Redis是基于内存的操作,CPU不是Redis的瓶颈,Redis的瓶颈最有可能是机器内存的大小或者网络带宽。

redis为什么单线程还那么快?

1、误区1:高性能的服务器一定是多线程的?

2、误区2:多线程(cpu上下文会切换!)一定比单线程效率高!?

核心:redis是将所有的数据全部放在内存中的,所以说使用单线程去操作效率是最高的,多线程会存在cpu上下文切换的耗时问题,对于内存

系统来讲则不需要去使用多线程操作

五大数据类型

Redis-Key

# 设置过期时间
127.0.0.1:6379> EXPIRE name 10
(integer) 1
# 查看过期时间
127.0.0.1:6379> ttl name
# 当前key的类型
127.0.0.1:6379> type name

String(字符串)

基础

# 设置值
127.0.0.1:6379> set name fanyuanxin
OK
# 追加值 没有key 则set值
127.0.0.1:6379> APPEND name 123
(integer) 13
127.0.0.1:6379> get name
"fanyuanxin123"
# 查看字符长度
127.0.0.1:6379> STRLEN name
(integer) 13
# 自增1
127.0.0.1:6379> INCR views
(integer) 1
# 自减1
127.0.0.1:6379> DECR views
(integer) 1
# 增长10
127.0.0.1:6379> INCRBY views 10
# 减去10
127.0.0.1:6379> DECRBY views 20
# 设置name值
127.0.0.1:6379> set name fanyuanxin1234
OK
# 取 三位
127.0.0.1:6379> GETRANGE name 0 2
"fan"
# 获取全部的字符串和get key 是一样的
127.0.0.1:6379> GETRANGE name 0 -1
"fanyuanxin1234"
# 替换
127.0.0.1:6379> set number 1012323
OK
127.0.0.1:6379> SETRANGE number 3 44
(integer) 7
127.0.0.1:6379> get number
"1014423"

重点

# setex (set with expire) 设置过期时间
127.0.0.1:6379> clear
127.0.0.1:6379> setex key3 30 fanyuanxin
OK
127.0.0.1:6379> ttl key3
(integer) 24

#setnx (不存在设置) 分布式锁常用 如果存在key就保存不成功 如果不存在Key就保存成功
127.0.0.1:6379> SETNX key4 yuanxin
(integer) 1
127.0.0.1:6379> SETNX key4 yuanxin
(integer) 0

# 批量设置Key
127.0.0.1:6379> mset key1 k1 k2 k2 k3 k3
OK
# 批量get key
127.0.0.1:6379> mget key1 k2 k3
1) "k1"
2) "k2"
3) "k3"
# 批量不存在设置是原子操作 要不全成功 要不全失败
127.0.0.1:6379> MSETNX key4 yuanxin Key1 ke

# 设置对象字符串
127.0.0.1:6379> mset user:1:name zhangsan
OK
127.0.0.1:6379> get user:1:name
"zhangsan"

# getset 操作 获取并替换
127.0.0.1:6379> getset name fanyuanxin
(nil)
127.0.0.1:6379> getset name fanyuanxin12
"fanyuanxin"
127.0.0.1:6379> getset name fanyuanxin13
"fanyuanxin12"

应用场景

  • 计数器(incr)
  • 分布式锁(setnx)

List(列表)

我们可以把List完成,栈,队列,阻塞队列!

# 添加一个List值
127.0.0.1:6379> LPUSH list one
(integer) 1
127.0.0.1:6379> LPUSH list two
(integer) 2
127.0.0.1:6379> LPUSH list three
(integer) 3
# 查询全部List值
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "two"
3) "one"
# 查询前两个值
127.0.0.1:6379> LRANGE list 0 1
1) "three"
2) "two"
# 向右边插入一条数据
127.0.0.1:6379> RPUSH list four
(integer) 4
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "two"
3) "one"
4) "four"
# 移除左边的元素
127.0.0.1:6379> LPOP list 
"two"
# 移除右边的元素
"four"
127.0.0.1:6379> RPOP list
# 通过下标获取值
127.0.0.1:6379> LINDEX list 0
"one"
# 返回列表长度
127.0.0.1:6379> Llen list
# 移除指定的值
127.0.0.1:6379> LPUSH list fanyuanxin
(integer) 1
127.0.0.1:6379> LPUSH list zhangsan
(integer) 2
127.0.0.1:6379> LPUSH list lisi
(integer) 3
127.0.0.1:6379> LPUSH list lisiwangwu
(integer) 4
127.0.0.1:6379> LRANGE list 0 -1
1) "lisiwangwu"
2) "lisi"
3) "zhangsan"
4) "fanyuanxin"
127.0.0.1:6379> LREM list 1 lisi
####################################### 移除固定长的的list集合
127.0.0.1:6379> LPUSH list data1
(integer) 1
127.0.0.1:6379> LPUSH list data2
(integer) 2
127.0.0.1:6379> LPUSH list data3
(integer) 3
127.0.0.1:6379> LTRIM list 1 2
OK
127.0.0.1:6379> LRANGE list 0 -1
1) "data2"
2) "data1"
#################################### 移除列表的第一个元素到其他列表
127.0.0.1:6379> LPUSH list data1
(integer) 1
127.0.0.1:6379> LPUSH list data2
(integer) 2
127.0.0.1:6379> LPUSH list data3
(integer) 3
127.0.0.1:6379> RPOPLPUSH list mylist
"data1"
127.0.0.1:6379> LRANGE mylist 0 -1
1) "data1"
################################### 将列表中指定的索引值替换成另外一个值 更新操作
127.0.0.1:6379> LPUSH list data1
(integer) 1
127.0.0.1:6379> LPUSH list data2
(integer) 2
127.0.0.1:6379> LPUSH list data3
(integer) 3
127.0.0.1:6379> LSET list 0 data10
OK
127.0.0.1:6379> LRANGE list 0 -1
1) "data10"
2) "data2"
3) "data1"
################################### 将数据插入指定值的前面(after|before)或者后面
127.0.0.1:6379> LRANGE list 0 -1
1) "data10"
2) "data2"
3) "data1"
127.0.0.1:6379> LINSERT list AFTER data2 data3
(integer) 4
127.0.0.1:6379> LRANGE list 0 -1
127.0.0.1:6379> LINSERT list before data2 data4

小结

  • 他实际上是一个链表 before Node after ,left right 都可以插入值
  • 如果key不存在创建新的链表
  • 如果key存在,新增内容
  • 如果移除了所有值,空链表,也代表不存在
  • 在两边插入值或者改动效率最高,中间元素相对来讲效率会低一点

消息队列(Lpush Rpop)

栈(Lpush Lpop)

Set(集合)

Set是无序不重复集合

##############################
127.0.0.1:6379> sadd myset hello # set集合中添加一个元素
(integer) 1
127.0.0.1:6379> sadd myset yuanxin
(integer) 1
127.0.0.1:6379> sadd myset loveyuanxin
(integer) 1
127.0.0.1:6379> SMEMBERS myset # 查看指定set的所有值
1) "loveyuanxin"
2) "yuanxin"
3) "hello"
127.0.0.1:6379> SISMEMBER myset hello # 判断某一个值是否再set集合中
(integer) 1
127.0.0.1:6379> SISMEMBER myset test
(integer) 0
#################################
127.0.0.1:6379> SCARD myset # 获取集合中元素的个数
(integer) 3
127.0.0.1:6379> SREM myset hello #移除集合中的指定元素
(integer) 1
###################################
127.0.0.1:6379> SRANDMEMBER myset  #随机抽出指定集合的值
"yuanxin"
127.0.0.1:6379> SRANDMEMBER myset
"loveyuanxin"
################################## 
127.0.0.1:6379> SPOP myset       # 随机移除指定集合中的值
"yuanxin"
127.0.0.1:6379> SMEMBERS myset
1) "loveyuanxin"
##################################  
127.0.0.1:6379> SADD myset1 hello  #将一个指定的值移植到另外一个Set集合当中
(integer) 1
127.0.0.1:6379> SADD myset2 hello
(integer) 1
127.0.0.1:6379> SADD myset1 hello1
(integer) 1
127.0.0.1:6379> SMOVE myset1 myset2 hello1
(integer) 1
127.0.0.1:6379> SMEMBERS myset2
1) "hello1"
2) "hello"
127.0.0.1:6379> SMEMBERS myset1
1) "hello"
################################ 重点  可以使用这个api可以做一些共同关注,共同爱好,推荐好友
127.0.0.1:6379> SADD mydata1 a
(integer) 1
127.0.0.1:6379> SADD mydata1 b
(integer) 1
127.0.0.1:6379> SADD mydata1 c
(integer) 1
127.0.0.1:6379> SADD mydata2 c
(integer) 1
127.0.0.1:6379> SADD mydata2 d
(integer) 1
127.0.0.1:6379> SADD mydata2 e
(integer) 1
127.0.0.1:6379> SDIFF mydata1 mydata2  #查看mydata1 与mydata2不同的值
1) "b"
2) "a"
127.0.0.1:6379> SINTER mydata1 mydata2 #查看相同的值
1) "c" 
127.0.0.1:6379> SUNION mydata1 mydata2 #查看两个集合总共的值
1) "b"
2) "c"
3) "a"
4) "e"
5) "d"

Hash(哈希)

Map集合,key-map

#############################################
127.0.0.1:6379> hset myhash name yuanxin age 18  #基础操作
(integer) 2
127.0.0.1:6379> hget myhash name
"yuanxin"
127.0.0.1:6379> hmget myhash name age
1) "yuanxin"
2) "18"
127.0.0.1:6379> hgetall myhash 
1) "name"
2) "yuanxin"
3) "age"
4) "18"
#############################################
127.0.0.1:6379> HDEL myhash name #删除指定的map值
(integer) 1
127.0.0.1:6379> hgetall myhash 
1) "age"
2) "18"
#############################################
127.0.0.1:6379> hgetall myhash  #获取hash的长度
1) "age"
2) "18"
127.0.0.1:6379> HLEN myhash
(integer) 1
###########################################
127.0.0.1:6379> HEXISTS myhash name # 获取指定集合中是否存在指定的key
(integer) 0
127.0.0.1:6379> HEXISTS myhash age
(integer) 1
###########################################
127.0.0.1:6379> HKEYS myhash #获取所有的Key
1) "age"
127.0.0.1:6379> HVALS myhash #获取所有的value
1) "18"                                
###########################################
127.0.0.1:6379> HINCRBY myhash age 1 #hash自增数
(integer) 19
127.0.0.1:6379> HINCRBY myhash age -1 # hash自动减1
(integer) 18
127.0.0.1:6379> HSETNX myhash name yuanxin #判断是否存在 存在报错不存在添加
(integer) 1
127.0.0.1:6379> HSETNX myhash name yuanxin
(integer) 0

hash更适合存储用户的数据,String更适合字符串的存储

Zset(有序集合)

#######################################
127.0.0.1:6379> ZADD myset 1 one #基础操作
(integer) 1
127.0.0.1:6379> ZADD myset 2 two 3 yuanxin
(integer) 2
127.0.0.1:6379> ZRANGE myset 0 -1
1) "one"
2) "two"
3) "yuanxin"
##################################### 
127.0.0.1:6379> ZADD salary 1000 zhangsan
(integer) 1
127.0.0.1:6379> ZADD salary 500  yuanxin
(integer) 1
127.0.0.1:6379> ZADD salary 5000 lisi
(integer) 1
127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf # 查询最小的到最大的所有值
1) "yuanxin"
2) "zhangsan"
3) "lisi"
127.0.0.1:6379> ZREVRANGE salary 0 -1 # 查询最大到最小的所有值
1) "lisi"
2) "zhangsan"
3) "yuanxin"
127.0.0.1:6379> ZRANGEBYSCORE salary -inf 2000 withscores # 查询最小值到2000值的数据并显示数值
1) "yuanxin"
2) "500"
3) "zhangsan"
4) "1000"
##################################### 
127.0.0.1:6379> ZCARD salary #查询zset数量
(integer) 3
127.0.0.1:6379> ZREM salary yuanxin #元素移除
(integer) 1
127.0.0.1:6379> ZRANGE salary 0 -1
1) "zhangsan"
2) "lisi"
######################################
127.0.0.1:6379> zcount salary -inf +inf #区间统计 也可以是指定的例如 100 200
(integer) 2

ZSET主要做排序什么的或者可以通过1、2、3做消息的权重

三种特殊数据类型

geospatial地理位置

朋友的定位,附近的人,打车距离计算

Redis的GEO在3.2版本就推出了,这个功能可以推算地理位置的信息,两地之间的距离,方圆几里的人!

经纬度查询测试数据:https://jingweidu.bmcx.com/

#添加地理位置命令 geoadd key 经度 纬度 名称 
#注意:不能直接添加北极和南极的坐标
127.0.0.1:6379> GEOADD china:city 113.26925238281248 34.84496433471186 gongyi
(integer) 1
127.0.0.1:6379> GEOADD china:city 113.6401 34.72468 zhengzhou
(integer) 1
127.0.0.1:6379> GEOADD china:city 116.23128 40.22077 beijing
(integer) 1
127.0.0.1:6379> GEOADD china:city 91.13775 29.65262 lasa
(integer) 1
127.0.0.1:6379> GEOADD china:city 121.48941 31.40527 shanghai
(integer) 1
127.0.0.1:6379> GEOADD china:city 120.21201 30.2084 hangzhou
(integer) 1
#获取城市的经纬度
127.0.0.1:6379> GEOPOS china:city gongyi
1) 1) "113.26925486326217651"
   2) "34.84496512806270374"
127.0.0.1:6379> GEOPOS china:city gongyi
1) 1) "113.26925486326217651"
   2) "34.84496512806270374"
127.0.0.1:6379> GEOPOS china:city gongyi beijing
1) 1) "113.26925486326217651"
   2) "34.84496512806270374"
2) 1) "116.23128265142440796"
   2) "40.22076905438526495"
#比较两个城市之间的距离
127.0.0.1:6379> GEODIST china:city beijing gongyi km
"652.4058"
#获取附近的人业务实现 
#获取经度113 维度34 1000千米以内的数据
127.0.0.1:6379> GEORADIUS china:city 113 34 1000 km
1) "gongyi"
2) "zhengzhou"
3) "beijing"
4) "hangzhou"
5) "shanghai"
127.0.0.1:6379> GEORADIUS china:city 113 34 500 km
1) "gongyi"
2) "zhengzhou"
#获取经度113 维度34 1000千米以内的数据名称及经纬度
127.0.0.1:6379> GEORADIUS china:city 110 30 1000 km withdist withcoord
1) 1) "hangzhou"
   2) "982.5796"
2) 1) "gongyi"
   2) "620.0669"
3) 1) "zhengzhou"
   2) "626.8644"
#获取经度113 维度34 1000千米的数据名称及经纬度 前两条数据
127.0.0.1:6379> GEORADIUS china:city 110 30 1000 km withdist withcoord count 2
1) 1) "gongyi"
   2) "620.0669"
2) 1) "zhengzhou"
   2) "626.8644"
# 以key值为半径获取1000千米的数据名称及经纬度
127.0.0.1:6379> GEORADIUSBYMEMBER china:city gongyi 1000 km
1) "gongyi"
2) "zhengzhou"
3) "beijing"
4) "hangzhou"
5) "shanghai"
#查看全部的元素
127.0.0.1:6379> ZRANGE china:city 0 -1
1) "lasa"
2) "hangzhou"
3) "shanghai"
4) "gongyi"
5) "zhengzhou"
6) "beijing"
#移除指定元素
127.0.0.1:6379> ZREM china:city beijing
(integer) 1

Hyperloglog

Redis2.8.9版本更新了Hyperloglog数据结构

Redis Hyperloglog 基数统计的算法!

优点:占用的内存是固定的,2^64长度只需要12kb的内存!如果要从内存角度来比较的话Hyperloglog首选

弊端: 0.81%错误率

应用场景 :网页的UV(一个人访问一个网站多次,但还是算作一个人!)

传统方式用Set类型可以解决 但是如果用户数量大就会严重占用内存

#添加mykey集合
127.0.0.1:6379> PFADD mykey a b c d f v m d i o
(integer) 1
# 统计
127.0.0.1:6379> PFCOUNT mykey
(integer) 9
127.0.0.1:6379> PFADD mykey2 a b c d f v m d i o
(integer) 1
#两个集合合并
127.0.0.1:6379> PFCOUNT mykey mykey2
(integer) 13

如果允许容错,那么一定可以使用Hyperloglog

Bitmaps

位图,数据结构 都是操作二进制来进行记录,就只有0和1两个状态

应用场景:统计用户活跃信息 登录 未登录 打卡 两个状态的都可以使用BitMaps

#保存一个用户1234 0(表示未打卡) 1(表示打卡)
127.0.0.1:6379> SETBIT uni:user:20170101 1234 0
(integer) 0
127.0.0.1:6379> getbit uni:user:20170101 1234
(integer) 0
#统计这个时间段打卡的人数
127.0.0.1:6379> bitcount uni:user:20170101
(integer) 1

事务

Redis事务不保证原子性!

Redis事务的本质:一组命令的集合 在事务的过程中,会按照顺序执行!

Redis特性:一次性,顺序性,排他性

事务过程

  1. 开启事务(multi)

  2. 命令入队(........)

  3. 执行事务(exec)

  4. 或者回滚事务(discard)

    正常事务

#开启事务
127.0.0.1:6379> multi
OK
# 添加命令
127.0.0.1:6379(TX)> set  key1 v1
QUEUED
127.0.0.1:6379(TX)> set  key2 v2
QUEUED
127.0.0.1:6379(TX)> get key2
QUEUED
127.0.0.1:6379(TX)> set key3 v3
QUEUED
# 执行提交成功
127.0.0.1:6379(TX)> exec
1) OK
2) OK
3) "v2"
4) OK

手动回滚事务

#开启事务
127.0.0.1:6379> multi
OK
# 添加命令
127.0.0.1:6379(TX)> set  key1 v1
QUEUED
127.0.0.1:6379(TX)> set  key2 v2
QUEUED
127.0.0.1:6379(TX)> get key2
QUEUED
127.0.0.1:6379(TX)> set key3 v3
QUEUED
# 回滚
127.0.0.1:6379(TX)> discard

编译型异常

# 开启事务
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set key1 v1
QUEUED
127.0.0.1:6379(TX)> set key2 v2 
QUEUED
#命令报错
127.0.0.1:6379(TX)> getset key3
(error) ERR wrong number of arguments for 'getset' command
# 事务提交的时候发现提交不了 会发现所有的数据回滚
127.0.0.1:6379(TX)> exec
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get key1
"v1"
127.0.0.1:6379> get key2
"v2"

运行时异常

#开启事务
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set key1 txkey1
QUEUED
127.0.0.1:6379(TX)> set key2 txkey2
QUEUED
#设置字符串值运行时添加报错
127.0.0.1:6379(TX)> set key3 "hello"
QUEUED
127.0.0.1:6379(TX)> INCR key3
QUEUED
127.0.0.1:6379(TX)> exec
1) OK
2) OK
3) OK
4) (error) ERR value is not an integer or out of range
# 这里发现在事务中修改的值还是生效的
127.0.0.1:6379> get key1
"txkey1"

Redis 实现乐观锁 watch(命令)

# 创建一个key
127.0.0.1:6379> INCRBY money 1000
(integer) 1000
# 监视Key
127.0.0.1:6379> WATCH money
OK
# 开启事务
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> INCRBY money 1000
QUEUED
127.0.0.1:6379(TX)> exec #再开一个客户端修改watch的值之后提交事务发现提交失败
(error) EXECABORT Transaction discarded because of previous errors.



######################提交事务失败后监视回自动取消 然后再watch Key 进行事务操作
#然后再重新监视
127.0.0.1:6379> WATCH money
OK
#开启事务
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> INCRBY money 100
QUEUED
#提交事务
127.0.0.1:6379(TX)> exec
1) (integer) 1000

整合Jedis

  1. 引入Maven

    <dependency>
                <groupId>redis.clients</groupId>
                <artifactId>jedis</artifactId>
                <version>3.2.0</version>
    </dependency>
    
  2. 编写连在这里插入图片描述
    代码

    package com.fyx.jedis;
    
    import redis.clients.jedis.Jedis;
    
    /**
     * @author yuanxin
     * @Date 2021/6/16 14:15
     **/
    public class TestPing {
    
        public static void main(String[] args) {
            Jedis jedis = new Jedis("127.0.0.1", 6379);
            System.out.println(jedis.ping());
        }
    }
    

    常用的API(百度Jedis常用api)

SpringBoot整合

SpringBoot操作数据:Spring-data jpa jdbc MongoDB redis!

SpringData也是和SpringBoot其名的项目!

说明:再SpringBoot2.x之后,原来使用的Jedis呗替换了lettuce

Jedis:采用的直连,多个线程操作的话,是不安全的,如果想要避免不安全的.使用 jedis pool连接池!

lettuce:采用netty,实力可以再多个线程中进行共享,不存再线程不安全的情况!可以减少

具体操作百度

Redis.conf详解

启动的时候,就通过Redis配置文件来启动

网络

bind 127.0.0.1 -::1  # 绑定的ip
protected-mode yes   # 是否受保护
port                 # 端口设置

通用GENERAL

daemonize yes        # 以守护进程的方式运行,默认是no, 我们需要自己开启为yes!
pidfile /var/run/redis_6379.pid # 如果指定了守护方式运行需要指定pid文件

# 日志
# Specify the server verbosity level.
# This can be one of:
# debug (a lot of information, useful for development/testing)
# verbose (many rarely useful info, but not a mess like the debug level)
# notice (moderately verbose, what you want in production probably) 生产环境级别
# warning (only very important / critical messages are logged)
loglevel notice
logfile "" # 日志的文件位置名
databases 16 # 数据库的数量,默认是16 个数据库
always-show-logo no # 显示Logo

快照

持久化,再规定的时间内,执行了多少次操作,则会持久化到文件。.rdb .aof文件

Redis是内存书库,如果没有持久化,那么数据断电及失!

 #如果900秒内至少有一个key进行修改 就进行持久化操作
 save 3600 1
 #3000秒之内至少有100个key进行修改 就进行持久化操作
 save 300 100
 #如果60s内,如果至少10000个key进行修改 就进行持久化操作
 save 60 10000
 
 # 持久化如果失败是否还要继续工作
 stop-writes-on-bgsave-error yes
 # 是否压缩rdb文件 需要消耗cpu的资源
 rdbcompression yes
 # 保存rdb文件的时候进行错误校验
 rdbchecksum yes
 # rdb 文件保存的路径
 dir ./

REPLICATION 主从复制 百度

SECURITY 安全

# requirepass foobared
requirepass fyxzuishuai12

限制 CLIENTS

# 配置最大的客户端连接数
maxclients 10000
# 设置redis占用的最大内存
maxmemory <bytes>
# 内存达到上限的时候触发的策略
maxmemory-policy noeviction
1、volatile-lru:只对设置了过期时间的key进行LRU(默认值) 

2、allkeys-lru : 删除lru算法的key   

3、volatile-random:随机删除即将过期key   

4、allkeys-random:随机删除   

5、volatile-ttl : 删除即将过期的   

6、noeviction : 永不过期,返回错误

APPEND ONLY MODE (aof) 持久化方案

#默认开启的是rdb持久化方式
appendonly no
#aof 文件名
appendfilename "appendonly.aof"
# always (每次修改都会同步 消耗性能) 
# everysec (每秒执行一次sync 可能回丢失1s的数据) 
# no 不执行sync 这个时候操作系统自己同步数据 速度最快
appendfsync everysec

Redis持久化

RDB(Redis DataBase)

什么是RDB

fast.jpg

设置rdb

  1. 修改redis.conf文件 更改快照保存策略
#10秒内至少有一个key修改就会触发snapshot保存操作
save 10 1

触发机制

1、符合save 机制触发

2、执行flushall命令,也会触发我们的rdb规则

3、退出redis ,也会产生rdb文件!

如何恢复rdb文件

1、只需要将rdb文件放在我们redis启动目录就可以,redis启动的时候会自动检查dump.rdb 恢复其中的数据

2、查看配置需要存在的位置

127.0.0.1:6379> config get dir
1) "dir"
2) "/usr/local/bin"

优点:

1、适合大规模的数据恢复

2、对数据的完整经要求不高

缺点:

1、需要一定的时间间隔

2、fork进程的时候,会占用一定的内存空间

AOF(Append Only File)

以日志的形式来记录每个写的操作,只需追加文件不许改写文件,redis启动就会读取改文件重新构建数据 ,大数据量情况下性能缓慢

设置AOF

############################## APPEND ONLY MODE ###############################

# By default Redis asynchronously dumps the dataset on disk. This mode is
# good enough in many applications, but an issue with the Redis process or
# a power outage may result into a few minutes of writes lost (depending on
# the configured save points).
#
# The Append Only File is an alternative persistence mode that provides
# much better durability. For instance using the default data fsync policy
# (see later in the config file) Redis can lose just one second of writes in a
# dramatic event like a server power outage, or a single write if something
# wrong with the Redis process itself happens, but the operating system is
# still running correctly.
#
# AOF and RDB persistence can be enabled at the same time without problems.
# If the AOF is enabled on startup Redis will load the AOF, that is the file
# with the better durability guarantees.
#
# Please check https://redis.io/topics/persistence for more information.
# 默认是不开启的
appendonly yes
# aof文件名
appendfilename "appendonly.aof"
#重启过后就会发现多了一个aof文件
[root@pinyoyougou-docker bin]# ls
appendonly.aof  dump.rdb  redis-benchmark  redis-check-aof  redis-check-rdb  redis-cli  redis.conf  redis-sentinel  redis-server

数据测试

[root@pinyoyougou-docker bin]# redis-cli
127.0.0.1:6379> auth fyxzuishuai12
OK
127.0.0.1:6379> flsuhall 
(error) ERR unknown command `flsuhall`, with args beginning with: 
127.0.0.1:6379> flushall
OK
127.0.0.1:6379> set name fanyuanxin
OK
127.0.0.1:6379> set age 10
OK
127.0.0.1:6379> set dick 19cm
# 接下来shutdown关闭redis服务 然后重启 发现数据还是存在的
127.0.0.1:6379> auth fyxzuishuai12
OK
127.0.0.1:6379> get name
"fanyuanxin"

AOF 文件损坏修复

如果这个AOF文件有错误,这时候redis是启动不了的 redis提供了redis-check-aof --fix 修复aof

#破坏aof文件
[root@pinyoyougou-docker bin]# vim appendonly.aof 
[root@pinyoyougou-docker bin]# redis-server redis.conf 
#发现redis 服务没启动启来
[root@pinyoyougou-docker bin]# netstat -tunlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      1068/sshd           
tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN      2071/master         
tcp6       0      0 :::22                   :::*                    LISTEN      1068/sshd           
tcp6       0      0 ::1:25                  :::*                    LISTEN      2071/master         
udp        0      0 0.0.0.0:8201            0.0.0.0:*                           764/dhclient        
udp        0      0 0.0.0.0:68              0.0.0.0:*                           764/dhclient        
udp6       0      0 :::42497                :::*                                764/dhclient     
# 使用官方的aof文件修复
[root@pinyoyougou-docker bin]# redis-check-aof --fix appendonly.aof 
0x              90: Expected prefix '*', got: 's'
AOF analyzed: size=168, ok_up_to=144, ok_up_to_line=30, diff=24
This will shrink the AOF from 168 bytes, with 24 bytes, to 144 bytes
Continue? [y/N]: y
Successfully truncated AOF
[root@pinyoyougou-docker bin]# redis-server redis.conf 
# 发现服务启动
[root@pinyoyougou-docker bin]# netstat -tunlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 127.0.0.1:6379          0.0.0.0:*               LISTEN      2410/redis-server 1 
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      1068/sshd           
tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN      2071/master         
tcp6       0      0 ::1:6379                :::*                    LISTEN      2410/redis-server 1 
tcp6       0      0 :::22                   :::*                    LISTEN      1068/sshd           
tcp6       0      0 ::1:25                  :::*                    LISTEN      2071/master         
udp        0      0 0.0.0.0:8201            0.0.0.0:*                           764/dhclient        
udp        0      0 0.0.0.0:68              0.0.0.0:*                           764/dhclient        
udp6       0      0 :::42497                :::*                                764/dhclient   

优缺点

优点:

1、每次修改都同步,文件的完整会更好

2、每秒同步一次,可能会丢失一秒的数据

3、从不同步,效率最高

缺点:

1、aof文件大,修复速度远慢与rdb

2、aof效率也要比rdb慢,所以我们默认的配置就是rdb持久化

Redis发布订阅

在这里插入图片描述

Redis发布订阅(pub/sub是一种消息通信模式):发送者(pub)发送消息,订阅者(sub)接受消息。微信,微博,关注系统

测试

# 发送端 PUBLISH <频道名>
127.0.0.1:6379> PUBLISH yuanxin nihao
(integer) 1

# 订阅端  SUBSCRIBE <频道名>
127.0.0.1:6379> SUBSCRIBE yuanxin 
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "yuanxin"
3) (integer) 1
1) "message"
2) "yuanxin"
3) "nihao"

Redis主从复制

主从复制,读写分离。主负责写,从负责读,主从架构最少有三台机器

主节点可以有多个从节点,从节点只能有一个主节点

uTools_1624521195656.png

只用配置从库,不用配置主库,redis默认的配置就是主库的配置

# 查看当前库的信息
127.0.0.1:6379> info replication
# Replication 
# 主机
role:master
# 从机0
connected_slaves:0
master_failover_state:no-failover
master_replid:d3e24756ffaa35a2a0b0ecc17a16acb309940052
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

单机模拟主从复制

1、复制三份redis.conf配置文件然后修改端口

port 端口
logfile "端口.log"
dbfilename "dump端口.rdb"

2、启动三次服务

uTools_1624594910286.png

3、设置80、81 为从机

#连接80 81 端口 redis服务器 执行下面命令
127.0.0.1:6380> SLAVEOF 127.0.0.1 6379
127.0.0.1:6380> INFO replication
# Replication
role:slave

这样的配置是暂时性的,想要永久修改配置就可以

# 配置主机ip 端口
# slaveof 127.0.0.1 6379
# 主机 密码
# masterauth fyxzuishuai12

重点

主机只能写,从机只能读

复制原理

Slave 启动成功连接到Master 后会发送一个异步同步命令

Master 接到命令启动后台的存盘进程,同时收集所有接收到的修改数据命令,将整个文件同步到Slave节点

全量复制:一次接受完所有命令,完成同步 (建立主从关系的时候执行)

增量复制:依次传递命令,完成同步(同步后主机发生改变时执行)

哨兵模式

哨兵是独立于Redis的单独进程,通过发送命令到Redis来监控服务是否存活

哨兵的两个作用

  • 通过发送命令,让Redis服务器返回其运行状态,包括主服务器和从服务器
  • 当哨兵检测到Master宕机,会自动开启选举机制切换从机为Master主机,然后通过发布订阅模式通知其他的从服务器,修改配置文件,让他们切换主机

当然哨兵除了监控Redis服务之外, 哨兵与哨兵之间也会相互监控

选举过程

假设主服务器宕机,哨兵1,2,3 都会检测,一个哨兵检测到Redis服务不可用会被成为主观下线 当所有的哨兵都检测服务不可用的时候会被认为是客观下线从而就会开始重新选举新的主机,获票多的从机当选新的主机

哨兵配置

vim sentinel.conf
#sentinel monitor 固定写法 
#myredis 自定义名命 
#127.0.0.1 监控那个ip 端口 
#1  表示有一个哨兵认为master失效时,master才算真失效 以此类推
sentinel monitor myredis 127.0.0.1 6379 1
#设置连接密码
sentinel auth-pass mymaster 123456
#启动哨兵
[root@pinyoyougou-docker bin]# redis-sentinel  sentinel.conf 

然后关闭主节点6379的Redis,

# 发现6380变成了主节点
127.0.0.1:6380> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=6381,state=online,offset=13904,lag=1
master_failover_state:no-failover
master_replid:d42bfd2df837d066be4b1daef9cd56215041cdc4
master_replid2:8c20e47ec07f30c543400148717e4236fd741c3b
master_repl_offset:13904
second_repl_offset:12804
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:13904

缓存穿透,缓存击穿和缓存雪崩

缓存穿透

用户请求数据库没有的数据,就请就会一直请求到数据库,而造压力

解决方案: 用户鉴权,id做基础校验,id<=0的拦截

缓存击穿

没有缓存的数据一瞬间同时请求导致的数据库压力过大

解决方案: 设置热点数据不过期、接口限流,熔断降级。布隆过滤器,加锁

缓存雪崩

同时间大批量缓存同时过期,导致访问数据库压力大导致down机

解决方案:随机生成过期时间,设置热点数据永不过期

posted @ 2022-04-12 17:37  xiye1  阅读(34)  评论(0编辑  收藏  举报