一份热乎乎的字节面试真题(三)
11. redis挂了怎么办?
Redis是基于内存的非关系型K-V数据库,既然它是基于内存的,如果Redis服务器挂了,数据就会丢失。为了避免数据丢失了,Redis提供了持久化,即把数据保存到磁盘。
Redis提供了RDB和AOF两种持久化机制,它持久化文件加载流程如下:11.1 RDB
RDB,就是把内存数据以快照的形式保存到磁盘上。
什么是快照? 可以这样理解,给当前时刻的数据,拍一张照片,然后保存下来。
RDB持久化,是指在指定的时间间隔内,执行指定次数的写操作,将内存中的数据集快照写入磁盘中,它是Redis默认的持久化方式。执行完操作后,在指定目录下会生成一个dump.rdb文件,Redis 重启的时候,通过加载dump.rdb文件来恢复数据。RDB触发机制主要有以下几种:RDB 的优点
• 适合大规模的数据恢复场景,如备份,全量复制等
RDB缺点
• 没办法做到实时持久化/秒级持久化。
• 新老版本存在RDB格式兼容问题
11.2 AOF
AOF(append only file) 持久化,采用日志的形式来记录每个写操作,追加到文件中,重启时再重新执行AOF文件中的命令来恢复数据。它主要解决数据持久化的实时性问题。默认是不开启的。
AOF的工作流程如下:AOF的优点
• 数据的一致性和完整性更高
AOF的缺点
• AOF记录的内容越多,文件越大,数据恢复变慢。
12.你怎么防止优惠券有人重复刷?
对于重复请求,要考虑接口幂等和接口防重。
大家可以看下之前我写的这篇文章哈:聊聊幂等设计
防刷的话,可以限流以及加入黑名单处理。
• 为了防止某个用户请求优惠券过于频繁,我们可以对同一用户限流。
• 为了防止黄牛等模拟几个用户请求,我们可以对某个IP进行限流。
• 为了防止有人使用代理,每次请求都更换IP请求,我们可以对接口进行限流。
13. 抖音评论系统怎么设计,如果加入好友关系呢?
需要考虑性能,以及可扩展性。大家平时有没有做过评论、好友关注等项目需求呀,发挥你聪明的小脑袋瓜,怎么去回答好这道题吧。
14. 怎么设计一个短链地址,要考虑跨机房部署问题
14.1 为什么需要短连接?
为什么需要短连接呢?长链接不香吗?因为有些平台有长度限制,并且链接太长容易被识别为超链接等等。
14.2 短链接的原理
其实就是一个302重定向而已。302状态码表示临时重定向。
14.3 短链接生成的方法
可以用哈希算法生成短链,但是会存在哈希冲突。怎么解决呢?可以用布隆过滤器。
有没有别的方案?自增序列算法,每次收到一个长链时,就分配一个ID,并转成62进制拼接到短域后面。因为高并发下,ID 自增生成器可能成为瓶颈。
一般有四种分布式ID生成方法:
1.uuid,它保证对在同一时空中的所有机器都是唯一的,但是这种方式生成的id比较长,并且是无序的,插入浪费空间。
2.Snowflake雪花算法,这种方案不错,但是如果某台机器的系统时钟回拨,有可能造成ID冲突重复,或者ID乱序(考虑跨机房部署问题)
3.Mysql 自增主键,在高并发下,db的写压力会很大
4.用Redis做自增id生成器,性能高,但要考虑持久性的问题;或者改造雪花算法,通过改造workId解决时钟回拨的问题)
15.有一个整型数组,数组元素不重复,数组元素先升序后降序,找出最大值。
例如:1,3,5,7,9,8,6,4,2,请写一个函数找出数组最大的元素
这道题大家都会觉得很简单,因为用快速排序排一下,时间复杂是O(nlgn),面试官可能不是很满意。其实可以用二分查找法,只要找到升序最后一个元素即可。
我们以1,6,5,4,2为例子,用二分法图解一下哈:如何用二分法缩小空间呢?只要比较中间元素与其下一个元素大小即可
如果中间元素大于其下一个元素大小,证明最大值在左侧,因此右指针左移
如果中间元素小于其下一个元素大小,证明最大值在左侧,因此右指针左移
因为nums[mid]=5>nums[mid+1]=4,因此右指针左移,right=mid-1=2-1=1mid = left+ (right-left)/2=left=0,因为nums[mid]=1<nums[mid+1]=6,所以左指针右移,left = mid+1=1;最后得出最大值是nums[left] =nums[1]=6
实现代码如下:
class Solution {
public static void main(String[] args) {
int[] nums = {1,3,5,7,9,8,6,4,2};
System.out.println(getLargestNumInArray(nums));
}
private static int getLargestNumInArray(int[] nums) {
if (nums == null || nums.length == 0) {
return -1;
}
int left = 0, right = nums.length - 1;
while (left <= right) {
int mid = left + ((right - left) / 2);
if (nums[mid] < nums[mid + 1]) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return nums[left];
}
}