Month: March 2012

从“构建、发布java程序”的角度看待OO Principles

这里的OO Principles是指Robert C. Martin提出的那一系列原则,如SRP,OCP等; 本文旨在从构建、发布java程序的角度理解这些原则,更具体一点,就是 要找出违背这些原则会对java程序的构建、发布等过程造成什么困扰。 首先可以先罗列一下构建、发布过程中可能出现的坏现象: 1. 编译、打包时间过长 2. 打出的包过大,导致网络传输久、应用启动慢、虚拟机方法区空间被浪费 3. 打出的包里有相同的库,如spring 2.5和spring2.0同时出现 4. 频繁发布应用,浪费时间,影响可用性 5. 做太多的回归测试 6. 发布前夕发现错误,不得不回滚 待续。。。 接下来进入正题, 逐个看下违反OO Principle的后果 (我们会用 caller代表模块的调用者, callee代表被调用的模块) 1. 违反SRP 场景: callee有两个互不相关的职责r1, r2; caller1依赖r1, caller2依赖r2. 后果:    a. caller因为callee中的无关代码而浪费构建自己的时间和空间。caller1与callee共同编译时,也需要编译r2相关的代码;但r2部分的代码caller1并不需要,这就意味着编译时间和打包空间的浪费  — 当然,这个浪费可能很小    b. caller因为callee中的无关第三方库,而浪费构建自己的时间和空间。 如果r2依赖了一些第三方库,而这些库又依赖了另一些第三库,打包caller1时就要把这些只能r2相关的第三方库统统纳入进来,造成打包时间过长、打出的包过大    c. 第三方库太多增加了callee包中库冲突的几率。如果r1依赖了spring 2.5, r2依赖了spring 2.0,callee在打包前就必须进行依赖调解,即两个spring只能留一个;你要么手动确定留哪个,要么通过Maven之类的依赖管理工具来处理;但不管怎么搞,都会比较繁琐,并且带来风险(maven环境中,一个极端情况就是,r1使用了官方的spring坐标,而r2使用了一个山寨的spring坐标)    d. callee的部分升级导致无关caller的回归测试。为了满足caller2的新功能,r2被升级了,这也意味着整个callee的升级;如果callee没有版本机制,则callee的更新会导致caller1不得不接受新的callee,并不得不做一下回归测试    e. callee的部分升级导致无关caller在callee发布时不可用。如果callee是一个web …

从“构建、发布java程序”的角度看待OO Principles Read More »

《构建高性能Web站点》笔记 – 7 集群与负载均衡

集群与负载均衡 负载分配的策略:    1. 按业务需要分配。比如“镜像下载”这种应用可以按用户所在地分配一个就近的实际服务器    2. Round Robin依次分配。实现这个策略需要记录上一次分发的去向。在高并发条件下,记录这个东西需要使用锁,因此对吞吐率有影响    3. 随机分配。做不到精确地平均分配,但一般情况下还是可以比较平均的 分发请求的手段:    1.前端服务器通过 http跳转将请求转发到实际服务器。缺点是用户可能会绕过前端服务器直接访问实际服务器,这样的话负载就不能均衡    2. DNS里一个域名配多个IP        a. DNS服务器一般采取Round Robin策略,但一般也支持其他智能策略;不管怎么样,分配策略的灵活度都比较有限,尤其是当你使用第三方的DNS服务时        b. DNS服务器不会成为性能瓶颈,这是它的最大优点        c. 由于DNS缓存问题,处理故障转移(某IP对应的服务机当机了)不是那么实时        d. 总的来说,DNS负载均衡简单可行,但比较粗放    3. 反向代理(第7层负载均衡)        a. 方便实现自己的调度策略,比如可以让好的机器多分担一些任务. Nginx就允许你设置“权重”        b. 反向代理本身要有比较强的性能,否则就会沦为瓶颈。当反向代理的能力到达极限时,后端再添加多少服务器都无济于事        c. 可以用作负载均衡器的反向代理:Nginx, HAProxy        d. 总的来说,反向代理做负载均衡比较灵活、好用,但额外开销比较大,容易成为瓶颈    4. DNAT: (传输层负载均衡)修改TCP数据包的目标IP和端口        a. …

《构建高性能Web站点》笔记 – 7 集群与负载均衡 Read More »

《构建高性能Web站点》笔记 – 6 写缓存

读缓存都好明白,这里就不说了 写缓存,实际上是写“缓冲”,即 数据进入到后端(如数据库)之前,先累积在一个缓冲区内,等满足了一定阈值再一次性写入。 这样对后端写只需要执行一次写操作,节省不少性能。 可以用缓存框架如memcached实现这个缓冲

apache httpd的优点

  1. 每个连接独占一个进程,进程之间比较独立; 一个进程的崩溃不会影响其他进程。   2. apache提供了大量的模块   3. 如果并发数在150以内,apache够用了 (郭欣)

《构建高性能Web站点》笔记:5 web组件分离

让你的网站的不同组件使用不同的域名 并且/或者 使用不同的服务器,如 www.glasswall.org          #信息、宣传相关的应用, 服务器名home bbs.glasswall.org          #论坛应用, 服务器名bbs image.static-glasswall.org    #图片,服务器名static js.static-glasswall.org       #javascript,服务器名static html.static-glasswall.org     #静态html,服务器名static 假设首页 /index既包含动态内容,又包含图片和js,使用上述方案有什么好处? 1. 不同域名,可以提高浏览器下载的并发数。 一个浏览器,对同一个域名只能同时下载5、6个组件;现在域名分开了,浏览器可以同时下载5、6个图片和5、6个js, 并发能力迅速翻倍 2. 不需要cookie的组件采用独立域名,避免不必要的cookie发送。你可以让动态内容发送的cookie只使用glasswall.org域,浏览器在请求*.static-glasswall.org时就不会发送cookie;这样可以减少http header的大小 3. 使用不同的硬软件服务器,以适应不同应用的特征;经过恰当的组合,可以获得最理想的总体请求时间或总体成本控制。 比如bbs服务器需要比较好的cpu/内存,而static服务器则需要比较好的带宽和磁盘,以及配置了非阻塞I/O的apache httpd和反向代理缓存。一台cpu强的机器 + 一台磁盘好的机器, 总价格小于两台 cpu/磁盘都强的机器 不同类型的内容,使用不同的优化方案 1. 图片   a.一个页面图片多而小,则可以使用长连接,避免频繁打开建立连接   b.图片内容一般不怎么变,所以Expires可以设得很大,以充分利用浏览器缓存 2. css/js: 变化频率比较小,所以Expires可以设得很大; 当真的发生变化时,可以给css的url加上新的版本号或时间戳,使浏览器原来缓存的内容失效 3. 大文件下载   a.服务器要接入高速宽带   b.磁盘有较好的并行能力   c.web服务器可以打开linux sendfile选项

《构建高性能Web站点》笔记:4.3 反向代理的缓存

用反向代理提供缓存:用户执行一次请求后,反向代理将请转发到后端服务器,转发应答时,反向代理将其内容缓存;下次再来同样的请求时,反向代理直接以自己的缓存应答   反向代理中如果不引入缓存,对性能可能会产生伤害;因为它引入了一次请求转发 提供缓存的反向代理:   1. Apache里可以mod_cache + mod_proxy联用实现代理,Nginx也有类似的模块。它们好用,但还不够强大   2. Squid是最著名的反向代理,它很强大,但过于重量级,使用比较复杂   3. Varnish则比较专注于反向代理,而且比较好用 Varnish   1.通过修改http头来决定是否缓存   2.它的配置文件是用一套长得很像c++/java的DSL写的,所以配置非常灵活   3.varnish的8011端口可以接受命令以清除缓存,你可以通过vinishadm工具直接向这个端口发送命令,也可以从它处向这个端口发送一个http请求   4.varnishstat提供了监控界面,给出诸如cache hit/cache miss之类的数据; varnish还有一个web监控界面 有了反向代理缓存,还有必要搞动态内容缓存(后端服务器自己的缓存)吗? 如果你的应用会有下列情形,则搞搞也无妨。   1. 有的请求不会通过反向代理,直接到达后端;这时后端的缓存就能发挥作用   2. 首次访问一个页面是没有缓存的,这时反向代理缓存就会miss。如果后端服务器预先实现了静态化(严格地说,这不算缓存),就可以解决这个问题    3. 如果一个后端服务器前面有N个反向代理,可能会出现缓存不均匀的情况;如果有的请求落在了缓存不丰满的反向代理服务器上,性能表现就会不佳;如果后端服务器有缓存,就可以为不丰满的反向代理服务器“补位”

缓存 V.S. 缓冲

缓存(cache)是指把远端的数据在本地复制一份,下次获取数据时在本地获取就可以了,以节省开销 缓冲(buffer)则是用于解决高速设备与低速设备的桥接问题。 高速设备如果直接把数据丢给低速设备(或从低速设备那里读),则数据的流速就受限于低速设备,高速设备也沦为了低速设备; buffer的作用就是让高速设备先按自己的速度把数据输出到缓冲区中,低速设备再来读取,这时高速设备可以干别的事,最大化地利用自己的吞吐量。 当然, 这里要有个时间差。

《构建高性能Web站点》笔记:4.2 动态内容静态化

把本应被动态的内容在被请求之前就存成静态文件,用户访问时不经web controller判断,而是让服务器直接返回静态文件;比如新闻网站的新闻,就可以直接存成html。 静态化对性能的帮助非常大。 静态化不属于缓存范畴,因为这里并没有缓存命中、过期等问题。    1. 不过, 静态文件仍有过期的问题,如新闻被修改了怎么办? 策略有两种,一是定时刷新,二是新闻在后端被修改时更新前端对应的静态文件    2. 局部化问题。 一个页面有一部分经常修改,有一部分基本不变,只有后一部分可以静态化。这种情况下应该把后一部分做成SSI文件,再包含到整体页面中; 不过,扫描SSI的include标签是比较耗CPU的;使用SSI机制时,应该告诉web服务器不要去不含SSI的文件中扫描include    3. 这样做可以大幅提升qps, 不过,你的服务器带宽要足够大才能最大地发挥它的优势