表對象緩存: 是將某個(gè)表對象的字典信息(定義內(nèi)容)緩存到內(nèi)存中,用來提高對表的訪問效率。某個(gè)表被訪問過一次后,只要服務(wù)器沒有關(guān)閉且表定義沒有被修改的條件下,訪問該表,只需要從內(nèi)存中找到這個(gè)已經(jīng)緩存起來的對象做相應(yīng)操作即可。
江岸網(wǎng)站制作公司哪家好,找創(chuàng)新互聯(lián)!從網(wǎng)頁設(shè)計(jì)、網(wǎng)站建設(shè)、微信開發(fā)、APP開發(fā)、響應(yīng)式網(wǎng)站開發(fā)等網(wǎng)站項(xiàng)目制作,到程序開發(fā),運(yùn)營維護(hù)。創(chuàng)新互聯(lián)成立于2013年到現(xiàn)在10年的時(shí)間,我們擁有了豐富的建站經(jīng)驗(yàn)和運(yùn)維經(jīng)驗(yàn),來保證我們的工作的順利進(jìn)行。專注于網(wǎng)站建設(shè)就選創(chuàng)新互聯(lián)。
用戶訪問表時(shí),表對象在緩存時(shí): 通過HASH算法找到TABLE_SHARE,然后每個(gè)線程構(gòu)造各自的實(shí)例化TABLE即可。
用戶訪問表時(shí),當(dāng)表沒有被緩存的情況下: 第一需要打開表,首先需要從系統(tǒng)表中將這個(gè)表的所有信息都讀入內(nèi)存中,這些信息包括表名、庫名、所有列信息、列的默認(rèn)值、表的字符集、對應(yīng)的frm文件路徑、所屬存儲(chǔ)引擎、主鍵等,將這些信息構(gòu)造一個(gè)TABLE_SHARE結(jié)構(gòu)體,這個(gè)結(jié)構(gòu)體是表對象緩存的第一層,所有用戶共享訪問且為靜態(tài)不允許修改,它是緩存在table_def_cache(由參數(shù)table_definition_cache控制)中的。
而真正與用戶打交道的是TABLE_SHARE的衍生品,它對應(yīng)結(jié)構(gòu)體為TABLE,在被使用前需要將TABLE_SHARE結(jié)構(gòu)體實(shí)例化TABLE才能被使用,由每個(gè)線程構(gòu)造各自的實(shí)例化TABLE即可。(實(shí)例化的TABLE由table_open_cache及table_open_cache_instance控制)
注意1: DDL操作時(shí)會(huì)將所有instance鎖住,而DML操作時(shí)instance之間互不干擾。
(DDL statements still require a lock on the entire cache, but such statements are much less frequent than DML statements.)
注意2: 一個(gè)線程中如果打開表過多,超過一個(gè)instance限制的大小時(shí),是不能跨instance緩存的
(instance大?。簍able_open_cache / table_open_cache_instances)
表緩存涉及其他參數(shù): 通過下面參數(shù)判斷table_open_cache參數(shù)設(shè)置是否合理
table_open_cache_hit:能夠從table open cache的free list中找到table則為命中,+1
table_open_cache_misses:與table_open_cache_hit相反,如果找不到則需要重新實(shí)例化則+1,通常發(fā)生在初始化第一次加載表或超過table_open_cache的設(shè)置被淘汰后需要重新實(shí)例化。
table_open_cache_overflow:table cache淘汰的數(shù)量,每次淘汰+1
opened_tables:已經(jīng)打開的表數(shù)。如果Opened_tables很大,那么table_open_cache的值可能太小了。
open_tables:總的instance (table cache)的總數(shù)
1.首先明確是不是一定要上緩存,當(dāng)前架構(gòu)的瓶頸在哪里,若瓶頸真是數(shù)據(jù)庫操作上,再繼續(xù)往下看。
2.明確memcached和redis的區(qū)別,到底要使用哪個(gè)。前者終究是個(gè)緩存,不可能永久保存數(shù)據(jù)(LRU機(jī)制),支持分布式,后者除了緩存的同時(shí)也支持把數(shù)據(jù)持久化到磁盤等,redis要自己去實(shí)現(xiàn)分布式緩存(貌似最新版本的已集成),自己去實(shí)現(xiàn)一致性hash。因?yàn)椴恢滥銈兊膽?yīng)用場景,不好說一定要用memcache還是redis,說不定用mongodb會(huì)更好,比如在存儲(chǔ)日志方面。
3.緩存量大但又不常變化的數(shù)據(jù),比如評(píng)論。
應(yīng)用redis實(shí)現(xiàn)數(shù)據(jù)的讀寫,同時(shí)利用隊(duì)列處理器定時(shí)將數(shù)據(jù)寫入mysql。
同時(shí)要注意避免沖突,在redis啟動(dòng)時(shí)去mysql讀取所有表鍵值存入redis中,往redis寫數(shù)據(jù)時(shí),對redis主鍵自增并進(jìn)行讀取,若mysql更新失敗,則需要及時(shí)清除緩存及同步redis主鍵。
這樣處理,主要是實(shí)時(shí)讀寫redis,而mysql數(shù)據(jù)則通過隊(duì)列異步處理,緩解mysql壓力,不過這種方法應(yīng)用場景主要基于高并發(fā),而且redis的高可用集群架構(gòu)相對更復(fù)雜,一般不是很推薦。
應(yīng)用Redis實(shí)現(xiàn)數(shù)據(jù)的讀寫,同時(shí)利用隊(duì)列處理器定時(shí)將數(shù)據(jù)寫入MySQL。
同時(shí)要注意避免沖突,在redis啟動(dòng)時(shí)去mysql讀取所有表鍵值存入redis中,往redis寫數(shù)據(jù)時(shí),對redis主鍵自增并進(jìn)行讀取,若mysql更新失敗,則需要及時(shí)清除緩存及同步redis主鍵。
這樣處理,主要是實(shí)時(shí)讀寫redis,而mysql數(shù)據(jù)則通過隊(duì)列異步處理,緩解mysql壓力,不過這種方法應(yīng)用場景主要基于高并發(fā),而且redis的高可用集群架構(gòu)相對更復(fù)雜,一般不是很推薦。
《內(nèi)存數(shù)據(jù)庫和mysql的同步機(jī)制》
redis如何做到和mysql數(shù)據(jù)庫的同步
【方案一】
程序?qū)崿F(xiàn)mysql更新、添加、刪除就刪除redis數(shù)據(jù)。
程序查詢r(jià)edis,不存在就查詢mysql并保存redis
redis和mysql數(shù)據(jù)的同步,代碼級(jí)別大致可以這樣做:
讀: 讀redis-沒有,讀mysql-把mysql數(shù)據(jù)寫回redis
寫: 寫mysql-成功,寫redis(捕捉所有mysql的修改,寫入和刪除事件,對redis進(jìn)行操作)
【方案二】
實(shí)時(shí)獲取mysql binlog進(jìn)行解析,然后修改redis
MySQL到Redis數(shù)據(jù)方案
無論MySQL還是Redis,自身都帶有數(shù)據(jù)同步的機(jī)制,像比較常用的MySQL的Master/Slave模式,就是由Slave端分析Master的binlog來實(shí)現(xiàn)的,這樣的數(shù)據(jù)其實(shí)還是一個(gè)異步過程,只不過當(dāng)服務(wù)器都在同一內(nèi)網(wǎng)時(shí),異步的延遲幾乎可以忽略。
那么理論上我們也可以用同樣方式,分析MySQL的binlog文件并將數(shù)據(jù)插入Redis。但是這需要對binlog文件以及MySQL有非常深入的理解,同時(shí)由于binlog存在Statement/Row/Mixedlevel多種形式,分析binlog實(shí)現(xiàn)同步的工作量是非常大的。
因此這里選擇了一種開發(fā)成本更加低廉的方式,借用已經(jīng)比較成熟的MySQL UDF,將MySQL數(shù)據(jù)首先放入Gearman中,然后通過一個(gè)自己編寫的PHP Gearman Worker,將數(shù)據(jù)同步到Redis。比分析binlog的方式增加了不少流程,但是實(shí)現(xiàn)成本更低,更容易操作。
【方案三】
使用mysql的udf,詳情請看MySQL :: MySQL 5.1 Reference Manual :: 22.3 Adding New Functions to MySQL 然后通過trigger在表update和insert之后進(jìn)行函數(shù)的調(diào)用,寫入到redis中去。大致是這個(gè)樣子。
【】
1.首先明確是不是一定要上緩存,當(dāng)前架構(gòu)的瓶頸在哪里,若瓶頸真是數(shù)據(jù)庫操作上,再繼續(xù)往下看。
2.明確memcached和redis的區(qū)別,到底要使用哪個(gè)。前者終究是個(gè)緩存,不可能永久保存數(shù)據(jù)(LRU機(jī)制),支持分布式,后者除了緩存的同時(shí)也支持把數(shù)據(jù)持久化到磁盤等,redis要自己去實(shí)現(xiàn)分布式緩存(貌似最新版本的已集成),自己去實(shí)現(xiàn)一致性hash。因?yàn)椴恢滥銈兊膽?yīng)用場景,不好說一定要用memcache還是redis,說不定用MongoDB會(huì)更好,比如在存儲(chǔ)日志方面。
3.緩存量大但又不常變化的數(shù)據(jù),比如評(píng)論。
4.你的思路是對的,清晰明了,讀DB前,先讀緩存,如果有直接返回,如果沒有再讀DB,然后寫入緩存層并返回。
5.考慮是否需要主從,讀寫分離,考慮是否分布式部署,考慮是否后續(xù)水平伸縮。
6.想要一勞永逸,后續(xù)維護(hù)和擴(kuò)展方便,那就將現(xiàn)有的代碼架構(gòu)優(yōu)化,按你說的替換數(shù)據(jù)庫組件需要改動(dòng)大量代碼,說明當(dāng)前架構(gòu)存在問題??梢岳矛F(xiàn)有的一些框架,比如SpringMVC,將你的應(yīng)用層和業(yè)務(wù)層和數(shù)據(jù)庫層解耦。再上緩存之前把這些做好。
7.把讀取緩存等操作做成服務(wù)組件,對業(yè)務(wù)層提供服務(wù),業(yè)務(wù)層對應(yīng)用層提供服務(wù)。
8.保留原始數(shù)據(jù)庫組件,優(yōu)化成服務(wù)組件,方便后續(xù)業(yè)務(wù)層靈活調(diào)用緩存或者是數(shù)據(jù)庫。
9.不建議一次性全量上緩存,最開始不動(dòng)核心業(yè)務(wù),可以將邊緣業(yè)務(wù)先換成緩存組件,一步步換至核心業(yè)務(wù)。
10.刷新內(nèi)存,以memcached為例,新增,修改和刪除操作,一般采用lazy load的策略,即新增時(shí)只寫入數(shù)據(jù)庫,并不會(huì)馬上更新Memcached,而是等到再次讀取時(shí)才會(huì)加載到Memcached中,修改和刪除操作也是更新數(shù)據(jù)庫,然后將Memcached中的數(shù)據(jù)標(biāo)記為失效,等待下次讀取時(shí)再加載。