最近在思考高可用的高性能的服务端架构,面临的主要问题如下:
- 服务端组件怎么做到可插拔?
- 消息怎么智能路由?一个服务端挂了不会影响整个应用,避免单点故障?
- 如何设计一套高性能的Req-Rep,Pub-Sub,Push-Poll模型;
- 如何做到跨语言,让各语言各尽其用,比如编写业务代码可用Java,编写网络通信压缩,加密解密,数据序列化等用C++,而且尽可能减少性能损失?
看来这并不是一件简单的事情,我们这篇博客仅仅思考Req-Rep模式的搭建,我们这里使用开源项目ZeroMQ:
ZeroMQ以嵌入式网络编程库的形式实现了一个并行开发框架(concurrencyframework),能够提供进程内(inproc)、进程间(IPC)、网络(TCP)和广播方式的消息信道,并支持扇出(fan-out)、发布--订阅(pub-sub)、任务分发(taskdistribution)、请求/响应(request-reply)等通信模式。ZeroMQ的性能足以用来构建集群产品,其异步I/O模型能够为多核消息系统提供足够的扩展性。ZeroMQ支持30多种语言的API,可以用于绝大多数操作系统。在提供这些优秀特性的同时,ZeroMQ是开源的,遵循LGPLv3许可。 ZeroMQ的明确目标是“成为标准网络协议栈的一部分,之后进入Linux内核”。
我们的目标是:
- 业务程序的Req-Server集群部署,从网关发来的请求处理(是C/C++编写的网关),程序自动找一台空闲的Req-Server来处理这个请求,并将结果异步分发到服务单网关,从而Push给客户端;
- 一套Req-Server挂了不会影响整个服务端程序运行;
- 当Req过载时,即发送的大量请求在服务端堆积时,服务端“热部署”挂一个新的Req-Server,而不需要重新启动服务端程序;
这看起来的一个简单的任务其实并不简单!
幸好,ZeroMQ已经帮我们处理了大部分工作,考虑到这个网站大多数是Javaer,所以这篇博文我们以Java代码举例,实际上,我们服务端网关使用C编写的。
最简单的请求/应答模式如下:
客户端:
ZMQ.Context context = ZMQ.context(1); ZMQ.Socket requester = context.socket(ZMQ.REQ); requester.connect("tcp://localhost:5559"); for (int requestNbr = 0; requestNbr != 100000; requestNbr++) { String request = "Hello"+requestNbr; System.out.println("Sending Hello " + requestNbr); requester.send(request.getBytes(), 0); byte[] reply = requester.recv(0); System.out.println("Received " + new String(reply) + " " + requestNbr); } requester.close(); context.term();服务端:
ZMQ.Context context = ZMQ.context(1); ZMQ.Socket responder = context.socket(ZMQ.REP); responder.bind("tcp://*:5559"); while (!Thread.currentThread().isInterrupted()) { byte[] request = responder.recv(0); System.out.println("Received from client req:"+new String(request)); Thread.sleep(100); String reply = "World"; responder.send(reply.getBytes(), 0); } responder.close(); context.term();这里有几个不足:
- 当请求方并发数达到一定量时,由于请求在服务端不丢失,对导致大量的请求在服务端堆积,造成server端内存溢出;
- 存在单点故障,当部署的响应程序crash时,请求就无法处理了。
这里我们改善一下,引入请求/响应的Broker,所有的请求经由Broker代理中转,请求方不需要知道有多少server在后台服务,有Broker去决策一个请求交由那个处理请求的server去处理并负责负载均衡,代码如下:
Broker Server:
System.out.println("req Server Broker start...."); ZMQ.Context context = ZMQ.context(1); ZMQ.Socket frontEnd = context.socket(ZMQ.ROUTER); frontEnd.bind("tcp://*:5559"); ZMQ.Socket backEnd = context.socket(ZMQ.DEALER); backEnd.bind("tcp://*:5560"); ZMQQueue q = new ZMQQueue(context,frontEnd,backEnd); q.run(); frontEnd.close(); backEnd.close(); context.term();处理请求的Server(可以部署N个,N个Server热插拔):
ZMQ.Context context = ZMQ.context(1); ZMQ.Socket responder = context.socket(ZMQ.REP); String brokerIP = prop.getProperty("server_req_broker"); System.out.println("serverName:" + brokerIP); responder.connect("tcp://"+brokerIP); while (!Thread.currentThread().isInterrupted()) { byte[] request = responder.recv(0); Thread.sleep(100); String reply = "World"; responder.send(reply.getBytes(), 0); } responder.close(); context.term();
相关推荐
nanomsg是一个开源的实现了几种“可扩展协议”的高性能通信库,本文针对请求/回复模式进行了简单的源码分析,包括请求的时序图,socket消息槽等
1. 学习ZMQ_REQ\REP模式 2. 方便自己日后使用
req-package, 在使用包之上,依赖管理系统 请求包 描述req-package 为使用软件包提供依赖管理。 这样可以写简单而模块化的配置。 从使用包迁移是简单的,语法几乎相同。用法加载请求包:(require 'req-package)(re
前端开源库-req-then然后,简单的HTTP(S)请求函数,返回一个承诺。
zeromq 的异步demo,简单描述zmq的事例
ZMQ的服务端、客户端小例子,ZMQ使用4.0.4,是最新版本;开发工具是VC2010;编译的程序和使用ZMQ都是x64位版本。希望对学习ZMQ有帮助。运行的时候先打开server,之后启动client;实现了服务端和客户端的简单收发通信...
ssrf-req-filter - 防止 SSRF 攻击 :shield: 服务器端请求伪造 (SSRF) SSRF 是一种攻击媒介,它滥用应用程序与内部/外部网络或机器本身进行交互。 此向量的促成因素之一是 URL 处理不当。 安装 npm install ssrf-...
api-req-example.js
前端开源库-req-fast快速,这个模块被设计成快速,轻量级的方式来获取Web内容(HTML流)。
IPS-sig-S595-req-E4.pkg
IPS-sig-S594-req-E4.pkg
python库,解压后可用。 资源全名:dothttp_req-0.0.6-py2-none-any.whl
前端开源库-req-from.zip
前端开源库-req-from从,需要一个模块
前端开源库-req-cwd要求CWD,需要类似模块
资源来自pypi官网。 资源全名:dothttp_req-0.0.6-py2-none-any.whl
O-RAN.WG9.XTRP-REQ-v01.00.pdf
Req-CB-AB_2023x.Reqtify.unix.1-1.zip
这是一个zmq的范例代码,可以用来学习rep和req模式
python库。资源全名:dothttp_req-wasm-0.0.33.tar.gz