当前位置: 首页 > 科技观察

微服务的接入层设计与动静态资源隔离

时间:2023-03-18 17:48:08 科技观察

零题记本系列是为微服务的高并发而设计的,那么我们先从最外层的接入层开始,看看有哪些策略可以保证高并发。接入层的架构画了一个简化图,包括以下几个部分。接下来我们依次分析各个部分以及可以做的优化。1、数据中心外:DNS、HttpDNS、GSLB当我们要访问一个网站的服务时,首先要访问一个域名,然后DNS将域名解析成IP地址。我们先以通过DNS访问数据中心对象存储上的静态资源为例,看一下整个过程。我们建议将文件、图片、视频、音频等静态资源放在对象存储中,直接通过CDN分发,而不是放在服务器上,与动态资源绑定。假设全国有多个数据中心,由多个运营商托管,每个数据中心有3个可用区。对象存储跨可用区域部署以实现高可用性。在每个数据中心,至少部署两个。内部负载均衡器,内部负载均衡器连接到多个对象存储的前端服务代理服务器。1、当客户端要访问object.yourcompany.com时,需要将域名转换为IP地址进行访问,因此需要请求本地解析器的帮助。2、本地解析器检查本地缓存是否有这条记录?如果可用,请直接使用它。3.如果没有本地缓存??,则需要请求本地NameServer。4、本地NameServer一般部署在客户的数据中心或客户所在运营商的网络中。本地名称服务器检查是否有本地缓存??,如果有则返回。5、如果没有本地NameServer,本地NameServer需要从RootNameServer查询,RootNameServer会将.comNameServer的地址返回给本地NameServer。6、然后本地NameServer访问.com的NameServer,他将你公司的yourcompany.com的NameServer交给本地NameServer。7.本地名称服务器然后访问yourcompany.com的名称服务器。据说这一步应该返回要访问的真实IP地址。对于不需要全局负载均衡的简单应用,yourcompany.com的NameServer可以直接将域名object.yourcompany.com解析为一个或多个IP地址,然后客户端进行简单的轮询即可实现简单的负载均衡.但对于复杂的应用,尤其是跨地域、跨运营商的大规模应用,需要更复杂的全局负载均衡机制,因此需要专门的设备或服务器来完成。这是GSLB,一个全局负载均衡器。从yourcompany.com的NameServer上,一般通过配置CNAME,给object.yourcompany.com起一个别名,比如object.vip.yourcomany.com,然后告诉本地NameServer去请求GSLB来解析这个域名,GSLB可以在解析域名的过程中通过自身的策略实现负载均衡。图中画了两层的GSLB,因为它分为运营商和区域。我们希望属于不同运营商的客户可以访问同一运营商机房的资源,这样就不需要跨运营商访问,有利于提高吞吐量。减少延迟。8.一级GSLB通过查询请求本地NameServer的运营商,知道用户的运营商,假设是移动的,然后通过CNAME,通过另一个别名object.yd.yourcompany.com,告诉本地请求二级GSLB的名称服务器。9、第二层的GSLB通过查询请求本地NameServer的地址知道用户的地理位置,然后返回离用户比较近的Region内部负载均衡SLB的共6个地址.到本地名称服务器。10.本地名称服务器将结果返回给解析器。11、解析器缓存结果返回给客户端。12、客户端开始访问Region1的对象存储,属于同一个运营商,距离比较近。当然,客户端已经获得了六个IP地址。他可以通过负载均衡随机或轮询选择可用区访问。对象存储一般有三备,这样可以实现对存储读写的负载均衡。从上面的过程可以看出,基于DNS域名的GSLB实现了全局的负载均衡,但是现在跨运营商、跨地域的流量调度,但是由于不同运营商的DNS缓存策略不同,GSLB并不会有效发挥作用。部分用户的DNS会将域名解析请求转发给其他运营商的DNS进行解析,导致用户运营商在到达GSLB时判断错误。部分运营商的DNS出口会进行NAT,导致GSLB误判用户的运营商。所以区别于传统的DNS,还有一种机制叫做httpDNS,可以把SDK嵌入到用户的手机APP中,通过http访问一个httpDNS服务器。由于手机APP可以准确获取自身的IP地址,因此可以将IP地址传递给httpDNS服务器,而httpDNS服务器完全由应用服务商提供,可以实现完全独立的全网流量调度。2、数据中心外:对于静态资源,其实在真正访问机房的对象存储之前,可以在离用户最近的地方使用CDN进行缓存,这也是高并发的一个整体方面应用程序。想法,能贴近客户,尽可能贴近客户。CDN制造商的覆盖范围通常更广。每个运营商、每个地域都有自己的POP点,所以总有同一运营商、位置相近、距离用户较近的CDN节点就近获取静态数据,避免跨运营商业务、跨地域访问。使用CDN后,用户在访问资源时,与上述过程类似,不同的是在进行DNS解析时,会将域名的解析权交给CDN厂商的DNS服务器,而CDN厂商的DNS服务器可以通过CDN厂商的GSLB找到离客户最近的POP点,返回数据给用户。当在CDN中找不到缓存的数据时,需要从真实服务器中获取。这叫做回源,只有极少量的流量需要回源,大大减轻了服务器的压力。3、数据中心边界和核心:如果边界路由、核心交换、等价路由确实需要回源,或者访问的根本不是静态资源,而是动态资源,就需要进入数据中心。刚才***段提到,GSLB最后返回了6个IP地址,都是内部负载均衡SLB的IP地址,说明这6个IP地址都是公网可以访问的,那么公网怎么访问呢?网络知道这些IP地址怎么样?这取决于机房的结构。一个机房一般有一个边界路由器和一个核心交换机,每个AZ有一个汇聚交换机,6个SLB在AZ内,所以它们的IP地址通过iBGP协议通知给边界路由器。当用户从这六个IP中选择一个IP地址访问时,就可以通过公网路由找到机房的边界路由器。边界路由器知道当时这条路由是在哪个AZ给他的,所以它通过核心交换层把请求转发给某个AZ,这个AZ的汇聚交换机再把请求转发给SLB。如果一个AZ出现问题,是否可以将某个公网IP的访问权限给到另一个AZ?当然有可能。核心路由和核心交换之间可以做ECMP等效路由。当然,外部地址NAT也可以称为边界路由上的内部VIP地址,通过等价路由实现跨AZ的流量分担。4、数据中心可用区:负载均衡SLB、LVS、HAProxy进入一个可用区AZ后,最先到达的是负载均衡SLB。可以购买商用的SLB,也可以自己搭建,比如通过LVS实现基本的负载均衡功能。LVS的性能比较好,通过内核模块ipvs完成了很多工作。LVS可以使用keepalived实现双机热备,也可以使用OSPF通过等价路由在多个LVS之间分流。常作为统一的负载均衡入口承载大流量。有时需要更复杂的4层、7层负载均衡,会在LVS后面加一个HAProxy集群,即将LVS导入的流量分发到大量的HAProxy中。这些HAProxy可以根据不同的应用程序或租户进行隔离。每个租户都有一个单独的HAProxy,但所有租户共享LVS集群。如果有云环境,HAProxy可以部署在虚拟机中,可以根据流量情况和租户请求动态创建和删除。5.数据中心可用区:接入层Nginx,负载均衡后的接入层缓存,是接入网关,或者API网关,往往需要实现很多灵活的转发策略,这里会选择使用Nginx+Lua或者OpenResty这一层。由于Nginx本身也有负载均衡机制,有时会将HAProxy层和Nginx层合并,直接在LVS后面接Nginx集群。接入层功能一:API聚合使用微服务后,后端服务会被拆分成非常小的块。因此,前端应用如果想要获取整个页面的展示,往往需要从多个服务中获取数据,并将数据进行一定的聚合后才能展示。如果它是一个网页,它实际上很好。如果你在Chrome的debug模式下打开一个复杂的电商主页,你会发现这个页面会同时发送很多http请求,最后聚合成一个页面。如果是APP的话,其实没有问题,但是在客户端会有很多工作要做,会非常耗电,用户体验很差,所以聚合请求最好的地方是API网关的职责之一。这样一来,对于前端APP来说,后端连接就好像是一个统一的入口,后端服务的拆分与聚合、灰度发布、缓存策略等都被阻断了。接入层的第二个作用:服务发现和动态负载均衡既然统一入口变成了接入层,接入层就有责任自动发现服务集群,进行后端拆分、聚合、扩容、缩容。当服务发生变化时,可以实现健康检查和动态负载均衡。对于微服务,服务之间也需要服务发现。常见的框架有Dubbo和SpringCloud,服务注册中心可以有ZooKeeper、Consul、etcd、Eureka等,这里以Consul为例。由于服务之间的调用已经注册到Consul上,Nginx也可以通过Consul获取后端服务的状态,实现动态负载均衡。Nginx可以集成consul-template,监听Consul事件。当注册的服务列表或key/value发生变化时,consul-template会修改配置文件并执行一个shell,比如nginxreload。consul-template\-template"/tmp/nginx.hcl:/var/nginx/nginx.conf:servicenginxreload"\consul-template模式配置比较复杂,需要reloadnginx。另外一种集成Consul的方式是nginx-upsync-module,它可以同步Consul的服务列表或者key/value存储。它需要重新编译nginx而不是重新加载nginx。upstreamtest{server127.0.0.1:11111;#所有后端服务列表都会从consul中拉取,并删除占位符serverupsync127.0.0.1:8500/v1/catelog/service/testupsync_timeout=6mupsync_interval=500msupsync_type=consulstrong_dependency=off;#备份地址,保证nginx不强依赖consulupsync_dump_path/usr/local/nginx/conf/servers/servers_test.conf;}另一种方式是OpenResty+Lua,相比nginx-upsync-module,可以增加更多自己的逻辑,init_*_by_lua阶段通过httpapi获取服务列表并加载到Nginx内存中,并设置定时器轮训更新列表,balancer_by_lua阶段读取内存列表并设置后端服务器。Lua实现也不需要重新加载nginx,这比nginx-upsync-module更具可扩展性。接入层的第三个功能:动静态资源隔离,静态页面缓存,页面静态化。为什么静态资源需要隔离?静态资源往往变化较少,但往往比较大。如果每次都加载它们,会影响性能并浪费带宽。事实上,静态资源可以预加载、缓存,甚至可以推送到CDN。因此,在访问层Nginx应该配置动态资源和静态资源分离,将静态资源的url导入到Nginx的本地缓存或者Varnish或Squid等单独的缓存层,将动态资源访问到后端应用程序或动态资源。缓存。在Nginx中,可以通过配置expires、cache-control、if-modified-since来控制浏览器端的缓存控制。使得浏览器不会在一段时间内反复向服务器请求静态资源。这一层称为浏览器端缓存。当一些请求确实到达了接入层的Nginx时,不需要一直去应用层获取页面,接入层的Nginx可以先拦截一些热点请求。这里可以有两层缓存。一个是Nginx本身的缓存proxy_cache,一个是缓存层的varnish或者squid。在使用接入层缓存时需要注意的是,缓存key的选择不要包含用户相关的信息,比如用户名、地理信息、cookie、deviceid等,相当于为每一个单独的缓存user,使得缓存攻击率相对较低。静态资源和动态资源分离之后,就有一个组合的问题。可以通过Ajax访问动态资源,在浏览器端组合,或者在访问层组合。如果在接入层做聚合,或者varnish做聚合,接入层缓存可以定时轮询后端应用,当有数据修改时,动态页面会静态化,这样用户访问的数据就会被发送到接入层被拦截的缺点是更新速度有点慢。对于大促场景下高并发访问的页面,可以进行这样的处理。接入层的作用有四个:动态资源缓存静态和动态分离后,静态页面可以很好的缓存,而动态数据仍然会请求到后端,而动态页面的静态延迟比较高,以及当页面数量较多时,静态工作量比较大,因此接入层也可以通过Redis或者Memcached来缓存动态资源。接入层作用五:资源隔离接入层没有一个Nginx集群,不同的请求可以有独立的Nginx集群。比如抢券或者秒杀系统会成为热点中的热点,所以应该有独立的Nginx集群。接入层功能6:统一认证、鉴权、过滤API网关的另一个功能是统一认证、鉴权。一种是基于会话的。客户端输入用户名和密码后,API网关会向后端服务提交鉴权和鉴权。成功后会生成session。session会放在Redis中,之后所有的访问都会带着session进行。另一种方式是通过统一的认证中心分发令牌。这是一个三角形结构。API网关收到登录请求后,会去认证中心请求认证授权。如果成功,则返回token,这是一个包含大量认证信息的加密字符串。下面在访问过程中,API网关可以验证token是否有效进行认证,真正的服务可以根据token进行认证。接入层功能7:限流在大促过程中,经常会遇到实际流量远大于系统测试可加载流量的情况。如果这些流量都进来,整个系统肯定会崩溃,没人知道不玩了。所以要做到这一点,很长的路要走就是限制电流。限流从上到下贯穿于整个应用。当然,接入层作为最外层的屏障,需要做好整个系统的限流工作。对于Nginx,限流的方式有很多种。可以限制连接数limit_conn,限制访问频率limit_req,开启过载保护sysgurad模块。限制请求的目标URL的流量(例如:每分钟允许调用某个URL的次数)。限制客户端访问IP的流量(例如:一个IP每分钟允许多少请求)。对于流量受限的用户,可以做相对友好的回报,不同页面的策略可以不同。对于首页和活动页面,读取较多,可以返回缓存中的旧页面,也可以定时刷新APP。加入购物车、下单、支付等写作请求受限的,可返回等待页面,或返回圈子。如果一段时间后仍无法转移,可以返回到拥挤的人群中。对于支付结果返回,如果流量受限,需要立即返回错误页面。接入层第八个作用:灰度发布和AB测试在接入层,由于可以配置访问路由和访问权重,可以实现灰度发布或AB测试,两套系统同时上线时间,并通过削减部分流量,测试新系统的稳定性或者是否更受欢迎。作者:刘超,毕业于上海交通大学,拥有15年云计算研发和架构经验,曾在EMC、央视证券资讯频道、惠普、华为、网易从事云计算和大数据架构工作。在工作中积累了大量运营商系统、互联网金融系统、电商系统的容器化和微服务经验。