第五篇:数据存储(Mysql、Redis、MongoDB)

目录

一. MySQL

1. 数据库三大范式是什么?

2. MyISAM和InnoDB存储引擎的区别?

3. 什么是MVCC?有什么作用?怎么实现的? 

4. 什么字段适合作为索引?

5. 索引的结构有哪些?

6. 为什么数据库主要使用B+树?B树和B+树有什么区别?

7. hash存储结构和B+树存储结构有什么优劣?

8. B+树的具体实现是什么样的?

9. 联合索引在B+树中怎么存储?

10. 最左匹配原则

11. 百万级的数据怎么删除

12. 什么是数据库事务?事务的四大特性ACID介绍一下

13. 什么是脏读、不可重复读、幻读?

14. 事务的隔离级别?怎么实现的(加了什么锁)?MySQL默认的隔离级别是什么?

15. 数据库的行锁和表锁是怎么实现的?

16.  如何定位sql语句的性能问题?如何解决?

17. 超大分页怎么处理?

18. 怎么排查慢sql?对于慢sql怎么优化?

19. MySQL数据库CPU飙升到500%怎么处理?

20. 千万数据的表,CRUD特别慢,怎么优化?

21. 数据库是怎么进行主从复制的?

22. count(*)、count(1)、count(列名)有什么区别?

23. 频繁的增删数据量某个表,数据库最终数据只有几万或者更少,为什么查询会变慢

24.  mysql执行sql流程?

25. 什么情况下会索引失效?

26. 分库分表的方案?

二. Redis

1. redis有哪些数据类型?

2. redis的适用场景?项目中哪里用过redis?

3. redis为什么快?

4. redis为什么单线程还快?

5. redis的持久化机制是什么?优缺点是什么?

6. redis过期键的删除策略?

7. 有2000万mysql数据,redis只能存储20w数据,怎么保证redis存储的都是热点数据?

8. redis支持事务吗?

9. redis事务的命令有哪些?

10. redis哨兵机制是什么?

11. redis集群模式(redis cluster)的工作原理知道吗?

12. redis是如何进行主从复制的?

13. 缓存异常

14. 如何用redis实现分布式锁?

15. 假设redis中有一亿数据,有10w个前缀都是一样的,如何把他们找出来?

16. 有10万条数据,要插入到redis中,如何操作?

17. 如何使用redis做异步队列?

18. 如何使用redis做延迟队列?

19. redis的回收线程是怎么工作的?

20. redis回收使用的是什么算法?

三.MongoDB

1. 你们项目中MongoDB中存储是什么数据?

2. MySQL和MongoDB和redis的特点、区别、使用场景?


一. MySQL

1. 数据库三大范式是什么?

  • 第一范式:每一列都不可拆分;
  • 第二范式:在第一范式基础上,非主键完全依赖主键,而非依赖主键的一部分;
  • 第三范式:在第二范式基础上,非主键只依赖主键,不依赖其他非主键。

2. MyISAM和InnoDB存储引擎的区别?

  • 从功能上来说,InnoDB支持事务和行级锁,MyISAM不支持事务和行级锁,只支持表级锁;
  • 从索引来说,InnoDB的索引是聚簇索引,MyISAM是非聚簇索引。InnoDB主键索引的叶子节点存放的是行数据,因此用主键查询非常快;非主键索引的叶子节点存放的是主键索引和其他非主键索引,因此索引覆盖查询非常快。MyISAM索引的叶子节点存放的是行数据地址。

什么是存储引擎?

存储引擎定义了如何存储数据、如何为存储的数据建立索引、如何查询更新数据等技术的查询方法。

如何选择存储引擎?

  • 当插入和查询比较多时,且对事务,并发性要求不高时使用MyISAM,因为MyISAM查询比较快。比如博客系统,新闻门户网站。
  • 当需要用到事务,行级锁时,都是用InnoDB存储引擎。

为什么MyISAM查询比InnoDB快?

从功能上来说,InnoDB支持事务,会有一个MVVC(多版本并发控制)比较,会消耗性能,以及行级锁也会有性能开销。

从索引上来说,InnoDB的非主键索引查询数据会有一个回表的过程。先从非主键索引查到主键索引,然后再定位到行数据。而MyISAM直接能用索引定位到行数据。

3. 什么是MVCC?有什么作用?怎么实现的? 

详情讲解链接:华为云讲解MVCC

        MVCC(Multi-Version Concurrency Control)是多版本并发控制,主要是为了实现读-写并发下的安全读。它是一种除了加锁之外的并发控制方案,能够代替行级锁,并发控制时系统性能消耗更少。

        当我们执行普通的select语句,如果发生了读写并发,mysql如何保证安全读数据呢?当然可以加锁,但是mysql使用了更高性能的方案,就是MVCC。MVCC是用两个隐藏的列和undoLog实现的。两个隐藏的列分别是 当前事务的版本号 和 回滚指针(指向undolog中的版本记录)。

MVCC多版本控制的过程:

        事务执行更新操作时,会先给行数据加排它锁,然后把当前数据快照存在undolog中,拷贝完毕后,再修改行数据,并把回滚指针指向undolog中的版本记录。事务执行期间只需要读undolog中的版本记录即可。

undolog:保存了事务发生前的数据的一个版本,可以用于回滚,同时可以提供多版本并发控制下的读。主要用于回滚和MVCC的快照读。

redolog:主要用于故障恢复。数据库操作数据的时候会先写入缓存,然后再写入数据库。但是如果写入缓存成功,但是数据库宕机,数据就丢失了。因此有了redolog,每次写入缓存后必须在redolog中记录该操作(对 XXX表空间中的XXX数据页XXX偏移量的地方做了XXX更新),这样即使数据库宕机,等数据库恢复后,仍然能把数据从redolog刷盘到数据库。主要用于数据恢复刷盘

快照读和当前读

  • 快照读:普通的select * from table就是快照读,利用MVCC保存的undolog快照实现读写并发下的安全读
  • 当前读:读取最新数据,会对读取的数据加锁
SELECT * FROM xx_table LOCK IN SHARE MODE; //共享锁
SELECT * FROM xx_table FOR UPDATE; //排他锁
INSERT INTO xx_table ...  //排他锁
DELETE FROM xx_table ...  //排他锁
UPDATE xx_table ...  //排他锁

4. 什么字段适合作为索引?

频繁使用的字段、区分度高的字段、外键

5. 索引的结构有哪些?

Hash、BTree(Blance Tree)、B+Tree。在MySQL的InnoDB存储引擎中,主要使用的是B+树。

B树讲解:什么是B树_石楠烟斗的雾的博客-CSDN博客

B+树讲解:什么是B+树_石楠烟斗的雾的博客-CSDN博客

6. 为什么数据库主要使用B+树?B树和B+树有什么区别?

  • B树的每个节点都存储卫星数据,而B+树中间节点只存储索引,所以一个磁盘也可以存更多的节点,就能以更少的IO次数遍历完整个数。叶子节点包含了全量的元素,并存储了卫星数据(索引指向的数据记录,比如数据库的某一行)
  • B+树的叶子节点形成了有序链表,每个节点都有指向下一个节点的指针,范围查询更方便。但B树范围查询就要遍历整个树。
  • B+树每次查询都查询到叶子节点,更稳定。

磁盘页:假设一次IO能读8K的数据,那么8K就是一个磁盘页

需要指出的是:聚簇索引的叶子节点存储了卫星数据,非聚簇索引存储的是指向卫星数据的指针。

B树:

B+树:

7. hash存储结构和B+树存储结构有什么优劣?

  • hash存储底层是Hash表,等值查询比较快,但无法进行范围查询,因为用hash算法构建的索引不能和原顺序保持一致;B+树叶子节点的链表天然有序,因此支持范围查询。
  • hash索引在某个键大量重复时,会出现hash冲突,此时效率极差;B+树都是从根节点到叶子节点,查询效率稳定。

因此一般情况下,用B+树就能获得稳定快速的查询

8. B+树的具体实现是什么样的?

  • 每个中间节点都只存储索引,叶子节点包含全量的元素,并且是天然有序的双向链表
  • 主键索引的B+树结构: 叶子节点存储的是卫星数据; 非主键索引的B+树结构: 叶子节点存储的是主键索引和其他非主键索引(再通过主键索引回表查询到卫星数据)。

9. 联合索引在B+树中怎么存储?

        联合索引主要是用索引第一列构建的树,因此第一列是有序的,其他列是无序的。但是当第一列确定时,其他列相对有序。最左匹配原则也由此而来。

10. 最左匹配原则

以最左边为起点,连续的索引都能匹配上,遇到范围查询(> < between like)就会终止。

例如:建立联合索引(a,b,c,d),where a=1 and b=1 and c>1 and d=1 则d用不到索引,因为c是范围查询。

最左匹配原则原理:

索引的底层是B+树,联合索引也是。但是联合索引是用最左边的字段来构建B+树,因此最左边的字段是有序的,后边的字段都是无序的。但是当最左边字段确定时,后边字段相对有序。

11. 百万级的数据怎么删除

删除数据需要的时间和索引数量成正比,因为维护索引需要成本。

因此删除百万级数据的时候,应该先删除索引,然后删除不用的数据,最后重新建立索引。这样绝对比直接删除快的多。

12. 什么是数据库事务?事务的四大特性ACID介绍一下

事务是一组操作,要么都执行,要么都不执行。

  • 原子性:要么都执行,要么都不执行
  • 一致性:数据前后一致,比如转账操作,转账前两个账户共2000元,转完后也应是2000元
  • 隔离性:各个事务之间互不影响
  • 持久性:事务一旦提交,改变就是永久性的

13. 什么是脏读、不可重复读、幻读?

  • 脏读:读到了未提交的数据
  • 不可重复读:一个事务中,前后两次读到的数据不一致
  • 幻读:一个事务中,前后两次读到的行数不一致

14. 事务的隔离级别?怎么实现的(加了什么锁)?MySQL默认的隔离级别是什么?

  • 读未提交:可以读没有提交的数据。没有加锁。
  • 读已提交:可以读已经提交的数据,解决了脏读。使用了MVCC,在事务执行过程中,每次读操作都会创建一个数据快照,并读取这个数据快照。
  • 可重复读:一个事务前后两次读到的数据必然相同,解决了不可重复读。使用了MVCC,在事务执行时生成一个数据快照,整个事务期间都读取这个数据快照。
  • 可串行化:最高隔离级别,各个事务之间依次执行,不可能相互影响,解决了幻读。事务中读操作的时候给整个范围内的数据都加共享锁,其他事务只能读不能写;写操作的时候加排他锁,其他事务不能读也不能写,事务执行完毕才释放锁。(间隙锁)

MySQL默认的隔离级别是 可重复读;Oracle是 读已提交。

15. 数据库的行锁和表锁是怎么实现的?

        行锁是对索引进行加锁,没有索引不能用行锁,会升级到表锁。并且如果两条数据的索引相同,另一条数据也会被锁住。

例如:select * from table where id = 1 for update;如果id是索引,则加的是行锁;如果不是,则加的是表锁。

行锁和表锁如何使用?

行锁:

数据库会默认给UPDATE、DELETE、INSERT加排它锁,SELECT语句不会加任何锁,但是用户可以通过如下语句自行加锁

  • 加共享锁:select * from table where xxx LOCK IN SHARE MODE;
  • 加排它锁:select * from table where xxx FOR UPDATE;

表锁:

        表锁必须手动释放,但是在事务提交前不要释放锁,因为UNLOCK TABLE隐含提交事务。如果要对t1写,对t2读,则按如下操作:

LOCK TABLES t1 WRITE, t2 READ;
dosomething......
COMMIT;
UNLOCK TABLES;

间隙锁

        间隙锁就是对数据之间的间隙加锁,用于多个事务时阻止其他事务往已存在的数据行间隙中插入输入

SELECT * FROM employees WHERE age BETWEEN 30 AND 40 FOR UPDATE;

16.  如何定位sql语句的性能问题?如何解决?

定位性能问题用explain命令查看执行计划。有几个关键的字段:

  • possible_keys:可能会用到的索引
  • key:用到的索引
  • type:访问类型(如:ALL-全表扫描、index-遍历索引、ref-使用非唯一索引查询、range-索引范围查询、fulltext-全文索引)
  • rows:估算的结果集数目
  • Extra:额外信息(如:Using index-使用索引覆盖、Using where-使用where、Using filesort-使用文件排序、Using temporary-使用临时表)

优化:

  • 看是否加载了额外的行或列,尽量缩小查询范围
  • 看是否能调整sql命中索引,或添加索引
  • 如果是长难sql,看是否能拆开查询,然后在内存中聚合处理

17. 超大分页怎么处理?

比如:select * from table where age>20 limit 1000000,10;  这样相当于把前一百万条数据抛弃了,取了后续10条,这样非常慢。

【优化方案一】数据库角度:

  • 如果有自增长的id,则可以优化为:select * from table where id>1000000 limit 10; 记录上一次查询的最大id,下一次查询直接从该id开始
  • 如果没有自增长id,可以用子查询索引覆盖:select * from table where id in ( select id from table where  age > 20 limit 1000000,10); 子查询索引覆盖,会快很多。

【优化方案二】需求角度:尽量不做这样的需求,问业务方这是强需求吗?是什么样的场景导致一定要这样做?是否可以限制用户的查询轨迹,只允许逐页查看之类的。

18. 怎么排查慢sql?对于慢sql怎么优化?

可以登录mysql配置开启慢查询日志,当有慢查询时,慢查询日志就会记录该sql。但是一般这个功能都是公司DBA做的,业务方可以在平台上查看慢sql耗时。

配置开启慢查询日志:set slow_query_log = on

配置临界时间:set long_query_time = 0.5

慢sql优化:

  • 看是否加载了额外的行或列,尽量缩小查询范围
  • 看是否能调整sql命中索引,或添加索引
  • 如果是长难sql,看是否能拆开查询,然后在内存中聚合处理

LEFT JOIN优化

  • 用大表去关联小表,也就是小表left join大表
  • 关联字段建立索引
  • 把关联查询拆成单个查询,然后在内存中做聚合
//原sql
select user.uid, userinfo.uname from user
left join userinfo on user.uid=userinfo.uid 
where user.country='c'

//拆成
select uid,uname from user where country='c'
select uid,add from userinfo where uid in(32,34,23,23)

19. MySQL数据库CPU飙升到500%怎么处理?

看一下有没有慢sql,用explain命令分析并优化慢sql

20. 千万数据的表,CRUD特别慢,怎么优化?

  • 缩小查询范围(行和列),比如只查近一个月的订单
  • 命中索引
  • 把热点数据放在缓存中
  • 分库分表

【分库分表】

垂直分表:把表按照某个维度(比如使用频率)垂直拆分开

  • 优点:一个数据页能存储更多的数据,能减少IO次数
  • 缺点:需要管理冗余列,有时候需要联表查询

水平分表:当数据超过200万行时,CRUD就会很慢,这时就需要用某种策略将数据水平分片

  • 优点:能够支撑大量的数据
  • 缺点:分布式事务难以处理、跨库的join、跨库的count orderby groupby等函数不好使用。后两个问题可以通过在应用程序中进行拼装来解决

21. 数据库是怎么进行主从复制的?

  • 主库把数据更改记录到binlog中
  • 通过IO把binlog传输到从库
  • 从库重新执行binlog中的语句就能实现主从复制了

读写分离造成数据不一致怎么处理?
        如果是对强一致性要求不高的业务,那在主从同步期间读到旧数据也没有关系。

        如果是一致性要求很高的业务,有三种方案:

(1)数据库的主从同步方案一般是异步,我们可以将其改为同步,主从同步完成,主库的写才能返回。缺点是写请求延迟会增加,吞吐量会降低。一般在线业务都无法接受。

(2)对于强一致的场景,我们可以将其读写请求都发往主库,就没有不一致的情况了

(3)缓存路由大发:写请求路由到主库,同时缓存记录操作的key(比如主键),缓存的失效时间设置为主从的延时;读请求先判读缓存是否存在,存在则读主库,否则读从库。

22. count(*)、count(1)、count(列名)有什么区别?

执行结果上:count(*)、count(1)没有区别,count(列名)不统计为null的记录。

执行效果上:mysql会自动优化count(*),因此当有主键的时候count(*)比count(1)快;没有主键的时候,count(1)比count(*)快。如果列名是主键,则count(列名)最快。

23. 频繁的增删数据量某个表,数据库最终数据只有几万或者更少,为什么查询会变慢

原因是该表的空间大了,查询起来很慢。解决的方法是把该表所占用的表空间缩小,或者说释放表空间。
alter table XXXX move; 这样处理后就释放了表空间了。
但是释放表空间后,表的行号rowid会发生变化,而基于rowid的索引则会变成无效。因此该操作后必须重建索引。
否则会 提示“ORA-01502: 索引'SMP.ITEMLOG_MID_IDX'或这类索引的分区处于不可用状态”
而重建索引的方法当然可以先drop掉再create ,但是这样太麻烦了,
用alter index XXX rebuild 这样最快了,不会改变原来的索引结构

24.  mysql执行sql流程?

1、连接器:客户端先和MySQL服务器建立连接,并发送查询sql脚本给服务器

2、查询缓存:服务器先检查查询缓存,如果命中了缓存,则立刻返回存储在缓存中的结果。(MySQL8.0删掉了这个功能)否则进入下一阶段。

3、分析器:服务器端SQL解析语句,判断SQL语法是否正确,查询的表、字段是否存在

4、优化器:对sql语句进行优化,并生成对应的执行计划。

5、执行器:根据执行计划调用存储引擎的API来执行查询,并把结果返回给客户端

25. 什么情况下会索引失效?

  • like左边包含%(like '张%' 能用到索引  like '%张' 用不到)
  • 使用了or 关键字(如果使用了or关键字,那么它前面和后面的字段都要加索引,不然所有的索引都会失效)
  • 使用了not in 或 not exist
  • is null走索引,is not null不走
  • 索引列使用了函数
  • 不满足最左匹配原则(联合索引abc,查询条件where b=? and c=? 则用不到联合索引)

26. 分库分表的方案?

概念:以某个字段为依据,按照一定策略,将一个表中的数据拆分到多个表中。
场景:单表的数据量太多,影响了SQL效率

工具:Sharding-JDBC

  • 选择分片键
  • 选择分片策略:取模、范围(Between AND)

27. 数据库使用自增ID和UUID作为主键有什么不同

  • 自增ID有序,生产速度快,存储空间小,数据库可以具有更好的性能,缺点是只在当前表中唯一,而不是全局唯一,而且自增ID会暴露表中数据规模;
  • UUID在分布式场景下依然全局唯一
  • 因此,UUID更适合数据量大的分布式场景,自增ID更适合小数据量追求性能的场景

28. 如何防止SQL注入?

  • 使用预编译,比如用#{}代替${}
  • 对用户输入进行严格的验证和过滤,只允许预期的输入格式和字符,拒绝特殊字符
  • 为数据库用户分配最小权限,限制数据库的访问范围和操作权限
  • 使用ORM框架,比如Mybatis,能够自动执行参数化查询防止sql注入

二. Redis

1. redis有哪些数据类型?

  • String:字符串。set get mset(批量set) mget
  • Hash:包含键值对的无序散列表。hmset key filed1 value1 filed2 value2;   hget key filed1;
  • List:有序列表。lpush key value; rpush key value; lrange key 0 3;
  • set:无序不重复集合。sadd key value; smembers key;
  • zset:有序不重复集合,每个元素都关联分数,通过分数来排序。zset key score value; zrangebyscore 0 3;

redis中String底层的数据结构?

Redis六种底层数据结构_星空是梦想的博客-CSDN博客_redis 底层数据结构图解redis五种数据结构底层实现(动图哦)

是简单动态字符串(SDS)。用char[]数组的形式保存String中每个字符,还有len属性保存字符串的长度,以及free属性保存未使用的字节数。

为什么要这样设计?

  • 高效的修改操作。可以直接在原字符串基础上修改,而不是像Java中String不可变,修改时需要频繁内存分配和拷贝。
  • 空间预分配。redis会根据当前字符串长度和剩余空间进行预分配,适应字符串长度变化
  • 杜绝空间溢出。字符串如果没有重新分配足够空间,直接修改字符串,可能会造成空间溢出。SDS会先判断空间是否够用,不够的话会扩展至所需大小。
  • 惰性空间释放。如果字符串变短,不会直接回收,而是存到free中,防止频繁内存释放
Java中String和StringBuffer
    String不可变,修改String实际上是创建了新的String对象。设计为不可变主要是为了线程安全,既然不可变,那么多线程操作也无需担心线程安全问题。
    StringBuffer可变,也是用char[]存储数据,如果容量足够则直接修改。不够的话,创建新的char[],将原有数据复制过来并修改,再把指针指向新char[]

redis中hash的底层数据结构?

        hash的底层数据结构是哈希表(数组加链表的结构)或ziplist(压缩列表)。当存储的数据量较小时会使用ziplist(元素个数小于512,且长度小于64字节)。

  • 数据结构:ziplist并不是以某种压缩算法来进行压缩存储数据,而是标识一段连续的内存空间存储数据。ziplist的数据结构有点类似于数组,但实际上是个特殊的双向链表,它不存储指向前节点或后节点的指针,存的是上一个节点长度和当前节点长度,由于内存连续因此通过偏移量就能完成前后节点访问
  • 优缺点:ziplist是以空间换时间的思路,它的优势在于空间紧凑,有效减少内存占用;缺点是读写性能不如链表,而且添加或删除数据都需要对内存进行扩展和减小。然而链表占用的空间通常比ziplist更多,因为每个元素都需要额外分配内存存储指针。

zipList的数据结构?

  • ziplist包括zip header、zip entry、zip end三个模块。
  • zip entry由prevlen、encoding&length、value三部分组成。
  • prevlen主要是指前面zipEntry的长度,coding&length是指编码字段长度和实际- 存储value的长度,value是指真正的内容。
  • 每个key/value存储结果中key用一个zipEntry存储,value用一个zipEntry存储。

本质上是个字节数组,把所有元素按照特定的编码格式编码后紧凑的排列在一起

redis中list的底层数据结构?

        redis中list的底层数据结构是一个双向链表或ziplist。

        当Hash、List、Zset存储的数据较小时,会优先使用ZipList

redis中set的数据结构?

        redis中set是一个intset或者hashtable的结构。当元素全为整数且元素数量不超过512时用intset存储,否则用hashtable的key保存数据。

        intset底层实际上是一个int数组。

zset底层的数据结构是什么?

漫画:什么是 “跳表”?跳跃表及底层实现原理解析_Slayer_Zhao的博客-CSDN博客_跳跃表原理和实现

        zset底层的存储结构包括跳表(skiplist)或压缩列表(ziplist),数据量小时使用ziplist(元素个数小于128且长度小于64字节),其他时候使用skiplist

  

压缩列表:

        当ziplist作为zset的底层存储结构时候,每个集合元素使用两个紧挨在一起的压缩列表节点来保存,第一个节点保存元素的成员,第二个元素保存元素的分值。

跳表:

        当skiplist作为zset的底层存储结构的时候,使用skiplist按序保存元素及分值,使用dict来保存元素和分值的映射关系。

        跳表的结构如下图所示,跳表是用来加速查询、插入和删除的,它是在原始链表的基础上加了多层索引链表,索引链表的节点指向原始列表的节点,使得查询数据的效率更高。

插入:

2. redis的适用场景?项目中哪里用过redis?

  • 缓存热点数据:如缓存标的列表
  • 计数器:一个月内优惠券一万张,发一张就减一
  • 分布式锁:比如一个人在交易完成前不能再进行第二次操作,用分布式锁来保证。再比如抢标时标的金额递减,也用分布式锁来保证。用setnx实现的

3. redis为什么快?

  • redis基于内存,所以高性能
  • redis是单线程,不需要多线程竞争CPU资源,也不需要切换上下文,减少了很多性能损耗
  • redis使用了IO多路复用的模型,用一个选择器监听多个通道,当通道有事件发生时,线程就处理事件

4. redis为什么单线程还快?

        因为redis使用了IO多路复用的模型,用一个选择器监听多个通道,当通道有事件发生时,线程就处理事件。相当于可以处理大量并发IO。

IO多路复用和多线程有什么区别?

  • IO多路复用适合处理IO密集型,IO等待的时间比较长,不需要太多CPU计算,单线程就处理计算逻辑了
  • 多线程适合处理CPU密集型,需要多线程使用多核CPU处理计算逻辑。

redis完全是单线程的吗?

        不是。redis 6.0 后读写命令是依然是单线程的,但是处理网络IO是多线程的,因为redis的瓶颈主要是网络IO,所以 处理网络IO 用多线程可以解决这个问题,并且不会造成数据并发读写。

5. redis的持久化机制是什么?优缺点是什么?

RDB:按照一定的时间间隔把内存快照保存到磁盘中

  • 优点:性能好,保存内存快照是子进程进行的,不需要占用主进程IO;而且恢复数据快
  • 缺点:如果在保存间隔内redis宕机,会丢失数据

AOF:把所有的写操作记录到磁盘日志中

  • 优点:保存数据完整
  • 缺点:数据集大的时候,恢复数据慢

项目中使用的是RDB还是AOF?

  • 用 AOF 来保证数据不丢失,作为数据恢复的第一选择;
  • 用 RDB 来做不同程度的冷备,在 AOF 文件都丢失或损坏不可用的时候,还可以使用 RDB 来进行快速的数据恢复

总的来说:都用,AOF 作为第一恢复方式,RDB 后补

6. redis过期键的删除策略?

  • 定时删除:给每个有过期时间的key都创建定时器,到过期时间就会清除;
  • 惰性删除:访问到key的时候,才判断有没有到过期时间,过期则清除;
  • 定期删除:每间隔一段时间,会扫描所有的key,清除已过期的key

redis使用:惰性删除 + 定期删除

7. 有2000万mysql数据,redis只能存储20w数据,怎么保证redis存储的都是热点数据?

当数据集上升到一定程度,要么对redis扩容,要么使用淘汰策略。

淘汰策略用于处理 内存不足时需要申请额外空间的数据,有三种策略:

  • 随机移除
  • 移除使用最少的key
  • 移除更早过期的key

当内存用完的时候,写操作会返回错误,或者你可以配置内存淘汰策略

8. redis支持事务吗?

        支持,redis的事务能保证一系列指令按顺序执行,中间不会插入其他语句。但是redis事务只支持隔离性,不支持原子性,不支持回滚。

        当中间有语句执行失败时,会继续执行其他语句。

9. redis事务的命令有哪些?

  • MULTI:开启事务
  • EXEC:执行事务
  • WATCH:监控一个或多个键,一旦键被修改,会通知客户端,事务就不会执行。本质是一个乐观锁,为事务提供CAS(compare and set)行为。用到的是发布订阅模式。
  • DISCARD:清空事务队列,并放弃执行事务

10. redis集群模式(redis cluster)的工作原理知道吗?

        redis集群使用了哈希槽的方式来进行数据存储和读取。

        假设redis集群有3个分片,数据将分别存储在这三个分片上,三个分片上被均分了16384个哈希槽。数据具体存储在哪个分片上,是由哈希槽算法决定的。CRC16(key) % 16384就可以得知数据要被存储在哪个槽上了。

        如果是服务端路由的方式,客户端把请求发送到任意分片节点,接收到请求的节点都会把请求转发到正确的节点上执行。

redis为什么不使用一致性哈希,而使用哈希槽?

        因为哈希槽好扩容,如果要增加节点,只需要把其他分片上的哈希槽迁移一部分到新节点即可。

一致性哈希(哈希环)

  • 普通做法:如果我们要确定一个key要放在ABC哪台服务器上,普通做法是 key的hash值%3(3台服务器),但是如果要再加一台服务器,所有图片的位置就都需要改变。
  • 一致性哈希:一致性哈希也叫哈希环,这个环分成了2^32个小块,ABC服务器则是环上三个点,然后用key的 hash值 对 2^32 取模,key的hash值必然落在弧形区间内,归为下一个最近的服务器。
  • 一致性哈希缺点:可能会数据分布不均匀,导致哈希倾斜。解法:把ABC服务器,多取几个hash值(A1A2A3)作为虚拟节点,虚拟节点越多,哈希倾斜带来的影响就越小。

什么是redis集群模式下的脑裂?如何解决脑裂?

        脑裂是因为网络原因,导致master、slave、sentinel不在一个网络分区。此时sentinel感应不到master,就会从slave中重新选举一个master,两个master看起来就像master分裂成了两个。

        集群脑裂问题中,如果客户端还继续往旧的master写数据,当网络恢复后,sentinel就会把之前master降为slave,此时再从新的master同步数据就会丢失大量数据。

解决方案:

        redis有两个配置如下,如果slave节点少于3个,或者slave超过10秒都没连接到master,master就拒绝写请求

//配置slave节点最少有3个
min-slaves-to-write 3

//配置slave连接到master的最大延时为10秒
min-slaves-max-lag 10

12. redis是如何进行主从复制的?

  • 当一个slave启动的时候,会发送一个同步命令(PSYNC)给master
  • master生成一个RDB文件发给slave,并把期间收到的写命令缓存起来,然后把RDB文件和缓存的写命令发送给slave
  • slave把RDB文件先写到磁盘,然后写到缓存中,再执行写命令
  • 之后master收到的写命令都会同步给slave,从而保证数据的一致性

        这样的主从复制模式有一个缺点,就是所有的复制同步都由master处理,导致master压力太大,可以使用主从从模式,slave同步到slave

Redis主从模式和集群模式的区别?

  • 主从模式,master可以读写,slave只能读,master会向slave同步数据
  • 集群模式,多个节点都可以读写,支持更高的并发

13. redis哨兵机制是什么?

sentinel,哨兵,用于保证redis主从集群的高可用。它有四个作用:

  • 集群监控:监控redis master 和 slave 的可用性
  • 消息通知:如果master宕机,会报警通知运维管理员。(判断master宕机,需要一半以上的sentinel同意才行,涉及到分布式选举)
  • 故障转移:如果master故障,会从slave中选举出一个新的master
  • 配置中心:管理配置信息,如主从节点的连接信息

哨兵机制不保证数据不丢失,只能保证redis集群高可用

13. 缓存异常

【缓存雪崩】:同一时间内大面积缓存失效,导致请求全都打到服务器上。

解决方案:缓存预热,在服务器启动前把热点数据提前刷到缓存中,并且过期时间尽量设置的随机一些,避免同一时间失效

【缓存击穿】:缓存中没有数据库中有的数据(一般是缓存时间到期)

解决方案:一般有两种解决方案。第一是让热点数据用不过期,但是轻易不使用这种方式。第二种是用双重判空的方式,先去缓存中拿,缓存中没有再加锁,再判断缓存中有没有,没有的话再到数据库拿。(加锁是为了保证高并发下只有一个请求到数据库拿数据,减轻压力;双重判空是因为加锁后,有可能其他线程已经往缓存中放了数据)

【缓存穿透】:缓存和数据库中都没有的数据

解决方案:可以在缓存中设置一个key,value是null,这样也就直接能从缓存拿到了

14. 如何用redis实现分布式锁?

  • 获取锁:SETNX(set if Not Exist), 设置成功返回1,设置失败返回0
  • 释放锁:DEL

如何获取分布式锁?怎么保证性能?

  • 可以用setnx()获取锁成功返回1,获取失败返回0;如果是获取成功则可以继续处理下边的业务,如果获取失败自旋5次,尝试去获取锁。
  • 如果要设置过期时间,用jedisClient.set(key, value, "NX", "EX", expireSecond);//NX是不存在时才set,XX是存在时才set,EX是秒,PX是毫秒

自旋比较消耗性能,如果不采用自旋的方式呢?

        使用阻塞队列的blpop。

redis和zk获取分布式锁有什么区别?

        zk获取分布式锁是通过创建临时节点的方式,如果创建临时节点成功就获取锁,释放锁就是删除临时节点。

        但是一般都不使用zk做分布式锁,很客观的原因是要用zk做分布式锁就得有zk集群,但是一般公司都没有zk集群,但是都有redis的集群,所以都用redis做分布式锁。

15. 假设redis中有一亿数据,有10w个前缀都是一样的,如何把他们找出来?

  • 使用keys指令,keys [前缀]*。缺点:redis是单线程的,keys指令会使线程阻塞一段时间,导致线上会停顿,直到该指令执行完毕。
  • 使用scan指令,scan指令是一个基于游标的迭代器。每次调用之后,都会返回一个新游标。用户下次可以使用这个游标继续迭代。
KEYS aaa*; //模糊匹配,aaa是key的前缀
SCAN 0 MATCH aaa* COUNT 10; //0是游标

16. 有10万条数据,要插入到redis中,如何操作?

  • 可以使用管道,分批提交数据。比一个一个提交快,是因为省去了多次网络IO的时间。
  • 可以使用AOF的方式,把10万条数据变成set key value,set ket value的形式,加载到redis中

17. 如何使用redis做异步队列?

        使用redis的list数据结构,blpush生产消息,brpop消费消息,brpop是阻塞的,没有消息就一直等待,直到消息到来。

18. 如何使用redis做延迟队列?

        用redis的zset做延迟队列,消息作为value,消息要发送的时间戳作为score

        用zrangebyscore以 0 < score <= 当前时间戳 来获取要执行的任务。

19. redis的回收线程是怎么工作的?

        当redis已使用内存达到阈值之上,如果有新请求进来,就会按照配置的淘汰策略进行回收。

20. redis回收使用的是什么算法?

        LRU算法,淘汰最少使用的数据。

LRU算法具体实现?

LRU算法的核心思想是:

        如果数据最近被访问过,那么将来被访问的几率也更高。

实现:

  • 新加入数据添加到链表头部
  • 被访问的数据也添加移动到链表头部
  • 当链表满时从底部淘汰数据

代价:命中需要遍历链表,找到命中的数据,并移动到链表头部

21. Redisson看门狗机制

        看门狗(WatchDog)是一个后台线程,它的主要作用是确保分布式锁续期和异常释放。

  • 它会启动一个定时任务,对于已经持有分布式锁,但是还没执行完业务流程的客户端,它会更新分布式锁的过期时间,进行锁续约,确保业务正常执行完。
  • 看门狗还会定期检查持有锁的客户端是否活跃(监控客户端和redis的心跳),如果客户端一段时间内没有响应(比如网络故障或客户端进行崩溃),看门狗将自动释放锁,确保其他客户端可以获取到锁资源。

22. 如何查看redis的内存和CPU?

  • 查看内存的命令:INFO memory
  • 查看CPU的命令:INFO CPU

如果内存突然满了,需要排查下是否是短时间内写入了大量数据。

解决方案一般是:

  • 设置key的过期时间自动清理不再需要的key,或手动删除不再需要的key
  • 对redis进行扩容,或者增加节点

三.MongoDB

1. 你们项目中MongoDB中存储是什么数据?

        费率、保单的扩展字段。

        由于费率计算复杂,每个保司计算费率的条件也都不一样,这时候如果用数据库存储,就没办法设计表,因此采用MongoDB存储,可以灵活的存储非结构化数据。

2. MySQL和MongoDB和redis的特点、区别、使用场景?

  • MySQL是关系型数据库,常用于存储结构化数据,并且支持事务。
  • MongoDB是文档型数据库,如果不确定的数据结构,就可以使用MongoDB,便于扩展字段。
  • redis当做缓存使用,查询非常快速,比如可以存储热点数据,缩小给前端的返回时间。

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在 Node.js 中,可以使用不同的方法来存储数据。以下是一些常用的存储数据的方法: 1. 文件系统(File System):Node.js 提供了文件系统模块(fs)来读取和写入文件。您可以将数据存储在文本文件中(如 CSV、JSON、XML 等格式),并使用 fs 模块读取和写入这些文件。 2. 关系型数据库:您可以使用 Node.js 驱动程序连接到关系型数据库(如 MySQL、PostgreSQL、Oracle 等),并执行 SQL 查询来存储和检索数据。一些常用的 Node.js 数据库驱动程序包括 Sequelize、Knex.js 和 node-mysql。 3. 非关系型数据库:非关系型数据库(如 MongoDBRedis、Cassandra 等)提供了一种不同的方式来存储和查询数据。您可以使用适合的 Node.js 驱动程序连接到这些数据库,并使用其相应的 API 进行数据操作。一些常用的 Node.js 非关系型数据库驱动程序包括 Mongoose、ioredis 和 cassandra-driver。 4. 内存缓存:在某些情况下,您可能只需要将数据保存在内存中,而不是持久化存储。Node.js 提供了内置的内存缓存模块(如 MemoryCache、Node-cache 等),您可以使用这些模块来存储和检索数据,并在需要时进行过期处理。 5. 第三方存储服务:除了上述方法外,您还可以使用云存储服务(如 Amazon S3、Google Cloud Storage、Azure Blob Storage 等)来存储数据。这些服务通常提供了简单的 API 来上传、下载和管理文件。 选择哪种存储方法取决于您的需求、数据类型和性能要求。您也可以根据具体场景组合使用不同的存储方法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值