#网络安全#一行代码引起的协程泄露( 二 )
不出所望依然是过了一两周 , 问题又来了 。。
暂时是最后一次猜想这次是大半夜突然连续出了两三次 , 而且出的频率还特别高 , 迁移了实例后过一两个钟又会有实例协程泄露 。 所以恰好发现 , 所有会造成突然协程泄露的操作 , 都是调用了一个写数据的接口导致的 。 把接口来回看了好几次 , 硬是没看出问题 。 但是我意识到一件事 , 这个接口调用了三次db , 而我设置db查询/写的超时时间是3s , 而上游却过了10s才熔断 , 那么按道理来说应该是9s后会超时 , 感觉到了事情有一点不对 。
所以再一次协程泄露时 , 我暂时没有迁移实例 , 而是爬上了实例查看实例日志 , 发现某一行debug日志并未执行 。 看来问题已经缩小到某几行代码了 。
没错 , 我在开始怀疑gorm框架有问题了 , 看起了源码 。 发现我们实现查找最大值的代码很神奇 , 竟然是拿了rows
。 代码如下 。
乍一眼看 , 貌似没啥问题 , 看一下next
的源码 , 在没有下一行数据时 , 不会将rows close
掉 , 代码如下 , 代码来自go 1.13.4源码 , 只有中文注释是自己加上的:
咦这个不close
真的不会有问题吗? 我们再看看这个rows
是从哪里拿出来的 , 没错线程池 , 那么不close掉是不是会导致这个线程不会放回去线程池里呢? 我们看看close的代码 , 代码如下:
事实上 , 应该是的 。 所以事情到这里应该是已经解决了 。解决完的代码如下:
但是实际上取max值只会有一个值 , 为何会使用rows而不使用row呢?不得而知 。 因为根据go源码来看如果这么写的话是不需要自己去close掉线程的 。
还有另一个问题是 , 为什么会两周一次呢 , 算一算 , 实例差不多有15台 , 而进行这个查max的操作只有在申请某个配置的时候才会触发 , 而线程池里有10个线程 , 所以在假设请求是均衡的情况下 , 要申请100+次才会开始命中这个问题 。 而且也只有db线程数不够的机器才会出现这种问题 , 再加上这个服务已经相对比较稳定了 , 很久没有怎么加过需求了 , 所以容器不会重启 , 内存不会重置 。 至于GC到底能不能把解决这个问题呢 , 应该是不行的 , 因为解决了只会让你的线程数减少 。
哎 , 真的是菜 , 定位问题都那么难 。 主要还是没啥经验吧 , 所有接口都报错了 , 一开始无从下手 , 直到某天凌晨给报警电话打醒 , 才突发奇想去定位这个问题 。
内存全表存储设计为什么要设计用内存呢?首先 , 表不多 , 其次 , 数据也不太多平均每张表也就5k , 而且 , 由于并不希望上游每次拿数据都需要请求这个服务 , 所以需要扫表 。 基于以上原因 , 该服务是没有用redis做缓存的 , 服务设计如下 。
这样设计的优缺点是什么呢优点:
- db压力小 , 数据量不多的情况下扫表问题不大 。
- 当上游服务多时 , 实例充当了一个redis , db没有来自上游的请求压力 。
- 没有序列化和反序列化的时间复杂度
- 开发成本高 , go没有泛型 , 为了减少序列化 , 代码写的比较暴力
- 更新效率慢 , 取决于数据轮训的时间 , 适用于不需要及时更新的数据
服务设计是挺不错的 , 就是开发起来特别恶心 。
还是自己太菜了 , 多学点东西吧 。
推荐阅读
- 『程序员』装出新高度! 程序员用代码写招租广告只因不想与其它行业人士合租
- 【网络安全】你还在浏览“黄色网站”吗?当手机有这几种现象,你就该停手了
- 路飞写代码|浪潮也难以逃脱限制,自主自研迫在眉睫!美国科技霸凌背后的“获利”浪潮也被美国进行断供更大的风暴还在后面写在最后:,中兴、华为之
- 灵锦文化|网络安全需求有望进一步加速释放,《数据安全法》出台
- 『』公司新招架构师,同事让他写代码被怼:我不写代码的,结果愣住了!
- 黑客@2名顶级黑客轻松“入侵”支付宝,转账完成后1秒,屏幕弹出一行字
- 点点雨落山岚|人才增长超20倍,月薪过万,马云再次“神预言”:又一行业大火
- 『马云』马云又一预言成真?这一行业太火,人才需求暴涨20倍,月薪超万
- 老盖聊技术|批处理bat转换为exe,dos脚本代码加密,bat转exe软件图文教程
- 产业气象站|代码人生丨C++程序员容易走入性能优化误区!对此你怎么看呢?