首页 文章 精选 留言 我的

精选列表

搜索[官方镜像],共10000篇文章
优秀的个人博客,低调大师

官方文档】Nginx负载均衡学习笔记(二)负载均衡基本概念介绍

简介 负载均衡(Server Load Balancer)是将访问流量根据转发策略分发到后端多台 ECS 的流量分发控制服务。负载均衡可以通过流量分发扩展应用系统对外的服务能力,通过消除单点故障提升应用系统的可用性。 负载均衡主要有如下几个功能点: 负载均衡服务通过设置虚拟服务地址(IP),将位于同一地域(Region)的多台云服务器(Elastic Compute Service,简称ECS)资源虚拟成一个高性能、高可用的应用服务池;根据应用指定的方式,将来自客户端的网络请求分发到云服务器池中。 负载均衡服务会检查云服务器池中ECS的健康状态,自动隔离异常状态的ECS,从而解决了单台ECS的单点问题,同时提高了应用的整体服务能力。在标准的负载均衡功能之外,负载均衡服务还具备TCP与HTTP抗DDoS攻击的特性,增强了应用服务器的防护能力。 负载均衡服务是ECS面向多机方案的一个配套服务,需要同ECS结合使用。 核心概念 负载均衡服务主要有三个核心概念: LoadBalancer:负载均衡实例。 Listener:用户定制的监听器,定义了负载均衡策略和转发规则。 BackendServer:后端的一组ECS(云服务器)。 下图描述了负载均衡服务的核心概念。来自外部的访问请求,由负载均衡实例根据相关的策略和转发规则分发到后端ECS进行处理。 协议支持 当前提供4层(TCP协议和UDP协议)和7层(HTTP和HTTPS协议)的负载均衡服务。 健康检查 支持对后端ECS进行健康检查,自动屏蔽异常状态的ECS,待该ECS恢复正常后自动解除屏蔽。 会话保持 提供会话保持功能,在Session的生命周期内,可以将同一客户端的请求转发到同一台后端ECS上。 调度算法 支持加权轮询(WRR),加权最小连接数(WLC),和轮询3种调度算法。 加权轮询:根据服务器的处理能力为后端 ECS 分配不同的权值,将外部请求依序分发到后端ECS上,后端ECS权重越高被分发的几率也越大。 加权最小连接数:根据服务器的处理能力为后端 ECS 分配不同的权值,将外部请求分发到当前连接数最小的后端ECS上,后端ECS权重越高被分发的几率也越大。 轮询:将外部请求依序分发到后端ECS上。 域名URL转发 针对七层协议(HTTP协议和HTTPS协议),支持按用户访问的域名和URL来转发流量到不同的虚拟服务器组。 访问控制 支持白名单控制,通过设置负载均衡监听,仅允许特定IP访问,适用于用户的应用只允许特定IP访问的场景。(只能通过Lua) 使用场景 负载均衡主要可以应用于以下场景中: 灵活的进行流量分发,适用于具有高访问量的业务。 横向扩展应用系统的服务能力,适用于各种 web server 和 app server。 消除应用系统的单点故障,当其中一部分 ECS 发生故障后,应用系统仍能正常工作。 提高应用系统容灾能力,多可用区部署,机房发生故障后,仍能正常工作。 https://help.aliyun.com/document_detail/27541.html?spm=5176.doc27543.6.544.5RC2R1 术语表 中文 英文 说明 负载均衡服务 Server Load Balancer 阿里云计算提供的一种网络负载均衡服务,可以结合阿里云提供的 ECS 服务为用户提供基于 ECS 实例的 TCP 与 HTTP 负载均衡服务。 负载均衡实例 Load Balancer 负载均衡实例可以理解为负载均衡服务的一个运行实例,用户要使用负载均衡服务,就必须先创建一个负载均衡实例,LoadBalancerId 是识别用户负载均衡实例的唯一标识。 负载均衡服务监听 Listener 负载均衡服务监听,包括监听端口、负载均衡策略和健康检查配置等,每个监听对应后端的一个应用服务。 后端服务器 Backend Server 接受负载均衡分发请求的一组ECS,负载均衡服务将外部的访问请求按照用户设定的规则转发到这一组后端 ECS上进行处理。 服务地址 Address 系统分配的服务地址,当前为IP地址。用户可以选择该服务地址是否对外公开,来分别创建公网和私网类型的负载均衡服务。 证书 Certificate 用于 HTTPS 协议。用户将证书上传到负载均衡中,在创建 HTTPS 协议监听的时候绑定证书,提供 HTTPS 服务。 主可用区 Master Availability Zone 负载均衡会在某些地域的多个可用区进行部署,用户可指定主备可用区创建负载均衡实例,该实例将默认工作在主可用区。 备可用区 Slave Availability Zone 负载均衡会在某些地域的多个可用区进行部署,用户可指定主备可用区创建负载均衡实例,当主可用区发生故障时,该实例可切换到备可用区工作。

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

Android官方开发文档Training系列课程中文版:如何避免ANR?

原文地址:http://android.xsoftlab.net/training/articles/perf-anr.html#anr 尽管你写代码可能通过了世界上所有的性能测试,但是它还是可能会让人感觉到卡顿。当应用卡的不成样子时,系统会给你弹一个”Application Not Responding”的对话框。 在Android中,系统会对那些长时间没有响应的应用采取一些措施:弹出一个对话框告诉用户APP已经停止了响应,如下图所示: 正出于这个原因,系统会在APP长时间没有响应的时候为用户提供一个退出APP的选项。所以使APP能够及时响应这一点是至关重要的,这样系统才不会向用户显示ANR对话框。 这节课我们会学习Android系统如何检测应用程序是否是未响应,以及应用程序如何保持响应能力的一些改进措施。 什么触发了ANR? 通常情况下,系统会在应用程序不再能够响应用户的输入时显示ANR对话框。比如,如果应用阻塞在了UI线程的IO操作上,那么系统就不能够处理用户的输入事件。或者应用花费了大量的时间在内存模型的构建上或者是在UI线程中计算了游戏的下一步动作。要记住: 即便是最高效的代码也需要花费时间来运行。 任何情况下都不要在UI线程中执行耗时操作,而是要将这些工作放在一个单独的线程中执行。这可以使UI线程保持流畅工作(UI线程负责驱动用户界面的事件循环)。 在Android中,应用程序的响应态由Activity Manager及Window Manager负责监控。系统会在侦测到以下状况时显示ANR对话框: 对输入事件在5秒内没有作出响应。 BroadcastReceiver在10秒内没有执行完毕。 如何避免ANR? Android应用程序默认运行在UI线程中。这意味着在UI线程中的任何耗时操作都会引发ANR问题,因为这会使应用程序给不到输入事件或者意图广播处理的机会。 因此,在UI线程中的每个方法都应当做尽可能少的工作,尤其是Activity的生命周期回调函数。像网络或数据库操作,或者大量的计算之类的耗时操作应当在工作线程中执行。 创建用于执行耗时操作的线程最便捷的方式莫过于使用AsyncTask了。只需要继承AsyncTask,然后重写doInBackground()就可以执行了。如果要向用户展示工作进度,你可以使用publishProgress()方法,它会回调onProgressUpdate()方法(该方法运行于UI线程)。 在onProgressUpdate()内我们可以更新进度条。 private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> { // Do the long-running work in here protected Long doInBackground(URL... urls) { int count = urls.length; long totalSize = 0; for (int i = 0; i < count; i++) { totalSize += Downloader.downloadFile(urls[i]); publishProgress((int) ((i / (float) count) * 100)); // Escape early if cancel() is called if (isCancelled()) break; } return totalSize; } // This is called each time you call publishProgress() protected void onProgressUpdate(Integer... progress) { setProgressPercent(progress[0]); } // This is called when doInBackground() is finished protected void onPostExecute(Long result) { showNotification("Downloaded " + result + " bytes"); } } 使用execute()方法启动工作线程: new DownloadFilesTask().execute(url1, url2, url3); 如果不采用这种方式,我们还有另一种实现方法:创建自己的Thread或HandlerThread。如果采用这种方法,那么应该设置该线程的优先级为”background”:通过Process.setThreadPriority()方法及参数THREAD_PRIORITY_BACKGROUND设置。 如果没有设置该优先级,那么该线程会使应用感到变慢,因为该线程的优先级默认与UI线程的优先级一致,它们会互相抢占CPU资源。 如果实现了自己的Thread或HandlerThread,那么要确保在等待其它工作线程完成之前UI线程不被阻塞—不要调用Thread.wait()或Thread.sleep()。如果需要等待其它线程的执行结果,可以为UI线程创建一个Handler。这样做可以使UI线程还可以对 输入事件保持响应能力。这样就可以避免5秒内无响应的ANR对话框出现。 BroadcastReceiver在执行时间上有特殊的限制,这意味着在其内部的工作一定是轻量级的:比如在后台做一些保存设置或者发送通知的工作。所以与UI线程中执行的方法一样,广播接收器内也应当杜绝耗时操作的出现。 TIP: 你可以使用StrictMode来发现UI线程中意外出现的耗时操作。 ANR相关优化 一般来说,100~200毫秒是用户所能感知到应用卡顿的极限。下面列出了一些可以避免应用程序ANR的一些点,同样也有助于防止出现卡顿的情况: 如果应用需要对用户输入做大量的后台工作,可以显示一个进度表示工作正在进行。 对于游戏类的复杂计算,应该将这些工作放在工作线程中执行。 如果应用在初始化阶段需要花费一些时间,可以考虑显示一个闪屏页面或者尽可能快的显示主界面:展示加载正在进行,并进行异步数据填充。在这些情况下都应当表明任务正在进行,以免让用户认为应用已经卡死。 使用Systrace或Traceview等性能工具检查APP的响应瓶颈。

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

Android官方开发文档Training系列课程中文版:性能优化建议

原文地址:http://android.xsoftlab.net/training/articles/perf-tips.html 本篇文章主要介绍那些可以提升整体性能的微小优化点。它与那些能突然改观性能效果的优化手段并不属于同一类。选择正确的算法与数据结构必然是我们的第一总则,但是这不是我们这篇文章要介绍的。你应该将这篇文章所提及的知识点作为编码的日常习惯,这可以提升常规代码的执行效率。 下面是书写代码的基本准则: 绝不要做你不需要的工作。 如果可以不申请内存就不要申请,要合理复用已有的对象。 另一个较复杂的问题就是被优化过的APP肯定是要运行在各种类型的硬件平台上。不同版本的虚拟机运行在不同的处理器上肯定会有不同的运行速度。需要特别说明的是,在模拟器上测试很少会得知其它设备的性能。在不同设备上还有一个很大的不同点就是有没有JIT(JIT的意思是即时编译器):在JIT设备上运行的最优代码并不总在没有JIT设备上有效。 为了确保APP可以在各类设备上运行良好,要确保代码在各个版本的平台上都是高效的。 避免创建不必要的对象 创建对象绝不是没有成本的。虽然分代垃圾收集器可以使临时对象的分配成本变得很低,但是内存分配的成本总是远高于非内存分配的成本。 随着更多对象的生成,你可能就开始关注垃圾收集器了。虽然Android 2.3中出现的并发收集器可能会帮到你,但是不必要的工作总是应该避免的。 因此,要避免创建不需要的对象。下面的示例可能会帮到你: 如果你有个返回字符串的方法,该方法所返回的字符串总是被接在一个StringBuffer对象后面。那么就可以更改此方法的实现方式:让该字符串直接跟在StringBuffer的后面返回。这样就可以避免创建那些临时性的变量。 当从字符串中提取子串时,应该尝试返回原始数据的子串,而不是创建一个副本。子串将会创建一个新的String对象,但是它与char[]共用的是同一数据。采用这种方式的唯一不足就是:虽然使用了其中的一部分数据,但是剩余的数据还都保留在内存中。 一条更为先进的法则就是,将多维数组转换为平行数组使用: int数组的效率要比Integer数组的效率高的多。 如果你需要实现一个用于存储(Foo,Bar)对象的数组,要记得使用两个平行的Foo[],Bar[]数组,这要比单一的(Foo,Bar)数组效率好太多。 通常来说,要尽量避免创建那些生命周期很短的临时变量。更少的对象创建意味着更低频率的垃圾回收,这会直接反应到用户体验上。 首选静态 如果不需要访问对象的属性,那么就可以将方法设置为静态方法。这样调用将会增加15%-20%的速度。这还是一个好的习惯,因为这样可以告诉其它方法一个信号:它们更改不了对象的状态。 使用常量 请先考虑以下声明: static int intVal = 42; static String strVal = "Hello, world!"; 编译器会产生出一个类的实例化方法,名为< clinit>,它会在类首次被用到的时候执行。该方法会将值42存到intVal中,并将字符串常量表中的引用赋给strVal。当这些值被引用之后,其它属性才可以访问它们。 我们可以使用”final”关键字来改进一下: static final int intVal = 42; static final String strVal = "Hello, world!"; 这样的话,类就不需要再调用< clinit>方法,因为常量的初始化工作被移入了dex文件中。代码可以直接引用intVal为42的值,并且访问strVal也会直接得到字符串”string constant” ,这样可以省去了查找字符串的过程。 Note: 这样优化手段仅仅适用于基本数据类型以及字符串常量,不要作用其它类型。 避免内部的get\set方法 像C++这种本地语言通常都会使用get方法来访问属性。这对C++来说是一个非常好的习惯,并且C#、Java等面向对象语言也广泛使用这种方式,因为编译器通常会进行内联访问,并且如果你需要限制访问或者调试属性的话,只需要添加代码就可以。 不过,这在Android上并不是个好习惯。方法调用的开销是非常大的。虽然为了遵循面向对象语言提供get、set方法是合理的,但是在Android中最好是可以直接访问对象的字段。 在没有JIT的设备中,直接访问对象字段的速度要比通过get方法访问的速度快3倍。在含有JIT的设备中,这个效率会达到7倍之多。 注意:如果你使用了ProGuard,那么就有了一个两全其美的结果,因为ProGuard会直接为你进行内联访问。 使用增强for循环 增强for循环可用于实现了Iterable接口的集合或数组。在集合内部,迭代器需要实现接口方法:hasNext()以及next()。 有以下几种访问数组的方式: static class Foo { int mSplat; } Foo[] mArray = ... public void zero() { int sum = 0; for (int i = 0; i < mArray.length; ++i) { sum += mArray[i].mSplat; } } public void one() { int sum = 0; Foo[] localArray = mArray; int len = localArray.length; for (int i = 0; i < len; ++i) { sum += localArray[i].mSplat; } } public void two() { int sum = 0; for (Foo a : mArray) { sum += a.mSplat; } } zero()方法是最慢的,因为JIT不能够对每次访问数组长度的开销进行优化。 one()方法是稍快点的。它将一切元素放入了本地变量,这样避免了每一次的查询。只有数组的长度提供了明显的性能提升。 two()方法是最快的。它使用了增强for循环。 所以应当在默认情况下使用增强for循环。 Tip: 也可以查看Josh Bloch 的 Effective Java,第46条。 考虑使用包内访问 请先思考以下类定义: public class Foo { private class Inner { void stuff() { Foo.this.doStuff(Foo.this.mValue); } } private int mValue; public void run() { Inner in = new Inner(); mValue = 27; in.stuff(); } private void doStuff(int value) { System.out.println("Value is " + value); } } 上面的代码定义了一个内部类,它可以直接访问外部类的私有成员以及私有方法。这是正确的,这段代码将会打印出我们所期望的”Value is 27”。 这里的问题是:VM会认为Foo$Inner直接访问Foo对象的私有成员是非法的,因为Foo和Foo$Inner是两个不同的类,虽然Java语言允许内部类可以直接访问外部类的私有成员(PS:虚拟机与语言是两种互不干扰的存在)。为了弥补这种差异,编译器专门为此生成了一组方法: /*package*/ static int Foo.access$100(Foo foo) { return foo.mValue; } /*package*/ static void Foo.access$200(Foo foo, int value) { foo.doStuff(value); } 当内部类代码需要访问属性mValue或者调用doStuff()方法时会调用上面这些静态方法。上面的代码归结为你所访问的成员属性都是通过访问器方法访问的。早期我们说通过访问器访问要比直接访问慢很多,所以这是一段特定语言形成的隐性性能开销示例。 避免使用浮点型 一般来说,在Android设备上浮点型要比整型慢大概2倍的速度。 在速度方面,float与double并没有什么区别。在空间方面,double是float的两倍大。所以在桌面级设备上,假设空间不是问题,那么我们应当首选double,而不是float。 还有,在对待整型方面,某些处理器擅长乘法,不擅长除法。在这种情况下,整型的除法与取模运算都是在软件中进行的,如果你正在设计一个哈希表或者做其它大量的数学运算的话,这些东西应该考虑到。 使用本地方法要当心 使用本地代码开发的APP并不一定比Java语言编写的APP高效多少。首先,它会花费在Java-本地代码的转换过程中,并且JIT也不能优化到这些边界。如果你正在申请本地资源,那么对于这些资源的收集能明显的感觉到困难。除此之外,你还需要对每一种CPU架构进行单独编译。你可能甚至还需要为同一个CPU架构编译多个不同的版本:为G1的ARM处理器编译的代码不能运行在Nexus One的ARM处理上,为Nexus One的ARM处理器编译的代码也同样不能运行在G1的ARM处理器上。 本地代码在这种情况下适宜采用:当你有一个已经存在的本地代码库,你希望将它移植到Android上时,不要为了改善Java语言所编写的代码速度而去使用本地代码。 如果你需要使用本地代码,那么应该读一读JNI Tips. Tip: 相关信息也可以查看Josh Bloch 的 Effective Java,第54条。 性能误区 在没有JIT的设备中,通过具体类型的变量调用方法要比抽象接口的调用要高效,这是事实。举个例子,通过HashMap map调用方法要比Map map调用方法要高效的多,开销也少,虽然这两个实现都是HashMap。事实上速度并不会慢2倍这么多;真实的不同大概有6%的减缓。进一步讲,JIT会使两者的差别进一步缩小。 在没有JIT的设备上,通过缓存访问属性要比反复访问属性要快将近20%的速度。在JIT的设备中,属性访问的花销与本地访问的花销基本一致,所以这不是一项有多少价值的优化手段,除非你觉得这样做的话代码更易读(这对static,final,常量同样适用)。 经常估测 在开始优化之前,要确保你有个问题需要解决:要确保你可以精准测量现有的性能,否则将不能观察到优化所带来的提升。 基准点由Caliper的微型基准点框架创建。基准点很难正确获得,所以Caliper将这份很难处理的工作做了,甚至是在你没有在测量那些你想测量的地方的时候它也在工作。我们强烈的推荐你使用Caliper来创建自己的微型基准点。 你可能还发现Traceview非常有助于提升性能,不过你应该意识到Traceview工作的时候JIT并没有开启。这会错误的认为JIT会将损失掉的时间弥补回来。这尤其重要:根据Traceview所更改的结果会使实际代码运行的更快。 有关更多提升APP性能的工具及方法,请参见以下文档: Profiling with Traceview and dmtracedump Analyzing UI Performance with Systrace

资源下载

更多资源
优质分享App

优质分享App

近一个月的开发和优化,本站点的第一个app全新上线。该app采用极致压缩,本体才4.36MB。系统里面做了大量数据访问、缓存优化。方便用户在手机上查看文章。后续会推出HarmonyOS的适配版本。

Mario

Mario

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

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册