背景问题
公司需要对用户的行为做分析
所以在服务端上通过 HTTP 的方式上报数据
想要将上报数据的网关容器化了
方面以后的维护和管理
因为节点少, 相对于 K8S 来说太重了.
所以准备尝试一下 Docker Swarm
没想到在测试环境没问题, 一上生产.
结果立马出现了一大堆上报失败的错误
吓的我立马回滚了操作, 再慢慢来排查.
我们是游戏研发公司, 需要和不同的发行商合作运营
而且很多发行商要求使用自己的服务器(毕竟自己控制更可靠)
所以就出现了这么一种情况
业务不大, 但是不同云厂和区域的服务器不少.
并且我们使用 SaltStack 来管理主机的信息.
从主机的注册到作业的执行, 基本上是这样的
1 | salt-master<----->nginx-stream<----->salt-minion |
这里为啥使用 nginx-stream, 而不是 salt-syndic
主要是因为简单, 稳定, 而且 salt-syndic 无法针对单个 minion 下发 job
把 nginx 部署在docker swarm
上
有一个区域就添加一个docker worker
, 然后自动的部署上去了
大概的思路是这样的, 然而在部署好了后使用salt 'h72g9g19vr391.qcloud.hk' test.ping
有时正常, 有时却返回超时
突然被抓来协助大数据的上报网关(OpenResty)
client -> OpenResty -> Kafka -> ClickHouse
这里的 OpenResty 负责数据的兼容, 过滤, 路由
因为需要经常的修改 OpenResty 的逻辑配合数据分析这边的需求
导致改动容易出现问题, 需要搞个测试环境.
通过测试环境的验证后, 在更新到正式环境
实施方案是使用 nginx 的 mirror 模块将请求镜像到测试站点.
同样的代码和配置, 通过环境变量来区分生产和测试环境
大概是这样的.
1 | (不返回client) |
那么问题来了
在实施中, 请求主站点时, 镜像站点也能收到请求
但一直显示status_code 400
, 从表现上来看像是 POST 的数据丢失了.
在 nginx 的 log_format 把$request_body
参数加上, 发现确实 POST 数据没有.
1 | 172.19.0.1 - [08/May/2020:06:35:09] "POST /user_login HTTP/1.0" 400 419 "-" |
我们是一家 H5 的游戏公司
客户端以网页, 小程序, APP 的方式发布
对 CDN 的请求非常的大, 所以 CDN 请求的影响是非常大的.
其实一开始是想放在 服务端业务异常日志监控 一起讲的
然而因为这里有一些情况不太一样, 细讲起来差异还挺大的.
所以这里就拆开单独写了(真的不是为了凑数!!!)
elasticsearch, 存储检索
logstash, 上报格式转换
kibana, 统计展示
openresty, 上报网关
(和”隔壁”的架构差不多, 只是用 openresty 替代了 filebeat)
看图…
Ask 是 K8S 的一种特殊扩展, 它屏蔽了 node 层, 按 pod 收费.
这样可以实现低成本和弹性扩容, 在大规模的伸缩中极大的增加了效率和降低了成本
弹性扩展, 用多少算多少, 听起来确实很美好.
Ingress 本质上是一种抽象, 顾名思义, 就是所有请求的入口, 可以对请求进行控制和验证
常用的是 nginx 实现的 ingress, 通过规则映射, 将站点信息抽象各位一个个的匹配规则
接着, 我们有一个前端打点上报需求, 准备用阿里云的 ask 来做.
只是一个很简单的通过 http 请求将数据上报至阿里云 SLS 的服务.
没有状态, 存储之类的需求, 所以用 golang 写了一个简单的 api 来解决.
万事俱备, 等待数据, 然而研发同学说不太对劲.
业务需求要通过事件触发, 来实现两个 table 的数据合并.
理清了需求和思路并思考下扩展, 记录下来, 用于分享和沉淀.
因为用 lua 写的业务, 所以这里用 lua
实现的.
PS: 在 lua 里 table 和 hash 的结构类似
1 | local a = { |
1 | function table.merge(dest, src, cover) |
1 | { |
你看我想将 table B.a.aa.aaa 的值合并到 table A.a.aa.aaa
但是直接用 table B.a 将 table A.a 的值给覆盖了
所以这个函数只能用于一层 hash 函数的合并了
1 | local a = { |
1 | function table.r_merge(dest, src, cover) |
1 | { |
table B.a.aa.aaa1 追加到了 table A.a.aa 里面
table B.a.aa.aaa 覆盖了 table A.a.aa.aaa
table B.b.bb 覆盖了 table A.b.aa
table B.c.cc.ccc 覆盖了 table A.c.cc.ccc
一层合并和递归合并都不灵活
所以需要有一个提供给调用者想要合并层级的函数
1 | local A = { |
1 | function table.r_merge(dest, src, cover, depth) |
其实我不喜欢这样的函数.
因为在调用的时候就要明确的知道层级的范围是多少.
也就是说层级前和层级后的数据是不同的.
这种结构的不同是隐性存在的.
需要调用者自行把控.
1 | { |
table A.a.bb 添加到了 table A.a
table B.aa 覆盖了 table A.a.aa, A.a.aa.xxx 没有了, 去哪了? ^.^
table A.a.bb 还在 A 里乖乖的呆着.
table B.b.bb 覆盖了 table A.b.bb
table B.c.cc 覆盖了 table A.c.cc