随笔 - 71  文章 - 0  trackbacks - 0
<2019年8月>
28293031123
45678910
11121314151617
18192021222324
25262728293031
1234567

常用链接

留言簿

随笔分类

随笔档案

收藏夹

调试技巧

搜索

  •  

最新评论

阅读排行榜

评论排行榜

60天内阅读排行

     摘要: 以下是对相关流程和socket错误码正?#21453;?#29702;的小结。一. Socket/Epoll主要遇到的问题:(1) 非阻塞socket下,接收流程(recv/recvfrom)对错误(EINTR/EAGAIN/EWOULDBLOCK)当成Fatal错误处理,产生频繁断连.(2)EPOLLERR/EPOLLHUP?#24405;?#26102;,直接调用socket异常处理,产生频繁断连.(3)udp socket接收到size为0数...  阅读全文
posted @ 2019-08-14 19:11 长戟十三千 阅读(10) | 评论 (0)编辑 收藏
     摘要: 目前银联采用的方法是LT模式,如果epoll可读(大于某个边沿值),读取需要的数据长度,从epollset中del掉,处理完逻辑之后再加入epollset,如果接收缓冲区仍然有数据,因为是LT模式,会继续通知,重复上述过程(读取需要的长度...),如果不del,则其他线程可能会读取该fd接收缓冲区数据,因此存在竞争,采用的方式是在set中暂时del掉淘米框架则采用ET模式,可读(只通知一次,后面不...  阅读全文
posted @ 2019-08-14 19:01 长戟十三千 阅读(1) | 评论 (0)编辑 收藏

开发高?#38405;?#32593;络程序时,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是内核保证能够正?#21453;?#29702;的最大句柄数,多于这个最大数时内核可不保证效果。

2 epoll_ctl可以操作上面建立的epoll,例如,将刚建立的socket加入到epoll中让其监控,或者把 epoll正在监控的某个socket句柄移出epoll,不再监控它等?#21462;?/p>

3 epoll_wait在调用时,在给定的timeout时间内,当在监控的所有句柄中有?#24405;?#21457;生时,就返回用户态的进程。

从上面的调用方式就可以看到epoll比select/poll的优越之处:

因为后者?#30475;?#35843;用时都要传递你所要监控的所有socket给select/poll系统调用,这意味着需要将用户态的socket列表copy到内核态,如果以万计的句柄会导致?#30475;?#37117;要copy几十几百KB的内存到内核态,非常低效。

而我们调用epoll_wait时就相当于以往调用select/poll,但是这时却不用传递socket句柄给内核,因为内核已经在epoll_ctl中拿到了要监控的句柄列表。

所以,实际上在你调用epoll_create后,内核就已经在内核态开始准备帮你存储要监控的句柄了,?#30475;?#35843;用epoll_ctl只是在往内核的数据结构里塞入新的socket句柄。

在内核里,一切皆文件。所以,epoll向内核注册了一个文件系?#24120;?#29992;于存储上述的被监控socket。当你调用epoll_create时,就会在这个虚拟的epoll文件系统里创建一个file结点。当然这个file不是普通文件,它只服务于epoll。

epoll在被内核初始化时(操作系?#31216;?#21160;),同时会开辟出epoll自己的内核高速cache区,用于安置每一个我们想监控的socket,这些socket会以红黑树的?#38382;?#20445;存在内核cache里,以支持快速的查找、插入、删除。

这个内核高速cache区,就是建立连续的物理内存页,然后在之上建立slab层,简单的说,就是物理上分配好你想要的size的内存对象,?#30475;问?#29992;时都是使用空闲的已分配好的对象。

 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仍然可以飞快的返回,并?#34892;?#30340;将发生?#24405;?#30340;句柄给我们用户。

这是由于我们在调用epoll_create时,内核除了帮我们在epoll文件系统里建了个file结点,在内核cache里建了个红黑树用于存储以后epoll_ctl传来的socket外,还会再建立一个list链表,用于存储准备就绪的?#24405;?#24403;epoll_wait调用时,仅仅观察这个list链表里有没有数据即可。

有数据就返回,没有数据就sleep,等到timeout时间到后即使链表没数据也返回。所以,epoll_wait非常高效。

而且,通常情况下即使我们要监控百万计的句柄,大多一?#25105;?#21482;返回很少量的准备就绪句柄而已,所以,epoll_wait仅需要从内核态copy少量的句柄到用户态而已,如?#25991;?#19981;高效?!

那么,这个准备就绪list链表是怎?#27425;?#25252;的呢?

当我们执行epoll_ctl时,除了把socket放到epoll文件系统里file对象对应的红黑树上之外,还会给内核中断处理程序注册一个回调函数,告诉内核,如果这个句柄的中?#31995;?#20102;,就把它放到准备就绪list链表里。

所以,当一个socket上有数据到了,内核在把网卡?#31995;?#25968;据copy到内核中后就来把socket插入到准备就绪链表里了。

如此,一颗红黑树,一张准备就绪句柄链表,少量的内核cache,就帮我们解决了大并发下的socket处理问题。

执行epoll_create时,创建了红黑树和就绪链表,执行epoll_ctl时,如果增加socket句柄,则检查在红黑树中是否存在,存在立即返回,不存在则添加到树干上,然后向内核注册回调函数,用于当中断?#24405;?#26469;临时向准备就绪链表中插入数据。执行epoll_wait时立刻返回准备就绪链表里的数据即可。

最后看看epoll独有的两种模式LT和ET。无论是LT和ET模式,?#38469;?#29992;于以上所说的流程。区别是,LT模式下,只要一个句柄?#31995;氖录?#19968;次没?#20889;?#29702;完,会在以后调用epoll_wait时次次返回这个句柄,而ET模式仅在第一次返回。

这件事怎么做到的呢?

当一个socket句柄上有?#24405;?#26102;,内核会把该句柄插入上面所说的准备就绪list链表,这时我们调用epoll_wait,会把准备就绪的socket拷贝到用户态内存,然后清空准备就绪list链表,

最后,epoll_wait干了件事,就是检查这些socket,如果不是ET模式(就是LT模式的句柄了),并且这些socket上确实有未处理的?#24405;?#26102;,又把该句柄放回到刚刚清空的准备就绪链表了。

所以,非ET的句柄,只要它上面还有?#24405;琫poll_wait?#30475;?#37117;会返回。而ET模式的句柄,除非有新中?#31995;劍?#21363;使socket?#31995;氖录?#27809;?#20889;?#29702;完,也是不会次次从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操作中?#24405;?#30340;个数    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         //记录发生的?#24405;?#21644;对应的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         //文件描述符的状态,在收集和传输时用?#27492;?#20303;空的?#24405;?#38598;合    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         //已经完成的操作?#24405;?#30340;队?#23567;?   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中的等待?#24405;?#25918;在哪里呢?见下面    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 //构体只?#24039;?#26377;不同,与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 长戟十三千 阅读(4) | 评论 (0)编辑 收藏
768字节,而dynamic格式下,溢出的列只存储前20字节,一旦发生了行溢出, dynamic其实就存储一个?#21018;耄?#25968;据都放在溢出页里,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:  

该表是一个产?#26041;?#32461;详情表,有20多个TEXT 字段,刚好碰到了一个产品,每个字段录入的数据都很长,
而mysql 中有了个限制,一个页(这里pagesize 是16K)必须至少存2行,?#31807;?#26159;说每行的存储长度必须小于等于8192,而这么多 TEXT 字段,一行肯定是存不下来,?#31807;?#26159;会发生溢出,而即例发生溢出,每个列仍然会存储前768字节(该表的row_formart 是compact),字段一多还是超过了8192,于是就报错,插不进了。
最后将表的row_format 改为 dynamic 得以解决。alter table … row_format=dynamic;

所以,如果大家遇到一些表TEXT 或 VARCHAR 大字段很多,又?#32531;?#25286;解时,可能需要考虑下溢出后列的长度了,如果溢出后列的长度还是太大,则要看一下表的 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 长戟十三千 阅读(4) | 评论 (0)编辑 收藏

记得一次面试中,面试官问我是否知道表的压缩,这个时候我才知道mysql有个表压缩这么个功能,今天试用下看看表的压缩?#35797;?#20040;样。

这里分两个部分说明,第一部分:官方文档说明;第二部分:具体实例测试。

【第一部分】

一、表压缩概述:

表压缩可以在创建表时开启,压缩表能够使表中的数据以压缩格式存储,压缩能够显著提高原生?#38405;?#21644;可伸缩性。压缩意味着在?#25165;?#21644;内存之间传输的数据更小且占用相对少的内存及?#25165;蹋?#23545;于辅助索引,这种压缩带来更?#29992;?#26174;的好处,因为索引数据也被压缩了。压缩对于?#25165;?#26159;SSD的存储设备尤为重要,因为它们相对普通的HDD?#25165;?#27604;较贵且容?#22353;?#38480;。

我们都知道,CPU和内存的速度?#23545;?#22823;于?#25490;蹋?#22240;为对于数据库服务器,?#25490;蘄O可能会成为紧要?#35797;?#25110;者瓶颈。数据压缩能够让数据库变得更小,从而减少?#25490;?#30340;I/O,还能提高系统吞吐量,以很小的成本(耗费较多的CPU?#35797;矗?#23545;于读比重比较多的应用,压缩是特别有用。压缩能够让系统拥有足够的内存来存储热数据。

在创建innodb表时带上ROW_FORMAT=COMPRESSED参数能够使用比默?#31995;?6K更小的页。这样在读写时需要更少的I/O,对于SSD?#25490;?#26356;有价值。

页的大小通过KEY_BLOCK_SIZE参数指定。不同大小的页意味着需要使用独立表空间,不能使用系统共享表空间,可以通过innodb_file_per_table指定。KEY_BLOCK_SIZE的值越小,你获得I/O好处就越多,但是如果因为你指定的值太小,?#31508;?#25454;被压缩到不足够满足每页多行数据记录时,会产生额外的开销来重组页。对于一个表,KEY_BLOCK_SIZE的值有多小是有?#32454;?#30340;限制的,一般是基于每个索引键的长?#21462;?#26377;时指定值过小,当create table或者alter table会失败。

在缓冲池中,被压缩的数据是存储在小页中的,这个小页的实际大小就是KEY_BLOCK_SIZE的值。为了提取和更新列值,mysql也会在缓冲池?#20889;?#24314;一个未压缩的16k页。任何更新到未压缩的页也需要重新写入到压缩的页,这时你需要估计缓冲池的大小?#26376;?#36275;压缩和未压缩的页,尽管当缓冲空间不足时,未压缩的页会被挤出缓冲池。在下次访问时,不压缩的页还会被创建。

二、使用表的压缩

在创建一个压缩表之前,需要启用独立表空间参数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的值,这?#31508;?#29992;默认innodb页的一半,即8kb;
  • 如果你指定了KEY_BLOCK_SIZE的值,那么你可以忽略ROW_FORMAT=COMPRESSED,因为这时会自动启用压缩;
  • 为了指定最合适KEY_BLOCK_SIZE的值,你可以创建表的多个副本,使用不同的?#21040;?#34892;测试,比较他们的.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并不能?#34892;?#30340;进行压缩,因为默?#31995;膇nnodb页就是16k,但是对于拥有很多BLOB,TEXT,VARCHAR类型字段的表可能会?#34892;?#26524;的。

三、InnoDB表的压缩优化

 在进行表压缩时需要考虑影响压缩?#38405;?#30340;因素,如:

  • 哪些表需要压缩
  • 如何选择压缩表的页大小
  • 基于运行时?#38405;?#29305;征是否需要调整buffer pool大小,如系统在压缩和解压缩数据所花费的时间量,系统负载更像一个数据仓库还是OLTP事务性系统。
  • 如果在压缩表上执行DML操作,由于数据分布的方式,可能导致压缩失败,这时你可能需要配置额外的更高级的配置选项

1、何时用压缩表

一般而言,对于读?#23545;?#22823;于写的应用以及拥有合理数量的字符串列的表,使用压缩效果会更好。

2、数据特性及压缩率

影响数据文件压缩效率的一个关键因素是数据本身的结构,在块数据中,压缩是通过识别重复字符进行压缩的,对于完全随机的数据是一个糟糕的情况,一般而言,有重复数据的压缩更好。对于字符串的列压缩就不错,无论是string还是blob、text等类型的。另一方面,如果表中的数据是二进?#35780;?#22411;,如整形、浮点型?#28982;?#32773;之前别压缩过的如jpg、png类型的,压缩效果一般?#32531;茫?#20294;也不是绝对的。

为了决定是否?#38405;?#20010;表进行压缩,你需要进行试验,可以对比未压缩与压缩后的数据文件的大小,以及监控系统对于压缩表的工作负载进行决定。具体试验请查看第二部分。

查看监控压缩表的负载,如下:

  • 对于简单的测试,如一个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、数据库压缩和应用程序压缩

不需要在应用端和数据库同时压缩相同的数据,那样效果并不明显而?#19968;?#28040;耗很多CPU?#35797;礎?#23545;于数据库压缩,是在server?#31169;?#34892;的。如果你在插入数据前通过代码进行数据压缩,然后插入数据库,这样耗费很多CPU?#35797;矗?#24403;然如果你的CPU?#20889;?#37327;结余。你也可以结合两者,对于某些表进行应用程序压缩,而对其他数据采用数据库压缩。

4、工作负载特性和压缩率

为?#25628;?#25321;哪些表可以使用压缩,工作负载是另一个决定因素,一般而言,如果你的系统是I/O瓶?#20445;?#37027;么可以使用CPU进行压缩与解压缩,以CPU换取I/O。

四、INNODB表是如何压缩的?

1、压缩算法

mysql进行压缩是借助于zlib库,采用L777压缩算法,这种算法在减少数据大小、CPU利用方面是成熟的、健壮的、高效的。同时这种算法是无失真的,因此原生的未压缩的数据总是能够从压缩文件中重构,LZ777实现原理是查找重复数据的序列号然后进行压缩,所以数据模式决定?#25628;?#32553;效率,一般而言,用户的数据能够被压缩50%以上。

不同于应用程序压缩或者其他数据库系统的压缩,InnoDB压缩是同时对数据和索引进行压缩,很多情况下,索引能够占数据库总大小的40%-50%。如果压缩效果很好,一般innodb文件会减少25%-50%或者更多,而且减少I/O增加系统吞吐量,但是会增加CPU的占用,你可通过设置innodb_compression_level参数来平衡压缩级别和CPU占用。

2、InnoDB数据存储及压缩

所有数据和b-tree索引都是按页进行存储的,每行包含主键和表的其他?#23567;?#36741;助索引也是b-tree结构的,包含对值:索引值及指向每行记录的?#21018;耄?#36825;个?#21018;?#23454;际上就是表的主键值。

在innodb压缩表中,每个压缩页(1,2,4,8)都对应一个未压缩的页16K,为了访问压缩页中的数据,如果该页在buffer pool中不存在,那么就从?#25165;?#19978;读到这个压缩页,然后进行解压到原来的数据结构。为了最小化I/O和减少解压页的?#38382;?#26377;时,buffer pool中包括压缩和未压缩的页,为给其他页腾出地方,buffer pool会驱逐未压缩页,仅仅留下压缩页在内存中。或者如果一个页一?#38382;?#38388;没有被访问,那么会被写到?#25165;?#19978;。这样一来,任何时候,buffer pool中都可以包含压缩页和未压缩页,或者只有压缩页或者两者都没?#23567;?/p>

Mysql采用LRU算法来保证哪些页应该在内存中还是被驱逐。因此热数据一般都会在内存中。

五、OLTP系统压缩负载优化

一般而言,innodb压缩对于只读或者读比重比较多的应用效果更好,SSD的出现,使得压缩更加吸引我们,尤其对于OLTP系统。对于经常update、delete、insert的应用,通过压缩表能够减少他们的存储需求和每秒I/O操作。

下面是针对写密集的应用,设置压缩表的一些有用参数:

  • innodb_compression_level:决定压缩程度的参数,如果你设置比较大,那么压缩比较多,耗费的CPU?#35797;?#20063;较多;相反,如果设置较小的值,那么CPU占用少。默?#29616;?,可以设置0-9
  • innodb_compression_failure_threshold_pct?#32791;现?,?#27573;?到100.设置中?#31995;?#36991;免高昂的压缩失败率。
  • innodb_compression_pad_pct_max:指定在每个压缩页面可以作为空闲空间的最大比例,该参数仅仅应用在设置了innodb_compression_failure_threshold_pct不为零情况下,并且压缩失败率通过了中?#31995;恪?#40664;?#29616;?0,可以设置?#27573;?#26159;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%  
复制代码

【总结】?#21644;?#36807;以上测试可知,当KEY_BLOCK_SIZE的值设置为4或者8时,压缩效果最好,设置为16效果最差,因为页的默?#29616;?6K。通常我?#24039;?#32622;为8。

posted @ 2019-08-14 15:31 长戟十三千 阅读(1) | 评论 (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)
复制代码

官方的解释可以参考如下的链接:http://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 长戟十三千 阅读(2) | 评论 (0)编辑 收藏
 解决办法:
vim /etc/my.cnf,根据实?#26159;?#20917;进行参数调整:
[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
# http://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 长戟十三千 阅读(4) | 评论 (0)编辑 收藏
     摘要: attribute是GNU C特色之一,在iOS用的比较广泛.系统中?#34892;?#22810;地方使用到. attribute可以设置函数属性(Function Attribute )、变量属性(Variable Attribute )和类型属性(Type Attribute)等.函数属性(Function Attribute)noreturnnoinlinealways_inlinepureconstno...  阅读全文
posted @ 2019-01-26 15:28 长戟十三千 阅读(60) | 评论 (0)编辑 收藏
1.下载并安装python-dev
    sudo apt-get install python-dev
2.下载并解压distcc:
    tar xvf distcc-3.2rc1.tar.bz2
3.配置
    cd distcc-3.2rc1/
    ./configure --prefix=/home/you/distcc-install --disable-Werror
4.安装
    make install
5.运行
    服务端运行 
        export PATH=$PATH:服务端distcc程序路径:服务器编译工具路径
        distcc --deamon --allow 192.168.0.0/16  --job 8 --user nobody
    客户端运行 :
        export PATH=$PATH:客户端distcc程序路径:客户端编译工具路径
        export DISTCC_HOSTS="server_ip1 server_ip2 ..."
        make -j8 CC=distcc
6、cmake
cd build/
CC="distcc cc" CXX="distcc g++" cmake ../cmake/





Other:
一个大型的C/C++项目的编译非常耗时。distcc和ccache这两个工具能够非常?#34892;?#22320;压缩编译时间。它们并不是独立的编译器,而是配合 GNU GCC使用(它们的资料明确说明并不关注其他编译器)。distcc介绍中说,有人完整编译KDE项目只花费6分钟。可见其厉害!此外,它们都非常易用,保证几分钟就能上手!

这两个项目的主页:
distcc            http://distcc.samba.org/
ccache            http://ccache.samba.org/
这两个软件的安装没什么好说的,都是标准的"./configure;make;make install"。在Ubuntu?#20064;滄案?#31616;单:sudo apt-get install distcc ccache。

distcc工作原理:

GCC 编译C/C++构建一个execualble分为三个阶段:(1)C/C++预处理(gcc -E);(2)编译(gcc -c);(3)链接(ld)。其中第二阶段是效率瓶?#20445;?#23588;其在指定“-O2”等优化选项时。distcc是一个编译器驱动器。它在"gcc -c"阶段?#35328;?#22788;理输出分发到指定的服务器阵列(各服务器监听TCP端口3632)并收集结果。GNU Make和SCons的"-j"并行编译可以利用distcc来加速编译。

distcc用法:
(1)服务器端以普通用户执行“distccd --daemon --allow 10.0.0.0/16”。这使得distccd接受来自10.0网段的所有TCP连接。
注意:distcc文档中说"--allow 0.0.0.0"是接受所有连接--这已经过时,实际效果是拒绝所有连接!
(2)如果工程使用automake机制。
设置DISTCC_HOSTS环境变量。
在configure阶段执行"CC=distcc ./configure"。然后执行"make -j XX"。XX是并发任务数目上限。
(3)如果工程由GNU make管理。
设置DISTCC_HOSTS环境变量。
修改Makefile使得在原来C/C++编译器名称前加上"distcc ",例如设置CC="distcc arm-linux-gcc"。然后执行"make -j XX"。XX是并发任务数目上限。
(4)如果工程由SCons管理。
修改SConstruct使得在原来C/C++编译器名称前加上"distcc "。导出环境变量HOME和DISTCC_HOSTS到构建环?#24120;?#27880;意SCons不会自动把系统环境变量导出到builder子进程):
 Environment(ENV={'HOME': os.environ['HOME'],'DISTCC_HOSTS': ‘localhost 10.0.0.2’},...)
然后执行"scons -j XX"。XX是并发任务数目上限。


distcc?#25910;?#22788;理:
运行distccmon-gnome。如果在编译期间某个distcc服务器一直不活跃,可能的原因比较多。
distcc服务器的问题可能有
(1) IP地址不可达。
(2) distccd进程没有启动。
(3) distcc客户端IP不在--allow指定的?#27573;?#20869;。
(4) distccd监听的3632端口被防火墙屏蔽。
distccd的日志记录在/var/log/messages。必要时查看一下。

客户端的问题可能有:
(1) 一些环境变量没有设置
distcc依赖的环境变?#22353;蠬OME和DISTCC_HOSTS。
distcc 日志在解决问题时尤其有用。默?#31995;?#38169;误信息输出在console。还可以设置DISTCC_VERBOSE和DISTCC_LOG环境变量以记录详细的调试信息到一日志文件(这对理解distcc工作过程也非常有用)。参考distcc和distccd联机帮助。

ccache工作原理:
ccache也是一个编译器驱动器。第一趟编译时ccache缓存了GCC的“-E”输出、编译选项以及.o文件到$HOME/.ccache。第二次编译时尽量利用缓存,必要时更新缓存。所以即使"make clean; make"也能从中获得好处。ccache是经过仔细编写的,确保了与直接使用GCC获得完全相同的输出。


ccache用法:
很简单,就像上面distcc用法提到的那样,给所有C/C++编译器名称前加上"ccache "即可。
ccache还可以把distcc作为后台的编译器。编译器设置为"ccache distcc "+原编译器即可。

从我经历的两个项目来看,单独使用ccache或distcc(除localhost外只用1台distcc服务器)效果比较显著。但是联合使用distcc和ccache的效果就和仅使用distcc差不多。个人倾向于只使用distcc,多加几台distcc服务器。


用distcc,ccache是两年前,项目结束的空隙,自己拿来玩的。?#31508;笔?#22312;arm上做的一个很大的工程,?#31508;?#30340;PC,只编UI部分就需要3个小时,这也是为什么后来我用分?#38469;?#32534;译的原因。那个项目是c++加adobe的flash,仿iphone做一款很炫的?#21482;?#20854;中UI全部用flash做,效果很炫,速度就比较差了。后来,我也试过在arm9261(200MHz)上用gnash播放flash,效果确实比较一般。言归正传,还是?#27492;?#19979;分?#38469;?#32534;译,其实它的原理很简单,把c文件在本机预编译,然后发到其他主机进行编译,编译的后的o文件再传回本机,最后在本机进行链接。没有看过代码,猜测对于每个编译的c文件对应产生一个编译任务,下发到其他机器或本机,最终完成编译。

我们的环境是ADS1.2+cygwin,用tcc,tcpp进行编译。distcc,ccache本来是在cygwin上直接装的的,但后来在使用时发现会碰到一些问题。所以从源码编译了。distcc产生的中间文件是.i的格式,tcc无法识别该文件类型,需要修改源码。就一句话,网上可以搜到的。if(dcc_getenv_bool("DISTCC_KEEP_FILETYPE", 1)).然后,./configure; make; make install。ccache问题是一样的,无法识别.i文件,修改ccache.c,把中间文件i/ii改为c/cpp,一样的方式安装。

然后要对安装的东西进行配置,我?#31508;?#30340;配置如下,10.19.5.0网段的主机都可以做协同编译的主机,当然ads的licence只有20个啦。此处目录设置至关重要,tcc无法识别cygwin环?#24120;瑃cc -c /cygdriver/c/a.c,  tcc无法读取文件,错误码为C3052E。利用了cygwin既可以win32的路径,又可以识别posix路径。
export DISTCC_LOG='/var/log/distcc.log'
export DISTCC_HOSTS='localhost 10.19.5.0/24'
export DISTCC_VERBOSE=1
export DISTCC_SAVE_TEMPS=1
export TMPDIR=' e:/test '
export CCACHE_DIR=e:/test
export CCACHE_PREFIX=distcc
export CCACHE_LOGFILE=e:/test/ccache.log


distccd在没有设置DISTCCD_PATH时,使用系统的PATH作为搜索,和makefile里指定的不一致。设置了DISTCCD_PATH,很莫名其妙,?#31508;笔?#20026;什么。然后distccd --daemon --allow0.0.0.0/0,任何ip都可以接入,比较简单。

修改makefile,在CC,ARMCC,ARMCPP,TCPP原来的设置前,添加ccache。需要说明的是,distcc仅为编译器前端,编译器的指定需要distcc 。distcc支持的编译器必须可以预编译,?#31807;?#26159;常用的gcc -E这样的选项。

最后的测试很简单,自己写makefile,只做".c.o:" ,然后把.o文件链接到工程中就可以了。在?#21482;?#19978;还是可以很好的run起来的。当然验证的工作不是那么简单了,看了下反汇编的代码。一台主机编译的和分?#38469;?#32534;译的,没有什么太大的差别,汇编稍有不同,但功能一致。

项目结束后自?#21644;?#30340;东西,虽然没有用于实际来提高效率,但还是学到了一些东西。



posted @ 2018-09-08 20:56 长戟十三千 阅读(525) | 评论 (0)编辑 收藏
TcMalloc(Thread-CachingMalloc)是google-perftools工具中的一个内存管理库,与标准的glibc库中malloc相比,TcMalloc在内存分配的效率和速度上要高很多,可以提升高并发情况下的?#38405;埽档?#31995;统的负载。
Google-perftools项目的网址为:http://code.google.com/p/google-perftools/,该项目包括TcMalloc、heap-checker、heap-profiler和cpu-profiler共4个组件。在只使用TcMalloc情况下可以不编译其他三个组件。
注:使用线程内存池的方法,在小对象是在内存池中进行分配,使用分配较多的内存空间?#20174;?#21270;分配时间。
实现原理请参考网址http://goog-perftools.sourceforge.net/doc/tcmalloc.html

简介

TcMalloc是一个由Google开发的,比glibc的malloc更快的内存管理库。通常情况下ptmalloc2能在300ns执行一个malloc和free对,而TcMalloc能在50ns内执行一个malloc和free对。
TcMalloc可以减少多线程程序之间的锁争用问题,在小对象上能达到零争用。
TcMalloc为每个线程单独分配一个线程本地的Cache,少量的地址分配就直接从Cache中分配,并且定期做垃圾回收,将线程本地Cache中的空闲内存返回给全局控制堆。
TcMalloc认为小于(<=)32K为小对象,大对象直接从全局控制堆上以页(4K)为单位进行分配,?#31807;?#26159;说大对象总是页对齐的。
TcMalloc中一个页可以存入一些相同大小的小对象,小对象从本地内存链表中分配,大对象从?#34892;?#20869;存堆中分配。

安装

Linux下tcmalloc的安装过程如下:
1)  从Google源代码网址上下载源代码包,现在最新版本为2.0;
2)  解压缩源代码包
# unzip gperftools-2.0.zip          或
# tar zxvf gperftools-2.0.tar.gz
3)  编译动态库
# cd gperftools-2.0
# ./ configure  --disable-cpu-profiler --disable-heap-profiler--disable-heap-checker 
--disable-debugalloc--enable-minimal
加入上面的参数是为了只生成tcmalloc_minimal动态库,如果需要所有组件,命令如下:
# ./configure
# ./configure -h           用于查看编译选项。
编译和安装:
# make&& make install
使用最小安装时把tcmalloc_minimal的动态库拷贝到系统目录中:
# cplib/tcmalloc_minimal.so.0.0.0 /usr/local/lib
创建软连接指向tcmalloc:
# ls –s /usr/local/lib/libtcmalloc_minimal.so.0.0.0/usr/local/lib/libtcmalloc.so
启动程序之前,预先加载tcmalloc动态库的环境变量设置:
# exportLD_PRELOAD=”/usr/local/lib/libtcmalloc.so
使用losf检查程序是否已经加载tcmalloc库:
# lsof -n | greptcmalloc
在Linux下使用的tcmalloc安装完成,在Windows下使用VS(2003以?#20064;?#26412;)打开工程项目gperftools.sln进行编译。

使用

将libtcmalloc.so/libtcmalloc.a链接到程序中,或者设置LD_PRELOAD=libtcmalloc.so。这样就可以使用tcmalloc库中的函数替换掉操作系统的malloc、free、realloc、strdup内存管理函数。可以设置环境变量设置如下:
         TCMALLOC_DEBUG=<level>       调试级别,取值为1-2
         MALLOCSTATS=<level>                    设置显示内存使用状态级别,取值为1-2
         HEAPPROFILE=<pre>                     指定内存泄露检查的数据导出文件
         HEAPCHECK=<type>                        堆检查类型,type=normal/strict/draconian
TcMalloc库还可以进行内存泄露的检查,使用这个功能有两种方法:
1)将tcmalloc库链接到程序中,注意应该将tcmalloc库最后链接到程序中;
2)设置LD_PRELOAD=”libtcmalloc.so”/HEAPCHECK=normal,这样就不需重新编译程序
打开检查功能,有两种方式可以开启泄露检查功能:
1)  使用环境变量,对整个程序进行检查: HEAPCHECK=normal /bin/ls
2)  在源代码中插入检查点,这样可以控制只检查程序的某些部分,代码如下:
HeapProfileLeakCheckerchecker("foo");        // 开?#25216;?#26597;
Foo();                                                                         // 需要检查的部分
assert(checker.NoLeaks());                                 // 结束检查
调用checker建立一个内存快照,在调用checker.NoLeaks建立另一个快照,然后进行比较,如果内存有增长或者?#25105;?#21464;化,NoLeaks函数返回false,并输出一个信息告诉你如何使用pprof工具来分析具体的内存泄露。
    执行内存检查:
         #LD_PRELOAD=libtcmalloc.so HEAPCHECK=strict HEAPPROFILE=memtm ./a.out
执行完成后会输出检查的结果,如果?#34892;?#38706;,pprof会输出泄露多少个字节,有多少次分配,也会输出详细的列表指出在什么地方分配和分配多少次。
         比较两个快照:
         #pprof --base=profile.0001.heap 程序名 profile.0002.heap
    已知内存泄漏时,关闭内存泄露检查的代码:
void *mark =HeapLeakChecker::GetDisableChecksStart();
<leaky code>           //不做泄漏检查的部分
HeapLeakChecker::DisableChecksToHereFrom(mark);
         注:在某些libc中程序可能要关闭检查才能正常工作。
         注:不能检查数组删除的内存泄露,比如:char *str = new char[100]; delete str;。


=================================安装缺少库============================

libunwind库为基于64位CPU和操作系统的程序提供了基本的堆栈辗转开解功能,其中包括用于输出堆栈跟踪的API、用于以编程方式辗转开解堆栈的API以及支持C++异常处理机制的API。

64位操作系统一定要先装libunwind这个库。

wget http://download.savannah.gnu.org/releases/libunwind/libunwind-1.1.tar.gz

tar zxvf libunwind-1.1.tar.gz
cd libunwind-1.1
CFLAGS=-fPIC ./configure
make CFLAGS=-fPIC
make CFLAGS=-fPIC install
posted @ 2018-08-24 11:22 长戟十三千 阅读(718) | 评论 (0)编辑 收藏
仅列出标题  下一页
探灵笔记系统攻略
体彩老11选5开奖结果 极速时时彩是不是官方开奖的 天津时时后三走势 新时时走势图500 新宝皇冠体育娱乐 重庆时时彩个位4码计划 贵州11选5开奖查询结果 排列5推荐号预测 快速赛 下载福利时时彩开奖号码