隨筆 - 73  文章 - 0  trackbacks - 0
     摘要: 簡介用簡單的話來定義tcpdump,就是:dump the traffic on a network,根據使用者的定義對網絡上的數據包進行截獲的包分析工具。 tcpdump可以將網絡中傳送的數據包的“頭”完全截獲下來提供分析。它支持針對網絡層、協議、主機、網絡或端口的過濾,并提供and、or、not等邏輯語句來幫助你去掉無用的信息。 實用命令實例默認啟動...  閱讀全文
posted @ 2019-09-19 15:21 長戟十三千 閱讀(3) | 評論 (0)編輯 收藏

在工作中,經?;崤齙紺PU占用100%的情況,那如何找到是那個線程占用了cpu呢? 

1. top命令,找到cpu占用最高的進程

2. 查看該進程的線程, top  -p <pid>

3. H 切換到線程模式,找到占用cpu最高的線程。并把線程號轉化為十六進制,printf "%x\n" <線程ID>

4. pstack <進程號>,把線程棧打印出來。找到對應的線程號就可以分析為什么線程會占用那么高的cpu了。

posted @ 2019-09-03 16:12 長戟十三千 閱讀(4) | 評論 (0)編輯 收藏
     摘要: 以下是對相關流程和socket錯誤碼正確處理的小結。一. Socket/Epoll主要遇到的問題:(1) 非阻塞socket下,接收流程(recv/recvfrom)對錯誤(EINTR/EAGAIN/EWOULDBLOCK)當成Fatal錯誤處理,產生頻繁斷連.(2)EPOLLERR/EPOLLHUP事件時,直接調用socket異常處理,產生頻繁斷連.(3)udp socket接收到size為0數...  閱讀全文
posted @ 2019-08-14 19:11 長戟十三千 閱讀(26) | 評論 (0)編輯 收藏
     摘要: 目前銀聯采用的方法是LT模式,如果epoll可讀(大于某個邊沿值),讀取需要的數據長度,從epollset中del掉,處理完邏輯之后再加入epollset,如果接收緩沖區仍然有數據,因為是LT模式,會繼續通知,重復上述過程(讀取需要的長度...),如果不del,則其他線程可能會讀取該fd接收緩沖區數據,因此存在競爭,采用的方式是在set中暫時del掉淘米框架則采用ET模式,可讀(只通知一次,后面不...  閱讀全文
posted @ 2019-08-14 19:01 長戟十三千 閱讀(7) | 評論 (0)編輯 收藏

開發高性能網絡程序時,windows開發者們言必稱iocp,linux開發者們則言必稱epoll。

大家都明白epoll是一種IO多路復用技術,可以非常高效的處理數以百萬計的socket句柄,比起以前的select和poll效率高大發了。

我們用起epoll來都感覺挺爽,確實快,那么,它到底為什么可以高速處理這么多并發連接呢?

原理介紹

先簡單回顧下如何使用C庫封裝的3個epoll系統調用吧。

1 int epoll_create(int size);     2 int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);     3 int epoll_wait(int epfd, struct epoll_event *events,int maxevents, int timeout);   

使用起來很清晰,

1 首先要調用epoll_create建立一個epoll對象。參數size是內核保證能夠正確處理的最大句柄數,多于這個最大數時內核可不保證效果。

2 epoll_ctl可以操作上面建立的epoll,例如,將剛建立的socket加入到epoll中讓其監控,或者把 epoll正在監控的某個socket句柄移出epoll,不再監控它等等。

3 epoll_wait在調用時,在給定的timeout時間內,當在監控的所有句柄中有事件發生時,就返回用戶態的進程。

從上面的調用方式就可以看到epoll比select/poll的優越之處:

因為后者每次調用時都要傳遞你所要監控的所有socket給select/poll系統調用,這意味著需要將用戶態的socket列表copy到內核態,如果以萬計的句柄會導致每次都要copy幾十幾百KB的內存到內核態,非常低效。

而我們調用epoll_wait時就相當于以往調用select/poll,但是這時卻不用傳遞socket句柄給內核,因為內核已經在epoll_ctl中拿到了要監控的句柄列表。

所以,實際上在你調用epoll_create后,內核就已經在內核態開始準備幫你存儲要監控的句柄了,每次調用epoll_ctl只是在往內核的數據結構里塞入新的socket句柄。

在內核里,一切皆文件。所以,epoll向內核注冊了一個文件系統,用于存儲上述的被監控socket。當你調用epoll_create時,就會在這個虛擬的epoll文件系統里創建一個file結點。當然這個file不是普通文件,它只服務于epoll。

epoll在被內核初始化時(操作系統啟動),同時會開辟出epoll自己的內核高速cache區,用于安置每一個我們想監控的socket,這些socket會以紅黑樹的形式保存在內核cache里,以支持快速的查找、插入、刪除。

這個內核高速cache區,就是建立連續的物理內存頁,然后在之上建立slab層,簡單的說,就是物理上分配好你想要的size的內存對象,每次使用時都是使用空閑的已分配好的對象。

 1 static int __init eventpoll_init(void)      2 {      3     ... ...      4       5     /* Allocates slab cache used to allocate "struct epitem" items */      6     epi_cache = kmem_cache_create("eventpoll_epi", sizeof(struct epitem),      7             0, SLAB_HWCACHE_ALIGN|EPI_SLAB_DEBUG|SLAB_PANIC,      8             NULL, NULL);      9      10     /* Allocates slab cache used to allocate "struct eppoll_entry" */     11     pwq_cache = kmem_cache_create("eventpoll_pwq",     12             sizeof(struct eppoll_entry), 0,     13             EPI_SLAB_DEBUG|SLAB_PANIC, NULL, NULL);     14      15  ... ...     

epoll的高效在于

當我們調用epoll_ctl往里塞入百萬個句柄時,epoll_wait仍然可以飛快的返回,并有效的將發生事件的句柄給我們用戶。

這是由于我們在調用epoll_create時,內核除了幫我們在epoll文件系統里建了個file結點,在內核cache里建了個紅黑樹用于存儲以后epoll_ctl傳來的socket外,還會再建立一個list鏈表,用于存儲準備就緒的事件,當epoll_wait調用時,僅僅觀察這個list鏈表里有沒有數據即可。

有數據就返回,沒有數據就sleep,等到timeout時間到后即使鏈表沒數據也返回。所以,epoll_wait非常高效。

而且,通常情況下即使我們要監控百萬計的句柄,大多一次也只返回很少量的準備就緒句柄而已,所以,epoll_wait僅需要從內核態copy少量的句柄到用戶態而已,如何能不高效?!

那么,這個準備就緒list鏈表是怎么維護的呢?

當我們執行epoll_ctl時,除了把socket放到epoll文件系統里file對象對應的紅黑樹上之外,還會給內核中斷處理程序注冊一個回調函數,告訴內核,如果這個句柄的中斷到了,就把它放到準備就緒list鏈表里。

所以,當一個socket上有數據到了,內核在把網卡上的數據copy到內核中后就來把socket插入到準備就緒鏈表里了。

如此,一顆紅黑樹,一張準備就緒句柄鏈表,少量的內核cache,就幫我們解決了大并發下的socket處理問題。

執行epoll_create時,創建了紅黑樹和就緒鏈表,執行epoll_ctl時,如果增加socket句柄,則檢查在紅黑樹中是否存在,存在立即返回,不存在則添加到樹干上,然后向內核注冊回調函數,用于當中斷事件來臨時向準備就緒鏈表中插入數據。執行epoll_wait時立刻返回準備就緒鏈表里的數據即可。

最后看看epoll獨有的兩種模式LT和ET。無論是LT和ET模式,都適用于以上所說的流程。區別是,LT模式下,只要一個句柄上的事件一次沒有處理完,會在以后調用epoll_wait時次次返回這個句柄,而ET模式僅在第一次返回。

這件事怎么做到的呢?

當一個socket句柄上有事件時,內核會把該句柄插入上面所說的準備就緒list鏈表,這時我們調用epoll_wait,會把準備就緒的socket拷貝到用戶態內存,然后清空準備就緒list鏈表,

最后,epoll_wait干了件事,就是檢查這些socket,如果不是ET模式(就是LT模式的句柄了),并且這些socket上確實有未處理的事件時,又把該句柄放回到剛剛清空的準備就緒鏈表了。

所以,非ET的句柄,只要它上面還有事件,epoll_wait每次都會返回。而ET模式的句柄,除非有新中斷到,即使socket上的事件沒有處理完,也是不會次次從epoll_wait返回的。

  1 /*     2  * Each file descriptor added to the eventpoll interface will     3  * have an entry of this type linked to the hash.     4  */     5 struct epitem {     6         /* RB-Tree node used to link this structure to the eventpoll rb-tree */     7         struct rb_node rbn;     8         //紅黑樹,用來保存eventpoll     9             10         /* List header used to link this structure to the eventpoll ready list */    11         struct list_head rdllink;    12         //雙向鏈表,用來保存已經完成的eventpoll    13             14         /* The file descriptor information this item refers to */    15         struct epoll_filefd ffd;    16         //這個結構體對應的被監聽的文件描述符信息    17             18         /* Number of active wait queue attached to poll operations */    19         int nwait;    20         //poll操作中事件的個數    21             22         /* List containing poll wait queues */    23         struct list_head pwqlist;    24         //雙向鏈表,保存著被監視文件的等待隊列,功能類似于select/poll中的poll_table    25             26         /* The "container" of this item */    27         struct eventpoll *ep;    28         //指向eventpoll,多個epitem對應一個eventpoll    29             30         /* The structure that describe the interested events and the source fd */    31         struct epoll_event event;    32         //記錄發生的事件和對應的fd    33            34         /*    35          * Used to keep track of the usage count of the structure. This avoids    36          * that the structure will desappear from underneath our processing.    37 */    38         atomic_t usecnt;    39         //引用計數    40             41         /* List header used to link this item to the "struct file" items list */    42         struct list_head fllink;    43         雙向鏈表,用來鏈接被監視的文件描述符對應的struct file。因為file里有f_ep_link,用來保存所有監視這個文件的epoll節點    44             45         /* List header used to link the item to the transfer list */    46         struct list_head txlink;    47         雙向鏈表,用來保存傳輸隊列    48             49         /*    50          * This is used during the collection/transfer of events to userspace    51          * to pin items empty events set.    52 */         53         unsigned int revents;    54         //文件描述符的狀態,在收集和傳輸時用來鎖住空的事件集合    55 };    56         57 //該結構體用來保存與epoll節點關聯的多個文件描述符,保存的方式是使用紅黑樹實現的hash表.    58 //至于為什么要保存,下文有詳細解釋。它與被監聽的文件描述符一一對應.    59 struct eventpoll {    60         /* Protect the this structure access */    61         rwlock_t lock;    62         //讀寫鎖    63            64         /*    65          * This semaphore is used to ensure that files are not removed    66          * while epoll is using them. This is read-held during the event    67          * collection loop and it is write-held during the file cleanup    68          * path, the epoll file exit code and the ctl operations.    69 */    70         struct rw_semaphore sem;    71         //讀寫信號量    72             73         /* Wait queue used by sys_epoll_wait() */    74         wait_queue_head_t wq;    75         /* Wait queue used by file->poll() */    76             77         wait_queue_head_t poll_wait;    78         /* List of ready file descriptors */    79             80         struct list_head rdllist;    81         //已經完成的操作事件的隊列。    82             83         /* RB-Tree root used to store monitored fd structs */    84         struct rb_root rbr;    85         //保存epoll監視的文件描述符    86 };    87     88 //這個結構體保存了epoll文件描述符的擴展信息,它被保存在file結構體的private_data    89 //中。它與epoll文件節點一一對應。通常一個epoll文件節點對應多個被監視的文件描述符。    90 //所以一個eventpoll結構體會對應多個epitem結構體。那么,epoll中的等待事件放在哪里呢?見下面    91 /* Wait structure used by the poll hooks */    92 struct eppoll_entry {    93         /* List header used to link this structure to the "struct epitem" */    94         struct list_head llink;    95         /* The "base" pointer is set to the container "struct epitem" */    96         void *base;    97         /*    98          * Wait queue item that will be linked to the target file wait    99          * queue head.   100 */   101         wait_queue_t wait;   102         /* The wait queue head that linked the "wait" wait queue item */   103         wait_queue_head_t *whead;   104 };   105    106 //與select/poll的struct poll_table_entry相比,epoll的表示等待隊列節點的結   107 //構體只是稍有不同,與struct poll_table_entry比較一下。   108 struct poll_table_entry {   109         struct file * filp;   110         wait_queue_t wait;   111         wait_queue_head_t * wait_address;   112 };  
posted @ 2019-08-14 18:41 長戟十三千 閱讀(18) | 評論 (0)編輯 收藏
768字節,而dynamic格式下,溢出的列只存儲前20字節,一旦發生了行溢出, dynamic其實就存儲一個指針,數據都放在溢出頁里,dynamic代表將長字段(發生行溢出)完全off-page存儲。

Row_format 引發異常的一個案例:
前幾天生產MYSQL遇到的一個問題,在錄入數據時,整行數據完全錄不進去,報以下錯:

Cause:java.sql.SQLException: com.taobao.tddl.common.exception.TddlException:java.sql.SQLException: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException:Row size too large (> 8126). Changing some columns to TEXT or BLOB or usingROW_FORMAT=DYNAMIC or ROW_FORMAT=COMPRESSED may help. In current row format,BLOB prefix of 768 bytes is stored inline.; nested exception iscom.ibatis.common.jdbc.exception.NestedSQLException:  

該表是一個產品介紹詳情表,有20多個TEXT 字段,剛好碰到了一個產品,每個字段錄入的數據都很長,
而mysql 中有了個限制,一個頁(這里pagesize 是16K)必須至少存2行,也就是說每行的存儲長度必須小于等于8192,而這么多 TEXT 字段,一行肯定是存不下來,也就是會發生溢出,而即例發生溢出,每個列仍然會存儲前768字節(該表的row_formart 是compact),字段一多還是超過了8192,于是就報錯,插不進了。
最后將表的row_format 改為 dynamic 得以解決。alter table … row_format=dynamic;

所以,如果大家遇到一些表TEXT 或 VARCHAR 大字段很多,又不好拆解時,可能需要考慮下溢出后列的長度了,如果溢出后列的長度還是太大,則要看一下表的 row_format :

show table status like '%xxx%'\G  

必要時需要將其實設置為 dynamic 如:

create table test(id int,name text,...... ) row_format=dynamic; 或 alter table test row_format=dynamic;
posted @ 2019-08-14 15:38 長戟十三千 閱讀(12) | 評論 (0)編輯 收藏

記得一次面試中,面試官問我是否知道表的壓縮,這個時候我才知道mysql有個表壓縮這么個功能,今天試用下看看表的壓縮率怎么樣。

這里分兩個部分說明,第一部分:官方文檔說明;第二部分:具體實例測試。

【第一部分】

一、表壓縮概述:

表壓縮可以在創建表時開啟,壓縮表能夠使表中的數據以壓縮格式存儲,壓縮能夠顯著提高原生性能和可伸縮性。壓縮意味著在硬盤和內存之間傳輸的數據更小且占用相對少的內存及硬盤,對于輔助索引,這種壓縮帶來更加明顯的好處,因為索引數據也被壓縮了。壓縮對于硬盤是SSD的存儲設備尤為重要,因為它們相對普通的HDD硬盤比較貴且容量有限。

我們都知道,CPU和內存的速度遠遠大于磁盤,因為對于數據庫服務器,磁盤IO可能會成為緊要資源或者瓶頸。數據壓縮能夠讓數據庫變得更小,從而減少磁盤的I/O,還能提高系統吞吐量,以很小的成本(耗費較多的CPU資源)。對于讀比重比較多的應用,壓縮是特別有用。壓縮能夠讓系統擁有足夠的內存來存儲熱數據。

在創建innodb表時帶上ROW_FORMAT=COMPRESSED參數能夠使用比默認的16K更小的頁。這樣在讀寫時需要更少的I/O,對于SSD磁盤更有價值。

頁的大小通過KEY_BLOCK_SIZE參數指定。不同大小的頁意味著需要使用獨立表空間,不能使用系統共享表空間,可以通過innodb_file_per_table指定。KEY_BLOCK_SIZE的值越小,你獲得I/O好處就越多,但是如果因為你指定的值太小,當數據被壓縮到不足夠滿足每頁多行數據記錄時,會產生額外的開銷來重組頁。對于一個表,KEY_BLOCK_SIZE的值有多小是有嚴格的限制的,一般是基于每個索引鍵的長度。有時指定值過小,當create table或者alter table會失敗。

在緩沖池中,被壓縮的數據是存儲在小頁中的,這個小頁的實際大小就是KEY_BLOCK_SIZE的值。為了提取和更新列值,mysql也會在緩沖池中創建一個未壓縮的16k頁。任何更新到未壓縮的頁也需要重新寫入到壓縮的頁,這時你需要估計緩沖池的大小以滿足壓縮和未壓縮的頁,盡管當緩沖空間不足時,未壓縮的頁會被擠出緩沖池。在下次訪問時,不壓縮的頁還會被創建。

二、使用表的壓縮

在創建一個壓縮表之前,需要啟用獨立表空間參數innodb_file_per_table=1;也需要設置innodb_file_format=Barracuda,你可以寫到my.cnf文件中不需要重啟mysql服務。

SET GLOBAL innodb_file_per_table=1; SET GLOBAL innodb_file_format=Barracuda; CREATE TABLE t1  (c1 INT PRIMARY KEY)   ROW_FORMAT=COMPRESSED    KEY_BLOCK_SIZE=8;
  • 如果你指定ROW_FORMAT=COMPRESSED,那么可以忽略KEY_BLOCK_SIZE的值,這時使用默認innodb頁的一半,即8kb;
  • 如果你指定了KEY_BLOCK_SIZE的值,那么你可以忽略ROW_FORMAT=COMPRESSED,因為這時會自動啟用壓縮;
  • 為了指定最合適KEY_BLOCK_SIZE的值,你可以創建表的多個副本,使用不同的值進行測試,比較他們的.ibd文件的大??;
  • KEY_BLOCK_SIZE的值作為一種提示,如必要,Innodb也可以使用一個不同的值。0代表默認壓縮頁的值,Innodb頁的一半。KEY_BLOCK_SIZE的值只能小于等于innodb page size。如果你指定了一個大于innodb page size的值,mysql會忽略這個值然后產生一個警告,這時KEY_BLOCK_SIZE的值是Innodb頁的一半。如果設置了innodb_strict_mode=ON,那么指定一個不合法的KEY_BLOCK_SIZE的值是返回報錯。

InnoDB未壓縮的數據頁是16K,根據選項組合值,mysql為每個表的.ibd文件使用1kb,2kb,4kb,8kb,16kb頁大小,實際的壓縮算法并不會受KEY_BLOCK_SIZE值影響,這個值只是決定每個壓縮塊有多大,從而影響多少行被壓縮到每個頁。設置KEY_BLOCK_SIZE等于16k并不能有效的進行壓縮,因為默認的innodb頁就是16k,但是對于擁有很多BLOB,TEXT,VARCHAR類型字段的表可能會有效果的。

三、InnoDB表的壓縮優化

 在進行表壓縮時需要考慮影響壓縮性能的因素,如:

  • 哪些表需要壓縮
  • 如何選擇壓縮表的頁大小
  • 基于運行時性能特征是否需要調整buffer pool大小,如系統在壓縮和解壓縮數據所花費的時間量,系統負載更像一個數據倉庫還是OLTP事務性系統。
  • 如果在壓縮表上執行DML操作,由于數據分布的方式,可能導致壓縮失敗,這時你可能需要配置額外的更高級的配置選項

1、何時用壓縮表

一般而言,對于讀遠遠大于寫的應用以及擁有合理數量的字符串列的表,使用壓縮效果會更好。

2、數據特性及壓縮率

影響數據文件壓縮效率的一個關鍵因素是數據本身的結構,在塊數據中,壓縮是通過識別重復字符進行壓縮的,對于完全隨機的數據是一個糟糕的情況,一般而言,有重復數據的壓縮更好。對于字符串的列壓縮就不錯,無論是string還是blob、text等類型的。另一方面,如果表中的數據是二進制類型,如整形、浮點型等或者之前別壓縮過的如jpg、png類型的,壓縮效果一般不好,但也不是絕對的。

為了決定是否對某個表進行壓縮,你需要進行試驗,可以對比未壓縮與壓縮后的數據文件的大小,以及監控系統對于壓縮表的工作負載進行決定。具體試驗請查看第二部分。

查看監控壓縮表的負載,如下:

  • 對于簡單的測試,如一個mysql實例上沒有其他的壓縮表了,直接查詢INFORMATION_SCHEMA.INNODB_CMP表數據即可,該表存一些壓縮表的數據狀態,結構如下:
Column nameDescription
PAGE_SIZE采用壓縮頁大?。ㄗ紙謔?
COMPRESS_OPSNumber of times a B-tree page of the size PAGE_SIZE has been compressed. Pages are compressed whenever an empty page is created or the space for the uncompressed modification log runs out.
COMPRESS_OPS_OKNumber of times a B-tree page of the size PAGE_SIZE has been successfully compressed. This count should never exceed COMPRESS_OPS.
COMPRESS_TIMETotal time in seconds spent in attempts to compress B-tree pages of the size PAGE_SIZE.
UNCOMPRESS_OPSNumber of times a B-tree page of the size PAGE_SIZE has been uncompressed. B-tree pages are uncompressed whenever compression fails or at first access when the uncompressed page does not exist in the buffer pool.
UNCOMPRESS_TIMETotal time in seconds spent in uncompressing B-tree pages of the size PAGE_SIZE.
  • 對于精細的測試,如多個壓縮表,查詢INFORMATION_SCHEMA.INNODB_CMP_PER_INDEX表數據,由于該表收集數據需要付出昂貴得代價,所以必須啟動innodb_cmp_per_index_enabled選項才能查詢。一般不要在生產環境下開啟該選項。
  • 還可以針對壓縮運行一些測試SQL看看效率如何。
  • 如果發現很多壓縮失敗,那么你可以調整innodb_compression_levelinnodb_compression_failure_threshold_pct, 和innodb_compression_pad_pct_max參數。

3、數據庫壓縮和應用程序壓縮

不需要在應用端和數據庫同時壓縮相同的數據,那樣效果并不明顯而且還消耗很多CPU資源。對于數據庫壓縮,是在server端進行的。如果你在插入數據前通過代碼進行數據壓縮,然后插入數據庫,這樣耗費很多CPU資源,當然如果你的CPU有大量結余。你也可以結合兩者,對于某些表進行應用程序壓縮,而對其他數據采用數據庫壓縮。

4、工作負載特性和壓縮率

為了選擇哪些表可以使用壓縮,工作負載是另一個決定因素,一般而言,如果你的系統是I/O瓶頸,那么可以使用CPU進行壓縮與解壓縮,以CPU換取I/O。

四、INNODB表是如何壓縮的?

1、壓縮算法

mysql進行壓縮是借助于zlib庫,采用L777壓縮算法,這種算法在減少數據大小、CPU利用方面是成熟的、健壯的、高效的。同時這種算法是無失真的,因此原生的未壓縮的數據總是能夠從壓縮文件中重構,LZ777實現原理是查找重復數據的序列號然后進行壓縮,所以數據模式決定了壓縮效率,一般而言,用戶的數據能夠被壓縮50%以上。

不同于應用程序壓縮或者其他數據庫系統的壓縮,InnoDB壓縮是同時對數據和索引進行壓縮,很多情況下,索引能夠占數據庫總大小的40%-50%。如果壓縮效果很好,一般innodb文件會減少25%-50%或者更多,而且減少I/O增加系統吞吐量,但是會增加CPU的占用,你可通過設置innodb_compression_level參數來平衡壓縮級別和CPU占用。

2、InnoDB數據存儲及壓縮

所有數據和b-tree索引都是按頁進行存儲的,每行包含主鍵和表的其他列。輔助索引也是b-tree結構的,包含對值:索引值及指向每行記錄的指針,這個指針實際上就是表的主鍵值。

在innodb壓縮表中,每個壓縮頁(1,2,4,8)都對應一個未壓縮的頁16K,為了訪問壓縮頁中的數據,如果該頁在buffer pool中不存在,那么就從硬盤上讀到這個壓縮頁,然后進行解壓到原來的數據結構。為了最小化I/O和減少解壓頁的次數,有時,buffer pool中包括壓縮和未壓縮的頁,為給其他頁騰出地方,buffer pool會驅逐未壓縮頁,僅僅留下壓縮頁在內存中?;蛘呷綣桓鲆騁歡問奔涿揮斜環夢?,那么會被寫到硬盤上。這樣一來,任何時候,buffer pool中都可以包含壓縮頁和未壓縮頁,或者只有壓縮頁或者兩者都沒有。

Mysql采用LRU算法來保證哪些頁應該在內存中還是被驅逐。因此熱數據一般都會在內存中。

五、OLTP系統壓縮負載優化

一般而言,innodb壓縮對于只讀或者讀比重比較多的應用效果更好,SSD的出現,使得壓縮更加吸引我們,尤其對于OLTP系統。對于經常update、delete、insert的應用,通過壓縮表能夠減少他們的存儲需求和每秒I/O操作。

下面是針對寫密集的應用,設置壓縮表的一些有用參數:

  • innodb_compression_level:決定壓縮程度的參數,如果你設置比較大,那么壓縮比較多,耗費的CPU資源也較多;相反,如果設置較小的值,那么CPU占用少。默認值6,可以設置0-9
  • innodb_compression_failure_threshold_pct:默認值5,范圍0到100.設置中斷點避免高昂的壓縮失敗率。
  • innodb_compression_pad_pct_max:指定在每個壓縮頁面可以作為空閑空間的最大比例,該參數僅僅應用在設置了innodb_compression_failure_threshold_pct不為零情況下,并且壓縮失敗率通過了中斷點。默認值50,可以設置范圍是0到75.

【第二部分】實驗:

復制代碼
#沒有設置壓縮前的數據大小 -rw-rw----. 1 mysql mysql 368M 12月 29 11:05 test.ibd #設置KEY_BLOCK_SIZE=1 (product)root@localhost [sakila]> alter table test KEY_BLOCK_SIZE=1; Query OK, 0 rows affected (14 min 49.30 sec) Records: 0  Duplicates: 0  Warnings: 0  -rw-rw----. 1 mysql mysql 204M 1月  11 21:43 test.ibd      #####壓縮率44.5%
#設置KEY_BLOCK_SIZE=2 (product)root@localhost [sakila]> alter table test KEY_BLOCK_SIZE=2; Query OK, 0 rows affected (9 min 55.60 sec) Records: 0 Duplicates: 0 Warnings: 0 -rw-rw----. 1 mysql mysql 180M 1月 12 13:40 test.ibd #####壓縮率51% #設置KEY_BLOCK_SIZE=4 (product)root@localhost [sakila]> alter table test KEY_BLOCK_SIZE=4; Query OK, 0 rows affected (7 min 24.52 sec) Records: 0 Duplicates: 0 Warnings: 0 -rw-rw----. 1 mysql mysql 172M 1月 11 21:09 test.ibd #####壓縮率53.2% #設置KEY_BLOCK_SIZE=8 (product)root@localhost [sakila]> alter table test KEY_BLOCK_SIZE=8; Query OK, 0 rows affected (5 min 16.34 sec) Records: 0 Duplicates: 0 Warnings: 0 -rw-rw----. 1 mysql mysql 172M 1月 11 21:00 test.ibd #####壓縮率53.2% #設置KEY_BLOCK_SIZE=16 (product)root@localhost [sakila]> alter table test KEY_BLOCK_SIZE=16; Query OK, 0 rows affected (2 min 47.48 sec) Records: 0 Duplicates: 0 Warnings: 0 -rw-rw----. 1 mysql mysql 336M 1月 12 13:54 test.ibd #####壓縮率8.6%  
復制代碼

【總結】:通過以上測試可知,當KEY_BLOCK_SIZE的值設置為4或者8時,壓縮效果最好,設置為16效果最差,因為頁的默認值16K。通常我是設置為8。

posted @ 2019-08-14 15:31 長戟十三千 閱讀(7) | 評論 (0)編輯 收藏
      Row_format: Compressed            Rows: 0  Avg_row_length: 0     Data_length: 8192 Max_data_length: 0    Index_length: 0       Data_free: 0  Auto_increment: NULL     Create_time: 2013-09-27 16:09:51     Update_time: NULL      Check_time: NULL       Collation: utf8_general_ci        Checksum: NULL  Create_options: row_format=COMPRESSED KEY_BLOCK_SIZE=8         Comment: 1 row in set (0.00 sec)
復制代碼

 

No3:


 

發現和innodb_file_format相關的2個參數:

復制代碼
+--------------------------+-----------+ | Variable_name            | Value     | +--------------------------+-----------+ | innodb_file_format       | Barracuda | | innodb_file_format_check | ON        | | innodb_file_format_max   | Barracuda | +--------------------------+-----------+ 3 rows in set (0.00 sec)
復制代碼

官方的解釋可以參考如下的鏈接://dev.mysql.com/doc/refman/5.5/en/innodb-parameters.html#sysvar_innodb_file_format

測試過程中發現,如果是innodb_file_format=barracuda而innodb_file_format_max=antelop,那么在建立壓縮表的時候,max會自動變成barracuda。

復制代碼
localhost.test>show global variables like 'innodb_file_format%'; +--------------------------+-----------+ | Variable_name            | Value     | +--------------------------+-----------+ | innodb_file_format       | Barracuda | | innodb_file_format_check | ON        | | innodb_file_format_max   | Antelope  | +--------------------------+-----------+ 3 rows in set (0.00 sec)  localhost.test>create table test_4(x int) ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8; Query OK, 0 rows affected (0.01 sec)  localhost.test>show global variables like 'innodb_file_format%'; +--------------------------+-----------+ | Variable_name            | Value     | +--------------------------+-----------+ | innodb_file_format       | Barracuda | | innodb_file_format_check | ON        | | innodb_file_format_max   | Barracuda | +--------------------------+-----------+ 3 rows in set (0.00 sec)
復制代碼

如果innodb_file_format_check這參數解釋的,決定innodb是否會檢查共享表空間中的表格式的tag,如果檢查開啟,那么當標記的表格式的tag高于innodb可以支撐的表格式,那么innodb會報錯,并停止啟動。如果支持,那么會將innodb_file_format_max的值改為這個tag的值。

posted @ 2019-08-14 15:24 長戟十三千 閱讀(14) | 評論 (0)編輯 收藏
 解決辦法:
vim /etc/my.cnf,根據實際情況進行參數調整:
[mysqld]
max_allowed_packet = 1G
innodb_log_file_size = 30M
innodb_log_buffer_size = 512M
innodb_file_format='Barracuda'


alter table 'role' row_format=dynamic
修改之后,重啟mysql服務。 

mysql文檔
https://dev.mysql.com/doc/relnotes/mysql/5.6/en/news-5-6-20.html
In MySQL 5.6.22, the redo log BLOB write limit is relaxed to 10% of the total redo log size (innodb_log_file_size * innodb_log_files_in_group).



# For advice on how to change settings please see
# //dev.mysql.com/doc/refman/5.6/en/server-configuration-defaults.html
# *** DO NOT EDIT THIS FILE. It's a template which will be copied to the
# *** default location during install, and will be replaced if you
# *** upgrade to a newer version of MySQL.

[mysqld]

# Remove leading # and set to the amount of RAM for the most important data
# cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%.
# innodb_buffer_pool_size = 128M

# Remove leading # to turn on a very important data integrity option: logging
# changes to the binary log between backups.
# log_bin

# These are commonly set, remove the # and set as required.
# basedir = .....
# datadir = .....
# port = .....
#server_id = 1
# socket = .....

# Remove leading # to set options mainly useful for reporting servers.
# The server defaults are faster for transactions and fast SELECTs.
# Adjust sizes as needed, experiment to find the optimal values.
# join_buffer_size = 128M
# sort_buffer_size = 2M
# read_rnd_buffer_size = 2M 
#sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES 
port=3306
basedir=/data/mysql
datadir=/data/mysql/mysqldata
log-error=/data/mysql/log
socket=/tmp/mysqld.sock
server_id=1
back_log=2048
log-bin=mysql-bin 
bind-address=0.0.0.0
character-set-server=utf8
collation-server=utf8_general_ci
skip-external-locking
skip-name-resolve
query_cache_type=0
max_connections=2000
max_connect_errors=1000000
default-storage-engine=INNODB
innodb_buffer_pool_size=12884901888
innodb_concurrency_tickets=5000
innodb_flush_method=O_DIRECT
innodb_io_capacity=2000
innodb_io_capacity_max=4000
innodb_log_buffer_size=1048576
innodb_log_file_size=1048576000
innodb_log_files_in_group=2
innodb_file_format=Barracuda
innodb_file_per_table=ON
innodb_file_format_max=Antelope
innodb_max_dirty_pages_pct=75
innodb_open_files=3000
innodb_additional_mem_pool_size=20M
innodb_sort_buffer_size=8388608
join_buffer_size=262144
key_buffer_size=16777216
preload_buffer_size=32768
read_buffer_size=262144
read_rnd_buffer_size=262144
sort_buffer_size=262144
max_allowed_packet=1073741824
binlog_stmt_cache_size=32768
bulk_insert_buffer_size=4194304
key_buffer=64M
slow_query_log=1
slow_query_log_file=/data/mysql/log
long_query_time=5
sync_frm=ON
max_binlog_size=524288000
sync_binlog=1000
binlog_format=ROW
binlog_cache_size=2097152
expire_logs_days=3
tmpdir=/data/mysql/tmpdir
max_tmp_tables=32
tmp_table_size=262144
open_files_limit=65535
table_definition_cache=512
table_open_cache=100
default_storage_engine=InnoDB
default_tmp_storage_engine=InnoDB
log_queries_not_using_indexes=ON
interactive_timeout=7200
lock_wait_timeout=31536000
wait_timeout=86400
connect_timeout=120
pid_file=/data/mysql/mysqldata/mysqld.pid
slave-skip-errors=1062,1053,1146,1061

[mysql]
port=3306
socket=/tmp/mysqld.sock
default-character-set=utf8
posted @ 2019-08-08 18:11 長戟十三千 閱讀(14) | 評論 (0)編輯 收藏
     摘要: attribute是GNU C特色之一,在iOS用的比較廣泛.系統中有許多地方使用到. attribute可以設置函數屬性(Function Attribute )、變量屬性(Variable Attribute )和類型屬性(Type Attribute)等.函數屬性(Function Attribute)noreturnnoinlinealways_inlinepureconstno...  閱讀全文
posted @ 2019-01-26 15:28 長戟十三千 閱讀(76) | 評論 (0)編輯 收藏
僅列出標題  下一頁