[大神答疑]蛋疼的axb-微博技术专家

/ 转载 / 没有评论 / 501浏览

V2EX:

Q:怎么做到增加机器能线性增加性能的? A:线性扩容有两种情况,一种是“无状态”服务,比如常见的 web 后端;另一种是“有状态服务”,比如 mysql 这种数据库。

对于无状态服务,一般只要解决了“服务发现”功能,在服务启动之后能够把请求量引到新服务上,就可以做到线性扩容。常见的服务发现包括 DNS 调度(通过域名解析到不同机器)、负载均衡调度(通过反向代理服务转发到不同机器)或者动态服务发现(比如 dubbo ),等等。

对于有状态服务,除了要解决服务发现问题之外,还要解决状态(数据)迁移问题,迁移又分两步:先是数据拆分,常见的都是用哈希或者一致性哈希把数据打散。然后是迁移,常见的办法有快照和日志两类迁移方式。也有一些数据库直接实现了开发无感知的状态迁移功能,比如 hbase。


Q:代码优化,从哪些方向入手 A:代码优化分为几个层次。

初期的优化主要集中在功能上,不写 bug。 然后是鲁棒性,在异常情况下不写 bug。 然后是性能,提高系统吞吐量,或者执行降低延迟。 然后是可维护性,在团队开发过程中降低其他人的理解难度,再做好一些,通过设计做到模块解耦,降低删除无用代码的难度。 然后是可扩展性,能够预测系统或者业务的发展方向,提前设计好锚点,让系统能够通过扩展而不是修改的方式增加功能。

再往后就是各自的境界了,我至今也还没参透……


Q:做「你关注的某某人评论了某某人」之类的和几度人际关系相关的复杂功能的时候有没有遇到哪些性能上可能的问题 A:这肯定是有性能挑战的,比如“你关注的人也在关注”、“你关注的人最近发的微博”等等,都可以理解是二度关系。主要挑战点是数据的扇出量会比较大,我关注了 1000 人,这 1000 人又每人关注了 1000 人,那就是要 100 万的数据做处理。解决办法要么是减少扇出(比如限制关注人数量),要么是离线算数据,在线取结果。


Q:视频存储和提供有什么难点嘛,常年 mysql 中 varchar 选手想了解下 A:视频存储和播放难点要分开说。

对于分布式文件系统来说,有几个难点。 一个是文件大带来的执行效率,比如用户上传一个 10G 的文件,要 1 秒之后立刻能够访问,需要做一些性能优化的策略 一个是可用性,在某台机器宕机之后不能影响用户数据,需要有数据迁移和冗余的策略。 一个是文件多带来的元信息膨胀,分布式文件系统都要保存每个 key 的元信息(比如存在哪台机器上),当文件超过几百亿之后也会带来元信息存取的压力。

而播放一方面是整体缓存架构和调度策略的选择,另一方面的难点主要是对于网络(在目前场景下,主要是 tcp 协议)的理解、对协议(比如 http/http over quic )的理解和策略的选择。

当然,在国内 isp 环境下,更多的还是与人斗,其乐无穷。


Q:分布式事务这块是怎么处理的呢?是由业务系统去做一致,幂等之类的保证吗?还是有统一的中间件或框架呢? A:微博这边的一致性要求并不高,一般是通过幂等性和常规的乐观、悲观锁实现的,分布式事务(至少在我这里)用的不多。


Q:在系统或功能模块设计阶段是如何考虑系统的扩展性的呢?是快速原型,实现,上线,后续迭代升级,还是说会在一开始就做一些复杂的设计?在这方面是怎么作取舍呢? A:设计阶段要考虑的首先是“系统哪些功能是必不可少并且需要快速验证的”,然后是“系统 2 年以内有可能会有什么变化”,觉着不好设计的原因还是设计少了,踩的坑不够多。经验多了,就没这类问题了。


Q:视频类的后端开发和其他图文为主的社区产品后端开发,架构、技术选型上有哪些不一样的地方 A:从整体的角度来抽象看,要做的东西其实差不多,都会有增删改查,然后内容理解+推荐;视频特殊一些的地方是有视频编解码。 具体技术选型来说的话,业务上的增删改查都差不多,但是视频存储都是对象存储服务而非关系型数据库;视频方向的内容理解更多的偏向深度学习的实现;视频编解码是一门独立的专业,不过由于太耗计算资源所以还要配合着调度系统一起实现。


Q:怎么做才能做到不同地区,用户播放视频都比较流畅?会用到类似 CDN 的部署架构? A:如果往深了说,流畅是几方面的综合结果,包括视频体积、CDN 部署、播放调度、防劫持、播放调度、防劫持等等。

对于你说的不同地区来说,最重要的方面有两个:一个是 CDN 部署和调度情况,尽量让用户访问边缘节点;然后是防止劫持,一般流量被劫持后都不可避免的性能变差……


Q:应用服务器的数据库连接池应该设多大?看了一篇译文 jianshu.com/p/a8f653fc0c54 的观点是"连接数 = ((核心数 * 2) + 有效磁盘数)", 不知道实际一般是不是这样计算 A:我没太看懂你的问题,到底是数据库服务的连接池,还是应用服务连接数据库的连接池?文章里我简单扫了一眼,似乎是后者

不过无论哪个连接池,核心问题还是“同一时间内,需要同时请求的数量”,这个其实就是个数学公式,类似“这条路上每天要跑 1000 辆车,每辆车跑个来回要 10 分钟,那么路建多宽合适”。按我的经验,连接数多设一点不会有太多问题(除非设的数量太夸张把系统连接数耗尽了),而设少了,在系统负载变高的时候就会出现非常明显的排队现象,这对服务性能的影响更大一些。


Q:有使用 K8S 应用的案例吗,比如说用在数据库扩容上面 A:我的团队应用 k8s 更多的是在线下或者半离线业务场景下,做后台系统或者一些非实时任务。用来降低整体计算成本。至于线上业务,k8s 的能力还不足以让微博这种体量的公司开箱即用,这个改造成本也会比较高。


Q:老板好,正文描述的几个系统主要是用什么技术栈构建的呢?能谈谈当时技术选型的取舍吗? A:语言 Java 用的多,好招人;框架分场景,比如做消息推送服务就用了 netty。取舍:尽量好招人的技术栈。


Q:处理高并发有哪些难点?以前感觉这块挺神秘的,接触不到 A:能用缓存就用缓存 考虑并发场景下的一致性 在框架里做好断路器和保护机制 做压测和容量预估 加机器-.-

要做高并发,还是要有场景。这玩意就是个难者不会,会者不难的东西……


Q:大佬你现在自身的技术栈是怎么样的。3 年后端参考下。 A:我是属于那种“什么都会一点”的技术专家,如果单独说技术栈的话就太多了,列不下来。

换个回答方向,说一下我认为自己的技术强项吧。

一个是系统设计能力,能够设计微博这种用户和流量规模的后端服务。 一个是对操作系统、网络和 VM 的理解,能够排查复杂性能问题。 一个是业务方面的能力,包括通讯直播视频和社交媒体相关业务和对应技术(消息推送、视频编码、文件存储,等等)

总结下来的话,就是基础知识+架构经验+领域知识吧。


Q:微博有 golang 这块应用吗? A:微博的部门很多,每个部门情况不一样。在我这边有一部分 golang 的线上应用,也有一部分管理系统用的是 golang。


Q:很多公司要求的大数据高并发经验,在小公司工作的机会永远用不到的如果才能通过这种 offer A:分两方面说,很多地方招聘(包括我这边)虽然更倾向于有高并发经验的人,但是这也不是个绝对的必选项。我的判断条件是“是否达到了所在平台的天花板”和“是否有持续进步的潜力”,大部分情况下,能把当前工作搞的很好的人,也能把高并发搞的很好。

另一方面,我一直认为能去大厂还是尽可能的去大厂,毕竟大厂能带来的经验和提升很多小公司确实没有。通过自学能储备一些知识,网上的教程也有不少,不过经验的差距很难解决。

简单来说,把自己想象成应届生,工作几年没有高并发经验和应届生没有工作经验面临的状况是类似的。


Q:一个合格的 5 年后端要具备哪些能力? A:这问题有些宽泛,一线互联网公司的五年跟不知名公司的五年,完全不是一个概念。

我只说一线互联网公司的五年,基本上应该是小组长,能够独立设计日活百万级别的后端系统架构,在开发规范和效率方面能够指导初级工程师和工作。此外还有复杂问题的分析和解决能力。


Q:请问 估算一个对象的大小,这问题意义在哪? A:没看懂你的问题,是说 jvm 里的大小还是序列化后的大小?前者一般是面试的时候考查对 vm 的理解,后者是缓存容量评估。


Q:你们团队有测试开发吗?如果有,请问他们都做些什么工作?他们的技术栈大概是怎么样的? A:测试是另一个团队,他们做的事情是写测试框架、搭测试系统、写测试用例。 技术栈跟普通开发差不多。


Q:以前一直用 c++ 做游戏, 现在想转互联网后端, 做 Go 或 Java, 但是投了简历一直也没消息, 互联网的那些技术栈也比较难实践, 有啥好的方法么... A:先用 go 或者 java 做点实际的东西出来,比如我之前团队有个小伙之前也是用 C++,投我这边 Go 的职位。他业余时间用 Go 做了个 V2EX 的客户端,当场就要了。


Q:如果想重试大数据开发的话,平时应该多关注哪些技术栈呢,从服务端开发转过去有哪些地方需要了解提升的 A:大数据开发这个职位挺缥缈的……我不清楚你说的大数据开发是指的数据分析、数据中间件、有大数据场景的后端应用还是什么别的。

第一个,一般就是流式处理框架,Hadoop 全家桶之类的数据处理框架。 第二三个,跟普通后端开发没啥本质区别。


Q:.用户的关注列表分页拉取时,如何把正在直播的主播前置到列表 A:假设正在直播的主播不多,可以单独存正在直播的主播,插到关注列表前面。


Q:主播的粉丝量很大时,开播如何及时推送给粉丝 A:1 想办法并行取粉丝关系,并行推送 2 优先推送核心用户 3 改成拉取模式,实时获取当前主播的直播状态


Q: 应届生如何提高自己?看书总觉得是一个个点,学的技术很杂,前后端 /移动 app 都会一点,无法系统地整合。

A:多实践,找个有点难度的问题解决,实践一段时间再回过头来看书,会有不一样的收获。


Q: 请问一下,假设一个集群里 a,b,c 三个服务(或者叫应用)都依赖于 d ( v1.0 )这个服务,现在需要把 d 这个服务,从 1.0 升级到 2.0。

目前我的操作流程是额外开一台机器用于跑 d ( v1.0 ),然后把 d 的所有机器都升级到 2.0,然后把 a,b,c 三个服务都升级到依赖于 d ( v2.0 ),再把 d ( v1.0 )这台机器关闭。

感觉这么做很麻烦,而且也不自动。因为 a,b,c 都依赖于 1.0 版本,所以在整个升级过程,d 服务的两个版本,1.0 和 2.0 都是存在着的。请问能介绍一下你们的经验吗?我这里用的是 dubbo,每个服务各有两台机器运行着。

A: 这是个通用问题,解决办法是保持接口向前兼容。可以理解是先上 D1.5 版,升级完 ABC,再升级到 D2.0


Q: 专门请教下:后端扩容有什么好的方案和建议呢? 1,数据库变大,需要动态增加机器,怎样一种方案可以无感知增加? A: 要么是提前做逻辑分表,容量瓶颈之后把逻辑表做物理迁移。或者干脆用 hbase 这种天然扩容无感知的数据库。

Q: 2,数据量变大,查询效率如何维持? A: 提前做容量预估

Q: 3,老数据的删除,我们项目上有,不知道大佬的项目中怎么处理? A: 对 mysql 来说就是按月分表,定期删除过期表。对 hbase 之类的设个 ttl


Q: 大佬,在小公司里边想要进阶,有什么比较平滑且接地气的方法,适用于普通人的。

A: 尝试着站在领导的角度思考同一个问题,然后跟领导实际问你的问题做比较,逐渐建立起自己解决更高层问题的思考方式。


Q: 老师,您对于某些关于查询不允许 join 的规定是怎么看待的,微博现在也是这样的嘛?很多人都说在代码中处理,对于一些查询数据量较大,类似报表,统计相关场景,在代码中处理是不是不太合适?或者说还是采取分页查询进行处理?

A: 我们处理用户请求的服务是没有 join 的,对性能的影响太大。线下做报表当然需要 join……


Q: 再来一个,分布式数据库是如何进行数据同步的,对高并发大数据来说,除了主从复制还有其他方法吗?另一个问法就是有哪些可以参考的技术等等.谢谢大佬.

A: 要么类似 mysql 的异步主从,要么类似 hbase 冗余写多份。写多份的方案从简单的客户端多写,到通过共识算法达成一致都有,建议搜索引擎里直接列上几个数据库名字,比如 mysql hbase tidb,应该就能搜出一堆资料。


Q: 大佬你好,请教一个问题。 有两个百万条数据的表以及三张万以内数据表,取数据的时候不可避免要 join。 客户端可以自由调整日期,来查看数据。 因为表数据十分钟同步更新一次以及用户自由调整日期,感觉没办法做缓存。还有因为历史问题不能重建表结构。 现在每次查询都要 join 一次,导致查询数据很慢,要 10s 多,请问一下要怎么优化。

A: “有两个百万条数据的表以及三张万以内数据表,取数据的时候不可避免要 join”,如果能改表结构的话,把索引和内容分开存,其实百万级的数据全放内存里都没多少容量。如果非要 join,要么降低 join 的数据规模,要么提前算好数据,要么把能缓存的数据(比如那 3 张表)缓存起来,尽量降低查询时的磁盘消耗。


Q: 直播聊天室、弹幕、送礼物消息和特效展示这类消息群发,用到后端的技术栈是什么样的?

A: 最核心的是实现网络层推送的框架,比如 netty,其他跟普通后端开发没啥区别。


想问一下微博的 at 有针对性优化吗?比如我 at 一个朋友的号(几百粉丝的那种)和 at 一个大 V 的号(比如 @带带大师兄),他们 at 的提醒是同时收到的吗? 如果不是,可以在不透露具体机密的情况下谈谈这种系统应该如何设计吗?

是不是大 V,at 提醒都是立刻收到的,系统没有瓶颈,没必要限速。单个人 at 这种系统其实就是个简单的消息推送服务,网上一搜一大把。


Q: 一般线上出事故了,就是开会总结、发邮件改进流程之类的。类似这种的贵司有没啥经验之类的可以分享。 A: 总结发邮件肯定是少不了的,只是我不太信任流程,而是会想办法改进工具。

Q: 新功能提测之类的,是怎么个玩法,是各个功能特性分开提测还是一起合并了提测。另外比较偏向业务的, 单元测试集成测试这些要求怎样,还是会在合入的时候进行限制,不到一定比率不允许合入? A: 我们服务有一定程度的拆分,每天都会上线,所以冲突的概率不高。如果冲突了,那就合并测。单元测试有要求,但是最高就要求到 30%,再高维护成本成受不了。


微博:

架构师的基本功之一其实是算数,

比方说: 10亿个long型数据存到redis里大概要用多少内存; 每天1亿条long*2型存到数据库里,一年要占多少存储空间; 每天20亿次调用,每秒大概qps是多少;

架构师设计方案的时候需要做大量的数据量级估算,想要成为架构师熟练工,就需要能够几秒钟内算出这类问题的答案。

很多立志成为架构师的同学并没有刻意培养对数据的敏感度,做方案的大部分时间都浪费在算数上,甚至有的人跟我讨论架构的时候还要带个计算器


今天跟同事聊了一下他最近做的性能优化。

同事做了几个修改,大概结论是这几个修改“都提升了性能,但是不太好说什么提升了多少”。

实际上,性能优化有三个常见误区。

一个是过于深入细节,对整体性能把握不足,容易出现“花三天时间把某个函数执行性能优化了几百倍,最终整体耗时降低了不到一毫秒”。

一个是过度沉迷于技术视角,忘记了性能优化最终要服务于业务场景。容易出现“写了5000行代码,提高了一个每天调用量为5的服务的最大吞吐量”。

一个是把性能这个概念模糊化,一提优化必说性能。容易出现“我做这些不好说到底有什么收益,但肯定优化了一些性能”。

实际上,性能优化和数据分析是形影不离的两件事情,优化性能的前提是有明确的指标和完整的数据,指标里的延迟是延迟,吞吐是吞吐,避免模棱两可;整体指标和局部指标分开,避免抓小放大;数据一是一,二是二,不能凭空捏造。

在此前提下,把指标和数据作为性能优化迭代中的反馈,才能保证整体性能优化不跑偏,不绕远。

作为程序员,要敬畏数据。


前一阵读《架构整洁之道》一直在思考关于架构的事情,受益颇多。

如今的软件开发已经不再是传统的瀑布式开发模型:由上到下,层层分解,架构师设计,程序员编码,迭代周期以月或年计算。

互联网公司普遍采用的敏捷开发方式已经打破了这种分工,很多迭代是在架构师的注意力之外发生的,很可能一个明天要上线的简单改动就能破坏整个架构,大部分程序员其实已经承担了架构设计的工作,但却不自知。

而这种责任和认识不对等的情况造成了很多架构设计的不合理或者逐渐腐化的情况:架构师空有理论而不去实践,程序员埋头编码却不懂设计……他甚至都不知道自己可以做架构设计。

架构设计的核心目标也不应该只是“设计一个能扛多少万并发的分布式系统”,而是把架构作为一个持续的、多人参与的交付过程,在这个过程中把控迭代方向和降低开发成本。

架构师要解决的终极问题,一个是时间,一个是队友。


前段时间有个小伙伴找我聊天说最近一段时间一直在做需求没什么成就感:

虽然接口有每秒几十万的调用量但是写来写去就是那么些套路;

产品需求天天变搞得代码写的特别乱,很多需求都是前后矛盾的所以加了很多别扭的兼容,每次听到要再改需求就觉得特别“膈应”;

想做点什么有意思的事,结果时间都被各种细碎的需求和会议占据了,月底一总结忙了一个月没有什么收获。

本来觉得互联网公司里可以接触到高并发应该会很有意思,结果一年下来感觉也就服务上线的那一下比较有成就感……

因为在微博工作,所以我面试过很多很多很多希望“接触到高并发大数据”的求职者。包括我自己在内也一样,入职第一天听到周围的同事讨论着每秒上百万次的调用量,几十毫秒的响应时间,作为技术人员谁能不兴奋呢?

但是在微博工作了五年,设计了一个又一个高并发系统之后,回过头来看的时候,感觉高并发带给我的兴奋感已经不怎么强烈了。

那是什么原因让我一直窝在一线写代码而不是转向管理岗?

二十多岁的程序员特别喜欢并发、框架、协议、内核、中间件之类的名词,还有这些年的大数据、机器学习、VR、区块链之类的新技术。

在我不算长的十多年的编程经历里也学过很多很多新的技术,但是不管什么技术都只能维持一段时间的快感:大部分是浮于表面的技术本质没有变化,少数几个本质技术跟几十年前没有什么区别……

而对于“优雅的设计”的追求却一直能够带给我精神上的满足感:我一直在追求设计出高内聚、低耦合、易于扩展和维护的系统;代码简洁而高效,考虑周全又没有一丝多余,一切都是恰到好处的感觉:不仅能够应对当前的需求,还能够顺应这段代码、这个系统、这个组织,甚至于自己和这个行业的未来。

在形成了“追求优雅设计”的世界观之后,一切就都不一样了:

产品经理的每一个“膈应”的需求都是对自己优雅设计的挑战。

程序变得越来越灵活和抽象,细碎的问题渐渐变得不再需要改代码了。

未来每一次的修改都在自己的掌控中,三四年前的某个设计可能因为今天的需求而继续产生价值。

这是一种开了上帝视角的快感。


今天抽空思考了这样一个问题:假如有一个项目,期望是10天做完,做到第5天发现计划定的不准,预计可能要15天才能搞定,这个时候应该怎么处理。

常见的选择有降低标准、加人、加班或者延期。

降低标准看起来是可行的方案之一,所有的程序员应该都经历过“先保进度,凑合着上一版,之后再改造”,但是大多数改造最终都不了了之:真正改造的代价实在是太大,以至于要拿出数倍于第一遍开发的时间与人力把整个项目推倒重来一遍。即使这样,被改造过的项目也很大概率会带着之前错误的痕迹难以消除,不停的消耗后续开发人员的精力。

同时,质量标准又不像进度那样可以量化和快速反馈,很容易就把重构一拖再拖,标准一降再降,等到发现质量问题时,基本标准已经降无可降了。这不仅是对某个项目的影响,而是威胁到团队未来发展的问题。降低标准是个最差的方案。

加人看起来对项目的影响不大,但就像《人月神话》里说的那样,不考虑任务分解的限制和沟通带来的影响,而只是简单的把软件开发的工作量当做人月计算并不合理,我在负责一些项目的时候也犯过这种抱薪救火的错误,大部分情况下,临时加人带来的混乱远大于收益,最终新加入进来的人只能做一些边角工作。加人也不是一个好方案。

而加班和延期都会在相当程度上影响项目质量,并且有各种其他问题(影响健康,或者项目组不接受延期等等),不考虑。


为了统一微博里的所有视频业务,最近组里的小伙伴在讨论拆出一个新服务,但是根据什么来拆服务一直没能达成一致。

有人说为了统一,应该拆出一个“api网关层”,所有调用都要经过网关层,这样就能统一了。

也有人说网关层不能解决问题,应该拆出一个“平台层”,把跟某个具体业务线无关的代码都拆到平台层,这样就统一了。

还有人说平台层不合适,应该在平台和业务之间再拆出一个“中台层”,这样才能适应业务发展。

我觉着造成这种无意义争论的核心的问题有两个。

一个是引入动态链接和远程调用技术之后,一群人分不清楚自己到底是在“拆”什么,甚至简单的认为服务拆分=不在一块部署。

一个是互联网技术概念发展太快,很多人提出了新概念但是没有详细而准确的定义(其实提出的是概念的实践应用),导致出现了各种四不像系统。

我的解决思路很简单:先想明白自己要解决的到底是什么问题,然后牢记一个原则:跟开发有关的问题(复用,灵活性,降低耦合等)应该通过编译期隔离解决,而跟运维有关的问题(上线频率,故障隔离等)应该通过运行期隔离解决。

天天研究新概念并不能帮你理解问题的本质,多做几次有思想的重构却可以。