修復(fù)anylink增加Redis緩存后存在的bug
編輯:狂族晨曦 來源:腳本編程,WordPress技巧 日期:2022-04-04 閱讀: 2,901 次 4 條評論 » 百度已收錄
先森最近更新了一篇文章,發(fā)布后先森自己沒有去看,今天去看了一眼,結(jié)果突然發(fā)現(xiàn)這篇文章中所有的外鏈沒有自動轉(zhuǎn)成內(nèi)鏈。
以前優(yōu)化SEO的時候,看到的優(yōu)化建議基本都有不要直接跳轉(zhuǎn)到外鏈,會導(dǎo)致權(quán)重降低,所以先森一直都有用anylink這個插件來實現(xiàn)這個功能。
對于anylink這個插件,先森的使用體驗還是非常好的,之前一共還發(fā)過三篇博文:
WordPress為anylink插件外鏈跳轉(zhuǎn)添加漂亮的跳轉(zhuǎn)頁面
既然發(fā)現(xiàn)了問題,那么就得解決問題,正好是清明節(jié)放假期間,托疫情的福先森哪里也不好去,所以來會會這個bug。
排查過程
首先,出現(xiàn)沒有轉(zhuǎn)內(nèi)鏈的文章只有先森最新發(fā)布的那一篇,之前的文章都是正常的。
1、懷疑緩存
可能是CDN有緩存,先森將本機hosts改成源站,直接訪問源站,測試依舊正常,pass。
除了CDN,先森WordPress還有緩存,先森用的是插件wp-super-cache進行緩存。
先森清理了插件緩存后,問題依舊;
然后想是不是插件有問題,直接將wp-super-cache插件停用了,問題依舊。
2、懷疑anylink插件
排除了緩存的問題,先森又想是不是anylink插件自己出了什么問題,先森將anylink插件停用后再啟用,發(fā)現(xiàn)問題依舊,插件運行問題pass。
然后先森考慮是不是插件在本篇文章的執(zhí)行有問題,開debug看一看。
先森在WordPress的wp-config.php中打開了dubug:
define( 'WP_DEBUG', true ); define( 'SAVEQUERIES', true );
先森開debug主要是想看本篇文章中的SQL查詢,所以在后臺開啟了Debug Queries插件,結(jié)果開啟后并沒有看到anylink的查詢,然后先森想到了為anylink添加redis緩存這篇文章中,已經(jīng)將相關(guān)的SQL查詢優(yōu)化了,這樣debug確實已經(jīng)看不到去MySQL的查詢了。
此時先森已經(jīng)開始懷疑是不是當(dāng)時優(yōu)化有什么bug了,但還是需要先確認(rèn)一下是不是MySQL、Redis數(shù)據(jù)庫有問題。
3、懷疑數(shù)據(jù)庫有問題
先森的MySQL是云數(shù)據(jù)庫,Redis是部署在源站本機的。
MySQL運行肯定沒有問題, 不然就不只是外鏈有問題了;Redis檢查后發(fā)現(xiàn)也是正常運行的。
先森再去看anylink的MySQL表,發(fā)現(xiàn)wp_al_urls表里是有出問題這篇文章的外鏈轉(zhuǎn)內(nèi)鏈對應(yīng)表的,這就奇怪了,到這里MySQL的問題排除了,先森就懷疑是自己之前的優(yōu)化存在問題了。
4、懷疑優(yōu)化存在BUG
先森本來想直接在redis里查有問題文章的緩存,但是redis的key太多了,先森已經(jīng)忘了key是什么規(guī)則了,所以就先去研究了一下anylink的代碼,先搞清楚之前先森的優(yōu)化。
首先確認(rèn)到,先森優(yōu)化的是插件的classes/al_filter.php文件,優(yōu)化了getAllLnks()和get_slug_by_url()這兩個類中的函數(shù),增加了先查redis緩存,沒有再查數(shù)據(jù)庫并將結(jié)果存到redis的代碼。

修改的部分
這兩個函數(shù)先森研究了一下,get_slug_by_url()這個函數(shù)是用在把留言者的鏈接轉(zhuǎn)換成內(nèi)鏈的,所以出現(xiàn)問題的不可能是這個函數(shù),那只能是getAllLnks()這個函數(shù)了。
getAllLnks()這個函數(shù)保存緩存的key是‘getAllLnks:’開頭的,后面跟的是文章的id,先森就去redis查相關(guān)key。
應(yīng)該是redis的key不支持冒號,所以實際存儲的key是‘getAllLnks-’開頭的。
先森發(fā)現(xiàn)有問題的文章ID是1968,所以它的key是‘getAllLnks-1968’,先森先查的是正常文章的key,查出來是一大堆的內(nèi)容,而查到1968就發(fā)現(xiàn)明顯有問題:
![]()
getAllLnks有問題
這個key的內(nèi)容簡直就沒有內(nèi)容,按邏輯來想起碼有兩個內(nèi)容:外鏈地址、內(nèi)鏈地址,將這個key刪除,然后重新訪問有問題的文章,發(fā)現(xiàn)外鏈就已經(jīng)自動轉(zhuǎn)為內(nèi)鏈了,此時再來查redis的key查詢結(jié)果,正常多了:

getAllLnks正常結(jié)果
至此,問題已經(jīng)臨時得到了解決,但是原因還需要分析一下。
出現(xiàn)bug的原因
一開始,先森以為這個問題原因是anylink在管理員登錄時不會處理外鏈,先森預(yù)覽文章被緩存了,但是找了一圈anylink的代碼,沒有找到判斷管理員是否登錄的代碼,所以應(yīng)該不是這個原因。
好好想了一下,發(fā)現(xiàn)bug的原因應(yīng)該是這個:當(dāng)文章還在編輯的過程中,預(yù)覽文章,由于此時文章還沒有外鏈,所以數(shù)據(jù)庫查詢結(jié)果為空,但是這個空結(jié)果被先森的代碼保存到Redis中了,由于Redis的緩存沒有設(shè)置過期或到期時間未到,先森也沒有設(shè)置redis緩存更新,導(dǎo)致后續(xù)anylink插件來查詢這篇文章的外鏈時一直是空的。
解決方案
問題原因找到了,就好解決了,先森想到了兩個解決方案:
方法1:管理員登錄時anylink不處理鏈接方法2:文章發(fā)布、變更時更新anylink的緩存
第一種方法,管理員登錄時,尤其是正在編輯文章時,預(yù)覽文章不會造成錯誤的key被redis緩存。但此方法還是有bug,管理員未來更新文章時新增了其他外鏈,此時由于Redis已經(jīng)緩存了這篇文章的外鏈查詢情況,如果改緩存未過期,新增的外鏈在文章中會出現(xiàn)未被轉(zhuǎn)換的情況。且這種方法容易造成管理員視角和訪客視角不同,先森用的其它插件有類似設(shè)定,實際使用中會讓人比較頭疼,所以先森不太希望使用這種方式進行修復(fù)。
相較而言,第二種方法就要合理的多,只要文章有變動,那就把anylink該文章的redis緩存刪了,有人訪問該文章時再緩存。
實現(xiàn)也比較簡單,在自己的主體function.php最后加一個publish_post鉤子,實現(xiàn)這個需求:
/**
* 更新或發(fā)布文章清理Redis緩存
* 增加時間:2022-04-04 12:43:00
* By:http://www.cnidcc.cn/
*/
function Clean_Redis($post_ID){
wp_cache_delete( 'getAllLnks:'.$post_ID );
}
add_action('publish_post', 'Clean_Redis', 0);
來測試一下,在管理后臺隨便更新了一篇已發(fā)布的文章,發(fā)布前查詢該文章的redis緩存,刷新后再去查詢,該文章的key已經(jīng)查不到數(shù)據(jù)了。

測試hook刪除redis緩存
2020年埋下的bug終于在2022年被修復(fù)了,還好期間先森新發(fā)布的文章只有2021兩篇(有點慚愧),且不涉及外鏈,所以影響不大。按理說也會影響到舊文章的更新,但是先森最近幾年對博客這邊的關(guān)注實在太少,影響著實不大。
無論怎樣,寫代碼還是的考慮周到一點,還好先森不是程序員,只是一枚小運維。
歷史上的今天:
轉(zhuǎn)載請注明出處來自http://www.cnidcc.cn/anylink_redis_bug.html

川公網(wǎng)安備 51011202000104號
感謝分享,謝謝站長!!@天天下載
好久沒更新了
你寫得非常清晰明了,讓我很容易理解你的觀點。
博主的文章很有價值,期待新的更新