常用数据库 知识点大全 (Mysql,Redis,MongoDB)

目录
  1. Mysql
    1.1 5大引擎 共10个
    1.2 事务
    1.3 锁1 锁2
    1.4 Btree/B+tree
    1.5 mysql进阶
  2. Redis
    2.1 Redis介绍
    2.2 redis的五大数据类型实现原理
    2.3 Redis持久化方式
    2.4 Redis集群–> 主从复制
    2.5 Redis集群–> 哨兵、codis集群
    2.6 布隆过滤器
    2.7 redis事物与分布式锁
  3. MongoDB
  4. RabbitMQ

1. Mysql

简介:

MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS (Relational Database Management System,关系数据库管理系统) 应用软件之一。
MySQL是一种关系型数据库管理系统,关系数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。
MySQL所使用的 SQL 语言是用于访问数据库的最常用标准化语言。MySQL 软件采用了双授权政策,分为社区版和商业版,由于其体积小、速度快、总体拥有成本低,尤其是开放源码这一特点,一般中小型网站的开发都选择 MySQL 作为网站数据库。

五大引擎

因MyISAM 和 InnoDB 是主要引擎所以多做概述
  • MyISAM
    Myisam只支持表级锁,用户在操作 myisam 表时,select、update、delete、insert、语句都会给表自动加锁,如果加锁以后的表满足 insert 并发的情况下,可以在表的尾部插入新的数据。也可以通过 locktable 命令来锁表,这样的操作主要是可以模仿事务,但消耗特别大

    因为MyISAM表有无法处理事务,所以它只适合在一下几种情况下使用
    1.选择密集型的表。MyISAM存储引擎在筛选大量数据时非常迅速,这是它最突出的优点。
    2.插入密集型的表。MyISAM的并发插入特性允许同时选择和插入数据。例如:MyISAM存储引擎很适合管理邮件或Web服务器日志数据。

  • InnoDB

    1.更新密集的表。InnoDB存储引擎特别适合处理多重并发的更新请求。
    2.事务。InnoDB存储引擎是支持事务的标准MySQL存储引擎。
    3.自动灾难恢复。与其它存储引擎不同,InnoDB表能够自动从灾难中恢复。
    4.外键约束。MySQL支持外键的存储引擎只有InnoDB。
    5.支持自动增加列AUTO_INCREMENT属性。

    • Innodb支持事务和行级锁。
    • 事物的ACID属性:atomicity、consistent、isolation、durable
    • Innodb属于索引组织表。
    • Innodb有两种存储方式,共享表空间多表空间存储

在这里插入图片描述
MyISAM & InnoDB 差异:

- 自增长差异:

MyISAM 引擎的自动增长列必须是索引,如果是组合索引,自动增长可以不是第一列,
它可以根据前面几列进行排序后递增。

InnoDB 引擎的自动增长列必须是索引,如果是组合索引也必须是组合索引的第一列

- 主键差异:

MyISAM 允许没有任何索引和主键的存在,
MyISAM 的索引都是保存行的地址

InnoDB 如果没有设定主键 或者 非空唯一索引,就会自动生成一个6字节的主键(用户不可见)
InnoDB 的数据是主索引的一部分,附加索引保存的是主索引的值。

- count()函数差异:

MyISAM 保存有表的总行数,如果 select count(*) from table; 会直接取出该值
InnoDB 没有保存表的总行数,如果使用 select count(*) from table; 就会遍历整个表,消耗相当之大,但是加了 where  条件后,MyIASM 和 InnoDB 的处理方式都一样

- 全文索引差异:

MyISAM 支持 FullText 类型的全文索引
InnoDB 不支持 FullText 类型的全文索引,但是 InnoDB 可以使用 
	sphinx 插件支持全文索引,并且效果更好

delete from table 
使用这条命令时,InnoDB不会从新建立表,而实一条条的删除数据,在InnoDB上如果要清空保存有大量数据的表,最好不要使用这条命令。(推荐使用 truncate table,不过需要用户有 diop 此表的权限)

- 索引保留位置差异:

MYISAM 的索引以表名 + .MYI 文件分别保存
InnoDB 的索引和数据一起保存在 表空间里

- 存储疫情选择差异:
MyISAM B+tree
InnoDB B-tree
12345678910111213141516171819202122232425262728293031323334353637

在这里插入图片描述

  • MEMORY /meməri/ -- 买么瑞
    使用MEMORY引擎主要是因为速度,好处就在MEMORY采用的逻辑存储是系统内存,极大的提高了储存数据表的性能; 坏处就是当mysqld守护进程崩溃时,所有的Memory数据都会丢失。
    一般在以下几种情况下使用Memory存储引擎:

    1.目标数据较小,而且被非常频繁地访问。在内存中存放数据,所以会造成内存的使用,可以通过参数max_heap_table_size控制Memory表的大小,设置此参数,就可以限制Memory表的最大大小。
    2.如果数据是临时的,而且必须立即使用,那么就可以存放在内存表中。
    3.存储在Memory表中的数据如果突然丢失,不会对应用服务产生实质的负面影响。

  • MERGE /mɜːdʒ/ -- 么耳吱
    MERGE存储引擎是一组MyISAM表的组合,这些MyISAM表结构必须完全相同,所以就相当于一个集合器。比起其他储存引擎MERGE不是很优秀,但是在某些情况下MERGE还是非常的有用。对于服务器日志这种信息,一般常用的存储策略是将数据分成很多表,每个名称与特定的时间端相关。

  • ARCHIVE /'ɑ:kaiv/ -- 阿尔铠武
    Archive是归档的意思,在归档之后很多的高级功能就不再支持了,仅仅支持最基本的插入和查询两种功能。在MySQL 5.5版以前,Archive是不支持索引,但是在MySQL 5.5以后的版本就开始支持索引了。Archive拥有很好的压缩机制,它使用zlib压缩库,在记录被请求时会实时压缩,所以它经常被用来当做仓库使用。

  • BDB(BerkeleyDB)

  • EXAMPLE /ɪɡˈzæmpl/ -- 诶个曾伯

  • FEDERATED /'fɛdə,retɪd/ -- F艾 的瑞der

  • CSV

  • BLACKHOLE

事务原理

InnoDB事务原理
  1. 事务(Transaction)是数据库区别于文件系统的重要特性之一,事务会把数据库从一种一致性状态转换为另一种一致性状态。

  2. 在数据库提交时,可以确保要么所有修改都已保存,要么所有修改都不保存。

     MySQL数据库默认采用自动提交(autocommit)模式, 也就是说修改数据(insert、update、delete)的操 作会自动的触发事务,完成事务的提交或者回滚
     开启事务使用 begin 或者 start transaction; 
     回滚事务使用 rollback;
     pymysql 里面的 conn.commit() 操作就是提交事务
     pymysql 里面的 conn.rollback() 操作就是回滚事务
    12345
    
事务的(ACID)特征
  1. 原子性(Atomicity):整个事物的所有操作要么全部提交成功,要么全部失败回滚(不会出现部分执行的情况)。
  2. 一致性(Consistency):几个并行执行的事务,其执行结果必须与按某一顺序串行执行的结果相一致。
  3. 隔离性(Isolation):事务的执行不受其他事务的干扰,事务执行的中间结果对其他事务必须是透明的。
  4. 持久性(Durability): 一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。
事物隔离级别
  • 未提交读: 脏读(READ UNCOMMITTED) 读未提交

    1. 事务2查询到的数据是事务1中修改但未提交的数据,因为事务1回滚了数据
    2. 所以事务2查询的数据是不正确的,因此出现了脏读的问题。

    (存在4个问题 脏读、不可重复读、幻读、更新丢失)
    解决方法:
    将数据库事务隔离级别调整到 Read_Commited 读已提交

  • 提交读: 不可重复读(READ COMMITTED)

    1. 事务2执行update语句但未提交前,事务1的前两个select操作返回结果是相同的。
    2. 但事务2执行commit操作后,事务1的第三个select操作就读取到事务2对数据的改变。
    3. 导致与前两次select操作返回不同的数据,因此出现了不可重复读的问题。

    (不可重复读、幻读、丢失更新)
    解决方法:
    将数据库事务隔离级别调整到 Repeatable_read 可重复 读

  • 可重复读: 幻读(REPEATABLE READ):这是MySQL的默认事务隔离级别

    1. 事务每开启一个实例,都会分配一个版本号给它,如果读取的数据行正在被其它事务执行DELETE或UPDATE操作(即该行上有排他锁)
    2. 这时该事物的读取操作不会等待行上的锁释放,而是根据版本号去读取行的快照数据(记录在undo log中)
    3. 这样,事务中的查询操作返回的都是同一版本下的数据,解决了不可重复读问题。
    4. 虽然该隔离级别下解决了不可重复读问题,但理论上会导致另一个问题:幻读(Phantom Read)。
    5. 一个事务在执行过程中,另一个事物对已有数据行的更改,MVCC机制可保障该事物读取到的原有数据行的内容相同
    6. 但并不能阻止另一个事务插入新的数据行,这就会导致该事物中凭空多出数据行,像出现了幻读一样,这便是幻读问题。

    简易版
    指 事务A 对一个表中的数据进行了修改,而且该修改涉及到表中的所有数据行;同时另一个 事务B 也在修改表中的数据,该修改像表中插入一条新数据。那么经过操作之后,操作 事务A 的用户就会发现表中还有没修改的数据行,就像发觉了幻觉一样,故 幻读
    (存在两个问题 幻读、丢失更新)
    解决方法
    将数据库事务隔离级别调整到 Serializable_read 串行读

  • 可串行读(SERIALIZABLE) 序列化&串行读

  1. 这是事务的最高隔离级别,通过强制事务排序,使之不可能相互冲突,就是在每个读的数据行加上共享锁来实现
  2. 在该隔离级别下,可以解决前面出现的脏读、不可重复读和幻读问题,但也会导致大量的超时和锁竞争现象,一般不推荐使用
隔离级别 脏读 不可重复读 幻读
read uncommitted(未提交读)
read committed(提交读) ×
repeatable read(可重复读) × ×
serializable (可串行化) × × ×

级别高低:脏读 < 不可重复读 < 幻读
所以只要是设置了 最高级别 Serializable 就解决了 前三个问题了,当时 他的资源消耗是最致命的。

什么是锁?

锁是协调多个进程或线程并发访问某一资源的一种机制。在数据库当中,除了传统的计算资源(CPU、RAM、I/O等等)的争用之外,数据也是一种供许多用户共享访问的资源。如何保证数据并发访问的一致性、有效性,是所有数据库必须解决的一个问题,锁的冲突也是影响数据库并发访问性能的一个重要因素。从这一角度来说,锁对于数据库而言就显得尤为重要。

在 Mysql中 有两种锁:Lock 和 Latch

在这里插入图片描述

Latch一般称为闩锁(轻量级的锁),因为其要求锁定的时间必须非常短。若持续的时间长,则应用的性能会非常差,在InnoDB引擎中,Latch又可以分为mutex(互斥量)和 rwlock(读写锁)。其目的是用来保证并发线程操作临界资源的正确性,并且通常没有死锁检测的机制。

Lock的对象是事务,用来锁定的是数据库中的对象,如表、页、行。并且一般lock的对象仅在事务commit或rollback后进行释放(不同事务隔离级别释放的时间可能不同)。

关于Latch更详细的讲解可以参考:关于MySQL latch争用深入分析与判断,本文主要关注的是Lock锁。

锁的类型

对数据的操作其实只有两种,也就是读和写,而数据库在实现锁时,也会对这两种操作使用不同的锁;InnoDB 实现了标准的行级锁,也就是共享锁(Shared Lock)和互斥锁(Exclusive Lock)。

  • 共享锁(读锁),允许事务读一行数据。
  • 排他锁(写锁),允许事务删除或更新一行数据。

共享锁之间是兼容的,而互斥锁与其他任意锁都不兼容:

在这里插入图片描述
共享锁代表了读操作、互斥锁代表了写操作,所以我们可以在数据库中并行读,但是只能串行写,只有这样才能保证不会发生线程竞争,实现线程安全。

锁的粒度

Lock锁根据粒度主要分为表锁、页锁和行锁。不同的存储引擎拥有的锁粒度都不同。
在这里插入图片描述

表锁

表级别的锁定是MySQL各存储引擎中最大颗粒度的锁定机制。该锁定机制最大的特点是实现逻辑非常简单,带来的系统负面影响最小。所以获取锁和释放锁的速度很快。由于表级锁一次会将整个表锁定,所以可以很好的避免困扰我们的死锁问题。
当然,锁定颗粒度大所带来最大的负面影响就是出现锁定资源争用的概率也会最高,致使并发度大打折扣。
使用表级锁定的主要是MyISAM,MEMORY,CSV等一些非事务性存储引擎。

页锁

页级锁定是MySQL中比较独特的一种锁定级别,在其他数据库管理软件中也并不是太常见。页级锁定的特点是锁定颗粒度介于行级锁定与表级锁之间,所以获取锁定所需要的资源开销,以及所能提供的并发处理能力也同样是介于上面二者之间。另外,页级锁定和行级锁定一样,会发生死锁。
在数据库实现资源锁定的过程中,随着锁定资源颗粒度的减小,锁定相同数据量的数据所需要消耗的内存数量是越来越多的,实现算法也会越来越复杂。不过,随着锁定资源颗粒度的减小,应用程序的访问请求遇到锁等待的可能性也会随之降低,系统整体并发度也随之提升。
使用页级锁定的主要是BerkeleyDB存储引擎。

行锁

行级锁定最大的特点就是锁定对象的粒度很小,也是目前各大数据库管理软件所实现的锁定颗粒度最小的。由于锁定颗粒度很小,所以发生锁定资源争用的概率也最小,能够给予应用程序尽可能大的并发处理能力而提高一些需要高并发应用系统的整体性能。
虽然能够在并发处理能力上面有较大的优势,但是行级锁定也因此带来了不少弊端。由于锁定资源的颗粒度很小,所以每次获取锁和释放锁需要做的事情也更多,带来的消耗自然也就更大了。此外,行级锁定也最容易发生死锁。
使用行级锁定的主要是InnoDB存储引擎。

总结

  • 表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。
  • 行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
  • 页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。
InnoDB中的锁

意向锁

上节提到InnoDB 支持多种粒度的锁,也就是行锁和表锁。为了支持多粒度锁定,InnoDB 存储引擎引入了意向锁(Intention Lock)。

那什么是意向锁呢?我们在这里可以举一个例子:如果没有意向锁,当已经有人使用行锁对表中的某一行进行修改时,如果另外一个请求要对全表进行修改,那么就需要对所有的行是否被锁定进行扫描,在这种情况下,效率是非常低的;不过,在引入意向锁之后,当有人使用行锁对表中的某一行进行修改之前,会先为表添加意向互斥锁(IX),再为行记录添加互斥锁(X),在这时如果有人尝试对全表进行修改就不需要判断表中的每一行数据是否被加锁了,只需要通过等待意向互斥锁被释放就可以了。

与上一节中提到的两种锁的种类相似的是,意向锁也分为两种:

  • 意向共享锁(IS):事务想要在获得表中某些记录的共享锁,需要在表上先加意向共享锁。
  • 意向互斥锁(IX):事务想要在获得表中某些记录的互斥锁,需要在表上先加意向互斥锁。

以上原文出处:
https://blog.csdn.net/bruceleenumberone/article/details/81865045


锁分类

  1. 按操作划分:DML锁,DDL锁
  2. 按锁的粒度划分:表级锁、行级锁、页级锁
  3. 按锁级别划分:共享锁、排他锁
  4. 按加锁方式划分:自动锁、显示锁
  5. 按使用方式划分:乐观锁、悲观锁

乐观锁实现方法

  1. 每次获取商品时,(读操作)不对该商品加锁。
  2. 写操作加锁
  3. 在更新数据的时候需要比较程序中的库存量与数据库中的库存量是否相等,如果相等则进行更新
  4. 反之程序重新获取库存量,再次进行比较,直到两个库存量的数值相等才进行数据更新。

举例:
我们收藏购物车 就是乐观锁。假如商品只有1件的时候,所有人都会加入购物车,但是购买只会有一个人

#### 乐观锁实现加一操作代码
# 我们可以看到,只有当对数量-1操作时才会加锁,只有当程序中值和数据库中的值相等时才正真执行。
'''
//不加锁
select id,name,stock where id=1;
//业务处理
begin;
update shop set stock=stock-1 where id=1 and stock=stock;
commit;
'''
12345678910

悲观锁

  1. 每次获取商品时,对该商品加排他锁。
  2. 也就是在用户A获取获取 id=1 的商品信息时对该行记录加锁,期间其他用户阻塞等待访问该记录。

举例:
购买商品的付款时间就是悲观锁,购买商品 30分钟付款时间 就是开的悲观锁,假设商品只有一个,这三个小时我买了没付钱、最后订单取消。这30分钟你都不会购买到次商品

#### 悲观锁实现加一操作代码
# 我们可以看到,首先通过begin开启一个事物,在获得shop信息和修改数据的整个过程中都对数据加锁,保证了数据的一致性。
'''
begin;
select id,name,stock as old_stock from shop  where id=1 for update;
update shop set stock=stock-1 where id=1 and stock=old_stock;
commit
'''
12345678

排它锁

  1. 排它锁又叫写锁,如果事务T对A加上排它锁,则其它事务都不能对A加任何类型的锁。获准排它锁的事务既能读数据,又能写数据。
  2. 用法 : SELECT … FOR UPDATE

举例:

如果我们进入洗手间是为了上厕所,那么就不能允许任何人进来了。
这就是排他锁,也叫写锁,就是我们对数据进行写操作的时候,要想获得写锁,获得写锁的事务既可以写数据也可以读数据。
当时,如果数据库已经被别人增加了排他锁,那么后面的事务是无法在获得该数据库得任何锁得。
也就是说,如果事务A对 数据加上了排他锁后,则其他事务不能在对 数据 加任何类型得封锁。获准排他锁得事务既能读数据,又能修改数据。
1234

共享锁(share lock)

  1. 共享锁又叫读锁,如果事务T对A加上共享锁,则其它事务只能对A再加共享锁,不能加其它锁。
  2. 获准共享锁的事务只能读数据,不能写数据。
  3. 用法: SELECT … LOCK IN SHARE MODE;

举例:

如果我们进家里的洗手间只是想洗手,一般不会锁门,其他人也可以来洗手,但是 其他人是不可以进来上厕所的。
这就是共享锁,也叫读锁,就是我们对数据进行读取操作的时候,其实是不会改变数据的值的。所以我们可以给数据库增加读锁,获得读锁的事务j就可以读取数据了。
当数据库已经被别人增加了读锁的时候,其他新来的事务y也可以读数据,但是不能写。
也就是说,如果 事务A 对数据加上了 共享锁后,则 其他事务只能对 数据 再加共享锁,不能加排他锁。获取共享锁的事务只能读数据,不能修改数据。
1234

Btree/B+tree

Btree

Btree是一种多路自平衡搜索树,它类似普通的二叉树,但是Btree允许每个节点有更多的子节点。Btree示意图如下:

在这里插入图片描述
由上图可知 Btree 的一些特点:

  1. 所有键值分布在整个树中
  2. 任何关键字出现且只出现在一个节点中
  3. 搜索有可能在非叶子节点结束
  4. 在关键字全集内做一次查找,性能逼近二分查找算法

B+tree

B+树是B树的变体,也是一种多路平衡查找树,B+树的示意图为:

在这里插入图片描述
由图可看出B+tree的特点 同时也是 Btree 和 B+tree的区别

  1. 所有关键字存储在叶子节点,非叶子节点不存储真正的data
  2. 为所有叶子节点增加了一个链指针 只有一个

在数据存储的索引结构上 Btree 更偏向于 纵向深度的存储数据 而 B+tree 更青睐于 横向广度的存储数据。

参考原址-(写的非常好)

MySQL主从复制原理

什么是mysql的主从复制?

MySQL 主从复制是指数据可以从一个MySQL数据库服务器主节点复制到一个或多个从节点。MySQL 默认采用异步复制方式,这样从节点不用一直访问主服务器来更新自己的数据,数据的更新可以在远程连接上进行,从节点可以复制主数据库中的所有数据库或者特定的数据库,或者特定的表。

mysql复制原理
  1. master服务器将数据的改变记录二进制binlog日志,当master上的数据发生改变时,则将其改变写入二进制日志中;
  2. slave服务器会在一定时间间隔内对master二进制日志进行探测其是否发生改变,如果发生改变,则开始一个I/OThread请求master二进制事件
  3. 同时主节点为每个I/O线程启动一个dump线程,用于向其发送二进制事件,并保存至从节点本地的中继日志中,从节点将启动SQL线程从中继日志中读取二进制日志,在本地重放,使得其数据和主节点的保持一致,最后I/OThread和SQLThread将进入睡眠状态,等待下一次被唤醒。

在这里插入图片描述

也就是说
  • 从库会生成两个线程,一个I/O线程,一个SQL线程;
  • I/O线程会去请求主库的binlog,并将得到的binlog写到本地的relay-log(中继日志)文件中;
  • 主库会生成一个log dump线程,用来给从库I/O线程传binlog;
  • SQL线程,会读取relay log文件中的日志,并解析成sql语句逐一执行;

主从复制原址

binlog日志

简介

mysql-binlog是MySQL数据库的二进制日志,用于记录用户对数据库操作的SQL语句((除了数据查询语句)信息。可以使用mysqlbin命令查看二进制日志的内容。

MySQL binlog格式

binlog的格式也有三种:STATEMENT、ROW、MIXED 。

  1. STATMENT模式:基于SQL语句的复制(statement-based replication, SBR),每一条会修改数据的sql语句会记录到binlog中。
  • 优点:不需要记录每一条SQL语句与每行的数据变化,这样子binlog的日志也会比较少,减少了磁盘IO,提高性能。
  • 缺点:在某些情况下会导致master-slave中的数据不一致(如sleep()函数, last_insert_id(),以及user-defined functions(udf)等会出现问题)
  1. 基于行的复制(row-based replication, RBR):不记录每一条SQL语句的上下文信息,仅需记录哪条数据被修改了,修改成了什么样子了。
  • 优点:不会出现某些特定情况下的存储过程、或function、或trigger的调用和触发无法被正确复制的问题。
  • 缺点:会产生大量的日志,尤其是alter table的时候会让日志暴涨。
  1. 混合模式复制(mixed-based replication, MBR):以上两种模式的混合使用,一般的复制使用STATEMENT模式保存binlog,对于STATEMENT模式无法复制的操作使用ROW模式保存binlog,MySQL会根据执行的SQL语句选择日志保存方式。
总结

无论是增量备份还是主从复制,都是需要开启mysql-binlog日志,最好跟数据目录设置到不同的磁盘分区,可以降低io等待,提升性能;并且在磁盘故障的时候可以利用mysql-binlog恢复数据。

mysql优化

Mysql优化综合性的问题:
  1. 表的是设计合理化(符合 3范式)
  2. 添加适当的索引(index)[四种:普通索引,主键索引,唯一索引,unique,全文索引]
  3. 分表技术(水平分割,垂直分割)
  4. 读写[写:update/delete/add]分离
  5. 存储过程[模块化编程,可以提高速度]
  6. 对mysql配置优化[配置最大并发数,my.ini调整缓存大小]
  7. Mysql服务器引荐升级
  8. 定时的去清楚不需要的数据,定时进行碎片整理

1. 数据库的表设计

  • 第一范式:1NF是对属性的原子性约束,要求属性(列)具有原子性,不可再分解;(只要是关系型数据库都满足1NF)
  • 第二范式:2NF是对记录的惟一性约束,要求记录有惟一标识,即实体的惟一性;
  • 第三范式:3NF是对字段冗余性的约束,它要求字段没有冗余。没有冗余的数据库设计可以做到。

2. 索引

  1. 主键索引
    当把一张表的某列设置为主键的时候,则该列就是主键索引。
  2. 唯一索引
    当表的某列被指定为unique约束时,这列就是唯一索引
  3. 普通索引
    一般来说,普通索引是先创建表,然后创建普通索引。
  4. 全文索引
    全文索引,主要是针对文件,比如文章的索引全文索引针对MyISAM有用,针对innodb没有用

3. 表的分割
水平分割:
大数据量的表,我们在提供检索的时候,应该根据业务的需求,找到表的标准,并在检索页面约束用户的检索方式,而且要配合分页,
案例:大数据量的用户表
三张表:A, B, C

create table A(

       id int unsigned not null primary key,/* 这个id不能设置自增长 */

       name varchar(32)not null default'',

       pwd varchar(32)not null default''

)engine = myisam default charset = utf8;


create table B(

        id int unsigned not null主键,/ *这个id不能设置自增长* /

        name varchar(32)not null default'',

        pwd varchar(32)not null default''

    )engine = myisam default charset = utf8;

create table C(

        id int unsigned not null主键,/ *这个id不能设置自增长* /

        name varchar(32)not null default'',

        pwd varchar(32)not null default''

    )engine = myisam default charset = utf8;
123456789101112131415161718192021222324252627282930

垂直分割:

把某个表的某些字段,这些字段,在查询时候并不关系,但是数据量很大,我们建议将这些字段放到一个表中,从而提高效率,

Mysql优化原文链接

在这里插入图片描述


Redis

简介

Redis(全称:Remote Dictionary Server 远程字典服务)是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。从2010年3月15日起,Redis的开发工作由VMware主持。从2013年5月开始,Redis的开发由Pivotal赞助。

Redis介绍

Redis 的优点 和 缺点

优点:

  • 数据类型多 上面有介绍

  • \1. 纯内存操作
    \2. 单线程避免上下文切换
    \3. 非阻塞IO多路复用机制

缺点
- 内存限制,不能用作海量数据

redis的五大数据类型实现原理

1. redis中所有数据结构都以唯一的key字符串作为名称,然后通过这个唯一的key来获取对应的value`
`2. 不同的数据类型数据结构差异就在于value的结构不一样

1. 字符串(string)

  • value的数据结构(数组)
  1. 字符串value数据结构类似于数组,采用与分配容易空间来减少内存频繁分配
  2. 当字符串长度小于1M时,扩容就是加倍现有空间
  3. 如果字符串长度操作1M时,扩容时最多扩容1M空间,字符串最大长度为 512M
  • 字符串的使用场景(缓存)
  1. 字符串一个常见的用途是缓存用户信息,我们将用户信息使用JSON序列化成字符串
  2. 取用户信息时会经过一次反序列化的过程

2. list(列表)

  • value的数据结构(双向链表)
  1. 列表的数据结构是双向链表,这意味着插入和删除的时间复杂度是0(1),索引的时间复杂度位0(n)
  2. 当列表弹出最后一个元素后,该数据结构会被自动删除,内存被回手
  • 列表的使用场景(队列、栈)

3. hash(字典)

  • value的数据结构(HashMap)
  1. redis中的字典也是HashMap(数组+列表)的二维结构
  2. 不同的是redis的字典的值只能是字符串
  • hash的使用场景(缓存)
  1. hash可以用来缓存用户信息,与字符串一次性全部序列化整个对象不同,hash可以对每个字段进行单独存储
  2. 这样可以部分获取用户信息,节约网络流量
  3. hash也有缺点,hash结构的存储消耗要高于单个字符串

4. set ( 集合对象 )

  • 集合对象 set 是 string 类型(整数也会转换成string类型进行存储)的无序集合。
  • 集合类型和列表类型的最大的区别是
    有序性 – > 列表有序
    唯一性 – > 集合唯一
  • 数据结构
    底层数据结构以intset或者hashtable来存储
  • 最多包含2^32-1元素。

5. Sorted set (有序集合对象)

  • 有序集合类型为集合中的每个元素都关联了一个分数
  • 数据结构
  1. 内部是以ziplist或者skiplist+hashtable来实现
    skiplist,也就是跳跃表
持久化方式

前言
由于Redis的数据都存放在内存中,如果没有配置持久化,redis重启后数据就全丢失了,于是需要开启redis的持久化功能,将数据保存到磁盘上,当redis重启后,可以从磁盘中恢复数据。redis提供两种方式进行持久化,一种是RDB持久化(原理是将Reids在内存中的数据库记录定时dump到磁盘上的RDB持久化),另外一种是AOF(append only file)持久化(原理是将Reids的操作日志以追加的方式写入文件)。

RDB:
RDB持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘,实际操作过程是fork一个子进程,先将数据集写入临时文件,写入成功后,再替换之前的文件,用二进制压缩存储。
在这里插入图片描述

AOF:
AOF持久化以日志的形式记录服务器所处理的每一个写、删除操作,查询操作不会记录,以文本的方式记录,可以打开文件看到详细的操作记录。
在这里插入图片描述

二者之间的优缺点

RDB的优势

  1. 一旦采用该方式,那么你的 整个Redis数据库将只包含一个文件,这对于文件备份而言是非常完美的。比如,你可能打算每个小时归档一次最近24小时的数据,同时还要每天归档一次最近30天的数据。通过这样的备份策略,一旦系统出现灾难性故障,我们可以非常容易的进行恢复。
  2. 对于灾难恢复而言,RDB是非常不错的选择。因为我们可以非常轻松的将一个单独的文件压缩后再转移到其它存储介质上
  3. 性能最大化。对于Redis的服务进程而言,在开始持久化时,它唯一需要做的只是 fork 出子进程,之后再由子进程完成这些持久化的工作,这样就可以极大的避免服务进程执行IO操作了。
  4. 相比于AOF机制,如果 数据集很大,RDB的启动效率会更高

RDB的劣势

  1. 如果你想保证数据的高可用性,即最大限度的避免数据丢失,那么RDB将不是一个很好的选择。因为系统一旦在定时持久化之前出现宕机现象,此前没有来得及写入磁盘的数据都将丢失
  2. 由于RDB是通过fork子进程来协助完成数据持久化工作的,因此,如果当数据集较大时,可能会导致整个服务器停止服务几百毫秒,甚至是1秒钟

AOF的优势

  1. 该机制可以带来更高的数据安全性,即数据持久性。Redis中提供了3种同步策略,即每秒同步、每修改同步和不同步。事实上,每秒同步也是异步完成的,其效率也是非常高的,所差的是一旦系统出现宕机现象,那么这一秒钟之内修改的数据将会丢失。而每修改同步,我们可以将其视为同步持久化,即每次发生的数据变化都会被立即记录到磁盘中。可以预见,这种方式在效率上是最低的。至于无同步,无需多言,我想大家都能正确的理解它。
  2. 由于该机制对日志文件的写入操作采用的是append模式,因此在写入过程中即使出现宕机现象,也不会破坏日志文件中已经存在的内容。然而如果我们本次操作只是写入了一半数据就出现了系统崩溃问题,不用担心,在Redis下一次启动之前,我们可以通过redis-check-aof工具来帮助我们解决数据一致性的问题。
  3. 如果日志过大,Redis可以自动启用rewrite机制。即Redis以append模式不断的将修改数据写入到老的磁盘文件中,同时Redis还会创建一个新的文件用于记录此期间有哪些修改命令被执行。因此在进行rewrite切换时可以更好的保证数据安全性。
  4. AOF包含一个格式清晰、易于理解的日志文件用于记录所有的修改操作。事实上,我们也可以通过该文件完成数据的重建。

AOF的劣势

  1. 对于相同数量的数据集而言,AOF文件通常要大于RDB文件。RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。
  2. 根据同步策略的不同,AOF在运行效率上往往会慢于RDB。总之,每秒同步策略的效率是比较高的,同步禁用策略的效率和RDB一样高效。

二者选择的标准,就是看系统是愿意牺牲一些性能,换取更高的缓存一致性(aof),还是愿意写操作频繁的时候,不启用备份来换取更高的性能,待手动运行save的时候,再做备份(rdb)。rdb这个就更有些 eventually consistent的意思了。

高级

redis有哪几种集群?`
`主从模式 哨兵模式 codis
Redis主从复制

主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点(master),后者称为从节点(slave),数据的复制是单向的,只能由主节点到从节点。

默认情况下,每台Redis服务器都是主节点;且一个主节点可以有多个从节点(或没有从节点),但一个从节点只能有一个主节点。
在这里插入图片描述

主从复制的作用
  1. 数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式。
  2. 故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复;实际上是一种服务的冗余。
  3. 负载均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务(即写Redis数据时应用连接主节点,读Redis数据时应用连接从节点),分担服务器负载;尤其是在写少读多的场景下,通过多个从节点分担读负载,可以大大提高Redis服务器的并发量。
  4. 读写分离:可以用于实现读写分离,主库写、从库读,读写分离不仅可以提高服务器的负载能力,同时可根据需求的变化,改变从库的数量;
  5. 高可用基石:除了上述作用以外,主从复制还是哨兵和集群能够实施的基础,因此说主从复制是Redis高可用的基础。
主从复制原理

主从复制过程大体可以分为3个阶段:连接建立阶段(即准备阶段)、数据同步阶段、命令传播阶段。

在从节点执行 slaveof 命令后,复制过程便开始运作,下面图示大概可以看到,
从图中可以看出复制过程大致分为6个过程

在这里插入图片描述
主从复制参考原址

主从同步
CPA原理
  1. CPA原理是分布式存储理论的基石: C(一致性); A(可用性); P(分区容忍性);
  2. 当主从网络无法连通时,修改操作无法同步到节点,所以“一致性”无法满足
  3. 除非我们牺牲“可用性”,也就是暂停分布式节点服务,不再提供修改数据功能,知道网络恢复
    一句话概括CAP: 当网络分区发生时,一致性 和 可用性 两难全
redis主从同步介绍
  1. 和MySQL主从复制的原因一样,Redis虽然读取写入的速度都特别快,但是也会产生读压力特别大的情况。
  2. 为了分担读压力,Redis支持主从复制,Redis的主从结构可以采用一主多从或者级联结构。
  3. Redis主从复制可以根据是否是全量分为全量同步和增量同步。
    注:redis主节点Master挂掉时,运维让从节点Slave接管(redis主从默认无法自动切换,需要运维手动切换)

在这里插入图片描述

redis主动同步机制

全量同步(快照同步)RDB

从服务器把有的数据全部丢弃,让主服务把所有数据全部发给他

注:Redis全量复制一般发生在Slave初始化阶段,这时Slave需要将Master上的所有数据都复制一份。具体步骤如下:
  1. 从服务器连接主服务器,发送SYNC命令;
  2. 主服务器接收到SYNC命名后,开始执行BGSAVE命令生成RDB文件并使用缓冲区记录此后执行的所有写命令;
  3. 主服务器BGSAVE执行完后,向所有从服务器发送快照文件,并在发送期间继续记录被执行的写命令;
  4. 从服务器收到快照文件后丢弃所有旧数据,载入收到的快照;
  5. 主服务器快照发送完毕后开始向从服务器发送缓冲区中的写命令;
  6. 从服务器完成对快照的载入,开始接收命令请求,并执行来自主服务器缓冲区的写命令;
  7. 完成上面几个步骤后就完成了从服务器数据初始化的所有操作,从服务器此时可以接收来自用户的读请求。

在这里插入图片描述

增量同步 AOF

全量同步:从服务器把有的数据全部丢弃,让主服务把所有数据全部发给他

  1. 主节点会将那些对自己状态产生修改性影响的指令记录在本地内存buffer中,然后异步将buffer中指令同步到从节点
  2. 从节点一边执行同步指令达到主节点状态,一边向主节点反馈自己同步到哪里(偏移量)
  3. 当网络状态不好时,从节点无法和主节点进行同步,当网络恢复时需要进行快照同步
Redis主从同步策略
  1. 主从刚刚连接的时候,进行全量同步;全同步结束后,进行增量同步。
  2. 当然,如果有需要,slave 在任何时候都可以发起全量同步。
  3. redis 策略是,无论如何,首先会尝试进行增量同步,如不成功,要求从机进行全量同步。
注意点
  1. 如果多个Slave断线了,需要重启的时候,因为只要Slave启动,就会发送sync请求和主机全量同步,当多个同时出现的时候,可能会导致Master IO剧增宕机。
  2. 不能自动切换master,所以master如果挂掉了,整个集群都不可以写入啦

Redis主从同步参考地址

哨兵

哨兵模式如何解决主从问题?

当用Redis做主从方案时,假如master宕机,Redis本身无法自动进行主备切换
而Redis-sentinel本身也是一个独立运行的进程,它能监控多个master-slave集群,发现master宕机后能进行自动切换。

哨兵是redis集群架构中非常重要的一个组件,主要功能如下:

  1. 集群监控,负责监控redis master 和slave进程是否正常工作。
  2. 消息通知,如果某个redis实例有故障,那么哨兵负责发送消息作为报警通知给管理员。
  3. 故障转移,如果master node挂掉了,会自动转移到slave node上。
  4. 配置中心,如果故障转移发生了,通知client客户端新的master地址。

哨兵本身也是分布式的,作为一个哨兵集群去运行的,相互协同工作

  1. 故障转移时,判断一个master node宕机了,需要大部分哨兵都同意才行,涉及到分布式选举问题。
  2. 及时部分哨兵节点挂掉了,哨兵集群还是能正常工作的,因为如果一个作为高可用机制重要组成部分的故障转移系统本身就是单点,那么就不靠谱。

哨兵的核心知识

  • 哨兵至少需要3个实例,来保证自己的健壮性。
  • 哨兵+redis主从的部署架构,是不会保证数据零丢失的,只能保证redis集群的高可用性
  • 对于哨兵+redis主从这种复杂的部署架构,尽量在测试环境和生产环境,都进行充分的测试和演练。
    哨兵详解

哨兵模式----sentinel

sentinel作用
  1. 当用Redis做主从方案时,假如master宕机,Redis本身无法自动进行主备切换
  2. 而Redis-sentinel本身也是一个独立运行的进程,它能监控多个master-slave集群,发现master宕机后能进行自动切换。
sentinel原理
  1. sentinel负责持续监控主节点的健康,当主节挂掉时,自动选择一个最优的从节点切换成主节点
  2. 从节点来连接集群时会首先连接sentinel,通过sentinel来查询主节点的地址
  3. 当主节点发生故障时,sentinel会将最新的主节点地址告诉客户端,可以实现无需重启自动切换redis
Sentinel支持集群
  1. 只使用单个sentinel进程来监控redis集群是不可靠的,当sentinel进程宕掉后sentinel本身也有单点问题
  2. 如果有多个sentinel,redis的客户端可以随意地连接任意一个sentinel来获得关于redis集群中的信息。
Sentinel版本
  1. Sentinel当前稳定版本称为Sentinel 2,Redis2.8和Redis3.0附带稳定的哨兵版本
  2. 安装完redis-3.2.8后,redis-3.2.8/src/redis-sentinel启动程序 redis-3.2.8/sentinel.conf是配置文件。
运行sentinel两种方式(效果相同)

法1:redis-sentinel /path/to/sentinel.conf
法2:redis-server /path/to/sentinel.conf --sentinel

  1. 以上两种方式,都必须指定一个sentinel的配置文件sentinel.conf,如果不指定,将无法启动sentinel。
  2. sentinel默认监听26379端口,所以运行前必须确定该端口没有被别的进程占用。
sentinel.conf配置文件说明
  1. 配置文件只需要配置master的信息就好啦,不用配置slave的信息,因为slave能够被自动检测到
  2. 需要注意的是,配置文件在sentinel运行期间是会被动态修改的,例如当发生主备切换时候,配置文件中的master会被修改为另外一个slave。
  3. 这样,之后sentinel如果重启时,就可以根据这个配置来恢复其之前所监控的redis集群的状态。
# sentinel.conf 配置说明
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 60000
sentinel failover-timeout mymaster 180000
sentinel parallel-syncs mymaster 1
12345
配置传播
  1. 一旦一个sentinel成功地对一个master进行了failover,它将会把关于master的最新配置通过广播形式通知其它sentinel,其它的sentinel则更新对应master的配置。
  2. 一个faiover要想被成功实行,sentinel必须能够向选为master的slave发送SLAVE OF NO ONE命令,然后能够通过INFO命令看到新master的配置信息。
  3. 当将一个slave选举为master并发送SLAVE OF NO ONE`后,即使其它的slave还没针对新master重新配置自己,failover也被认为是成功了的。

因为每一个配置都有一个版本号,所以以版本号最大的那个为标准:

  1. 假设有一个名为mymaster的地址为192.168.1.50:6379。
  2. 一开始,集群中所有的sentinel都知道这个地址,于是为mymaster的配置打上版本号1。
  3. 一段时候后mymaster死了,有一个sentinel被授权用版本号2对其进行failover。
  4. 如果failover成功了,假设地址改为了192.168.1.50:9000,此时配置的版本号为2
  5. 进行failover的sentinel会将新配置广播给其他的sentinel,发现新配置的版本号为2时,版本号变大了,说明配置更新了,于是就会采用最新的版本号为2的配置。
sentinel缺点

redis的slave和master数据时完全一样的,但是有个问题,redis数据时存储在内存中
内存空间有限,所以哨兵模式不能处理大的数据量

如何解决?codis

codis集群

简介

Codis 是一个分布式 Redis 解决方案, 对于上层的应用来说, 连接到 Codis Proxy 和连接原生的 Redis Server 没有明显的区别 (不支持的命令列表), 上层应用可以像使用单机的 Redis 一样使用, Codis 底层会处理请求的转发, 不停机的数据迁移等工作, 所有后边的一切事情, 对于前面的客户端来说是透明的, 可以简单的认为后边连接的是一个内存无限大的 Redis 服务.

codis是redis集群解决方案之一,codis是GO语言开发的代理中间件
当客户端向codis发送指令时,codis负责将指令转发给后面的redis实例来执行,并将返回结果转发给客户端

为什么会出现codis

  1. 在大数据高并发场景下,单个redis实例往往会无法应对
  2. 首先redis内存不易过大,内存太大会导致rdb文件过大,导致主从同步时间过长
  3. 其次在CPU利用率中上,单个redis实例只能利用单核,数据量太大,压力就会特别大

codis部署方案
\4. 单个codis代理支撑的QPS比较有限,通过启动多个codis代理可以显著增加整体QPS
\5. 多codis还能起到容灾功能,挂掉一个codis代理还有很多codis代理可以继续服务
在这里插入图片描述
codis分片的原理

  1. codis负责将特定key转发到特定redis实例,codis默认将所有key划分为1024个槽位
  2. 首先会对客户端传来的key进行crc32计算hash值,然后将hash后的整数值对1024进行取模,这个余数就是对应的key槽位
  3. 每个槽位都会唯一映射到后面的多个redis实例之一,codis会在内存中维护槽位和redis实例的映射关系
  4. 这样有了上面key对应的槽位,那么它应该转发到那个redis实例就很明确了
  5. 槽位数量默认是1024,如果集群中节点较多,建议将这个数值大一些,比如2048,4096

不同codis槽位如何同步

  1. 如果codis槽位值存在内存中,那么不同的codis实例间的槽位关系得不到同步
  2. 所以codis还需要一个分布式配置存储的数据库专门来持久化槽位关系
  3. codis将槽位关系存储在zookeeper中,并且提供一个dashboard可以来观察和修改槽位关系

布隆过滤器

布隆过滤器是什么?(判断某个key一定不存在)

  1. 本质上布隆过滤器是一种数据结构,比较巧妙的概率型数据结构
  2. 特点是高效地插入和查询,可以用来告诉你 “某样东西一定不存在或者可能存在”。
  3. 相比于传统的 List、Set、Map 等数据结构,它更高效、占用空间更少,但是缺点是其返回的结果是概率性的,而不是确切的。
    使用:
      1. 布隆过滤器在NoSQL数据库领域中应用的非常广泛
      2. 当用户来查询某一个row时,可以先通过内存中的布隆过滤器过滤掉大量不存在的row请求,然后去再磁盘进行查询
      3. 布隆过滤器说某个值不存在时,那肯定就是不存在,可以显著降低数据库IO请求数量

应用场景

  • 场景1(给用户推荐新闻)
  1. 当用户看过的新闻,肯定会被过滤掉,对于没有看多的新闻,可能会过滤极少的一部分(误判)。
  2. 这样可以完全保证推送给用户的新闻都是无重复的。
  • 场景2(爬虫url去重)
  1. 在爬虫系统中,我们需要对url去重,已经爬取的页面不再爬取
  2. 当url高达几千万时,如果一个集合去装下这些URL地址非常浪费空间
  3. 使用布隆过滤器可以大幅降低去重存储消耗,只不过也会使爬虫系统错过少量页面

布隆过滤器原理

  1. 每个布隆过滤器对应到Redis的数据结构是一个大型的数组和几个不一样的无偏hash函数
  2. 如下图:f、g、h就是这样的hash函数(无偏差指让hash映射到数组的位置比较随机)

添加:值到布隆过滤器
\1. 向布隆过滤器添加key,会使用 f、g、h hash函数对key算出一个整数索引,然后对长度取余
\2. 每个hash函数都会算出一个不同的位置,把算出的位置都设置成1就完成了布隆过滤器添加过程
查询:布隆过滤器值
\1. 当查询某个key时,先用hash函数算出一个整数索引,然后对长度取余
\2. 当你有一个不为1时肯定不存在这个key,当全部都为1时可能有这个key
\3. 这样内存中的布隆过滤器过滤掉大量不存在的row请求,然后去再磁盘进行查询,减少IO操作
删除:不支持
\1. 目前我们知道布隆过滤器可以支持 add 和 isExist 操作
\2. 如何解决这个问题,答案是计数删除,但是计数删除需要存储一个数值,而不是原先的 bit 位,会增大占用的内存大小。
\3. 增加一个值就是将对应索引槽上存储的值加一,删除则是减一,判断是否存在则是看值是否大于0。

在这里插入图片描述

redis事物与分布式锁

redis事物
  1. 严格意义来讲,Redis的事务和我们理解的传统数据库(如mysql)的事务是不一样的;
  2. Redis的事务实质上是命令的集合,在一个事务中要么所有命令都被执行,要么所有命令都不执行。

需要注意的是:
  1.Redis的事务没有关系数据库事务提供的回滚(rollback),所以开发者必须在事务执行失败后进行后续的处理;
  2.如果在一个事务中的命令出现错误,那么所有的命令都不会执行;
  3.如果在一个事务中出现运行错误,那么正确的命令会被执行。

redis事物介绍
  1. redis事物是可以一次执行多个命令,本质是一组命令的集合。
  2. 一个事务中的所有命令都会序列化,按顺序串行化的执行而不会被其他命令插入
    作用:一个队列中,一次性、顺序性、排他性的执行一系列命令
redis事物基本使用
  1. 下面指令演示了一个完整的事物过程,所有指令在exec前不执行,而是缓存在服务器的一个事物队列中
  2. 服务器一旦收到exec指令才开始执行事物队列,执行完毕后一次性返回所有结果
  3. 因为redis是单线程的,所以不必担心自己在执行队列是被打断,可以保证这样的“原子性”

注:redis事物在遇到指令失败后,后面的指令会继续执行
mysql的rollback与redis的discard的区别:

  1. mysql回滚为sql全部成功才执行,一条sql失败则全部失败,执行rollback后所有语句造成的影响消失
  2. redis的discard只是结束本次事务,正确命令造成的影响仍然还在.
> multi(开始一个redis事物)
incr books
incr books
> exec (执行事物)
> discard (丢弃事物)
12345
watch指令
  1. watch其实就是redis提供的一种乐观锁,可以解决并发修改问题

  2. watch会在事物开始前盯住一个或多个关键变量,当服务器收到exec指令要顺序执行缓存中的事物队列时

  3. redis会检查关键变量自watch后是否被修改(包括当前事物所在的客户端)

  4. 如果关键变量被人改动过,exec指令就会返回null回复告知客户端事物执行失败,这个时候客户端会选择重试
    注:redis禁用在multi和exec之间执行watch指令,必须在multi之前盯住关键变量,否则会出错

redis分布式锁

redis原子操作
  1. 原子操作是指不会被线程调度机制打断的操作
  2. 这种操作一旦开始,就会一直运行到结束,中间不会切换任何进程
分布式锁
  1. 分布式锁本质是占一个坑,当别的进程也要来占坑时发现已经被占,就会放弃或者稍后重试
  2. 占坑一般使用 setnx(set if not exists)指令,只允许一个客户端占坑
  3. 先来先占,用完了在调用del指令释放坑
> setnx lock:codehole true
.... do something critical ....
> del lock:codehole
123
  1. 但是这样有一个问题,如果逻辑执行到中间出现异常,可能导致del指令没有被调用,这样就会陷入死锁,锁永远无法释放
  2. 为了解决死锁问题,我们拿到锁时可以加上一个expire过期时间,这样即使出现异常,当到达过期时间也会自动释放锁
> setnx lock:codehole true
> expire lock:codehole 5
.... do something critical ....
> del lock:codehole
1234
  1. 这样又有一个问题,setnx和expire是两条指令而不是原子指令,如果两条指令之间进程挂掉依然会出现死锁
  2. 为了治理上面乱象,在redis 2.8中加入了set指令的扩展参数,使setnx和expire指令可以一起执行
> set lock:codehole true ex 5 nx
''' do something '''
> del lock:codehole 
123

redis雪崩&穿透&击穿

缓存穿透
  • 定义
  1. 缓存穿透是指查询一个一定不存在的数据,由于缓存不命中,接着查询数据库也无法查询出结果,
  2. 虽然也不会写入到缓存中,但是这将会导致每个查询都会去请求数据库,造成缓存穿透;
  • 解决方法 :布隆过滤
  1. 对所有可能查询的参数以hash形式存储,在控制层先进行校验,不符合则丢弃,从而避免了对底层存储系统的查询压力;
缓存雪崩
  • 定义
  1. 缓存雪崩是指,由于缓存层承载着大量请求,有效的保护了存储层,但是如果缓存层由于某些原因整体不能提供服务
  2. 于是所有的请求都会达到存储层,存储层的调用量会暴增,造成存储层也会挂掉的情况。
  • 解决方法
  1. 保证缓存层服务高可用性:比如 Redis Sentinel 和 Redis Cluster 都实现了高可用
  2. 依赖隔离组件为后端限流并降级:比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。
缓存击穿
  • 定义:
  1. 缓存击穿,就是说某个 key 非常热点,访问非常频繁,处于集中式高并发访问的情况
  2. 当这个 key 在失效的瞬间,大量的请求就击穿了缓存,直接请求数据库,就像是在一道屏障上凿开了一个洞。
  • 解决方法
  1. 解决方式也很简单,可以将热点数据设置为永远不过期;
  2. 或者基于 redis or zookeeper 实现互斥锁,等待第一个请求构建完缓存之后,再释放锁,进而其它请求才能通过该 key 访问数据

redis项目缓存实现

待补充


MongoDB

应用场景
  1. 更高的写入负载
  2. 高可用性
  3. 表结构不明确,且数据在不断变大
缺点
  1. 不能保证事务安全性
  2. 消耗内存大
MongoDB为什么快

写快:
写入数据存在在内存里就返回给应用程序,
而保存到硬体的操作则在后台异步完成


RabbitMQ

RabbitMQ使用场景
  1. 异步处理
  2. 应用解耦
  3. 流量削锋
  4. 日志处理:Kalfka消息中间件
RabbitMq与Redis队列对比
  1. 可靠消费
  2. 可靠发布
  3. 高可用
  4. 持久化

你可能感兴趣的:(mysql,redis,mongodb)