发布日期:2017-05-10 15:37:28 +0000
那个,今天必须写一篇。因为明天晚上就飞欧洲了,必须跟读者报备一下,下面两周可能无法保证更新频率。
昨天那篇 从空空狐谈信用卡套利 访问量也是近期小高潮,增粉看趋势会过两千,话说连续多日都是两位数增长,看来蹭热点还是很有效果的。
按说今天应该蹭一下 罗永浩和锤子,可是想想算了,该说的以前都说了,就不跟这个风了。我前段时间朋友圈里说过一句,,我一次也没做过美联航,我朋友圈里也没有乐视,易道高管,这热点我一个都凑不上啊,那,今天多一句,我也没买过,没用过锤子手机。
好了,回到今天主题,其实也是旧话重提 如何应对并发(6) - 琐碎的日常 ,但最近帮小密圈优化,有些东西觉得还是值得重新说道说道。
优化经常遇到的一个场景,一条慢查询SQL过来,一个数据结构过来,然后看怎么调优,当然,对于有经验的老鸟来说,基于这两个信息已经可以解决大部分慢查询的问题,但这并不足够。
还经常遇到的问题,某个请求卡,慢,把代码拿来分析,看怎么优化;或者一个很泛泛的应用诉求讲出来,问如何做架构设计。
今天,我重新整理,罗列一下需要思考的重点
1、对于数据结构设计而言,需要考虑数据的容量和分布规律。
前面一个还很好理解,比如说,几百万条,几千万条,几亿条,这些不同数据容量的架构设计,肯定是不一样的。
但后一个很容易被无视,什么是分布规律?
比如说,
好友列表,平均每个人会有多少好友,有超过100个好友的比例是多少,系统上限是多少。
订阅列表,类似如上,双向和单向的关系。
用户黑名单设计,平均每个人会拉黑多少人,有超过100个拉黑的比例是多少,系统上限是多少。
除了如上的分布规律外呢,还有很重要的一点,就是与此相关数据的分布规律。
比如说,订阅列表里,主要内容是哪些人提供的,平均每次订阅所看到的内容来自于多少用户,top内容贡献者用户的分布规律是怎样的。这里就涉及了 内容数据,订阅数据,以及用户数据三部分的彼此关联。
那么,这些分布规律,其实对技术优化策略,和数据结构,缓存结构的设计,其实是影响非常大的。
2、请求频次和请求峰值频次分布的规律
同样的一些读写请求,同样的一些SQL,同样的数据内容,在不同请求频度上,结构设计可能会有很大的不同。
比如以前我提到过,如果写频率与读频率的比值很高,那么有些对查询优化改进不大的索引可能需要降级处理,比如一些复合索引是可以降级到单键索引的。这些我们也是有实践经验。
不考虑频次,盲目针对单条查询做优化,有可能会牺牲掉其他方面的响应。
请求频次必须考虑峰值,比如一个垂直电商,通常我们认为下单这个操作的频次不会特别夸张,优化商品展现是首要任务;但遇到类似秒杀这样的操作,下单这个操作的频次就会瞬间爆发,而一些为商品展现优化所设计的技术逻辑很可能就会成为巨大的拖累。
以前商派的系统就存在这个问题,我当时应朋友邀请分析过一个垂直电商的代码,发现当时的商派系统,在用户每次下单后,会重新生成大量的内容缓存页,正常情况下这个设计是为了优化内容展现,不构成任何问题,但一旦进入秒杀场景,系统瞬间崩溃。
3、异常的考量和降级策略
什么是异常考量呢,比如你系统有个搜索功能,很耗费资源,正常情况下,搜索频率很低,这个问题不那么严重,但如果遇到有人搞你,cc攻击,这个短时间大量不同关键词的搜索请求刷过来,一下子可以把你数据库刷爆。类似这样的事情。
再比如很常见的,有好多个创业团队中招过的,一个免费论坛系统,翻页是个低频需求,特别是大翻页(几十页,几百页),这种基本上用户很少有这样的操作,(对大翻页为什么效率低如果不理解的,重读这篇 如何应对并发(1) - 关于数据索引 )但半夜,某些搜索引擎蜘蛛来爬,刷刷的服务器就崩溃了。
那么我发现很多创业公司在系统设计的时候没有针对异常的设计,也没有降级考量,其实说实话,我以前也对这个很没有经验。
什么是降级呢,就是牺牲部分请求,保障系统的最基本可用性。
以前QQ邮箱有这个问题,如果出现一些异常,可能你无法发邮件,无法编辑邮件,但基本阅读邮件还是优先保障的。
那么如上的问题,很多特定诉求导致的负载问题,可以通过暂时的功能屏蔽或诉求屏蔽,来保障整体的系统可用。
很多创业者抱怨被人家CC攻击,各种寻求安全服务,我其实说句实话,CC攻击确实讨厌,但相当比例的情况下,程序员可以通过一些结构和代码的调整,来实现降级甚至特定的过滤处理,保证正常用户部分甚至全部常用功能的可用性,而不是整体崩溃掉后完全归咎于外部。
下面说个典型案例
比如微博这样的系统,基于订阅和内容发布,这是个很典型的案例。
一般来说,如果你的数据规模小,数据量小,用户少,你怎么处理都可以。
但我们知道微博的规模是巨大的,用户量巨大,数据量巨大,内容生成也巨大。通常的设计有两条思路
其一,是推策略,什么是推呢,就是每个内容制作者,发布内容后,都会把内容同步推送给所有的订阅者(把内容id推过去就行)。
这样的优势是,每个订阅者有个自己的内容列表,订阅者打开系统的速度超快,没有负载问题。
但这样的缺点是什么呢?很多大V有几万,甚至几十万订阅者,每发一条信息,就要同步发给几万,几十万订阅者,这发布信息的成本就会巨高。
其二,是拉策略,什么是拉呢,就是订阅者打开系统的时候,先拉取其订阅列表,然后针对每个订阅者去查询最新信息,汇总过来生成自己的订阅内容。
优势是,发布者发布内容只是一条记录,系统负载极低。
缺点是,很多订阅者订阅了大量微博主,那么每次拉取的开销就会巨大。
那,应该怎么选择呢?
说白了,推拉结合,怎么推拉结合?
就是要看数据的频率和分布规律了。
对于访问频率较高的订阅者(活跃用户),推送的效率收益比高;
对于访问频率较低的订阅者(僵尸用户,流失用户等),拉取的效率收益比高;
此外,要考虑用户平均订阅的分布;以及平均粉丝的分布。
而系统基于这种分布规律,就需要寻求一个最佳平衡。
那么,以上是今天要说的,针对数据分布的规律,针对请求频率,做优化设计,而不是单纯的说,我有什么请求,有什么数据结构,就得出优化结论。
设计过程中,对潜在的异常和风险要有敏感,但不需要过度考虑,可以用简单的降级策略控制风险,而不是说我要巨大的技术资源投入来彻底解决一些小概率事件,对创业公司来说这个可能得不偿失。
额外说几个系统设计容易犯得错误。
1、过度设计
过度担心某方面的问题,隐患和缺陷,大量精力投入到一些不必要的开发和系统保护上,其实没必要。有时候一些简单粗暴的保护策略是必须的,但要考虑你实现成本。
我们自己的程序员也存在过度设计的倾向。
2、主次不分
急于优化每个看到的问题,比如针对每条慢查询寻根究底。
其实要快速定位系统当前阶段的最大问题,快速解决当前最受制约的问题,这是最关键的,很多问题其实没有想象的那么可怕,一些对系统可用性影响不大的问题,可以等当前紧急问题解决后慢慢处理。
3、缺乏预警
直到问题爆发,才想起来去分析,去优化,去解决。
缺乏日常必要的数据跟踪和预警机制,在系统负载出现波动,数据连接池增长异常,但系统整体可用性尚未出现问题的时候,能体现发现这样的异常波动,并准确定位,早做计划,是非常重要的。
4、完美主义
程序员容易犯完美主义的问题,希望彻底,完全解决某个问题,当然,彻底,完全解决某个问题是好的,但如果问题难以定位,或者说解决成本很高,难道就束手无策,或者需要一个长时间的开发周期么?
我会倾向于,先使用一些简单粗暴,导致可用性降级但确定有效的过渡策略,保证系统基本可用性,然后逐渐去彻底解决整个问题。
以及,就算你找到了解决方案,一些简单粗暴的救命手段,或者说是备用方案,依然需要保存待命,万一你的解决方案不灵,或者遇到新情况的时候,依然是需要有一些策略的。
今天的文章,出发点,是针对小密圈 拉黑功能设计的一些思考。
为什么会有这样的讨论,拉黑功能也存在这样的设计问题。
是取出所有信息,然后摘掉拉黑的显示。
还是获取信息的时候,就过滤掉拉黑的内容。
前者信息的通用性更高,可以方便设置缓存;而后者则每个用户需要独立获取。
那么问题来了,多少用户会使用拉黑,平均拉黑多少人,以及,这些拉黑的人在信息的发布上占据了多少的比例,这些数据分布,会对最终设计产生极大的影响。
那么,在没有数据的时候,怎么做呢?
先按基本的方法做,因为初期,拉黑的用户少,先不用考虑哪些大量拉黑的特殊场景,但上线后,密切的数据观察和预警体系要做好,基于线上的数据变化,分析相关的数据分布规律,再来制定下一步的设计和优化策略。
那么,有个技术人员跟我提了一个问题,说我以前讲过的,少数特殊用户造成的影响可能会超过大量的普通用户,技术上也面临这样的挑战,所以对每个功能的设计都很谨慎。(这里提到的就是,如果存在一些拉黑大量用户的用户,其访问请求的处理可能会比较复杂,而且比较消耗资源。)
我的回复是这样的,你的系统设计要这样考虑,一旦出现少数特殊用户的问题,其影响尽可能控制在只限于他们自己,而大量普通用户的请求不受影响。如果是这样的设计,就可以大胆上线运营。如果少数特殊用户的问题会影响全局,那肯定是设计出了问题;那么至于如何完美的解决少数用户的问题,那是后续的事情了,不要急于寻求完美的方案。
我 5.12 日早上到巴黎, 5.15去意大利,之后明确会去法兰克福,5.24从阿姆斯特丹返回新加坡,中间的行程还没完全确定。
有在欧洲的小伙伴,如果恰好在我的行程中,有什么创业项目或其他一些有价值的信息可以分享,可以留言约起来。不过我可能只会酌情摘取一些和我业务目标最贴近的朋友,如果没有约到,也希望见谅。