两道困难leetcode
两场面试+复盘整理,重点重新学习了一遍答的不好,答的不对的地方
两篇百度面经,对面经里面不会的题目重新进行了整理
1.为什么Redis要用跳表来实现有序集合,而不是红黑树?
Redis的核心操作主要有:插入一个数据、删除一个数据、查找一个数据、按照区间查找数据(比如查找值在[100,235])之间的数据、迭代输出有序序列。
插入、删除、查找以及迭代输出这几个操作,红黑树跟跳表的时间复杂度是一样的。但是区间查找数据,红黑树的效率没有跳表高。跳表可以在O(logn)定位区间的起点。
2.http请求get和post的区别:
-
get都是向服务器请求一个资源,具有幂等性(多次请求得到同样的结果);
-
请求的数据会附加在URL之后,以?分割URL和传输数据,多个参数用&连接。URL的编码格式采用的是ASCII编码,而不是uniclde,即是说所有的非ASCII字符都要编码之后再传输。因此数据会暴露在url中;浏览器对url也有长度限制
-
post是会修改服务器里面的数据的。无长度限制;不具有幂等性
3.TCP的拆包和栈包?
-
TCP是流式的数据传输,没有边界;
-
粘包可能产生的原因:
-
由Nagle算法造成的发送端的粘包;
-
发送方传输数据频繁,可能产生
-
接收端接收不及时造成的接收端粘包;
-
-
如何解决粘包问题:
-
由发送方产生的话,可以通过编程设置避免,即利用TCP提供的强制数据立即传送的操作指令push,此命令表示tcp软件一收到此命令后,立马将本段数据传送出去,而不需要等待发送缓冲区满。即关闭Nagle算法
-
通过定长算法:每次发送规定好长度的数据,因数据不足规定长度,故可能造成带宽浪费。
-
尾部标记:在每一个数据包的尾部设计一个特殊的字节序列,表到达此数据包的边界了。
-
头部标记分步接收:定义一个用户报头,在报头中注明每次发送的数据包大小。此方法避免了程序设计的复杂性,其有效性便于验证,软件设计也更稳定;但,数据发送多了封装报头的动作;接收方将每个包的接收拆分成了两次,对内核性能是有影响的。
-
采用短连接,也不会出现粘包问题。
-
4.UDP为啥不需要考虑粘包拆包
-
面向无连接,每个数据包都有自己完整的数据源、目的地址及其分组编号,各自在网络中独自传输。
-
UDP支持的是一对多的模式,所以接收端的skbuff(套接字缓冲区)采用了链式结构来记录每一个到达的UDP包,在每个UDP包中就有了消息头(消息来源地址,端口等信息
mysql学习
-
-
确认是否使用了 set autocommit=0。这个确认工作可以在测试环境中开展,把 MySQL 的 general_log 开起来,然后随便跑一个业务逻辑,通过 general_log 的日志来确认。一般框架如果会设置这个值,也就会提供参数来控制行为,你的目标就是把它改成 1。
-
确认是否有不必要的只读事务。有些框架会习惯不管什么语句先用 begin/commit 框起来。我见过有些是业务并没有这个需要,但是也把好几个 select 语句放到了事务中。这种只读事务可以去掉。
-
业务连接数据库的时候,根据业务本身的预估,通过 SET MAX_EXECUTION_TIME 命令,来控制每个语句执行的最长时间,避免单个语句意外执行太长时间。(为什么会意外?在后续的文章中会提到这类案例)
-
-
其次,从数据库端来看:监控 information_schema.Innodb_trx 表,设置长事务阈值,超过就报警 / 或者 kill;
-
Percona 的 pt-kill 这个工具不错,推荐使用;
-
在业务功能测试阶段要求输出所有的 general_log,分析日志行为提前发现问题;
-
如果使用的是 MySQL 5.6 或者更新版本,把 innodb_undo_tablespaces 设置成 2(或更大的值)。如果真的出现大事务导致回滚段过大,这样设置后清理起来更方便。
-
-
事务的概念是什么? 事务是对数据库中数据操作的保证数据逻辑一致的最小操作单位。
-
mysql的事务隔离级别读未提交, 读已提交, 可重复读, 串行各是什么意思? 读未提交:一个事务读取到了其他事务未提交的操作。 读已提交:一个事务读取到了其他事务已经提交的操作。 可重复读:一个事务从它开始到结束整个生命周期中,所能读取到的数据内容和它启动的时候所能读到的数据内容是相同的。不会出现在事务运行的整个过程中,不同的时间点读取到的数据不一样的情况。 串行化:所有的事务都进行排队执行,事务之间不存才并发的情况。读有读锁,写有写锁。读、读之间不影响,读、写和写、写之间互相排斥,当遇到排斥的情况后,后发生的事务需要等待先发生的事务执行完成后才可以执行。
-
读已提交, 可重复读是怎么通过视图构建实现的? 读已提交:会在事务中的每一个SQL语句执行的时候都为对应的SQL创建一个一致性视图。此时这个SQL能读取到已经提交的事务对数据的操作。 可重复读:会在事务启动的时候,为整个事务创建一个一致性视图,这个视图会贯穿到这个事务执行结束。在整个事务执行过程中,都使用这个视图中的数据作为一致性读的依据。
-
可重复读的使用场景举例? 对账的时候应该很有用 库管盘货
-
事务隔离是怎么通过read-view(读视图)实现的? 每一行数有多个版本,当我们要去读取数据的时候,要判断这个数据的版本号,对当前事务而言,是否可见,如果不可见,则要根据undolog计算得到上一个版本。如果上一个版本也不符合要求,则要找到再上一个版本, 直到找到对应正确的数据版本。
-
并发版本控制(MCVV)的概念是什么, 是怎么实现的? 同一个数据行,在数据库中存在多个版本号,这个版本号可以理解为当初操作这行数据的事务的事务ID。当多个事务在并发进行的时候,判断某个事务是否可以读取到某一行时, 会使用行的版本号,和当前事务的ID进行比较。如果发现比这个事务ID小,表示之前的事务提交的操作,对当前事务来说,此版本的数据可见。 如果发现这个数据的版本号比当前事务的ID大,则表示有未来发生的事务提交生成的,对当前事务来说,此版本的数据不可见。 如果发现这个竖行的版本号刚好等于某个正在运行的是事务ID,表示当前数据是由正运行的某个事务提交生成的,对当前事务来说,此版本数据不可见。 如果当前事务自己修改的数据,当前事务还是可以看到的。
-
使用长事务的弊病? 为什么使用常事务可能拖垮整个库? 长事务导致表空间持续增长,即便是事务提交或者回滚后,回滚表空间被是否后,表空间大小仍然不会被缩小。 长事务的存在导致锁发生冲突或等待的几率大大增加。 如果某个应用有发生锁等待后尝试重新建立连接的机制,那么在发生锁等待或冲突的时候,应用就会不断地发起新的连接,导致MySQL的连接数被占用爆满。MySQL不能在提供连接服务,就挂掉了。
-
事务的启动方式有哪几种? begin;--一致性读的视图不会马上创建,而是在执行begin后面的第一个操作innodb表的SQL语句时生成。这个SQL可以是select,update,delete,insert。事务ID也是此时被分配的 start transaction;--和begin的功能效果一样。 start transaciton with consistent snapshot;--该语句执行后,会马上创建一致性读的视图。这个是它和begin的区别。事务ID也是此时被分配的。
-
commit work and chain的语法是做什么用的? 提交上一个事务,并且再开启一个新的事务。它的功能等效于:commit + begin。
-
怎么查询各个表中的长事务? select * from information_schema.innodb_trx; 这个表中记录了所有正在运行的事务信息,里面有事务的开始时间。可以从这里看出哪些事务运行的时间比较长。
-
如何避免长事务的出现? 从数据库方面: a.设置autocommit=1,不要设置为0。 b.写脚本监控information_schemal.innodb_trx表中数据内容,发现长事务,kill掉它。 c.配置SQL语句所能执行的最大运行时间,如果查过最大运行时间后,中断这个运行事情长的SQL语句。 d.设置回滚表空单独存放,便于回收表空间。 从业务代码方面: a.确认是否使用了autocommit=0的配置,如果有关闭它,然后再业务代码中手动的使用begin;commit来操作。 b.检查业务逻辑代码,能拆分为小事务的不要用大事务。