基础知识redis详解--【Foam番茄】

Redis

学习方式:html

  • 上手就用
  • 基本的理论先学习,而后将知识融汇贯通

nosql讲解

为何要用Nosqljava

如今都是大数据时代node

大数据通常的数据库没法进行分析处理了mysql

至少要会Springboot+SpringCloudlinux

压力必定会愈来愈大,适者生存android

1.单机MySQL的年代程序员

90年代,一个基本的网站访问量通常不会太大,单个数据库彻底足够,那个时候,更多的去使用静态网页,HTML,服务器根本没有太大的压力

思考一下,这种状况下:整个网站的瓶颈是什么?web

1.数据量若是太大,一个机器放不下了面试

2.数据的索引 300万就必定要创建索引(B+Tree),一个机器内存也放不下redis

3.访问量(读写混合),一个服务器承受不了

只要你出现以上的三种状况之一,那么你就必需要晋级

2.Memcached(缓存)+MYSQL+垂直拆分

网站80%的状况都是在读,每次都要去查詢数据库的话就十分的麻烦!因此说咱们但愿减轻数据的压力,咱们可使用缓存来保证效率!

发展过程:优化数据结构和索引->文件缓存(IO)->Memcachaed(当时最热门的技术!)

3.分库分表+水平分表+MYSQL集群

技术和业务在发展的同时,对人的要求也愈来愈高!

==本质:数据库(读,写)==

早些年MYISAM:表锁,十分影响效率!高并发下就会出现严重的锁问题

转战INNODB:行锁

慢慢的就开始使用分库分表来解决写的压力!Mysql在那个年代推出了表分区!这个并无多少公司使用!

Mysql的集群,很好的解决了那个年代的全部需求

4.现在最近的年代

技术爆炸

2010(按键手机 android1.0HTC)--2020

十年之间,世界已经发生了翻天覆地的变化(定位,也是一种数据,音乐,热榜!)

MySQL等关系型数据库就不够用了,数据量不少,变化很快!

图形数据库 JSON数据库

MYSQL有的时候使用它来存储一些比较大的文件,博客,图片!数据库表很大,效率就低了!若是有一种数据库来专门处理这种数据,mysql的压力就会变得十分小(研究如何处理这些问题!)大数据的io压力下,表几乎无法更大

目前一个基本的互联网项目

为何要用NoSQL

用户的我的信息,社交网络,==地理位置==。用户本身产生的数据,用户日志等等爆发式增加!

这时候咱们就须要使用NoSQL数据库的,NoSQL能够很好的处理以上的状况!

NoSQL=Not Only SQL(不只仅是SQL)

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

不少的数据类型用户的我的信息,社交网络,地理位置。这些数据类型的存储不须要一个固定的格式(行和列),不须要有多余的操做就能够横向扩展了!Map<String,Object>使用键值对来控制
在这里插入图片描述

C:\Users\12168\AppData\Roaming\Typora\typora-user-images\image-20200811155808548.png

NoSql特色

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

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

3.数据类型是多样型的!(不须要事先设计数据库!随取随用!若是是数据量十分大的表,不少人就没法设计了!)

4.传统RDBMS和NOSQL

传统的RDBMS

  • 结构化组织
  • SQL
  • 数据和关系都存在单独的表中
  • 操做操做,数据定义语言
  • 严格的一致性
  • 基础的事务
  • ……

NOSQL

  • 不只仅是数据
  • 没有固定的查询语言
  • 键值对存储,列存储,文档存储,图形数据库(社交关系)
  • 最终一致性
  • CAP定理 和 BASE理论(异地多活!)初级架构师
  • 高性能,高可用,高可扩
  • ……

了解:3V+3高

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

1.海量Volume

2.多样Variety

3.实时Velocity

大数据时代的3高:主要是对程序的要求

1.高并发

2.高可拓(随时水平拆分,机器不够了,能够扩展机器)

3.高性能(保证用户体验和性能!)

真正在公司中的实践:NOsql+RDBMS一块儿使用才是最强的,阿里巴巴的架构演进!

技术没有高低之分,看你如何使用!(提高内功,思惟的提升!)

技术急不得,越是慢慢学,才能越扎实

敏捷开发,极限编程

任何一家互联网的公司,都不可能只是简简单单让用户能用就行了

大量公司作的都是相同的业务(竞品协议)

随着这样的竞争,业务是愈来愈完善,而后对于开发者的要求也是愈来愈高!

C:\Users\12168\AppData\Roaming\Typora\typora-user-images\image-20200811153751574.png

若是你将来想当一个架构师:没有什么是加一层解决不了的

1.商品的基本信息

名称,价格,商家信息

关系型数据库就能够解决了(王坚:阿里云的这群疯子)

淘宝内部的mysql 不是你们用的mysql

2.商品的描述,评论(文字比较多)

文档型数据库中,mongodb

3.图片

分布式文件系统 FastDFS

  • 淘宝本身的TFS
  • Google的 GFS
  • Hadoop HDFS
  • 阿里云的 oss

4.商品的关键字(搜索)

  • 搜索引擎 solr elasticsearch
  • Isearch: 多隆

全部牛逼的人都有一段苦逼的岁月,可是你只要像sb同样的去坚持,终将牛逼!

5.商品热门的波段信息

  • 内存数据库
  • redis tair memache

6.商品的交易,外部的支付接口

  • 三方应用

要知道,一个简单的网页背后的技术不必定是你们所想的那么简单!

大型互联网应用问题

  • 数据类型太多了
  • 数据源太多了
  • 常常重构
  • 数据要改造,大面积改造麻烦

解决问题:

![\[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-544IbeI2-1605684515441)(C:\Users\12168\AppData\Roaming\Typora\typora-user-images\image-20200811155340164.png)\]](https://img-blog.csdnimg.cn/2...
在这里插入图片描述
在这里插入图片描述

关系型数据库:表格,行,列(POI)

NoSql的四大分类

kv键值对:

  • 新浪:redis
  • 美团:redis+tair
  • 阿里,百度:Redis+memcache

文档型数据库(bson格式和json同样)

  • mongodb(通常必需要掌握)

    • mongodb是一个基于分布式文件存储的数据库,C++编写,主要用来处理大量的文档
    • mongodb是一个介于关系型数据库和非关系型数据库之间的产品,Mongodb是非关系型数据库中功能最丰富,最像关系型数据库的
  • conthDB

列存储数据库

  • HBase
  • 分布式文件系统

图关系型数据库

  • 它不是存图形,放的是关系,好比:朋友圈社交网络,广告推荐
  • Neo4j,InfoGrid

在这里插入图片描述

Redis入门

redis是什么

Redis(Remote Dictionary Server ),即远程字典服务

是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。

区别的是redis会周期性的把更新的数据写入磁盘或者把修改操做写入追加的记录文件,而且在此基础上实现了master-slave(主从)同步

免费和开源,是当下最热门的nosql技术之一,也被人们称之为结构化数据库

Redis能干吗

在这里插入图片描述

1.内存存储,持久化,内存中是断电即失,因此说持久化很重要(rdb,aof)

2.效率高,能够用于高速缓存

3.发布订阅系统

4.地图信息分析

5.计时器,计数器(浏览量)

6.……

特性

1.多样的数据类型

2.持久化

3.集群

4.事务

……

注意

==Window在Github上下载(停更好久了)==

Redis推荐都是在Linux服务器上搭建的,咱们是基于Linux学习

在这里插入图片描述

默认端口是6379

在这里插入图片描述

window下使用确实简单,可是redis推荐咱们使用linux去开发使用

测试性能

“redis-benchmark” 是一个压力测试工具!

官方自带的性能测试工具

redis-benchmark

测试:100个并发链接 100000请求

redis-benchmark -h localhost -p 6379 -c 100 -n 100000

在这里插入图片描述

在这里插入图片描述

基础的知识

redis默认有16个数据库

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

可使用select进行切换数据库

select 3 //切换到第三个数据库

dbsize //查看当前的大小

set k v //插入数据

get k //查询数据

keys * //查询全部的k

flushdb //清空当前库

flushall //清空所有的数据库

exists name //判断name是否存在

move name 1 //移除在第一个数据库中的name

expire name 10 //该参数10秒后过时

ttl name //查询剩余的过时时间 -2表示没了

type name //查询当前的key的类型

append key1 “hello” //在key后面追加字符串,若是当前key不存在,就至关于setkey

strlen key1 //获取字符串长度

incr views //数据加1

decr views //数据减1

incrby views 10 //数据加10

decrby views 10 //数据减10

getrange key 0 3 //取0-3中间的字符串

getrange key 0 -1 //取所有符串和get key是同样的

setrange key 1 xx //替换指定位置的字符串

setex (set with expire) //设置过时时间

setnx (set if not expire) //不存在设置 (在分布式锁中会经常使用)若是存在就建立成功,若是不存在就建立失败

mset //批量插入

mget //批量获取

msetnx //批量不存在设置(原子性:一个错误所有错误)

对象

set user:1 {name:zhangsan,age:3} //设置一个user:1 对象 值为json字符串来保存一个对象

mset user:1:name zhangsan user:2:name lisi

这里的key是一个巧妙的设计: user:{id}:{filed} ,如此设计在redis中是彻底ok了

getset //先get而后再set 若是不存在值,则返回nil 若是存在值,获取原来的值,并设置新的值

数据结构是相同的,jedis

string类型的使用场景:value除了是咱们的字符串还能够是咱们的数字

  • 计数器
  • 统计多单位数量
  • 粉丝数
  • 对象缓存存储
思考:为何redis是6379

粉丝效应

Redis是单线程的

明白Redis是很快的,官方表示,Redis是基于内存操做,CPU不是redis性能瓶颈,redis的瓶颈是根据机器的内存和网络带宽,既然可使用单线程来实现,就使用单线程了

Reids是c语言写的,官方提供的数据为10W+的QPS,彻底不比一样是使用k-v的Memcache差

Redis为何单线程还这么快?

1.误区1:高性能的服务器必定是多线程的

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

cpu>内存>硬盘的速度要有所了解!

核心:redis是全部的数据所有放在内存中的,因此说使用单线程去操做效率就是最高的,多线程(cpu上下文会切换:耗时的操做),对于内存系统来讲,若是没有上下文切换效率就是最高的,屡次读写都是在一个cpu上的,在内存状况下,这个就是最佳的方案!

redis

Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它能够用做==数据库==、==缓存==和==消息中间件==。 它支持多种类型的数据结构,如 字符串(strings)散列(hashes)列表(lists)集合(sets)有序集合(sorted sets) 与范围查询, bitmapshyperloglogs地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication)LUA脚本(Lua scripting)LRU驱动事件(LRU eviction)事务(transactions) 和不一样级别的 磁盘持久化(persistence), 并经过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)

Redis-key

大基本数据类型

  • String(字符串)

    90%的java程序员使用redis只会使用一个String类型

  • List

    基本的数据类型,列表

    在redis里面,咱们能够把list玩成,栈,队列,阻塞队列

    全部的list命令都是l开头的

    #############################################
    > lpush list one #将一个值或者多个值,插入到列表头部(左)
    1
    > lpush list two
    2
    > lpush list three
    3
    > lrange list 0 -1
    three
    two
    one
    > lrange list 0 1
    three
    two
    > rpush list right #将一个值或者多个值,插入到列表头部(右)
    4
    > lrange list 0 -1
    three
    two
    one
    right
    #############################################
    lpop
    rpop
    > lrange list 0 -1 
    three
    two
    one
    right
    > lpop list #移除列表的第一个元素
    three
    > rpop list #移除列表的最后一个元素
    right
    > lrange list 0 -1
    two
    one
    
    #############################################
    lindex 
    > lindex list 1 #经过下标得到list中的某一个值
    one
    > lindex list 0
    two
    
    #############################################
    llen
    > lpush list one
    1
    > lpush list two
    2
    > lpush list three
    3
    > 
    (error) ERR unknown command
    > llen list #返回列表长度
    3
    #############################################
    移除指定的值!
    > lrange list 0 -1
    three
    three
    two
    > lrem list 1 three #移除list集合中指定个数的value,精确匹配
    1
    > lrange list 0 -1
    three
    two
    > lpush list three
    3
    > lrem list 2 three
    2
    > lrange list 0 -1
    two
    #############################################
    trim 修剪
    > rpush mylist "hello"
    1
    > rpush mylist "hello1"
    2
    > rpush mylist "hello2"
    3
    > rpush mylist "hello3"
    4
    > ltrim mylist 1 2 #经过下标截取指定的长度,这个list已经被改变了,只剩下截取的元素
    OK
    > lrange mylist 0 -1
    hello1
    hello2
    #############################################
    rpoplpush  #移除列表最后一个元素而且移动到新的列表中
    > rpush mylist "hello"
    1
    > rpush mylist "hello1"
    2
    > rpush mylist "hello2"
    3
    > rpoplpush mylist myotherlist  #移除列表最后一个元素而且移动到新的列表中
    hello2
    > lrange mylist 0 -1 #查看原来的列表
    hello
    hello1
    > lrange myotherlist 0 -1 #查看目标列表中,确实存在该值
    hello2
    #############################################
    lset 将列表中指定下标的值替换为另一个值,更新操做
    > exists list #判断这个列表是否存在
    0
    > lset list 0 item #若是不存在列表咱们去更新就会报错
    ERR no such key
    > lpush list value1
    1
    > lrange list 0 0
    value1
    > lset list 0 item #若是存在,更新当前下标的值
    OK
    > lrange list 0 0
    item
    > lset list 1 other #若是不存在,则会报错
    ERR index out of range
    #############################################
    linsert #将某个具体的value插入到列表中某个元素的前面或者后面
    > rpush mylist hello
    3
    > rpush mylist hello1
    4
    > linsert mylist before hello1 other
    5
    > lrange mylist 0 -1
    hello
    other
    hello1
    hello
    hello1
    > linsert mylist after other enw
    6
    > lrange mylist 0 -1
    hello
    other
    enw
    hello1
    hello
    hello1
    小结
    • 它其实是一个链表,before node after ,left ,right 均可以插入值
    • 若是key不存在,建立新的链表
    • 若是key存在,新增内容
    • 若是移除了全部的值,空链表,也表明不存在
    • 在两边插入或者改动值效率最高!中间元素,相对来讲效率会低一点

      消息队列(Lpush Rpop) 栈 (Lpush Lpop)

  • Set(集合)

    set中的值是不能重复的

    #############################################
    > sadd myset hello #set集合中添加元素
    1
    > sadd myset kuangshen
    1
    > sadd myset lovekuangshen
    1
    > smembers
    ERR wrong number of arguments for 'smembers' command
    > smembers myset #查看指定set的全部值
    lovekuangshen
    kuangshen
    hello
    > sismember myset hello #判断某一个值是否是在set集合中
    1
    > sismember myset world
    0
    #############################################
    > scard myset #获取set集合中的内容元素个数
    3
    > sadd myset lovekuangshen #已经存在的添加失败
    0
    #############################################
    > srem myset hello #移除set集合中的指定元素
    1
    > scard myset
    2
    > smembers myset
    lovekuangshen
    kuangshen
    #############################################
    set是无序不重复集合,抽随机
    > srandmember myset #随机抽选出一个元素
    kuangshen
    > srandmember myset
    lovekuangshen
    > srandmember myset 2 #随机抽取指定个数的元素
    kuangshen
    lovekuangshen
    
    #############################################
    删除指定的key,随机删除key
    > smembers myset
    lovekuangshen
    kuangshen
    > spop myset #随机删除一些set集合中的元素
    lovekuangshen
    > spop myset
    kuangshen
    #############################################
    将一个指定的值,移动到另一个set集合中
    > sadd myset hello
    1
    > sadd myset hello
    0
    > sadd myset world
    1
    > sadd myset kuangshen
    1
    > sadd myset2 set2
    1
    > smove myset myset2 kuangshen #将一个指定的值,移动到另一个set集合
    1
    > smembers myset
    world
    hello
    > smembers myset2
    set2
    kuangshen
    
    #############################################
    > sadd key1 a
    1
    > sadd key1 b
    1
    > sadd key1 c
    1
    > sadd key2 c
    1
    > sadd key2 d
    1
    > sadd key2 e
    1
    > sadd key2 e
    0
    > sadd key2 key
    1
    > sdiff key1 key2 #差集
    a
    b
    > sinter key1 key2 #交集(共同好友就能够这样实现)
    c
    > sunion key1 key2 #并集
    c
    e
    key
    d
    b
    a

    微博,a用户将全部关注的人放在一个set集合中,将它的粉丝也放在一个集合中

    共同关注,共同爱好,二度好友,推荐好友!(六度分割理论)

  • Hash(哈希)

    Map集合,key-Map集合,本质和String类型没有太大区别,仍是一个简单的kv

    set myhash field kuangshen

    > hset myhash field1 kuangshen #set一个具体key-value
    1
    > hget myhash field1 #获取一个字段值
    kuangshen
    > hmset myhash field1 hello field2 world #set多个key-value
    OK
    > hmget myhash field1 field2 #获取多个字段值
    hello
    world
    > hgetall myhash #获取所有的数据
    field1
    hello
    field2
    world
    
    #############################################
    > hdel myhash field1 #删除hash指定key字段,对应的value值也就消失了
    1
    > hgetall myhash
    field2
    world
    #############################################
    hlen
    > hmset myhash field1 hello field2 world
    OK
    > hgetall myhash
    field2
    world
    field1
    hello
    > hlen myhash #获取hash表的字段数量
    2
    
    #############################################
    > hexists myhash field #判断hash中指定字段是否存在
    0
    > hexists myhash field1
    1
    
    #############################################
    #只得到全部field
    #只得到全部value
    > hkeys myhash#只得到全部field
    field2
    field1
    > hvals myhash#只得到全部value
    world
    hello
    #############################################
    incr decr
    > hset myhash field3 5 #指定增量
    1
    > hincrby myhash field3 1
    6
    > hincrby myhash field3 -1
    5
    > hsetnx myhash field4 hello #若是不存在则能够设置
    1
    > hsetnx myhash field4 world #若是存在则不能设置
    0
    
    #############################################
    > hset user:1 name qinjiang
    1
    > hget user:1 name
    qinjiang

    hash变动的数据user name age 尤为是用户信息之类的,常常变更的信息!hash更适合于对象的存储,String更加适合字符串存储

  • Zset(有序集合)

    在set的基础上,增长了一个值,set k1 v1 zset k1 score1 v1

    > zadd myset 1 one #添加一个值
    1
    > zadd myset 2 two 3 three #添加多个值
    1
    > zrange myset 0 -1
    one
    two
    three
    
    #############################################
    排序如何实现
    > zadd salary 2500 xiaohogn #添加三个用户
    1
    > zadd salary 5000 zhangsan
    1
    > zadd salary 500 kuangshen
    1
    > zrangebyscore salary -inf +inf #显示所有的用户,从小到大排序
    kuangshen
    xiaohogn
    zhangsan
    > zrange salary 0 -1
    kuangshen
    xiaohogn
    zhangsan
    > zrangebyscore salary  0 -1 #显示所有的用户并附带成绩
    kuangshen
    500
    xiaohogn
    2500
    zhangsan
    5000
    > zrangebyscore salary -inf 2500 withscores #显示工资小于2500员工的降序排列
    kuangshen
    500
    xiaohogn
    2500
    > zrevrange salary 0 -1 #从大到小排序
    zhangsan
    kuangshen
    
    #############################################
    移除rem中的元素
    > zrange salary 0 -1
    kuangshen
    xiaohogn
    zhangsan
    > zrem salary xiaohogn #移除有序集合中的指定元素
    1
    > zrange salary 0 -1
    kuangshen
    zhangsan
    > zcard salary # 获取有序集合中的个数
    2
    #############################################
    > zadd myset 1 hello
    1
    > zadd myset 2 world 3 kuangshen
    2
    > zcount myset 1 3 #获取指定区间的成员数量
    3
    > zcount myset 1 2
    2

    案例思路:set排序 存储班级成绩表,工资排序

    普通消息1 重要消息2 带权重进行判断

    排行榜应用实现

三种特殊数据类型

  • geospatial 地理位置

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

    redis的geo在redis3.2版本就推出了!这个功能能够推算地理位置的信息,两地之间的距离,方圆几里的人

    在这里插入图片描述

getadd http://www.jsons.cn/lngcode/
#geoadd 地理位置
#规则:两极没法直接添加,咱们通常会直接下载城市数据,直接经过java程序一次性导入
#参数key 值(纬度经度名称)
> geoadd china:city 116.40 39.90 beijing
1
> geoadd china:city 121.47 31.23 shanghai
1
> geoadd china:city 106.50 29.53 chongqin
1
> geoadd china:city 114.08 22.54 shenzhen
1
> geoadd china:city 120.16 30.24 hangzhou
1
> geoadd china:city 108.96 34.26 xian
1
#有效的经度-180度到180度
#有效的纬度-85.05112878度到85.05112878度
#当坐标位置超出上述指定范围时,该命令将会返回一个错误
geopos
> geopos china:city beijing #获取指定的城市的经度和纬度
116.39999896287918
39.900000091670925

> geopos china:city beijing shanghai
116.39999896287918
39.900000091670925
121.47000163793564
31.229999039757836
geodist

两人之间的距离

单位以下

m表示单位为米

km表示单位为公里

mi表示单位为英里

ft表示单位为英尺

> geodist china:city beijing shanghai #查看上海到北京的直线距离
1067378.7564
> geodist china:city beijing shanghai km
1067.3788
> geodist china:city beijing chongqin km
1464.0708
georedius 以给定的经纬度为中心

我附近的人?(得到全部附近的人的地址,定位)经过半径来查询

得到指定数量的人,200

全部的数据都应该录入:china:city才会让结果更清晰

> georadius china:city 110 30 1000 km #以110 30这个经纬度为中心,寻找方圆1000km内的城市
chongqin
xian
shenzhen
hangzhou
> georadius china:city 110 30 500 km
chongqin
xian
> georadius china:city 110 30 500 km withdist #显示到中间距离的位置
chongqin
341.9374
xian
483.8340
> georadius china:city 110 30 500 km withcoord #显示他人的定位信息
chongqin
106.49999767541885
29.529999579006592
xian
108.96000176668167
34.2599996441893
> georadius china:city 110 30 500 km withdist withcoord count 1 #筛选出指定的用户
chongqin
341.9374
106.49999767541885
29.529999579006592
> georadius china:city 110 30 500 km withdist withcoord count 2
chongqin
341.9374
106.49999767541885
29.529999579006592
xian
483.8340
108.96000176668167
34.2599996441893
georadiusbymember
#找出位于指定元素周围的其余元素
> georadiusbymember china:city beijing 1000 km
beijing
xian
> georadiusbymember china:city shanghai 400 km
hangzhou
shanghai
gethash 命令-返回一个或多个位置元素的geohash表示

该命令将返回11个字符的geohash字符串

#将二维的经纬度转换为一维的字符串,若是两个字符串越接近,那么则距离越近
> geohash china:city beijing chongqin
wx4fbxxfke0
wm5xzrybty0
geo 底层的实现原理其实就是Zset!咱们可使用Zset命令来操做geo
> zrange china:city 0 -1 #查看地图中所有的元素
chongqin
xian
shenzhen
hangzhou
shanghai
beijing
> zrem china:city beijing #移除指定元素
1
  • hyperloglog

    什么是基数

    A{1.3.5.7.8.9.7}

    B{1,3,5,7,8}

    基数(不重复的元素) =5 ,能够接受偏差!

    简介

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

    reids hyperloglog 基数统计的算法

    网页的uv(一我的访问一个网站屡次,可是仍是算做一我的)

    传统的方式,set保存用户的id,而后就能够统计set中的元素数量做为标准判断

    这个方式若是保存大量的用户id,就会比较麻烦!咱们的目的是为了计数,而不是保存用户id

    优势:占用的内存是固定的,2^64不一样的元素的技术,只须要废12kb内存,若是要从内存角度来比较的话,hyperloglog是首选

    0.81%错误率,统计uv任务,能够忽略不计的

    > pfadd mykey a b c d e f g h i j #建立第一组元素
    1
    > pfcount mykey #统计mykey元素的基数数量
    10
    > pfadd mykey2 i j z x c v b n m #建立第二组元素 
    1
    > pfcount mykey2
    9
    > pfmerge mykey3 mykey mykey2 #合并两组 mykey mykey2 => mykey3 (并集)
    OK
    > pfcount mykey3 #查看并集的数量
    15

    若是容许容错,那么必定可使用hyperloglog

    若是不容许容错,就使用set或者本身的数据类型便可

  • bitmap

    位存储

    统计疫情感染人数:010101

    统计用户信息,活跃,不活跃!登陆,未登陆!打卡,365打卡!两个状态的,均可以使用bitmaps

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

    365天=365bit 1字节 = 8bit 46个字节左右

    测试

    使用bitmap来记录 周一到周日的打卡

    setbit sign 0 1
    0
    setbit sign 1 0
    0
    setbit sign 3 0
    0
    setbit sign 4 0
    0
    setbit sign 5 1
    0
    setbit sign 6 1
    0

    查看某一天是否有打卡

    #############################################
    > getbit sign 4
    0
    > getbit sign 6
    1

    统计打卡天数

    > bitcount sign #统计这周的打卡记录,就能够看到是否有全勤
    3

Redis配置详解

Redis持久化

  • RDB
  • AOF

Redis事务操做 ACID

redis单条命令是保证原子性的,可是事务不保证原子性的,要么同时成功,要么同时失败,原子性!

redis事务的本质:一组命令的集合!一个事务中的全部命令都会被序列化,在事务执行的过程当中,会按照顺序执行

一次性,顺序性,排他性!执行一些列的命令

-----队列 set set set 执行 ----

redis事务没有隔离级别的概念!

全部的命令在事务中,并无直接被执行!只有发起执行命令的时候才会执行!exec

redis的事务

  • 开启事务 (multi)
  • 命令入队
  • 执行事务 (exec)

锁:redis能够实现乐观锁

正常执行事务!
> multi #开启事务
OK 
#命令入队
> set k1 v1
QUEUED
> set k2 v2
QUEUED
> get k2
QUEUED
> set k3 v3
QUEUED
> exec #执行事务
OK
OK
v2
OK
放弃事务
multi #开启事务
OK
> set k1 v1
QUEUED
> set k2 v3
QUEUED
> set k4 b5
QUEUED
> discard #取消事务
QUEUED
> get k4 #事务队列中命令都不会被执行
QUEUED
> 
(error) ERR unknown command
> DISCARD 
QUEUED
编译型异常(代码有问题!命令有错!),事务中全部的命令都不会被执行
> multi
OK
> set k1 v1
QUEUED
> set k2 v2
QUEUED
> set k3 v3
QUEUED
> getset k3 #错误命令
QUEUED
> set k4 v4
QUEUED
> set k5 v5
QUEUED
> exec #执行事务报错
EXECABORT Transaction discarded because of previous errors.
> get k5 #全部的命令都不会被执行
null
运行时异常(1/0),若是队列中存在一些语法型错误,那么执行命令的时候,其余命令式能够正常执行的,错误命令会抛出异常
> set k1 v1
OK
> multi
OK
> incr k1 #会执行的时候失败
QUEUED
> set k2 v2
QUEUED
> set k3 v3
QUEUED
> get k3
QUEUED
> exec
OK
OK
v3
> get k2
v2
> get k3
v3
> get k1
v1
> incr k1
ERR value is not an integer or out of range #虽然第一条命令报错了,可是依旧正常执行成功了
监控!watch(面试常问)

悲观锁

  • 很悲观,何时都会出问题,不管作什么都会加锁!

乐观锁

  • 很乐观,认为何时候都不会出现问题,因此不会上锁!更新数据的时候去判断一下,在此期间是否有人修改过这个数据,version
  • 获取version
  • 更新的时候比较version
redis测监视测试
正常执行成功
> set money 100
OK
> set out 0
OK
> watch money #监视money对象
OK
> multi #事务正常结束,数据期间没有发生变更,这个时候就正常执行成功
OK
> decrby money 20
QUEUED
> incrby out 20
QUEUED
> exec
80
20

测试多线程修改值,使用watch能够当作redis的乐观锁操做!

> set money 100
OK
> set out 0
OK
> watch money #监视money
OK
> multi
OK
> decrby money 20
QUEUED
> incrby out 20
QUEUED
> exec #执行以前,另一个线程,修改了咱们的值,这个时候,就会致使事务执行失败
null

若是修改失败,获取最新的值就好
在这里插入图片描述

Jedis

咱们要使用java来操做redis

什么是jedis是redis官方推荐的java链接开发工具!使用java操做redis,若是你要使用java操做redis,那么必定要对jedis十分的熟悉

测试

1.导入对应的依赖

<!--导入jedis的包-->
    <dependencies>
        <!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>3.3.0</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.73</version>
        </dependency>

    </dependencies>

2.编码测试:

  • 链接数据库
  • package com.kuang;
     
     import redis.clients.jedis.Jedis;
     
     public class testPing {
         public static void main(String[] args) {
             //1.new jedis对象便可
             Jedis jedis = new Jedis("127.0.0.1",6379);
             //jedis全部的命令就是咱们以前学习的全部指令~!因此以前的指令学习很重要
             System.out.println(jedis.ping());
         }
     }

    输出

    在这里插入图片描述

#### 经常使用的api

String

List

Set

Hash

Zset
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

全部的api命令,就是咱们对应的上面的指令!因此以前的指令学习很重要
  • 操做命令
  • 断开链接!

SpringBoot整合

SpringBoot操做数据:spring-data jpa jdbc mongodb redis

SpringData也是和Springboot齐名的项目

说明:在springboot2.x后,原来使用的jedis被替换成为了lettuce

jedis:采用的是直连,多个线程操做的话是不安全的,若是想要避免不安全的,使用jedis pool链接池!BIO阻塞

lettuce:采用netty,实例能够在多个线程中进行共享,不存在线程不安全的状况!能够减小线程数量,更像Nio模式

Springboot 全部的配置类,都有一个自动配置类

自动配置类都会绑定一个properties 配置文件

源码分析

在这里插入图片描述

整合测试一下

1.导入依赖

2.配置链接

3.测试

在这里插入图片描述

Redis实现订阅发布(消息队列)

Redis主从复制

概念

主从复制,是指将一台redis服务器的数据,复制到其余redis服务器。前者称为主节点(master/leader),后者称为从节点(slave/follower);数据的复制都是单向的,只能由主节点到从节点。master以写为主,slave以读为主。

==默认状况下,每台redis服务器都是主节点==;且一个主节点能够有多个从节点(或没有从节点),但一个从节点只能有一个主节点。

主从复制的做用主要包括:

1.数据冗余:主从复制实现了数据的热备份,是持久化以外的一种数据冗余方式

2.故障恢复:当主节点出现问题时,能够由从节点提供服务,实现快速的故障恢复,其实是一种服务的冗余

3.负载均衡:在主从复制的基础上,配合读写分离,能够由主节点提供写服务,由从节点提供读服务(即写redis服务时应用读取主节点,读redis服务时应用链接从节点),分担服务器负载;尤为是在写少读多的场景下,经过多个从节点分担读负载,能够大大提升redis服务器的并发量

4.高可用基石(集群):除了上述做用之外,主从复制仍是哨兵和集群可以实施的基础,所以说主从复制是redis高可用的基础

通常来讲,==要将redis应用于项目工程中,只使用的一台redis服务器是万万不能的==,缘由以下:

1.从结构上,单个redis服务器会发生单点故障,而且一台服务器须要处理全部的请求负载,压力较大;

2.从容量上,单个redis服务器内存容量有限,就算一台redis服务器容量为256g,也不能将全部内存用做于redis存储内存,通常来讲,==单台redis最大使用内存不该该超过20g==

电商网站上的商品,通常都是一次上传,无数次浏览的,说专业点也就是“多读少写”

在这里插入图片描述

主从复制,读写分离!80%的状况下都是在进行读操做!减缓服务器的压力!架构中常用!一主二从!

只要在公司中,主从复制就是必需要使用的

,由于在真实的项目中不可能单机使用redis

环境配置

只配置从库,不配置主库

> info replication #查看当前库的信息
# Replication
role:master #角色 master
connected_slaves:0 #没有从机
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

复制3个配置文件,而后修改对应的信息

1.端口

2.pid名字

3.log文件名字

4.dump.rdb名字

一主二从

咱们通常状况下只用配置从机就行了

一个主机两个从机

slaveof 127.0.0.1 6379

在这里插入图片描述

在这里插入图片描述

真实得从主配置应该在配置文件中配置,这样的话是永久的,咱们这里使用的是命令,暂时的!

细节

主机能够写,从机不能写只能读!主机中全部的信息和数据,都会自动被从机保存

主机写:
在这里插入图片描述

从机只能读取内容:

在这里插入图片描述

测试:主机断开链接,从机依旧链接到主机的,可是没有写操做,这个时候,主机若是回来了,从机依旧能够直接获取到主机写的信息!

若是是使用命令行来配置的主从,这个时候若是重启了,就会自动变回主机!只要变为从机,立马就会从主机中获取值!

复制原理

slave启动成功链接到master后会发送一个sync同步命令

Master接到命令,启动后台的存盘进程,同时收集全部接收到的用于修改数据集命令,在后台进程执行完毕以后,==master将传送整个数据文件到slave,并完成一次彻底同步==

==全量复制==:而salve服务在接收到数据库文件数据后,将其存盘并加载到内存中

==增量复制==:master继续将新的全部收集到的修改命令依次传给slave,完成同步

可是只要是从新链接master,一次彻底同步(全量复制)将被自动执行

咱们的数据必定能够在从机中看到!

层层链路

上一个M链接下一个S!

在这里插入图片描述

这个时候也能够完成咱们的主从复制!

若是没有老大了,这个时候能不能选择一个老大出来呢?手动!

谋权篡位

若是主机断开了链接,咱们可使用SLAVEOF no one让本身变成主机!其余的节点就能够手动链接到最新的这个主节点(手动)!若是这个时候老大修复了,那就从新链接

Redis哨兵模式(如今公司中全部的集群都用哨兵模式)

自动选举老大的模式

概述:

主从切换技术的方法是:当主服务器宕机后,须要手动把一台服务器切换为主服务器,这就须要人工干预,费时费力,还会形成一段时间内服务不可用。这不是一种推荐的方式,更多时候,咱们优先考虑哨兵模式。redis从2.8开始正式提供了Sentinel(哨兵模式)架构来解决这个问题

谋权篡位的自动版,可以后台监控主机是否故障,若是故障了根据投票数自动将从库转换为主库

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

在这里插入图片描述

这里哨兵有两个做用

  • 经过发送命令,让redis服务器返回监控其运行状态,包括主服务器和从服务器
  • 当哨兵检测到master宕机,会自动将slave切换为master,而后经过发布订阅模式通知其余的从服务器,修改配置文件,让它们切换主机

然而一个哨兵进程对redis服务器进行监控,可能会出现问题,为此,咱们可使用多个哨兵进行监控,各个哨兵之间还会进行监控,这样酒就造成了多哨兵模式

在这里插入图片描述

假设主服务器宕机,哨兵1先检测到这个结果,系统并不会立刻进行failover过程,仅仅是哨兵1主观的认为主服务器不可用,这个现象成为主观下线。当后面的哨兵也检测到主服务器不可用,而且数量达到必定值时,那么哨兵之间就会进行一次投票,投票结果由一个哨兵发起,进行failover[故障转移]操做。切换成功后,就会经过发布订阅模式,让各个哨兵把本身监控的从服务器实现切换主机,这个过程称为客观下线

测试

咱们目前的状态是一主二从

1.配置哨兵配置文件

# sentinel monitor 被监控的名称 host port 1
sentinel monitor myredis 127.0.0.1 6379 1

后面的数字1,表明主机挂了,slave投票看让谁接替成为主机,票数最多的,就会成为主机!

2.启动哨兵

在这里插入图片描述

若是Master节点断开了,这个时候就会从从机中随机选择一个服务器(这里面有一个投票算法)

哨兵日志

在这里插入图片描述

若是主机此时回来了,只能归并到新的主机下,当作从机,这就是哨兵模式的规则!

哨兵模式

优势:

1.哨兵集群,基于主从复制模式,全部的主从配置的优势它全有

2.主从能够切换,故障能够转移,系统的可用性就会更好

3.哨兵模式就是主从模式的升级,手动到自动,更加健壮!

缺点:

1.redis很差啊在线扩容的,集群容量一旦到达上限,在线扩容就十分麻烦

2.实现哨兵模式的配置实际上是很麻烦的,里面有不少选择

哨兵模式的所有配置
# Example sentinel.conf

# port <sentinel-port>
port 8001

# 守护进程模式
daemonize yes

# 指明日志文件名
logfile "./sentinel1.log"

# 工做路径,sentinel通常指定/tmp比较简单
dir ./

# 哨兵监控这个master,在至少quorum个哨兵实例都认为master down后把master标记为odown
# (objective down客观down;相对应的存在sdown,subjective down,主观down)状态。
# slaves是自动发现,因此你不必明确指定slaves。
sentinel monitor MyMaster 127.0.0.1 7001 1

# master或slave多长时间(默认30秒)不能使用后标记为s_down状态。
sentinel down-after-milliseconds MyMaster 1500

# 若sentinel在该配置值内未能完成failover操做(即故障时master/slave自动切换),则认为本次failover失败。
sentinel failover-timeout TestMaster 10000

# 设置master和slaves验证密码
sentinel auth-pass TestMaster testmaster123

sentinel config-epoch TestMaster 15
#除了当前哨兵, 还有哪些在监控这个master的哨兵
sentinel known-sentinel TestMaster 127.0.0.1 8002 0aca3a57038e2907c8a07be2b3c0d15171e44da5
sentinel known-sentinel TestMaster 127.0.0.1 8003 ac1ef015411583d4b9f3d81cee830060b2f29862

Redis缓存穿透和雪崩(面试高频,工做经常使用)

Redis缓存的使用,极大的提高了应用程序的性能和效率,特别是数据查询方面。但同时,它也带来了一些问题。其中,最要害的问题,就是数据的一致性问题,从严格意义上讲,这个问题无解。若是对数据的一致性要求很高,那么就不能使用缓存。

另外的一些典型问题就是,缓存穿透,缓存雪崩和缓存击穿。目前,业界也都有比较流行的解决方案

在这里插入图片描述

缓存穿透(查不到)
概览

缓存穿透的概念很简单,用户想要查询一个数据,发现redis内存数据库没有,也就是缓存没有命中,因而向持久层数据库查询。发现也没有,因而本次查询失败。当用户不少的时候,缓存都没有命中,因而都去请求了持久层数据库。这会给持久层数据库形成很大的压力,这个时候就至关于出现了缓存穿透。

解决方案

布隆过滤器

布隆过滤器是一种数据结构,对全部可能查询的参数以hash形式存储,在控制层先进行校验,不符合则丢弃,从而避免了对底层存储系统的查询压力

在这里插入图片描述

缓存空对象

当存储层不命中后,即便返回的空对象也将其缓存起来,同时会设置一个过时时间,以后再访问这个数据将会直接从缓存中获取,保护了后端数据源;
在这里插入图片描述

可是这种方法会存在两个问题:

1.若是空值可以被缓存起来,这就意味着缓存须要更多的空间存储更多的键,由于这当中可能会有不少的空值的键

2.即便对空值设置了过时时间,仍是会存在缓存层的数据会有一段时间窗口的不一致,这对于须要保持一致性的业务会有影响。

缓存击穿(量太大,缓存过时!)
概述

微博服务器宕机

这里须要注意和缓存击穿的区别,缓存击穿,是指一个key很是热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就像在一个屏障上凿开了一个洞。

当某个key在过时的瞬间,有大量的请求并发访问,这类数据通常是热点数据,因为缓存过时,会同时访问数据库来查询最新数据,而且回写缓存,会致使数据库瞬间压力过大 。

解决方案

设置热点数据永不过时

从缓存层面来看,没有设置过时时间,因此不会出现热点key过时后产生的问题

加互斥锁

分布式锁:使用分布式锁,保证对于每一个key同时只有一个线程去查询后端服务,其余线程没有得到分布式锁的权限,所以只须要等待便可。这种方式将高并发的压力转移到了分布式锁,所以对分布式锁的考验很大

在这里插入图片描述

缓存雪崩

服务器的高可用问题

概念

缓存雪崩,是指在某一个时间段,缓存集中过时失效,redis宕机!

产生雪崩的缘由之一,好比在写文本的时候,立刻就要双十二零点,很快就会迎来一波抢购,这波商品时间比较集中的放入了缓存,假设缓存一个小时,那么到了凌晨一点钟的时候,这批商品的缓存就都过时了。而对这批商品访问查询,都落到了数据库上,对于数据库而言,就会产生周期性的压力波峰。因而全部的请求都会达到存储层,存储层的调用量会暴增,形成存储层也会挂掉的状况
在这里插入图片描述

其实集中过时,倒不是很是致命,比较致命的缓存雪崩,是缓存服务器某个节点宕机或断网。由于天然造成的缓存雪崩,必定是在某个时间段集中建立缓存,这个时候,数据库也是考研顶住压力的。无非就是对数据库产生周期性的压力而已。而缓存服务节点的宕机,对数据库服务器形成的压力是不可预知的,颇有可能瞬间就把数据库压垮。

双十一:停掉一些服务,(保证主要的服务可用!)==服务降级==

解决方案

redis高可用

这个思想的含义是,既然redis有可能挂掉,那我多增设几台redis,这样一台挂掉以后其余的还能够继续工做,其实就是搭建的集群(异地多活)

限流降级(在springCloud讲解过!)

这个解决方案的思想是,在缓存失效后,经过加锁或者队列来控制读数据库写缓存的线程数量。好比对某个key只容许一个线程查询数据和写缓存,其余线程等待。

数据预热

数据加热的含义就是在正式部署以前,我线把可能的数据先预先访问一遍,这样部分可能大量访问的数据就会加载到缓存中。在即将发生大并发访问前手动触发加载缓存不一样的key,设置不一样的过时时间,让缓存失效的时间点尽可能均匀

相关文章
相关标签/搜索