如果是保存不重要的数据可以使用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、分库分表(更大的数据量)等。
今日份其他面试问题:
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有