1、redis中RDB和AOF的使用情况分别是什么?
如果是保存不重要的数据可以使用RDB方式(比如缓存数据),如果是保存很重要的数据就要使用AOF,但是两种方式也可以同时使用。
RDB触发机制:
第一种: save(同步) 1 客户端输入save命令----》redis服务端----》同步创建RDB二进制文件 2 会造成redis的阻塞(数据量非常大的时候) 3 文件策略:如果老的RDB存在,会替换老的 4 复杂度 o(n)
第二种: bgsave(异步,Backgroud saving started) 1 客户端输入save命令----》redis服务端----》异步创建RDB二进制文件(fork函数生成一个子进程(fork会阻塞reids),执行createRDB,执行成功,返回给reids消息) 2 此时访问redis,会正常响应客户端 3 文件策略:跟save相同,如果老的RDB存在,会替换老的 4 复杂度 o(n)
第三种:(常用方式)(******) 自动(通过配置文件) 配置 seconds changes save 900 1 save 300 10 save 60 10000 如果60s中改变了1w条数据,自动生成rdb 如果300s中改变了10条数据,自动生成rdb 如果900s中改变了1条数据,自动生成rdb
以上三条符合任意一条,就自动生成rdb,内部使用bgsave。
RDB触发机制一般使用第三种方式,但是这种方式也会有缺点。如果修改的条数没有在设置范围内那么就不会触发,就会引发很多数据没有持久化的情况。所以我们一般采用下面方式:AOF。
AOF
问题:耗时,耗性能。不可控,可能会丢失数据。
实现策略:
日志不是直接写到硬盘上,而是先放在缓冲区,缓冲区根据一些策略,写到硬盘上 #第一种: always:redis--》写命令刷新的缓冲区---》每条命令fsync到硬盘---》AOF文件 #第二种: everysec(默认值):redis——》写命令刷新的缓冲区---》每秒把缓冲区fsync到硬盘--》AOF文件 #第三种: no:redis——》写命令刷新的缓冲区---》操作系统决定,缓冲区fsync到硬盘--》AOF文件
RDB和AOF的选择
rdb最佳策略
rdb关掉,主从操作时; 集中管理:按天,按小时备份数据;
主从配置,从节点打开。
aof最佳策略
开:缓存和存储,大部分情况都打开, aof重写集中管理 everysec:通过每秒刷新的策略
最佳策略
小分片:每个redis的最大内存为4g; 缓存或存储:根据特性,使用不通策略; 时时监控硬盘,内存,负载网络等; 有足够内存。
2、斐波那契数列的实现。
实现一:基于递归形式实现
public static int getFib(int n){ if(n < 0){ return -1; }else if(n == 0){ return 0; }else if(n == 1 || n ==2){ return 1; }else{ return getFib(n - 1) + getFib(n - 2); } }
递归是最简单的实现方式,但递归有很多的问题,在n的值非常大时,会占用很多的内存空间,既然该数列定义F(n)=F(n-1)+F(n-2)(n≥2,n∈N*),那么我们可以从头到尾进行计算,先计算前面的值,然后逐步算出第n个值。
方式二:基于变量形式实现
public static int getFib2(int n){ if(n < 0){ return -1; }else if(n == 0){ return 0; }else if (n == 1 || n == 2){ return 1; }else{ int c = 0, a = 1, b = 1; for(int i = 3; i <= n; i++){ c = a + b; a = b; b = c; } return c; } }
从上面的实现中我们定义了3个变量a、b、c其中c=a+b,然后逐步进行计算从而得到下标为n的值。 既然我们可以定义变量进行存储,那么同样我们还可以定义一个数组,该数组的每一个元素即一个斐波那契数列的值,这样我们不仅能得到第n个值,还能获取整个斐波那契数列。
方式三:基于数组的实现
public static int getFib3(int n){ if(n < 0){ return -1; }else if(n == 0){ return 0; }else if (n == 1 || n == 2){ return 1; }else{ int[] fibAry = new int[n + 1]; fibAry[0] = 0; fibAry[1] = fibAry[2] = 1; for(int i = 3; i <= n; i++){ fibAry[i] = fibAry[i - 1] + fibAry[i - 2]; } return fibAry[n]; } }
3、数据库插入大批量数据的优化方案。
3.1、数据有序插入;
由于数据库插入时,需要维护索引数据,无序的记录会增大维护索引的成本。我们可以参照InnoDB使用的B+tree索引,如果每次插入记录都在索引的最后面,索引的定位效率很高,并且对索引调整较小;如果插入的记录在索引中间,需要B+tree进行分裂合并等处理,会消耗比较多计算资源,并且插入记录的索引定位效率会下降,数据量较大时会有频繁的磁盘操作。
3.2、在事务中进行插入处理;
使用事务可以提高数据的插入效率,这是因为进行一个INSERT操作时,MySQL内部会建立一个事务,在事务内才进行真正插入处理操作。通过使用事务可以减少创建事务的消耗,所有插入都在执行后才进行提交操作。
结论:
合并数据+事务的方法在较小数据量时,性能提高是很明显的,数据量较大时(1千万以上),性能会急剧下降,这是由于此时数据量超过了innodb_buffer的容量,每次定位索引涉及较多的磁盘读写操作,性能下降较快。而使用合并数据+事务+有序数据的方式在数据量达到千万级以上表现依旧是良好,在数据量较大时,有序数据索引定位较为方便,不需要频繁对磁盘进行读写操作,所以可以维持较高的性能。
注意事项:
SQL语句是有长度限制,在进行数据合并在同一SQL中务必不能超过SQL长度限制,通过max_allowed_packet配置可以修改,默认是1M,测试时修改为8M。
事务需要控制大小,事务太大可能会影响执行的效率。MySQL有innodb_log_buffer_size配置项,超过这个值会把innodb的数据刷到磁盘中,这时,效率会有所下降。所以比较好的做法是,在数据达到这个这个值前进行事务提交。
3.3、存储过程;
3.4、加缓存,使用redis等对数据进行预加载;
3.5、临时表;
3.6、队列;
3.7、分库分表(更大的数据量)等。
今日份其他面试问题:
哈希原理;
哈希结构和b+tree谁的速度更快;
如何分库分表;
分布式事务解决方案;
kafka如何解决不能传送大于10k的消息;
nacos和eruika如何选型;
你的项目上线了吗?日火多少,统计用户是多少?
说说多表子查询;
刷盘策略是什么;
dc分布式中心;
关于项目的问题;
项目从开发到结束是怎么个流程;
项目团队有多人人;
项目怎么部署发布的;
Redis的应用场景,请列举一个场景,并说明怎么实现的;
SQL优化;
项目为什么选择了spring cloud ,不用Dubbo;
介绍一下使用了Spring cloud哪些组件;
MongoDB的应用场景,为什么选择MongoDB,不选择mysql;
介绍一下你了解的MQ;
Spring Boot常用注解及作用;
Vue怎么使用的,常用标签;
如果让你设计消息队列,你怎么设计;
开发代码的规范,你谈一谈;
Mybatis和mybatis-plus的区别,怎么选型;
说说bean的生命周期;
缓存雪崩如何解决? 缓存穿透如何解决?
如何使用Redis完成订单列表场景?
MySQL里有2000w数据,Redis中只存20w的数据,如何保证Redis中的都是热点数据?
Redis相比memcached有哪些优势?
假如Redis里面有1亿个key,其中有10w个key是以某个固定的已知的前缀开头的,如何将它们全部找出来?
我说的登录验证.加密方式是什么?
有没有参与部署?
为什么用mq不是kafuka?
说一下你对高并发线程的理解?
说一下mysql调优?
项目中第三方支付接口是什么?
讲一下项目中用到的搜索引擎?
redis的增量更新;
懒汉式在多线程中如何保证唯一又不影响效率的;
springboot的启动类,为什么添加上后就可以启动了;
MQ生产者生产消息如何保证消息被消费了;
冒泡排序后开始索引值与输出结果对应;
词典,set存储,如何获取词典中的词汇;
你以后的职业规划是什么。