likes
comments
collection
share

一年经验后端开发的性能优化浅谈

作者站长头像
站长
· 阅读数 3

永远不打没有准备的仗

使用 wrk/ jmeter 压测性能指标

一年经验后端开发的性能优化浅谈

使用 pprof 定位性能瓶颈

一年经验后端开发的性能优化浅谈

一些常见的极其耗时操作

  1. SQL查询(表记录较多,没有索引或者索引失效,常用联系的两种表为建立关联表)
  2. 密码学操作,如使用1024位或者更长位的rsa秘钥进行加密或延签
  3. 跨服务请求,频繁调用http(s)或rpc请求,

梳理业务逻辑,简化业务流程

减少SQL查询操作

由于历史原因(业务逐步复杂,或者人员交接),通常很多业务的代码是由冗余的,最常见的就是重复查询。

比如登录账号密码的过程,就有至少要查询4类信息,分别是查询获取用户登录别名(如果支持别名登录),查询用户密码状态(是否为初始密码),获查询用户盐值用于将名为密码哈希,查询服务端公钥用于非对称加密。

如果4类信息如果分为分为4个接口查询,则会至少需要4次http/RPC调用和4次数据库查询。这时候就需要合并接口的数量,争取一次性查询出全部结果并且缓存下来。

一年经验后端开发的性能优化浅谈

减少接口调用

随着业务的复杂,接口会越来越多,许多时候需要级联调用多个接口,但很多情况下这些接口的调用顺序是无所谓的,这时就可以将多个接口进行合并,将多次请求合并成一个请求。

该上缓存上缓存

分布式缓存 or 本地缓存

缓存大分两种,分布式缓存 和 本地缓存。分布式缓存最常用的也有两种,etcd 和 Redis

分布式缓存和本地缓存的使用场景区别还是挺大的。如果需要数据在所有机器上面共享,就选分布式缓存,如果数据不需要多台机器共享就本地缓存。

本地缓存使用场景

比如我上面说的和用户信息相关的,就应该选本地缓存,在负载均衡使用client hash算法的情况下,同一个客户端的请求一定是打到同一台机器上,所以没有必要将同一份数据缓存到所有机器上

缓存预估 与 缓存预热

选择本地缓存,最需要考虑的是两个方面

  1. 一数据规模,避免长时间大量缓存生效,从而占用系统内存
  2. 缓存的生命周期,什么时候写入,什么时候删除,这里既有占用内存的考虑,也有数据一致性的考虑。

在用户认证的场景(输入用户名,密码,获取token的场景),我的方案是

一年经验后端开发的性能优化浅谈

  1. 使用缓存预热技术,也就是当访问不到缓存时被动的从数据库获取数据再写入缓存。当用户输入用户名时,就将用户的相关信息一次性全部塞入本地缓存,当用户密码校验通过后就立即将密码相关的缓存清空(密码状态,盐值,哈希后的密码等)。之所以需要立即删除操作是为了尽可能的维持数据的一致性。当这个数据确定以后不再使用后就应该立即删除。如果认证完需要签发token,则需要继续维持一段token换取用户信息的缓存的时间。

分布式缓存场景

一年经验后端开发的性能优化浅谈

如果对数据的可用性,容灾性要求没那么高,则可使用Redis集群,其底层实现是基于 gossip 算法(一种数据复制算法)。比如iam系统可以配置各种认证协议(扫码登陆,账号密码登陆,短信登陆等等),这种数据规模虽然不大,一个租户下也就是两三条,或者三五条记录顶天了,但是每个用户来都需要查一次(一般情况是查两次,第一次是静态验证比如账号密码,第二次是动态验证比如短信,otp动态码),只要有查询就占用SQL连接,就会消耗更大的资源。而且这些查询到的的数据是所有用户共享的,数据一般由管理员配置好以后不再变化,所以这种场景放入Redis是最好的。

缓存一致性

接上面,我们常将一些不经常变的数据写入redis(过期时间通常较长或者永不过期),但一旦修改数据库数据后后,数据库和redis的数据总会存在不一致的问题。简单来看有有两种方式

  1. 先删除redis, 再修改数据。但如果好巧不巧,在写入的过程中来了个新请求则会将旧数据搬到缓存上去并且长期生效
  2. 先修改数据库,再修改缓存。但如果更新 redis 过程中出错,则会导致数据不一致

延迟双删除

一个简单的,尽可能保持数据一致性的方案是延迟双闪。先删除redis,再更新数据库,然后再删除redis。 这样下一次请求来的时候先读redis, redis 没有再度 数据库,将数据库的数据写入 redis。 之所以更新数据库后再删除缓存,就是为了防止更新数据库一半时刚好有历史数据被塞入 redis 并且长期生效,所以一旦成功更新数据库后应该立马删除redis缓存。之所以是删除redis缓存而不是更新,是因为删除操作更快速,原子性更高。

其他优化 tips

使用 go routine 提高程序并发性能

一年经验后端开发的性能优化浅谈

尽量少打印info级别的日志

日志打印也需要IO操作,尤其是一些结构化的日志,打印起来相当的耗时。对于一些简单的接口,不容易报错的接口,尽量不要在函数的入口打印 info 级别的日志

用ECC非对称加密替换RSA非对称加密

一年经验后端开发的性能优化浅谈

一点感慨

一年经验后端开发的性能优化浅谈

参考

转载自:https://juejin.cn/post/7317908028082274340
评论
请登录