首页 文章 精选 留言 我的

精选列表

搜索[笔记工具],共10000篇文章
优秀的个人博客,低调大师

2018年6月21日笔记

1.操作系统基础 操作系统(Operation System,简称OS)是管理和控制计算机硬件与软件资源的计算机程序,是直接运行在“裸机”上的最基本的系统软件,任何其他软件都必须在操作系统的支持下才能运行。 常见的操作系统:Windows、Unit、Linux、Mac OS MacOS很少受病毒的袭击 2.网络编程基础 HTTP:超文本传输协议(Hypertext transfer protocol)是一种详细规定了浏览器和万维网服务器之间互相通信的规则,通过因特网传送万维网文档的数据传送协议。 HTTPS:是以安全以目标的HTTP通道,简单讲是HTTP的安全版。即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容需要SSL。 HTTP协议的基本原理:HTTP是在客户机/服务器模式下,分为HTTP客户端和HTTP服务器两个部分,双方每次进行交互,都是由客户端发出的请求和服务器发出的相应构成。HTTP协议规定的用户使用浏览器访问万维网的过程可以总结为: 用户在浏览器输入需要访问网站的URL或者点击网站中某个网页链接 浏览器根据URL中的域名,通过DNS解析出目标网页的IP地址 浏览器与网页所在服务器建立TCP连接 浏览器发送HTTP请求报文,获取目标网页的文件 服务器发送HTTP响应报文,将目标网页文件发送给浏览器 释放TCP链接 浏览器将网页的内容包括文本、图像、声音等呈现在用户计算机屏幕。 当我们向服务器发送HTTP请求,获取数据、修改信息时,都需要建立TCP连接,包括三次握手,四次挥手。 3.Python性能 不同的语言有不同的侧重,python语言毫无疑问在乎编码效率,life is short, we use python。 虽然使用python的编程人员都应该接受其运行效率低的事实,但python在越来越多的领域都有广泛应用,比如科学计算、web服务器等。 python与C++的对比: python是动态语言 python中一切都是对象,每个对象都需要维护引用计数,增加额外的工作。 python GUI(Global Interpreter Lock) 垃圾回收,这个可能是所有具有垃圾编程语言的通病。python采用标记和分代的垃圾回收策略,每次垃圾回收都会中断正在执行的程序,造成所谓的卡顿。 4.同步异步,阻塞非阻塞 同步需要自己去轮询,异步就是中断会通知你是否已经完成。同步和异步的区别,对于操作结果来说,会不会等待结果返回。 阻塞是在中断的过程中,你不可以去干其他事。非阻塞就是在同样的情况下,可以同时去干其他的事情。阻塞与非阻塞的区别是相对于线程是否被阻塞。

优秀的个人博客,低调大师

2018年6月11日笔记

主讲老师: 胡浩 人工智能应用领域:医疗,搜素,无人驾驶,人脸识别,语音识别,智能仓库,金融 人工智能主要应用:智能搜索与推荐,无人驾驶,人脸识别,语音识别,智能仓库,个人助理(智能手机上的语音助理、语音输入、家庭管家和陪护机器人),金融,教育 课程简介:https://tpcst.erongda.com/ 安装google,用360软件中心安装。以前可以百度软件中心安装,但是百度软件中心因为内部问题被百度禁止了。 安装python2.7.15,安装包只有20M,不大。 想象力训练 爬虫程序运行基于python2.7版本的爬虫程序爬取51job 投影仪复制的关键点是两个显示屏分辨率相同

优秀的个人博客,低调大师

架构文摘:LSV负载均衡技术笔记

一、LVS介绍 在本部分,我们将介绍Linux服务器集群系统——LVS(Linux Virtual Server)项目的产生背景和目标,并描述LVS服务器集群框架及目前提供的软件,列举LVS集群系统的特点和一些实际应用。 1、背景 当今计算机技术已进入以网络为中心的计算时期。由于客户/服务器模型的简单性、易管理性和易维护性,客户/服务器计算模式在网上被大量采用。同时,Internet的飞速发展给网络带宽和服务器带来巨大的挑战。 因此,对于大型网站的构建,其对于用硬件和软件方法实现高可伸缩性、高可用网络服务的需求不断增长,这种需求可以归结为以下几点: 可伸缩性(Scalability):当服务的负载增长时,系统能被扩展来满足需求,且不降低服务质量。 高可用性(Availability):尽管部分硬件和软件会发生故障,整个系统的服务必须是7*24小时可用的。 可管理性(Manageability):整个系统可能在物理上很大,但应该容易管理。 价格有效性(Cost-Effectiveness):整个系统实现是经济的、易支付的。 2、服务器集群系统 由于SMP的可扩展能力有限,SMP服务器显然不能满足高可伸缩、高可用网络服务中的负载处理能力不断增长需求。随着负载不断增长,会导致服务器不断地升级。这种服务器升级有下列不足:一是升级过程繁琐,机器切换会使服务暂时中断,并造成原有计算资源的浪费;二是越往高端的服务器,所花费的代价越大;三是 SMP服务器是单一故障点(Single Point of Failure),一旦该服务器或应用软件失效,会导致整个服务的中断。 通过高性能网络或局域网互联的服务器集群正成为实现高可伸缩的、高可用网络服务的有效结构。这种松耦合结构的服务器集群系统有下列优点: 性能 网络服务的工作负载通常是大量相互独立的任务,通过一组服务器分而治之,可以获得很高的整体性能。 性价比 组成集群系统的PC服务器或RISC服务器和标准网络设备因为大规模生产降低成本,价格低,具有最高的性能/价格比。若整体性能随着结点数的增长而接近线性增加,该系统的性能/价格比接近于PC服务器。所以,这种松耦合结构比紧耦合的多处理器系统具有更好的性能/价格比。 可伸缩性 集群系统中的结点数目可以增长到几千个,乃至上万个,其伸缩性远超过单台超级计算机。 高可用性 在硬件和软件上都有冗余,通过检测软硬件的故障,将故障屏蔽,由存活结点提供服务,可实现高可用性。 当然,用服务器集群系统实现可伸缩网络服务也存在很多挑战性的工作: 透明性(Transparency) 如何高效地使得由多个独立计算机组成的松藕合的集群系统构成一个虚拟服务器;客户端应用程序与集群系统交互时,就像与一台高性能、高可用的服务器交互一样,客户端无须作任何修改。部分服务器的切入和切出不会中断服务,这对用户也是透明的。 性能(Performance) 性能要接近线性加速,这需要设计很好的软硬件的体系结构,消除系统可能存在的瓶颈。将负载较均衡地调度到各台服务器上。 高可用性(Availability) 需要设计和实现很好的系统资源和故障的监测和处理系统。当发现一个模块失败时,要这模块上提供的服务迁移到其他模块上。在理想状况下,这种迁移是即时的、自动的。 可管理性(Manageability) 要使集群系统变得易管理,就像管理一个单一映像系统一样。在理想状况下,软硬件模块的插入能做到即插即用(Plug & Play)。 可编程性(Programmability) 在集群系统上,容易开发应用程序。 3、LVS项目 针对高可伸缩、高可用网络服务的需求,我们给出了基于IP层和基于内容请求分发的负载平衡调度解决方法,并在Linux内核中实现了这些方法,将一组服务器构成一个实现可伸缩的、高可用网络服务的虚拟服务器。 虚拟服务器的体系结构如下图所示: 一组服务器通过高速的局域网或者地理分布的广域网相互连接,在它们的前端有一个负载调度器(Load Balancer)。负载调度器能无缝地将网络请求调度到真实服务器上,从而使得服务器集群的结构对客户是透明的,客户访问集群系统提供的网络服务就像访问一台高性能、高可用的服务器一样。客户程序不受服务器集群的影响不需做任何修改。系统的伸缩性通过在服务机群中透明地加入和删除一个节点来达到,通过检测节点或服务进程故障和正确地重置系统达到高可用性。由于我们的负载调度技术是在Linux内核中实现的,我们称之为Linux虚拟服务器(Linux Virtual Server)。 Linux Virtual Server项目的目标 :使用集群技术和Linux操作系统实现一个高性能、高可用的服务器,它具有很好的可伸缩性(Scalability)、可靠性(Reliability)和可管理性(Manageability)。 目前,LVS项目已提供了一个实现可伸缩网络服务的Linux Virtual Server框架,如下图所示。 在LVS框架中,提供了含有三种IP负载均衡技术的IP虚拟服务器软件IPVS、基于内容请求分发的内核Layer-7交换机KTCPVS和集群管理软件。可以利用LVS框架实现高可伸缩的、高可用的Web、Cache、Mail和Media等网络服务;在此基础上,可以开发支持庞大用户数的、高可伸缩的、高可用的电子商务应用。 3.1 IP虚拟服务器软件IPVS 在调度器的实现技术中,IP负载均衡技术是效率最高的。 3.1.1 IP负载均衡技术 在已有的IP负载均衡技术中有通过网络地址转换(Network Address Translation)将一组服务器构成一个高性能的、高可用的虚拟服务器,我们称之为VS/NAT技术(Virtual Server via Network Address Translation)。 在分析VS/NAT的缺点和网络服务的非对称性的基础上,我们提出通过IP隧道实现虚拟服务器的方法VS/TUN (Virtual Server via IP Tunneling),和通过直接路由实现虚拟服务器的方法VS/DR(Virtual Server via Direct Routing),它们可以极大地提高系统的伸缩性。 所以,IPVS软件实现了这三种IP负载均衡技术,它们的大致原理如下(我们将在其他章节对其工作原理进行详细描述): Virtual Server via Network Address Translation (VS/NAT) 通过网络地址转换,调度器重写请求报文的目标地址,将请求分派给后端的真实服务器;真实服务器的响应报文通过调度器时,报文的源地址被重写,再返回给客户,完成整个负载调度过程。 Virtual Server via IP Tunneling(VS/TUN) 采用NAT技术时,由于请求和响应报文都必须经过调度器进行地址重写,当客户请求越来越多时,调度器的能力将成为瓶颈。为了解决这个问题,调度器把请求报文通过IP隧道转发至真实服务器,而真实服务器将响应直接返回给客户,所以调度器只处理请求报文。由于一般网络服务响应比请求报文大许多,采用VS/TUN技术后,集群系统的最大吞吐量可以提高10倍。 Virtual Server via Direct Routing(VS/DR) VS/DR通过改写请求报文的MAC地址,将请求发送到真实服务器,而真实服务器将响应直接返回给客户。同VS/TUN技术一样,VS/DR技术可极大地提高集群系统的伸缩性。这种方法没有IP隧道的开销,对集群中的真实服务器也没有必须支持IP隧道协议的要求,但是要求调度器与真实服务器都有一块网卡连在同一物理网段上。 3.1.2 负载调度算法 针对不同的网络服务需求和服务器配置,IPVS调度器实现了如下八种负载调度算法: 轮询(Round Robin) 调度器通过“轮询”调度算法将外部请求按顺序轮流分配到集群中的真实服务器上,它均等地对待每一台服务器,而不管服务器上实际的连接数和系统负载。 加权轮询(Weighted Round Robin) 调度器通过“加权轮询”调度算法根据真实服务器的不同处理能力来调度访问请求。这样可以保证处理能力强的服务器处理更多的访问流量。调度器可以自动询问真实服务器的负载情况,并动态地调整其权值。 最少连接(Least Connections) 调度器通过“最少连接”调度算法动态地将网络请求调度到已建立的连接数最少的服务器上。如果集群系统的真实服务器具有相近的系统性能,采用最少连接调度算法可以较好地均衡负载。 加权最少连接(Weighted Least Connections) 在集群系统中的服务器性能差异较大的情况下,调度器采用“加权最少连接”调度算法优化负载均衡性能,具有较高权值的服务器将承受较大比例的活动连接负载。调度器可以自动询问真实服务器的负载情况,并动态地调整其权值。 基于局部性的最少连接(Locality-Based Least Connections) “基于局部性的最少连接”调度算法是针对目标IP地址的负载均衡,目前主要用于Cache集群系统。该算法根据请求的目标IP地址找出该目标IP地址最近使用的服务器。若该服务器是可用的且没有超载,则将请求发送到该服务器;若该服务器不存在,或者该服务器超载且有服务器处于一半的工作负载,则用最少连接的原则选出一个可用的服务器,将请求发送到该服务器。 带复制的基于局部性最少连接(Locality-Based Least Connections with Replication) “带复制的基于局部性最少连接”调度算法也是针对目标IP地址的负载均衡,目前主要用于Cache集群系统。它与LBLC算法不同的是:它要维护一个目标IP地址到一组服务器的映射,而LBLC算法维护从一个目标IP地址到一台服务器的映射。该算法根据请求的目标IP地址找出该目标IP地址对应的服务器组,按最少连接原则从服务器组中选出一台服务器。若服务器没有超载,则将请求发送到该服务器;若服务器超载,则按最少连接原则从这个集群中选出一台服务器,将该服务器加入到服务器组中,将请求发送到该服务器。同时,当该服务器组有一段时间没有被修改,将最忙的服务器从服务器组中删除,以降低复制的程度。 目标地址散列(Destination Hashing) “目标地址散列”调度算法根据请求的目标IP地址,作为散列键(Hash Key)从静态分配的散列表中找出对应的服务器,若该服务器是可用的且未超载,则将请求发送到该服务器,否则返回空。 源地址散列(Source Hashing) “源地址散列”调度算法根据请求的源IP地址,作为散列键(Hash Key)从静态分配的散列表中找出对应的服务器,若该服务器是可用的且未超载,将请求发送到该服务器,否则返回空。 3.2 内核七层交换机KTCPVS 在基于IP负载调度技术中,当一个TCP连接的初始SYN报文到达时,调度器就选择一台服务器,将报文转发给它。此后通过查发报文的IP和TCP报文头地址,保证此连接的后继报文被转发到该服务器。这样,IPVS无法检查到请求的内容再选择服务器,这就要求后端服务器组提供相同的服务,不管请求被发送到哪 一台服务器,返回结果都是一样的。 但是,在有些应用中,后端服务器功能不一,有的提供HTML文档,有的提供图片,有的提供CGI,这就需要基于内容的调度(Content-Based Schduling)。 由于用户空间TCP Gateway的开销太大,我们提出在操作系统的内核中实现七层交换方法,来避免用户空间与核心空间的切换和内存复制的开销。在Linux操作系统的内核中,我们实现了七层交换,称之为KTCPVS(Kernel TCP Virtual Server)。目前,KTCPVS已经能对HTTP请求进行基于内容的调度。 虽然应用层交换处理复杂,它的伸缩性有限,但应用层交换带来以下好处: 相同页面的请求被发送到同一服务器,可以提高单台服务器的Cache命中率。 七层交换可以充分利用访问的局部性,将相同类型的请求发送到同一台服务器,使得每台服务器收到的请求具有更好的相似性,可进一步提高单台服务器的Cache命中率。 后端服务器可运行不同类型的服务,如文档服务,图片服务,CGI服务和数据库服务等。 3.3 LVS集群 LVS集群的特点可以归结如下: 功能 有实现三种IP负载均衡技术和八种连接调度算法的IPVS软件。在IPVS内部实现上,采用了高效的Hash函数和垃圾回收机制,能正确处理所调度报文相关的ICMP消息(有些商品化的系统反而不能)。虚拟服务的设置数目没有限制,每个虚拟服务有自己的服务器集。它支持持久的虚拟服务(如HTTP Cookie和HTTPS等需要该功能的支持),并提供详尽的统计数据,如连接的处理速率和报文的流量等。针对大规模拒绝服务(Deny of Service)攻击,实现了三种防卫策略。 有基于内容请求分发的应用层交换软件KTCPVS,它也是在Linux内核中实现。有相关的集群管理软件对资源进行监测,能及时将故障屏蔽,实现系统的高可用性。主、从调度器能周期性地进行状态同步,从而实现更高的可用性。 适用性 后端服务器可运行任何支持TCP/IP的操作系统,包括Linux,各种Unix(如FreeBSD、Sun Solaris、HP Unix等),Mac/OS和Windows NT/2000等。 负载调度器能够支持绝大多数的TCP和UDP协议,无需对客户机和服务器作任何修改,可适用大多数Internet服务。 性能 LVS服务器集群系统具有良好的伸缩性,可支持几百万个并发连接。配置100M网卡,采用VS/TUN或VS/DR调度技术,集群系统的吞吐量可高达1Gbits/s;如配置千兆网卡,则系统的最大吞吐量可接近10Gbits/s。 可靠性 LVS服务器集群软件已经在很多大型的、关键性的站点得到很好的应用,所以它的可靠性在真实应用得到很好的证实。有很多调度器运行一年多,未作一次重启动。 软件许可证 LVS集群软件是按GPL(GNU Public License)许可证发行的自由软件,这意味着你可以得到软件的源代码,有权对其进行修改,但必须保证你的修改也是以GPL方式发行。 二、LVS集群的体系结构 1、LVS集群的通用体系结构 LVS集群采用IP负载均衡技术和基于内容请求分发技术。调度器具有良好的吞吐率,将请求均衡地转移到不同的服务器上执行,且调度器自动屏蔽掉服务器故障,从而将一组服务器构成一个高性能的、高可用的虚拟服务器。整个服务器集群的结构对客户是透明的,而且无需修改客户端和服务器端的程序。 为此,在设计时需要考虑系统的透明性、可伸缩性、高可用性和易管理性。 一般来说,LVS集群采用三层结构,如上图所示。三层结构的主要组成部分为: 负载调度器(Load Balancer):它是整个集群对外面的前端机,负责将客户的请求发送到一组服务器上执行,而客户认为服务是来自一个IP地址(我们可称之为虚拟IP地址)上的。 服务器池(Server Pool):它是一组真正执行客户请求的服务器,执行的服务有WEB/Mail/FTP/DNS等等。 共享存储(Shared Storage):它为服务器池提供了一个共享的存储区,这样很容易使得服务器池拥有相同的内容,提供相同的服务。 调度器是服务器集群系统的唯一入口点(Single Entry Point),它可以采用IP负载均衡技术、基于内容请求分发技术或者两者相结合。在IP负载均衡技术中,需要服务器池拥有相同的内容提供相同的服务。当客户请求到达时,调度器只根据服务器负载情况和设定的调度算法从服务器池中选出一个服务器,将该请求转发到选出的服务器,并记录这个调度;当这个请求的其他报文到达,也会被转发到前面选出的服务器。在基于内容请求分发技术中,服务器可以提供不同的服务,当客户请求到达时,调度器可根据请求的内容选择服务器执行请求。因为所有的操作都是在Linux操作系统核心空间中将完成的,它的调度开销很小,所以它具有很高的吞吐率。 服务器池的节点数目是可变的。当整个系统收到的负载超过目前所有节点的处理能力时,可以在服务器池中增加服务器来满足不断增长的请求负载。对大多数网络服务来说,请求间不存在很强的相关性,请求可以在不同的节点上并行执行,所以整个系统的性能基本上可以随着服务器池的节点数目增加而线性增长。 共享存储通常是数据库、网络文件系统或者分布式文件系统。服务器节点需要动态更新的数据一般存储在数据库系统中,同时数据库会保证并发访问时数据的一致性。静态的数据可以存储在网络文件系统(如NFS/CIFS)中,但网络文件系统的伸缩能力有限。对于规模较大的集群系统,可以考虑用分布式文件系统。分布式文件系统可为各服务器提供共享的存储区,它们访问分布式文件系统就像访问本地文件系统一样,同时分布式文件系统可提供良好的伸缩性和可用性。此外,当不同服务器上的应用程序同时读写访问分布式文件系统上同一资源时,应用程序的访问冲突需要消解才能使得资源处于一致状态。这需要一个分布式锁管理器(Distributed Lock Manager),它可能是分布式文件系统内部提供的,也可能是外部的。开发者在写应用程序时,可以使用分布式锁管理器来保证应用程序在不同节点上并发访问的一致性。 负载调度器、服务器池和共享存储系统通过高速网络相连接,如Gigabit网络等。使用高速的网络,主要为避免当系统规模扩大时互联网络成为整个系统的瓶颈。 1.1 为什么使用层次的体系结构 层次的体系结构可以使得层与层之间相互独立,每一个层次提供不同的功能,在一个层次可以重用不同的已有软件。例如,调度器层提供了负载平衡、可伸缩性和高可用性等,在服务器层可以运行不同的网络服务,如Web、Cache、Mail和Media等,来提供不同的可伸缩网络服务。明确的功能划分和清晰的层次结构使得系统容易建设,以后整个系统容易维护,而且系统的性能容易被扩展。 1.2 为什么使用共享存储 共享存储如分布式文件系统在这个LVS集群系统是可选项。当网络服务需要有相同的内容,共享存储是很好的选择,否则每台服务器需要将相同的内容复制到本地硬盘上。当系统存储的内容越多,这种无共享结构(Shared-nothing Structure)的代价越大,因为每台服务器需要一样大的存储空间,任何的更新需要涉及到每台服务器,系统的维护代价会非常高。 共享存储为服务器组提供统一的存储空间,这使得系统的内容维护工作比较轻松,如Webmaster只需要更新共享存储中的页面,对所有的服务器都有效。分布式文件系统提供良好的伸缩性和可用性,当分布式文件系统的存储空间增加时,所有服务器的存储空间也随之增大。对于大多数 Internet服务来说,它们都是读密集型(Read-intensive)的应用,分布式文件系统在每台服务器使用本地硬盘作Cache(如 2Gbytes的空间),可以使得访问分布式文件系统本地的速度接近于访问本地硬盘。 1.3 高可用性 集群系统的特点是它在软硬件上都有冗余。系统的高可用性可以通过检测节点或服务进程故障和正确地重置系统来实现,使得系统收到的请求能被存活的服务器节点处理。 通常,我们在调度器上有资源监测进程来时刻监视各个服务器节点的健康状况。当服务器对ICMP ping不可达时或者探测到它的网络服务在指定的时间没有响应时,资源监测进程就会通知操作系统内核将该服务器从调度列表中删除或者失效。这样,新的服务请求就不会被调度到坏的节点。资源监测进程能通过电子邮件或传呼机向管理员报告故障。一旦监测进程监测到服务器恢复工作,其通知调度器将该服务器节点重新加入调度列表进行调度。另外,通过系统提供的管理程序,管理员可发命令随时可以将新机器加入服务来提高系统的处理性能,也可以将已有的服务器移出服务,以便对服务器进行系统维护。 现在前端的调度器有可能成为系统的单一失效点(Single Point of Failure)。一般来说,调度器的可靠性较高,因为调度器上运行的程序较少而且大部分程序早已经遍历过,但我们不能排除硬件老化、网络线路或者人为误操作等主要故障。为了避免调度器失效而导致整个系统不能工作,我们需要设立一个从调度器作为主调度器的备份。两个心跳(Heartbeat)进程分别在主、从调度器上运行,它们通过串口线和UDP等心跳线来相互定时地汇报各自的健康状况。当从调度器不能听得主调度器的心跳时,从调度器通过ARP欺骗 (Gratuitous ARP)来接管集群对外的Virtual IP Address,同时接管主调度器的工作来提供负载调度服务。当主调度器恢复时,这里有两种方法,一是主调度器自动变成从调度器,二是从调度器释放Virtual IP Address,主调度器收回Virtual IP Address并提供负载调度服务。这里,多条心跳线可以使得因心跳线故障导致误判(即从调度器认为主调度器已经失效,其实主调度器还在正常工作)的概率降到最低。 通常,当主调度器失效时,主调度器上所有已建立连接的状态信息将丢失,已有的连接会中断。客户需要向重新连接,从调度器才会将新连接调度到各个服务器上,这对客户会造成一定的不便。为此,IPVS调度器在Linux内核中实现一种高效状态同步机制,将主调度器的状态信息及时地同步到从调度器。当从调度器接管时,绝大部分已建立的连接会持续下去。 2、可伸缩Web服务 基于LVS的Web集群的体系结构如下图所示。 第一层是负载调度器,一般采用IP负载均衡技术,可以使得整个系统有较高的吞吐量; 第二层是Web服务器池,在每个节点上可以分别运行HTTP服务或HTTPS服务,或者两者都运行; 第三层是共享存储,它可以是数据库,可以是网络文件系统或分布式文件系统,或者是三者的混合; 集群中各个节点通过高速网络相连接。 对于动态页面(如PHP、JSP和ASP等),需要访问的动态数据一般存储在数据库服务器中。数据库服务运行在独立的服务器上,为所有Web服务器共享。无论同一Web服务器上多个动态页面访问同一数据,还是不同Web服务器上多个动态页面访问同一数据,数据库服务器有锁机制使得这些访问有序地进行,从而保证数据的一致性。 对于静态的页面和文件(如HTML文档和图片等),可以存储在网络文件系统或者分布式文件系统中。至于选择哪一种,看系统的规模和需求而定。通过共享的网络文件系统或者分布式文件系统,WebMaster可以看到统一的文档存储空间,维护和更新页面比较方便,对共享存储中页面的修改对所有的服务器都有效。 在这种结构下,当所有服务器节点超载时,管理员可以很快地加入新的服务器节点来处理请求,而无需将Web文档等复制到节点的本地硬盘上。 有些Web服务可能用到HTTP Cookie,它是将数据存储在客户的浏览器来追踪和标识客户的机制。使用HTTP Cookie后,来自同一客户的不同连接存在相关性,这些连接必须被发送到同一Web服务器。一些Web服务使用安全的HTTPS协议,它是HTTP协议加 SSL(Secure Socket Layer)协议。另有些Web服务可能使用安全的HTTPS协议,它是HTTP协议加SSL协议。当客户访问HTTPS服务(HTTPS的缺省端口为 443)时,会先建立一个SSL连接,来交换对称公钥加密的证书并协商一个SSL Key,来加密以后的会话。在SSL Key的生命周期内,后续的所有HTTPS连接都使用这个SSL Key,所以同一客户的不同HTTPS连接也存在相关性。针对这些需要,IPVS调度器提供了持久服务的功能,它可以使得在设定的时间内,来自同一IP地 址的不同连接会被发送到集群中同一个服务器结点,可以很好地解决客户连接的相关性问题。 3、可伸缩Cache服务 有效的网络Cache系统可以大大地减少网络流量、降低响应延时以及服务器的负载。但是,若Cache服务器超载而不能及时地处理请求,反而会增加响应延时。所以,Cache服务的可伸缩性很重要,当系统负载不断增长时,整个系统能被扩展来提高Cache服务的处理能力。尤其,在主干网上的 Cache服务可能需要几个Gbps的吞吐率,单台服务器(例如SUN目前最高端的Enterprise 10000服务器)远不能达到这个吞吐率。可见,通过PC服务器集群实现可伸缩Cache服务是很有效的方法,也是性能价格比最高的方法。 基于LVS的Cache集群的体系结构如下所示。 第一层是负载调度器,一般采用IP负载均衡技术,可以使得整个系统有较高的吞吐率; 第二层是Cache服务器池,一般Cache服务器放置在接近主干Internet连接处,它们可以分布在不同的网络中。 调度器可以有多个,放在离客户接近的地方。 IPVS负载调度器一般使用IP隧道方法(即VS/TUN方法),来架构Cache集群系统,因为Cache服务器可能被放置不同的地方(例如在接近主干Internet连接处),而调度器与Cache服务器池可能不在同一个物理网络中。采用VS/TUN方法,调度器只调度Web Cache请求,而Cache服务器将响应数据直接返回给客户。在请求对象不能在本地命中的情况下,Cache服务器要向源服务器发请求,将结果取回,最后将结果返回给客户。 三、IP负载均衡技术 1、实现虚拟服务的相关方法 在网络服务中,一端是客户程序,另一端是服务程序,在中间可能有代理程序。由此看来,可以在不同层次上实现多台服务器的负载均衡。用集群解决网络服务性能问题的现有方法主要有以下四类: 1.1 基于RR-DNS的解决方法 服务器组拥有相同的域名(如www.jjj.com),当用户按照该域名访问时,RR-DNS服务器会把域名轮流解析到这组服务器的不同IP地址,从而将访问负载分到各台服务器上。 这种方法会带来几个问题。 第一,域名服务器是一个分布式系统,是按照一定的层次结构组织的。当用户就域名解析请求提交给本地的域名服务器,它会因不能直接解析而向上一级域名服务器提交,上一级域名服务器再依次向上提交,直到RR-DNS域名服器把这个域名解析到其中一台服务器的IP地址。可见,从用户到RR-DNS间存在多台域名服器,而它们都会缓冲已解析的名字到IP地址的映射,这会导致该域名服器组下所有用户都会访问同一Web服务器,出现不同Web服务器间严重的负载不平衡。为了保证在域名服务器中域名到IP地址的映射不被长久缓冲,RR-DNS在域名到IP地址的映射上设置一个TTL(Time To Live)值,过了这一段时间,域名服务器将这个映射从缓冲中淘汰。当用户请求,它会再向上一级域名服器提交请求并进行重新映射。这就涉及到如何设置这个TTL值,若这个值太大,在这个TTL期间,很多请求会被映射到同一台Web服务器上,同样会导致严重的负载不平衡。若这个值太小,例如是0,会导致本地域名服务器频繁地向RR-DNS提交请求,增加了域名解析的网络流量,同样会使RR-DNS服务器成为系统中一个新的瓶颈。 第二,用户机器会缓存从名字到IP地址的映射,而不受TTL值的影响,用户的访问请求会被送到同一台WEB服务器上。由于用户访问请求的突发性和访问方式不同,例如有的人访问一下就离开了,而有的人访问可长达几个小时,所以各台服务器间的负载仍存在倾斜(Skew)而不能控制。假设用户在每个会话中平均请求数为20,负载最大的服务器获得的请求数额高于各服务器平均请求数的平均比率超过百分之三十。也就是说,当TTL值为0时,因为用户访问的突发性也会存在着较严重的负载不平衡。 第三,系统的可靠性和可维护性差。若一台服务器失效,会导致将域名解析到该服务器的用户看到服务中断,即使用户按 “Reload”按钮,也无济于事。 1.2 基于客户端的解决方法 基于客户端的解决方法需要每个客户程序都有一定的服务器集群的知识,进而把以负载均衡的方式将请求发到不同的服务器。例如,Netscape Navigator浏览器访问Netscape的主页时,它会随机地从一百多台服务器中挑选第N台,最后将请求送往wwwN.netscape.com。 1.3 基于应用层负载均衡调度的解决方法 多台服务器通过高速的互联网络连接成一个集群系统,在前端有一个基于应用层的负载调度器。当用户访问请求到达调度器时,请求会提交给用作负载均衡调度的应用程序,分析请求,根据各个服务器的负载情况,选出一台服务器,重写请求并向选出的服务器访问,取得结果后,再返回给用户。 基于应用层负载均衡调度的多服务器解决方法也存在一些问题。 第一,系统处理开销特别大,致使系统的伸缩性有限。同时,需要两次TCP连接,一次是从用户到调度器,另一次是从调度器到真实服务器,同时需要对请求进行分析和重写。 第二,基于应用层的负载均衡调度器对于不同的应用,需要写不同的调度器。 1.4 基于IP层负载均衡调度的解决方法 用户通过虚拟IP地址(Virtual IP Address)访问服务时,访问请求的报文会到达负载调度器,由它进行负载均衡调度,从一组真实服务器选出一个,将报文的目标地址Virtual IP Address改写成选定服务器的地址,报文的目标端口改写成选定服务器的相应端口,最后将报文发送给选定的服务器。真实服务器的回应报文经过负载调度器时,将报文的源地址和源端口改为Virtual IP Address和相应的端口,再把报文发给用户。 2、通过NAT实现虚拟服务器(VS/NAT) 客户通过Virtual IP Address(虚拟服务的IP地址)访问网络服务时,请求报文到达调度器,调度器根据连接调度算法从一组真实服务器中选出一台服务器,将报文的目标地址 Virtual IP Address改写成选定服务器的地址,报文的目标端口改写成选定服务器的相应端口,最后将修改后的报文发送给选出的服务器。 同时,调度器在连接Hash 表中记录这个连接,当这个连接的下一个报文到达时,从连接Hash表中可以得到原选定服务器的地址和端口,进行同样的改写操作,并将报文传给原选定的服务器。当来自真实服务器的响应报文经过调度器时,调度器将报文的源地址和源端口改为Virtual IP Address和相应的端口,再把报文发给用户。 3、通过IP隧道实现虚拟服务器(VS/TUN) 在VS/NAT 的集群系统中,请求和响应的数据报文都需要通过负载调度器,当真实服务器的数目在10台和20台之间时,负载调度器将成为整个集群系统的新瓶颈。大多数 Internet服务都有这样的特点:请求报文较短而响应报文往往包含大量的数据。如果能将请求和响应分开处理,即在负载调度器中只负责调度请求而响应直接返回给客户,将极大地提高整个集群系统的吞吐量。 我们利用IP隧道技术将请求报文封装转发给后端服务器,响应报文能从后端服务器直接返回给客户。但在这里,后端服务器有一组而非一个,所以我们不可能静态地建立一一对应的隧道,而是动态地选择一台服务器,将请求报文封装和转发给选出的服务器。这样,我们可以利用IP隧道的原理将一组服务器上的网络服务组成在一个IP地址上的虚拟网络服务。 VS/TUN的体系结构如下图所示,各个服务器将VIP地址配置在自己的IP隧道设备上。 VS/TUN的工作流程如下: 调度器根据各个服务器的负载情况,动态地选择一台服务器, 将请求报文封装在另一个IP报文中,再将封装后的IP报文转发给选出的服务器;服务器收到报文后,先将报文解封获得原来目标地址为VIP的报文,服务器发现VIP地址被配置在本地的IP隧道设备上,所以就处理这个请求,然后根据路由表将响应报文直接返回给客户。 4、通过直接路由实现虚拟服务器(VS/DR) 跟VS/TUN方法相同,VS/DR利用大多数Internet服务的非对称特点,负载调度器中只负责调度请求,而服务器直接将响应返回给客户,可以极大地提高整个集群系统的吞吐量。 VS/DR的体系结构如下图所示: 调度器和服务器组都必须在物理上有一个网卡通过不分断的局域网相连,如通过高速的交换机或者HUB相连。VIP地址为调度器和服务器组共享,调度器配置的VIP地址是对外可见的,用于接收虚拟服务的请求报文;所有的服务器把VIP地址配置在各自的Non-ARP网络设备上,它对外面是不可见的,只是用于处理目标地址为VIP的网络请求。 VS/DR的工作流程如下: 在VS/DR 中,调度器根据各个服务器的负载情况,动态地选择一台服务器,不修改也不封装IP报文,而是将数据帧的MAC地址改为选出服务器的MAC地址,再将修改后的数据帧在与服务器组的局域网上发送。因为数据帧的MAC地址是选出的服务器,所以服务器肯定可以收到这个数据帧,从中可以获得该IP报文。当服务器发现报文的目标地址VIP是在本地的网络设备上,服务器处理这个报文,然后根据路由表将响应报文直接返回给客户。 5、三种方法的优缺点比较 三种IP负载均衡技术的优缺点归纳在下表中: 6、小结 在本部分,我们主要讲述了LVS集群中的三种IP负载均衡技术。在分析网络地址转换方法(VS/NAT)的缺点和网络服务的非对称性的基础上,我们给出了通过IP隧道实现虚拟服务器的方法VS/TUN,和通过直接路由实现虚拟服务器的方法VS/DR,极大地提高了系统的伸缩性。 四、LVS集群的负载调度 在本部分,我们将主要讲述在负载调度器上的负载调度策略和算法,如何将请求流调度到各台服务器,使得各台服务器尽可能地保持负载均衡。 主要由两个部分组成。第一部分描述IP负载均衡软件IPVS在内核中所实现的各种连接调度算法;第二部分给出一个动态反馈负载均衡算法(Dynamic-feedback load balancing),它结合内核中的加权连接调度算法,根据动态反馈回来的负载信息来调整服务器的权值,来进一步避免服务器间的负载不平衡。 1、内核中的连接调度算法 在内核中的连接调度算法上,IPVS已实现了以下八种调度算法: 轮询调度(Round-Robin Scheduling) 加权轮询调度(Weighted Round-Robin Scheduling) 最少连接调度(Least-Connection Scheduling) 加权最少连接调度(Weighted Least-Connection Scheduling) 基于局部性的最少连接(Locality-Based Least Connections Scheduling) 带复制的基于局部性最少连接(Locality-Based Least Connections with Replication Scheduling) 目标地址散列调度(Destination Hashing Scheduling) 源地址散列调度(Source Hashing Scheduling) 下面,我们先介绍这八种连接调度算法的工作原理和算法流程,会在以后的文章中描述怎么用它们。 1.1 轮询调度 轮询调度(Round Robin Scheduling)算法就是以轮询的方式依次将请求调度不同的服务器,即每次调度执行i = (i + 1) mod n,并选出第i台服务器。算法的优点是其简洁性,它无需记录当前所有连接的状态,所以它是一种无状态调度。 在系统实现时,我们引入了一个额外条件,当服务器的权值为零时,表示该服务器不可用而不被调度。这样做的目的是将服务器切出服务(如屏蔽服务器故障和系统维护),同时与其他加权算法保持一致。 所以,算法要作相应的改动,它的算法流程如下: 假设有一组服务器S = {S0, S1, …, Sn-1},一个指示变量i表示上一次选择的 服务器,W(Si)表示服务器Si的权值。变量i被初始化为n-1,其中n > 0。 j = i; do { j = (j + 1) mod n; if (W(Sj) > 0) { i = j; return Si; } } while (j != i); return NULL; 轮询调度算法假设所有服务器处理性能均相同,不管服务器的当前连接数和响应速度。该算法相对简单,不适用于服务器组中处理性能不一的情况,而且当请求服务时间变化比较大时,轮询调度算法容易导致服务器间的负载不平衡。 虽然Round-Robin DNS方法也是以轮询调度的方式将一个域名解析到多个IP地址,但轮询DNS方法的调度粒度是基于每个域名服务器的,域名服务器对域名解析的缓存会妨碍轮询解析域名生效,这会导致服务器间负载的严重不平衡。这里,IPVS轮询调度算法的粒度是基于每个连接的,同一用户的不同连接都会被调度到不同的服务器上,所以这种细粒度的轮询调度要比DNS的轮询调度优越很多。 1.2 加权轮询调度 加权轮询调度(Weighted Round-Robin Scheduling)算法可以解决服务器间性能不一的情况,它用相应的权值表示服务器的处理性能,服务器的缺省权值为1。假设服务器A的权值为1,B的权值为2,则表示服务器B的处理性能是A的两倍。加权轮询调度算法是按权值的高低和轮询方式分配请求到各服务器。权值高的服务器先收到的连接,权值高的服务器比权值低的服务器处理更多的连接,相同权值的服务器处理相同数目的连接数。 加权轮询调度算法流程如下: 假设有一组服务器S = {S0, S1, …, Sn-1},W(Si)表示服务器Si的权值,一个 指示变量i表示上一次选择的服务器,指示变量cw表示当前调度的权值,max(S) 表示集合S中所有服务器的最大权值,gcd(S)表示集合S中所有服务器权值的最大 公约数。变量i初始化为-1,cw初始化为零。 while (true) { i = (i + 1) mod n; if (i == 0) { cw = cw - gcd(S); if (cw <= 0) { cw = max(S); if (cw == 0) return NULL; } } if (W(Si) >= cw) return Si; } 例如,有三个服务器A、B和C分别有权值4、3和2,则在一个调度周期内(mod sum(W(Si)))调度序列为AABABCABC。加权轮询调度算法还是比较简单和高效。当请求的服务时间变化很大,单独的加权轮询调度算法依然会导致服务器间的负载不平衡。 从上面的算法流程中,我们可以看出当服务器的权值为零时,该服务器不被被调度;当所有服务器的权值为零,即对于任意i有W(Si)=0,则没有任何服务器可用,算法返回NULL,所有的新连接都会被丢掉。加权轮询调度也无需记录当前所有连接的状态,所以它也是一种无状态调度。 1.3 最少连接调度 最少连接调度(Least-Connection Scheduling)算法是把新的连接请求分配到当前连接数最小的服务器。 最少连接调度是一种动态调度算法,它通过服务器当前所活跃的连接数来估计服务器的负载情况。调度器需要记录各个服务器已建立连接的数目,当一个请求被调度到某台服务器,其连接数加1;当连接中止或超时,其连接数减1。 在系统实现时,我们也引入当服务器的权值为零时,表示该服务器不可用而不被调度。 它的算法流程如下: 假设有一组服务器S = {S0, S1, ..., Sn-1},W(Si)表示服务器Si的权值, C(Si)表示服务器Si的当前连接数。 for (m = 0; m < n; m++) { if (W(Sm) > 0) { for (i = m+1; i < n; i++) { if (W(Si) <= 0) continue; if (C(Si) < C(Sm)) m = i; } return Sm; } } return NULL; 当各个服务器有相同的处理性能时,最少连接调度算法能把负载变化大的请求分布平滑到各个服务器上,所有处理时间比较长的请求不可能被发送到同一台服 务器上。但是,当各个服务器的处理能力不同时,该算法并不理想,因为TCP连接处理请求后会进入TIME_WAIT状态,TCP的TIME_WAIT一般为2分钟,此时连接还占用服务器的资源,所以会出现这样情形,性能高的服务器已处理所收到的连接,连接处于TIME_WAIT状态,而性能低的服务器已经忙于处理所收到的连接,还不断地收到新的连接请求。 1.4 加权最少连接调度 加权最少连接调度(Weighted Least-Connection Scheduling)算法是最少连接调度的超集,各个服务器用相应的权值表示其处理性能。服务器的缺省权值为1,系统管理员可以动态地设置服务器的权值。加权最少连接调度在调度新连接时尽可能使服务器的已建立连接数和其权值成比例。 加权最少连接调度的算法流程如下: 假设有一组服务器S = {S0, S1, ..., Sn-1},W(Si)表示服务器Si的权值, C(Si)表示服务器Si的当前连接数。所有服务器当前连接数的总和为 CSUM = ΣC(Si) (i=0, 1, .. , n-1)。当前的新连接请求会被发送服务器Sm, 当且仅当服务器Sm满足以下条件 (C(Sm) / CSUM)/ W(Sm) = min { (C(Si) / CSUM) / W(Si)} (i=0, 1, . , n-1) 其中W(Si)不为零 因为CSUM在这一轮查找中是个常数,所以判断条件可以简化为 C(Sm) / W(Sm) = min { C(Si) / W(Si)} (i=0, 1, . , n-1) 其中W(Si)不为零 因为除法所需的CPU周期比乘法多,且在Linux内核中不允许浮点除法,服务器的 权值都大于零,所以判断条件C(Sm) / W(Sm) > C(Si) / W(Si) 可以进一步优化 为C(Sm)*W(Si) > C(Si)* W(Sm)。同时保证服务器的权值为零时,服务器不被调 度。所以,算法只要执行以下流程。 for (m = 0; m < n; m++) { if (W(Sm) > 0) { for (i = m+1; i < n; i++) { if (C(Sm)*W(Si) > C(Si)*W(Sm)) m = i; } return Sm; } } return NULL; 1.5 基于局部性的最少连接调度 基于局部性的最少连接调度(Locality-Based Least Connections Scheduling,以下简称为LBLC)算法是针对请求报文的目标IP地址的负载均衡调度,目前主要用于Cache集群系统,因为在Cache集群中客户请求报文的目标IP地址是变化的。这里假设任何后端服务器都可以处理任一请求,算法的设计目标是在服务器的负载基本平衡情况下,将相同目标IP地址的请求调度到同一台服务器,来提高各台服务器的访问局部性和主存Cache命中率,从而整个集群系统的处理能力。 LBLC调度算法先根据请求的目标IP地址找出该目标IP地址最近使用的服务器,若该服务器是可用的且没有超载,将请求发送到该服务器;若服务器不存在,或者该服务器超载且有服务器处于其一半的工作负载,则用“最少连接”的原则选出一个可用的服务器,将请求发送到该服务器。 该算法的详细流程如下: 假设有一组服务器S = {S0, S1, ..., Sn-1},W(Si)表示服务器Si的权值, C(Si)表示服务器Si的当前连接数。ServerNode[dest_ip]是一个关联变量,表示 目标IP地址所对应的服务器结点,一般来说它是通过Hash表实现的。WLC(S)表示 在集合S中的加权最少连接服务器,即前面的加权最少连接调度。Now为当前系统 时间。 if (ServerNode[dest_ip] is NULL) then { n = WLC(S); if (n is NULL) then return NULL; ServerNode[dest_ip].server = n; } else { n = ServerNode[dest_ip].server; if ((n is dead) OR (C(n) > W(n) AND there is a node m with C(m) < W(m)/2))) then { n = WLC(S); if (n is NULL) then return NULL; ServerNode[dest_ip].server = n; } } ServerNode[dest_ip].lastuse = Now; return n; 此外,对关联变量ServerNode[dest_ip]要进行周期性的垃圾回收(Garbage Collection),将过期的目标IP地址到服务器关联项进行回收。过期的关联项是指哪些当前时间(实现时采用系统时钟节拍数jiffies)减去最 近使用时间超过设定过期时间的关联项,系统缺省的设定过期时间为24小时。 1.6 带复制的基于局部性最少连接调度 带复制的基于局部性最少连接调度(Locality-Based Least Connections with Replication Scheduling,以下简称为LBLCR)算法也是针对目标IP地址的负载均衡,目前主要用于Cache集群系统。 它与LBLC算法的不同之处是它要维护从一个目标IP地址到一组服务器的映射,而LBLC算法维护从一个目标IP地址到一台服务器的映射。对于一个“热门”站点的服务请求,一台Cache 服务器可能会忙不过来处理这些请求。这时,LBLC调度算法会从所有的Cache服务器中按“最少连接”原则选出一台Cache服务器,映射该“热门”站点到这台Cache服务器,很快这台Cache服务器也会超载,就会重复上述过程选出新的Cache服务器。这样,可能会导致该“热门”站点的映像会出现在所有的Cache服务器上,降低了Cache服务器的使用效率。LBLCR调度算法将“热门”站点映射到一组Cache服务器(服务器集合),当该“热 门”站点的请求负载增加时,会增加集合里的Cache服务器,来处理不断增长的负载;当该“热门”站点的请求负载降低时,会减少集合里的Cache服务器数目。这样,该“热门”站点的映像不太可能出现在所有的Cache服务器上,从而提供Cache集群系统的使用效率。 LBLCR算法先根据请求的目标IP地址找出该目标IP地址对应的服务器组;按“最少连接”原则从该服务器组中选出一台服务器,若服务器没有超载, 将请求发送到该服务器;若服务器超载;则按“最少连接”原则从整个集群中选出一台服务器,将该服务器加入到服务器组中,将请求发送到该服务器。同时,当该 服务器组有一段时间没有被修改,将最忙的服务器从服务器组中删除,以降低复制的程度。 LBLCR调度算法的流程如下: 假设有一组服务器S = {S0, S1, ..., Sn-1},W(Si)表示服务器Si的权值, C(Si)表示服务器Si的当前连接数。ServerSet[dest_ip]是一个关联变量,表示 目标IP地址所对应的服务器集合,一般来说它是通过Hash表实现的。WLC(S)表示 在集合S中的加权最少连接服务器,即前面的加权最少连接调度;WGC(S)表示在 集合S中的加权最大连接服务器。Now为当前系统时间,lastmod表示集合的最近 修改时间,T为对集合进行调整的设定时间。 if (ServerSet[dest_ip] is NULL) then { n = WLC(S); if (n is NULL) then return NULL; add n into ServerSet[dest_ip]; } else { n = WLC(ServerSet[dest_ip]); if ((n is NULL) OR (n is dead) OR (C(n) > W(n) AND there is a node m with C(m) < W(m)/2))) then { n = WLC(S); if (n is NULL) then return NULL; add n into ServerSet[dest_ip]; } else if (|ServerSet[dest_ip]| > 1 AND Now - ServerSet[dest_ip].lastmod > T) then { m = WGC(ServerSet[dest_ip]); remove m from ServerSet[dest_ip]; } } ServerSet[dest_ip].lastuse = Now; if (ServerSet[dest_ip] changed) then ServerSet[dest_ip].lastmod = Now; return n; 此外,对关联变量ServerSet[dest_ip]也要进行周期性的垃圾回收(Garbage Collection),将过期的目标IP地址到服务器关联项进行回收。过期的关联项是指哪些当前时间(实现时采用系统时钟节拍数jiffies)减去最近使用时间(lastuse)超过设定过期时间的关联项,系统缺省的设定过期时间为24小时。 1.7 目标地址散列调度 目标地址散列调度(Destination Hashing Scheduling)算法也是针对目标IP地址的负载均衡,但它是一种静态映射算法,通过一个散列(Hash)函数将一个目标IP地址映射到一台服务器。 目标地址散列调度算法先根据请求的目标IP地址,作为散列键(Hash Key)从静态分配的散列表找出对应的服务器,若该服务器是可用的且未超载,将请求发送到该服务器,否则返回空。 该算法的流程如下: 假设有一组服务器S = {S0, S1, ..., Sn-1},W(Si)表示服务器Si的权值, C(Si)表示服务器Si的当前连接数。ServerNode[]是一个有256个桶(Bucket)的 Hash表,一般来说服务器的数目会运小于256,当然表的大小也是可以调整的。 算法的初始化是将所有服务器顺序、循环地放置到ServerNode表中。若服务器的 连接数目大于2倍的权值,则表示服务器已超载。 n = ServerNode[hashkey(dest_ip)]; if ((n is dead) OR (W(n) == 0) OR (C(n) > 2*W(n))) then return NULL; return n; 在实现时,我们采用素数乘法Hash函数,通过乘以素数使得散列键值尽可能地达到较均匀的分布。所采用的素数乘法Hash函数如下: static inline unsigned hashkey(unsigned int dest_ip) { return (dest_ip* 2654435761UL) & HASH_TAB_MASK; } 其中,2654435761UL是2到2^32 (4294967296)间接近于黄金分割的素数, 1.8 源地址散列调度 源地址散列调度(Source Hashing Scheduling)算法正好与目标地址散列调度算法相反,它根据请求的源IP地址,作为散列键(Hash Key)从静态分配的散列表找出对应的服务器,若该服务器是可用的且未超载,将请求发送到该服务器,否则返回空。它采用的散列函数与目标地址散列调度算法 的相同。它的算法流程与目标地址散列调度算法的基本相似,除了将请求的目标IP地址换成请求的源IP地址,所以这里不一一叙述。 在实际应用中,源地址散列调度和目标地址散列调度可以结合使用在防火墙集群中,它们可以保证整个系统的唯一出入口。 2、动态反馈负载均衡算法 我们提出基于动态反馈负载均衡机制,来控制新连接的分配,从而控制各个服务器的负载。例如,在IPVS调度器的内核中使用加权轮询调度 (Weighted Round-Robin Scheduling)算法来调度新的请求连接;在负载调度器的用户空间中运行Monitor Daemon。Monitor Daemon定时地监视和收集各个服务器的负载信息,根据多个负载信息算出一个综合负载值。Monitor Daemon将各个服务器的综合负载值和当前权值算出一组新的权值。当综合负载值表示服务器比较忙时,新算出的权值会比其当前权值要小,这样新分配到该服务器的请求数就会少一些。当综合负载值表示服务器处于低利用率时,新算出的权值会比其当前权值要大,来增加新分配到该服务器的请求数。若新权值和当前权值的差值大于设定的阈值,Monitor Daemon将该服务器的权值设置到内核中的IPVS调度中。过了一定的时间间隔(如2秒钟),Monitor Daemon再查询各个服务器的情况,并相应调整服务器的权值;这样周期性地进行。可以说,这是一个负反馈机制,使得服务器保持较好的利用率。 在加权轮询调度算法中,当服务器的权值为零,已建立的连接会继续得到该服务器的服务,而新的连接不会分配到该服务器。系统管理员可以将一台服务器的权值设置为零,使得该服务器安静下来,当已有的连接都结束后,他可以将该服务器切出,对其进行维护。维护工作对系统都是不可少的,比如硬件升级和软件更新等,零权值使得服务器安静的功能很主要。所以,在动态反馈负载均衡机制中我们要保证该功能,当服务器的权值为零时,我们不对服务器的权值进行调整。 五、总结 在本文,我们主要对LVS技术进行了原理级的介绍。

优秀的个人博客,低调大师

Nginx upload上传模块(学习笔记十七)

上传模块配置样例: # 上传大小限制(包括所有内容) client_max_body_size 100m; # 上传path配置 location /upload { # 转到后台处理URL upload_pass /uploadHandle; # 临时保存路径 # 可以使用散列 upload_store /tmp/nginx_upload; # 上传文件的权限,rw表示读写 r只读 upload_store_access user:rw; # 这里写入http报头,pass到后台页面后能获取这里set的报头字段 upload_set_form_field "${upload_field_name}_name"$upload_file_name; upload_set_form_field "${upload_field_name}_content_type"$upload_content_type; upload_set_form_field "${upload_field_name}_path"$upload_tmp_path; # Upload模块自动生成的一些信息,如文件大小与文件md5值 upload_aggregate_form_field "${upload_field_name}_md5"$upload_file_md5; upload_aggregate_form_field "${upload_field_name}_size"$upload_file_size; # 允许的字段,允许全部可以 "^.*$" upload_pass_form_field "^submit$|^description$"; # 每秒字节速度控制,0表示不受控制,默认0 upload_limit_rate 0; # 如果pass页面是以下状态码,就删除此次上传的临时文件 upload_cleanup 400 404 499 500-505; } 一. nginx upload module原理 官方文档:http://www.grid.net.ru/nginx/upload.en.html Nginx upload module通过nginx服务来接受用户上传的文件,自动解析请求体中存储的所有文件上传到upload_store指定的目录下。这些文件信息从原始请求体中分离并根据nginx.conf中的配置重新组装好上传参数,交由upload_pass指定的段处理,从而允许处理任意上传文件。每个上传文件中的file字段值被一系列的upload_set_form_field指令值替换。每个上传文件的内容可以从$upload_tmp_path变量读取,或者可以将文件转移到目的目录下。上传的文件移除可以通过upload_cleanup指令控制。如果请求的方法不是POST,模块将返回405错误(405 Not Allowed),该错误提示可以通过error_page指令处理。 具体的过程如下: 1. 用户访问能够选择上传文件的页面 2. 用户提交表单 3. 浏览器把文件和有关文件的信息作为请求的一部分发送给服务器 4. 服务器把文件保存到临时存储目录下upload_store 5. upload_pass指定的处理表单提交的php页面将文件从upload_store拷贝到持久存储位置 二.nginx upload module配置参数 upload_pass 指明后续处理的php地址。文件中的字段将被分离和取代,包含必要的信息处理上传文件。 upload_resumable 是否启动可恢复上传。 upload_store 指定上传文件存放地址(目录)。目录可以散列,在这种情况下,在nginx启动前,所有的子目录必须存在。 upload_state_store 指定保存上传文件可恢复上传的文件状态信息目录。目录可以散列,在这种情况下,在nginx启动前,所有的子目录必须存在。 upload_store_access 上传文件的访问权限,user:r是指用户可读 upload_pass_form_field 从表单原样转到后端的参数,可以正则表达式表示。: $upload_field_name — 原始文件中的字段的名称 upload_pass_form_field “^submit$|^description$”; 意思是把submit,description这两个字段也原样通过upload_pass传递到后端php处理。如果希望把所有的表单字段都传给后端可以用upload_pass_form_field “^.*$”; upload_set_form_field 名称和值都可能包含以下特殊变量: $upload_field_name 表单的name值 $upload_content_type 上传文件的类型 $upload_file_name 客户端上传的原始文件名称 $upload_tmp_path 文件上传后保存在服务端的位置 upload_aggregate_form_field 可以多使用的几个变量,文件接收完毕后生成的并传递到后端 $upload_file_md5 文件的MD5校验值 $upload_file_md5_uc 大写字母表示的MD5校验值 $upload_file_sha1 文件的SHA1校验值 $upload_file_sha1_uc 大写字母表示的SHA1校验值 $upload_file_crc32 16进制表示的文件CRC32值 $upload_file_size 文件大小 $upload_file_number 请求体中的文件序号 这些字段值是在文件成功上传后计算的。 upload_cleanup 如果出现400 404 499 500-505之类的错误,则删除上传的文件 upload_buffer_size 上传缓冲区大小 upload_max_part_header_len 指定头部分最大长度字节。 upload_max_file_size 指定上传文件最大大小,软限制。client_max_body_size硬限制。 upload_limit_rate 上传限速,如果设置为0则表示不限制。 upload_max_output_body_len 超过这个大小,将报403错(Request entity too large)。 upload_tame_arrays 指定文件字段名的方括号是否删除 upload_pass_args 是否转发参数。 三. nginx配置 # wget http://www.nginx.org/download/nginx-1.2.2.tar.gz # wget http://www.grid.net.ru/nginx/download/nginx_upload_module-2.2.0.tar.gz # tar zxvf nginx_upload_module-2.2.0.tar.gz -c ../software/ # tar zxvf nginx_upload_module-2.2.0.tar.gz -C ../software/ # ./configure –prefix=/usr/local/nginx –add-module=../nginx_upload_module-2.2.0 –with-http_secure_link_module # make # make install # vi nginx.conf user www-data; worker_processes 20; error_log logs/error.log notice; working_directory /usr/local/nginx; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; root /www/web/upload; server { listen 80; server_name 192.168.41.129; error_page 405 =200 @405; //处理405错误 location / { index index.html index.htm index.php; } location @405 { root /www/web/upload; } location ~ \.php$ { try_files $uri /404.html; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include /etc/nginx/fastcgi_params; } client_max_body_size 100m; # 上传页面提交到这个location location /upload { # 文件上传以后转交给后端的php代码处理 upload_pass @test; # 上传文件的临时存储位置,目录是散列的,应该存在子目录0 1 2 3 4 5 6 7 8 9 upload_store /www/web/upload/tmp 1; upload_store_access user:r; # 设置请求体的字段 upload_set_form_field “${upload_field_name}_name” $upload_file_name; upload_set_form_field “${upload_field_name}_content_type” $upload_content_type; upload_set_form_field “${upload_field_name}_path” $upload_tmp_path; # 指示后端关于上传文件的md5值和文件大小 upload_aggregate_form_field “${upload_field_name}_md5″ $upload_file_md5; upload_aggregate_form_field “${upload_field_name}_size” $upload_file_size; # 指示原样转到后端的参数,可以用正则表达式表示 upload_pass_form_field “^submit$|^description$”; upload_pass_args on; } # 将请求转到后端的地址处理 location @test { rewrite ^(.*)$ /test.php last; } } } 四. 上传界面 # cat /www/web/upload/upload.html Test upload Select files to upload 五. upload_pass处理内容 # cat test.php //这里只是简单的打印出来,便于先理解上传原理。请对着输出内容理解下nginx upload module配置参数。 print_r($_POST); ?> 对上传文件的处理请参考:http://cn.php.net/manual/en/features.file-upload.php 六. 测试 http://192.168.41.129/upload.html 输出内容如下所示: Array ( [file1_name] => LearningPerl, Sixth Edition.pdf [file1_content_type] => application/pdf [file1_path] => /www/web/upload/tmp/4/0000000014 [file1_md5] => 87032cc58109f5c6bb866d2684f9b48c [file1_size] => 8927511 [file2_name] => Programming Perl, 4th Edition.pdf [file2_content_type] => application/pdf [file2_path] => /www/web/upload/tmp/5/0000000015 [file2_md5] => 82a52df177a8912c06af276581cfd5e4 [file2_size] => 21146356 [submit] => Upload ) 注意:需要修改php.ini以下参数 file_uploads on 是否允许通过http上传 upload_max_filesize 8m 允许上传文件的最大大小 post_max_size 8m 通过表单POST给php所能接收的最大值 另外nginx.conf中设置上传文件大小 upload_max_file_size 软限制 client_max_body_size 硬限制 一.nginxuploadmodule原理 官方文档:http://www.grid.net.ru/nginx/upload.en.html Nginxuploadmodule通过nginx服务来接受用户上传的文件,自动解析请求体中存储的所有文件上传到upload_store指定的目录下。这些文件信息从原始请求体中分离并根据nginx.conf中的配置重新组装好上传参数,交由upload_pass指定的段处理,从而允许处理任意上传文件。每个上传文件中的file字段值被一系列的upload_set_form_field指令值替换。每个上传文件的内容可以从$upload_tmp_path变量读取,或者可以将文件转移到目的目录下。上传的文件移除可以通过upload_cleanup指令控制。如果请求的方法不是POST,模块将返回405错误(405NotAllowed),该错误提示可以通过error_page指令处理。 具体的过程如下: 1.用户访问能够选择上传文件的页面 2.用户提交表单 3.浏览器把文件和有关文件的信息作为请求的一部分发送给服务器 4.服务器把文件保存到临时存储目录下upload_store 5.upload_pass指定的处理表单提交的php页面将文件从upload_store拷贝到持久存储位置 P.S. 安装编译方法 1.下载 1wget http://www.grid.net.ru/nginx/download/nginx_upload_module-2.2.0.tar.gz 2.编译(在NGINX编译目录执行以下命令,其中--add-module=你下载解压的上传插件目录) ./configure--user=www --group=www --prefix=/usr/local/nginx--with-http_stub_status_module --with-http_s sl_module --with-http_gzip_static_module --add-module=/data/downfile/nginx_upload_module-2.2.0 二.nginxuploadmodule配置参数 upload_pass指明后续处理的php地址。文件中的字段将被分离和取代,包含必要的信息处理上传文件。 upload_resumable是否启动可恢复上传。 upload_store指定上传文件存放地址(目录)。目录可以散列,在这种情况下,在nginx启动前,所有的子目录必须存在。 upload_state_store指定保存上传文件可恢复上传的文件状态信息目录。目录可以散列,在这种情况下,在nginx启动前,所有的子目录必须存在。 upload_store_access上传文件的访问权限,user:r是指用户可读 upload_pass_form_field从表单原样转到后端的参数,可以正则表达式表示。: $upload_field_name—原始文件中的字段的名称 upload_pass_form_field“^submit$|^description$”; 意思是把submit,description这两个字段也原样通过upload_pass传递到后端php处理。如果希望把所有的表单字段都传给后端可以用upload_pass_form_field“^.*$”; upload_set_form_field名称和值都可能包含以下特殊变量: $upload_field_name表单的name值 $upload_content_type上传文件的类型 $upload_file_name客户端上传的原始文件名称 $upload_tmp_path文件上传后保存在服务端的位置 upload_aggregate_form_field可以多使用的几个变量,文件接收完毕后生成的并传递到后端 $upload_file_md5文件的MD5校验值 $upload_file_md5_uc大写字母表示的MD5校验值 $upload_file_sha1文件的SHA1校验值 $upload_file_sha1_uc大写字母表示的SHA1校验值 $upload_file_crc3216进制表示的文件CRC32值 $upload_file_size文件大小 $upload_file_number请求体中的文件序号 这些字段值是在文件成功上传后计算的。 upload_cleanup如果出现400404499500-505之类的错误,则删除上传的文件 upload_buffer_size上传缓冲区大小 upload_max_part_header_len指定头部分最大长度字节。 upload_max_file_size指定上传文件最大大小,软限制。client_max_body_size硬限制。 upload_limit_rate上传限速,如果设置为0则表示不限制。 upload_max_output_body_len超过这个大小,将报403错(Requestentitytoolarge)。 upload_tame_arrays指定文件字段名的方括号是否删除 upload_pass_args是否转发参数。 三.nginx配置 #wget http: //www.nginx.org/download/nginx-1.2.2.tar.gz #wget http: //www.grid.net.ru/nginx/download/nginx_upload_module-2.2.0.tar.gz #tar zxvf nginx_upload_module - 2.2.0.tar.gz - c.. / software / #tar zxvf nginx_upload_module - 2.2.0.tar.gz - C.. / software / #. / configure–prefix = /usr/local / nginx–add - module = .. / nginx_upload_module - 2.2.0–with - http_secure_link_module #make #make install #vi nginx.conf user www - data; worker_processes 20; error_log logs / error.log notice; working_directory / usr /local/ nginx; events { worker_connections 1024; } http { include mime.types; default_type application / octet - stream; root / www / web / upload; server { listen 80; server_name 192.168.41.129; error_page 405 = 200@405;//处理405错误 location / { index index.html index.htm index.php; } location@405 { root / www / web / upload; } location~\.php$ { try_files $uri / 404.html; fastcgi_pass 127.0.0.1 : 9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include/etc/nginx/fastcgi_params; } client_max_body_size 100m;#上传页面提交到这个location location / upload { #文件上传以后转交给后端的php代码处理 upload_pass@test; #上传文件的临时存储位置,目录是散列的,应该存在子目录0 1 2 3 4 5 6 7 8 9 upload_store/www/web/upload/tmp1; upload_store_access user: r; #设置请求体的字段 upload_set_form_field "${upload_field_name}_name" $upload_file_name; upload_set_form_field"${upload_field_name}_content_type"$upload_content_type; upload_set_form_field"${upload_field_name}_path"$upload_tmp_path; # 指示后端关于上传文件的md5值和文件大小 upload_aggregate_form_field"${upload_field_name}_md5"$upload_file_md5; upload_aggregate_form_field"${upload_field_name}_size"$upload_file_size; # 指示原样转到后端的参数,可以用正则表达式表示 upload_pass_form_field"^submit$|^description$"; upload_pass_args on; }#将请求转到后端的地址处理 location@test{ rewrite ^ (. * ) $ /test.php last; } } } 四.上传界面 #cat/www/web/upload/upload.html 五.upload_pass处理内容 #cattest.php//这里只是简单的打印出来,便于先理解上传原理。请对着输出内容理解下nginxuploadmodule配置参数。 print_r($_POST); ?> 对上传文件的处理请参考:http://cn.php.net/manual/en/features.file-upload.php 六.测试 http://192.168.41.129/upload.html 输出内容如下所示: Array ( [file1_name]=>LearningPerl,SixthEdition.pdf [file1_content_type]=>application/pdf [file1_path]=>/www/web/upload/tmp/4/0000000014 [file1_md5]=>87032cc58109f5c6bb866d2684f9b48c [file1_size]=>8927511 [file2_name]=>ProgrammingPerl,4thEdition.pdf [file2_content_type]=>application/pdf [file2_path]=>/www/web/upload/tmp/5/0000000015 [file2_md5]=>82a52df177a8912c06af276581cfd5e4 [file2_size]=>21146356 [submit]=>Upload ) 注意:需要修改php.ini以下参数 file_uploadson是否允许通过http上传 upload_max_filesize8m允许上传文件的最大大小 post_max_size8m通过表单POST给php所能接收的最大值 另外nginx.conf中设置上传文件大小 upload_max_file_size软限制 client_max_body_size硬限制

优秀的个人博客,低调大师

Nginx 动静分离架构(学习笔记九)

一、原理 Nginx 动静分离简单来说就是把动态跟静态请求分开,不能理解成只是单纯的把动态页面和静态页面物理分离。严格意义上说应该是动态请求跟静态请求分开,可以理解成使用Nginx 处理静态页面,Tomcat、 Resin 出来动态页面。动静分离从目前实现角度来讲大致分为两种, 一种是纯粹把静态文件独立成单独的域名,放在独立的服务器上,也是目前主流推崇的方案; 另外一种方法就是动态跟静态文件混合在一起发布,通过 nginx 来分开。这样也是本次课程要讲解的,具体怎么来实现呢, 通过 location 指定不同的后缀名实现不同的请求转发。通过 expires 参数设置,可以使浏览器缓存过期时间,减少与服务器之前的请求和流量。具体 Expires 定义:是给一个资源设定一个过期时间,也就是说无需去服务端验证,直接通过浏览器自身确认是否过期即可,所以不会产生额外的流量。此种方法非常适合不经常变动的资源。(如果经常更新的文件,不建议使用 Expires 来缓存),我这里设置 3d,表示在这 3 天之内访问这个 URL,发送一个请求,比对服务器该文件最后更新时间没有变化,则不会从服务器抓取,返回状态码 304,如果有修改,则直接从服务器重新下载,返回状态码 200。 二、例子 在 nginx-1.13.0.tar.gz下测试 项目 静态文件路径 配置文件 server { listen 80; server_name a; location /t1 { proxy_pass http://192.168.56.90:8180/t1; } location ~ .*\.(html|htm|gif|jpg|jpeg|bmp|png|ico|txt|js|css)$ { root /usr/local/tomcat/apache-tomcat-7.0.70-8180/webapps/; expires 30d; } } 测试 访问静态文件 再次访问 状态为304 最后检查 Nginx 配置是否正确即可,然后测试动静分离是否成功,之需要删除后端tomcat 服务器上的某个静态文件,查看是否能访问,如果可以访问说明静态资源 nginx 直接返回了,不走后端 tomcat 服务器

优秀的个人博客,低调大师

【Android学习笔记】布局的简单介绍

我在学习Android开发的时候是基于实战项目的,基础理论知识以前也是零散的看过一些,个人还是觉得边做项目边学要快些。现在做的这个项目iOS端是我做的,这样逻辑什么的都很熟悉,于我而言换个平台也只是换个语言语法而已,但是不得不说,Android开发和iOS开发差别还是很大的,特别是布局方面,iOS我都是纯代码开发的,对于Android而言布局用的比较多的是xml,很是不习惯。而且Android的布局我觉得比较复杂,界面做做还可以,大部分都是网上现查现用的,如果真的说Android的布局我可能讲不清楚,毕竟很多原理和细节我都还不知道。不过我们的Android开发告诉我,他们也可以用Java纯代码来写布局,我在考虑去学学。xml布局,感觉菜鸟教程上讲的还是可以的,就是给的例子比较少,情况也没有很复杂的,在做项目开发的时候帮助不大,但是入门看看还是可以的,在这里给一下链接,有兴趣的可以看看。 线性布局:http://www.runoob.com/w3cnote/android-tutorial-linearlayout.html 相对布局:http://www.runoob.com/w3cnote/android-tutorial-relativelayout.html 表格布局:http://www.runoob.com/w3cnote/android-tutorial-tablelayout.html 帧布局:http://www.runoob.com/w3cnote/android-tutorial-framelayout.html 网格布局:http://www.runoob.com/w3cnote/android-tutorial-gridlayout.html 绝对布局:http://www.runoob.com/w3cnote/android-tutorial-absolutelayout.html 还听说Android最近新出了约束布局,听说与iOS的布局很像,但是我还没有去查过相关资料,后面有新的资料了会在这里更新。

优秀的个人博客,低调大师

【Android学习笔记】设置App启动页

先将启动页放到项目资源中,图片一般是1080*1920的jpg。 新建一个activity,如图: 创建成功之后,打开刚刚创建的activity,来进行代码的编写: public class BZLaunchActivity extends AppCompatActivity { private final int SPLASH_DISPLAY_LENGHT = 2000;//两秒后进入系统,时间可自行调整 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_bzlaunch); //在BZLaunchActivity停留2秒然后进入BZLaunchActivity new android.os.Handler().postDelayed(new Runnable() { @Override public void run() { Intent mainIntent = new Intent(BZLaunchActivity.this,MainActivity.class); BZLaunchActivity.this.startActivity(mainIntent); BZLaunchActivity.this.finish(); } },SPLASH_DISPLAY_LENGHT); } } 然后去xml配置文件里画界面,配置文件在res/layout与创建时layout同名的的xml文件,代码如下: <?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".BZLaunchActivity"> <ImageView android:id="@+id/imageView" android:layout_width="wrap_content" android:layout_height="wrap_content" //让图片全屏显示 android:scaleType="fitXY" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" //启动页图片 app:srcCompat="@mipmap/zqq_launch" /> </android.support.constraint.ConstraintLayout> 如果android:scaleType="fitXY"不设置,可能出现启动页图片不全屏的情况。 最后要去AndroidManifest.xml文件中修改一下启动页的activity的位置,未修改之前,MainActivity是在前面的,这个时候运行App,发现并没有启动页,我们需要把启动页的activity调到MainActivity的前面,也就是: <activity android:name=".BZLaunchActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> 好了,完成上面这些,再运行App,就会看到启动页了。

优秀的个人博客,低调大师

【Android学习笔记】设置项目桌面icon

近来项目处于测试阶段,工作少了许多,就装了个最新的Android Studio,想写一下安卓。新建好项目,想设置个桌面的icon。我先准备好自己的icon图片,然后复制粘贴到res/mipmap-hdpi文件夹下,然后在AndroidManifest中将icon的地址改为我自己图片的命名,运行之后,发现模拟器所有icon都是圆的,我的图片是方形的,显示的样子为一个圆的白色里面套着我的方形icon,然后就上网查了一下安卓icon适配的问题。Android Studio确实也提供了适配的方法,网上也有很多,不过我掉进了一个坑里,先来介绍下icon自适应的配置,首先新建一个Image Asset,如图: 选择Image Asset之后, 如图在标注的地方选择自己要设置的icon的图片。前面我说过,我已经将icon复制到res/mipmap-hdpi文件夹,然后我去那里选择图片,但是并没有我粘贴进去的图片,然后我直接右键res/mipmap-hdpi文件夹,选择显示文件夹,就看到图片在那里。也就是在设置icon选择路径那里选不到自己的icon,然后弄了好久,icon一直设置不成功,最后我在路径那里选了那张图片在我电脑上的路径,然后就发现右边图片不再显示默认的icon而是我自己的icon了,然后点击next,再点击finish,App的icon就设置好了。 说一下主要坑点,icon图片已经复制粘贴到项目下,但是在选择图片的时候去到图片所在的路径却看不到图片。如果遇到这种情况,就不要先把图片放到项目里,设置的时候直接选择图片就可以了。 由于做安卓开发不久,处于菜鸟阶段,我不知道这是什么原因造成的,有路过的大神可以给我解答一下疑惑。另外我之前用过Android Studio2.x的版本,设置icon的时候就没遇到过这个问题。

优秀的个人博客,低调大师

Java-学习笔记-4-抽象

不足之处,欢迎专家、同行、读者批评指正。 上一篇在说类库文件时提到了封装,不够严谨,这一篇来简单讲讲。 抽象和封装,这是面向对象程序设计中的一个重要思想。换句话说,是思维方式的转变。以前我们编程,是围绕某一个问题的,研究它的过程是怎样的。现在嘛,是考虑不同的对象之间的信息传递,更适合来写不同对象交互信息的业务。 先说说抽象。最关键的在于属性和功能。举个例子吧,比如说现在你要去图书馆借书,那对你来说,你的属性就是个人ID,借阅权限,借了几本书等等,图书馆那边对象很多,比如说管理员、书等等。你们之间的业务往来,就可以看作功能。 更直白点说,属性通常就是信息的那个值,编程时我们写成int的这种,所谓的功能就是对这个值进行操作的函数或者说方法。当然啦,一个类之中嵌套另一个类,并且把里边的那个类看做是成员变量,这种情况也是有的,不过在理解含义时可以把它和上文的“值”看作一回事。

优秀的个人博客,低调大师

Java-学习笔记-5-封装

不足之处,欢迎专家、同行、读者批评指正。 抽象和封装其实可以放到一起来记。 封装,字面意思看起来像是封上口打包装起来——实际上就是这个意思。只不过,这里我们打包的不是快递包裹,是代码的源文件。Java是有包管理机制的。 这个包,在资源管理器里看的话,是一个个的文件夹——但反过来不能说文件夹就是包。你看,封装,打包,命名的时候就是这么直白。 这个机制,是对访问权限的限制。不过它限制的不是我们。作为开发者,我们自己所负责的几个包中,所有代码都是可以看到的。但是,它限制了不同包的源文件中的变量或者方法,访问其他源文件中的变量或者方法的权限。 关于这个,和C++相似,但不一样。具体可以查阅文档。搜索的关键字可以是public、private等。 是的,文档永远是第一手信息。

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册