文章目录
如果说,学习知识就像遍历一个巨大的图一样,那么必然有深度优先遍历和广度优先遍历,本文大概属于广度优先遍历,相关知识点点到即止。文末的链接里的文章是更为详细的内容,代表着这些知识点的子结点。
1 数据库相关知识总结
1.2 MySQL数据库
1.2.1 索引有哪些?
按照底层数据结构分为:
-
B+ 树索引,如InnoDB 引擎里的聚簇索引,每个节点都是页,叶子节点存放记录,非叶子节点存放的是主键和页编号的映射,每个页采用槽+单向链表的方式组织,页与页之间是双向链表。
-
Hash索引,如InnoDB 会在频繁使用的索引上自动创建hash索引以提高速度,其采用除法散列函数,冲突机制采用拉链法。
-
MyISAM引擎不支持事务,数据和索引是分开存储的。
-
位图索引,非常适合在
性别,婚姻状况
这样自由度/删选能力很低的字段上建立。 -
B*树索引是B+树索引的进一步演变,不仅叶子节点使用指针连接起来,中间结点也使用指针连接起来。
-
R树空间索引是B树在高纬空间的扩展,基于R树数据结构,解决了高纬空间搜索问题,R+树空间索引允许矩形重叠,MyISAM支持,主要用于GIS数据。
-
倒排索引,搜索引擎常用,其结构是key-value,key是关键词,value是文档ID[和频率]。
-
前缀树索引,百度搜索框自动提示应该用的就是这个,可以快速地从巨大的数据中查询出目标前缀字符串。
-
全文索引,MyISAM和InnoDB(5.6以上)均可以支持。
按照聚簇索引和非聚簇索引分为:
-
聚簇索引
-
二级索引
- 联合索引
按照应用层面(逻辑)分:
- 主键索引,不允许空值,看做特殊的唯一索引
- 唯一索引,允许空值
- 多列索引
- 普通索引
- 空间索引,仅MyISAM支持,猜测底层 就是R树
B+ 树索引的结构是什么样的?
- 每个节点都是数据页(tablespace表空间,segment段,extent区, page页,row记录),默认大小16k,非叶子节点的仅仅存储数据索引,叶子结点如果是聚簇索引,则会存放数据记录,如果是非聚簇索引,则仅仅存放主键。
1.2.2 MyISAM 和 InnoDB有什么不同?
- 一般说MyISAM比InnoDB查询快,因为其数据和索引是分开的,数据是顺序存放的通过offset可以快速找到数据,另外MyISAM比较简单,因此快。
- MyISAM不支持事务,只支持表级锁,不支持外键,崩溃无法安全恢复数据,不持之MVCC。
1.2.3 MySQL 有哪些锁?
按照锁的粒度分:
- 表级锁
- 页级锁
- 行级锁 (innodb还有间隙锁Gap-lock, 用于锁定一个范围)
按照锁的级别 :
- 共享锁(读锁,事务自动加,也可以显示声明: SELECT … LOCK IN SHARE MODE)
- 排它锁(写锁,更新操作时会给涉及的数据自动加,也可显示声明:SELECT … FOR UPDATE)
- 意向锁(用户不可感知)
1.2.4 有哪些隔离级别
- 读取未提交:丢失修改,脏读(ABBA,对B来说脏读且丢失修改,ABAB对B是脏读,对A是丢失修改),不可重复度,幻读
- 读取已提交:不可重复读,幻读
- 可重复读:幻读 (MySQL默认的事务隔离级别)
- 可串行化:事务依次逐个执行,不存在上述四个问题
1.2.5 如何解决脏读,不可重复读和幻读
-
解决脏读: 更新时加写锁(排它锁),查询时加读锁(共享锁),只允许同时读操作。
-
解决不可重复读: MVCC (多版本并发控制),mvcc为没条数据增加了隐藏的两列(创建版本号和删除版本号)。
-
解决幻读:基于next-key锁(记录锁+ 间隙锁 就是在索引和索引之间上面加锁)和 基于MVCC的快照读(所有其他事物增加与删除数据对于当前事务不可见)。
1.2.6 什么是悲观锁乐观锁
-
悲观锁包括共享锁和排它锁。
-
乐观锁在事务进行到提交阶段通过版本判断是否冲突,返回错误信息让用户自己处理。
1.2.7 undo日志和redo日志的作用
-
undo日志用于事务回滚,记录数据修改前的原版数据。
-
redo日志用于解决服务器崩溃等问题造成的缓存buffer和硬盘持久化数据的不一致性,两阶段提交。
-
两者都有缓存,崩溃恢复时,先恢复redo日志,再恢复undo日志(数据回滚时的日志也会写入redo)。
-
undo日志位于共享表空间。
## 日志记录过程简化后看是这样的 A.事务开始. B.记录A=1到undo log. C.修改A=3. D.记录A=3到redo log. E.记录B=2到undo log. F.修改B=4. G.记录B=4到redo log. H.将redo log写入磁盘。 I.事务提交
-
此外还有binlog(二进制归档日志),用于主从复制。
-
日志都是顺序写的,通常磁盘顺序写的性能是很好的。
1.2.8 简单易答的SQL优化方案
-
总体来说有四个优化方向(越往下收益越小,成本越高)
- SQL及索引
- 数据库表结构
- 系统配置
- 硬件
-
主要说SQL及索引的方案
- 少用*,减少数据库服务解析代价,增加索引覆盖的可能性,减少网络带宽占用。
- 少用 like、union、or、!= 关键字。
- where限定语句限定效果好的放在前面。
- 特定情况下用子查询代替连接操作。
- 少对字段进行null判断。
- in,not in慎用。
- where条件语句里少用运算。
-
MySQL不会命中索引的情况
- 负向查询都不会命中索引: NOT IN,NOT LIKE,NOT EXTSTS
- 用like查询的话,%在右边会命中索引的,而%在左边则不会,单不绝对
- or条件查询时,如果每一个条件都有索引(单列的那种)时,会命中索引,各个字段在一个联合索引里无法命中
- 如果列类型是字符串,那一定要在条件中将数据使用引号引用起来,否则不命中索引
- 在where字句中使用类似于
age - 1 = 19
的计算不命中索引,除非建立了函数索引 - B-tree 索引 is null 不会走, is not null 会走,位图索引都会走索引
- 没建立索引或者没使用where子句不会命中索引
- 查询的数量是大部分,如30%以上,则会扫描表而不是走索引
- 对小表的查询
> <
有时会命中索引,有些情况下不会- 单独引用联合索引中非第一列的情况,
index(name,age,weight)
相当于附赠了index(name,age)
,index(name)
两个索引
-
EXPLAIN
关键字加在查询前面如explain select actor_id from actor order by actor_id
可打印一些SQL解系信息,用于分析索引命中等等。 -
MySQL索引命中规则
- 最左匹配原则: where字句的条件分等值条件和范围条件,等值条件依次命中索引中最左边的字段,然后依次向右命中,范围放在最后。
1.2.9 数据库范式
-
1NF 每一列都是不可再分的
-
2NF 每一条记录都是和主键相关的(在1NF的基础上消除非主属性之间的传递依赖)
-
3NF 每一条记录都和主键直接相关(在2NF的基础上消除传递依赖)
-
BCNF 消除某一列与复合主键某一列相关,而与其他主键列无关(消除主键间的传递依赖)
-
4NF 非主属性不应该有多值
-
5NF 终极范式,极力消除冗余
1.3 Redis 数据库
-
Redis有哪些数据类型?
- String: Redis不使用C语言的String而是自己实现了CDS,CDS在头部存储了长度信息,空间分配机制更高效
- Hash: 和Java的Hash类似,拉链发解决冲突,初始空间为4,2倍扩容,扩容需要rehash,缩容发生在占用10%时。
- List:双向链表实现;quicklist实现,类似于B树,节点存放多个值,且使用双向链表指针连接节点;3.2版本之前有ziplist(压缩列表)实现,省内存但是查询效率差;
- Set: hash和intSet两种实现,前者和Java类似,Java中HashSet使用HashMap实现,后者维护一个int数组,有序存放
- SortedSet(zset): 跳跃表
-
除此之外Redis还有哪些数据类型?
- Pub/Sub,如字面意思,可以往此类型key写数据,则订阅了该key的客户端会收到消息,接收消息是阻塞的。
- Bitmaps
- HyperLogLog,HyperLogLog算法用一个固定长度的字节统计流数据的基数,有2^14方个桶
-
Redis怎么实现分布式锁的?
- 题外话,除了redis实现,还可以zookeeper实现,DB锁实现(乐观锁,悲观锁)
- 如果用php的redis、Jedis客户端,可以使用setnx来加锁,mutil-exce来解锁
- 这种分布式锁需要超时时间、key-value验证value才能解锁
- 加锁setnx并同时指定超时时间,具有原子性,锁已存在的情况下自旋等待
- 解锁判断value和事务传入的是否匹配,匹配才能完成解锁,通过Lua批量执行事项原子性
- 获取锁(unique_value可以是UUID等) SET resource_name unique_value NX PX 30000 - 释放锁(lua脚本中,一定要比较value,防止误解锁) if redis.call("get",KEYS[1]) == ARGV[1] then return redis.call("del",KEYS[1]) else return 0 end
-
如果使用Redissson客户端,则直接调用接口即可,此外该客户端还支持更丰富的锁,其底层实现暂未研究
-
后来的Redis原生支持了分布式锁,Redlock(Redis Distributed Lock),依赖多个Redis,是真正意义上的分布
1.3.1 Redis 集群
-
Redis高可用模型
- Redis主从模型,主写,从获得同步,可一主多从,读写分离
- Redis-Sentinel哨兵模型,通过一个独立的哨兵来监控主节点,哨兵通过发送命令,等待Redis服务器响应,从而监控运行的多个Redis实例,Master宕机,则可以把slave切换成master
- Redis-Cluster 集群模型,Redis 3.0之后支持的,是一种无中心的集群(其实这样的集群挺常见的,zookeeper也是这样的集群,差异可能在于选举算法上)
-
Redis的Cluster需要客户端支持,如php的redis扩展不支持cluster,而predis支持,无论是Redission(题外话,这个真的很强大)还是predis都需要在客户端配置及群里的全部redis连接(没有中心,考虑到任何一个master都可能宕机)。
-
集群的架构如上图所示,集群节点之间两两通过gossip协议交换信息,是去中心化的协调
-
节点间分区容错,分区的方法和一致性Hash算法基本一样,有2^14个槽,根据集群结点数目把槽分成多个段
1.4 Hadoop相关
1.4.1 HDFS
- 全程Hadoop Distribute File System
- 特点:
- 存储非常大的文件,百度云的HDFS集群有约10万台主机,具备PB级别的存储能力。
- 采用流式数据访问方式,采用append-only的方式写入数据,吞吐量大,但是延时较高。
- 对硬件不敏感,即不需要特别贵的、可靠的机器。
- 不适合存储大量的小文件,因为一个文件/目录/文件块占150字节的元数据空间,如果有100万个文件,则需要大约300M的内存。
- 不适合多方读写,需要任意修改文件的场景,不支持文件任意offset的修改,不支持多个写入器(writer)。
- 物理磁盘的扇区通常为512byte,为什么HDFS的Block大至128M?
- 为了最小化查找(seek)时间。
- HDFS集群组成
- HDFS集群由Namenode和Datanode组成,构成了master-worker模式。
- Namenode负责构建命名空间,管理元数据等,而Datanode负责实际数据存储,负责读写工作。
- 为避免Namenode的单点问题,有两个措施,持久化元数据和Secondary Namenode。
1.4.2 Hadoop
- 核心部件
- HDFS: 分布式文件存储(GFS的一个实现?)
- MapReduce: 分布式计算
- YARN: 分布式资源管理
- Others: 利用YARN的资源管理功能实现其他的数据处理方式
1.4.3 MapReduce
-
定义: MapReduce是一个面向大数据的高性能的并行计算平台/框架/方法, 其借鉴了函数式编程语言的设计思想,方便我们编写并行算法,其本质就是分治算法。
-
应用场景如:有1TB数据,如何建立倒排索引?如何排序?
-
MapReduce的工作过程:
- 打个比方
- 举个栗子:统计词频率
- 举个栗子: 建立倒排索引
Spark、Hive、Hbase、Flink、Kafka
- 简言之:这些都大数据相关的东西
- Spark比较流行,是基于内存计算的大数据并行计算框架,Spark-Streaming可做高吞吐率的实时计算。
- Hive是基于Hadoop的数据仓库工具,可将结构化的数据映射为数据库表,提供简单的sql查询(可以说Hive是类SQL引擎),将SQL转化为MapReduce,数据不支持更新操作。
- Hbase是基于Hadoop的数据库,key-value数据库,是一个分布式、可扩展、大数据的存储库,不能兼容所有的ACID特性,需要分布式协调zookeeper来协调。
- Flink最近非常火,和Hive,Spark, MapReduce的角色相同,能进行流处理和批处理分布式计算
- Kafka是一个分布式的高性能的消息队列中间件,我们通常拿来跟RocketMQ,RabbitMQ比较。其又一个流式处理Kafka Streams是一个用于构建流式处理的客户端,其输入输出都在Kafka集群中。
1.4.4 有哪些流式大数据处理框架?
- Storm
- Trident
- Spark Streaming
- Flink
产品 | 模型 | API | 保证次数 | 容错机制 | 状态管理 | 延时 | 吞吐量 |
---|---|---|---|---|---|---|---|
Storm | Native(数据进入立即处理) | 组合式(基础API) | At-least-once (至少一次) | Record ACK(ACK机制) | 无 | 低 | 低 |
Trident | Micro-Batching(划分为小批 处理) | 组合式 | Exactly-once (仅一次) | Record ACK | 基于操作(每次操作有一个状态) | 中等 | 中等 |
Spark Streaming | Micro-Batching | 声明式(提供封装后的高阶函数,如count函数) | Exactly-once | RDD CheckPoint(基于RDD做CheckPoint) | 基于DStream | 中等 | 高 |
Flink | Native | 声明式 | Exactly-once | CheckPoint(Flink的一种快照) | 基于操作 | 低 | 高 |
注: 本人2020年秋招面试了几个数据开发岗: ClickHouse 和 Flink 几乎是必问的内容
1.5 OLTP和OLAP
- OnLine Transaction Processing,数据库,有事务,追求一致性
- OnLine Access Processing,数据仓库,无事务,追求能快速查能计算
- 也就是上文中Hbase属于OLTP,Hive、Spark等属于OLAP
1.6 mongoDB 数据库
1.6.1 在什么场景下用它
-
和Hbase角色相同,是OLTP,不过不支持事务,因此不适合用在银行会计场合。
-
有数据量大,高伸缩性需求,适合实时的插入更新和查询。
-
文档型数据,尤其是字段多结构复杂的json数据,mongo的BSON。
-
性能高,做缓存基础设施,能在一定程度上干Redis的事情。
1.6.2 市场萎缩了?
- 笔者感觉市场有一定的萎缩,不过应该较受Nodejs、PHP和Ruby技术栈人员喜爱。
- 如果追求数据量较大,且可靠,用Cassandra,用MySQL+MyCat,用兼容MySQL的大型的开源的关系型数据库如 tiDB, Cubrid。
- 如果追求高性能的数据分析,Hbase家族得天独厚。
2 分布式系统理论
2.1 什么是强一致性弱一致性
- 一致性分为数据一致性和事务一致性,后者就是ACID里的一致性。
- 数据复制是导致数据一致性问题的唯一原因。
- 强一致性又称为线性一致性,数据复制过程是同步的。
- 除了强一致性,其他一致性都是弱一致性,弱一致性的数据复制是异步的。
- 强一致性结构中,主库宕机时从库的数据是完整的,但是如果从库阻塞或宕机,则主库就无法完成写入操作。
- 最终一致性,从库的数据是异步更新的,等一段时间之后会和主库保持一致。
2.2 CAP理论
- CAP理论指的是一个分布式系统最多只能同时满足一致性(Consistency)、可用性(Availability)和分区容错性(Partition tolerance)这三项中的两项。拿一个网上的图来看看。
- 这里的一致性是强一致性。
- 可用性可以理解为性能好,不阻塞。
- 分区容错性指的是数据在不同节点上有备份容易,避免单点故障。
- 如果只能取两个,通常一定会取分区容错性P,不然有违设计初衷,大型系统性能必须优于单机,因此性能要好,因此很多时候会采用AP。
- 分布式事务要做到的就是保证AP,然后尽可能保证C,通常是通过柔性事务实现最终一致性。
- TCC操作:Try阶段,尝试执行业务,完成所有业务的检查,实现一致性;预留必须的业务资源,实现准隔离性。Confirm阶段:真正的去执行业务,不做任何检查,仅适用Try阶段预留的业务资源,Confirm操作还要满足幂等性。Cancel阶段:取消执行业务,释放Try阶段预留的业务资源,Cancel操作要满足幂等性。TCC与2PC(两阶段提交)协议的区别:TCC位于业务服务层而不是资源层,TCC没有单独准备阶段,Try操作兼备资源操作与准备的能力,TCC中Try操作可以灵活的选择业务资源,锁定粒度。TCC的开发成本比2PC高。实际上TCC也属于两阶段操作,但是TCC不等同于2PC操作。
2.3 分布式事务的三种常见解决方案
- 基于可靠消息的最终一致性方案
- 实现:业务处理服务在业务事务提交之前,向实时消息服务请求发送消息,实时消息服务只记录消息数据,而不是真正的发送。业务处理服务在业务事务提交之后,向实时消息服务确认发送。只有在得到确认发送指令后,实时消息服务才会真正发送。
- 消息:业务处理服务在业务事务回滚后,向实时消息服务取消发送。消息发送状态确认系统定期找到未确认发送或者回滚发送的消息,向业务处理服务询问消息状态,业务处理服务根据消息ID或者消息内容确认该消息是否有效。被动方的处理结果不会影响主动方的处理结果,被动方的消息处理操作是幂等操作。
- 成本:可靠的消息系统建设成本,一次消息发送需要两次请求,业务处理服务需要实现消息状态回查接口。
- 优点:消息数据独立存储,独立伸缩,降低业务系统和消息系统之间的耦合。对最终一致性时间敏感度较高,降低业务被动方的实现成本。兼容所有实现JMS标准的MQ中间件,确保业务数据可靠的前提下,实现业务的最终一致性,理想状态下是准实时的一致性。
-
TCC事务补偿型方案
- 实现:一个完整的业务活动由一个主业务服务于若干的从业务服务组成。主业务服务负责发起并完成整个业务活动。从业务服务提供TCC型业务操作。业务活动管理器控制业务活动的一致性,它登记业务活动的操作,并在业务活动提交时确认所有的TCC型操作的Confirm操作,在业务活动取消时调用所有TCC型操作的Cancel操作。
- 成本:实现TCC操作的成本较高,业务活动结束的时候Confirm和Cancel操作的执行成本。业务活动的日志成本。
- 使用范围:强隔离性,严格一致性要求的业务活动。适用于执行时间较短的业务,比如处理账户或者收费等等。
- 特点:不与具体的服务框架耦合,位于业务服务层,而不是资源层,可以灵活的选择业务资源的锁定粒度。TCC里对每个服务资源操作的是本地事务,数据被锁住的时间短,可扩展性好,可以说是为独立部署的SOA服务而设计的。
-
最大努力通知型
-
实现:业务活动的主动方在完成处理之后向业务活动的被动方发送消息,允许消息丢失。业务活动的被动方根据定时策略,向业务活动的主动方查询,恢复丢失的业务消息。
-
约束:被动方的处理结果不影响主动方的处理结果。
-
成本:业务查询与校对系统的建设成本。
-
使用范围:对业务最终一致性的时间敏感度低。跨企业的业务活动。
-
特点:业务活动的主动方在完成业务处理之后,向业务活动的被动方发送通知消息。主动方可以设置时间阶梯通知规则,在通知失败后按规则重复通知,知道通知N次后不再通知。主动方提供校对查询接口给被动方按需校对查询,用户恢复丢失的业务消息。
-
适用范围:银行通知,商户通知。
-
2.4 一致性Hash算法
-
一致性hash算法的性质
- 平衡性:尽可能保证所有的缓冲空间得以被利用
- 单调性:结点数目发生变化,无需全部重新hash
- 分散性:分散性应当尽量降低,尽量避免相同的内容被分散到不同结点
- 负载: 和分散性讲的是同样的问题
- 平滑性:服务器节点数平滑改变对应的缓存对象也平滑改变
-
如何一致性?如下图,如果某个结点宕机,则数据被hash到下一个结点。
- 引入虚拟节点来解决不平衡问题
2.5 服务降级、限流和熔断
-
什么是微服务的雪崩效应?
- 在微服务架构中,微服务是完成一个单一的业务功能,这样做的好处是可以做到解耦,每个微服务可以独立演进。但是,一个应用可能会有多个微服务组成,微服务之间的数据交互通过远程过程调用完成。这就带来一个问题,假设微服务A调用微服务B和微服务C,微服务B和微服务C又调用其它的微服务,这就是所谓的“扇出”。如果扇出的链路上某个微服务的调用响应时间过长或者不可用,对微服务A的调用就会占用越来越多的系统资源,进而引起系统崩溃,所谓的“雪崩效应”。
-
什么是服务降级?
- 服务降级有很多种降级方式!如开关降级、限流降级、熔断降级!
-
怎么降级?
- 简化执行流程,如蚂蚁森林只返回最近100天的日志,而不是特别多的内容。
- 关闭次要功能,如一个实时系统面临高负载,暂时关闭报表功能。
- 降低一致性,即将核心业务流程的同步改异步,将强一致性改最终一致性!
-
什么是熔断?
- 这个概念很好理解,比如电流过大或者短路就会熔断,避免电路大面积烧毁,股市暴跌之后停止交易,避免过大亏损。在微服务中熔断的作用就是避免雪崩发生,当某个服务长时间不能正常响应时,对其熔断,不再使用,快速返回,释放资源。
-
在Spring Cloud框架里,熔断机制通过Hystrix实现。Hystrix会监控微服务间调用的状况,当失败的调用到一定阈值,缺省是5秒内20次调用失败,就会启动熔断机制,5s之后再判断是否符合解除熔断条件。阿里出的Sentinel也是熔断实现方案。
-
如何限流降级?
- 令牌桶方法:以固定速率生成令牌,每个请求获得令牌消费了令牌才能通过过滤得到服务。
- 漏桶算法:有一个固定容量的漏桶(请求缓冲区),溢出则丢弃,漏桶里的请求消费速率是固定的。
3 友情链接:
[1] 知乎:MySQL 索引
[3] 什么是乐观锁,悲观锁
[4] 通俗易懂 强一致性、弱一致性、最终一致性、读写一致性、单调读、因果一致性 的区别与联系
[5] CAP理论
[6] 分布式事务中常见的三种解决方案
[8] undo日志和redo日志
[9] MySQL日志系统:redo log、binlog、undo log 区别与作用
[10] MySQL Innodb 数据页结构分析
[11] 一条SQL语句在MySQL中是如何执行的
[12] SQL语句优化分析
[13] 史上最全SQL优化方案
[14] 必须掌握的30种SQL语句优化
[15] 数据库设计三大范式
[16] 数据库设计六大范式
[17] 单点故障与分布式锁
[18] 一致性Hash算法
[19] Elasticsearch如何做到亿级数据查询毫秒级返回?
[20] MySQL索引类型都有哪些?
[21] MySQL中不会命中索引的情况
[22] MySQL索引命中规则
[23] 关系型数据库大数据解决方案OLTP
[24] 数据库常见索引解析(B树,B-树,B+树,B*树,位图索引,Hash索引)
[25] 服务降级和限流
[26] 谈谈服务雪崩、降级与熔断
[27] 高并发系统限流-漏桶算法和令牌桶算法
[28] Redis的Hash实现详解
[29] Redis源码走马观花(5)HyperLogLog
[31] Redis集合set底层原理
[32] Hadoop教程
[34] 【Spark】Spark基础教程
[35] Spark Streaming简介及原理
[36] 阿里巴巴主推的 Flink 为什么火?
[37] 用Redis构建分布式锁-RedLock(真分布)
[38] redis分布式锁的安全性探讨(二):分布式锁Redlock
[40] springboot2.0集成redisson搭建redis-cluster集群模式开发
[41] redis cluster介绍
[42] Kafka流式处理
[43] mysql索引之一:索引基础(B-Tree索引、哈希索引、聚簇索引、全文(Full-text)索引区别)(唯一索引、最左前缀索引、前缀索引、多列索引)
[44] HBase、MongoDB、cassandra比较
[45] 关系型数据库大数据解决方案OLTP