数据库学习

  1. 数据库三大范式
    1. 确保每列原子性,所有字段值都是不可分解的原子值,每个列都不可以再拆分
    2. 非码属性必须完全依赖于候选码,在第一范式的基础上,非主键列完全依赖于主键,而不能是依赖于主键的一部分。
    3. 每一个表不能包含其他表的分主键信息,在第二范式的基础上,非主键列只依赖于主键,不依赖于其他非主键。
  2. MySQL基本机构:
    1. Server层
      1. 链接器:身份认证
      2. 查询缓存:执行查询语句的时候,会先查缓存(MySQL 8.0 版本后移除,表的更新会使缓存清空,且有更好的,例如redis)
      3. 分析器:对SQL语句进行分析,分析语句的方式,查询的表和字段,查询条件等,检查SQL语句是否正确
      4. 优化器:按照MYSQL认为最优的方案执行(例如多个索引,多表查询如何关联顺序)
      5. 执行器:执行语句(效验用户权限),然后从存储引擎返回数据
    2. 存储引擎:主要负责数据的存储和读取,采用可以替换的插件式架构, InnoDB、MyISAM、Memory,默认InnoDB。
      1. InnoDB在主键上建聚簇索引,将主键组织到一棵B+树中,而行数据就储存在叶子节点上。在非主键上建辅助索引,查找的时候,首先在辅助索引B+树上检索,找到叶子节点获取对应主键,再在主键索引执行一次B+树搜索操作,叶子节点即为数据。
      2. InnoDB内存结构:
        1. Buffer Pool缓冲池:基于LRU算法(最近最少使用页面置换算法),80%占80%以上的物理内存。Page,InnoDB存储的最基本结构,磁盘管理的最小单元,最小16K。分为数据页,索引页,日志页等。
        2. Insert Buffer更改缓冲区(实现插入缓冲),数据页的存放还是按照主键进行顺序存放,但对于非聚簇索引叶节点则是随机的,此时就需要使用到插入缓冲技术。插入时,首先判断插入的非聚集索引页面是否在缓冲区里面,是就直接插入。不是就先存放到Insert Buffer,达到一定数量进行排序,然后再将排序的结果插入叶子节点。使用Insert Buffer条件,辅助索引,索引非唯一。
          1. 为什么索引非唯一?:因为如果索引唯一,则他对应B+树的索引只会包含唯一一个对应的主键值;只有当索引非唯一的时候,所对应的B+树叶子节点能对应多个主键值,多次插入才能合并。
          2. Mysql5.5以后改名为Change Buffer,不仅仅支持插入操作,还支持更新,删除操作
        3. 自适应哈希索引:InnoDB会根据热点索引页(经常访问的二级索引数据会自动被生成到hash索引里面去),计算效率,建立哈希索引,具体搜索过程中,首先尝试hash搜索,如果失败再尝试二进制搜索。
        4. Log Buffer日志缓冲区:保存要写入磁盘上日志文件的数据的内存区域,默认大小16M,有三种刷到磁盘的方式:
          1. 每次事务都会写入内核缓冲区,并将数据刷到磁盘
          2. 每秒写事务到内核缓冲区,并将数据刷到磁盘
          3. 每次事务都会写入内核缓冲区,每秒将数据刷到磁盘
      3. InnoDB磁盘结构:表、索引、表空间、数据字典信息、双写缓冲区,重做日志,撤销日志
        1. 表空间:
          1. 系统表空间:数据字典、双写缓冲区、更改缓冲区和撤消日志的存储区域 。
          2. 通用表空间:存储表数据,共享空间
          3. 撤销表空间:存储回滚段(并发,回滚消息)
          4. 临时表空间:存储临时表,正常关闭或中止初始化时被删除,并在每次服务器启动时重新创建。
        2. 数据字典信息:数据库中数据、库对象、表对象、索引等元信息的集合
        3. doublewrite buffer
          1. 若在将脏页(内存数据页跟磁盘数据页内容不一致)写到数据库的过程中,写到一半,突然断电。
          2. innodb的数据页一般大小是16KB,有可能在一个页中写入一半时(比如8K)数据库宕机,部分写失效,而磁盘上的数据页损坏,就需要用到二次写
          3. 写数据页之前,先把这个数据页写到一块独立的物理文件位置,再写到数据页。这样在宕机重启时,先用副本恢复数据页,然后再使用rado log重做
        4. 重做日志(rado log):物理日志,当记录需要更新的时候,InnoDB 引擎就会先把记录写到 redo log里面,并更新内存,这个时候更新就算完成了。当系统比较闲或者redo log满了的时候更新刷新到磁盘。
        5. 撤销日志(undo log):包含撤销日志
      4. InnoDB特性:
        1. 插入缓冲(insert buffer):Change Buffer

        2. 二次写(double write)

        3. 自适应哈希索引(ahi)

        4. 预读(read ahead),rado log

      5. InnoDB优点:
        1. 支持事务
        2. 灾难恢复性好:
        3. 使用行级锁:
        4. 实现缓冲处理:InnoDB 提供了专门的缓存池,实现了缓冲管理,不仅能缓冲索引也能缓冲数据,常用的数据可以直接从内存中处理,比从磁盘获取数据处理速度要快。
        5. 支持外键:InnoDB 支持外键约束,检查外键、插入、更新和删除,以确保数据的完整性。
        6. 适合大数据:InnoDB 是为处理巨大数据量时的最大性能设计
    3. mysql语句执行流程;
      1. 查询语句:权限效验->查询缓存->分析器->优化器->权限效验->执行器->引擎
      2. 更新语句:权限效验->查询缓存->分析器->优化器->权限效验->执行器->引擎 redo log prepare(InnoDB重做日志 预提交状态)->binlog(归档日志)->redo log commit(提交状态)
        1. 需更新的数据首先放在BufferPool缓冲池
        2. 若prepare完毕,binlog出错,会根据redo log回滚
        3. 若prepare完毕,binlog完毕,commit出错,会执行提交
  3. 事务:
    1. 事务ACID特性:
      1. 原子性:事务包含的所有操作要么全部成功,要么全部失败回滚。事务执行的时候,innodb会制作撤销日志(undo log),当事务执行失败或调用 rollback回调函数,数据库会根据undo log的记录反向操作。
      2. 持久性:事务一旦提交,他对数据库的改变就应该是永久的。其他影响,即使发生故障,也不会对这个改变发生影响。基于重做日志(rado log)实现,如果 MySQL 宕机,重启时可以读取 redo log 中的数据,对数据库进行恢复。
      3. 隔离性:事务执行的内部操作与其他事务是隔离的,并发执行时各个事务是隔离的。基于锁机制实现。
      4. 一致性:事务执行后,数据库的完整性不会被破坏,事务执行前后都是合法数据状态。其他三种特性的实现,才能保证数据库一致性的实现,且数据库本身会提供保障(例如:不允许向整形列插入字符串值,字符串值长度限制等),还需用户层面来保障一致性(例如:转账操作只扣钱不加钱)。
    2. 并发情况下,数据操作所存在的问题:
      1. 丢失更新:A,B两个事务获得同一个数据并将其修改,则A,B事务执行结束后,数据会丢失某个事务的修改。
      2. 脏读:事务A读取到事务B修改但是未提交的事务,然后事务B发生了回滚。
      3. 不可重复读:事务A两次读取的数据不一致,在事务两次读取数据之间,事务B将数据进行修改,并提交了事务。
      4. 幻读:事务A两次读取结果不一致,事务两次读取数据之间,事务B新增,并提交了事务。
    3. 事务的隔离级别:
      1. 读未提交:最低的隔离级别,运行读取未提交的数据,读取数据不加锁,修改数据增加行级共享锁。
      2. 读已提交:允许读取事务已经提交的数据,读取数据增加行级共享锁,读取结束释放,修改数据时增加行级排它锁,事务结束释放
      3. 可重复读:对同一字段的多次读取结果都是一致的,读取数据增加行级共享锁,事务结束释放,修改数据时增加行级排它锁,事务结束释放(mysql默认级别)
      4. 可串行化:最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行
    4. InnoDB,MVCC(多版本并发控制):
      1. 查询一些正在被另一个事务更新的行,但可以看到它们被更新之前的值,这样查询就不用等待另一个事务释放锁。
      2. InnoDB数据行包含两个隐藏列:(最近修改该行数据的事务的ID),(该行回滚段的指针,指向undo中该行的历史记录链表)。MVCC并没有简单的使用数据库的行锁,而是使用了行级锁。
      3. 为什么叫多版本?版本号并不是实际的时间值,而是系统版本号。每开始新的事务,系统版本号(事务版本)都会自动递增。
      4. 更新操作(删除再插入)
      5. 两个隐藏列也可看作:创建时的版本号和删除时的版本号
      6. 增删改查:
        1. 增加,创建一行,并将当前版本号设置为此事务的id
        2. 删除,将删除行的删除版本号的事务id设为当前事务的id
        3. 更新:(更新 = 删除 + 增加),将删除行的删除版本号的事务id设为当前事务的id,创建一行,并将当前版本号设置为此事务的id。
        4. 查询:只查找小于或等于当前事务版本的数据行。数据行的删除版本号一定大于当前事务id或者为未定义。
  4. 索引:
    1. 索引是对数据库表中一个或多个列的值排序的结构
    2. 索引类型:
      1. 聚簇索引:叶子节点为行数据的全部信息。此列或列集特点:非空唯一。如果没有定义,则会自动选择合适的唯一索引作为聚簇索引,并将其设为非空;如果没有合适,会自动创建隐藏列作为聚簇索引。主键索引是聚簇索引的一种具体展现。
      2. 二级索引:非聚簇索引
    3. 索引分类:
      1. 主键索引:列值唯一,非空,表中唯一
      2. 唯一索引:列值唯一,可以有null
      3. 普通索引
      4. 联合索引:多列值组成一个索引,专门用于组合搜索,查询的时候会基于最左前缀匹配原则。
        1. 最左前缀:例如表对于(a,b,c)创建了联合索引,则匹配的时候可以通过(a)或者(a,b)或者(a,b,c)进行索引查找。而其他组合均不能利用到索引
    4. 覆盖索引:查询的字段已经全部被索引包含了,不需要回表查询了
    5. 排序索引的构建(创建或重建索引时执行),采用自下而上的构建方式,不需要页面分裂合并,不需要多次搜索查找插入位置。顺序创建节点,然后子节点满了,创建父节点。
    6. 全文索引:把包含一定的字符串的的行记录挑选出来,以一定字符串创建索引。简单来说,就是记录某些词会在哪些行中出现。
    7. 索引实现:
      1. Hash索引:基于hash表实现,适合精确查找不适合范围查找
      2. B树索引:
        1. 根节点非叶子节点至少有两个子树
        2. 非根节点有M/2 - 1 ~ M-1个关键字
        3. 叶子节点均在同一层
        4. 插入节点,逐层往上,插入,分离
        5. 删除节点,父节点下移,兄弟节点上移
      3. B+树索引
        1. 与B大致相同,子树与关键字数相等,父节点指也在子节点中
        2. 叶子节点包含全部数据
        3. 所有查询的时间一致
    8. 索引失效:
      1. 违反最左前缀
      2. 在索引列上做一些操作,例:计算、函数、类型转换
      3. 多个单列索引,只会生效最左边的
      4. 使用不等于(!=、<>)
      5. 条件中有or
      6. like查询以通配符%开头
      7. 字符串不加单引号
      8. mysql判断全表查询更快,就会使用全表查询
    1. 锁分类:
      1. 共享锁和排他锁
        1. 共享锁(读锁):其他事务可以读,但不能写。
        2. 排他锁(写锁):其他事务不可以读,但也不能写。
      2. 锁粒度:表级锁,页级锁,行级锁(Innodb支持行级锁和表级锁)
        1. 表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。
        2. 行级锁(innodb特有):开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
        3. 页级锁(BDB支持):表级锁和行级锁之间的锁。
      3. 悲观锁和乐观锁:
        1. 乐观锁:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。CAS,假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作。在查询完数据的时候就把事务锁起来,直到提交事务。
        2. 悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作。在查询完数据的时候就把事务锁起来,直到提交事务。
    2. innodb锁机制:
      1. innodb的行级锁是对索引加锁,而不是对数据行加锁。当SQL语句通过索引锁定数据行,则对索引加的是行级锁;若全表扫描找到数据行,则加的是表锁。
        1. 具体加行锁还是表锁,由mysql优化器决定。因为有可能mysql会认为表很小,不需索引。就会加表锁。
        2. 因为是行锁是对索引加锁,不是对数据行加锁,所以有可能不同的行,使用了相同索引,还是会出现冲突。例如表包含a,b两个字段,a建立了索引,b没有。则如果以索引查询,查询条件 a = 1and b = 1 就会和 a = 1and b = 4冲突
        3. 当表有多个事务的时候,不同的事务可以通过不同的索引加锁,不论是使用主键索引、唯一索引或普通索引,InnoDB都会使用行锁来对数据加锁。
      2. 行级锁:共享锁 和 排他锁
      3. 表级锁:意向共享锁 和 意向排它锁 ;共享锁 和 排他锁
        1. 意向共享锁: 事务想要获得一张表中的某几行的共享锁
        2. 意向排它锁: 事务想要获得一张表中的某几行的排它锁
      4. 一致性非锁定读(快照读):普通读写,普通的select语句
      5. 一致性锁定读(当前读):显示加锁:
        1. select ... for update  使用临键锁,相当于加排它锁(行)
          1. 间隙锁:封锁索引记录中的间隔,开区间()。
          2. 临键锁:间隙锁 + 记录锁(行锁)。(】左开右闭区间,防止幻读。
          3. 产生情况:
            1. 可重复读 级别下
            2. 普通索引
            3. 唯一索引范围查找
          4. 注:唯一索引会降级为行锁
        2. select ... lock in share mode 加共享锁(行)
  5. 数据库优化
    1. SQL语句优化
      1. 尽量避免全表扫描,
      2. 字段尽量不要出现NULL
      3. 避免在where子句中使用!=、or、in、not in
      4. 避免不带任何限制范围的条件查询语句
    2. 索引优化:在where和order by涉及的列上创建索引,避免索引失效
    3. SQL结构优化
      1. 分库分表:垂直分表和水平分表
        1. 垂直拆分针对表,字段太多
          1. 垂直分库:关联度低的不同表存储在不同的数据库
          2. 垂直分表:将某些不常用的,但是长度又很大的字段拎出来放到另外一张表。
        2. 水平拆分:针对数据量太大
          1. 库内分表:同一个db上,将表按照某种条件拆分为多张表。
          2. 分库分表:将表拆分到不同的机器上
        3. 常用分库分表策略:
          1. HASH取摸:用户表user,将其分成3个表user0,user1,user2.路由规则是对3取模,当uid=1时,对应到的是user1,uid=2时,对应的是user2.
          2. 范围分片:从1-10000一个表,10001-20000一个表
          3. 地理位置分片
      2. 缓存:使用MySQL缓存,另外对重量级、更新少的数据可以考虑使用应用级别的缓存,例如redis。
      3. 读/写分离:经典数据库拆分方式,利用主从复制实现,主库负责写,从库负责读
        1. 主从复制流程:
          1. 主库更新事件写入binlog
          2. 主库创建线程,将binlog内容发送到从库
          3. 从库启动,并发起连接到主库
          4. 从库创建一个I/O线程,读取主库传过来的binlog内容并写入到relay log
          5. 从库创建一个SQL线程,从relay log里面读取内容,将更新内容写入从库
        2. 主从复制方式:
          1. 异步复制:主库在执行完客户端提交的事务后会立即将结果返给给客户端,并不关心从库是否已经接收并处理,早期MySQL仅仅支持异步复制
          2. 半同步复制:主库在执行完客户端提交的事务后不是立刻返回给客户端,而是等待至少一个从库接收到并写到relay log中才返回给客户端。
          3. 全同步复制
  6. Raids:
    1. 基本概念:用C语言编写的开源高性能非关系型键值对数据库
    2. 支持的数据类型:
      1. 字符串
      2. 列表
      3. 集合
      4. 散列表
      5. 有序集合
    3. 优点:
      1. 读写数独很快
      2. 支持数据持久化,AOF和RDB
      3. 支持事务
      4. 数据结构丰富
      5. 支持主从复制
      6. 高性能高并发
    4. 缺点:
      1. 受内存限制,不能存储海量数据
      2. 不具备容错和恢复功能,主机从机宕机,前端请求会出错,需要重启或切换IP
      3. 主机宕机,还有数据没有备份到从机,切换IP到从机会导致数据不一致问题
      4. 很难在线扩容
    5. 快的原因:
      1. 完全基于内存
      2. 数据结构简单
      3. 采用单线程
      4. 使用I/O多路复用,非阻塞I/O
      5. 底层模型不同,Redis 直接自己构建了 VM 机制
    6. 应用场景:
      1. 计数器
      2. 缓存
      3. 消息队列
      4. 分布式锁
    7. 底层实现
      1. 压缩列表:将数据按照一定规则编码在一块连续的内存区域
      2. 整数集合:编码方式(int16,int32,int64),长度,整数数组。可以升级编码方式,不能降级
      3. 跳跃表(有序数据结构):
        1. 多层结构
        2. 每一层都是有序链表
        3. 最底层包含所有数据,最上层节点数最少
        4. 如果一个节点出现在某一层,其下所有层都包含这个节点。
        5. 莫一层节点有两个指针,一个指针指向同一层下一个节点,一个指针指向下一层节点。
        6. 搜索,插入,删除:
          1. 搜索:从左往右,从上往下
          2. 插入:随机确定插入层数,从下往上添加
          3. 删除:删除这一层的节点。
      4. 字典:使用哈希表作为底层实现,哈希冲突使用链表,使用重新散列进行扩容和收缩。
        1. 重新散列:底层有两个哈希表,一个空白,一个存数据,扩容和收缩时,为空白的哈希表分配空间,将数据刷新到这个哈希表上,重新计算hash值,并将之前存数据的哈希表置空,交换两个哈希表。
        2. 扩容和收缩都是非一致性的,都是渐进。查找数据的时候,在一个哈希表没找到就会去另外一个哈希表查找。
      5. 链表:双向链表,节点数据可以是不同类型的值。记录头结点,尾节点和节点数
      6. Redis的字符串:简单动态字符串(SDS)
        1. 结构:
          1. free记录buf中未使用的字节数量
          2. len保存字符串长度
          3. buf[] 保存字符串每个元素
        2. 优点:
          1. 读取长度的时间复制度为O(1)
          2. 杜绝缓冲区溢出:C语言使用函数将两个字符串进行拼接,可能因为内存不够而造成缓冲区溢出,SDS拼接字符串会检查len属性,不够会进行相应的空间扩展。
          3. 减少修改字符串所造成的内存重新分配:C语言修改字符串需要重新分配内存。SDS修改字符串使用了空间预分配和惰性空间释放两种策略。
            1. 空间预分配:当需要对 SDS 进行空间扩展的时候, 程序不仅会为 SDS 分配修改所必须要的空间, 还会为 SDS 分配额外的未使用空间。当SDS长度小于1M时,会分配与实际字符串相同的长度,此时free = len;当SDS长度大于1M时,会分配1M的额外空间。
            2. 惰性空间释放:当SDS需要缩短的时候,不是直接内存重新分配,而是使用free记录多余的字节。
          4. 二级制安全:字符串以空字符串表示结束,而一些二进制文件(图片)可能包含空字符,不能保存。SDS以len元素判断结束,且都以二进制方式处理buf中的字符。
          5. 兼容C语言:字符串最后包含空字符,可以使用C语言的一些函数
    8. 持久化
      1. RDB(默认):按照一定时间,将内存中的数据保存到硬盘中去。使用单独子进程进行持久化,主进程不会进行IO操作。
        1. 只有一个文件,方便
        2. 内容可以保存到安全磁盘,安全。
        3. 单独进程,性能好
        4. 间隔一段时间才持久化,若持久化之间 redis 发生故障,会照成数据丢失,数据安全低
      2. AOF持久化:将redis执行的每次写命令到写到单独的日志文件中,当重启redis会重新基于持久化文件进行数据恢复。
        1. 数据安全,速度慢,需手动启动
        2. RDB与AOF同事配备,优先加载AOF
    9. 扩容:
      1. Radis作为缓存,使用一致性哈希(用hash环存值)实现动态扩容缩容。
        1. 一致性哈希:构建一个0到2^32-1的hash环,根据hash值将服务器节点放到环中,存储key值,key值顺时针执行最近的节点。
      2. 如果radis当做持久化存储,则必须使用节点-键映射关系,节点数量一旦确定不能变化。因为运行时需要数据平衡。
    10. 过期策略:
      1. 定时过期:每个设置过期时间的key都需要创建一个定时器,到过期时间就会立即清除。
      2. 惰性过期:当访问key时才会判断这个key是否过期
      3. 定期过期:每隔一段时间扫描key(非全部),过期则清除。
    11. 内存淘汰策略:
      1. 内存不足,新写入会报错
      2. 内存不足,会移除最近最少使用的key(最常用)
      3. 内存不足,随机移除某个key
      4. 内存不足,在设置了过期时间的键空间中,移除最近最少使用的key。
      5. 内存不足,在设置了过期时间的键空间中,随机移除某个key
      6. 内存不足,在设置了过期时间的键空间中,移除最早过期时间的key
    12. radis内存优化:
      1. 利用好hash,set,list等集合,尽可能将数据(例如对象)抽象到散列表中
    13. 事务:一次性、顺序性、排他性的执行一个队列中的一系列命令
    14. 集群方案Redis 常见面试题(2020最新版)
      1. 哨兵模式:客户端和radis集群之间使用哨兵集群(至少三个实例)监管控制,不保证数据零丢失,保证高可用性。判断一个主radi是否宕机,需要大多数哨兵同意,且一个哨兵挂掉,哨兵集群还是能够正常工作。哨兵的具体作用如下:
        1. 集群监控:监控主radis和从radis进程是否能正常使用
        2. 消息通知:某个radis发生故障,会通知管理员
        3. 故障转移:主radis故障,会自动转移到从radis上
        4. 配置中心:主radis故障,通知客户端新的主radis地址
      2. 主从结构:一主多从,主负责写,从负责读。先写主再写从。
        1. 异步复制
        2. 主radis链接到多个从服务器,从服务器之间也可以互相链接
        3. 主从复制,使用单独的进程,不会影响主服务器
        4. 主从复制期间,从服务器正常工作,从服务器更新的时候,暂停服务
        5. 过程:
          1. 从服务器链接到主服务器,发送同步(SYNC)命令
          2. 主服务器收到命令,生成RDB快照文件,并使用缓存区记录此后的写操作
          3. 快照文件完成后,会将文件和缓冲区所有缓存的写命令发送给从服务器(先发文件,再发缓存)
          4. 从服务器收到后,会载入快照文件,并执行收到的缓存
      3. 工作原理:radis集群由多个节点组成,一个节点包含一个主radis和多个从radis。radis集群通过分片来保存数据库中的键值对,集群数据库包含2^14个槽,数据库的键值对都放在这些槽中。并将这些槽分给radis集群多个节点。每个节点可以包含0~2^14个槽。具体流程如下:
        1. 通过hash将数据分片
        2. 将数据片存储到互为主从的多个节点
        3. 先写入主节点,再写入从节点
        4. 读取数据时,若key值没有在此节点上,会放回转向指令,指向正确的节点
    15. 分区:
      1. 提高多核cpu利用率:radis是单线程的,在一个服务器上部署多个radis实例能更好的利用内存
      2. 好处:可以使用更大的内存
      3. 分区方案:
        1. 客户端分区:客户端知道键值对在哪个集群节点
        2. 代理分区:客户端将请求发送给代理,代理决定在哪个节点进行数据读写
        3. 查询路由:客户端随机向节点发送请求,然后由此节点将请求转发给正确的节点
      4. 缺点:
        1. 数据处理麻烦(例如:数据备份)
        2. 扩容缩荣麻烦
        3. 不能操作多个key(例:不能将两个key进行合并,因为他们可能分布在不同的节点)
    16. 分布式锁:
      1. 使用setnx实现分布式锁。若key不存在则将key的值设为value,若key存在则不进行操作。
      2. RedLock:使用redis实现的分布式锁(多个服务间保证同时同用户只能有一个请求) 
        1. 流程:假设有5台实例
          1. 客户端设置锁的过期时间TTL,使用相同key-value去各个节点获取锁
          2. 在各个radis实例获取锁的时间的总和要小于TTL。例:5台实例,TTL=5s,则每个radis获取锁的时间最多为1s,超过就是获取锁失败
          3. 只有获得半数以上radis实例的锁,才算获取锁成功 
          4. 获取锁成功,则锁的真正有效时间 = TTL - 获取锁所用时间
          5. 获取锁失败,必须解锁所有节点的锁
        2. 特性:
          1. 互斥:只有一个 client 能拿到锁
          2. 避免死锁:即使锁定资源的服务崩溃或者分区,仍然能释放锁
          3. 容错性:只要大部分 Redis 节点存活就可以正常提供服务
    17. 缓存异常:
      1. 缓存雪崩:缓存同一时间大面积失效,就会有大量请求同时落在数据库上,造成数据库崩溃
        1. 缓存过期时间随机
        2. 并发量不高,加锁
        3. 给每个缓存添加缓存标记,标记失效更新缓存
      2. 缓存穿透:缓存,数据库都没有数据,大量请求就会落在数据库上,造成数据库崩溃
        1. 增加校验,不合理请求直接拦截,例:id<0
        2. 查找数据库发现没有数据,缓存设置为key-null,将其过期时间设置短一些
        3. 采用布隆过滤器,将所有可能存在的数据,hash存到哈希表中,一个一定不存在就直接过滤
      3. 缓存击穿:缓存失效了(过期),高并发查数据库
        1. 热点数据永不过期
        2. 加锁
      4. 缓存预热:系统上线,直接将相关缓存加到系统
        1. 直接写一个缓存页,上线手动刷新一下
        2. 数据量不大,系统启动直接加载
        3. 定时刷新
      5. 缓存降级:高并发,服务出现问题、非核心服务影响到核心服务,自动降级或手动减级,例:radis出现问题,不去访问数据库,直接返回默认值给用户
    18. Redisson:Redis官方推荐的Java版的Redis客户端
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值