weipai网络-面试回顾

本片章节:

介绍一下自己在实习期间的工作内容吧!
什么是四层代理、什么是七层代理?
介绍一下这个自己开发的上线项目吧!
MySQL常用的字符集及字符序;
有没有遇到过慢SQL问题;
需要在性别或年龄上建立索引吗?
事务的隔离级别;
tcp三握四挥;
redis的数据类型;
redis的Sorted_Set可以干什么;
五个数组如何找并集、交集;
跨域请求会不会到服务器那里;
二分查找; 

1. 介绍一下自己在实习期间的工作内容吧!

在这实习了两个月左右。大致做了四个方面的内容,分别是 服务测试、代理配置、优化代码以及线上项目开发 ;
服务测试:利用JMeter测试了小组开发的C++服务及利用PostMan测试了还未上线数据接口。输出了两份邮件、五份测试报告及五十多张结果截图;
代理配置:在进行线上项目开发时,组长给我了这样一个需求。为上线项目配置错误页面,因为当项目更新时要给用户一种良好的使用体验;
但是这个错误页面尽量不要放在项目中,单独做出来,复用一下。然后我就想到了Nginx来做这个需求;
后期由于用户需求的不断变更,组长又让我配置了负载均衡及传递用户IP的需求;
优化代码:团队开发了一个无人车巡逻的项目,组长在进行运维的时候给我提出了优化车辆巡逻模板的需求。因为初始的巡逻模板建立只能设置起点和终点,用户体验度不够;
然后我就从前端到后端整体完成了这个需求。难点在于设定中间点的次序问题及与算法的衔接部分;
项目开发:团队跟用户协商好了需求,说年后再进行项目开发。但后期时用户这边突然提出要看展示型项目。组长这边要求我在半个月之内做出一个演示项目。这其中涉及了 需求分析 数据库设定 设备协议设定 接口开发 设备联调  前端开发 打包部署 运维 这些工作内容;
核心功能是一个数据展示页面,虽然说项目总体难度不是很大,但是它是一个小而美的内容,让我学习到了小型项目的生命周期;

2. 什么是四层代理、什么是七层代理?

这个所谓的 四层、七层代理 是依据 网络模型 OSI 来划分的。OSI就是我们在计算机网络里面学的那个;
因为在OSI中,分为七层,从硬件到软件分别是:物理层、数据链路层、网络层、传输层、会话层、表示层、应用层;
而四层的就是传输层,也就是说四层代理就是代理传输层,而七层代理就是代理应用层;

四层代理和七层代理的区别:

四层代理:
四层代理是在传输层的,此时的代理只起到了一种转发的作用,当它接收到用户的请求之后,它会把修改报文中的目的IP地址为真实服务器的IP地址;
因为在使用四层代理的时候,用户访问的目的IP地址其实是四层代理的IP,当四层代理接收到用户的请求之后,会把报文中目的地址改为真实服务器的IP地址;
这样的过程实际只建立了一个TCP连接。是用户和服务器间的TCP连接,这个TCP没有四层代理的踪迹;
有时候根据配置的不同,四层代理服务器接收到用户的请求之后,也会把源地址给改了,改为四层代理的IP地址,这是为了防止真实服务器接收到请求之后转发错误;

七层代理:
作用于七层代理的服务器我们也可以称之为反向代理服务器;
当我们使用七层代理进行配置时,它的工作流程是这样的:用户请求七层代理,七层代理代替用户去请求真实的服务器;
再细致一些就是,当用户请求七层代理的时候,七层代理会拿到请求体,然后依据这个请求体去访问真实的服务器,真实的服务器把数据返回给七层代理;
七层代理拿到这些返回数据之后会拼接为一个响应体,然后再返回给用户那里去展示;
这里可以和四层代理区分一下,四层只起转发作用,不会拼接数据包的内容,但是七层代理是把用户的请求直接拦在自己这里了,然后代替用户访问服务器,之后拼接数据包然后再返回到用户那里;
当在使用七层代理时,用户需要访问的真实服务器其实通常是一个服务器集群,但我们肯定会把这样的集群配置进行一些隐匿的;
此时通常就会使用到七层代理,当用户请求真实的服务器集群时,首先访问的是七层代理再由七层代理代替用户去访问真实的服务器,真实的服务器把响应的数据返回给七层代理,由七层代理再转发给用户那里去;
这样的一种工作过程会建立两个TCP连接分别是 用户 和 七层代理之间,七层代理 和 服务器集群之间;

同时,七层代理和四层代理进行服务代理时依据的条件是不同的;
四层代理:
因为它作用在传输层,所以进行服务代理时它根据 IP+PORT 的方式进行工作;
七层代理:
七层代理作用于应用层,它可以使用 HTTP协议 URL Cookie 请求体 中的内容,所以依据的方法比较多样;

3. 介绍一下这个自己开发的上线项目吧!

说一下核心模块:
核心模块分为两个部分,分别是设备端数据接收及数据处理并展示;
使用的技术的SpringBoot+Vue,数据库是MySQL;
因为数据是由设备上传的,所以需要设定一份数据上报协议给设备开发人员。这是业务中比较特殊的部分;
之后就是拿设备上传的数据在页面中进行展示,数据分为数值型数据,还有GPS数据及图片数据;
图片直接放在了工程目录下,然后GPS使用到了百度地图的逆地址服务,因为这边使用的是WGS84这种经纬度格式;

4. MySQL常用的字符集及字符序

字符集:英文名字 character set ,它所代表的就是对于字符的编码形式。说到这里就必须要提到 GBK Unicode UTF-X ASCII;
其中上面列举的每一个都是一个字符集,其中GBK就是国标的意思,可以把它理解为我们汉字的编码形式,也就是属于我们汉字的字符集(同时呢,它也是我们中国人自己做出来的 哈);
Unicode也叫万国码,没错,它就是大一统的意思,使用它就可以包揽世界上几乎所有语言的字符编码形式;
但是呢,它类似于 OSI模型 和 ES6 一样,它们都是一种理论上的标准,实际上的产品落地通常会有落差,它的代表性产品就是UTF-X,所以说UTF-X具备万国码的特征,就是万金油,几乎所有的语言都可以使用它来作为自己的编码方式;
最后的就是ASCII了,它是美国做出来的字符集,所以说它只能编码那些 英文字母、特殊字符 ,因为英语文字中也只包含这些;

字符序:针对字符集而言,字符序没有那么多的开放性,它针对于字符的序列性,英文名字是 Collation ;
每一种字符集通常会有 1到多种的字符序,同时呢每两种字符集之间不会有共同的字符序。最后呢,每一种字符集都会有一个默认的字符序;
字符序描述的就是字符之间的排序规则,通常来说,字符序的命名会以 ci 或 cs 或 bin 来结尾;
ci:不区分大小写;
cs:区分大小写;
bin:使用二进制进行排序,区分大小写;
以 utf-8 来描述字符序,每一个字符序我们用一个SQL来理解:假设有一个表名为 user1 ,表中有俩字段,分别是 user_1_name 和 user_1_age ;
假设它使用了如下几种字符序,会出现这样的结果:
utf8_general_ci:SELECT user_1_name , user_1_age FROM USER1 WHERE User_1_name = 'LMJ' ; == SELECT user_1_name , user_1_age FROM USER1 WHERE User_1_name = 'lmj' ;
这俩SQL的最大不同就是 WHERE User_1_name = '' 处,在 ci 中因为不区分大小写,所以 lmj == LMJ ; 
utf8_general_cs:SELECT user_1_name , user_1_age FROM USER1 WHERE User_1_name = 'LMJ' ; != SELECT user_1_name , user_1_age FROM USER1 WHERE User_1_name = 'lmj' ;
而在 cs 中,LMJ != lmj ,所以最终的查询结果为空;
utf8_bin:bin 因为是基于二进制进行排序,所以和 cs 结果一致;

但是哈,这三种方式各有优缺,比如 ci 和 cs与bin 相比,ci 效率更快但是准确率低一些,而 cs和bin却恰恰相反。但最常用的是ci结尾;

解释一个小问题:
有些博客里面会说 ci 和 cs与bin 的区别在于 假设字段名为 user_1_name 时,ci 可以使用 USER_1_NAME 或者 user_1_name ,但 cs和bin 只能使用 user_1_name ;
他们的意思是区分大小是在这里体现的,其实他们说的是错误的哈!!!
MySQL 数据库在 windows 下是不区分大小写的,也就是说 select user_1_name from user == SELECT USER_1_NAME FROM USER ;
这是已知事实,但这个事实不是靠 cs ci bin 来决定的。而 cs ci bin 决定的是表里面的数据在进行写入和取出的时候是否会区分大小写(我建表实测过);

5. 有没有遇到过慢SQL问题

导致慢SQL的原因(通常就是索引失效):
	1. 使用 like '%李%' ,这个时候即使 name 上有索引也不会生效,因为 % 在模糊匹配字符串的第一个字符时索引会失效;
	2. 在使用联合索引时,没有使用联合索引的第一个字段作为条件。因为联合索引如果第一个字段没有作为条件就会失效;

解决方案:
	1. 建立索引或者是优化SQL写法使索引生效;
	2. 优化表结构,因为优质的表结构即可以节约空间也可以优化查询速度;
	3. 减少表与表的连接次数,因为两表之间的连接都是笛卡尔积形式的暴增型对比次数增加;

6. 需要在性别或年龄上建立索引吗?

年龄上可以建立索引,但是性别上不能建立索引。因为重复率过高的字段建立索引查询效率反而会降低;
因为数据表通常分为两个文件,一个是数据文件一个索引文件,所以当我们访问索引的时候其实这是一次IO操作;
如果100万条记录中男女各有50万条,那显然在性别上建立索引是得不偿失的,因为50万次的IO操作会把这条SQL的速度降低到比没有建立索引时还慢;

7. 事务的隔离级别

事务:通常在我们的业务流程中DML都不是一条两条或三条,而是一捆。也就是说一个事务就是一捆DML;
事务四特性:原子性、一致性、隔离性、持久性;

细究隔离性:

读未提交(read uncommited):事务A可以读取到事务B还未提交的数据;
造成的问题:脏读。读取到其他事务还未提交的数据;
实例:假设此时money(家庭共同财产)为10000元,程序猿小张(事务B)首先用8000元买了一台外星人,小红(小张的妻子,事务A)此时查询money时为2000;
但是小张突然想把外星人换成败家之眼,所以就先退掉了这台外星人,然后回家了(事务提交了)。所以此时money为10000元,但是小红此时认为money仍旧是2000元;
所以此时小张回到家莫名其妙的就迎来了自己的一顿搓衣板;
我们可以把这种错误理解为:脏读,解决方案是使用下一种事务隔离级别:读已提交;

读已提交(read commited);事务A只能读取到事务B已经提交的数据;
造成的问题:不可重复读。在一次事务过程中两次查询同一数据得到不同结果;
实例:昨晚跪完搓衣板之后,小张解释了一下便顺利调解了此事。第二天一早小张就去败家之眼旗舰店了,一进店门小张就被一台9000元的笔记本给吸引住了;
(事务B开始)同时呢,小红不放心小张,小张出门后小红又查询了一下money,还是10000万元,小红就安心的去懒觉了;
(事务A开始)一小时后,小张经过多方面的细致了解,以8500的价格顺利拿下了这台败家之眼。之后小张一看时间也快中午了,就直接回家了(事务A结束);
回到家后小红一看小张手提一台笔记本,然后她急忙又查询了一下money发现只有1500了,然后小红就默默打开了存放搓衣板的柜门(事务B结束);
在这种隔离级别之下,事务B只能读取到事务A已经提交的数据,就会产生不可重复读的问题,就是说它前一次读取的数据等一会儿读取时就会有所改变。也可以理解为在事务B进行的过程中(事务B还未结束),对于同一数据的两次查询却出现了不同的查询结果;

可重复读:它解决了不可重复读的问题。解决的方案就是在开启事务B的时候,对money建立一份数据快照(money在事务B开启的那一刻时的数据备份);
一旦事务B开启时对money建立一份数据快照,那在事务B的整个操作过程中,money都是一致的。因为任何其他事务都无法改变这份数据快照;
但它依旧会产生问题,那就是幻读;
实例:第二天一大早,小红就嚷嚷着要让小张赶紧把败家之眼给退了,无奈之下小张只能暂时放弃了自己的“好兄弟”(小张是个妻管严);
小张出门一个小时后,(money数据快照建立)(事务B开启)小红赶紧查询money。一看依旧是1500元,小红心想大概是堵车了吧,于是就继续等着。十分钟后,小张到家了,小红赶忙查询money,发现依旧是1500。于是乎小红又打开了柜门;
但这是为什么呢?
小张已经把电脑退掉,但小红查询的money依旧是1500;
原因就是那份数据快照,有了数据快照,在一次事务的过程中,money的值确实唯一了,但是它还是不真实,有种虚幻的感觉;
所以此处依旧是存在问题的,这个问题被称为:幻读。解决方案使用串行化;

串行化:见名知意,它的含义就是在一个事务操作money的过程中,任何事务都不能操作money;这里的操作指的是 insert update delete ;
这样的话,只有一个事务在操作money,一定会把 脏读、不可重复读、幻读 都给干掉;
但它也有巨大且明显的问题,那就是效率。只允许一个事务进行操作,在很多业务流程中这样的设定几乎是不存在的;

总结:
读未提交:事务B可以读取到事务A操作过程中的中间数据(还未提交时对于money的操作)。产生的问题:脏读;
读已提交:事务B只能读取到事务A已经提交的数据。产生的问题:不可重复读(一次事务过程中对同一数据读取两次结果却不唯一);
可重复度:事务B在开启事务的那一刻对money建立一份数据快照。产生的问题:幻读。事务B操作过程中都是根据一份数据快照来进行操作;
串行化:事务B开启的时候,任何其他事务都不能对money再做insert update delete。产生的问题:效率低;

8. tcp三握四挥

建立连接三次握手(发起端只能是client):
		request报文
client -------------> server 文字描述: client 向 server 发送 request 报文;
		ACK+SYN报文
server -------------> client 文字描述: server 接收到 request 报文之后,为此次连接分配资源然后向 client 回应 ACK+SYN 报文(其中SYN是用来做同步的);
		   ACK报文
client -------------> server 文字描述: client 接收到 server 发送的 ACK 报文之后向 server 回应 ACK 报文并为此次连接分配资源;

断开连接四次握手(发起端可以是client也可以是server,这里以client为例):
		   FIN报文
client -------------> server 文字描述: client 认为自己此次连接过程中的数据都发送完毕了,就会向 server 发送 FIN 报文;
用人的交流沟通这次对话是这样的过程:
server,你好!我的数据发送完毕了,我打算关闭连接了。但是你不用着急关闭连接,等你的数据发送完成之后再关闭就可以了。我等着你的FIN报文。over;
同时呢!这个时候,client会进入到 FIN_WAIT 状态,因为它在等待 server 向它发送 FIN ;		

		   ACK报文
server -------------> client 文字描述: server 接收到了client发送过来的FIN,但它需要向client证明自己确实接收到了它发送的FIN,所以它发送ACK给client;
用人的交流沟通这次对话是这样的过程:
client,你好!你的FIN我收到了,我这边需要进行一些收尾数据的发送,你先稍等一下。但我先把ACK给你代表我接收到了你的FIN,我等会儿就把FIN发你。over;

		  FIN报文
server -------------> client 文字描述: server 确认自己的数据发送完毕之后,会向 client 发送自己的 FIN 报文;
用人的交流沟通这次对话是这样的过程:
client,你好!我这边把数据发送完毕了,准备好关闭连接了,现在把FIN发给你。voer;

		  ACK报文
client -------------> server 文字描述: client 接收到 server 的 FIN 之后知道自己可以关闭连接了。但是它要给 server 发送一个 ACK 来确保让 server 知道自己接收到了它的 FIN ;
用人的交流沟通这次对话是这样的过程:
server,你好!我接收到了你的FIN,现在向你发送ACK。但是我怕网络问题你接收不到我的ACK,然后傻等我而不关闭此次连接;
所以我再经过一个 2MSL 的 TIME_WAIT 时间,如果你接收不到我的ACK可以给我发消息,我再给你重新发送。但是如果我经过TIME_WAIT之后你仍旧没有再给我发送任何消息。就意味着你已经关闭了此次连接,那我也要关闭了。over;

为什么连接要三次,而结束要四次呢?
因为连接的建立是同步的,其中server会向client发送SYN,而SYN就是用来同步的报文;
但是连接关闭的时候,是异步的。发起者往往率先准备好关闭连接,接收者都是被动的来进行连接关闭的;

2MSL:最大报文段生存时间;

9. redis的数据类型

它的数据类型分为:String Hash List Set Sorted_Set;
其实这些数据类型都是指 value 的类型,因为Redis中存储数据都是以 key-value 这种形式进行存储的。而且它的key只能是String;
同时呢!Redis是一款用C语言编写的开源的单线程数据库;

10. redis的Sorted_Set可以干什么?

Sorted_Set是有序Set,它可以用来做实时排行榜;

11. 五个数组如何找并集、交集

并集:{
	1. 直接把这个五个数组放到Set里面,自动去重;
	2. 两个两个的处理这些数组;
		1)首先拿出来两个数组进行排序,利用API就可以。因为是快排;
		2)依次比较排序后数组每一位上的数据(假设是a[n]和b[n]);
			if a[i] > b[j] -> j++else if a[i] < b[j] -> i++else 否则就把a[i]或b[j]放到result数组中(因为排除了大于或者小于的情况,只剩下等于了)-> i++ , j++;
		注:循环的条件是( i != a.length && j != b.length );
		3) 经历上面的循环之后,a或者b数组肯定会有一个到达了尾部。我们假设是a,那b数组就可以从刚才j结束的位置将数据全部遍历出来并加入到result中;
			因为a数组没了,且俩数组都是有序的,那此时b数组中的第一个元素的值肯定比a数组中最大的值还要大;
			也就是说剩下的数据都是b特有的。所以这些都是并集的内容;
		
}
交集:{
	1. 直接把这个五个数组放到Set里面,自动去重;
	此时呢,做一个判断。如果一个元素在Set中不存在就直接添加,否则就放到新建的result数组中,因为已经存在的就是交集;
	2. 两个两个的处理这些数组;
		1)首先拿出来两个数组进行排序,利用API就可以。因为是快排;
		2)依次比较排序后数组每一位上的数据(假设是a[n]和b[n]);
			if a[i] > b[j] -> j++else if a[i] < b[j] -> i++else 否则就把a[i]或b[j]放到result数组中(因为排除了大于或者小于的情况,只剩下等于了)-> i++ , j++;
		注:循环的条件是( i != a.length && j != b.length )。因为一旦一个数组到达尾部,那另一个数组中不管剩多少数据都绝不会是交集了;
}
算法方面非常薄弱,大佬勿喷,蟹蟹!

12. 跨域请求会不会到服务器那里?

可以到;
我们都知道,服务器可以处理跨域请求,只需要进行配置即可;
设想一下,如果服务器接收不到跨域请求,那服务器又如何处理跨域请求呢?
这里也贴一篇我的另一个文章,里面对跨域请求可以到后端进行了论证;

地址:跨域请求后端能接收到吗?

13. 二分查找

二分查找中间元素的下标值是向下取整的;
之所以这样写是因为遇到了这样的一个数组:1357911;
此时二分的话会以5作为起始值;
  • 8
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 11
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值