构建api gateway之 健康检查
Healthcheck
由于服务无法保证永远不会下线,而且下线时不一定能有人员能及时发现,
所以api gateway 一般会引入一个监工 Healthcheck, 像大家每年体检一样定时确认服务是否存活。
这样就可以在上游节点发生故障或者迁移时,将请求代理到健康的节点上,最大程度避免服务不可用的问题。
一般其分为主动检查和被动检查。
主动检查
其一般为使用单独的线程、进程、甚至独立的程序的探针,不断轮休式主动检查服务存活性。
一般支持 HTTP、HTTPS、TCP 三种探针类型, 也就是实际存不存活就是访问大家服务,看能不能得到正常结果。
其判定存活逻辑一般为:当发向健康节点 A 的 N 个连续探针都失败时(取决于如何配置),则该节点将被标记为不健康,不健康的节点将会被 api gateway忽略,无法收到请求;若某个不健康的节点,连续 M 个探针都成功,则该节点将被重新标记为健康,进而可以被代理。
(PS: 一般很多api gateway 为了方便大家使用,程序自带主动检查,所以api gateway 实例很多时,这样主动检查的请求就会过于大量,有些就会独立搭建独立的检查服务,减少请求量级)
被动检查
其一般为根据上游服务返回的情况,来判断对应的上游节点是否健康。相对于主动健康检查,被动健康检查的方式无需发起额外的探针,但是也无法提前感知节点状态,可能会有一定量的失败请求。
同理一般也是发向健康节点 A 的 N 个连续请求都被判定为失败(取决于如何配置),则该节点才被标记为不健康。
实践
由于篇幅关系,这里就只介绍被动检查的实现例子。
更具体实现可以参考 简化的healthcheck 或者 完整的lua-resty-healthcheck (ps: lua-resty-healthcheck 被动检查被标记为不健康之后无法恢复健康状态)
worker_processes 1; #nginx worker 数量
error_log logs/error.log; #指定错误日志文件路径
events {
worker_connections 1024;
}
http {
log_format main '$remote_addr [$time_local] $status $request_time $upstream_status $upstream_addr $upstream_response_time';
access_log logs/access.log main buffer=16384 flush=3; #access_log 文件配置
lua_package_path "$prefix/deps/share/lua/5.1/?.lua;$prefix/deps/share/lua/5.1/?/init.lua;$prefix/?.lua;$prefix/?/init.lua;;./?.lua;/usr/local/openresty/luajit/share/luajit-2.1.0-beta3/?.lua;/usr/local/share/lua/5.1/?.lua;/usr/local/share/lua/5.1/?/init.lua;/usr/local/openresty/luajit/share/lua/5.1/?.lua;/usr/local/openresty/luajit/share/lua/5.1/?/init.lua;";
lua_package_cpath "$prefix/deps/lib64/lua/5.1/?.so;$prefix/deps/lib/lua/5.1/?.so;;./?.so;/usr/local/lib/lua/5.1/?.so;/usr/local/openresty/luajit/lib/lua/5.1/?.so;/usr/local/lib/lua/5.1/loadall.so;";
# 开启 lua code 缓存
lua_code_cache on;
lua_shared_dict http_healthcheck 20m;
upstream nature_upstream {
server 127.0.0.1:6699; #upstream 配置为 hello world 服务
# 一样的balancer
balancer_by_lua_block {
local balancer = require "ngx.balancer"
local upstream = ngx.ctx.api_ctx.upstream
local ok, err = balancer.set_current_peer(upstream.host, upstream.port)
if not ok then
ngx.log(ngx.ERR, "failed to set the current peer: ", err)
return ngx.exit(ngx.ERROR)
end
}
}
init_by_lua_block {
-- 初始化 lb
local roundrobin = require("resty.roundrobin")
local nodes = {k1 = {host = '127.0.0.1', port = 6698}, k2 = {host = '127.0.0.1', port = 6699}}
local ns = {}
for k, v in pairs(nodes) do
-- 初始化 weight
ns[k] = 1
end
local picker = roundrobin:new(ns)
-- 被动检查
local shm_healthcheck = ngx.shared["http_healthcheck"]
local check_healthcheck = function()
for _ in pairs(nodes) do
local k, err = picker:find()
if not k then
return nil, err
end
local node = nodes[k]
-- 检查是否不健康
local status = shm_healthcheck:get(node.host..':'..tostring(node.port))
if not status then
return node
end
end
return nil, 'no health node'
end
-- 初始化路由
local radix = require("resty.radixtree")
local r = radix.new({
{paths = {'/aa/d'}, metadata = {
find = check_healthcheck
}},
})
-- 匹配路由
router_match = function()
local p, err = r:match(ngx.var.uri, {})
if err then
log.error(err)
end
-- 执行 roundrobin lb 选择
local k, err = p:find()
if not k then
return nil, err
end
return k
end
}
server {
#监听端口,若你的8699端口已经被占用,则需要修改
listen 8699 reuseport;
location / {
# 在access阶段匹配路由
access_by_lua_block {
local upstream = router_match()
if upstream then
ngx.ctx.api_ctx = { upstream = upstream }
else
ngx.exit(404)
end
}
proxy_http_version 1.1;
proxy_pass http://nature_upstream; #转发到 upstream
# 上游节点 502 记录到不健康列表,这里为了理解简单,失败一次就写入
log_by_lua_block {
local s = ngx.var.upstream_status
if s and s == '502' then
ngx.shared["http_healthcheck"]:incr(ngx.var.upstream_addr, 1, 5)
end
}
}
}
#为了大家方便理解和测试,我们引入一个hello world 服务
server {
#监听端口,若你的6699端口已经被占用,则需要修改
listen 6699;
location / {
default_type text/html;
content_by_lua_block {
ngx.say("HelloWorld")
}
}
}
}
启动服务并测试
$ openresty -p ~/openresty-test -c openresty.conf #启动
$ curl --request GET 'http://127.0.0.1:8699/aa/d' #第一次
<html>
<head><title>502 Bad Gateway</title></head>
<body>
<center><h1>502 Bad Gateway</h1></center>
</body>
</html>
$ curl --request GET 'http://127.0.0.1:8699/aa/d' #第二次
HelloWorld
$ curl --request GET 'http://127.0.0.1:8699/aa/d' #第三次
HelloWorld
$ curl --request GET 'http://127.0.0.1:8699/aa/d' #第四次
HelloWorld
可以看到不可访问的服务节点只被访问了一次,后续都到了健康的节点上
目录
构建api gateway之 健康检查的更多相关文章
- [转载] 构建微服务:使用API Gateway
原文: http://mp.weixin.qq.com/s?__biz=MzA5OTAyNzQ2OA==&mid=206889381&idx=1&sn=478ccb35294c ...
- docker 构建带健康检查的redis镜像
=============================================== 2018/11/5_第1次修改 ccb_warlock == ...
- 架构模式: 健康检查API
架构模式: 健康检查API 上下文 您已应用微服务架构模式.有时,服务实例可能无法处理仍在运行的请求.例如,它可能已用完数据库连接.发生这种情况时,监控系统应生成警报.此外,负载平衡器或服务注册表不应 ...
- 0601-Zuul构建API Gateway-API gateway简介、基础使用、路由配置、负载配置
一.API Gateway简介 参看:http://www.cnblogs.com/bjlhx/p/8794437.html 二.zuul简介[路由器和过滤器:Zuul] 在微服务架构的组成部分进行路 ...
- Amazon API Gateway Importer整合过程小结
(1)需要将swagger json转换成amazon api gateway 所需要的格式(根据Method Request中 Request PathsURL Query String Param ...
- 聊聊 API Gateway 和 Netflix Zuul
最近参与了公司 API Gateway 的搭建工作,技术选型是 Netflix Zuul,主要聊一聊其中的一些心得和体会. 本文主要是介绍使用 Zuul 且在不强制使用其他 Neflix OSS 组件 ...
- 几种部署Goku API Gateway的方式,最快一分钟可使用上网关
本文将介绍几种部署Goku API Gateway的方式,最快一分钟可使用上为网关,详情请看全文. 什么是Goku API Gateway? Goku API Gateway (中文名:悟空 API ...
- 使用AWS Lambda,API Gateway和S3 Storage快速调整图片大小
https://www.obytes.com/blog/2019/image-resizing-on-the-fly-with-aws-lambda,-api-gateway,-and-s3-stor ...
- Openshift中Pod的SpringBoot2健康检查
Openshift中Pod的SpringBoot2应用程序健康检查 1. 准备测试的SpringBoot工程, 需要Java 8 JDK or greater and Maven 3.3.x or g ...
- 关于kong | API Gateway
目录 为什么需要 API 网关(more) kong的概念 为什么使用Kong Kong 的管理方式 高可扩展性的背后-插件机制 [前言]: Kong是一个云原生,高效,可扩展的分布式 API 网关. ...
随机推荐
- 聊聊kafka
两个月因为忙于工作毫无输出了,最近想给团队小伙伴分享下kafka的相关知识,于是就想着利用博客来做个提前的准备工作了:接下来会对kafka做一个简单的介绍,包括利用akf原则来解析单机下kafk的各个 ...
- 【Java并发002】使用级别:线程同步与线程通信
一.前言 本文介绍Java多线程技术,分为五个部分:多线程的两种实现方式--继承Thread类和实现Runnable接口:线程同步应用:三人吃苹果:线程同步+线程通信应用之一:生产者-消费者问题:线程 ...
- 6个tips缓解第三方访问风险
随着开发和交付的压力越来越大,许多企业选择依赖第三方来帮助运营和发展业务.值得重视的是,第三方软件及服务供应商和合作伙伴也是云环境攻击面的重要组成部分.尽管企业无法完全切断与第三方的关联,但可以在向他 ...
- OSI传输层TCP与UDP协议、应用层简介、socket模块介绍及代码优化、半连接池的概念
目录 传输层之TCP与UDP协议 应用层 socket模块 socket基本使用 代码优化 半连接池的概念 传输层之TCP与UDP协议 TCP与UDP都是用来规定通信方式的 通信的时候可以随心所欲的聊 ...
- 树莓派配置uwsgi服务
前言 我配置 uwsgi 服务是为了运行给 python flask 项目,如果直接 pip3 install uwsgi 得到的uwsgi服务可以直接使用,只不过需要在命令行中启动服务(当然也可以使 ...
- QMetaObject::connectSlotsByName: No matching signal for xxx
问题描述 这个问题是没有与 xxx 这个槽函数匹配的信号,但是我做了 QMetaObject::connectSlotsByName(this);, 自动连接.并且确保了函数名和信号名是没有错误的,还 ...
- 记一次windows10电脑连上wifi无法上网的解决问题
前言 今天下午同学的电脑能连上wifi,但是却上不了互联网 开始思考 首先想到的肯定是WiFi驱动问题,但是wifi能连上大部分的原因可能就不是驱动问题了,为了彻底排除这个因素,我用到了我的usb网卡 ...
- Docker定时删除none镜像
在使用docker的时候会产生none镜像文件,偶尔没什么,但是比如使用了自动化部署工具那就不一样了,一天没准就上百个none镜像了,非常消耗资源,所以需要定时清理 删除 none 镜像命令 dock ...
- vue3 watch笔记
watchEffect 执行传入的一个函数,同时自动追踪函数中依赖到的数据,并在其依赖变更时重新运行该函数. 并且会在 组件挂载前 立即调用一次,(默认是挂载前,可通过修改 flush 属性改变,后边 ...
- webflux延迟队列逻辑更改过程记录
title : webflux延迟队列逻辑更改过程记录 author : simonLee date : 2022/11/22 10:26 目录 webflux延迟队列逻辑更改过程记录 一.问题背景 ...