学习了,感谢大佬分享!
线上问题排查不容易!
可以试试 stack profiler,rbspy,vernier 之类的。
https://github.com/yfractal/sdb/pull/4 可以查看 http 了,同样不需要 root 权限。
sorry, I don't know the answer. Maybe need to ask Rust2go's author. I guess it's much faster than Thrift or Protocol Buffers as it doesn't need deep copy except go returns variable to rust. I think this copy can be avoided too, if Go can keep an additional reference of the variable and let Rust release the reference when it is dropped.
I believe this is achievable, this article introduces similar things
https://metalbear.co/blog/hooking-go-from-rust-hitchhikers-guide-to-the-go-laxy/
哈哈哈,是的。
多跟你身边的人聊聊,大公司人多,有技术好的人概率更大,看看他们怎么看待后端开发,框架是后端很小的一部分。
做 Rails 的,多数是小项目。全栈,确实开发更快。但项目复杂、难度大的项目,能把后端的事情做好的程序员都不多,更别说再做前端开发。
Github 这种服务,三天两头挂。。。
有利有弊,听老板的。
需求需要技术支撑,有的时候,需求在现有的情况下,不那么合理,就需要需求让步。所谓的 trade-off。
选用 ES 一个主要原因是性能。数据库 like 扛不住了,或者不想影响其他查询太多,所以才上 ES。ES 简单的找找文档就能搞定,真正优化什么的,就需要深入研究。
技术影响需求,到了一定阈值,甚至决定了需求。比如延迟超过 10s,这个就不仅仅是技术问题,而是需求问题了。
技术是工具,或者说是手段,不是目的。
之前的 leader,说他刚来的时候,技术上还会管管我们。之后我们都进入角色了,技术就不怎么需要他了。这个时候,他主要任务是忽悠产品,砍需求,在技术和产品之间找平衡。以及教育他的领导没事少管闲事,这个是他的领导在全体会议上说的。
说事就说事呗,抒啥情啊。。。说了一大堆,观点不明确,数据也没有。。。
还不如找个算命的聊聊天,或者看看成功学找找自我安慰。
神烦这种,指点人生的人。
lead 这个项目的人有博士学位,之后一直做 compiler 相关的工作。
这个 id 都是从一个 Redis 里拿。
哈哈哈哈,Redis 这种太粗糙了 只试用与可用性要求不高,还可以重试的场景。
线上跑的单机,偶尔并发高会出现重复 id 插入失败
多线程,需要锁。
这对数据库查询性能是不是有影响
没影响,数据是大体离散的。除非有非常特别的 query。
要不用 Redis INCR key 算了。Redis 单机性能可以 6w+,够用了。如果这个的 qps 10w+,当我没说。
一些有趣的问题
先说我的想法,如果 fork 频繁的话,有可能会影响性能。
首先这个是针对 low delay 的 request,比如 20m 这种,而且也只是猜测。然后,我觉得这个大概率会被打脸,毕竟 Shopify 有很多优化经验。但技术吗,要抱着怀疑的态度去看,要大胆假设,小心求证。打脸了也是次学习的机会。
下面会先介绍一下我对这个 Gem 和相关问题的理解。为什么会觉得有性能问题,压测以及有的没的。
因为一般 web server 都是无状态的,所以很容易横向扩展。流量一台扛不住,我就再加一台。如果一个 app server 需要内存 2GB,我们搞两个,就需要 4GB。但实际上,这两个 sever 跑的代码是一样的,那么共享代码占用的内存,就可以省很多的内存。比如从 4GB 降到 2.2GB。而操作系统刚好提供了 copy on write(COW)。
操作系统在 fork 进程的时候,不会 copy 物理内存,而是只写一个新的 page table,物理内存是同一份。当某个进程改内存的时候,就需要 trigger page fault exception,操作系统处理这个 exception 的时候,要 duplicate 一下内存,以及改 page table 的映射,之后回到抛异常的指令,再执行一次。这个就是 cow 大致的工作原理。
看起来,我们 fork Ruby 应用,就可以省很多内存,但实际上并没有,因为 Ruby 应用在运行的时候,会改很多的内存(我还不知道啥原因,Ruby 是解释型语言,代码应该是丢在 data 那块的,可能跟 GC 之类的有关),这样导致被共享的内存越来越少,内存也越用越多。
pitchfork 的解决方案是隔一段时间,回收进程,然后再创建新的。
我们知道,随着 Ruby 应用的运行,被共享的内存越来越少,如果为了省内存,就不能太久 fork 一次。但 fork 对性能是有影响的,如果频繁的 fork,虽然省了内存,但会影响性能。或者说,我们要知道,多久 fork 一次,会省多少内存,以及对性能有什么样的影响。
pitchfork 压测用的参数是 refork_after [50, 100, 1000]
,我们这里先按照,当一个进程,处理了 50 次请求,就会重新 fork 一次。
假设一个请求是 20ms,50 次请求,共消耗 1000ms。然后回收这个 process 再 fork 新的。假设应用消耗 2GB 内存,在这 1s 内,需要写 200MB 的内存。
现在我们来看,系统需要多少时间进行处理。一个 generation(回收旧的,fork 新的),系统需要做的事情有,回收进程,fork 新进程,以及处理 page fault。
fork 新进程根据下面这个图 [1],fork 2GB 的进程大约需要 10ms。回收进程,虽然系统会用 lazy 来处理,我们可以假设这个会分担到每个 generation。回收进程消耗的时间要比 fork 多,因为 fork 只写 page table 但回收进程的时候,要擦掉非共享内存里的内容,所以要大于 10ms(这个地方,八成是错的,因为系统这块似乎也有优化,似乎是没有 0 的 table 才会去擦除)。
现在我们来算 page fault 产生的影响。根据假设,一个 generation 需要写 200MB 的内存,一个 page 是 4kb(咱不考虑什么 huge page,这个应该是全局的设置),每次 page fault 需要 0.0023s,依旧是需要 200 mb * 1000kb/mb / 4kb * 0.0023 = 111.5 ms。
那么系统上要消耗大约是 1 - 1000 / (1000 + 111.5) ~ 10%
这种算法有没有问题?有。比如 50 次请求,只多了 10MB 的内存,那损耗可能只有 1% 左右。再或者,系统处理 page fault 时有优化,比如做了 batch,那就会更快。再比如时间数据是有问题的。等等等等,都影响结论。所以需要具体 benchmark。
这里不是说会有影响,而是说,经过分析,发现有可能有影响,所以需要 benchmark 来验证。
第一个变量是多久 fork 一次,需要给不同频率的 fork 对应的内存使用。最好用比较真实的项目和比较真实的流量,比如 RubyChina。最后还可以有就是做长时间压测。
第二个变量是性能影响。一个是系统多花了多少时间,p50,p99 的延迟。
这个 Gem 毕竟刚开始开发,相信之后会有人给出更详细的 benchmark。
个人比较好奇,为啥 Ruby fork 后,随着进程运行,会有内存的问题。以及为啥不好在 Ruby 层面改。和有没有其他解决方案。
这个可能有用 The Internals of PostgreSQL https://www.interdb.jp/pg/index.html
很久以前做的,找不到了。。。不过可以在 github 搜一下 6.824
我做了 mapreduce 和 raft 的部分实现。Golang 写复杂的并非程序太难受了 :facepalm:
conditional variable + pthread_kill?
只有 thread a 可以改那个 thread variable,其他 thread 执行完了,等那个 conditional variable
pthread_kill 干掉执行一半的 thread。
假设 A 先执行完,那么其他线程就立即结束
这句话我没理解。。。是说 B,C 先执行完的话,要等 A?没先执行完,就要被马上中断?
想为 user level thread 实现抢占式调度,应该有不少办法。
user-programmable schedulers
Kostis Kaffes Syrup: User-Defined Scheduling Across the Stack. SOSP ’21.
Towards User-Programmable Schedulers in the Operating System Kernel https://www.pure.ed.ac.uk/ws/files/265136338/Towards_User_MVONDO_DOA04032022_AFV.pdf
没具体看,似乎是相关的东西。
Andrew Huberman 的 podcast 挺有意思的,neuroscientist,讲 neuroscience 相关的知识,可以在油管上搜。
人是会成长的。
刚开始学写代码,有可能会觉得,Ruby 这么写可以,那么写可以,真神奇。写多了,发现状态,继承确实让代码少了,但直观吗?再然后,可能会发现,代码整体的合理,比局部的简洁重要。之后是设计,做什么,不做什么,让哪个服务/部分做,设计好了,如何描述,问题都不大。
对我个人来说,最大的好处是逼迫我把问题想清楚。想不清楚,肯定写不出来。当然也有别的方法,比如和人讨论。
再一个是反应技术能力。我面试过的人中,有两位本来面试表现的并不好(只是表现不好),我犹豫要不要 fail,但发现文章写得不错,最后就通过了。
全栈的里面目前来说最优的