日常知识点之面试后反思遗留问题汇总
梳理一下最近接触到的几个知识点:
1:突然问到端口复用 (SO_REUSEADDR)
端口复用一般用在服务端重启时,套接字处于time_wait状态时,无法绑定该端口,导致无法启动问题。
设置端口复用,可以多个进程绑定同一个端口(注意考虑数据接收业务处理)。
端口复用也可以用在udp。
2:工作中涉及到使用udp传输大报文的场景(udp数据包中有最大限制,两个字节存长度 2^16 - 1 = 65535字节,包括头部)。
1:使用多进程方案,同时监听同一个端口,需要设置端口可重用。 但是在处理时就得注意接收。
我的项目中用的是udp多进程监听不同的端口,然后进行汇总(业务相关,接收同一个业务选优)。
2:与应用场景有关,客户端(硬件设备)不支持修改协议以及进行udp拆包,所以只能传输大报文。
首先需要测试网络链路无问题,可以传输udp大包(实际上借助底层ip分片)(防止中间有节点限制包大小)。
传输大包时,需要对udp的接收缓冲区进行扩大,同时需要考虑接收时缓冲区大小设置。
recvfrom接收到数据后,完整性初步校验后交给下一个处理线程(包的形式,或者数据结构/类)。
(这里业务场景相关,协议比较复杂,协议长度一般是240*64的包大小,一包这么大)
(不同的协议用不同的头部可以进行区分,比如这里区分全帧和挑路数据,之后就是解析)
(需要计算带宽,这里的带宽大概是 每秒4帧 每帧240 *64 总共 61440 字节)
61440byte = 60kb ===>0.0586Mb
61440*8 bit ==491520bit = 0.491Mbps (每秒传输的比特位)
3:问到丢包率
实现的过程中会统计接收到的包的信息,并未统计过丢包率。(未进行测试)
从业务运行场景进行分析,在网络状态良好的情况下,甚至可能不丢包,与业务相关,极端场景下可能直接收不到包。
3:问到一个场景,多个服务器进程同时接收一个客户端的场景,处理相同的业务
(是我理解错了,有前置条件,先入为主,以为听说多进程同时接收一个业务的处理,这种冗余吧,不会这样设计)
1:从架构角度考虑,使用负载均衡的方式,使客户端连接同一个服务器进行处理。
2:服务器互相交互,对处理业务进行存储处理(如数据库)。
4:思考如何实现一个服务器
网络入口,业务处理。
1: 网络入口,如果并发并不超级大,以及业务不复杂的话,一个epoll就够用,用于接收。(nginx是多个进程负责接入,然后本进程处理业务,与nginx处理的业务场景有关)
2:如果并发比较大,业务不复杂,如niginx的业务场景,可以采用类似nginx的场景吧。
===》业务不复杂的话,epoll作为入口,接收后管理fd,把fd和接收数据放入队列,下一个线程取队列进行处理,处理完找fd回复。
===》tcp需要业务处理时 可以用session对象进行管理,管理接收数据拆包等处理。
3:如果并发还可以,要维持长连接进行交互,以及涉及复杂业务,操作数据库等。
关于入口:
===》网络入口可以是一个进程的epoll(其他也行),负责数据的接入。 (设置fd非阻塞) -->负责与session管理交互 智能指针管理session
===》以fd和session的对应关系,处理长连接。(stl管理或者对象管理 连接在epoll中管理 可以用回调函数的方式 适配连接到业务 处理心跳)
===》session读写数据,构造task(包含回调), 用线程池的方案处理对应业务,回调函数返回结构。 (1:管理连接的回调,在epoll中处理。 2:管理协议的回调,传给task在线程池中返回, 传递fd,对应关系进行发送)
===》线程池中专门的线程1负责消费线程,(除了执行线程外 线程1管理消费task的调用函数和task进行绑定(确定调用函数) 线程2 负责执行task进行消费 线程3 负责线程的释放)
=======》通过回调函数可以设置自定义执行业务,对结果进行返回 数据的发送 同样是调用上面的网络入口id和session的关联进行回复。
关于业务:
上面的回调中处理业务,根据不同的协议进行处理。 比如心跳,比如登录,操作数据库等。
使用连接池可以优化数据库的操作。 已有连接池DBpool +自己实现相关数据库操作接口
连接池的个数(小型10~20个,这里用10个)
线程池的线程个数(可以设置限制,根据空闲线程数,按需进行扩容。 (最大线程数,当前线程数))
===》一般定义为核心的2倍,io密集型可以更多。 根据业务,如果短小快业务,也可以适当更多线程。
4:并发超级大,可以考虑负载均衡吧。
并发超级大,业务不复杂,可以自己设计(如epoll支持百万并发)
5:服务器设计时为啥设计成这种分模块
可维护性(单一职责,减少复杂性),可扩展性,便于合作,重用性,便于改进,部署。