link重构过程中,发现一个问题,存在2个大key(很大那种),在PHP版代码下,是通过构造函数读取redis拿到,众所周知,PHP每次请求结束后都会销毁, 那么就意味着PHP版会反复读取这个大key,虽然现在线上没问题,但是却是一颗毒瘤。
既然我们用golang重构项目,那么我们是不是需要发挥go的语言特性来优化掉这个地方呢?同事建议使用常驻内存在做这块,充分发挥go的特性,项目初始化的时候我们读一次放到内存里,然后使用go的定时器,每分钟获取一次配置更新内存中的配置,这样会极大的减小redis的这俩key的请求量,间接的减轻了redis的压力,并且可以优化接口性能,虽然说优化可能是毫秒级别。
我是这么想的
我们既然要做常驻内存,那么我们就需要一个全局变量,拿到的数据放到这个变量里,其他场景才能用到 有了全局变量我们就得考虑如何从缓存拿数据,实际上这俩key在PHP版本是读不通实例的,一个读主,一个读从,既然改成常驻的,我这里全部读主,就不再额外加载一个从实例了,这里封装了一个拿缓存配置并赋值给全局变量的方法 SetCacheConfig 我们已经拿到了缓存中的数据,那我们可以解析出来直接给全局变量,这里要注意的是解析过程的报错,我们要层级反馈报错,因为是常驻内存,放在全局,所以项目启动时会加载,如果有报错,项目会无法启动,当然我们已经处理的没有报错了。 接下来我们要做的是定时更新这个变量,毕竟这个配置是可以通过后台更改的,我们设定1分钟查一次,1分钟内更改并生效,这个是可以容忍的,要实现这个,我们就需要用go的定时器语法,即ticker, ticker可以设定时间,实际上就是每次调用ticker, 到了指定时间,它就给你发一个信号,我们用一个死循环for加select语法,我们在死循环里创造一个阻塞,如果ticker没有发信号我们就阻塞一下,直到ticker返回信号,时间我们设定了1分钟,所以每一分钟我们都会拿到一个信号,当我们拿到信号的时候,我们再调用一下第二步里的SetCacheConfig方法,这样我们就实现了每隔一分钟更新一次全局变量。 有了第四步,那么我们怎么能让程序启动时,走到了第四步但不阻塞呢,毕竟一个死循环是无法跳出的,如果串行,那么会直接阻塞下面的逻辑,这个时候我们就祭出golang强大的一个功能,内置并发,关键字go, 在我们要使用并发的函数前面加上关键字 go 比如 go DaemonSetCacheConfig(), 这样一来,此方法go会直接开启一个协程运行,而不阻塞剩下的逻辑,到此为止,我们的功能就已经实现了。 有一点要注意,就是,这里获取redis实例的时候我们需要给一个上下文content, 咱们的每个请求及请求里用到的变量、配置都在上下文里,而我们这个功能并不是跟随请求的,而是项目启动的时候就使用,那么我们去哪找上下文呢?答曰:content.TODO 我们可以使用这个上下文,go文档里指出,如果我们不知道用什么上下文,我们就用这个,如果是上下文起始位置,我们可以使用context.Background, 实际上从go源码来看,这俩上下文只是互为别名而已。。。