首页 » PHP教程 » php办事发明技巧_若何基于DockerNodeJs实现高可用的做事创造

php办事发明技巧_若何基于DockerNodeJs实现高可用的做事创造

访客 2024-11-14 0

扫一扫用手机浏览

文章目录 [+]

基于上一篇的 “基于Docker、Registrator、Zookeeper实现的做事自动注册”,完成了 “做事注册与创造” 的上半部分(即上图中的1)。
本文就来讲讲图中的2、3、4、5 分别是如何实现的。

功能点做事订阅

1.动态获取做事列表

php办事发明技巧_若何基于DockerNodeJs实现高可用的做事创造

2.获取做事节点信息(IP、Port)

php办事发明技巧_若何基于DockerNodeJs实现高可用的做事创造
(图片来自网络侵删)
本地缓存

1.缓存做事路由表

做事调用

1.做事要求的负载均衡策略

2.反向代理

变更关照

1.监听做事节点变革

2.更新做事路由表

技能方案做事创造办法

关于做事创造的办法,紧张分为两种办法:客户端创造与做事端创造。
它们的紧张差异为:前者是由调用者本身去调用做事,后者是将调用者要求统一指向类似做事网关的做事,由做事网关代为调用。

这里采取做事端创造机制,即做事网关(把稳:做事网关的浸染不仅仅是做事创造)。

与客户端创造比较,可见的上风有:

做事调用的统一管理;减少客户端与注册中央不必要的连接数;将后端做事与调用者相隔离,降落做事对外暴露的风险;所选技能

本文采取 NodeJs 作为做事网关的实现技能。
当然,这不是唯一的技能手段,像nginx+lua,php等都能实现类似的功能。
我这里采取 NodeJs 紧张出于以下几个缘故原由:

NodeJs 采取的是事宜驱动、非壅塞 I/O 模型,具有天生的异步性。
在处理做事网关这种以IO密集型为主的业务时,正是 NodeJs 所善于的。
NodeJs 基于Chrome V8 引擎的 JavaScript 措辞的运行环境,对付有一定 JavaScript 根本的同学,上手相对大略。

所有技能都有其利害所在,NodeJs 在这里的利用也存在一定的问题(本文末了会讲述它的高可用策略):

NodeJs 是基于单进程单线程的办法,这种办法存在一定的不可靠性。
一旦进程崩溃,对应的做事将变得不可用;单进程单线程办法,也导致了只能利用单核CPU。
为了充分利用打算机资源,还需进行做事的水平扩展;代码示例

代码地址:https://github.com/jasonGeng88/service_registry_discovery

代码目录

本文紧张先容做事创造干系实现,其他部分已在上篇中先容过,感兴趣的同学可查看上篇。

目录构造(discovery项目)

依赖配置(package.json)

{

"name": "service-discovery",

"version": "0.0.0",

"private": true,

"scripts": {

"start": "node ./bin/www"

},

"dependencies": {

"debug": "~2.6.3",

"express": "~4.15.2",

"http-proxy": "^1.16.2",

"loadbalance": "^0.2.7",

"node-zookeeper-client": "^0.2.2"

}

}

debug:用于开拓调试;express:作为 NodeJs 的Web运用框架,这里紧张用到了它的相应HTTP要求以及路由规则功能;http-proxy:用作反向代理;loadbalance:负载均衡策略,目前供应随机、轮询、权重;node-zookeeper-client:ZK 客户端,用作获取注册中央做事信息与节点监听;常量设置(constants.js)

"use strict";

function define(name, value) {

Object.defineProperty(exports, name, {

value: value,

enumerable: true

});

}

define('ZK_HOSTS', '${PRIVATE_IP}:2181,${PRIVATE_IP}:2182,${PRIVATE_IP}:2183');

define('SERVICE_ROOT_PATH', '/services');

define('ROUTE_KEY', 'services');

define('SERVICE_NAME', 'service_name');

define('API_NAME', 'api_name');

功能点详细实现

下面会对上面供应的功能点依次进行实现(展示代码中只保留核心代码,详细请见代码

做事订阅 - 动态获取做事列表

var zookeeper = require('node-zookeeper-client');

var constants = require('../constants');

var debug = require('debug')('dev:discovery');

var zkClient = zookeeper.createClient(constants.ZK_HOSTS);

/

连接ZK

/

function connect() {

zkClient.connect();

zkClient.once('connected', function() {

console.log('Connected to ZooKeeper.');

getServices(constants.SERVICE_ROOT_PATH);

});

}

/

获取做事列表

/

function getServices(path) {

zkClient.getChildren(

path,

null,

function(error, children, stat) {

if (error) {

console.log(

'Failed to list children of %s due to: %s.',

path,

error

);

return;

}

// 遍历做事列表,获取做事节点信息

children.forEach(function(item) {

getService(path + '/' + item);

})

}

);

}

做事订阅 - 获取做事节点信息(IP、Port)

/

获取做事节点信息(IP,Port)

/

function getService(path) {

zkClient.getChildren(

path,

null,

function(error, children, stat) {

if (error) {

console.log(

'Failed to list children of %s due to: %s.',

path,

error

);

return;

}

// 打印节点信息

debug('path: ' + path + ', children is ' + children);

}

);

}

本地缓存 - 缓存做事路由表

// 初始化缓存

var cache = require('./local-storage');

cache.setItem(constants.ROUTE_KEY, {});

/

获取做事节点信息(IP,Port)

/

function getService(path) {

...

// 打印节点信息

debug('path: ' + path + ', children is ' + children);

if (children.length > 0) {

//设置本地路由缓存

cache.getItem(constants.ROUTE_KEY)[path] = children;

}

...

}

做事调用 - 负载均衡策略

/

获取做事节点信息(IP,Port)

/

function getService(path) {

...

if (children.length > 0) {

//设置负载策略(轮询)

cache.getItem(constants.ROUTE_KEY)[path] = loadbalance.roundRobin(children);

}

...

}

要求的负载均衡,实质是对路由表中要求地址进行记录与分发。
记录:上一次要求的地址;分发:按照策略选择接下来要求的地址。
这里为了简便起见,将负载与缓存并在一起。

做事调用 - 反向代理

var proxy = require('http-proxy').createProxyServer({});

var cache = require('../middlewares/local-storage');

var constants = require("../constants");

var debug = require('debug')('dev:reserveProxy');

/

根据headers的 service_name 与 api_name 进行代理要求

/

function reverseProxy(req, res, next) {

var serviceName = req.headers[constants.SERVICE_NAME];

var apiName = req.headers[constants.API_NAME];

var serviceNode = constants.SERVICE_ROOT_PATH + '/' + serviceName;

debug(cache.getItem(constants.ROUTE_KEY)[serviceNode]);

var host = cache.getItem(constants.ROUTE_KEY)[serviceNode].pick();

var url = 'http://' + host + apiName;

debug('The proxy url is ' + url);

proxy.web(req, res, {

target: url

});

}

变更关照 - 监听做事节点 && 更新路由缓存

/

获取做事列表

/

function getServices(path) {

zkClient.getChildren(

path,

// 监听列表变革

function(event) {

console.log('Got Services watcher event: %s', event);

getServices(constants.SERVICE_ROOT_PATH);

},

function(error, children, stat) {

...

}

);

}

/

获取做事节点信息(IP,Port)

/

function getService(path) {

zkClient.getChildren(

path,

// 监听做事节点变革

function(event) {

console.log('Got Serivce watcher event: %s', event);

getService(path);

},

function(error, children, stat) {

...

}

);

}

主文件(src/app.js)

var express = require('express');

var reverseProxy = require('./routes/reverse-proxy');

var discovery = require('./middlewares/discovery');

var app = express();

// service discovery start

discovery();

// define the home page route

app.get('/', function(req, res) {

res.send('This is a Service Gateway Demo')

});

// define proxy route

app.use('/services', reverseProxy);

启动脚本(src/bin/www)

脚本中含有单进程与多进程两种启动办法,由于 NodeJs 单进程的不可靠性,一样平常生产环境中采取多进程办法启动,担保它的稳定性。

#!/usr/bin/env node

var app = require('../app');

var http = require('http');

var port = 8080;

//单进程运行

//http.createServer(app).listen(port);

//多进程运行

var cluster = require('cluster');

var numCPUs = require('os').cpus().length;

if (cluster.isMaster) {

console.log("master start...");

// Fork workers.

for (var i = 0; i < numCPUs; i++) {

cluster.fork();

}

cluster.on('listening',function(worker,address){

console.log('listening: worker ' + worker.process.pid +', Address: '+address.address+":"+address.port);

});

cluster.on('exit', function(worker, code, signal) {

console.log('worker ' + worker.process.pid + ' died');

cluster.fork();

});

} else if (cluster.isWorker) {

http.createServer(app).listen(port);

}

镜像构建

为演示方便,采取单进程办法

# Dockerfile

FROM node:6.10.2

MAINTAINER jasongeng88@gmail.com

ENV TZ="Asia/Shanghai" HOME="/usr/src/app"

WORKDIR ${HOME}

COPY src/ ${HOME}/

RUN npm install

EXPOSE 8080

ENTRYPOINT ["npm", "run", "start"]

# 构建命令

docker build -t node_discovery .

场景演示改动

坑:由于 docker --net=host 在 Mac 上存在问题,以是对 Registrator 做出调度。
原来向注册中央注册的是 127.0.0.1 改为 内网IP,担保容器内可以访问。

Linux 环境下不须要此改动,做事网关网络模式应为host。

准备事情

为了方便演示,对原来的做事模块进行调度,供应如下做事:

做事模块启动如下(service_1:2个,service_2:1个)

启动做事网关

cd discovery && docker-compose up -d

输出效果(docker logs -f discovery_discovery_1 看出日志输出):

场景1:GET办法,要求做事2,API路径为 / ,无要求参数

场景2:GET办法,要求做事1,API路径为 /user ,要求参数为id=1

场景3:GET办法,多次要求做事1,API路径为 / ,查看负载均衡情形

场景4:启停做事2实例,不雅观察路由表变革

// 停用 serivce_2

cd services && docker-compose stop service_2

查看网关监听变革:

高可用NodeJs 自身通过 cluster 模块,进行多进程启动,防止单进程崩溃的不稳定性;通过 Docker 容器化启动,在启动时设置restart策略,一旦做事崩溃将立即重启;上述的利用场景都在单机上运行,在分布式情形下,可以将 NodeJs 容器多主机支配,采取 nginx + NodeJs 的架构进行水平扩展;总结

本文以上篇 “做事自动化注册” 遗留的功能点开头,讲述了做事创造的2种实现办法,以及其利害。
并以 NodeJs 作为做事网关的实现手段,详细先容了个中各功能点的实现细节。
末了通过场景代入的办法,展示了厥后果。

对付网关的高可用,也通过了2种办法进行了担保。
自身高可用通过多进程、失落败重启策略进行担保;分布式下则以 nginx + NodeJs 的架构进行了担保。

文中也提到,做事创造实则只是做事网关的一个部分,做事网关还包括做事鉴权、访问掌握等。
这里的代码仅是个Demo示例,目的是让大家更好的看清它的实质,希望对大家有所帮助~

江苏立维成立于2015年,核心团队来自焦点、华为、复兴,专注于企业信息化领域的安全、运维产品的开拓和做事,为企业供应包含业务迁移上云、业务稳定性保障、安全运维是海内首批专注于企业业务安全稳定运行做事保障的公司。

标签:

相关文章

吾爱破解php视频技巧_吾爱破解漫游指南

吾爱破解漫游指南作为一个新人同学,在群友和朋友或者一些媒体的宣扬下,你一定理解到了吾爱这个大家庭,并想加入与大家共同谈论(吹水),...

PHP教程 2024-12-15 阅读0 评论0

php前端ssh后端技巧_前端开拓 后端开拓

建筑师每个产品线都有一个架构师,技能平台部门也须要一个技能平台架构师。架构师卖力设计整体系统架构,考虑到从需求到设计的每一个细节,...

PHP教程 2024-12-15 阅读0 评论0