• 汉能发布汉纸、汉包:移动能源时代全面到来 2019-05-26
  • 高清:阿根廷训练备战小组赛 今晚首战对阵冰岛 2019-05-25
  • 【访民情 惠民生 聚民心】果勒买里村丰收忙 2019-05-25
  • 如何理解孔子这句话?北大教授胡军动情论生死 2019-05-23
  • 2026世界杯花落北美三国 2019-05-20
  • 地价10年暴涨4倍背后:供地减半 开发商拿地疯狂 ——凤凰网房产杭州 2019-05-20
  • 建设海洋强国,习近平总书记在多个场合这样说 2019-05-14
  • 美国又打出2000亿关税牌,中方这300字声明暗藏玄机! 2019-05-12
  • 世界杯专版 竞猜型彩票 赔率是公认的竞猜利器 2019-05-08
  • 要战胜对手必须了介他学习对手长处改掉自己短处,所以我们要学习美國长处为我所用.曰本在唐朝派遣唐史向中國学习,近代学西方进行明治维新迅速强大成为东方最强國家即证据 2019-05-04
  • [雷人]跟你的铁环玩去! 2019-05-01
  • 回复@老老保老张工:那只能证明你的智商不达标!对于计划经济的构想,咱敢说强坛没有一个人比咱考虑得更周全!伪高工排在一个筋斗云之外! 2019-04-15
  • 傍晚,听一曲温柔的天鹅湖 2019-04-15
  • 马刺头号球星申请换队并确定下家 波波维奇也不好使了 2019-04-15
  • [大笑]所以说你不仅智商低还不谦虚嘛! 2019-04-15
  • 2019年3月30日

    from:https://blog.csdn.net/lycyingO/article/details/80854669


     版权声明:微信公众号《小姐姐味道》,转载注明出处 https://blog.csdn.net/lycyingO/article/details/80854669
    简介
    JVM堆外内存难排查但经?;岢鱿治侍?,这可能是目前最全的JVM堆外内存排查思路。
    通过本文,你应该了解:
    pmap 命令
    gdb 命令
    perf 命令
    内存 RSS、VSZ的区别
    java NMT
    起因
    这几天遇到一个比较奇怪的问题,觉得有必要和大家分享一下。我们的一个服务,运行在docker上,在某个版本之后,占用的内存开始增长,直到docker分配的内存上限,但是并不会OOM。版本的更改如下:
    升级了基础软件的版本
    将docker的内存上限由4GB扩展到8GB
    上上个版本的一项变动是使用了EhCache的Heap缓存
    没有读文件,也没有mmap操作
    使用jps 查看启动参数,发现分配了大约3GB的堆内存
    [root]$ jps -v
    75 Bootstrap -Xmx3000m -Xms3000m  -verbose:gc -Xloggc:/home/logs/gc.log -XX:CMSInitiatingOccupancyFraction=80 -XX:+UseCMSCompactAtFullCollection -XX:MaxTenuringThreshold=10 -XX:MaxPermSize=128M -XX:SurvivorRatio=3 -XX:NewRatio=2 -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:+UseParNewGC -XX:+UseConcMarkSweepGC
    使用ps查看进程使用的内存和虚拟内存 ( Linux内存管理 )。除了虚拟内存比较高达到17GB以外,实际使用的内存RSS也夸张的达到了7GB,远远超过了-Xmx的设定。
    [root]$ ps -p 75 -o rss,vsz  
     
    RSS    VSZ 7152568 17485844
    原创文章,转载注明出处 (//sayhiai.com)
    排查过程
    明显的,是有堆外内存的使用,不太可能是由于EhCache引起的(因为我们使用了heap方式)。了解到基础软件的升级涉及到netty版本升级,netty会用到一些DirectByteBuffer,第一轮排查我们采用如下方式:
    jmap -dump:format=b,file=75.dump 75 通过分析堆内存找到DirectByteBuffer的引用和大小
    部署一个升级基础软件之前的版本,持续观察
    部署另一个版本,更改EhCache限制其大小到1024M
    考虑到可能由Docker的内存分配机制引起,部署一实例到实体机
    结果4个环境中的服务,无一例外的都出现了内存超用的问题。问题很奇怪,宝宝睡不着觉。
    pmap
    为了进一步分析问题,我们使用pmap查看进程的内存分配,通过RSS升序序排列。结果发现除了地址000000073c800000上分配的3GB堆以外,还有数量非常多的64M一块的内存段,还有巨量小的物理内存块映射到不同的虚拟内存段上。但到现在为止,我们不知道里面的内容是什么,是通过什么产生的。
    [root]$ pmap -x 75  | sort -n -k3
     
    .....省略N行
     
    0000000040626000   55488   55484   55484 rwx--    [ anon ]
     
    00007fa07c000000   65536   55820   55820 rwx--    [ anon ]
     
    00007fa044000000   65536   55896   55896 rwx--    [ anon ]
     
    00007fa0c0000000   65536   56304   56304 rwx--    [ anon ]
     
    00007f9db8000000   65536   56360   56360 rwx--    [ anon ]
     
    00007fa0b8000000   65536   56836   56836 rwx--    [ anon ]
     
    00007fa084000000   65536   57916   57916 rwx--    [ anon ]
     
    00007f9ec4000000   65532   59752   59752 rwx--    [ anon ]
     
    00007fa008000000   65536   60012   60012 rwx--    [ anon ]
     
    00007f9e58000000   65536   61608   61608 rwx--    [ anon ]
     
    00007f9f18000000   65532   61732   61732 rwx--    [ anon ]
     
    00007fa018000000   65532   61928   61928 rwx--    [ anon ]
     
    00007fa088000000   65536   62336   62336 rwx--    [ anon ]
     
    00007fa020000000   65536   62428   62428 rwx--    [ anon ]
     
    00007f9e44000000   65536   64352   64352 rwx--    [ anon ]
     
    00007f9ec0000000   65528   64928   64928 rwx--    [ anon ]
     
    00007fa050000000   65532   65424   65424 rwx--    [ anon ]
     
    00007f9e08000000   65512   65472   65472 rwx--    [ anon ]
     
    00007f9de0000000   65524   65512   65512 rwx--    [ anon ]
     
    00007f9dec000000   65532   65532   65532 rwx--    [ anon ]
     
    00007f9dac000000   65536   65536   65536 rwx--    [ anon ]
     
    00007f9dc8000000   65536   65536   65536 rwx--    [ anon ]
     
    00007f9e30000000   65536   65536   65536 rwx--    [ anon ]
     
    00007f9eb4000000   65536   65536   65536 rwx--    [ anon ]
     
    00007fa030000000   65536   65536   65536 rwx--    [ anon ]
     
    00007fa0b0000000   65536   65536   65536 rwx--    [ anon ]
     
    000000073c800000 3119140 2488596 2487228 rwx--    [ anon ]
     
    total kB        17629516 7384476 7377520
    通过google,找到以下资料 Linux glibc >= 2.10 (RHEL 6) malloc may show excessive virtual memory usage)
    文章指出造成应用程序大量申请64M大内存块的原因是由Glibc的一个版本升级引起的,通过export MALLOC_ARENA_MAX=4可以解决VSZ占用过高的问题。虽然这也是一个问题,但却不是我们想要的,因为我们增长的是物理内存,而不是虚拟内存。
    NMT
    幸运的是 JDK1.8有Native Memory Tracker可以帮助定位。通过在启动参数上加入-XX:NativeMemoryTracking=detail就可以启用。在命令行执行jcmd可查看内存分配。
    #jcmd 75 VM.native_memory summary
     
    Native Memory Tracking: Total: reserved=5074027KB, committed=3798707KB -                 Java Heap (reserved=3072000KB, committed=3072000KB)                            (mmap: reserved=3072000KB, committed=3072000KB) -                     Class (reserved=1075949KB, committed=28973KB)                            (classes #4819)                            (malloc=749KB #13158)                            (mmap: reserved=1075200KB, committed=28224KB) -                    Thread (reserved=484222KB, committed=484222KB)                            (thread #470)                            (stack: reserved=482132KB, committed=482132KB)                            (malloc=1541KB #2371)                            (arena=550KB #938) -                      Code (reserved=253414KB, committed=25070KB)                            (malloc=3814KB #5593)                            (mmap: reserved=249600KB, committed=21256KB) -                        GC (reserved=64102KB, committed=64102KB)                            (malloc=54094KB #255)                            (mmap: reserved=10008KB, committed=10008KB) -                  Compiler (reserved=542KB, committed=542KB)                            (malloc=411KB #543)                            (arena=131KB #3) -                  Internal (reserved=50582KB, committed=50582KB)                            (malloc=50550KB #13713)                            (mmap: reserved=32KB, committed=32KB) -                    Symbol (reserved=6384KB, committed=6384KB)                            (malloc=4266KB #31727)                            (arena=2118KB #1) -    Native Memory Tracking (reserved=1325KB, committed=1325KB)                            (malloc=208KB #3083)                            (tracking overhead=1117KB) -               Arena Chunk (reserved=231KB, committed=231KB)                            (malloc=231KB) -                   Unknown (reserved=65276KB, committed=65276KB)                            (mmap: reserved=65276KB, committed=65276KB)
    虽然pmap得到的内存地址和NMT大体能对的上,但仍然有不少内存去向成谜。虽然是个好工具但问题并不能解决。
    gdb
    非常好奇64M或者其他小内存块中是什么内容,接下来通过gdbdump出来。读取/proc目录下的maps文件,能精准的知晓目前进程的内存分布。
    以下脚本通过传入进程id,能够将所关联的内存全部dump到文件中(会影响服务,慎用)。
    grep rw-p /proc/$1/maps | sed -n 's/^\([0-9a-f]*\)-\([0-9a-f]*\) .*$/\1 \2/p' | while read start stop; do gdb --batch --pid $1 -ex "dump memory $1-$start-$stop.dump 0x$start 0x$stop"; done
    更多时候,推荐之dump一部分内存。(再次提醒操作会影响服务,注意dump的内存块大小,慎用)。
    gdb --batch --pid 75 -ex "dump memory a.dump 0x7f2bceda1000 0x7f2bcef2b000
    [root]$ du -h *
    dump 4.0K
    55-00600000-00601000.dump 400K
    55-00eb7000-00f1b000.dump 0
    55-704800000-7c0352000.dump 47M
    55-7f2840000000-7f2842eb8000.dump 53M
    55-7f2848000000-7f284b467000.dump 64M
    55-7f284c000000-7f284fffa000.dump 64M
    55-7f2854000000-7f2857fff000.dump 64M
    55-7f285c000000-7f2860000000.dump 64M
    55-7f2864000000-7f2867ffd000.dump 1016K
    55-7f286a024000-7f286a122000.dump 1016K
    55-7f286a62a000-7f286a728000.dump 1016K
    55-7f286d559000-7f286d657000.dump
    是时候查看里面的内容了
    [root]$ view 55-7f284c000000-7f284fffa000.dump
    ^@^@X+^?^@^@^@^@^@d(^?^@^@^@ ÿ^C^@^@^@^@^@ ÿ^C^@^@^@^@^@^@^@^@^@^@^@^@±<97>p^C^@^@^@^@ 8^^Z+^?^@^@ ^@^@d(^?^@^@ 8^^Z+^?^@^@ ^@^@d(^?^@^@
    achine":524993642,"timeSecond":1460272569,"inc":2145712868,"new":false},"device":{"client":"android","uid":"xxxxx","version":881},"
    device_android":{"BootSerialno":"xxxxx","CpuInfo":"0-7","MacInfo":"2c:5b:b8:b0:d5:10","RAMSize":"4027212","SdcardInfo":"xxxx","Serialno":"xxxx",
    "android_id":"488aedba19097476","buildnumber":"KTU84P/1416486236","device_ip":"0.0.0.0","mac":"2c:5b:b8:b0:d5:10","market_source":"12","model":"OPPO ...more
    纳尼?这些内容不应该在堆里面么?为何还会使用额外的内存进行分配?上面已经排查netty申请directbuffer的原因了,那么还有什么地方在分配堆外内存呢?
    perf
    传统工具失灵,快到了黔驴技穷的时候了,是时候祭出神器perf了。
    使用 perf record -g -p 55 开启监控栈函数调用。运行一段时间后Ctrl+C结束,会生成一个文件perf.data。
    执行perf report -i perf.data查看报告。
    如图,进程大量执行bzip相关函数。搜索zip,结果如下:
    -.-!
    进程调用了Java_java_util_zip_Inflater_inflatBytes() 申请了内存,仅有一小部分调用Deflater释放内存。与pmap内存地址相比对,确实是bzip在搞鬼。
    原创文章,转载注明出处 (//sayhiai.com)
    解决
    java项目搜索zip定位到代码,发现确实有相关bzip压缩解压操作,而且GZIPInputStream有个地方没有close。
    GZIPInputStream使用Inflater申请堆外内存,Deflater释放内存,调用close()方法来主动释放。如果忘记关闭,Inflater对象的生命会延续到下一次GC。在此过程中,堆外内存会一直增长。
    原代码:
    public byte[] decompress ( byte[] input) throws IOException {
                    ByteArrayOutputStream out = new ByteArrayOutputStream();
                    IOUtils.copy(new GZIPInputStream(new ByteArrayInputStream(input)), out);
                    return out.toByteArray();
                }
    修改后:
     public byte[] decompress(byte[] input) throws IOException {
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            GZIPInputStream gzip = new GZIPInputStream(new ByteArrayInputStream(input));
            IOUtils.copy(gzip, out);
            gzip.close();
            return out.toByteArray();
        }
    经观察,问题解决。
    --------------------- 
    作者:lycyingO 
    来源:CSDN 
    原文:https://blog.csdn.net/lycyingO/article/details/80854669 
    版权声明:本文为博主原创文章,转载请附上博文链接!
    posted @ 2019-03-30 11:44 小马歌 阅读(10) | 评论 (0)编辑 收藏

    2019年2月16日

         摘要: from:https://www.ibm.com/developerworks/cn/linux/thread/posix_thread1/index.htmlhttps://www.ibm.com/developerworks/cn/linux/thread/posix_thread2/index.htmlhttps://www.ibm.com/developerworks/cn/linux/t...  阅读全文
    posted @ 2019-02-16 11:37 小马歌 阅读(25) | 评论 (0)编辑 收藏

    2019年2月13日

         摘要: from://www.fanyilun.me/2017/04/20/MySQL%E5%8A%A0%E9%94%81%E5%88%86%E6%9E%90/MySQL加锁分析目录前言MySQL的锁如何查看事务的加锁情况不同语句的加锁情况1. 查询命中聚簇索引(主键索引)2. 查询命中唯一索引3. 查询命中二级索引(非唯一索引)4. 查询没有命中索引5. 对索引键值有修改6. 插入数据隐式锁一...  阅读全文
    posted @ 2019-02-13 17:07 小马歌 阅读(34) | 评论 (0)编辑 收藏

    2018年12月25日

    摘要: MySQL replace into 错误案例 背景 * MySQL5.7 * ROW模式 * 表结构 CREATE TABLE `test` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `col_1` varc

    MySQL replace into 错误案例

    背景

    * MySQL5.7  * ROW模式   * 表结构 CREATE TABLE `test` (   `id` int(10) unsigned NOT NULL AUTO_INCREMENT,   `col_1` varchar(100) DEFAULT NULL,   `col_2` varchar(100) DEFAULT NULL,   `col_3` varchar(100) DEFAULT NULL,   PRIMARY KEY (`id`),   UNIQUE KEY `col_1` (`col_1`) ) ENGINE=InnoDB  DEFAULT CHARSET=utf8 

    错误场景一

    其他字段value莫名其妙的没了

    • step1 初始化记录
    mater:lc> REPLACE INTO test (col_1,col_2,col_3) values('a','a','a'); Query OK, 1 row affected (0.00 sec) --注意,这里是影响了1条记录  master:lc> REPLACE INTO test (col_1,col_2,col_3) values('b','b','b'); Query OK, 1 row affected (0.00 sec) --注意,这里是影响了1条记录  master:lc> REPLACE INTO test (col_1,col_2,col_3) values('c','c','c'); Query OK, 1 row affected (0.00 sec) --注意,这里是影响了1条记录   master > show create table test  | test  | CREATE TABLE `test` (   `id` int(10) unsigned NOT NULL AUTO_INCREMENT,   `col_1` varchar(100) DEFAULT NULL,   `col_2` varchar(100) DEFAULT NULL,   `col_3` varchar(100) DEFAULT NULL,   PRIMARY KEY (`id`),   UNIQUE KEY `col_1` (`col_1`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 |   mater > select * from test; +----+-------+-------+-------+ | id | col_1 | col_2 | col_3 | +----+-------+-------+-------+ |  1 | a     | a     | a     | |  2 | b     | b     | b     | |  3 | c     | c     | c     | +----+-------+-------+-------+ 3 rows in set (0.00 sec)  
    • step2 构造错误场景
    master:lc> replace into test(col_1,col_2) values('c','cc'); Query OK, 2 rows affected (0.00 sec)  dba:lc> select * from test; +----+-------+-------+-------+ | id | col_1 | col_2 | col_3 | +----+-------+-------+-------+ |  1 | a     | a     | a     | |  2 | b     | b     | b     | |  4 | c     | cc    | NULL  | +----+-------+-------+-------+ 3 rows in set (0.00 sec)  
    • 总结
    1. col_3 的值,从原来的c,变成了NULL,天呐,数据不见了。 id 也变了。
    2. 用户原本的需求,应该是如果col_1='c' 存在,那么就改变col_2='cc',其余的记录保持不变,结果id,col_3都变化了
    3. 解决方案就是:将replace into 改成 INSERT INTO … ON DUPLICATE KEY UPDATE

    但是你以为这样就完美的解决了吗? 马上就会带来另外一场灾难,请看下面的错误场景

    错误场景二

    ERROR 1062 (23000): Duplicate entry 'x' for key 'PRIMARY'

    • step1 初始化记录
     mater:lc> REPLACE INTO test (col_1,col_2) values('a','a'); Query OK, 1 row affected (0.00 sec) --注意,这里是影响了1条记录  master:lc> REPLACE INTO test (col_1,col_2) values('b','b'); Query OK, 1 row affected (0.00 sec) --注意,这里是影响了1条记录  master:lc> REPLACE INTO test (col_1,col_2) values('c','c'); Query OK, 1 row affected (0.00 sec) --注意,这里是影响了1条记录   master > show create table test  | test  | CREATE TABLE `test` (   `id` int(10) unsigned NOT NULL AUTO_INCREMENT,   `col_1` varchar(100) DEFAULT NULL,   `col_2` varchar(100) DEFAULT NULL,   PRIMARY KEY (`id`),   UNIQUE KEY `col_1` (`col_1`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 |   slave > show create table test  | test  | CREATE TABLE `test` (   `id` int(10) unsigned NOT NULL AUTO_INCREMENT,   `col_1` varchar(100) DEFAULT NULL,   `col_2` varchar(100) DEFAULT NULL,   PRIMARY KEY (`id`),   UNIQUE KEY `col_1` (`col_1`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 |
    • step2 构造错误场景
    * master  mater:lc> REPLACE INTO test (col_1,col_2) values('c','cc'); Query OK, 2 rows affected (0.00 sec)  --注意,这里是影响了两条记录  mater:lc> show create table test  | test  | CREATE TABLE `test` (   `id` int(10) unsigned NOT NULL AUTO_INCREMENT,   `col_1` varchar(100) DEFAULT NULL,   `col_2` varchar(100) DEFAULT NULL,   PRIMARY KEY (`id`),   UNIQUE KEY `col_1` (`col_1`) ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 |  master:lc> select * from test +----+-------+-------+ | id | col_1 | col_2 | +----+-------+-------+ |  1 | a     | a     | |  2 | b     | b     | |  4 | c     | cc    | +----+-------+-------+ 3 rows in set (0.00 sec)  * slave  slave:lc> show create table test  | test  | CREATE TABLE `test` (   `id` int(10) unsigned NOT NULL AUTO_INCREMENT,   `col_1` varchar(100) DEFAULT NULL,   `col_2` varchar(100) DEFAULT NULL,   PRIMARY KEY (`id`),   UNIQUE KEY `col_1` (`col_1`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 |  slave:lc> select * from test +----+-------+-------+ | id | col_1 | col_2 | +----+-------+-------+ |  1 | a     | a     | |  2 | b     | b     | |  4 | c     | cc    | +----+-------+-------+ 3 rows in set (0.00 sec) 
    • step3 错误案例产生
    * 假设有一天,master 挂了, 由slave 提升为 new mater  原slave:lc> show create table test  | test  | CREATE TABLE `test` (   `id` int(10) unsigned NOT NULL AUTO_INCREMENT,   `col_1` varchar(100) DEFAULT NULL,   `col_2` varchar(100) DEFAULT NULL,   PRIMARY KEY (`id`),   UNIQUE KEY `col_1` (`col_1`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 |  原slave:lc> select * from test +----+-------+-------+ | id | col_1 | col_2 | +----+-------+-------+ |  1 | a     | a     | |  2 | b     | b     | |  4 | c     | cc    | +----+-------+-------+ 3 rows in set (0.00 sec)   ===注意==  root:lc> REPLACE INTO test (col_1,col_2) values('d','d'); ERROR 1062 (23000): Duplicate entry '4' for key 'PRIMARY'  
    • 总结
    * Row 模式,主从情况下,replace into 和 INSERT INTO … ON DUPLICATE KEY UPDATE 都会导致以上问题的发生 * 解决方案: 最后可以通过alter table auto_increment值解决,但是这样已经造成mater的表很长时间没有写入了。。。

    最后总结

    • replace with unique key
    1. 禁止 replace into (错误一,错误二 都会发生) 2. 禁止 INSERT INTOON DUPLICATE KEY UPDATE (错误二 会发生)
    • replace with primary key
    1. 禁止 replace into (会发生错误场景一的案例,丢失部分字段数据) 2. 可以使用INSERT INTOON DUPLICATE KEY UPDATE 代替 replace into
    posted @ 2018-12-25 19:19 小马歌 阅读(55) | 评论 (0)编辑 收藏

    2018年12月3日

         摘要: from:https://cloud.tencent.com/developer/article/1004475最近研发的项目对 DB 依赖比较重,梳理了这段时间使用MySQL遇到的8个比较具有代表性的问题,答案也比较偏自己的开发实践,没有 DBA专业和深入,有出入的请使劲拍砖!MySQL读写性能是多少,有哪些性能相关的配置参数?MySQL负载高时,如何找到是由哪些SQL引起的?如何针对具体的SQ...  阅读全文
    posted @ 2018-12-03 15:55 小马歌 阅读(66) | 评论 (0)编辑 收藏
     
    from://mingxinglai.com/cn/2015/12/material-of-mysql/

    我这里推荐几本MySQL的好书,应该能够有效避免学习MySQL的弯路,并且达到一个不错的水平。 我这里推荐的书或材料分为两个部分,分别是MySQL的使用和MySQL的源码学习。在介绍的过程中,我会穿插简单的评语或感想。

    1.MySQL的使用

    1.1 MySQL技术内幕:InnoDB存储引擎

    学习MySQL的使用,首推姜承尧的《MySQL技术内幕:InnoDB存储引擎》,当然不是因为姜sir是我的经理才推荐这本书。这本书确实做到了由渐入深、深入浅出,是中国人写的最赞的MySQL技术书籍,符合国人的思维方式和阅读习惯,而且,这本书简直就是面试宝典,对于近期有求职MySQL相关岗位的朋友,可以认真阅读,对找工作有很大的帮助。当然,也有人说这本书入门难度较大,这个就自己取舍了,个人建议就以这本书入门即可,有不懂的地方可以求助官方手册和google。

    MySQL技术内幕

    1.2 MySQL的官方手册

    我刚开始学习MySQL的时候误区就是,没有好好阅读MySQL的官方手册。例如,我刚开始很难理解InnoDB的锁,尤其是各个情况下如何加锁,这个问题在我师弟进入百度做DBA时,也困扰了他一阵子,我们两还讨论来讨论去,其实,MySQL官方手册已经写得清清楚楚,什么样的SQL语句加什么样的锁,当然,MySQL的官方手册非常庞大,一时半会很难看完,建议先看InnoDB相关的部分。

    //dev.mysql.com/doc/refman/5.7/en/innodb-storage-engine.html

    1.3 MySQL排错指南

    MySQL排错指南》是2015年夏天引入中国的书籍,这本书可以说是DBA速成指南,介绍的内容其实比较简单,但是也非常实用,对于DBA这个讲究经验的工种,这本书就是传授经验的,可能对有较多工作经验的DBA来说,这本书基本没有什么用,但是,对于刚入职场的新人,或学校里的学生,这本书会有较大的帮助,非常推荐。

    MySQL排错指南

    1.4 高性能MySQL

    高性能MySQL》是MySQL领域的经典之作,拥有广泛的影响力,学习MySQL的朋友都应该有所耳闻,所以我就不作过多介绍,唯一的建议就是仔细看、认真看、多看几遍,我每次看都会有不小的收获。这就是一本虽然书很厚,但是需要一页一页、一行一行都认真看的书。

    高性能MySQL

    1.5 数据库索引设计与优化

    如果认真学习完前面几本书,基本上都已经对MySQL掌握得不错了,但是,如果不了解如何设计一个好的索引,仍然不能成为牛逼的DBA,牛逼的DBA和不牛逼的DBA,一半就是看对索引的掌握情况,《数据库索引设计与优化》就是从普通DBA走向牛逼DBA的捷径,这本书在淘宝内部非常推崇,但是在中国名气却不是很大,很多人不了解。这本书也是今年夏天刚有中文版本的,非常值得入手以后跟着练习,虽然知道的人不多,豆瓣上也几乎没有什么评价,但是,强烈推荐、吐血推荐!

    数据库索引设计与优化

    1.6 Effective MySQL系列

    Effective MySQL系列》是指:

    • Effective MySQL Replication Techniques in Depth
    • Effective MySQL之SQL语句最优化
    • Effective MySQL之备份与恢复

    effective

    这一系列并不如前面推荐的好,其中,我只看了前两本,这几本书只能算是小册子,如果有时间可以看看,对某一个”???#8221;进入深入了解。

    2.MySQL的源码

    关于MySQL源码的书非常少,还好现在市面上有两本不错的书,而且刚好一本讲server层,一本讲innodb存储引擎层,对于学习MySQL源码会很有帮助,至少能够更加快速地了解MySQL的原理和宏观结构,然后再深入细节。此外,还有一些博客或PPT将得也很不错,这里推荐最好的几份材料。

    2.1 InnoDB - A journey to the core

    InnoDB - A journey to the core》 是MySQL大牛Jeremy Cole写的PPT,介绍InnoDB的存储???,即表空间、区、段、页的格式、记录的格式、槽等等。是学习Innodb存储的最好的材料。感谢Jeremy Cole!

    2.2 深入MySQL源码

    登博的分享《深入MySQL源码》,相信很多想了解MySQL源码的朋友已经知道这份PPT,就不过多介绍,不过,要多说一句,登博的参考资料里列出的几个博客,都要关注一下,干货满满,是学习MySQL必须关注的博客。

    2.3 深入理解MySQL核心技术

    深入理解MySQL核心技术》是第一本关于MySQL源码的书,着重介绍了MySQL的Server层,重点介绍了宏观架构,对于刚开始学习MySQL源码的人,相信会有很大的帮助,我在学习MySQL源码的过程中,反复的翻阅了几遍,这本书刚开始看的时候会很痛苦,但是,对于研究MySQL源码,非常有帮助,就看你是否需要,如果没有研究MySQL源码的决心,这本书应该会被唾弃。

    深入理解MySQL核心技术

    2.4 MySQL内核:InnoDB存储引擎

    我们组的同事写的《MySQL内核:InnoDB存储引擎》,可能宇宙范围内这本书就数我学得最认真了,虽然书中有很多编辑错误,但是,平心而论,还是写得非常好的,相对于《深入理解MySQL核心技术》,可读性更强一些,建议研究Innodb存储引擎的朋友,可以了解一下,先对Innodb有一个宏观的概念,对大致原理有一个整体的了解,然后再深入细节,肯定会比自己从头开始研究会快很多,这本书可以帮助你事半功倍。

    MySQL内核

    2.5 MySQL Internals Manual

    MySQL Internals Manual》相对于MySQL Manual来说,写的太粗糙,谁让人家是官方文档呢,研究MySQL源码的时候可以简单地参考一下,但是,还是不要指望文档能够回答你的问题,还需要看代码才行。

    //dev.mysql.com/doc/internals/en/

    2.6 MariaDB原理与实现

    评论里提到的《MariaDB原理与实现》我也买了一本,还不错,MariaDB讲的并不多,重点讲了Group Commit、线程池和复制的实现,都是MySQL Server层的知识,对MySQL Server层感兴趣的可以参考一下。

    MariaDB

    3. 后记

    希望这里推荐的材料对学习MySQL的同学、朋友有所帮助,也欢迎推荐靠谱的学习材料,大家共同进步。

    posted @ 2018-12-03 15:54 小马歌 阅读(91) | 评论 (0)编辑 收藏

    2018年11月23日

         摘要: from:https://yq.aliyun.com/articles/69520?utm_content=m_10360#6摘要: # 我的问题排查工具箱 ## 前言 平时的工作中经常碰到很多疑难问题的处理,在解决问题的同时,有一些工具起到了相当大的作用,在此书写下来,一是作为笔记,可以让自己后续忘记了可快速翻阅,二是分享,希望看到此文的同学们可以拿出自己日常觉得帮助很大的工具,大家一...  阅读全文
    posted @ 2018-11-23 10:47 小马歌 阅读(49) | 评论 (0)编辑 收藏

    2018年9月3日

         摘要: from:https://www.cnblogs.com/Anker/p/3271773.html1、前言  之前在看《unix环境高级编程》第八章进程时候,提到孤儿进程和僵尸进程,一直对这两个概念比较模糊。今天被人问到什么是孤儿进程和僵尸进程,会带来什么问题,怎么解决,我只停留在概念上面,没有深入,倍感惭愧。晚上回来google了一下,再次参考APUE,认真总结一下,加深理解。2、基本概念  我...  阅读全文
    posted @ 2018-09-03 19:53 小马歌 阅读(39) | 评论 (0)编辑 收藏

    2017年10月12日

    from://blog.csdn.net/vfush/article/details/51086274

    最近做了个Web项目, 架构上使用了 Nginx +tomcat 集群, 且全站HTTPS,用nginx 做负载,nginx和tomcat 使用内网http通信,遇到http css,js静态资源被浏览器拦截问题,网上搜索到的很多文章在描述 Nginx + Tomcat 启用 HTTPS 支持的时候,都必须在 Nginx 和 Tomcat 两边同时配置 SSL 支持,今天做个总结。

    遇到问题

    1. nginx强制使用https访问(http跳转到https)
    2. http的js,css 等静态资源被浏览器拦截(http不被信任)

    最后的解决方案

    首先解决第一个问题全站https 
    参考 
    三种方式,跟大家共享一下

    nginx的rewrite方法

    server {   listen  192.168.1.111:80;   server_name test.com;   rewrite ^(.*)$  https://$host$1 permanent; }   

    nginx的497状态码,我选择了这种方式

    server {       listen       192.168.1.11:443;  #ssl端口       listen       192.168.1.11:80;   #用户习惯用http访问,加上80,后面通过497状态码让它自动跳到443端口       server_name  test.com;       #为一个server{......}开启ssl支持       ssl                  on;       #指定PEM格式的证书文件        ssl_certificate      /etc/nginx/test.pem;        #指定PEM格式的私钥文件       ssl_certificate_key  /etc/nginx/test.key;        #让http请求重定向到https请求        error_page 497  https://$host$uri?$args;   }   

    index.html刷新网页

    <html>   <meta http-equiv="refresh" content="0;url=https://test.com/">   </html>  

    当http访问到index.html时候自动跳转到https


    接下来解决第二个问题 
    如果tomcat 和nginx 双方没有配置X-Forwarded-Proto tomcat就不能正确区分实际用户是http 还是https,导致tomcat 里配置的静态资源被认为是http而被浏览器拦截,request.getScheme()总是 http,而不是实际的http或https

    分别配置一下 Nginx 和 Tomcat ,果然好了。 
    配置 Nginx 的转发选项:

     proxy_set_header       Host $host;       proxy_set_header  X-Real-IP  $remote_addr;       proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;       proxy_set_header X-Forwarded-Proto  $scheme;  
    • 1
    • 2
    • 3
    • 4

    配置Tomcat server.xml 的 Engine ??橄屡渲靡桓?Valve:

    <Valve className="org.apache.catalina.valves.RemoteIpValve"   remoteIpHeader="X-Forwarded-For"   protocolHeader="X-Forwarded-Proto"   protocolHeaderHttpsValue="https"/>  
    • 1
    • 2
    • 3
    • 4

    非80端口配置 
    Nginx增加以下配置 
    proxy_set_header Host $host:$server_port; 非80端口 ,用80端口时 不需要$server_port 
    proxy_set_header X-Real-IP $remote_addr; 
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
    proxy_set_header X-Forwarded-Proto $scheme; 

    Tomcat server.xml配置 
    <Engine name="Catalina" defaultHost="localhost"> 
    <Valve className="org.apache.catalina.valves.RemoteIpValve" 
    remoteIpHeader="X-Forwarded-For" 
    protocolHeader="X-Forwarded-Proto" 
    protocolHeaderHttpsValue="https" httpsServerPort="7001"/> 非80端口时,必须增加httpsServerPort配置,不然request.getServerPort()方法返回 443. 
    </Engine>

    关于 RemoteIpValve,可以阅读下 doc

    //tomcat.apache.org/tomcat-6.0-doc/api/org/apache/catalina/valves/RemoteIpValve.html

    posted @ 2017-10-12 11:02 小马歌 阅读(223) | 评论 (0)编辑 收藏

    2017年8月11日

    gerrit还是轻易不要尝试引入,它的权限管理,真是复杂极了。对于小型团队,初期这将是个噩梦,但是对于像OpenStack,安卓这种大型team,又是一把利器。
    下面尝试测试了两个用户的简单情况,很多配置都是系统默认,没有进行啥复杂配置,即使这样也是错误百出,光一个commit就要折腾半天,而且还有些机制没搞清楚。
    首先要做的准备工作就是准备两个gerrit用户,user1和user2,并且分别把user1和user2的ssh pub-key通过gerrit setting添加好。
    1. 首先user1创建一个叫HelloWord的project。
       如何创建project请参考前期博客或者官方文档。
    2. user1在自己的工作环境中把HelloWord clone下来
    [user1@jenkins ~]$ git clone ssh://user1@gerrit.example.com:29418/HelloWorld.git
    Initialized empty Git repository in /home/user1/HelloWorld/.git/
    remote: Counting objects: 2, done
    remote: Finding sources: 100% (2/2)
    remote: Total 2 (delta 0), reused 0 (delta 0)
    Receiving objects: 100% (2/2), done.
    加入user1没有添加ssh pubkey的话,这一步会出permission deny

    clone后,创建一个README文件并add,commit
    [user1@jenkins ~]$ cd HelloWorld
    [user1@jenkins HelloWorld]$ ls
    [user1@jenkins HelloWorld]$ touch README
    [penxiao@jenkins test]$ git add README 
    [penxiao@jenkins test]$ git commit -m add README
    这里注意一点,在下面要push之前,一定要配置好git config的 username和email
    可以通过命令行或者直接编辑 ~/.gitconfig文件实现,而且email一定要和gerrit里注册的email一致,否者push也会出错。
    [user1@jenkins HelloWorld]$ git push origin master
    Counting objects: 3, done.
    Writing objects: 100% (3/3), 213 bytes, done.
    Total 3 (delta 0), reused 0 (delta 0)
    remote: Processing changes: refs: 1, done    
    To ssh://user1@gerrit.example.com:29418/HelloWorld.git
     * [new branch]      master -> master
    [user1@jenkins HelloWorld]$

    在gerrit的gitweb链接可以查看push的文件。
    3. user2加入
    [user2@jenkins ~]$ git clone ssh://user1@gerrit.example.com:29418/HelloWorld.git
    Initialized empty Git repository in /home/user2/HelloWorld/.git/
    remote: Counting objects: 3, done
    remote: Finding sources: 100% (3/3)
    remote: Total 3 (delta 0), reused 3 (delta 0)
    Receiving objects: 100% (3/3), done.
    [user2@jenkins ~]$ cd HelloWorld
    [user2@jenkins HelloWorld]$ ls
    README
    [user2@jenkins HelloWorld]$ 
    user2对README文件进行修改,然后要commit,push
    ?。?!也同样注意,user2的git config,username和email的配置,email要和gerrit setting里的一致。
    commit完以后可以看到
    [user2@jenkins HelloWorld]$ git log
    commit 7959fe47bc2d2f53539a1861aa6b0d71afe0a531
    Author: user2 <user2@gerrit.com>
    Date:   Thu Dec 12 00:24:53 2013 -0500
        edit README
    commit 98099fc0de3ba889b18cf36f9a5af267b3ddb501
    Author: user1 <user@gerrit.com>
    Date:   Thu Dec 12 00:15:08 2013 -0500
        add README
    [user2@jenkins HelloWorld]$
    现在user2要把这次的改变push到gerrit,可以么?
    不行的,可以看到
    [user2@jenkins HelloWorld]$ git push origin master
    Counting objects: 5, done.
    Writing objects: 100% (3/3), 249 bytes, done.
    Total 3 (delta 0), reused 0 (delta 0)
    remote: Branch refs/heads/master:
    remote: You are not allowed to perform this operation.
    remote: To push into this reference you need 'Push' rights.
    remote: User: user2
    remote: Please read the documentation and contact an administrator
    remote: if you feel the configuration is incorrect
    remote: Processing changes: refs: 1, done    
    To ssh://user2@gerrit.example.com:29418/HelloWorld.git
     ! [remote rejected] master -> master (prohibited by Gerrit)
    error: failed to push some refs to 'ssh://user2@gerrit.example.com:29418/HelloWorld.git'
    [user2@jenkins HelloWorld]$ 
    这就是gerrit的精髓所在了。原因是gerrit不允许直接将本地修改同步到远程仓库??突Щ匦胂萷ush到远程仓库的refs/for/*分支上,等待审核。这也是为什么我们需要使用gerrit的原因。gerrit本身就是个代码审核工具。

    接下来更该push的地址:  
    [user2@jenkins HelloWorld]$git config remote.origin.push refs/heads/*:refs/for/*  
    此命令实际是更改的是本地仓库test_project/.git/config文件。 
    再次push   
    [user2@jenkins HelloWorld]$git push origin  
    这次不要加master
    [user2@jenkins HelloWorld]$ git push origin
    Counting objects: 5, done.
    Writing objects: 100% (3/3), 249 bytes, done.
    Total 3 (delta 0), reused 0 (delta 0)
    remote: Processing changes: refs: 1, done    
    remote: ERROR: missing Change-Id in commit message footer
    remote: Suggestion for commit message:
    remote: edit README
    remote: 
    remote: Change-Id: I7959fe47bc2d2f53539a1861aa6b0d71afe0a531
    remote: 
    remote: Hint: To automatically insert Change-Id, install the hook:
    remote:   gitdir=$(git rev-parse --git-dir); scp -p -P 29418 user2@gerrit.example.com:hooks/commit-msg ${gitdir}/hooks/
    remote: 
    remote: 
    To ssh://user2@gerrit.example.com:29418/HelloWorld.git
     ! [remote rejected] master -> refs/for/master (missing Change-Id in commit message footer)
    error: failed to push some refs to 'ssh://user2@gerrit.example.com:29418/HelloWorld.git'
    尼玛,还是不行,说缺change-Id,为了能让每次commit能自己insert 这个change-id,需要从gerrit server上下载一个脚本
    [user2@jenkins HelloWorld] scp -p 29418 user2@gerrit.example.com:hooks/commit-msg <local path to your git>/.git/hooks/
    然后重新commit
    [user2@jenkins HelloWorld]$ git commit --amend
    再次查看git log
    [user2@jenkins HelloWorld]$ git log
    commit f6b5919170875b5b4870fca2ab906c516c97006e
    Author: user2 <user2@gerrit.com>
    Date:   Thu Dec 12 00:24:53 2013 -0500
        edit by user2
        
        Change-Id: Ieac68bebefee7c6d4237fa5c058386bf7c4f66b7
    commit 98099fc0de3ba889b18cf36f9a5af267b3ddb501
    Author: user1 <user1@gerrit.com>
    Date:   Thu Dec 12 00:15:08 2013 -0500
        add README
    [user2@jenkins HelloWorld]$ 
    这次就有了change id
    然后再次push
    [user2@jenkins HelloWorld]$ git push origin
    Counting objects: 5, done.
    Writing objects: 100% (3/3), 289 bytes, done.
    Total 3 (delta 0), reused 0 (delta 0)
    remote: Processing changes: new: 1, refs: 1, done    
    remote: 
    remote: New Changes:
    remote:   //gerrit.example.com:8080/1
    remote: 
    To ssh://user2@gerrit.example.com:29418/HelloWorld.git
     * [new branch]      master -> refs/for/master
    [user2@jenkins HelloWorld]$ 
    posted @ 2017-08-11 11:23 小马歌 阅读(100) | 评论 (0)编辑 收藏
    仅列出标题  3d走势图综合版
     
  • 汉能发布汉纸、汉包:移动能源时代全面到来 2019-05-26
  • 高清:阿根廷训练备战小组赛 今晚首战对阵冰岛 2019-05-25
  • 【访民情 惠民生 聚民心】果勒买里村丰收忙 2019-05-25
  • 如何理解孔子这句话?北大教授胡军动情论生死 2019-05-23
  • 2026世界杯花落北美三国 2019-05-20
  • 地价10年暴涨4倍背后:供地减半 开发商拿地疯狂 ——凤凰网房产杭州 2019-05-20
  • 建设海洋强国,习近平总书记在多个场合这样说 2019-05-14
  • 美国又打出2000亿关税牌,中方这300字声明暗藏玄机! 2019-05-12
  • 世界杯专版 竞猜型彩票 赔率是公认的竞猜利器 2019-05-08
  • 要战胜对手必须了介他学习对手长处改掉自己短处,所以我们要学习美國长处为我所用.曰本在唐朝派遣唐史向中國学习,近代学西方进行明治维新迅速强大成为东方最强國家即证据 2019-05-04
  • [雷人]跟你的铁环玩去! 2019-05-01
  • 回复@老老保老张工:那只能证明你的智商不达标!对于计划经济的构想,咱敢说强坛没有一个人比咱考虑得更周全!伪高工排在一个筋斗云之外! 2019-04-15
  • 傍晚,听一曲温柔的天鹅湖 2019-04-15
  • 马刺头号球星申请换队并确定下家 波波维奇也不好使了 2019-04-15
  • [大笑]所以说你不仅智商低还不谦虚嘛! 2019-04-15
  • 海南飞鱼体彩网 福彩3d字谜总汇 北京赛车pk10技巧 双色球走势图500期 赛车北京pk10心得 3d走势图网易彩票 二八杠游戏 体彩p3字谜图谜总汇 特区七星彩论坛 11选5怎么算中奖规则 好多乐彩票 体彩排列5走势图 广东时时彩怎么玩 重庆幸运农场技巧规律 新时时彩和老时时彩有什么区别 河北时时彩平台