首页 文章 精选 留言 我的

精选列表

搜索[SEO优化],共10000篇文章
优秀的个人博客,低调大师

百万会员推荐关系优化实战

最近,一朋友整天因为CPU 99%搞得茶饭不思,夜不能寐,找到我”诉苦“。听完成,心中一阵窃喜:是时候展现真正的实力了(其实是练手的机会来了)。半推半就应承了下来。 01分析问题 几分钟了解下来,大概情况如下:会员可以推荐其他用户注册,会员有一个属性--活跃度,用户观看视频,签到等等行为时,这个属性会动态变化,其中有个需求是统计所有下级活跃度。会员模型如下,模型比较简单,使用使用sqlserver 2016。 了解需求后,再来看看占cpu高的查询。其中占cpu 时间最多的就是下面这条sql,查询某个用户所有下级的活跃度之和。这条语句使用递归查询,那是比较耗时的,另外如果层级太多还有如下错误:语句被终止。完成执行语句前已用完最大递归 100。 1 WITH T 2 AS( 3 SELECt DataID, avtivenewss FROM User WHERE DataID = 4167 4 UNION ALL 5 SELECT u.DataID, u.avtivenewss 6 FROM User U INNER JOIN T ON U.parentUserid=T.DataID 7 ) 8 SELECT sum(avtivenewss) FROM T 当前用户1W+。 02失败的尝试:前缀法 几乎没思考,就想到了一个方法:前缀法。一个用户的所有后代使用同一个前缀。增加一个字段 paths,以用户编号为基础,格式为:/1/2/3/,用户注册时使用记录上级的paths + 上级id 生成自己的paths, 增加paths的索引,这样更具此字段就可以查询我的所有下级了,再写个脚步初始化。非常简单,三下五除二就解决了。上线效果非常明显。 但是好景真短,没两天cpu 又高了。一查,好多查询都没有走索引,明明字段已经加了索引。一看数据,原来是索引长度限制问题。用户居然有好几十个层级,且还在不断增加,长度超过索引最大长度后,索引失效。 当前用户10W+。 04大胆猜测,小心尝试 会员关系是一棵树,不管怎么遍历,效率都有限。如果把树拉平,用户与所有后代都建立一个关系,性能会怎么样呢。为了避免再次打脸,悄悄的开始了尝试。增加模型tree。 这需要在用户注册时,添加与所有祖祖辈辈的关系。比如 4167用户注册,需要一次添加14条关系记录。而查询用户的所有子子孙孙时,也会非常方便。 编写脚本初始化数据,增加切换开关,战战兢兢的上线了。经过一个高峰,cpu居然都在10%以下,完全没有压力嘛,终于可以亮出脸来了。这是典型的空间换时间。但是高兴之余,心中闪过一个念头--这个表的膨胀速度有点快,它会有极限么。不过,马上被另一个念头压制了:小网站能有多大量! 有个什么定律来着:凡事只要有可能出错,那就一定会出错。果不其然,10天后同样的问题再次发生。cpu几乎爆满。只能不停重启,最后干脆下掉了这个统计功能,为此还被怼了一顿。此时关系表总数为10亿。 当前用户100W+。 05终级方案:分表 其实对于分表这样的事儿,一直都有想过,就是没干过,另外也一直以为是sum()引起的cpu问题。后来咨询了公司做交易的同学,传说他们每天处理2kw的订单,基本思路也是根据用户id分了2048张表。反正也没辙了,撸起袖子搞起来吧。分析了tree 表只有两个查询场景,查用户所有后代及查用户所有祖先。分别以ancestor ,descendant 分256 张表。用户注册时,把关系分别写到个分表中。 编写脚本初始化两个纬度的分表数据,再次战战兢兢的上线了。经过数个高峰,效果比预期好太多了。彻底告别了cpu告警。 经历了几次失败,早以没了高兴劲儿,心中有个疑问,如果是sum引起的cpu跑满的话,现在sum并没有减少,但是cpu为啥清闲了呢?这背后一定有原因的。 06刨根问底 带着上面的疑问,对比了一些监控数据,发现了一个可疑的地方,磁盘请求减少了数百次。那么磁盘与cpu有什么样的关系呢? 查询相关资料后,得出一个猜测: 未分表前,每次查询所有后代(祖先时)时,因为数据在磁盘上非常分散,page cache 命中率低,磁盘预读失效,所以一次查询要进行很多次磁盘随机读,大量的io操作,cpu就要进行大量的上下文切换,从而导致cpu跑满。 分表后,每次查询所有后代(祖先时)时,每次都在特定的分表中查询,数据在磁盘上非常紧凑,磁盘预读发挥最大性能,page cache 命中率高,io次数据大量减少,cpu上下文切换次数减少,没了压力,cpu自然清闲了。 最后打个广告:哈啰出行,base杭州,java我们的部门有大量HC,欢迎私聊哈。微信:jijunjian I have a dream to be a good programmer。

优秀的个人博客,低调大师

优化代码中的“坏味道”

“一颗老鼠屎,坏了一锅粥,代码也是如此。” 在我们的项目中,也许在刚开始开发的时候,大家都会遵从一些规范来实施,但是当业务进度催的紧,或者人员变动,随着时间的迁移,项目不断的迭代以后,这时的代码可能就会出现一些“坏味道”了。 “坏味道”代码的出现可能不会影响我们的业务逻辑,大家自然也就比较容易忽视掉了,但是这如同是给我们代码埋下的定时炸弹,当爆炸的那天,需要我们背锅处理的时候,就会后悔当初为何不去解决这些问题呢?下面我们来看一下有哪些“坏味道”代码可以提前处理的吧。 1、多此一举型代码。 if(a > b){ return true;}else{returnfalse;} 也许一些经验不那么老道的开发会觉得这段代码没问题呀,可以跑得通,确实,在逻辑上是没问题的,但是有更简洁明了的写法为何不用?if() 里面的条件是boolean ,然后我们的返回值也是boolean,所以可以改写成 returna>b; 2、瞎命名型代码。 int a;Stringwzbt;// 文章标题Stringfastdi;//fastdi快递。。中西结合... 以上只是不规范命名的实例的冰山一角,良好的命名除了见名知意以外,还可以在长时间以后回来阅读代码时,更快的回忆起业务逻辑,不至于在各种无解的命名中乱了手脚,为了一时的方便而随意命名是非常不值得的。 3、if完一定要加else型代码 if(condition){ //dosm}else{ return ;} if(condition){ //dosm}else{thrownewException();} ​​​​ while(xx){if(condition){//dosm}else{continue;}} 很多情况下,我们通过一些语句的前置类减少不必要的else,让代码看起来更简练清晰。 if(!condition){return;}//dosm if(!condition){thrownewException();}//dosm 4、复制粘贴型 举个例子,项目中A模块引入B模块的优惠券业务,此时C模块也要引入B模块的优惠券业务,由于此时的优惠券业务可能是B模块中的几行代码,很多人就为了贪图方便,直接复制这几行代码直接放到C模块了。so easy,代码完美运行。 看起来似乎又没什么毛病,此时程序员的天敌产品经理过来了,他说在要在优惠券逻辑前面加点限制条件,ok,那么此时就要改动A模块跟B模块2份代码,而且要保持一致性,这个需求就完成了。过了一个版本,D模块也要引用优惠券业务,此时你又愉快的复制过去,然后可爱的产品经理又过来跟你说,这个版本我们要砍掉前面的限制条件...这时候你就要同步三段代码...跟产品经理的一场大战估计在所难免了。 所以从上面的案例中,如果我们一开始不偷懒把公共逻辑抽取出来,在各个模块引用的话,不论怎么修改,我们只要维护一份逻辑就可以,不至于手忙脚乱。 5、又长又臭型代码 此类坏味道代码一般出现在“有历史“的代码中,经过不同开发人员的迭代,一个方法可能会出现几千行的情况,即使有注释,也会让人看得痛不欲生,这时候刚接手修改的人必然会说一句“WTF”了。 所以这就要求我们在平时写代码的过程中养成提炼的习惯,一般来说,当某块业务逻辑需要注释来说明的时候,一般都可以提炼成方法来调用,通过这种方式会使得阅读代码的时候逻辑更加清晰。 还有一种又长又臭情况是出现在方法的参数中,不断的迭代过程也会导致参数的增加或者修改,甚至有看过朋友公司的代码出现一个方法10多个参数的情况。一般来说,当参数超过5个的时候就要考虑封装到对象当中了。 6、无病呻吟型 //输出info日志logger.info("xxx");//定义num变量intnum=0;... 上面举例的是一些无关痛痒的注释,当代码中充斥着这些玩意的时候会让人觉得很臃肿,当你做到上面五点的时候,代码已经不需要太多注释了(滑稽),所以我们的注释要注释到痛点,具体可参考《阿里java开发规范手册》 细节决定成败,在我们工作的过程中,当然还有很多需要我们注意的细节,大家有什么心得可以留言交流一下~ 最后推荐一下<重构 改善代码的既有设计>这本书,比较详细的介绍有那些坏味道需要重构的地方。 喜欢的话,劳烦关注一下微信公众号《深夜里的程序猿》噢~

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册