c++基础问题总结(三)

1、TCP

  • TCP如何保证可靠性

(1)序列号、确认应答、超时重传

数据到达接收方,接收方需要发出一个确认应答,表示已经收到该数据段,并且确认序号会说明了它下一次需要接收的数据序列号。如果发送方迟迟未收到确认应答,那么可能是发送的数据丢失,也可能是确认应答丢失,这时发送方在等待一定时间后会进行重传。这个时间一般是2*RTT(报文段往返时间)+一个偏差值。

(2)窗口控制与高速重发控制/快速重传(重复确认应答)

TCP会利用窗口控制来提高传输速度,意思是在一个窗口大小内,不用一定要等到应答才能发送下一段数据,窗口大小就是无需等待确认而可以继续发送数据的最大值。如果不使用窗口控制,每一个没收到确认应答的数据都要重发。

使用窗口控制,如果数据段1001-2000丢失,后面数据每次传输,确认应答都会不停地发送序号为1001的应答,表示我要接收1001开始的数据,发送端如果收到3次相同应答,就会立刻进行重发;但还有种情况有可能是数据都收到了,但是有的应答丢失了,这种情况不会进行重发,因为发送端知道,如果是数据段丢失,接收端不会放过它的,会疯狂向它提醒......

(3)拥塞控制

如果把窗口定的很大,发送端连续发送大量的数据,可能会造成网络的拥堵(大家都在用网,你在这狂发,吞吐量就那么大,当然会堵),甚至造成网络的瘫痪。所以TCP在为了防止这种情况而进行了拥塞控制。

慢启动:定义拥塞窗口,一开始将该窗口大小设为1,之后每次收到确认应答(经过一个rtt),将拥塞窗口大小*2。

拥塞避免:设置慢启动阈值,一般开始都设为65536。拥塞避免是指当拥塞窗口大小达到这个阈值,拥塞窗口的值不再指数上升,而是加法增加(每次确认应答/每个rtt,拥塞窗口大小+1),以此来避免拥塞。

将报文段的超时重传看做拥塞,则一旦发生超时重传,我们需要先将阈值设为当前窗口大小的一半,并且将窗口大小设为初值1,然后重新进入慢启动过程。

快速重传:在遇到3次重复确认应答(高速重发控制)时,代表收到了3个报文段,但是这之前的1个段丢失了,便对它进行立即重传。

然后,先将阈值设为当前窗口大小的一半,然后将拥塞窗口大小设为慢启动阈值+3的大小。

这样可以达到:在TCP通信时,网络吞吐量呈现逐渐的上升,并且随着拥堵来降低吞吐量,再进入慢慢上升的过程,网络不会轻易的发生瘫痪。

  • 三次握手

1. Client将标志位SYN置为1,随机产生一个值seq=J,并将该数据包发送给Server,Client进入SYN_SENT状态,等待Server确认。

2. Server收到数据包后由标志位SYN=1知道Client请求建立连接,Server将标志位SYN和ACK都置为1,ack=J+1,随机产生一个值seq=K,并将该数据包发送给Client以确认连接请求,Server进入SYN_RCVD状态。

3. Client收到确认后,检查ack是否为J+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=K+1,并将该数据包发送给Server,Server检查ack是否为K+1,ACK是否为1,如果正确则连接建立成功,Client和Server进入ESTABLISHED状态,完成三次握手,随后Client与Server之间可以开始传输数据了。

  • 四次挥手

由于TCP连接时全双工的,因此,每个方向都必须要单独进行关闭,这一原则是当一方完成数据发送任务后,发送一个FIN来终止这一方向的连接,收到一个FIN只是意味着这一方向上没有数据流动了,即不会再收到数据了,但是在这个TCP连接上仍然能够发送数据,直到这一方向也发送了FIN。首先进行关闭的一方将执行主动关闭,而另一方则执行被动关闭。

1.数据传输结束后,客户端的应用进程发出连接释放报文段,并停止发送数据,客户端进入FIN_WAIT_1状态,此时客户端依然可以接收服务器发送来的数据。

2.服务器接收到FIN后,发送一个ACK给客户端,确认序号为收到的序号+1,服务器进入CLOSE_WAIT状态。客户端收到后进入FIN_WAIT_2状态。

3.当服务器没有数据要发送时,服务器发送一个FIN报文,此时服务器进入LAST_ACK状态,等待客户端的确认

4.客户端收到服务器的FIN报文后,给服务器发送一个ACK报文,确认序列号为收到的序号+1。此时客户端进入TIME_WAIT状态,等待2MSL(MSL:报文段最大生存时间),然后关闭连接。


2、HTTP和HTTPS

  • 区别:

1)HTTP协议是以明文的方式在网络中传输数据,而HTTPS协议传输的数据则是经过TLS加密后的,HTTPS具有更高的安全性;

2)HTTPS在TCP三次握手阶段之后,还需要进行SSL 的handshake,协商加密使用的对称加密密钥;

3)HTTPS协议需要服务端申请证书,浏览器端安装对应的根证书;

4)HTTP协议端口是80,HTTPS协议端口是443;

  • HTTPS优点:

HTTPS传输数据过程中使用密钥进行加密,所以安全性更高

HTTPS协议可以认证用户和服务器,确保数据发送到正确的用户和服务器

  • HTTPS缺点:

​​​​​HTTPS握手阶段延时较高:由于在进行HTTP会话之前还需要进行SSL握手,因此HTTPS协议握手阶段延时增加;

HTTPS部署成本高:一方面HTTPS协议需要使用证书来验证自身的安全性,所以需要购买CA证书;另一方面由于采用HTTPS协议需要进行加解密的计算,占用CPU资源较多,需要的服务器配置或数目高;

  • HTTP返回码:

1xx:指示信息--表示请求已接收,继续处理。

2xx:成功--表示请求已被成功接收、理解、接受。

3xx:重定向--要完成请求必须进行更进一步的操作。

4xx:客户端错误--请求有语法错误或请求无法实现。

5xx:服务器端错误--服务器未能实现合法的请求。

常用的状态码:

  1. 200 OK:请求已正常处理。
  2. 204 No Content:请求处理成功,但没有任何资源可以返回给客户端。
  3. 206 Partial Content:是对资源某一部分的请求。
  4. 301 Moved Permanently:永久性重定向。资源的uri已更新。
  5. 302 Found:临时性重定向。资源的URI已临时定位到其他位置了。
  6. 304 Not Modified:资源已找到,但未符合条件请求。
  7. 400 Bad Request:服务器端无法理解客户端发送的请求,请求报文中可能存在语法错误。
  8. 401 Unauthorized:该状态码表示发送的请求需要有通过HTTP认证(BASIC认证,DIGEST认证)的认证信息。
  9. 403 Forbidden:不允许访问那个资源。该状态码表明对请求资源的访问被服务器拒绝了。(权限,未授权IP等)。
  10. 404 Not Found:服务器上没有请求的资源。路径错误等。
  11. 500 Internal Server Error:貌似服务器内部资源出故障了。
  12. 503 Service Unavailable:服务器暂时处于超负载或正在停机维护,现在无法处理请求。

3、数据库事务

事务(Transaction)是由一系列对系统中数据进行访问与更新的操作所组成的一个程序执行逻辑单元。事务是DBMS中最基础的单位,事务不可分割。

事务具有4个基本特征,分别是:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Duration),简称ACID。

1. 原子性(Atomicity)

原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。

2. 一致性(Consistency)

一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。

拿转账来说,假设用户A和用户B两者的钱加起来一共是5000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是5000,这就是事务的一致性。

3. 隔离性(Isolation)

隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。

即要达到这么一种效果:对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始,这样每个事务都感觉不到有其他事务在并发地执行。

多个事务并发访问时,事务之间是隔离的,一个事务不应该影响其它事务运行效果。

这指的是在并发环境中,当不同的事务同时操纵相同的数据时,每个事务都有各自的完整数据空间。由并发事务所做的修改必须与任何其他并发事务所做的修改隔离。

不同的隔离级别:

Read Uncommitted(读取未提交内容):最低的隔离级别,什么都不需要做,一个事务可以读到另一个事务未提交的结果。所有的并发事务问题都会发生。

Read Committed(读取提交内容):只有在事务提交后,其更新结果才会被其他事务看见。可以解决脏读问题。

Repeated Read(可重复读):在一个事务中,对于同一份数据的读取结果总是相同的,无论是否有其他事务对这份数据进行操作,以及这个事务是否提交。可以解决脏读、不可重复读。

Serialization(可串行化):事务串行化执行,隔离级别最高,牺牲了系统的并发性。可以解决并发事务的所有问题。

4. 持久性(Durability)

持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。

例如我们在使用JDBC操作数据库时,在提交事务方法后,提示用户事务操作完成,当我们程序执行完成直到看到提示后,就可以认定事务以及正确提交,即使这时候数据库出现了问题,也必须要将我们的事务完全执行完成,否则就会造成我们看到提示事务处理完毕,但是数据库因为故障而没有执行事务的重大错误。


4、数据库三大范式

第一范式(1NF):

定义:关系模式R的每个属性都不可再分,符合1NF。

1NF强调数据表的原子性

第二范式(2NF):

定义:关系模式R满足1NF,并且R得所有非主属性都完全依赖于R的每一个候选关键属性,称R满足2NF。

2NF强调数据表的唯一性,要求记录有惟一标识,即实体的惟一性,即不存在部分依赖。

第三范式(3NF):

定义:关系模式R满足2NF,X是R的任意属性集,如果X非传递依赖于R的任意一个候选关键字,称R满足第三范式,即非主属性不传递依赖于键码。

3NF是对字段冗余性的约束,即任何字段不能由其他字段派生出来,它要求字段没有冗余。


5、mysql四种隔离状态

  • 事务并发会产生的问题:

1、脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据

2、不可重复读:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致。

3、幻读:系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。

小结:不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表。

事务隔离级别脏读不可重复读幻读
读未提交(read-uncommitted)
不可重复读(read-committed)
可重复读(repeatable-read)
串行化(serializable)

6、索引

索引:对表中的一列或者多列进行排序的结构,可快速访问表中的特定信息。

创建索引可以大大提高系统的性能。 

索引常见模型:

哈希表、有序数组、二叉搜索树

优点:
1、通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。 
2、可以大大加快数据的检索速度,这也是创建索引的最主要的原因。 
3、可以加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义。 
4、在使用分组和排序子句进行数据检索时,同样可以显著减少查询中分组和排序的时间。 
5、通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能。
 

缺点:

1、创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加。 
2、索引需要占物理空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间,如果要建立聚簇索引,那么需要的空间就会更大。 
3、当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,这样就降低了数据的维护速度。

添加索引原则:

1、在查询中很少使用或者参考的列不应该创建索引;

2、只有很少的数据值的列不应该增加索引;

3、定义为text、image、bit数据类型的列不应该创建索引;

4、修改性能远远大于检索性能时,不应该创建索引;

索引分类:

  • 聚集索引:聚集索引表示表中存储的数据按照索引的顺序存储,检索效率比非聚集索引高,但对数据更新影响较大;

  • 非聚集索引:非聚集索引表示数据存储在一个地方,索引存储在另一个地方,索引带有指针指向数据的存储位置,非聚集索引检索效率比聚集索引低,但对数据更新影响较小。


7、mysql的锁

锁的设计是处理并发问题的,根据加锁的范围, MySQL里面的锁大致可以分成全局锁表级锁行锁三类。

全局锁:

对整个数据库实例加锁。

全局锁的典型使用场景是, 做全库逻辑备份。

表级锁:

MySQL里面表级别的锁有两种: 一种是表锁, 一种是元数据锁( meta data lock, MDL)。

在MySQL 5.5版本中引入了MDL, 当对一个表做增删改查操作的时候, 加MDL读锁; 当要对表做结构变更操作的时候, 加MDL写锁;

  • 读锁之间不互斥, 因此你可以有多个线程同时对一张表增删改查。
  • 读写锁之间、 写锁之间是互斥的, 用来保证变更表结构操作的安全性。 因此, 如果有两个线程要同时给一个表加字段, 其中一个要等另一个执行完才能开始执行。

行锁:

两阶段锁:在InnoDB事务中, 行锁是在需要的时候才加上的, 但并不是不需要了就立刻释放, 而是要等到事务结束时才释放。 这个就是两阶段锁协议。

如果你的事务中需要锁多个行, 要把最可能造成锁冲突、 最可能影响并发度的锁尽量往后放。
死锁和死锁检测:

一种策略是, 直接进入等待, 直到超时。 这个超时时间可以通过参数innodb_lock_wait_timeout来设置。
另一种策略是, 发起死锁检测, 发现死锁后, 主动回滚死锁链条中的某一个事务, 让其他事务得以继续执行。 将参数innodb_deadlock_detect设置为on, 表示开启这个逻辑。

每个新来的被堵住的线程, 都要判断会不会由于自己的加入导致了死锁, 这是一个时间复杂度是O(n)的操作。 假设有1000个并发线程要同时更新同一行, 那么死锁检测操作就是100万这个量级的。 虽然最终检测的结果是没有死锁, 但是这期间要消耗大量的CPU资源。 因此, 你就会看到CPU利用率很高, 但是每秒却执行不了几个事务。
根据上面的分析, 我们来讨论一下, 怎么解决由这种热点行更新导致的性能问题呢? 问题的症结在于 死锁检测要耗费大量的CPU资源。

解决办法:临时把死锁检测关掉控制并发度



 


 




 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值