高性能服务器的分布式设计

何为高性能服务器

服务器分类

目前的高性能服务器,大家耳熟能详的有很多,
这里对通用的做了分类:
http服务器:nginx, apache
java http容器:tomcat, jetty
java 服务器框架: jetty, mina

其中nginx/apache/tomcat已被用于各大在线业务,按各使用场景来看功能,可概览如下:
高性能服务器的分布式设计

也可将这些功能分为基本与扩展。
基本功能:请求过滤,静态处理,长短连接,规则配置,动态容器,内容压缩。
扩展功能:负载均衡,反向代理, 容器。

为什么需要扩展功能

概括一些,基本功能可以被视为静态功能,扩展功能可被视为动态功能,所以问题被理解为为什么需要动态功能。
我们拿一个视频服务器来看,其需要具备哪些功能。
网页静态模板, 用户模块, 视频分发等。

静态服务器仅仅满足了静态模板的功能, 用户模块的鉴权与视频分发才是重点。

回过来看下服务器的动态扩展功能。

容器

这里以nginx, tomcat为例。
高性能服务器的分布式设计

tomcat为java容器而生,其上可运行各种组件与servlet。
nginx与tomcat对容器的支持方式不太一样,nginx原生不支持容器,将其扩展后可运行lua脚本,参见openresty。

tomcat 加载容器的方式:
xml/jar
xml决定配置, jar包含逻辑。
tomcat运行jar包的方式比较方便, 因为tomcat与容器内jar包都是运行在jvm之上。

nginx加载配置的方式

location /test/hello{
    default_type 'text/plain';
    charset UTF-8;
    content_by_lua_file /data/test/htdocs/hello.lua;
}

nginx运行容器其实是加载了lua运行库。

反向代理

早期的服务器对cgi的支持以spawn的形式支持。

通过反向代理,server可以不用关注后端连接的是什么服务, 后端的服务崩溃了也不影响server的稳定性。

负载均衡

通过反向代理,可以使用后端的负载均衡:
高性能服务器的分布式设计

通过配置规则,可以将负载均衡的负载到后面的各个点上。

有了容器,我们可以轻易定制业务逻辑。
有了反向代理与负载均衡,就可以异步化处理请求与前后分离。

还缺点什么

目前的主流服务器都支持http协议,原因并不是为了方便大家用浏览器,而是方便约定,通用。http+https 解决了加密的问题,于是所有对外的服务
都可以用http+https协议。
但是http包有点大了,对于高密度小包的服务,不太适用http了,需要定制的tcp/udp 协议,比如protobuf,这时就产生了各种服务器框架,如netty。

如何设计一个高性能服务器

框架

高性能服务器必须具备哪些素质,我们可以按互联网2个标准来定义:
高QPS,低响应时间。

有时候我们发现这两者有一定的关系,响应时间高的系统往往QPS低,对于同步处理可以套用公式:
QPS=1/响应时间
如果一个请求处理的平均时间为1mm,则QPS不会高于1K,假设每秒请求的次数为1W,则会形成请求堆积:
高性能服务器的分布式设计

问题很大,举一个简单的例子,一条针对nginx请求某文本文件的请求, 假设响应时间为2mm,那QPS岂不只有500了。
对于多个服务器串型处理的业务,情况恶劣成:

高性能服务器的分布式设计

一台服务器的瓶颈成为整条服务流的瓶颈。

简单一点类比,同步请求可以理解为:

A a = funcA();
B b = funcB(a);

funcA未结束是不能进行funcB的,线程在funcA是阻塞的。
如果funcA是IO处理(本地IO,网络IO),目前各操作系统已经提供异步库。
拿linux里的epoll为例, 可以在某fd可读可写时调用读写回调,而不可读不可写时不占用CPU时间。
可以理解为

func cb(A a)
{
    B b = funcB(a);
}
funcA(cb);

当调用funcA时,传入回调函数,等消息回调时才会处理funcB。虽然响应时间一样,线程不再阻塞了,QPS提高了。
这种做法叫异步。
异步大法好,前面列的nginx, apache, tomcat, jetty,netty都标配异步。
于是我们经常看到nginx读文本的QPS达到几万,虽然读一个文本的响应时间有几个耗秒。

业务为王, 没有最好的服务器,只有最满足业务的服务器,业务如果复杂,链路很深,就需要进行框架级的设计。
不能让所有业务都用一套框架,也不能为某个业务开发一个框架,但是不同的业务可以有不同的架构,在框架上可以对非业务逻辑部分进行抽象,整合,以期尽量简单的满足所有的业务。
所以架构应该分为框架架构与业务架构。
框架架构的目标功能:异步、反向代理,规则配置、均衡负载

为何需要业务架构

假设我们为了处理一个业务,
业务条件:平均一个业务的处理时间为5mm,无后端资源依赖。
要求:QPS 达到1W。
变量:机器数N, CPU核M, 内存数K
无论N等于几,无论同步还是异步,我们知道必须要启动20个线程或者进程,

假设业务条件改为:5个业务必须中行处理,平均一个业务的处理时间为5mm,无后端资源依赖,
QPS还是要求1W。
我们对数据整理:
5个业务的合并处理时间为25mm
每mm需要的业务处理数为10
单线程每秒的QPS为40,则需要250个线程处理,这250个线程分担到N个机器,假设机器数为1, 无论同步还是异步,单机器需要运行250个业务线程或者进程。
因此依靠框架的功能是解决不了具体业务的性能提升的。

上一篇:X-Forwarded-For信息头的处理


下一篇:nginx配置文件的逻辑关系