构建api gateway之 基于etcd实现动态配置同步
配置中心
在之前 tcp的yaml配置 介绍了如何监听yaml文件变化然后更新配置。
当然假如我们有很多实例,那么yaml改动将是非常痛苦的事情,那么如何做到配置文件统一管理,实时更新呢?
我们可以引入配置中心,从而达到这样的效果。
业界已经有非常多配置中心了,这里为了简化内容,将选用etcd作为配置中心来介绍实现。
etcd
etcd 是一个分布式键值对存储系统。
设计用于可靠存储不频繁更新的数据,并提供可靠的观察查询。
etcd 暴露键值对的先前版本来支持不昂贵的快速和观察历史事件(“time travel queries”)。
对于这些使用场景,持久化,多版本,并发控制的数据模型是非常适合的。
ectd 使用多版本持久化键值存储来存储数据。
当键值对的值被新的数据替代时,持久化键值存储保存先前版本的键值对。
键值存储事实上是不可变的;它的操作不会就地更新结构,替代的是总是生成一个新的更新后的结构。
在修改之后,key的所有先前版本还是可以访问和观察的。为了防止随着时间的过去为了维护老版本导致数据存储无限增长,存储应该压缩来脱离被替代的数据的最旧的版本。
所以其非常适合作为配置中心,每一个配置变动都是有序的。
使用 etcd
大家测试可以使用docker 实验
docker run -p 2479:2479 -p 2480:2480 --mount type=bind,source=$(shell pwd)/tmp/etcd-data.tmp,destination=/etcd-data --name etcd \
gcr.io/etcd-development/etcd:v3.5.0 \
/usr/local/bin/etcd \
--name s1 \
--data-dir /etcd-data \
--listen-client-urls http://0.0.0.0:2479 \
--advertise-client-urls http://0.0.0.0:2479 \
--listen-peer-urls http://0.0.0.0:2480 \
--initial-advertise-peer-urls http://0.0.0.0:2480 \
--initial-cluster s1=http://0.0.0.0:2480 \
--initial-cluster-token tkn \
--initial-cluster-state new \
--log-level info \
--logger zap \
--log-outputs stderr
cli
可以使用 cli 工具: https://github.com/etcd-io/etcd/tree/main/etcdctl
./etcdctl put foo bar --lease=1234abcd
# OK
./etcdctl get foo
# foo
# bar
./etcdctl put foo --ignore-value # to detache lease
# OK
ui
或者使用ui工具: https://github.com/evildecay/etcdkeeper

实践
以下内容更新到 openresty-dev-1.rockspec
-- 依赖包
dependencies = {
"lua-resty-etcd >= 1.9.0",
}
然后执行
luarocks install openresty-dev-1.rockspec --tree=deps --only-deps --local
代码内容:
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;
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_worker 是因为 init 不允许请求etcd
init_worker_by_lua_block {
node = nil
-- 匹配路由, 为了演示,这里简化为单个节点,并且路由处理也去掉了
router_match = function()
return node
end
-- 从etcd 加载配置,同理为了演示简单,这里只做单个节点
local etcdlib = require("resty.etcd").new({
protocol = "v3",
api_prefix = "/v3",
http_host = 'http://127.0.0.1:2479',
key_prefix = '/test/'
})
-- 这里为了简单,展示轮询方式, watch 的方式可以参考 https://github.com/fs7744/nature/blob/main/nature/config/etcd.lua
ngx.timer.every(1, function()
local res, err = etcdlib:get('node')
local json = require('cjson.safe')
if res ~= nil and res.body ~= nil and res.body.kvs ~= nil and res.body.kvs[1] ~= nil then
node = res.body.kvs[1].value
ngx.log(ngx.ERR, json.encode(node))
end
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
}
}
#为了大家方便理解和测试,我们引入一个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>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
</body>
</html>
$ ./etcdctl put /test/node {"host":"127.0.0.1","port":6699} # 写入测试节点数据
$ curl --request GET 'http://127.0.0.1:8699/aa/d' #第二次测试
HelloWorld
可以看到获取到了etcd的配置变化
目录
构建api gateway之 基于etcd实现动态配置同步的更多相关文章
- Yii2 advanced版API接口开发 基于RESTful架构的 配置、实现、测试
参考地址: http://www.xiaoxiangzi.com/Programme/PHP/3348.html http://www.cnblogs.com/ganiks/p/yii2-restfu ...
- 基于通用jar、动态配置、组件编排的会员任务中心系统设计
# 一.聊聊本文想说什么: 为更好帮助商家的会员快速成长,保持用户活性,完善用户的成长体系,有赞用户中心-会员成长团队基于现有的业务场景,设计了一套较完备任务中心系统.同时也有很多通用技术组件能够 ...
- 实战:基于 Spring 的应用配置如何迁移至阿里云应用配置管理 ACM
最近遇到一些开发者朋友,准备将原有的Java Spring的应用配置迁移到 阿里云应用配置管理 ACM 中.迁移过程中,遇到不少有趣的问题.本文将通过一个简单的样例来还原迁移过程中遇到的问题和相关解决 ...
- [转载] 构建微服务:使用API Gateway
原文: http://mp.weixin.qq.com/s?__biz=MzA5OTAyNzQ2OA==&mid=206889381&idx=1&sn=478ccb35294c ...
- 0601-Zuul构建API Gateway-API gateway简介、基础使用、路由配置、负载配置
一.API Gateway简介 参看:http://www.cnblogs.com/bjlhx/p/8794437.html 二.zuul简介[路由器和过滤器:Zuul] 在微服务架构的组成部分进行路 ...
- 基于etcd插件的CoreDNS动态域名添加
前提条件:已经有一个可用的etcd环境. 一.CoreDNS简介 CoreDNS是一个DNS服务器,和Caddy Server具有相同的模型:它链接插件.CoreDNS是云本土计算基金会启动阶段项目. ...
- 基于aws api gateway的asp.net core验证
本文是介绍aws 作为api gateway,用asp.net core用web应用,.net core作为aws lambda function. api gateway和asp.net core的 ...
- 谈谈微服务中的 API 网关(API Gateway)
前言 又是很久没写博客了,最近一段时间换了新工作,比较忙,所以没有抽出来太多的时间写给关注我的粉丝写一些干货了,就有人问我怎么最近没有更新博客了,在这里给大家抱歉. 那么,在本篇文章中,我们就一起来探 ...
- 微服务中的 API 网关(API Gateway)
API 网关(API Gateway)提供高性能.高可用的 API 托管服务,帮助用户对外开放其部署在 ECS.容器服务等云产品上的应用,提供完整的 API 发布.管理.维护生命周期管理.用户只需进行 ...
- API Gateway微服务
微服务中的 API 网关(API Gateway) 前言 又是很久没写博客了,最近一段时间换了新工作,比较忙,所以没有抽出来太多的时间写给关注我的粉丝写一些干货了,就有人问我怎么最近没有更新博客了 ...
随机推荐
- promise 的串行执行
function pri (num) { return new Promise((resolve,reject) => { console.log('开始'+num) res ...
- Redisson源码解读-公平锁
前言 我在上一篇文章聊了Redisson的可重入锁,这次继续来聊聊Redisson的公平锁.下面是官方原话: 它保证了当多个Redisson客户端线程同时请求加锁时,优先分配给先发出请求的线程.所有请 ...
- 陪你去看 Lodash.js 起步
lodash 起步(数组) Lodash 是一个较为流行的 JavaScript 的实用工具库. 在开发过程中如果能熟练使用一些工具库提供的方法,有利于提高开发效率. 笔者从 API 上入手,不分析其 ...
- K8s如何启用cgroup2支持?
什么是 cgroup ️Reference: control groups(控制组),通常被称为cgroup,是Linux内核的一项功能.它允许将进程组织成分层的组,然后限制和监控各种资源的使用. 内 ...
- 「工具推荐」golang 代码可视化工具 go-callvis
「工具推荐」go-callvis go-callvis是相对 以图片的形式展示了go程序的调用关系,这个工具在看复杂项目时尤其有用. 亲测,借助它看祖传golang代码,头痛好多了. 安装 go ge ...
- 安装mySql 出现 one more product requirements have not been satisified
安装mySql 出现 one more product requirements have not been satisified 原因是缺少一些依赖环境. 在弹出的对话框中点击 否. 然后点击执行, ...
- vulnhub靶场之CONTAINME: 1
准备: 攻击机:虚拟机kali.本机win10. 靶机:CONTAINME: 1,下载地址:https://download.vulnhub.com/containme/THM-ContainMe-v ...
- 【zookeeper】Zookeeper相关概念、重难点(myid)、语法、使用、工具
1234567890 1请按照我是想额度插入fvtgb6yhn7ujm8ik,9ol.
- websockets的原理
一.应用场景 http 协议 客户端发起请求的时候才会返回内容,如果要处理类似于聊天室的应用,需要客户端不间断的发起请求(轮询),非常占用服务器的性能.所以websocket出现了. 二.ws(wss ...
- django.core.exceptions.ImproperlyConfigured: Application labels aren't unique, duplicates: rest_framework_swagger
在启动服务时报django.core.exceptions.ImproperlyConfigured: Application labels aren't unique, duplicates: re ...