<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet type="text/css" href="/css/feed.min.862ab8f8bb15f1f3203a5b9e6a474b6fcd7e7137c22209e346175b0856acfd97.css"?><rss data-theme="dark" data-theme-default="dark" version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:h="http://www.w3.org/1999/xhtml"><channel><title>Troubleshooting · atman · ihx.cc | AirPlan - A biger solution</title><link>https://atman.ihx.cc/tags/troubleshooting/</link><description>君子不器，日日自新。一處關於技術、生活與自我探索的行記。</description><language>zh-CN</language><generator>Hugo</generator><copyright>DataBase - Atman as @man</copyright><lastBuildDate>Thu, 02 Jul 2020 00:00:00 +0800</lastBuildDate><atom:link href="https://atman.ihx.cc/tags/troubleshooting/index.xml" rel="self" type="application/rss+xml"/><h:script src="/js/theme.min.e9b6d7597dde98fbf1181117d7e72cec3c16ab35de5b3f3bdb17dbd866e0c62c.js" type="text/javascript" defer="defer"/><h:header class="feed-header"><h:nav><h:a href="https://atman.ihx.cc/">首页</h:a><h:a href="https://atman.ihx.cc/archive/">Archive</h:a><h:button id="theme-toggle" class="feed-theme-toggle" type="button" aria-label="暗色模式" aria-pressed="true" title="切换亮暗风格">亮 / 暗</h:button></h:nav><h:p class="feed-eyebrow">RSS / 全文订阅</h:p><h:h1>Troubleshooting · atman · ihx.cc | AirPlan - A biger solution</h:h1><h:p>将下面的地址粘贴到 RSS 阅读器，即可订阅更新。这里展示最近 12 篇文章的摘要，阅读器中可阅读文章全文。</h:p><h:a class="feed-address" href="https://atman.ihx.cc/tags/troubleshooting/index.xml">https://atman.ihx.cc/tags/troubleshooting/index.xml</h:a><h:p class="feed-note">包含 post 和 look 中的文章 · 按发布时间倒序</h:p></h:header><item><title>九死一生 - 运维小技巧</title><link>https://atman.ihx.cc/post/20200703-27-tskill/</link><guid isPermaLink="true">https://atman.ihx.cc/post/20200703-27-tskill/</guid><pubDate>Thu, 02 Jul 2020 00:00:00 +0800</pubDate><dc:creator>Atman</dc:creator><category>AirPlan</category><category>Troubleshooting</category><description>0x00 陷入江局 回顾下前两篇文档 《纸上谈兵 - TiDB 性能调优》&amp;amp; 《沙盘点将 - TiDB 监控知识初始化》；处理问题的时候从总是一脸懵逼到偶尔无证懵逼；然后尝试给某个组件加个「无证之罪」先绕过这个棘手的问题。 程序在干什么？观察 tidb 监控和 profile 获取 SQL 运行在 TiDB Cluster 的情况 系统在干什么？ …</description><content:encoded><![CDATA[<h2 id="0x00-陷入江局">0x00 陷入江局</h2>
<p>回顾下前两篇文档 <a href="https://atman.ihx.cc/post/20200311-11-performance-map/">《纸上谈兵 - TiDB 性能调优》</a>&amp; <a href="https://atman.ihx.cc/post/20200416-16-init-monitoring-map/">《沙盘点将 - TiDB 监控知识初始化》</a>；处理问题的时候从总是一脸懵逼到偶尔无证懵逼；然后尝试给某个组件加个「无证之罪」先绕过这个棘手的问题。</p>
<p><img src="https://atman.ihx.cc/post/20200703-27-tskill/jiangju.png" alt="陷入江局" loading="lazy" decoding="async">
</p>
<blockquote>
<p>程序在干什么？观察 tidb 监控和 profile 获取 SQL 运行在 TiDB Cluster 的情况
系统在干什么？使用 linux 命令和 node export 查看运行负载
程序和系统一起在干什么？比如 disk util 高的原因？CPU / MEM 占用高的原因？</p>
<p>重点回顾；《一条 SQL 的使命》</p>
</blockquote>
<ul>
<li>TiDB
<ul>
<li>QPS / duration / statement / slow query</li>
<li>parser / compile / PD tso query</li>
<li>kv count / kv error / kv duration</li>
</ul>
</li>
<li>TiKV
<ul>
<li>GRPC「TiKV 进出口港」 / thread cpu / cluster / error</li>
<li>coprocessor / schedule prewrite &amp; commit
<ul>
<li>coprocessor 与 store readpool 是两种查询方式，store readpool 主要应用<strong>不回表主键点查</strong></li>
</ul>
</li>
<li>task / Raft / RocksDB</li>
</ul>
</li>
<li>overview
<ul>
<li>CPU / Memory / Disk performance / OPEN FD / Network IO</li>
</ul>
</li>
<li>SQL 在 TiDB cluster 内运行的过程均有打点记录，资源/耗时 可在 Grafana 上分析后查证</li>
<li>SQL 进入 TiDB 之前、TiKV 与磁盘的交互；该怎么和 SQL 做一一对应呢？</li>
</ul>
<h2 id="0x01-slow-query">0x01 Slow Query</h2>
<p>slow query 文件支持 <a href="https://www.percona.com/doc/percona-toolkit/LATEST/pt-query-digest.html">pt-query-digest</a> 工具分析<br>
<a href="https://docs.pingcap.com/zh/tidb/dev/identify-slow-queries">PingCAP 官网-slow query 慢日志</a>；TiDB 会将执行时间超过 slow-threshold（默认值为 300 毫秒）的语句输出到 slow-query-file（默认值：&ldquo;tidb-slow.log&rdquo;）日志文件中，用于帮助用户定位慢查询语句，分析和解决 SQL 执行的性能问题</p>
<pre><code class="language-sql" data-lang="sql"># Time: 2020-07-02T16:45:48.948834124+08:00  // 执行 query 时间
# Txn_start_ts: 417773531665268886          // 事物 tso  ，类似  mysql gtid
# User: dms@172.16.4.51                     // 执行用户与客户端 IP「前置为 Proxy 时，此处显示 Proxy IP」
# Conn_ID: 327382                           // 链接 ID
# Query_time: 32.452025271                  // query 从 begin 至 commit 总时长，begin 开启后发送 select 语句后，空置一段时间后提交也会被计入
# Parse_time: 0.056166789                   // TiDB-server AST 解析 text to sql 耗时
# Compile_time: 0.000314969                 // TiDB-server Plan 编译耗时
# Process_time: 0.001 Wait_time: 0.001 Request_count: 2 Prewrite_time: 0.003820812 Commit_time: 0.003007832 Get_commit_ts_time: 0.000107308 Write_keys: 1 Write_size: 539 Prewrite_region: 1
# DB: dms                                     // 数据库信息
# Index_names: [t_data_0210:index_id]        // index 使用信息
# Is_internal: false
# Digest: 26becfd8135c8f31011bdb317406018a8de4473c26af18180ef97a91c224a77e
# Stats: t_data_0210:pseudo  // # Stats: t_data_0210:417773784057512074
# Num_cop_tasks: 2
# Cop_proc_avg: 0.0005 Cop_proc_p90: 0.001 Cop_proc_max: 0.001 Cop_proc_addr: 172.16.4.51:20160  // store readpool 不显示该部分信息
# Cop_wait_avg: 0.0005 Cop_wait_p90: 0.001 Cop_wait_max: 0.001 Cop_wait_addr: 172.16.4.51:20160
# Mem_max: 27644
# Prepared: false
# Has_more_results: false
# Succ: true
# Plan: tidb_decode_plan(&#39;2gHwaTAJMzFfNgkwCTEJCjEJMTNfNAkxCTEJdGFibGU6VF9EQVRBXzAyMTkxMDE3MDc0NDk4NjAsIGluZGV4OmRldmljZV9pZCwgcmFuZ2U6WyIyMDAxMTgwMDc2NDE4MSIsIjIwMDExODAwNzYFEYBdLCBrZWVwIG9yZGVyOmZhbHNlLCBzdGF0czpwc2V1ZG8BhQgwXzWOhQB6SQA=&#39;)
UPDATE t_data_0210 SET `pos`=&#39;114&#39; WHERE (`id`=&#39;800764181&#39;);
</code></pre><h3 id="explan">exPlan</h3>
<pre><code class="language-sql" data-lang="sql">(root@127.0.0.1) [(none)]&gt;select tidb_decode_plan(&#39;2gHwaTAJMzFfNgkwCTEJCjEJMTNfNAkxCTEJdGFibGU6VF9EQVRBXzAyMTkxMDE3MDc0NDk4NjAsIGluZGV4OmRldmljZV9pZCwgcmFuZ2U6WyIyMDAxMTgwMDc2NDE4MSIsIjIwMDExODAwNzYFEYBdLCBrZWVwIG9yZGVyOmZhbHNlLCBzdGF0czpwc2V1ZG8BhQgwXzWOhQB6SQA=&#39;);
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| tidb_decode_plan(&#39;2gHwaTAJMzFfNgkwCTEJCjEJMTNfNAkxCTEJdGFibGU6VF9EQVRBXzAyMTkxMDE3MDc0NDk4NjAsIGluZGV4OmRldmljZV9pZCwgcmFuZ2U6WyIyMDAxMTgwMDc2NDE4MSIsIjIwMDExODAwNzYFEYBdLCBrZWVwIG9yZGVyOmZhbHNlLCBzdGF0czpwc2V1ZG8BhQgwXzWOhQB6SQA=&#39;)                           |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| 	TableReader_6	root	1	
	├─IndexScan_4	cop 	1	table:t_data_0210, index:id, range:[&#34;800764181&#34;,&#34;800764181&#34;], keep order:false, stats:pseudo
	└─TableScan_5	cop 	1	table:t_data_0210, keep order:false, stats:pseudo         |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
</code></pre><h3 id="analyze">Analyze</h3>
<p><a href="https://docs.pingcap.com/zh/tidb/v4.0/sql-statement-explain-analyze">PingCAP 官网-Analyze</a>；EXPLAIN ANALYZE 语句的工作方式类似于 EXPLAIN，主要区别在于前者实际上会执行语句。这样可以将查询计划中的估计值与执行时所遇到的实际值进行比较。如果估计值与实际值显著不同，那么应考虑在受影响的表上运行 ANALYZE TABLE。</p>
<blockquote>
<p>explain analyze 是将 SQL 语句在数据库中执行了一遍，然后通过打点收集到的数据；如果是 insert / update /delete 会被实际运行并且操作数据</p>
</blockquote>
<pre><code class="language-sql" data-lang="sql">explain analyze select id from T_DATA_0210  WHERE (`id`=&#39;800764181&#39;);
+---------------------+-------+------+-------------------------------------------------------------------------------------------------------------+----------------------------------+---------+
| id                  | count | task | operator info                                                                                               | execution info                   | memory  |
+---------------------+-------+------+-------------------------------------------------------------------------------------------------------------+----------------------------------+---------+
| Projection_4        | 2.00  | root | paas_dms.t_data_0210.id                                                                         | time:1.195879ms, loops:2, rows:1 | N/A     |
| └─IndexLookUp_7     | 2.00  | root |                                                                                                             | time:1.189899ms, loops:2, rows:1 | 1.25 KB |
|   ├─IndexScan_5     | 2.00  | cop  | table:t_data_0210, index:id, range:[&#34;800764181&#34;,&#34;800764181&#34;], keep order:false | time:0s, loops:1, rows:1         | N/A     |
|   └─TableScan_6     | 2.00  | cop  | table:t_data_0210, keep order:false                                                             | time:0s, loops:1, rows:1         | N/A     |
+---------------------+-------+------+-------------------------------------------------------------------------------------------------------------+----------------------------------+---------+
4 rows in set (0.00 sec)
</code></pre><pre><code class="language-sql" data-lang="sql">// explain analyze select count(*)/count(distinct date_format(account_mdate,&#39;%Y-%m-%d&#39;)) from account;
// 看起来只做了一次 table full scan、同时 distinct 与 date_format 无法下推到 tikv 上执行
+-----------------------------+--------------+-----------+-----------+---------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------+-----------------------+------+
| id                          | estRows      | actRows   | task      | access object | execution info                                                                                                                                                             | operator info                                                                                | memory                | disk |
+-----------------------------+--------------+-----------+-----------+---------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------+-----------------------+------+
| Projection_4                | 1.00         | 1         | root      |               | time:18.899834996s, loops:2, Concurrency:OFF                                                                                                                               | div(cast(Column#19, decimal(20,0) BINARY), cast(Column#20, decimal(20,0) BINARY))-&gt;Column#21 | 744 Bytes             | N/A  |
| └─StreamAgg_6               | 1.00         | 1         | root      |               | time:18.899801597s, loops:2                                                                                                                                                | funcs:count(1)-&gt;Column#19, funcs:count(distinct Column#23)-&gt;Column#20                        | 17.5087890625 KB      | N/A  |
|   └─Projection_11           | 100036000.00 | 100036000 | root      |               | time:670.978479ms, loops:98163, Concurrency:8                                                                                                                              | date_format(findpt.account.account_mdate, %Y-%m-%d)-&gt;Column#23                               | 208.76953125 KB       | N/A  |
|     └─TableReader_10        | 100036000.00 | 100036000 | root      |               | time:528.386518ms, loops:98163, rpc num: 560, rpc max:684.898903ms, min:70.020085ms, avg:427.347923ms, p80:474.446604ms, p95:546.15945ms, proc keys max:255761, p95:178374 | data:TableFullScan_9                                                                         | 113.44037055969238 MB | N/A  |
|       └─TableFullScan_9     | 100036000.00 | 100036000 | cop[tikv] | table:account | proc max:659ms, min:65ms, p80:459ms, p95:529ms, iters:100403, tasks:560                                                                                                    | keep order:false                                                                             | N/A                   | N/A  |
+-----------------------------+--------------+-----------+-----------+---------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------+-----------------------+------+
5 rows in set (18.98 sec)
</code></pre><h3 id="trace">Trace</h3>
<p><a href="https://docs.pingcap.com/zh/tidb/v4.0/sql-statement-trace#trace">PingCAP 官网-Trace</a>；TRACE 语句用于提供查询执行的详细信息，可通过 TiDB 服务器状态端口所公开的图形界面进行查看。</p>
<pre><code class="language-sql" data-lang="sql">trace format = &#39;row&#39; select id from T_DATA_0210  WHERE (`id`=&#39;800764181&#39;);
+---------------------------+-----------------+------------+
| operation                 | startTS         | duration   |
+---------------------------+-----------------+------------+
| session.getTxnFuture      | 17:10:42.721708 | 10.991µs   |
|   ├─session.Execute       | 17:10:42.721705 | 978.341µs  |
|   ├─session.ParseSQL      | 17:10:42.722064 | 28.325µs   |
|   ├─executor.Compile      | 17:10:42.722106 | 191.556µs  |
|   ├─session.runStmt       | 17:10:42.722318 | 314.567µs  |
|   ├─session.CommitTxn     | 17:10:42.722616 | 2.942µs    |
|   ├─recordSet.Next        | 17:10:42.722694 | 812.092µs  |
|   ├─projection.Next       | 17:10:42.722696 | 801.486µs  |
|   ├─tableReader.Next      | 17:10:42.723073 | 394.131µs  |
|   ├─tableReader.Next      | 17:10:42.723484 | 947ns      |
|   ├─recordSet.Next        | 17:10:42.723516 | 12.577µs   |
|   └─projection.Next       | 17:10:42.723518 | 1.747µs    |
+---------------------------+-----------------+------------+
12 rows in set (0.01 sec)
</code></pre><pre><code class="language-sql" data-lang="sql">// 以下信息省略 19 万行，通过 trace 清晰的发现 tidb 与 tikv 之间的网络交互频率
trace format = &#39;row&#39; select count(*)/count(distinct date_format(account_mdate,&#39;%Y-%m-%d&#39;)) from account;
+------------------------------------------------------+-----------------+-----------------+
| operation                                            | startTS         | duration        |
+------------------------------------------------------+-----------------+-----------------+
| trace                                                | 11:37:08.052125 | 3m58.620078133s |
|   ├─session.Execute                                  | 11:37:08.052129 | 1.714218ms      |
|   │ ├─session.ParseSQL                               | 11:37:08.052134 | 21.379µs        |
|   │ ├─executor.Compile                               | 11:37:08.052177 | 270.936µs       |
|   │ │ └─session.getTxnFuture                         | 11:37:08.052184 | 2.886µs         |
|   │ └─session.runStmt                                | 11:37:08.052468 | 1.353082ms      |
|   │   ├─TableReaderExecutor.Open                     | 11:37:08.052518 | 1.215215ms      |
|   │   │ └─distsql.Select                             | 11:37:08.052529 | 1.193386ms      |
|   │   │   ├─rpcClient.SendRequest                    | 11:37:08.053832 | 404.531258ms    |
|   │   │   ├─rpcClient.SendRequest                    | 11:39:53.082502 | 269.187122ms    |
|   │   │   ├─rpcClient.SendRequest                    | 11:39:53.785311 | 240.928959ms    |
|   │   │   └─rpcClient.SendRequest * N                | 11:39:54.539536 | 331.98845ms     |
|   │   └─session.CommitTxn                            | 11:37:08.053803 | 13.513µs        |
|   │     └─session.doCommitWitRetry                   | 11:37:08.053806 | 2.235µs         |
|   ├─*executor.ProjectionExec.Next                    | 11:37:08.053865 | 3m58.617880366s |
|   │ └─*executor.StreamAggExec.Next                   | 11:37:08.053867 | 3m58.614767904s |
|   │   ├─*executor.ProjectionExec.Next                | 11:37:08.053869 | 26.269835ms     |
|   │   │ ├─*executor.TableReaderExecutor.Next         | 11:37:08.053915 | 25.530341ms     |
|   │   │ ├─*executor.TableReaderExecutor.Next         | 11:37:08.079471 | 8.329µs         |
|   │   │ ├─*executor.TableReaderExecutor.Next         | 11:37:08.079491 | 3.369µs         |
|   │   │ ├─*executor.TableReaderExecutor.Next         | 11:41:06.572221 | 14.026µs        |
|   │   │ ├─*executor.TableReaderExecutor.Next         | 11:41:06.577805 | 31.832µs        |
|   │   │ └─*executor.TableReaderExecutor.Next  * N    | 11:41:06.583194 | 19.7µs          |
|   │   ├─*executor.ProjectionExec.Next                | 11:37:08.080339 | 5.499µs         |
|   │   ├─*executor.ProjectionExec.Next                | 11:37:08.080509 | 5.065µs         |
|   │   ├─*executor.ProjectionExec.Next                | 11:37:08.080681 | 5.46µs          |
|   │   ├─*executor.ProjectionExec.Next                | 11:37:08.080855 | 9.297µs         |
|   │   ├─*executor.ProjectionExec.Next                | 11:41:06.663323 | 2.028µs         |
|   │   └─*executor.ProjectionExec.Next  * N           | 11:41:06.665968 | 1.844µs         |
|   └─*executor.ProjectionExec.Next                    | 11:41:06.671764 | 11.448µs        |
|     └─*executor.StreamAggExec.Next                   | 11:41:06.671767 | 568ns           |
+------------------------------------------------------+-----------------+-----------------+
196901 rows in set (5 min 56.31 sec)
</code></pre><h2 id="0x02-ssr">0x02 SSR</h2>
<ul>
<li>Cluster info</li>
</ul>
<p><a href="https://docs.pingcap.com/zh/tidb/v4.0/system-table-cluster-info">PingCAP 官网-Cluster info</a>；集群拓扑表 CLUSTER_INFO 提供集群当前的拓扑信息，以及各个节点的版本信息、版本对应的 Git Hash、各节点的启动时间、各实例的运行时间。</p>
<ul>
<li>TiDB-dashboard</li>
</ul>
<p><a href="https://docs.pingcap.com/zh/tidb/v4.0/dashboard-intro#tidb-dashboard-%E4%BB%8B%E7%BB%8D">TiDB Dashboard</a>是 TiDB 自 4.0 版本起提供的图形化界面，可用于监控及诊断 TiDB 集群。TiDB Dashboard 内置于 TiDB 的 PD 组件中，无需独立部署。</p>
<h2 id="0x03-profile">0x03 Profile</h2>
<blockquote>
<p>Profile 用于分析函数占用内存、CPU 资源信息，TiDB 4.0 版本可以在 tidb-dashboard 上一键获取；以下为分析 tidb-dashboard 后挖掘到的 HTTP API 信息</p>
</blockquote>
<ul>
<li>获取 PD-server Profile
<ul>
<li>内容来自 <a href="https://github.com/pingcap/pd/blob/master/server/api/router.go">PD 代码</a></li>
</ul>
</li>
</ul>
<pre><code class="language-json" data-lang="json">curl http://{PD IP}:{PD 2379}/pd/api/v1/debug/pprof/profile?seconds={int} &gt; CPU-profile
// 上述命令获取 CPU profile 信息

// PD 所有 Profile api 请求，每条 api 输出后二进制文件，使用 go tool pprof 解析
apiRouter.HandleFunc(&#34;/debug/pprof/profile&#34;, pprof.Profile)
apiRouter.Handle(&#34;/debug/pprof/heap&#34;, pprof.Handler(&#34;heap&#34;))
apiRouter.Handle(&#34;/debug/pprof/mutex&#34;, pprof.Handler(&#34;mutex&#34;))
apiRouter.Handle(&#34;/debug/pprof/allocs&#34;, pprof.Handler(&#34;allocs&#34;))
apiRouter.Handle(&#34;/debug/pprof/block&#34;, pprof.Handler(&#34;block&#34;))
apiRouter.Handle(&#34;/debug/pprof/goroutine&#34;, pprof.Handler(&#34;goroutine&#34;))
</code></pre><ul>
<li>获取 TiDB-server Profile
<ul>
<li>该接口可以获取 tidb-server profile 压缩包，内涵 cpu、内存等信息</li>
<li>内容来自 <a href="https://github.com/pingcap/tidb/blob/master/docs/tidb_http_api.md">TiDB http api 文档</a> Download TiDB debug info</li>
</ul>
</li>
</ul>
<pre><code class="language-bash" data-lang="bash">curl http://{TiDB IP}:{TiDB status_port}/debug/pprof/profile?seconds={int} &gt; debug.zip

// zip file will include:
// Go heap pprof(after GC)
// Go cpu pprof(10s)
// Go mutex pprof
// Full goroutine
// TiDB config and version
// Param:
// seconds: profile time(s), default is 10s.
</code></pre><ul>
<li>获取 TiKV-server Profile
<ul>
<li>该接口获取为 svg 图片内容；内容来自 <a href="https://github.com/tikv/tikv/pull/4600">TiKV issue #4600</a></li>
<li>2020 年以后发布的版本支持该功能</li>
</ul>
</li>
</ul>
<pre><code class="language-bash" data-lang="bash">curl http://{TiKV IP}:{TiKV status_port}/debug/pprof/profile?seconds={int} &gt; tikv.svg
</code></pre><ul>
<li>查看 Profile</li>
</ul>
<pre><code class="language-bash" data-lang="bash">yum install go
// 安装 go 程序环境

go tool pprof -http 172.16.4.51:890 &lt;profile-name&gt;
// 使用 go tool pprof 工具解析 profile 数据，并开启一个网页以便在浏览器上查看

浏览器打开该网页访问并分析信息 http://172.16.4.51:890/
</code></pre><h2 id="0x04-linux">0x04 Linux</h2>
<ul>
<li>vmstat / top / htop</li>
<li>dstat / iotop / iostat</li>
<li>lsof</li>
<li>pstack // 该命令会阻断程序正常运行，禁止在 TiKV 使用；会导致 tikv 状态变为 Disconnected，从而丢失所有 region leader</li>
<li>strace</li>
<li>gdb</li>
</ul>
<h3 id="sar">Sar</h3>
<p>SAR（System Activity Reporter），可以从 14 个大方面对系统的活动进行报告，包括文件的读写情况、系统调用的使用情况、串口、CPU 效率、内存使用状况、进程活动及 IPC 有关的活动等，使用也是较为复杂。</p>
<ul>
<li>
<p>追溯过去的统计数据（默认）</p>
</li>
<li>
<p>周期性的查看当前数据</p>
</li>
<li>
<p>怀疑 CPU 存在瓶颈，可用 sar -u 和 sar -q 等来查看</p>
</li>
<li>
<p>怀疑内存存在瓶颈，可用 sar -B、sar -r 和 sar -W 等来查看</p>
</li>
<li>
<p>怀疑 I/O 存在瓶颈，可用 sar -b、sar -u 和 sar -d 等来查看</p>
</li>
</ul>
<pre><code class="language-bash" data-lang="bash">-A 汇总所有的报告
-a 报告文件读写使用情况
-B 报告附加的缓存的使用情况
-b 报告缓存的使用情况
-c 报告系统调用的使用情况
-d 报告磁盘的使用情况
-g 报告串口的使用情况
-h 报告关于 buffer 使用的统计数据
-m 报告 IPC 消息队列和信号量的使用情况
-n 报告命名 cache 的使用情况
-p 报告调页活动的使用情况
-q 报告运行队列和交换队列的平均长度
-R 报告进程的活动情况
-r 报告没有使用的内存页面和硬盘块
-u 报告 CPU 的利用率
-v 报告进程、i 节点、文件和锁表状态
-w 报告系统交换活动状况
-y 报告 TTY 设备活动状况
</code></pre><h2 id="0x05-不友好的">0x05 不友好的</h2>
<ul>
<li>useCursorFetch=True&amp;defaultFetchSize&gt;0</li>
<li>update batchexecutor</li>
</ul>
]]></content:encoded><h:time datetime="2020-07-02T00:00:00+08:00">2020-07-02 · post</h:time><h:a class="feed-article-title" href="https://atman.ihx.cc/post/20200703-27-tskill/">九死一生 - 运维小技巧</h:a></item><item><title>总结 - Data Migration（数据同步）</title><link>https://atman.ihx.cc/post/20191008-41-dm-faq/</link><guid isPermaLink="true">https://atman.ihx.cc/post/20191008-41-dm-faq/</guid><pubDate>Tue, 08 Oct 2019 00:00:00 +0800</pubDate><dc:creator>Atman</dc:creator><category>DM</category><category>mindmap</category><category>Troubleshooting</category><description>0x00 开局 本文仅记录了对 DM 的学习，处理问题经验慢慢补充（没有素材编场景） 版本使用从 RC 到 v1.0.3 ；架构整体变化不大，有着上纲上线的框架守护 本页内容没有干货、学习 DM 使用请关闭本页去 PingCAP 官网文档 0x01 一 DM (Data Migration) 是一体化的数据同步任务管理平台，支持从 MySQL …</description><content:encoded><![CDATA[<h2 id="0x00-开局">0x00 开局</h2>
<blockquote>
<p>本文仅记录了对 DM 的学习，处理问题经验慢慢补充（没有素材编场景）<br>
版本使用从 RC 到 v1.0.3 ；架构整体变化不大，有着上纲上线的框架守护<br>
<strong>本页内容没有干货</strong>、学习 DM 使用请关闭本页去 PingCAP <a href="https://pingcap.com/docs-cn/stable/reference/tools/data-migration/overview/#dm-%e6%9e%b6%e6%9e%84">官网文档</a></p>
</blockquote>
<h2 id="0x01-一">0x01 一</h2>
<blockquote>
<p>DM (Data Migration) 是一体化的数据同步任务管理平台，支持从 MySQL 或 MariaDB 到 TiDB 的全量数据迁移和增量数据同步。使用 DM 工具有利于简化错误处理流程，降低运维成本。<br>
如有 Syncer、Loader、MyDumper 使用经验，学习速度加倍</p>
</blockquote>
<p>DM 设计之初是将之前常用的三组件（Syncer、Loader、MyDumper ）数据同步方式做了一个打包集合体，然后加了一些增值管理功能来维护同步任务，同时增加 <strong>sharding ddl lock、auto increment ID 重写</strong>两个刚需功能。<br>
此处回顾一句话 <em>“如果整篇文章你只想记住一句话，那就是数据条数少于 5000w 的场景下通常用不到 TiDB，TiDB 是为大规模的数据场景设计的。如果还想记住一句话，那就是单机 MySQL 能满足的场景也用不到 TiDB（<a href="https://pingcap.com/blog-cn/how-to-use-tidb/">文字传送门</a>）”</em>。<br>
数据群体来自于分库分表，如果不支持 sharding ddl 、auto increment ID 那么帮助客户导入数据呢？之前方案 Syncer 同步数据如果有 DDL 就主动退出，等所有分片退出后手动下游执行 DDL，跳过 DDL 后启动 Syncer 继续同步（对于不频繁操作 DDL 场景能用）。<br>
DM 主要包括三个组件：DM-master，DM-worker 和 dmctl。其中 DM Worker 内打包了 （Syncer、Loader、MyDumper ）；DM master 管理 sharding ddl 状态和同步任务状态，DM-ctl 是运维管理入口。</p>
<p>创造来下图这个架构流程来同步 MySQL、MariaDB 的数据到 TiDB cluster ⬇️：</p>
<ul>
<li>想要了解 DM 可阅读<a href="https://pingcap.com/docs-cn/stable/reference/tools/data-migration/overview/#dm-%e6%9e%b6%e6%9e%84">官网文档</a>（toc 直达车）
<ul>
<li>四大<a href="https://pingcap.com/docs-cn/stable/reference/tools/data-migration/features/overview/">增值功能</a></li>
<li>使用场景：<a href="https://pingcap.com/docs-cn/stable/reference/tools/data-migration/usage-scenarios/simple-synchronization/">单库同步场景</a>
<ul>
<li>分库分表<a href="https://pingcap.com/docs-cn/stable/reference/tools/data-migration/usage-scenarios/best-practice-dm-shard/">最佳实践</a></li>
</ul>
</li>
<li><a href="https://pingcap.com/docs-cn/stable/reference/tools/data-migration/deploy/">安装方式</a></li>
<li>同步会话相关
<ul>
<li>task <a href="https://pingcap.com/docs-cn/stable/reference/tools/data-migration/configure/task-configuration-file/">配置手册</a></li>
<li><a href="https://pingcap.com/docs-cn/stable/reference/tools/data-migration/manage-tasks/">任务管理</a></li>
</ul>
</li>
<li><a href="https://pingcap.com/docs-cn/stable/reference/tools/data-migration/monitor/">监控信息</a></li>
<li><a href="https://pingcap.com/docs-cn/stable/reference/tools/data-migration/glossary/">术语表</a></li>
</ul>
</li>
</ul>
<p><img src="https://atman.ihx.cc/post/20191008-41-dm-faq/dm-architecture.png" alt="官方架构图" loading="lazy" decoding="async">
</p>
<h2 id="0x02-张">0x02 张</h2>
<p>通过这张图（下面这张图有 2MB ⬇️）复习下 DM 框架架构（图片按照顺时针的方式查看）：</p>
<p>这张图将 DM 整体流程划分 上游、开局（框架结构）、增值（核心功能）、task.yml（任务配置）、运维（部署、监控 、日常运维）五个部分；本图不是一概而全，只是列出一些关键信息方便浏览和阅读。</p>
<p><img src="https://atman.ihx.cc/post/20191008-41-dm-faq/DM-mindmap.png" alt="DM mindmap" title="ap.tidb.cc DM 开局一张图 202200205" loading="lazy" decoding="async">
</p>
<blockquote>
<p>自我诡辩，DM 架构是在 syncer、loader 架构上做了个打包，然后使用 DM 做了几个同步数据的项目场景，然后绘制此图。改图肯定还有一些遗漏和错误，仅供参考。</p>
</blockquote>
<p>顺时针介绍了 DM 支持上游的 Mysql、MariaDB 版本信息，不在版本范围中的可能会遇见 Binlog 数据不兼容问题，mysql 5.5 到 5.7 横跨近十年的产品，在早起版本和最新版本上有很多数据相关的优化，特定优化需要做相关的兼容性。<br>
第二、第三两个小节介绍 DM master、DM workder 架构与 DM worker 内部逻辑、DM 核心功能。目前 DM 还没有物理结构的高可用方案，链路上的高可用方案目前有下游到 TiDB 的心跳保持。DM master 管理同步数据任务与 sharding ddl 状态，DM worker 处理数据导出、数据导入、增量数据同步工作（DM worker 与上游 instanceDB 一一绑定工作，无法切换自身状态）。DM 的核心功能中的 route、黑白名单与之前 Syncer 上的一样，只不过此处填写 values 时全部按照上游的信息填写（syncer 在使用 route 后需要按照下游写黑白名单）。而剩下两个功能一个是自动维护的，另一个 column mapping 是人工指定的，在使用上有比较大的限制，如果业务代码中有使用 auto increment id 做业务属性关联，使用 column mapping 改写数据会导致业务失效的，新业务推荐此处修改为全局 UUID 、sequence ID、业务流水号等作为全局唯一 KEY。<br>
第四小节 task yaml 说了下配置文件内从上到下的划分功能，全局是针对该同步任务的一些开关操作（比如 shard、检查项、断点信息、心跳信息、数据工作模式等），然后是 上下游信息，此处下游信息仅此处填写一个、上游信息支持填写多个 instance （每个 instance 对应一个 DM worker，然后通过 DM-master 配置文件映射到上游的 mysql 实例），在上游 instance 区域内可以选择使用 route、column mapping 、黑白名单等功能（类似与先声明函数然后调用执行函数块）。接下来是声明 route、黑白名单、column mapping 功能了，这部分仅仅是书写规则，在不被调用的情况下是不会开启的。最后这部分是一些特殊参数，关于 syncer、loader、mydumper 原本自身携带的特性，需要通过配置文件传递给这些组件来运行。<br>
第五、第六两个小节是记录了下 DM 监控和 DM 文档的位置，从这些地方可以看到 DM 相关的文档信息。</p>
<h2 id="0x03-图">0x03 图</h2>
<blockquote>
<p>ToDo：此处准备整理几个容易出问题的场景介绍下（预计在未来一个月时间凑够蔬菜做饭 20200315）</p>
</blockquote>
<ul>
<li><input disabled="" type="checkbox"> 数据不一致</li>
<li><input disabled="" type="checkbox"> 数据同步慢</li>
<li><input disabled="" type="checkbox"> 服务启动失败</li>
<li><input disabled="" type="checkbox"> 数据重新同步</li>
</ul>
]]></content:encoded><h:time datetime="2019-10-08T00:00:00+08:00">2019-10-08 · post</h:time><h:a class="feed-article-title" href="https://atman.ihx.cc/post/20191008-41-dm-faq/">总结 - Data Migration（数据同步）</h:a></item><item><title>School - TiKV not leader</title><link>https://atman.ihx.cc/post/20181126-48-not-leader/</link><guid isPermaLink="true">https://atman.ihx.cc/post/20181126-48-not-leader/</guid><pubDate>Mon, 26 Nov 2018 00:00:00 +0800</pubDate><dc:creator>Atman</dc:creator><category>not leader</category><category>server is busy</category><category>prevote</category><category>Troubleshooting</category><description>0x00 监控 使用云机房物理机设备组建同城三中心方式部署 部署时已知 idc3 与其他两个机房 ping latency 稍高，大约在 1 - 3 ms 之间，idc1 与 idc2 机房延迟稳定在 1ms 以内 0x01 架构 排查思路 0x02 原因 14:56:30 - 14:58:00 时间出现网络抖动 TiKV to TiKV …</description><content:encoded><![CDATA[<h2 id="0x00-监控">0x00 监控</h2>
<p>使用云机房物理机设备组建同城三中心方式部署<br>
部署时已知 idc3 与其他两个机房 ping latency 稍高，大约在 1 - 3 ms 之间，idc1 与 idc2 机房延迟稳定在 1ms 以内</p>
<p><img src="https://atman.ihx.cc/post/20181126-48-not-leader/multi-data-centers-in-one-city-deployment-sample.png" alt="同城多中心部署" title="ap.tidb.cc" loading="lazy" decoding="async">
</p>
<h2 id="0x01-架构">0x01 架构</h2>
<p><img src="https://atman.ihx.cc/post/20181126-48-not-leader/QPS-duration.png" alt="QPS 出现较大延迟" title="ap.tidb.cc" loading="lazy" decoding="async">

<img src="https://atman.ihx.cc/post/20181126-48-not-leader/qps-by-instance.png" alt="QPS 链接出现下降" title="ap.tidb.cc" loading="lazy" decoding="async">
</p>
<p><img src="https://atman.ihx.cc/post/20181126-48-not-leader/tikv-error.png" alt="tikv error 没有明显错误" title="ap.tidb.cc" loading="lazy" decoding="async">
</p>
<p><img src="https://atman.ihx.cc/post/20181126-48-not-leader/blackbox-ping.png" alt="网络 ping 延迟增高" title="ap.tidb.cc" loading="lazy" decoding="async">
</p>
<h3 id="排查思路">排查思路</h3>
<p><img src="https://atman.ihx.cc/post/20181126-48-not-leader/not-leader.png" alt="not leader 排查思路" title="ap.tidb.cc" loading="lazy" decoding="async">
</p>
<h2 id="0x02-原因">0x02 原因</h2>
<ul>
<li>14:56:30 - 14:58:00 时间出现网络抖动
<ul>
<li>TiKV to TiKV 之间出现 region 心跳链接断开发起重新选举</li>
</ul>
</li>
<li>14:58 region 重新被选举过程中遇到 TiDB 读取数据
<ul>
<li>TiKV 经 backoff 返回 not leader 消息</li>
</ul>
</li>
<li>整体场景是某个节点被网络隔离后出现的问题（CAP 隔离）</li>
</ul>
<p><img src="https://atman.ihx.cc/post/20181126-48-not-leader/cap.png" alt="cap" title="ap.tidb.cc" loading="lazy" decoding="async">
</p>
<h3 id="prevote">prevote</h3>
<p><img src="https://atman.ihx.cc/post/20181126-48-not-leader/prevote.webp" alt="prevote" title="ap.tidb.cc" loading="lazy" decoding="async">
</p>
<p>Follower_2 在 electionTimeout 没收到心跳之后, 会发起选举，并转为 Candidate。每次发起选举时，会把 Term 加一。由于网络隔离，它既不会被选成 Leader，也不会收到 Leader 的消息，而是会一直不断地发起选举。Term 会不断增大。</p>
<p>一段时间之后，这个节点的 Term 会非常大。在网络恢复之后，这个节点会把它的 Term 传播到集群的其他节点，导致其他节点更新自己的 term，变为 Follower。然后触发重新选主，但这个旧的 Follower_2 节点由于其日志不是最新，并不会成为 Leader。整个集群被这个网络隔离过的旧节点扰乱，显然需要避免的。</p>
<blockquote>
<p>Raft 作者博士论文《CONSENSUS: BRIDGING THEORY AND PRACTICE》的第 9.6 节 &ldquo;Preventing disruptions when a server rejoins the cluster&rdquo; 提到了 PreVote 算法的大概实现思路。</p>
</blockquote>
<p>在 PreVote 算法中，Candidate 首先要确认自己能赢得集群中大多数节点的投票，这样才会把自己的 term 增加，然后发起真正的投票。其他投票节点同意发起选举的条件是（同时满足下面两个条件）：</p>
<p>没有收到有效领导的心跳，至少有一次选举超时<br>
Candidate 的日志足够新（Term 更大，或者 Term 相同 raft index 更大）<br>
PreVote 算法解决了网络分区节点在重新加入时，会中断集群的问题。在 PreVote 算法中，网络分区节点由于无法获得大部分节点的许可，因此无法增加其 Term<br>
然后当它重新加入集群时，它仍然无法递增其 Term，因为其他服务器将一直收到来自 Leader 节点的定期心跳信息。一旦该服务器从领导者接收到心跳，它将返回到 Follower 状态，Term 和 Leader 一致</p>
]]></content:encoded><h:time datetime="2018-11-26T00:00:00+08:00">2018-11-26 · post</h:time><h:a class="feed-article-title" href="https://atman.ihx.cc/post/20181126-48-not-leader/">School - TiKV not leader</h:a></item><item><title>School - Binlog &amp; TSO</title><link>https://atman.ihx.cc/post/20181029-44-binlog-tso/</link><guid isPermaLink="true">https://atman.ihx.cc/post/20181029-44-binlog-tso/</guid><pubDate>Mon, 29 Oct 2018 00:00:00 +0800</pubDate><dc:creator>Atman</dc:creator><category>Binlog</category><category>TSO</category><category>Troubleshooting</category><description>0x00 事前 维护该 Binlog 架构下的问题之一 “GC 数据问题” 0x01 FAQ-1 某天巡检发现以下现象，pump 还在工作、Drainer 写入出现中断 查看 Drainer 日志 pump.go:433: ESC[0;37m[info] [pump 10-30-1-9:8250] consume from topic …</description><content:encoded><![CDATA[<h2 id="0x00-事前">0x00 事前</h2>
<blockquote>
<p>维护该 Binlog 架构下的问题之一 “GC 数据问题”</p>
</blockquote>
<p><img src="https://atman.ihx.cc/post/20181029-44-binlog-tso/1-binlog.png" alt="ap.tidb.cc" title="ap.tidb.cc" loading="lazy" decoding="async">
</p>
<h2 id="0x01-faq-1">0x01 FAQ-1</h2>
<blockquote>
<p>某天巡检发现以下现象，pump 还在工作、Drainer 写入出现中断</p>
</blockquote>
<p><img src="https://atman.ihx.cc/post/20181029-44-binlog-tso/2-pump.png" alt="ap.tidb.cc" title="ap.tidb.cc" loading="lazy" decoding="async">
</p>
<p><img src="https://atman.ihx.cc/post/20181029-44-binlog-tso/3-drainer.png" alt="ap.tidb.cc" title="ap.tidb.cc" loading="lazy" decoding="async">
</p>
<blockquote>
<p>查看 Drainer 日志</p>
</blockquote>
<pre><code class="language-fallback" data-lang="fallback">pump.go:433: ESC[0;37m[info] [pump 10-30-1-9:8250] consume from topic 6502327210476397260_10-30-1-9_8250 partition 0 offset 71500ESC[0m
pump.go:436: ESC[0;33m[warning] [pump 10-30-1-9:8250] get consumer partition client error kafka server: The requested offset is outside the range of offsets maintained by the server for the given topic/partition.ESC[0m
pump.go:433: ESC[0;37m[info] [pump 10-30-1-10:8250] consume from topic 6502327210476397260_10-30-1-10_8250 partition 0 offset 4633751ESC[0m
pump.go:436: ESC[0;33m[warning] [pump 10-30-1-10:8250] get consumer partition client error kafka server: The requested offset is outside the range of offsets maintained by the server for the given topic/partition.ESC[0m
pump.go:433: ESC[0;37m[info] [pump 10-30-1-11:8250] consume from topic 6502327210476397260_10-30-1-11_8250 partition 0 offset 3693588ESC[0m
pump.go:436: ESC[0;33m[warning] [pump 10-30-1-11:8250] get consumer partition client error kafka server: The requested offset is outside the range of offsets maintained by the server for the given topic/partition.ESC[0m
</code></pre><h3 id="过程">过程</h3>
<p>Drainer 链接 Kafka 获取指定 offset 数据时，发现超出 kafka 内实际数据范围。该现象分头部越界与尾部越界：</p>
<p><img src="https://atman.ihx.cc/post/20181029-44-binlog-tso/4-offset.png" alt="ap.tidb.cc Drainer kafka offset" title="ap.tidb.cc" loading="lazy" decoding="async">
</p>
<p>造成数据超越界限的情况有两种：</p>
<ol>
<li>人工主动删除 Kafka 内的数据，</li>
<li>Kafka GC 机制主动删除了过期数据；
<ul>
<li>Kafka 配置文件中的 retention 参数控制</li>
<li>例如 <code>log.retention.bytes=1024</code> 只保留 1024 个字节，<code>log.retention.hours=1</code> 只保留最近 1 小时数据；</li>
<li>如果配置两个参数，任何一个达到阈值都会被 Kafka 执行</li>
</ul>
</li>
</ol>
<blockquote>
<p>Binlog 2.0<br>
Pump 先将数据 Push 到 Kafka；Drainer 读取 Kafka 内的数据进行消费，如果 Kafka 内数据 <strong>GC 阈值不合理</strong>或者被<strong>人工主动删除</strong>，会出现以上问题。</p>
</blockquote>
<p><img src="https://atman.ihx.cc/post/20181029-44-binlog-tso/5-ts.png" alt="ap.tidb.cc Drainer kafka offset" title="ap.tidb.cc" loading="lazy" decoding="async">
</p>
<blockquote>
<p>按照全量+增量从头再来一遍</p>
</blockquote>
<h2 id="0x02-faq-2">0x02 FAQ-2</h2>
<blockquote>
<p>该条 FAQ 来源于上条 Drainer 重新启动失败</p>
</blockquote>
<ul>
<li>API 获取 PUMP 节点状态</li>
</ul>
<pre><code class="language-json" data-lang="json">curl http:// PUMPip:PUMPport/status
curl http://10.30.1.10:8250/status

{
	&#34;LatestBinlog&#34;: {
		&#34;10-30-1-10:8250&#34;: {
			&#34;file-position&#34;: {
				&#34;suffix&#34;: 297,
				&#34;offset&#34;: 254175949
			},
			&#34;kafka-position&#34;: {
				&#34;offset&#34;: 14535476
			}
		},
		&#34;10-30-1-10:8251&#34;: {
			&#34;file-position&#34;: {
				&#34;offset&#34;: 7939251
			},
			&#34;kafka-position&#34;: {
				&#34;offset&#34;: 173037
			}
		},
		&#34;10-30-1-11:8250&#34;: {
			&#34;file-position&#34;: {
				&#34;suffix&#34;: 308,
				&#34;offset&#34;: 292719018
			},
			&#34;kafka-position&#34;: {
				&#34;offset&#34;: 13891570
			}
		},
		&#34;10-30-1-11:8251&#34;: {
			&#34;file-position&#34;: {
				&#34;offset&#34;: 8005580
			},
			&#34;kafka-position&#34;: {
				&#34;offset&#34;: 172300
			}
		},
		&#34;10-30-1-9:8250&#34;: {
			&#34;file-position&#34;: {
				&#34;suffix&#34;: 476,
				&#34;offset&#34;: 466616386
			},
			&#34;kafka-position&#34;: {
				&#34;offset&#34;: 93158361
			}
		},
		&#34;10-30-1-9:8251&#34;: {
			&#34;file-position&#34;: {
				&#34;offset&#34;: 8029075
			},
			&#34;kafka-position&#34;: {
				&#34;offset&#34;: 173146
			}
		}
	},
	&#34;CommitTS&#34;: 403911906584952955,
	&#34;Checkpoint&#34;: {
		&#34;suffix&#34;: 8,
		&#34;offset&#34;: 143423140
	},
	&#34;ErrMsg&#34;: &#34;&#34;
}
</code></pre><ul>
<li>Kafka tools 工具查看 Kafka 消息信息
<ul>
<li>PUMP 自动创建的 topic 格式为： <code>clusterID + 主机名 + 端口</code></li>
<li>例如：<code>6502327210476397260_10-30-1-10_8250</code></li>
<li>或者使用以下工具获取所有 topic name</li>
</ul>
</li>
</ul>
<pre><code class="language-json" data-lang="json">./kafka-topics.sh  --list --zookeeper zk.xxxyyy.com:2181
</code></pre><blockquote>
<p>综上信息以及监控信息结合判断 PUMP 最新状态是正常的；持续在向 local disk 写入数据<br>
查看日志发现了新的问题</p>
</blockquote>
<ul>
<li>PUMP 日志提示推送到 Kafka 的消息过大，无法成功写入到 Kafka</li>
</ul>
<pre><code class="language-fallback" data-lang="fallback">kafka_binlogger.go:74: ESC[0;31m[error] write binlog into kafka 13891570 error kafka: Failed to deliver 1 messages.ESC[0m
proxy_binlogger.go:148: ESC[0;31m[error] write binlog to replicate error kafka: Failed to deliver 1 messages. payload length 1918645ESC[0m
proxy_binlogger.go:164: ESC[0;31m[error] master walk error kafka: Failed to deliver 1 messages.
    /home/jenkins/workspace/build_tidb_binlog_master/go/src/github.com/pingcap/tidb-binlog/pump/encoder.go:111:
    /home/jenkins/workspace/build_tidb_binlog_master/go/src/github.com/pingcap/tidb-binlog/pump/kafka_binlogger.go:80:
    /home/jenkins/workspace/build_tidb_binlog_master/go/src/github.com/pingcap/tidb-binlog/pump/proxy_binlogger.go:149:
    /home/jenkins/workspace/build_tidb_binlog_master/go/src/github.com/pingcap/tidb-binlog/pump/binlogger.go:336: ESC[0m
binlogger.go:252: ESC[0;37m[info] [binlogger] walk from position {Suffix:7 Offset:480977849}ESC[0m
encoder.go:101: ESC[0;31m[error] [encoder] produce meesage error kafka: Failed to deliver 1 messages.ESC[0m
encoder.go:105: ESC[0;31m[error] [encode] produce message kafka: Failed to produce message to topic 6502327210476397260_10-30-1-11_8250: kafka server: Message was too large, server rejected it to avoid allocation error., now retry No. 1ESC[0m
encoder.go:101: ESC[0;31m[error] [encoder] produce meesage error kafka: Failed to deliver 1 messages.ESC[0m
</code></pre><blockquote>
<p>此处检查 kafka 配置文件中的 <code>message.max.bytes=1073741824</code> 参数，目前官方推荐 1073741824  大小<br>
调整后 PUMP 日志显示正在写入数据</p>
</blockquote>
<h2 id="0x03-faq-3">0x03 FAQ-3</h2>
<blockquote>
<p>本条 FAQ 来自上一条中的人工复检：PUMP 本地 Binlog 文件数量核对
检查发现 PUMP 本地磁盘中 Binlog 文件以超过 PUMP GC 阈值但未被 GC 删除<br>
tips：Binlog 2.0 架构中 PUMP 接收到事物数据先存储到本地磁盘，然后推送到 Kafka 后删除本地文件</p>
</blockquote>
<ul>
<li>文件创建时间是 10 月 23 日，修复时间是 10 月 29 日，GC 时间参数是 5 天，该文件实际超过了 GC 时间</li>
</ul>
<pre><code class="language-shell" data-lang="shell">[root@localhost]#  stat binlog-0000000000000008-20181023115001
  File: ‘binlog-0000000000000008-20181023115001’
  Size: 539246691   Blocks: 1053232    IO Block: 4096   regular file
Device: 811h/2065d  Inode: 12845065    Links: 1
Access: (0600/-rw-------)  Uid: ( 1000/     ops)   Gid: ( 1000/     ops)
Access: 2018-10-29 16:58:17.197615887 +0800
Modify: 2018-10-23 11:59:31.930792955 +0800
Change: 2018-10-23 11:59:31.930792955 +0800
 Birth: -
</code></pre><ul>
<li>查看 PUMP 日志，提示该文件还未推送到 Kafka 服务</li>
</ul>
<pre><code class="language-shell" data-lang="shell">binlogger.go:387: [warning] binlog file /data1/deploy/data.pump/clusters/6502327210476397260/binlog-0000000000000043-20181024160016 is already reach the gc time, but data is not send to kafka, position is {8 142486881}
binlogger.go:387: [warning] binlog file /data1/deploy/data.pump/clusters/6502327210476397260/binlog-0000000000000044-20181024162025 is already reach the gc time, but data is not send to kafka, position is {8 142486881}
binlogger.go:387: [warning] binlog file /data1/deploy/data.pump/clusters/6502327210476397260/binlog-0000000000000045-20181024163951 is already reach the gc time, but data is not send to kafka, position is {8 142486881}
</code></pre><blockquote>
<p>以上场景在修复 kafka message size 之后逐渐恢复正常</p>
</blockquote>
<h2 id="0x04-撒花">0x04 撒花</h2>
<blockquote>
<p>观察监控 ing</p>
</blockquote>
<p><img src="https://atman.ihx.cc/post/20181029-44-binlog-tso/6-kafka.png" alt="ap.tidb.cc" title="ap.tidb.cc" loading="lazy" decoding="async">
</p>
<p><img src="https://atman.ihx.cc/post/20181029-44-binlog-tso/7-k-p.png" alt="ap.tidb.cc" title="ap.tidb.cc" loading="lazy" decoding="async">
</p>
<h3 id="小结">小结</h3>
<ol>
<li>
<p>PUMP 长时间写数据到 Kafka 失败，未能及时告警发现</p>
<ul>
<li>写入失败原因是 Kafka <code>message.max.bytes</code> 参数太小，binlog 数据写入失败</li>
</ul>
<pre><code class="language-yaml" data-lang="yaml"># 在 kafka 的文件 server.properties 中检查如下三个个配置项

#broker 能接收消息的最大字节数
message.max.bytes=1073741824
#broker 可复制的消息的最大字节数
replica.fetch.max.bytes=1073741824
# 消费者端的可读取的最大消息
fetch.message.max.bytes=1073741824
</code></pre></li>
<li>
<p>Drainer 启动时出现指定 TSO 信息超出 Kafka topic 范围；没有 Kafka 监控，未能及时判定 Drainer 需要读取的数据是否存在</p>
</li>
<li>
<p>Drainer 需要等待启动原因是 PUMP 目前正在推送 binlog 数据到 Kafka ，Drainer 后续要去 Kafka 内读取</p>
<ul>
<li>如果 Drainer 现在要立即启动，只能指定 10 月 23 日 的 commit-ts 信息，因为目前 Kafka 内数据范围是从 10 月 23 日 开始的</li>
</ul>
</li>
</ol>
]]></content:encoded><h:time datetime="2018-10-29T00:00:00+08:00">2018-10-29 · post</h:time><h:a class="feed-article-title" href="https://atman.ihx.cc/post/20181029-44-binlog-tso/">School - Binlog &amp; TSO</h:a></item><item><title>School - TiDB table info &amp; DDL history</title><link>https://atman.ihx.cc/post/20190116-3-ddl-history/</link><guid isPermaLink="true">https://atman.ihx.cc/post/20190116-3-ddl-history/</guid><pubDate>Fri, 24 Aug 2018 00:00:00 +0800</pubDate><dc:creator>Atman</dc:creator><category>DDL</category><category>Troubleshooting</category><description>0x00 元 tidb ddl 3.0 版本之前只有一个队列提供服务，所有 ddl 都要在这个队列阻塞 多个 TiDB-server 会先选举 DDL owner TiDB 配置文件中的 run-ddl = false 该节点不支持运行 DDL DDL owner 处理所有 DDL 信息 更多可阅读 TiDB 异步 schema 变更实现 文档 add …</description><content:encoded><![CDATA[<h2 id="0x00-元">0x00 元</h2>
<blockquote>
<p>tidb ddl 3.0 版本之前只有一个队列提供服务，所有 ddl 都要在这个队列阻塞</p>
</blockquote>
<ul>
<li>多个 TiDB-server 会先选举 DDL owner
<ul>
<li>TiDB 配置文件中的 <code>run-ddl = false</code> 该节点不支持运行 DDL</li>
</ul>
</li>
<li>DDL owner 处理所有 DDL 信息
<ul>
<li>更多可阅读 <a href="https://github.com/ngaut/builddatabase/blob/master/f1/schema-change-implement.md">TiDB 异步 schema 变更实现</a> 文档</li>
<li>add index 是所有 DDL 中最耗时的</li>
<li>其他 DDL 均为修改元数据信息，秒级以内可返回</li>
</ul>
</li>
</ul>
<p><img src="https://atman.ihx.cc/post/20190116-3-ddl-history/3-ddl.jpg" alt="ap.tidb.cc TiDB 异步 schema 变更实现" title="ap.tidb.cc TiDB 异步 schema 变更实现" loading="lazy" decoding="async">
</p>
<blockquote>
<p>ddl history 功能来自 <a href="https://github.com/pingcap/tidb/blob/master/docs/tidb_http_api.md">TiDB-API</a></p>
</blockquote>
<ul>
<li>通过 API 获取到指定 tidb cluster 集群“自搭建成功”到“现在运行”的所有 DDL 记录
<ul>
<li>早前版本数据输出时所有数据「json」都在一行，通过 jq 命令或者 python 格式化之后会比较方便查看信息</li>
<li><a href="https://github.com/pingcap/tidb/pull/9104">PR #9104</a> 之后的版本优化了「大一行」输出</li>
<li><del>ddl/history 早前版本获取到 DDL 的信息「不完整」，信息记录了 truncate 当前版本的变更，没有记录 truncate 变更后的信息；问题早已修复</del></li>
</ul>
</li>
</ul>
<pre><code class="language-json" data-lang="json">#Get all TiDB DDL job history information.

curl http://{TiDBIP}:10080/ddl/history

#Get count {number} TiDB DDL job history information.

curl http://{TiDBIP}:10080/ddl/history?limit={number}
</code></pre><ul>
<li>通过 API 获取指定 db 下所有表、指定 table id、指定 db.table 的 json 元信息</li>
</ul>
<pre><code class="language-json" data-lang="json"># Get schema Information about db

curl http://{TiDBIP}:10080/schema/{db}


# Get schema Information about db.table, and you can get schema info by tableID (tableID is the unique identifier of table in TiDB)

curl http://{TiDBIP}:10080/schema/{db}/{table}

curl http://{TiDBIP}:10080/schema?table_id={tableID}
</code></pre><h2 id="0x01-admin-show-ddl">0x01 Admin show ddl</h2>
<p>TiDB-server 除 API 功能还有个 <a href="https://docs.pingcap.com/tidb/stable/sql-statement-admin#admin-show-ddl">admin show ddl jobs 与 admin show ddl jobs 100</a>(该语句需要 3.0 版本以上，输出最近 100 条信息)</p>
<p><img src="https://atman.ihx.cc/post/20190116-3-ddl-history/2-admin.png" alt="ap.tidb.cc truncare table ddl admin show ddl jobs " title="ap.tidb.cc truncare table ddl admin show ddl jobs" loading="lazy" decoding="async">
</p>
<h2 id="0x02-truncate">0x02 Truncate</h2>
<ul>
<li>truncate table DDL 操作是通过 DROP table + Create table 组成实现，table id 会紧随更改 「DDL 操作 “元信息” 数据」
<ul>
<li>图片中的首行 ID 是 DDL job ID</li>
<li>每次 truncate table 后的 table_id 会变化「scheme id、table id 、ddl job id 共用同一套计数器」</li>
</ul>
</li>
</ul>
<p><img src="https://atman.ihx.cc/post/20190116-3-ddl-history/1-truncate.png" alt="ap.tidb.cc truncare table ddl" title="ap.tidb.cc truncare table ddl" loading="lazy" decoding="async">
</p>
<h2 id="0x03-json">0x03 Json</h2>
<ul>
<li>以下为某张表的元信息展示「通过 tidb 4.0 补测」</li>
</ul>
<pre><code class="language-json" data-lang="json">{
 &#34;id&#34;: 47,          // table id
 &#34;name&#34;: {
  &#34;O&#34;: &#34;sbtest1&#34;,  // 原始输入展示
  &#34;L&#34;: &#34;sbtest1&#34;   // 程序强转小写展示
 },
 &#34;charset&#34;: &#34;utf8mb4&#34;,
 &#34;collate&#34;: &#34;utf8mb4_bin&#34;,
 &#34;cols&#34;: [
  {
   &#34;id&#34;: 1,         // 列 id
   &#34;name&#34;: {        // 列名
    &#34;O&#34;: &#34;k&#34;,
    &#34;L&#34;: &#34;k&#34;
   },
   &#34;offset&#34;: 0,     // 以下为 列关键特性
   &#34;origin_default&#34;: null,
   &#34;origin_default_bit&#34;: null,
   &#34;default&#34;: null,
   &#34;default_bit&#34;: null,
   &#34;default_is_expr&#34;: false,
   &#34;generated_expr_string&#34;: &#34;&#34;,
   &#34;generated_stored&#34;: false,
   &#34;dependences&#34;: null,
   &#34;type&#34;: {
    &#34;Tp&#34;: 3,
    &#34;Flag&#34;: 515,
    &#34;Flen&#34;: 11,
    &#34;Decimal&#34;: 0,
    &#34;Charset&#34;: &#34;binary&#34;,
    &#34;Collate&#34;: &#34;binary&#34;,
    &#34;Elems&#34;: null
   },
   &#34;state&#34;: 5,
   &#34;comment&#34;: &#34;&#34;,
   &#34;hidden&#34;: false,
   &#34;version&#34;: 2
  },

 ],
 &#34;index_info&#34;: [        // index 信息
  {
   &#34;id&#34;: 1,
   &#34;idx_name&#34;: {
    &#34;O&#34;: &#34;k_1&#34;,
    &#34;L&#34;: &#34;k_1&#34;
   },
   &#34;tbl_name&#34;: {
    &#34;O&#34;: &#34;&#34;,
    &#34;L&#34;: &#34;&#34;
   },
   &#34;idx_cols&#34;: [
    {
     &#34;name&#34;: {
      &#34;O&#34;: &#34;k&#34;,
      &#34;L&#34;: &#34;k&#34;
     },
     &#34;offset&#34;: 1,
     &#34;length&#34;: -1
    }
   ],
   &#34;state&#34;: 5,
   &#34;comment&#34;: &#34;&#34;,
   &#34;index_type&#34;: 1,
   &#34;is_unique&#34;: false,
   &#34;is_primary&#34;: false,
   &#34;is_invisible&#34;: false,
   &#34;is_global&#34;: false
  }
 ],                             // 以下为 tidb 在 table 级别的特性
 &#34;constraint_info&#34;: null,       // 4.0 的新字符集架构
 &#34;fk_info&#34;: null,               // 盲猜 foreign key
 &#34;state&#34;: 5,
 &#34;pk_is_handle&#34;: true,          // int 类型的 PK == true
 &#34;is_common_handle&#34;: false,     // varchar 类型的 PK 或者联合主键 == true
                    // 表未设置主键时 pk_is_handle &amp; is_common_handle 均为 false
 &#34;comment&#34;: &#34;&#34;,
 &#34;auto_inc_id&#34;: 0,          // AUTO_INCREMENT 功能
 &#34;auto_id_cache&#34;: 0,        // AUTO_ID_CACHE 自增 ID 缓存功能
 &#34;auto_rand_id&#34;: 0,         // AUTO_RANDOM 功能
 &#34;max_col_id&#34;: 4,
 &#34;max_idx_id&#34;: 1,
 &#34;max_cst_id&#34;: 0,
 &#34;update_timestamp&#34;: 418539877049565193,
 &#34;ShardRowIDBits&#34;: 0,       // SHARD_ROW_ID_BITS 功能
 &#34;max_shard_row_id_bits&#34;: 0,
 &#34;auto_random_bits&#34;: 0,     // 与 shard row id bits 结合使用
 &#34;pre_split_regions&#34;: 0,    // pre split 预打散 table region 功能
 &#34;partition&#34;: null,         // 是否为分区表
 &#34;compression&#34;: &#34;&#34;,         // 该表是否启用 「COMPRESSION [=] {&#39;ZLIB&#39;|&#39;LZ4&#39;|&#39;NONE&#39;}」 属性
 &#34;view&#34;: null,              // 视图功能
 &#34;sequence&#34;: null,          // sequence 功能
 &#34;Lock&#34;: null,              // 盲猜 table lock，无证实
 &#34;version&#34;: 3,
 &#34;tiflash_replica&#34;: null    // tiflash 列存副本
}
</code></pre>]]></content:encoded><h:time datetime="2018-08-24T00:00:00+08:00">2018-08-24 · post</h:time><h:a class="feed-article-title" href="https://atman.ihx.cc/post/20190116-3-ddl-history/">School - TiDB table info &amp; DDL history</h:a></item><item><title>School - TiDB Region Spilt</title><link>https://atman.ihx.cc/post/20180824-34-region-spilt/</link><guid isPermaLink="true">https://atman.ihx.cc/post/20180824-34-region-spilt/</guid><pubDate>Fri, 24 Aug 2018 00:00:00 +0800</pubDate><dc:creator>Atman</dc:creator><category>Region Split</category><category>Troubleshooting</category><description>0x00 元 收到监控 &amp;amp; 业务告警，内容为目前 QPS duration &amp;gt; 1s 首先排查监控缩小范围 交叉信息判定为 region 超过 144mb 以后未分裂，造成 get snapshot 持续失败，同时 region 过大造成写入和读取数据动作资源消耗过大 SQL 读取数据时 tikv 向命中每 region 发送单次 tikvRPC 请求； …</description><content:encoded><![CDATA[<h2 id="0x00-元">0x00 元</h2>
<blockquote>
<p>收到监控 &amp; 业务告警，内容为目前 QPS duration &gt; 1s<br>
首先排查监控缩小范围</p>
</blockquote>
<p><img src="https://atman.ihx.cc/post/20180824-34-region-spilt/1-qps.png" alt="ap.tidb.cc TiDB Region Spilt QPS duration" title="ap.tidb.cc TiDB Region Spilt" loading="lazy" decoding="async">
<br>
<img src="https://atman.ihx.cc/post/20180824-34-region-spilt/2-apply.png" alt="ap.tidb.cc TiDB Region Spilt apply cpu 上涨" title="ap.tidb.cc TiDB Region Spilt" loading="lazy" decoding="async">
<br>
<img src="https://atman.ihx.cc/post/20180824-34-region-spilt/3-max.png" alt="ap.tidb.cc TiDB Region Spilt region 大小" title="ap.tidb.cc TiDB Region Spilt" loading="lazy" decoding="async">
<br>
<img src="https://atman.ihx.cc/post/20180824-34-region-spilt/4-snapshot.png" alt="ap.tidb.cc TiDB Region Spilt get snapshot failed" title="ap.tidb.cc TiDB Region Spilt" loading="lazy" decoding="async">
<br>
<img src="https://atman.ihx.cc/post/20180824-34-region-spilt/5-schedule.png" alt="ap.tidb.cc TiDB Region Spilt schedule duration" title="ap.tidb.cc TiDB Region Spilt" loading="lazy" decoding="async">
</p>
<blockquote>
<p>交叉信息判定为 region 超过 144mb 以后未分裂，造成 get snapshot 持续失败，同时 region 过大造成<strong>写入和读取</strong>数据动作资源消耗过大<br>
SQL 读取数据时 tikv 向命中每 region 发送单次 tikvRPC 请求；由于 region 过大，可能包含该 SQL 命中的所有数据，造成 tikvRPC 数据包过大<br>
写入数据时，region 数量大于过半时才能提交成功，region 过大造成无法 compaction 、被 PD schedule region 时成本加大、region 内查询数据成本过大等</p>
</blockquote>
<h3 id="region-spilt">region spilt</h3>
<blockquote>
<p>正常流程</p>
</blockquote>
<ol>
<li>初始化 region ，region id 2</li>
<li>region id 2 写入数据达到 144MB</li>
<li>region id 2 接收 split 操作
<ol>
<li>region 从尾部追加写入</li>
<li>切割时从头部粗略计算 96mb</li>
<li>保持尾部 id 不变、尾部可持续写入</li>
</ol>
</li>
<li>region id 2 分列成 id 2 &amp; id 10 两个 region / 其中 id 2 为 48mb，id 10 为 96mb（实际非精准计算）</li>
</ol>
<blockquote>
<p>异常场景</p>
</blockquote>
<ul>
<li>数据写入过快时，磁盘或者 split cpu work 跟不上时可能会出现 split 持续失败
<ul>
<li>region spilt 单线程工作，前期版本 reigon spilt 根据 IO 大小扫描 96mb 后执行 split</li>
<li>会实际消耗 96mb 扫描 region 的 IOPS / 消耗创建新 region + 创建 snapshot 等 IOPS</li>
</ul>
</li>
</ul>
<h3 id="0x01-二次确认">0x01 二次确认</h3>
<h3 id="tikv-日志">TiKV 日志</h3>
<pre><code class="language-fallback" data-lang="fallback">2018/08/10 22:13:03.168 scheduler.rs:1306: [ERROR] 
    get snapshot failed for cids=[1792370849], error Request(message: &#34;region is stale&#34; 
        stale_epoch {new_regions {id: 4351912 
            start_key:&#34;t\200\000\000\000\000\0009\377\364_i\200\000\000\000\000\377\000\000\003\001A336\3770001\37762\000\377\000\000\000\000\000\371\003\216\377\000\000\001\344\317\341i\000\376&#34; 
            end_key: &#34;t\200\000\000\000\000\0009\377\364_i\200\000\000\000\000\377\000\000\003\001A760\3770035\37733\000\377\000\000\000\000\000\371\003\200\377\000\000\000\000\2233\242\000\376&#34; 
        region_epoch {conf_ver: 1153 version: 15846} peers {id: 4351914 store_id: 4215749} peers {id: 4351915 store_id: 3169321} peers {id: 4841324 store_id: 8}} 
    new_regions {id: 4841440 
            start_key: &#34;t\200\000\000\000\000\0009\377\364_i\200\000\000\000\000\377\000\000\003\001A120\3770031\37739\000\377\000\000\000\000\000\371\003\200\377\000\000\000\000V\311\254\000\376&#34; 
            end_key: &#34;t\200\000\000\000\000\0009\377\364_i\200\000\000\000\000\377\000\000\003\001A336\3770001\37762\000\377\000\000\000\000\000\371\003\216\377\000\000\001\344\317\341i\000\376&#34; 
        region_epoch {conf_ver: 1153 version: 15846} peers {id: 4841441 store_id: 4215749} peers {id: 4841442 store_id: 3169321} peers {id: 4841443 store_id: 8}}})
</code></pre><h3 id="region-meta">Region meta</h3>
<pre><code class="language-json" data-lang="json">» region 4803248
{
  &#34;id&#34;: 4803248,
  &#34;start_key&#34;: &#34;t\\x80\\x00\\x00\\x00\\x00\\x00:\\xff$_r\\x80\\x00\\x00\\x00&#39;\\xffױ\\xf4\\x00\\x00\\x00\\x00\\x00\\xfa&#34;,
  &#34;end_key&#34;: &#34;&#34;,
  &#34;epoch&#34;: {
    &#34;conf_ver&#34;: 1159,
    &#34;version&#34;: 17467
  },
  &#34;peers&#34;: [
    {
      &#34;id&#34;: 4227577,
      &#34;store_id&#34;: 4215744
    },
    {
      &#34;id&#34;: 4803248,
      &#34;store_id&#34;: 4215749
    },
    {
      &#34;id&#34;: 4804713,
      &#34;store_id&#34;: 4
    }
  ],
  &#34;leader&#34;: {
    &#34;id&#34;: 4803248,
    &#34;store_id&#34;: 4215749
  },
  &#34;pending_peers&#34;: [
    {
      &#34;id&#34;: 4804713,
      &#34;store_id&#34;: 4
    }
  ],
  &#34;written_bytes&#34;: 267,
  &#34;approximate_size&#34;: 124183 // 此处是 MB 大小。正常应该再 144M 以内
}
</code></pre><h3 id="0x02-修复">0x02 修复</h3>
<ul>
<li>
<p>查看 split 线程状态使用用 <code>strace -p &quot;tid of split worker&quot;</code></p>
<ul>
<li>strace 会阻断程序运行，谨慎使用</li>
</ul>
</li>
<li>
<p>使用 PD-ctl 工具手工发起 split region 请求</p>
<pre><code class="language-json" data-lang="json">&gt;&gt; operator add split-region 1 --policy=approximate     // 将 Region 1 对半拆分成两个 Region，基于粗略估计值
&gt;&gt; operator add split-region 1 --policy=scan            // 将 Region 1 对半拆分成两个 Region，基于精确扫描值
</code></pre></li>
</ul>
<p><img src="https://atman.ihx.cc/post/20180824-34-region-spilt/6-split.png" alt="ap.tidb.cc TiDB Region Spilt region split 请求后" title="ap.tidb.cc TiDB Region Spilt" loading="lazy" decoding="async">
<br>
<img src="https://atman.ihx.cc/post/20180824-34-region-spilt/7-snapshot-cpu.png" alt="ap.tidb.cc TiDB Region Spilt region split 请求后 snapshot cpu 占用" title="ap.tidb.cc TiDB Region Spilt" loading="lazy" decoding="async">
<br>
<img src="https://atman.ihx.cc/post/20180824-34-region-spilt/8-region-sum.png" alt="ap.tidb.cc TiDB Region Spilt region split 请求后 region 增长状态" title="ap.tidb.cc TiDB Region Spilt" loading="lazy" decoding="async">
</p>
]]></content:encoded><h:time datetime="2018-08-24T00:00:00+08:00">2018-08-24 · post</h:time><h:a class="feed-article-title" href="https://atman.ihx.cc/post/20180824-34-region-spilt/">School - TiDB Region Spilt</h:a></item><item><title>School - TiKV write stall</title><link>https://atman.ihx.cc/post/20180807-32-write-stall/</link><guid isPermaLink="true">https://atman.ihx.cc/post/20180807-32-write-stall/</guid><pubDate>Tue, 07 Aug 2018 00:00:00 +0800</pubDate><dc:creator>Atman</dc:creator><category>TiDB</category><category>server is busy</category><category>write stall</category><category>Troubleshooting</category><description>适用版本：TiDB 2.0。 0x00 告警 TiDB 与 TiKV 出现大量 backoff；触发 backoff 告警阈值 相应时间段 tidb kv error 监控趋势升高 相应时间段 tikv thread cpu / apply cpu 监控趋势升高 [FIRING:1] TiDB_tikvclient_region_err_total tidb …</description><content:encoded><![CDATA[<blockquote>
<p>适用版本：TiDB 2.0。</p>
</blockquote>
<h2 id="0x00-告警">0x00 告警</h2>
<ul>
<li>TiDB 与 TiKV 出现大量 backoff；触发 backoff 告警阈值
<ul>
<li>相应时间段 tidb kv error 监控趋势升高</li>
<li>相应时间段 tikv thread cpu / apply cpu 监控趋势升高</li>
</ul>
</li>
</ul>
<pre><code class="language-json" data-lang="json">[FIRING:1] TiDB_tikvclient_region_err_total tidb 1-1-1-9_4000 tidb stale_epoch (tidb increase( tidb_tikvclient_region_err_total[10m] )  &gt; 6000 emergency prometheus)
cluster: tidb, instance: 1-1-1-9_4000, values:7059.979666666667 TiDB tikvclient_backoff_count error 7059.979666666667
Alerts Firing:
Labels:
 - alertname = TiDB_tikvclient_region_err_total
 - cluster = tidb
 - env = tidb
 - expr = increase( tidb_tikvclient_region_err_total[10m] )  &gt; 6000
 - instance = 1-1-1-9_4000
 - job = tidb
 - level = emergency
 - monitor = prometheus
 - type = stale_epoch
Annotations:
 - description = cluster: tidb, instance: 1-1-1-9_4000, values:7059.979666666667
 - summary = TiDB tikvclient_backoff_count error
 - value = 7059.979666666667
Source: http://1.1.1.9:9090/graph?g0.expr=increase%28tidb_tikvclient_region_err_total%5B10m%5D%29+%3E+6000&amp;g0.tab=1
</code></pre><h2 id="0x01-监控">0x01 监控</h2>
<blockquote>
<p>如不确定趋势为正常状态，请采用划分时间对比方式评估，然后合理进行怀疑</p>
</blockquote>
<p><img src="https://atman.ihx.cc/post/20180807-32-write-stall/lock-resolve.png" alt="锁冲突" title="ap.tidb.cc" loading="lazy" decoding="async">

<img src="https://atman.ihx.cc/post/20180807-32-write-stall/serverisbusy.png" alt="server is busy" title="ap.tidb.cc" loading="lazy" decoding="async">
</p>
<p><img src="https://atman.ihx.cc/post/20180807-32-write-stall/schdule-latch.png" alt="schedule latch duration" title="ap.tidb.cc" loading="lazy" decoding="async">
</p>
<p><img src="https://atman.ihx.cc/post/20180807-32-write-stall/append.png" alt="append log" title="ap.tidb.cc" loading="lazy" decoding="async">

<img src="https://atman.ihx.cc/post/20180807-32-write-stall/ioutil.png" alt="io util" title="ap.tidb.cc" loading="lazy" decoding="async">
</p>
<p><img src="https://atman.ihx.cc/post/20180807-32-write-stall/compaction.png" alt="compaction sst" title="ap.tidb.cc" loading="lazy" decoding="async">

<img src="https://atman.ihx.cc/post/20180807-32-write-stall/stall.png" alt="write stall" title="ap.tidb.cc" loading="lazy" decoding="async">
</p>
<h3 id="二次确认">二次确认</h3>
<ul>
<li>{{tikv_deploy_dir}}/db/LOG 日志内搜索 <code>Stalling writes</code> 关键词</li>
</ul>
<pre><code class="language-fallback" data-lang="fallback">2018/08/06-00:18:17.562487 7f23db1ff700 [WARN] [/home/jenkins/.cargo/git/checkouts/rust-rocksdb-82ef6e5337b3fbe6/9a1c83c/librocksdb_sys/rocksdb/db/column_family.cc:696] [write] Stalling writes because we have 21 level-0 files rate 13421772
2018/08/06-00:18:17.562509 7f23db1ff700 [/home/jenkins/.cargo/git/checkouts/rust-rocksdb-82ef6e5337b3fbe6/9a1c83c/librocksdb_sys/rocksdb/db/external_sst_file_ingestion_job.cc:231] [AddFile] External SST file /data1/deploy1/data/snap/rev_514666_37_190_write.sst.clone was ingested in L0 with path /data1/deploy1/data/db/23352686.sst (global_seqno=0)
</code></pre><h3 id="排查思路图">排查思路图</h3>
<p><img src="https://atman.ihx.cc/post/20180807-32-write-stall/mind-stall.png" alt="排查 write stall 思维导图" title="ap.tidb.cc" loading="lazy" decoding="async">
</p>
<h2 id="0x02-原因">0x02 原因</h2>
<ul>
<li>
<p>Write stall</p>
<ul>
<li>RocksDB L0 层的文件数量超过流控阈值，默认超过 20 * region 会减缓该节点写入，超过 36 个会停止该节点写入</li>
<li>L0 层文件的减少需要 compaction 操作，将 L0 文件合并排序后写入到 L1 层「粗略计算需要 region-size * 2 的 IOPS（读、压缩、写入）」</li>
<li>2.0 版本 compaction 是单线程工作；会出现 写入速度过快、compaction 跟不上或者磁盘跟不上的场景</li>
</ul>
</li>
<li>
<p>临时解决方案 1</p>
<ul>
<li>
<p>确定<strong>磁盘</strong>是否还有 IOPS 余量，如果无余量请扩容 TiKV 集群机器</p>
</li>
<li>
<p>调整 <code>[rocksdb.writecf]</code> 和 <code>[rocksdb.defaultcf]</code> 以下参数</p>
<pre><code class="language-toml" data-lang="toml"># level0-file-num-compaction-trigger = 4
# 达到 4 个文件开始 compaction

# level0-slowdown-writes-trigger = 20
# 达到 20 个文件，放慢写入速度

# level0-stop-writes-trigger = 36
# 达到 36 个文件，停止写入
</code></pre></li>
</ul>
</li>
</ul>
<blockquote>
<p>Update: 3.0 以后版本加入 <code>max-sub-compaction = 2</code> 参数，加快 compaction sst 动作</p>
</blockquote>
<ul>
<li>临时解决方案 2
<ul>
<li>
<p>RocksDB 总 7 层，L0 - L1 未开启压缩</p>
</li>
<li>
<p>将 L0 与 L1 修改为 lz4 压缩算法；如不熟悉请勿操作</p>
<pre><code class="language-toml" data-lang="toml"># compression-per-level = [&#34;no&#34;, &#34;no&#34;, &#34;lz4&#34;, &#34;lz4&#34;, &#34;lz4&#34;, &#34;zstd&#34;, &#34;zstd&#34;]
## Compression method (if any) is used to compress a block.
##   no:     kNoCompression
##   snappy: kSnappyCompression
##   zlib:   kZlibCompression
##   bzip2:  kBZip2Compression
##   lz4:    kLZ4Compression
##   lz4hc:  kLZ4HCCompression
##   zstd:   kZSTD
</code></pre></li>
</ul>
</li>
</ul>
]]></content:encoded><h:time datetime="2018-08-07T00:00:00+08:00">2018-08-07 · post</h:time><h:a class="feed-article-title" href="https://atman.ihx.cc/post/20180807-32-write-stall/">School - TiKV write stall</h:a></item><item><title>School - TiDB 根据 PK 查询不到数据</title><link>https://atman.ihx.cc/post/20180803-31-select-hash/</link><guid isPermaLink="true">https://atman.ihx.cc/post/20180803-31-select-hash/</guid><pubDate>Fri, 03 Aug 2018 00:00:00 +0800</pubDate><dc:creator>Atman</dc:creator><category>TiDB</category><category>Troubleshooting</category><description>适用版本：TiDB 2.0。 0x00 复古文档 根据 PK 查询不不到数据、根据其他索引字段可以查询到数据、根据 count 确认不同字段下数据量一致； 0x01 过程 先行随机校验数据 // 使用 min 函数可以查看到数据 MySQL [order-tidb]&amp;gt; select min(order_id) from t-order; …</description><content:encoded><![CDATA[<blockquote>
<p>适用版本：TiDB 2.0。</p>
</blockquote>
<h2 id="0x00-复古文档">0x00 复古文档</h2>
<p>根据 PK 查询不不到数据、根据其他索引字段可以查询到数据、根据 count 确认不同字段下数据量一致；</p>
<h2 id="0x01-过程">0x01 过程</h2>
<ul>
<li>先行随机校验数据</li>
</ul>
<pre><code class="language-sql" data-lang="sql">// 使用 min 函数可以查看到数据
MySQL [order-tidb]&gt; select min(order_id) from t-order;
+----------------------------+
| min(order_id)              |
+----------------------------+
|   MBK0100057406149351733 |
+----------------------------+
1 row in set (0.12 sec)

// 执行 where 条件后返回为空
MySQL [tid b]&gt; select * from t-order where order_id = &#39;MBK0100057406149351733&#39;;
Empty set (0.00 sec)

MySQL [ordertidb]&gt; select max(order_id) from t-order;
+-----------------------------+
| max(order_id)               |
+-----------------------------+
| MBKÁ0060110911529542324199  |
+-----------------------------+
1 row in set (0.09 sec)

MySQL [order-tidb]&gt; select order_id from t-order where order_id = &#39;MBKÁ0060110911529542324199&#39;;
+-----------------------------+
| order_id                    |
+-----------------------------+
| MBKÁ0060110911529542324199  |
+-----------------------------+
1 row in set (0.00 sec)
</code></pre><ul>
<li>查看表结构</li>
</ul>
<pre><code class="language-sql" data-lang="sql">CREATE TABLE `t-order` (
  `order_id` varchar(35) NOT NULL COMMENT &#39;订单ID&#39;,
  …… 省略其他信息
  PRIMARY KEY (`order_id`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT=&#39;骑行订单表&#39;
1 row in set (0.00 sec)
</code></pre><ul>
<li>查询索引与数据是否一致
<ul>
<li>2.0 版本，暂无 admin check table index 功能</li>
</ul>
</li>
</ul>
<pre><code class="language-sql" data-lang="sql">// 查询 PK 与数据 行数是否一致
// 开始操作前调整 GC life 作为数据保底
update mysql.tidb set VARIABLE_VALUE = &#39;1h&#39; where VARIABLE_NAME = &#39;tikv_gc_life_time&#39;;

// 锁定 snapshot
MySQL [order-tidb]&gt; set @@tidb_snapshot=now();
Query OK, 0 rows affected (0.01 sec)

// count 全表数据量查询
MySQL [order-tidb]&gt; select count(*) from t-order;
+------------+
| count(*)   |
+------------+
| 1969978080 |
+------------+
1 row in set (3 min 4.04 sec)

// 使用 PK 查询数据量
MySQL [order-tidb]&gt; select count(*) from t-order use index(`primary`);
+------------+
| count(*)   |
+------------+
| 1969978080 |
+------------+
1 row in set (3 min 56.73 sec)

// 得到结果数据一致
</code></pre><ul>
<li>校验数据是否存在特殊字符</li>
</ul>
<pre><code class="language-sql" data-lang="sql">// 通过 base64 校验
MySQL [order-tidb]&gt; select to_base64(min(order_id)) from t-order;
+--------------------------------------+
| to_base64(min(order_id))             |
+--------------------------------------+
| AAAfGk1CSzAxMDAwNTc0MDYxNDkzNTE3MzM= |
+--------------------------------------+
1 row in set (0.08 sec)

MySQL [order-tidb]&gt; select to_base64(&#39;MBK0100057406149351733&#39;);
+-------------------------------------+
| to_base64(&#39;MBK0100057406149351733&#39;) |
+-------------------------------------+
| TUJLMDEwMDA1NzQwNjE0OTM1MTczMw==    |
+-------------------------------------+
1 row in set (0.00 sec)

// to base64 后得到得结果不一致，数据可能存在 UTF8 不可见字符
</code></pre><ul>
<li>使用编辑器查看发现头部有不可见特殊字符</li>
</ul>
<p><img src="https://atman.ihx.cc/post/20180803-31-select-hash/tobase64.png" alt="to base64" loading="lazy" decoding="async">
</p>
<h2 id="0x02-其他">0x02 其他</h2>
<blockquote>
<p>2.0 版本处理相关问题时，其他知识点<br>
table 内数据小于 1w 行，select point 使用 tablefullsacn 算子时正常现象</p>
</blockquote>
<pre><code class="language-sql" data-lang="sql">// PK(varchar) 在 2.0 版本中强制使用索引查询 / PK(varchar) 需要 TiDB 分配 tidb_rowid 作为 handle id 使用
MySQL [order-tidb]&gt; explain select count(*) from trip_order use index(`primary`);
+----------------+--------------+----------------+------+------------------------------------------------------------------------+----------+
| id             | parents      | children       | task | operator info                                                          | count    |
+----------------+--------------+----------------+------+------------------------------------------------------------------------+----------+
| IndexScan_16   | StreamAgg_8  |                | cop  | table:trip_order, index:order_id, range:[&lt;nil&gt;,+inf], keep order:false | 10000.00 |
| StreamAgg_8    |              | IndexScan_16   | cop  | , funcs:count(1)                                                       | 1.00     |
| IndexReader_18 | StreamAgg_17 |                | root | index:StreamAgg_8                                                      | 1.00     |
| StreamAgg_17   |              | IndexReader_18 | root | , funcs:count(col_0)                                                   | 1.00     |
+----------------+--------------+----------------+------+------------------------------------------------------------------------+----------+
4 rows in set (0.01 sec)

// PK(int) 在 2.0 版本中强制使用索引查询 / PK(int) 等于 row handle id
MySQL [order-tidb]&gt; explain select count(*) from trip_order use index();
+----------------+--------------+----------------+------+-------------------------------------------------------+----------+
| id             | parents      | children       | task | operator info                                         | count    |
+----------------+--------------+----------------+------+-------------------------------------------------------+----------+
| TableScan_15   | StreamAgg_8  |                | cop  | table:trip_order, range:[-inf,+inf], keep order:false | 10000.00 |
| StreamAgg_8    |              | TableScan_15   | cop  | , funcs:count(1)                                      | 1.00     |
| TableReader_17 | StreamAgg_16 |                | root | data:StreamAgg_8                                      | 1.00     |
| StreamAgg_16   |              | TableReader_17 | root | , funcs:count(col_0)                                  | 1.00     |
+----------------+--------------+----------------+------+-------------------------------------------------------+----------+
4 rows in set (0.00 sec)

MySQL [order-tidb]&gt; explain select count(*) from trip_order use index( );
+----------------+--------------+----------------+------+-------------------------------------------------------+----------+
| id             | parents      | children       | task | operator info                                         | count    |
+----------------+--------------+----------------+------+-------------------------------------------------------+----------+
| TableScan_15   | StreamAgg_8  |                | cop  | table:trip_order, range:[-inf,+inf], keep order:false | 10000.00 |
| StreamAgg_8    |              | TableScan_15   | cop  | , funcs:count(1)                                      | 1.00     |
| TableReader_17 | StreamAgg_16 |                | root | data:StreamAgg_8                                      | 1.00     |
| StreamAgg_16   |              | TableReader_17 | root | , funcs:count(col_0)                                  | 1.00     |
+----------------+--------------+----------------+------+-------------------------------------------------------+----------+
4 rows in set (0.00 sec)
</code></pre>]]></content:encoded><h:time datetime="2018-08-03T00:00:00+08:00">2018-08-03 · post</h:time><h:a class="feed-article-title" href="https://atman.ihx.cc/post/20180803-31-select-hash/">School - TiDB 根据 PK 查询不到数据</h:a></item><item><title>总结 - Syncer 助力思维成长</title><link>https://atman.ihx.cc/post/20180605-syncer-mindmap/</link><guid isPermaLink="true">https://atman.ihx.cc/post/20180605-syncer-mindmap/</guid><pubDate>Tue, 05 Jun 2018 00:00:00 +0800</pubDate><dc:creator>Atman</dc:creator><category>Syncer</category><category>enterprise tools</category><category>Troubleshooting</category><description>0x00 背景 长期使用 Syncer 之后经过一番胡思乱想之后的总结经验，类似于“久病成医”的感觉 内容按照 201706 - 201806 期间使用经验整理，后续大致是不会遇见了，因为有了新工具（DM） 0x01 Syncer-FAQ 使用 Syncer 前请详细阅读官方 Syncer 文档 Syncer 是一个 同步工具 ，通过 Syncer 配置文件 …</description><content:encoded><![CDATA[<h2 id="0x00-背景">0x00 背景</h2>
<blockquote>
<p>长期使用 Syncer 之后经过一番胡思乱想之后的总结经验，类似于“久病成医”的感觉
内容按照 201706 - 201806 期间使用经验整理，后续大致是不会遇见了，因为有了新工具（DM）</p>
</blockquote>
<h2 id="0x01-syncer-faq">0x01 Syncer-FAQ</h2>
<ul>
<li>使用 Syncer 前请详细阅读官方 <a href="https://github.com/pingcap/docs-cn/blob/master/tools/syncer.md">Syncer</a> 文档</li>
<li>Syncer 是一个 <strong>同步工具</strong> ，通过 Syncer 配置文件中的 [from] 获取上游 MySQL binlog 信息，解析 binlog 后会根据配置文件中的 skip-dmls、skip-ddls、replicate-do-db、replicate-do-table、route-rules 等参数匹配 or 过滤，然后将匹配 or 过滤后的数据集通过 SQL Client 的方式写入到 [to] 下游数据库</li>
</ul>
<h2 id="0x02-业务逻辑">0x02 业务逻辑</h2>
<p><img src="https://atman.ihx.cc/post/20180605-syncer-mindmap/180101-Syncer-FAQ.svg" alt="Syncer 业务逻辑，by: https://github.com/BigerCAP" loading="lazy" decoding="async">
</p>
<ul>
<li>Syncer 是个同步工具，Syncer 中分三个部分
<ul>
<li><strong>上游</strong> binlog 数据读取：这是个单线程模拟读取 MySQL binlog 内容，Syncer 针对 from binlog 有一定的 <a href="https://github.com/pingcap/docs-cn/blob/master/tools/syncer.md#syncer-%E5%90%8C%E6%AD%A5%E5%89%8D%E6%A3%80%E6%9F%A5">约束检查</a>，检查通过后开始拉取数据并进行数据预处理工作
<ul>
<li>目前 Syncer 拉取 binlog 不存在性能瓶颈 (远程网络读取 binlog 会受带宽质量影响)</li>
<li>数据预处理工作是主动去掉 TiDB 目前不支持的 SQL format 、DML SQL format 转换、DDL Spilt 等内容</li>
</ul>
</li>
<li><strong>中层</strong> 数据处理：将上游预处理的数据与配置文件中的 <code>skip-dmls、skip-ddls、replicate-do-db、replicate-do-table、route-rule</code> 参数做数据过滤、数据匹配、数据转换、数据检查
<ul>
<li>此处会消耗 Syncer 所在主机的计算资源、内存资源</li>
</ul>
</li>
<li><strong>下游</strong> 数据消费：Syncer 作为 SQL Client 链接 TiDB 消费数据，由配置文件中 worker-count * batch 控制 Syncer 消费数据的速度
<ul>
<li>在数据消费时 binlog 的语句会被以下方式进行替换：
<ul>
<li>insert == replace</li>
<li>update == update / update == delete + replace (safemode)</li>
<li>delete == delete</li>
</ul>
</li>
<li>数据消费过程中会记录下数据同步断点：Syncer 断点记录在 Syncer.meta 文件中， 格式是 binlog-name、Position 与 GTID
<ul>
<li>Syncer 会将上游一个大事务进行切分为多个小事务到下游执行，如在一个大事务内发生退出，Syncer 再次启动时会重新执行这个事务</li>
<li>Syncer 是以 ROW format binlog 进行回放 SQL 语句，即使事务被重复执行也会保持一致性</li>
</ul>
</li>
<li>此处会消耗 Syncer 所在主机的网络资源</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="0x03-性能调优">0x03 性能调优</h2>
<ul>
<li>Syncer 根据下游消费能力调整 worker-count 与 batch 参数控制其同步速度，worker-count 提供了并发能力，batch 是每个并发的数据量
<ul>
<li>worker-count 工作能力受 syncer 所在机器的 CPU 影响， worker-count 与 CPU 至少是 1:1 关系</li>
<li>首先提高 worker-count(1-256 之间) ，batch 固定 (比如 100 )，当调大 worker-count 无法加快消费时，可以适当增加 batch 大小，不建议超过 1000
<ul>
<li>调整 worker-count * batch 时应当注意 <a href="https://github.com/pingcap/docs-cn/blob/master/tools/syncer.md#%E7%9B%91%E6%8E%A7%E6%96%B9%E6%A1%88" title="看这里可以知道如何配置 Syncer 监控">Syncer dashboard</a> 中的 <code>syncer_txn_costs_gauge_in_second</code> Panel，该项为 Syncer 执行语句到下游消费成功的时长 (正常该数值在 ms 级)</li>
</ul>
</li>
<li>worker count * batch 等于最大消费 QPS ，实际运行过程会低于这个假设值，尤其当内外网之间进行同步时，此时应当注意内外网之间的最大带宽</li>
</ul>
</li>
</ul>
<h2 id="0x04-问题整理">0x04 问题整理</h2>
<ul>
<li>Syncer 在使用过程中会遇见以下错误：
<ol>
<li>Syncer 解析 binlog 出错：Syncer 目前支持的 binlog 有限，初始时按照 MySQL 5.7\5.6 版本开发，后期加入了 MariaDB 10 ；如果使用版本不在这个范围之内可能会出现一些异常错误。同时 MySQL 与 MariaDB 自身软件也会产生一些 binglog 相关的 BUG，这类 BUG 需要升级软件版本才可以解决</li>
<li>Syncer 插入数据到下游出错：此类一般是下游 TiDB 不支持。此类报错与 SQL Client 执行 SQL 语句得到的报错一致</li>
<li>Syncer 因为某些事件产生 panic (如使用了比较老版本的 MySQL)：此时需要联系 PingCAP 官方技术支持，发送业务场景、使用疑问信息到 <a href="mailto:info@pingcap.com">info@pingcap.com</a></li>
<li>Syncer 使用过程中其他错误：如数据库权限问题、网络闪断或不可达、下游消费出现堵塞、写入冲突、数据同步慢、数据同步不正常 等，其实均可通过自建与阅读文档解决</li>
</ol>
</li>
<li>Syncer 出现问题时应当先进行自检，完成以下步骤内容
<ul>
<li>Sycner <a href="https://github.com/pingcap/docs-cn/blob/master/tools/syncer.md#syncer-%E5%90%8C%E6%AD%A5%E5%89%8D%E6%A3%80%E6%9F%A5">同步前的一些检查项</a> ：检查上下游之间的参数是否符合需求</li>
<li>Syncer <a href="https://github.com/pingcap/docs-cn/blob/master/tools/syncer.md#%E7%9B%91%E6%8E%A7%E6%96%B9%E6%A1%88">监控项 / 告警项配置</a> ：设置这个可以观察 Syncer 运行状态</li>
<li>Syncer 数据同步不正常，应当先检查 <a href="https://github.com/pingcap/docs-cn/blob/master/tools/syncer.md#%E5%90%AF%E5%8A%A8-syncer">配置文件</a> 与 <a href="https://github.com/pingcap/docs-cn/blob/master/tools/syncer.md#%E6%8C%87%E5%AE%9A%E6%95%B0%E6%8D%AE%E5%BA%93%E5%90%8C%E6%AD%A5">route-rule</a>，检查这些是否与期望相等</li>
<li>Syncer <a href="https://atman.ihx.cc/post/20180323-systemd-syncer/">启动方式与守护进程</a></li>
</ul>
</li>
</ul>
<h3 id="上下游-schema-不一致场景">上下游 schema 不一致场景</h3>
<ul>
<li>该问题主要出现于分库分表，上游执行 DDL 后，Syncer 出现上下游 schema 信息不一致。</li>
<li>原因是上游分表同步进步不一致，没有有效的通过中控机制锁住所有分表的 DDL 执行状态。</li>
<li>日志输出如下：</li>
</ul>
<pre><code class="language-fallback" data-lang="fallback">2018/07/18 19:21:17 main.go:79: [error] /home/jenkins/workspace/build_tidb_enterprise_tools_master/go/src/github.com/pingcap/tidb-enterprise-tools/syncer/syncer.go:529: gen insert sqls failed: insert columns and data mismatch in length: 25 vs 23, schema: CRM, table: ORDER
/home/jenkins/workspace/build_tidb_enterprise_tools_master/go/src/github.com/pingcap/tidb-enterprise-tools/syncer/syncer.go:165:
2018/07/18 19:21:17 syncer.go:752: [info] print status exits, err:context canceled
</code></pre><ul>
<li>
<p>核验步骤</p>
<ul>
<li>通过 <code>show create table tablename</code> 核实上下游 schema info ，或者通过 mysqlbinlog 查看 binlog 内容，或者 syncer 开启 Debug 模式查看输出
<ul>
<li>mysqlbinlog 示例如下 (注意修改 binlogname 与 pos 点位置，可以使用 log 或者 syncer.meta 中的信息)
<ul>
<li><code>mysqlbinlog --base64-output=DECODE-ROWS  mysql-bin.002019 --start-position 430862799 --stop-position 430866627 -vv</code></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li>
<p>解决方案</p>
<ul>
<li>如果数据量小，可以从新来一遍全量，然后再做增量数据</li>
<li>联系 PingCAP 官方服务，官方会解决详细解决方案。
<ul>
<li>比如：去掉上下游 schema 检查，这种会有一定的潜在问题，如先执行 <code>alter table A add column</code>，紧随执行 <code>alter table A delete column</code>，此时数据会有影响。</li>
<li>或者使用 Syncer 升级版 Data Migration Product Proposal (DM)，需要联系 PingCAP 商务支持 <a href="mailto:info@pingcap.com">info@pingcap.com</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="unsupported-ddl">unsupported DDL</h3>
<blockquote>
<p>Error 1105: unsupported modify column null to not null</p>
</blockquote>
<ul>
<li>
<p>Syncer 日志文件</p>
<pre><code class="language-SQL" data-lang="SQL">2018/09/28 18:40:54 db.go:123: [warning] [exec][sql]USE `qxf`; ALTER TABLE `fof_strategy` MODIFY COLUMN `start_date` datetime NOT NULL;[args][][error]Error 1105: unsupported modify column null to not null
</code></pre></li>
<li>
<p>问题原因</p>
<ul>
<li>这个错误是 TiDB 不支持  default null 与 default not null 之间的互相转换。详情阅读 <a href="https://github.com/pingcap/docs-cn/blob/master/sql/ddl.md#alter-table-%E8%AF%AD%E6%B3%95">官方文档 DDL 之 Alter table</a></li>
</ul>
</li>
</ul>
<h3 id="启动-syner-失败">启动 Syner 失败</h3>
<ul>
<li>
<p>Meta 文件或者配置文件参数有回车符</p>
<ul>
<li><code>[error] Near line 3 (last key parsed ''): Strings cannot contain new lines.</code></li>
</ul>
<pre><code class="language-fallback" data-lang="fallback">2017/12/14 08:36:20 main.go:52: [info] config: log-level:info log-file:/root/prega-syncer/log/card.log log-rotate:day status-addr::11105 server-id:999 worker-count:32 batch:100 meta-file:/root/prega-syncer/meta/card.meta do-tables:[] do-dbs:[~^mmm*] ignore-tables:[] ignore-dbs:[] from:DBConfig(host:10.1.1.14, user:root, port:3306, pass:&lt;omitted&gt;) to:DBConfig(host:10.1.1.25, user:syncer, port:5555, pass:&lt;omitted&gt;) skip-sqls:[] route-rules:[] enable-gtid:true safe-mode:false git-hash: ba3ca1271bb63d58f4d4eecf6d189e353b40440a utc-build-time:[2017-11-23 11:34:40] go-version:go1.9.2
2017/12/14 08:36:20 main.go:75: [error] Near line 3 (last key parsed &#39;&#39;): Strings cannot contain new lines.
/home/jenkins/workspace/build_tidb_enterprise_tools_master/go/src/github.com/pingcap/tidb-enterprise-tools/syncer/meta.go:85:
/home/jenkins/workspace/build_tidb_enterprise_tools_master/go/src/github.com/pingcap/tidb-enterprise-tools/syncer/syncer.go:136:
2017/12/14 08:36:20 metrics.go:107: [info] listening on :11105 for status and metrics report.
</code></pre></li>
</ul>
<h3 id="数据同步不正常或数据上下游不一致">数据同步不正常或数据上下游不一致</h3>
<blockquote>
<p>数据同步不正常或数据上下游不一致问题检查</p>
</blockquote>
<ul>
<li>
<p>自检 <a href="https://github.com/pingcap/docs-cn/blob/master/tools/syncer.md#syncer-%E5%90%8C%E6%AD%A5%E5%89%8D%E6%A3%80%E6%9F%A5">checklist</a></p>
</li>
<li>
<p>Syncer 正常运行，主库有插入数据，备库不同步</p>
<ul>
<li>
<p>检查 binlog 是否存在</p>
</li>
<li>
<p>检查 binlog 格式</p>
</li>
<li>
<p>检查 binlog 内容</p>
<pre><code class="language-sql" data-lang="sql">MySQL [(none)]&gt; show master logs;
+------------------+------------+
| Log_name         | File_size  |
+------------------+------------+
| mysql-bin.000023 | 1073742014 |
| mysql-bin.000024 | 1073742302 |
| mysql-bin.000025 |  101832651 |
+------------------+------------+
</code></pre></li>
</ul>
</li>
<li>
<p>如何区分 binlog 内容格式为 row 模式</p>
<ul>
<li>使用 <code>show master logs;</code> 查到最新的 binlog file name 。</li>
<li>使用 <code>show binlog events in 'mysql-bin.000025'  limit 10;</code></li>
<li>查看 Event_type 列是否有 <code>Write_rows</code> <code>Update_rows</code> 等值。</li>
</ul>
</li>
<li>
<p><code>SET GLOBAL binlog_format = ROW;</code> 修改 binlog 格式后，下一个 binlog file 才会生效。</p>
<ul>
<li>执行 <code>flush logs;</code> 手动刷新生成 binlog file 。</li>
</ul>
</li>
<li>
<p>查看 binlog 文件大小</p>
<ul>
<li>
<p>默认 binlog file size  <code>show global variables like '%max_binlog_size%';</code></p>
<pre><code class="language-sql" data-lang="sql">+-----------------+------------+
| Variable_name   | Value      |
+-----------------+------------+
| max_binlog_size | 1073741824 |
+-----------------+------------+
</code></pre></li>
</ul>
</li>
</ul>
<h3 id="mysql-a--b--c--syncer-同步场景">MySQL A &gt; B &gt; C &gt; Syncer 同步场景</h3>
<p><img src="https://atman.ihx.cc/post/20180605-syncer-mindmap/180101-Syncer-FAQ-181123.svg" alt="MySQL 主从从架构" loading="lazy" decoding="async">
</p>
<ul>
<li>MySQL 生产环境数据环境通过 MySQL “主从从” 架构实现高可用灾备模式
<ul>
<li>在该模式后面放置 syncer 工具同步数据到 TiDB Cluster, 如果未开启 log slave update 参数，会导致数据不一致。</li>
<li>该参数具体功能以及主从之间其他参数可以查看 MySQL 官网 <a href="https://dev.mysql.com/doc/refman/8.0/en/replication-options-slave.html" title="TiDB-OPS, --log-slave-updates , MySQL 主从从模式">17.1.6.3 Replication Slave Options and Variables</a></li>
</ul>
</li>
<li>该参数功能
<ul>
<li>从库只开启 log-bin 功能，不使用 log-slave-updates 功能
<ul>
<li>从库在主库复制的数据，不会写入 log-bin 文件</li>
<li>直接向从库写入数据时，会写入 log-bin 文件</li>
<li>此时 syncer 读到的数据并不是最终完整数据</li>
</ul>
</li>
<li>从库开启 log-slave-updates 功能
<ul>
<li>从库从主库复制的数据会写入 log-bin 日志文件里</li>
<li>此时 syncer 可读到最终完整数据</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="0x05-已-fixbug">0x05 已 fixbug</h2>
<h3 id="gtid-开关问题">GTID 开关问题</h3>
<ul>
<li>
<p>UUID 获取问题</p>
<ul>
<li>Syncer 引入 UUID 库版本问题，即时没有开启 enable-gtid，也会解析 binlog 中 UUID 信息，解析数据时失败</li>
<li>与 syncer.meta 文件内 <code>binlog-gtid = &quot;&quot;</code> 信息无关</li>
</ul>
<pre><code class="language-fallback" data-lang="fallback">2018/01/17 13:58:17 main.go:75: [error] uuid: invalid version number: %!s(uint8=101)
</code></pre></li>
</ul>
<h3 id="syncer-未关闭的长连接">Syncer 未关闭的长连接</h3>
<ul>
<li>
<p>MySQL 上游出现由 Syncer 创建的大量长连接</p>
<ul>
<li>上游持续未插入数据，Syncer 会固定时间进行重连获取最新信息</li>
<li>syncer 每隔一个小时会获取一次新的数据，但在建立新连接的时候未关闭老的连接，导致 mysql 出现非常多的长连接。导致业务告警。</li>
<li>主要原因是，syncer 建立连接未进行正确关闭。</li>
<li>日志 tps 持续为 0 ，通过 sql 查询上下游同步正常</li>
</ul>
<pre><code class="language-fallback" data-lang="fallback">2017/12/30 00:17:40 syncer.go:803: [info] [syncer]total events = 102214510, total tps = 50, recent tps = 0, master-binlog = (mysql-bin.001244, 66802580), master-binlog-gtid=8c38f844-2985-11e7-a6f2-18ded76e567c:1-1838809963, syncer-binlog = (mysql-bin.001244, 66802580), syncer-binlog-gtid = 8c38f844-2985-11e7-a6f2-18ded76e567c:1-1838809963,b7ff0e7e-2985-11e7-a6f3-18ded76e34de:1-37
</code></pre><ul>
<li>通过 <code>show processlist</code> 查看到很多长连接，通过相邻 time 相减得到固定值 3614s ，确定每隔一段时间去检查一次信息。</li>
</ul>
<pre><code class="language-SQL" data-lang="SQL">849978  sync_tidb       10.1.1.2:49773        NULL    Binlog Dump GTID        401307  Master has sent all binlog to slave; waiting for binlog to be updated   NULL
850140  sync_tidb       10.1.1.2:60822        NULL    Binlog Dump GTID        397693  Master has sent all binlog to slave; waiting for binlog to be updated   NULL
850308  sync_tidb       10.1.1.2:43534        NULL    Binlog Dump GTID        394079  Master has sent all binlog to slave; waiting for binlog to be updated   NULL
</code></pre><ul>
<li>修复办法：杀掉 syncer 进程，然后登陆 MySQL 杀死所有长连接。</li>
</ul>
</li>
</ul>
<h2 id="0x06-问题排查示例">0x06 问题排查示例</h2>
<h3 id="开启-debug-日志">开启 Debug 日志</h3>
<pre><code class="language-mysql" data-lang="mysql">2018/01/13 12:04:12 binlogsyncer.go:98: [info] create BinlogSyncer with config &amp;{100 mysql rm-bp173ev012345rp03.mysql.rds.tidbclouds.com 3306 g7pay_link_ro nxrwcQ47kdIn   false false &lt;nil&gt; false debug 0}
2018/01/13 12:04:12 metrics.go:107: [info] listening on :10073 for status and metrics report.
2018/01/13 12:04:12 binlogsyncer.go:274: [info] begin to sync binlog from position (mysql-bin.002019, 430862751)
2018/01/13 12:04:12 binlogsyncer.go:158: [info] register slave for master server rm-bp173ev012345rp03.mysql.rds.tidbclouds.com:3306
2018/01/13 12:04:12 binlogsyncer.go:632: [info] rotate to (mysql-bin.002019, 430862751)
2018/01/13 12:04:12 syncer.go:521: [info] rotate binlog to (mysql-bin.002019, 430862751)
2018/01/13 12:04:12 syncer.go:676: [debug] gtid information: binlog (mysql-bin.002019, 430862799), gtid b470bfb4-bdb4-11e6-a7e5-70106fac1460:1-277917818
2018/01/13 12:04:12 syncer.go:525: [debug] source-db:cat_link table:link_cat; target-db:cat_link table:link_cat, RowsEvent data: [[E78D56BBBC2357PPPBBBBCACD6EBD2AC 区域经营 - 华南 118OO6009 华中 - 桂琼 - 柳州门店 118006GHJ025OO1 H00O6Q H00O6Q 浙广 TiDB 储物流动公司 陈王 120123ABCD149rrr2 桂 A88888 0 2 梁王 18212238888 &lt;nil&gt; 0000-00-00 00:00:00 0 0 0000-00-00 00:00:00 小芳 lij 0 1 2018-01-12 21:10:09 &lt;nil&gt; 2  291464]]
2018/01/13 12:04:12 db.go:55: [debug] [query][sql]SHOW COLUMNS FROM `cat_link`.`link_cat`
2018/01/13 12:04:12 db.go:55: [debug] [query][sql]SHOW INDEX FROM `cat_link`.`link_cat`
2018/01/13 12:04:12 syncer.go:882: [info] flush all jobs meta = syncer-binlog = (mysql-bin.002019, 430862751), syncer-binlog-gtid = b470bfb4-bdb4-11e6-a7e5-70106fac1460:1-277917817
2018/01/13 12:04:12 meta.go:120: [info] save position to file, binlog-name:mysql-bin.002019 binlog-pos:430862751 binlog-gtid:b470bfb4-bdb4-11e6-a7e5-70106fac1460:1-277917817
2018/01/13 12:04:12 main.go:75: [error] /home/jenkins/workspace/build_tidb_enterprise_tools_master/go/src/github.com/pingcap/tidb-enterprise-tools/syncer/syncer.go:556: gen insert sqls failed: insert columns and data mismatch in length: 27 vs 28, schema: cat_link, table: link_cat
/home/jenkins/workspace/build_tidb_enterprise_tools_master/go/src/github.com/pingcap/tidb-enterprise-tools/syncer/syncer.go:143:
2018/01/13 12:04:12 syncer.go:795: [info] print status exits, err:context canceled
2018/01/13 12:04:12 binlogsyncer.go:126: [info] syncer is closing...
2018/01/13 12:04:12 binlogstreamer.go:47: [error] close sync with err: sync is been closing...
2018/01/13 12:04:12 binlogsyncer.go:141: [info] syncer is closed
</code></pre><h3 id="查看下游-tidb-日志">查看下游 TiDB 日志</h3>
<ul>
<li>
<p>Syncer 是作为上游的服务端，获取数据转换后，作为下游的客户端插入数据，以下信息是在插入数据的时候遇见错误接受到的返回</p>
</li>
<li>
<p>Syncer 日志内显示以下信息，实际是 Syncer 下游 TiDB 返回的错误信息</p>
<pre><code class="language-fallback" data-lang="fallback">begin failed Error 1105: [try again later]: backoffer.maxSleep 5000ms is exceeded, errors:
get timestamp failed: rpc error: code = Unknown desc = rpc error: code = Unavailable desc = not leader
get timestamp failed: rpc error: code = Unavailable desc = grpc: the connection is unavailable
get timestamp failed: rpc error: code = Unavailable desc = grpc: the connection is unavailable
db.go💯 [warning] sql stmt_exec retry 90
</code></pre></li>
</ul>
<h3 id="查看运行状态">查看运行状态</h3>
<ul>
<li>检查 syncer 是否还在运行</li>
<li>查看 syncer 最后 50 行日志，根据日志提示修复</li>
<li>提示 <code>2017/08/01 08:28:59 binlogsyncer.go:554: [error] connection was bad</code></li>
<li>tidb 链接 源库网络出现异常，tidb 会重试一段时间后退出</li>
</ul>
]]></content:encoded><h:time datetime="2018-06-05T00:00:00+08:00">2018-06-05 · post</h:time><h:a class="feed-article-title" href="https://atman.ihx.cc/post/20180605-syncer-mindmap/">总结 - Syncer 助力思维成长</h:a></item><item><title>Drainer &amp; Binlog crc mismatch</title><link>https://atman.ihx.cc/post/20180512-drainer-crc/</link><guid isPermaLink="true">https://atman.ihx.cc/post/20180512-drainer-crc/</guid><pubDate>Sat, 12 May 2018 00:00:00 +0800</pubDate><dc:creator>Atman</dc:creator><category>Binlog</category><category>Drainer</category><category>PUMP</category><category>Troubleshooting</category><description>0x00 借口 该问题出现时间为 2018 年 5 月 12 日，影响版本范围在 1.0.x &amp;amp; 2.0 附近；基本上算运维事故，一定要配置告警啊，就算系统不重要 现象总结 出现 crc mismatch 可能是 pump binlog 数据损坏，drainer 对 binlog 内容校验失败 tidb 进程存在，业务端口不可用, 当 pump 不可用 …</description><content:encoded><![CDATA[<h2 id="0x00-借口">0x00 借口</h2>
<blockquote>
<p>该问题出现时间为 2018 年 5 月 12 日，影响版本范围在 1.0.x &amp; 2.0 附近；基本上算运维事故，一定要配置告警啊，就算系统不重要</p>
</blockquote>
<ul>
<li>现象总结
<ul>
<li>出现 crc mismatch 可能是 pump binlog 数据损坏，drainer 对 binlog 内容校验失败</li>
<li>tidb 进程存在，业务端口不可用, 当 pump 不可用后，tidb 自动丢掉业务端口
<ul>
<li><code>listener stopped, waiting for manual kill</code></li>
</ul>
</li>
</ul>
</li>
<li>触发原因可能是
<ul>
<li>服务器重启</li>
<li>kill -9</li>
<li>磁盘写满</li>
</ul>
</li>
</ul>
<h3 id="drainer-log">Drainer Log</h3>
<blockquote>
<p>Drainer 服务日志持续刷以下日志<br>
Drainer 需要去每个 PUMP 节点收集 Binlog 数据，汇总时按照时许排序并做一致性校验，根据提示看时数据校验未通过</p>
</blockquote>
<pre><code class="language-fallback" data-lang="fallback">2018/01/08 15:44:59 pump.go:386: [warning] [stream] node ip-10-0-70-42:8250, pos {Suffix:351 Offset:520960160}, error rpc error: code = Unknown desc = binlogger: crc mismatch
2018/01/08 15:45:00 pump.go:386: [warning] [stream] node ip-10-0-70-40:8250, pos {Suffix:354 Offset:182450922}, error rpc error: code = Unknown desc = binlogger: crc mismatch
</code></pre><h3 id="pump-log">PUMP Log</h3>
<blockquote>
<p>在 drainer 出现问题集群中发现一个 PUMP 磁盘写满的现象，猜测可能是这里先出现写满然后导致部分数据未写入成功</p>
</blockquote>
<pre><code class="language-fallback" data-lang="fallback">2018/01/05 11:54:28 server.go:364: ^[[0;31m[error] generate forward binlog, write binlog err write /data1/deploy/data.pump/clusters/6485556578803970722/binlog-0000000000000354: no space left on device^[[0m
</code></pre><h3 id="修复">修复</h3>
<p>根据官方指导，这种情况只能通过重新搭建 Binlog 架构进行修复。重新开始做以下流程：</p>
<ol>
<li>Binlog 重新搭建，根据数据情况调整 PUMP 节点 GC 参数，默认 7 天开始 GC Binlog</li>
<li>获取上游主库的 tso 时间点，也就是断点信息</li>
<li>数据的全量导出：使用 mydumper 工具导出，数据导出时间视数据量、并发数、磁盘读写速度、网络速度而定</li>
<li>全量导入：使用的官方 loader 工具，没办法使用 myloader 或者 mysqlload 工具，因为事物大小问题无法提交</li>
<li>开启 Drainer 服务：使用第二步获取的 tso 断点信息，如果遇见重复数据，drainer 开启时有个 5 分钟的 safe mode 模式可以强制刷写下游数据
<ul>
<li>其实就是开启了 sql 转换，比如 insert 转 replace、update 转 delete + replace</li>
</ul>
</li>
<li>注意观察监控，比如 binlog 上下游延迟、binlog tps 消费速度、磁盘空间大小，最后设置下告警</li>
</ol>
<h2 id="0x01-买一送一">0x01 买一送一</h2>
<blockquote>
<p>Drainer 同步下游是个 mysql 数据库，Drainer 同步采用的是高并发提交事物模式写入数据，偶遇一个死锁错误<br>
这种错误只能靠人工清理了，备库无业务流量，选择了直接重启处理 死锁 deadlock</p>
</blockquote>
<pre><code class="language-fallback" data-lang="fallback">2018/01/08 20:09:23 syncer.go:517: [fatal] Error 1213: Deadlock found when trying to get lock; try restarting transaction
/home/pingcap/go/src/github.com/pingcap/tidb-binlog/drainer/executor/util.go:72:
/home/pingcap/go/src/github.com/pingcap/tidb-binlog/drainer/executor/util.go:52:
</code></pre><h2 id="0x02-再送一条存货">0x02 再送一条存货</h2>
<blockquote>
<p>Drainer 数据同步下游慢，PUMP GC Binlog 的惨案</p>
</blockquote>
<p>早起刚做 Binlog 同步时，上游是 <code>TiDB * 4、PD * 3、TiKV * 9</code> 规模的集群，下游使用 8U 16G 虚拟机外加 2T sas 磁盘安装了一个 mysql 服务做数据同步。当初没有考虑同步性能，刚开始数据量比较小，虽然有些延迟但是能忍。<br>
逐渐逐渐发现越来越慢，终于有一天业务提示下游备库查不到数据了（刚开始也没有配置同步链路告警，被踢了一觉）。<br>
然后开始排查 Drainer &amp; PUMP 日志，看见 PUMP 日志中提示 <code>commitTs(396914383516074000) of binlog exceeds the lower boundary of window 396981384481603586, may miss processing, ITEM(&amp;{0xc50ebf8980 {75 0} tidb-online-tidb-2:8250 &lt;nil&gt;})ESC[0m</code> 信息，看的我一脸懵逼。咨询官方后说是 PUMP 已经 GC binlog 了，Drainer 拿不到数据所以同步就断了。<br>
详细的解释就是下面这样：</p>
<ol>
<li>a b c 三个 pump 共存储了 100 条数据，每个 pump 隔三差五的存了一些数据</li>
<li>Drainer 同步到了 77 ，想要 78 的时候发现是在 a pump 节点</li>
<li>a pump gc 时间到了，在早些时间已经把 78 数据删除了</li>
<li>Drainer 拿不到数据啊，就炸火了</li>
<li>优化方案两种，第一个是调整 PUMP GC 时间、第二个是改善下游机器配置
<ul>
<li>因为 xx 原因，先把 PUMP GC 时间调大了…… ，然后就出现上面的惨案，磁盘写满</li>
</ul>
</li>
</ol>
<h3 id="drainer-log2">Drainer log2</h3>
<pre><code class="language-fallback" data-lang="fallback">2017/12/27 07:40:06 pump.go:386: ESC[0;33m[warning] [stream] node tidb-online-tidb-1:8250, pos {Suffix:80 Offset:495074285}, error rpc error: code = Unknown desc = unexpected EOFESC[0m
2017/12/27 08:14:25 pump.go:386: ESC[0;33m[warning] [stream] node ip-10-10-8-6:8250, pos {Suffix:76 Offset:392531590}, error rpc error: code = Unknown desc = unexpected EOFESC[0m
2017/12/27 09:59:30 pump.go:386: ESC[0;33m[warning] [stream] node ip-10-10-8-7:8250, pos {Suffix:80 Offset:39373906}, error rpc error: code = Unknown desc = unexpected EOFESC[0m
2017/12/27 12:14:59 pump.go:386: ESC[0;33m[warning] [stream] node ip-10-10-8-6:8250, pos {Suffix:76 Offset:472984304}, error rpc error: code = Unknown desc = unexpected EOFESC[0m
2017/12/27 15:12:19 pump.go:386: ESC[0;33m[warning] [stream] node tidb-online-tidb-1:8250, pos {Suffix:81 Offset:111758786}, error rpc error: code = Unknown desc = unexpected EOFESC[0m
2017/12/27 16:36:42 pump.go:386: ESC[0;33m[warning] [stream] node tidb-online-tidb-2:8250, pos {Suffix:77 Offset:26308812}, error rpc error: code = Internal desc = transport is closingESC[0m
2017/12/27 16:36:42 pump.go:386: ESC[0;33m[warning] [stream] node ip-10-10-8-6:8250, pos {Suffix:77 Offset:26308812}, error rpc error: code = Internal desc = transport is closingESC[0m
2017/12/27 16:36:45 collector.go:184: ESC[0;37m[info] node(tidb-online-tidb-2:8250) of cluster(6493070954582498647)  has been removed and release the connection to itESC[0m
2017/12/27 16:36:45 pump.go:378: ESC[0;33m[warning] [Get pull binlogs stream ip-10-10-8-6:8250] rpc error: code = Unavailable desc = grpc: the connection is unavailableESC[0m
2017/12/27 16:36:48 pump.go:378: ESC[0;33m[warning] [Get pull binlogs stream ip-10-10-8-6:8250] rpc error: code = Unavailable desc = grpc: the connection is unavailableESC[0m
2017/12/27 16:36:51 pump.go:378: ESC[0;33m[warning] [Get pull binlogs stream ip-10-10-8-6:8250] rpc error: code = Unavailable desc = grpc: the connection is unavailableESC[0m
2017/12/27 16:36:54 pump.go:378: ESC[0;33m[warning] [Get pull binlogs stream ip-10-10-8-6:8250] rpc error: code = Unavailable desc = grpc: the connection is unavailableESC[0m
2017/12/27 16:36:57 pump.go:378: ESC[0;33m[warning] [Get pull binlogs stream ip-10-10-8-6:8250] rpc error: code = Unavailable desc = grpc: the connection is unavailableESC[0m
2017/12/27 16:37:00 pump.go:378: ESC[0;33m[warning] [Get pull binlogs stream ip-10-10-8-6:8250] rpc error: code = Unavailable desc = grpc: the connection is unavailableESC[0m
2017/12/27 16:37:03 pump.go:378: ESC[0;33m[warning] [Get pull binlogs stream ip-10-10-8-6:8250] rpc error: code = Unavailable desc = grpc: the connection is unavailableESC[0m
2017/12/27 16:37:05 collector.go:166: ESC[0;37m[info] node tidb-online-tidb-2:8250 get save point {75 0}ESC[0m
2017/12/27 16:37:05 pump.go:378: ESC[0;33m[warning] [Get pull binlogs stream tidb-online-tidb-2:8250] rpc error: code = Unavailable desc = grpc: the connection is unavailableESC[0m
2017/12/27 16:37:06 pump.go:378: ESC[0;33m[warning] [Get pull binlogs stream ip-10-10-8-6:8250] rpc error: code = Unavailable desc = grpc: the connection is unavailableESC[0m
2017/12/27 16:37:08 pump.go:284: ESC[0;31m[error] FATAL ERROR: commitTs(396914383516074000) of binlog exceeds the lower boundary of window 396981384481603586, may miss processing, ITEM(&amp;{0xc50ebf8980 {75 0} tidb-online-tidb-2:8250 &lt;nil&gt;})ESC[0m
2017/12/27 16:37:08 pump.go:284: ESC[0;31m[error] FATAL ERROR: commitTs(396914383542288387) of binlog exceeds the lower boundary of window 396981384481603586, may miss processing, ITEM(&amp;{0xc50201cf80 {75 1105} tidb-online-tidb-2:8250 &lt;nil&gt;})ESC[0m
2017/12/27 16:37:08 pump.go:284: ESC[0;31m[error] FATAL ERROR: commitTs(396914383542288392) of binlog exceeds the lower boundary of window 396981384481603586, may miss processing, ITEM(&amp;{0xc50201d580 {75 1865} tidb-online-tidb-2:8250 &lt;nil&gt;})ESC[0m
2017/12/27 16:37:08 pump.go:284: ESC[0;31m[error] FATAL ERROR: commitTs(396914383555395593) of binlog exceeds the lower boundary of window 396981384481603586, may miss processing, ITEM(&amp;{0xc4f4b98580 {75 2599} tidb-online-tidb-2:8250 &lt;nil&gt;})ESC[0m
2017/12/27 17:28:35 pump.go:386: ESC[0;33m[warning] [stream] node ip-10-10-8-7:8250, pos {Suffix:80 Offset:210137628}, error rpc error: code = Canceled desc = context canceledESC[0m
2017/12/27 17:28:38 collector.go:184: ESC[0;37m[info] node(ip-10-10-8-7:8250) of cluster(6493070954582498647)  has been removed and release the connection to itESC[0m
2017/12/27 17:28:58 pump.go:386: ESC[0;33m[warning] [stream] node ip-10-10-8-6:8250, pos {Suffix:77 Offset:26341996}, error rpc error: code = Canceled desc = context canceledESC[0m
2017/12/27 17:29:01 collector.go:184: ESC[0;37m[info] node(ip-10-10-8-6:8250) of cluster(6493070954582498647)  has been removed and release the connection to itESC[0m
2017/12/27 17:58:47 pump.go:386: ESC[0;33m[warning] [stream] node tidb-online-tidb-1:8250, pos {Suffix:81 Offset:177552746}, error rpc error: code = Unknown desc = unexpected EOFESC[0m
2017/12/27 18:34:29 pump.go:386: ESC[0;33m[warning] [stream] node tidb-online-tidb-3:8250, pos {Suffix:80 Offset:273173616}, error rpc error: code = Unknown desc = unexpected EOFESC[0m
2017/12/27 19:16:06 pump.go:386: ESC[0;33m[warning] [stream] node tidb-online-tidb-1:8250, pos {Suffix:81 Offset:212949758}, error rpc error: code = Unknown desc = unexpected EOFESC[0m
2017/12/27 19:28:17 pump.go:386: ESC[0;33m[warning] [stream] node tidb-online-tidb-4:8250, pos {Suffix:80 Offset:526663116}, error rpc error: code = Unknown desc = unexpected EOFESC[0m
2017/12/29 11:58:13 pump.go:386: ESC[0;33m[warning] [stream] node tidb-online-tidb-4:8250, pos {Suffix:81 Offset:480434923}, error rpc error: code = Unknown desc = unexpected EOFESC[0m
2017/12/29 12:38:00 pump.go:386: ESC[0;33m[warning] [stream] node tidb-online-tidb-1:8250, pos {Suffix:82 Offset:184323012}, error rpc error: code = Unknown desc = unexpected EOFESC[0m
2017/12/29 14:25:16 pump.go:386: ESC[0;33m[warning] [stream] node tidb-online-tidb-4:8250, pos {Suffix:82 Offset:3389669}, error rpc error: code = Unknown desc = unexpected EOFESC[0m
2017/12/29 18:50:41 pump.go:386: ESC[0;33m[warning] [stream] node tidb-online-tidb-1:8250, pos {Suffix:82 Offset:365276552}, error rpc error: code = Unknown desc = unexpected EOFESC[0m
2017/12/12 20:38:38 pump.go:386: ESC[0;33m[warning] [stream] node tidb-online-tidb-1:8250, pos {Suffix:70 Offset:517918272}, error rpc error: code = Unknown desc = unexpected EOFESC[0m
2017/12/12 20:59:17 pump.go:386: ESC[0;33m[warning] [stream] node tidb-online-tidb-3:8250, pos {Suffix:69 Offset:505588696}, error rpc error: code = Unknown desc = unexpected EOFESC[0m
2017/12/12 23:52:17 util.go:161: ESC[0;31m[error] close db failed - driver: bad connectionESC[0m
</code></pre><p><img src="https://atman.ihx.cc/global/helpertools.jpg" alt="helper-tools" title="ap.tidb.cc helper tools" loading="lazy" decoding="async">
</p>
]]></content:encoded><h:time datetime="2018-05-12T00:00:00+08:00">2018-05-12 · post</h:time><h:a class="feed-article-title" href="https://atman.ihx.cc/post/20180512-drainer-crc/">Drainer &amp; Binlog crc mismatch</h:a></item><item><title>TiKV 磁盘空间回收步骤记录</title><link>https://atman.ihx.cc/post/20180503-disk-space-recovery/</link><guid isPermaLink="true">https://atman.ihx.cc/post/20180503-disk-space-recovery/</guid><pubDate>Thu, 03 May 2018 00:00:00 +0800</pubDate><dc:creator>Atman</dc:creator><category>TiKV</category><category>Disk</category><category>Troubleshooting</category><description>0x00 前景介绍 该版本文档内容适用于 TiKV 3.0 之前版本；不包含使用 TiKV Titan engine 架构的内容 TiKV 节点磁盘占用主要为以下三个目录 {{deploy_dir}}/log TiKV 日志目录，目前日志 GC 需要单独脚本操作 {{deploy_dir}}/data TiKV rocksDB 数据目录，用来存放 KV …</description><content:encoded><![CDATA[<h2 id="0x00-前景介绍">0x00 前景介绍</h2>
<blockquote>
<p>该版本文档内容适用于 TiKV 3.0 之前版本；不包含使用 TiKV Titan engine 架构的内容</p>
</blockquote>
<ul>
<li>TiKV 节点磁盘占用主要为以下三个目录
<ul>
<li><code>{{deploy_dir}}/log</code>  TiKV 日志目录，目前日志 GC 需要单独脚本操作</li>
<li><code>{{deploy_dir}}/data</code> TiKV rocksDB 数据目录，用来存放 KV 数据</li>
<li><code>{{deploy_dir}}/data/snap</code> TiKV snap 数据目录，region 迁移时会先生成一个 snapshot 文件，然后通过网络传输到其他节点</li>
</ul>
</li>
</ul>
<h3 id="场景">场景</h3>
<ul>
<li>业务：持续写入数据，仅保留最近一月数据；要求快速回收磁盘空间或磁盘空间相对均匀</li>
<li>集群：有数十台 TiKV ，每台 TiKV 磁盘大小仅为 500G</li>
<li>现象：仅有三十几台 TiKV 磁盘占用超过 60%，其余 TiKV 在空跑状态；个别 TiKV 持续写入达到 90%</li>
</ul>
<h2 id="0x01---操作">0x01 - 操作</h2>
<ul>
<li>调整磁盘占用比较高得 store 权重，控制磁盘 TiKV 写入量。
<ul>
<li>release-2.0(RC &amp; GA) 之后，通过调整 store 权重，可以降低 leader 与 region 的数量，进而控制磁盘空间的占用率</li>
<li>release-1.0 调整 store 权重，在不涉及 null region 时，可以控制磁盘空间占用率 (如果长期持续删除大量输出会造成 null region)</li>
</ul>
</li>
<li>release-1.0 之前，通过下线方式控制磁盘空间占用</li>
<li>本文中未涉及的信息点
<ul>
<li>TiKV <code>dynamic-level-bytes</code> 参数（动态管理 LSM 技术，配合 LSM compactions 食用）</li>
<li>TiKV 2.0 版本 <code>use-delete-range</code> 参数</li>
<li>2.0 版本 <code>region-merge</code> 功能（主动合并 table 纬度内 null region 或小于阈值参数的 region）</li>
<li>修改 TiKV LSM 每层压缩参数，如：
<ul>
<li>no:     kNoCompression</li>
<li>snappy: kSnappyCompression</li>
<li>zlib:   kZlibCompression</li>
<li>bzip2:  kBZip2Compression</li>
<li>lz4:    kLZ4Compression</li>
<li>lz4hc:  kLZ4HCCompression</li>
<li>zstd:   kZSTD</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="调整-store-权重">调整 store 权重</h3>
<p>通过 PD http API 快速查看集群内所有 Store 权重信息</p>
<pre><code class="language-bash" data-lang="bash">curl http://10.10.10.15:2379/pd/api/v1/stores |  egrep &#39;(id|address|state_name|region_weight|available)&#39; | awk &#39;{if(NR%5!=0)ORS=&#34; &#34;; else ORS=&#34;\n&#34;}1&#39; | sed &#39;s/[ ][ ]*/  /g&#39; | sed &#39;s/&#34;//g&#39; | sort -nrk 8
</code></pre><ul>
<li>
<p>通过 pd-ctl 工具调整 store 权重</p>
<ul>
<li>优势：使用 API 调用，操作方便，不涉及 store 上下线等危险操作</li>
<li>缺点：当磁盘空间仅剩 50G 以内，且数据依旧高歌猛进写入时，无法使用；调整权重是使用 <code>balance-region-scheduler</code> 与 <code>balance-leader-scheduler</code> 调度器，需要一定的时间调度 region ，调度 region 需要额外的空间，写入 snapshot</li>
</ul>
</li>
<li>
<p>通过 pd-ctl 工具连接 PD Cluster</p>
</li>
</ul>
<pre><code class="language-bash" data-lang="bash">./pd-ctl -u http://10.10.10.15:2379
</code></pre><ul>
<li>help store ，查看命令使用方法</li>
</ul>
<pre><code class="language-bash" data-lang="bash">» help store
show the store status

Usage:
  pdctl store [delete|label|weight] &lt;store_id&gt;
  store [command]

Available Commands:
  delete      delete the store
  label       set a store&#39;s label value
  weight      set a store&#39;s leader and region balance weight

Use &#34;help store [command] &#34; for more information about a command.
</code></pre><ul>
<li>调整 store 194 节点的 leader 与 region 权重
<ul>
<li>权重可调范围 <code>0.000001 到 1</code> ，默认值为 1</li>
<li>格式为： <code>store weight storeID leader权重 region权重</code></li>
</ul>
</li>
</ul>
<pre><code class="language-bash" data-lang="bash">» store weight 194 0.1 0.1
</code></pre><ul>
<li>查看调整后结果</li>
</ul>
<pre><code class="language-bash" data-lang="bash">» store 194
{
  &#34;store&#34;: {
    &#34;id&#34;: 194,
    &#34;address&#34;: &#34;10.10.10.13:20160&#34;,
    &#34;state&#34;: 0,
    &#34;state_name&#34;: &#34;Up&#34;
  },
  &#34;status&#34;: {
    &#34;capacity&#34;: &#34;500 GiB&#34;,
    &#34;available&#34;: &#34;82 GiB&#34;,
    &#34;leader_weight&#34;: 0.1,   # leader 权重
    &#34;region_count&#34;: 31316,
    &#34;region_weight&#34;: 0.1,   # region 权重
    &#34;region_score&#34;: 313160,
    &#34;start_ts&#34;: &#34;2018-04-22T08:05:13+08:00&#34;,
    &#34;last_heartbeat_ts&#34;: &#34;2018-05-03T16:27:12.85852309+08:00&#34;,
    &#34;uptime&#34;: &#34;272h21m59.85852309s&#34;
  }
}
</code></pre><h3 id="添加-store-调度">添加 store 调度</h3>
<blockquote>
<p>添加指定 store <code>evict scheduler</code> ，控制该 store 在集群内 region leader 数量为 0 或者接近 0 值，不能控制该 store 是否增加成员副本。</p>
</blockquote>
<ul>
<li>
<p>通过 pd-ctl 工具调整 store 权重</p>
<ul>
<li>优势：该节点添加调度器后，该 store 不存在 region leader ，该单节点短暂挂掉或重启不影响集群读写（该方案可与 region weight 同时使用，不过该方案更多是用于重启 tikv ，业务不受影响场景）</li>
<li>缺点：该调度器并不能控制空间使用状态</li>
</ul>
</li>
<li>
<p>添加调度器，将 store 194 上所有 leader 自动迁移到其他节点。10000 数量 leader 仅需 5 - 10 分钟</p>
<ul>
<li>该调度器添加后持续生效，需要删除调度器释放 store <code>evict scheduler</code> 状态</li>
</ul>
</li>
</ul>
<pre><code class="language-bash" data-lang="bash">curl -X POST -d &#39;{&#34;name&#34;:&#34;evict-leader-scheduler&#34;,&#34;store_id&#34;: 194}&#39; &#34;http://10.10.10.15:2379/pd/api/v1/schedulers&#34;
</code></pre><ul>
<li>查看当前所有调度器</li>
</ul>
<pre><code class="language-bash" data-lang="bash"># curl http://10.13.128.205:2379/pd/api/v1/schedulers

[
  &#34;evict-leader-scheduler-194&#34;,   # store 194 调度器
  &#34;balance-region-scheduler&#34;,     # 默认调度器，region 均衡调度
  &#34;balance-leader-scheduler&#34;,     # 默认调度器，leader 均衡调度
  &#34;balance-hot-region-scheduler&#34;  # 默认调度器，热点调度
]
</code></pre><ul>
<li>删除迁移 leader 调度器
<ul>
<li>删除后，该节点参与集群内 leader 调度</li>
</ul>
</li>
</ul>
<pre><code class="language-bash" data-lang="bash">curl -X DELETE &#34;http://10.10.10.15:2379/pd/api/v1/schedulers/evict-leader-scheduler-194&#34;
</code></pre><h3 id="下线-store">下线 Store</h3>
<blockquote>
<p>该方案可作为压轴方案 (集群内只有三台 TiKV 时，下线一台后，region 无处调度，但剩余两副本可继续维持集群使用)</p>
</blockquote>
<ul>
<li>通过 pd-ctl 工具连接 PD Cluster</li>
</ul>
<pre><code class="language-bash" data-lang="bash">./pd-ctl -u http://10.10.10.15:2379
</code></pre><ul>
<li>help store ，查看命令使用方法</li>
</ul>
<pre><code class="language-bash" data-lang="bash">» help store
show the store status

Usage:
  pdctl store [delete|label|weight] &lt;store_id&gt;
  store [command]

Available Commands:
  delete      delete the store
  label       set a store&#39;s label value
  weight      set a store&#39;s leader and region balance weight

Use &#34;help store [command] &#34; for more information about a command.
</code></pre><ul>
<li>通过 pd-ctl 删除 store 194 节点
<ul>
<li>节点会先进入 offline 状态，当该节点数据迁移完成后 (数据迁移与磁盘读写和其他 store 节点繁忙程度有关)</li>
<li>节点进入 Tomestone 状态，此时可物理删除该节点数据 (<code>{{deploy_dir/data}}</code> 存放 rocksDB 数据)</li>
</ul>
</li>
</ul>
<pre><code class="language-bash" data-lang="bash">» store delete 194
</code></pre><ul>
<li>查看调整后结果</li>
</ul>
<pre><code class="language-bash" data-lang="bash">» store 194
{
  &#34;store&#34;: {
    &#34;id&#34;: 194,
    &#34;address&#34;: &#34;10.10.10.13:20160&#34;,
    &#34;state&#34;: 0,
    &#34;state_name&#34;: &#34;Offline&#34;  # store 状态 ( UP 、Down 、Offline 、Tomestone)
  },
  &#34;status&#34;: {
    &#34;capacity&#34;: &#34;500 GiB&#34;,
    &#34;available&#34;: &#34;82 GiB&#34;,
    &#34;leader_weight&#34;: 0.1,   # leader 权重
    &#34;region_count&#34;: 31316,
    &#34;region_weight&#34;: 0.1,   # region 权重
    &#34;region_score&#34;: 313160,
    &#34;start_ts&#34;: &#34;2018-04-22T08:05:13+08:00&#34;,
    &#34;last_heartbeat_ts&#34;: &#34;2018-05-03T16:27:12.85852309+08:00&#34;,
    &#34;uptime&#34;: &#34;272h21m59.85852309s&#34;
  }
}
</code></pre>]]></content:encoded><h:time datetime="2018-05-03T00:00:00+08:00">2018-05-03 · post</h:time><h:a class="feed-article-title" href="https://atman.ihx.cc/post/20180503-disk-space-recovery/">TiKV 磁盘空间回收步骤记录</h:a></item><item><title>Linux - OOM > out of memory</title><link>https://atman.ihx.cc/post/20171119-46-linux-oom-killer/</link><guid isPermaLink="true">https://atman.ihx.cc/post/20171119-46-linux-oom-killer/</guid><pubDate>Sun, 19 Nov 2017 00:00:00 +0800</pubDate><dc:creator>Atman</dc:creator><category>Linux</category><category>TiDB</category><category>OOM</category><category>Troubleshooting</category><description>0x00 开头 测试机器环境配置比较低，使用 TiDB Join 表连接查询时偶尔会出现重启现象，按照官方指导查看问题原因说时 TiDB-server OOM 了，那么 OOM 是什么呢？为什么 OOM 啊？怎么才能避免 OOM 呢？ 思考这个现象的时候在网上搜到了一些内容，在本文总结下（从其他家复制到自己家） 0x01 现象 TiDB-server 运行在 …</description><content:encoded><![CDATA[<h2 id="0x00-开头">0x00 开头</h2>
<p>测试机器环境配置比较低，使用 TiDB Join 表连接查询时偶尔会出现重启现象，按照官方指导查看问题原因说时 TiDB-server OOM 了，那么 OOM 是什么呢？为什么 OOM 啊？怎么才能避免 OOM 呢？<br>
思考这个现象的时候在网上搜到了一些内容，在本文总结下（<del>从其他家复制到自己家</del>）</p>
<h2 id="0x01-现象">0x01 现象</h2>
<p>TiDB-server 运行在一个 8U 8G 的虚拟机上，有时候 BDA 写出一些神奇的 SQL 在 TiDB-server 上运行的会导致内存瞬间上涨；根据需要查询的数据量级，可能会瞬间导致内存爆炸然后触发 TiDB-server 重启。<br>
通过以下三种方式交叉验证 TiDB-server 是否是 OOM：</p>
<ol>
<li>内存在用状态可以在监控上看到一个上涨趋势，位置在 <code>TiDB-dashboard &gt; server &gt; memory</code> 查看，出现重启的现象就是内存瞬间上涨然后出现断崖式下降。</li>
<li>链接 TiDB-server 的 mysql 客户端会出现一条信息返回 <code>ERROR 2013 (HY000): Lost connection to MySQL server during query</code></li>
<li>使用 root 用户登录 Linux 系统，然后执行 <code>dmesg -T | grep -i oom</code> 命令，查看是否有相应信息返回
<ul>
<li>dmesg 记录了硬件启动后自检信息、kernel 系统运行信息</li>
</ul>
</li>
</ol>
<h2 id="0x02-原因">0x02 原因</h2>
<p>TiDB-server 相比 mysql ，木有临时物理表、木有中间数据转存磁盘。所以当 client 发起请求从 TiDB 获取大量数据时，TiDB 需要从 TiKV 获取数据然后在 TiDB-server 内存中做计算，此处的计算会造成写放大，然后内存爆炸导致触发 Linux OOM 机制。</p>
<p>这个现象影响程度不定，如果是在线联机服务遇见这种情况就是日了🐶啦，如果是测试或者内部人员使用还好，大家重新执行个查询就好了。该现象木有啥完美解决方案，可以考虑找个超大内存机器部署 TiDB-server 、或者让 DBA 处理数据时缩小范围（不明所以）。</p>
<h2 id="0x03-oom">0x03 OOM</h2>
<blockquote>
<p>linux OOM killer（Out Of Memory killer）这个东西会在系统内存耗尽的情况下跳出来，选择性的干掉一些进程以求释放一些内存（<del>不负责的个人经验：这把刀杀的是压死骆驼的最后一根稻草，并不是捅刀子最多的人</del>）<br>
Linux 下每个进程都有个 OOM 权重，在 <code>/proc/&lt;pid&gt;/oom_adj</code> 里面，权重是 -17 ~~ +15<br>
同时 OOM killer 会计算一个叫 score 的东东 <code>/proc/&lt;pid&gt;/oom_score</code> ，天黑闭眼之后用来确定要被杀的人；这个值是系统收集 进程的内存消耗量（计算时：父进程会承包所有子进程的内存占用）、CPU 时间 (utime + stime)、生存时间 (uptime - start time)、oom_adj 综合计算之后的结果<br>
消耗内存越多分越高，存活时间越长分越低 == “损失最少的工作，释放最大的内存同时不伤及无辜的用了很大内存的进程，并且杀掉的进程数尽量少”</p>
</blockquote>
<p>友好方式人工控制降低被杀几率，辣么就是控制进程的权重，比如这样调整 <code>echo -17 &gt; /proc/$PID/oom_adj</code> “源码说 -17 可以禁止进程被 OOM，15 会最大几率被打死”</p>
<p>还有个不那么友好的方案：</p>
<ul>
<li>修改参数 <code>/proc/sys/vm/overcommit_memory</code> 可以控制进程对内存过量使用的应对策略
<ul>
<li><code>overcommit_memory=0</code> 允许进程轻微过量使用内存，但对于瞬间大容量内存占用请求则不允许【默认值】
<ul>
<li>单次申请的内存大小不能超过 【free memory + free swap + pagecache 大小 + SLAB 中可回收的部分】，否则本次申请失败。</li>
</ul>
</li>
<li><code>overcommit_memory=1</code> 永远允许进程 overcommit</li>
<li><code>overcommit_memory=2</code> 永远禁止 overcommit</li>
</ul>
</li>
</ul>
<blockquote>
<p>本段内容复制于 <a href="http://linuxperf.com/?p=102">LINUX MEMORY OVERCOMMIT</a></p>
</blockquote>
<p>overcommit 还有个延伸内容，那就是怎么判断什么是 overcommit？Linux 内核设置了个内存阈值开关，超过开关后直接干掉。所以配置成 overvcommit 时注意修改参数 <code>/proc/meminfo</code></p>
<pre><code class="language-shell" data-lang="shell"># grep -i commit /proc/meminfo
CommitLimit:     5967744 kB
Committed_AS:    5363236 kB
</code></pre><p>CommitLimit 就是 overcommit 的阈值，申请的内存总数超过 CommitLimit 的话就算是 overcommit。<br>
这个阈值是如何计算出来的呢？它既不是物理内存的大小，也不是 free memory 的大小，它是通过内核参数 vm.overcommit_ratio 或 vm.overcommit_kbytes 间接设置的，公式如：<code>CommitLimit = (Physical RAM * vm.overcommit_ratio / 100) + Swap</code></p>
<p>vm.overcommit_ratio 是内核参数，缺省值是 50，表示物理内存的 50%。如果你不想使用比率，也可以直接指定内存的字节数大小，通过另一个内核参数 vm.overcommit_kbytes 即可.
如果使用了 huge pages，那么需要从物理内存中减去，公式变成：<code>CommitLimit = ([total RAM] – [total huge TLB RAM]) * vm.overcommit_ratio / 100 + swap</code>
参见 <a href="https://access.redhat.com/solutions/665023">https://access.redhat.com/solutions/665023</a></p>
<p>/proc/meminfo 中的 Committed_AS 表示所有进程已经申请的内存总大小，（注意是已经申请的，不是已经分配的），如果 Committed_AS 超过 CommitLimit 就表示发生了 overcommit，超出越多表示 overcommit 越严重。Committed_AS 的含义换一种说法就是，如果要绝对保证不发生 OOM (out of memory) 需要多少物理内存。</p>
<p>查看内存使用状况的常用工具 sar -r ，输出结果中有两个与 overcommit 有关，kbcommit 和 %commit</p>
<ul>
<li>kbcommit 对应 / proc/meminfo 中的 Committed_AS</li>
<li>%commit 的计算公式并没有采用 CommitLimit 作分母，而是 Committed_AS/(MemTotal+SwapTotal)，意思是_内存申请_占_物理内存与交换区之和_的百分比</li>
</ul>
<pre><code class="language-shell" data-lang="shell">$ sar -r

05:00:01 PM kbmemfree kbmemused  %memused kbbuffers  kbcached  kbcommit   %commit  kbactive   kbinact   kbdirty
05:10:01 PM    160576   3648460     95.78         0   1846212   4939368     62.74   1390292   1854880         4
</code></pre><p>课外阅读 <a href="https://www.oracle.com/technical-resources/articles/it-infrastructure/dev-oom-killer.html">How to Configure the Linux Out-of-Memory Killer</a></p>
]]></content:encoded><h:time datetime="2017-11-19T00:00:00+08:00">2017-11-19 · post</h:time><h:a class="feed-article-title" href="https://atman.ihx.cc/post/20171119-46-linux-oom-killer/">Linux - OOM > out of memory</h:a></item></channel></rss>