人们喜欢谈论微服务。"你应该迁移到微服务",他们说。但是,为什么呢?当开始做产品时,你会被催促着建立更多的功能。通常情况下,它将增长到你的员工的2x-3x的数量。目前,流量还没有那么大。你得到的少数客户应该被视为天使投资人。因为你需要确保你的应用程序的工作,尽管在几个功能上有很多变化。
解决方案你需要将你的应用程序分割成多个服务,分别升级或添加服务。当升级失败时,它可以被回滚,所以它将更安全。但是,它很难管理许多服务。你需要docker或kubernetes。然后使用管理平台,如portainer、docker swarm或rancher。还有,不要忘记安装api网关、grpc和graphql。为了提供数据的一致性,请使用消息代理将你的后端折射为事件驱动的架构。对于升级版本,你可以使用特性标志,或者使用gitlab CI进行CI/CD。但是,最近用gitlab CI实现的CI/CD是错误的。最好只用gitlab CI做CI,而用terraform做CD。所以,你需要用terraform(和ansible)把你的架构重写成云架构。它仍然需要写集成测试和模拟服务器,以确保CI在staging上正常运行。不要忘记使用fluentd、loki等进行监控,这样你就可以通过追踪x-request-id来跟踪微服务中的用户行为。
用Openresty部署Canary金丝雀大多谈论A/B测试。但是,A/B测试通常有一些目标计划。在这种情况下,使用百分比进行分割是很奇怪的。当你把金丝雀分成10%的时候,一个人用两个设备会得到不同的版本。
在这个小型创业公司中,金丝雀被用来根据哪些普通用户和VIP用户来分割流量。VIP用户由他们支付的费用或其他有影响的方面决定,或者你的应用程序对他们的业务有多大影响(长期用户)。
在这个例子中,我们通过以下步骤将流量按http cookie分开。
- 后台对任何想被标记的用户会话设置cookie ISCANARY=true。
- lua脚本读取http cookie。
- lua脚本从redis读取所有的上游。
- 改变nginx配置的lua脚本上游
pip安装Flask
vim main.py
import sys
from flask import Flask
port = 10000
message = "default message"
try:
port = int(sys.argv[1])
message = str(sys.argv[2])
except Exception as e:
pass
app = Flask(__name__)
@app.route("/", methods=["GET"])
def getMessage():
return message "\n"if __name__=='__main__':
app.run(debug=True,port=port)
python main.py 10001 "This is version 1"
python main.py 10002 "This is version 2"
[]# curl localhost:10001
This is version 1
[]# curl localhost:10002
This is version 2
先决条件。
wget https://openresty.org/package/centos/openresty.repo
mv openresty.repo /etc/yum.repos.d/
yum -y install openresty openresty-resty
systemctl enable openresty
systemctl start openresty
ln -s /usr/local/openresty/nginx/conf /etc/nginx
ln -s /usr/local/openresty/nginx/logs /var/log/nginx
mkdir /etc/nginx/conf.d
export PATH=/usr/local/openresty/nginx/sbin:$PATH
vim /etc/bashrc
...
...
export PATH=/usr/local/openresty/nginx/sbin:$PATH
vim /etc/nginx/nginx.conf
http {
...
include /etc/nginx/conf.d/*.conf;
}
vim /etc/nginx/conf.d/canary.conf
#map $http_upgrade $connection_upgrade{
# default upgrade;
# `` close;
#}
upstream v1{
server 127.0.0.1:10001;
}
upstream v2{
server 127.0.0.1:10002;
}
server {
listen 80 ;
server_name tools2online.com;
location / {
proxy_pass http://v1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
#proxy_set_header Upgrade $http_upgrade;
#proxy_set_header Connection "Upgrade";
proxy_http_version 1.1;
}
}
nginx -t
nginx -s reload
[]# curl http://tools2online.com
This is version 1
Lua脚本写起来有点不寻常。我们将尝试一步一步地实现lua。
- Nginx配置
- 通过lua块配置 *似乎proxy_pass被lua块覆盖了
- 在lua块中创建函数 *it import script from hello.lua on dir $prefix/conf/lua/.
- 在lua文件中创建函数 *lua块可以被写成文件
- 测试随机数
- 设置上游 *有可能以随机方式分割流量。不建议这样做,因为它可能会导致不一致的http响应。 1.websocket 2.资产 3.同一个用户,两个浏览器标签,显示不同的版本。
- 基于http cookie的上游路由 *金丝雀的最安全策略是使用cookie(仅限http),它可以从后台控制某些用户是否会在金丝雀组中。
- Lua从redis中读取json *在上一个例子中,上游是硬编码的配置。它有可能从redis上进行二进制配置。
总结
在这篇文章中,我们证明了在特定情况下使用canary和openresty是可行的,比如保护你的VIP用户不受部署后错误的影响。有些人建议用Nginx Proxy Manager代替openresty,以方便配置管理。也许这可以改进为两个不同的路径。首先,从NginxPM更新redis。第二,将数据从redis迁移到NginxPM数据库。但它应该比redis慢很多。
,