前端包括客户端(Web浏览器、移动端)、客户端和数据中心之间的网络,以及数据中心响应用户请求的部分。因为用户的每次交互、每个连接、每个响应都要穿越前端的各个组件,所以前端需要具备很大的吞吐能力、并发处理能力等。
状态管理是Web前端伸缩性最重要的方面。状态管理分为有状态服务和无状态服务。
有状态服务和无状态服务的关键区别是无状态服务的实例是完全可交换的,客户端可以访问任意实例而不用担心结果会有不同。有状态服务需要知道不同请求的一些上下文信息,对于某个请求,并不是每个服务都是可用的。任何一个服务端想要使用一个有状态的服务,都必须黏滞在这个服务器实例上面,以避免产生各种难以预期的后果。
会话是用cookie实现的。通过使用cookie,服务器可以识别出来自同一个会话的请求。
会话需要存储在Web服务器之外,才能被任何一个Web服务器使用到。有三种常用的方法解决这个问题:
以上方法中:采用第一种可以让事情变得简单,麻烦就是会话存储的代价非常高昂,cookie加密后再进行Base64编码数据量会增大三分之一;第二种方式是将会话存储在外部的数据存储服务器中,可以使用Memcached、Redis、DynamoDB或者Cassandra, 主要的要求是基于key的读写操作的低延迟 ,如果使用技术是基于JVM可以使用Teracotta这类对象集群技术实现会话存储;第三种是在负载均衡服务器上获得相应以后往请求中插入一个负载cookie,用来跟踪请求的客户端与相应的服务器,但是这样允许了Web服务器存储本地数据,服务器件存在差异,系统会失去弹性,不推荐使用。
Web应用前端第二种常见的状态类型是文件存储,有两类:
可以考虑使用S3、七牛等第三方供应商服务进行分布式文件存储,不建议自己实现文件存储(特别对于创业公司来说)。如果非要自己做,可以使用MongoDB的GridFS、Netflix的Astyanax等。
这里的其他类型的姿态包括:本地缓存、应用内存状态、资源锁等。
针对不同的应用采用不同的本地缓存策略(比如,博客系统和竞拍系统)。使用本地锁同步共享资源的访问时没有用的,它只能再每台服务器上起作用,不可能在服务器之间同步。所以,不能再Web服务器上使用锁。
资源锁的解决方案:创建一个独立的锁服务,然后用这个锁服务weib所有的Web应用服务器提供锁服务。优点是,比较容易实现伸缩、还能把共享状态从其他系统中分离成一个抽象层;缺点是,会增加延迟(因为需要执行一个远程调用)而且会增加更多组件,管理起来比较麻烦。可以使用到的技术:Zookeeper、Netflix的Curator库、结合Memcached/Redis和MySQL/PostgreSQl实现。
要使具有良好的伸缩性,那么就要保证所有Web服务器都是无状态的,包括所有的Web前端服务器和Web服务服务器。同时,不允许服务器在本地存储数据,不允许在Web服务器上使用资源锁。
前端组件包括Web服务器、负载均衡器、域名系统(DNS)、反向代理、以及CDN等。
DNS就是域名系统,用户在访问网站时第一个需要的就是它。可以使用阿里云、腾讯云、DNSPod等供应商提供的服务。
强烈建议使用负载均衡器作为数据中心的入口点,这样做一则进行伸缩扩容的时候更方便,二则改变底层基础设施架构的时候也不会影响到用户。
在实践中常用的使用负载均衡的方法是,在Web服务器和客户端之间配置一个负载均衡器。Web服务器和客户端之间的所有的流量都会经过负载均衡器。这样做的好处有:
目前的系统主要使用的负载均衡类型有以下3种:
前端服务器不应该包含太多业务逻辑,应该只是一个用来集成Web服务层结果的展示层,不能是系统的核心。
可选择的技术有:PHP、Python、Groovy、Ruby、NodeJs等。任何语言、任何Web服务器并不重要。只要前端服务器是无状态的,就可以简单的通过增加机器实现水平伸缩。
前端常用的缓存有CDN等。好处是,CDN可以处理绝大部分的访问流量,减少服务器的负载压力并提高响应速度;坏处,不是所有的Web应用都能使用CDN有效缓存界面。
可以使用反向代理服务器控制哪些需要被缓存以及缓存多久,也在SPA或者移动端中通过浏览器存储来实现缓存。
本文为读《互联网创业核心技术——构建可伸缩的Web应用》读书笔记。