当年 1.6 亿美金估值的公司—— Digg 是如何被一句 Python 函数可变默参 毁掉的

2018-07-03 16:18:14 +08:00
 est

https://lethain.com/digg-v4/

太戏剧性了。画重点:

2011 年,Google 推出「 Panda 」 机制动摇了很多老的 SEO 手段,digg 流量被腰斩。推出 DiggV4 作战计划。经过紧张的开发发布,不过访客页面没问题,已登录用户打不开 MyNews 页面。开发不得不用临时手段把登录用户的默认页面改成 TopNews

MyNews 只能通过不断重启进程才能短暂修复。初期以为是 cassandra 的缓存击穿了 memcache,后来加紧用 redis 重写了,还是得几个小时重启一次

(折腾了一个月之后)

终于发现原因了:API 服务器是 tornado 写的名字叫 Bobtail。里面最常用的函数是:

def get_user_by_ids(ids=[])

然后这个 ids 就一直被 append 直到撑爆内存

所以这个 MyNews 功能也渐渐用的人少,因为没法定制化看新闻,后来,大家都不去 diggv4 而去 reddit 了。。

后来,digg 以 50w 美金被别人收了。。

作为这次 digg v4 事件的受害者,觉得太神奇了。。

20674 次点击
所在节点    Python
80 条回复
PythonAnswer
2018-07-03 21:04:30 +08:00
迪哥用户报道。原来经常过去挖土豆
Ehco1996
2018-07-03 21:12:20 +08:00
@monsterxx03 我最近也遇到了 celery 内存泄露的问题,也还在排查,我怀疑是用了 pyopenssl 导致的,今天晚上实验一下。话说你的问题排查出来了么?
monsterxx03
2018-07-03 21:25:53 +08:00
@Ehco1996 你用的什么版本? 我的是 4.2,问题查出来了,可以看下我这个 pull request https://github.com/celery/celery/pull/4839,我这个只能算临时 fix, 那段代码本来就不会被执行,官方 master 上还没修,但确认了这个问题,估计会在 4.3 里修,我碰到的这个问题,只会在插入 task 的进程里发生泄漏。4.x 问题都蛮多的,如果你用 redis 做 broker 的话,还会碰到其他问题
liuxey
2018-07-03 21:40:22 +08:00
@tabris17 谢谢,你这么一说就非常清楚了
wwqgtxx
2018-07-03 22:06:01 +08:00
@monsterxx03 没看出来你#33 的代码为什么会导致内存泄漏,能否解释一下
yangqi
2018-07-03 22:07:17 +08:00
有点标题党,最后总结是他们发布新版本太仓促了,没有经过详细全面的测试就发布,而且没有回滚计划,所以出了问题只能硬着头皮上,这才是最大的经验教训。至于 bug, 任何软件都会有的。
menc
2018-07-03 22:11:25 +08:00
@wwqgtxx 循环引用,counter 不可能为 0,就不可能被 GC 掉,造成内存泄漏
wwqgtxx
2018-07-03 22:15:13 +08:00
@menc cpython 的 GC 早就可以解决循环引用的问题了,都什么年代了
swulling
2018-07-03 22:23:01 +08:00
这种超大 Object,随便就分析出来了啊,Python 的内存分析工具不要太多
monsterxx03
2018-07-03 22:32:23 +08:00
@wwqgtxx 循环引用是不会造成内存泄漏,前提是没有同时重载__del__, 这会导致 mark and sweep 机制在回收对象的时候,不知道以什么顺序去执行对象的__del__, https://docs.python.org/2/library/gc.html#gc.garbage

这里如果尝试想用 weak.ref 去修的话还会碰到另一个坑,weak.ref 对 instance method 不起作用,解引用永远是 None, 需要 python3.4 里的 WeakMethod
falcon05
2018-07-03 22:59:50 +08:00
老实说 Python 这个特征挺反直觉的.
joyqi
2018-07-03 23:11:52 +08:00
居然只卖了 50w 刀。。。
wwqgtxx
2018-07-04 00:51:07 +08:00
@monsterxx03 那么为什么不看看 py3 的文档呢
Changed in version 3.4: Following PEP 442, objects with a __del__() method don ’ t end up in gc.garbage anymore.
ofooo
2018-07-04 06:38:09 +08:00
3/2=1 你们觉得反直觉不?
数组从 0 开始查,你们觉得反直觉不?
cf472436288
2018-07-04 09:12:26 +08:00
广州天河东圃诚聘 python 工程师,主要负责公司后端服务系统的开发工作,12-20K,双休。欢迎加我微信:cf472436288.谢谢!
Marmot
2018-07-04 09:26:52 +08:00
可变参数做默认值本来大多时候都是错误,很早就明白这个开始避免了
Ghayn
2018-07-04 09:29:10 +08:00
ruby 没有这样的问题
# test.rb
def test(args=[])
args.push(1)
p args
end

test()
test()
test()

-> ruby test.rb
[1]
[1]
[1]
deepreader
2018-07-04 09:29:11 +08:00
我就得题主就是断章取义。读了下原文,作者发现了这个 bug,然后很快就修好了,然后成功地 launch 了。
est
2018-07-04 09:37:00 +08:00
@deepreader

> It really was limping though, requiring manual restarts of every process each four hours. It took a month to track this bug down, and by the end only three people were left trying.

断章取义?
deepreader
2018-07-04 09:44:36 +08:00
@est Sorry,我理解错了。整体这篇文章还是相当棒的。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/467817

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX