- 2025-04-23·Java后端查看全文复习第十五天 Java 中 volatile 关键字的作用是什么? 可见性,禁止指令重排序 可见性:读主内存 禁止指令重排序:内存屏障,读屏障,写屏障...编程导航_小y:恭喜小伙伴参与编程导航活动,可查看私信填写奖励收集表410分享
- 2025-04-16·Java后端查看全文复习第八天 进程的调度算法你知道吗? 先来先服务:优点:公平,缺点:长作业影响后面的短作业运行 短作业优先:优点:可以得到最小等待事件 缺点:长作业可能饥饿...600分享
人以伪来 我以诚往
安卓八股文
复习第十五天 Java 中 volatile 关键字的作用是什么? 可见性,禁止指令重排序 可见性:读主内存 禁止指令重排序:内存屏障,读屏障,写屏障 Synchronized 和 ReentrantLock 有什么区别? Synchronized 是一种基础的同步操作,没有非公平和超时等待的概率 Synchronized 实现锁主要依赖与监视器锁和对象头 需要先获取到对象头的监视器锁才能进行执行 修饰方法: 修饰代码快: JDK1.6对Synchronized 的优化 偏向锁 轻量级锁 重量级锁 锁消除 锁粗化 ReentrantLock 是AQS的具体实现 包含state、同步队列、条件队列 state: * state为1表示锁被占有 * state为0表示锁空闲 同步队列 * 非公平锁时,如果抢不到锁,通过CAS抢锁,如果还是抢不到,加入同步队列中 条件队列 * 使用Contidion.wait() 加入条件队列,使用Condition.singnal()从条件队列加入同步队列中 ReentrantLock 是一种比较复杂的锁,可以实现公平和超时 说说 AQS 吧? 抽象队列同步器,定义了一系列规范,很多同步器都对其进行了实现,比如说ReentrantLock、Semaphore、CyclicBarrier、CountDownLatch等 核心:volatile修饰的state变量和CLH队列 CLH队列的演变过程 * CAS自旋一个变量,产生总线风暴 * CLH通过一个隐式队列,每个线程自旋判断前一个线程是否释放了锁 * AQS实现的CLH队列 通过一个双向队列,除了队头的线程是持有锁的,其他的都处于阻塞状态,队头释放锁通知下一个线程执行。 Redis 中的 Big Key 问题是什么?如何解决? 占用内存比较大的key 问题: * 内存倾斜 * 服务端查找慢 * 网络传输也慢 * 客户端超时 解决: * 数据压缩 * 拆分 * 只存储必要信息 Redis 集群的实现原理是什么? 每个节点负责一部分的数据,2^14次方个槽位,通过hash计算出键所在的槽位 请求的时候随机请求一个节点,如果不存在,放回数据所在节点的信息给客户端,客户端重新请求 如何保证节点中数据的一致性? 使用Gossip协议 每个节点发生自身的信息给其他节点 其他节点收到信息之后和自身的信息汇总继续发送给其他节点,也就是更新哈希槽数组的信息,每一个槽指向那个节点实例 最终整个集群达到一致性 为什么槽的数目是2^14次方? 主要是为了防止心跳包太大了 如何解决 Redis 中的热点 key 问题? 访问频率占比很高的key 限流 读写分离 多级缓存 拆分 发现 hotkey命令 monitor命令
复习第十四天 什么是 Java 的 CAS(Compare-And-Swap)操作? 存在的问题 ABA:通过添加版本解决 单变量 循环开销 你使用过哪些 Java 并发工具类? Semaphore acquire release 信号量 AtomicInteger 原子整形 ReentranLock 可重入锁 CyclicBarrier 循环屏障 循环屏障 wait CountDown 计数器 wait countdown 你了解 Java 线程池的原理吗? 核心参数:核心线程数、最大线程数、存活时间、工作队列、拒绝策略 工作队列: SynchronizedQueue:不使用队列 PriorityQueue: LinkedBlockQueue: ArrayBlockQueue: 拒绝策略: 丢弃抛出异常 直接丢弃 丢弃队头元素 调用者来执行 创建线程池方式: 单个 多个 不设上限 定时任务 偷取任务的 Redis 数据过期后的删除策略是什么? 定期删除:周期性删除100ms,拉取20个键,判断是否有超过25%的键过期,如果是,则继续拉去,总时长不可以超过25ms。缺点CPU占用率高 惰性删除:查找到的时候才删除,缺点:内存泄露 兜底策略 如果内存满了 最近最少使用 最少使用频率 随机删除 最小存活时间的进行删除 不执行删除操作,拒绝 Redis 主从复制的实现原理是什么? 主节点将数据同步给从节点 开始同步 全量同步:psync ?-1 触发全量复制,主节点生成RDB文件发给从节点,从节点根据RDB文件进行重放,主节点将这生成RDB文件之后的数据也发给从节点。 增量同步:主节点和从节点会维护一个长链接,psync 主节点ID offset 主节点从环形缓冲区中取出偏移量后面的数据发给从节点,如果没有,则进行全量复制 Redis 的持久化机制有哪些? RDB:生成内存中的一个快照,以二进制的形式进行存储,适合主从复制,备份等场景 AOF:写入命令的时候追加到AOF文件中,实时性比较高 RDB优点:恢复快,服务器宕机后可以使用其进行恢复 缺点:缺少上一次备份后的数据 AOF优点:缺失数据比较少 缺点:恢复速度比较慢 生成RDB流程 * 先判断是否在生成RDB或者执行AOF重写 * fork一个子进程 * 子进程复制生成RDB文件 * 将新的替换旧的 生成RDB过程中的写入操作 * 使用写时复制技术 * 将要写入数据所在的页进行复制 AOF重写 * fork一个子进程 * 将内存中的键转化为对应的写入命令,写入到AOF文件中 * 主进程仍然将新的请求写入到原来的AOF缓冲区并刷入到原来的AOF文件中 * 主进程还需要将重写期间的命令写入新的AOF文件中 * 新的替换旧的 混合持久化机制 * 先fork一个子进程 * 生成RDB文件 * 将RDB文件添加到AOF的头部,将生成RDB文件期间新增的数据添加到AOF文件中 * 旧的替换新的 * redis7.0做了优化,主进程直接生成增量AOF文件,然后和重写的AOF文件进行合并
复习第十三天 Java 中 HashMap 的扩容机制是怎样的? Java 中有哪些集合类?请简单介绍 说说 Java 中 HashMap 的原理? 存储键值对,通过计算键值的hash值,找到数组中对应的位置进行插入,如果存在元素,则产生冲突,此时使用链表或者红黑树解决冲突(JDK1.8之后引入红黑树) 扩容和负载因子 Redis 实现分布式锁时可能遇到的问题有哪些? * 锁过期 * 锁被误释放 * 单点故障 * 主从故障 * 时钟漂移 * 网络分区 Redis 的 Red Lock 是什么?你了解吗? redis的红锁,当主从架构的时候,如果主节点加完锁还没同步给从节点,主节点就挂了,此时会有多个线程获取到锁。此时就需要红锁来避免这一过程。 具体来说 * 存在多个实例通常是5个 * 客户端轮询向这多个实例中加锁, * 只有超过半数的加锁成功才算成功 缺点: * 复杂度高,是一个重锁 * 多个锁续期复杂 * 时钟漂移问题 * 不适合高并发场景,多个锁同时加锁时间长 Redis 中如何实现分布式锁? 使用lua脚本加setnx 加锁:set key_lock value_unique ex expire_time nx 解锁:使用lua脚本,先获取唯一标识,判断是否是当前线程加的锁,如果是才能释放锁,完整的流程,需要使用lua脚本来实现。 为什么要有唯一值? 防止锁被误释放 为什么要设置过期时间? 防止用户程序崩溃导致锁无法释放 复习第十二天 (补昨天的) 接口和抽象类有什么区别? 接口是规范,客户端不需要底层的具体实现,对客户端无感。(JDK1.8及之后可以实现默认方法和静态方法) 抽象类是模板:便于子类的复用和重写。 JDK 动态代理和 CGLIB 动态代理有什么区别? JDK动态代理:代理类需要实现接口,通过实现Invocationhandler来增强被代理累。然后在客户端中使用Proxy创建代理类 CGLIB动态代理:基于字节码的形式,通过生成被代理累的子类来对对象进行增强 你使用过 Java 的反射机制吗?如何应用反射? 可以动态的创建对象和访问方法和属性 核心时Class类 通过Class类创建实例对象 访问方法clazz.getMethods() 访问属性class.getField() Redis String 类型的底层实现是什么?(SDS) 简单动态字符串 和C语言先比 * O(1)获取长度 * 预留空间 * 动态扩容 此外还有多种编码方式 * int编码:存储整数 * embstr编码:存储短字符串,元数据(编码类型)和SDS存放在一起 * raw编码:长字符串,元素局和SDS分开存储 Redis 中的缓存击穿、缓存穿透和缓存雪崩是什么? 缓存击穿: 热点数据过期。 加锁,用不过期 缓存穿透: 大量请求数据库不存在的数据 缓存空值 加锁 布隆过滤器 缓存雪崩: 热点数据同时过期、或者缓存服务崩溃 * 随机性,加锁 * 集群架构 Redis 中如何保证缓存与数据库的数据一致性? 先更新数据库后更新缓存 先更新缓存后更新数据库 先删除缓存后更新数据库 先更新数据库后删除缓存 先删除缓存后更新数据库,在删除缓存(缓存双删) 基于binlog日志文件的异步更新缓存 实时一致性 度写锁,读读不互斥,读写互斥 读流程 * 读锁 * 先查询缓存 * 缓存命中返回 释放读锁 * 不命中,查询数据库,写入缓存,返回 * 释放读锁 写流程 * 写锁 * 写数据库 * 删除缓存 * 释放写锁
复习第十一天 什么是软中断、什么是硬中断? 软中断:软件中断,需要请求内核的服务,(网络传输、文件读取等),从用户态切换到内核态(上下文切换) 硬中断:硬件中断,网卡、硬盘、计时器等发起的中断,优先级高,却要进行上下文切换,根据中断向量,通过中断向量表,找到对应的中断处理程序进行执行。 什么是分段、什么是分页? 分段和分页都是内存管理技术 分页:页的大小是固定的,将物理内存和逻辑内存分成大小相同的页或页框,会存在内部碎片 分段:段的大小不固定,根据程序的逻辑功能进行划分(代码段、程序段、堆栈段),会出现外部碎片 段页式:先按程序的逻辑进行分段,然后再进行分页,使用(段号,页号,页内偏移量)来表示逻辑内存,通过其找到对应的物理内存。 说下你常用的 Linux 命令? cd ls mkdir cp mv tar -zxvf tar -zcvf chmod 777 ps -ef | grep java top kill ipconfg Redis 的 hash 是什么? Redis 中跳表的实现原理是什么? Redis Zset 的实现原理是什么? 底层是哈希表+跳表 可以用来实现排行版 哈希表:用于等值查询 跳表:用于范围查询 当元素个数小于128 且 元素大小小于64B的时候,使用压缩列表 JDK1.7后使用紧凑列表,否则使用哈希表+跳表 哈希表底层原理 将多个键值对存储在一个键中 适合存储对象,购物车等场景 底层实现 当元素个数小于512 且 元素大小小于64B的时候使用的是压缩列表或紧凑列表(JDK1.7之后),否则使用哈希表 哈希表的底层原理 在哈希表的结构体中,有一个table数组、数组大小、掩码(大小-1)和元素个数 其中table数组存储的是一个个的键值对 当发送冲突的时候使用链表解决 扩容和缩容 扩容:主要根据负载因子的情况判断,当元素个数达到所允许的负载的时候,则会继续扩容,扩容为原来的两倍 缩容:当元素的个数比较少的时候,会进行缩容,缩小为元素个数最近的那个2次幂 扩容时机: 当负载因子大于1,且此时在进行RDB生成或者AOF重写,则先不进行扩容,否则进行扩容 当负载银日大于5,无论是否继续持久化,都立即进行扩容 缩容: 负载因子小于0.1的时候 渐进式扩容 一点点的扩容 扩容的时候会使用多一个哈希表结构体,在这两个哈希表的上层,还有一个结构体引向它们,存储这哈希表数组[0]和[1],还有rehashidx,当进行渐进式扩容的时候rehashidx为一个非-1的值,表示扩容的进度 每次增删改查的时候,将一部分的数据移动到新的数组中去 新增加的数据直接添加到新数组中 最终完成渐进式哈希的时候,将rehashidx设置为-1,表示扩容完毕。 跳表: 有多条链表,越往上的链表存储的元素个数越少, 查找流程:从最上层的链表开始查找,如果能从当前链表中直接找到,则返回,如果找不到则确定一个区间,进入下一层继续查找,直到来到最后一层的链表,最后一层的链表是包含所有元素,找到则返回,找不到说明元素不存在。 插入流程:从最上层的链表开始查找,确定插入的区间(每一层都记录区间的左节点),进入下一层继续查找,直到来到最后一层的链表,找到插入的位置,此时通过摇塞子的形式,判断当前插入元素会横跨多少层,此时上面记录区间的左节点就有用了,可以方便在多层进行插入。 ★学习紧凑列表和压缩列表的思想 压缩列表 * 记录节点数目 * 记录占用空间大小 * 记录尾节点的距离开始节点的偏移量(辅助倒序遍历) * 列表节点(每个节点会存储上一个节点的长度信息1字节~5字节,这里是级联更新的关键) 紧凑列表(和紧凑列表类似) * 记录节点数目 * 记录占用空间大小 * ❌不需要记录尾节点的距离开始节点的偏移量(也就是不支持倒序遍历) * 列表节点(只存储自身的节点长度信息,且放在尾部) 问题:哈希表和HashMap有什么区别
复习第十天 为什么要有虚拟内存? 虚拟内存,实际看起来比实际内存多 虚拟内存由三大特性 虚拟性: 对换性: 多次性: 到底什么是 Reactor? 可以处理多个网络请求,基于同步非阻塞IO(NIO),由事件来驱动。 核心组件: 1、Reactor:反应器,将客户端的请求转发到对应的Acceptor(连接请求)和handler(具体的读写请求) 2、Acceptor:处理连接请求,为连接分配handler和向Acceptor注册该handler 3、Handler:处理具体的读写请求 单Reactor单线程:处理简单的业务 单Reactor多线程:处理中等复杂的连接请求 主从Reactor多线程:主Reactor复杂将连接请求发给Acceptor,将读写请求发给从Reactor。 什么是用户态和内核态? 用户态:权限低,无法直接操作硬件和执行特权指令,需要通过系统调用的方式,请求内核提供服务 内核态:权限高,可以直接操作硬件和执行特权指令(进程调度、内存管理),软件中断和硬件中断,从用户态到内核态需要进行上下文的切换 软中断:软件中断,请求系统服务(网络处理,文件读取),需要进入内核态,产生上下文切换 硬中断:硬件中断,如时钟、计时器、硬盘、网卡中断,每个硬件有一个中断向量,通过中断向量表找到对应的中断处理程序,需要上下文切换。 为什么 Redis 设计为单线程?6.0 版本为何引入多线程? 单线程、没有上下文的切换。 使用IO多路复用,单个线程可以监听多个客户端请求。 基于内存,内存的操作速度比磁盘要快很多1000倍。 引入多线程? Redis的性能瓶颈主要在网络IO这一块,IO多路复用本质上还是同步IO,将数据在用户空间和内核之间来回拷贝还是需要Redis线程参与,使用多线程的话能够有效减轻这一过程的负担。但具体的指令执行仍然是单线程的所以还是线程安全的。 Redis 为什么这么快? 单线程、没有上下文的切换。 使用IO多路复用,单个线程可以监听多个客户端请求。 基于内存,内存的操作速度比磁盘要快很多1000倍。 Redis 中常见的数据类型有哪些? String,底层简单动态字符串SDS,最大512MB,分布式事务、锁、对象、计数器 List,底层双向链表,消息队列(需要自行实现消息唯一ID和消费组的概念) Hash,底层哈希表,存储对象购物车场景 Set,底层哈希表,集合运算,,共同关注 ZSet,底层哈希表+跳表,排行榜 BitMap,位图,布隆过滤器 Stream,消息队列,实现了消息ID和消费组的概念 HyperLogLog,基数统计,基于概率统计一个集合中不重复元素的个数 GEO:适合地理位置信息的计算
复习第九天 为什么网络 I/O 会被阻塞? 读:缓存区中没有数据 写:缓冲区中数据满了 accept 等待别人连接也需要时间 connect 三次握手需要阻塞 系统资源有限:无法创建新的连接 Select、Poll、Epoll 之间有什么区别? Select和Poll 线程每次调用select或者poll的时候,将文件描述符数组拷贝给内核,内核遍历文件描述符,看看是否有事件完成,如果完成了则将修改后的文件描述符数据拷贝回用户空间,线程遍历数组获取改变的文件描述符进行处理 Select:文件描述符数量固定通常为1024个 Poll:文件描述符数量不固定 Epoll是对select、poll的改进 不需要再内核和用户空间中来回拷贝数组 epoll_create(),在内核中会维护一颗B+数 epoll_ctl(),向这颗B+数种注册文件描述符 epoll_wait(),每次有事件发生的时候,就将文件描述符添加到就绪链表中 线程只需要遍历就绪链表即可处理响应的事件。 I/O模型有哪些? 服务器发起IO请求(比如read读取内核中的数据),申请内核服务,内核从网卡中读取数据进行处理,然后将数据从内核写回到用户空间 同步阻塞IO:一直处于阻塞状态 同步非阻塞IO:只有将数据从内核拷贝回用户空间才需要阻塞 IO多路复用:可以处理多个IO请求(select、poll、epoll),本质上还是同步IO 信号驱动时IO:只有当数据准备好时,才通知服务器过来处理数据,用户不需要一直轮询 异步IO:服务器发起IO请求之后,一直到数据从内核拷贝回用户空间都不需要参与 如何处理 MySQL 的主从同步延迟? 首先主从延迟是一定会存在的 1、二次查询 2、关键查询走主库 3、写后立即查的走主库 4、使用缓存 减少主从查询? 从从库上入手 1、使用并行复制 2、硬件 3、物理距离 4、减少慢查询 5、从库不能太多 什么是 MySQL 的主从同步机制?它是如何实现的? 主节点将数据同步给从节点 主节点将数据写入binlog,将binlog传给从节点,等待一部分从节点的回复同步完成,然后在通知客户端,从节点将binlog日志转移到relay log中继日志中,然后据此进行回放操作。 同步复制:需要等待所有从节点同步完成才通知客户端 半同步复制:只需要部分从节点同步完成就通知客户端 异步复制:不需要从节点回复就通知可以端 并行复制:从节点使用并行的方式进行复制操作 库级别的:不同的数据库可以并行执行 组级别:同时处于prepare状态的事务可以并行执行 基于WriteSet的:串行的也能并行复制,通过ID进行哈希运算,判断是否可以并行执行 MySQL 中如何解决深度分页的问题? 1、记录上一次查询的最大ID 2、子查询 select * from table limit 10000000, 10 换成 select * from table where id > (select id from table order by id limit 1) limit 10
复习第八天 进程的调度算法你知道吗? 先来先服务:优点:公平,缺点:长作业影响后面的短作业运行 短作业优先:优点:可以得到最小等待事件 缺点:长作业可能饥饿 优先级调度:优点:根据任务轻重来执行 缺点:优先级低的可能饥饿 时间片轮转算法:优点:客户端的响应性比较好 缺点:时间片不好确定 最高响应比优先:优点:解决短作业优先中的长作业饥饿问题 缺点:需要实时计算响应比 多级反馈队列调度算法:优点:适合多种场景 缺点:实现复杂 进程之间的通信方式有哪些? 管道:本质是一个文件,单方向通信,先进先出,不限制传输的数据格式 匿名管道:用于父子进程间的通信 有名管道:只要有进程使用管道就不会被销毁 消息队列:多个进程可以往一个消息队列中写入和读取数据 共享内存:多个进程往一片共享的内存区域中写入和读取数据,需要实现同步 信号量:可以用于实现同步和互斥操作,初始值1互斥,0同步 信号:当有事件发生的时候通知线程 套接字:用于不同网络之间的进程间的通信 线程和进程有什么区别? 线程:CPU调度的基本单位,多个线程共享进程的内存区域,但也有自己独立的栈和寄存器,线程创建和切换速度相对较快,但需要注意线程安全问题 进程:资源分配机基本单位,每个进程有自己独立的内存区域,进程创建和切换开销大,通信复杂 MySQL 中如果发生死锁应该如何解决? 1、死锁检测机制,回滚占有资源少的事务 2、等待时间过长也会自动回滚 3、手动kill 有以下几个方式可以减少死锁的发生? 1、减少长事务 2、降低事务的隔离级别为读已提交 3、开启死锁检测 4、合理创建索引,避免锁住过多的范围 5、合理安排锁的申请顺序,先获取大的锁 为了保证binlog 和 undo log 的一致性 MySQL 事务的二阶段提交是什么? 事务提交的时,先写redo log并设置为prepara状态 再写binlog 最后再将redolog设置为comiit状态 什么时binlog redolog? binlog:二进制日志,记录的是实际操作过程中的sql语句 redolog:重做日志,记录的是具体物理页的修改,系统崩溃的时候如果发现物理页和redolog记录的不一样,则需要重新修改保持一致。 为什么需要二阶段提交? 如果没有二阶段提交,无论是先提交redo log 还是binlog 如果提交一个成功后崩溃了,那会导致数据不一致的问题 虽然可以通过补写的方式完成,但还是不如二阶段提交 MySQL 中有哪些锁类型? 行锁: 表锁: 读锁: 写锁: 间隙锁:锁住记录前后的一片间隙 临建锁:锁住记录和记录前后的间隙
复习第七天 说说 AQS 吧? 抽象队列同步器,定义了一系列规范,是其他同步器的基础 核心:volatile修饰的state变量,等待队列、条件队列 state变量:独占锁的时候1表示被占由,0表示空闲 等待队列(CLH):非公平锁的情况下,先抢占锁,如果强不到,则通过CAS自旋,如果还是没抢到,则进入等待队列中 为什么使用CLH队列? 自旋锁:多个线程CAS一个变量,可能造成总线风暴 CLH:对自旋锁的改进,多个线程组成一个隐式队列,每个线程自旋查看前一个线程的状态,如果上一个线程释放锁了自己则可以获取 AQS实现的CLH:多个线程组成一个双向队列,只有队头的是在运行,其他的都是阻塞的,当队头的释放锁的时候在通知后一个线程获取锁。 Synchronized 和 ReentrantLock 有什么区别? Synchronized 基于JDK层面的,适合基本的同步操作,不能实现超时、非公平等操作 ReentrantLock 基于JUC并发包下的,适合复杂的同步操作,可以实现超时、非公平等操作 Synchronized 原理 依赖于监视器和对象头来实现同步操作 修饰方法时:会在方法的访问标志中加上ACC_SYNC标注,当线程访问该方法的时候,会先去获取它的监视器锁,获取到了才能继续执行 修饰代码:在代码的前面加上mnitorenter,具体代码,在代码的后面加上monitorexit来实现同步操作 本质都是获取对象的监视器锁 对象头: Mark Work:运行时的数据,GC年龄、锁的信息(偏向锁、轻量级锁。) Class Point:指向类元信息 Synchronized jdk1.6后优化 偏向锁:监视器锁偏向于第一个获取它的线程 轻量级锁:如果获取一个被偏向的锁,则会通过自旋的方式获取 重量级锁:如果自旋失败了,则会继续阻塞操作 锁粗化:多个锁如果和一个锁等效,则会锁粗化 锁消除:通过逃逸分析,如果发现代码不会存在线程安全,则锁消除。 ReentrantLock 原理 是AQS的具体实现之一,可重入锁 核心:volatile修饰的state变量,等待队列、条件队列 state变量:独占锁的时候1表示被占由,0表示空闲 等待队列:非公平锁的情况下,先抢占锁,如果强不到,则通过CAS自旋,如果还是没抢到,则进入等待队列中 条件队列:如果不满足条件调用Condition.wait()继续等待,需要其他线程调用Condition.signal()进行唤醒,或者设置超时等待 Java 中 volatile 关键字的作用是什么? 保证被修饰变量的可见性和禁止指令重排序 可见性:强制线程读取volatile修饰的变量的时候不从工作内存中读取,而是直接去主内存中读取 禁止指令重排序:通过插入内存屏障的方式来禁止指令重排序,比如,读屏障:当读取volatile修饰的变量的时候,会在其前面插入读屏障,防止前面的指令重排到屏障后面去,写屏障:写volatile修饰的变量的时候,会在其后面插入写屏障,防止后面的指令重排到屏障前面去 用途: 双重检查锁定 从网络角度来看,用户从输入网址到网页显示,期间发生了什么? URL解析:解析URL封装成HTTP报文 DNS域名解析:将域名转化为对应的IP地址 TCP/UDP:将报文加上TCP头,为不同主机间的应用程序提供服务 IP:给报文再加上IP头,用于不用网络之间传输 MAC:继续加上MAC头,用于相邻节点之间的传输 网卡:将二进制转化为电信号通过网线进行传输 交换机:取下MAC头上的目标MAC地址和原MAC地址,根据交互机上的交换表选择端口进行传输,如果不存在则通过广播的形式找到端口 路由器:取下IP头上的目标IP地址,根据路由器上的路由表选择对应的网络进行传输 层层验证:最终到达服务器,服务器层层校验MAC、IP、根据TCP报上的端口找到主机上的应用程序 处理请求:应用程序处理具体的请求 返回相应:处理完成之后返回相应 前端进行渲染: 交换机:交换表,通过广播的形式进行更新 路由器:路由表,有内部网关协议OSPF(基于成本计算迪杰斯特拉单源最短路径),RIP(基于跳数),外部网关协议:BGP进行更新 DNS域名解析: 递归:查看本地缓存、浏览器、操作系统缓存看看是否有,如果没有客户端再去本地DNS服务器中招,如果没有本地去找顶级域名服务器,没有去找根域名,最后去找权威域名服务器 迭代:由客户端分别去问本地(得到根域名DNS)、根域名(得到顶级DNS)、顶级(得到权威DNS) Cookie、Session、Token 之间有什么区别? Cookie:存储在浏览器用户信息,适合存储不敏感的信息,比如个性化设置等 Session:存储在服务器的用户信息,安全性比较高,将session_id存储在cookie Token:一串加密的字符串,存储在客户端,每次客户端都带上这一串信息和用户信息,到服务器中去验证,可以跨平台使用。 TCP/IP 四层模型是什么? 应用层:为应用程序提供服务,比如HTTP,DNS,FTP 传输层:为不同主机上的应用程序提供服务,TCP、IP 网络层:为不同主机的网络通信提供服务,IP 网络链路层:为相邻的节点提供服务,以太网,PPP 为什么分层? 1、不同层之间的作用不同,层与层之间各司其职, 2、相互隔离又相互联调 TCP/IP四层模型和OSI七层模型有什么区别? OSI七层模型是一个理论层面的,但实现起来比较复杂,有很多层其实可以合并起来,所以市面上主要还是TCP/IP四层模型 数据库的脏读、不可重复读和幻读分别是什么? easy 脏读:在一个事务中,读取到未提交的数据 不可重复读:在一个事务中,多次读取一个数据,产生的结果是不一样的 幻读:在一个事务中,同一条查询语句,多次查询可能返回不同的结果集 MySQL 默认的事务隔离级别是什么?为什么选择这个级别? 默认的隔离级别是可重复读 主要是为了避免早期的binlog的statement格式进行主从复制的时候产生的数据不一致的问题(向前兼容) 在读已提交隔离级别下:现在有两个事务先后执行,事务1执行删除where a = 1操作后提交、事务2执行插入where a = 1操作先提交,此时主库中会存在where a = 1 这一条数据(因为事务1的删除操作是事务1的ReadView视图下执行的),在通过binlog去回放的时候却不会存在where a = 1者一条数据,因为binlog先记录的是插入,后记录的是删除操作 在可重复读隔离级别下:因为有行锁和临建锁,所以事务1已执行删除操作后,事务2是不能执行插入的。要等到事务1已经提交了才行。 MySQL 中的事务隔离级别有哪些? easy 读未提交:可以读到为提交的数据,产生脏读 读已提交:只能读取到已经提交的数据,但是不可以重复读 可重复读:可以重复读取,但是会产生幻读 串行化:事务与事务之间串行执行,此时不会出现幻读 读已提交:事务中每次select的时候都会产生一个ReadView视图 可重复读:事务中只有第一次select的时候会产生一个ReadView视图


