你好,我是yes。
之前不是稍微吐槽了下一个项目的代码嘛,有几个同学(1V1问答的同学)就顺着问了我几个平日里一些编码的问题。
【资料图】
不同人写代码其实分了好几种情况:
有些人完全没意识到问题,这个属于个人知识瓶颈,需要多加学习。有些人就随意写,赶时间,没责任心,当下能跑就行,后面管它洪水滔天。有些人就贼纠结,写个小功能想七想八,脑子总往着亿级流量上怼,可能项目黄了之前其实都只几个人用。这几个情况我都经历过,写代码虽被戏称搬砖,但咱毕竟也是类似阿提斯特一样的创作型工作,跟心情有一定的关系。
工期紧心情差,将就将就,闲得很心情好,我缀一口咖啡精雕细琢。
咳咳,扯远了,回到今天的主题。其实平日里想要写好代码,没那么难,这篇我就总结下需要注意的几个要点,不是很全,但是都是比较常见的点。
批处理思想遥想当年我还是实习生的时候,写个代码风风火火闯九州!就没有我不敢莽的代码。
一个 for 循环闯天下:
for (YesDTO dto : yesDTOList) { //do sh save(xx);//插入数据库}
dev 和 qa 库里就几条数据,跑的好好的,一上线几千条数据,直接干蒙 mentor。
我当时都没意识到问题所在,但从他的眼神中我看到了杀气。
影响不大,这锅还得他背,谁让他不 check 我的代码?
现在知道了,一条一条插入太慢了,涉及到网络的开销,数据的解析等等。
所以特别在 for 循环的时候要想到批处理思想
for (YesDTO dto : yesDTOList) { //do sh xxList.add(xx);//添加列表}//批量插入saveBatch(xxList);
不仅仅是我提到的数据库操作,还有 RPC、HTTP 调用也是一样,需要提供批量处理的接口替换 for 循环的一次次调用。
批处理能显著提高吞吐,如果你看过一些中间件的源码或底层一些实现你肯定能 get 里面很多批处理的思想。
事务本地操作,如果涉及多个表的修改,不要忘了上事务,不然一旦中间处理出了差错,数据就不一致了,意味着需要补数据,而补数据是一件非常麻烦且敏感的事情。
如果本地操作,涉及多个表的修改,又涉及远程调用(或HTTP调用),需要注意事务的范围。
开始事务修改ARPC调用修改B结束事务
不推荐在事务中使用远程调用(或HTTP调用)。
因为远程调用(或HTTP调用)可能因为网络等其他原因导致响应很慢,而如果你的事务包裹了这些调用,可能会因为处理慢而长时间持有数据库连接,或阻塞后续其他请求修改对应的值,使得连接池的连接耗尽,然后就都堵着,就都挂了。
所以写代码的时候要想着上事务保证数据的一致性,又得想着事务内部的行为会不会阻塞连接的释放导致后续雪崩问题。
还有要注意一点,有些同学在事务里面包了 RPC 调用(或HTTP)是想着如果 RPC 调用失败本地事务就回滚,通过这样的手段来保证一致性。
这种想法是错的,因为调用可能是超时或其他网络情况,这不能代表对方的业务执行失败,所以如果对方执行成功,你还是回滚了本地事务,其实数据还是不一致的。
如果需要确保一致性,就只能上分布式事务,可以看下我这篇:分布式事务汇总
异步异步化改造是提升服务性能的一个有力手段!
如果某个模块流量高,异步能减轻压力。
如果某个模块处理流程复杂且缓慢,异步能避免同步调用超时。
在编码中遇到以上这两个问题,就可以考虑异步。(当然还有其他场景,但这两个比较常见)
可以通过 MQ 或者线程池来实现异步。
在平日工作的场景中,我更多使用 MQ 来实现异步,因为线程池的任务毕竟是存储在内存中的,它没有自带的持久化操作,而且任务队列大小也有限,而 MQ 自带持久化且能存储的任务量更大。
你想,假设你线程池堆积了1千个任务,然后服务挂了,那不又得考虑补偿的机制了?而 MQ 就没有这个烦恼。
当然,一些定时批处理任务类的场景还是要利用线程池的,不过这种场景的数据源已经持久化在数据库中了,不会丢失。
重试就像我前面说的,RPC 调用或 HTTP 调用可能因为网络问题没拿到正确的响应,这时候你必须要有重试的操作。
比如有个业务是异步的,别人调了你之后,你慢慢处理,等你处理完了需要通知别人,这就涉及到回调。
而回调别人接口的时候,脑子里一点要想着会遇到网络问题,比如超时等,你必需要设计一个重试机制来保证通知到对方。
这个重试机制最好是间隔延迟的,比如1s、5s、30s、1min 、5min这种间隔重试,也就是说需要给对方一点时间来恢复服务,避免对方服务出问题的前几分钟把重试都用了,导致后面需要人工介入补偿。
还有需要限制重试次数,因为我们的资源也是有限的,不可能给它无限重试,当达到一定的失败次数后进行记录,后续人工介入处理。
幂等提到重试,那肯定伴随着幂等。
一切接口,如果可以,就按幂等实现,也是说一个接口同样的入参,调用多次都跟调用一次产生的结果是一样的。
因为现在基本上都是微服务,远程调用非常频繁,基本上 RPC 框架都会自带重试机制,你的接口很有可能在你没准备的情况下被被重复调用,所以幂等就很重要。
并且有时候需要补偿等动作时,幂等的接口可以让你补偿更加方便且没有后顾之忧。
缓存缓存是提高服务性能的一个重要手段之一。
很多大流量高并发服务基本上业务层的数据源都来自于缓存,对于一些精细化拆分的业务组来说,可能几年都没写过 SQL。
我相信市面上公司基本都会接入 Redis(或类似组件),咱也不是说啥都要上缓存,只是说编码时候考虑下这块是否需要利用缓存来减少服务的压力,比如一些频繁调用且基本上不会更改的固定配置等等。
而缓存不仅仅是分布式缓存,还有本地缓存,也要善于利用本地缓存来实现优化。
总结我稍微总结下以上内容:
编码时要有批处理思维,避免 for 循环单条保存数据和远程调用(效率极低)。注意事务的范围,避免事务中进行远程调用或分布式锁竞争等可能长时间造成数据库连接不释放的场景,也就是说不要无脑用 @Transactional 包裹整个方法;异步改造提高性能,但是要注意异步后如何保证异步的逻辑一定会被执行,且异步逻辑出错如何补偿等问题;网络是不稳定的未知的,重试机制必不可少,要注意重试间隔,给对端多点时间恢复,减少需要人工介入的场景;尽可能按幂等实现方法,防止被重复调用导致数据错乱;缓存,缓存大法YYDS,但是要注意失效时间以及大 key 问题。虽说咱是打工人,不是给人卖命,但是一些基本职业素养还是要有的,我们还是需要有责任地管一管,避免后面的“洪水滔天”。
好了,今天就暂时分享这么多,后期我看着再整理一下实现的细节点。
你好,我是yes。之前不是稍微吐槽了下一个项目的代码嘛,有几个同学...
购买了售价195块钱“世喜”奶瓶,使用后没有宣传中的效果,认为该品...
据“云谷教育”微信公众号今日消息,马云来到云谷学校,和校园长讨...
杉杉股份创始人、实际控制人郑永刚突发意外过世一月有余,他所留下...
3月28日,烽火通信(600498)融资买入7539 26万元,融资偿还7012 ...
1、去意大利工作,要办工作签证。要办工作签证,需要满足以下两个条...
最新民调显示美国总统拜登支持率下滑至40%:据媒体新闻,当地时间3...
1、中文版FC码:_SULJM-05262_GDISSIDIAFINALFANTASY_C0战胜后获得AP25
南方网讯(记者 谢婧)近日,广东省政府办公厅印发《2023年广东金...
3月28日,上交所发布通知称,根据证监会的统一部署安排,为确保全面...
永磁电机是现代材料科学、电子电力科学及电动机控制理论相结合的产...
河南广电·大象新闻记者吴彦飞通讯员金正义余洪磊自“双争”活动开...
十万级别的SUV可以说是很多家庭买车的首选细分赛道,相比轿车,SUV...
根据内部备忘录,Facebook母公司MetaPlatforms计划减少向部分员工发...
为扎实推进西安市八个方面重点工作,着力提升市级应急救援队伍的抢...
“阿六汤圆广利粽,洪喜摊粉味不同,腐干出自三星斋,洪兴美酒酱同...
欢迎观看本篇文章,小勉来为大家解答以上问题。顿字组词,汉字顿组...
1、诀窍买便宜船。2、早期钱较少时,为了能够买到便宜点的船,可以...
1、柯南·道尔一共写了四篇长篇、56篇短篇的福尔摩斯系列小说。2、...
1、大概是1万年前的河姆渡氏族,他们使用骨器、木器、石器和陶器,...
要说这个野钓人装备的携带量分化极大:有的钓友提个蛇皮袋拿一根杆...
进入三月底,距离夏天就更近了,一些城市已经开始热了起来。进入到...
中国商务新闻网是商务部国际商报社主办,国家互联网信息办公室批准...
报告:2023年中国棉花意向种植面积4389 1万亩,同比减少4 9%,种植...
3月27日,中国心连心化肥(01866)在香港举行2022年度业绩发布会。会...
长剑在手缚苍龙,绝术傍身走四方!中联重科不负众望,再度升华。近...
1、首先在系统下方的任务栏上点击鼠标右键,选择【启动任务管理器】...
3月23日,云筑携手中建海峡建设发展有限公司主办的“第九届云筑蜂会...
以下是诺普信在北京时间3月27日14:45分盘口异动快照:3月27日14点45...
1、设用x立方米钢材做A部件,则用(6-x)立方米钢材做B部件。2、列...