diff --git a/docs/mysql.md b/docs/mysql.md index 0a636dd..4df7771 100644 --- a/docs/mysql.md +++ b/docs/mysql.md @@ -99,7 +99,7 @@ MyISAM 提供了大量的特性,包括压缩表、空间数据索引等。 下面的语句可以将 mytable 表的引擎修改为 InnoDB ```sql -ALTER TABLE mytable ENGINE = InnoDB; +ALTER TABLE mytable ENGINE = InnoDB ``` ## 2. 数据类型 diff --git a/docs/redis/Redis面试题.md b/docs/redis/Redis面试题.md new file mode 100644 index 0000000..6752fc0 --- /dev/null +++ b/docs/redis/Redis面试题.md @@ -0,0 +1,137 @@ +# Redis 面试题 + + + +- [Redis 有什么数据类型?分别用于什么场景?](#redis-有什么数据类型分别用于什么场景) +- [Redis 的主从复制是如何实现的?](#redis-的主从复制是如何实现的) +- [Redis 的 key 是如何寻址的?](#redis-的-key-是如何寻址的) +- [Redis 的集群模式是如何实现的?](#redis-的集群模式是如何实现的) +- [Redis 如何实现分布式锁?ZooKeeper 如何实现分布式锁?比较二者优劣?](#redis-如何实现分布式锁zookeeper-如何实现分布式锁比较二者优劣) +- [Redis 的持久化方式?有什么优缺点?持久化实现原理?](#redis-的持久化方式有什么优缺点持久化实现原理) + - [RDB 快照(snapshot)](#rdb-快照snapshot) + - [AOF](#aof) + - [AOF 的原理](#aof-的原理) + - [AOF 的优点](#aof-的优点) + - [AOF 的缺点](#aof-的缺点) +- [Redis 过期策略有哪些?](#redis-过期策略有哪些) +- [Redis 和 Memcached 有什么区别?](#redis-和-memcached-有什么区别) +- [为什么单线程的 Redis 性能反而优于多线程的 Memcached?](#为什么单线程的-redis-性能反而优于多线程的-memcached) + + + +## Redis 有什么数据类型?分别用于什么场景? + +| 数据类型 | 可以存储的值 | 操作 | +| -------- | ---------------------- | ---------------------------------------------------------------------------------------------------------------- | +| STRING | 字符串、整数或者浮点数 | 对整个字符串或者字符串的其中一部分执行操作
对整数和浮点数执行自增或者自减操作 | +| LIST | 列表 | 从两端压入或者弹出元素
读取单个或者多个元素
进行修剪,只保留一个范围内的元素 | +| SET | 无序集合 | 添加、获取、移除单个元素
检查一个元素是否存在于集合中
计算交集、并集、差集
从集合里面随机获取元素 | +| HASH | 包含键值对的无序散列表 | 添加、获取、移除单个键值对
获取所有键值对
检查某个键是否存在 | +| ZSET | 有序集合 | 添加、获取、删除元素
根据分值范围或者成员来获取元素
计算一个键的排名 | + +> [What Redis data structures look like](https://redislabs.com/ebook/part-1-getting-started/chapter-1-getting-to-know-redis/1-2-what-redis-data-structures-look-like/) + +## Redis 的主从复制是如何实现的? + +## Redis 的 key 是如何寻址的? + +## Redis 的集群模式是如何实现的? + +## Redis 如何实现分布式锁?ZooKeeper 如何实现分布式锁?比较二者优劣? + +## Redis 的持久化方式?有什么优缺点?持久化实现原理? + +### RDB 快照(snapshot) + +将存在于某一时刻的所有数据都写入到硬盘中。 + +#### 快照的原理 + +在默认情况下,Redis 将数据库快照保存在名字为 dump.rdb 的二进制文件中。你可以对 Redis 进行设置, 让它在“N 秒内数据集至少有 M 个改动”这一条件被满足时, 自动保存一次数据集。你也可以通过调用 SAVE 或者 BGSAVE,手动让 Redis 进行数据集保存操作。这种持久化方式被称为快照。 + +当 Redis 需要保存 dump.rdb 文件时, 服务器执行以下操作: + +- Redis 创建一个子进程。 +- 子进程将数据集写入到一个临时快照文件中。 +- 当子进程完成对新快照文件的写入时,Redis 用新快照文件替换原来的快照文件,并删除旧的快照文件。 + +这种工作方式使得 Redis 可以从写时复制(copy-on-write)机制中获益。 + +#### 快照的优点 + +- 它保存了某个时间点的数据集,非常适用于数据集的备份。 +- 很方便传送到另一个远端数据中心或者亚马逊的 S3(可能加密),非常适用于灾难恢复。 +- 快照在保存 RDB 文件时父进程唯一需要做的就是 fork 出一个子进程,接下来的工作全部由子进程来做,父进程不需要再做其他 IO 操作,所以快照持久化方式可以最大化 redis 的性能。 +- 与 AOF 相比,在恢复大的数据集的时候,DB 方式会更快一些。 + +#### 快照的缺点 + +- 如果你希望在 redis 意外停止工作(例如电源中断)的情况下丢失的数据最少的话,那么快照不适合你。 +- 快照需要经常 fork 子进程来保存数据集到硬盘上。当数据集比较大的时候,fork 的过程是非常耗时的,可能会导致 Redis 在一些毫秒级内不能响应客户端的请求。 + +### AOF + +AOF 持久化方式记录每次对服务器执行的写操作。当服务器重启的时候会重新执行这些命令来恢复原始的数据。 + +### AOF 的原理 + +- Redis 创建一个子进程。 +- 子进程开始将新 AOF 文件的内容写入到临时文件。 +- 对于所有新执行的写入命令,父进程一边将它们累积到一个内存缓存中,一边将这些改动追加到现有 AOF 文件的末尾,这样样即使在重写的中途发生停机,现有的 AOF 文件也还是安全的。 +- 当子进程完成重写工作时,它给父进程发送一个信号,父进程在接收到信号之后,将内存缓存中的所有数据追加到新 AOF 文件的末尾。 +- 搞定!现在 Redis 原子地用新文件替换旧文件,之后所有命令都会直接追加到新 AOF 文件的末尾。 + +### AOF 的优点 + +- 使用默认的每秒 fsync 策略,Redis 的性能依然很好(fsync 是由后台线程进行处理的,主线程会尽力处理客户端请求),一旦出现故障,使用 AOF ,你最多丢失 1 秒的数据。 +- AOF 文件是一个只进行追加的日志文件,所以不需要写入 seek,即使由于某些原因(磁盘空间已满,写的过程中宕机等等)未执行完整的写入命令,你也也可使用 redis-check-aof 工具修复这些问题。 +- Redis 可以在 AOF 文件体积变得过大时,自动地在后台对 AOF 进行重写:重写后的新 AOF 文件包含了恢复当前数据集所需的最小命令集合。整个重写操作是绝对安全的。 +- AOF 文件有序地保存了对数据库执行的所有写入操作,这些写入操作以 Redis 协议的格式保存。因此 AOF 文件的内容非常容易被人读懂,对文件进行分析(parse)也很轻松。 + +### AOF 的缺点 + +- 对于相同的数据集来说,AOF 文件的体积通常要大于 RDB 文件的体积。 +- 根据所使用的 fsync 策略,AOF 的速度可能会慢于快照。在一般情况下,每秒 fsync 的性能依然非常高,而关闭 fsync 可以让 AOF 的速度和快照一样快,即使在高负荷之下也是如此。不过在处理巨大的写入载入时,快照可以提供更有保证的最大延迟时间(latency)。 + +## Redis 过期策略有哪些? + +- **noeviction** - 当内存使用达到阈值的时候,所有引起申请内存的命令会报错。 +- **allkeys-lru** - 在主键空间中,优先移除最近未使用的 key。 +- **allkeys-random** - 在主键空间中,随机移除某个 key。 +- **volatile-lru** - 在设置了过期时间的键空间中,优先移除最近未使用的 key。 +- **volatile-random** - 在设置了过期时间的键空间中,随机移除某个 key。 +- **volatile-ttl** - 在设置了过期时间的键空间中,具有更早过期时间的 key 优先移除。 + +## Redis 和 Memcached 有什么区别? + +两者都是非关系型内存键值数据库。有以下主要不同: + +**数据类型** + +- Memcached 仅支持字符串类型; +- 而 Redis 支持五种不同种类的数据类型,使得它可以更灵活地解决问题。 + +**数据持久化** + +- Memcached 不支持持久化; +- Redis 支持两种持久化策略:RDB 快照和 AOF 日志。 + +**分布式** + +- Memcached 不支持分布式,只能通过在客户端使用像一致性哈希这样的分布式算法来实现分布式存储,这种方式在存储和查询时都需要先在客户端计算一次数据所在的节点。 +- Redis Cluster 实现了分布式的支持。 + +**内存管理机制** + +- Memcached 将内存分割成特定长度的块来存储数据,以完全解决内存碎片的问题,但是这种方式会使得内存的利用率不高,例如块的大小为 128 bytes,只存储 100 bytes 的数据,那么剩下的 28 bytes 就浪费掉了。 +- 在 Redis 中,并不是所有数据都一直存储在内存中,可以将一些很久没用的 value 交换到磁盘。而 Memcached 的数据则会一直在内存中。 + +## 为什么单线程的 Redis 性能反而优于多线程的 Memcached? + +Redis 快速的原因: + +1. 绝大部分请求是纯粹的内存操作(非常快速) +2. 采用单线程,避免了不必要的上下文切换和竞争条件 +3. 非阻塞 IO + +内部实现采用 epoll,采用了 epoll+自己实现的简单的事件框架。epoll 中的读、写、关闭、连接都转化成了事件,然后利用 epoll 的多路复用特性,绝不在 io 上浪费一点时间。 diff --git a/docs/数据库面试题.md b/docs/数据库面试题.md index 5b04fd8..f42776b 100644 --- a/docs/数据库面试题.md +++ b/docs/数据库面试题.md @@ -1,54 +1,27 @@ # 数据库面试题 - + - [1. 存储引擎](#1-存储引擎) - [1.1. mysql 有哪些存储引擎?有什么区别?](#11-mysql-有哪些存储引擎有什么区别) - [2. 索引](#2-索引) - [2.1. 数据库索引有哪些数据结构?](#21-数据库索引有哪些数据结构) - - [2.1.1. B-Tree](#211-b-tree) - - [2.1.2. B+Tree](#212-btree) - - [2.1.3. Hash](#213-hash) - [2.2. B-Tree 和 B+Tree 有什么区别?](#22-b-tree-和-btree-有什么区别) - [2.3. 索引原则有哪些?](#23-索引原则有哪些) - - [2.3.1. 独立的列](#231-独立的列) - - [2.3.2. 前缀索引和索引选择性](#232-前缀索引和索引选择性) - - [2.3.3. 多列索引](#233-多列索引) - - [2.3.4. 选择合适的索引列顺序](#234-选择合适的索引列顺序) - - [2.3.5. 聚簇索引](#235-聚簇索引) - - [2.3.6. 覆盖索引](#236-覆盖索引) - - [2.3.7. 使用索引扫描来做排序](#237-使用索引扫描来做排序) - - [2.3.8. = 和 in 可以乱序](#238--和-in-可以乱序) - - [2.3.9. 尽量的扩展索引,不要新建索引](#239-尽量的扩展索引不要新建索引) - [3. 事务](#3-事务) - [3.1. 数据库事务隔离级别?事务隔离级别分别解决什么问题?](#31-数据库事务隔离级别事务隔离级别分别解决什么问题) - [3.2. 如何解决分布式事务?若出现网络问题或宕机问题,如何解决?](#32-如何解决分布式事务若出现网络问题或宕机问题如何解决) - [4. 锁](#4-锁) - [4.1. 数据库锁有哪些类型?如何实现?](#41-数据库锁有哪些类型如何实现) - - [4.1.1. 锁粒度](#411-锁粒度) - - [4.1.2. 读写锁](#412-读写锁) - - [4.1.3. 意向锁](#413-意向锁) - [5. 分库分表](#5-分库分表) - [5.1. 为什么要分库分表?](#51-为什么要分库分表) - [5.2. 分库分表的常见问题以及解决方案?](#52-分库分表的常见问题以及解决方案) - - [5.2.1. 事务问题](#521-事务问题) - - [5.2.2. 跨节点 Join 的问题](#522-跨节点-join-的问题) - - [5.2.3. 跨节点的 count,order by,group by 以及聚合函数问题](#523-跨节点的-countorder-bygroup-by-以及聚合函数问题) - - [5.2.4. ID 唯一性](#524-id-唯一性) - - [5.2.5. 数据迁移,容量规划,扩容等问题](#525-数据迁移容量规划扩容等问题) - - [5.2.6. 分库数量](#526-分库数量) - - [5.2.7. 跨分片的排序分页](#527-跨分片的排序分页) - [5.3. 如何设计可以动态扩容缩容的分库分表方案?](#53-如何设计可以动态扩容缩容的分库分表方案) - [5.4. 有哪些分库分表中间件?各自有什么优缺点?底层实现原理?](#54-有哪些分库分表中间件各自有什么优缺点底层实现原理) - - [简单易用的组件:](#简单易用的组件) - - [强悍重量级的中间件:](#强悍重量级的中间件) - [6. 数据库优化](#6-数据库优化) - [6.1. 什么是执行计划?](#61-什么是执行计划) - [7. 数据库架构设计](#7-数据库架构设计) - [7.1. 高并发系统数据层面如何设计?](#71-高并发系统数据层面如何设计) - - [读写分离的原理](#读写分离的原理) - - [垂直切分](#垂直切分) - - [水平切分](#水平切分) @@ -423,4 +396,7 @@ Mysql 支持两种复制:基于行的复制和基于语句的复制。 - 哈希取模:hash(key) % NUM_DB - 范围:可以是 ID 范围也可以是时间范围 -- 映射表:使用单独的一个数据库来存储映射关系 \ No newline at end of file +- 映射表:使用单独的一个数据库来存储映射关系 + +---- +