如何实现分布式

关于最近很多人在询问,如何利用EasySwoole做分布式负载均衡,复杂的就不讲解了,就讲解如何实现最简单的负载均衡。

相关知识

DNS轮训

一个域名针对多个ip A记录的解析,DNS服务器将解析请求按照A记录的顺序,逐一分配到不同的IP上,这样就完成了简单的负载均衡。

DNS轮询的优点:

  • 低成本:只是在DNS服务器上绑定几个A记录,域名注册商一般都免费提供解析服务。
  • 部署简单:就是在网络拓扑进行设备扩增,然后在DNS服务器上添加记录。

DNS轮询的缺点:

  • 可靠性低

    假设一个域名DNS轮询多台服务器,如果其中的一台服务器发生故障,那么所有的访问该服务器的请求将不会有所回应,这是任何人都不愿意看到的。即使从DNS中去掉该服务器的IP,但在Internet上,各地区电信、网通等宽带接入商将众多的DNS存放在缓存中,以节省访问时间,DNS记录全部生效需要几个小时,甚至更久。所以,尽管DNS轮询在一定程度上解决了负载均衡问题,但是却存在可靠性不高的缺点。

  • 负载分配不均匀(有,但不会有那么大的影响)

    DNS负载均衡采用的是简单的轮询算法,不能区分服务器的差异,不能反映服务器的当前运行状态,不能做到为性能较好的服务器多分配请求,甚至会出现客户请求集中在某一台服务器上的情况。DNS服务器是按照一定的层次结构组织的,本地DNS服务器会缓存已解析的域名到IP地址的映射,这会导致使用该DNS服务器的用户在一段时间内访问的是同一台Web服务器,导致Web服务器间的负载不均匀。此外,用户本地计算机也会缓存已解析的域名到IP地址的映射。当多个用户计算机都缓存了某个域名到IP地址的映射时,而这些用户又继续访问该域名下的网页,这时也会导致不同Web服务器间的负载分配不均匀。负载不均匀可能导致的后果有:某几台服务器负荷很低,而另几台服务器负载很高、处理缓慢;配置高的服务器分配到的请求少,而配置低的服务器分配到的请求多。

统一网关设计

假设,一个系统中,可以拆分为A、B、C三个服务,为了从架构层对外统一暴露,那么一般的设立一个网关服务器,全部的应用请求全部从该网关服务器作为流量入口,而网关服务器则按照设定的规则,将请求分发给A、B、C三台服务器,并将结果返回给客户端。对于外界而言,该网关就是一个完整的应用服务。

  • 屏蔽内部实现
  • 做体力活,转发各种包
  • 负载均衡和广播消息的负载均衡(也是体力活)
  • 减少带宽需求.比如把好多个网关架设到一台服务器上.因为某讯的平台,就是每台机器收带宽费,而不是一起收多少带宽流量费.
  • 路由.可以控制客户端消息到内网的走向,分发到不同服务器上面去.

数据中心

典型的一个场景,某业务随着访问量的增长,单机场景下总出现CPU居高不下,甚至是面临死机的风险,为此,最简单粗暴的解决方案(数据库不是系统瓶颈为前提),就是将相同的代码部署到N台机器,利用网关,将请求平均分配到各台机器上。
而这样处理后,又面临一个问题:用户状态如何在多台机器中共享(随机转发或者是某台机器突然下线的场景)。例如,在经典的HTTP应用中,某个用户在A机器中登录,若为A用户分配的token,只存在于A机器本地中,那么就面临当下次用户请求被分配到B机器的时候,token就会无效,需要用户重新再次登录,很显然,这是非常不合理的。
而若再让我们自己去实现类似zookeeper一样的东西,来实现自动的数据调度迁移,显然是不现实的。因此,我们引入数据中心模式,实际上这是典型的分布式中master-slave的思想。以php Session为例子,我们可以为N台机器的Session handler设计为redis驱动,连接到一个redis集群。这样,用户不论在A还是B机器登录的token都存储到该redis数据中心中,
因此不论用户请求被分配到A还是B机器,用户的token一样可以被真实有效的读取到。

实战操作

HTTP应用

其实我觉得,大多数人的HTTP应用,基本上利用网关分发+数据中心设计,基本就可以解决了,而且大多网上也有相应的教程,因此我这里就不详细说明。

SOCKET 应用

我们以WEB SOCKET作为例子,假设在某游戏大型应用中,为了实现均衡负载,我们使用了网关,例如Nginx对用户连接进行随机分发到不同的机器。
而此刻,一个问题就是,在swoole中,如何推送给一个用户信息,那么是以$server->push($fd,message)的形式,单机下,这个fd是不会重复的,为一个非常大的自增整数,而如果在多机器的情况下,那么就可能,
A、B用户分别连接到A1,B1这两台机器,而且此时,刚好,A,B两个人分配到的fd可能都是相同的,例如,都是1。因此如果此刻想给A或者B下发消息,就会存在问题。因此,一个做法,那么就是在用户与机器建立连接的时候,记录
userId=>[serverId,serverFd] 这样的映射关系到数据中心。若此时,想给任意一个用户发消息,那么就去数据中心查询得到[serverId,serverFd],通过serverId,你可以获取得到目标服务器的ip地址或者通讯方式,比如,我们就是有一个HTTP服务用于接受消息推送请求,
那么你就可以post [serverFd,message]到目标机器接口,由目标机器执行$server->push($fd,message)。

其他

EasySwoole支持分布式吗

EasySwoole 3.x中有实现了对等模式的集群通讯,支持集群命令广播,节点发现与监控,RPC服务发现与远程调用等,具体的可以看代码实现,非常简单。

EasySwoole支持微服务吗

其实微服务与框架无关,微服务是人为划分出来的概念,简单理解,就是把一个非常庞大的系统切分为N个独立互不依赖的服务部署到不同的服务器上。举个例子,
一个商城中,就可以把用户与商品sku切分开,一台服务器用于用户权限管理,一台服务器用于处理商品sku信息,那么这就是微服务了。因此,请不要再问,EasySwoole支持微服务吗这样的问题了。