Mysql
mysql事务
共享锁与排他锁
共享锁:允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁。(读都允许读,但我在读不允许你去改)
排他锁:允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁。(我在修改数据,别的操作都被禁止)
事务特性
事务四个特性:ACID
- 原子性(Atomicity):指事务是一个不可分割的最小工作单位,事务中的操作只有都发生和都不发生两种情况
- 一致性(Consistency):数据库总是从一个一致性的状态转换到另外一个一致性的状态。
- 隔离性(Isolation):一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
- 持久性(Durability):一个事务一旦提交成功,它对数据库中数据的改变将是永久性的,接下来的其他操作或故障不应对其有任何影响。
如何实现这些特性
- 原子性:靠Undo log实现,即如果一个事务异常或执行失败后进行回滚
- 当事务对数据库进行修改时,InnoDB会生成对应的 undo log;
- 如果事务执行失败或调用了 rollback,导致事务需要回滚,便可以利用 undo log 中的信息将数据回滚到修改之前的样子。
- undo log 属于逻辑日志,它记录的是sql执行相关的信息。
- 当发生回滚时,InnoDB 会根据 undo log 的内容做与之前相反的工作
- 一致性:事务的最终目的,即需要数据库层面保证,又需要应用层面进行保证,并且MySQL底层通过两阶段提交事务保证了事务持久化时的一致性。
- 隔离性:靠锁和MVCC实现
- 锁:
- 在 InnoDB 事务中,行锁通过给索引上的索引项加锁来实现。
- 只有通过索引条件检索数据,InnoDB才使用行级锁,否则将使用表锁。
- 行级锁定同样分为两种类型:共享锁和排他锁
- 使用Record Lock和Gap Lock(解决幻读)
- MVCC:多版本并发控制
- DB_TRX_ID:事务 ID,是根据事务产生时间顺序自动递增的
- DB_ROLL_PTR:回滚指针,本质上就是一个指向记录对应的undo log的一个指针,InnoDB 通过这个指针找到之前版本的数据
- MVCC在事务开启时会为事务生成一个ID,并且在查询时生成一个快照,能看到当前活跃的事务,然后通过比较快照的生成时间和活跃事务的提交时间进行对比,判断读取哪个版本的数据。
- 锁:
- 持久性:靠Redo log实现
- mysq|修改数据的时候会在redo log中记录一份日志数据,就算数据没有保存成功,只要日志保存成功了,数据仍然不会丢失
- 当一条数据需要更新时,InnoDB会先将数据更新,然后记录redoLog 在内存中,然后找个时间将redoLog的操作执行到磁盘上的文件上。
mysql隔离级别
mysql具有四种隔离级别
隔离级别 | 说明 |
---|---|
读未提交 | 一个事务还没提交时,它做的变更就能被别的事务看到 |
读已提交 | 一个事务提交之后,它做的变更才会被其他事务看到 |
一个事务提交之后,它做的变更才会被其他事务看到 | 一个事务中,对同一份数据的读取结果总是相同的,无论是否有其他事务对这份数据进行操作,以及这个事务是否提交。InnoDB默认级别 |
串行化 | 事务串行化执行,每次读都需要获得表级共享锁,读写相互都会阻塞,隔离级别最高,牺牲系统并发性。 |
不同的隔离级别是为了解决不同的问题。也就是脏读、幻读、不可重复读。
问题 | 说明 |
---|---|
脏读 | 读到了其他事务未提交的数据 |
不可重复读 | 在一个事务内,最开始读到的数据和事务结束前的任意时刻读到的同一批数据出现不一致的情况 |
幻读 | 在一个事务中,后续读取的数据,在最开始读取的数据中不存在 |
隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
读未提交 | 可以出现 | 可以出现 | 可以出现 |
读已提交 | 不允许出现 | 可以出现 | 可以出现 |
一个事务提交之后,它做的变更才会被其他事务看到 | 不允许出现 | 不允许出现 | 可以出现 |
串行化 | 不允许出现 | 不允许出现 | 不允许出现 |
Mysql和MangoDB的比较
Mysql:
- 关系数据库系统,相关信息可能存储在单独的表中,但通过使用关联查询来关联。通过使用这种方式,使得数据重复量被最小化。
- 关系型数据库的最大特点就是事务的一致性
- 为了维护一执行需要消耗大量的性能
MangoDB:
- 少量数据时,数据存在内存中。当内存不够时,只将热点数据放在内存,其他存入磁盘
- 数据存储在类似JSON的文档中,并且文档中每个json串结构可能有所不同
- 使用动态模式,这意味着您可以在不首先定义结构的情况下创建记录,例如字段或其值的类型
- 支持多种存储格式(mysql只支持基本类型)
- 设计了高可用性和可扩展性,并提供了即用型复制和自动分片功能。
- 简化了开发,因为 MongoDB 文档自然映射到现代的面向对象编程语言。使用 MongoDB 可以避免将代码中的对象转换为关系表的复杂对象关系映射(ORM)层。
sql优化
select *
浪费资源,减少使用,且不走索引union all
比union
更快(但是不去重)- 小表驱动大表:大表
in
小表 ; 小表exists
大表; - 批量插入数据尽量使用
insertBatch
,而不是循环(循环会多次请求数据库) - 多使用
limit
,减少内存消耗 - 海量数据查询分页,使用条件查询结合
limt size
,去替代limit start size
- 使用连接查询代替子查询(子查询会为子查询额外创建一个表)
join
的表不能太多,否则容易选错索引- 索引不宜太多,因为在增删改查的时候都需要更新索引表(使用联合索引)
- 将
group by
后接的having
条件适当提到前面的where
中
Spring
maven中版本 版本冲突
maven依赖中不允许存在两个不同版本的同名依赖。(添加<exclusion>
标签来解决冲突)
Kafka
Kafka和其他消息队列对比
对比 | Kafka | RocketMQ | RabbitMQ |
---|---|---|---|
优先级队列 | 不支持 | 通过建立不同的队列 | 通过建立不同的队列 |
延迟队列 | 不支持 | 基于队列的延迟 | 基于队列的延迟 |
死信队列 | 不支持 | 支持 | 支持 |
消费模式 | pull | pull/push | pull/push |
广播模式 | 发布订阅 | 发布订阅 | 点对点 (但可以由交换机实现发布订阅模式) |
消息回溯 | offset和timestamp | 按时间回溯 | 不支持 |
消息堆积&持久化 | 磁盘堆积:所有消息都存在磁盘 每个partition对应一个或多个segment file | 基于磁盘存储 使用commit Log存储消息(顺序写到文章末尾) 后台异步线程同步到consumerQueue 使用内存映射文件加速消息读取 | 内存堆积(换页操作存储到磁盘) (或使用惰性队列将消息持久化到磁盘) |
流量控制 | 支持client和user级别 | 多种维度的流量控制 | 流量控制基于credit-base算法,是内部被动触发的保护机制,作用于生产者层面 |
顺序性消息 | 同分区内有序 | Broker消息队列锁(分布式锁) Consumer消息队列锁(本地锁) Consumer消息处理队列消费锁(本地锁) | 无法保证全局有序 |
性能 | 最快 | 中等 | 最慢 |
高可用和容错 | 包含Leaer和Follower Leader失效后随机选举Leader | Master和Slave | cluster(集群),federation(联盟),shovel |
定时消息 | 不支持 | 支持 | 支持 |
负载均衡 (三者都是软件负载均衡) | consumer端实现 每个消费者组都有指定一个broker为coordinator(群组协调器) | consumer端实现 所有的consumer都能得到consumer的订阅表,每个consumer自己做负载均衡 | 设置Prefetch count来限制Queue每次发送给每个消费者的消息数 |
刷盘策略 | 异步刷盘 每3s钟调用1次fsync 支持同步刷盘 | CommitRealTimeService 异步刷盘 && 开启内存字节缓冲区 第一 FLushRealTimeService 异步刷盘 && 关闭内存字节缓冲区 第二 GroupCommitService 同步刷盘 第三 | 优先内存存储,Buff不够再刷盘 |
消息中间件 | Kafka | RocketMQ | RabbitMQ |
---|---|---|---|
特点 | 高吞吐量 持久性 分布式 发布订阅 | 高可用性 顺序消息 分布式事务 高扩展性 | 灵活路由 点对点+发布订阅+请求响应 可靠性 插件扩展 |
适用场景 | 流式处理(日志收集 实时分析) 大数据集成 可靠性(持久化)要求高 | 异步消息处理 顺序消息 分布式事务 | 复杂路由 灵活消息模式 异步任务处理 |
Redis
缓存穿透、击穿、雪崩
缓存穿透
指访问一个缓存和数据库中都不存在的key,由于这个key在缓存中不存在,则会到数据库中查询,数据库中也不存在该key,无法将数据添加到缓存中,所以每次都会访问数据库导致数据库压力增大。
解决办法
将访问过的key设置为空key,加入到缓存中
缓存击穿
指大量请求访问缓存中的一个key时,该key过期了,导致这些请求都去直接访问数据库,短时间大量的请求可能会将数据库击垮。
解决办法
添加互斥锁或分布式锁,让一个线程去访问数据库,将数据添加到缓存中后,其他线程直接从缓存中获取。
热点数据key不过期,定时更新缓存
缓存雪崩
指在系统运行过程中,缓存服务宕机或大量的key值同时过期,导致所有请求都直接访问数据库导致数据库压力增大
解决办法
将key的过期时间打散,避免大量key同时过期。
对缓存服务做高可用处理。
加互斥锁,同一key值只允许一个线程去访问数据库,其余线程等待写入后直接从缓存中获取。
缓存不一致
数据库中的数据和Redis缓存中的数据不一致的问题
出现原因:
缓存和数据库中都需要更新数据,对二者的操作无法保证原子性的情况下,就会出现不一致问题
解决办法:
- 重试机制:使用消息队列暂存要操作的数据,操作失败再从消息队列取回
- 延迟双删:先删除缓存数据 ->再执行update更新数据表 ->最后(延迟N秒)再删除缓存
Redis的优势
数据存在内存中,直接与内存相连,读写速度很快。
使用单线程模型,无多线程 竞争 锁 等问题
支持数据持久化
支持数据备份 master-slave模式数据备份(需要多个redis实例)
操作均为原子性的
Redis持久化
- AOF:采用日志的形式来记录每个写操作,追加到AOF文件的末尾(默认情况是不开启AOF)重启时再重新执行AOF文件中的命令来恢复数据(AOF是执行完命令后才记录日志的)
- RDB:把内存数据以快照的形式保存到磁盘上。RDB持久化,是指在指定的时间间隔内,执行指定次数的写操作
Redis面对大量访问时的处理办法
Redis是单线程服务,所有指令都是顺序执行,当某一指令耗时很长时,就会阻塞后续的指令执行。当被积压的指令越来越多时,Redis服务占用CPU将不断升高,最终导致Redis实例崩溃甚至服务器宕机。
处理办法:
- 使用Redis连接池
- 批量操作,使用Redis管道机制
- 使用合适的数据结构和命令
- 使用Reids集群
Redis面对大量数据存储
- 数据分片,将数据存储到多个Redis节点上
- 使用合适的数据结构
- 合理设置过期时间
- 使用持久化机制
Redis键的设计
- 遵循基本格式:[业务名称]:[数据名]:[id]
长度不超过44字节 - 拒绝BigKey
- 恰当的数据格式
对象格式的数据可以采用json存储,但是更好的是采用hash格式存储 - 将集合类型中数据量大的进行拆分
Redis中各类型的底层结构
String:简单动态字符串
List:双向链表或压缩链表(ziplist)
- 双向链表:列表长度较长或包含较多元素
- 压缩链表:在一定程度上减少内存使用,存储在连续的内存区域中
Set:哈希表(Hash Table)和跳跃表(Skip List)
- 哈希表:集合元素较多或元素大。将集合的元素作为哈希表的键,值被设为固定的空值
- 跳跃表:有序的数据结构,支持快速查找、插入和删除(因此也被用于ZSet)
ZSet:使用跳跃表存储元素,使用哈希表存储 元素:分值
Hash:哈希表和压缩链表
- 哈希表:hash类型的字段数量较多,或字段大小较大时
- 压缩链表:字段的顺序是按照插入的先后顺序进行存储的
Elasticsearch
es的数据格式怎么规定的
通过mapping进行定义,可以查看我的相关文档 ElasticSearch 其中的mapping映射属性
为什么使用es
- 分布式实时文件存储,可将每一个字段存入索引,使其可以被检索到
- 实时分析的分布式搜索引擎
- 索引分拆成多个分片,每个分片可以有多个副本存储在不同的节点上,负载均衡等
- 可以扩展到上百台服务器
- 支持插件机制,分词插件、同步插件、Hadoop插件、可视化插件等
Docker
Docker镜像
Docker参考文章
Docker 容器的运行是基于宿主机的内核,通过linux的namespaces来实现隔离,相对于虚拟机而言降低了硬件资源的性能损耗,且具备一定程度上的应用隔离效果。
镜像是一种轻量级,可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件所需的所有内容,包括代码、运行时、库、环境变量和配置文件。
Java基础
Hash冲突的解决方式
- 链表法(HashMap)+ 红黑树(默认链表长度超过8)
- 再哈希法
- 开放定址法
- 建立公共溢出区
HashMap和CurrentHashMap的对比
HashMap线程不同步,底层使用链表和红黑树的方式处理冲突
CurrentHashMap:
- JDK 1.7 :使用segment数组,每个segment中存储一定量的HashEntry,HashEntry用链表处理冲突;线程安全通过锁被操作的segment
- JDK 1.8 :直接使用Node结点,使用Synchronized和CAS的方式实现线程安全
红黑树的特性,以及保持平衡的方式
- 每个结点不是红色就是黑色
- 根节点是黑色的
- 如果一个节点是红色的,则它的子结点必须是黑色的(没有连续的红色节点)
- 对于每个结点,从该结点到其所有可到达的叶结点的路径中,均包含相同数目的黑色结点
- 每个 NIL 叶子结点都是黑色的(此处的叶子结点指的是空结点)
保持平衡:
- 插入:
- 插入新节点涂红色
- 如果父节点为黑色不用操作
- 如果父节点为红色
- 父节点无兄弟节点或父节点的兄弟节点为黑色,直接旋转操作
- 父节点有兄弟结点,且兄弟结点也为黑色,直接上溢:将父节点和叔都涂为黑色,将祖父节点涂为红色,然后在上溢部分继续判断是否需要处理
- 删除:
- 删除结点都在B树的最后一层,可以理解为都在红黑树的最下面2层
- 删除最后一层的红色结点没有影响
- 删除最后一层的黑色节点:
- 如果黑色节点有2个子节点,不允许删除
- 如果黑色结点只有一个子节点,删除黑色结点,并用子节点取代该位置,同时染成黑色
- 如果黑色结点为叶子节点:
- 该节点没有兄弟节点(只能是根节点),直接删除
- 该节点的兄弟结点为黑色,旋转兄弟结点
- 该节点的兄弟结点为红色,旋转兄弟和父节点
线程
自定义线程池有哪些参数,分别是什么
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler)
参数 | 参数意义 | 参数名称 | 参数要求 |
---|---|---|---|
参数一 | 指定线程池的线程数量(核心线程) | corePoolSize | 不能小于0 |
参数二 | 指定线程池可支持的最大线程数 | maximumPoolSize | 最大数量 >= 核心线程数量 |
参数三 | 指定临时线程的最大存活时间 | keepAliveTime | 不能小于0 |
参数四 | 指定存活时间的单位(秒、分、时、天) | unit | 时间单位 |
参数五 | 指定任务队列 | workQueue | 不能为null |
参数六 | 指定用哪个线程工厂创建线程 | threadFactory | 不能为null |
参数七 | 指定线程忙,任务满的时候,新任务来了怎么办 | handler | 不能为null |
volitail关键字
保证了不同线程之间对共享变量操作的可见性
- 每个线程都能从主内存中获取volitail修饰的属性,并缓存在本地工作内存中
- 一旦有线程修改了该值,会自动刷新到主内存中,同时其他内存中的该值失效,再次访问需要重新到主内存中获取
禁止对指令进行重排序操作。
- 保证该指令前的所有指令都执行,该指令后的所有指令都未执行
锁
AQS
AQS
( Abstract Queued Synchronizer )是一个抽象的队列同步器,通过维护一个共享资源状态( Volatile Int State )和一个先进先出( FIFO )的线程等待队列来实现一个多线程访问共享资源的同步框架。
原理:
AQS 为每个共享资源都设置一个共享资源锁,线程在需要访问共享资源时首先需要获取共享资源锁,如果获取到了共享资源锁,便可以在当前线程中使用该共享资源,如果获取不到,则将该线程放入线程等待队列(先进先出),等待下一次资源调度
使用:
在使用AQS创建自定义锁时,AQS一般是被内部类去继承实现的。需要去重写几个方法:tryAcquire(int)
,tryRelease(int)
,tryAcquireShared(int)
,tryReleaseShared(int)
,isHeldExclusively()
(最后一个方法一般在需要使用condition时才需要重写,即当某线程需要放到条件队列中,遇到某条件才唤醒时使用)
在使用时可以在tryAcquire(int)
和tryRelease(int)
中使用getState()
,setState(int)
,compareAndSetState(int,int)
去获取和改变AQS的状态码,AQS的状态码默认情况下是:0代表锁可用,1代表锁被占有;使用setExclusiveOwnerThread()设置独占资源的线程;因此可以在tryAcquire(int)
获取状态码,为0的情况下置为1,并返回true,在tryRelease(int)
将状态码置为0,完成锁的释放。在继承AQS类并重写完这些方法后,就可以调用其本身的acquire和release方法获取和释放锁了。
CAS如何实现
CAS:CompareAndSwep,其中包括几个参数:①对象本身②值的内存偏移地址③期望更新的值(旧值)④更新的值(新值),只有当目前的值和期望更新的值相同时,才会去完成更新操作,否则会自旋或者不操作。
但作为乐观锁,可能会遇到ABA问题,可用版本号和时间戳来解决
共享锁
mysql的行锁中的读锁即是共享锁。即:多个线程如果都对某一行数据发起读请求,就会尝试获取该行数据的共享锁,可由多个线程或事务获取到该共享锁,即读操作可同时发生。
与此相对的就是排他锁/互斥锁,一旦获取了一行数据的排他锁/互斥锁,其他事务或线程就不能获取该数据的任何锁;并且如某行数据被获取了共享锁,也不能再被获取排他锁/互斥锁。
读可共享-读写不共享-写写不共享
分布式锁
分布式锁用于解决分布式系统中控制共享资源的访问
Redis的分布式锁:
- 使用setnx添加锁(setnx保证原子性,且只有在key不存在时才能成功,即多个系统并发获取锁,也只有一个系统能成功获取到锁)
set <lock.key> <lock.value> nx ex <expireTime>
同时用ex能设置过期时间 - 可使用del主动释放锁,即直接删除该键值对
- 可重入锁的实现方式:hash类型设置可重入锁,
HSETNX
,然后通过获取其中的字段判断是否可重入,并且能够设置重入的次数。 - 使用Redission的看门狗机制或者自定义守护线程维护获取锁的业务的锁过期时间
ReentrantLock和Synchronized
ReentrantLock | Synchronized | |
---|---|---|
锁实现机制 | 依赖AQS | 监视器模式 |
灵活性 | 支持响应中断、超时、尝试获取锁 | 不灵活 |
释放形式 | 必须显式调用unlock() | 自动释放监视器 |
锁类型 | 公平锁&非公平锁 | 非公平锁 |
条件队列 | 可关联多个条件队列 | 关联一个条件队列 |
可重入性 | 可重入 | 可重入 |
JVM
JVM有哪些垃圾回收器
垃圾回收器 | 版本 | 适用范围 | 特点 | 算法 |
---|---|---|---|---|
Serial(串行收集器) | jdk1.1 | 新生代 | 只会使用一个CPU或者一条GC线程进行垃圾回收 并且在垃圾回收过程中暂停其他工作线程 | 标记-复制-清除 |
ParNew | jdk1.3 | 新生代 | Serial的多线程版本 | 标记-复制-清除 |
Parallel Scavenge | jdk1.4 | 新生代 | 追求CPU吞吐量的优化 能在较短的时间内完成指定的任务 | 标记-复制-清除 |
Serial Old | jdk1.3 | 老年代 | 单线程 暂停应用程序执行 | 标记-整理 |
Parallel Old | jdk1.5 | 老年代 | 多线程 和用户线程并发 | 标记-整理 |
CMS(concurrent mark sweep) | jdk1.4 | 老年代 | 初始标记(停) 并发标记(运) 重新标记(运) 并发清除 | 标记-清除 |
G1 | jdk1.7引入 jdk1.9默认 | 老年代 | 重新标记阶段停止业务线程 软实时 内存划分变为Region并评估每个region价值 首先清除垃圾最多的区域 | 标记-整理 |
类加载机制
java源码经过javac编译后形成class字节码文件,jvm将字节码文件加载进内存,经过字节码验证器验证,为类变量进行内存分配和初始化零值,字节码解释器解释执行字节码指令转换为底层机器代码并执行。
双亲委派
如果一个类加载器收到了类加载的请求,他首先不会自己去尝试加载这个类,而是把这个请求委派父类加载器去完成。每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父加载器反馈自己无法完成这个请求时,子加载器才会尝试自己去加载。
当发现在某一步该类已经被加载过时,会直接返回已加载的类,避免重复加载
反射
反射通过类加载器加载class字节码文件实现,可通过一个类的字节码获取该类的所有信息,包括属性、方法等
获取类对象:
Class<?> clazz = MyClass.class;
通过类字面常量获取类对象Class<?> clazz = Class.forName("com.example.MyClass");
通过Class.forName()方法获取MyClass object = new MyClass(); Class<?> clazz = obj.getClass();
通过对象的getClass()获取Class<?> clazz = getClass().getClassLoader().loadClass("com.example.MyClass");
根据类对象生成对象实例:Object object = (Object)clazz.newInstance();
根据类对象获取属性和方法:
getFields()
:获取所有public的属性getDeclaredFields()
:获取所有(不限修饰符的)属性getType
:以Class形式返回类型getName
:返回属性名setAccessible(true)
:使用
getMethods()
:获取所有pubic的方法getDeclaredMethods()
:获取所有(不限修饰符的)方法getReturnType
:以Class形式获取返回类型getName
:返回方法名getParameterTypes
:以Class[]返回参数类型数组invoke(obj, param1, ...)
:调用方法
getConstructors()
:获取所有public的构造方法getDeclaredConstructors()
:获取所有(不限修饰符的)构造方法getModifiers
:以int形式返回修饰符.getName
:返回构造器名(全类名).getParameterTypes
:以Class[]返回参数类型数组
异常
异常的分类,以及有什么区别
Error(错误):是程序无法处理的错误,表示代码运行时JVM出现的问题。例如:OutOfMemoryError
、NullPointerException
Exception(异常):是程序本身可以处理的异常。
- RuntimeException:运行时异常,不受检查异常,表示JVM常用操作引发的错误,编译时能通过,但会在后期代码的执行过程中暴露出来
- 其他异常:受检查异常,在编译时不能被忽略,程序必须对它有相应的处理
计算机网络
Https为什么安全
- 浏览器发起 HTTPS 请求
- 服务端返回 HTTPS 证书
- 客户端验证证书是否合法,如果不合法则提示告警
- 当证书验证合法后,在本地生成随机数
- 通过公钥加密随机数,并把加密后的随机数传输到服务端
- 服务端通过私钥对随机数进行解密
- 服务端通过客户端传入的随机数构造对称加密算法,对返回结果内容进行加密后传输
数据传输是用对称加密:非对称加密的加解密效率非常低
- https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。
- http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
- http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
- http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。
TCP拥塞控制
- 慢启动
- 最初拥塞控制窗口cwnd的初始值为一个小值,推荐为2个MSS(MSS通常为536字节或1460字节)
- MSS:Maximum Segment Size ,最大报文段长度,TCP提交给IP层最大分段大小
- 当收到一个ACK后,
cwnd = cwnd*2
- 最初拥塞控制窗口cwnd的初始值为一个小值,推荐为2个MSS(MSS通常为536字节或1460字节)
- 拥塞避免
- 拥塞窗口cwnd值等于慢开始门限值后,
cwnd = cwnd+1
- 拥塞窗口cwnd值等于慢开始门限值后,
- 快速恢复
- 拥塞时,将慢开始门限修改为cwnd/2,并且将
cwnd = cwnd/2
- 拥塞时,将慢开始门限修改为cwnd/2,并且将
- 快速重传
- 连续收到3条对某报文段的重传确认,就需要快速重传该报文段
地址框输入url后经历了什么
- DNS解析
- 在自己的DNS高速缓存中查找
- 权限域名服务器->顶级域名服务器->根域名服务器
- TCP连接
- TCP三次握手
- 发送HTTP请求
- 服务端处理请求:根据路径查找对应的资源(服务),然后返回数据报
- 浏览器收到返回的数据,进行渲染,形成页面
- TCP断开
- 四次挥手