背景
毕业之后没有留在实习的公司,之后从新找工作,因为是应届生,工作时间不长,所以找不到一个高薪的工作,后来朋友开导我,鼓励我先在大城市生存下去,努力提高自己,未来会开花结果的。所以我决定开始写博客,分享自己的学习成果,向优秀的人学习,与优秀的人一起交流,以此来提高自己。
离职之后面试了很多家公司,我一开始准备的也不太充分,所以答得不是特别好,不过我还是觉得有的问题虽然当时没有答上来,不过问的确实好,所以我就记录下来跟大家分享一下。
正文
问题一:分布式 Session 如何设计?
之前实习写的都是一些简单的业务代码,所以问我这个问题时我答的不太好,毕竟是没有参与过的设计所以在此记录一下:
我学习分布式的时候,总结了一个原则:一切分布式的设计,都是为了让业务开发,变得和在单机上一样,就好像在开发单机程序一样。
在单机应用程序开发时,session是存在服务器上的,现在分布式系统下,服务器分散,我们可以让每一个服务器上存一份session,从而保证系统像在单机上运行一样。或者,我们单独将session放在一个服务器上,通过调用的形式达到session的一致性。
在这两种思想的指导下,可以有许多方案:
Sticky Session:需要配置负载均衡器,使得一个用户的所有请求都路由到同一个服务器,这样就可以把用户的 Session 存放在该服务器中。
Session Replication:在服务器之间进行 Session 同步操作,每个服务器都有所有用户的 Session 信息,因此用户可以向任何一个服务器进行请求。
Session Server:使用一个单独的服务器存储 Session 数据,可以使用传统的 MySQL,也使用 Redis 或者 Memcached 这种内存型数据库。
问题二:四次挥手,如何保证服务器接收到浏览器的最后一次消息?
被问这个问题时,真的很佩服面试官的学识跟能力,在学习过程中自以为将TCP的三次握手和四次挥手完全搞明白了,为什么是三次、四次、每次都干了什么都了解了,但是却没有思考过面试官提出的这个问题,所以回到家,我有重新看了一遍这一块的相关知识点。同时也得出一个结论,学习过程中多问几个问什么,或许对我们会有很大的帮助。
回到问题本身,我们知道四次挥手的过程如下:
A :主动关闭方 B:被动关闭方
- A 发送连接释放报文,FIN=1。
- B 收到之后发出确认,此时 TCP 属于半关闭状态,B 能向 A 发送数据但是 A 不能向 B 发送数据。
- 当 B 不再需要连接时,发送连接释放报文,FIN=1。
- A 收到后发出确认,进入 TIME-WAIT 状态,等待 2 MSL(最大报文存活时间)后释放连接。
- B 收到 A 的确认后释放连接。
从一开始,我就没有对这个 TIME-WAIT 状态产生过疑问,直到面试官问我这个问题,我才明白这样设计的用意:
- TCP 拥有超时重传机制,等待状态可以如果最后B没有收到A的确认,B会在等待时间内再次重传数据给A,从而确保B收到A的确认;
- 若是一直收不到B的重传数据,等待时间结束后,可以确保此次连接的报文从网络中消失,从而避免新连接使用旧报文。
总之,这个设计就是为了确保B可以收到A的确认而存在的,同时也是为了清空本次连接产生在网络当中的报文而存在的。
问题三:MongoDB 为什么比 MySQL 快?
根据普遍的经验来讲,一般项目会把历史数据、浏览记录这样的数据量大、不常修改的数据存放到 MongoDB 中,因为大家都这样做,我也就这样学习了,但是当面试官问我的时候,我却什么都说不上来,所以我得出一个好的结论,学习不应当只是会用就行。
MongoDB的相关概念
概念:基于分布式文件存储的数据库,由 C++ 语言编写。旨在为 WEB 应用提供可扩展的高性能数据存储解决方案。
特点:无Schema限制、灵活度高、BSON(类似JSON的二进制形式)存储格式、支持内嵌的文档对象和数组对象、自动分片、自动转移分片里面的数据块、异步写入。
根据其定义与特点,我们可以大概梳理出一下几点MongoDB高性能的原因:
- 无Schema限制:使得MongoDB能在生产环境中提供高读写的能力,吞吐量较于mysql等SQL数据库大大增强。
- 分布式文件存储:提供了分片能力,能对数据集进行分片,数据的存储压力分摊给多台服务器。
- 异步写入:写入时,可以立即得到返回得到成功的结果(即使是报错),这样让写入的速度更加快,MongoDB提供了Journaling日志的概念,实际上像mysql的bin-log日志,当需要插入的时候会先往日志里面写入记录,再完成实际的数据操作。从而避免停电对系统的影响。
除此以外,我还在网上搜集了一些MongoDB快的原因,如常用数据放在内存里、存储数据相对集中这样的概念,本质上就是尽可能减少磁盘IO,从而提高查询性能。
一些自己的思考
既然 MongoDB 性能这么高,但是 MySQL 并没有被淘汰,说明两者之间时各有优劣的,MySQL 有着完整固定的表结构,以及事务支持,可以提供数据的完整性和一致性,MongoDB 有高性能和易于扩展的特性。在开发过程中,就要根据业务的具体需求去设计,而且也不是非黑即白,可以配合着使用,集中两者的优点。
问题四:进程通信
问我这个问题时,我当时没有把进程通信和进程同步搞混了,因此我当时的回答时很糟糕的,所以总结一下分享给大家
进程同步
定义:在多道程序环境下,进程是并发执行的,不同进程之间存在着不同的相互制约关系。
相关概念:
-
临界区:对临界资源访问的代码
-
同步与互斥:
- 同步:多个进程合作产生的一种关系,使得进程有一定的执行顺序
- 互斥:多个进程在同一时刻只有一个进程可以进入临界区
-
信号量:信号量(Semaphore)是一个整型变量,可以对其执行 down 和 up 操作,也就是常见的 P 和 V 操作。
- down: 如果信号量大于 0 ,执行 -1 操作;如果信号量等于 0,进程睡眠,等待信号量大于 0;
- up:对信号量执行 +1 操作,唤醒睡眠的进程让其完成 down 操作。
down 和 up 操作需要被设计成原语,不可分割,通常的做法是在执行这些操作的时候屏蔽中断。如果信号量的取值只能为 0 或者 1,那么就成为了互斥量(Mutex),0 表示临界区已经加锁,1 表示临界区解锁
-
管程:使用信号量机制实现的生产者消费者问题需要客户端代码做很多控制,而管程把控制的代码独立出来,不仅不容易出错,也使得客户端代码调用更容易。
进程通信
定义:进程间传输数据(交换信息)。
实现方式:
-
管道:管道是通过 pipe 函数创建的,fd[0] 用于读,fd[1] 用于写。
特点:半双工、父子进程通信
-
FIFO:命名管道,去除了管道只能在父子进程中使用的限制。
-
消息队列:消息传输过程中的容器,特点就是异步解耦,可以实现跨进程异步(进程通信)
特点:
- 异步:避免了管道同步阻塞的问题,不需要进程自己提供同步方法
- 可选择性:可以根据消息标识有选择的接收消息
-
信号量:计数器,用于为多个进程提供对共享数据对象的访问。
-
共享存储:允许多个进程共享给定的存储区,因为数据不需要在进程之间复制,所以这是最快的一种 IPC。需要使用信号量用来同步对共享存储的访问。多个进程可以将同一个文件映射到它们的地址空间从而实现共享内存。另外 XSI 共享内存不是使用文件,而是使用内存的匿名段。
-
套接字:用于不同机器间的进程通信
两者的区别和联系
区别:
- 进程通信:控制多个进程按一定顺序执行;
- 进程同步:进程间传递信息。
联系:
为了达到进程同步的目的,通过进程通信传输一些必要的消息
总结感悟
感悟有两点吧,一个就是对与学习的感悟,感觉学的可以的知识还是会被问倒,原因很简单,学的时候比较浮躁,觉得会用就可以了,但是显然不是这样的,看似学的会用了,但是在出了问题是,自己不会排查,分析不出原因,我觉得这是很失败的,如果想要在这条路上走的远,就不能仅限于自己知道是啥,只是会用这样。还有一点就是学习计算机知识,不能只局限于形象的产品,对于一个方案的设计,思想很重要,就像分布式session那样,方案有很多,但是思想总结起来就两种,至少暂时我能想到的就是两种。
另一个是对人生的感悟,我之前一直回忆,发现其实摆在我眼前的机会有很多,我每一次在机会来临时,都觉得没有准备好,而且觉得人生已经完了,不会再有机会了,然后继续浑浑噩噩,知道下一次机会到了我的面前,在此重复这个过程。或许,机会一直都在,觉得没机会其实只是我的一种主观感受,我要做的其实是在机会来之前做足准备,这样才能走出这个恶性循环。人生是一场长跑,一时的落后不代表一辈子落后,只要每一天都拼命往前跑,我相信我也能跑出好的成绩。
对于以上知识的总结,有许多是我主观上的观点,欢迎大家批评指正,谢谢!!!