乐趣区

关于redis:基础知识redis详解Foam番茄

Redis

学习形式:

  • 上手就用
  • 根本的实践先学习, 而后将常识融汇贯通

nosql 解说

为什么要用 Nosql

当初都是大数据时代

大数据个别的数据库无奈进行剖析解决了

至多要会 Springboot+SpringCloud

压力肯定会越来越大,适者生存

1. 单机 MySQL 的年代

90 年代,一个根本的网站访问量个别不会太大,单个数据库齐全足够,那个时候,更多的去应用动态网页,HTML,服务器基本没有太大的压力

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

1. 数据量如果太大,一个机器放不下了

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

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> 应用键值对来管制

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 一起应用才是最强的,阿里巴巴的架构演进!

技术没有高下之分,看你如何应用!(晋升内功,思维的进步!)

技术急不得,越是缓缓学,能力越扎实

麻利开发,极限编程

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

大量公司做的都是雷同的业务(竞品协定)

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

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

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)与范畴查问,bitmaps,hyperloglogs 和 天文空间(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,设置不同的过期工夫,让缓存生效的工夫点尽量平均

退出移动版