成航先森 成航先森

成都航院计算机系一个学生的个人博客

 

脚本编程

  • 没有分类目录

最新文章

脚本编程
当前位置: 首页 » 脚本编程 » 修复anylink增加Redis缓存后存在的bug

修复anylink增加Redis缓存后存在的bug

编辑:狂族晨曦 来源:脚本编程WordPress技巧 日期:2022-04-04 阅读: 963 次 4 条评论 » 百度已收录

最后更新时间:2022-06-10

先森最近更新了一篇文章,发布后先森自己没有去看,今天去看了一眼,结果突然发现这篇文章中所有的外链没有自动转成内链。

以前优化SEO的时候,看到的优化建议基本都有不要直接跳转到外链,会导致权重降低,所以先森一直都有用anylink这个插件来实现这个功能。

对于anylink这个插件,先森的使用体验还是非常好的,之前一共还发过三篇博文:

WordPress为anylink插件外链跳转添加漂亮的跳转页面

WordPress:WPJAM BASIC插件与anylink冲突

WordPress优化:为anylink插件增加缓存

既然发现了问题,那么就得解决问题,正好是清明节放假期间,托疫情的福先森哪里也不好去,所以来会会这个bug。

排查过程

首先,出现没有转内链的文章只有先森最新发布的那一篇,之前的文章都是正常的。

1、怀疑缓存

可能是CDN有缓存,先森将本机hosts改成源站,直接访问源站,测试依旧正常,pass。

除了CDN,先森WordPress还有缓存,先森用的是插件wp-super-cache进行缓存。

先森清理了插件缓存后,问题依旧;

然后想是不是插件有问题,直接将wp-super-cache插件停用了,问题依旧。

2、怀疑anylink插件

排除了缓存的问题,先森又想是不是anylink插件自己出了什么问题,先森将anylink插件停用后再启用,发现问题依旧,插件运行问题pass。

然后先森考虑是不是插件在本篇文章的执行有问题,开debug看一看。

先森在WordPress的wp-config.php中打开了dubug:

define( 'WP_DEBUG', true );
define( 'SAVEQUERIES', true );

先森开debug主要是想看本篇文章中的SQL查询,所以在后台开启了Debug Queries插件,结果开启后并没有看到anylink的查询,然后先森想到了为anylink添加redis缓存这篇文章中,已经将相关的SQL查询优化了,这样debug确实已经看不到去MySQL的查询了。

此时先森已经开始怀疑是不是当时优化有什么bug了,但还是需要先确认一下是不是MySQL、Redis数据库有问题。

3、怀疑数据库有问题

先森的MySQL是云数据库,Redis是部署在源站本机的。

MySQL运行肯定没有问题, 不然就不只是外链有问题了;Redis检查后发现也是正常运行的。

先森再去看anylink的MySQL表,发现wp_al_urls表里是有出问题这篇文章的外链转内链对应表的,这就奇怪了,到这里MySQL的问题排除了,先森就怀疑是自己之前的优化存在问题了。

4、怀疑优化存在BUG

先森本来想直接在redis里查有问题文章的缓存,但是redis的key太多了,先森已经忘了key是什么规则了,所以就先去研究了一下anylink的代码,先搞清楚之前先森的优化。

首先确认到,先森优化的是插件的classes/al_filter.php文件,优化了getAllLnks()和get_slug_by_url()这两个类中的函数,增加了先查redis缓存,没有再查数据库并将结果存到redis的代码。

修改的部分 -1

修改的部分

这两个函数先森研究了一下,get_slug_by_url()这个函数是用在把留言者的链接转换成内链的,所以出现问题的不可能是这个函数,那只能是getAllLnks()这个函数了。

getAllLnks()这个函数保存缓存的key是‘getAllLnks:’开头的,后面跟的是文章的id,先森就去redis查相关key。

应该是redis的key不支持冒号,所以实际存储的key是‘getAllLnks-’开头的。

先森发现有问题的文章ID是1968,所以它的key是‘getAllLnks-1968’,先森先查的是正常文章的key,查出来是一大堆的内容,而查到1968就发现明显有问题:

getAllLnks有问题 -2

getAllLnks有问题

这个key的内容简直就没有内容,按逻辑来想起码有两个内容:外链地址、内链地址,将这个key删除,然后重新访问有问题的文章,发现外链就已经自动转为内链了,此时再来查redis的key查询结果,正常多了:

getAllLnks正常结果 -3

getAllLnks正常结果

至此,问题已经临时得到了解决,但是原因还需要分析一下。

出现bug的原因

一开始,先森以为这个问题原因是anylink在管理员登录时不会处理外链,先森预览文章被缓存了,但是找了一圈anylink的代码,没有找到判断管理员是否登录的代码,所以应该不是这个原因。

好好想了一下,发现bug的原因应该是这个:当文章还在编辑的过程中,预览文章,由于此时文章还没有外链,所以数据库查询结果为空,但是这个空结果被先森的代码保存到Redis中了,由于Redis的缓存没有设置过期或到期时间未到,先森也没有设置redis缓存更新,导致后续anylink插件来查询这篇文章的外链时一直是空的。

解决方案

问题原因找到了,就好解决了,先森想到了两个解决方案:

方法1:管理员登录时anylink不处理链接

方法2:文章发布、变更时更新anylink的缓存

第一种方法,管理员登录时,尤其是正在编辑文章时,预览文章不会造成错误的key被redis缓存。但此方法还是有bug,管理员未来更新文章时新增了其他外链,此时由于Redis已经缓存了这篇文章的外链查询情况,如果改缓存未过期,新增的外链在文章中会出现未被转换的情况。且这种方法容易造成管理员视角和访客视角不同,先森用的其它插件有类似设定,实际使用中会让人比较头疼,所以先森不太希望使用这种方式进行修复。

相较而言,第二种方法就要合理的多,只要文章有变动,那就把anylink该文章的redis缓存删了,有人访问该文章时再缓存。

实现也比较简单,在自己的主体function.php最后加一个publish_post钩子,实现这个需求:

/**
 * 更新或发布文章清理Redis缓存
 * 增加时间:2022-04-04 12:43:00
 * By:https://www.capjsj.cn/
 */
function Clean_Redis($post_ID){
	wp_cache_delete( 'getAllLnks:'.$post_ID );
}
add_action('publish_post', 'Clean_Redis', 0);

来测试一下,在管理后台随便更新了一篇已发布的文章,发布前查询该文章的redis缓存,刷新后再去查询,该文章的key已经查不到数据了。

测试hook删除redis缓存 -4

测试hook删除redis缓存

2020年埋下的bug终于在2022年被修复了,还好期间先森新发布的文章只有2021两篇(有点惭愧),且不涉及外链,所以影响不大。按理说也会影响到旧文章的更新,但是先森最近几年对博客这边的关注实在太少,影响着实不大。

无论怎样,写代码还是的考虑周到一点,还好先森不是程序员,只是一枚小运维。

历史上的今天:

标签:
除特别注明外,本站所有文章均为成航先森 www.capjsj.cn 原创,本文共2898个字
转载请注明出处来自https://www.capjsj.cn/anylink_redis_bug.html
已有 4 位"计工"发布了激烈的评论,还有N多人围观笑而不语评论
的头像
欢迎发表评论
取消评论

表情
疑问调皮伤心抠鼻黑线微笑可爱奸笑震惊吓到了撇嘴大兵忍不住笑笑狂骂狂怒噢?鼓掌酷⊙﹏⊙b汗鄙视大哭嘿嘿

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
  1. 的头像

    感谢分享,谢谢站长!!@天天下载

    2023-03-15 23:20 回复
  2. 的头像

    好久没更新了

    2023-03-29 21:00 回复
  3. 的头像

    你写得非常清晰明了,让我很容易理解你的观点。

    2023-04-29 20:04 回复
  4. 的头像

    博主的文章很有价值,期待新的更新

    2023-10-25 21:34 回复
官方微信
发表评论 返回顶部