# Distributed_Web_System **Repository Path**: weixiong/Distributed_Web_System ## Basic Information - **Project Name**: Distributed_Web_System - **Description**: 分布式Web系统(Python实现) - **Primary Language**: Python - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2022-09-17 - **Last Updated**: 2022-09-17 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README [TOC] # Distributed_Web_System 分布式Web系统(Python实现)。 ## 系统需求 该系统由**一个重定向负载均衡服务器、四个Web服务器**组成,要求: (1) 重定向服务器**接收**客户的网页访问请求,基于要访问的URL和Web服务器的实时负载情况(与Web服务器**通信**以获取负载信息),将客户**重定向**到相应的Web服务器上,实现负载均衡。 (2) 重定向服务器计算各个Web服务器的潜在负荷,即特定Web服务器上**各个页面在一个统计周期内****(30s)****的总体访问量**;在接收到新网页的上传请求后根据各服务器的潜在负荷决定将新网页存储到哪个服务器上,以及在哪个服务器上存放其副本(即**每个网页要求存放两份**),实现文件存放操作并记录存储位置(也可以自行设计其他的文件放置策略)。 (3) 测试时,至少2台客户端,用程序分别产生每分钟**上千次**的访问请求(随机决定访问哪个URL),记录并分析运行结果。 ## 系统设计 ### Client (1) handle_Input:输入请求类型R、请求次数C、线程数T、单次文件数N。根据用户的输入,往线程池里push进C个任务,每个任务包含一次请求(多个文件),交付给T个线程,这也就意味着每个任务一次要处理N个文件。若是下载请求,产生随机的N个下载文件的列表;若是上传请求,根据本地所有的文件产生随机的N个上传文件的列表。列表也可事先给定,避免线程之间冲突。 (2) handle_Req:无。 (3) Download:单线程,处理一个下载任务,先向balancer发送文件列表,balancer将对应文件的目标地址存储在一个列表,返回给客户端。 (4) Upload:单线程,处理一个上传任务,先向balancer发文件列表,balancer计算哪些文件可上传、确定一个目标WebServer之后,返回的可上传文件列表和目标地址,客户端将文件全部上传至该地址。 ### Load Balancer (1) handle_request:处理每个socket的request,用于解析msg。减轻主线程的负担,即各种判断,主线程只负责接收请求(accept),请求具体干啥的交给子线程去做。 (2) WebServer_Conn:每当一个WebServer尝试连接我,交互信息,更新文件列表,在WebServer状态表添加新的WebServer。 (3) Load_Balance:长期执行的任务,每30s的一个周期中,第10s、第20s都要发送一次“alive”消息给WebServers并接收“yes”,从发送时刻记录来回时间,以此作为WebServers的响应时间,**若**,第30s时发送“detail”给WebServers并接收它们的当前状态信息——访问量、剩余存储空间、性能等指标。更新。。为了简单起见,假设每15s更新一次,先发送“alive”消息,接收“yes”之后,再发送“detail”消息,接收访问量、剩余存储空间等,然后更新WebServer状态信息表。一旦发生断线,及时更新其存活状态或删除WebServer。 (4) Req_Download:文件列表,生成对应文件的目标地址列表,并返回。 (5) Req_Upload:文件列表,过滤已有文件,返回可上传文件列表、一个WebServer地址。 (6) Req_Backup:文件列表,过滤已备份文件,返回可备份文件列表、一个备份WebServer地址。 ### WebServer (1) handle_socket:处理每个socket连接,用于解析msg。减轻主线程的负担,即各种判断,主线程只负责接收请求(accept),请求具体干啥的交给子线程去做。注意一个请求来自于一个客户端,一个请求可以做多个任务。如果是一个客户端的多个文件上传请求,成功接收所有文件后,一起发给balancer通知其更新文件列表并返回需要备份的文件对应的WebServer列表。如果是一个WebServer的多个文件上传请求,成功接收所有文件后,也要一起发给balancer通知其更新文件列表,此时balancer会发送空列表,表示文件不再需要备份。 (2) Init_:初始化,剩余存储,连上Balancer并交互信息。 (3) BalancerReq:不停地等待接收balancer的心跳请求,然后计算负载。 (4) SendFile:发送文件。 (5) RecvFile:接收文件。凡是成功接收文件后必须执行BackupReq,通告balancer。 (6) BackupReq:向Balancer发出文件备份请求,接收需要备份的文件列表list和备份地址,然后SendFile给该地址。如果list为空,则不备份。 **Web服务器的负载:** **访问量**:当前线程池中的剩余任务数 **线程数**:处理任务的能力/效率 **响应时间**:由balancer计算 **剩余文件大小**:用于均衡文件上传 ## 值得注意的一些思考 系统的下载/上传效率跟客户端的下载/上传线程数有关。客户端一个线程创建一个套接字,跟Web Server连接,假定客户端下载/上传一个文件就创建一个线程吧,然后创建一个套接字吧。 虽然线程启动销毁频繁,但简单易行就ok。 **不同的任务持续时间不一样!** **系统启动的时候,要有一个自适应的方法,把负载均衡服务器(Balancer)上的表和WebServer上的文件进行同步!** Clients创建一个线程池来准备“多线程访问请求”任务,每个线程可handle两种事情——**上传**和**下载**。 Balancer每收到一个客户端的请求就添加一个**查询任务**给自己的线程池,待空闲线程来处理,即回复客户端让其重定向一个WebServer。Balancer还要handle其他的任务:**请求WebServer的负载状况来更新Server表**(这个优先级比较高,最好单开个持久线程...不啊,只要看看哪个倒霉蛋线程处理了这个任务,来了就别想走hhh);**接收WebServer的文件备份消息并更新file表**(我完整地接收了一个文件,现在要备份给我的“兄弟”,请发它的地址给我)。 WebServer干的事情比较多,有点累... 注意: 要把一次上传请求的多个文件当成一个大文件来看待。 对于一次下载请求的多个文件,每个文件都对应着一个WebServer地址,服务器不能统计汇总,必须发回客户端进行汇总,再一同下载所有对应着同一WebServer地址的文件。为了不频繁建立连接,客户端解析“文件+地址”之后,直到所有文件下载完成之后线程才断开与对应地址的连接。 对于Clients来说,没有balancer和WebServer的区别,统一当做服务器,针对服务器进行上传/下载。 **线程池会不会把其他任务“饿死”呢?** Load Balancer管理这么多file和对应的WebServers,它必须做的事情有: 计算各WebServers的负载:至少响应时间要计算吧,然后更新负载状态表。 资源查找:一个Client要下载files,负载均衡器要将拥有这些files的负载最小的WebServers的地址依次发给该Client。一个WebServer成功接收完一个Client上传的files之后要告诉负载均衡器,负载均衡器一定要更新文件列表。WebServer断线了,负载均衡器必须及时更新它的存活状态,防止后来的Client错误请求。而如果WebServer重连了,假设文件没有丢失,负载均衡器必须知道。 不如这样,**“上传”、“备份”的时候,Balancer就直接发一个WebServer(负载最小,“备份”时除自身以外)的地址**,让文件发送端和文件接收端自己处理,因为同一个文件在一个WebServer上只能存一份,多个WebServer之间互相存储,但不会有死循环,所以文件备份数可能是2~4。这样Balancer的负担就减轻了! 定义几个类?分别用于存储什么? **负载均衡服务器上的文件列表详情(文件索引对象):** **文件url、Web服务器1、Web服务器2、...、Web服务器n;** 特殊情况:多个客户端上传同一个文件到4个Web服务器,由于请求的时候balancer还没有更新,导致大家都可以传,然后4个Web服务器都收到了,所以同一个文件并不一定只存在两台Web服务器上面。 如果多个相同文件都往同一台Web服务器上面传,可以让Web自己判断,先来先创建文件,然后程序判断。 负荷(上传) = Web服务器总文件大小、访问量、响应时间(判活) 负载(下载) = 访问量、响应时间(判活) 客户端上传的时候,负载均衡服务器判断所有Web服务器的负荷状态,然后发送2个负荷最小(次小)的Web服务器地址(即备份存放)。 客户端请求的时候,负载均衡服务器判断拥有该文件的2个Web服务器的负载状态,,负载均衡服务器向客户端发送拥有其所请求文件的2个Web服务器当中响应时间最短的一个。 **一些Bugs:** **多线程编程,主进程执行完毕后,同时会销毁所有守护线程,若此时守护线程正在执行,则会报错!** socket编程时,连续发送两个信息,对方可能会同时接收,**recv(1024),只要一直发它可以一直接收(最大接受1024个字节)。** **要保证消息收发不会出错:** **(1) 严格规定“一发一收,一收一发”,类似zmq的req和rep;** **(2) 事先确定消息长度,接收方“收多少减多少”。** ### 其他问题 全局文件唯一标识符,Python标准库uuid可用,但用不到。 报文设计,消息传递, 错误处理,服务器宕机…… 分布式计算、系统是计算机学科的底层技术,图像处理、大数据分析都是计算机学科的应用方面。 计算机学科的底层技术都是人家(国外)设计和实现的!!!我们无法DIY啊! 自己动手,丰衣足食!从零开始弄懂! ### 具体实现详细见代码,Talk is very cheap. Python版本:Python 3.7.4