|
|
|
@ -172,7 +172,6 @@ SQL的执行顺序:from---where--group by---having---select---order by
|
|
|
|
|
* undoLog 也就是我们常说的回滚日志文件 主要用于事务中执行失败,进行回滚,以及MVCC中对于数据历史版本的查看。由引擎层的InnoDB引擎实现,是逻辑日志,记录数据修改被修改前的值,比如"把id='B' 修改为id = 'B2' ,那么undo日志就会用来存放id ='B'的记录”。当一条数据需要更新前,会先把修改前的记录存储在undolog中,如果这个修改出现异常,,则会使用undo日志来实现回滚操作,保证事务的一致性。当事务提交之后,undo log并不能立马被删除,而是会被放到待清理链表中,待判断没有事物用到该版本的信息时才可以清理相应undolog。它保存了事务发生之前的数据的一个版本,用于回滚,同时可以提供多版本并发控制下的读(MVCC),也即非锁定读。
|
|
|
|
|
* redoLog 是重做日志文件是记录数据修改之后的值,用于持久化到磁盘中。redo log包括两部分:一是内存中的日志缓冲(redo log buffer),该部分日志是易失性的;二是磁盘上的重做日志文件(redo log file),该部分日志是持久的。由引擎层的InnoDB引擎实现,是物理日志,记录的是物理数据页修改的信息,比如“某个数据页上内容发生了哪些改动”。当一条数据需要更新时,InnoDB会先将数据更新,然后记录redoLog 在内存中,然后找个时间将redoLog的操作执行到磁盘上的文件上。不管是否提交成功我都记录,你要是回滚了,那我连回滚的修改也记录。它确保了事务的持久性。每个InnoDB存储引擎至少有1个重做日志文件组(group),每个文件组下至少有2个重做日志文件,如默认的ib_logfile0和ib_logfile1。为了得到更高的可靠性,用户可以设置多个的镜像日志组(mirrored log groups),将不同的文件组放在不同的磁盘上,以此提高重做日志的高可用性。在日志组中每个重做日志文件的大小一致,并以循环写入的方式运行。InnoDB存储引擎先写重做日志文件1,当达到文件的最后时,会切换至重做日志文件2,再当重做日志文件2也被写满时,会再切换到重做日志文件1中。
|
|
|
|
|
* MVCC多版本并发控制是MySQL中基于乐观锁理论实现隔离级别的方式,用于读已提交和可重复读取隔离级别的实现。在MySQL中,会在表中每一条数据后面添加两个字段:最近修改该行数据的事务ID,指向该行(undolog表中)回滚段的指针。Read View判断行的可见性,创建一个新事务时,copy一份当前系统中的活跃事务列表。意思是,当前不应该被本事务看到的其他事务id列表。已提交读隔离级别下的事务在每次查询的开始都会生成一个独立的ReadView,而可重复读隔离级别则在第一次读的时候生成一个ReadView,之后的读都复用之前的ReadView。
|
|
|
|
|
* binlog由Mysql的Server层实现,是逻辑日志,记录的是sql语句的原始逻辑,比如"把id='B' 修改为id = ‘B2’。binlog会写入指定大小的物理文件中,是追加写入的,当前文件写满则会创建新的文件写入。 产生:事务提交的时候,一次性将事务中的sql语句,按照一定的格式记录到binlog中。用于复制和恢复在主从复制中,从库利用主库上的binlog进行重播(执行日志中记录的修改逻辑),实现主从同步。业务数据不一致或者错了,用binlog恢复。
|
|
|
|
|
|
|
|
|
|
### binlog和redolog的区别
|
|
|
|
|
|
|
|
|
@ -740,29 +739,6 @@ Kafka最初考虑的问题是,customer应该从brokes拉取消息还是brokers
|
|
|
|
|
4. 信号量:不能传递复杂消息,只能用来同步。
|
|
|
|
|
5. 共享内存区:能够很容易控制容量,速度快,但要保持同步,比如一个进程在写的时候,另一个进程要注意读写的问题,相当于线程中的线程安全,当然,共享内存区同样可以用作线程间通讯,不过没这个必要,线程间本来就已经共享了同一进程内的一块内存。
|
|
|
|
|
|
|
|
|
|
### 内存管理有哪几种方式
|
|
|
|
|
|
|
|
|
|
1. 块式管理:把主存分为一大块、一大块的,当所需的程序片断不在主存时就分配一块主存空间,把程序片断load入主存,就算所需的程序片度只有几个字节也只能把这一块分配给它。这样会造成很大的浪费,平均浪费了50%的内存空间,但是易于管理。
|
|
|
|
|
2. 页式管理:把主存分为一页一页的,每一页的空间要比一块一块的空间小很多,显然这种方法的空间利用率要比块式管理高很多。
|
|
|
|
|
3. 段式管理:把主存分为一段一段的,每一段的空间又要比一页一页的空间小很多,这种方法在空间利用率上又比页式管理高很多,但是也有另外一个缺点。一个程序片断可能会被分为几十段,这样很多时间就会被浪费在计算每一段的物理地址上。
|
|
|
|
|
4. 段页式管理:结合了段式管理和页式管理的优点。将程序分成若干段,每个段分成若干页。段页式管理每取一数据,要访问3次内存。
|
|
|
|
|
|
|
|
|
|
### 页面置换算法
|
|
|
|
|
|
|
|
|
|
1. 最佳置换算法OPT:只具有理论意义的算法,用来评价其他页面置换算法。置换策略是将当前页面中在未来最长时间内不会被访问的页置换出去。
|
|
|
|
|
2. 先进先出置换算法FIFO:简单粗暴的一种置换算法,没有考虑页面访问频率信息。每次淘汰最早调入的页面。
|
|
|
|
|
3. 最近最久未使用算法LRU:算法赋予每个页面一个访问字段,用来记录上次页面被访问到现在所经历的时间t,每次置换的时候把t值最大的页面置换出去(实现方面可以采用寄存器或者栈的方式实现)。
|
|
|
|
|
4. 时钟算法clock(也被称为是最近未使用算法NRU):页面设置一个访问位,并将页面链接为一个环形队列,页面被访问的时候访问位设置为1。页面置换的时候,如果当前指针所指页面访问为为0,那么置换,否则将其置为0,循环直到遇到一个访问为位0的页面。
|
|
|
|
|
5. 改进型Clock算法:在Clock算法的基础上添加一个修改位,替换时根究访问位和修改位综合判断。优先替换访问位和修改位都是0的页面,其次是访问位为0修改位为1的页面。
|
|
|
|
|
6. LFU最少使用算法LFU:设置寄存器记录页面被访问次数,每次置换的时候置换当前访问次数最少的。
|
|
|
|
|
|
|
|
|
|
### 操作系统中进程调度策略有哪几种
|
|
|
|
|
|
|
|
|
|
1. 先来先服务调度算法FCFS:队列实现,非抢占,先请求CPU的进程先分配到CPU,可以作为作业调度算法也可以作为进程调度算法;按作业或者进程到达的先后顺序依次调度,对于长作业比较有利.
|
|
|
|
|
2. 最短作业优先调度算法SJF:作业调度算法,算法从就绪队列中选择估计时间最短的作业进行处理,直到得出结果或者无法继续执行,平均等待时间最短,但难以知道下一个CPU区间长度;缺点:不利于长作业;未考虑作业的重要性;运行时间是预估的,并不靠谱.
|
|
|
|
|
3. 优先级调度算法(可以是抢占的,也可以是非抢占的):优先级越高越先分配到CPU,相同优先级先到先服务,存在的主要问题是:低优先级进程无穷等待CPU,会导致无穷阻塞或饥饿.
|
|
|
|
|
4. 时间片轮转调度算法(可抢占的):按到达的先后对进程放入队列中,然后给队首进程分配CPU时间片,时间片用完之后计时器发出中断,暂停当前进程并将其放到队列尾部,循环 ;队列中没有进程被分配超过一个时间片的CPU时间,除非它是唯一可运行的进程。如果进程的CPU区间超过了一个时间片,那么该进程就被抢占并放回就绪队列。
|
|
|
|
|
|
|
|
|
|
### 死锁的4个必要条件
|
|
|
|
|
|
|
|
|
|
1. 互斥条件:一个资源每次只能被一个线程使用;
|
|
|
|
@ -794,14 +770,6 @@ Kafka最初考虑的问题是,customer应该从brokes拉取消息还是brokers
|
|
|
|
|
4. 服务端响应HTTP响应报文,报文由状态行(status line)、相应头部(headers)、空行(blank line)和响应数据(response body)4个部分组成。
|
|
|
|
|
5. 浏览器解析渲染
|
|
|
|
|
|
|
|
|
|
### 计算机网络的五层模型
|
|
|
|
|
|
|
|
|
|
1. 应用层:为操作系统或网络应用程序提供访问网络服务的接口 ,通过应用进程间的交互完成特定网络应用。应用层定义的是应用进程间通信和交互的规则。(HTTP,FTP,SMTP,RPC)
|
|
|
|
|
2. 传输层:负责向两个主机中进程之间的通信提供通用数据服务。(TCP,UDP)
|
|
|
|
|
3. 网络层:负责对数据包进行路由选择和存储转发。(IP,ICMP(ping命令))
|
|
|
|
|
4. 数据链路层:两个相邻节点之间传送数据时,数据链路层将网络层交下来的IP数据报组装成帧,在两个相邻的链路上传送帧(frame)。每一帧包括数据和必要的控制信息。
|
|
|
|
|
5. 物理层:物理层所传数据单位是比特(bit)。物理层要考虑用多大的电压代表1 或 0 ,以及接受方如何识别发送方所发送的比特。
|
|
|
|
|
|
|
|
|
|
### tcp和udp区别
|
|
|
|
|
|
|
|
|
|
1. TCP面向连接,UDP是无连接的,即发送数据之前不需要建立连接。
|
|
|
|
@ -867,50 +835,7 @@ void quick_sort(int a[], int low, int high){
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
5. 堆排序:将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了。
|
|
|
|
|
```java
|
|
|
|
|
public class Test {
|
|
|
|
|
|
|
|
|
|
public void sort(int[] arr) {
|
|
|
|
|
for (int i = arr.length / 2 - 1; i >= 0; i--) {
|
|
|
|
|
adjustHeap(arr, i, arr.length);
|
|
|
|
|
}
|
|
|
|
|
for (int j = arr.length - 1; j > 0; j--) {
|
|
|
|
|
swap(arr, 0, j);
|
|
|
|
|
adjustHeap(arr, 0, j);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void adjustHeap(int[] arr, int i, int length) {
|
|
|
|
|
int temp = arr[i];
|
|
|
|
|
for (int k = i * 2 + 1; k < length; k = k * 2 + 1) {
|
|
|
|
|
if (k + 1 < length && arr[k] < arr[k + 1]) {
|
|
|
|
|
k++;
|
|
|
|
|
}
|
|
|
|
|
if (arr[k] > temp) {
|
|
|
|
|
arr[i] = arr[k];
|
|
|
|
|
i = k;
|
|
|
|
|
} else {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
arr[i] = temp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void swap(int[] arr, int a, int b) {
|
|
|
|
|
int temp = arr[a];
|
|
|
|
|
arr[a] = arr[b];
|
|
|
|
|
arr[b] = temp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void main(String[] args) {
|
|
|
|
|
int[] arr = {9, 8, 7, 6, 5, 4, 3, 2, 1};
|
|
|
|
|
new Test().sort(arr);
|
|
|
|
|
System.out.println(Arrays.toString(arr));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
5. 堆排序:假设序列有n个元素,先将这n建成大顶堆,然后取堆顶元素,与序列第n个元素交换,然后调整前n-1元素,使其重新成为堆,然后再取堆顶元素,与第n-1个元素交换,再调整前n-2个元素...直至整个序列有序。
|
|
|
|
|
6. 希尔排序:先将整个待排记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录基本有序时再对全体记录进行一次直接插入排序。
|
|
|
|
|
7. 归并排序:把有序表划分成元素个数尽量相等的两半,把两半元素分别排序,两个有序表合并成一个
|
|
|
|
|
|
|
|
|
|