From c44ce559191d7f0feaa2f65047c7837672696484 Mon Sep 17 00:00:00 2001 From: Docsite Preview Bot <> Date: Mon, 8 Apr 2024 06:36:28 +0000 Subject: [PATCH] Preview PR https://github.com/pingcap/docs-cn/pull/17018 and this preview is triggered from commit https://github.com/pingcap/docs-cn/pull/17018/commits/ab99109d71dceace350eb8e2c017bc909d112b82 --- markdown-pages/zh/tidb/master/_docHome.md | 1 + markdown-pages/zh/tidb/master/_index.md | 1 + .../tidb/master/agg-distinct-optimization.md | 57 + .../zh/tidb/master/basic-sql-operations.md | 230 +++ .../master/benchmark/benchmark-sysbench-v2.md | 130 ++ .../master/benchmark/benchmark-sysbench-v3.md | 143 ++ .../benchmark/benchmark-sysbench-v4-vs-v3.md | 194 +++ .../benchmark/benchmark-sysbench-v5-vs-v4.md | 207 +++ .../benchmark-sysbench-v5.1.0-vs-v5.0.2.md | 177 ++ .../benchmark-sysbench-v5.2.0-vs-v5.1.1.md | 177 ++ .../benchmark-sysbench-v5.3.0-vs-v5.2.2.md | 193 +++ .../benchmark-sysbench-v5.4.0-vs-v5.3.0.md | 193 +++ .../benchmark-sysbench-v6.0.0-vs-v5.4.0.md | 189 +++ .../benchmark-sysbench-v6.1.0-vs-v6.0.0.md | 187 ++ .../benchmark-sysbench-v6.2.0-vs-v6.1.0.md | 187 ++ .../benchmark-tidb-using-sysbench.md | 178 ++ .../benchmark/benchmark-tidb-using-tpcc.md | 90 + .../tidb/master/benchmark/benchmark-tpch.md | 109 ++ ...line-workloads-and-add-index-operations.md | 345 ++++ ...-performance-benchmarking-with-sysbench.md | 273 +++ ...v3.0-performance-benchmarking-with-tpcc.md | 96 ++ ...v4.0-performance-benchmarking-with-tpcc.md | 119 ++ ...v4.0-performance-benchmarking-with-tpch.md | 184 ++ ...v5.0-performance-benchmarking-with-tpcc.md | 135 ++ ...v5.1-performance-benchmarking-with-tpcc.md | 87 + ...v5.2-performance-benchmarking-with-tpcc.md | 87 + ...v5.3-performance-benchmarking-with-tpcc.md | 123 ++ ...v5.4-performance-benchmarking-with-tpcc.md | 123 ++ ...v5.4-performance-benchmarking-with-tpch.md | 117 ++ ...v6.0-performance-benchmarking-with-tpcc.md | 119 ++ ...v6.0-performance-benchmarking-with-tpch.md | 8 + ...v6.1-performance-benchmarking-with-tpcc.md | 116 ++ ...v6.1-performance-benchmarking-with-tpch.md | 8 + ...v6.2-performance-benchmarking-with-tpcc.md | 116 ++ ...v6.2-performance-benchmarking-with-tpch.md | 8 + .../best-practices/haproxy-best-practices.md | 233 +++ .../best-practices/java-app-best-practices.md | 326 ++++ .../master/character-set-and-collation.md | 567 +++++++ .../zh/tidb/master/column-pruning.md | 19 + ...command-line-flags-for-pd-configuration.md | 114 ++ ...mmand-line-flags-for-tidb-configuration.md | 235 +++ ...mmand-line-flags-for-tikv-configuration.md | 99 ++ .../zh/tidb/master/configure-time-zone.md | 94 ++ markdown-pages/zh/tidb/master/constraints.md | 449 +++++ .../zh/tidb/master/control-execution-plan.md | 15 + .../zh/tidb/master/coprocessor-cache.md | 61 + .../tidb/master/dashboard/dashboard-access.md | 68 + .../dashboard/dashboard-diagnostics-access.md | 62 + .../dashboard/dashboard-diagnostics-report.md | 369 ++++ .../dashboard/dashboard-diagnostics-usage.md | 115 ++ .../zh/tidb/master/dashboard/dashboard-faq.md | 152 ++ .../tidb/master/dashboard/dashboard-intro.md | 73 + .../dashboard/dashboard-key-visualizer.md | 177 ++ .../master/dashboard/dashboard-ops-deploy.md | 133 ++ .../dashboard/dashboard-ops-reverse-proxy.md | 274 +++ .../dashboard/dashboard-ops-security.md | 102 ++ .../master/dashboard/dashboard-overview.md | 95 ++ .../zh/tidb/master/data-type-date-and-time.md | 311 ++++ .../tidb/master/data-type-default-values.md | 66 + .../zh/tidb/master/data-type-json.md | 103 ++ .../zh/tidb/master/data-type-numeric.md | 183 ++ .../zh/tidb/master/data-type-overview.md | 16 + .../zh/tidb/master/data-type-string.md | 179 ++ .../tidb/master/deploy-monitoring-services.md | 261 +++ .../develop/dev-guide-playground-gitpod.md | 168 ++ .../develop/dev-guide-third-party-support.md | 192 +++ .../dm/deploy-a-dm-cluster-using-binary.md | 200 +++ markdown-pages/zh/tidb/master/dm/dm-arch.md | 48 + .../zh/tidb/master/dm/dm-config-overview.md | 35 + .../zh/tidb/master/dm/dm-ddl-compatible.md | 143 ++ markdown-pages/zh/tidb/master/dm/dm-faq.md | 374 ++++ .../master/dm/dm-master-configuration-file.md | 61 + .../zh/tidb/master/dm/dm-release-notes.md | 37 + .../master/dm/dm-source-configuration-file.md | 111 ++ .../master/dm/dm-task-configuration-guide.md | 235 +++ .../master/dm/dm-worker-configuration-file.md | 55 + .../zh/tidb/master/dm/dm-worker-intro.md | 97 ++ .../master/dm/feature-expression-filter.md | 12 + .../zh/tidb/master/dm/feature-online-ddl.md | 221 +++ .../zh/tidb/master/dm/feature-shard-merge.md | 36 + .../manually-handling-sharding-ddl-locks.md | 380 +++++ .../tidb/master/dm/migrate-data-using-dm.md | 180 ++ .../master/dm/task-configuration-file-full.md | 275 +++ .../tidb/master/download-ecosystem-tools.md | 53 + .../tidb/master/ecosystem-tool-user-guide.md | 147 ++ .../enable-tls-between-clients-and-servers.md | 183 ++ markdown-pages/zh/tidb/master/error-codes.md | 551 ++++++ markdown-pages/zh/tidb/master/faq/tidb-faq.md | 119 ++ .../aggregate-group-by-functions.md | 169 ++ .../bit-functions-and-operators.md | 21 + .../cast-functions-and-operators.md | 21 + .../control-flow-functions.md | 16 + .../date-and-time-functions.md | 102 ++ .../encryption-and-compression-functions.md | 35 + .../functions-and-operators-overview.md | 13 + .../information-functions.md | 40 + .../functions-and-operators/json-functions.md | 78 + .../miscellaneous-functions.md | 37 + .../numeric-functions-and-operators.md | 56 + .../functions-and-operators/operators.md | 135 ++ .../functions-and-operators/precision-math.md | 163 ++ .../string-functions.md | 1500 +++++++++++++++++ ...ype-conversion-in-expression-evaluation.md | 9 + .../window-functions.md | 27 + .../garbage-collection-configuration.md | 87 + .../master/garbage-collection-overview.md | 54 + .../generate-self-signed-certificates.md | 155 ++ .../zh/tidb/master/generated-columns.md | 148 ++ .../master/get-started-with-tidb-lightning.md | 116 ++ .../tidb/master/grafana-overview-dashboard.md | 87 + .../zh/tidb/master/grafana-pd-dashboard.md | 156 ++ .../hardware-and-software-requirements.md | 208 +++ .../tidb/master/identify-expensive-queries.md | 53 + .../information-schema/information-schema.md | 103 ++ markdown-pages/zh/tidb/master/join-reorder.md | 52 + .../tidb/master/maintain-tidb-using-tiup.md | 234 +++ .../zh/tidb/master/max-min-eliminate.md | 108 ++ markdown-pages/zh/tidb/master/overview.md | 72 + .../zh/tidb/master/pd-configuration-file.md | 519 ++++++ markdown-pages/zh/tidb/master/pd-recover.md | 164 ++ .../zh/tidb/master/predicate-push-down.md | 151 ++ .../zh/tidb/master/privilege-management.md | 524 ++++++ .../zh/tidb/master/read-historical-data.md | 205 +++ .../tidb/master/role-based-access-control.md | 351 ++++ .../zh/tidb/master/scale-tidb-using-tiup.md | 488 ++++++ .../schedule-replicas-by-topology-labels.md | 245 +++ .../tidb/master/sql-logical-optimization.md | 20 + markdown-pages/zh/tidb/master/sql-mode.md | 58 + .../tidb/master/sql-optimization-concepts.md | 17 + .../tidb/master/sql-physical-optimization.md | 17 + .../zh/tidb/master/sql-prepared-plan-cache.md | 316 ++++ .../sql-statement-admin-show-telemetry.md | 430 +++++ .../sql-statements/sql-statement-admin.md | 219 +++ .../sql-statement-flashback-table.md | 93 + .../sql-statement-recover-table.md | 114 ++ .../sql-statement-split-region.md | 400 +++++ .../zh/tidb/master/sql-tuning-overview.md | 17 + .../tidb/master/statement-summary-tables.md | 367 ++++ .../master/storage-engine/rocksdb-overview.md | 59 + .../storage-engine/titan-configuration.md | 195 +++ .../master/storage-engine/titan-overview.md | 147 ++ .../master/sync-diff-inspector/route-diff.md | 196 +++ .../master/sync-diff-inspector/shard-diff.md | 147 ++ .../sync-diff-inspector-overview.md | 301 ++++ .../zh/tidb/master/ticdc/ticdc-overview.md | 87 + .../ticdc/ticdc-upstream-downstream-check.md | 104 ++ ...ional-replication-between-tidb-clusters.md | 121 ++ .../tidb-binlog/binlog-consumer-client.md | 148 ++ .../master/tidb-binlog/deploy-tidb-binlog.md | 360 ++++ .../get-started-with-tidb-binlog.md | 463 +++++ .../tidb-binlog/handle-tidb-binlog-errors.md | 46 + .../maintain-tidb-binlog-cluster.md | 124 ++ .../monitor-tidb-binlog-cluster.md | 165 ++ .../tidb-binlog-configuration-file.md | 349 ++++ .../master/tidb-binlog/tidb-binlog-faq.md | 237 +++ .../tidb-binlog/tidb-binlog-overview.md | 79 + .../tidb-binlog/tidb-binlog-relay-log.md | 56 + .../master/tidb-binlog/tidb-binlog-reparo.md | 105 ++ .../tidb-binlog/troubleshoot-tidb-binlog.md | 19 + .../master/tidb-binlog/upgrade-tidb-binlog.md | 72 + markdown-pages/zh/tidb/master/tidb-control.md | 342 ++++ .../zh/tidb/master/tidb-in-kubernetes.md | 12 + .../tidb-lightning/monitor-tidb-lightning.md | 243 +++ .../tidb-lightning-checkpoints.md | 109 ++ .../tidb-lightning/tidb-lightning-faq.md | 215 +++ .../zh/tidb/master/tidb-monitoring-api.md | 134 ++ .../tidb/master/tidb-monitoring-framework.md | 58 + .../zh/tidb/master/tidb-scheduling.md | 154 ++ .../tidb/master/tiflash/maintain-tiflash.md | 53 + .../zh/tidb/master/tiflash/monitor-tiflash.md | 105 ++ .../master/tiflash/tiflash-alert-rules.md | 69 + .../tiflash/tiflash-command-line-flags.md | 77 + .../master/tiflash/tiflash-configuration.md | 325 ++++ .../tidb/master/tiflash/tiflash-overview.md | 82 + .../zh/tidb/master/tikv-overview.md | 37 + .../master/tiup/tiup-command-mirror-genkey.md | 56 + .../master/tiup/tiup-component-dm-disable.md | 48 + .../master/tiup/tiup-component-dm-start.md | 46 + .../zh/tidb/master/topn-limit-push-down.md | 117 ++ .../troubleshoot-data-inconsistency-errors.md | 91 + .../zh/tidb/master/troubleshoot-stale-read.md | 237 +++ .../tidb/master/troubleshoot-tidb-cluster.md | 143 ++ .../zh/tidb/master/troubleshoot-tidb-oom.md | 198 +++ .../master/tune-tikv-memory-performance.md | 248 +++ .../zh/tidb/master/upgrade-tidb-using-tiup.md | 322 ++++ .../zh/tidb/master/user-account-management.md | 215 +++ markdown-pages/zh/tidb/master/views.md | 225 +++ 187 files changed, 29882 insertions(+) create mode 100644 markdown-pages/zh/tidb/master/agg-distinct-optimization.md create mode 100644 markdown-pages/zh/tidb/master/basic-sql-operations.md create mode 100644 markdown-pages/zh/tidb/master/benchmark/benchmark-sysbench-v2.md create mode 100644 markdown-pages/zh/tidb/master/benchmark/benchmark-sysbench-v3.md create mode 100644 markdown-pages/zh/tidb/master/benchmark/benchmark-sysbench-v4-vs-v3.md create mode 100644 markdown-pages/zh/tidb/master/benchmark/benchmark-sysbench-v5-vs-v4.md create mode 100644 markdown-pages/zh/tidb/master/benchmark/benchmark-sysbench-v5.1.0-vs-v5.0.2.md create mode 100644 markdown-pages/zh/tidb/master/benchmark/benchmark-sysbench-v5.2.0-vs-v5.1.1.md create mode 100644 markdown-pages/zh/tidb/master/benchmark/benchmark-sysbench-v5.3.0-vs-v5.2.2.md create mode 100644 markdown-pages/zh/tidb/master/benchmark/benchmark-sysbench-v5.4.0-vs-v5.3.0.md create mode 100644 markdown-pages/zh/tidb/master/benchmark/benchmark-sysbench-v6.0.0-vs-v5.4.0.md create mode 100644 markdown-pages/zh/tidb/master/benchmark/benchmark-sysbench-v6.1.0-vs-v6.0.0.md create mode 100644 markdown-pages/zh/tidb/master/benchmark/benchmark-sysbench-v6.2.0-vs-v6.1.0.md create mode 100644 markdown-pages/zh/tidb/master/benchmark/benchmark-tidb-using-sysbench.md create mode 100644 markdown-pages/zh/tidb/master/benchmark/benchmark-tidb-using-tpcc.md create mode 100644 markdown-pages/zh/tidb/master/benchmark/benchmark-tpch.md create mode 100644 markdown-pages/zh/tidb/master/benchmark/online-workloads-and-add-index-operations.md create mode 100644 markdown-pages/zh/tidb/master/benchmark/v3.0-performance-benchmarking-with-sysbench.md create mode 100644 markdown-pages/zh/tidb/master/benchmark/v3.0-performance-benchmarking-with-tpcc.md create mode 100644 markdown-pages/zh/tidb/master/benchmark/v4.0-performance-benchmarking-with-tpcc.md create mode 100644 markdown-pages/zh/tidb/master/benchmark/v4.0-performance-benchmarking-with-tpch.md create mode 100644 markdown-pages/zh/tidb/master/benchmark/v5.0-performance-benchmarking-with-tpcc.md create mode 100644 markdown-pages/zh/tidb/master/benchmark/v5.1-performance-benchmarking-with-tpcc.md create mode 100644 markdown-pages/zh/tidb/master/benchmark/v5.2-performance-benchmarking-with-tpcc.md create mode 100644 markdown-pages/zh/tidb/master/benchmark/v5.3-performance-benchmarking-with-tpcc.md create mode 100644 markdown-pages/zh/tidb/master/benchmark/v5.4-performance-benchmarking-with-tpcc.md create mode 100644 markdown-pages/zh/tidb/master/benchmark/v5.4-performance-benchmarking-with-tpch.md create mode 100644 markdown-pages/zh/tidb/master/benchmark/v6.0-performance-benchmarking-with-tpcc.md create mode 100644 markdown-pages/zh/tidb/master/benchmark/v6.0-performance-benchmarking-with-tpch.md create mode 100644 markdown-pages/zh/tidb/master/benchmark/v6.1-performance-benchmarking-with-tpcc.md create mode 100644 markdown-pages/zh/tidb/master/benchmark/v6.1-performance-benchmarking-with-tpch.md create mode 100644 markdown-pages/zh/tidb/master/benchmark/v6.2-performance-benchmarking-with-tpcc.md create mode 100644 markdown-pages/zh/tidb/master/benchmark/v6.2-performance-benchmarking-with-tpch.md create mode 100644 markdown-pages/zh/tidb/master/best-practices/haproxy-best-practices.md create mode 100644 markdown-pages/zh/tidb/master/best-practices/java-app-best-practices.md create mode 100644 markdown-pages/zh/tidb/master/character-set-and-collation.md create mode 100644 markdown-pages/zh/tidb/master/column-pruning.md create mode 100644 markdown-pages/zh/tidb/master/command-line-flags-for-pd-configuration.md create mode 100644 markdown-pages/zh/tidb/master/command-line-flags-for-tidb-configuration.md create mode 100644 markdown-pages/zh/tidb/master/command-line-flags-for-tikv-configuration.md create mode 100644 markdown-pages/zh/tidb/master/configure-time-zone.md create mode 100644 markdown-pages/zh/tidb/master/constraints.md create mode 100644 markdown-pages/zh/tidb/master/control-execution-plan.md create mode 100644 markdown-pages/zh/tidb/master/coprocessor-cache.md create mode 100644 markdown-pages/zh/tidb/master/dashboard/dashboard-access.md create mode 100644 markdown-pages/zh/tidb/master/dashboard/dashboard-diagnostics-access.md create mode 100644 markdown-pages/zh/tidb/master/dashboard/dashboard-diagnostics-report.md create mode 100644 markdown-pages/zh/tidb/master/dashboard/dashboard-diagnostics-usage.md create mode 100644 markdown-pages/zh/tidb/master/dashboard/dashboard-faq.md create mode 100644 markdown-pages/zh/tidb/master/dashboard/dashboard-intro.md create mode 100644 markdown-pages/zh/tidb/master/dashboard/dashboard-key-visualizer.md create mode 100644 markdown-pages/zh/tidb/master/dashboard/dashboard-ops-deploy.md create mode 100644 markdown-pages/zh/tidb/master/dashboard/dashboard-ops-reverse-proxy.md create mode 100644 markdown-pages/zh/tidb/master/dashboard/dashboard-ops-security.md create mode 100644 markdown-pages/zh/tidb/master/dashboard/dashboard-overview.md create mode 100644 markdown-pages/zh/tidb/master/data-type-date-and-time.md create mode 100644 markdown-pages/zh/tidb/master/data-type-default-values.md create mode 100644 markdown-pages/zh/tidb/master/data-type-json.md create mode 100644 markdown-pages/zh/tidb/master/data-type-numeric.md create mode 100644 markdown-pages/zh/tidb/master/data-type-overview.md create mode 100644 markdown-pages/zh/tidb/master/data-type-string.md create mode 100644 markdown-pages/zh/tidb/master/deploy-monitoring-services.md create mode 100644 markdown-pages/zh/tidb/master/develop/dev-guide-playground-gitpod.md create mode 100644 markdown-pages/zh/tidb/master/develop/dev-guide-third-party-support.md create mode 100644 markdown-pages/zh/tidb/master/dm/deploy-a-dm-cluster-using-binary.md create mode 100644 markdown-pages/zh/tidb/master/dm/dm-arch.md create mode 100644 markdown-pages/zh/tidb/master/dm/dm-config-overview.md create mode 100644 markdown-pages/zh/tidb/master/dm/dm-ddl-compatible.md create mode 100644 markdown-pages/zh/tidb/master/dm/dm-faq.md create mode 100644 markdown-pages/zh/tidb/master/dm/dm-master-configuration-file.md create mode 100644 markdown-pages/zh/tidb/master/dm/dm-release-notes.md create mode 100644 markdown-pages/zh/tidb/master/dm/dm-source-configuration-file.md create mode 100644 markdown-pages/zh/tidb/master/dm/dm-task-configuration-guide.md create mode 100644 markdown-pages/zh/tidb/master/dm/dm-worker-configuration-file.md create mode 100644 markdown-pages/zh/tidb/master/dm/dm-worker-intro.md create mode 100644 markdown-pages/zh/tidb/master/dm/feature-expression-filter.md create mode 100644 markdown-pages/zh/tidb/master/dm/feature-online-ddl.md create mode 100644 markdown-pages/zh/tidb/master/dm/feature-shard-merge.md create mode 100644 markdown-pages/zh/tidb/master/dm/manually-handling-sharding-ddl-locks.md create mode 100644 markdown-pages/zh/tidb/master/dm/migrate-data-using-dm.md create mode 100644 markdown-pages/zh/tidb/master/dm/task-configuration-file-full.md create mode 100644 markdown-pages/zh/tidb/master/download-ecosystem-tools.md create mode 100644 markdown-pages/zh/tidb/master/ecosystem-tool-user-guide.md create mode 100644 markdown-pages/zh/tidb/master/enable-tls-between-clients-and-servers.md create mode 100644 markdown-pages/zh/tidb/master/error-codes.md create mode 100644 markdown-pages/zh/tidb/master/faq/tidb-faq.md create mode 100644 markdown-pages/zh/tidb/master/functions-and-operators/aggregate-group-by-functions.md create mode 100644 markdown-pages/zh/tidb/master/functions-and-operators/bit-functions-and-operators.md create mode 100644 markdown-pages/zh/tidb/master/functions-and-operators/cast-functions-and-operators.md create mode 100644 markdown-pages/zh/tidb/master/functions-and-operators/control-flow-functions.md create mode 100644 markdown-pages/zh/tidb/master/functions-and-operators/date-and-time-functions.md create mode 100644 markdown-pages/zh/tidb/master/functions-and-operators/encryption-and-compression-functions.md create mode 100644 markdown-pages/zh/tidb/master/functions-and-operators/functions-and-operators-overview.md create mode 100644 markdown-pages/zh/tidb/master/functions-and-operators/information-functions.md create mode 100644 markdown-pages/zh/tidb/master/functions-and-operators/json-functions.md create mode 100644 markdown-pages/zh/tidb/master/functions-and-operators/miscellaneous-functions.md create mode 100644 markdown-pages/zh/tidb/master/functions-and-operators/numeric-functions-and-operators.md create mode 100644 markdown-pages/zh/tidb/master/functions-and-operators/operators.md create mode 100644 markdown-pages/zh/tidb/master/functions-and-operators/precision-math.md create mode 100644 markdown-pages/zh/tidb/master/functions-and-operators/string-functions.md create mode 100644 markdown-pages/zh/tidb/master/functions-and-operators/type-conversion-in-expression-evaluation.md create mode 100644 markdown-pages/zh/tidb/master/functions-and-operators/window-functions.md create mode 100644 markdown-pages/zh/tidb/master/garbage-collection-configuration.md create mode 100644 markdown-pages/zh/tidb/master/garbage-collection-overview.md create mode 100644 markdown-pages/zh/tidb/master/generate-self-signed-certificates.md create mode 100644 markdown-pages/zh/tidb/master/generated-columns.md create mode 100644 markdown-pages/zh/tidb/master/get-started-with-tidb-lightning.md create mode 100644 markdown-pages/zh/tidb/master/grafana-overview-dashboard.md create mode 100644 markdown-pages/zh/tidb/master/grafana-pd-dashboard.md create mode 100644 markdown-pages/zh/tidb/master/hardware-and-software-requirements.md create mode 100644 markdown-pages/zh/tidb/master/identify-expensive-queries.md create mode 100644 markdown-pages/zh/tidb/master/information-schema/information-schema.md create mode 100644 markdown-pages/zh/tidb/master/join-reorder.md create mode 100644 markdown-pages/zh/tidb/master/maintain-tidb-using-tiup.md create mode 100644 markdown-pages/zh/tidb/master/max-min-eliminate.md create mode 100644 markdown-pages/zh/tidb/master/overview.md create mode 100644 markdown-pages/zh/tidb/master/pd-configuration-file.md create mode 100644 markdown-pages/zh/tidb/master/pd-recover.md create mode 100644 markdown-pages/zh/tidb/master/predicate-push-down.md create mode 100644 markdown-pages/zh/tidb/master/privilege-management.md create mode 100644 markdown-pages/zh/tidb/master/read-historical-data.md create mode 100644 markdown-pages/zh/tidb/master/role-based-access-control.md create mode 100644 markdown-pages/zh/tidb/master/scale-tidb-using-tiup.md create mode 100644 markdown-pages/zh/tidb/master/schedule-replicas-by-topology-labels.md create mode 100644 markdown-pages/zh/tidb/master/sql-logical-optimization.md create mode 100644 markdown-pages/zh/tidb/master/sql-mode.md create mode 100644 markdown-pages/zh/tidb/master/sql-optimization-concepts.md create mode 100644 markdown-pages/zh/tidb/master/sql-physical-optimization.md create mode 100644 markdown-pages/zh/tidb/master/sql-prepared-plan-cache.md create mode 100644 markdown-pages/zh/tidb/master/sql-statements/sql-statement-admin-show-telemetry.md create mode 100644 markdown-pages/zh/tidb/master/sql-statements/sql-statement-admin.md create mode 100644 markdown-pages/zh/tidb/master/sql-statements/sql-statement-flashback-table.md create mode 100644 markdown-pages/zh/tidb/master/sql-statements/sql-statement-recover-table.md create mode 100644 markdown-pages/zh/tidb/master/sql-statements/sql-statement-split-region.md create mode 100644 markdown-pages/zh/tidb/master/sql-tuning-overview.md create mode 100644 markdown-pages/zh/tidb/master/statement-summary-tables.md create mode 100644 markdown-pages/zh/tidb/master/storage-engine/rocksdb-overview.md create mode 100644 markdown-pages/zh/tidb/master/storage-engine/titan-configuration.md create mode 100644 markdown-pages/zh/tidb/master/storage-engine/titan-overview.md create mode 100644 markdown-pages/zh/tidb/master/sync-diff-inspector/route-diff.md create mode 100644 markdown-pages/zh/tidb/master/sync-diff-inspector/shard-diff.md create mode 100644 markdown-pages/zh/tidb/master/sync-diff-inspector/sync-diff-inspector-overview.md create mode 100644 markdown-pages/zh/tidb/master/ticdc/ticdc-overview.md create mode 100644 markdown-pages/zh/tidb/master/ticdc/ticdc-upstream-downstream-check.md create mode 100644 markdown-pages/zh/tidb/master/tidb-binlog/bidirectional-replication-between-tidb-clusters.md create mode 100644 markdown-pages/zh/tidb/master/tidb-binlog/binlog-consumer-client.md create mode 100644 markdown-pages/zh/tidb/master/tidb-binlog/deploy-tidb-binlog.md create mode 100644 markdown-pages/zh/tidb/master/tidb-binlog/get-started-with-tidb-binlog.md create mode 100644 markdown-pages/zh/tidb/master/tidb-binlog/handle-tidb-binlog-errors.md create mode 100644 markdown-pages/zh/tidb/master/tidb-binlog/maintain-tidb-binlog-cluster.md create mode 100644 markdown-pages/zh/tidb/master/tidb-binlog/monitor-tidb-binlog-cluster.md create mode 100644 markdown-pages/zh/tidb/master/tidb-binlog/tidb-binlog-configuration-file.md create mode 100644 markdown-pages/zh/tidb/master/tidb-binlog/tidb-binlog-faq.md create mode 100644 markdown-pages/zh/tidb/master/tidb-binlog/tidb-binlog-overview.md create mode 100644 markdown-pages/zh/tidb/master/tidb-binlog/tidb-binlog-relay-log.md create mode 100644 markdown-pages/zh/tidb/master/tidb-binlog/tidb-binlog-reparo.md create mode 100644 markdown-pages/zh/tidb/master/tidb-binlog/troubleshoot-tidb-binlog.md create mode 100644 markdown-pages/zh/tidb/master/tidb-binlog/upgrade-tidb-binlog.md create mode 100644 markdown-pages/zh/tidb/master/tidb-control.md create mode 100644 markdown-pages/zh/tidb/master/tidb-in-kubernetes.md create mode 100644 markdown-pages/zh/tidb/master/tidb-lightning/monitor-tidb-lightning.md create mode 100644 markdown-pages/zh/tidb/master/tidb-lightning/tidb-lightning-checkpoints.md create mode 100644 markdown-pages/zh/tidb/master/tidb-lightning/tidb-lightning-faq.md create mode 100644 markdown-pages/zh/tidb/master/tidb-monitoring-api.md create mode 100644 markdown-pages/zh/tidb/master/tidb-monitoring-framework.md create mode 100644 markdown-pages/zh/tidb/master/tidb-scheduling.md create mode 100644 markdown-pages/zh/tidb/master/tiflash/maintain-tiflash.md create mode 100644 markdown-pages/zh/tidb/master/tiflash/monitor-tiflash.md create mode 100644 markdown-pages/zh/tidb/master/tiflash/tiflash-alert-rules.md create mode 100644 markdown-pages/zh/tidb/master/tiflash/tiflash-command-line-flags.md create mode 100644 markdown-pages/zh/tidb/master/tiflash/tiflash-configuration.md create mode 100644 markdown-pages/zh/tidb/master/tiflash/tiflash-overview.md create mode 100644 markdown-pages/zh/tidb/master/tikv-overview.md create mode 100644 markdown-pages/zh/tidb/master/tiup/tiup-command-mirror-genkey.md create mode 100644 markdown-pages/zh/tidb/master/tiup/tiup-component-dm-disable.md create mode 100644 markdown-pages/zh/tidb/master/tiup/tiup-component-dm-start.md create mode 100644 markdown-pages/zh/tidb/master/topn-limit-push-down.md create mode 100644 markdown-pages/zh/tidb/master/troubleshoot-data-inconsistency-errors.md create mode 100644 markdown-pages/zh/tidb/master/troubleshoot-stale-read.md create mode 100644 markdown-pages/zh/tidb/master/troubleshoot-tidb-cluster.md create mode 100644 markdown-pages/zh/tidb/master/troubleshoot-tidb-oom.md create mode 100644 markdown-pages/zh/tidb/master/tune-tikv-memory-performance.md create mode 100644 markdown-pages/zh/tidb/master/upgrade-tidb-using-tiup.md create mode 100644 markdown-pages/zh/tidb/master/user-account-management.md create mode 100644 markdown-pages/zh/tidb/master/views.md diff --git a/markdown-pages/zh/tidb/master/_docHome.md b/markdown-pages/zh/tidb/master/_docHome.md index c2bba79..dd3617b 100644 --- a/markdown-pages/zh/tidb/master/_docHome.md +++ b/markdown-pages/zh/tidb/master/_docHome.md @@ -3,6 +3,7 @@ title: PingCAP 文档中心 hide_sidebar: true hide_commit: true hide_leftNav: true +summary: PingCAP 文档中心为您提供丰富的操作指南和参考资料,助您轻松上手 TiDB 产品,完成数据迁移和应用开发等操作。TiDB 是一款开源分布式关系型数据库,支持在线事务处理与在线分析处理,具备水平扩容、高可用、云原生、兼容 MySQL 协议等特性。TiDB Cloud 是全托管的数据库即服务产品,让数据库部署、运维和性能调优变得轻松简单,适用于中国出海企业和开发者。此外,还提供开发者手册、免费课程、TiDB 社区、TiDB 博客等资源,欢迎贡献内容。 --- diff --git a/markdown-pages/zh/tidb/master/_index.md b/markdown-pages/zh/tidb/master/_index.md index c616e86..7995570 100644 --- a/markdown-pages/zh/tidb/master/_index.md +++ b/markdown-pages/zh/tidb/master/_index.md @@ -3,6 +3,7 @@ title: TiDB 产品文档 aliases: ['/docs-cn/dev/','/docs-cn/','/docs-cn/stable/'] hide_sidebar: true hide_commit: true +summary: TiDB 是 PingCAP 公司自主设计、研发的开源分布式关系型数据库。产品文档包括了 TiDB 简介、功能概览、TiFlash、快速上手 TiDB、HTAP、开发者手册概览、软硬件环境需求、使用 TiUP 部署 TiDB、数据迁移概览、运维、监控、调优、工具、TiDB 路线图、配置文件参数、命令行参数、TiDB Control、系统变量、发布历史、常见问题。 --- diff --git a/markdown-pages/zh/tidb/master/agg-distinct-optimization.md b/markdown-pages/zh/tidb/master/agg-distinct-optimization.md new file mode 100644 index 0000000..9117474 --- /dev/null +++ b/markdown-pages/zh/tidb/master/agg-distinct-optimization.md @@ -0,0 +1,57 @@ +--- +title: Distinct 优化 +aliases: ['/docs-cn/dev/agg-distinct-optimization/'] +summary: 本文介绍了对于 DISTINCT 的优化,包括简单 DISTINCT 和聚合函数 DISTINCT 的优化。简单的 DISTINCT 通常会被优化成 GROUP BY 来执行。而带有 DISTINCT 的聚合函数会在 TiDB 侧单线程执行,可以通过系统变量或 TiDB 配置项控制优化器是否执行。在优化后,DISTINCT 被下推到了 Coprocessor,在 HashAgg 里新增了一个 group by 列。 +--- + +# Distinct 优化 + +本文档介绍可用于 `DISTINCT` 的优化,包括简单 `DISTINCT` 和聚合函数 `DISTINCT` 的优化。 + +## 简单 DISTINCT + +通常简单的 `DISTINCT` 会被优化成 GROUP BY 来执行。例如: + +```sql +mysql> explain select DISTINCT a from t; ++--------------------------+---------+-----------+---------------+-------------------------------------------------------+ +| id | estRows | task | access object | operator info | ++--------------------------+---------+-----------+---------------+-------------------------------------------------------+ +| HashAgg_6 | 2.40 | root | | group by:test.t.a, funcs:firstrow(test.t.a)->test.t.a | +| └─TableReader_11 | 3.00 | root | | data:TableFullScan_10 | +| └─TableFullScan_10 | 3.00 | cop[tikv] | table:t | keep order:false, stats:pseudo | ++--------------------------+---------+-----------+---------------+-------------------------------------------------------+ +3 rows in set (0.00 sec) +``` + +## 聚合函数 DISTINCT + +通常来说,带有 `DISTINCT` 的聚合函数会单线程的在 TiDB 侧执行。使用系统变量 [`tidb_opt_distinct_agg_push_down`](/system-variables.md#tidb_opt_distinct_agg_push_down) 或者 TiDB 的配置项 [distinct-agg-push-down](/tidb-configuration-file.md#distinct-agg-push-down) 控制优化器是否执行带有 `DISTINCT` 的聚合函数(比如 `select count(distinct a) from t`)下推到 Coprocessor 的优化操作。 + +在以下示例中,`tidb_opt_distinct_agg_push_down` 开启前,TiDB 需要从 TiKV 读取所有数据,并在 TiDB 侧执行 `disctinct`。`tidb_opt_distinct_agg_push_down` 开启后,`distinct a` 被下推到了 Coprocessor,在 `HashAgg_5` 里新增了一个 `group by` 列 `test.t.a`。 + +```sql +mysql> desc select count(distinct a) from test.t; ++-------------------------+----------+-----------+---------------+------------------------------------------+ +| id | estRows | task | access object | operator info | ++-------------------------+----------+-----------+---------------+------------------------------------------+ +| StreamAgg_6 | 1.00 | root | | funcs:count(distinct test.t.a)->Column#4 | +| └─TableReader_10 | 10000.00 | root | | data:TableFullScan_9 | +| └─TableFullScan_9 | 10000.00 | cop[tikv] | table:t | keep order:false, stats:pseudo | ++-------------------------+----------+-----------+---------------+------------------------------------------+ +3 rows in set (0.01 sec) + +mysql> set session tidb_opt_distinct_agg_push_down = 1; +Query OK, 0 rows affected (0.00 sec) + +mysql> desc select count(distinct a) from test.t; ++---------------------------+----------+-----------+---------------+------------------------------------------+ +| id | estRows | task | access object | operator info | ++---------------------------+----------+-----------+---------------+------------------------------------------+ +| HashAgg_8 | 1.00 | root | | funcs:count(distinct test.t.a)->Column#3 | +| └─TableReader_9 | 1.00 | root | | data:HashAgg_5 | +| └─HashAgg_5 | 1.00 | cop[tikv] | | group by:test.t.a, | +| └─TableFullScan_7 | 10000.00 | cop[tikv] | table:t | keep order:false, stats:pseudo | ++---------------------------+----------+-----------+---------------+------------------------------------------+ +4 rows in set (0.00 sec) +``` diff --git a/markdown-pages/zh/tidb/master/basic-sql-operations.md b/markdown-pages/zh/tidb/master/basic-sql-operations.md new file mode 100644 index 0000000..ade90a3 --- /dev/null +++ b/markdown-pages/zh/tidb/master/basic-sql-operations.md @@ -0,0 +1,230 @@ +--- +title: SQL 基本操作 +aliases: ['/docs-cn/dev/basic-sql-operations/','/docs-cn/dev/how-to/get-started/explore-sql/'] +summary: TiDB 是一个兼容 MySQL 的数据库,可以执行 DDL、DML、DQL 和 DCL 操作。可以使用 SHOW DATABASES 查看数据库列表,使用 CREATE DATABASE 创建数据库,使用 DROP DATABASE 删除数据库。使用 CREATE TABLE 创建表,使用 SHOW CREATE TABLE 查看建表语句,使用 DROP TABLE 删除表。使用 CREATE INDEX 创建索引,使用 SHOW INDEX 查看表内所有索引,使用 DROP INDEX 删除索引。使用 INSERT 向表内插入记录,使用 UPDATE 修改记录,使用 DELETE 删除记录。使用 SELECT 检索表内数据,使用 WHERE 子句进行筛选。使用 CREATE USER 创建用户,使用 GRANT 授权用户,使用 DROP USER 删除用户。 +--- + +# SQL 基本操作 + +成功部署 TiDB 集群之后,便可以在 TiDB 中执行 SQL 语句了。因为 TiDB 兼容 MySQL,你可以使用 MySQL 客户端连接 TiDB,并且[大多数情况下](/mysql-compatibility.md)可以直接执行 MySQL 语句。 + +SQL 是一门声明性语言,它是数据库用户与数据库交互的方式。它更像是一种自然语言,好像在用英语与数据库进行对话。本文档介绍基本的 SQL 操作。完整的 SQL 语句列表,参见 [TiDB SQL 语法详解](https://pingcap.github.io/sqlgram/)。 + +## 分类 + +SQL 语言通常按照功能划分成以下的 4 个部分: + +- DDL (Data Definition Language):数据定义语言,用来定义数据库对象,包括库、表、视图和索引等。 + +- DML (Data Manipulation Language):数据操作语言,用来操作和业务相关的记录。 + +- DQL (Data Query Language):数据查询语言,用来查询经过条件筛选的记录。 + +- DCL (Data Control Language):数据控制语言,用来定义访问权限和安全级别。 + +常用的 DDL 功能是对象(如表、索引等)的创建、属性修改和删除,对应的命令分别是 CREATE、ALTER 和 DROP。 + +## 查看、创建和删除数据库 + +TiDB 语境中的 Database 或者说数据库,可以认为是表和索引等对象的集合。 + +使用 `SHOW DATABASES` 语句查看系统中数据库列表: + +```sql +SHOW DATABASES; +``` + +使用名为 `mysql` 的数据库: + +```sql +USE mysql; +``` + +使用 `SHOW TABLES` 语句查看数据库中的所有表。例如: + +```sql +SHOW TABLES FROM mysql; +``` + +使用 `CREATE DATABASE` 语句创建数据库。语法如下: + +```sql +CREATE DATABASE db_name [options]; +``` + +例如,要创建一个名为 `samp_db` 的数据库,可使用以下语句: + +```sql +CREATE DATABASE IF NOT EXISTS samp_db; +``` + +添加 `IF NOT EXISTS` 可防止发生错误。 + +使用 `DROP DATABASE` 语句删除数据库。例如: + +```sql +DROP DATABASE samp_db; +``` + +## 创建、查看和删除表 + +使用 `CREATE TABLE` 语句创建表。语法如下: + +```sql +CREATE TABLE table_name column_name data_type constraint; +``` + +例如,要创建一个名为 `person` 的表,包括编号、名字、生日等字段,可使用以下语句: + +```sql +CREATE TABLE person ( + id INT(11), + name VARCHAR(255), + birthday DATE + ); +``` + +使用 `SHOW CREATE` 语句查看建表语句,即 DDL。例如: + +```sql +SHOW CREATE TABLE person; +``` + +使用 `DROP TABLE` 语句删除表。例如: + +```sql +DROP TABLE person; +``` + +## 创建、查看和删除索引 + +索引通常用于加速索引列上的查询。对于值不唯一的列,可使用 `CREATE INDEX` 或 `ALTER TABLE` 语句创建普通索引。例如: + +```sql +CREATE INDEX person_id ON person (id); +``` + +或者: + +```sql +ALTER TABLE person ADD INDEX person_id (id); +``` + +对于值唯一的列,可以创建唯一索引。例如: + +```sql +CREATE UNIQUE INDEX person_unique_id ON person (id); +``` + +或者: + +```sql +ALTER TABLE person ADD UNIQUE person_unique_id (id); +``` + +使用 `SHOW INDEX` 语句查看表内所有索引: + +```sql +SHOW INDEX FROM person; +``` + +使用 `ALTER TABLE` 或 `DROP INDEX` 语句来删除索引。与 `CREATE INDEX` 语句类似,`DROP INDEX` 也可以嵌入 `ALTER TABLE` 语句。例如: + +```sql +DROP INDEX person_id ON person; +``` + +```sql +ALTER TABLE person DROP INDEX person_unique_id; +``` + +注意:DDL 操作不是事务,在执行 DDL 时,不需要对应 COMMIT 语句。 + +常用的 DML 功能是对表记录的新增、修改和删除,对应的命令分别是 INSERT、UPDATE 和 DELETE。 + +## 记录的增删改 + +使用 `INSERT` 语句向表内插入表记录。例如: + +```sql +INSERT INTO person VALUES(1,'tom','20170912'); +``` + +使用 `INSERT` 语句向表内插入包含部分字段数据的表记录。例如: + +```sql +INSERT INTO person(id,name) VALUES('2','bob'); +``` + +使用 `UPDATE` 语句向表内修改表记录的部分字段数据。例如: + +```sql +UPDATE person SET birthday='20180808' WHERE id=2; +``` + +使用 `DELETE` 语句向表内删除部分表记录。例如: + +```sql +DELETE FROM person WHERE id=2; +``` + +注意:UPDATE 和 DELETE 操作如果不带 WHERE 过滤条件是对全表进行操作。 + +DQL 数据查询语言是从一个表或多个表中检索出想要的数据行,通常是业务开发的核心内容。 + +## 查询数据 + +使用 `SELECT` 语句检索表内数据。例如: + +```sql +SELECT * FROM person; +``` + +在 SELECT 后面加上要查询的列名。例如: + +```sql +SELECT name FROM person; +``` + +```sql ++------+ +| name | ++------+ +| tom | ++------+ +1 rows in set (0.00 sec) +``` + +使用 WHERE 子句,对所有记录进行是否符合条件的筛选后再返回。例如: + +```sql +SELECT * FROM person WHERE id<5; +``` + +常用的 DCL 功能是创建或删除用户,和对用户权限的管理。 + +## 创建、授权和删除用户 + +使用 `CREATE USER` 语句创建一个用户 `tiuser`,密码为 `123456`: + +```sql +CREATE USER 'tiuser'@'localhost' IDENTIFIED BY '123456'; +``` + +授权用户 `tiuser` 可检索数据库 `samp_db` 内的表: + +```sql +GRANT SELECT ON samp_db.* TO 'tiuser'@'localhost'; +``` + +查询用户 `tiuser` 的权限: + +```sql +SHOW GRANTS for tiuser@localhost; +``` + +删除用户 `tiuser`: + +```sql +DROP USER 'tiuser'@'localhost'; +``` diff --git a/markdown-pages/zh/tidb/master/benchmark/benchmark-sysbench-v2.md b/markdown-pages/zh/tidb/master/benchmark/benchmark-sysbench-v2.md new file mode 100644 index 0000000..5e8a1b8 --- /dev/null +++ b/markdown-pages/zh/tidb/master/benchmark/benchmark-sysbench-v2.md @@ -0,0 +1,130 @@ +--- +title: TiDB Sysbench 性能对比测试报告 - v2.0.0 对比 v1.0.0 +aliases: ['/docs-cn/dev/benchmark/benchmark-sysbench-v2/','/docs-cn/dev/benchmark/sysbench-v2/'] +summary: TiDB 2.0 版本和 1.0 版本在 OLTP 场景下进行性能对比测试。测试结果显示,GA 2.0 在 Select 查询性能上提升了约 10%,在 OLTP 性能上基本一致,而在 Insert 性能上略有提升。 +--- + +# TiDB Sysbench 性能对比测试报告 - v2.0.0 对比 v1.0.0 + +## 测试目的 + +对比 TiDB 2.0 版本和 1.0 版本在 OLTP 场景下的性能。 + +## 测试版本、时间、地点 + +TiDB 版本:v1.0.8 Vs v2.0.0-rc6 + +时间:2018 年 4 月 + +地点:北京 + +## 测试环境 + +IDC 机器 + +| 类别 | 名称 | +| :--------: | :---------: | +| OS | Linux (CentOS 7.3.1611) | +| CPU | 40 vCPUs, Intel(R) Xeon(R) CPU E5-2630 v4 @ 2.20GHz | +| RAM | 128GB | +| DISK | Optane 500GB SSD * 1 | + +## 测试方案 + +### TiDB 版本信息 + +### v1.0.8 + +| 组件 | GitHash | +| :--------: | :---------: | +| TiDB | 571f0bbd28a0b8155a5ee831992c986b90d21ab7 | +| TiKV | 4ef5889947019e3cb55cc744f487aa63b42540e7 | +| PD | 776bcd940b71d295a2c7ed762582bc3aff7d3c0e | + +### v2.0.0-rc6 + +| 组件 | GitHash | +| :--------: | :---------: | +| TiDB | 82d35f1b7f9047c478f4e1e82aa0002abc8107e7 | +| TiKV | 7ed4f6a91f92cad5cd5323aaebe7d9f04b77cc79 | +| PD | 2c8e7d7e33b38e457169ce5dfb2f461fced82d65 | + +### TiKV 参数配置 + +* v1.0.8 + + ``` + sync-log = false + grpc-concurrency = 8 + grpc-raft-conn-num = 24 + ``` + +* v2.0.0-rc6 + + ``` + sync-log = false + grpc-concurrency = 8 + grpc-raft-conn-num = 24 + use-delete-range: false + ``` + +### 集群拓扑 + +| 机器 IP | 部署实例 | +|--------------|------------| +| 172.16.21.1 | 1*tidb 1*pd 1*sysbench | +| 172.16.21.2 | 1*tidb 1*pd 1*sysbench | +| 172.16.21.3 | 1*tidb 1*pd 1*sysbench | +| 172.16.11.4 | 1*tikv | +| 172.16.11.5 | 1*tikv | +| 172.16.11.6 | 1*tikv | +| 172.16.11.7 | 1*tikv | +| 172.16.11.8 | 1*tikv | +| 172.16.11.9 | 1*tikv | + +## 测试结果 + +### 标准 Select 测试 + +| 版本 | table count | table size | sysbench threads |qps | latency(avg / .95) | +| :---: | :---: | :---: | :---: | :---: | :---: | +| v2.0.0-rc6 | 32 | 1000 万 | 128 * 3 | 201936 | 1.9033 ms / 5.67667 ms | +| v2.0.0-rc6 | 32 | 1000 万 | 256 * 3 | 208130 | 3.69333 ms / 8.90333 ms | +| v2.0.0-rc6 | 32 | 1000 万 | 512 * 3 | 211788 | 7.23333 ms / 15.59 ms | +| v2.0.0-rc6 | 32 | 1000 万 | 1024 * 3 | 212868 | 14.5933 ms / 43.2133 ms | +| v1.0.8 | 32 | 1000 万 | 128 * 3 | 188686 | 2.03667 ms / 5.99 ms | +| v1.0.8 | 32 | 1000 万 | 256 * 3 | 195090 |3.94 ms / 9.12 ms | +| v1.0.8 | 32 | 1000 万 | 512 * 3 | 203012 | 7.57333 ms / 15.3733 ms | +| v1.0.8 | 32 | 1000 万 | 1024 * 3 | 205932 | 14.9267 ms / 40.7633 ms | + +GA2.0 比 GA1.0 在 Select 查询性能上,最高提升了 10% 左右。 + +### 标准 OLTP 测试 + +| 版本 | table count | table size | sysbench threads | tps | qps | latency(avg / .95) | +| :---: | :---: | :---: | :---: | :---: | :---: | :---:| +| v2.0.0-rc6 | 32 | 1000 万 | 128 * 3 | 5404.22 | 108084.4 | 87.2033 ms / 110 ms | +| v2.0.0-rc6 | 32 | 1000 万 | 256 * 3 | 5578.165 | 111563.3 | 167.673 ms / 275.623 ms | +| v2.0.0-rc6 | 32 | 1000 万 | 512 * 3 | 5874.045 | 117480.9 | 315.083 ms / 674.017 ms | +| v2.0.0-rc6 | 32 | 1000 万 | 1024 * 3 | 6290.7 | 125814 | 529.183 ms / 857.007 ms | +| v1.0.8 | 32 | 1000 万 | 128 * 3 | 5523.91 | 110478 | 69.53 ms / 88.6333 ms | +| v1.0.8 | 32 | 1000 万 | 256 * 3 | 5969.43 | 119389 |128.63 ms / 162.58 ms | +| v1.0.8 | 32 | 1000 万 | 512 * 3 | 6308.93 | 126179 | 243.543 ms / 310.913 ms | +| v1.0.8 | 32 | 1000 万 | 1024 * 3 | 6444.25 | 128885 | 476.787ms / 635.143 ms | + +GA2.0 比 GA1.0 在 OLTP 性能上,性能基本一致。 + +### 标准 Insert 测试 + +| 版本 | table count | table size | sysbench threads |qps | latency(avg / .95) | +| :---: | :---: | :---: | :---: | :---: | :---: | +| v2.0.0-rc6 | 32 | 1000 万 | 128 * 3 | 31707.5 | 12.11 ms / 21.1167 ms | +| v2.0.0-rc6 | 32 | 1000 万 | 256 * 3 | 38741.2 | 19.8233 ms / 39.65 ms | +| v2.0.0-rc6 | 32 | 1000 万 | 512 * 3 | 45136.8 | 34.0267 ms / 66.84 ms | +| v2.0.0-rc6 | 32 | 1000 万 | 1024 * 3 | 48667 | 63.1167 ms / 121.08 ms | +| v1.0.8 | 32 | 1000 万 | 128 * 3 | 31125.7 | 12.3367 ms / 19.89 ms | +| v1.0.8 | 32 | 1000 万 | 256 * 3 | 36800 | 20.8667 ms / 35.3767 ms | +| v1.0.8 | 32 | 1000 万 | 512 * 3 | 44123 | 34.8067 ms / 63.32 ms | +| v1.0.8 | 32 | 1000 万 | 1024 * 3 | 48496 | 63.3333 ms / 118.92 ms | + +GA2.0 比 GA1.0 在 Insert 性能上略有提升。 diff --git a/markdown-pages/zh/tidb/master/benchmark/benchmark-sysbench-v3.md b/markdown-pages/zh/tidb/master/benchmark/benchmark-sysbench-v3.md new file mode 100644 index 0000000..f320cd9 --- /dev/null +++ b/markdown-pages/zh/tidb/master/benchmark/benchmark-sysbench-v3.md @@ -0,0 +1,143 @@ +--- +title: TiDB Sysbench 性能对比测试报告 - v2.1 对比 v2.0 +aliases: ['/docs-cn/dev/benchmark/benchmark-sysbench-v3/','/docs-cn/dev/benchmark/sysbench-v3/'] +summary: TiDB 2.1 版本在 Point Select 查询性能上提升了 50%,而在 Update Non-Index 和 Update Index 写入性能上与 2.0 版本基本一致。 +--- + +# TiDB Sysbench 性能对比测试报告 - v2.1 对比 v2.0 + +## 测试目的 + +对比 TiDB 2.1 版本和 2.0 版本在 OLTP 场景下的性能。 + +## 测试版本、时间、地点 + +TiDB 版本:v2.1.0-rc.2 vs. v2.0.6 + +时间:2018 年 9 月 + +地点:北京 + +## 测试环境 + +IDC 机器: + +| 类别 | 名称 | +| :-: | :-: | +| OS | Linux (CentOS 7.3.1611) | +| CPU | 40 vCPUs, Intel(R) Xeon(R) CPU E5-2630 v4 @ 2.20GHz | +| RAM | 128GB | +| DISK | Optane 500GB SSD \* 1 | + +Sysbench 版本:1.1.0 + +## 测试方案 + +使用 Sysbench 向集群导入 **16 张表,每张数据 1000 万**。通过 HAProxy 代理,分别以递增并发数向集群发送请求,单次并发测试时间 5 分钟。 + +### TiDB 版本信息 + +### v2.1.0-rc.2 + +| 组件 | GitHash | +| :-: | :-: | +| TiDB | 08e56cd3bae166b2af3c2f52354fbc9818717f62 | +| TiKV | 57e684016dafb17dc8a6837d30224be66cbc7246 | +| PD | 6a7832d2d6e5b2923c79683183e63d030f954563 | + +### v2.0.6 + +| 组件 | GitHash | +| :-: | :-: | +| TiDB | b13bc08462a584a085f377625a7bab0cc0351570 | +| TiKV | 57c83dc4ebc93d38d77dc8f7d66db224760766cc | +| PD | b64716707b7279a4ae822be767085ff17b5f3fea | + +### TiDB 参数配置 + +两版本 TiDB 均使用**默认配置**。 + +### TiKV 参数配置 + +两版本 TiKV 均使用如下配置: + +```txt +[readpool.storage] +normal-concurrency = 8 +[server] +grpc-concurrency = 8 +[raftstore] +sync-log = false +[rocksdb.defaultcf] +block-cache-size = "60GB" +[rocksdb.writecf] +block-cache-size = "20GB" +``` + +### 集群拓扑 + +| 机器 IP | 部署实例 | +| :-: | :-: | +| 172.16.30.31 | 1\*Sysbench 1\*HAProxy | +| 172.16.30.32 | 1\*TiDB 1\*pd 1\*TiKV | +| 172.16.30.33 | 1\*TiDB 1\*TiKV | +| 172.16.30.34 | 1\*TiDB 1\*TiKV | + +## 测试结果 + +### Point Select 测试 + +| 版本 | threads | qps | 95% latency(ms) | +| :-: | :-: | :-: | :-: | +| v2.1 | 64 | 111481.09 | 1.16 | +| v2.1 | 128 | 145102.62 | 2.52 | +| v2.1 | 256 | 161311.9 | 4.57 | +| v2.1 | 512 | 184991.19 | 7.56 | +| v2.1 | 1024 | 230282.74 | 10.84 | +| v2.0 | 64 | 75285.87 | 1.93 | +| v2.0 | 128 | 92141.79 | 3.68 | +| v2.0 | 256 | 107464.93 | 6.67 | +| v2.0 | 512 | 121350.61 | 11.65 | +| v2.0 | 1024 | 150036.31 | 17.32 | + +![point select](/media/sysbench_v3_point_select.png) + +v2.1 比 v2.0 在 Point Select 查询性能上,**提升了 50%**。 + +### Update Non-Index 测试 + +| 版本 | threads | qps | 95% latency(ms) | +| :-: | :-: | :-: | :-: | +| v2.1 | 64 | 18946.09 | 5.77 | +| v2.1 | 128 | 22022.82 | 12.08 | +| v2.1 | 256 | 24679.68 | 25.74 | +| v2.1 | 512 | 25107.1 | 51.94 | +| v2.1 | 1024 | 27144.92 | 106.75 | +| v2.0 | 64 | 16316.85 | 6.91 | +| v2.0 | 128 | 20944.6 | 11.45 | +| v2.0 | 256 | 24017.42 | 23.1 | +| v2.0 | 512 | 25994.33 | 46.63 | +| v2.0 | 1024 | 27917.52 | 92.42 | + +![update non-index](/media/sysbench_v3_update_non_index.png) + +v2.1 与 v2.0 在 Update Non-Index 写入性能上基本一致。 + +### Update Index 测试 + +| 版本 | threads | qps | 95% latency(ms) | +| :-: | :-: | :-: | :-: | +| v2.1 | 64 | 9934.49 | 12.08 | +| v2.1 | 128 | 10505.95 | 25.28 | +| v2.1 | 256 | 11007.7 | 55.82 | +| v2.1 | 512 | 11198.81 | 106.75 | +| v2.1 | 1024 | 11591.89 | 200.47 | +| v2.0 | 64 | 9754.68 | 11.65 | +| v2.0 | 128 | 10603.31 | 24.38 | +| v2.0 | 256 | 11011.71 | 50.11 | +| v2.0 | 512 | 11162.63 | 104.84 | +| v2.0 | 1024 | 12067.63 | 179.94 | + +![update index](/media/sysbench_v3_update_index.png) + +v2.1 与 v2.0 在 Update Index 写入性能上基本一致。 diff --git a/markdown-pages/zh/tidb/master/benchmark/benchmark-sysbench-v4-vs-v3.md b/markdown-pages/zh/tidb/master/benchmark/benchmark-sysbench-v4-vs-v3.md new file mode 100644 index 0000000..537397e --- /dev/null +++ b/markdown-pages/zh/tidb/master/benchmark/benchmark-sysbench-v4-vs-v3.md @@ -0,0 +1,194 @@ +--- +title: TiDB Sysbench 性能对比测试报告 - v4.0 对比 v3.0 +aliases: ['/docs-cn/dev/benchmark/benchmark-sysbench-v4-vs-v3/'] +summary: TiDB v4.0 在 OLTP 场景下的性能优于 v3.0。Point Select、Update Non-index、Update Index 和 Read Write 性能分别提升了 14%、15%、17% 和 31%。 +--- + +# TiDB Sysbench 性能对比测试报告 - v4.0 对比 v3.0 + +## 测试目的 + +测试对比 TiDB v4.0 和 v3.0 在 OLTP 场景下的性能。 + +## 测试环境 (AWS EC2) + +### 硬件配置 + +| 服务类型 | EC2 类型 | 实例数 | +|:----------|:----------|:----------| +| PD | m5.xlarge | 3 | +| TiKV | i3.4xlarge| 3 | +| TiDB | c5.4xlarge| 3 | +| Sysbench | m5.4xlarge| 1 | + +### 软件版本 + +| 服务类型 | 软件版本 | +|:----------|:-----------| +| PD | 3.0、4.0 | +| TiDB | 3.0、4.0 | +| TiKV | 3.0、4.0 | +| Sysbench | 1.0.20 | + +### 参数配置 + +#### TiDB v3.0 参数配置 + +```yaml +log.level: “error” +performance.max-procs: 20 +prepared-plan-cache.enabled: true +tikv-client.max-batch-wait-time: 2000000 +``` + +#### TiKV v3.0 参数配置 + +```yaml +storage.scheduler-worker-pool-size: 5 +raftstore.store-pool-size: 3 +raftstore.apply-pool-size: 3 +rocksdb.max-background-jobs: 3 +raftdb.max-background-jobs: 3 +raftdb.allow-concurrent-memtable-write: true +server.grpc-concurrency: 6 +readpool.storage.normal-concurrency: 10 +readpool.coprocessor.normal-concurrency: 5 +``` + +#### TiDB v4.0 参数配置 + +```yaml +log.level: “error” +performance.max-procs: 20 +prepared-plan-cache.enabled: true +tikv-client.max-batch-wait-time: 2000000 +``` + +#### TiKV v4.0 参数配置 + +```yaml +storage.scheduler-worker-pool-size: 5 +raftstore.store-pool-size: 3 +raftstore.apply-pool-size: 3 +rocksdb.max-background-jobs: 3 +raftdb.max-background-jobs: 3 +raftdb.allow-concurrent-memtable-write: true +server.grpc-concurrency: 6 +readpool.unified.min-thread-count: 5 +readpool.unified.max-thread-count: 20 +readpool.storage.normal-concurrency: 10 +pessimistic-txn.pipelined: true +``` + +#### 全局变量配置 + +```sql +set global tidb_hashagg_final_concurrency=1; +set global tidb_hashagg_partial_concurrency=1; +set global tidb_disable_txn_auto_retry=0; +``` + +## 测试方案 + +1. 通过 TiUP 部署 TiDB v4.0 和 v3.0。 +2. 通过 Sysbench 导入 16 张表,每张表有 1000 万行数据。 +3. 分别对每个表执行 `analyze table` 命令。 +4. 备份数据,用于不同并发测试前进行数据恢复,以保证每次数据一致。 +5. 启动 Sysbench 客户端,进行 `point_select`、`read_write`、`update_index` 和 `update_non_index` 测试。通过 AWS NLB 向 TiDB 加压,单轮预热 1 分钟,测试 5 分钟。 +6. 每轮完成后停止集群,使用之前的备份的数据覆盖,再启动集群。 + +### 准备测试数据 + +执行以下命令来准备测试数据: + +```bash +sysbench oltp_common \ + --threads=16 \ + --rand-type=uniform \ + --db-driver=mysql \ + --mysql-db=sbtest \ + --mysql-host=$aws_nlb_host \ + --mysql-port=$aws_nlb_port \ + --mysql-user=root \ + --mysql-password=password \ + prepare --tables=16 --table-size=10000000 +``` + +### 执行测试命令 + +执行以下命令来执行测试: + +```bash +sysbench $testname \ + --threads=$threads \ + --time=300 \ + --report-interval=1 \ + --rand-type=uniform \ + --db-driver=mysql \ + --mysql-db=sbtest \ + --mysql-host=$aws_nlb_host \ + --mysql-port=$aws_nlb_port \ + run --tables=16 --table-size=10000000 +``` + +## 测试结果 + +### Point Select 性能 + +| Threads | v3.0 QPS | v3.0 95% latency (ms) | v4.0 QPS | v4.0 95% latency (ms) | QPS 提升 | +|:----------|:----------|:----------|:----------|:----------|:----------| +| 150 | 117085.701 | 1.667 | 118165.1357 | 1.608 | 0.92% | +| 300 | 200621.4471| 2.615 | 207774.0859 | 2.032 | 3.57% | +| 600 | 283928.9323| 4.569 | 320673.342 | 3.304 | 12.94% | +| 900 | 343218.2624| 6.686 | 383913.3855 | 4.652 | 11.86% | +| 1200 | 347200.2366| 8.092 | 408929.4372 | 6.318 | 17.78% | +| 1500 | 366406.2767| 10.562 | 418268.8856 | 7.985 | 14.15% | + +v4.0 对比 v3.0,Point Select 性能提升了 14%。 + +![Point Select](/media/sysbench_v4vsv3_point_select.png) + +### Update Non-index 性能 + +| Threads | v3.0 QPS | v3.0 95% latency (ms) | v4.0 QPS | v4.0 95% latency (ms) | QPS 提升 | +|:----------|:----------|:----------|:----------|:----------|:----------| +| 150 | 15446.41024 | 11.446 | 16954.39971 | 10.844 | 9.76% | +| 300 | 22276.15572| 17.319 | 24364.44689 | 16.706 | 9.37% | +| 600 | 28784.88353| 29.194 | 31635.70833 | 28.162 | 9.90% | +| 900 | 32194.15548| 42.611 | 35787.66078 | 38.942 | 11.16% | +| 1200 | 33954.69114| 58.923 | 38552.63158 | 51.018 | 13.54% | +| 1500 | 35412.0032| 74.464 | 40859.63755 | 62.193 | 15.38% | + +v4.0 对比 v3.0,Update Non-index 性能提升了 15%。 + +![Update Non-index](/media/sysbench_v4vsv3_update_non_index.png) + +### Update Index 性能 + +| Threads | v3.0 QPS | v3.0 95% latency (ms) | v4.0 QPS | v4.0 95% latency (ms) | QPS 提升 | +|:----------|:----------|:----------|:----------|:----------|:----------| +| 150 | 11164.40571 | 16.706 | 11954.73635 | 16.408 | 7.08% | +| 300 | 14460.98057| 28.162 | 15243.40899 | 28.162 | 5.41% | +| 600 | 17112.73036| 53.85 | 18535.07515 | 50.107 | 8.31% | +| 900 | 18233.83426| 86.002 | 20339.6901 | 70.548 | 11.55% | +| 1200 | 18622.50283| 127.805 | 21390.25122 | 94.104 | 14.86% | +| 1500 | 18980.34447| 170.479 | 22359.996 | 114.717 | 17.81% | + +v4.0 对比 v3.0,Update Index 性能提升了 17%。 + +![Update Index](/media/sysbench_v4vsv3_update_index.png) + +### Read Write 性能 + +| Threads | v3.0 QPS | v3.0 95% latency (ms) | v4.0 QPS | v4.0 95% latency (ms) | QPS 提升 | +|:----------|:----------|:----------|:----------|:----------|:----------| +| 150 | 43768.33633 | 71.83 | 53912.63705 | 59.993 | 23.18% | +| 300 | 55655.63589| 121.085 | 71327.21336 | 97.555 | 28.16% | +| 600 | 64642.96992| 223.344 | 84487.75483 | 176.731 | 30.70% | +| 900 | 68947.25293| 325.984 | 90177.94612 | 257.95 | 30.79% | +| 1200 | 71334.80099| 434.829 | 92779.71507 | 344.078 | 30.06% | +| 1500 | 72069.9115| 580.017 | 95088.50812 | 434.829 | 31.94% | + +v4.0 对比 v3.0,Read Write 性能提升了 31%。 + +![Read Write](/media/sysbench_v4vsv3_read_write.png) diff --git a/markdown-pages/zh/tidb/master/benchmark/benchmark-sysbench-v5-vs-v4.md b/markdown-pages/zh/tidb/master/benchmark/benchmark-sysbench-v5-vs-v4.md new file mode 100644 index 0000000..6a7c058 --- /dev/null +++ b/markdown-pages/zh/tidb/master/benchmark/benchmark-sysbench-v5-vs-v4.md @@ -0,0 +1,207 @@ +--- +title: TiDB Sysbench 性能对比测试报告 - v5.0 对比 v4.0 +summary: TiDB v5.0 在 OLTP 场景下的性能测试结果显示,Point Select 性能提升了 2.7%,Update Non-index 性能提升了 81%,Update Index 性能提升了 28%,Read Write 性能提升了 9%。这表明在 AWS EC2 环境下,TiDB v5.0 相对于 v4.0 在各项性能指标上都有所提升。 +--- + +# TiDB Sysbench 性能对比测试报告 - v5.0 对比 v4.0 + +## 测试目的 + +测试对比 TiDB v5.0 和 v4.0 在 OLTP 场景下的性能。 + +## 测试环境 (AWS EC2) + +### 硬件配置 + +| 服务类型 | EC2 类型 | 实例数 | +|:----------|:----------|:----------| +| PD | m5.xlarge | 3 | +| TiKV | i3.4xlarge| 3 | +| TiDB | c5.4xlarge| 3 | +| Sysbench | c5.9xlarge| 1 | + +### 软件版本 + +| 服务类型 | 软件版本 | +|:----------|:-----------| +| PD | 4.0、5.0 | +| TiDB | 4.0、5.0 | +| TiKV | 4.0、5.0 | +| Sysbench | 1.0.20 | + +### 参数配置 + +#### TiDB v4.0 参数配置 + +```yaml +log.level: "error" +performance.max-procs: 20 +prepared-plan-cache.enabled: true +tikv-client.max-batch-wait-time: 2000000 +``` + +#### TiKV v4.0 参数配置 + +```yaml +storage.scheduler-worker-pool-size: 5 +raftstore.store-pool-size: 3 +raftstore.apply-pool-size: 3 +rocksdb.max-background-jobs: 3 +raftdb.max-background-jobs: 3 +raftdb.allow-concurrent-memtable-write: true +server.grpc-concurrency: 6 +readpool.unified.min-thread-count: 5 +readpool.unified.max-thread-count: 20 +readpool.storage.normal-concurrency: 10 +pessimistic-txn.pipelined: true +``` + +#### TiDB v5.0 参数配置 + +```yaml +log.level: "error" +performance.max-procs: 20 +prepared-plan-cache.enabled: true +tikv-client.max-batch-wait-time: 2000000 +``` + +#### TiKV v5.0 参数配置 + +```yaml +storage.scheduler-worker-pool-size: 5 +raftstore.store-pool-size: 3 +raftstore.apply-pool-size: 3 +rocksdb.max-background-jobs: 8 +raftdb.max-background-jobs: 4 +raftdb.allow-concurrent-memtable-write: true +server.grpc-concurrency: 6 +readpool.unified.min-thread-count: 5 +readpool.unified.max-thread-count: 20 +readpool.storage.normal-concurrency: 10 +pessimistic-txn.pipelined: true +server.enable-request-batch: false +``` + +#### TiDB v4.0 全局变量配置 + +```sql +set global tidb_hashagg_final_concurrency=1; +set global tidb_hashagg_partial_concurrency=1; +``` + +#### TiDB v5.0 全局变量配置 + +```sql +set global tidb_hashagg_final_concurrency=1; +set global tidb_hashagg_partial_concurrency=1; +set global tidb_enable_async_commit = 1; +set global tidb_enable_1pc = 1; +set global tidb_guarantee_linearizability = 0; +set global tidb_enable_clustered_index = 1; + +``` + +## 测试方案 + +1. 通过 TiUP 部署 TiDB v5.0 和 v4.0。 +2. 通过 Sysbench 导入 16 张表,每张表有 1000 万行数据。 +3. 分别对每个表执行 `analyze table` 命令。 +4. 备份数据,用于不同并发测试前进行数据恢复,以保证每次数据一致。 +5. 启动 Sysbench 客户端,进行 `point_select`、`read_write`、`update_index` 和 `update_non_index` 测试。通过 AWS NLB 向 TiDB 加压,单轮预热 1 分钟,测试 5 分钟。 +6. 每轮完成后停止集群,使用之前的备份的数据覆盖,再启动集群。 + +### 准备测试数据 + +执行以下命令来准备测试数据: + +```bash +sysbench oltp_common \ + --threads=16 \ + --rand-type=uniform \ + --db-driver=mysql \ + --mysql-db=sbtest \ + --mysql-host=$aws_nlb_host \ + --mysql-port=$aws_nlb_port \ + --mysql-user=root \ + --mysql-password=password \ + prepare --tables=16 --table-size=10000000 +``` + +### 执行测试命令 + +执行以下命令来执行测试: + +```bash +sysbench $testname \ + --threads=$threads \ + --time=300 \ + --report-interval=1 \ + --rand-type=uniform \ + --db-driver=mysql \ + --mysql-db=sbtest \ + --mysql-host=$aws_nlb_host \ + --mysql-port=$aws_nlb_port \ + run --tables=16 --table-size=10000000 +``` + +## 测试结果 + +### Point Select 性能 + +| Threads | v4.0 QPS | v4.0 95% latency (ms) | v5.0 QPS | v5.0 95% latency (ms) | QPS 提升 | +|:----------|:----------|:----------|:----------|:----------|:----------| +| 150 | 159451.19 | 1.32 | 177876.25 | 1.23 | 11.56% | +| 300 | 244790.38 | 1.96 | 252675.03 | 1.82 | 3.22% | +| 600 | 322929.05 | 3.75 | 331956.84 | 3.36 | 2.80% | +| 900 | 364840.05 | 5.67 | 365655.04 | 5.09 | 0.22% | +| 1200 | 376529.18 | 7.98 | 366507.47 | 7.04 | -2.66% | +| 1500 | 368390.52 | 10.84 | 372476.35 | 8.90 | 1.11% | + +v5.0 对比 v4.0,Point Select 性能提升了 2.7%。 + +![Point Select](/media/sysbench_v5vsv4_point_select.png) + +### Update Non-index 性能 + +| Threads | v4.0 QPS | v4.0 95% latency (ms) | v5.0 QPS | v5.0 95% latency (ms) | QPS 提升 | +|:----------|:----------|:----------|:----------|:----------|:----------| +| 150 | 17243.78 | 11.04 | 30866.23 | 6.91 | 79.00% | +| 300 | 25397.06 | 15.83 | 45915.39 | 9.73 | 80.79% | +| 600 | 33388.08 | 25.28 | 60098.52 | 16.41 | 80.00% | +| 900 | 38291.75 | 36.89 | 70317.41 | 21.89 | 83.64% | +| 1200 | 41003.46 | 55.82 | 76376.22 | 28.67 | 86.27% | +| 1500 | 44702.84 | 62.19 | 80234.58 | 34.95 | 79.48% | + +v5.0 对比 v4.0,Update Non-index 性能提升了 81%。 + +![Update Non-index](/media/sysbench_v5vsv4_update_non_index.png) + +### Update Index 性能 + +| Threads | v4.0 QPS | v4.0 95% latency (ms) | v5.0 QPS | v5.0 95% latency (ms) | QPS 提升 | +|:----------|:----------|:----------|:----------|:----------|:----------| +| 150 | 11736.21 | 17.01 | 15631.34 | 17.01 | 33.19% | +| 300 | 15435.95 | 28.67 | 19957.06 | 22.69 | 29.29% | +| 600 | 18983.21 | 49.21 | 23218.14 | 41.85 | 22.31% | +| 900 | 20855.29 | 74.46 | 26226.76 | 53.85 | 25.76% | +| 1200 | 21887.64 | 102.97 | 28505.41 | 69.29 | 30.24% | +| 1500 | 23621.15 | 110.66 | 30341.06 | 82.96 | 28.45% | + +v5.0 对比 v4.0,Update Index 性能提升了 28%。 + +![Update Index](/media/sysbench_v5vsv4_update_index.png) + +### Read Write 性能 + +| Threads | v4.0 QPS | v4.0 95% latency (ms) | v5.0 QPS | v5.0 95% latency (ms) | QPS 提升 | +|:----------|:----------|:----------|:----------|:----------|:----------| +| 150 | 59979.91 | 61.08 | 66098.57 | 55.82 | 10.20% | +| 300 | 77118.32 | 102.97 | 84639.48 | 90.78 | 9.75% | +| 600 | 90619.52 | 183.21 | 101477.46 | 167.44 | 11.98% | +| 900 | 97085.57 | 267.41 | 109463.46 | 240.02 | 12.75% | +| 1200 | 106521.61 | 331.91 | 115416.05 | 320.17 | 8.35% | +| 1500 | 116278.96 | 363.18 | 118807.5 | 411.96 | 2.17% | + +v5.0 对比 v4.0,Read Write 性能提升了 9%。 + +![Read Write](/media/sysbench_v5vsv4_read_write.png) diff --git a/markdown-pages/zh/tidb/master/benchmark/benchmark-sysbench-v5.1.0-vs-v5.0.2.md b/markdown-pages/zh/tidb/master/benchmark/benchmark-sysbench-v5.1.0-vs-v5.0.2.md new file mode 100644 index 0000000..cafaf8a --- /dev/null +++ b/markdown-pages/zh/tidb/master/benchmark/benchmark-sysbench-v5.1.0-vs-v5.0.2.md @@ -0,0 +1,177 @@ +--- +title: TiDB Sysbench 性能对比测试报告 - v5.1.0 对比 v5.0.2 +summary: TiDB v5.1.0 在 OLTP 场景下的 Sysbench 性能表现对比 v5.0.2。Point Select 性能提升了 19.4%,Read Write 和 Update Index 性能略有下降。测试环境为 AWS EC2,硬件配置包括 PD、TiKV、TiDB 和 Sysbench。软件版本为 v5.0.2、v5.1.0。参数配置相同。测试方案包括部署、数据准备和执行测试。测试结果显示各场景性能对比情况。 +--- + +# TiDB Sysbench 性能对比测试报告 - v5.1.0 对比 v5.0.2 + +## 测试概况 + +本次测试对比了 TiDB v5.1.0 和 v5.0.2 在 OLTP 场景下的 Sysbench 性能表现。结果显示,v5.1.0 相比于 v5.0.2,Point Select 场景性能提升了 19.4%,Read Write 和 Update Index 场景性能略有下降。 + +## 测试环境 (AWS EC2) + +### 硬件配置 + +| 服务类型 | EC2 类型 | 实例数 | +|:----------|:----------|:----------| +| PD | m5.xlarge | 3 | +| TiKV | i3.4xlarge| 3 | +| TiDB | c5.4xlarge| 3 | +| Sysbench | c5.9xlarge| 1 | + +### 软件版本 + +| 服务类型 | 软件版本 | +|:----------|:-----------| +| PD | v5.0.2、v5.1.0 | +| TiDB | v5.0.2、v5.1.0 | +| TiKV | v5.0.2、v5.1.0 | +| Sysbench | 1.0.20 | + +### 参数配置 + +两个版本使用相同的配置 + +#### TiDB 参数配置 + +```yaml +log.level: "error" +performance.max-procs: 20 +prepared-plan-cache.enabled: true +tikv-client.max-batch-wait-time: 2000000 +``` + +#### TiKV 参数配置 + +```yaml +storage.scheduler-worker-pool-size: 5 +raftstore.store-pool-size: 3 +raftstore.apply-pool-size: 3 +rocksdb.max-background-jobs: 8 +raftdb.max-background-jobs: 4 +raftdb.allow-concurrent-memtable-write: true +server.grpc-concurrency: 6 +readpool.unified.min-thread-count: 5 +readpool.unified.max-thread-count: 20 +readpool.storage.normal-concurrency: 10 +pessimistic-txn.pipelined: true +server.enable-request-batch: false +``` + +#### TiDB 全局变量配置 + +```sql +set global tidb_hashagg_final_concurrency=1; +set global tidb_hashagg_partial_concurrency=1; +set global tidb_enable_async_commit = 1; +set global tidb_enable_1pc = 1; +set global tidb_guarantee_linearizability = 0; +set global tidb_enable_clustered_index = 1; + +``` + +## 测试方案 + +1. 通过 TiUP 部署 TiDB v5.1.0 和 v5.0.2。 +2. 通过 Sysbench 导入 16 张表,每张表有 1000 万行数据。 +3. 分别对每个表执行 `analyze table` 命令。 +4. 备份数据,用于不同并发测试前进行数据恢复,以保证每次数据一致。 +5. 启动 Sysbench 客户端,进行 `point_select`、`read_write`、`update_index` 和 `update_non_index` 测试。通过 HAProxy 向 TiDB 加压,测试 5 分钟。 +6. 每轮完成后停止集群,使用之前的备份的数据覆盖,再启动集群。 + +### 准备测试数据 + +执行以下命令来准备测试数据: + +```bash +sysbench oltp_common \ + --threads=16 \ + --rand-type=uniform \ + --db-driver=mysql \ + --mysql-db=sbtest \ + --mysql-host=$aws_nlb_host \ + --mysql-port=$aws_nlb_port \ + --mysql-user=root \ + --mysql-password=password \ + prepare --tables=16 --table-size=10000000 +``` + +### 执行测试命令 + +执行以下命令来执行测试: + +```bash +sysbench $testname \ + --threads=$threads \ + --time=300 \ + --report-interval=1 \ + --rand-type=uniform \ + --db-driver=mysql \ + --mysql-db=sbtest \ + --mysql-host=$aws_nlb_host \ + --mysql-port=$aws_nlb_port \ + run --tables=16 --table-size=10000000 +``` + +## 测试结果 + +### Point Select 性能 + +| Threads | v5.0.2 QPS | v5.0.2 95% latency (ms) | v5.1.0 QPS | v5.1.0 95% latency (ms) | QPS 提升 | +|:----------|:----------|:----------|:----------|:----------|:----------| +|150|137732.27|1.86|158861.67|2|15.34%| +|300|201420.58|2.91|238038.44|2.71|18.18%| +|600|303631.52|3.49|428573.21|2.07|41.15%| +|900|383628.13|3.55|464863.22|3.89|21.18%| +|1200|391451.54|5.28|413656.74|13.46|5.67%| +|1500|410276.93|7.43|471418.78|10.65|14.90%| + +v5.1.0 对比 v5.0.2,Point Select 性能提升了 19.4%。 + +![Point Select](/media/sysbench_v510vsv502_point_select.png) + +### Update Non-index 性能 + +| Threads | v5.0.2 QPS | v5.0.2 95% latency (ms) | v5.1.0 QPS | v5.1.0 95% latency (ms) | QPS 提升 | +|:----------|:----------|:----------|:----------|:----------|:----------| +|150|29248.2|7.17|29362.7|8.13|0.39%| +|300|40316.09|12.52|39651.52|13.7|-1.65%| +|600|51011.11|22.28|47047.9|27.66|-7.77%| +|900|58814.16|27.66|59331.84|28.67|0.88%| +|1200|65286.52|32.53|67745.39|31.37|3.77%| +|1500|68300.86|39.65|67899.17|44.17|-0.59%| + +v5.1.0 对比 v5.0.2,Update Non-index 性能下降了 0.8%。 + +![Update Non-index](/media/sysbench_v510vsv502_update_non_index.png) + +### Update Index 性能 + +| Threads | v5.0.2 QPS | v5.0.2 95% latency (ms) | v5.1.0 QPS | v5.1.0 95% latency (ms) | QPS 提升 | +|:----------|:----------|:----------|:----------|:----------|:----------| +|150|15066.54|14.73|14829.31|14.73|-1.57%| +|300|18535.92|24.83|17401.01|29.72|-6.12%| +|600|22862.73|41.1|21923.78|44.98|-4.11%| +|900|25286.74|57.87|24916.76|58.92|-1.46%| +|1200|27566.18|70.55|27800.62|69.29|0.85%| +|1500|28184.76|92.42|28679.72|86|1.76%| + +v5.1.0 对比 v5.0.2,Update Index 性能下降了 1.8%。 + +![Update Index](/media/sysbench_v510vsv502_update_index.png) + +### Read Write 性能 + +| Threads | v5.0.2 QPS | v5.0.2 95% latency (ms) | v5.1.0 QPS | v5.1.0 95% latency (ms) | QPS 提升 | +|:----------|:----------|:----------|:----------|:----------|:----------| +|150|66415.33|56.84|66591.49|57.87|0.27%| +|300|82488.39|97.55|81226.41|101.13|-1.53%| +|600|99195.36|173.58|97357.86|179.94|-1.85%| +|900|107382.76|253.35|101665.95|267.41|-5.32%| +|1200|112389.23|337.94|107426.41|350.33|-4.42%| +|1500|113548.73|450.77|109805.26|442.73|-3.30%| + +v5.1.0 对比 v5.0.2,Read Write 性能下降了 2.7%。 + +![Read Write](/media/sysbench_v510vsv502_read_write.png) diff --git a/markdown-pages/zh/tidb/master/benchmark/benchmark-sysbench-v5.2.0-vs-v5.1.1.md b/markdown-pages/zh/tidb/master/benchmark/benchmark-sysbench-v5.2.0-vs-v5.1.1.md new file mode 100644 index 0000000..63e9399 --- /dev/null +++ b/markdown-pages/zh/tidb/master/benchmark/benchmark-sysbench-v5.2.0-vs-v5.1.1.md @@ -0,0 +1,177 @@ +--- +title: TiDB Sysbench 性能对比测试报告 - v5.2.0 对比 v5.1.1 +summary: TiDB v5.2.0 在 OLTP 场景下的 Sysbench 性能对比测试显示,Point Select 性能提升了 11.03%,但其余场景性能略有下降。硬件配置为 PD m5.xlarge 3 台、TiKV i3.4xlarge 3 台、TiDB c5.4xlarge 3 台、Sysbench c5.9xlarge 1 台。软件版本为 PD v5.1.1、v5.2.0、TiDB v5.1.1、v5.2.0、TiKV v5.1.1、v5.2.0、Sysbench 1.1.0-ead2689。测试方案包括数据准备、执行测试命令和测试结果。Point Select 性能提升 11.03%,Update Non-index 性能下降 1.98%,Update Index 性能下降 4.33%,Read Write 性能下降 1.24%。 +--- + +# TiDB Sysbench 性能对比测试报告 - v5.2.0 对比 v5.1.1 + +## 测试概况 + +本次测试对比了 TiDB v5.2.0 和 v5.1.1 在 OLTP 场景下的 Sysbench 性能表现。结果显示,v5.2.0 相比于 v5.1.1,Point Select 场景性能提升了 11.03%,其余场景性能略有下降。 + +## 测试环境 (AWS EC2) + +### 硬件配置 + +| 服务类型 | EC2 类型 | 实例数 | +|:----------|:----------|:----------| +| PD | m5.xlarge | 3 | +| TiKV | i3.4xlarge| 3 | +| TiDB | c5.4xlarge| 3 | +| Sysbench | c5.9xlarge| 1 | + +### 软件版本 + +| 服务类型 | 软件版本 | +|:----------|:-----------| +| PD | v5.1.1、v5.2.0 | +| TiDB | v5.1.1、v5.2.0 | +| TiKV | v5.1.1、v5.2.0 | +| Sysbench | 1.1.0-ead2689 | + +### 参数配置 + +两个版本使用相同的配置 + +#### TiDB 参数配置 + +```yaml +log.level: "error" +performance.max-procs: 20 +prepared-plan-cache.enabled: true +tikv-client.max-batch-wait-time: 2000000 +``` + +#### TiKV 参数配置 + +```yaml +storage.scheduler-worker-pool-size: 5 +raftstore.store-pool-size: 3 +raftstore.apply-pool-size: 3 +rocksdb.max-background-jobs: 8 +raftdb.max-background-jobs: 4 +raftdb.allow-concurrent-memtable-write: true +server.grpc-concurrency: 6 +readpool.unified.min-thread-count: 5 +readpool.unified.max-thread-count: 20 +readpool.storage.normal-concurrency: 10 +pessimistic-txn.pipelined: true +server.enable-request-batch: false +``` + +#### TiDB 全局变量配置 + +```sql +set global tidb_hashagg_final_concurrency=1; +set global tidb_hashagg_partial_concurrency=1; +set global tidb_enable_async_commit = 1; +set global tidb_enable_1pc = 1; +set global tidb_guarantee_linearizability = 0; +set global tidb_enable_clustered_index = 1; + +``` + +## 测试方案 + +1. 通过 TiUP 部署 TiDB v5.2.0 和 v5.1.1。 +2. 通过 Sysbench 导入 16 张表,每张表有 1000 万行数据。 +3. 分别对每个表执行 `analyze table` 命令。 +4. 备份数据,用于不同并发测试前进行数据恢复,以保证每次数据一致。 +5. 启动 Sysbench 客户端,进行 `point_select`、`read_write`、`update_index` 和 `update_non_index` 测试。通过 HAProxy 向 TiDB 加压,测试 5 分钟。 +6. 每轮完成后停止集群,使用之前的备份的数据覆盖,再启动集群。 + +### 准备测试数据 + +执行以下命令来准备测试数据: + +```bash +sysbench oltp_common \ + --threads=16 \ + --rand-type=uniform \ + --db-driver=mysql \ + --mysql-db=sbtest \ + --mysql-host=$aws_nlb_host \ + --mysql-port=$aws_nlb_port \ + --mysql-user=root \ + --mysql-password=password \ + prepare --tables=16 --table-size=10000000 +``` + +### 执行测试命令 + +执行以下命令来执行测试: + +```bash +sysbench $testname \ + --threads=$threads \ + --time=300 \ + --report-interval=1 \ + --rand-type=uniform \ + --db-driver=mysql \ + --mysql-db=sbtest \ + --mysql-host=$aws_nlb_host \ + --mysql-port=$aws_nlb_port \ + run --tables=16 --table-size=10000000 +``` + +## 测试结果 + +### Point Select 性能 + +| Threads | v5.1.1 QPS | v5.1.1 95% latency (ms) | v5.2.0 QPS | v5.2.0 95% latency (ms) | QPS 提升 | +|:----------|:----------|:----------|:----------|:----------|:----------| +|150|143014.13|2.35|174402.5|1.23|21.95%| +|300|199133.06|3.68|272018|1.64|36.60%| +|600|389391.65|2.18|393536.4|2.11|1.06%| +|900|468338.82|2.97|447981.98|3.3|-4.35%| +|1200|448348.52|5.18|468241.29|4.65|4.44%| +|1500|454376.79|7.04|483888.42|6.09|6.49%| + +v5.2.0 对比 v5.1.1,Point Select 性能提升了 11.03%。 + +![Point Select](/media/sysbench_v511vsv520_point_select.png) + +### Update Non-index 性能 + +| Threads | v5.1.1 QPS | v5.1.1 95% latency (ms) | v5.2.0 QPS | v5.2.0 95% latency (ms) | QPS 提升 | +|:----------|:----------|:----------|:----------|:----------|:----------| +|150|31198.68|6.43|30714.73|6.09|-1.55%| +|300|43577.15|10.46|42997.92|9.73|-1.33%| +|600|57230.18|17.32|56168.81|16.71|-1.85%| +|900|65325.11|23.1|64098.04|22.69|-1.88%| +|1200|71528.26|28.67|69908.15|28.67|-2.26%| +|1500|76652.5|33.12|74371.79|33.72|-2.98%| + +v5.2.0 对比 v5.1.1,Update Non-index 性能下降了 1.98%。 + +![Update Non-index](/media/sysbench_v511vsv520_update_non_index.png) + +### Update Index 性能 + +| Threads | v5.1.1 QPS | v5.1.1 95% latency (ms) | v5.2.0 QPS | v5.2.0 95% latency (ms) | QPS 提升 | +|:----------|:----------|:----------|:----------|:----------|:----------| +|150|15641.04|13.22|15320|13.46|-2.05%| +|300|19787.73|21.89|19161.35|22.69|-3.17%| +|600|24566.74|36.89|23616.07|38.94|-3.87%| +|900|27516.57|50.11|26270.04|54.83|-4.53%| +|1200|29421.10|63.32|28002.65|69.29|-4.82%| +|1500|30957.84|77.19|28624.44|95.81|-7.54%| + +v5.2.0 对比 v5.1.1,Update Index 性能下降了 4.33%。 + +![Update Index](/media/sysbench_v511vsv520_update_index.png) + +### Read Write 性能 + +| Threads | v5.1.1 QPS | v5.1.1 95% latency (ms) | v5.2.0 QPS | v5.2.0 95% latency (ms) | QPS 提升 | +|:----------|:----------|:----------|:----------|:----------|:----------| +|150|68471.02|57.87|69246|54.83|1.13%| +|300|86573.09|97.55|85340.42|94.10|-1.42%| +|600|101760.75|176.73|102221.31|173.58|0.45%| +|900|111877.55|248.83|109276.45|257.95|-2.32%| +|1200|117479.4|337.94|114231.33|344.08|-2.76%| +|1500|119662.91|419.45|116663.28|434.83|-2.51%| + +v5.2.0 对比 v5.1.1,Read Write 性能下降了 1.24%。 + +![Read Write](/media/sysbench_v511vsv520_read_write.png) diff --git a/markdown-pages/zh/tidb/master/benchmark/benchmark-sysbench-v5.3.0-vs-v5.2.2.md b/markdown-pages/zh/tidb/master/benchmark/benchmark-sysbench-v5.3.0-vs-v5.2.2.md new file mode 100644 index 0000000..dafe469 --- /dev/null +++ b/markdown-pages/zh/tidb/master/benchmark/benchmark-sysbench-v5.3.0-vs-v5.2.2.md @@ -0,0 +1,193 @@ +--- +title: TiDB Sysbench 性能对比测试报告 - v5.3.0 对比 v5.2.2 +summary: TiDB v5.3.0 和 v5.2.2 在 OLTP 场景下的 Sysbench 性能对比测试结果显示,v5.3.0 相比于 v5.2.2,性能基本持平。具体测试结果如下:Point Select 性能:v5.3.0 略下降了 0.81%、Update Non-index 性能:v5.3.0 略上升了 0.95%、Update Index 性能:v5.3.0 略上升了 1.83%、Read Write 性能:v5.3.0 略下降了 0.62%。 +--- + +# TiDB Sysbench 性能对比测试报告 - v5.3.0 对比 v5.2.2 + +## 测试概况 + +本次测试对比了 TiDB v5.3.0 和 v5.2.2 在 OLTP 场景下的 Sysbench 性能表现。结果显示,v5.3.0 相比于 v5.2.2,性能基本持平。 + +## 测试环境 (AWS EC2) + +### 硬件配置 + +| 服务类型 | EC2 类型 | 实例数 | +|:----------|:----------|:----------| +| PD | m5.xlarge | 3 | +| TiKV | i3.4xlarge| 3 | +| TiDB | c5.4xlarge| 3 | +| Sysbench | c5.9xlarge| 1 | + +### 软件版本 + +| 服务类型 | 软件版本 | +|:----------|:-----------| +| PD | v5.2.2、v5.3.0 | +| TiDB | v5.2.2、v5.3.0 | +| TiKV | v5.2.2、v5.3.0 | +| Sysbench | 1.1.0-ead2689 | + +### 参数配置 + +两个版本使用相同的配置 + +#### TiDB 参数配置 + +```yaml +log.level: "error" +performance.max-procs: 20 +prepared-plan-cache.enabled: true +tikv-client.max-batch-wait-time: 2000000 +``` + +#### TiKV 参数配置 + +```yaml +storage.scheduler-worker-pool-size: 5 +raftstore.store-pool-size: 3 +raftstore.apply-pool-size: 3 +rocksdb.max-background-jobs: 8 +raftdb.max-background-jobs: 4 +raftdb.allow-concurrent-memtable-write: true +server.grpc-concurrency: 6 +readpool.unified.min-thread-count: 5 +readpool.unified.max-thread-count: 20 +readpool.storage.normal-concurrency: 10 +pessimistic-txn.pipelined: true +``` + +#### TiDB 全局变量配置 + +```sql +set global tidb_hashagg_final_concurrency=1; +set global tidb_hashagg_partial_concurrency=1; +set global tidb_enable_async_commit = 1; +set global tidb_enable_1pc = 1; +set global tidb_guarantee_linearizability = 0; +set global tidb_enable_clustered_index = 1; +``` + +#### HAProxy 配置 - haproxy.cfg 文件 + +更多有关 HAProxy 在 TiDB 上的使用,可参阅 [HAProxy 在 TiDB 中的最佳实践](/best-practices/haproxy-best-practices.md)。 + +```yaml +global # 全局配置。 + chroot /var/lib/haproxy # 更改当前目录并为启动进程设置超级用户权限,从而提高安全性。 + pidfile /var/run/haproxy.pid # 将 HAProxy 进程的 PID 写入 pidfile。 + maxconn 4000 # 每个 HAProxy 进程所接受的最大并发连接数。 + user haproxy # 同 UID 参数。 + group haproxy # 同 GID 参数,建议使用专用用户组。 + nbproc 64 # 在后台运行时创建的进程数。在启动多个进程转发请求时,确保该值足够大,保证 HAProxy 不会成为瓶颈。 + daemon # 让 HAProxy 以守护进程的方式工作于后台,等同于命令行参数“-D”的功能。当然,也可以在命令行中用“-db”参数将其禁用。 + +defaults # 默认配置。 + log global # 日志继承全局配置段的设置。 + retries 2 # 向上游服务器尝试连接的最大次数,超过此值便认为后端服务器不可用。 + timeout connect 2s # HAProxy 与后端服务器连接超时时间。如果在同一个局域网内,可设置成较短的时间。 + timeout client 30000s # 客户端与 HAProxy 连接后,数据传输完毕,即非活动连接的超时时间。 + timeout server 30000s # 服务器端非活动连接的超时时间。 + +listen tidb-cluster # 配置 database 负载均衡。 + bind 0.0.0.0:3390 # 浮动 IP 和 监听端口。 + mode tcp # HAProxy 要使用第 4 层的传输层。 + balance roundrobin # 连接数最少的服务器优先接收连接。`leastconn` 建议用于长会话服务,例如 LDAP、SQL、TSE 等,而不是短会话协议,如 HTTP。该算法是动态的,对于启动慢的服务器,服务器权重会在运行中作调整。 + server tidb-1 10.9.18.229:4000 check inter 2000 rise 2 fall 3 # 检测 4000 端口,检测频率为每 2000 毫秒一次。如果 2 次检测为成功,则认为服务器可用;如果 3 次检测为失败,则认为服务器不可用。 + server tidb-2 10.9.39.208:4000 check inter 2000 rise 2 fall 3 + server tidb-3 10.9.64.166:4000 check inter 2000 rise 2 fall 3 +``` + +## 测试方案 + +1. 通过 TiUP 部署 TiDB v5.3.0 和 v5.2.2。 +2. 通过 Sysbench 导入 16 张表,每张表有 1000 万行数据。 +3. 分别对每个表执行 `analyze table` 命令。 +4. 备份数据,用于不同并发测试前进行数据恢复,以保证每次数据一致。 +5. 启动 Sysbench 客户端,进行 `point_select`、`read_write`、`update_index` 和 `update_non_index` 测试。通过 HAProxy 向 TiDB 加压,每种负载每个并发数各测试 20 分钟。 +6. 每轮完成后停止集群,使用之前的备份的数据覆盖,再启动集群。 + +### 准备测试数据 + +执行以下命令来准备测试数据: + +```bash +sysbench oltp_common \ + --threads=16 \ + --rand-type=uniform \ + --db-driver=mysql \ + --mysql-db=sbtest \ + --mysql-host=$aws_nlb_host \ + --mysql-port=$aws_nlb_port \ + --mysql-user=root \ + --mysql-password=password \ + prepare --tables=16 --table-size=10000000 +``` + +### 执行测试命令 + +执行以下命令来执行测试: + +```bash +sysbench $testname \ + --threads=$threads \ + --time=1200 \ + --report-interval=1 \ + --rand-type=uniform \ + --db-driver=mysql \ + --mysql-db=sbtest \ + --mysql-host=$aws_nlb_host \ + --mysql-port=$aws_nlb_port \ + run --tables=16 --table-size=10000000 +``` + +## 测试结果 + +### Point Select 性能 + +| Threads | v5.2.2 TPS | v5.3.0 TPS | v5.2.2 95% latency (ms) | v5.3.0 95% latency (ms) | TPS 提升 (%) | +|:----------|:----------|:----------|:----------|:----------|:----------| +|300|267673.17|267516.77|1.76|1.67|-0.06| +|600|369820.29|361672.56|2.91|2.97|-2.20| +|900|417143.31|416479.47|4.1|4.18|-0.16| + +v5.3.0 对比 v5.2.2,Point Select 性能基本持平,略下降了 0.81%。 + +![Point Select](/media/sysbench_v522vsv530_point_select.png) + +### Update Non-index 性能 + +| Threads | v5.2.2 TPS | v5.3.0 TPS | v5.2.2 95% latency (ms) | v5.3.0 95% latency (ms) | TPS 提升 (%) | +|:----------|:----------|:----------|:----------|:----------|:----------| +|300|39715.31|40041.03|11.87|12.08|0.82| +|600|50239.42|51110.04|20.74|20.37|1.73| +|900|57073.97|57252.74|28.16|27.66|0.31| + +v5.3.0 对比 v5.2.2,Update Non-index 性能基本持平,略上升了 0.95%。 + +![Update Non-index](/media/sysbench_v522vsv530_update_non_index.png) + +### Update Index 性能 + +| Threads | v5.2.2 TPS | v5.3.0 TPS | v5.2.2 95% latency (ms) | v5.3.0 95% latency (ms) | TPS 提升 (%) | +|:----------|:----------|:----------|:----------|:----------|:----------| +|300|17634.03|17821.1|25.74|25.74|1.06| +|600|20998.59|21534.13|46.63|45.79|2.55| +|900|23420.75|23859.64|64.47|62.19|1.87| + +v5.3.0 对比 v5.2.2,Update Index 性能基本持平,略上升了 1.83%。 + +![Update Index](/media/sysbench_v522vsv530_update_index.png) + +### Read Write 性能 + +| Threads | v5.2.2 TPS | v5.3.0 TPS | v5.2.2 95% latency (ms) | v5.3.0 95% latency (ms) | TPS 提升 (%) | +|:----------|:----------|:----------|:----------|:----------|:----------| +|300|3872.01|3848.63|106.75|106.75|-0.60| +|600|4514.17|4471.77|200.47|196.89|-0.94| +|900|4877.05|4861.45|287.38|282.25|-0.32| + +v5.3.0 对比 v5.2.2,Read Write 性能基本持平,略下降了 0.62%。 + +![Read Write](/media/sysbench_v522vsv530_read_write.png) diff --git a/markdown-pages/zh/tidb/master/benchmark/benchmark-sysbench-v5.4.0-vs-v5.3.0.md b/markdown-pages/zh/tidb/master/benchmark/benchmark-sysbench-v5.4.0-vs-v5.3.0.md new file mode 100644 index 0000000..f4bedb4 --- /dev/null +++ b/markdown-pages/zh/tidb/master/benchmark/benchmark-sysbench-v5.4.0-vs-v5.3.0.md @@ -0,0 +1,193 @@ +--- +title: TiDB Sysbench 性能对比测试报告 - v5.4.0 对比 v5.3.0 +summary: TiDB v5.4.0 在 OLTP 场景下的 Sysbench 性能比 v5.3.0 有所提升,其中写负载性能提升了 2.59% ~ 4.85%。测试环境为 AWS EC2,硬件配置包括 PD、TiKV、TiDB 和 Sysbench 实例。两个版本使用相同的配置,通过 TiUP 部署。测试结果显示 Point Select 性能基本持平,Update Non-index 性能提升了 2.59%,Update Index 性能提升了 4.85%,Read Write 性能提升了 3.30%。 +--- + +# TiDB Sysbench 性能对比测试报告 - v5.4.0 对比 v5.3.0 + +## 测试概况 + +本次测试对比了 TiDB v5.4.0 和 v5.3.0 在 OLTP 场景下的 Sysbench 性能表现。结果显示,相比于 v5.3.0,v5.4.0 的写负载 (Write-heavy Workload) 性能有 2.59% ~ 4.85% 的提升。 + +## 测试环境 (AWS EC2) + +### 硬件配置 + +| 服务类型 | EC2 类型 | 实例数 | +|:----------|:----------|:----------| +| PD | m5.xlarge | 3 | +| TiKV | i3.4xlarge| 3 | +| TiDB | c5.4xlarge| 3 | +| Sysbench | c5.9xlarge| 1 | + +### 软件版本 + +| 服务类型 | 软件版本 | +|:----------|:-----------| +| PD | v5.3.0、v5.4.0 | +| TiDB | v5.3.0、v5.4.0 | +| TiKV | v5.3.0、v5.4.0 | +| Sysbench | 1.1.0-ead2689 | + +### 参数配置 + +两个版本使用相同的配置 + +#### TiDB 参数配置 + +```yaml +log.level: "error" +performance.max-procs: 20 +prepared-plan-cache.enabled: true +tikv-client.max-batch-wait-time: 2000000 +``` + +#### TiKV 参数配置 + +```yaml +storage.scheduler-worker-pool-size: 5 +raftstore.store-pool-size: 3 +raftstore.apply-pool-size: 3 +rocksdb.max-background-jobs: 8 +raftdb.max-background-jobs: 4 +raftdb.allow-concurrent-memtable-write: true +server.grpc-concurrency: 6 +readpool.unified.min-thread-count: 5 +readpool.unified.max-thread-count: 20 +readpool.storage.normal-concurrency: 10 +pessimistic-txn.pipelined: true +``` + +#### TiDB 全局变量配置 + +```sql +set global tidb_hashagg_final_concurrency=1; +set global tidb_hashagg_partial_concurrency=1; +set global tidb_enable_async_commit = 1; +set global tidb_enable_1pc = 1; +set global tidb_guarantee_linearizability = 0; +set global tidb_enable_clustered_index = 1; +``` + +#### HAProxy 配置 - haproxy.cfg 文件 + +更多有关 HAProxy 在 TiDB 上的使用,可参阅 [HAProxy 在 TiDB 中的最佳实践](/best-practices/haproxy-best-practices.md)。 + +```yaml +global # 全局配置。 + chroot /var/lib/haproxy # 更改当前目录并为启动进程设置超级用户权限,从而提高安全性。 + pidfile /var/run/haproxy.pid # 将 HAProxy 进程的 PID 写入 pidfile。 + maxconn 4000 # 每个 HAProxy 进程所接受的最大并发连接数。 + user haproxy # 同 UID 参数。 + group haproxy # 同 GID 参数,建议使用专用用户组。 + nbproc 64 # 在后台运行时创建的进程数。在启动多个进程转发请求时,确保该值足够大,保证 HAProxy 不会成为瓶颈。 + daemon # 让 HAProxy 以守护进程的方式工作于后台,等同于命令行参数“-D”的功能。当然,也可以在命令行中用“-db”参数将其禁用。 + +defaults # 默认配置。 + log global # 日志继承全局配置段的设置。 + retries 2 # 向上游服务器尝试连接的最大次数,超过此值便认为后端服务器不可用。 + timeout connect 2s # HAProxy 与后端服务器连接超时时间。如果在同一个局域网内,可设置成较短的时间。 + timeout client 30000s # 客户端与 HAProxy 连接后,数据传输完毕,即非活动连接的超时时间。 + timeout server 30000s # 服务器端非活动连接的超时时间。 + +listen tidb-cluster # 配置 database 负载均衡。 + bind 0.0.0.0:3390 # 浮动 IP 和 监听端口。 + mode tcp # HAProxy 要使用第 4 层的传输层。 + balance roundrobin # 连接数最少的服务器优先接收连接。`leastconn` 建议用于长会话服务,例如 LDAP、SQL、TSE 等,而不是短会话协议,如 HTTP。该算法是动态的,对于启动慢的服务器,服务器权重会在运行中作调整。 + server tidb-1 10.9.18.229:4000 check inter 2000 rise 2 fall 3 # 检测 4000 端口,检测频率为每 2000 毫秒一次。如果 2 次检测为成功,则认为服务器可用;如果 3 次检测为失败,则认为服务器不可用。 + server tidb-2 10.9.39.208:4000 check inter 2000 rise 2 fall 3 + server tidb-3 10.9.64.166:4000 check inter 2000 rise 2 fall 3 +``` + +## 测试方案 + +1. 通过 TiUP 部署 TiDB v5.4.0 和 v5.3.0。 +2. 通过 Sysbench 导入 16 张表,每张表有 1000 万行数据。 +3. 分别对每个表执行 `analyze table` 命令。 +4. 备份数据,用于不同并发测试前进行数据恢复,以保证每次数据一致。 +5. 启动 Sysbench 客户端,进行 `point_select`、`read_write`、`update_index` 和 `update_non_index` 测试。通过 HAProxy 向 TiDB 加压,每种负载每个并发数各测试 20 分钟。 +6. 每轮完成后停止集群,使用之前的备份的数据覆盖,再启动集群。 + +### 准备测试数据 + +执行以下命令来准备测试数据: + +```bash +sysbench oltp_common \ + --threads=16 \ + --rand-type=uniform \ + --db-driver=mysql \ + --mysql-db=sbtest \ + --mysql-host=$aws_nlb_host \ + --mysql-port=$aws_nlb_port \ + --mysql-user=root \ + --mysql-password=password \ + prepare --tables=16 --table-size=10000000 +``` + +### 执行测试命令 + +执行以下命令来执行测试: + +```bash +sysbench $testname \ + --threads=$threads \ + --time=1200 \ + --report-interval=1 \ + --rand-type=uniform \ + --db-driver=mysql \ + --mysql-db=sbtest \ + --mysql-host=$aws_nlb_host \ + --mysql-port=$aws_nlb_port \ + run --tables=16 --table-size=10000000 +``` + +## 测试结果 + +### Point Select 性能 + +| Threads | v5.3.0 TPS | v5.4.0 TPS | v5.3.0 95% latency (ms) | v5.4.0 95% latency (ms) | TPS 提升 (%) | +|:----------|:----------|:----------|:----------|:----------|:----------| +|300|266041.84|264345.73|1.96|2.07|-0.64| +|600|351782.71|348715.98|3.43|3.49|-0.87| +|900|386553.31|399777.11|5.09|4.74|3.42| + +v5.4.0 对比 v5.3.0,Point Select 性能基本持平,略提升了 0.64%。 + +![Point Select](/media/sysbench_v530vsv540_point_select.png) + +### Update Non-index 性能 + +| Threads | v5.3.0 TPS | v5.4.0 TPS | v5.3.0 95% latency (ms) | v5.4.0 95% latency (ms) | TPS 提升 (%) | +|:----------|:----------|:----------|:----------|:----------|:----------| +|300|40804.31|41187.1|11.87|11.87|0.94| +|600|51239.4|53172.03|20.74|19.65|3.77| +|900|57897.56|59666.8|27.66|27.66|3.06| + +v5.4.0 对比 v5.3.0,Update Non-index 性能提升了 2.59%。 + +![Update Non-index](/media/sysbench_v530vsv540_update_non_index.png) + +### Update Index 性能 + +| Threads | v5.3.0 TPS | v5.4.0 TPS | v5.3.0 95% latency (ms) | v5.4.0 95% latency (ms) | TPS 提升 (%) | +|:----------|:----------|:----------|:----------|:----------|:----------| +|300|17737.82|18716.5|26.2|24.83|5.52| +|600|21614.39|22670.74|44.98|42.61|4.89| +|900|23933.7|24922.05|62.19|61.08|4.13| + +v5.4.0 对比 v5.3.0,Update Index 性能提升了 4.85%。 + +![Update Index](/media/sysbench_v530vsv540_update_index.png) + +### Read Write 性能 + +| Threads | v5.3.0 TPS | v5.4.0 TPS | v5.3.0 95% latency (ms) | v5.4.0 95% latency (ms) | TPS 提升 (%) | +|:----------|:----------|:----------|:----------|:----------|:----------| +|300|3810.78|3929.29|108.68|106.75|3.11| +|600|4514.28|4684.64|193.38|186.54|3.77| +|900|4842.49|4988.49|282.25|277.21|3.01| + +v5.4.0 对比 v5.3.0,Read Write 性能提升了 3.30%。 + +![Read Write](/media/sysbench_v530vsv540_read_write.png) diff --git a/markdown-pages/zh/tidb/master/benchmark/benchmark-sysbench-v6.0.0-vs-v5.4.0.md b/markdown-pages/zh/tidb/master/benchmark/benchmark-sysbench-v6.0.0-vs-v5.4.0.md new file mode 100644 index 0000000..e8ffadb --- /dev/null +++ b/markdown-pages/zh/tidb/master/benchmark/benchmark-sysbench-v6.0.0-vs-v5.4.0.md @@ -0,0 +1,189 @@ +--- +title: TiDB Sysbench 性能对比测试报告 - v6.0.0 对比 v5.4.0 +summary: TiDB v6.0.0 在 OLTP 场景下的 Sysbench 性能表现对比 v5.4.0。结果显示,Read Write 负载性能有大幅提升,提升了 16.17%,其他负载性能基本持平。测试环境为AWS EC2,硬件配置包括 PD、TiKV、TiDB和Sysbench实例。软件版本为 v5.4.0 和 v6.0.0,参数配置相同。测试方案包括部署 TiDB、导入数据、执行测试命令和备份数据。测试结果显示 Point Select 性能基本持平,Update Non-index 性能基本持平,Update Index 性能下降了 3.05%。Update Index 性能下降了 3.05%。 +--- + +# TiDB Sysbench 性能对比测试报告 - v6.0.0 对比 v5.4.0 + +## 测试概况 + +本次测试对比了 TiDB v6.0.0 和 v5.4.0 在 OLTP 场景下的 Sysbench 性能表现。结果显示,相比于 v5.4.0,v6.0.0 的 Read Write 负载性能有大幅提升,提升了 16.17%。其他负载性能基本与 v5.4.0 的持平。 + +## 测试环境 (AWS EC2) + +### 硬件配置 + +| 服务类型 | EC2 类型 | 实例数 | +|:----------|:----------|:----------| +| PD | m5.xlarge | 3 | +| TiKV | i3.4xlarge| 3 | +| TiDB | c5.4xlarge| 3 | +| Sysbench | c5.9xlarge| 1 | + +### 软件版本 + +| 服务类型 | 软件版本 | +|:----------|:-----------| +| PD | v5.4.0、v6.0.0 | +| TiDB | v5.4.0、v6.0.0 | +| TiKV | v5.4.0、v6.0.0 | +| Sysbench | 1.1.0-df89d34 | + +### 参数配置 + +两个版本使用相同的配置 + +#### TiDB 参数配置 + +```yaml +log.level: "error" +prepared-plan-cache.enabled: true +tikv-client.max-batch-wait-time: 2000000 +``` + +#### TiKV 参数配置 + +```yaml +storage.scheduler-worker-pool-size: 5 +raftstore.store-pool-size: 3 +raftstore.apply-pool-size: 3 +rocksdb.max-background-jobs: 8 +raftdb.max-background-jobs: 4 +raftdb.allow-concurrent-memtable-write: true +server.grpc-concurrency: 6 +readpool.storage.normal-concurrency: 10 +pessimistic-txn.pipelined: true +``` + +#### TiDB 全局变量配置 + +```sql +set global tidb_hashagg_final_concurrency=1; +set global tidb_hashagg_partial_concurrency=1; +set global tidb_enable_async_commit = 1; +set global tidb_enable_1pc = 1; +set global tidb_guarantee_linearizability = 0; +set global tidb_enable_clustered_index = 1; +``` + +#### HAProxy 配置 - haproxy.cfg 文件 + +更多有关 HAProxy 在 TiDB 上的使用,可参阅 [HAProxy 在 TiDB 中的最佳实践](/best-practices/haproxy-best-practices.md)。 + +```yaml +global # 全局配置。 + pidfile /var/run/haproxy.pid # 将 HAProxy 进程的 PID 写入 pidfile。 + maxconn 4000 # 每个 HAProxy 进程所接受的最大并发连接数。 + user haproxy # 同 UID 参数。 + group haproxy # 同 GID 参数,建议使用专用用户组。 + nbproc 64 # 在后台运行时创建的进程数。在启动多个进程转发请求时,确保该值足够大,保证 HAProxy 不会成为瓶颈。 + daemon # 让 HAProxy 以守护进程的方式工作于后台,等同于命令行参数“-D”的功能。当然,也可以在命令行中用“-db”参数将其禁用。 + +defaults # 默认配置。 + log global # 日志继承全局配置段的设置。 + retries 2 # 向上游服务器尝试连接的最大次数,超过此值便认为后端服务器不可用。 + timeout connect 2s # HAProxy 与后端服务器连接超时时间。如果在同一个局域网内,可设置成较短的时间。 + timeout client 30000s # 客户端与 HAProxy 连接后,数据传输完毕,即非活动连接的超时时间。 + timeout server 30000s # 服务器端非活动连接的超时时间。 + +listen tidb-cluster # 配置 database 负载均衡。 + bind 0.0.0.0:3390 # 浮动 IP 和 监听端口。 + mode tcp # HAProxy 要使用第 4 层的传输层。 + balance leastconn # 连接数最少的服务器优先接收连接。`leastconn` 建议用于长会话服务,例如 LDAP、SQL、TSE 等,而不是短会话协议,如 HTTP。该算法是动态的,对于启动慢的服务器,服务器权重会在运行中作调整。 + server tidb-1 10.9.18.229:4000 check inter 2000 rise 2 fall 3 # 检测 4000 端口,检测频率为每 2000 毫秒一次。如果 2 次检测为成功,则认为服务器可用;如果 3 次检测为失败,则认为服务器不可用。 + server tidb-2 10.9.39.208:4000 check inter 2000 rise 2 fall 3 + server tidb-3 10.9.64.166:4000 check inter 2000 rise 2 fall 3 +``` + +## 测试方案 + +1. 通过 TiUP 部署 TiDB v6.0.0 和 v5.4.0。 +2. 通过 Sysbench 导入 16 张表,每张表有 1000 万行数据。 +3. 分别对每个表执行 `analyze table` 命令。 +4. 备份数据,用于不同并发测试前进行数据恢复,以保证每次数据一致。 +5. 启动 Sysbench 客户端,进行 `point_select`、`read_write`、`update_index` 和 `update_non_index` 测试。通过 HAProxy 向 TiDB 加压,每种负载每个并发数各测试 20 分钟。 +6. 每轮完成后停止集群,使用之前的备份的数据覆盖,再启动集群。 + +### 准备测试数据 + +执行以下命令来准备测试数据: + +```bash +sysbench oltp_common \ + --threads=16 \ + --rand-type=uniform \ + --db-driver=mysql \ + --mysql-db=sbtest \ + --mysql-host=$aws_nlb_host \ + --mysql-port=$aws_nlb_port \ + --mysql-user=root \ + --mysql-password=password \ + prepare --tables=16 --table-size=10000000 +``` + +### 执行测试命令 + +执行以下命令来执行测试: + +```bash +sysbench $testname \ + --threads=$threads \ + --time=1200 \ + --report-interval=1 \ + --rand-type=uniform \ + --db-driver=mysql \ + --mysql-db=sbtest \ + --mysql-host=$aws_nlb_host \ + --mysql-port=$aws_nlb_port \ + run --tables=16 --table-size=10000000 +``` + +## 测试结果 + +### Point Select 性能 + +| Threads | v5.4.0 TPS | v6.0.0 TPS | v5.4.0 95% latency (ms) | v6.0.0 95% latency (ms) | TPS 提升 (%) | +|:----------|:----------|:----------|:----------|:----------|:----------| +|300|260085.19|265207.73|1.82|1.93|1.97| +|600|378098.48|365173.66|2.48|2.61|-3.42| +|900|441294.61|424031.23|3.75|3.49|-3.91| + +v6.0.0 对比 v5.4.0,Point Select 性能基本持平,略下降了 1.79%。 + +![Point Select](/media/sysbench_v540vsv600_point_select.png) + +### Update Non-index 性能 + +| Threads | v5.4.0 TPS | v6.0.0 TPS | v5.4.0 95% latency (ms) | v6.0.0 95% latency (ms) | TPS 提升 (%) | +|:----------|:----------|:----------|:----------|:----------|:----------| +|300|41528.7|40814.23|11.65|11.45|-1.72| +|600|53220.96|51746.21|19.29|20.74|-2.77| +|900|59977.58|59095.34|26.68|28.16|-1.47| + +v6.0.0 对比 v5.4.0,Update Non-index 性能基本持平,略下降了 1.98%。 + +![Update Non-index](/media/sysbench_v540vsv600_update_non_index.png) + +### Update Index 性能 + +| Threads | v5.4.0 TPS | v6.0.0 TPS | v5.4.0 95% latency (ms) | v6.0.0 95% latency (ms) | TPS 提升 (%) | +|:----------|:----------|:----------|:----------|:----------|:----------| +|300|18659.11|18187.54|23.95|25.74|-2.53| +|600|23195.83|22270.81|40.37|44.17|-3.99| +|900|25798.31|25118.78|56.84|57.87|-2.63| + +v6.0.0 对比 v5.4.0,Update Index 性能下降了 3.05%。 + +![Update Index](/media/sysbench_v540vsv600_update_index.png) + +### Read Write 性能 + +| Threads | v5.4.0 TPS | v6.0.0 TPS | v5.4.0 95% latency (ms) | v6.0.0 95% latency (ms) | TPS 提升 (%) | +|:----------|:----------|:----------|:----------|:----------|:----------| +|300|4141.72|4829.01|97.55|82.96|16.59| +|600|4892.76|5693.12|173.58|153.02|16.36| +|900|5217.94|6029.95|257.95|235.74|15.56| + +v6.0.0 对比 v5.4.0,Read Write 性能有大幅提升,提升了 16.17%。 + +![Read Write](/media/sysbench_v540vsv600_read_write.png) diff --git a/markdown-pages/zh/tidb/master/benchmark/benchmark-sysbench-v6.1.0-vs-v6.0.0.md b/markdown-pages/zh/tidb/master/benchmark/benchmark-sysbench-v6.1.0-vs-v6.0.0.md new file mode 100644 index 0000000..90de58d --- /dev/null +++ b/markdown-pages/zh/tidb/master/benchmark/benchmark-sysbench-v6.1.0-vs-v6.0.0.md @@ -0,0 +1,187 @@ +--- +title: TiDB Sysbench 性能对比测试报告 - v6.1.0 对比 v6.0.0 +summary: TiDB v6.1.0 在 OLTP 场景下的 Sysbench 性能表现优于 v6.0.0。写性能有提升,Write-heavy 负载性能提升了 2.33% 到 4.61%。Point Select 性能基本持平,略下降了 2.1%。Update Non-index 性能提升了 3.88%。Update Index 性能提升了 4.61%。Read Write 性能提升了 2.23%。 +--- + +# TiDB Sysbench 性能对比测试报告 - v6.1.0 对比 v6.0.0 + +## 测试概况 + +本次测试对比了 TiDB v6.1.0 和 v6.0.0 在 OLTP 场景下的 Sysbench 性能表现。结果显示,相比于 v6.0.0,v6.1.0 的写性能有提升,Write-heavy 负载性能有 2.33% 到 4.61% 的提升。 + +## 测试环境 (AWS EC2) + +### 硬件配置 + +| 服务类型 | EC2 类型 | 实例数 | +|:----------|:----------|:----------| +| PD | m5.xlarge | 3 | +| TiKV | i3.4xlarge| 3 | +| TiDB | c5.4xlarge| 3 | +| Sysbench | c5.9xlarge| 1 | + +### 软件版本 + +| 服务类型 | 软件版本 | +|:----------|:-----------| +| PD | v6.0.0、v6.1.0 | +| TiDB | v6.0.0、v6.1.0 | +| TiKV | v6.0.0、v6.1.0 | +| Sysbench | 1.1.0-df89d34 | + +### 参数配置 + +两个版本使用相同的配置。 + +#### TiDB 参数配置 + +```yaml +log.level: "error" +prepared-plan-cache.enabled: true +tikv-client.max-batch-wait-time: 2000000 +``` + +#### TiKV 参数配置 + +```yaml +storage.scheduler-worker-pool-size: 5 +raftstore.store-pool-size: 3 +raftstore.apply-pool-size: 3 +rocksdb.max-background-jobs: 8 +server.grpc-concurrency: 6 +readpool.storage.normal-concurrency: 10 +``` + +#### TiDB 全局变量配置 + +```sql +set global tidb_hashagg_final_concurrency=1; +set global tidb_hashagg_partial_concurrency=1; +set global tidb_enable_async_commit = 1; +set global tidb_enable_1pc = 1; +set global tidb_guarantee_linearizability = 0; +set global tidb_enable_clustered_index = 1; +set global tidb_prepared_plan_cache_size=1000; +``` + +#### HAProxy 配置 - haproxy.cfg 文件 + +更多有关 HAProxy 在 TiDB 上的使用,可参阅 [HAProxy 在 TiDB 中的最佳实践](/best-practices/haproxy-best-practices.md)。 + +```yaml +global # 全局配置。 + pidfile /var/run/haproxy.pid # 将 HAProxy 进程的 PID 写入 pidfile。 + maxconn 4000 # 每个 HAProxy 进程所接受的最大并发连接数。 + user haproxy # 同 UID 参数。 + group haproxy # 同 GID 参数,建议使用专用用户组。 + nbproc 64 # 在后台运行时创建的进程数。在启动多个进程转发请求时,确保该值足够大,保证 HAProxy 不会成为瓶颈。 + daemon # 让 HAProxy 以守护进程的方式工作于后台,等同于命令行参数“-D”的功能。当然,也可以在命令行中用“-db”参数将其禁用。 + +defaults # 默认配置。 + log global # 日志继承全局配置段的设置。 + retries 2 # 向上游服务器尝试连接的最大次数,超过此值便认为后端服务器不可用。 + timeout connect 2s # HAProxy 与后端服务器连接超时时间。如果在同一个局域网内,可设置成较短的时间。 + timeout client 30000s # 客户端与 HAProxy 连接后,数据传输完毕,即非活动连接的超时时间。 + timeout server 30000s # 服务器端非活动连接的超时时间。 + +listen tidb-cluster # 配置 database 负载均衡。 + bind 0.0.0.0:3390 # 浮动 IP 和 监听端口。 + mode tcp # HAProxy 要使用第 4 层的传输层。 + balance leastconn # 连接数最少的服务器优先接收连接。`leastconn` 建议用于长会话服务,例如 LDAP、SQL、TSE 等,而不是短会话协议,如 HTTP。该算法是动态的,对于启动慢的服务器,服务器权重会在运行中作调整。 + server tidb-1 10.9.18.229:4000 check inter 2000 rise 2 fall 3 # 检测 4000 端口,检测频率为每 2000 毫秒一次。如果 2 次检测为成功,则认为服务器可用;如果 3 次检测为失败,则认为服务器不可用。 + server tidb-2 10.9.39.208:4000 check inter 2000 rise 2 fall 3 + server tidb-3 10.9.64.166:4000 check inter 2000 rise 2 fall 3 +``` + +## 测试方案 + +1. 通过 TiUP 部署 TiDB v6.1.0 和 v6.0.0。 +2. 通过 Sysbench 导入 16 张表,每张表有 1000 万行数据。 +3. 分别对每个表执行 `analyze table` 命令。 +4. 备份数据,用于不同并发测试前进行数据恢复,以保证每次数据一致。 +5. 启动 Sysbench 客户端,进行 `point_select`、`read_write`、`update_index` 和 `update_non_index` 测试。通过 HAProxy 向 TiDB 加压,每种负载每个并发数各测试 20 分钟。 +6. 每轮完成后停止集群,使用之前的备份的数据覆盖,再启动集群。 + +### 准备测试数据 + +执行以下命令来准备测试数据: + +```bash +sysbench oltp_common \ + --threads=16 \ + --rand-type=uniform \ + --db-driver=mysql \ + --mysql-db=sbtest \ + --mysql-host=$aws_nlb_host \ + --mysql-port=$aws_nlb_port \ + --mysql-user=root \ + --mysql-password=password \ + prepare --tables=16 --table-size=10000000 +``` + +### 执行测试命令 + +执行以下命令来执行测试: + +```bash +sysbench $testname \ + --threads=$threads \ + --time=1200 \ + --report-interval=1 \ + --rand-type=uniform \ + --db-driver=mysql \ + --mysql-db=sbtest \ + --mysql-host=$aws_nlb_host \ + --mysql-port=$aws_nlb_port \ + run --tables=16 --table-size=10000000 +``` + +## 测试结果 + +### Point Select 性能 + +| Threads | v6.0.0 TPS | v6.1.0 TPS | v6.0.0 95% latency (ms) | v6.1.0 95% latency (ms) | TPS 提升 (%) | +|:----------|:----------|:----------|:----------|:----------|:----------| +|300|268934.84|265353.15|1.89|1.96|-1.33| +|600|365217.96|358976.94|2.57|2.66|-1.71| +|900|420799.64|407625.11|3.68|3.82|-3.13| + +v6.1.0 对比 v6.0.0,Point Select 性能基本持平,略下降了 2.1%。 + +![Point Select](/media/sysbench_v600vsv610_point_select.png) + +### Update Non-index 性能 + +| Threads | v6.0.0 TPS | v6.1.0 TPS | v6.0.0 95% latency (ms) | v6.1.0 95% latency (ms) | TPS 提升 (%) | +|:----------|:----------|:----------|:----------|:----------|:----------| +|300|41778.95|42991.9|11.24|11.45|2.90 | +|600|52045.39|54099.58|20.74|20.37|3.95| +|900|59243.35|62084.65|27.66|26.68|4.80| + +v6.1.0 对比 v6.0.0,Update Non-index 性能提升了 3.88%。 + +![Update Non-index](/media/sysbench_v600vsv610_update_non_index.png) + +### Update Index 性能 + +| Threads | v6.0.0 TPS | v6.1.0 TPS | v6.0.0 95% latency (ms) | v6.1.0 95% latency (ms) | TPS 提升 (%) | +|:----------|:----------|:----------|:----------|:----------|:----------| +|300|18085.79|19198.89|25.28|23.95|6.15| +|600|22210.8|22877.58|42.61|41.85|3.00| +|900|25249.81|26431.12|55.82|53.85|4.68| + +v6.1.0 对比 v6.0.0,Update Index 性能提升 4.61%。 + +![Update Index](/media/sysbench_v600vsv610_update_index.png) + +### Read Write 性能 + +| Threads | v6.0.0 TPS | v6.1.0 TPS | v6.0.0 95% latency (ms) | v6.1.0 95% latency (ms) | TPS 提升 (%) | +|:----------|:----------|:----------|:----------|:----------|:----------| +|300|4856.23|4914.11|84.47|82.96|1.19| +|600|5676.46|5848.09|161.51|150.29|3.02| +|900|6072.97|6223.95|240.02|223.34|2.49| + +v6.1.0 对比 v6.0.0,Read Write 性能提升了 2.23%。 + +![Read Write](/media/sysbench_v600vsv610_read_write.png) diff --git a/markdown-pages/zh/tidb/master/benchmark/benchmark-sysbench-v6.2.0-vs-v6.1.0.md b/markdown-pages/zh/tidb/master/benchmark/benchmark-sysbench-v6.2.0-vs-v6.1.0.md new file mode 100644 index 0000000..4e279d2 --- /dev/null +++ b/markdown-pages/zh/tidb/master/benchmark/benchmark-sysbench-v6.2.0-vs-v6.1.0.md @@ -0,0 +1,187 @@ +--- +title: TiDB Sysbench 性能对比测试报告 - v6.2.0 对比 v6.1.0 +summary: TiDB v6.2.0 和 v6.1.0 在 OLTP 场景下的 Sysbench 性能对比测试结果显示,两个版本性能基本持平。然而,v6.2.0 的 Point Select 性能下降了 3.58%,而 Update Non-index、Update Index 和 Read Write 性能基本持平或下降了不到 1.5%。 +--- + +# TiDB Sysbench 性能对比测试报告 - v6.2.0 对比 v6.1.0 + +## 测试概况 + +本次测试对比了 TiDB v6.2.0 和 v6.1.0 在 OLTP 场景下的 Sysbench 性能表现。结果显示,两个版本性能基本持平,相比于 v6.1.0,v6.2.0 的 Point Select 性能下降了 3.58%。 + +## 测试环境 (AWS EC2) + +### 硬件配置 + +| 服务类型 | EC2 类型 | 实例数 | +| :------- | :--------- | :----- | +| PD | m5.xlarge | 3 | +| TiKV | i3.4xlarge | 3 | +| TiDB | c5.4xlarge | 3 | +| Sysbench | c5.9xlarge | 1 | + +### 软件版本 + +| 服务类型 | 软件版本 | +| :------- | :------------- | +| PD | v6.1.0、v6.2.0 | +| TiDB | v6.1.0、v6.2.0 | +| TiKV | v6.1.0、v6.2.0 | +| Sysbench | 1.1.0-df89d34 | + +### 参数配置 + +两个版本使用相同的配置。 + +#### TiDB 参数配置 + +```yaml +log.level: "error" +prepared-plan-cache.enabled: true +tikv-client.max-batch-wait-time: 2000000 +``` + +#### TiKV 参数配置 + +```yaml +storage.scheduler-worker-pool-size: 5 +raftstore.store-pool-size: 3 +raftstore.apply-pool-size: 3 +rocksdb.max-background-jobs: 8 +server.grpc-concurrency: 6 +readpool.unified.max-thread-count: 10 +``` + +#### TiDB 全局变量配置 + +```sql +set global tidb_hashagg_final_concurrency=1; +set global tidb_hashagg_partial_concurrency=1; +set global tidb_enable_async_commit = 1; +set global tidb_enable_1pc = 1; +set global tidb_guarantee_linearizability = 0; +set global tidb_enable_clustered_index = 1; +set global tidb_prepared_plan_cache_size=1000; +``` + +#### HAProxy 配置 - haproxy.cfg 文件 + +更多有关 HAProxy 在 TiDB 上的使用,可参阅 [HAProxy 在 TiDB 中的最佳实践](/best-practices/haproxy-best-practices.md)。 + +```yaml +global # 全局配置。 + pidfile /var/run/haproxy.pid # 将 HAProxy 进程的 PID 写入 pidfile。 + maxconn 4000 # 每个 HAProxy 进程所接受的最大并发连接数。 + user haproxy # 同 UID 参数。 + group haproxy # 同 GID 参数,建议使用专用用户组。 + nbproc 64 # 在后台运行时创建的进程数。在启动多个进程转发请求时,确保该值足够大,保证 HAProxy 不会成为瓶颈。 + daemon # 让 HAProxy 以守护进程的方式工作于后台,等同于命令行参数“-D”的功能。当然,也可以在命令行中用“-db”参数将其禁用。 + +defaults # 默认配置。 + log global # 日志继承全局配置段的设置。 + retries 2 # 向上游服务器尝试连接的最大次数,超过此值便认为后端服务器不可用。 + timeout connect 2s # HAProxy 与后端服务器连接超时时间。如果在同一个局域网内,可设置成较短的时间。 + timeout client 30000s # 客户端与 HAProxy 连接后,数据传输完毕,即非活动连接的超时时间。 + timeout server 30000s # 服务器端非活动连接的超时时间。 + +listen tidb-cluster # 配置 database 负载均衡。 + bind 0.0.0.0:3390 # 浮动 IP 和 监听端口。 + mode tcp # HAProxy 要使用第 4 层的传输层。 + balance leastconn # 连接数最少的服务器优先接收连接。`leastconn` 建议用于长会话服务,例如 LDAP、SQL、TSE 等,而不是短会话协议,如 HTTP。该算法是动态的,对于启动慢的服务器,服务器权重会在运行中作调整。 + server tidb-1 10.9.18.229:4000 check inter 2000 rise 2 fall 3 # 检测 4000 端口,检测频率为每 2000 毫秒一次。如果 2 次检测为成功,则认为服务器可用;如果 3 次检测为失败,则认为服务器不可用。 + server tidb-2 10.9.39.208:4000 check inter 2000 rise 2 fall 3 + server tidb-3 10.9.64.166:4000 check inter 2000 rise 2 fall 3 +``` + +## 测试方案 + +1. 通过 TiUP 部署 TiDB v6.2.0 和 v6.1.0。 +2. 通过 Sysbench 导入 16 张表,每张表有 1000 万行数据。 +3. 分别对每个表执行 `analyze table` 命令。 +4. 备份数据,用于不同并发测试前进行数据恢复,以保证每次数据一致。 +5. 启动 Sysbench 客户端,进行 `point_select`、`read_write`、`update_index` 和 `update_non_index` 测试。通过 HAProxy 向 TiDB 加压,每种负载每个并发数各测试 20 分钟。 +6. 每轮完成后停止集群,使用之前的备份的数据覆盖,再启动集群。 + +### 准备测试数据 + +执行以下命令来准备测试数据: + +```bash +sysbench oltp_common \ + --threads=16 \ + --rand-type=uniform \ + --db-driver=mysql \ + --mysql-db=sbtest \ + --mysql-host=$aws_nlb_host \ + --mysql-port=$aws_nlb_port \ + --mysql-user=root \ + --mysql-password=password \ + prepare --tables=16 --table-size=10000000 +``` + +### 执行测试命令 + +执行以下命令来执行测试: + +```bash +sysbench $testname \ + --threads=$threads \ + --time=1200 \ + --report-interval=1 \ + --rand-type=uniform \ + --db-driver=mysql \ + --mysql-db=sbtest \ + --mysql-host=$aws_nlb_host \ + --mysql-port=$aws_nlb_port \ + run --tables=16 --table-size=10000000 +``` + +## 测试结果 + +### Point Select 性能 + +| Threads | v6.1.0 TPS | v6.2.0 TPS | v6.1.0 95% latency (ms) | v6.2.0 95% latency (ms) | TPS 提升 (%) | +| :------ | :--------- | :--------- | :---------------------- | :---------------------- | :----------- | +| 300 | 243530.01 | 236885.24 | 1.93 | 2.07 | -2.73 | +| 600 | 304121.47 | 291395.84 | 3.68 | 4.03 | -4.18 | +| 900 | 327301.23 | 314720.02 | 5 | 5.47 | -3.84 | + +v6.2.0 对比 v6.1.0,Point Select 性能下降了 3.58%。 + +![Point Select](/media/sysbench_v610vsv620_point_select.png) + +### Update Non-index 性能 + +| Threads | v6.1.0 TPS | v6.2.0 TPS | v6.1.0 95% latency (ms) | v6.2.0 95% latency (ms) | TPS 提升 (%) | +| :------ | :--------- | :--------- | :---------------------- | :---------------------- | :----------- | +| 300 | 42608.8 | 42372.82 | 11.45 | 11.24 | -0.55 | +| 600 | 54264.47 | 53672.69 | 18.95 | 18.95 | -1.09 | +| 900 | 60667.47 | 60116.14 | 26.2 | 26.68 | -0.91 | + +v6.2.0 对比 v6.1.0,Update Non-index 性能基本持平,下降了 0.85%。 + +![Update Non-index](/media/sysbench_v610vsv620_update_non_index.png) + +### Update Index 性能 + +| Threads | v6.1.0 TPS | v6.2.0 TPS | v6.1.0 95% latency (ms) | v6.2.0 95% latency (ms) | TPS 提升 (%) | +| :------ | :--------- | :--------- | :---------------------- | :---------------------- | :----------- | +| 300 | 19384.75 | 19353.58 | 23.52 | 23.52 | -0.16 | +| 600 | 24144.78 | 24007.57 | 38.25 | 37.56 | -0.57 | +| 900 | 26770.9 | 26589.84 | 51.94 | 52.89 | -0.68 | + +v6.2.0 对比 v6.1.0,Update Index 性能基本持平,下降了 0.47%。 + +![Update Index](/media/sysbench_v610vsv620_update_index.png) + +### Read Write 性能 + +| Threads | v6.1.0 TPS | v6.2.0 TPS | v6.1.0 95% latency (ms) | v6.2.0 95% latency (ms) | TPS 提升 (%) | +| :------ | :--------- | :--------- | :---------------------- | :---------------------- | :----------- | +| 300 | 4849.67 | 4797.59 | 86 | 84.47 | -1.07 | +| 600 | 5643.89 | 5565.17 | 161.51 | 161.51 | -1.39 | +| 900 | 5954.91 | 5885.22 | 235.74 | 235.74 | -1.17 | + +v6.2.0 对比 v6.1.0,Read Write 性能下降了 1.21%。 + +![Read Write](/media/sysbench_v610vsv620_read_write.png) diff --git a/markdown-pages/zh/tidb/master/benchmark/benchmark-tidb-using-sysbench.md b/markdown-pages/zh/tidb/master/benchmark/benchmark-tidb-using-sysbench.md new file mode 100644 index 0000000..cae6780 --- /dev/null +++ b/markdown-pages/zh/tidb/master/benchmark/benchmark-tidb-using-sysbench.md @@ -0,0 +1,178 @@ +--- +title: 如何用 Sysbench 测试 TiDB +aliases: ['/docs-cn/dev/benchmark/benchmark-tidb-using-sysbench/','/docs-cn/dev/benchmark/how-to-run-sysbench/'] +summary: 使用 Sysbench 1.0 或更新版本测试 TiDB 性能。调整 TiDB 和 TiKV 的日志级别以提高性能。配置 RocksDB 的 block cache 以充分利用内存。调整 Sysbench 配置文件并导入数据。进行数据预热和统计信息收集。执行 Point select、Update index 和 Read-only 测试命令。解决可能出现的性能问题。 +--- + +# 如何用 Sysbench 测试 TiDB + +建议使用 Sysbench 1.0 或之后的更新版本,可在 [Sysbench Release 1.0.20 页面](https://github.com/akopytov/sysbench/releases/tag/1.0.20)下载。 + +## 测试方案 + +### TiDB 配置 + +升高日志级别,可以减少打印日志数量,对 TiDB 的性能有积极影响。具体在 TiUP 配置文件中加入: + +```yaml +server_configs: + tidb: + log.level: "error" +``` + +同时,推荐启用 [`tidb_enable_prepared_plan_cache`](/system-variables.md#tidb_enable_prepared_plan_cache-从-v610-版本开始引入),并保证 `--db-ps-mode` 设置为 `auto`,这样 Sysbench 就可以使用预处理语句。关于 SQL 执行计划缓存的功能及监控,请参考[执行计划缓存](/sql-prepared-plan-cache.md)。 + +> **注意:** +> +> 不同版本 Sysbench 的 `db-ps-mode` 参数默认值可能会不同,建议在命令中显式指定。 + +### TiKV 配置 + +升高 TiKV 的日志级别同样有利于提高性能表现。 + +TiKV 集群存在多个 Column Family,包括 Default CF、Write CF 和 LockCF,主要用于存储不同类型的数据。对于 Sysbench 测试,需要关注 Default CF 和 Write CF,导入数据的 Column Family 在 TiDB 集群中的比例是固定的。这个比例是: + +Default CF : Write CF = 4 : 1 + +在 TiKV 中需要根据机器内存大小配置 RocksDB 的 block cache,以充分利用内存。以 40 GB 内存的虚拟机部署一个 TiKV 为例,其 block cache 建议配置如下: + +```yaml +server_configs: + tikv: + log-level: "error" + rocksdb.defaultcf.block-cache-size: "24GB" + rocksdb.writecf.block-cache-size: "6GB" +``` + +还可以使用共享 block cache 的方式进行设置: + +```yaml +server_configs: + tikv: + storage.block-cache.capacity: "30GB" +``` + +更详细的 TiKV 参数调优请参考 [TiKV 内存参数性能调优](/tune-tikv-memory-performance.md)。 + +## 测试过程 + +> **注意:** +> +> 此文档中的测试并没有使用如 HAproxy 等负载均衡工具。在 TiDB 单一节点上进行 Sysbench 测试,并把结果相加。负载均衡工具和不同版本参数也会影响性能表现。 + +### Sysbench 配置 + +以下为 Sysbench 配置文件样例: + +```txt +mysql-host={TIDB_HOST} +mysql-port=4000 +mysql-user=root +mysql-password=password +mysql-db=sbtest +time=600 +threads={8, 16, 32, 64, 128, 256} +report-interval=10 +db-driver=mysql +``` + +可根据实际需求调整其参数,其中 `TIDB_HOST` 为 TiDB server 的 IP 地址(配置文件中不能写多个地址),`threads` 为测试中的并发连接数,可在 “8, 16, 32, 64, 128, 256” 中调整,导入数据时,建议设置 threads = 8 或者 16。调整后,将该文件保存为名为 **config** 的文件。 + +**配置文件**参考示例如下: + +```txt +mysql-host=172.16.30.33 +mysql-port=4000 +mysql-user=root +mysql-password=password +mysql-db=sbtest +time=600 +threads=16 +report-interval=10 +db-driver=mysql +``` + +### 数据导入 + +> **注意:** +> +> 如果 TiDB 启用了乐观事务模型(默认为悲观锁模式),当发现并发冲突时,会回滚事务。将 `tidb_disable_txn_auto_retry` 设置为 `off` 会开启事务冲突后的自动重试机制,可以尽可能避免事务冲突报错导致 Sysbench 程序退出的问题。 + +在数据导入前,需要对 TiDB 进行简单设置。在 MySQL 客户端中执行如下命令: + +```sql +set global tidb_disable_txn_auto_retry = off; +``` + +然后退出客户端。 + +重新启动 MySQL 客户端执行以下 SQL 语句,创建数据库 `sbtest`: + +```sql +create database sbtest; +``` + +调整 Sysbench 脚本创建索引的顺序。Sysbench 按照“建表->插入数据->创建索引”的顺序导入数据。对于 TiDB 而言,该方式会花费更多的导入时间。你可以通过调整顺序来加速数据的导入。 + +假设使用的 Sysbench 版本为 [1.0.20](https://github.com/akopytov/sysbench/tree/1.0.20),可以通过以下两种方式来修改: + +1. 直接下载为 TiDB 修改好的 [oltp_common.lua](https://raw.githubusercontent.com/pingcap/tidb-bench/master/sysbench/sysbench-patch/oltp_common.lua) 文件,覆盖 `/usr/share/sysbench/oltp_common.lua` 文件。 +2. 将 `/usr/share/sysbench/oltp_common.lua` 的第 [235-240](https://github.com/akopytov/sysbench/blob/1.0.20/src/lua/oltp_common.lua#L235-L240) 行移动到第 198 行以后。 + +> **注意:** +> +> 此操作为可选操作,仅节约了数据导入时间。 + +命令行输入以下命令,开始导入数据,config 文件为上一步中配置的文件: + +```bash +sysbench --config-file=config oltp_point_select --tables=32 --table-size=10000000 prepare +``` + +### 数据预热与统计信息收集 + +数据预热可将磁盘中的数据载入内存的 block cache 中,预热后的数据对系统整体的性能有较大的改善,建议在每次重启集群后进行一次数据预热。 + +```bash +sysbench --config-file=config oltp_point_select --tables=32 --table-size=10000000 prewarm +``` + +### Point select 测试命令 + +```bash +sysbench --config-file=config oltp_point_select --tables=32 --table-size=10000000 --db-ps-mode=auto --rand-type=uniform run +``` + +### Update index 测试命令 + +```bash +sysbench --config-file=config oltp_update_index --tables=32 --table-size=10000000 --db-ps-mode=auto --rand-type=uniform run +``` + +### Read-only 测试命令 + +```bash +sysbench --config-file=config oltp_read_only --tables=32 --table-size=10000000 --db-ps-mode=auto --rand-type=uniform run +``` + +## 常见问题 + +### 在高并发压力下,TiDB、TiKV 的配置都合理,为什么整体性能还是偏低? + +这种情况可能与使用了 proxy 有关。可以尝试直接对单个 TiDB 加压,将求和后的结果与使用 proxy 的情况进行对比。 + +以 HAproxy 为例。`nbproc` 参数可以增加其最大启动的进程数,较新版本的 HAproxy 还支持 `nbthread` 和 `cpu-map` 等。这些都可以减少对其性能的不利影响。 + +### 在高并发压力下,为什么 TiKV 的 CPU 利用率依然很低? + +TiKV 虽然整体 CPU 偏低,但部分模块的 CPU 可能已经达到了很高的利用率。 + +TiKV 的其他模块,如 storage readpool、coprocessor 和 gRPC 的最大并发度限制是可以通过 TiKV 的配置文件进行调整的。 + +通过 Grafana 的 TiKV Thread CPU 监控面板可以观察到其实际使用率。如出现多线程模块瓶颈,可以通过增加该模块并发度进行调整。 + +### 在高并发压力下,TiKV 也未达到 CPU 使用瓶颈,为什么 TiDB 的 CPU 利用率依然很低? + +在某些高端设备上,使用的是 NUMA 架构的 CPU,跨 CPU 访问远端内存将极大降低性能。TiDB 默认将使用服务器所有 CPU,goroutine 的调度不可避免地会出现跨 CPU 内存访问。 + +因此,建议在 NUMA 架构服务器上,部署 *n* 个 TiDB(*n* = NUMA CPU 的个数),同时将 TiDB 的 `max-procs` 变量的值设置为与 NUMA CPU 的核数相同。 diff --git a/markdown-pages/zh/tidb/master/benchmark/benchmark-tidb-using-tpcc.md b/markdown-pages/zh/tidb/master/benchmark/benchmark-tidb-using-tpcc.md new file mode 100644 index 0000000..0fd6fc1 --- /dev/null +++ b/markdown-pages/zh/tidb/master/benchmark/benchmark-tidb-using-tpcc.md @@ -0,0 +1,90 @@ +--- +title: 如何对 TiDB 进行 TPC-C 测试 +aliases: ['/docs-cn/dev/benchmark/benchmark-tidb-using-tpcc/','/docs-cn/dev/benchmark/how-to-run-tpcc/'] +summary: 本文介绍了如何对 TiDB 进行 TPC-C 测试。TPC-C 是一个对 OLTP 系统进行测试的规范,使用商品销售模型对系统进行测试,包含五类事务:NewOrder、Payment、OrderStatus、Delivery、StockLevel。测试使用 tpmC 值衡量系统最大有效吞吐量,以 NewOrder Transaction 为准。使用 go-tpc 进行测试实现,通过 TiUP 命令下载测试程序。测试包括数据导入、运行测试和清理测试数据。 +--- + +# 如何对 TiDB 进行 TPC-C 测试 + +本文介绍如何对 TiDB 进行 [TPC-C](http://www.tpc.org/tpcc/) 测试。 + +TPC-C 是一个对 OLTP(联机交易处理)系统进行测试的规范,使用一个商品销售模型对 OLTP 系统进行测试,其中包含五类事务: + +* NewOrder – 新订单的生成 +* Payment – 订单付款 +* OrderStatus – 最近订单查询 +* Delivery – 配送 +* StockLevel – 库存缺货状态分析 + +在测试开始前,TPC-C Benchmark 规定了数据库的初始状态,也就是数据库中数据生成的规则,其中 ITEM 表中固定包含 10 万种商品,仓库的数量可进行调整,假设 WAREHOUSE 表中有 W 条记录,那么: + +* STOCK 表中应有 W \* 10 万条记录(每个仓库对应 10 万种商品的库存数据) +* DISTRICT 表中应有 W \* 10 条记录(每个仓库为 10 个地区提供服务) +* CUSTOMER 表中应有 W \* 10 \* 3000 条记录(每个地区有 3000 个客户) +* HISTORY 表中应有 W \* 10 \* 3000 条记录(每个客户一条交易历史) +* ORDER 表中应有 W \* 10 \* 3000 条记录(每个地区 3000 个订单),并且最后生成的 900 个订单被添加到 NEW-ORDER 表中,每个订单随机生成 5 ~ 15 条 ORDER-LINE 记录。 + +我们将以 1000 WAREHOUSE 为例进行测试。 + +TPC-C 使用 tpmC 值 (Transactions per Minute) 来衡量系统最大有效吞吐量 (MQTh, Max Qualified Throughput),其中 Transactions 以 NewOrder Transaction 为准,即最终衡量单位为每分钟处理的新订单数。 + +本文使用 [go-tpc](https://github.com/pingcap/go-tpc) 作为 TPC-C 测试实现,可以通过 [TiUP](/tiup/tiup-overview.md) 命令下载测试程序: + +```shell +tiup install bench +``` + +关于 TiUP Bench 组件的详细用法可参考 [TiUP Bench](/tiup/tiup-bench.md)。 + +假设已部署 TiDB 集群,其中 TiDB 节点部署在 172.16.5.140、 172.16.5.141 实例上,端口都为 4000,可按如下步骤进行 TPC-C 测试。 + +## 导入数据 + +**导入数据通常是整个 TPC-C 测试中最耗时,也是最容易出问题的阶段。** + +在 shell 中运行 TiUP 命令: + +```shell +tiup bench tpcc -H 172.16.5.140,172.16.5.141 -P 4000 -D tpcc --warehouses 1000 --threads 20 prepare +``` + +基于不同的机器配置,这个过程可能会持续几个小时。如果是小型集群,可以使用较小的 WAREHOUSE 值进行测试。 + +数据导入完成后,可以通过命令 `tiup bench tpcc -H 172.16.5.140 -P 4000 -D tpcc --warehouses 4 check` 验证数据正确性。 + +## 运行测试 + +运行测试的命令是: + +```shell +tiup bench tpcc -H 172.16.5.140,172.16.5.141 -P 4000 -D tpcc --warehouses 1000 --threads 100 --time 10m run +``` + +运行过程中控制台上会持续打印测试结果: + +```text +[Current] NEW_ORDER - Takes(s): 4.6, Count: 5, TPM: 65.5, Sum(ms): 4604, Avg(ms): 920, 90th(ms): 1500, 99th(ms): 1500, 99.9th(ms): 1500 +[Current] ORDER_STATUS - Takes(s): 1.4, Count: 1, TPM: 42.2, Sum(ms): 256, Avg(ms): 256, 90th(ms): 256, 99th(ms): 256, 99.9th(ms): 256 +[Current] PAYMENT - Takes(s): 6.9, Count: 5, TPM: 43.7, Sum(ms): 2208, Avg(ms): 441, 90th(ms): 512, 99th(ms): 512, 99.9th(ms): 512 +[Current] STOCK_LEVEL - Takes(s): 4.4, Count: 1, TPM: 13.8, Sum(ms): 224, Avg(ms): 224, 90th(ms): 256, 99th(ms): 256, 99.9th(ms): 256 +... +``` + +运行结束后,会打印测试统计结果: + +```text +[Summary] DELIVERY - Takes(s): 455.2, Count: 32, TPM: 4.2, Sum(ms): 44376, Avg(ms): 1386, 90th(ms): 2000, 99th(ms): 4000, 99.9th(ms): 4000 +[Summary] DELIVERY_ERR - Takes(s): 455.2, Count: 1, TPM: 0.1, Sum(ms): 953, Avg(ms): 953, 90th(ms): 1000, 99th(ms): 1000, 99.9th(ms): 1000 +[Summary] NEW_ORDER - Takes(s): 487.8, Count: 314, TPM: 38.6, Sum(ms): 282377, Avg(ms): 899, 90th(ms): 1500, 99th(ms): 1500, 99.9th(ms): 1500 +[Summary] ORDER_STATUS - Takes(s): 484.6, Count: 29, TPM: 3.6, Sum(ms): 8423, Avg(ms): 290, 90th(ms): 512, 99th(ms): 1500, 99.9th(ms): 1500 +[Summary] PAYMENT - Takes(s): 490.1, Count: 321, TPM: 39.3, Sum(ms): 144708, Avg(ms): 450, 90th(ms): 512, 99th(ms): 1000, 99.9th(ms): 1500 +[Summary] STOCK_LEVEL - Takes(s): 487.6, Count: 41, TPM: 5.0, Sum(ms): 9318, Avg(ms): 227, 90th(ms): 512, 99th(ms): 1000, 99.9th(ms): 1000 +``` + +测试完成之后,也可以运行 `tiup bench tpcc -H 172.16.5.140 -P 4000 -D tpcc --warehouses 4 check` 进行数据正确性验证。 + +## 清理测试数据 + +```shell +tiup bench tpcc -H 172.16.5.140 -P 4000 -D tpcc --warehouses 4 cleanup +``` diff --git a/markdown-pages/zh/tidb/master/benchmark/benchmark-tpch.md b/markdown-pages/zh/tidb/master/benchmark/benchmark-tpch.md new file mode 100644 index 0000000..14720a3 --- /dev/null +++ b/markdown-pages/zh/tidb/master/benchmark/benchmark-tpch.md @@ -0,0 +1,109 @@ +--- +title: TiDB TPC-H 50G 性能测试报告 +aliases: ['/docs-cn/dev/benchmark/benchmark-tpch/','/docs-cn/dev/benchmark/tpch/'] +summary: TiDB TPC-H 50G 性能测试报告显示,TiDB 2.0 在大部分查询中表现优于 TiDB 1.0。然而,部分查询在 TiDB 1.0 中未能完成或因内存占用过多而被终止。测试环境包括不同操作系统和硬件信息,测试结果以图表形式展示。 +--- + +# TiDB TPC-H 50G 性能测试报告 + +## 测试目的 + +测试 TiDB 在 OLAP 场景下 1.0 和 2.0 版本的性能对比。 + +> **注意:** +> +> 不同的测试环境可能使测试结果发生改变。 + +## 测试环境 + +### 测试机器信息 + +1. 系统信息 + + | 机器 IP | 操作系统 | 内核版本 | 文件系统类型 | + |--------------|------------------------|------------------------------|--------------| + | 172.16.31.2 | Ubuntu 17.10 64bit | 4.13.0-16-generic | ext4 | + | 172.16.31.3 | Ubuntu 17.10 64bit | 4.13.0-16-generic | ext4 | + | 172.16.31.4 | Ubuntu 17.10 64bit | 4.13.0-16-generic | ext4 | + | 172.16.31.6 | CentOS 7.4.1708 64bit | 3.10.0-693.11.6.el7.x86\_64 | ext4 | + | 172.16.31.8 | CentOS 7.4.1708 64bit | 3.10.0-693.11.6.el7.x86\_64 | ext4 | + | 172.16.31.10 | CentOS 7.4.1708 64bit | 3.10.0-693.11.6.el7.x86\_64 | ext4 | + +2. 硬件信息 + + | 类别 | 名称 | + |------------|------------------------------------------------------| + | CPU | 40 vCPUs, Intel(R) Xeon(R) CPU E5-2630 v4 @ 2.20GHz | + | 内存 | 128GB, 8条16GB RDIMM, 2400MT/s, 双列, x8 带宽 | + | 磁盘 | 2 块 Intel P4500 系列 4T SSD 硬盘 | + | 网卡 | 万兆网卡 | + +### TPC-H + +[tidb-bench/tpch](https://github.com/pingcap/tidb-bench/tree/master/tpch) + +### 集群拓扑 + +| 机器 IP | 部署的实例 | +|--------------|------------| +| 172.16.31.2 | TiKV \* 2 | +| 172.16.31.3 | TiKV \* 2 | +| 172.16.31.6 | TiKV \* 2 | +| 172.16.31.8 | TiKV \* 2 | +| 172.16.31.10 | TiKV \* 2 | +| 172.16.31.10 | PD \* 1 | +| 172.16.31.4 | TiDB \* 1 | + +### TiDB 版本信息 + +TiDB 1.0: + +| 组件名 | 版本号 | commit hash | +|--------|-------------|--------------------------------------------| +| TiDB | v1.0.9 | 4c7ee3580cd0a69319b2c0c08abdc59900df7344 | +| TiKV | v1.0.8 | 2bb923a4cd23dbf68f0d16169fd526dc5c1a9f4a | +| PD | v1.0.8 | 137fa734472a76c509fbfd9cb9bc6d0dc804a3b7 | + +TiDB 2.0: + +| 组件名 | 版本号 | commit hash | +|--------|-------------|--------------------------------------------| +| TiDB | v2.0.0-rc.6 | 82d35f1b7f9047c478f4e1e82aa0002abc8107e7 | +| TiKV | v2.0.0-rc.6 | 8bd5c54966c6ef42578a27519bce4915c5b0c81f | +| PD | v2.0.0-rc.6 | 9b824d288126173a61ce7d51a71fc4cb12360201 | + +## 测试结果 + +| Query ID | TiDB 2.0 | TiDB 1.0 | +|-----------|--------------------|------------------| +| 1 | 33.915s | 215.305s | +| 2 | 25.575s | NaN | +| 3 | 59.631s | 196.003s | +| 4 | 30.234s | 249.919s | +| 5 | 31.666s | OOM | +| 6 | 13.111s | 118.709s | +| 7 | 31.710s | OOM | +| 8 | 31.734s | 800.546s | +| 9 | 34.211s | 630.639s | +| 10 | 30.774s | 133.547s | +| 11 | 27.692s | 78.026s | +| 12 | 27.962s | 124.641s | +| 13 | 27.676s | 174.695s | +| 14 | 19.676s | 110.602s | +| 15 | View Required | View Required | +| 16 | 24.890s | 40.529s | +| 17 | 245.796s | NaN | +| 18 | 91.256s | OOM | +| 19 | 37.615s | NaN | +| 20 | 44.167s | 212.201s | +| 21 | 31.466s | OOM | +| 22 | 31.539s | 125.471s | + +![TPC-H Query Result](/media/tpch-query-result.png) + +说明: + +- 图中橙色为 Release 1.0,蓝色为 Release 2.0,纵坐标是 Query 的处理时间,越低越好 +- Query 15 因为 1.0 和 2.0 都还未支持视图,所以结果标记为 "View Required" +- Query 2, 17, 19 因为 TiDB 1.0 长时间未跑出结果,所以结果标记为 "Nan" +- Query 5, 7, 18, 21 因为 TiDB 1.0 在跑的过程中内存占用过多被 oom-killer 杀死,所以结果标记为 "OOM" diff --git a/markdown-pages/zh/tidb/master/benchmark/online-workloads-and-add-index-operations.md b/markdown-pages/zh/tidb/master/benchmark/online-workloads-and-add-index-operations.md new file mode 100644 index 0000000..b645845 --- /dev/null +++ b/markdown-pages/zh/tidb/master/benchmark/online-workloads-and-add-index-operations.md @@ -0,0 +1,345 @@ +--- +title: 线上负载与 `ADD INDEX` 相互影响测试 +aliases: ['/docs-cn/dev/benchmark/online-workloads-and-add-index-operations/','/docs-cn/dev/benchmark/add-index-with-load/'] +summary: 线上负载与 ADD INDEX 相互影响测试结果显示,当目标列频繁更新时,会造成写冲突和长时间完成。目标列仅涉及查询负载或与线上负载不相关时,可以直接使用默认配置。 +--- + +# 线上负载与 `ADD INDEX` 相互影响测试 + +## 测试目的 + +测试 OLTP 场景下,`ADD INDEX` 与线上负载的相互影响。 + +## 测试版本、时间、地点 + +TiDB 版本:v3.0.1 + +时间:2019 年 7 月 + +地点:北京 + +## 测试环境 + +测试在 Kubernetes 集群上进行,部署了 3 个 TiDB 实例,3 个 TiKV 实例和 3 个 PD 实例。 + +### 版本信息 + +| 组件 | GitHash | +| :--- | :---------------------------------------- | +| TiDB | `9e4e8da3c58c65123db5f26409759fe1847529f8` | +| TiKV | `4151dc8878985df191b47851d67ca21365396133` | +| PD | `811ce0b9a1335d1b2a049fd97ef9e186f1c9efc1` | + +Sysbench 版本:1.0.17 + +### TiDB 参数配置 + +TiDB、TiKV 和 PD 均使用 [TiDB Operator](https://github.com/pingcap/tidb-operator) 默认配置。 + +### 集群拓扑 + +| 机器 IP | 部署实例 | +| :-------------------------------------- | :----------| +| 172.31.8.8 | Sysbench | +| 172.31.7.69, 172.31.5.152, 172.31.11.133 | PD | +| 172.31.4.172, 172.31.1.155, 172.31.9.210 | TiKV | +| 172.31.7.80, 172.31.5.163, 172.31.11.123 | TiDB | + +### 使用 Sysbench 模拟线上负载 + +使用 Sysbench 向集群导入 **1 张表,200 万行数据**。 + +执行如下命令导入数据: + +```sh +sysbench oltp_common \ + --threads=16 \ + --rand-type=uniform \ + --db-driver=mysql \ + --mysql-db=sbtest \ + --mysql-host=$tidb_host \ + --mysql-port=$tidb_port \ + --mysql-user=root \ + prepare --tables=1 --table-size=2000000 +``` + +执行如下命令测试数据: + +```sh +sysbench $testname \ + --threads=$threads \ + --time=300000 \ + --report-interval=15 \ + --rand-type=uniform \ + --rand-seed=$RANDOM \ + --db-driver=mysql \ + --mysql-db=sbtest \ + --mysql-host=$tidb_host \ + --mysql-port=$tidb_port \ + --mysql-user=root \ + run --tables=1 --table-size=2000000 +``` + +## 测试方案 1:`ADD INDEX` 目标列被频繁 Update + +1. 开始 `oltp_read_write` 测试。 +2. 与步骤 1 同时,使用 `alter table sbtest1 add index c_idx(c)` 添加索引。 +3. 在步骤 2 结束,即索引添加完成时,停止步骤 1 的测试。 +4. 获取 `alter table ... add index` 的运行时间、sysbench 在该时间段内的平均 TPS 和 QPS 作为指标。 +5. 逐渐增大 `tidb_ddl_reorg_worker_cnt` 和 `tidb_ddl_reorg_batch_size` 两个参数的值,重复步骤 1-4。 + +### 测试结果 + +#### 无 `ADD INDEX` 时 `oltp_read_write` 的结果 + +| sysbench TPS | sysbench QPS | +| :------- | :-------- | +| 350.31 | 6806 | + +#### `tidb_ddl_reorg_batch_size = 32` + +| tidb_ddl_reorg_worker_cnt | add_index_durations(s) | sysbench TPS | sysbench QPS | +| :------------------------ | :---------------------- | :------------- | :----------- | +| 1 | 402 | 338.4 | 6776 | +| 2 | 266 | 330.3 | 6001 | +| 4 | 174 | 288.5 | 5769 | +| 8 | 129 | 280.6 | 5612 | +| 16 | 90 | 263.5 | 5273 | +| 32 | 54 | 229.2 | 4583 | +| 48 | 57 | 230.1 | 4601 | + +![add-index-load-1-b32](/media/add-index-load-1-b32.png) + +#### `tidb_ddl_reorg_batch_size = 64` + +| tidb_ddl_reorg_worker_cnt | add_index_durations(s) | sysbench TPS | sysbench QPS | +| :------------------------ | :---------------------- | :------------- | :----------- | +| 1 | 264 | 269.4 | 5388 | +| 2 | 163 | 266.2 | 5324 | +| 4 | 105 | 272.5 | 5430 | +| 8 | 78 | 262.5 | 5228 | +| 16 | 57 | 215.5 | 4308 | +| 32 | 42 | 185.2 | 3715 | +| 48 | 45 | 189.2 | 3794 | + +![add-index-load-1-b64](/media/add-index-load-1-b64.png) + +#### `tidb_ddl_reorg_batch_size = 128` + +| tidb_ddl_reorg_worker_cnt | add_index_durations(s) | sysbench TPS | sysbench QPS | +| :------------------------ | :---------------------- | :------------- | :----------- | +| 1 | 171 | 289.1 | 5779 | +| 2 | 110 | 274.2 | 5485 | +| 4 | 79 | 250.6 | 5011 | +| 8 | 51 | 246.1 | 4922 | +| 16 | 39 | 171.1 | 3431 | +| 32 | 35 | 130.8 | 2629 | +| 48 | 35 | 120.5 | 2425 | + +![add-index-load-1-b128](/media/add-index-load-1-b128.png) + +#### `tidb_ddl_reorg_batch_size = 256` + +| tidb_ddl_reorg_worker_cnt | add_index_durations(s) | sysbench TPS | sysbench QPS | +| :------------------------ | :---------------------- | :------------- | :----------- | +| 1 | 145 | 283.0 | 5659 | +| 2 | 96 | 282.2 | 5593 | +| 4 | 56 | 236.5 | 4735 | +| 8 | 45 | 194.2 | 3882 | +| 16 | 39 | 149.3 | 2893 | +| 32 | 36 | 113.5 | 2268 | +| 48 | 33 | 86.2 | 1715 | + +![add-index-load-1-b256](/media/add-index-load-1-b256.png) + +#### `tidb_ddl_reorg_batch_size = 512` + +| tidb_ddl_reorg_worker_cnt | add_index_durations(s) | sysbench TPS | sysbench QPS | +| :------------------------ | :---------------------- | :------------- | :----------- | +| 1 | 135 | 257.8 | 5147 | +| 2 | 78 | 252.8 | 5053 | +| 4 | 49 | 222.7 | 4478 | +| 8 | 36 | 145.4 | 2904 | +| 16 | 33 | 109 | 2190 | +| 32 | 33 | 72.5 | 1503 | +| 48 | 33 | 54.2 | 1318 | + +![add-index-load-1-b512](/media/add-index-load-1-b512.png) + +#### `tidb_ddl_reorg_batch_size = 1024` + +| tidb_ddl_reorg_worker_cnt | add_index_durations(s) | sysbench TPS | sysbench QPS | +| :------------------------ | :---------------------- | :------------- | :----------- | +| 1 | 111 | 244.3 | 4885 | +| 2 | 78 | 228.4 | 4573 | +| 4 | 54 | 168.8 | 3320 | +| 8 | 39 | 123.8 | 2475 | +| 16 | 36 | 59.6 | 1213 | +| 32 | 42 | 93.2 | 1835 | +| 48 | 51 | 115.7 | 2261 | + +![add-index-load-1-b1024](/media/add-index-load-1-b1024.png) + +#### `tidb_ddl_reorg_batch_size = 2048` + +| tidb_ddl_reorg_worker_cnt | add_index_durations(s) | sysbench TPS | sysbench QPS | +| :------------------------ | :---------------------- | :------------- | :----------- | +| 1 | 918 | 243.3 | 4855 | +| 2 | 1160 | 209.9 | 4194 | +| 4 | 342 | 185.4 | 3707 | +| 8 | 1316 | 151.0 | 3027 | +| 16 | 795 | 30.5 | 679 | +| 32 | 1130 | 26.69 | 547 | +| 48 | 893 | 27.5 | 552 | + +![add-index-load-1-b2048](/media/add-index-load-1-b2048.png) + +#### `tidb_ddl_reorg_batch_size = 4096` + +| tidb_ddl_reorg_worker_cnt | add_index_durations(s) | sysbench TPS | sysbench QPS | +| :------------------------ | :---------------------- | :------------- | :----------- | +| 1 | 3042 | 200.0 | 4001 | +| 2 | 3022 | 203.8 | 4076 | +| 4 | 858 | 195.5 | 3971 | +| 8 | 3015 | 177.1 | 3522 | +| 16 | 837 | 143.8 | 2875 | +| 32 | 942 | 114 | 2267 | +| 48 | 187 | 54.2 | 1416 | + +![add-index-load-1-b4096](/media/add-index-load-1-b4096.png) + +### 测试结论 + +若 `ADD INDEX` 的目标列正在进行较为频繁的写操作(本测试涉及列的 `UPDATE`、`INSERT` 和 `DELETE`),默认 `ADD INDEX` 配置对系统的线上负载有比较明显的影响,该影响主要来源于 `ADD INDEX` 与 Column Update 并发进行造成的写冲突,系统的表现反应在: + +- 随着两个参数的逐渐增大,`TiKV_prewrite_latch_wait_duration` 有明显的升高,造成写入变慢。 +- `tidb_ddl_reorg_worker_cnt` 与 `tidb_ddl_reorg_batch_size` 非常大时,`admin show ddl` 命令可以看到 DDL job 的多次重试(例如 `Write conflict, txnStartTS 410327455965380624 is stale [try again later], ErrCount:38, SnapshotVersion:410327228136030220`),此时 `ADD INDEX` 会持续非常久才能完成。 + +## 测试方案 2:`ADD INDEX` 目标列不涉及写入(仅查询) + +1. 开始 `oltp_read_only` 测试。 +2. 与步骤 1 同时,使用 `alter table sbtest1 add index c_idx(c)` 添加索引。 +3. 在步骤 2 结束,即索引添加完成时,停止步骤 1。 +4. 获取 `alter table ... add index` 的运行时间、sysbench 在该时间段内的平均 TPS 和 QPS 作为指标。 +5. 逐渐增大 `tidb_ddl_reorg_worker_cnt` 和 `tidb_ddl_reorg_batch_size` 两个参数,重复步骤 1-4。 + +### 测试结果 + +#### 无 `ADD INDEX` 时 `oltp_read_only` 结果 + +| sysbench TPS | sysbench QPS | +| :------- | :-------- | +| 550.9 | 8812.8 | + +#### `tidb_ddl_reorg_batch_size = 32` + +| tidb_ddl_reorg_worker_cnt | add_index_durations(s) | sysbench TPS | sysbench QPS | +| :------------------------ | :---------------------- | :------------- | :----------- | +| 1 | 376 | 548.9 | 8780 | +| 2 | 212 | 541.5 | 8523 | +| 4 | 135 | 538.6 | 8549 | +| 8 | 114 | 536.7 | 8393 | +| 16 | 77 | 533.9 | 8292 | +| 32 | 46 | 533.4 | 8103 | +| 48 | 46 | 532.2 | 8074 | + +![add-index-load-2-b32](/media/add-index-load-2-b32.png) + +#### `tidb_ddl_reorg_batch_size = 1024` + +| tidb_ddl_reorg_worker_cnt | add_index_durations(s) | sysbench TPS | sysbench QPS | +| :------------------------ | :---------------------- | :------------- | :----------- | +| 1 | 91 | 536.8 | 8316 | +| 2 | 52 | 533.9 | 8165 | +| 4 | 40 | 522.4 | 7947 | +| 8 | 36 | 510 | 7860 | +| 16 | 33 | 485.5 | 7704 | +| 32 | 31 | 467.5 | 7516 | +| 48 | 30 | 562.1 | 7442 | + +![add-index-load-2-b1024](/media/add-index-load-2-b1024.png) + +#### `tidb_ddl_reorg_batch_size = 4096` + +| tidb_ddl_reorg_worker_cnt | add_index_durations(s) | sysbench TPS | sysbench QPS | +| :------------------------ | :---------------------- | :------------- | :----------- | +| 1 | 103 | 502.2 | 7823 | +| 2 | 63 | 486.5 | 7672 | +| 4 | 52 | 467.4 | 7516 | +| 8 | 39 | 452.5 | 7302 | +| 16 | 35 | 447.2 | 7206 | +| 32 | 30 | 441.9 | 7057 | +| 48 | 30 | 440.1 | 7004 | + +![add-index-load-2-b4096](/media/add-index-load-2-b4096.png) + +### 测试结论 + +`ADD INDEX` 的目标列仅有查询负载时,`ADD INDEX` 对负载的影响不明显。 + +## 测试方案 3:集群负载不涉及 `ADD INDEX` 目标列 + +1. 开始 `oltp_read_write` 测试。 +2. 与步骤 1 同时,使用 `alter table test add index pad_idx(pad)` 添加索引。 +3. 在步骤 2 结束,即索引添加完成时,停止步骤 1 的测试。 +4. 获取 `alter table ... add index` 的运行时间、sysbench 在该时间段内的平均 TPS 和 QPS 作为指标。 +5. 逐渐增大 `tidb_ddl_reorg_worker_cnt` 和 `tidb_ddl_reorg_batch_size` 两个参数,重复步骤 1-4。 + +### 测试结果 + +#### 无 `ADD INDEX` 时 `oltp_read_write` 的结果 + +| sysbench TPS | sysbench QPS | +| :------- | :-------- | +| 350.31 | 6806 | + +#### `tidb_ddl_reorg_batch_size = 32` + +| tidb_ddl_reorg_worker_cnt | add_index_durations(s) | sysbench TPS | sysbench QPS | +| :------------------------ | :---------------------- | :------------- | :----------- | +| 1 | 372 | 350.4 | 6892 | +| 2 | 207 | 344.2 | 6700 | +| 4 | 140 | 343.1 | 6672 | +| 8 | 121 | 339.1 | 6579 | +| 16 | 76 | 340 | 6607 | +| 32 | 42 | 343.1 | 6695 | +| 48 | 42 | 333.4 | 6454 | + +![add-index-load-3-b32](/media/add-index-load-3-b32.png) + +#### `tidb_ddl_reorg_batch_size = 1024` + +| tidb_ddl_reorg_worker_cnt | add_index_durations(s) | sysbench TPS | sysbench QPS | +| :------------------------ | :---------------------- | :------------- | :----------- | +| 1 | 94 | 352.4 | 6794 | +| 2 | 50 | 332 | 6493 | +| 4 | 45 | 330 | 6456 | +| 8 | 36 | 325.5 | 6324 | +| 16 | 32 | 312.5 | 6294 | +| 32 | 32 | 300.6 | 6017 | +| 48 | 31 | 279.5 | 5612 | + +![add-index-load-3-b1024](/media/add-index-load-3-b1024.png) + +#### `tidb_ddl_reorg_batch_size = 4096` + +| tidb_ddl_reorg_worker_cnt | add_index_durations(s) | sysbench TPS | sysbench QPS | +| :------------------------ | :---------------------- | :------------- | :----------- | +| 1 | 116 | 325.5 | 6324 | +| 2 | 65 | 312.5 | 6290 | +| 4 | 50 | 300.6 | 6017 | +| 8 | 37 | 279.5 | 5612 | +| 16 | 34 | 250.4 | 5365 | +| 32 | 32 | 220.2 | 4924 | +| 48 | 33 | 214.8 | 4544 | + +![add-index-load-3-b4096](/media/add-index-load-3-b4096.png) + +### 测试结论 + +`ADD INDEX` 的目标列与负载无关时,`ADD INDEX` 对负载的影响不明显。 + +## 总结 + +- 当 `ADD INDEX` 的目标列被频繁更新(包含 `UPDATE`、`INSERT` 和 `DELETE`)时,默认配置会造成较为频繁的写冲突,使得在线负载较大;同时 `ADD INDEX` 也可能由于不断地重试,需要很长的时间才能完成。在本次测试中,将 `tidb_ddl_reorg_worker_cnt` 和 `tidb_ddl_reorg_batch_size` 的乘积调整为默认值的 1/32(例如 `tidb_ddl_reorg_worker_cnt` = 4,`tidb_ddl_reorg_batch_size` = 256)可以取得较好的效果。 +- 当 `ADD INDEX` 的目标列仅涉及查询负载,或者与线上负载不直接相关时,可以直接使用默认配置。 \ No newline at end of file diff --git a/markdown-pages/zh/tidb/master/benchmark/v3.0-performance-benchmarking-with-sysbench.md b/markdown-pages/zh/tidb/master/benchmark/v3.0-performance-benchmarking-with-sysbench.md new file mode 100644 index 0000000..b85aedc --- /dev/null +++ b/markdown-pages/zh/tidb/master/benchmark/v3.0-performance-benchmarking-with-sysbench.md @@ -0,0 +1,273 @@ +--- +title: TiDB Sysbench 性能对比测试报告 - v3.0 对比 v2.1 +aliases: ['/docs-cn/dev/benchmark/v3.0-performance-benchmarking-with-sysbench/','/docs-cn/dev/benchmark/sysbench-v4/'] +summary: TiDB 3.0 版本和 2.1 版本在 OLTP 场景下进行了性能对比测试。测试环境为 AWS EC2,使用 Sysbench 向集群导入 16 张表,每张数据 1000 万。测试结果显示,v3.0 在 Point Select、Update Non-Index、Update Index 和 Read Write 测试中的性能均优于 v2.1。 +--- + +# TiDB Sysbench 性能对比测试报告 - v3.0 对比 v2.1 + +## 测试目的 + +对比 TiDB 3.0 版本和 2.1 版本在 OLTP 场景下的性能。 + +## 测试版本、时间、地点 + +TiDB 版本:v3.0.0 vs. v2.1.13 + +时间:2019 年 6 月 + +地点:北京 + +## 测试环境 + +测试在 AWS EC2 上进行,使用 CentOS-7.6.1810-Nitro (ami-028946f4cffc8b916) 镜像,各组件实例类型如下: + +| 组件 | 实例类型 | +| :--- | :--------- | +| PD | r5d.xlarge | +| TiKV | c5d.4xlarge | +| TiDB | c5.4xlarge | + +Sysbench 版本:1.0.17 + +## 测试方案 + +使用 Sysbench 向集群导入 **16 张表,每张数据 1000 万**。起 3 个 sysbench 分别向 3 个 TiDB 发压,请求并发数逐步增加,单次测试时间 5 分钟。 + +准备数据命令: + +```sh +sysbench oltp_common \ + --threads=16 \ + --rand-type=uniform \ + --db-driver=mysql \ + --mysql-db=sbtest \ + --mysql-host=$tidb_host \ + --mysql-port=$tidb_port \ + --mysql-user=root \ + --mysql-password=password \ + prepare --tables=16 --table-size=10000000 +``` + +执行测试命令: + +```sh +sysbench $testname \ + --threads=$threads \ + --time=300 \ + --report-interval=15 \ + --rand-type=uniform \ + --rand-seed=$RANDOM \ + --db-driver=mysql \ + --mysql-db=sbtest \ + --mysql-host=$tidb_host \ + --mysql-port=$tidb_port \ + --mysql-user=root \ + --mysql-password=password \ + run --tables=16 --table-size=10000000 +``` + +### TiDB 版本信息 + +### v3.0.0 + +| 组件 | GitHash | +| :--- | :---------------------------------------- | +| TiDB | `8efbe62313e2c1c42fd76d35c6f020087eef22c2` | +| TiKV | `a467f410d235fa9c5b3c355e3b620f81d3ac0e0c` | +| PD | `70aaa5eee830e21068f1ba2d4c9bae59153e5ca3` | + +### v2.1.13 + +| 组件 | GitHash | +| :--- | :---------------------------------------- | +| TiDB | `6b5b1a6802f9b8f5a22d8aab24ac80729331e1bc` | +| TiKV | `b3cf3c8d642534ea6fa93d475a46da285cc6acbf` | +| PD | `886362ebfb26ef0834935afc57bcee8a39c88e54` | + +### TiDB 参数配置 + +2.1 和 3.0 中开启 prepared plan cache(出于优化考虑,2.1 的 point select 与 read write 并未开启): + +```toml +[prepared-plan-cache] +enabled = true +``` + +并设置全局变量: + +```sql +set global tidb_hashagg_final_concurrency=1; +set global tidb_hashagg_partial_concurrency=1; +set global tidb_disable_txn_auto_retry=0; +``` + +此外 3.0 还做了如下配置: + +```toml +[tikv-client] +max-batch-wait-time = 2000000 +``` + +### TiKV 参数配置 + +2.1 和 3.0 使用如下配置: + +```toml +log-level = "error" +[readpool.storage] +normal-concurrency = 10 +[server] +grpc-concurrency = 6 +[rocksdb.defaultcf] +block-cache-size = "14GB" +[rocksdb.writecf] +block-cache-size = "8GB" +[rocksdb.lockcf] +block-cache-size = "1GB" +``` + +3.0 还做了如下配置: + +```toml +[raftstore] +apply-pool-size = 3 +store-pool-size = 3 +``` + +### 集群拓扑 + +| 机器 IP | 部署实例 | +| :-------------------------------------- | :----------| +| 172.31.8.8 | 3 * Sysbench | +| 172.31.7.80, 172.31.5.163, 172.31.11.123 | PD | +| 172.31.4.172, 172.31.1.155, 172.31.9.210 | TiKV | +| 172.31.7.80, 172.31.5.163, 172.31.11.123 | TiDB | + +## 测试结果 + +### Point Select 测试 + +**v2.1** + +| Threads | QPS | 95% latency(ms) | +| :------- | :-------- | :------------- | +| 150 | 240304.06 | 1.61 | +| 300 | 276635.75 | 2.97 | +| 600 | 307838.06 | 5.18 | +| 900 | 323667.93 | 7.30 | +| 1200 | 330925.73 | 9.39 | +| 1500 | 336250.38 | 11.65 | + + + +**v3.0** + +| Threads | QPS | 95% latency(ms) | +| :------- | :-------- | :-------------- | +| 150 | 334219.04 | 0.64 | +| 300 | 456444.86 | 1.10 | +| 600 | 512177.48 | 2.11 | +| 900 | 525945.13 | 3.13 | +| 1200 | 534577.36 | 4.18 | +| 1500 | 533944.64 | 5.28 | + +![point select](/media/sysbench_v4_point_select.png) + +### Update Non-Index 测试 + +**v2.1** + +| threads | qps | 95% latency(ms) | +| ------- | -------: | --------------: | +| 150 | 21785.37 | 8.58 | +| 300 | 28979.27 | 13.70 | +| 600 | 34629.72 | 24.83 | +| 900 | 36410.06 | 43.39 | +| 1200 | 37174.15 | 62.19 | +| 1500 | 37408.88 | 87.56 | + +**v3.0** + +| threads | qps | 95% latency(ms) | +| ------- | -------: | --------------: | +| 150 | 28045.75 | 6.67 | +| 300 | 39237.77 | 9.91 | +| 600 | 49536.56 | 16.71 | +| 900 | 55963.73 | 22.69 | +| 1200 | 59904.02 | 29.72 | +| 1500 | 62247.95 | 42.61 | + +![update non-index](/media/sysbench_v4_update_non_index.png) + +### Update Index 测试 + +**v2.1** + +| Threads | QPS | 95% latency(ms) | +| :------- | :------- | :-------------- | +| 150 | 14378.24 | 13.22 | +| 300 | 16916.43 | 24.38 | +| 600 | 17636.11 | 57.87 | +| 900 | 17740.92 | 95.81 | +| 1200 | 17929.24 | 130.13 | +| 1500 | 18012.80 | 161.51 | + +**v3.0** + +| Threads | QPS | 95% latency(ms) | +| :------- | :------- | :-------------| +| 150 | 19047.32 | 10.09 | +| 300 | 24467.64 | 16.71 | +| 600 | 28882.66 | 31.94 | +| 900 | 30298.41 | 57.87 | +| 1200 | 30419.40 | 92.42 | +| 1500 | 30643.55 | 125.52 | + +![update index](/media/sysbench_v4_update_index.png) + +### Read Write 测试 + +**v2.1** + +| Threads | QPS | 95% latency(ms) | +| :------- | :-------- | :-------------- | +| 150 | 85140.60 | 44.98 | +| 300 | 96773.01 | 82.96 | +| 600 | 105139.81 | 153.02 | +| 900 | 110041.83 | 215.44 | +| 1200 | 113242.70 | 277.21 | +| 1500 | 114542.19 | 337.94 | + + + +**v3.0** + +| Threads | QPS | 95% latency(ms) | +| :------- | :-------- | :-------------- | +| 150 | 105692.08 | 35.59 | +| 300 | 129769.69 | 58.92 | +| 600 | 141430.86 | 114.72 | +| 900 | 144371.76 | 170.48 | +| 1200 | 143344.37 | 223.34 | +| 1500 | 144567.91 | 277.21 | + +![read write](/media/sysbench_v4_read_write.png) diff --git a/markdown-pages/zh/tidb/master/benchmark/v3.0-performance-benchmarking-with-tpcc.md b/markdown-pages/zh/tidb/master/benchmark/v3.0-performance-benchmarking-with-tpcc.md new file mode 100644 index 0000000..4571774 --- /dev/null +++ b/markdown-pages/zh/tidb/master/benchmark/v3.0-performance-benchmarking-with-tpcc.md @@ -0,0 +1,96 @@ +--- +title: TiDB TPC-C 性能对比测试报告 - v3.0 对比 v2.1 +aliases: ['/docs-cn/dev/benchmark/v3.0-performance-benchmarking-with-tpcc/','/docs-cn/dev/benchmark/tpcc/'] +summary: TiDB 3.0 版本在 TPC-C 性能上提升了450%,性能表现明显优于 2.1 版本。 +--- + +# TiDB TPC-C 性能对比测试报告 - v3.0 对比 v2.1 + +## 测试目的 + +对比 TiDB 3.0 版本和 2.1 版本的 TPC-C 性能表现。 + +## 测试版本、时间、地点 + +TiDB 版本:v3.0.0 vs. v2.1.13 + +时间:2019 年 6 月 + +地点:北京 + +## 测试环境 + +IDC 机器: + +| 类别 | 名称 | +| :-: | :-: | +| OS | Linux (CentOS 7.3.1611) | +| CPU | 40 vCPUs, Intel(R) Xeon(R) CPU E5-2630 v4 @ 2.20GHz | +| RAM | 128GB | +| DISK | 1.5TB SSD \* 2 | + +本文使用开源的 BenchmarkSQL 5.0 作为 TPC-C 测试工具并添加对 MySQL 协议支持,可以通过以下命令下载测试程序: + +```shell +git clone -b 5.0-mysql-support-opt https://github.com/pingcap/benchmarksql.git +``` + +## 测试方案 + +使用 BenchmarkSQL 向集群导入 **1000 warehouse** 的数据。通过 HAProxy 代理,分别以递增并发数向集群发送请求,单次并发测试时间 10 分钟。 + +### TiDB 版本信息 + +### v3.0.0 + +| 组件 | GitHash | +| :-: | :-: | +| TiDB | 46c38e15eba43346fb3001280c5034385171ee20 | +| TiKV | a467f410d235fa9c5b3c355e3b620f81d3ac0e0c | +| PD | 70aaa5eee830e21068f1ba2d4c9bae59153e5ca3 | + +### v2.1.13 + +| 组件 | GitHash | +| :-: | :-: | +| TiDB | 6b5b1a6802f9b8f5a22d8aab24ac80729331e1bc | +| TiKV | b3cf3c8d642534ea6fa93d475a46da285cc6acbf | +| PD | 886362ebfb26ef0834935afc57bcee8a39c88e54 | + +### TiDB 参数配置 + +```toml +[log] +level = "error" +[performance] +max-procs = 20 +[prepared_plan_cache] +enabled = true +``` + +### TiKV 参数配置 + +默认配置 + +### 集群拓扑 + +| 机器 IP | 部署实例 | +| :-: | :-: | +| 172.16.4.75 | 2\*TiDB 2\*TiKV 1\*pd | +| 172.16.4.76 | 2\*TiDB 2\*TiKV 1\*pd | +| 172.16.4.77 | 2\*TiDB 2\*TiKV 1\*pd | + +## 测试结果 + +| 版本 | threads | tpmC | +| :-: | :-: | :-: | +| v3.0 | 128 | 44068.55 | +| v3.0 | 256 | 47094.06 | +| v3.0 | 512 | 48808.65 | +| v2.1 | 128 | 10641.71 | +| v2.1 | 256 | 10861.62 | +| v2.1 | 512 | 10965.39 | + +![tpcc](/media/tpcc-2.1-3.0.png) + +v3.0 比 v2.1 在 TPC-C 性能上,**提升了 450%**。 diff --git a/markdown-pages/zh/tidb/master/benchmark/v4.0-performance-benchmarking-with-tpcc.md b/markdown-pages/zh/tidb/master/benchmark/v4.0-performance-benchmarking-with-tpcc.md new file mode 100644 index 0000000..f53a60d --- /dev/null +++ b/markdown-pages/zh/tidb/master/benchmark/v4.0-performance-benchmarking-with-tpcc.md @@ -0,0 +1,119 @@ +--- +title: TiDB TPC-C 性能对比测试报告 - v4.0 对比 v3.0 +aliases: ['/docs-cn/dev/benchmark/v4.0-performance-benchmarking-with-tpcc/'] +summary: TiDB v4.0 在 TPC-C 性能上提升了50%,比 v3.0 高出一半。 +--- + +# TiDB TPC-C 性能对比测试报告 - v4.0 对比 v3.0 + +## 测试目的 + +测试对比 TiDB v4.0 和 v3.0 OLTP 场景下的性能。 + +## 测试环境 (AWS EC2) + +### 硬件配置 + +| 服务类型 | EC2 类型 | 实例数 | +|:----------|:----------|:----------| +| PD | m5.xlarge | 3 | +| TiKV | i3.4xlarge| 3 | +| TiDB | c5.4xlarge| 3 | +| TPC-C | m5.4xlarge| 1 | + +### 软件版本 + +| 服务类型 | 软件版本 | +|:----------|:-----------| +| PD | 3.0、4.0 | +| TiDB | 3.0、4.0 | +| TiKV | 3.0、4.0 | +| BenchmarkSQL | 无 | + +### 配置参数 + +#### TiDB v3.0 参数配置 + +```yaml +log.level: "error" +performance.max-procs: 20 +prepared-plan-cache.enabled: true +tikv-client.max-batch-wait-time: 2000000 +``` + +#### TiKV v3.0 参数配置 + +```yaml +storage.scheduler-worker-pool-size: 5 +raftstore.store-pool-size: 3 +raftstore.apply-pool-size: 3 +rocksdb.max-background-jobs: 3 +raftdb.max-background-jobs: 3 +raftdb.allow-concurrent-memtable-write: true +server.grpc-concurrency: 6 +readpool.storage.normal-concurrency: 10 +readpool.coprocessor.normal-concurrency: 5 +``` + +#### TiDB v4.0 参数配置 + +```yaml +log.level: "error" +performance.max-procs: 20 +prepared-plan-cache.enabled: true +tikv-client.max-batch-wait-time: 2000000 +``` + +#### TiKV v4.0 参数配置 + +```yaml +storage.scheduler-worker-pool-size: 5 +raftstore.store-pool-size: 3 +raftstore.apply-pool-size: 3 +rocksdb.max-background-jobs: 3 +raftdb.max-background-jobs: 3 +raftdb.allow-concurrent-memtable-write: true +server.grpc-concurrency: 6 +readpool.unified.min-thread-count: 5 +readpool.unified.max-thread-count: 20 +readpool.storage.normal-concurrency: 10 +pessimistic-txn.pipelined: true +``` + +#### 全局变量配置 + +```sql +set global tidb_hashagg_final_concurrency=1; +set global tidb_hashagg_partial_concurrency=1; +set global tidb_disable_txn_auto_retry=0; +``` + +### 测试方案 + +1. 通过 TiUP 部署 TiDB v4.0 和 v3.0。 + +2. 通过 BenchmarkSQL 导入 TPC-C 5000 Warehouse 数据。 + + 1. 编译 BenchmarkSQL: + + ```bash + git clone https://github.com/pingcap/benchmarksql && cd benchmarksql && ant + ``` + + 2. 进入 `run` 目录,根据实际情况编辑 `props.mysql` 文件,调整 `conn`、`warehouses`、`loadWorkers`、`terminals`、`runMins` 配置项。 + + 3. 运行 `runSQL.sh ./props.mysql sql.mysql/tableCreates.sql` 命令。 + + 4. 运行 `runSQL.sh ./props.mysql sql.mysql/indexCreates.sql` 命令。 + + 5. 运行 MySQL client 并对每个表执行 `analyze table` 语句。 + +3. 运行 `runBenchmark.sh ./props.mysql` 命令。 + +4. 从结果中提取 New Order 的 tpmC 的数据。 + +### 测试结果 + +v4.0 比 v3.0 在 TPC-C 性能上**提升了 50%**。 + +![TPC-C](/media/tpcc_v4vsv3.png) diff --git a/markdown-pages/zh/tidb/master/benchmark/v4.0-performance-benchmarking-with-tpch.md b/markdown-pages/zh/tidb/master/benchmark/v4.0-performance-benchmarking-with-tpch.md new file mode 100644 index 0000000..65eadc7 --- /dev/null +++ b/markdown-pages/zh/tidb/master/benchmark/v4.0-performance-benchmarking-with-tpch.md @@ -0,0 +1,184 @@ +--- +title: TiDB TPC-H 性能对比测试报告 - v4.0 对比 v3.0 +aliases: ['/docs-cn/dev/benchmark/v4.0-performance-benchmarking-with-tpch/'] +summary: TiDB v4.0 和 v3.0 在 OLAP 场景下的性能对比测试报告显示,v4.0 通过智能选择混合读取 TiKV、TiFlash 的数据,性能明显优于 v3.0 仅从 TiKV 读取数据。在完整的 HTAP 形态下,v4.0 的性能得到了显著提升。 +--- + +# TiDB TPC-H 性能对比测试报告 - v4.0 对比 v3.0 + +## 测试目的 + +对比 TiDB v4.0 和 v3.0 OLAP 场景下的性能。 + +因为 TiDB v4.0 中新引入了 [TiFlash](/tiflash/tiflash-overview.md) 组件增强 TiDB HTAP 形态,本文的测试对象如下: + ++ v3.0 仅从 TiKV 读取数据。 ++ v4.0 仅从 TiKV 读取数据。 ++ v4.0 通过智能选择混合读取 TiKV、TiFlash 的数据。 + +## 测试环境 (AWS EC2) + +### 硬件配置 + +| 服务类型 | EC2 类型 | 实例数 | +|:----------------|:------------|:----| +| PD | m5.xlarge | 3 | +| TiDB | c5.4xlarge | 2 | +| TiKV & TiFlash | i3.4xlarge | 3 | +| TPC-H | m5.xlarge | 1 | + +### 软件版本 + +| 服务类型 | 软件版本 | +|:----------|:-----------| +| PD | 3.0、4.0 | +| TiDB | 3.0、4.0 | +| TiKV | 3.0、4.0 | +| TiFlash | 4.0 | +| tiup-bench | 0.2 | + +### 配置参数 + +#### v3.0 + +v3.0 的 TiDB 和 TiKV 均为默认参数配置。 + +##### 变量配置 + +```sql +set global tidb_distsql_scan_concurrency = 30; +set global tidb_projection_concurrency = 16; +set global tidb_hashagg_partial_concurrency = 16; +set global tidb_hashagg_final_concurrency = 16; +set global tidb_hash_join_concurrency = 16; +set global tidb_index_lookup_concurrency = 16; +set global tidb_index_lookup_join_concurrency = 16; +``` + +#### v4.0 + +v4.0 的 TiDB 为默认参数配置。 + +##### TiKV 配置 + +```yaml +readpool.storage.use-unified-pool: false +readpool.coprocessor.use-unified-pool: true +``` + +##### PD 配置 + +```yaml +replication.enable-placement-rules: true +``` + +##### TiFlash 配置 + +```yaml +logger.level: "info" +learner_config.log-level: "info" +``` + +##### 变量配置 + +> **注意:** +> +> 部分参数为 SESSION 变量。建议所有查询都在当前 SESSION 中执行。 + +```sql +set global tidb_allow_batch_cop = 1; +set session tidb_opt_distinct_agg_push_down = 1; +set global tidb_distsql_scan_concurrency = 30; +set global tidb_projection_concurrency = 16; +set global tidb_hashagg_partial_concurrency = 16; +set global tidb_hashagg_final_concurrency = 16; +set global tidb_hash_join_concurrency = 16; +set global tidb_index_lookup_concurrency = 16; +set global tidb_index_lookup_join_concurrency = 16; +``` + +### 测试方案 + +#### 硬件准备 + +为了避免 TiKV 和 TiFlash 争抢磁盘和 I/O 资源,把 EC2 配置的两个 NVMe SSD 盘分别挂载为 `/data1` 及 `/data2`,把 TiKV 的部署至 `/data1`,TiFlash 部署至 `/data2`。 + +#### 测试过程 + +1. 通过 TiUP 部署 TiDB v4.0 和 v3.0。 + +2. 通过 TiUP 的 bench 工具导入 TPC-H 10G 数据。 + + * 执行以下命令将数据导入 v3.0: + + ```bash + tiup bench tpch prepare \ + --host ${tidb_v3_host} --port ${tidb_v3_port} --db tpch_10 \ + --sf 10 \ + --analyze --tidb_build_stats_concurrency 8 --tidb_distsql_scan_concurrency 30 + ``` + + * 执行以下命令将数据导入 v4.0: + + ```bash + tiup bench tpch prepare \ + --host ${tidb_v4_host} --port ${tidb_v4_port} --db tpch_10 --password ${password} \ + --sf 10 \ + --tiflash \ + --analyze --tidb_build_stats_concurrency 8 --tidb_distsql_scan_concurrency 30 + ``` + +3. 运行 TPC-H 的查询。 + + 1. 下载 TPC-H 的 SQL 查询文件: + + ```bash + git clone https://github.com/pingcap/tidb-bench.git && cd tpch/queries + ``` + + 2. 查询并记录耗时。 + + * 对于 TiDB v3.0,使用 MySQL 客户端连接到 TiDB,然后执行查询,记录 v3.0 查询耗时。 + * 对于 TiDB v4.0,使用 MySQL 客户端连接到 TiDB,再根据测试的形态,选择其中一种操作: + * 设置 `set @@session.tidb_isolation_read_engines = 'tikv,tidb';` 后,再执行查询,记录 v4.0 仅从 TiKV 读取数据的查询耗时。 + * 设置 `set @@session.tidb_isolation_read_engines = 'tikv,tiflash,tidb';` 后,再执行查询,记录 v4.0 通过智能选择从 TiKV 和 TiFlash 混合读取数据的查询耗时。 + +4. 提取整理耗时数据。 + +### 测试结果 + +> **注意:** +> +> 本测试所执行 SQL 语句对应的表只有主键,没有建立二级索引。因此以下测试结果为无索引结果。 + +| Query ID | v3.0 | v4.0 TiKV Only | v4.0 TiKV / TiFlash Automatically | +| :-------- | :----------- | :------------ | :-------------- | +| 1 | 7.78s | 7.45s | 2.09s | +| 2 | 3.15s | 1.71s | 1.71s | +| 3 | 6.61s | 4.10s | 4.05s | +| 4 | 2.98s | 2.56s | 1.87s | +| 5 | 20.35s | 5.71s | 8.53s | +| 6 | 4.75s | 2.44s | 0.39s | +| 7 | 7.97s | 3.72s | 3.59s | +| 8 | 5.89s | 3.22s | 8.59s | +| 9 | 34.08s | 11.87s | 15.41s | +| 10 | 4.83s | 2.75s | 3.35s | +| 11 | 3.98s | 1.60s | 1.59s | +| 12 | 5.63s | 3.40s | 1.03s | +| 13 | 5.41s | 4.56s | 4.02s | +| 14 | 5.19s | 3.10s | 0.78s | +| 15 | 10.25s | 1.82s | 1.26s | +| 16 | 2.46s | 1.51s | 1.58s | +| 17 | 23.76s | 12.38s | 8.52s | +| 18 | 17.14s | 16.38s | 16.06s | +| 19 | 5.70s | 4.59s | 3.20s | +| 20 | 4.98s | 1.89s | 1.29s | +| 21 | 11.12s | 6.23s | 6.26s | +| 22 | 4.49s | 3.05s | 2.31s | + +![TPC-H](/media/tpch_v4vsv3.png) + +以上性能图中蓝色为 v3.0,红色为 v4.0(仅从 TiKV 读),黄色为 v4.0(从 TiKV、TiFlash 智能选取),纵坐标是查询的处理时间。纵坐标越低,表示性能越好。 + +- v4.0(仅从 TiKV 读取数据),即 TiDB 仅会从 TiKV 中读取数据。将该结果与 v3.0 的结果对比可得知,TiDB、TiKV 升级至 4.0 版本后,TPC-H 性能得到的提升幅度。 +- v4.0(从 TiKV、TiFlash 智能选取),即 TiDB 优化器会自动根据代价估算选择是否使用 TiFlash 副本。将该结果与 v3.0 的结果对比可得知,在 v4.0 完整的 HTAP 形态下,TPC-H 性能得到的提升幅度。 diff --git a/markdown-pages/zh/tidb/master/benchmark/v5.0-performance-benchmarking-with-tpcc.md b/markdown-pages/zh/tidb/master/benchmark/v5.0-performance-benchmarking-with-tpcc.md new file mode 100644 index 0000000..5575e78 --- /dev/null +++ b/markdown-pages/zh/tidb/master/benchmark/v5.0-performance-benchmarking-with-tpcc.md @@ -0,0 +1,135 @@ +--- +title: TiDB TPC-C 性能对比测试报告 - v5.0 对比 v4.0 +summary: TiDB v5.0 在 TPC-C 性能上提升了 36%,比 v4.0 更优。 +--- + +# TiDB TPC-C 性能对比测试报告 - v5.0 对比 v4.0 + +## 测试目的 + +测试对比 TiDB v5.0 和 v4.0 OLTP 场景下的性能。 + +## 测试环境 (AWS EC2) + +### 硬件配置 + +| 服务类型 | EC2 类型 | 实例数 | +|:----------|:----------|:----------| +| PD | m5.xlarge | 3 | +| TiKV | i3.4xlarge| 3 | +| TiDB | c5.4xlarge| 3 | +| TPC-C | c5.9xlarge| 1 | + +### 软件版本 + +| 服务类型 | 软件版本 | +|:----------|:-----------| +| PD | 4.0、5.0 | +| TiDB | 4.0、5.0 | +| TiKV | 4.0、5.0 | +| BenchmarkSQL | 无 | + +### 配置参数 + +#### TiDB v4.0 参数配置 + +```yaml +log.level: "error" +performance.max-procs: 20 +prepared-plan-cache.enabled: true +tikv-client.max-batch-wait-time: 2000000 +``` + +#### TiKV v4.0 参数配置 + +```yaml +pessimistic-txn.pipelined: true +raftdb.allow-concurrent-memtable-write: true +raftdb.max-background-jobs: 4 +raftstore.apply-max-batch-size: 2048 +raftstore.apply-pool-size: 3 +raftstore.store-max-batch-size: 2048 +raftstore.store-pool-size: 3 +readpool.storage.normal-concurrency: 10 +readpool.unified.max-thread-count: 20 +readpool.unified.min-thread-count: 5 +rocksdb.max-background-jobs: 8 +server.grpc-concurrency: 6 +storage.scheduler-worker-pool-size: 20 +``` + +#### TiDB v5.0 参数配置 + +```yaml +log.level: "error" +performance.max-procs: 20 +prepared-plan-cache.enabled: true +tikv-client.max-batch-wait-time: 2000000 +``` + +#### TiKV v5.0 参数配置 + +```yaml +pessimistic-txn.pipelined: true +raftdb.allow-concurrent-memtable-write: true +raftdb.max-background-jobs: 4 +raftstore.apply-max-batch-size: 2048 +raftstore.apply-pool-size: 3 +raftstore.store-max-batch-size: 2048 +raftstore.store-pool-size: 3 +readpool.storage.normal-concurrency: 10 +readpool.unified.max-thread-count: 20 +readpool.unified.min-thread-count: 5 +rocksdb.max-background-jobs: 8 +server.grpc-concurrency: 6 +storage.scheduler-worker-pool-size: 20 +server.enable-request-batch: false +``` + +#### TiDB v4.0 全局变量配置 + +```sql +set global tidb_hashagg_final_concurrency=1; +set global tidb_hashagg_partial_concurrency=1; +``` + +#### TiDB v5.0 全局变量配置 + +```sql +set global tidb_hashagg_final_concurrency=1; +set global tidb_hashagg_partial_concurrency=1; +set global tidb_enable_async_commit = 1; +set global tidb_enable_1pc = 1; +set global tidb_guarantee_linearizability = 0; +set global tidb_enable_clustered_index = 1; +``` + +## 测试方案 + +1. 通过 TiUP 部署 TiDB v5.0 和 v4.0。 + +2. 通过 BenchmarkSQL 导入 TPC-C 5000 Warehouse 数据。 + + 1. 编译 BenchmarkSQL: + + ```bash + git clone https://github.com/pingcap/benchmarksql && cd benchmarksql && ant + ``` + + 2. 进入 `run` 目录,根据实际情况编辑 `props.mysql` 文件,调整 `conn`、`warehouses`、`loadWorkers`、`terminals`、`runMins` 配置项。 + + 3. 运行 `runSQL.sh ./props.mysql sql.mysql/tableCreates.sql` 命令。 + + 4. 运行 `runSQL.sh ./props.mysql sql.mysql/indexCreates.sql` 命令。 + + 5. 运行 MySQL client 并对每个表执行 `analyze table` 语句。 + +3. 运行 `runBenchmark.sh ./props.mysql` 命令。 + +4. 从结果中提取 New Order 的 tpmC 的数据。 + +## 测试结果 + +v5.0 比 v4.0 在 TPC-C 性能上**提升了 36%**。 + +![TPC-C](/media/tpcc_v5vsv4_corrected_v2.png) diff --git a/markdown-pages/zh/tidb/master/benchmark/v5.1-performance-benchmarking-with-tpcc.md b/markdown-pages/zh/tidb/master/benchmark/v5.1-performance-benchmarking-with-tpcc.md new file mode 100644 index 0000000..b5d452d --- /dev/null +++ b/markdown-pages/zh/tidb/master/benchmark/v5.1-performance-benchmarking-with-tpcc.md @@ -0,0 +1,87 @@ +--- +title: TiDB TPC-C 性能对比测试报告 - v5.1.0 对比 v5.0.2 +summary: TiDB v5.1.0 在 TPC-C 性能上提升了 2.8%,测试环境为 AWS EC2,硬件配置包括 PD、TiKV、TiDB 和 TPC-C 实例,软件版本为 v5.0.2 和 v5.1.0,配置参数相同。测试方案包括部署、创建数据库、导入数据和运行压力测试,结果显示性能提升。 +--- + +# TiDB TPC-C 性能对比测试报告 - v5.1.0 对比 v5.0.2 + +## 测试概况 + +本次测试对比了 TiDB v5.1.0 和 v5.0.2 在 OLTP 场景下的 TPC-C 性能表现。结果显示,v5.1.0 相比于 v5.0.2 在 TPC-C 性能上提升了 2.8%。 + +## 测试环境 (AWS EC2) + +### 硬件配置 + +| 服务类型 | EC2 类型 | 实例数 | +|:----------|:----------|:----------| +| PD | m5.xlarge | 3 | +| TiKV | i3.4xlarge| 3 | +| TiDB | c5.4xlarge| 3 | +| TPC-C | c5.9xlarge| 1 | + +### 软件版本 + +| 服务类型 | 软件版本 | +|:----------|:-----------| +| PD | v5.0.2、v5.1.0 | +| TiDB | v5.0.2、v5.1.0 | +| TiKV | v5.0.2、v5.1.0 | +| TiUP | 1.5.1 | + +### 配置参数 + +两个版本使用同样的配置 + +#### TiDB 参数配置 + +```yaml +log.level: "error" +performance.max-procs: 20 +prepared-plan-cache.enabled: true +tikv-client.max-batch-wait-time: 2000000 +``` + +#### TiKV 参数配置 + +```yaml +pessimistic-txn.pipelined: true +raftdb.allow-concurrent-memtable-write: true +raftdb.max-background-jobs: 4 +raftstore.apply-max-batch-size: 2048 +raftstore.apply-pool-size: 3 +raftstore.store-max-batch-size: 2048 +raftstore.store-pool-size: 3 +readpool.storage.normal-concurrency: 10 +readpool.unified.max-thread-count: 20 +readpool.unified.min-thread-count: 5 +rocksdb.max-background-jobs: 8 +server.grpc-concurrency: 6 +storage.scheduler-worker-pool-size: 20 +server.enable-request-batch: false +``` + +#### TiDB 全局变量配置 + +```sql +set global tidb_hashagg_final_concurrency=1; +set global tidb_hashagg_partial_concurrency=1; +set global tidb_enable_async_commit = 1; +set global tidb_enable_1pc = 1; +set global tidb_guarantee_linearizability = 0; +set global tidb_enable_clustered_index = 1; +``` + +## 测试方案 + +1. 通过 TiUP 部署 TiDB v5.1.0 和 v5.0.2。 +2. 创建数据库 tpcc:`create database tpcc;` +3. 通过 tiup bench 导入 TPC-C 5000 Warehouse 数据:`tiup bench tpcc prepare --warehouses 5000 --db tpcc -H 127.0.0.1 -p 4000`。 +4. 运行 `tiup bench tpcc run -U root --db tpcc --host 127.0.0.1 --port 4000 --time 300s --warehouses 5000 --threads {{thread}}` 命令,通过 HAProxy 向 TiDB 加压。 +5. 从结果中提取 New Order 的 tpmC 的数据。 + +## 测试结果 + +v5.1.0 比 v5.0.2 在 TPC-C 性能上**提升了 2.8%**。 + +![TPC-C](/media/tpcc_v510_vs_v502.png) diff --git a/markdown-pages/zh/tidb/master/benchmark/v5.2-performance-benchmarking-with-tpcc.md b/markdown-pages/zh/tidb/master/benchmark/v5.2-performance-benchmarking-with-tpcc.md new file mode 100644 index 0000000..6830b46 --- /dev/null +++ b/markdown-pages/zh/tidb/master/benchmark/v5.2-performance-benchmarking-with-tpcc.md @@ -0,0 +1,87 @@ +--- +title: TiDB TPC-C 性能对比测试报告 - v5.2.0 对比 v5.1.1 +summary: TiDB v5.2.0 在 TPC-C 性能上下降了 4.22%,测试环境为 AWS EC2,硬件配置包括 PD、TiKV、TiDB 和 TPC-C 实例,软件版本为 v5.1.1 和 v5.2.0,配置参数相同。测试方案包括部署、创建数据库、导入数据和运行压力测试,结果显示性能下降。 +--- + +# TiDB TPC-C 性能对比测试报告 - v5.2.0 对比 v5.1.1 + +## 测试概况 + +本次测试对比了 TiDB v5.2.0 和 v5.1.1 在 OLTP 场景下的 TPC-C 性能表现。结果显示,v5.2.0 相比于 v5.1.1 在 TPC-C 性能上下降了 4.22%。 + +## 测试环境 (AWS EC2) + +### 硬件配置 + +| 服务类型 | EC2 类型 | 实例数 | +|:----------|:----------|:----------| +| PD | m5.xlarge | 3 | +| TiKV | i3.4xlarge| 3 | +| TiDB | c5.4xlarge| 3 | +| TPC-C | c5.9xlarge| 1 | + +### 软件版本 + +| 服务类型 | 软件版本 | +|:----------|:-----------| +| PD | v5.1.1、v5.2.0 | +| TiDB | v5.1.1、v5.2.0 | +| TiKV | v5.1.1、v5.2.0 | +| TiUP | 1.5.1 | + +### 配置参数 + +两个版本使用同样的配置 + +#### TiDB 参数配置 + +```yaml +log.level: "error" +performance.max-procs: 20 +prepared-plan-cache.enabled: true +tikv-client.max-batch-wait-time: 2000000 +``` + +#### TiKV 参数配置 + +```yaml +pessimistic-txn.pipelined: true +raftdb.allow-concurrent-memtable-write: true +raftdb.max-background-jobs: 4 +raftstore.apply-max-batch-size: 2048 +raftstore.apply-pool-size: 3 +raftstore.store-max-batch-size: 2048 +raftstore.store-pool-size: 3 +readpool.storage.normal-concurrency: 10 +readpool.unified.max-thread-count: 20 +readpool.unified.min-thread-count: 5 +rocksdb.max-background-jobs: 8 +server.grpc-concurrency: 6 +storage.scheduler-worker-pool-size: 20 +server.enable-request-batch: false +``` + +#### TiDB 全局变量配置 + +```sql +set global tidb_hashagg_final_concurrency=1; +set global tidb_hashagg_partial_concurrency=1; +set global tidb_enable_async_commit = 1; +set global tidb_enable_1pc = 1; +set global tidb_guarantee_linearizability = 0; +set global tidb_enable_clustered_index = 1; +``` + +## 测试方案 + +1. 通过 TiUP 部署 TiDB v5.2.0 和 v5.1.1。 +2. 创建数据库 tpcc:`create database tpcc;` +3. 通过 tiup bench 导入 TPC-C 5000 Warehouse 数据:`tiup bench tpcc prepare --warehouses 5000 --db tpcc -H 127.0.0.1 -p 4000`。 +4. 运行 `tiup bench tpcc run -U root --db tpcc --host 127.0.0.1 --port 4000 --time 300s --warehouses 5000 --threads {{thread}}` 命令,通过 HAProxy 向 TiDB 加压。 +5. 从结果中提取 New Order 的 tpmC 的数据。 + +## 测试结果 + +v5.2.0 相比 v5.1.1 在 TPC-C 性能上**下降了 4.22%**。 + +![TPC-C](/media/tpcc_v511_vs_v520.png) diff --git a/markdown-pages/zh/tidb/master/benchmark/v5.3-performance-benchmarking-with-tpcc.md b/markdown-pages/zh/tidb/master/benchmark/v5.3-performance-benchmarking-with-tpcc.md new file mode 100644 index 0000000..f3abdb5 --- /dev/null +++ b/markdown-pages/zh/tidb/master/benchmark/v5.3-performance-benchmarking-with-tpcc.md @@ -0,0 +1,123 @@ +--- +title: TiDB TPC-C 性能对比测试报告 - v5.3.0 对比 v5.2.2 +summary: TiDB v5.3.0 在 TPC-C 性能上略下降了 2.99%,与 v5.2.2 相比。测试结果显示,不同线程下,v5.3.0 的 tpmC 提升率分别为 -1.54%,-2.33%,-2.99%,-5.10%。 +--- + +# TiDB TPC-C 性能对比测试报告 - v5.3.0 对比 v5.2.2 + +## 测试概况 + +本次测试对比了 TiDB v5.3.0 和 v5.2.2 在 OLTP 场景下的 TPC-C 性能表现。结果显示,v5.3.0 相比于 v5.2.2 在 TPC-C 性能上略下降了 2.99%。 + +## 测试环境 (AWS EC2) + +### 硬件配置 + +| 服务类型 | EC2 类型 | 实例数 | +|:----------|:----------|:----------| +| PD | m5.xlarge | 3 | +| TiKV | i3.4xlarge| 3 | +| TiDB | c5.4xlarge| 3 | +| TPC-C | c5.9xlarge| 1 | + +### 软件版本 + +| 服务类型 | 软件版本 | +|:----------|:-----------| +| PD | v5.2.2、v5.3.0 | +| TiDB | v5.2.2、v5.3.0 | +| TiKV | v5.2.2、v5.3.0 | +| TiUP | 1.5.1 | + +### 配置参数 + +两个版本使用同样的配置 + +#### TiDB 参数配置 + +```yaml +log.level: "error" +performance.max-procs: 20 +prepared-plan-cache.enabled: true +tikv-client.max-batch-wait-time: 2000000 +``` + +#### TiKV 参数配置 + +```yaml +pessimistic-txn.pipelined: true +raftdb.allow-concurrent-memtable-write: true +raftdb.max-background-jobs: 4 +raftstore.apply-max-batch-size: 2048 +raftstore.apply-pool-size: 3 +raftstore.store-max-batch-size: 2048 +raftstore.store-pool-size: 3 +readpool.storage.normal-concurrency: 10 +readpool.unified.max-thread-count: 20 +readpool.unified.min-thread-count: 5 +rocksdb.max-background-jobs: 8 +server.grpc-concurrency: 6 +storage.scheduler-worker-pool-size: 20 +``` + +#### TiDB 全局变量配置 + +```sql +set global tidb_hashagg_final_concurrency=1; +set global tidb_hashagg_partial_concurrency=1; +set global tidb_enable_async_commit = 1; +set global tidb_enable_1pc = 1; +set global tidb_guarantee_linearizability = 0; +set global tidb_enable_clustered_index = 1; +``` + +#### HAProxy 配置 - haproxy.cfg 文件 + +更多有关 HAProxy 在 TiDB 上的使用,可参阅 [HAProxy 在 TiDB 中的最佳实践](/best-practices/haproxy-best-practices.md)。 + +```yaml +global # 全局配置。 + chroot /var/lib/haproxy # 更改当前目录并为启动进程设置超级用户权限,从而提高安全性。 + pidfile /var/run/haproxy.pid # 将 HAProxy 进程的 PID 写入 pidfile。 + maxconn 4000 # 每个 HAProxy 进程所接受的最大并发连接数。 + user haproxy # 同 UID 参数。 + group haproxy # 同 GID 参数,建议使用专用用户组。 + nbproc 64 # 在后台运行时创建的进程数。在启动多个进程转发请求时,确保该值足够大,保证 HAProxy 不会成为瓶颈。 + daemon # 让 HAProxy 以守护进程的方式工作于后台,等同于命令行参数“-D”的功能。当然,也可以在命令行中用“-db”参数将其禁用。 + +defaults # 默认配置。 + log global # 日志继承全局配置段的设置。 + retries 2 # 向上游服务器尝试连接的最大次数,超过此值便认为后端服务器不可用。 + timeout connect 2s # HAProxy 与后端服务器连接超时时间。如果在同一个局域网内,可设置成较短的时间。 + timeout client 30000s # 客户端与 HAProxy 连接后,数据传输完毕,即非活动连接的超时时间。 + timeout server 30000s # 服务器端非活动连接的超时时间。 + +listen tidb-cluster # 配置 database 负载均衡。 + bind 0.0.0.0:3390 # 浮动 IP 和 监听端口。 + mode tcp # HAProxy 要使用第 4 层的传输层。 + balance roundrobin # 连接数最少的服务器优先接收连接。`leastconn` 建议用于长会话服务,例如 LDAP、SQL、TSE 等,而不是短会话协议,如 HTTP。该算法是动态的,对于启动慢的服务器,服务器权重会在运行中作调整。 + server tidb-1 10.9.18.229:4000 check inter 2000 rise 2 fall 3 # 检测 4000 端口,检测频率为每 2000 毫秒一次。如果 2 次检测为成功,则认为服务器可用;如果 3 次检测为失败,则认为服务器不可用。 + server tidb-2 10.9.39.208:4000 check inter 2000 rise 2 fall 3 + server tidb-3 10.9.64.166:4000 check inter 2000 rise 2 fall 3 +``` + +## 测试方案 + +1. 通过 TiUP 部署 TiDB v5.3.0 和 v5.2.2。 +2. 创建数据库 tpcc:`create database tpcc;` +3. 通过 tiup bench 导入 TPC-C 5000 Warehouse 数据:`tiup bench tpcc prepare --warehouses 5000 --db tpcc -H 127.0.0.1 -p 4000`。 +4. 运行 `tiup bench tpcc run -U root --db tpcc --host 127.0.0.1 --port 4000 --time 1800s --warehouses 5000 --threads {{thread}}` 命令,通过 HAProxy 向 TiDB 加压,每个并发数各测试 30 分钟。 +5. 从结果中提取 New Order 的 tpmC 的数据。 + +## 测试结果 + +v5.3.0 相比 v5.2.2 在 TPC-C 性能上**略下降了 2.99%**。 + +| Threads | v5.2.2 tpmC | v5.3.0 tpmC | tpmC 提升 (%) | +|:----------|:----------|:----------|:----------| +|50|42228.8|41580|-1.54| +|100|49400|48248.2|-2.33| +|200|54436.6|52809.4|-2.99| +|400|57026.7|54117.1|-5.10| + +![TPC-C](/media/tpcc_v522_vs_v530.png) diff --git a/markdown-pages/zh/tidb/master/benchmark/v5.4-performance-benchmarking-with-tpcc.md b/markdown-pages/zh/tidb/master/benchmark/v5.4-performance-benchmarking-with-tpcc.md new file mode 100644 index 0000000..96efb3e --- /dev/null +++ b/markdown-pages/zh/tidb/master/benchmark/v5.4-performance-benchmarking-with-tpcc.md @@ -0,0 +1,123 @@ +--- +title: TiDB TPC-C 性能对比测试报告 - v5.4.0 对比 v5.3.0 +summary: TiDB v5.4.0 在 TPC-C 性能上提升了 3.16%,测试结果显示不同并发下,性能均有提升。 +--- + +# TiDB TPC-C 性能对比测试报告 - v5.4.0 对比 v5.3.0 + +## 测试概况 + +本次测试对比了 TiDB v5.4.0 和 v5.3.0 在 OLTP 场景下的 TPC-C 性能表现。结果显示,v5.4.0 相比于 v5.3.0 在 TPC-C 性能提升了 3.16%。 + +## 测试环境 (AWS EC2) + +### 硬件配置 + +| 服务类型 | EC2 类型 | 实例数 | +|:----------|:----------|:----------| +| PD | m5.xlarge | 3 | +| TiKV | i3.4xlarge| 3 | +| TiDB | c5.4xlarge| 3 | +| TPC-C | c5.9xlarge| 1 | + +### 软件版本 + +| 服务类型 | 软件版本 | +|:----------|:-----------| +| PD | v5.3.0、v5.4.0 | +| TiDB | v5.3.0、v5.4.0 | +| TiKV | v5.3.0、v5.4.0 | +| TiUP | 1.5.1 | + +### 配置参数 + +两个版本使用同样的配置 + +#### TiDB 参数配置 + +```yaml +log.level: "error" +performance.max-procs: 20 +prepared-plan-cache.enabled: true +tikv-client.max-batch-wait-time: 2000000 +``` + +#### TiKV 参数配置 + +```yaml +pessimistic-txn.pipelined: true +raftdb.allow-concurrent-memtable-write: true +raftdb.max-background-jobs: 4 +raftstore.apply-max-batch-size: 2048 +raftstore.apply-pool-size: 3 +raftstore.store-max-batch-size: 2048 +raftstore.store-pool-size: 3 +readpool.storage.normal-concurrency: 10 +readpool.unified.max-thread-count: 20 +readpool.unified.min-thread-count: 5 +rocksdb.max-background-jobs: 8 +server.grpc-concurrency: 6 +storage.scheduler-worker-pool-size: 20 +``` + +#### TiDB 全局变量配置 + +```sql +set global tidb_hashagg_final_concurrency=1; +set global tidb_hashagg_partial_concurrency=1; +set global tidb_enable_async_commit = 1; +set global tidb_enable_1pc = 1; +set global tidb_guarantee_linearizability = 0; +set global tidb_enable_clustered_index = 1; +``` + +#### HAProxy 配置 - haproxy.cfg 文件 + +更多有关 HAProxy 在 TiDB 上的使用,可参阅 [HAProxy 在 TiDB 中的最佳实践](/best-practices/haproxy-best-practices.md)。 + +```yaml +global # 全局配置。 + chroot /var/lib/haproxy # 更改当前目录并为启动进程设置超级用户权限,从而提高安全性。 + pidfile /var/run/haproxy.pid # 将 HAProxy 进程的 PID 写入 pidfile。 + maxconn 4000 # 每个 HAProxy 进程所接受的最大并发连接数。 + user haproxy # 同 UID 参数。 + group haproxy # 同 GID 参数,建议使用专用用户组。 + nbproc 64 # 在后台运行时创建的进程数。在启动多个进程转发请求时,确保该值足够大,保证 HAProxy 不会成为瓶颈。 + daemon # 让 HAProxy 以守护进程的方式工作于后台,等同于命令行参数“-D”的功能。当然,也可以在命令行中用“-db”参数将其禁用。 + +defaults # 默认配置。 + log global # 日志继承全局配置段的设置。 + retries 2 # 向上游服务器尝试连接的最大次数,超过此值便认为后端服务器不可用。 + timeout connect 2s # HAProxy 与后端服务器连接超时时间。如果在同一个局域网内,可设置成较短的时间。 + timeout client 30000s # 客户端与 HAProxy 连接后,数据传输完毕,即非活动连接的超时时间。 + timeout server 30000s # 服务器端非活动连接的超时时间。 + +listen tidb-cluster # 配置 database 负载均衡。 + bind 0.0.0.0:3390 # 浮动 IP 和 监听端口。 + mode tcp # HAProxy 要使用第 4 层的传输层。 + balance roundrobin # 连接数最少的服务器优先接收连接。`leastconn` 建议用于长会话服务,例如 LDAP、SQL、TSE 等,而不是短会话协议,如 HTTP。该算法是动态的,对于启动慢的服务器,服务器权重会在运行中作调整。 + server tidb-1 10.9.18.229:4000 check inter 2000 rise 2 fall 3 # 检测 4000 端口,检测频率为每 2000 毫秒一次。如果 2 次检测为成功,则认为服务器可用;如果 3 次检测为失败,则认为服务器不可用。 + server tidb-2 10.9.39.208:4000 check inter 2000 rise 2 fall 3 + server tidb-3 10.9.64.166:4000 check inter 2000 rise 2 fall 3 +``` + +## 测试方案 + +1. 通过 TiUP 部署 TiDB v5.4.0 和 v5.3.0。 +2. 创建数据库 tpcc:`create database tpcc;`。 +3. 通过 tiup bench 导入 TPC-C 5000 Warehouse 数据:`tiup bench tpcc prepare --warehouses 5000 --db tpcc -H 127.0.0.1 -P 4000`。 +4. 运行 `tiup bench tpcc run -U root --db tpcc --host 127.0.0.1 --port 4000 --time 1800s --warehouses 5000 --threads {{thread}}` 命令,通过 HAProxy 向 TiDB 加压,每个并发数各测试 30 分钟。 +5. 从结果中提取 New Order 的 tpmC 的数据。 + +## 测试结果 + +v5.4.0 相比 v5.3.0 在 TPC-C 性能上**提升了 3.16%**。 + +| Threads | v5.3.0 tpmC | v5.4.0 tpmC | tpmC 提升 (%) | +|:----------|:----------|:----------|:----------| +|50|43002.4|44204.4|2.80| +|100|50162.7|52305|4.27| +|200|55768.2|57690.7|3.45| +|400|56836.8|58034.6|2.11| + +![TPC-C](/media/tpcc_v530_vs_v540.png) diff --git a/markdown-pages/zh/tidb/master/benchmark/v5.4-performance-benchmarking-with-tpch.md b/markdown-pages/zh/tidb/master/benchmark/v5.4-performance-benchmarking-with-tpch.md new file mode 100644 index 0000000..781b600 --- /dev/null +++ b/markdown-pages/zh/tidb/master/benchmark/v5.4-performance-benchmarking-with-tpch.md @@ -0,0 +1,117 @@ +--- +title: TiDB TPC-H 性能对比测试报告 - v5.4 MPP 模式对比 Greenplum 6.15.0 以及 Apache Spark 3.1.1 +summary: TiDB v5.4 MPP 模式在 TPC-H 100 GB 数据下的性能测试结果显示,相对于 Greenplum 6.15.0 和 Apache Spark 3.1.1,有 2-3 倍的性能提升。测试环境包括 TiDB v5.4 MPP、Greenplum 6.15.0 和 Apache Spark 3.1.1 + Parquet。测试结果显示 TiDB v5.4 在各个查询中的处理时间明显低于其他两者,表现更优。 +--- + +# TiDB TPC-H 性能对比测试报告 - v5.4 MPP 模式对比 Greenplum 6.15.0 以及 Apache Spark 3.1.1 + +## 测试概况 + +本次测试对比了 TiDB v5.4 MPP 模式下和主流分析引擎例如 Greenplum 和 Apache Spark 最新版本在 TPC-H 100 GB 数据下的性能表现。结果显示,TiDB v5.4 MPP 模式下相对这些方案有 2-3 倍的性能提升。 + +TiDB v5.0 中引入的 [TiFlash](/tiflash/tiflash-overview.md) 组件的 MPP 模式大大幅增强了 TiDB HTAP 形态。本文的测试对象如下: + ++ TiDB v5.4 MPP 执行模式下的列式存储 ++ Greenplum 6.15.0 ++ Apache Spark 3.1.1 + Parquet + +## 测试环境 + +### 硬件配置 + +| 实例类型 | 实例数 | +|:----------|:----------| +| PD | 1 | +| TiDB | 1 | +| TiKV | 3 | +| TiFlash | 3 | + ++ CPU:Intel(R) Xeon(R) CPU E5-2630 v4 @ 2.20GHz,40 核 ++ 内存:189 GB ++ 磁盘:NVMe 3TB * 2 + +### 软件版本 + +| 服务类型 | 软件版本 | +|:----------|:-----------| +| TiDB | 5.4 | +| Greenplum | 6.15.0 | +| Apache Spark | 3.1.1 | + +### 配置参数 + +#### TiDB v5.4 配置 + +v5.4 的 TiDB 集群除以下配置项外均使用默认参数配置。所有 TPC-H 测试表均以 TiFlash 列存进行同步,无额外分区和索引。 + +在 TiFlash 的 `users.toml` 配置文件中进行如下配置: + +```toml +[profiles.default] +max_memory_usage = 10000000000000 +``` + +使用 SQL 语句设置以下会话变量: + +```sql +set @@tidb_isolation_read_engines='tiflash'; +set @@tidb_allow_mpp=1; +set @@tidb_mem_quota_query = 10 << 30; +``` + +#### Greenplum 配置 + +Greenplum 集群使用额外的一台 Master 节点部署(共四台),每台 Segment Server 部署 8 Segments(每个 NVMe SSD 各 4 个),总共 24 Segments。存储格式为 append-only / 列式存储,分区键为主键。 + +``` +log_statement = all +gp_autostats_mode = none +statement_mem = 2048MB +gp_vmem_protect_limit = 16384 +``` + +#### Apache Spark 配置 + +Apache Spark 测试使用 Apache Parquet 作为存储格式,数据存储在 HDFS 上。HDFS 为三节点,为每个节点指定两块 NVMe SSD 盘作为数据盘。通过 Standalone 方式启动 Spark 集群,使用 NVMe SSD 盘作为 `spark.local.dir` 本地目录以借助快速盘加速 Shuffle Spill 过程,无额外分区和索引。 + +``` +--driver-memory 20G +--total-executor-cores 120 +--executor-cores 5 +--executor-memory 15G +``` + +## 测试结果 + +> **注意:** +> +> 以下测试结果均为 3 次测试的平均值,单位均为秒。 + +| Query ID | TiDB v5.4 | Greenplum 6.15.0 | Apache Spark 3.1.1 + Parquet | +| :-------- | :----------- | :------------ | :-------------- | +| 1 | 8.08 | 64.1307 | 52.64 | +| 2 | 2.53 | 4.76612 | 11.83 | +| 3 | 4.84 | 15.62898 | 13.39 | +| 4 | 10.94 | 12.88318 | 8.54 | +| 5 | 12.27 | 23.35449 | 25.23 | +| 6 | 1.32 | 6.033 | 2.21 | +| 7 | 5.91 | 12.31266 | 25.45 | +| 8 | 6.71 | 11.82444 | 23.12 | +| 9 | 44.19 | 22.40144 | 35.2 | +| 10 | 7.13 | 12.51071 | 12.18 | +| 11 | 2.18 | 2.6221 | 10.99 | +| 12 | 2.88 | 7.97906 | 6.99 | +| 13 | 6.84 | 10.15873 | 12.26 | +| 14 | 1.69 | 4.79394 | 3.89 | +| 15 | 3.29 | 10.48785 | 9.82 | +| 16 | 5.04 | 4.64262 | 6.76 | +| 17 | 11.7 | 74.65243 | 44.65 | +| 18 | 12.87 | 64.87646 | 30.27 | +| 19 | 4.75 | 8.08625 | 4.7 | +| 20 | 8.89 | 15.47016 | 8.4 | +| 21 | 24.44 | 39.08594 | 34.83 | +| 22 | 1.23 | 7.67476 | 4.59 | + +![TPC-H](/media/tidb-v5.4-tpch-100-vs-gp-spark.png) + +以上性能图中蓝色为 TiDB v5.4,红色为 Greenplum 6.15.0,黄色为 Apache Spark 3.1.1,纵坐标是查询的处理时间。纵坐标数值越低,表示 TPC-H 性能越好。 diff --git a/markdown-pages/zh/tidb/master/benchmark/v6.0-performance-benchmarking-with-tpcc.md b/markdown-pages/zh/tidb/master/benchmark/v6.0-performance-benchmarking-with-tpcc.md new file mode 100644 index 0000000..b6944cf --- /dev/null +++ b/markdown-pages/zh/tidb/master/benchmark/v6.0-performance-benchmarking-with-tpcc.md @@ -0,0 +1,119 @@ +--- +title: TiDB TPC-C 性能对比测试报告 - v6.0.0 对比 v5.4.0 +summary: TiDB v6.0.0 在 TPC-C 性能上比 v5.4.0 提升了 24.20%,表现更好。测试环境为 AWS EC2,硬件配置包括PD、TiKV、TiDB 和 TPC-C 实例。软件版本为 v5.4.0 和 v6.0.0,配置参数相同。测试方案包括通过 TiUP 部署 TiDB,创建数据库 tpcc,导入数据,运行压力测试,提取结果。测试结果显示 v6.0.0 在不同并发下的 tpmC 均有提升,最高达26.97%。 +--- + +# TiDB TPC-C 性能对比测试报告 - v6.0.0 对比 v5.4.0 + +## 测试概况 + +本次测试对比了 TiDB v6.0.0 和 v5.4.0 在 OLTP 场景下的 TPC-C 性能表现。结果显示,v6.0.0 相比于 v5.4.0 在 TPC-C 性能提升了 24.20%。 + +## 测试环境 (AWS EC2) + +### 硬件配置 + +| 服务类型 | EC2 类型 | 实例数 | +|:----------|:----------|:----------| +| PD | m5.xlarge | 3 | +| TiKV | i3.4xlarge| 3 | +| TiDB | c5.4xlarge| 3 | +| TPC-C | c5.9xlarge| 1 | + +### 软件版本 + +| 服务类型 | 软件版本 | +|:----------|:-----------| +| PD | v5.4.0、v6.0.0 | +| TiDB | v5.4.0、v6.0.0 | +| TiKV | v5.4.0、v6.0.0 | +| TiUP | 1.9.3 | +| HAProxy | 2.5.0 | + +### 配置参数 + +两个版本使用同样的配置 + +#### TiDB 参数配置 + +```yaml +log.level: "error" +prepared-plan-cache.enabled: true +tikv-client.max-batch-wait-time: 2000000 +``` + +#### TiKV 参数配置 + +```yaml +pessimistic-txn.pipelined: true +raftdb.allow-concurrent-memtable-write: true +raftdb.max-background-jobs: 4 +raftstore.apply-max-batch-size: 2048 +raftstore.apply-pool-size: 3 +raftstore.store-max-batch-size: 2048 +raftstore.store-pool-size: 3 +readpool.storage.normal-concurrency: 10 +rocksdb.max-background-jobs: 8 +server.grpc-concurrency: 6 +``` + +#### TiDB 全局变量配置 + +```sql +set global tidb_hashagg_final_concurrency=1; +set global tidb_hashagg_partial_concurrency=1; +set global tidb_enable_async_commit = 1; +set global tidb_enable_1pc = 1; +set global tidb_guarantee_linearizability = 0; +set global tidb_enable_clustered_index = 1; +``` + +#### HAProxy 配置 - haproxy.cfg 文件 + +更多有关 HAProxy 在 TiDB 上的使用,可参阅 [HAProxy 在 TiDB 中的最佳实践](/best-practices/haproxy-best-practices.md)。 + +```yaml +global # 全局配置。 + pidfile /var/run/haproxy.pid # 将 HAProxy 进程的 PID 写入 pidfile。 + maxconn 4000 # 每个 HAProxy 进程所接受的最大并发连接数。 + user haproxy # 同 UID 参数。 + group haproxy # 同 GID 参数,建议使用专用用户组。 + nbproc 64 # 在后台运行时创建的进程数。在启动多个进程转发请求时,确保该值足够大,保证 HAProxy 不会成为瓶颈。 + daemon # 让 HAProxy 以守护进程的方式工作于后台,等同于命令行参数“-D”的功能。当然,也可以在命令行中用“-db”参数将其禁用。 + +defaults # 默认配置。 + log global # 日志继承全局配置段的设置。 + retries 2 # 向上游服务器尝试连接的最大次数,超过此值便认为后端服务器不可用。 + timeout connect 2s # HAProxy 与后端服务器连接超时时间。如果在同一个局域网内,可设置成较短的时间。 + timeout client 30000s # 客户端与 HAProxy 连接后,数据传输完毕,即非活动连接的超时时间。 + timeout server 30000s # 服务器端非活动连接的超时时间。 + +listen tidb-cluster # 配置 database 负载均衡。 + bind 0.0.0.0:3390 # 浮动 IP 和 监听端口。 + mode tcp # HAProxy 要使用第 4 层的传输层。 + balance leastconn # 连接数最少的服务器优先接收连接。`leastconn` 建议用于长会话服务,例如 LDAP、SQL、TSE 等,而不是短会话协议,如 HTTP。该算法是动态的,对于启动慢的服务器,服务器权重会在运行中作调整。 + server tidb-1 10.9.18.229:4000 check inter 2000 rise 2 fall 3 # 检测 4000 端口,检测频率为每 2000 毫秒一次。如果 2 次检测为成功,则认为服务器可用;如果 3 次检测为失败,则认为服务器不可用。 + server tidb-2 10.9.39.208:4000 check inter 2000 rise 2 fall 3 + server tidb-3 10.9.64.166:4000 check inter 2000 rise 2 fall 3 +``` + +## 测试方案 + +1. 通过 TiUP 部署 TiDB v6.0.0 和 v5.4.0。 +2. 创建数据库 tpcc:`create database tpcc;`。 +3. 通过 tiup bench 导入 TPC-C 5000 Warehouse 数据:`tiup bench tpcc prepare --warehouses 5000 --db tpcc -H 127.0.0.1 -p 4000`。 +4. 运行 `tiup bench tpcc run -U root --db tpcc --host 127.0.0.1 --port 4000 --time 1800s --warehouses 5000 --threads {{thread}}` 命令,通过 HAProxy 向 TiDB 加压,每个并发数各测试 30 分钟。 +5. 从结果中提取 New Order 的 tpmC 的数据。 + +## 测试结果 + +v6.0.0 相比 v5.4.0 在 TPC-C 性能上有大幅提升,**平均提升了 24.20%**。 + +| Threads | v5.4.0 tpmC | v6.0.0 tpmC | tpmC 提升 (%) | +|:----------|:----------|:----------|:----------| +|50|44822.8|54956.6|22.61| +|100|52150.3|66216.6|26.97| +|200|57344.9|72116.7|25.76| +|400|58675|71254.8|21.44| + +![TPC-C](/media/tpcc_v540_vs_v600.png) diff --git a/markdown-pages/zh/tidb/master/benchmark/v6.0-performance-benchmarking-with-tpch.md b/markdown-pages/zh/tidb/master/benchmark/v6.0-performance-benchmarking-with-tpch.md new file mode 100644 index 0000000..0d20f8c --- /dev/null +++ b/markdown-pages/zh/tidb/master/benchmark/v6.0-performance-benchmarking-with-tpch.md @@ -0,0 +1,8 @@ +--- +title: TiFlash 与 Greenplum/Spark 性能比较 +summary: TiFlash 与 Greenplum/Spark 性能进行了比较。请参考 TiDB v5.4 TPC-H 性能对比测试报告。 +--- + +# TiFlash 与 Greenplum/Spark 性能比较 + +请参考 [TiDB v5.4 TPC-H 性能对比测试报告](https://docs.pingcap.com/zh/tidb/stable/v5.4-performance-benchmarking-with-tpch)。 \ No newline at end of file diff --git a/markdown-pages/zh/tidb/master/benchmark/v6.1-performance-benchmarking-with-tpcc.md b/markdown-pages/zh/tidb/master/benchmark/v6.1-performance-benchmarking-with-tpcc.md new file mode 100644 index 0000000..b7d7f49 --- /dev/null +++ b/markdown-pages/zh/tidb/master/benchmark/v6.1-performance-benchmarking-with-tpcc.md @@ -0,0 +1,116 @@ +--- +title: TiDB TPC-C 性能对比测试报告 - v6.1.0 对比 v6.0.0 +summary: TiDB v6.1.0 在 TPC-C 性能上平均提升了 2.85%,分别为:50 线程提升 2.31%,100 线程提升 2.71%,200 线程提升 3.86%,400 线程提升 2.52%。 +--- + +# TiDB TPC-C 性能对比测试报告 - v6.1.0 对比 v6.0.0 + +## 测试概况 + +本次测试对比了 TiDB v6.1.0 和 v6.0.0 在 OLTP 场景下的 TPC-C 性能表现。结果显示,v6.1.0 相比于 v6.0.0 在 TPC-C 性能提升了 2.85%。 + +## 测试环境 (AWS EC2) + +### 硬件配置 + +| 服务类型 | EC2 类型 | 实例数 | +|:----------|:----------|:----------| +| PD | m5.xlarge | 3 | +| TiKV | i3.4xlarge| 3 | +| TiDB | c5.4xlarge| 3 | +| TPC-C | c5.9xlarge| 1 | + +### 软件版本 + +| 服务类型 | 软件版本 | +|:----------|:-----------| +| PD | v6.0.0、v6.1.0 | +| TiDB | v6.0.0、v6.1.0 | +| TiKV | v6.0.0、v6.1.0 | +| TiUP | 1.9.3 | +| HAProxy | 2.5.0 | + +### 配置参数 + +两个版本使用同样的配置。 + +#### TiDB 参数配置 + +```yaml +log.level: "error" +prepared-plan-cache.enabled: true +tikv-client.max-batch-wait-time: 2000000 +``` + +#### TiKV 参数配置 + +```yaml +raftstore.apply-max-batch-size: 2048 +raftstore.apply-pool-size: 3 +raftstore.store-max-batch-size: 2048 +raftstore.store-pool-size: 2 +readpool.storage.normal-concurrency: 10 +server.grpc-concurrency: 6 +``` + +#### TiDB 全局变量配置 + +```sql +set global tidb_hashagg_final_concurrency=1; +set global tidb_hashagg_partial_concurrency=1; +set global tidb_enable_async_commit = 1; +set global tidb_enable_1pc = 1; +set global tidb_guarantee_linearizability = 0; +set global tidb_enable_clustered_index = 1; +set global tidb_prepared_plan_cache_size=1000; +``` + +#### HAProxy 配置 - haproxy.cfg 文件 + +更多有关 HAProxy 在 TiDB 上的使用,可参阅 [HAProxy 在 TiDB 中的最佳实践](/best-practices/haproxy-best-practices.md)。 + +```yaml +global # 全局配置。 + pidfile /var/run/haproxy.pid # 将 HAProxy 进程的 PID 写入 pidfile。 + maxconn 4000 # 每个 HAProxy 进程所接受的最大并发连接数。 + user haproxy # 同 UID 参数。 + group haproxy # 同 GID 参数,建议使用专用用户组。 + nbproc 64 # 在后台运行时创建的进程数。在启动多个进程转发请求时,确保该值足够大,保证 HAProxy 不会成为瓶颈。 + daemon # 让 HAProxy 以守护进程的方式工作于后台,等同于命令行参数“-D”的功能。当然,也可以在命令行中用“-db”参数将其禁用。 + +defaults # 默认配置。 + log global # 日志继承全局配置段的设置。 + retries 2 # 向上游服务器尝试连接的最大次数,超过此值便认为后端服务器不可用。 + timeout connect 2s # HAProxy 与后端服务器连接超时时间。如果在同一个局域网内,可设置成较短的时间。 + timeout client 30000s # 客户端与 HAProxy 连接后,数据传输完毕,即非活动连接的超时时间。 + timeout server 30000s # 服务器端非活动连接的超时时间。 + +listen tidb-cluster # 配置 database 负载均衡。 + bind 0.0.0.0:3390 # 浮动 IP 和 监听端口。 + mode tcp # HAProxy 要使用第 4 层的传输层。 + balance leastconn # 连接数最少的服务器优先接收连接。`leastconn` 建议用于长会话服务,例如 LDAP、SQL、TSE 等,而不是短会话协议,如 HTTP。该算法是动态的,对于启动慢的服务器,服务器权重会在运行中作调整。 + server tidb-1 10.9.18.229:4000 check inter 2000 rise 2 fall 3 # 检测 4000 端口,检测频率为每 2000 毫秒一次。如果 2 次检测为成功,则认为服务器可用;如果 3 次检测为失败,则认为服务器不可用。 + server tidb-2 10.9.39.208:4000 check inter 2000 rise 2 fall 3 + server tidb-3 10.9.64.166:4000 check inter 2000 rise 2 fall 3 +``` + +## 测试方案 + +1. 通过 TiUP 部署 TiDB v6.1.0 和 v6.0.0。 +2. 创建数据库 tpcc:`create database tpcc;`。 +3. 通过 tiup bench 导入 TPC-C 5000 Warehouse 数据:`tiup bench tpcc prepare --warehouses 5000 --db tpcc -H 127.0.0.1 -p 4000`。 +4. 运行 `tiup bench tpcc run -U root --db tpcc --host 127.0.0.1 --port 4000 --time 1800s --warehouses 5000 --threads {{thread}}` 命令,通过 HAProxy 向 TiDB 加压,每个并发数各测试 30 分钟。 +5. 从结果中提取 New Order 的 tpmC 的数据。 + +## 测试结果 + +v6.1.0 相比 v6.0.0 在 TPC-C 性能上**平均提升了 2.85%**。 + +| Threads | v6.0.0 tpmC | v6.1.0 tpmC | tpmC 提升 (%) | +|:----------|:----------|:----------|:----------| +|50|59059.2|60424.4|2.31| +|100|69357.6|71235.5|2.71| +|200|71364.8|74117.8|3.86| +|400|72694.3|74525.3|2.52| + +![TPC-C](/media/tpcc_v600_vs_v610.png) diff --git a/markdown-pages/zh/tidb/master/benchmark/v6.1-performance-benchmarking-with-tpch.md b/markdown-pages/zh/tidb/master/benchmark/v6.1-performance-benchmarking-with-tpch.md new file mode 100644 index 0000000..6533d99 --- /dev/null +++ b/markdown-pages/zh/tidb/master/benchmark/v6.1-performance-benchmarking-with-tpch.md @@ -0,0 +1,8 @@ +--- +title: TiFlash 与 Greenplum/Spark 性能比较 +summary: TiFlash 与 Greenplum/Spark 性能比较。请参考 TiDB v5.4 TPC-H 性能对比测试报告。 +--- + +# TiFlash 与 Greenplum/Spark 性能比较 + +请参考 [TiDB v5.4 TPC-H 性能对比测试报告](https://docs.pingcap.com/zh/tidb/stable/v5.4-performance-benchmarking-with-tpch)。 \ No newline at end of file diff --git a/markdown-pages/zh/tidb/master/benchmark/v6.2-performance-benchmarking-with-tpcc.md b/markdown-pages/zh/tidb/master/benchmark/v6.2-performance-benchmarking-with-tpcc.md new file mode 100644 index 0000000..5affcbf --- /dev/null +++ b/markdown-pages/zh/tidb/master/benchmark/v6.2-performance-benchmarking-with-tpcc.md @@ -0,0 +1,116 @@ +--- +title: TiDB TPC-C 性能对比测试报告 - v6.2.0 对比 v6.1.0 +summary: TiDB v6.2.0 在 TPC-C 性能测试中相比 v6.1.0 下降了 2.00%,平均性能下降了 2.00%。在不同并发数下,v6.2.0 的性能都有所下降,最高下降达到 3.60%。 +--- + +# TiDB TPC-C 性能对比测试报告 - v6.2.0 对比 v6.1.0 + +## 测试概况 + +本次测试对比了 TiDB v6.2.0 和 v6.1.0 在 OLTP 场景下的 TPC-C 性能表现。结果显示,v6.2.0 相比于 v6.1.0 在 TPC-C 性能下降了 2.00%。 + +## 测试环境 (AWS EC2) + +### 硬件配置 + +| 服务类型 | EC2 类型 | 实例数 | +| :------- | :--------- | :----- | +| PD | m5.xlarge | 3 | +| TiKV | i3.4xlarge | 3 | +| TiDB | c5.4xlarge | 3 | +| TPC-C | c5.9xlarge | 1 | + +### 软件版本 + +| 服务类型 | 软件版本 | +| :------- | :------------- | +| PD | v6.1.0、v6.2.0 | +| TiDB | v6.1.0、v6.2.0 | +| TiKV | v6.1.0、v6.2.0 | +| TiUP | 1.9.3 | +| HAProxy | 2.5.0 | + +### 配置参数 + +两个版本使用同样的配置。 + +#### TiDB 参数配置 + +```yaml +log.level: "error" +prepared-plan-cache.enabled: true +tikv-client.max-batch-wait-time: 2000000 +``` + +#### TiKV 参数配置 + +```yaml +raftstore.apply-max-batch-size: 2048 +raftstore.apply-pool-size: 3 +raftstore.store-max-batch-size: 2048 +raftstore.store-pool-size: 2 +readpool.storage.normal-concurrency: 10 +server.grpc-concurrency: 6 +``` + +#### TiDB 全局变量配置 + +```sql +set global tidb_hashagg_final_concurrency=1; +set global tidb_hashagg_partial_concurrency=1; +set global tidb_enable_async_commit = 1; +set global tidb_enable_1pc = 1; +set global tidb_guarantee_linearizability = 0; +set global tidb_enable_clustered_index = 1; +set global tidb_prepared_plan_cache_size=1000; +``` + +#### HAProxy 配置 - haproxy.cfg 文件 + +更多有关 HAProxy 在 TiDB 上的使用,可参阅 [HAProxy 在 TiDB 中的最佳实践](/best-practices/haproxy-best-practices.md)。 + +```yaml +global # 全局配置。 + pidfile /var/run/haproxy.pid # 将 HAProxy 进程的 PID 写入 pidfile。 + maxconn 4000 # 每个 HAProxy 进程所接受的最大并发连接数。 + user haproxy # 同 UID 参数。 + group haproxy # 同 GID 参数,建议使用专用用户组。 + nbproc 64 # 在后台运行时创建的进程数。在启动多个进程转发请求时,确保该值足够大,保证 HAProxy 不会成为瓶颈。 + daemon # 让 HAProxy 以守护进程的方式工作于后台,等同于命令行参数“-D”的功能。当然,也可以在命令行中用“-db”参数将其禁用。 + +defaults # 默认配置。 + log global # 日志继承全局配置段的设置。 + retries 2 # 向上游服务器尝试连接的最大次数,超过此值便认为后端服务器不可用。 + timeout connect 2s # HAProxy 与后端服务器连接超时时间。如果在同一个局域网内,可设置成较短的时间。 + timeout client 30000s # 客户端与 HAProxy 连接后,数据传输完毕,即非活动连接的超时时间。 + timeout server 30000s # 服务器端非活动连接的超时时间。 + +listen tidb-cluster # 配置 database 负载均衡。 + bind 0.0.0.0:3390 # 浮动 IP 和 监听端口。 + mode tcp # HAProxy 要使用第 4 层的传输层。 + balance leastconn # 连接数最少的服务器优先接收连接。`leastconn` 建议用于长会话服务,例如 LDAP、SQL、TSE 等,而不是短会话协议,如 HTTP。该算法是动态的,对于启动慢的服务器,服务器权重会在运行中作调整。 + server tidb-1 10.9.18.229:4000 check inter 2000 rise 2 fall 3 # 检测 4000 端口,检测频率为每 2000 毫秒一次。如果 2 次检测为成功,则认为服务器可用;如果 3 次检测为失败,则认为服务器不可用。 + server tidb-2 10.9.39.208:4000 check inter 2000 rise 2 fall 3 + server tidb-3 10.9.64.166:4000 check inter 2000 rise 2 fall 3 +``` + +## 测试方案 + +1. 通过 TiUP 部署 TiDB v6.2.0 和 v6.1.0。 +2. 创建数据库 tpcc:`create database tpcc;`。 +3. 通过 tiup bench 导入 TPC-C 5000 Warehouse 数据:`tiup bench tpcc prepare --warehouses 5000 --db tpcc -H 127.0.0.1 -P 4000`。 +4. 运行 `tiup bench tpcc run -U root --db tpcc --host 127.0.0.1 --port 4000 --time 1800s --warehouses 5000 --threads {{thread}}` 命令,通过 HAProxy 向 TiDB 加压,每个并发数各测试 30 分钟。 +5. 从结果中提取 New Order 的 tpmC 的数据。 + +## 测试结果 + +v6.2.0 相比 v6.1.0 在 TPC-C 性能上**平均下降了 2.00%**。 + +| Threads | v6.1.0 tpmC | v6.2.0 tpmC | tpmC 提升 (%) | +| :------ | :---------- | :---------- | :------------ | +| 50 | 62212.4 | 61874.4 | -0.54 | +| 100 | 72790.7 | 71317.5 | -2.02 | +| 200 | 75818.6 | 73090.4 | -3.60 | +| 400 | 74515.3 | 73156.9 | -1.82 | + +![TPC-C](/media/tpcc_v610_vs_v620.png) diff --git a/markdown-pages/zh/tidb/master/benchmark/v6.2-performance-benchmarking-with-tpch.md b/markdown-pages/zh/tidb/master/benchmark/v6.2-performance-benchmarking-with-tpch.md new file mode 100644 index 0000000..50487b0 --- /dev/null +++ b/markdown-pages/zh/tidb/master/benchmark/v6.2-performance-benchmarking-with-tpch.md @@ -0,0 +1,8 @@ +--- +title: TiFlash 与 Greenplum/Spark 性能比较 +summary: TiFlash 与 Greenplum/Spark 性能进行了比较。请参考 TiDB v5.4 TPC-H 性能对比测试报告。 +--- + +# TiFlash 与 Greenplum/Spark 性能比较 + +请参考 [TiDB v5.4 TPC-H 性能对比测试报告](https://docs.pingcap.com/zh/tidb/stable/v5.4-performance-benchmarking-with-tpch)。 diff --git a/markdown-pages/zh/tidb/master/best-practices/haproxy-best-practices.md b/markdown-pages/zh/tidb/master/best-practices/haproxy-best-practices.md new file mode 100644 index 0000000..57db284 --- /dev/null +++ b/markdown-pages/zh/tidb/master/best-practices/haproxy-best-practices.md @@ -0,0 +1,233 @@ +--- +title: HAProxy 在 TiDB 中的最佳实践 +aliases: ['/docs-cn/dev/best-practices/haproxy-best-practices/','/docs-cn/dev/reference/best-practices/haproxy/'] +summary: HAProxy 是 TiDB 中实现负载均衡的最佳实践。它提供 TCP 协议下的负载均衡能力,通过连接 HAProxy 提供的浮动 IP 对数据进行操作,实现 TiDB Server 层的负载均衡。HAProxy 提供高可用性、负载均衡、健康检查、会话保持、SSL 支持和监控统计等核心功能。部署 HAProxy 需要满足一定的硬件和软件要求,配置和启动 HAProxy 后即可实现数据库负载均衡。 +--- + +# HAProxy 在 TiDB 中的最佳实践 + +本文介绍 [HAProxy](https://github.com/haproxy/haproxy) 在 TiDB 中的最佳配置和使用方法。HAProxy 提供 TCP 协议下的负载均衡能力,TiDB 客户端通过连接 HAProxy 提供的浮动 IP 即可对数据进行操作,实现 TiDB Server 层的负载均衡。 + +![HAProxy 在 TiDB 中的最佳实践](/media/haproxy.jpg) + +> **注意:** +> +> TiDB 支持的最小 HAProxy 版本为 v1.5。使用 v1.5 到 v2.1 之间的 HAProxy 时,需要在 `mysql-check` 中配置 `post-41`。建议使用 HAProxy v2.2 或更高版本。 + +## HAProxy 简介 + +HAProxy 是由 C 语言编写的自由开放源码的软件,为基于 TCP 和 HTTP 协议的应用程序提供高可用性、负载均衡和代理服务。因为 HAProxy 能够快速、高效使用 CPU 和内存,所以目前使用非常广泛,许多知名网站诸如 GitHub、Bitbucket、Stack Overflow、Reddit、Tumblr、Twitter 和 Tuenti 以及亚马逊网络服务系统都在使用 HAProxy。 + +HAProxy 由 Linux 内核的核心贡献者 Willy Tarreau 于 2000 年编写,他现在仍然负责该项目的维护,并在开源社区免费提供版本迭代。本文示例使用 HAProxy [2.6](https://www.haproxy.com/blog/announcing-haproxy-2-6/)。推荐使用最新稳定版的 HAProxy,详情见[已发布的 HAProxy 版本](http://www.haproxy.org/)。 + +## HAProxy 部分核心功能介绍 + +- [高可用性](http://cbonte.github.io/haproxy-dconv/2.6/intro.html#3.3.4):HAProxy 提供优雅关闭服务和无缝切换的高可用功能; +- [负载均衡](http://cbonte.github.io/haproxy-dconv/2.6/configuration.html#4.2-balance):L4 (TCP) 和 L7 (HTTP) 两种负载均衡模式,至少 9 类均衡算法,比如 roundrobin,leastconn,random 等; +- [健康检查](http://cbonte.github.io/haproxy-dconv/2.6/configuration.html#5.2-check):对 HAProxy 配置的 HTTP 或者 TCP 模式状态进行检查; +- [会话保持](http://cbonte.github.io/haproxy-dconv/2.6/intro.html#3.3.6):在应用程序没有提供会话保持功能的情况下,HAProxy 可以提供该项功能; +- [SSL](http://cbonte.github.io/haproxy-dconv/2.6/intro.html#3.3.2):支持 HTTPS 通信和解析; +- [监控与统计](http://cbonte.github.io/haproxy-dconv/2.6/intro.html#3.3.3):通过 web 页面可以实时监控服务状态以及具体的流量信息。 + +## 准备环境 + +在部署 HAProxy 之前,需准备好以下环境。 + +### 硬件要求 + +根据[HAProxy 官方文档](https://www.haproxy.com/documentation/haproxy-enterprise/getting-started/installation/linux/),HAProxy 的服务器硬件的最低配置如下。在 Sysbench `oltp_read_write` 工作负载下,该配置的最高 QPS 约为 50K。你可以根据负载均衡环境进行推算,在此基础上提高服务器配置。 + +|硬件资源|最低配置| +|:---|:---| +|CPU|2 核,3.5 GHz| +|内存|4 GB| +|存储容量|50 GB(SATA 盘)| +|网卡|万兆网卡| + +### 依赖软件 + +根据 HAProxy 官方文档,对操作系统和依赖包有以下建议,如果通过 yum 源部署安装 HAProxy 软件,依赖包无需单独安装。 + +#### 操作系统 + +| Linux 操作系统 | 版本 | +| :----------------------- | :----------- | +| Red Hat Enterprise Linux | 7 或者 8 | +| CentOS | 7 或者 8 | +| Oracle Enterprise Linux | 7 或者 8 | +| Ubuntu LTS | 18.04 或者以上版本 | + +> **注意:** +> +> - 其他操作系统支持情况,详见 [HAProxy 文档](https://github.com/haproxy/haproxy/blob/master/INSTALL)。 + +#### 依赖包 + +- epel-release +- gcc +- systemd-devel + +执行如下命令安装依赖包: + +```bash +yum -y install epel-release gcc systemd-devel +``` + +## 部署 HAProxy + +HAProxy 配置 Database 负载均衡场景操作简单,以下部署操作具有普遍性,不具有特殊性,建议根据实际场景,个性化配置相关的[配置文件](http://cbonte.github.io/haproxy-dconv/2.6/configuration.html)。 + +### 安装 HAProxy + +1. 下载 HAProxy 2.6.2 的源码包: + + ```bash + wget https://www.haproxy.org/download/2.6/src/haproxy-2.6.2.tar.gz + ``` + +2. 解压源码包: + + ```bash + tar zxf haproxy-2.6.2.tar.gz + ``` + +3. 从源码编译 HAProxy 应用: + + ```bash + cd haproxy-2.6.2 + make clean + make -j 8 TARGET=linux-glibc USE_THREAD=1 + make PREFIX=${/app/haproxy} SBINDIR=${/app/haproxy/bin} install # 将 `${/app/haproxy}` 和 `${/app/haproxy/bin}` 替换为自定义的实际路径。 + ``` + +4. 重新配置 `profile` 文件: + + ```bash + echo 'export PATH=/app/haproxy/bin:$PATH' >> /etc/profile + . /etc/profile + ``` + +5. 检查 HAProxy 是否安装成功: + + ```bash + which haproxy + ``` + +#### HAProxy 命令介绍 + +执行如下命令查看命令行参数及基本用法: + +```bash +haproxy --help +``` + +| 参数 | 说明 | +| :------- | :--------- | +| `-v` | 显示简略的版本信息。 | +| `-vv` | 显示详细的版本信息。 | +| `-d` | 开启 debug 模式。 | +| `-db` | 禁用后台模式和多进程模式。 | +| `-dM []` | 执行分配内存。| +| `-V` | 启动过程显示配置和轮询信息。 | +| `-D` | 开启守护进程模式。 | +| `-C ` | 在加载配置文件之前更改目录位置至 ``。 | +| `-W` | 主从模式。 | +| `-q` | 静默模式,不输出信息。 | +| `-c` | 只检查配置文件并在尝试绑定之前退出。 | +| `-n ` | 设置每个进程的最大总连接数为 ``。 | +| `-m ` | 设置所有进程的最大可用内存为 ``(单位:MB)。 | +| `-N ` | 设置单点最大连接数为 ``,默认为 2000。 | +| `-L ` | 将本地实例对等名称改为 ``,默认为本地主机名。 | +| `-p ` | 将 HAProxy 所有子进程的 PID 信息写入 ``。 | +| `-de` | 禁止使用 epoll(7),epoll(7) 仅在 Linux 2.6 和某些定制的 Linux 2.4 系统上可用。 | +| `-dp` | 禁止使用 epoll(2),可改用 select(2)。 | +| `-dS` | 禁止使用 splice(2),splice(2) 在一些旧版 Linux 内核上不可用。 | +| `-dR` | 禁止使用 SO_REUSEPORT。 | +| `-dr` | 忽略服务器地址解析失败。 | +| `-dV` | 禁止在服务器端使用 SSL。 | +| `-sf ` | 启动后,向 pidlist 中的 PID 发送 `finish` 信号,收到此信号的进程在退出之前将等待所有会话完成,即优雅停止服务。此选项必须最后指定,后跟任意数量的 PID。从技术上讲,SIGTTOU 和 SIGUSR1 都被发送。 | +| `-st ` | 启动后,向 pidlist 中的 PID 发送 `terminate` 信号,收到此信号的进程将立即终止,关闭所有活动会话。此选项必须最后指定,后跟任意数量的 PID。从技术上讲,SIGTTOU 和 SIGTERM 都被发送。 | +| `-x ` | 连接指定的 socket 并从旧进程中获取所有 listening socket,然后,使用这些 socket 而不是绑定新的。 | +| `-S [,...]` | 主从模式下,创建绑定到主进程的 socket,此 socket 可访问每个子进程的 socket。 | + +更多有关 HAProxy 命令参数的信息,可参阅 [Management Guide of HAProxy](http://cbonte.github.io/haproxy-dconv/2.6/management.html) 和 [General Commands Manual of HAProxy](https://manpages.debian.org/buster-backports/haproxy/haproxy.1.en.html)。 + +### 配置 HAProxy + +yum 安装过程中会生成配置模版,你也可以根据实际场景自定义配置如下配置项。 + +```yaml +global # 全局配置。 + log 127.0.0.1 local2 # 定义全局的 syslog 服务器,最多可以定义两个。 + chroot /var/lib/haproxy # 更改当前目录并为启动进程设置超级用户权限,从而提高安全性。 + pidfile /var/run/haproxy.pid # 将 HAProxy 进程的 PID 写入 pidfile。 + maxconn 4096 # 单个 HAProxy 进程可接受的最大并发连接数,等价于命令行参数 "-n"。 + nbthread 48 # 最大线程数。线程数的上限与 CPU 数量相同。 + user haproxy # 同 UID 参数。 + group haproxy # 同 GID 参数,建议使用专用用户组。 + daemon # 让 HAProxy 以守护进程的方式工作于后台,等同于命令行参数“-D”的功能。当然,也可以在命令行中用“-db”参数将其禁用。 + stats socket /var/lib/haproxy/stats # 统计信息保存位置。 + +defaults # 默认配置。 + log global # 日志继承全局配置段的设置。 + retries 2 # 向上游服务器尝试连接的最大次数,超过此值便认为后端服务器不可用。 + timeout connect 2s # HAProxy 与后端服务器连接超时时间。如果在同一个局域网内,可设置成较短的时间。 + timeout client 30000s # 客户端与 HAProxy 连接后,数据传输完毕,即非活动连接的超时时间。 + timeout server 30000s # 服务器端非活动连接的超时时间。 + +listen admin_stats # frontend 和 backend 的组合体,此监控组的名称可按需进行自定义。 + bind 0.0.0.0:8080 # 监听端口。 + mode http # 监控运行的模式,此处为 `http` 模式。 + option httplog # 开始启用记录 HTTP 请求的日志功能。 + maxconn 10 # 最大并发连接数。 + stats refresh 30s # 每隔 30 秒自动刷新监控页面。 + stats uri /haproxy # 监控页面的 URL。 + stats realm HAProxy # 监控页面的提示信息。 + stats auth admin:pingcap123 # 监控页面的用户和密码,可设置多个用户名。 + stats hide-version # 隐藏监控页面上的 HAProxy 版本信息。 + stats admin if TRUE # 手工启用或禁用后端服务器(HAProxy 1.4.9 及之后版本开始支持)。 + +listen tidb-cluster # 配置 database 负载均衡。 + bind 0.0.0.0:3390 # 浮动 IP 和 监听端口。 + mode tcp # HAProxy 要使用第 4 层的传输层。 + balance leastconn # 连接数最少的服务器优先接收连接。`leastconn` 建议用于长会话服务,例如 LDAP、SQL、TSE 等,而不是短会话协议,如 HTTP。该算法是动态的,对于启动慢的服务器,服务器权重会在运行中作调整。 + server tidb-1 10.9.18.229:4000 check inter 2000 rise 2 fall 3 # 检测 4000 端口,检测频率为每 2000 毫秒一次。如果 2 次检测为成功,则认为服务器可用;如果 3 次检测为失败,则认为服务器不可用。 + server tidb-2 10.9.39.208:4000 check inter 2000 rise 2 fall 3 + server tidb-3 10.9.64.166:4000 check inter 2000 rise 2 fall 3 +``` + +如要通过 `SHOW PROCESSLIST` 查看连接来源 IP,需要配置使用 [PROXY 协议](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt)连接 TiDB。 + +```yaml + server tidb-1 10.9.18.229:4000 send-proxy check inter 2000 rise 2 fall 3 + server tidb-2 10.9.39.208:4000 send-proxy check inter 2000 rise 2 fall 3 + server tidb-3 10.9.64.166:4000 send-proxy check inter 2000 rise 2 fall 3 +``` + +> **注意:** +> +> 使用 PROXY 协议时,你需要在 tidb-server 的配置文件中设置 [`proxy-protocol.networks`](/tidb-configuration-file.md#networks)。 + +### 启动 HAProxy + +要启动 HAProxy,执行 `haproxy` 命令。默认读取 `/etc/haproxy/haproxy.cfg`(推荐)。 + +```bash +haproxy -f /etc/haproxy/haproxy.cfg +``` + +### 停止 HAProxy + +要停止 HAProxy,使用 `kill -9` 命令。 + +1. 执行如下命令: + + ```bash + ps -ef | grep haproxy + ``` + +2. 终止 HAProxy 相关的 PID 进程: + + ```bash + kill -9 ${haproxy.pid} + ``` diff --git a/markdown-pages/zh/tidb/master/best-practices/java-app-best-practices.md b/markdown-pages/zh/tidb/master/best-practices/java-app-best-practices.md new file mode 100644 index 0000000..747dd5d --- /dev/null +++ b/markdown-pages/zh/tidb/master/best-practices/java-app-best-practices.md @@ -0,0 +1,326 @@ +--- +title: 开发 Java 应用使用 TiDB 的最佳实践 +aliases: ['/docs-cn/dev/best-practices/java-app-best-practices/','/docs-cn/dev/reference/best-practices/java-app/','/docs-cn/dev/reference/best-practices/using-tidb-in-java/'] +summary: 本文介绍了开发 Java 应用程序使用 TiDB 的常见问题与解决办法。TiDB 是高度兼容 MySQL 协议的数据库,基于 MySQL 开发的 Java 应用的最佳实践也多适用于 TiDB。 +--- + +# 开发 Java 应用使用 TiDB 的最佳实践 + +本文主要介绍如何开发 Java 应用程序以更好地使用 TiDB,包括开发中的常见问题与最佳实践。 + +## Java 应用中的数据库相关组件 + +通常 Java 应用中和数据库相关的常用组件有: + +- 网络协议:客户端通过标准 [MySQL 协议](https://dev.mysql.com/doc/dev/mysql-server/latest/PAGE_PROTOCOL.html)和 TiDB 进行网络交互。 +- JDBC API 及实现:Java 应用通常使用 [JDBC (Java Database Connectivity)](https://docs.oracle.com/javase/8/docs/technotes/guides/jdbc/) 来访问数据库。JDBC 定义了访问数据库 API,而 JDBC 实现完成标准 API 到 MySQL 协议的转换,常见的 JDBC 实现是 [MySQL Connector/J](https://github.com/mysql/mysql-connector-j),此外有些用户可能使用 [MariaDB Connector/J](https://mariadb.com/kb/en/library/about-mariadb-connector-j/#about-mariadb-connectorj)。 +- 数据库连接池:为了避免每次创建连接,通常应用会选择使用数据库连接池来复用连接,JDBC [DataSource](https://docs.oracle.com/javase/8/docs/api/javax/sql/DataSource.html) 定义了连接池 API,开发者可根据实际需求选择使用某种开源连接池实现。 +- 数据访问框架:应用通常选择通过数据访问框架 ([MyBatis](https://mybatis.org/mybatis-3/zh_CN/index.html), [Hibernate](https://hibernate.org/)) 的封装来进一步简化和管理数据库访问操作。 +- 业务实现:业务逻辑控制着何时发送和发送什么指令到数据库,其中有些业务会使用 [Spring Transaction](https://docs.spring.io/spring/docs/4.2.x/spring-framework-reference/html/transaction.html) 切面来控制管理事务的开始和提交逻辑。 + +![Java Component](/media/best-practices/java-practice-1.png) + +如上图所示,应用可能使用 Spring Transaction 来管理控制事务非手工启停,通过类似 MyBatis 的数据访问框架管理生成和执行 SQL,通过连接池获取已池化的长连接,最后通过 JDBC 接口调用实现通过 MySQL 协议和 TiDB 完成交互。 + +接下来将分别介绍使用各个组件时可能需要关注的问题。 + +## JDBC + +Java 应用尽管可以选择在不同的框架中封装,但在最底层一般会通过调用 JDBC 来与数据库服务器进行交互。对于 JDBC,需要关注的主要有:API 的使用选择和 API Implementer 的参数配置。 + +### JDBC API + +对于基本的 JDBC API 使用可以参考 [JDBC 官方教程](https://docs.oracle.com/javase/tutorial/jdbc/),本文主要强调几个比较重要的 API 选择。 + +#### 使用 Prepare API + +对于 OLTP 场景,程序发送给数据库的 SQL 语句在去除参数变化后都是可穷举的某几类,因此建议使用[预处理语句 (Prepared Statements)](https://docs.oracle.com/javase/tutorial/jdbc/basics/prepared.html) 代替普通的[文本执行](https://docs.oracle.com/javase/tutorial/jdbc/basics/processingsqlstatements.html#executing_queries),并复用预处理语句来直接执行,从而避免 TiDB 重复解析和生成 SQL 执行计划的开销。 + +目前多数上层框架都会调用 Prepare API 进行 SQL 执行,如果直接使用 JDBC API 进行开发,注意选择使用 Prepare API。 + +另外需要注意 MySQL Connector/J 实现中默认只会做客户端的语句预处理,会将 `?` 在客户端替换后以文本形式发送到服务端,所以除了要使用 Prepare API,还需要在 JDBC 连接参数中配置 `useServerPrepStmts = true`,才能在 TiDB 服务器端进行语句预处理(下面参数配置章节有详细介绍)。 + +#### 使用 Batch 批量插入更新 + +对于批量插入更新,如果插入记录较多,可以选择使用 [addBatch/executeBatch API](https://www.tutorialspoint.com/jdbc/jdbc-batch-processing)。通过 addBatch 的方式将多条 SQL 的插入更新记录先缓存在客户端,然后在 executeBatch 时一起发送到数据库服务器。 + +> **注意:** +> +> 对于 MySQL Connector/J 实现,默认 Batch 只是将多次 addBatch 的 SQL 发送时机延迟到调用 executeBatch 的时候,但实际网络发送还是会一条条的发送,通常不会降低与数据库服务器的网络交互次数。 +> +> 如果希望 Batch 网络发送,需要在 JDBC 连接参数中配置 `rewriteBatchedStatements = true`(下面参数配置章节有详细介绍)。 + +#### 使用 StreamingResult 流式获取执行结果 + +一般情况下,为提升执行效率,JDBC 会默认提前获取查询结果并将其保存在客户端内存中。但在查询返回超大结果集的场景中,客户端会希望数据库服务器减少向客户端一次返回的记录数,等客户端在有限内存处理完一部分后再去向服务器要下一批。 + +在 JDBC 中通常有以下两种处理方式: + +- 设置 [`FetchSize` 为 `Integer.MIN_VALUE`](https://dev.mysql.com/doc/connector-j/en/connector-j-reference-implementation-notes.html#ResultSet) 让客户端不缓存,客户端通过 StreamingResult 的方式从网络连接上流式读取执行结果。 + + 使用流式读取数据时,需要将 `resultset` 读取完成或 close 后,才能继续使用该语句进行下次查询,否则会报错 `No statements may be issued when any streaming result sets are open and in use on a given connection. Ensure that you have called .close() on any active streaming result sets before attempting more queries.`。 + + 如果需要在 `resultset` 读取完成或 close 前进行查询避免上述报错,可在 URL 中添加配置参数 `clobberStreamingResults=true`,这样会自动 close `resultset`,但之前流式查询未被读取的结果集会丢失。 + +- 使用 Cursor Fetch,首先需[设置 `FetchSize`](http://makejavafaster.blogspot.com/2015/06/jdbc-fetch-size-performance.html) 为正整数,且在 JDBC URL 中配置 `useCursorFetch = true`。 + +TiDB 中同时支持两种方式,但更推荐使用第一种将 `FetchSize` 设置为 `Integer.MIN_VALUE` 的方式,比第二种功能实现更简单且执行效率更高。 + +### MySQL JDBC 参数 + +JDBC 实现通常通过 JDBC URL 参数的形式来提供实现相关的配置。这里以 MySQL 官方的 Connector/J 来介绍[参数配置](https://dev.mysql.com/doc/connector-j/en/connector-j-reference-configuration-properties.html)(如果使用的是 MariaDB,可以参考 [MariaDB 的类似配置](https://mariadb.com/kb/en/library/about-mariadb-connector-j/#optional-url-parameters))。因为配置项较多,这里主要关注几个可能影响到性能的参数。 + +#### Prepare 相关参数 + +##### `useServerPrepStmts` + +默认情况下,`useServerPrepStmts` 的值为 `false`,即尽管使用了 Prepare API,也只会在客户端做 “prepare”。因此为了避免服务器重复解析的开销,如果同一条 SQL 语句需要多次使用 Prepare API,则建议设置该选项为 `true`。 + +在 TiDB 监控中可以通过 **Query Summary** > **CPS By Instance** 查看请求命令类型,如果请求中 `COM_QUERY` 被 `COM_STMT_EXECUTE` 或 `COM_STMT_PREPARE` 代替即生效。 + +##### `cachePrepStmts` + +虽然 `useServerPrepStmts = true` 能让服务端执行预处理语句,但默认情况下客户端每次执行完后会 close 预处理语句,并不会复用,这样预处理的效率甚至不如文本执行。所以建议开启 `useServerPrepStmts = true` 后同时配置 `cachePrepStmts = true`,这会让客户端缓存预处理语句。 + +在 TiDB 监控中可以通过 **Query Summary** > **CPS By Instance** 查看请求命令类型,如果请求中 `COM_STMT_EXECUTE` 数目远远多于 `COM_STMT_PREPARE` 即生效。 + +另外,通过 `useConfigs = maxPerformance` 配置会同时配置多个参数,其中也包括 `cachePrepStmts = true`。 + +##### `prepStmtCacheSqlLimit` + +在配置 `cachePrepStmts` 后还需要注意 `prepStmtCacheSqlLimit` 配置(默认为 `256`),该配置控制客户端缓存预处理语句的最大长度,超过该长度将不会被缓存。 + +在一些场景 SQL 的长度可能超过该配置,导致预处理 SQL 不能复用,建议根据应用 SQL 长度情况决定是否需要调大该值。 + +在 TiDB 监控中通过 **Query Summary** > **CPS By Instance** 查看请求命令类型,如果已经配置了 `cachePrepStmts = true`,但 `COM_STMT_PREPARE` 还是和 `COM_STMT_EXECUTE` 基本相等且有 `COM_STMT_CLOSE`,需要检查这个配置项是否设置得太小。 + +##### `prepStmtCacheSize` + +`prepStmtCacheSize` 控制缓存的预处理语句数目(默认为 `25`),如果应用需要预处理的 SQL 种类很多且希望复用预处理语句,可以调大该值。 + +和上一条类似,在监控中通过 **Query Summary** > **CPS By Instance** 查看请求中 `COM_STMT_EXECUTE` 数目是否远远多于 `COM_STMT_PREPARE` 来确认是否正常。 + +#### Batch 相关参数 + +在进行 batch 写入处理时推荐配置 `rewriteBatchedStatements = true`,在已经使用 `addBatch` 或 `executeBatch` 后默认 JDBC 还是会一条条 SQL 发送,例如: + +```java +pstmt = prepare(“insert into t (a) values(?)”); +pstmt.setInt(1, 10); +pstmt.addBatch(); +pstmt.setInt(1, 11); +pstmt.addBatch(); +pstmt.setInt(1, 12); +pstmt.executeBatch(); +``` + +虽然使用了 batch 但发送到 TiDB 语句还是单独的多条 insert: + +```sql +insert into t(a) values(10); +insert into t(a) values(11); +insert into t(a) values(12); +``` + +如果设置 `rewriteBatchedStatements = true`,发送到 TiDB 的 SQL 将是: + +```sql +insert into t(a) values(10),(11),(12); +``` + +需要注意的是,insert 语句的改写,只能将多个 values 后的值拼接成一整条 SQL,insert 语句如果有其他差异将无法被改写。例如: + +```sql +insert into t (a) values (10) on duplicate key update a = 10; +insert into t (a) values (11) on duplicate key update a = 11; +insert into t (a) values (12) on duplicate key update a = 12; +``` + +上述 insert 语句将无法被改写成一条语句。该例子中,如果将 SQL 改写成如下形式: + +```sql +insert into t (a) values (10) on duplicate key update a = values(a); +insert into t (a) values (11) on duplicate key update a = values(a); +insert into t (a) values (12) on duplicate key update a = values(a); +``` + +即可满足改写条件,最终被改写成: + +```sql +insert into t (a) values (10), (11), (12) on duplicate key update a = values(a); +``` + +批量更新时如果有 3 处或 3 处以上更新,则 SQL 语句会改写为 multiple-queries 的形式并发送,这样可以有效减少客户端到服务器的请求开销,但副作用是会产生较大的 SQL 语句,例如这样: + +```sql +update t set a = 10 where id = 1; update t set a = 11 where id = 2; update t set a = 12 where id = 3; +``` + +另外,因为一个[客户端 bug](https://bugs.mysql.com/bug.php?id=96623),批量更新时如果要配置 `rewriteBatchedStatements = true` 和 `useServerPrepStmts = true`,推荐同时配置 `allowMultiQueries = true` 参数来避免这个 bug。 + +#### 集成参数 + +通过监控可能会发现,虽然业务只向集群进行 insert 操作,却看到有很多多余的 select 语句。通常这是因为 JDBC 发送了一些查询设置类的 SQL 语句(例如 `select @@session.transaction_read_only`)。这些 SQL 对 TiDB 无用,推荐配置 `useConfigs = maxPerformance` 来避免额外开销。 + +`useConfigs = maxPerformance` 会包含一组配置,可查看 MySQL Connector/J [8.0 版本](https://github.com/mysql/mysql-connector-j/blob/release/8.0/src/main/resources/com/mysql/cj/configurations/maxPerformance.properties) 或 [5.1 版本](https://github.com/mysql/mysql-connector-j/blob/release/5.1/src/com/mysql/jdbc/configs/maxPerformance.properties) 来确认当前 MySQL Connector/J 中 `maxPerformance` 包含的具体配置。 + +配置后查看监控,可以看到多余语句减少。 + +#### 超时参数 + +TiDB 提供两个与 MySQL 兼容的超时控制参数,`wait_timeout` 和 `max_execution_time`。这两个参数分别控制与 Java 应用连接的空闲超时时间和连接中 SQL 执行的超时时间,即控制 TiDB 与 Java 应用的连接最长闲多久和最长忙多久。这两个参数的默认值都是 `0`,即默认允许连接无限闲置以及无限忙碌(一个 SQL 语句执行无限的长的时间)。 + +但在实际生产环境中,空闲连接和一直无限执行的 SQL 对数据库和应用都有不好的影响。你可以通过在应用的连接字符串中配置这两个参数来避免空闲连接和执行时间过长的 SQL 语句。例如,设置 `sessionVariables=wait_timeout=3600`(1 小时)和 `sessionVariables=max_execution_time=300000`(5 分钟)。 + +## 连接池 + +TiDB (MySQL) 连接建立是比较昂贵的操作(至少对于 OLTP),除了建立 TCP 连接外还需要进行连接鉴权操作,所以客户端通常会把 TiDB (MySQL) 连接保存到连接池中进行复用。 + +Java 的连接池实现很多 ([HikariCP](https://github.com/brettwooldridge/HikariCP), [tomcat-jdbc](https://tomcat.apache.org/tomcat-10.1-doc/jdbc-pool.html), [druid](https://github.com/alibaba/druid), [c3p0](https://www.mchange.com/projects/c3p0/), [dbcp](https://commons.apache.org/proper/commons-dbcp/)),TiDB 不会限定使用的连接池,应用可以根据业务特点自行选择连接池实现。 + +### 连接数配置 + +比较常见的是应用需要根据自身情况配置合适的连接池大小,以 HikariCP 为例: + +- `maximumPoolSize`:连接池最大连接数,配置过大会导致 TiDB 消耗资源维护无用连接,配置过小则会导致应用获取连接变慢,所以需根据应用自身特点配置合适的值,可参考[这篇文章](https://github.com/brettwooldridge/HikariCP/wiki/About-Pool-Sizing)。 +- `minimumIdle`:连接池最小空闲连接数,主要用于在应用空闲时存留一些连接以应对突发请求,同样是需要根据业务情况进行配置。 + +应用在使用连接池时,需要注意连接使用完成后归还连接,推荐应用使用对应的连接池相关监控(如 `metricRegistry`),通过监控能及时定位连接池问题。 + +### 探活配置 + +连接池维护客户端到 TiDB 的长连接的方式如下: + +- v5.4 版本前,TiDB 默认不会主动关闭客户端连接,除非出现报错情况。 +- 从 v5.4 起,TiDB 默认会在连接空闲超过 `28800` 秒(即 8 小时)后,自动关闭客户端连接。你可以使用 TiDB 与 MySQL 兼容的 `wait_timeout` 变量控制此超时时间,详见 [JDBC 查询超时](/develop/dev-guide-timeouts-in-tidb.md#jdbc-查询超时)文档。 + +此外,客户端到 TiDB 之间通常还会有 [LVS](https://en.wikipedia.org/wiki/Linux_Virtual_Server) 或 [HAProxy](https://en.wikipedia.org/wiki/HAProxy) 之类的网络代理。这些代理通常会在连接空闲超过特定时间(由代理的 idle 配置决定)后主动清理连接。除了关注代理的 idle 配置外,连接池还需要进行保活或探测连接。 + +如果常在 Java 应用中看到以下错误: + +``` +The last packet sent successfully to the server was 3600000 milliseconds ago. The driver has not received any packets from the server. com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure +``` + +如果 `n milliseconds ago` 中的 `n` 如果是 0 或很小的值,则通常是执行的 SQL 导致 TiDB 异常退出引起的报错,推荐查看 TiDB stderr 日志;如果 n 是一个非常大的值(比如这里的 3600000),很可能是因为这个连接空闲太久然后被中间 proxy 关闭了,通常解决方式除了调大 proxy 的 idle 配置,还可以让连接池执行以下操作: + +- 每次使用连接前检查连接是否可用。 +- 使用单独线程定期检查连接是否可用。 +- 定期发送 test query 保活连接。 + +不同的连接池实现可能会支持其中一种或多种方式,可以查看所使用的连接池文档来寻找对应配置。 + +## 数据访问框架 + +业务应用通常会使用某种数据访问框架来简化数据库的访问。 + +### MyBatis + +[MyBatis](http://www.mybatis.org/mybatis-3/) 是目前比较流行的 Java 数据访问框架,主要用于管理 SQL 并完成结果集和 Java 对象的来回映射工作。MyBatis 和 TiDB 兼容性很好,从历史 issue 可以看出 MyBatis 很少出现问题。这里主要关注如下几个配置。 + +#### Mapper 参数 + +MyBatis 的 Mapper 中支持两种参数: + +- `select 1 from t where id = #{param1}` 会作为预处理语句,被转换为 `select 1 from t where id = ?` 进行预处理,并使用实际参数来复用执行,通过配合前面的 Prepare 连接参数能获得最佳性能。 +- `select 1 from t where id = ${param2}` 会做文本替换为 `select 1 from t where id = 1` 执行,如果这条语句被预处理为不同参数,可能会导致 TiDB 缓存大量的预处理语句,并且以这种方式执行 SQL 有注入安全风险。 + +#### 动态 SQL Batch + +[动态 SQL - foreach](http://www.mybatis.org/mybatis-3/dynamic-sql.html#foreach) + +要支持将多条 insert 语句自动重写为 `insert ... values(...), (...), ...` 的形式,除了前面所说的在 JDBC 配置 `rewriteBatchedStatements = true` 外,MyBatis 还可以使用动态 SQL 来半自动生成 batch insert。比如下面的 mapper: + +```xml + + insert into test + (id, v1, v2) + values + + ( + #{item.id}, #{item.v1}, #{item.v2} + ) + + on duplicate key update v2 = v1 + values(v1) + +``` + +会生成一个 `insert on duplicate key update` 语句,values 后面的 `(?, ?, ?)` 数目是根据传入的 list 个数决定,最终效果和使用 `rewriteBatchStatements = true` 类似,可以有效减少客户端和 TiDB 的网络交互次数,同样需要注意预处理后超过 `prepStmtCacheSqlLimit` 限制导致不缓存预处理语句的问题。 + +#### Streaming 结果 + +前面介绍了在 JDBC 中如何使用流式读取结果,除了 JDBC 相应的配置外,在 MyBatis 中如果希望读取超大结果集合也需要注意: + +- 可以通过在 mapper 配置中对单独一条 SQL 设置 `fetchSize`(见上一段代码段),效果等同于调用 JDBC `setFetchSize` +- 可以使用带 `ResultHandler` 的查询接口来避免一次获取整个结果集 +- 可以使用 `Cursor` 类来进行流式读取 + +对于使用 xml 配置映射,可以通过在映射 ` + select * from post; + +``` + +而使用代码配置映射,则可以使用 `@Options(fetchSize = Integer.MIN_VALUE)` 并返回 `Cursor` 从而让 SQL 结果能被流式读取。 + +```java +@Select("select * from post") +@Options(fetchSize = Integer.MIN_VALUE) +Cursor queryAllPost(); +``` + +### `ExecutorType` + +在 `openSession` 的时候可以选择 `ExecutorType`,MyBatis 支持三种 executor: + +- Simple:每次执行都会向 JDBC 进行预处理语句的调用(如果 JDBC 配置有开启 `cachePrepStmts`,重复的预处理语句会复用)。 +- Reuse:在 `executor` 中缓存预处理语句,这样不用 JDBC 的 `cachePrepStmts` 也能减少重复预处理语句的调用。 +- Batch:每次更新只有在 `addBatch` 到 query 或 commit 时才会调用 `executeBatch` 执行,如果 JDBC 层开启了 `rewriteBatchStatements`,则会尝试改写,没有开启则会一条条发送。 + +通常默认值是 `Simple`,需要在调用 `openSession` 时改变 `ExecutorType`。如果是 Batch 执行,会遇到事务中前面的 update 或 insert 都非常快,而在读数据或 commit 事务时比较慢的情况,这实际上是正常的,在排查慢 SQL 时需要注意。 + +## Spring Transaction + +在应用代码中业务可能会通过使用 [Spring Transaction](https://docs.spring.io/spring/docs/4.2.x/spring-framework-reference/html/transaction.html) 和 AOP 切面的方式来启停事务。 + +通过在方法定义上添加 `@Transactional` 注解标记方法,AOP 将会在方法前开启事务,方法返回结果前提交事务。如果遇到类似业务,可以通过查找代码 `@Transactional` 来确定事务的开启和关闭时机。需要特别注意有内嵌的情况,如果发生内嵌,Spring 会根据 [Propagation](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/transaction/annotation/Propagation.html) 配置使用不同的行为。 + +## 其他 + +### 排查工具 + +在 Java 应用发生问题并且不知道业务逻辑情况下,使用 JVM 强大的排查工具会比较有用。这里简单介绍几个常用工具: + +#### jstack + +[jstack](https://docs.oracle.com/javase/7/docs/technotes/tools/share/jstack.html) 对应于 Go 中的 pprof/goroutine,可以比较方便地排查进程卡死的问题。 + +通过执行 `jstack pid`,即可输出目标进程中所有线程的线程 id 和堆栈信息。输出中默认只有 Java 堆栈,如果希望同时输出 JVM 中的 C++ 堆栈,需要加 `-m` 选项。 + +通过多次 jstack 可以方便地发现卡死问题(比如:都通过 Mybatis BatchExecutor flush 调用 update)或死锁问题(比如:测试程序都在抢占应用中某把锁导致没发送 SQL) + +另外,`top -p $PID -H` 或者 Java swiss knife 都是常用的查看线程 ID 的方法。通过 `printf "%x\n" pid` 把线程 ID 转换成 16 进制,然后去 jstack 输出结果中找对应线程的栈信息,可以定位”某个线程占用 CPU 比较高,不知道它在执行什么”的问题。 + +#### jmap & mat + +和 Go 中的 pprof/heap 不同,[jmap](https://docs.oracle.com/javase/7/docs/technotes/tools/share/jmap.html) 会将整个进程的内存快照 dump 下来(go 是分配器的采样),然后可以通过另一个工具 [mat](https://www.eclipse.org/mat/) 做分析。 + +通过 mat 可以看到进程中所有对象的关联信息和属性,还可以观察线程运行的状态。比如:我们可以通过 mat 找到当前应用中有多少 MySQL 连接对象,每个连接对象的地址和状态信息是什么。 + +需要注意 mat 默认只会处理 reachable objects,如果要排查 young gc 问题可以在 mat 配置中设置查看 unreachable objects。另外对于调查 young gc 问题(或者大量生命周期较短的对象)的内存分配,用 Java Flight Recorder 比较方便。 + +#### trace + +线上应用通常无法修改代码,又希望在 Java 中做动态插桩来定位问题,推荐使用 btrace 或 arthas trace。它们可以在不重启进程的情况下动态插入 trace 代码。 + +#### 火焰图 + +Java 应用中获取火焰图较繁琐,可参阅 [Java Flame Graphs Introduction: Fire For Everyone!](http://psy-lob-saw.blogspot.com/2017/02/flamegraphs-intro-fire-for-everyone.html) 来手动获取。 + +## 总结 + +本文从常用的和数据库交互的 Java 组件的角度,阐述了开发 Java 应用程序使用 TiDB 的常见问题与解决办法。TiDB 是高度兼容 MySQL 协议的数据库,基于 MySQL 开发的 Java 应用的最佳实践也多适用于 TiDB。 + +欢迎大家在 [ASK TUG](https://asktug.com/) 踊跃发言,和我们一起分享讨论 Java 应用使用 TiDB 的实践技巧或遇到的问题。 diff --git a/markdown-pages/zh/tidb/master/character-set-and-collation.md b/markdown-pages/zh/tidb/master/character-set-and-collation.md new file mode 100644 index 0000000..e1ffbe1 --- /dev/null +++ b/markdown-pages/zh/tidb/master/character-set-and-collation.md @@ -0,0 +1,567 @@ +--- +title: 字符集和排序规则 +aliases: ['/docs-cn/dev/character-set-and-collation/','/docs-cn/dev/reference/sql/characterset-and-collation/','/docs-cn/dev/reference/sql/character-set/'] +summary: TiDB 支持的字符集包括 ascii、binary、gbk、latin1、utf8 和 utf8mb4。排序规则包括 ascii_bin、binary、gbk_bin、gbk_chinese_ci、latin1_bin、utf8_bin、utf8_general_ci、utf8_unicode_ci、utf8mb4_0900_ai_ci、utf8mb4_0900_bin、utf8mb4_bin、utf8mb4_general_ci 和 utf8mb4_unicode_ci。TiDB 强烈建议使用 utf8mb4 字符集,因为它支持更多字符。在 TiDB 中,默认的排序规则受到客户端的连接排序规则设置的影响。如果客户端使用 utf8mb4_0900_ai_ci 作为连接排序规则,TiDB 将遵循客户端的配置。TiDB 还支持新的排序规则框架,用于在语义上支持不同的排序规则。 +--- + +# 字符集和排序规则 + +本文介绍了 TiDB 中支持的字符集和排序规则。 + +## 字符集和排序规则的概念 + +字符集 (character set) 是符号与编码的集合。TiDB 中的默认字符集是 utf8mb4,与 MySQL 8.0 及更高版本中的默认字符集匹配。 + +排序规则 (collation) 是在字符集中比较字符以及字符排序顺序的规则。例如,在二进制排序规则中,比较 `A` 和 `a` 的结果是不一样的: + +```sql +SET NAMES utf8mb4 COLLATE utf8mb4_bin; +SELECT 'A' = 'a'; +SET NAMES utf8mb4 COLLATE utf8mb4_general_ci; +SELECT 'A' = 'a'; +``` + +```sql +SELECT 'A' = 'a'; +``` + +```sql ++-----------+ +| 'A' = 'a' | ++-----------+ +| 0 | ++-----------+ +1 row in set (0.00 sec) +``` + +```sql +SET NAMES utf8mb4 COLLATE utf8mb4_general_ci; +``` + +```sql +Query OK, 0 rows affected (0.00 sec) +``` + +```sql +SELECT 'A' = 'a'; +``` + +```sql ++-----------+ +| 'A' = 'a' | ++-----------+ +| 1 | ++-----------+ +1 row in set (0.00 sec) +``` + +## 支持的字符集和排序规则 + +目前 TiDB 支持以下字符集: + +```sql +SHOW CHARACTER SET; +``` + +```sql ++---------+-------------------------------------+-------------------+--------+ +| Charset | Description | Default collation | Maxlen | ++---------+-------------------------------------+-------------------+--------+ +| ascii | US ASCII | ascii_bin | 1 | +| binary | binary | binary | 1 | +| gbk | Chinese Internal Code Specification | gbk_bin | 2 | +| latin1 | Latin1 | latin1_bin | 1 | +| utf8 | UTF-8 Unicode | utf8_bin | 3 | +| utf8mb4 | UTF-8 Unicode | utf8mb4_bin | 4 | ++---------+-------------------------------------+-------------------+--------+ +6 rows in set (0.00 sec) +``` + +TiDB 支持以下排序规则: + +```sql +SHOW COLLATION; +``` + +```sql ++--------------------+---------+------+---------+----------+---------+ +| Collation | Charset | Id | Default | Compiled | Sortlen | ++--------------------+---------+------+---------+----------+---------+ +| ascii_bin | ascii | 65 | Yes | Yes | 1 | +| binary | binary | 63 | Yes | Yes | 1 | +| gbk_bin | gbk | 87 | | Yes | 1 | +| gbk_chinese_ci | gbk | 28 | Yes | Yes | 1 | +| latin1_bin | latin1 | 47 | Yes | Yes | 1 | +| utf8_bin | utf8 | 83 | Yes | Yes | 1 | +| utf8_general_ci | utf8 | 33 | | Yes | 1 | +| utf8_unicode_ci | utf8 | 192 | | Yes | 1 | +| utf8mb4_0900_ai_ci | utf8mb4 | 255 | | Yes | 1 | +| utf8mb4_0900_bin | utf8mb4 | 309 | | Yes | 1 | +| utf8mb4_bin | utf8mb4 | 46 | Yes | Yes | 1 | +| utf8mb4_general_ci | utf8mb4 | 45 | | Yes | 1 | +| utf8mb4_unicode_ci | utf8mb4 | 224 | | Yes | 1 | ++--------------------+---------+------+---------+----------+---------+ +13 rows in set (0.00 sec) +``` + +> **警告:** +> +> TiDB 会错误地将 `latin1` 视为 `utf8` 的子集。当用户存储不同于 `latin1` 和 `utf8` 编码的字符时,可能会导致意外情况出现。因此强烈建议使用 `utf8mb4` 字符集。详情参阅 [TiDB #18955](https://github.com/pingcap/tidb/issues/18955)。 + +> **注意:** +> +> TiDB 中的默认排序规则(后缀为 `_bin` 的二进制排序规则)与 [MySQL 中的默认排序规则](https://dev.mysql.com/doc/refman/8.0/en/charset-charsets.html)不同,后者通常是一般排序规则,后缀为 `_general_ci` 或 `_ai_ci`。当用户指定了显式字符集,但依赖于待选的隐式默认排序规则时,这个差异可能导致兼容性问题。 +> 在 TiDB 中,默认的排序规则也受到客户端的[连接排序规则](https://dev.mysql.com/doc/refman/8.0/en/charset-connection.html#charset-connection-system-variables)设置的影响。例如,MySQL 8.x 客户端默认使用 `utf8mb4_0900_ai_ci` 作为 `utf8mb4` 字符集的连接排序规则。 +> +> - 在 TiDB v7.4.0 之前,如果客户端使用 `utf8mb4_0900_ai_ci` 作为[连接排序规则](https://dev.mysql.com/doc/refman/8.0/en/charset-connection.html#charset-connection-system-variables),因为 TiDB 不支持 `utf8mb4_0900_ai_ci` 排序规则,TiDB 将回退到使用 TiDB 服务器默认的排序规则 `utf8mb4_bin`。 +> - 从 v7.4.0 开始,如果客户端使用 `utf8mb4_0900_ai_ci` 作为[连接排序规则](https://dev.mysql.com/doc/refman/8.0/en/charset-connection.html#charset-connection-system-variables),TiDB 将遵循客户端的配置,使用 `utf8mb4_0900_ai_ci` 作为默认排序规则。 + +利用以下的语句可以查看字符集对应的排序规则(以下是[新的排序规则框架](#新框架下的排序规则支持))下的结果: + +```sql +SHOW COLLATION WHERE Charset = 'utf8mb4'; +``` + +```sql ++--------------------+---------+------+---------+----------+---------+ +| Collation | Charset | Id | Default | Compiled | Sortlen | ++--------------------+---------+------+---------+----------+---------+ +| utf8mb4_0900_ai_ci | utf8mb4 | 255 | | Yes | 1 | +| utf8mb4_0900_bin | utf8mb4 | 309 | | Yes | 1 | +| utf8mb4_bin | utf8mb4 | 46 | Yes | Yes | 1 | +| utf8mb4_general_ci | utf8mb4 | 45 | | Yes | 1 | +| utf8mb4_unicode_ci | utf8mb4 | 224 | | Yes | 1 | ++--------------------+---------+------+---------+----------+---------+ +5 rows in set (0.00 sec) +``` + +TiDB 对 GBK 字符集的支持详情见 [GBK](/character-set-gbk.md)。 + +## TiDB 中的 `utf8` 和 `utf8mb4` + +MySQL 限制字符集 `utf8` 为最多 3 个字节。这足以存储在基本多语言平面 (BMP) 中的字符,但不足以存储表情符号 (emoji) 等字符。因此,建议改用字符集`utf8mb4`。 + +默认情况下,TiDB 同样限制字符集 `utf8` 为最多 3 个字节,以确保 TiDB 中创建的数据可以在 MySQL 中顺利恢复。你可以禁用此功能,方法是将系统变量 [`tidb_check_mb4_value_in_utf8`](/system-variables.md#tidb_check_mb4_value_in_utf8) 的值更改为 `OFF`。 + +以下示例演示了在表中插入 4 字节的表情符号字符(emoji 字符)时的默认行为。`utf8` 字符集下 `INSERT` 语句不能执行,`utf8mb4` 字符集下可以执行 `INSERT` 语句: + +```sql +CREATE TABLE utf8_test ( + c char(1) NOT NULL + ) CHARACTER SET utf8; +``` + +```sql +Query OK, 0 rows affected (0.09 sec) +``` + +```sql +CREATE TABLE utf8m4_test ( + c char(1) NOT NULL + ) CHARACTER SET utf8mb4; +``` + +```sql +Query OK, 0 rows affected (0.09 sec) +``` + +```sql +INSERT INTO utf8_test VALUES ('😉'); +``` + +```sql +ERROR 1366 (HY000): incorrect utf8 value f09f9889(😉) for column c +``` + +```sql +INSERT INTO utf8m4_test VALUES ('😉'); +``` + +```sql +Query OK, 1 row affected (0.02 sec) +``` + +```sql +SELECT char_length(c), length(c), c FROM utf8_test; +``` + +```sql +Empty set (0.01 sec) +``` + +```sql +SELECT char_length(c), length(c), c FROM utf8m4_test; +``` + +```sql ++----------------+-----------+------+ +| char_length(c) | length(c) | c | ++----------------+-----------+------+ +| 1 | 4 | 😉 | ++----------------+-----------+------+ +1 row in set (0.00 sec) +``` + +## 不同范围的字符集和排序规则 + +字符集和排序规则可以在设置在不同的层次。 + +### 数据库的字符集和排序规则 + +每个数据库都有相应的字符集和排序规则。数据库的字符集和排序规则可以通过以下语句来设置: + +```sql +CREATE DATABASE db_name + [[DEFAULT] CHARACTER SET charset_name] + [[DEFAULT] COLLATE collation_name] + +ALTER DATABASE db_name + [[DEFAULT] CHARACTER SET charset_name] + [[DEFAULT] COLLATE collation_name] +``` + +在这里 `DATABASE` 可以跟 `SCHEMA` 互换使用。 + +不同的数据库之间可以使用不一样的字符集和排序规则。 + +通过系统变量 `character_set_database` 和 `collation_database` 可以查看到当前数据库的字符集以及排序规则: + +```sql +CREATE SCHEMA test1 CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; +``` + +```sql +Query OK, 0 rows affected (0.09 sec) +``` + +```sql +USE test1; +``` + +```sql +Database changed +``` + +```sql +SELECT @@character_set_database, @@collation_database; +``` + +```sql ++--------------------------|----------------------+ +| @@character_set_database | @@collation_database | ++--------------------------|----------------------+ +| utf8mb4 | utf8mb4_general_ci | ++--------------------------|----------------------+ +1 row in set (0.00 sec) +``` + +```sql +CREATE SCHEMA test2 CHARACTER SET latin1 COLLATE latin1_bin; +``` + +```sql +Query OK, 0 rows affected (0.09 sec) +``` + +```sql +USE test2; +``` + +```sql +Database changed +``` + +```sql +SELECT @@character_set_database, @@collation_database; +``` + +```sql ++--------------------------|----------------------+ +| @@character_set_database | @@collation_database | ++--------------------------|----------------------+ +| latin1 | latin1_bin | ++--------------------------|----------------------+ +1 row in set (0.00 sec) +``` + +在 INFORMATION_SCHEMA 中也可以查看到这两个值: + +```sql +SELECT DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME +FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = 'db_name'; +``` + +### 表的字符集和排序规则 + +表的字符集和排序规则可以通过以下语句来设置: + +```sql +CREATE TABLE tbl_name (column_list) + [[DEFAULT] CHARACTER SET charset_name] + [COLLATE collation_name]] + +ALTER TABLE tbl_name + [[DEFAULT] CHARACTER SET charset_name] + [COLLATE collation_name] +``` + +例如: + +```sql +CREATE TABLE t1(a int) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; +``` + +```sql +Query OK, 0 rows affected (0.08 sec) +``` + +如果表的字符集和排序规则没有设置,那么数据库的字符集和排序规则就作为其默认值。在仅指定字符集为 `utf8mb4`,但未设置排序规则时,排序规则为变量 [`default_collation_for_utf8mb4`](/system-variables.md#default_collation_for_utf8mb4-从-v740-版本开始引入) 指定的值。 + +### 列的字符集和排序规则 + +列的字符集和排序规则的语法如下: + +```sql +col_name {CHAR | VARCHAR | TEXT} (col_length) + [CHARACTER SET charset_name] + [COLLATE collation_name] + +col_name {ENUM | SET} (val_list) + [CHARACTER SET charset_name] + [COLLATE collation_name] +``` + +如果列的字符集和排序规则没有设置,那么表的字符集和排序规则就作为其默认值。在仅指定字符集为 `utf8mb4`,但未设置排序规则时,排序规则为变量 [`default_collation_for_utf8mb4`](/system-variables.md#default_collation_for_utf8mb4-从-v740-版本开始引入) 指定的值。 + +### 字符串的字符集和排序规则 + +每一个字符串都对应一个字符集和一个排序规则,在使用字符串时指此选项可选,如下: + +```sql +[_charset_name]'string' [COLLATE collation_name] +``` + +示例如下: + +```sql +SELECT 'string'; +SELECT _utf8mb4'string'; +SELECT _utf8mb4'string' COLLATE utf8mb4_general_ci; +``` + +规则如下: + +* 规则 1:如果指定了 `CHARACTER SET charset_name` 和 `COLLATE collation_name`,则直接使用 `charset_name` 字符集和 `collation_name` 排序规则。 +* 规则 2:如果指定了 `CHARACTER SET charset_name` 且未指定 `COLLATE collation_name`,则使用 `charset_name` 字符集和 `charset_name` 对应的默认排序规则。 +* 规则 3:如果 `CHARACTER SET charset_name` 和 `COLLATE collation_name` 都未指定,则使用 `character_set_connection` 和 `collation_connection` 系统变量给出的字符集和排序规则。 + +### 客户端连接的字符集和排序规则 + +* 服务器的字符集和排序规则可以通过系统变量 `character_set_server` 和 `collation_server` 获取。 +* 数据库的字符集和排序规则可以通过环境变量 `character_set_database` 和 `collation_database` 获取。 + +对于每一个客户端的连接,也有相应的变量表示字符集和排序规则:`character_set_connection` 和 `collation_connection`。 + +`character_set_client` 代表客户端的字符集。在返回结果前,服务端会把结果根据 `character_set_results` 转换成对应的字符集,包括结果的元信息等。 + +可以用以下的语句来影响这些跟客户端相关的字符集变量: + +* `SET NAMES 'charset_name' [COLLATE 'collation_name']` + + `SET NAMES` 用来设定客户端会在之后的请求中使用的字符集。`SET NAMES utf8mb4` 表示客户端会在接下来的请求中,都使用 utf8mb4 字符集。服务端也会在之后返回结果的时候使用 utf8mb4 字符集。`SET NAMES 'charset_name'` 语句其实等于下面语句的组合: + + ```sql + SET character_set_client = charset_name; + SET character_set_results = charset_name; + SET character_set_connection = charset_name; + ``` + + `COLLATE` 是可选的,如果没有提供,将会用 `charset_name` 对应的默认排序规则设置 `collation_connection`。 + +* `SET CHARACTER SET 'charset_name'` + + 跟 `SET NAMES` 类似,等价于下面语句的组合: + + ```sql + SET character_set_client = charset_name; + SET character_set_results = charset_name; + SET charset_connection = @@charset_database; + SET collation_connection = @@collation_database; + ``` + +## 服务器、数据库、表、列、字符串的字符集和排序规则的优先级 + +优先级从高到低排列顺序为: + +字符串 > 列 > 表 > 数据库 > 服务器 + +## 字符集和排序规则的通用选择规则 + +* 规则 1:如果指定了 `CHARACTER SET charset_name` 和 `COLLATE collation_name`,则直接使用 `charset_name` 字符集和 `collation_name` 排序规则。 +* 规则 2:如果指定了 `CHARACTER SET charset_name` 且未指定 `COLLATE collation_name`,则使用 `charset_name` 字符集和 `charset_name` 对应的默认排序规则。 +* 规则 3:如果 `CHARACTER SET charset_name` 和 `COLLATE collation_name` 都未指定,则使用更高优先级的字符集和排序规则。 + +## 字符合法性检查 + +当指定的字符集为 utf8 或 utf8mb4 时,TiDB 仅支持合法的 utf8 字符。对于不合法的字符,会报错:`incorrect utf8 value`。该字符合法性检查与 MySQL 8.0 兼容,与 MySQL 5.7 及以下版本不兼容。 + +如果不希望报错,可以通过 `set @@tidb_skip_utf8_check=1;` 跳过字符检查。 + +> **注意:** +> +> 跳过字符检查可能会使 TiDB 检测不到应用写入的非法 UTF-8 字符,进一步导致执行 `ANALYZE` 时解码错误,以及引入其他未知的编码问题。如果应用不能保证写入字符串的合法性,不建议跳过该检查。 + +## 排序规则支持 + +排序规则的语法支持和语义支持受到配置项 [`new_collations_enabled_on_first_bootstrap`](/tidb-configuration-file.md#new_collations_enabled_on_first_bootstrap) 的影响。这里语法支持和语义支持有所区别。语法支持是指 TiDB 能够解析和设置排序规则;而语义支持是指 TiDB 能够在比较字符串时正确地使用排序规则。 + +在 4.0 版本之前,TiDB 只提供了旧的排序规则框架,能够在语法上支持的绝大部分 MySQL 排序规则,但语义上所有的排序规则都当成二进制排序规则。 + +4.0 版本中,TiDB 增加了新的排序规则框架用于在语义上支持不同的排序规则,保证字符串比较时严格遵循对应的排序规则,详情请见下文。 + +### 旧框架下的排序规则支持 + +在 4.0 版本之前,TiDB 中可以指定大部分 MySQL 中的排序规则,并把这些排序规则按照默认排序规则处理,即以编码字节序为字符定序。和 MySQL 不同的是,TiDB 不会处理字符末尾的空格,因此会造成以下的行为区别: + +```sql +CREATE TABLE t(a varchar(20) charset utf8mb4 collate utf8mb4_general_ci PRIMARY KEY); +``` + +```sql +Query OK, 0 rows affected +``` + +```sql +INSERT INTO t VALUES ('A'); +``` + +```sql +Query OK, 1 row affected +``` + +```sql +INSERT INTO t VALUES ('a'); +``` + +```sql +Query OK, 1 row affected +``` + +以上语句,在 TiDB 会执行成功,而在 MySQL 中,由于 `utf8mb4_general_ci` 大小写不敏感,报错 `Duplicate entry 'a'`。 + +```sql +INSERT INTO t VALUES ('a '); +``` + +```sql +Query OK, 1 row affected +``` + +以上语句,在 TiDB 会执行成功,而在 MySQL 中,由于补齐空格比较,报错 `Duplicate entry 'a '`。 + +### 新框架下的排序规则支持 + +TiDB 4.0 新增了完整的排序规则支持框架,从语义上支持了排序规则,并新增了配置开关 `new_collations_enabled_on_first_bootstrap`,在集群初次初始化时决定是否启用新排序规则框架。如需启用新排序规则框架,可将 `new_collations_enabled_on_first_bootstrap` 的值设为 `true`,详情参见 [`new_collations_enabled_on_first_bootstrap`](/tidb-configuration-file.md#new_collations_enabled_on_first_bootstrap)。 + +对于一个已经初始化完成的 TiDB 集群,可以通过 `mysql.tidb` 表中的 `new_collation_enabled` 变量确认是否启用了新排序规则框架。 + +> **注意:** +> +> 当 `mysql.tidb` 表查询结果和 `new_collations_enabled_on_first_bootstrap` 的值不同时,以 `mysql.tidb` 表的结果为准。 + +```sql +SELECT VARIABLE_VALUE FROM mysql.tidb WHERE VARIABLE_NAME='new_collation_enabled'; +``` + +```sql ++----------------+ +| VARIABLE_VALUE | ++----------------+ +| True | ++----------------+ +1 row in set (0.00 sec) +``` + +在新的排序规则框架下,TiDB 能够支持 `utf8_general_ci`、`utf8mb4_general_ci`、`utf8_unicode_ci`、`utf8mb4_unicode_ci`、`utf8mb4_0900_bin`、`utf8mb4_0900_ai_ci`、`gbk_chinese_ci` 和 `gbk_bin` 这几种排序规则,与 MySQL 兼容。 + +使用 `utf8_general_ci`、`utf8mb4_general_ci`、`utf8_unicode_ci`、`utf8mb4_unicode_ci`、`utf8mb4_0900_ai_ci` 和 `gbk_chinese_ci` 中任一种时,字符串之间的比较是大小写不敏感 (case-insensitive) 和口音不敏感 (accent-insensitive) 的。同时,TiDB 还修正了排序规则的 `PADDING` 行为: + +```sql +CREATE TABLE t(a varchar(20) charset utf8mb4 collate utf8mb4_general_ci PRIMARY KEY); +``` + +```sql +Query OK, 0 rows affected (0.00 sec) +``` + +```sql +INSERT INTO t VALUES ('A'); +``` + +```sql +Query OK, 1 row affected (0.00 sec) +``` + +```sql +INSERT INTO t VALUES ('a'); +``` + +```sql +ERROR 1062 (23000): Duplicate entry 'a' for key 't.PRIMARY' +``` + +TiDB 兼容了 MySQL 的 case insensitive collation。 + +```sql +INSERT INTO t VALUES ('a '); +``` + +```sql +ERROR 1062 (23000): Duplicate entry 'a ' for key 't.PRIMARY' +``` + +TiDB 修正了 `PADDING` 行为,与 MySQL 兼容。 + +> **注意:** +> +> TiDB 中 padding 的实现方式与 MySQL 的不同。在 MySQL 中,padding 是通过补齐空格实现的。而在 TiDB 中 padding 是通过裁剪掉末尾的空格来实现的。两种做法在绝大多数情况下是一致的,唯一的例外是字符串尾部包含小于空格 (0x20) 的字符时,例如 `'a' < 'a\t'` 在 TiDB 中的结果为 `1`,而在 MySQL 中,其等价于 `'a ' < 'a\t'`,结果为 `0`。 + +## 表达式中排序规则的 Coercibility 值 + +如果一个表达式涉及多个不同排序规则的子表达式时,需要对计算时用的排序规则进行推断,规则如下: + ++ 显式 `COLLATE` 子句的 coercibility 值为 `0`。 ++ 如果两个字符串的排序规则不兼容,这两个字符串 `concat` 结果的 coercibility 值为 `1`。 ++ 列或者 `CAST()`、`CONVERT()` 和 `BINARY()` 的排序规则的 coercibility 值为 `2`。 ++ 系统常量(`USER()` 或者 `VERSION()` 返回的字符串)的 coercibility 值为 `3`。 ++ 常量的 coercibility 值为 `4`。 ++ 数字或者中间变量的 coercibility 值为 `5`。 ++ `NULL` 或者由 `NULL` 派生出的表达式的 coercibility 值为 `6`。 + +在推断排序规则时,TiDB 优先使用 coercibility 值较低的表达式的排序规则。如果 coercibility 值相同,则按以下优先级确定排序规则: + +binary > utf8mb4_bin > (utf8mb4_general_ci = utf8mb4_unicode_ci) > utf8_bin > (utf8_general_ci = utf8_unicode_ci) > latin1_bin > ascii_bin + +以下情况 TiDB 无法推断排序规则并报错: + +- 如果两个子表达式的排序规则不相同,而且表达式的 coercibility 值都为 `0`。 +- 如果两个子表达式的排序规则不兼容,而且表达式的返回类型为 `String` 类。 + +## `COLLATE` 子句 + +TiDB 支持使用 `COLLATE` 子句来指定一个表达式的排序规则,该表达式的 coercibility 值为 `0`,具有最高的优先级。示例如下: + +```sql +SELECT 'a' = _utf8mb4 'A' collate utf8mb4_general_ci; +``` + +```sql ++-----------------------------------------------+ +| 'a' = _utf8mb4 'A' collate utf8mb4_general_ci | ++-----------------------------------------------+ +| 1 | ++-----------------------------------------------+ +1 row in set (0.00 sec) +``` + +更多细节,参考 [Connection Character Sets and Collations](https://dev.mysql.com/doc/refman/8.0/en/charset-connection.html)。 diff --git a/markdown-pages/zh/tidb/master/column-pruning.md b/markdown-pages/zh/tidb/master/column-pruning.md new file mode 100644 index 0000000..544fa87 --- /dev/null +++ b/markdown-pages/zh/tidb/master/column-pruning.md @@ -0,0 +1,19 @@ +--- +title: 列裁剪 +aliases: ['/docs-cn/dev/column-pruning/'] +summary: 列裁剪是优化器在优化过程中删除不需要的列的基本思想。这样可以减少 I/O 资源占用并为后续优化带来便利。TiDB 会在逻辑优化阶段进行列裁剪,减少资源浪费。该扫描过程称作“列裁剪”,对应逻辑优化规则中的 columnPruner。如果要关闭这个规则,可以参照优化规则及表达式下推的黑名单中的关闭方法。 +--- + +# 列裁剪 + +列裁剪的基本思想在于:对于算子中实际用不上的列,优化器在优化的过程中没有必要保留它们。对这些列的删除会减少 I/O 资源占用,并为后续的优化带来便利。下面给出一个列重复的例子: + +假设表 t 里面有 a b c d 四列,执行如下语句: + +```sql +select a from t where b > 5 +``` + +在该查询的过程中,t 表实际上只有 a, b 两列会被用到,而 c, d 的数据则显得多余。对应到该语句的查询计划,Selection 算子会用到 b 列,下面接着的 DataSource 算子会用到 a, b 两列,而剩下 c, d 两列则都可以裁剪掉,DataSource 算子在读数据时不需要将它们读进来。 + +出于上述考量,TiDB 会在逻辑优化阶段进行自上而下的扫描,裁剪不需要的列,减少资源浪费。该扫描过程称作 “列裁剪”,对应逻辑优化规则中的 `columnPruner`。如果要关闭这个规则,可以在参照[优化规则及表达式下推的黑名单](/blocklist-control-plan.md)中的关闭方法。 diff --git a/markdown-pages/zh/tidb/master/command-line-flags-for-pd-configuration.md b/markdown-pages/zh/tidb/master/command-line-flags-for-pd-configuration.md new file mode 100644 index 0000000..f2da10c --- /dev/null +++ b/markdown-pages/zh/tidb/master/command-line-flags-for-pd-configuration.md @@ -0,0 +1,114 @@ +--- +title: PD 配置参数 +aliases: ['/docs-cn/dev/command-line-flags-for-pd-configuration/','/docs-cn/dev/reference/configuration/pd-server/configuration/'] +summary: PD 配置参数可以通过命令行参数或环境变量配置。包括外部访问 PD 的 URL 列表,其他 PD 节点访问某个 PD 节点的 URL 列表,PD 监听的客户端 URL 列表,PD 节点监听其他 PD 节点的 URL 列表,配置文件,PD 存储数据路径,初始化 PD 集群配置,动态加入 PD 集群,Log 级别,Log 文件,是否开启日志切割,当前 PD 的名字,CA 文件路径,包含 X509 证书的 PEM 文件路径,包含 X509 key 的 PEM 文件路径,指定 Prometheus Pushgateway 的地址,强制使用当前节点创建新的集群,输出版本信息并退出。 +--- + +# PD 配置参数 + +PD 可以通过命令行参数或环境变量配置。 + +## `--advertise-client-urls` + ++ 用于外部访问 PD 的 URL 列表。 ++ 默认:`${client-urls}` ++ 在某些情况下,例如 Docker 或者 NAT 网络环境,客户端并不能通过 PD 自己监听的 client URLs 来访问到 PD,这时候,你就可以设置 advertise URLs 来让客户端访问。 ++ 例如,Docker 内部 IP 地址为 `172.17.0.1`,而宿主机的 IP 地址为 `192.168.100.113` 并且设置了端口映射 `-p 2379:2379`,那么可以设置为 `--advertise-client-urls="http://192.168.100.113:2379"`,客户端可以通过 `http://192.168.100.113:2379` 来找到这个服务。 + +## `--advertise-peer-urls` + ++ 用于其他 PD 节点访问某个 PD 节点的 URL 列表。 ++ 默认:`${peer-urls}` ++ 在某些情况下,例如 Docker 或者 NAT 网络环境,其他节点并不能通过 PD 自己监听的 peer URLs 来访问到 PD,这时候,你就可以设置 advertise URLs 来让其他节点访问。 ++ 例如,Docker 内部 IP 地址为 `172.17.0.1`,而宿主机的 IP 地址为 `192.168.100.113` 并且设置了端口映射 `-p 2380:2380`,那么可以设置为 `advertise-peer-urls="http://192.168.100.113:2380"`,其他 PD 节点可以通过 `http://192.168.100.113:2380` 来找到这个服务。 + +## `--client-urls` + ++ PD 监听的客户端 URL 列表。 ++ 默认:`http://127.0.0.1:2379` ++ 如果部署一个集群,`--client-urls` 必须指定当前主机的 IP 地址,例如 `http://192.168.100.113:2379"`,如果是运行在 Docker 则需要指定为 `http://0.0.0.0:2379`。 + +## `--peer-urls` + ++ PD 节点监听其他 PD 节点的 URL 列表。 ++ 默认:`http://127.0.0.1:2380` ++ 如果部署一个集群,`--peer-urls` 必须指定当前主机的 IP 地址,例如 `http://192.168.100.113:2380`,如果是运行在 Docker 则需要指定为 `http://0.0.0.0:2380`。 + +## `--config` + ++ 配置文件。 ++ 默认:"" ++ 如果你指定了配置文件,PD 会首先读取配置文件的配置。然后如果对应的配置在命令行参数里面也存在,PD 就会使用命令行参数的配置来覆盖配置文件里面的。 + +## `--data-dir` + ++ PD 存储数据路径。 ++ 默认:`default.${name}` + +## `--initial-cluster` + ++ 初始化 PD 集群配置。 ++ 默认:`"{name}=http://{advertise-peer-url}"` ++ 例如,如果 name 是 "pd",并且 `advertise-peer-urls` 是 `http://192.168.100.113:2380`,那么 `initial-cluster` 就是 `pd=http://192.168.100.113:2380`。 ++ 如果你需要启动三台 PD,那么 `initial-cluster` 可能就是 `pd1=http://192.168.100.113:2380, pd2=http://192.168.100.114:2380, pd3=192.168.100.115:2380`。 + +## `--join` + ++ 动态加入 PD 集群。 ++ 默认:"" ++ 如果你想动态将一台 PD 加入集群,你可以使用 `--join="${advertise-client-urls}"`,`advertise-client-url` 是当前集群里面任意 PD 的 `advertise-client-url`,你也可以使用多个 PD 的,需要用逗号分隔。 + +## `-L` + ++ Log 级别。 ++ 默认:"info" ++ 可选:"debug","info","warn","error","fatal" + +## `--log-file` + ++ Log 文件。 ++ 默认:"" ++ 如果没设置这个参数,log 会默认输出到 "stderr",如果设置了,log 就会输出到对应的文件里面。 + +## `--log-rotate` + ++ 是否开启日志切割。 ++ 默认:true ++ 当值为 true 时,按照 PD 配置文件中 `[log.file]` 信息执行。 + +## `--name` + ++ 当前 PD 的名字。 ++ 默认:"pd" ++ 如果你需要启动多个 PD,一定要给 PD 使用不同的名字 + +## `--cacert` + ++ CA 文件路径,用于开启 TLS。 ++ 默认:"" + +## `--cert` + ++ 包含 X509 证书的 PEM 文件路径,用户开启 TLS。 ++ 默认:"" + +## `--key` + ++ 包含 X509 key 的 PEM 文件路径,用于开启 TLS。 ++ 默认:"" + +## `--metrics-addr` + ++ 指定 Prometheus Pushgateway 的地址。 ++ 默认:"" ++ 如果留空,则不开启 Prometheus Push。 + +## `--force-new-cluster` + ++ 强制使用当前节点创建新的集群。 ++ 默认:false ++ 仅用于在 PD 丢失多数副本的情况下恢复服务,可能会产生部分数据丢失。 + +## `-V`, `--version` + ++ 输出版本信息并退出。 diff --git a/markdown-pages/zh/tidb/master/command-line-flags-for-tidb-configuration.md b/markdown-pages/zh/tidb/master/command-line-flags-for-tidb-configuration.md new file mode 100644 index 0000000..dbe79b4 --- /dev/null +++ b/markdown-pages/zh/tidb/master/command-line-flags-for-tidb-configuration.md @@ -0,0 +1,235 @@ +--- +title: TiDB 配置参数 +aliases: ['/docs-cn/dev/command-line-flags-for-tidb-configuration/','/docs-cn/dev/reference/configuration/tidb-server/configuration/'] +summary: TiDB 配置参数包括启动参数和环境变量。启动参数包括 advertise-address、config、config-check、config-strict、cors、enable-binlog 等。其中默认端口为 4000 和 10080。其他参数包括 log-file、metrics-addr、metrics-interval 等。注意配置文件的有效性和安全模式下的启动。 +--- + +# TiDB 配置参数 + +在启动 TiDB 时,你可以使用命令行参数或环境变量来配置 TiDB。 + +要快速了解 TiDB 的参数体系与参数作用域,建议先观看下面的培训视频(时长 17 分钟)。 + + + +本文将详细介绍 TiDB 的命令行启动参数。TiDB 的默认端口为 4000(客户端请求)与 10080(状态报告)。 + +## `--advertise-address` + ++ 登录 TiDB 的 IP 地址 ++ 默认:"" ++ 必须确保用户和集群中的其他机器都能够访问到该 IP 地址 + +## `--config` + ++ 配置文件 ++ 默认:"" ++ 如果你指定了配置文件,TiDB 会首先读取配置文件的配置。如果对应的配置在命令行参数里面也存在,TiDB 就会使用命令行参数的配置来覆盖配置文件中的配置。详细的配置项请参阅 [TiDB 配置文件描述](/tidb-configuration-file.md)。 + +## `--config-check` + +- 检查配置文件的有效性并退出 +- 默认:false + +## `--config-strict` + +- 增强配置文件的有效性 +- 默认:false + +## `--cors` + ++ 用于设置 TiDB HTTP 状态服务的 Access-Control-Allow-Origin ++ 默认:"" + +## `--enable-binlog` + ++ 开启或关闭 TiDB 中 binlog 的生成 ++ 默认:false + +## `--host` + ++ TiDB 服务监听的 host ++ 默认:"0.0.0.0" ++ 0.0.0.0 默认会监听所有的网卡地址。如果有多块网卡,可以指定对外提供服务的网卡,如 192.168.100.113 + +## `--initialize-insecure` + +- 在不安全模式下启动 tidb-server +- 默认:true + +## `--initialize-secure` + +- 在安全模式下启动 tidb-server +- 默认:false + +## `--initialize-sql-file` + +- 用于指定 TiDB 集群初次启动时执行的 SQL 脚本。参考[配置项 `initialize-sql-file`](/tidb-configuration-file.md#initialize-sql-file-从-v660-版本开始引入) +- 默认:"" + +## `-L` + ++ Log 级别 ++ 默认:"info" ++ 可选:"debug","info","warn","error","fatal" + +## `--lease` + +- Schema lease 的持续时间。除非你知道更改该值带来的后果,否则你的更改操作是**危险的**。 +- 默认:45s + +## `--log-file` + ++ Log 文件 ++ 默认:"" ++ 如果未设置该参数,log 会默认输出到 "stderr";如果设置了该参数,log 会输出到对应的文件中。 + +## `--log-general` + ++ [General Log](/system-variables.md#tidb_general_log) 文件名 ++ 默认:"" ++ 如果未设置该参数,general log 会默认输出到 [`--log-file`](#--log-file) 指定的文件中。 + +## `--log-slow-query` + ++ 慢查询日志文件路径 ++ 默认:"" ++ 如果未设置该参数,log 会默认输出到 `--log-file` 指定的文件中 + +## `--metrics-addr` + ++ Prometheus Pushgateway 地址 ++ 默认:"" ++ 如果该参数为空,TiDB 不会将统计信息推送给 Pushgateway。参数格式示例:`--metrics-addr=192.168.100.115:9091` + +## `--metrics-interval` + ++ 推送统计信息到 Prometheus Pushgateway 的时间间隔 ++ 默认:15s ++ 设置为 0 表示不推送统计信息给 Pushgateway。示例:`--metrics-interval=2` 指每两秒推送到 Pushgateway + +## `-P` + ++ TiDB 服务监听端口 ++ 默认:"4000" ++ TiDB 服务会使用该端口接受 MySQL 客户端发来的请求 + +## `--path` + ++ 对于本地存储引擎 "unistore" 来说,path 指定的是实际的数据存放路径 ++ 当 `--store = tikv` 时,必须指定 path;当 `--store = unistore` 时,如果不指定 path,会使用默认值。 ++ 对于 "TiKV" 存储引擎来说,path 指定的是实际的 PD 地址。假如在 192.168.100.113:2379、192.168.100.114:2379 和 192.168.100.115:2379 上面部署了 PD,那么 path 为 "192.168.100.113:2379, 192.168.100.114:2379, 192.168.100.115:2379" ++ 默认:"/tmp/tidb" ++ 可以通过 `tidb-server --store=unistore --path=""` 来启动一个纯内存引擎的 TiDB + +## `--proxy-protocol-networks` + ++ 允许使用 [PROXY 协议](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt)连接 TiDB 的代理服务器地址列表。 ++ 默认:"" ++ 通常情况下,通过反向代理使用 TiDB 时,TiDB 会将反向代理服务器的 IP 地址视为客户端 IP 地址。对于支持 [PROXY 协议](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt)的反向代理(如 HAProxy),开启 PROXY 协议后能让反向代理透传客户端真实的 IP 地址给 TiDB。 ++ 配置该参数后,TiDB 将允许配置的源 IP 地址使用 PROXY 协议连接到 TiDB,且拒绝这些源 IP 地址使用非 PROXY 协议连接。其他地址可以使用非 PROXY 协议连接到 TiDB。若该参数为空,则任何源 IP 地址都不能使用 PROXY 协议连接到 TiDB。地址可以使用 IP 地址格式 (192.168.1.50) 或者 CIDR 格式 (192.168.1.0/24),并可用 `,` 分隔多个地址,或用 `*` 代表所有 IP 地址。 + +> **警告:** +> +> 需谨慎使用 `*` 符号,因为它可能引入安全风险,允许来自任何 IP 的客户端自行汇报其 IP 地址。另外,当 [`--proxy-protocol-fallbackable`](#--proxy-protocol-fallbackable) 设置为 `true` 以外的值时,使用 `*` 可能会导致部分直接连接 TiDB 的内部组件无法使用,例如 TiDB Dashboard。 + +> **注意:** +> +> 如果使用 AWS 的 Network Load Balancer (NLB) 并开启 PROXY 协议,需要设置 NLB 的 `target group` 属性:将 `proxy_protocol_v2.client_to_server.header_place` 设为 `on_first_ack`。同时向 AWS 的 Support 提工单开通此功能的支持。注意,AWS NLB 在开启 PROXY 协议后,客户端将无法获取服务器端的握手报文,因此报文会一直阻塞到客户端超时。这是因为,NLB 默认只在客户端发送数据之后才会发送 PROXY 的报文,而在客户端发送数据包之前,服务器端发送的任何数据包都会在内网被丢弃。 + +## `--proxy-protocol-fallbackable` + ++ 用于控制是否启用 PROXY 协议回退模式。如果设置为 `true`,TiDB 可以接受属于 `--proxy-protocol-networks` 的客户端使用非 PROXY 协议规范或者没有发送 PROXY 协议头的客户端连接。默认情况下,TiDB 仅接受属于 `--proxy-protocol-networks` 的客户端发送 PROXY 协议头的客户端连接。 ++ 默认:`false` + +## `--proxy-protocol-header-timeout` + ++ PROXY 协议请求头读取超时时间 ++ 默认:5 ++ 单位:秒 + +> **警告:** +> +> 自 v6.3.0 起,该参数被废弃。因为自 v6.3.0 起,读取 PROXY 协议报头的操作会在第一次读取网络数据时进行,废弃该参数可避免影响首次读取网络数据时设置的超时时间。 + +> **注意:** +> +> 不要将该参数配置为 `0`。除非特殊情况,一般使用默认值即可。 + +## `--report-status` + ++ 用于打开或者关闭服务状态监听端口 ++ 默认:true ++ 将参数值设置为 `true` 表明开启状态监听端口;设置为 `false` 表明关闭状态监听端口 + +## `--run-ddl` + ++ tidb-server 是否运行 DDL 语句,集群内至少需要有一台 tidb-server 设置该参数 ++ 默认:true ++ 值可以为 `true` 或者 `false`。设置为 `true` 表明自身会运行 DDL;设置为 `false` 表明自身不会运行 DDL + +## `--socket string` + ++ TiDB 服务使用 unix socket file 方式接受外部连接 ++ 默认:"" ++ 例如可以使用 "/tmp/tidb.sock" 来打开 unix socket file + +## `--status` + ++ TiDB 服务状态监听端口 ++ 默认:"10080" ++ 该端口用于展示 TiDB 内部数据,包括 [prometheus 统计](https://prometheus.io/)和 [pprof](https://golang.org/pkg/net/http/pprof/) ++ Prometheus 统计可以通过 `http://host:status_port/metrics` 访问 ++ pprof 数据可以通过 `http://host:status_port/debug/pprof` 访问 + +## `--status-host` + ++ TiDB 服务状态监听 host ++ 默认:"0.0.0.0" + +## `--store` + ++ 用来指定 TiDB 底层使用的存储引擎 ++ 默认:"unistore" ++ 可以选择 "unistore"(本地存储引擎)或者 "tikv"(分布式存储引擎) + +## `--temp-dir` + +- TiDB 用于存放临时文件的目录 +- 默认:"/tmp/tidb" + +## `--token-limit` + ++ TiDB 中同时允许运行的 Session 数量,用于流量控制 ++ 默认:1000 ++ 如果当前运行的连接多于该 token-limit,那么请求会阻塞,等待已经完成的操作释放 Token + +## `-V` + ++ 输出 TiDB 的版本 ++ 默认:"" + +## `--plugin-dir` + ++ plugin 存放目录 ++ 默认:"/data/deploy/plugin" + +## `--plugin-load` + ++ 需要加载的 plugin 名称,多个 plugin 以 "," 逗号分隔 ++ 默认:"" + +## `--affinity-cpus` + ++ 设置 TiDB server CPU 亲和性,以 "," 逗号分隔,例如 "1,2,3" ++ 默认:"" + +## `--repair-mode` + ++ 是否开启修复模式,仅用于数据修复场景 ++ 默认:false + +## `--repair-list` + ++ 修复模式下需要修复的表名 ++ 默认:"" diff --git a/markdown-pages/zh/tidb/master/command-line-flags-for-tikv-configuration.md b/markdown-pages/zh/tidb/master/command-line-flags-for-tikv-configuration.md new file mode 100644 index 0000000..d176ddc --- /dev/null +++ b/markdown-pages/zh/tidb/master/command-line-flags-for-tikv-configuration.md @@ -0,0 +1,99 @@ +--- +title: TiKV 配置参数 +aliases: ['/docs-cn/dev/command-line-flags-for-tikv-configuration/','/docs-cn/dev/reference/configuration/tikv-server/configuration/'] +summary: TiKV 配置参数支持文件大小和时间的可读性好的单位转换。命令行参数包括监听地址、对外访问地址、服务状态监听端口、对外访问服务状态地址、配置文件、存储数据的容量、配置信息输出格式、数据存储路径、日志级别、日志文件、PD 地址列表。需要注意的是,PD 地址列表需要使用逗号分隔多个地址。 +--- + +# TiKV 配置参数 + +TiKV 的命令行参数支持一些可读性好的单位转换。 + ++ 文件大小(以 bytes 为单位):KB, MB, GB, TB, PB(也可以全小写) ++ 时间(以毫秒为单位):ms, s, m, h + +## `-A, --addr` + ++ TiKV 监听地址。 ++ 默认:"127.0.0.1:20160" ++ 如果部署一个集群,\-\-addr 必须指定当前主机的 IP 地址,例如 "192.168.100.113:20160",如果是运行在 docker 则需要指定为 "0.0.0.0:20160"。 + +## `--advertise-addr` + ++ TiKV 对外访问地址。 ++ 默认:${addr} ++ 在某些情况下,比如 Docker 或者 NAT 网络环境,客户端并不能通过 `--addr` 的地址来访问到 TiKV。这时候,你可以设置 `--advertise-addr` 来让客户端访问 TiKV。 ++ 例如,docker 内部 IP 地址为 172.17.0.1,而宿主机的 IP 地址为 192.168.100.113 并且设置了端口映射 -p 20160:20160,那么可以设置为 \-\-advertise-addr="192.168.100.113:20160",客户端可以通过 192.168.100.113:20160 来找到这个服务。 + +## `--status-addr` + ++ TiKV 服务状态监听端口。 ++ 默认:"20180" ++ Prometheus 统计可以通过 `http://host:status_port/metrics` 访问。 ++ Profile 数据可以通过 `http://host:status_port/debug/pprof/profile` 访问。 + +## `--advertise-status-addr` + ++ TiKV 对外访问服务状态地址。 ++ 默认:使用 `--status-addr` ++ 在某些情况下,例如 docker 或者 NAT 网络环境,客户端并不能通过 `--status-addr` 的地址来访问到 TiKV。此时,你可以设置 `--advertise-status-addr` 来让客户端访问 TiKV。 ++ 例如,Docker 内部 IP 地址为 `172.17.0.1`,而宿主机的 IP 地址为 `192.168.100.113` 并且设置了端口映射 `-p 20180:20180`,那么可以设置 `--advertise-status-addr="192.168.100.113:20180"`,客户端可以通过 `192.168.100.113:20180` 来找到这个服务。 + +## `-C, --config` + ++ 配置文件。 ++ 默认:"" ++ 如果你指定了配置文件,TiKV 会首先读取配置文件的配置。然后如果对应的配置在命令行参数里面也存在,TiKV 就会使用命令行参数的配置来覆盖配置文件里面的。 + +## `--capacity` + ++ TiKV 存储数据的容量。 ++ 默认:0(无限) ++ PD 需要使用这个值来对整个集群做 balance 操作。(提示:你可以使用 10GB 来替代 10737418240,从而简化参数的传递)。 + +## `--config-info ` + ++ 按照指定的 `FORMAT` 输出各个配置项的取值信息并退出。 ++ `FORMAT` 可选值:`json`。 ++ 目前仅支持以 JSON 格式输出每个配置项的名字 (Name)、默认值 (DefaultValue) 和当前配置值 (ValueInFile)。当执行此命令时,若同时指定了 `-C` 或 `--config` 参数,则对应的配置文件包含的配置项会同时输出当前配置值和默认值,其他未指定的配置项仅输出默认值,示例如下: + + ```json + { + "Component": "TiKV Server", + "Version": "6.2.0", + "Parameters": [ + { + "Name": "log-level", + "DefaultValue": "info", + "ValueInFile": "warn" + }, + { + "Name": "log-file", + "DefaultValue": "" + }, + ... + ] + } + ``` + +## `--data-dir` + ++ TiKV 数据存储路径。 ++ 默认:"/tmp/tikv/store" + +## `-L` + ++ Log 级别。 ++ 默认:"info" ++ 可选值:"debug","info","warn","error","fatal" + +## `--log-file` + ++ Log 文件。 ++ 默认:"" ++ 如果没设置这个参数,log 会默认输出到 "stderr",如果设置了,log 就会输出到对应的文件里面。 + +## `--pd` + ++ PD 地址列表。 ++ 默认:"" ++ TiKV 必须使用这个值连接 PD,才能正常工作。使用逗号来分隔多个 PD 地址,例如:192.168.100.113:2379, 192.168.100.114:2379, 192.168.100.115:2379。 diff --git a/markdown-pages/zh/tidb/master/configure-time-zone.md b/markdown-pages/zh/tidb/master/configure-time-zone.md new file mode 100644 index 0000000..13474e1 --- /dev/null +++ b/markdown-pages/zh/tidb/master/configure-time-zone.md @@ -0,0 +1,94 @@ +--- +title: 时区支持 +aliases: ['/docs-cn/dev/configure-time-zone/','/docs-cn/dev/how-to/configure/time-zone/'] +summary: TiDB 使用的时区由全局变量和 session 变量决定。全局变量的默认值是 System,实际时区在集群初始化时设置。可以通过设置全局时区和 session 变量来修改时区。Timestamp 数据类型受时区影响,而 Datetime/Date/Time 不受影响。在导数据时需注意主从库的时区设定是否一致。 +--- + +# 时区支持 + +TiDB 使用的时区由 `time_zone` 全局变量和 session 变量决定。`time_zone` 的默认值是 `System`,`System` 对应的实际时区在 `TiDB` 集群 bootstrap 初始化时设置。具体逻辑如下: + +* 优先使用 `TZ` 环境变量 +* 如果失败,则从 `/etc/localtime` 的实际软链地址提取。 +* 如果上面两种都失败则使用 `UTC` 作为系统时区。 + +在运行过程中可以修改全局时区: + +```sql +SET GLOBAL time_zone = timezone; +``` + +TiDB 还可以通过设置 session 变量 `time_zone` 为每个连接维护各自的时区。默认条件下,这个值取的是全局变量 `time_zone` 的值。修改 session 使用的时区: + +```sql +SET time_zone = timezone; +``` + +使用以下 SQL 语句查看当前全局时区、客户端时区和系统时区的值: + +```sql +SELECT @@global.time_zone, @@session.time_zone, @@global.system_time_zone; +``` + +设置 `time_zone` 的值的格式: + +* 'SYSTEM' 表明使用系统时间 +* 相对于 UTC 时间的偏移,比如 '+10:00' 或者 '-6:00' +* 某个时区的名字,比如 'Europe/Helsinki','US/Eastern' 或 'MET' + +`NOW()` 和 `CURTIME()` 的返回值都受到时区设置的影响。 + +> **注意:** +> +> 只有 Timestamp 数据类型的值是受时区影响的。可以理解为,Timestamp 数据类型的实际表示使用的是(字面值 + 时区信息)。其它时间和日期类型,比如 Datetime/Date/Time 是不包含时区信息的,所以也不受到时区变化的影响。 + +```sql +create table t (ts timestamp, dt datetime); +``` + +``` +Query OK, 0 rows affected (0.02 sec) +``` + +```sql +set @@time_zone = 'UTC'; +``` + +``` +Query OK, 0 rows affected (0.00 sec) +``` + +```sql +insert into t values ('2017-09-30 11:11:11', '2017-09-30 11:11:11'); +``` + +``` +Query OK, 1 row affected (0.00 sec) +``` + +```sql +set @@time_zone = '+8:00'; +``` + +``` +Query OK, 0 rows affected (0.00 sec) +``` + +```sql +select * from t; +``` + +``` ++---------------------|---------------------+ +| ts | dt | ++---------------------|---------------------+ +| 2017-09-30 19:11:11 | 2017-09-30 11:11:11 | ++---------------------|---------------------+ +1 row in set (0.00 sec) +``` + +上面的例子中,无论怎么调整时区的值,Datetime 类型字段的值是不受影响的,而 Timestamp 则随着时区改变,显示的值会发生变化。其实 Timestamp 持久化到存储的值始终没有变化过,只是根据时区的不同显示值不同。 + +Timestamp 类型和 Datetime 等类型的值,两者相互转换的过程中,会涉及到时区。这种情况一律基于 session 的当前 `time_zone` 时区处理。 + +另外,用户在导数据的过程中,也要需注意主库和从库之间的时区设定是否一致。 diff --git a/markdown-pages/zh/tidb/master/constraints.md b/markdown-pages/zh/tidb/master/constraints.md new file mode 100644 index 0000000..70e04cf --- /dev/null +++ b/markdown-pages/zh/tidb/master/constraints.md @@ -0,0 +1,449 @@ +--- +title: 约束 +aliases: ['/docs-cn/dev/constraints/','/docs-cn/dev/reference/sql/constraints/'] +summary: TiDB 支持的约束与 MySQL 基本相同,包括非空约束和 CHECK 约束。非空约束规则与 MySQL 相同,而 CHECK 约束需要在 tidb_enable_check_constraint 设置为 ON 后才能开启。可以通过 CREATE TABLE 或 ALTER TABLE 语句添加 CHECK 约束。唯一约束和主键约束也与 MySQL 相似,但 TiDB 目前仅支持对 NONCLUSTERED 的主键进行添加和删除操作。外键约束从 v6.6.0 开始支持,可以使用 CREATE TABLE 和 ALTER TABLE 命令来添加和删除外键。 +--- + +# 约束 + +TiDB 支持的约束与 MySQL 的基本相同。 + +## 非空约束 + +TiDB 支持的非空约束规则与 MySQL 支持的一致。例如: + +```sql +CREATE TABLE users ( + id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, + age INT NOT NULL, + last_login TIMESTAMP +); +``` + +```sql +INSERT INTO users (id,age,last_login) VALUES (NULL,123,NOW()); +``` + +``` +Query OK, 1 row affected (0.02 sec) +``` + +```sql +INSERT INTO users (id,age,last_login) VALUES (NULL,NULL,NOW()); +``` + +``` +ERROR 1048 (23000): Column 'age' cannot be null +``` + +```sql +INSERT INTO users (id,age,last_login) VALUES (NULL,123,NULL); +``` + +``` +Query OK, 1 row affected (0.03 sec) +``` + +* 第一条 `INSERT` 语句成功,因为对于定义为 `AUTO_INCREMENT` 的列,允许 `NULL` 作为其特殊值。TiDB 将为其分配下一个自动值。 + +* 第二条 `INSERT` 语句失败,因为 `age` 列被定义为 `NOT NULL`。 + +* 第三条 `INSERT` 语句成功,因为 `last_login` 列没有被明确地指定为 `NOT NULL`。默认允许 `NULL` 值。 + +## `CHECK` 约束 + +> **注意:** +> +> `CHECK` 约束功能默认关闭,需要将变量 [`tidb_enable_check_constraint`](/system-variables.md#tidb_enable_check_constraint-从-v720-版本开始引入) 设置为 `ON` 后才能开启。 + +`CHECK` 约束用于限制表中某个字段的值必须满足指定条件。当为表添加 `CHECK` 约束后,在插入或者更新表的数据时,TiDB 会检查约束条件是否满足,如果不满足,则会报错。 + +TiDB 中 `CHECK` 约束的语法如下,与 MySQL 中一致: + +```sql +[CONSTRAINT [symbol]] CHECK (expr) [[NOT] ENFORCED] +``` + +语法说明: + +- `[]` 中的内容表示可选项。 +- `CONSTRAINT [symbol]` 表示 `CHECK` 约束的名称。 +- `CHECK (expr)` 表示约束条件,其中 `expr` 需要为一个布尔表达式。对于表中的每一行,该表达式的计算结果必须为 `TRUE`、`FALSE` 或 `UNKNOWN` (对于 `NULL` 值) 中的一个。对于某行数据,如果该表达式计算结果为 `FALSE`,则表示违反约束条件。 +- `[NOT] ENFORCED` 表示是否执行约束,可以用于启用或者禁用 `CHECK` 约束。 + +### 添加 `CHECK` 约束 + +在 TiDB 中,你可以在 [`CREATE TABLE`](/sql-statements/sql-statement-create-table.md) 或者 [`ALTER TABLE`](/sql-statements/sql-statement-modify-column.md) 语句中为表添加 `CHECK` 约束。 + +- 在 `CREATE TABLE` 语句中添加 `CHECK` 约束的示例: + + ```sql + CREATE TABLE t(a INT CHECK(a > 10) NOT ENFORCED, b INT, c INT, CONSTRAINT c1 CHECK (b > c)); + ``` + +- 在 `ALTER TABLE` 语句中添加 `CHECK` 约束的示例: + + ```sql + ALTER TABLE t ADD CONSTRAINT CHECK (1 < c); + ``` + +在添加或者启用 `CHECK` 约束时,TiDB 会对表中的存量数据进行校验。如果存在违反约束的数据,添加 `CHECK` 约束操作将失败并且报错。 + +在添加 `CHECK` 约束时,可以指定约束名,也可以不指定约束名。如果不指定约束名,那么 TiDB 会自动生成一个格式为 `_chk_<1, 2, 3...>` 的约束名。 + +### 查看 `CHECK` 约束 + +你可以通过 [`SHOW CREATE TABLE`](/sql-statements/sql-statement-show-create-table.md) 查看表中的约束信息。例如: + +```sql +SHOW CREATE TABLE t; ++-------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Table | Create Table | ++-------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| t | CREATE TABLE `t` ( + `a` int(11) DEFAULT NULL, + `b` int(11) DEFAULT NULL, + `c` int(11) DEFAULT NULL, +CONSTRAINT `c1` CHECK ((`b` > `c`)), +CONSTRAINT `t_chk_1` CHECK ((`a` > 10)) /*!80016 NOT ENFORCED */, +CONSTRAINT `t_chk_2` CHECK ((1 < `c`)) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin | ++-------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +1 row in set (0.00 sec) +``` + +### 删除 `CHECK` 约束 + +删除 `CHECK` 约束时,你需要指定需要删除的约束名。例如: + +```sql +ALTER TABLE t DROP CONSTRAINT t_chk_1; +``` + +### 启用或禁用 `CHECK` 约束 + +在为表[添加 `CHECK` 约束](#添加-check-约束)的时候,可以指定当插入或者更新数据时 TiDB 是否执行约束检查。 + +- 如果指定了 `NOT ENFORCED`,当插入或者更新数据时,TiDB 不会检查约束条件。 +- 如果未指定 `NOT ENFORCED` 或者指定了 `ENFORCED`,当插入或者更新数据时,TiDB 会检查约束条件。 + +除了在添加约束时候指定 `[NOT] ENFORCED`,你还可以在 `ALTER TABLE` 语句中启用或者禁用 `CHECK` 约束。例如: + +```sql +ALTER TABLE t ALTER CONSTRAINT c1 NOT ENFORCED; +``` + +### 与 MySQL 的兼容性 + +- 不支持在添加列的同时添加 `CHECK` 约束(例如,`ALTER TABLE t ADD COLUMN a CHECK(a > 0)`)),否则只有列会被添加成功,TiDB 会忽略 `CHECK` 约束但不会报错。 +- 不支持使用 `ALTER TABLE t CHANGE a b int CHECK(b > 0)` 添加 `CHECK` 约束,使用该语句时 TiDB 会报错。 + +## 唯一约束 + +唯一约束是指唯一索引和主键列中所有的非空值都是唯一的。 + +### 乐观事务 + +在 TiDB 的乐观事务中,默认会对唯一约束进行[惰性检查](/transaction-overview.md#惰性检查)。通过在事务提交时再进行批量检查,TiDB 能够减少网络开销、提升性能。例如: + +```sql +DROP TABLE IF EXISTS users; +CREATE TABLE users ( + id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, + username VARCHAR(60) NOT NULL, + UNIQUE KEY (username) +); +INSERT INTO users (username) VALUES ('dave'), ('sarah'), ('bill'); +``` + +乐观事务模式下且 `tidb_constraint_check_in_place=OFF`: + +```sql +BEGIN OPTIMISTIC; +INSERT INTO users (username) VALUES ('jane'), ('chris'), ('bill'); +``` + +``` +Query OK, 3 rows affected (0.00 sec) +Records: 3 Duplicates: 0 Warnings: 0 +``` + +```sql +INSERT INTO users (username) VALUES ('steve'),('elizabeth'); +``` + +``` +Query OK, 2 rows affected (0.00 sec) +Records: 2 Duplicates: 0 Warnings: 0 +``` + +```sql +COMMIT; +``` + +``` +ERROR 1062 (23000): Duplicate entry 'bill' for key 'users.username' +``` + +在以上乐观事务的示例中,唯一约束的检查推迟到事务提交时才进行。由于 `bill` 值已经存在,这一行为导致了重复键错误。 + +你可通过设置 [`tidb_constraint_check_in_place`](/system-variables.md#tidb_constraint_check_in_place) 为 `ON` 停用此行为(该变量仅适用于乐观事务,悲观事务需通过 `tidb_constraint_check_in_place_pessimistic` 设置)。当 `tidb_constraint_check_in_place` 设置为 `ON` 时,TiDB 会在执行语句时就对唯一约束进行检查。例如: + +```sql +DROP TABLE IF EXISTS users; +CREATE TABLE users ( + id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, + username VARCHAR(60) NOT NULL, + UNIQUE KEY (username) +); +INSERT INTO users (username) VALUES ('dave'), ('sarah'), ('bill'); +``` + +```sql +SET tidb_constraint_check_in_place = ON; +``` + +``` +Query OK, 0 rows affected (0.00 sec) +``` + +```sql +BEGIN OPTIMISTIC; +``` + +``` +Query OK, 0 rows affected (0.00 sec) +``` + +```sql +INSERT INTO users (username) VALUES ('jane'), ('chris'), ('bill'); +``` + +``` +ERROR 1062 (23000): Duplicate entry 'bill' for key 'users.username' +``` + +第一条 `INSERT` 语句导致了重复键错误。这会造成额外的网络通信开销,并可能降低插入操作的吞吐量。 + +### 悲观事务 + +在 TiDB 的悲观事务中,默认在执行任何一条需要插入或更新唯一索引的 SQL 语句时都会进行唯一约束检查: + +```sql +DROP TABLE IF EXISTS users; +CREATE TABLE users ( + id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, + username VARCHAR(60) NOT NULL, + UNIQUE KEY (username) +); +INSERT INTO users (username) VALUES ('dave'), ('sarah'), ('bill'); + +BEGIN PESSIMISTIC; +INSERT INTO users (username) VALUES ('jane'), ('chris'), ('bill'); +``` + +``` +ERROR 1062 (23000): Duplicate entry 'bill' for key 'users.username' +``` + +对于悲观事务,你可以设置变量 [`tidb_constraint_check_in_place_pessimistic`](/system-variables.md#tidb_constraint_check_in_place_pessimistic-从-v630-版本开始引入) 为 `OFF` 来推迟唯一约束检查,到下一次对该唯一索引项加锁时或事务提交时再进行检查,同时也跳过对该悲观锁加锁,以获得更好的性能。此时需要注意: + +- 由于推迟了唯一约束检查,TiDB 可能会读取到不满足唯一约束的结果,执行 `COMMIT` 语句时可能返回 `Duplicate entry` 错误。返回该错误时,TiDB 会回滚当前事务。 + + 下面这个例子跳过了对 `bill` 的加锁,因此 TiDB 可能读到不满足唯一性约束的结果: + + ```sql + SET tidb_constraint_check_in_place_pessimistic = OFF; + BEGIN PESSIMISTIC; + INSERT INTO users (username) VALUES ('jane'), ('chris'), ('bill'); -- Query OK, 3 rows affected + SELECT * FROM users FOR UPDATE; + ``` + + TiDB 读到了不满足唯一性约束的结果:有两个 `bill`。 + + ```sql + +----+----------+ + | id | username | + +----+----------+ + | 1 | dave | + | 2 | sarah | + | 3 | bill | + | 7 | jane | + | 8 | chris | + | 9 | bill | + +----+----------+ + ``` + + 此时,如果提交事务,TiDB 将进行唯一约束检查,报出 `Duplicate entry` 错误并回滚事务。 + + ```sql + COMMIT; + ``` + + ``` + ERROR 1062 (23000): Duplicate entry 'bill' for key 'users.username' + ``` + +- 关闭该变量时,如果在事务中写入数据,执行 `COMMIT` 语句可能会返回 `Write conflict` 错误。返回该错误时,TiDB 会回滚当前事务。 + + 在下面这个例子中,当有并发事务写入时,跳过悲观锁导致事务提交时报出 `Write conflict` 错误并回滚。 + + ```sql + DROP TABLE IF EXISTS users; + CREATE TABLE users ( + id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, + username VARCHAR(60) NOT NULL, + UNIQUE KEY (username) + ); + + SET tidb_constraint_check_in_place_pessimistic = OFF; + BEGIN PESSIMISTIC; + INSERT INTO users (username) VALUES ('jane'), ('chris'), ('bill'); -- Query OK, 3 rows affected + ``` + + 然后另一个会话中写入了 `bill`: + + ```sql + INSERT INTO users (username) VALUES ('bill'); -- Query OK, 1 row affected + ``` + + 在第一个会话中提交时,TiDB 会报出 `Write conflict` 错误。 + + ```sql + COMMIT; + ``` + + ``` + ERROR 9007 (HY000): Write conflict, txnStartTS=435688780611190794, conflictStartTS=435688783311536129, conflictCommitTS=435688783311536130, key={tableID=74, indexID=1, indexValues={bill, }} primary={tableID=74, indexID=1, indexValues={bill, }}, reason=LazyUniquenessCheck [try again later] + ``` + +- 关闭该变量时,如果多个悲观事务之间存在写冲突,悲观锁可能会在其它悲观事务提交时被强制回滚,因此产生 `PessimisticLockNotFound` 错误。发生该错误时,说明该业务不适合推迟悲观事务的唯一约束检查,应考虑调整业务避免冲突,或在发生错误后重试事务。 + +- 关闭该变量会导致悲观事务中可能报出错误 `8147: LazyUniquenessCheckFailure`。 + + > **注意:** + > + > 返回 8147 错误时当前事务回滚。 + + 下面的例子在 INSERT 语句执行时跳过了一次加锁后,在 DELETE 语句执行时对该唯一索引加锁并检查,即会在该语句报错: + + ```sql + SET tidb_constraint_check_in_place_pessimistic = OFF; + BEGIN PESSIMISTIC; + INSERT INTO users (username) VALUES ('jane'), ('chris'), ('bill'); -- Query OK, 3 rows affected + DELETE FROM users where username = 'bill'; + ``` + + ``` + ERROR 8147 (23000): transaction aborted because lazy uniqueness check is enabled and an error occurred: [kv:1062]Duplicate entry 'bill' for key 'users.username' + ``` + +- 关闭该变量时,`1062 Duplicate entry` 报错不一定是当前执行的 SQL 语句所发生的错误。因此,在一个事务操作多个表,且这些表有同名索引时,请注意 `1062` 报错信息中提示的是哪个表的哪个索引发生了错误。 + +## 主键约束 + +与 MySQL 行为一样,主键约束包含了唯一约束,即创建了主键约束相当于拥有了唯一约束。此外,TiDB 其他的主键约束规则也与 MySQL 相似。例如: + +```sql +CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY); +``` + +``` +Query OK, 0 rows affected (0.12 sec) +``` + +```sql +CREATE TABLE t2 (a INT NULL PRIMARY KEY); +``` + +``` +ERROR 1171 (42000): All parts of a PRIMARY KEY must be NOT NULL; if you need NULL in a key, use UNIQUE instead +``` + +```sql +CREATE TABLE t3 (a INT NOT NULL PRIMARY KEY, b INT NOT NULL PRIMARY KEY); +``` + +``` +ERROR 1068 (42000): Multiple primary key defined +``` + +```sql +CREATE TABLE t4 (a INT NOT NULL, b INT NOT NULL, PRIMARY KEY (a,b)); +``` + +``` +Query OK, 0 rows affected (0.10 sec) +``` + +分析: + +* 表 `t2` 创建失败,因为定义为主键的列 `a` 不能允许 `NULL` 值。 +* 表 `t3` 创建失败,因为一张表只能有一个主键。 +* 表 `t4` 创建成功,因为虽然只能有一个主键,但 TiDB 支持定义一个多列组合作为复合主键。 + +除上述规则外,TiDB 目前仅支持对 `NONCLUSTERED` 的主键进行添加和删除操作。例如: + +```sql +CREATE TABLE t5 (a INT NOT NULL, b INT NOT NULL, PRIMARY KEY (a,b) CLUSTERED); +ALTER TABLE t5 DROP PRIMARY KEY; +``` + +``` +ERROR 8200 (HY000): Unsupported drop primary key when the table is using clustered index +``` + +```sql +CREATE TABLE t5 (a INT NOT NULL, b INT NOT NULL, PRIMARY KEY (a,b) NONCLUSTERED); +ALTER TABLE t5 DROP PRIMARY KEY; +``` + +``` +Query OK, 0 rows affected (0.10 sec) +``` + +要了解关于 `CLUSTERED` 主键的详细信息,请参考[聚簇索引](/clustered-indexes.md)。 + +## 外键约束 + +> **注意:** +> +> TiDB 从 v6.6.0 开始支持[外键约束](/foreign-key.md)(实验特性)。在 v6.6.0 之前,TiDB 支持创建和删除外键约束,但外键约束并不生效。升级到 v6.6.0 后,可以先删除不生效的外键后再创建外键使外键约束生效。 + +TiDB 支持创建外键约束。例如: + +```sql +CREATE TABLE users ( + id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, + doc JSON +); +CREATE TABLE orders ( + id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, + user_id INT NOT NULL, + doc JSON, + FOREIGN KEY fk_user_id (user_id) REFERENCES users(id) +); +``` + +```sql +SELECT table_name, column_name, constraint_name, referenced_table_name, referenced_column_name +FROM information_schema.key_column_usage WHERE table_name IN ('users', 'orders'); +``` + +``` ++------------+-------------+-----------------+-----------------------+------------------------+ +| table_name | column_name | constraint_name | referenced_table_name | referenced_column_name | ++------------+-------------+-----------------+-----------------------+------------------------+ +| users | id | PRIMARY | NULL | NULL | +| orders | id | PRIMARY | NULL | NULL | +| orders | user_id | fk_user_id | users | id | ++------------+-------------+-----------------+-----------------------+------------------------+ +3 rows in set (0.00 sec) +``` + +TiDB 也支持使用 `ALTER TABLE` 命令来删除外键 (`DROP FOREIGN KEY`) 和添加外键 (`ADD FOREIGN KEY`): + +```sql +ALTER TABLE orders DROP FOREIGN KEY fk_user_id; +ALTER TABLE orders ADD FOREIGN KEY fk_user_id (user_id) REFERENCES users(id); +``` diff --git a/markdown-pages/zh/tidb/master/control-execution-plan.md b/markdown-pages/zh/tidb/master/control-execution-plan.md new file mode 100644 index 0000000..5b74ffb --- /dev/null +++ b/markdown-pages/zh/tidb/master/control-execution-plan.md @@ -0,0 +1,15 @@ +--- +title: 控制执行计划 +aliases: ['/docs-cn/dev/control-execution-plan/'] +summary: 本章节介绍了控制执行计划的方法,包括使用提示指导执行计划、执行计划管理、优化规则及表达式下推的黑名单。此外,还介绍了一些系统变量对执行计划的影响,以及引入的特殊变量 `tidb_opt_fix_control`,用于更细粒度地控制优化器的行为。 +--- + +# 控制执行计划 + +SQL 性能调优的前两个章节介绍了如何理解 TiDB 的执行计划以及 TiDB 如何生成一个执行计划。本章节将介绍当你确定了执行计划所存在的问题时,可以使用哪些手段来控制执行计划的生成。本章节主要包括以下三方面内容: + +- [Optimizer Hints](/optimizer-hints.md)中,我们会介绍如何使用 Hint 来指导 TiDB 生成执行计划。 +- 但是使用 Hint 会侵入性地更改 SQL,在一些场景下并不能简单的插入 Hint。在[执行计划管理](/sql-plan-management.md)中,我们会介绍 TiDB 如何使用另一种语法来非侵入地控制执行计划的生成,同时还会介绍后台自动对执行计划进行演进的手段。该手段可用来减轻诸如版本升级等原因造成的执行计划不稳定和集群性能下降的问题。 +- 最后在[优化规则及表达式下推的黑名单](/blocklist-control-plan.md)中,我们会介绍黑名单的使用。 + +除以上手段之外,执行计划还会被一部分系统变量所影响。通过在系统级或会话级对变量进行修改,能够控制执行计划的生成。自 v6.5.3 和 v7.1.0 起,TiDB 引入了一个相对特殊的变量 [`tidb_opt_fix_control`](/system-variables.md#tidb_opt_fix_control-从-v653-和-v710-版本开始引入)。这个变量能够接受多个控制项,用来更细粒度地控制优化器的行为,避免集群升级后优化器行为变化导致的性能回退。详细介绍请参考 [Optimizer Fix Controls](/optimizer-fix-controls.md)。 diff --git a/markdown-pages/zh/tidb/master/coprocessor-cache.md b/markdown-pages/zh/tidb/master/coprocessor-cache.md new file mode 100644 index 0000000..9012673 --- /dev/null +++ b/markdown-pages/zh/tidb/master/coprocessor-cache.md @@ -0,0 +1,61 @@ +--- +title: 下推计算结果缓存 +aliases: ['/docs-cn/dev/coprocessor-cache/'] +summary: TiDB 4.0 支持下推计算结果缓存,配置位于 `tikv-client.copr-cache`,缓存仅存储在 TiDB 内存中,不共享缓存,对 Region 写入会导致缓存失效。缓存命中率可通过 `EXPLAIN ANALYZE` 或 Grafana 监控面板查看。 +--- + +# 下推计算结果缓存 + +TiDB 从 4.0 起支持下推计算结果缓存(即 Coprocessor Cache 功能)。开启该功能后,将在 TiDB 实例侧缓存下推给 TiKV 计算的结果,在部分场景下起到加速效果。 + +## 配置 + +Coprocessor Cache 的配置均位于 TiDB 的 `tikv-client.copr-cache` 配置项中。Coprocessor 的具体开启和配置方法,见 [TiDB 配置文件描述](/tidb-configuration-file.md#tikv-clientcopr-cache-从-v400-版本开始引入)。 + +## 特性说明 + ++ 所有 SQL 在单个 TiDB 实例上的首次执行都不会被缓存。 ++ 缓存仅存储在 TiDB 内存中,TiDB 重启后缓存会失效。 ++ 不同 TiDB 实例之间不共享缓存。 ++ 缓存的是下推计算结果,即使缓存命中,后续仍有 TiDB 计算。 ++ 缓存以 Region 为单位。对 Region 的写入会导致涉及该 Region 的缓存失效。基于此原因,该功能主要会对很少变更的数据有效果。 ++ 下推计算请求相同时,缓存会被命中。通常在以下场景下,下推计算的请求是相同或部分相同的: + - SQL 语句完全一致,例如重复执行相同的 SQL 语句。 + + 该场景下所有下推计算的请求都是一致的,所有请求都能利用上下推计算缓存。 + + - SQL 语句包含一个变化的条件,其他部分一致,变化的条件是表主键或分区主键。 + + 该场景下一部分下推计算的请求会与之前出现过的一致,部分请求能利用上下推计算结果缓存。 + + - SQL 语句包含多个变化的条件,其他部分一致,变化的条件完全匹配一个复合索引列。 + + 该场景下一部分下推计算的请求会与之前出现过的一致,部分请求能利用上下推计算结果缓存。 + ++ 该功能对用户透明,开启和关闭都不影响计算结果,仅影响 SQL 执行时间。 + +## 检验缓存效果 + +可以通过执行 `EXPLAIN ANALYZE` 或查看 Grafana 监控面板来检查 Coprocessor 的缓存效果。 + +### 使用 `EXPLAIN ANALYZE` + +用户可以通过 [`EXPLAIN ANALYZE` 语句](/sql-statements/sql-statement-explain-analyze.md)查看[读表算子](/choose-index.md#读表算子)中的缓存命中率,示例如下: + +```sql +EXPLAIN ANALYZE SELECT * FROM t USE INDEX(a); ++-------------------------------+-----------+---------+-----------+------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------+-----------------------+------+ +| id | estRows | actRows | task | access object | execution info | operator info | memory | disk | ++-------------------------------+-----------+---------+-----------+------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------+-----------------------+------+ +| IndexLookUp_6 | 262400.00 | 262400 | root | | time:620.513742ms, loops:258, cop_task: {num: 4, max: 5.530817ms, min: 1.51829ms, avg: 2.70883ms, p95: 5.530817ms, max_proc_keys: 2480, p95_proc_keys: 2480, tot_proc: 1ms, tot_wait: 1ms, rpc_num: 4, rpc_time: 10.816328ms, copr_cache_hit_rate: 0.75} | | 6.685169219970703 MB | N/A | +| ├─IndexFullScan_4(Build) | 262400.00 | 262400 | cop[tikv] | table:t, index:a(a, c) | proc max:93ms, min:1ms, p80:93ms, p95:93ms, iters:275, tasks:4 | keep order:false, stats:pseudo | 1.7549400329589844 MB | N/A | +| └─TableRowIDScan_5(Probe) | 262400.00 | 0 | cop[tikv] | table:t | time:0ns, loops:0 | keep order:false, stats:pseudo | N/A | N/A | ++-------------------------------+-----------+---------+-----------+------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------+-----------------------+------+ +3 rows in set (0.62 sec) +``` + +执行结果的 `execution info` 列有 `copr_cache_hit_ratio` 信息,表示下推计算结果缓存的命中率。以上示例的 `0.75` 表示命中率大约是 75%。 + +### 查看 Grafana 监控面板 + +在 Grafana 监控中,`tidb` 命名空间下 `distsql` 子系统中可见 **copr-cache** 面板,该面板监控整个集群中下推计算结果缓存的命中次数、未命中次数和缓存丢弃次数。 diff --git a/markdown-pages/zh/tidb/master/dashboard/dashboard-access.md b/markdown-pages/zh/tidb/master/dashboard/dashboard-access.md new file mode 100644 index 0000000..68f7b1f --- /dev/null +++ b/markdown-pages/zh/tidb/master/dashboard/dashboard-access.md @@ -0,0 +1,68 @@ +--- +title: 访问 TiDB Dashboard +aliases: ['/docs-cn/dev/dashboard/dashboard-access/'] +summary: TiDB Dashboard 可通过浏览器访问,支持多 PD 实例访问。浏览器兼容性包括 Chrome、Firefox 和 Edge。登录界面可使用 root 用户或自定义 SQL 用户登录。支持简体中文和英文语言切换。可在用户页面登出当前用户。 +--- + +# 访问 TiDB Dashboard + +通过浏览器访问 (将 `127.0.0.1:2379` 替换为实际 PD 实例的地址和端口)即可打开 TiDB Dashboard。 + +> **注意:** +> +> TiDB v6.5.0 且 TiDB Operator v1.4.0 之后,在 Kubernetes 上支持将 TiDB Dashboard 作为独立的 Pod 部署。在 TiDB Operator 环境,可直接访问该 Pod 的 IP 来打开 TiDB Dashboard。具体信息,参考 [TiDB Operator 部署独立的 TiDB Dashboard](https://docs.pingcap.com/zh/tidb-in-kubernetes/dev/get-started#部署独立的-tidb-dashboard)。 + +## 多 PD 实例访问 + +当集群中部署有多个 PD 实例、且您可以直接访问到**每个** PD 实例地址和端口时,可以简单地将 地址中的 `127.0.0.1:2379` 替换为集群中**任意一个** PD 实例的地址和端口进行访问。 + +> **注意:** +> +> 当处于防火墙或反向代理等环境下、无法直接访问每个 PD 实例时,可能会无法访问 TiDB Dashboard。这通常是防火墙或反向代理没有正确配置导致的。可参阅[通过反向代理使用 TiDB Dashboard](/dashboard/dashboard-ops-reverse-proxy.md) 或[提高 TiDB Dashboard 安全性](/dashboard/dashboard-ops-security.md)章节了解如何在多 PD 实例情况下正确配置防火墙或反向代理规则。 + +## 浏览器兼容性 + +TiDB Dashboard 可在常见的、更新及时的桌面浏览器中使用,具体版本号为: + +- Chrome >= 77 +- Firefox >= 68 +- Edge >= 17 + +> **注意:** +> +> 若使用旧版本浏览器或其他浏览器访问 TiDB Dashboard,部分界面可能不能正常工作。 + +## 登录 + +访问 TiDB Dashboard 将会显示用户登录界面。 + +- 可使用 TiDB 的 root 用户登录。 +- 如果创建了[自定义 SQL 用户](/dashboard/dashboard-user.md),也可以使用自定义的 SQL 用户和密码登录。 + +![登录界面](/media/dashboard/dashboard-access-login.png) + +如果存在以下情况,则可能会登录失败: + +- TiDB root 用户不存在 +- PD 未启动或无法访问 +- TiDB 未启动或无法访问 +- root 密码错误 + +登录后,24 小时内将保持自动登录状态。参见[登出](#登出)章节了解如何登出用户。 + +## 切换语言 + +TiDB Dashboard 目前支持以下语言: + +- 简体中文 +- 英文 + +在登录界面中,可点击 **Switch Language** 下拉框切换界面显示语言: + +![切换语言](/media/dashboard/dashboard-access-switch-language.png) + +## 登出 + +登录后,在左侧导航处点击登录用户名,可切换到用户页面。在用户页面点击**登出** (Logout) 按钮即可登出当前用户。登出后,需重新输入用户名密码。 + +![登出](/media/dashboard/dashboard-access-logout.png) diff --git a/markdown-pages/zh/tidb/master/dashboard/dashboard-diagnostics-access.md b/markdown-pages/zh/tidb/master/dashboard/dashboard-diagnostics-access.md new file mode 100644 index 0000000..73ee752 --- /dev/null +++ b/markdown-pages/zh/tidb/master/dashboard/dashboard-diagnostics-access.md @@ -0,0 +1,62 @@ +--- +title: TiDB Dashboard 集群诊断页面 +aliases: ['/docs-cn/dev/dashboard/dashboard-diagnostics-access/'] +summary: TiDB Dashboard 集群诊断页面是用于诊断集群问题并生成诊断报告的工具。可以通过 TiDB Dashboard 或浏览器访问诊断页面。生成诊断报告的步骤包括设置时间范围和长度,然后点击开始。还可以生成对比报告来比较异常时间段和正常时间段的情况。已生成的报告会显示在主页列表中,可随时查看。 +--- + +# TiDB Dashboard 集群诊断页面 + +集群诊断是在指定的时间范围内,对集群可能存在的问题进行诊断,并将诊断结果和一些集群相关的负载监控信息汇总成一个诊断报告。诊断报告是网页形式,通过浏览器保存后可离线浏览和传阅。 + +> **注意:** +> +> 集群诊断功能依赖于集群中部署有 Prometheus 监控组件,参见 [TiUP](/tiup/tiup-overview.md) 部署文档了解如何部署监控组件。若集群中没有部署监控组件,生成的诊断报告中将提示生成失败。 + +## 访问 + +可以通过以下两种方法访问集群诊断页面: + +* 登录 TiDB Dashboard 后,在左侧导航栏中点击**集群诊断** (Cluster Diagnostics)。 + + ![访问](/media/dashboard/dashboard-diagnostics-access-v650.png) + +* 在浏览器中访问 [http://127.0.0.1:2379/dashboard/#/diagnose](http://127.0.0.1:2379/dashboard/#/diagnose)(将 `127.0.0.1:2379` 替换为你的实际 PD 地址和端口)。 + +## 生成诊断报告 + +如果想对一个时间范围内的集群进行诊断,查看集群的负载等情况,可以使用以下步骤来生成一段时间范围的诊断报告: + +1. 设置区间的开始时间,例如 2022-05-21 14:40:00。 +2. 设置区间长度。例如 10 min。 +3. 点击开始 (Start)。 + +![生成单个时间段的诊断报告](/media/dashboard/dashboard-diagnostics-gen-report-v650.png) + +> **注意:** +> +> 建议生成报告的时间范围在 1 min ~ 60 min 内,目前不建议生成超过 1 小时范围的报告。 + +以上操作会生成 2022-05-21 14:40:00 至 2022-05-21 14:50:00 时间范围的诊断报告。点击**开始** (start) 后,会看到以下界面,**生成进度** (Progress) 是生成报告的进度条,生成报告完成后,点击**查看报告** (View Full Report) 即可。 + +![生成报告的进度](/media/dashboard/dashboard-diagnostics-gen-process-v650.png) + +## 生成对比诊断报告 + +如果系统在某个时间点发生异常,如 QPS 抖动或者延迟变高,可以生成一份异常时间范围和正常时间范围的对比报告,例如: + +* 系统异常时间段:2022-05-21 14:40:00 ~ 2022-05-21 14:45:00,系统异常时间。 +* 系统正常时间段:2022-05-21 14:30:00 ~ 2022-05-21 14:35:00,系统正常时间。 + +生成以上两个时间范围的对比报告的步骤如下: + +1. 设置区间的开始时间,即异常时间段的开始时间,如 2022-05-21 14:40:00。 +2. 设置区间长度 (Range Duration)。一般指系统异常的持续时间,例如 5 min。 +3. 开启与基线区间对比开关 (Compare by Baseline)。 +4. 设置基线开始时间 (Baseline Range Start Time),即想要对比的系统正常时段的开始时间,如 2022-05-21 14:30:00。 +5. 点击开始 (Start)。 + +![生成对比报告](/media/dashboard/dashboard-diagnostics-gen-compare-report-v650.png) + +然后同样等报告生成完成后点击**查看报告** (View Full Report) 即可。 + +另外,已生成的诊断报告会显式在诊断报告主页的列表里面,可以点击查看之前生成的报告,不用重复生成。 diff --git a/markdown-pages/zh/tidb/master/dashboard/dashboard-diagnostics-report.md b/markdown-pages/zh/tidb/master/dashboard/dashboard-diagnostics-report.md new file mode 100644 index 0000000..bb941bb --- /dev/null +++ b/markdown-pages/zh/tidb/master/dashboard/dashboard-diagnostics-report.md @@ -0,0 +1,369 @@ +--- +title: TiDB Dashboard 诊断报告 +aliases: ['/docs-cn/dev/dashboard/dashboard-diagnostics-report/'] +summary: TiDB Dashboard 诊断报告介绍了诊断报告的内容和查看技巧。报告包括基本信息、诊断信息、负载信息、概览信息、TiDB/PD/TiKV 监控信息和配置信息。对比报告显示两个时间段的差异,通过 DIFF_RATIO 和 Maximum Different Item 报表可以快速发现监控项的差异。 +--- + +# TiDB Dashboard 诊断报告 + +本文档主要介绍诊断报告的内容以及查看技巧,访问集群诊断和生成报告请参考[诊断报告访问文档](/dashboard/dashboard-diagnostics-access.md)。 + +## 查看报告 + +诊断报告由以下几部分组成: + +* 基本信息:包括生成报告的时间范围,集群的硬件信息,集群的拓扑版本信息。 +* 诊断信息:显示自动诊断的结果。 +* 负载信息:包括服务器,TIDB/PD/TiKV 相关的 CPU、内存等负载信息。 +* 概览信息:包括 TiDB/PD/TiKV 的各个模块的耗时信息和错误信息。 +* TiDB/PD/TiKV 监控信息:包括各个组件的监控信息。 +* 配置信息:包括各个组件的配置信息。 + +报告中报表示例如下: + +![示例报表](/media/dashboard/dashboard-diagnostics-example-table.png) + +上图中,最上面蓝框内的 **Total Time Consume** 是报表名。下方红框内的内容是对该报表意义的解释,以及报表中各个字段的含义。 + +报表中小按钮图标的解释如下: + +* **i** 图标:鼠标移动到 **i** 图标处会显示该行的说明注释。 +* **expand**:点击 **expand** 会看到这项监控更加详细的信息。如是上图中 `tidb_get_token` 的详细信息包括各个 TiDB 实例的延迟监控信息。 +* **fold**:和 **expand** 相反,用于把监控的详细信息折叠起来。 + +所有监控基本上和 TiDB Grafna 监控面板上的监控内容相对应,发现某个模块异常后,可以在 TiDB Grafna 监控面板上查看更多详细的监控信息。 + +另外,报表中统计的 `TOTAL_TIME` 和 `TOTAL_COUNT` 由于是从 Prometheus 读取的监控数据,其统计会有一些计算上的精度误差。 + +以下介绍诊断报告的各部分内容。 + +### 基本信息 + +#### Report Time Range + +**Report Time Range** 表显示生成报告的时间范围,包括开始时间和结束时间。 + +![report time range 报表](/media/dashboard/dashboard-diagnostics-report-time-range.png) + +#### Cluster Hardware + +**Cluster Hardware** 表显示集群中各服务器的硬件信息,包括 CPU、Memory、磁盘等信息。 + +![Cluster Hardware 报表](/media/dashboard/dashboard-diagnostics-cluster-hardware.png) + +上表中各个字段含义如下: + +* `HOST`:服务器的 IP 地址。 +* `INSTANCE`:该服务器部署的实例数量,如 `pd * 1` 代表这台服务器部署了 1 个 PD 实例。如 `tidb * 2 pd * 1` 表示这台服务器部署了 2 个 TiDB 实例和 1 个 PD 实例。 +* `CPU_CORES`:表示服务器 CPU 的核心数,物理核心/逻辑核心。 +* `MEMORY`:表示服务器的内存大小,单位是 GB。 +* `DISK`:表示服务器磁盘大小,单位是 GB。 +* `UPTIME`:服务器的启动时间,单位是 DAY。 + +#### Cluster Info + +**Cluster Info** 为集群拓扑信息。表中信息来自 TiDB 的 [information_schema.cluster_info](/information-schema/information-schema-cluster-info.md) 系统表。 + +![Cluster Info 报表](/media/dashboard/dashboard-diagnostics-cluster-info.png) + +上表中各个字段含义如下: + +* `TYPE`:节点类型。 +* `INSTANCE`:实例地址,为 `IP:PORT` 格式的字符串。 +* `STATUS_ADDRESS`:HTTP API 的服务地址。 +* `VERSION`:对应节点的语义版本号。 +* `GIT_HASH`:编译节点版本时的 Git Commit Hash,用于识别两个节点是否是绝对一致的版本。 +* `START_TIME`:对应节点的启动时间。 +* `UPTIME`:对应节点已经运行的时间。 + +### 诊断信息 + +TiDB 内置自动诊断的结果,具体各字段含义以及介绍可以参考 [information_schema.inspection_result](/information-schema/information-schema-inspection-result.md) 系统表的内容。 + +### 负载信息 + +#### Node Load Info + +**Node Load Info** 表显示服务器节点的负载信息,包括时间范围内,服务器以下指标的平均值 (AVG)、最大值 (MAX)、最小值 (MIN): + +* CPU 使用率,最大值是 100% +* 内存使用率 +* 磁盘 I/O 使用率 +* 磁盘写延迟 +* 磁盘读延迟 +* 磁盘每秒的读取字节数 +* 磁盘每秒的写入字节数 +* 节点网络每分钟收到的字节数 +* 节点网络每分钟发送的字节数 +* 节点正在使用的 TCP 连接数 +* 节点所有的 TCP 连接数 + +![Node Load Info 报表](/media/dashboard/dashboard-diagnostics-node-load-info.png) + +#### Instance CPU Usage + +**Instance CPU Usage** 表显示各个 TiDB/PD/TiKV 进程的 CPU 使用率的平均值 (AVG),最大值 (MAX),最小值 (MIN),这里进程 CPU 使用率最大值是 `100% * CPU 逻辑核心数`。 + +![Instance CPU Usage 报表](/media/dashboard/dashboard-diagnostics-process-cpu-usage.png) + +#### Instance Memory Usage + +**Instance Memory Usage** 表显示各个 TiDB/PD/TiKV 进程占用内存字节数的平均值 (AVG),最大值 (MAX),最小值 (MIN)。 + +![Instance Memory Usage 报表](/media/dashboard/dashboard-diagnostics-process-memory-usage.png) + +#### TiKV Thread CPU Usage + +**TiKV Thread CPU Usage** 表显示 TiKV 内部各个模块线程的 CPU 使用率的平均值 (AVG)、最大值 (MAX)、和最小值 (MIN)。这里进程 CPU 使用率最大值为 `100% * 对应配置的线程数量`。 + +![TiKV Thread CPU Usage 报表](/media/dashboard/dashboard-diagnostics-thread-cpu-usage.png) + +上表中的字段解释如下: + +* `CONFIG_KEY`:表示对应模块的相关线程数配置。 +* `CURRENT_CONFIG_VALUE`:表示配置在生成报表时刻的当前值。 + +> **注意:** +> +> `CURRENT_CONFIG_VALUE` 是生成报告时的值,并不是报告时间范围内的值。目前不能获取历史时间某些配置的值。 + +#### TiDB/PD Goroutines Count + +**TiDB/PD Goroutines Count** 表显示 TiDB/PD goroutines 数量的平均值 (AVG),最大值 (MAX),和最小值 (MIN)。如果 goroutines 数量超过 2000,说明该进程并发太高,会对整体请求的延迟有影响。 + +![TiDB/PD goroutines count 报表](/media/dashboard/dashboard-diagnostics-goroutines-count.png) + +### 概览信息 + +#### Time Consumed by Each Component + +**Time Consumed by Each Component** 显示包括集群中 TiDB、PD、TiKV 各个模块的监控耗时以及各项耗时的占比。默认时间单位是秒。用户可以用该表快速定位哪些模块的耗时较多。 + +![Total Time Consume 报表](/media/dashboard/dashboard-diagnostics-total-time-consume.png) + +上表各列的字段含义如下: + +* `METRIC_NAME`:监控项的名称。 +* `Label`:监控的 label 信息,点击 expand 后可以查看该项监控更加详细的各项 label 的监控信息。 +* `TIME_RATIO`:该项为 `TIME_RATIO` 为 `1` 的监控行总时间与监控消耗的总时间的比例。如 `kv_request` 的总耗时占 `tidb_query` 总耗时的 `1.65 = 38325.58/23223.86`。因为 KV 请求会并行执行,所以所有 KV 请求的总时间有可能超过总查询 (`tidb_query`) 的执行时间。 +* `TOTAL_TIME`:该项监控的总耗时。 +* `TOTAL_COUNT`:该项监控执行的总次数。 +* `P999`:该项监控的 P999 最大时间。 +* `P99`:该项监控的 P99 最大时间。 +* `P90`:该项监控的 P90 最大时间。 +* `P80`:该项监控的 P80 最大时间。 + +以上监控中相关模块的耗时关系如下所示: + +![各个模块耗时关系图](/media/dashboard/dashboard-diagnostics-time-relation.png) + +上图中,黄色部分是 TiDB 相关的监控,蓝色部分是 TiKV 相关的监控,灰色部分暂时没有具体对应的监控项。 + +上图中,`tidb_query` 的耗时包括以下部分的耗时: + +* `get_token` +* `parse` +* `compile` +* `execute` + +其中 `execute` 的耗时包括以下部分: + +* `wait_start_tso` +* TiDB 层的执行时间,目前暂无监控 +* KV 请求的时间 +* `tidb_kv_backoff` 的时间,这是 KV 请求失败后进行 backoff 的时间 + +其中,KV 请求时间包含以下部分: + +* 请求的网络发送以及接收耗时,目前该项暂无监控,可以大致用 KV 请求时间减去 `tikv_grpc_message` 的时间 +* `tikv_grpc_message` 的耗时 + +其中,`tikv_grpc_message` 耗时包含以下部分: + +* Coprocessor request 耗时,指用于处理 COP 类型的请求,该耗时包括以下部分: + * `tikv_cop_wait`,请求排队等待的耗时 + * `Coprocessor handling request`,处理 COP 请求的耗时 +* `tikv_scheduler_command` 耗时,该耗时包含以下部分: + * `tikv_scheduler_processing_read`,处理读请求的耗时 + * `tikv_storage_async_request` 中获取 snapshot 的耗时(snapshot 是该项监控的 label) + * 处理写请求的耗时,该耗时包括以下部分: + * `tikv_scheduler_latch_wait`,等待 latch 的耗时 + * `tikv_storage_async_request` 中 write 的耗时(write 是该监控的 label) + +其中,`tikv_storage_async_request` 中的 write 耗时是指 raft kv 写入的耗时,包括以下部分: + +* `tikv_raft_propose_wait` +* `tikv_raft_process`,该耗时主要时间包括: + * `tikv_raft_append_log` + * `tikv_raft_commit_log` + * `tikv_raft_apply_wait` + * `tikv_raft_apply_log` + +用户可以根据上述耗时之间的关系,利用 `TOTAL_TIME` 以及 P999,P99 的时间大致定位哪些模块耗时比较长,然后再看相关的监控。 + +> **注意:** +> +> 由于 Raft KV 可能会将多个请求作为一个 batch 来写入,所以 `TOTAL_TIME` 不适用于来衡量 Raft KV 的写入相关监控项的耗时,这些监控项具体是 `tikv_raft_process`、`tikv_raft_append_log`、`tikv_raft_commit_log`、`tikv_raft_apply_wait`、`tikv_raft_apply_log`。此时用 P999 和 P99 的时间来对比各个模块的耗时更加合理。 +> +> 原因是,假如有 10 个 async write 请求,Raft KV 内部将 10 个请求打包成一个 batch 执行,执行时间为 1 秒,所以每个请求的执行时间为 1 秒,10 个请求的总时间是 10 秒。但是 Raft KV 处理的总时间是 1 秒。如果用 `TOTAL_TIME` 来衡量,用户可能不明白剩余的 9 秒耗时在哪些模块下。这里从总请求数 (`TOTAL_COUNT`) 也能看出 Raft KV 的监控和其他监控的差异。 + +#### Errors Occurred in Each Component + +**Errors Occurred in Each Component** 表显示包括 TiDB 和 TiKV 出现错误的总数。例如写 binlog 失败、`tikv server is busy`、`TiKV channel full`、`tikv write stall` 等错误,具体各项错误含义可以看行注释。 + +![Errors Occurred in Each Component 报表](/media/dashboard/dashboard-diagnostics-error.png) + +### TiDB/PD/TiKV 的具体监控信息 + +这部分包括了 TiDB/PD/TiKV 更多的具体的监控信息。 + +#### TiDB 相关监控信息 + +##### Time Consumed by TiDB Component + +**Time Consumed by TiDB Component** 表显示 TiDB 的各项监控耗时以及各项耗时的占比。和 [Time Consumed by Each Component](#time-consumed-by-each-component) 表类似,但是这个表的 label 信息会更丰富,细节更多。 + +##### TiDB Server Connections + +**TiDB Server Connections** 表显示 TiDB 各个实例的客户端连接数。 + +##### TiDB Transaction + +**TiDB Transaction** 表显示 TiDB 事务相关的监控。 + +![Transaction 报表](/media/dashboard/dashboard-diagnostics-tidb-txn.png) + +* `TOTAL_VALUE`:该项监控在报告时间段内所有值的和 (SUM)。 +* `TOTAL_COUNT`:该项监控出现的总次数。 +* P999: 该项监控的 P999 最大值。 +* P99: 该项监控的 P99 最大值。 +* P90: 该项监控的 P90 最大值。 +* P80: 该项监控的 P80 最大值。 + +示例: + +上表中,在报告时间范围的 `tidb_txn_kv_write_size` 表示一共约有 181296 次事务的 KV 写入,总 kV 写入大小是 266.772 MB,其中单次事务的 KV 写入的 P999、P99、P90、P80 的最大值分别为 116.913 KB、1.996 KB、1.905 KB、1.805 KB。 + +##### DDL Owner + +![TiDB DDL Owner 报表](/media/dashboard/dashboard-diagnostics-tidb-ddl.png) + +上表表示从 `2020-05-21 14:40:00` 开始,集群的 DDL owner 在 `10.0.1.13:10080` 节点。如果 owner 发生变更,上表会有多行数据,其中 `MinTime` 列表示已知对应 Owner 的最小时间。 + +> **注意:** +> +> 如果 owner 信息为空,不代表这个时间段内一定没有 owner,因为这里是依靠 `ddl_worker` 的监控信息来判断 DDL owner 的。也可能是这个时间段内 `ddl_worker` 没有做任何 DDL job 导致 owner 信息为空。 + +TiDB 中其他部分监控表如下: + +* **Statistics Info**:TiDB 统计信息的相关监控。 +* **Top 10 Slow Query**:报表时间范围内 Top 10 的慢查询信息。 +* **Top 10 Slow Query Group By Digest**:报表时间范围内 Top 10 的慢查询信息,并按照 SQL 指纹聚合。 +* **Slow Query With Diff Plan**:报表时间范围内执行计划发生变更的 SQL 语句。 + +#### PD 相关监控信息 + +PD 模块相关监控的报表如下: + +* **Time Consumed by PD Component**:PD 中相关模块的耗时监控 +* **Scheduled Leader/Region**:报表时间范围内集群发生的 `balance-region` 和 `balance leader` 监控,比如从 `tikv_note_1` 上调度走了多少个 leader,调度进了多少个 leader。 +* **Cluster Status**:集群的状态信息,包括总 TiKV 数量、总集群存储容量、Region 数量、离线 TiKV 的数量等信息。 +* **Store Status**:记录各个 TiKV 节点的状态信息,包括 Region score、leader score、Region/leader 的数量。 +* **etcd Status**:PD 内部的 etcd 相关信息。 + +#### TiKV 相关监控信息 + +TIKV 模块的相关监控报表如下: + +* **Time Consumed by TiKV Component**:TiKV 中相关模块的耗时监控。 +* **Time Consumed by RocksDB**:TiKV 中 RocksDB 的耗时监控。 +* **TiKV Error**:TiKV 中各个模块相关的 error 信息。 +* **TiKV Engine Size**:TiKV 中各个节点 column family 的存储数据大小。 +* **Coprocessor Info**:TiKV 中 Coprocessor 模块相关的监控。 +* **Raft Info**:TiKV 中 Raft 模块的相关监控信息。 +* **Snapshot Info**:TiKV 中 snapshot 相关监控信息。 +* **GC Info**:TiKV 中 GC 相关的监控信息。 +* **Cache Hit**:TiKV 中 Rocksdb 的各个缓存的命中率监控信息。 + +### 配置信息 + +配置信息中,部分模块的配置信息可以显示报告时间范围内的配置值,有部分配置则因为无法获取到历史的配置值,所以是生成报告时刻的当前配置值。 + +在报告时间范围内,以下表包括部分配置的在报告时间范围的开始时间的值: + +* **Scheduler Initial Config**:PD 调度相关配置在报告开始时间的初始值。 +* **TiDB GC Initial Config**:TiDB GC 相关配置在报告开始时间的初始值。 +* **TiKV RocksDB Initial Config**:TiKV RocksDB 相关配置在报告开始时间的初始值。 +* **TiKV RaftStore Initial Config**:TiKV RaftStore 相关配置在报告开始时间的初始值。 + +在报表时间范围内,如若有些配置被修改过,以下表包括部分配置被修改的记录: + +* **Scheduler Config Change History** +* **TiDB GC Config Change History** +* **TiKV RocksDB Config Change History** +* **TiKV RaftStore Config Change History** + +示例: + +![Scheduler Config Change History 报表](/media/dashboard/dashboard-diagnostics-config-change.png) + +上面报表显示,`leader-schedule-limit` 配置参数在报告时间范围内有被修改过: + +* `2020-05-22T20:00:00+08:00`,即报告的开始时间 `leader-schedule-limit` 的配置值为 `4`,这里并不是指该配置被修改了,只是说明在报告时间范围的开始时间其配置值是 `4`。 +* `2020-05-22T20:07:00+08:00`,`leader-schedule-limit` 的配置值为 `8`,说明在 `2020-05-22T20:07:00+08:00` 左右,该配置的值被修改了。 + +下面的报表是生成报告时,TiDB、PD、TiKV 的在生成报告时刻的当前配置: + +* **TiDB's Current Config** +* **PD's Current Config** +* **TiKV's Current Config** + +## 对比报告 + +生成两个时间段的对比报告,其内容和单个时间段的报告是一样的,只是加入了对比列显示两个时间段的差别。下面主要介绍对比报告中的一些特有表以及如何查看对比报表。 + +首先在基本信息中的 **Compare Report Time Range** 报表会显示出对比的两个时间段: + +![Compare Report Time Range 报表](/media/dashboard/dashboard-diagnostics-compare-time.png) + +其中 `t1` 是正常时间段,或者叫参考时间段,`t2` 是异常时间段。 + +下面是一些慢查询相关的报表: + +* **Slow Queries In Time Range t2**:仅出现在 `t2` 时间段但没有出现在 `t1` 时间段的慢查询。 +* **Top 10 slow query in time range t1**:`t1` 时间段的 Top10 慢查询。 +* **Top 10 slow query in time range t2**:`t2` 时间段的 Top10 慢查询。 + +### DIFF_RATIO 介绍 + +本部分以 `Instance CPU Usage` 为例介绍 `DIFF_RATIO`。 + +![Compare Instance CPU Usage 报表](/media/dashboard/dashboard-diagnostics-compare-instance-cpu-usage.png) + +* `t1.AVG`、`t1.MAX`、`t1.Min` 分别是 `t1` 时间段内 CPU 使用率的平均值、最大值、最小值。 +* `t2.AVG`、`t2.MAX`、`t2.Min` 分别是 `t2` 时间段内 CPU 使用率的平均值、最大值、最小值。 +* `AVG_DIFF_RATIO` 表示 `t1` 和 `t2` 时间段平均值的 `DIFF_RATIO`。 +* `MAX_DIFF_RATIO` 表示 `t1` 和 `t2` 时间段最大值的 `DIFF_RATIO`。 +* `MIN_DIFF_RATIO` 表示 `t1` 和 `t2` 时间段最小值的 `DIFF_RATIO`。 + +`DIFF_RATIO` 表示两个时间段的差异大小,有以下几个取值方式: + +* 如果该监控仅在 `t2` 时间内才有值,`t1` 时间段没有,则 `DIFF_RATIO` 取值为 `1`。 +* 如果监控项仅在 `t1` 时间内才有值,`t1` 时间段没有,则 `DIFF_RATIO` 取值为 `-1`。 +* 如果 t2 时间段的值比 t1 时间段的值大,则 `DIFF_RATIO` = `(t2.value / t1.value) - 1`。 +* 如果 `t2` 时间段的值比 `t1` 时间段的值小,则 `DIFF_RATIO` = `1 - (t1.value / t2.value)`。 + +例如上表中,`tidb` 节点的平均 CPU 使用率在 `t2` 时间段比 `t1` 时间段高 `2.02` 倍,`2.02` = `1240/410 - 1`。 + +### Maximum Different Item 报表介绍 + +`Maximum Different Item` 的报表是对比两个时间段的监控项后,按照监控项的差异大小排序,通过这个表可以很快发现两个时间段哪些监控的差异最大。示例如下: + +![Maximum Different Item 报表](/media/dashboard/dashboard-diagnostics-maximum-different-item.png) + +* `Table`:表示这个监控项来自于对比报告中报表,如 `TiKV, coprocessor_info` 表示是 TiKV 组件下的 `coprocessor_info` 报表。 +* `METRIC_NAME`:监控项名,点击 `expand` 可以查看该监控的不同 label 的差异对比。 +* `LABEL`:监控项对应的 label。比如 `TiKV Coprocessor scan` 监控项有两个 label,分别是 instance、req、tag、sql_type,分别表示为 TiKV 地址、请求类型、操作类型和操作的 column family。 +* `MAX_DIFF`:差异大小,取值为 `t1.VALUE` 和 `t2.VALUE` 的 `DIFF_RATIO` 计算。 + +可以从上表中发现,`t2` 时间段比 `t1` 时间段多出了大量的 Coprocessor 请求,TiDB 的解析 SQL (parse) 时间也多了很多。 diff --git a/markdown-pages/zh/tidb/master/dashboard/dashboard-diagnostics-usage.md b/markdown-pages/zh/tidb/master/dashboard/dashboard-diagnostics-usage.md new file mode 100644 index 0000000..ed6c919 --- /dev/null +++ b/markdown-pages/zh/tidb/master/dashboard/dashboard-diagnostics-usage.md @@ -0,0 +1,115 @@ +--- +title: 使用 TiDB Dashboard 诊断报告定位问题 +aliases: ['/docs-cn/dev/dashboard/dashboard-diagnostics-usage/'] +summary: 本文介绍了使用 TiDB Dashboard 诊断报告定位问题的方法。通过对比两个时间段的监控项差异来帮助 DBA 定位问题。示例中展示了大查询/写入导致 QPS 抖动或延迟上升的诊断方法,以及如何用对比报告定位问题。对比报告可以帮助 DBA 更快速地定位问题,例如通过查看监控项的差异大小排序来发现异常。通过对比报告定位问题,可以更准确地诊断可能的慢查询和影响查询执行的负载。 +--- + +# 使用 TiDB Dashboard 诊断报告定位问题 + +本文介绍如何使用 TiDB Dashboard 诊断报告定位问题。 + +## 对比诊断功能示例 + +对比报告中对比诊断的功能,通过对比两个时间段的监控项差异来尝试帮助 DBA 定位问题。先看以下示例。 + +### 大查询/写入导致 QPS 抖动或延迟上升诊断 + +#### 示例 1 + +![QPS 图](/media/dashboard/dashboard-diagnostics-usage1.png) + +上图是 go-ycsb 压测的监控。可以发现,在 `2020-03-10 13:24:30` 时,QPS 突然开始下降,3 分钟后,QPS 开始恢复正常。 + +生成以下两个时间范围的对比报告: + +- t1: 2020-03-10 13:21:00 - 2020-03-10 13:23:00,正常时间段,又叫参考时间段。 +- t2: 2020-03-10 13:24:30 - 2020-03-10 13:27:30,QPS 开始下降的异常时间段。 + +这里两个时间间隔都是 3 分钟,因为抖动的影响范围为 3 分钟。因为诊断时会用一些监控的平均值做对比,所有间隔时间太长会导致平均值差异不明显,无法准确定位问题。 + +生成报告后查看 **Compare Diagnose** 报表内容如下: + +![对比诊断结果](/media/dashboard/dashboard-diagnostics-usage2.png) + +上面诊断结果显示,在诊断的时间内可能有大查询,下面的每一行的含义是: + +* `tidb_qps`:QPS 下降 0.93 倍。 +* `tidb_query_duration`:P999 的查询延迟上升 1.54 倍。 +* `tidb_cop_duration`:P999 的 COP 请求的处理延迟上升 2.48 倍。 +* `tidb_kv_write_num`:P999 的 tidb 的事务写入 kv 数量上升 7.61 倍。 +* `tikv_cop_scan_keys_total_nun`:TiKV 的 coprocessor 扫描 key/value 的数量分别在 3 台 TiKV 上有很大的提升。 +* `pd_operator_step_finish_total_count` 中,transfer leader 的数量上升 2.45 倍,说明异常时间段的调度比正常时间段要高。 +* 提示可能有慢查询,并提示用 SQL 查询 TiDB 的慢日志。在 TiDB 中执行结果如下: + +```sql +SELECT * FROM (SELECT count(*), min(time), sum(query_time) AS sum_query_time, sum(Process_time) AS sum_process_time, sum(Wait_time) AS sum_wait_time, sum(Commit_time), sum(Request_count), sum(process_keys), sum(Write_keys), max(Cop_proc_max), min(query),min(prev_stmt), digest FROM information_schema.CLUSTER_SLOW_QUERY WHERE time >= '2020-03-10 13:24:30' AND time < '2020-03-10 13:27:30' AND Is_internal = false GROUP BY digest) AS t1 WHERE t1.digest NOT IN (SELECT digest FROM information_schema.CLUSTER_SLOW_QUERY WHERE time >= '2020-03-10 13:21:00' AND time < '2020-03-10 13:24:00' GROUP BY digest) ORDER BY t1.sum_query_time DESC limit 10\G +***************************[ 1. row ]*************************** +count(*) | 196 +min(time) | 2020-03-10 13:24:30.204326 +sum_query_time | 46.878509117 +sum_process_time | 265.924 +sum_wait_time | 8.308 +sum(Commit_time) | 0.926820886 +sum(Request_count) | 6035 +sum(process_keys) | 201453000 +sum(Write_keys) | 274500 +max(Cop_proc_max) | 0.263 +min(query) | delete from test.tcs2 limit 5000; +min(prev_stmt) | +digest | 24bd6d8a9b238086c9b8c3d240ad4ef32f79ce94cf5a468c0b8fe1eb5f8d03df +``` + +可以发现,从 13:24:30 开始有一个批量删除的大写入,一共执行了 196 次,每次删除 5000 行数据,总共耗时 46.8 秒。 + +#### 示例 2 + +如果大查询一直没执行完,就不会记录慢日志,但仍可以进行诊断,示例如下: + +![QPS 图](/media/dashboard/dashboard-diagnostics-usage3.png) + +上图中,也是在跑 go-ycsb 的压测。可以发现,在 `2020-03-08 01:46:30` 时,QPS 突然开始下降,并且一直没有恢复。 + +生成以下两个时间范围的对比报告: + +- t1: 2020-03-08 01:36:00 - 2020-03-08 01:41:00,正常时间段,又叫参考时间段。 +- t2: 2020-03-08 01:46:30 - 2020-03-08 01:51:30,QPS 开始下降的异常时间段。 + +生成报告后看 **Compare Diagnose** 报表的内容如下: + +![对比诊断结果](/media/dashboard/dashboard-diagnostics-usage4.png) + +上面诊断结果的最后一行显示可能有慢查询,并提示用 SQL 查询 TiDB 日志中的 expensive query。在 TiDB 中执行结果如下: + +```sql +> SELECT * FROM information_schema.cluster_log WHERE type='tidb' AND time >= '2020-03-08 01:46:30' AND time < '2020-03-08 01:51:30' AND level = 'warn' AND message LIKE '%expensive_query%'\G +TIME | 2020/03/08 01:47:35.846 +TYPE | tidb +INSTANCE | 172.16.5.40:4009 +LEVEL | WARN +MESSAGE | [expensivequery.go:167] [expensive_query] [cost_time=60.085949605s] [process_time=2.52s] [wait_time=2.52s] [request_count=9] [total_keys=996009] [process_keys=996000] [num_cop_tasks=9] [process_avg_time=0.28s] [process_p90_time=0.344s] [process_max_time=0.344s] [process_max_addr=172.16.5.40:20150] [wait_avg_time=0.000777777s] [wait_p90_time=0.003s] [wait_max_time=0.003s] [wait_max_addr=172.16.5.40:20150] [stats=t_wide:pseudo] [conn_id=19717] [user=root] [database=test] [table_ids="[80,80]"] [txn_start_ts=415132076148785201] [mem_max="23583169 Bytes (22.490662574768066 MB)"] [sql="select count(*) from t_wide as t1 join t_wide as t2 where t1.c0>t2.c1 and t1.c2>0"] +``` + +以上查询结果显示,在 `172.16.5.40:4009` 这台 TiDB 上,`2020/03/08 01:47:35.846` 有一个已经执行了 60s 但还没有执行完的 expensive_query。 + +## 用对比报告定位问题 + +诊断有可能是误诊,使用对比报告或许可以帮助 DBA 更快速的定位问题。参考以下示例。 + +![QPS 图](/media/dashboard/dashboard-diagnostics-usage5.png) + +上图中,也是在跑 go-ycsb 的压测,可以发现,在 `2020-05-22 22:14:00` 时,QPS 突然开始下降,大概在持续 3 分钟后恢复。 + +生成以下 2 个时间范围的对比报告: + +- t1: 2020-05-22 22:11:00 - 2020-05-22 22:14:00,正常时间段。 +- t2: 2020-05-22 22:14:00 - 2020-05-22 22:17:00,QPS 开始下降的异常时间段。 + +生成对比报告后,查看 **Max diff item** 报表,该报表对比两个时间段的监控项后,按照监控项的差异大小排序,这个表的结果如下: + +![对比结果](/media/dashboard/dashboard-diagnostics-usage6.png) + +从上面结果可以看出 `t2` 时间段新增了很多 Coprocessor 请求,可以猜测可能是 `t2` 时间段出现了一些大查询,或者是查询较多的负载。 + +实际上,在 `t1` - `t2` 整个时间段内都在进行 `go-ycsb` 的压测,然后在 `t2` 时间段跑了 20 个 `tpch` 的查询,所以是因为 `tpch` 大查询导致了出现很多的 cop 请求。 + +这种大查询执行时间超过慢日志的阈值后也会记录在慢日志里面,可以继续查看 `Slow Queries In Time Range t2` 报表查看是否有一些慢查询。一些在 `t1` 时间段存在的查询,可能在 `t2` 时间段内就变成了慢查询,是因为 t2 时间段的其他负载影响导致该查询的执行变慢。 diff --git a/markdown-pages/zh/tidb/master/dashboard/dashboard-faq.md b/markdown-pages/zh/tidb/master/dashboard/dashboard-faq.md new file mode 100644 index 0000000..982e219 --- /dev/null +++ b/markdown-pages/zh/tidb/master/dashboard/dashboard-faq.md @@ -0,0 +1,152 @@ +--- +title: TiDB Dashboard 常见问题 +aliases: ['/docs-cn/dev/dashboard/dashboard-faq/'] +summary: TiDB Dashboard 常见问题汇总,包括访问、界面功能方面的常见问题与解决办法。若无法解决,请获取官方或社区支持。 +--- + +# TiDB Dashboard 常见问题 + +本文汇总了使用 TiDB Dashboard 过程中的常见问题与解决办法。若无法找到对应问题,或者根据指引操作后问题仍然存在,请从 PingCAP 官方或 TiDB 社区[获取支持](/support.md)。 + +## 访问 + +### 已配置防火墙或反向代理,但访问后被跳转到一个内部地址无法访问 TiDB Dashboard + +集群部署有多个 PD 实例的情况下,只有其中某一个 PD 实例会真正运行 TiDB Dashboard 服务,访问其他 PD 实例时会发生浏览器端重定向。若防火墙或反向代理没有为此进行正确配置,就可能出现访问后被重定向到一个被防火墙或反向代理保护的内部地址的情况。 + +- 参阅 [TiDB Dashboard 多 PD 实例部署](/dashboard/dashboard-ops-deploy.md#多-pd-实例部署)章节了解多 PD 实例下 TiDB Dashboard 的工作原理。 +- 参阅[通过反向代理使用 TiDB Dashboard](/dashboard/dashboard-ops-reverse-proxy.md) 章节了解如何正确配置反向代理。 +- 参阅[提高 TiDB Dashboard 安全性](/dashboard/dashboard-ops-security.md)章节了解如何正确配置防火墙。 + +### 双网卡部署时无法通过另一个网卡访问 TiDB Dashboard + +PD 中的 TiDB Dashboard 出于安全考虑仅监听部署时所指定的 IP 地址(即只监听在一个网卡上),而非 `0.0.0.0`,因此当主机上安装了多个网卡时,通过另一个网卡将无法访问。 + +当你使用 `tiup cluster` 或 `tiup playground` 命令部署时,目前尚没有方法改变该行为。推荐使用反向代理将 TiDB Dashboard 安全地暴露给另一个网卡,具体参见[通过反向代理使用 TiDB Dashboard](/dashboard/dashboard-ops-reverse-proxy.md) 章节。 + +## 界面功能 + +### 概况页面中 QPS 及 Latency 显示 `prometheus_not_found` 错误 + +QPS 及 Latency 监控依赖于集群中已正常部署 Prometheus 监控实例,没有部署的情况下就会显示为错误。向集群中新部署 Prometheus 实例即可解决该问题。 + +若已经部署 Prometheus 监控实例但仍然显示为错误,可能的原因是您使用的部署工具(TiUP 或 TiDB Operator)版本比较旧,没有自动汇报监控地址,导致 TiDB Dashboard 无法感知并查询监控数据。可以升级到最新的部署工具并重试。 + +以下给出 TiUP 部署工具的操作方法,对于其他部署工具,请参阅工具对应文档。 + +1. 升级 TiUP、TiUP Cluster: + + ```bash + tiup update --self + tiup update cluster --force + ``` + +2. 升级后,部署包含监控节点的新集群时,应当能正常显示监控。 + +3. 升级后,对于现有集群,可通过再次启动集群的方法汇报监控地址(将 `CLUSTER_NAME` 替换为实际集群名称): + + ```bash + tiup cluster start CLUSTER_NAME + ``` + + 即使集群已经启动,请仍然执行该命令。该命令不会影响集群上正常的业务,但会刷新并上报监控地址,从而能让监控在 TiDB Dashboard 中正常显示。 + +### 慢查询页面显示 `invalid connection` 错误 + +可能的原因是你开启了 TiDB 的 `prepared-plan-cache` 功能。`prepared-plan-cache` 是实验性功能,在某些版本的 TiDB 中可能无法正常运行,开启后可能会导致 TiDB Dashboard(及其他应用)出现该问题。你可以通过系统变量 [`tidb_enable_prepared_plan_cache`](/system-variables.md#tidb_enable_prepared_plan_cache-从-v610-版本开始引入) 关闭这项功能。 + +### 界面提示 `集群中未启动必要组件 NgMonitoring` + +NgMonitoring 是 TiDB v5.4.0 及以上集群中内置的高级监控组件,用于支撑 TiDB Dashboard 的 **持续性能分析** 和 **Top SQL** 等功能。使用较新版本 TiUP 部署或升级集群时,NgMonitoring 会自动部署;使用 TiDB Operator 部署集群时,需要依据[启用持续性能分析](https://docs.pingcap.com/zh/tidb-in-kubernetes/dev/access-dashboard#启用持续性能分析)手动部署 NgMonitoring。 + +如果界面提示 `集群中未启动必要组件 NgMonitoring`,可按以下方式排查部署问题。 + +
+ 使用 TiUP 部署的集群 + +第 1 步:检查 TiUP Cluster 版本 + + 1. 检查 TiUP Cluster 版本,NgMonitoring 组件需要较高版本的部署工具支持(TiUP v1.9.0 及以上): + + ```shell + tiup cluster --version + ``` + + 上述命令可查看 TiUP Cluster 的具体版本。例如: + + ``` + tiup version 1.9.0 tiup + Go Version: go1.17.2 + Git Ref: v1.9.0 + ``` + + 2. 如果 TiUP 版本低于 v1.9.0,升级 TiUP 和 TiUP Cluster 版本至最新。 + + ```shell + tiup update --all + ``` + +第 2 步:在中控机上,通过 TiUP 添加 ng_port 配置项,然后重启 Prometheus 节点。 + + 1. 以编辑模式打开集群的配置文件: + + ```shell + tiup cluster edit-config ${cluster-name} + ``` + + 2. 在 `monitoring_servers` 下面增加 `ng_port:12020` 参数: + + ``` + monitoring_servers: + - host: 172.16.6.6 + ng_port: 12020 + ``` + + 3. 重启 Prometheus 节点: + + ```shell + tiup cluster reload ${cluster-name} --role prometheus + ``` + +如果执行完上述步骤后依然提示 NgMonitoring 未启动,请从 PingCAP 官方或 TiDB 社区[获取支持](/support.md)。 + +
+ +
+ 使用 TiDB Operator 部署的集群 + +请参见 TiDB Operator 文档中[启用持续性能分析](https://docs.pingcap.com/zh/tidb-in-kubernetes/dev/access-dashboard#启用持续性能分析)的步骤部署 NgMonitoring 组件。 + +
+ +
+ 使用 TiUP Playground 启动的集群 + +TiUP Playground (>= v1.8.0) 在启动集群时会自动启动 NgMonitoring 组件。可使用以下命令更新 TiUP Playground 到最新版: + +```shell +tiup update --self +tiup update playground +``` + +
+ +### 慢查询页面显示 `unknown field` 错误 + +集群升级后,如果慢查询页面出现 `unknown field` 错误,是由于升级后新版本 TiDB Dashboard 字段与浏览器缓存内的用户偏好设置的字段不兼容导致的。该问题已修复。如果你的集群版本低于 v5.0.3 或 v4.0.14,需要执行以下步骤清理浏览器缓存: + +1. 打开 TiDB Dashboard 页面。 + +2. 打开浏览器的开发者工具。各浏览器的打开方式不同。 + + - Firefox:**菜单** > **Web 开发者** > **切换工具箱**(译者注:此处修改为最新的 Firefox Quantum),或者**工具栏** > **切换工具箱**。 + - Chrome:**菜单** > **更多工具** > **开发者工具**。 + - Safari:**Develop** > **Show Web Inspector**。如果你看不到 Develop 菜单,选择 **Preferences** > **Advanced**,然后点击 **Show Develop menu in menu bar** 复选框。 + + 以 Chrome 为例: + + ![打开开发者工具](/media/dashboard/dashboard-faq-devtools.png) + +3. 选中 **Application** 面板,展开 **Local Storage** 菜单并选中 **TiDB Dashboard 页面的域名**,点击 **Clear All**。 + + ![清理 Local Storage](/media/dashboard/dashboard-faq-devtools-application.png) diff --git a/markdown-pages/zh/tidb/master/dashboard/dashboard-intro.md b/markdown-pages/zh/tidb/master/dashboard/dashboard-intro.md new file mode 100644 index 0000000..798f673 --- /dev/null +++ b/markdown-pages/zh/tidb/master/dashboard/dashboard-intro.md @@ -0,0 +1,73 @@ +--- +title: TiDB Dashboard 介绍 +aliases: ['/docs-cn/dev/dashboard/dashboard-intro/'] +summary: TiDB Dashboard 是 TiDB 4.0 版本后提供的图形化界面,用于监控和诊断集群。它内置于 TiDB 的 PD 组件中,无需独立部署。可以查看集群整体运行概况、组件及主机运行状态、集群读写流量分布、SQL 查询的执行信息、耗时较长的 SQL 语句执行信息、诊断集群问题并生成报告、查询所有组件日志、预估资源管控容量、收集分析各个组件的性能数据。 +--- + +# TiDB Dashboard 介绍 + +TiDB Dashboard 是 TiDB 自 4.0 版本起提供的图形化界面,可用于监控及诊断 TiDB 集群。TiDB Dashboard 内置于 TiDB 的 PD 组件中,无需独立部署。 + +> **注意:** +> +> TiDB v6.5.0 且 TiDB Operator v1.4.0 之后,在 Kubernetes 上支持将 TiDB Dashboard 作为独立的 Pod 部署。具体信息,参考 [TiDB Operator 部署独立的 TiDB Dashboard](https://docs.pingcap.com/zh/tidb-in-kubernetes/dev/get-started#部署独立的-tidb-dashboard)。 + +![界面](/media/dashboard/dashboard-intro.gif) + +TiDB Dashboard 在 GitHub 上[开源](https://github.com/pingcap-incubator/tidb-dashboard)。 + +以下列出了 TiDB Dashboard 的主要功能,可分别点击小节内的链接进一步了解详情。 + +## 了解集群整体运行概况 + +查看集群整体 QPS 数值、执行耗时、消耗资源最多的几类 SQL 语句等概况信息。 + +参阅[概况页面](/dashboard/dashboard-overview.md)了解详情。 + +## 查看组件及主机运行状态 + +查看整个集群中 TiDB、TiKV、PD、TiFlash 组件的运行状态及其所在主机的运行状态。 + +参阅[集群信息页面](/dashboard/dashboard-cluster-info.md)了解详情。 + +## 分析集群读写流量分布及趋势变化 + +通过热力图形式可视化地展示整个集群中读写流量随时间的变化情况,及时发现业务模式的变化,或定位性能不均衡的热点所在。 + +参阅[流量可视化页面](/dashboard/dashboard-key-visualizer.md)了解详情。 + +## 列出所有 SQL 查询的耗时等执行信息 + +列出所有 SQL 语句在集群上执行情况,了解各个阶段的执行时间、总运行次数等信息,帮助用户分析和定位集群中最消耗资源的查询,优化整体性能。 + +参阅 [SQL 语句分析页面](/dashboard/dashboard-statement-list.md)了解详情。 + +## 详细了解耗时较长的 SQL 语句的执行信息 + +列出所有耗时较长的 SQL 语句文本及其执行信息,帮助用户定位 SQL 语句性能缓慢或发生性能抖动的原因。 + +参阅[慢查询页面](/dashboard/dashboard-slow-query.md)了解详情。 + +## 诊断常见集群问题并生成报告 + +自动判断集群中是否存在一些常见的风险(如配置不一致)或问题,生成报告并给出操作建议,或对比集群在不同时间段的各个指标状态,供用户分析可能存在问题的方向。 + +参阅[集群诊断页面](/dashboard/dashboard-diagnostics-access.md)了解详情。 + +## 查询所有组件日志 + +按关键字、时间范围等条件快速搜索集群中所有运行实例的日志,并可打包下载到本地。 + +参阅[日志搜索页面](/dashboard/dashboard-log-search.md)了解详情。 + +## 预估资源管控容量 + +为使用[资源管控 (Resource Control)](/tidb-resource-control.md) 特性实现资源隔离,集群管理员可以定义资源组 (Resource Group),通过资源组限定配额。 + +在进行资源规划之前,你需要了解集群的整体容量。参阅[资源管控页面](/dashboard/dashboard-resource-manager.md)了解详情。 + +## 收集分析各个组件的性能数据 + +高级调试功能:无需第三方工具,在线地对各个组件进行性能分析,剖析组件实例在分析时间段内执行的各种内部操作及比例。 + +参阅[实例性能分析页面](/dashboard/dashboard-profiling.md)了解详情。 diff --git a/markdown-pages/zh/tidb/master/dashboard/dashboard-key-visualizer.md b/markdown-pages/zh/tidb/master/dashboard/dashboard-key-visualizer.md new file mode 100644 index 0000000..815f0d5 --- /dev/null +++ b/markdown-pages/zh/tidb/master/dashboard/dashboard-key-visualizer.md @@ -0,0 +1,177 @@ +--- +title: TiDB Dashboard 流量可视化页面 +aliases: ['/docs-cn/dev/dashboard/dashboard-key-visualizer/','/docs-cn/dev/how-to/monitor/key-visualizer/','/docs-cn/dev/key-visualizer-monitoring-tool/'] +summary: TiDB Dashboard 的流量可视化页面可用于分析 TiDB 集群的使用模式和排查流量热点。通过登录 TiDB Dashboard 或在浏览器中访问指定链接,可以查看流量可视化页面。页面展示了流量热力图,可观察到整体访问流量随时间的变化情况,以及热力图某个坐标的详细信息。流量可视化页面涉及的基本概念包括 Region、热点、热力图和 Region 压缩。使用介绍包括设置、观察时间段或 Region 范围、调整亮度、选择指标、刷新与自动刷新以及查看详情。常见热力图解读包括均衡结果、X 轴明暗交替、Y 轴明暗交替和明亮斜线。解决热点问题可参考 TiDB 高并发写入场景最佳实践。 +--- + +# TiDB Dashboard 流量可视化页面 + +流量可视化页面 (Key Visualizer) 可用于分析 TiDB 集群的使用模式和排查流量热点。该页面可视化地呈现了 TiDB 集群一段时间的流量情况。 + +## 访问页面 + +可以通过以下两种方法访问 Key Visualizer 流量可视化页面: + +* 登录 TiDB Dashboard 后,点击左侧导航条的**流量可视化** (Key Visualizer): + + ![访问](/media/dashboard/dashboard-keyviz-access-v650.png) + +* 在浏览器中访问 `http://127.0.0.1:2379/dashboard/#/keyviz`(将 `127.0.0.1:2379` 替换为实际 PD 实例地址和端口)。 + +## 界面示例 + +流量可视化页面示例如下: + +![Key Visualizer 示例图](/media/dashboard/dashboard-keyviz-overview.png) + +从以上流量可视化界面可以观察到以下信息: + ++ 一个大型热力图,显示整体访问流量随时间的变化情况。 ++ 热力图某个坐标的详细信息。 ++ 左侧为表、索引等标识信息。 + +## 基本概念 + +本节介绍流量可视化涉及的一些基本概念。 + +### Region + +在 TiDB 集群中,数据以分布式的方式存储在所有的 TiKV 实例中。TiKV 在逻辑上是一个巨大且有序的 KV Map。整个 Key-Value 空间分成很多 Region,每一个 Region 是一系列连续的 Key。 + +> **注意:** +> +> 关于 Region 的详细介绍,请参考[三篇文章了解 TiDB 技术内幕 - 说存储](https://pingcap.com/blog-cn/tidb-internal-1/#region) + +### 热点 + +在使用 TiDB 的过程中,热点是一个典型的现象,它表现为大量的流量都在读写一小块数据。由于连续的数据往往由同一个 TiKV 实例处理,因此热点对应的 TiKV 实例的性能就成为了整个业务的性能瓶颈。常见的热点场景有使用自增主键连续写入相邻数据导致的写入表数据热点、时间索引下写入相邻时间数据导致的写入表索引热点等。 + +> **注意:** +> +> 热点问题详情请参阅 [TiDB 热点问题详解](https://tidb.net/blog/dffb428a)。 + +### 热力图 + +热力图是流量可视化页面的核心,它显示了一个指标随时间的变化。热力图的横轴 X 是时间,纵轴 Y 则是按 Key 排序的连续 Region,横跨 TiDB 集群上所有数据库和数据表。颜色越暗 (cold) 表示该区域的 Region 在这个时间段上读写流量较低,颜色越亮 (hot) 表示读写流量越高,即越热。 + +### Region 压缩 + +一个 TiDB 集群中,Region 的数量可能多达数十万。在屏幕上是难以显示这么多 Region 信息的。因此,在一张热力图中,Region 会被压缩到约 1500 个连续范围,每个范围称为 Bucket。在一个热力图上,热的实例更需要关注,因此 Region 压缩总是倾向于将流量较小的大量 Region 压缩为一个 Bucket,而尽量让高流量的 Region 独立成 Bucket。 + +## 使用介绍 + +本节介绍如何使用流量可视化页面。 + +### 设置 + +首次使用流量可视化页面需要先通过**设置**页面手动开启此功能。参考页面指引,点击**打开设置** (Open Settings) 即可打开设置页面: + +![功能未开启](/media/dashboard/dashboard-keyviz-not-enabled.png) + +在功能已经开启时,可通过右上角的设置图标打开设置页面: + +![设置按钮](/media/dashboard/dashboard-keyviz-settings-button.png) + +设置页面如下图所示: + +![设置页面](/media/dashboard/dashboard-keyviz-settings.png) + +通过开关设定好是否开启收集,并点击**保存** (Save) 后生效。开启后,在界面上观察到工具栏已经可以使用: + +![工具栏](/media/dashboard/dashboard-keyviz-toolbar.png) + +功能开启后,后台会持续收集数据,稍等一段时间即可看到热力图。 + +### 观察某一段时间或者 Region 范围 + +打开流量可视化页面时,默认会显示最近六小时整个数据库内的热力图。其中,越靠近右侧(当前时间)时,每列 Bucket 对应的时间间隔会越小。如果你想观察某个特定时间段或者特定的 Region 范围,则可以通过放大来获得更多细节。具体操作描述如下: + +* 在热力图中向上或向下滚动。 +* 点击**框选** (Select & Zoom) 按钮,然后点击并拖动以选择要放大的区域。 + +![框选](/media/dashboard/dashboard-keyviz-select-zoom.gif) + +* 点击**重置** (Reset) 按钮,将 Region 范围重置为整个数据库。 +* 点击「时间选择框」(界面的 **6 hour** 处),重新选择观察时间段。 + +![时间选择](/media/dashboard/dashboard-keyviz-select-time.png) + +> **注意:** +> +> 进行后三种操作,将引起热力图的重新绘制。你可能观察到热力图与放大前有较大差异。这是一个正常的现象,可能是由于在进行局部观察时,Region 压缩的粒度发生了变化,或者是局部范围内,“热”的基准发生了改变。 + +### 调整亮度 + +热力图使用颜色的明暗来表达一个 Bucket 的流量高低,颜色越暗 (cold) 表示该区域的 Region 在这个时间段上读写流量较低,颜色越亮 (hot) 表示读写流量越高,即越热。如果热力图中的颜色太亮或太暗,则可能很难观察到细节。此时,可以点击**调整亮度** (Brightness) 按钮,然后通过滑块来调节页面的亮度。 + +> **注意:** +> +> 在显示一个区域内的热力图时,会根据区域内的流量情况来界定冷热。当整个区域流量较为平均时,即使整体流量在数值上很低,你依然有可能观察到较大的亮色区域。请注意一定要结合数值一起分析。 + +### 选择指标 + +![指标选择](/media/dashboard/dashboard-keyviz-select-type.png) + +你可以通过「指标选择框」(以上界面中 **Write (bytes)** 处)来查看你关心的指标: + +* `Read (bytes)`:读取字节量 +* `Write (bytes)`:写入字节量 +* `Read (keys)`:读取次数 +* `Write (keys)`:写入次数 +* `All`:所有(读写流量的总和) + +### 刷新与自动刷新 + +可以通过点击**刷新** (Refresh) 按钮来重新获得基于当前时间的热力图。当需要实时观察数据库的流量分布情况时,可以点击按钮右侧的向下箭头,选择一个固定的时间间隔让热力图按此间隔自动刷新。 + +> **注意:** +> +> 如果进行了时间范围或者 Region 范围的调整,自动刷新会被关闭。 + +### 查看详情 + +可以将鼠标悬停在你所关注的 Bucket 上,来查看这个区域的详细信息: + +![Bucket 详细信息](/media/dashboard/dashboard-keyviz-tooltip.png) + +如果需要复制某个信息,可以进行点击 Bucket。此时相关详细信息的页面会被暂时钉住。点击你关注的信息,即可将其复制到剪切板: + +![复制 Bucket 详细信息](/media/dashboard/dashboard-keyviz-tooltip-copy.png) + +## 常见热力图解读 + +本章节选取了 Key Visualizer 中常见的四种热力图进行解读。 + +### 均衡:期望结果 + +![均衡结果图](/media/dashboard/dashboard-keyviz-well-dist.png) + +如上图所示,热力图颜色均匀或者深色和亮色混合良好,说明读取或写入在时间和 Region 空间范围上都分布得比较均衡,访问压力均匀地分摊在所有的机器上。这种负载是最适合分布式数据库的。 + +### X 轴明暗交替:需要关注高峰期的资源情况 + +![X 轴明暗交替](/media/dashboard/dashboard-keyviz-period.png) + +如上图所示,热力图在 X 轴(时间)上表现出明暗交替,但 Y 轴 (Region) 则比较均匀,说明读取或写入负载具有周期性的变化。这种情况可能出现在周期性的定时任务场景,如大数据平台每天定时从 TiDB 中抽取数据。一般来说可以关注一下使用高峰时期资源是否充裕。 + +### Y 轴明暗交替:需要关注产生的热点聚集程度 + +![Y 轴明暗交替](/media/dashboard/dashboard-keyviz-continue.png) + +如上图所示,热力图包含几个明亮的条纹,从 Y 轴来看条纹周围都是暗的,这表明明亮条纹区域的 Region 有很高的读写流量,可以从业务角度观察一下是否符合预期。例如,所有业务都关联用户表的情况下,用户表的整体流量就会很高,那么在热力图中表现为亮色区域就非常合理。 + +另外,明亮区域的高度(Y 轴方向的粗细)非常关键。由于 TiKV 自身拥有以 Region 为单位的热点平衡机制,因此涉及热点的 Region 越多其实越能有利于在所有 TiKV 实例上均衡流量。明亮条纹越粗、数量越多则意味着热点越分散、更多的 TiKV 能得到利用;明亮条纹越细、数量越少意味着热点越集中、热点 TiKV 越显著、越需要人工介入并关注。 + +### 明亮斜线:需要关注业务模式 + +![明亮斜线](/media/dashboard/dashboard-keyviz-sequential.png) + +如上图所示,热力图显示了明亮的斜线,表明读写的 Region 是连续的。这种场景常常出现在带索引的数据导入或者扫描阶段。例如,向自增 ID 的表进行连续写入等等。图中明亮部分对应的 Region 是读写流量的热点,往往会成为整个集群的性能问题所在。这种时候,可能需要业务重新调整主键,尽可能打散以将压力分散在多个 Region 上,或者选择将业务任务安排在低峰期。 + +> **注意:** +> +> 这里只是列出了几种常见的热力图模式。流量可视化页面中实际展示的是整个集群上所有数据库、数据表的热力图,因此非常有可能在不同的区域观察到不同的热力图模式,也可能观察到多种热力图模式的混合结果。使用的时候应当视实际情况灵活判断。 + +## 解决热点问题 + +TiDB 内置了不少帮助缓解常见热点问题的功能,深入了解请参考 [TiDB 高并发写入场景最佳实践](/best-practices/high-concurrency-best-practices.md)。 diff --git a/markdown-pages/zh/tidb/master/dashboard/dashboard-ops-deploy.md b/markdown-pages/zh/tidb/master/dashboard/dashboard-ops-deploy.md new file mode 100644 index 0000000..3146a91 --- /dev/null +++ b/markdown-pages/zh/tidb/master/dashboard/dashboard-ops-deploy.md @@ -0,0 +1,133 @@ +--- +title: 部署 TiDB Dashboard +aliases: ['/docs-cn/dev/dashboard/dashboard-ops-deploy/'] +summary: TiDB Dashboard 是内置于 TiDB 4.0 或更高版本的 PD 组件中的界面,无需额外部署。对于 TiDB v6.5.0 及 TiDB Operator v1.4.0 之后的版本,在 Kubernetes 上支持将 TiDB Dashboard 作为独立的 Pod 部署。部署标准 TiDB 集群的文档可参考快速试用 TiDB 集群、生产环境部署和 Kubernetes 环境部署。当集群中部署了多个 PD 实例时,仅有一个 PD 实例会提供 TiDB Dashboard 服务。可通过 TiUP 查看实际运行 TiDB Dashboard 服务的 PD 实例,并切换其他 PD 实例提供 TiDB Dashboard 服务。也可以禁用和重新启用 TiDB Dashboard。 +--- + +# 部署 TiDB Dashboard + +TiDB Dashboard 界面内置于 TiDB 4.0 或更高版本的 PD 组件中,无需额外部署。只需部署标准 TiDB 集群,TiDB Dashboard 就会原生集成。 + +> **注意:** +> +> TiDB v6.5.0 且 TiDB Operator v1.4.0 之后,在 Kubernetes 上支持将 TiDB Dashboard 作为独立的 Pod 部署。具体信息,参考 [TiDB Operator 部署独立的 TiDB Dashboard](https://docs.pingcap.com/zh/tidb-in-kubernetes/dev/get-started#部署独立的-tidb-dashboard)。 + +请参阅下列文档了解如何部署标准 TiDB 集群: + +- [快速试用 TiDB 集群](/quick-start-with-tidb.md) +- [生产环境部署](/production-deployment-using-tiup.md) +- [Kubernetes 环境部署](https://docs.pingcap.com/zh/tidb-in-kubernetes/stable/access-dashboard/) + +> **注意:** +> +> TiDB Dashboard 目前不能在低于 4.0 版本的集群中部署或使用。 + +## 多 PD 实例部署 + +当集群中部署了多个 PD 实例时,其中仅有一个 PD 实例会固定地提供 TiDB Dashboard 服务。 + +各个 PD 首次运行时会自动协商出其中某一个实例提供 TiDB Dashboard 服务。协商完毕后,无论重启或扩容,都会固定在这个实例上运行 TiDB Dashboard 服务,除非该实例被手动缩容。其他 PD 实例不会运行 TiDB Dashboard 服务。这个协商过程无需用户介入,会自动完成。 + +当用户访问不提供 TiDB Dashboard 服务的 PD 实例时,浏览器将会收到重定向指令,自动引导用户重新访问提供了 TiDB Dashboard 服务的 PD 实例,从而能正常使用。流程如下图所示。 + +![流程示意](/media/dashboard/dashboard-ops-multiple-pd.png) + +> **注意:** +> +> 提供 TiDB Dashboard 服务的 PD 实例不一定与 PD leader 一致。 + +### 查询实际运行 TiDB Dashboard 服务的 PD 实例 + +使用 TiUP 部署时,对于已启动的集群,可通过 `tiup cluster display` 命令查看哪个 PD 节点提供了 TiDB Dashboard 服务(将 `CLUSTER_NAME` 替换为集群名称): + +```bash +tiup cluster display CLUSTER_NAME --dashboard +``` + +输出样例如下: + +``` +http://192.168.0.123:2379/dashboard/ +``` + +> **注意:** +> +> 该功能在 TiUP Cluster v1.0.3 或更高版本部署工具中提供。 +> +>
+> 升级 TiUP Cluster 步骤 +> +> ```shell +> tiup update --self +> tiup update cluster --force +> ``` +> +>
+ +### 切换其他 PD 实例提供 TiDB Dashboard 服务 + +使用 TiUP 部署时,对于已启动的集群,可使用 `tiup ctl:v pd` 命令切换其他 PD 实例运行 TiDB Dashboard,或在禁用 TiDB Dashboard 的情况下重新指定一个 PD 实例运行 TiDB Dashboard: + +```bash +tiup ctl:v pd -u http://127.0.0.1:2379 config set dashboard-address http://9.9.9.9:2379 +``` + +其中: + +- 将 `127.0.0.1:2379` 替换为任意 PD 实例的 IP 和端口 +- 将 `9.9.9.9:2379` 替换为想运行 TiDB Dashboard 服务的新 PD 实例的 IP 和端口 + +修改完毕后,可使用 `tiup cluster display` 命令确认修改是否生效(将 `CLUSTER_NAME` 替换为集群名称): + +```bash +tiup cluster display CLUSTER_NAME --dashboard +``` + +> **警告:** +> +> 切换 TiDB Dashboard 将会丢失之前 TiDB Dashboard 实例所存储的本地数据,包括流量可视化历史、历史搜索记录等。 + +## 禁用 TiDB Dashboard + +使用 TiUP 部署时,对于已启动的集群,可使用 `tiup ctl:v pd` 命令在所有 PD 实例上禁用 TiDB Dashboard(将 `127.0.0.1:2379` 替换为任意 PD 实例的 IP 和端口): + +```bash +tiup ctl:v pd -u http://127.0.0.1:2379 config set dashboard-address none +``` + +禁用 TiDB Dashboard 后,查询哪个 PD 实例提供 TiDB Dashboard 服务将会失败: + +``` +Error: TiDB Dashboard is disabled +``` + +浏览器访问任意 PD 实例的 TiDB Dashboard 地址也将提示失败: + +``` +Dashboard is not started. +``` + +## 重新启用 TiDB Dashboard + +使用 TiUP 部署时,对于已启动的集群,可使用 `tiup ctl:v pd` 命令,要求 PD 重新协商出某一个实例运行 TiDB Dashboard(将 `127.0.0.1:2379` 替换为任意 PD 实例的 IP 和端口): + +```bash +tiup ctl:v pd -u http://127.0.0.1:2379 config set dashboard-address auto +``` + +修改完毕后,使用 `tiup cluster display` 命令查看 PD 自动协商出的 TiDB Dashboard 实例地址(将 `CLUSTER_NAME` 替换为集群名称): + +```bash +tiup cluster display CLUSTER_NAME --dashboard +``` + +还可以通过手动指定哪个 PD 实例运行 TiDB Dashboard 服务的方式重新启用 TiDB Dashboard,具体操作参见上文[切换其他 PD 实例提供 TiDB Dashboard 服务](#切换其他-pd-实例提供-tidb-dashboard-服务)。 + +> **警告:** +> +> 若新启用的 TiDB Dashboard 实例与禁用前的实例不一致,将会丢失之前 TiDB Dashboard 实例所存储的本地数据,包括流量可视化历史、历史搜索记录等。 + +## 下一步 + +- 参阅[访问 TiDB Dashboard](/dashboard/dashboard-access.md) 章节了解如何访问及登录集群上的 TiDB Dashboard 界面。 +- 参阅[提高 TiDB Dashboard 安全性](/dashboard/dashboard-ops-security.md)章节了解如何增强 TiDB Dashboard 的安全性,如配置防火墙等。 diff --git a/markdown-pages/zh/tidb/master/dashboard/dashboard-ops-reverse-proxy.md b/markdown-pages/zh/tidb/master/dashboard/dashboard-ops-reverse-proxy.md new file mode 100644 index 0000000..a9154a9 --- /dev/null +++ b/markdown-pages/zh/tidb/master/dashboard/dashboard-ops-reverse-proxy.md @@ -0,0 +1,274 @@ +--- +title: 通过反向代理使用 TiDB Dashboard +aliases: ['/docs-cn/dev/dashboard/dashboard-ops-reverse-proxy/'] +summary: TiDB Dashboard 可通过反向代理安全提供给外部网络。首先获取实际地址,然后配置反向代理,最后修改路径前缀。详细步骤可参考官方文档。 +--- + +# 通过反向代理使用 TiDB Dashboard + +你可以使用反向代理将 TiDB Dashboard 服务安全从内部网络提供给外部网络。 + +## 操作步骤 + +### 第 1 步:获取实际 TiDB Dashboard 地址 + +当集群中部署有多个 PD 实例时,其中仅有一个 PD 实例会真正运行 TiDB Dashboard,因此需要确保反向代理的上游 (Upstream) 指向了正确的地址。关于该机制的详情,可参阅 [TiDB Dashboard 多 PD 实例部署](/dashboard/dashboard-ops-deploy.md#多-pd-实例部署)章节。 + +使用 TiUP 部署工具时,操作命令如下(将 `CLUSTER_NAME` 替换为集群名称): + +```shell +tiup cluster display CLUSTER_NAME --dashboard +``` + +输出即为实际 TiDB Dashboard 地址。样例如下: + +``` +http://192.168.0.123:2379/dashboard/ +``` + +> **注意:** +> +> 该功能在 TiUP Cluster v1.0.3 或更高版本部署工具中提供。 +> +>
+> 升级 TiUP Cluster 步骤 +> +> ```shell +> tiup update --self +> tiup update cluster --force +> ``` +> +>
+ +### 第 2 步:配置反向代理 + +
+使用 HAProxy 反向代理 + +[HAProxy](https://www.haproxy.org/) 作为反向代理时,方法如下: + +1. 以在 8033 端口反向代理 TiDB Dashboard 为例,在 HAProxy 配置文件中,新增如下配置: + + ```haproxy + frontend tidb_dashboard_front + bind *:8033 + use_backend tidb_dashboard_back if { path /dashboard } or { path_beg /dashboard/ } + + backend tidb_dashboard_back + mode http + server tidb_dashboard 192.168.0.123:2379 + ``` + + 其中 `192.168.0.123:2379` 需替换为[第 1 步:获取实际 TiDB Dashboard 地址](#第-1-步获取实际-tidb-dashboard-地址)中取得的 TiDB Dashboard 实际地址中的 IP 及端口部分。 + + > **警告:** + > + > 请务必保留 `use_backend` 指令中的 `if` 部分,确保只有该路径下的服务会被反向代理,否则将引入安全风险。参见[提高 TiDB Dashboard 安全性](/dashboard/dashboard-ops-security.md)。 + +2. 重启 HAProxy,以使配置生效。 + +3. 测试反向代理是否生效:访问 HAProxy 所在机器的 8033 端口下 `/dashboard/` 地址,如 ,即可访问 TiDB Dashboard。 + +
+ +
+使用 NGINX 反向代理 + +[NGINX](https://nginx.org/) 作为反向代理时,方法如下: + +1. 以在 8033 端口反向代理 TiDB Dashboard 为例,在 NGINX 配置文件中,新增如下配置: + + ```nginx + server { + listen 8033; + location /dashboard/ { + proxy_pass http://192.168.0.123:2379/dashboard/; + } + } + ``` + + 其中 `http://192.168.0.123:2379/dashboard/` 需替换为[第 1 步:获取实际 TiDB Dashboard 地址](#第-1-步获取实际-tidb-dashboard-地址)中取得的 TiDB Dashboard 实际地址。 + + > **警告:** + > + > 请务必保留 `proxy_pass` 指令中的 `/dashboard/` 路径,确保只有该路径下的服务会被反向代理,否则将引入安全风险。参见[提高 TiDB Dashboard 安全性](/dashboard/dashboard-ops-security.md)。 + +2. 重新载入 NGINX 以使配置生效: + + ```shell + sudo nginx -s reload + ``` + +3. 测试反向代理是否生效:访问 NGINX 所在机器的 8033 端口下 `/dashboard/` 地址,如 `http://example.com:8033/dashboard/`,即可访问 TiDB Dashboard。 + +
+ +## 自定义路径前缀 + +TiDB Dashboard 默认在 `/dashboard/` 路径下提供服务,即使是反向代理也是如此,例如 `http://example.com:8033/dashboard/`。若要配置反向代理以非默认的路径提供 TiDB Dashboard 服务,例如 `http://example.com:8033/foo/` 或 `http://example.com:8033/`,可参考以下步骤。 + +### 第 1 步:修改 PD 配置指定 TiDB Dashboard 服务路径前缀 + +修改 PD 配置中 `[dashboard]` 类别的 `public-path-prefix` 配置项,可指定服务路径前缀。该配置修改后需要重启 PD 实例生效。 + +以 TiUP 部署且希望运行在 `http://example.com:8033/foo/` 为例,可指定以下配置: + +```yaml +server_configs: + pd: + dashboard.public-path-prefix: /foo +``` + +
+ 使用 TiUP 部署全新集群时修改配置 + +若要全新部署集群,可在 TiUP 拓扑文件 `topology.yaml` 中加入上述配置项后进行部署,具体步骤参阅 [TiUP 部署文档](/production-deployment-using-tiup.md#第-3-步初始化集群拓扑文件)。 + +
+ +
+ 使用 TiUP 修改已部署集群的配置 + +1. 以编辑模式打开该集群的配置文件(将 `CLUSTER_NAME` 替换为集群名称) + + ```shell + tiup cluster edit-config CLUSTER_NAME + ``` + +2. 在 `server_configs` 的 `pd` 配置下修改或新增配置项,若没有 `server_configs` 请在最顶层新增: + + ```yaml + server_configs: + pd: + dashboard.public-path-prefix: /foo + ``` + + 修改完成后的配置文件类似于: + + ```yaml + server_configs: + pd: + dashboard.public-path-prefix: /foo + global: + user: tidb + ... + ``` + + 或 + + ```yaml + monitored: + ... + server_configs: + tidb: ... + tikv: ... + pd: + dashboard.public-path-prefix: /foo + ... + ``` + +3. 滚动重启所有 PD 实例生效配置(将 `CLUSTER_NAME` 替换为集群名称) + + ```shell + tiup cluster reload CLUSTER_NAME -R pd + ``` + + 详情请参阅 [TiUP 常见运维操作 - 修改配置参数](/maintain-tidb-using-tiup.md#修改配置参数)。 + +
+ +若希望运行在根路径(如 `http://example.com:8033/`)下,相应的配置为: + +```yaml +server_configs: + pd: + dashboard.public-path-prefix: / +``` + +> **警告:** +> +> 修改自定义路径前缀生效后,直接访问将不能正常使用 TiDB Dashboard,您只能通过和路径前缀匹配的反向代理访问。 + +### 第 2 步:修改反向代理配置 + +
+使用 HAProxy 反向代理 + +以 `http://example.com:8033/foo/` 为例,HAProxy 配置如下: + +```haproxy +frontend tidb_dashboard_front + bind *:8033 + use_backend tidb_dashboard_back if { path /foo } or { path_beg /foo/ } + +backend tidb_dashboard_back + mode http + http-request set-path %[path,regsub(^/foo/?,/dashboard/)] + server tidb_dashboard 192.168.0.123:2379 +``` + +其中 `192.168.0.123:2379` 需替换为[第 1 步:获取实际 TiDB Dashboard 地址](#第-1-步获取实际-tidb-dashboard-地址)中取得的 TiDB Dashboard 实际地址中的 IP 及端口部分。 + +> **警告:** +> +> 请务必保留 `use_backend` 指令中的 `if` 部分,确保只有该路径下的服务会被反向代理,否则将引入安全风险。参见[提高 TiDB Dashboard 安全性](/dashboard/dashboard-ops-security.md)。 + +若希望运行在根路径(如 `http://example.com:8033/`),HAProxy 配置如下: + +```nginx +frontend tidb_dashboard_front + bind *:8033 + use_backend tidb_dashboard_back + +backend tidb_dashboard_back + mode http + http-request set-path /dashboard%[path] + server tidb_dashboard 192.168.0.123:2379 +``` + +修改配置并重启 HAProxy 后即可生效。 + +
+ +
+使用 NGINX 反向代理 + +以 `http://example.com:8033/foo/` 为例,相应的 NGINX 配置为: + +```nginx +server { + listen 8033; + location /foo/ { + proxy_pass http://192.168.0.123:2379/dashboard/; + } +} +``` + +其中 `http://192.168.0.123:2379/dashboard/` 需替换为[第 1 步:获取实际 TiDB Dashboard 地址](#第-1-步获取实际-tidb-dashboard-地址)中取得的 TiDB Dashboard 实际地址。 + +> **警告:** +> +> 请务必保留 `proxy_pass` 指令中的 `/dashboard/` 路径,确保只有该路径下的服务会被反向代理,否则将引入安全风险。参见[提高 TiDB Dashboard 安全性](/dashboard/dashboard-ops-security.md)。 + +若希望运行在根路径(如 `http://example.com:8033/`),NGINX 配置为: + +```nginx +server { + listen 8033; + location / { + proxy_pass http://192.168.0.123:2379/dashboard/; + } +} +``` + +修改配置并重启 NGINX 后即可生效: + +```shell +sudo nginx -s reload +``` + +
+ +## 下一步 + +参阅[提高 TiDB Dashboard 安全性](/dashboard/dashboard-ops-security.md)文档了解如何增强 TiDB Dashboard 的安全性,如配置防火墙等。 diff --git a/markdown-pages/zh/tidb/master/dashboard/dashboard-ops-security.md b/markdown-pages/zh/tidb/master/dashboard/dashboard-ops-security.md new file mode 100644 index 0000000..bb3d3be --- /dev/null +++ b/markdown-pages/zh/tidb/master/dashboard/dashboard-ops-security.md @@ -0,0 +1,102 @@ +--- +title: 提高 TiDB Dashboard 安全性 +aliases: ['/docs-cn/dev/dashboard/dashboard-ops-security/'] +summary: TiDB Dashboard 需要提高安全性。建议为 `root` 用户设置强密码或禁用 `root` 账户,并为 TiDB Dashboard 创建最小权限用户。使用防火墙阻止不可信访问,配置反向代理仅代理 TiDB Dashboard,并为反向代理开启 TLS。其他建议的安全措施包括为组件间通信和客户端服务端间通信开启加密传输。 +--- + +# 提高 TiDB Dashboard 安全性 + +尽管访问 TiDB Dashboard 需要登录,但它被设计为默认供可信的用户实体访问。当你希望将 TiDB Dashboard 提供给外部网络用户或不可信用户访问时,需要注意采取以下措施以避免安全漏洞。 + +## 提高 TiDB 用户安全性 + +### 为 `root` 用户设置强密码 + +TiDB Dashboard 的账号体系与 TiDB SQL 用户一致。默认部署情况下,TiDB 的 `root` 用户没有密码,因而访问 TiDB Dashboard 也不需要密码验证。这将会给恶意访问者极大的集群权限,包括执行特权 SQL 等。 + +建议的措施: + +- 为 TiDB 的 `root` 用户设置一个强密码(请参见 [TiDB 用户账户管理](/user-account-management.md)了解详情),或禁用 `root` 账户。 + +### 为 TiDB Dashboard 创建最小权限用户 + +TiDB Dashboard 的账号体系与 TiDB SQL 用户一致,并基于 TiDB SQL 用户的权限进行 TiDB Dashboard 授权验证。TiDB Dashboard 所需的权限较少,甚至可以只有只读权限。可以基于最小权限原则配置合适的用户访问 TiDB Dashboard,减少高权限用户的使用场景。 + +建议的措施: + +- 为访问 TiDB Dashboard 创建一个最小权限的 SQL 用户,并用该用户登录 TiDB Dashboard,避免使用高权限用户,提升安全性。请参见 [TiDB Dashboard 用户管理](/dashboard/dashboard-user.md)了解详情。 + +## 使用防火墙阻止不可信访问 + +> **注意:** +> +> TiDB v6.5.0 且 TiDB Operator v1.4.0 之后,在 Kubernetes 上支持将 TiDB Dashboard 作为独立的 Pod 部署。在 TiDB Operator 环境,可直接访问该 Pod 的 IP 来打开 TiDB Dashboard,该端口不与其他 PD 内部特权接口关联,对外提供该端口不需要额外的防火墙操作。具体信息,参考 [TiDB Operator 部署独立的 TiDB Dashboard](https://docs.pingcap.com/zh/tidb-in-kubernetes/dev/get-started#部署独立的-tidb-dashboard)。 + +TiDB Dashboard 通过 PD Client 端口提供服务,默认为 。尽管 TiDB Dashboard 需要验证身份,但 PD Client 端口上承载的其他 PD 内部特权接口不需要验证身份,且能进行特权操作,例如 。因此,将 PD Client 端口直接暴露给外部网络具有极大的风险。 + +建议的措施: + +1. 使用防火墙禁止组件外部网络或不可信网络访问**任何** PD 组件的 Client 端口。 + + 注意,TiDB、TiKV 等组件需要通过 PD Client 端口与 PD 组件进行通信,因此请勿对组件内部网络阻止访问,这将导致集群不可用。 + +2. 参见[通过反向代理使用 TiDB Dashboard](/dashboard/dashboard-ops-reverse-proxy.md) 了解如何配置反向代理将 TiDB Dashboard 服务在另一个端口上安全地提供给外部网络。 + +### 如何在多 PD 实例部署时开放 TiDB Dashboard 端口访问 + +> **警告:** +> +> 本章节描述了一个不安全的访问方案,仅供测试环境使用。在生产环境中,不要使用本方案。请参见本文的其余章节。 + +在测试环境中,您可能需要配置防火墙开放 TiDB Dashboard 端口供外部访问。 + +当部署了多个 PD 实例时,其中仅有一个 PD 实例会真正运行 TiDB Dashboard,访问其他 PD 实例时会发生浏览器重定向,因此需要确保防火墙配置了正确的 IP 地址。关于该机制的详情,可参阅 [TiDB Dashboard 多 PD 实例部署](/dashboard/dashboard-ops-deploy.md#多-pd-实例部署)章节。 + +使用 TiUP 部署工具时,可使用以下命令查看实际运行 TiDB Dashboard 的 PD 实例地址(将 `CLUSTER_NAME` 替换为集群名称): + +```bash +tiup cluster display CLUSTER_NAME --dashboard +``` + +输出即为实际 TiDB Dashboard 地址。 + +> **注意:** +> +> 该功能在 TiUP Cluster v1.0.3 或更高版本部署工具中提供。 +> +>
+> 升级 TiUP Cluster 步骤 +> +> ```shell +> tiup update --self +> tiup update cluster --force +> ``` +> +>
+ +以下是一个样例输出: + +``` +http://192.168.0.123:2379/dashboard/ +``` + +在这个样例中,需要为防火墙配置开放 IP `192.168.0.123` 的 `2379` 端口入站访问,并通过 访问 TiDB Dashboard。 + +## 反向代理仅代理 TiDB Dashboard + +如前文所述,PD Client 端口下提供的服务不仅有 TiDB Dashboard(位于 ),还有其他 PD 内部特权接口(如 )。因此,使用反向代理将 TiDB Dashboard 提供给外部网络时,应当确保仅提供 `/dashboard` 前缀下的服务,而非该端口下所有服务,避免外部网络能通过反向代理访问到 PD 内部特权接口。 + +建议的措施: + +- 参见[通过反向代理使用 TiDB Dashboard](/dashboard/dashboard-ops-reverse-proxy.md) 了解安全且推荐的反向代理配置。 + +## 为反向代理开启 TLS + +为了进一步加强传输层安全性,可以为反向代理开启 TLS,甚至可以引入 mTLS 实现访问用户的证书验证。 + +请参阅 [NGINX 文档](http://nginx.org/en/docs/http/configuring_https_servers.html)或 [HAProxy 文档](https://www.haproxy.com/blog/haproxy-ssl-termination/)了解如何为它们开启 TLS。 + +## 其他建议的安全措施 + +- [为 TiDB 组件间通信开启加密传输](/enable-tls-between-components.md) +- [为 TiDB 客户端服务端间通信开启加密传输](/enable-tls-between-clients-and-servers.md) diff --git a/markdown-pages/zh/tidb/master/dashboard/dashboard-overview.md b/markdown-pages/zh/tidb/master/dashboard/dashboard-overview.md new file mode 100644 index 0000000..6adcf1a --- /dev/null +++ b/markdown-pages/zh/tidb/master/dashboard/dashboard-overview.md @@ -0,0 +1,95 @@ +--- +title: TiDB Dashboard 概况页面 +aliases: ['/docs-cn/dev/dashboard/dashboard-overview/'] +summary: TiDB Dashboard 概况页面显示整个集群的 QPS、查询延迟、Top SQL 语句、最近的慢查询、实例状态和监控及告警信息。登录后默认进入该页面,也可通过左侧导航条点击概况进入。包含最近一小时整个集群的 QPS 和查询延迟,以及最近一段时间内累计耗时最多的 SQL 语句和运行时间超过一定阈值的慢查询。还显示各个实例的节点数和状态,以及提供了便捷的链接方便用户查看详细监控或告警。 +--- + +# TiDB Dashboard 概况页面 + +该页面显示了整个集群的概况,包含以下信息: + +- 整个集群的 QPS +- 整个集群的查询延迟 +- 最近一段时间内累计耗时最多的若干 SQL 语句 +- 最近一段时间内运行时间超过一定阈值的慢查询 +- 各个实例的节点数和状态 +- 监控及告警信息 + +## 访问 + +登录 TiDB Dashboard 后默认进入该页面,也可以左侧导航条点击**概况** (Overview) 进入: + +![访问](/media/dashboard/dashboard-overview-access-v650.png) + +## QPS + +该区域显示最近一小时整个集群的每秒成功和失败查询数量: + +![界面](/media/dashboard/dashboard-overview-qps.png) + +> **注意:** +> +> 该功能仅在部署了 Prometheus 监控组件的集群上可用,未部署监控组件的情况下会显示为失败。 + +## 延迟 + +该区域显示最近一小时整个集群中 99.9%、99% 和 90% 查询的延迟: + +![界面](/media/dashboard/dashboard-overview-latency.png) + +> **注意:** +> +> 该功能仅在部署了 Prometheus 监控组件的集群上可用,未部署监控组件的情况下会显示为失败。 + +## Top SQL 语句 + +该区域显示最近一段时间内整个群集中累计耗时最长的 10 类 SQL 语句。查询参数不一样但结构一样的 SQL 会归为同一类 SQL 语句,在同一行中显示: + +![界面](/media/dashboard/dashboard-overview-top-statements.png) + +该区域显示的内容与 [SQL 语句分析页面](/dashboard/dashboard-statement-list.md)一致,可点击 **Top SQL 语句** (Top SQL Statements) 标题查看完整列表。关于该表格中各列详情,见 [SQL 语句分析页面](/dashboard/dashboard-statement-list.md)。 + +> **注意:** +> +> 该功能仅在开启了 SQL 语句分析功能的集群上可用。 + +## 最近的慢查询 + +该区域默认显示最近 30 分钟内整个集群中最新的 10 条慢查询: + +![界面](/media/dashboard/dashboard-overview-slow-query.png) + +默认情况下运行时间超过 300ms 的 SQL 查询即会被计为慢查询并显示在该表格中。可通过调整 [tidb_slow_log_threshold](/system-variables.md#tidb_slow_log_threshold) 变量或 TiDB [instance.tidb_slow_log_threshold](/tidb-configuration-file.md#tidb_slow_log_threshold) 参数调整阈值。 + +该区域显示的内容与[慢查询页面](/dashboard/dashboard-slow-query.md)一致,可点击**最近的慢查询** (Recent Slow Queries) 标题查看完整列表。关于该表格中各列详情,见[慢查询页面](/dashboard/dashboard-slow-query.md)。 + +> **注意:** +> +> 该功能仅在配置开启了慢查询日志的集群中可用,使用 TiUP 部署的集群默认开启慢查询日志。 + +## 实例 + +该区域汇总显示了整个集群中 TiDB、TiKV、PD、TiFlash 的总实例数量及异常实例数量: + +![界面](/media/dashboard/dashboard-overview-instances.png) + +状态描述如下: + +- Up:实例运行正常(含下线中的存储实例)。 +- Down:实例运行异常,例如网络无法连接、进程已崩溃等。 + +点击**实例**标题可进入[集群信息页面](/dashboard/dashboard-cluster-info.md)查看各个实例的详细运行状态。 + +## 监控和告警 + +该区域提供了便捷的链接方便用户查看详细监控或告警: + +![界面](/media/dashboard/dashboard-overview-monitor.png) + +- **查看监控**链接:点击后跳转至 Grafana 页面,可查看集群详细监控信息。关于 Grafana 监控面板中各个详细监控指标的解释,参见[监控指标](/grafana-overview-dashboard.md)文档。 +- **查看告警**链接:点击后跳转至 AlertManager 页面,可查看集群详细告警信息。当集群中已有告警时,告警数量将会直接显示在链接文本上。 +- **运行诊断**链接:点击后跳转至集群诊断页面,参见[集群诊断页面](/dashboard/dashboard-diagnostics-access.md)了解详情。 + +> **注意:** +> +> **查看监控**链接仅在集群中部署了 Grafana 节点时可用,**查看告警**链接仅在集群中部署了 AlertManager 节点时可用。 diff --git a/markdown-pages/zh/tidb/master/data-type-date-and-time.md b/markdown-pages/zh/tidb/master/data-type-date-and-time.md new file mode 100644 index 0000000..f13b211 --- /dev/null +++ b/markdown-pages/zh/tidb/master/data-type-date-and-time.md @@ -0,0 +1,311 @@ +--- +title: 日期和时间类型 +aliases: ['/docs-cn/dev/data-type-date-and-time/','/docs-cn/dev/reference/sql/data-types/date-and-time/'] +summary: TiDB 支持 MySQL 的所有日期和时间类型,包括 DATE、TIME、DATETIME、TIMESTAMP 和 YEAR。每种类型都有有效值范围,值为 0 表示无效值。TIMESTAMP 和 DATETIME 类型能自动生成新的时间值。关于日期和时间值类型,需要注意日期部分必须是“年 - 月 - 日”的格式,如果日期的年份部分是 2 位数,TiDB 会根据具体规则进行转换。不同类型的零值如下表所示:DATE:0000-00-00, TIME:00:00:00, DATETIME:0000-00-00 00:00:00, TIMESTAMP:0000-00-00 00:00:00, YEAR:0000。如果 SQL 模式允许使用无效的 DATE、DATETIME、TIMESTAMP 值,无效值会自动转换为相应的零值。 +--- + +# 日期和时间类型 + +TiDB 支持 MySQL 所有的日期和时间类型,包括 [`DATE`](#date-类型)、[`TIME`](#time-类型)、[`DATETIME`](#datetime-类型)、[`TIMESTAMP`](#timestamp-类型) 以及 [`YEAR`](#year-类型)。完整信息可以参考 [MySQL 中的时间和日期类型](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-types.html)。 + +每种类型都有有效值范围,值为 0 表示无效值。此外,`TIMESTAMP` 和 `DATETIME` 类型能自动生成新的时间值。 + +关于日期和时间值类型,需要注意: + +- 日期部分必须是“年-月-日”的格式(例如 `1998-09-04`),而不是“月-日-年”或“日-月-年”的格式。 +- 如果日期的年份部分是 2 位数,TiDB 会根据[年份为两位数的具体规则](#年份为两位数)进行转换。 +- 如果格式必须是数值类型,TiDB 会自动将日期或时间值转换为数值类型。例如: + + ```sql + SELECT NOW(), NOW()+0, NOW(3)+0; + ``` + + ```sql + +---------------------+----------------+--------------------+ + | NOW() | NOW()+0 | NOW(3)+0 | + +---------------------+----------------+--------------------+ + | 2012-08-15 09:28:00 | 20120815092800 | 20120815092800.889 | + +---------------------+----------------+--------------------+ + ``` + +- TiDB 可以自动将无效值转换同一类型的零值。是否进行转换取决于 SQL 模式的设置。比如: + + ```sql + show create table t1; + ``` + + ```sql + +-------+---------------------------------------------------------------------------------------------------------+ + | Table | Create Table | + +-------+---------------------------------------------------------------------------------------------------------+ + | t1 | CREATE TABLE `t1` ( + `a` time DEFAULT NULL + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin | + +-------+---------------------------------------------------------------------------------------------------------+ + 1 row in set (0.00 sec) + ``` + + ```sql + select @@sql_mode; + ``` + + ```sql + +-------------------------------------------------------------------------------------------------------------------------------------------+ + | @@sql_mode | + +-------------------------------------------------------------------------------------------------------------------------------------------+ + | ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION | + +-------------------------------------------------------------------------------------------------------------------------------------------+ + 1 row in set (0.00 sec) + ``` + + ```sql + insert into t1 values (`2090-11-32:22:33:44`); + ``` + + ```sql + ERROR 1292 (22007): Truncated incorrect time value: `2090-11-32:22:33:44` + ``` + + ```sql + set @@sql_mode=``; + ``` + + ```sql + Query OK, 0 rows affected (0.01 sec) + ``` + + ```sql + insert into t1 values (`2090-11-32:22:33:44`); + ``` + + ```sql + Query OK, 1 row affected, 1 warning (0.01 sec) + ``` + + ```sql + select * from t1; + ``` + + ```sql + +----------+ + | a | + +----------+ + | 00:00:00 | + +----------+ + 1 row in set (0.01 sec) + ``` + +- SQL 模式的不同设置,会改变 TiDB 对格式的要求。 +- 如果 SQL 模式的 `NO_ZERO_DATE` 被禁用,TiDB 允许 `DATE` 和 `DATETIME` 列中的月份或日期为零。例如,`2009-00-00` 或 `2009-01-00`。如果使用函数计算这种日期类型,例如使用 `DATE_SUB()` 或 `DATE_ADD()` 函数,计算结果可能不正确。 +- 默认情况下,TiDB 启用 `NO_ZERO_DATE` SQL 模式。该模式可以避免存储像 `0000-00-00` 这样的零值。 + +不同类型的零值如下表所示: + +| 数据类型 | 零值 | +| :------ | :---- | +| DATE | `0000-00-00` | +| TIME | `00:00:00` | +| DATETIME | `0000-00-00 00:00:00` | +| TIMESTAMP | `0000-00-00 00:00:00` | +| YEAR | 0000 | + +如果 SQL 模式允许使用无效的 `DATE`、`DATETIME`、`TIMESTAMP` 值,无效值会自动转换为相应的零值(`0000-00-00` 或 `0000-00-00 00:00:00`)。 + +## 类型定义 + +### `DATE` 类型 + +`DATE` 类型只包含日期部分,不包含时间部分。`DATE` 类型的格式为 `YYYY-MM-DD`,支持的范围是 `0000-01-01` 到 `9999-12-31`。 + +```sql +DATE +``` + +### `TIME` 类型 + +`TIME` 类型的格式为 `HH:MM:SS[.fraction]`,支持的范围是 `-838:59:59.000000` 到 `838:59:59.000000`。`TIME` 不仅可用于指示一天内的时间,还可用于指两个事件之间的时间间隔。`fsp` 参数表示秒精度,取值范围为:0 ~ 6,默认值为 0。 + +```sql +TIME[(fsp)] +``` + +> **注意:** +> +> 注意 `TIME` 的缩写形式。例如,`11:12` 表示 `11:12:00` 而不是 `00:11:12`。但是,`1112` 表示 `00:11:12`。这些差异取决于 `:` 字符的存在与否。 + +### `DATETIME` 类型 + +`DATETIME` 类型是日期和时间的组合,格式为 `YYYY-MM-DD HH:MM:SS[.fraction]`。支持的范围是 `0000-01-01 00:00:00.000000` 到 `9999-12-31 23:59:59.999999`。`fsp` 参数表示秒精度,取值范围为 0~6,默认值为 0。TiDB 支持字符串或数字转换为 `DATETIME` 类型。 + +```sql +DATETIME[(fsp)] +``` + +### `TIMESTAMP` 类型 + +`TIMESTAMP` 类型是日期和时间的组合,支持的范围是 UTC 时间从 `1970-01-01 00:00:01.000000` 到 `2038-01-19 03:14:07.999999`。`fsp` 参数表示秒精度,取值范围为 0~6,默认值为 0。在 `TIMESTAMP` 中,不允许零出现在月份部分或日期部分,唯一的例外是零值本身 `0000-00-00 00:00:00`。 + +```sql +TIMESTAMP[(fsp)] +``` + +#### 时区处理 + +当存储 `TIMESTAMP` 时,TiDB 会将当前时区的 `TIMESTAMP` 值转换为 UTC 时区。当读取 `TIMESTAMP` 时,TiDB 将存储的 `TIMESTAMP` 值从 UTC 时区转换为当前时区(注意:`DATETIME` 不会这样处理)。每次连接的默认时区是服务器的本地时区,可以通过环境变量 `time_zone` 进行修改。 + +> **警告:** +> +> 和 MySQL 一样,`TIMESTAMP` 数据类型受 [2038 年问题](https://zh.wikipedia.org/wiki/2038%E5%B9%B4%E9%97%AE%E9%A2%98)的影响。如果存储的值大于 2038,建议使用 `DATETIME` 类型。 + +### `YEAR` 类型 + +`YEAR` 类型的格式为 `YYYY`,支持的值范围是 `1901` 到 `2155`,也支持零值 `0000`。 + +```sql +YEAR[(4)] +``` + +`YEAR` 类型遵循以下格式规则: + ++ 如果是四位数的数值,支持的范围是 `1901` 至 `2155`。 ++ 如果是四位数的字符串,支持的范围是 `'1901'` 到 `'2155'`。 ++ 如果是 1~99 之间的一位数或两位数的数字,1~69 换算成 2001~2069,70~99 换算成 1970~1999。 ++ 支持 `'0'` 到 `'99'` 之间的一位数或两位数字符串的范围 ++ 将数值 `0` 转换为 `0000`,将字符串 `'0'` 或 `'00'` 转换为 `'2000'`。 + +无效的 `YEAR` 值会自动转换为 `0000`(如果用户没有使用 `NO_ZERO_DATE` SQL 模式)。 + +## 自动初始化和更新 `TIMESTAMP` 或 `DATETIME` + +带有 `TIMESTAMP` 或 `DATETIME` 数据类型的列可以自动初始化为或更新为当前时间。 + +对于表中任何带有 `TIMESTAMP` 或 `DATETIME` 数据类型的列,你可以设置默认值,或自动更新为当前时间戳。 + +在定义列的时候,`TIMESTAMP` 和 `DATETIME` 可以通过 `DEFAULT CURRENT_TIMESTAMP` 和 `ON UPDATE CURRENT_TIMESTAMP` 来设置。`DEFAULT` 也可以设置为一个特定的值,例如 `DEFAULT 0` 或 `DEFAULT '2000-01-01 00:00:00'`。 + +```sql +CREATE TABLE t1 ( + ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + dt DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +); +``` + +除非指定 `DATETIME` 的值为 `NOT NULL`,否则默认 `DATETIME` 的值为 `NULL`。指定 `DATETIME` 的值为 `NOT NULL` 时,如果没有设置默认值,则默认值为 `0`。 + +```sql +CREATE TABLE t1 ( + dt1 DATETIME ON UPDATE CURRENT_TIMESTAMP, -- default NULL + dt2 DATETIME NOT NULL ON UPDATE CURRENT_TIMESTAMP -- default 0 +); +``` + +## 时间值的小数部分 + +`DATETIME` 和 `TIMESTAMP` 值最多可以有 6 位小数,精确到微秒。如果包含小数部分,值的格式为 `YYYY-MM-DD HH:MM:SS[.fraction]`,小数部分的范围为 `000000` 到`999999`。必须使用小数点分隔小数部分与其他部分。 + ++ 使用 `type_name(fsp)` 可以定义精确到小数的列,其中 `type_name` 可以是`TIME`、`DATETIME` 或 `TIMESTAMP`。例如: + + ```sql + CREATE TABLE t1 (t TIME(3), dt DATETIME(6)); + ``` + + `fsp` 范围是 `0` 到 `6`。 + + `0` 表示没有小数部分。如果省略了 `fsp`,默认为 `0`。 + ++ 当插入包含小数部分的 `TIME`、`DATETIME` 或 `TIMESTAMP` 时,如果小数部分的位数过少或过多,可能需要进行四舍五入。例如: + + ```sql + CREATE TABLE fractest( c1 TIME(2), c2 DATETIME(2), c3 TIMESTAMP(2) ); + ``` + + ```sql + Query OK, 0 rows affected (0.33 sec) + ``` + + ```sql + INSERT INTO fractest VALUES + > ('17:51:04.777', '2014-09-08 17:51:04.777', '2014-09-08 17:51:04.777'); + ``` + + ```sql + Query OK, 1 row affected (0.03 sec) + ``` + + ```sql + SELECT * FROM fractest; + ``` + + ```sql + +-------------|------------------------|------------------------+ + | c1 | c2 | c3 | + +-------------|------------------------|------------------------+ + | 17:51:04.78 | 2014-09-08 17:51:04.78 | 2014-09-08 17:51:04.78 | + +-------------|------------------------|------------------------+ + 1 row in set (0.00 sec) + ``` + +## 日期和时间类型的转换 + +在日期和时间类型之间进行转换时,有些转换可能会导致信息丢失。例如,`DATE`、`DATETIME` 和 `TIMESTAMP` 都有各自的有效值范围。`TIMESTAMP` 不能早于 UTC 时间的 1970 年,也不能晚于 UTC 时间的 `2038-01-19 03:14:07`。根据这个规则,`1968-01-01` 对于 `DATE` 或 `DATETIME` 是有效的,但当 `1968-01-01` 转换为 `TIMESTAMP` 时,就会变成 0。 + +`DATE` 的转换: + ++ 当 `DATE` 转换为 `DATETIME` 或 `TIMESTAMP` 时,会添加时间部分 `00:00:00`,因为 `DATE` 不包含任何时间信息。 ++ 当 `DATE` 转换为 `TIME` 时,结果是 `00:00:00`。 + +`DATETIME` 或 `TIMESTAMP` 的转换: + ++ 当 `DATETIME` 或 `TIMESTAMP` 转换为 `DATE` 时,时间和小数部分将被舍弃。例如,`1999-12-31 23:59:59.499` 被转换为 `1999-12-31`。 ++ 当 `DATETIME` 或 `TIMESTAMP` 转换为 `TIME` 时,日期部分被舍弃,因为 `TIME` 不包含任何日期信息。 + +如果要将 `TIME` 转换为其他时间和日期格式,日期部分会自动指定为 `CURRENT_DATE()`。最终的转换结果是由 `TIME` 和 `CURRENT_DATE()` 组成的日期。也就是说,如果 `TIME` 的值超出了 `00:00:00` 到 `23:59:59` 的范围,那么转换后的日期部分并不表示当前的日期。 + +当 `TIME` 转换为 `DATE` 时,转换过程类似,时间部分被舍弃。 + +使用 `CAST()` 函数可以显式地将值转换为 `DATE` 类型。例如: + +```sql +date_col = CAST(datetime_col AS DATE) +``` + +将 `TIME` 和 `DATETIME` 转换为数字格式。例如: + +```sql +SELECT CURTIME(), CURTIME()+0, CURTIME(3)+0; +``` + +```sql ++-----------|-------------|--------------+ +| CURTIME() | CURTIME()+0 | CURTIME(3)+0 | ++-----------|-------------|--------------+ +| 09:28:00 | 92800 | 92800.887 | ++-----------|-------------|--------------+ +``` + +```sql +SELECT NOW(), NOW()+0, NOW(3)+0; +``` + +```sql ++---------------------|----------------|--------------------+ +| NOW() | NOW()+0 | NOW(3)+0 | ++---------------------|----------------|--------------------+ +| 2012-08-15 09:28:00 | 20120815092800 | 20120815092800.889 | ++---------------------|----------------|--------------------+ +``` + +## 年份为两位数 + +如果日期中包含年份为两位数,这个年份是有歧义的,并不显式地表示实际年份。 + +对于 `DATETIME`、`DATE` 和 `TIMESTAMP` 类型,TiDB 使用如下规则来消除歧义。 + +- 将 01 至 69 之间的值转换为 2001 至 2069 之间的值。 +- 将 70 至 99 之间的值转化为 1970 至 1999 之间的值。 + +上述规则也适用于 `YEAR` 类型,但有一个例外。将数字 `00` 插入到 `YEAR(4)` 中时,结果是 0000 而不是 2000。 + +如果想让结果是 2000,需要指定值为 `2000`。 + +对于 `MIN()` 和 `MAX()` 等函数,年份为两位数时可能会得到错误的计算结果。建议年份为四位数时使用这类函数。 diff --git a/markdown-pages/zh/tidb/master/data-type-default-values.md b/markdown-pages/zh/tidb/master/data-type-default-values.md new file mode 100644 index 0000000..02afa5e --- /dev/null +++ b/markdown-pages/zh/tidb/master/data-type-default-values.md @@ -0,0 +1,66 @@ +--- +title: 数据类型的默认值 +aliases: ['/docs-cn/dev/data-type-default-values/','/docs-cn/dev/reference/sql/data-types/default-values/'] +summary: 数据类型的默认值描述了列的默认值设置规则。默认值必须是常量,对于时间类型可以使用特定函数。从 v8.0.0 开始,BLOB、TEXT 和 JSON 可以设置表达式默认值。如果列没有设置 DEFAULT,TiDB 会根据规则添加隐式默认值。对于 NOT NULL 列,根据 SQL_MODE 进行不同行为。表达式默认值是实验特性,不建议在生产环境中使用。MySQL 8.0.13 开始支持在 DEFAULT 子句中指定表达式为默认值。TiDB 支持为 BLOB、TEXT 和 JSON 数据类型分配默认值,但仅支持通过表达式来设置。 +--- + +# 数据类型的默认值 + +在一个数据类型描述中的 `DEFAULT value` 段描述了一个列的默认值。这个默认值必须是常量,不可以是一个函数或者是表达式。但是对于时间类型,可以例外的使用 `NOW`、`CURRENT_TIMESTAMP`、`LOCALTIME`、`LOCALTIMESTAMP` 等函数作为 `DATETIME` 或者 `TIMESTAMP` 的默认值。 + +从 v8.0.0 开始,[`BLOB`](/data-type-string.md#blob-类型)、[`TEXT`](/data-type-string.md#text-类型) 以及 [`JSON`](/data-type-json.md#json-类型) 可以设置[表达式默认值](#表达式默认值)。 + +如果一个列的定义中没有 `DEFAULT` 的设置。TiDB 按照如下的规则决定: + +* 如果该类型可以使用 `NULL` 作为值,那么这个列会在定义时添加隐式的默认值设置 `DEFAULT NULL`。 +* 如果该类型无法使用 `NULL` 作为值,那么这个列在定义时不会添加隐式的默认值设置。 + +对于一个设置了 `NOT NULL` 但是没有显式设置 `DEFAULT` 的列,当 `INSERT`、`REPLACE` 没有涉及到该列的值时,TiDB 根据当时的 `SQL_MODE` 进行不同的行为: + +* 如果此时是 `strict sql mode`,在事务中的语句会导致事务失败并回滚,非事务中的语句会直接报错。 +* 如果此时不是 `strict sql mode`,TiDB 会为这列赋值为列数据类型的隐式默认值。 + +此时隐式默认值的设置按照如下规则: + +* 对于数值类型,它们的默认值是 0。当有 `AUTO_INCREMENT` 参数时,默认值会按照增量情况赋予正确的值。 +* 对于除了时间戳外的日期时间类型,默认值会是该类型的“零值”。时间戳类型的默认值会是当前的时间。 +* 对于除枚举以外的字符串类型,默认值会是空字符串。对于枚举类型,默认值是枚举中的第一个值。 + +## 表达式默认值 + +> **警告:** +> +> 该特性为实验特性,不建议在生产环境中使用。该功能可能会在未事先通知的情况下发生变化或删除。如果发现 bug,请在 GitHub 上提 [issue](https://github.com/pingcap/tidb/issues) 反馈。 + +MySQL 从 8.0.13 开始支持在 `DEFAULT` 子句中指定表达式为默认值。具体可参考 [Explicit Default Handling as of MySQL 8.0.13](https://dev.mysql.com/doc/refman/8.0/en/data-type-defaults.html#data-type-defaults-explicit)。 + +TiDB 参考了该功能,支持在 `DEFAULT` 子句中指定部分表达式作为字段的默认值。从 v8.0.0 开始,TiDB 支持为 `BLOB`、`TEXT` 以及 `JSON` 数据类型分配默认值,但是默认值仅支持通过表达式来设置。以下是 `BLOB` 的示例: + +```sql +CREATE TABLE t2 (b BLOB DEFAULT (RAND())); +``` + +TiDB 支持以下表达式: + +* [`RAND()`](/functions-and-operators/numeric-functions-and-operators.md) +* [`UUID()`](/functions-and-operators/miscellaneous-functions.md) +* [`UUID_TO_BIN()`](/functions-and-operators/miscellaneous-functions.md) + +从 v8.0.0 开始,在 `DEFAULT` 子句中可以使用以下表达式来设置默认值。 + +* `UPPER(SUBSTRING_INDEX(USER(), '@', 1))` + +* `REPLACE(UPPER(UUID()), '-', '')` + +* `DATE_FORMAT` 相关表达式,具体格式如下: + + * `DATE_FORMAT(NOW(), '%Y-%m')` + * `DATE_FORMAT(NOW(), '%Y-%m-%d')` + * `DATE_FORMAT(NOW(), '%Y-%m-%d %H.%i.%s')` + * `DATE_FORMAT(NOW(), '%Y-%m-%d %H:%i:%s')` + +* `STR_TO_DATE('1980-01-01', '%Y-%m-%d')` + +> **注意:** +> +> 目前 `ADD COLUMN` 语句不支持使用表达式来设置默认值。 diff --git a/markdown-pages/zh/tidb/master/data-type-json.md b/markdown-pages/zh/tidb/master/data-type-json.md new file mode 100644 index 0000000..8bf9aaa --- /dev/null +++ b/markdown-pages/zh/tidb/master/data-type-json.md @@ -0,0 +1,103 @@ +--- +title: JSON 类型 +aliases: ['/docs-cn/dev/data-type-json/','/docs-cn/dev/reference/sql/data-types/json/'] +summary: JSON 类型存储半结构化数据,使用 Binary 格式序列化,加快查询和解析速度。JSON 字段不能创建索引,但可以对 JSON 文档中的子字段创建索引。TiDB 仅支持下推部分 JSON 函数到 TiFlash,不建议使用 BR 恢复包含 JSON 列的数据到 v6.3.0 之前的 TiDB 集群。请勿同步非标准 JSON 类型的数据。MySQL 误标记二进制类型数据为 STRING 类型,TiDB 保持正确的二进制类型。ENUM 或 SET 数据类型转换为 JSON 时,TiDB 会检查格式正确性。TiDB 支持使用 ORDER BY 对 JSON Array 或 JSON Object 进行排序。在 INSERT JSON 列时,TiDB 会将值隐式转换为 JSON。 +--- + +# JSON 类型 + +JSON 类型可以存储 JSON 这种半结构化的数据,相比于直接将 JSON 存储为字符串,它的好处在于: + +1. 使用 Binary 格式进行序列化,对 JSON 的内部字段的查询、解析加快; +2. 多了 JSON 合法性验证的步骤,只有合法的 JSON 文档才可以放入这个字段中; + +JSON 字段本身上,并不能创建索引,但是可以对 JSON 文档中的某个子字段创建索引。例如: + +```sql +CREATE TABLE city ( + id INT PRIMARY KEY, + detail JSON, + population INT AS (JSON_EXTRACT(detail, '$.population')), + index index_name (population) +); +INSERT INTO city (id,detail) VALUES (1, '{"name": "Beijing", "population": 100}'); +SELECT id FROM city WHERE population >= 100; +``` + +## 使用限制 + +- 目前 TiDB 仅支持下推部分 JSON 函数到 TiFlash。详情请参考 [TiFlash 支持下推的表达式](/tiflash/tiflash-supported-pushdown-calculations.md#支持下推的表达式)。 +- TiDB Backup & Restore(BR)在 v6.3.0 版本对 JSON 列的数据的编码进行了修改。因此不建议使用 BR 恢复包含 JSON 列的数据到 v6.3.0 之前的 TiDB 集群。 +- 请勿使用任何同步工具同步非标准 JSON 类型(例如 DATE、DATETIME、TIME 等)的数据。 + +## MySQL 兼容性 + +- 当使用二进制类型数据创建 JSON 时,目前 MySQL 会将其误标记为 STRING 类型,而 TiDB 会保持正确的二进制类型。 + + ```sql + CREATE TABLE test(a json); + INSERT INTO test SELECT json_objectagg('a', b'01010101'); + + -- 在 TiDB 中,执行以下 SQL 语句返回结果如下所示。在 MySQL 中,执行以下 SQL 语句的结果为 `0, 1`。 + mysql> SELECT JSON_EXTRACT(JSON_OBJECT('a', b'01010101'), '$.a') = "base64:type15:VQ==" AS r1, JSON_EXTRACT(a, '$.a') = "base64:type15:VQ==" AS r2 FROM test; + +------+------+ + | r1 | r2 | + +------+------+ + | 0 | 0 | + +------+------+ + 1 row in set (0.01 sec) + ``` + + 详情可见此 [issue](https://github.com/pingcap/tidb/issues/37443)。 + +- 当将 ENUM 或 SET 数据类型转换为 JSON 时,TiDB 会检查其格式正确性。例如,当执行下面的 SQL 语句时,TiDB 中会报错: + + ```sql + CREATE TABLE t(e ENUM('a')); + INSERT INTO t VALUES ('a'); + mysql> SELECT CAST(e AS JSON) FROM t; + ERROR 3140 (22032): Invalid JSON text: The document root must not be followed by other values. + ``` + + 详情可见此 [issue](https://github.com/pingcap/tidb/issues/9999)。 + +- TiDB 支持使用 `ORDER BY` 对 JSON Array 或 JSON Object 进行排序。 + + 当使用 `ORDER BY` 对 JSON Array 或 JSON Object 进行排序时,MySQL 会返回一个警告,且排序结果与比较运算结果不一致: + + ```sql + CREATE TABLE t(j JSON); + INSERT INTO t VALUES ('[1,2,3,4]'); + INSERT INTO t VALUES ('[5]'); + + mysql> SELECT j FROM t WHERE j < JSON_ARRAY(5); + +--------------+ + | j | + +--------------+ + | [1, 2, 3, 4] | + +--------------+ + 1 row in set (0.00 sec) + + -- 在 TiDB 中,执行以下 SQL 语句返回结果如下所示。在 MySQL 中,执行以下 SQL 语句会返回警告 “This version of MySQL doesn't yet support 'sorting of non-scalar JSON values'. ”,且排序结果与 `<` 比较结果不一致。 + mysql> SELECT j FROM t ORDER BY j; + +--------------+ + | j | + +--------------+ + | [1, 2, 3, 4] | + | [5] | + +--------------+ + 2 rows in set (0.00 sec) + ``` + + 详情可见此 [issue](https://github.com/pingcap/tidb/issues/37506)。 + +- 在 INSERT JSON 列时,TiDB 会将值隐式转换为 JSON: + + ```sql + CREATE TABLE t(col JSON); + + -- 在 TiDB 中,执行以下 INSERT 语句成功。在 MySQL 中,执行以下 INSERT 语句将返回 Invalid JSON text 错误。 + INSERT INTO t VALUES (3); + ``` + +有关 JSON 的更多信息,可以参考 [JSON 函数](/functions-and-operators/json-functions.md)和[生成列](/generated-columns.md)。 diff --git a/markdown-pages/zh/tidb/master/data-type-numeric.md b/markdown-pages/zh/tidb/master/data-type-numeric.md new file mode 100644 index 0000000..212bf80 --- /dev/null +++ b/markdown-pages/zh/tidb/master/data-type-numeric.md @@ -0,0 +1,183 @@ +--- +title: 数值类型 +aliases: ['/docs-cn/dev/data-type-numeric/','/docs-cn/dev/reference/sql/data-types/numeric/'] +summary: TiDB 支持 MySQL 的所有数值类型,包括整数类型、浮点类型和定点类型。整数类型包括 BIT、BOOLEAN、TINYINT、SMALLINT、MEDIUMINT、INTEGER 和 BIGINT,存储空间和取值范围各不相同。浮点类型包括 FLOAT 和 DOUBLE,存储空间分别为 4 和 8 字节。定点类型包括 DECIMAL 和 NUMERIC,可设置小数位数和小数点后位数。建议使用 DECIMAL 类型存储精确值。 +--- + +# 数值类型 + +TiDB 支持 MySQL 所有的数值类型,按照精度可以分为: + ++ [整数类型(精确值)](#整数类型) ++ [浮点类型(近似值)](#浮点类型) ++ [定点类型(精确值)](#定点类型) + +## 整数类型 + +TiDB 支持 MySQL 所有的整数类型,包括 `INTEGER`/`INT`、`TINYINT`、`SMALLINT`、`MEDIUMINT` 以及 `BIGINT`,完整信息参考[这篇](https://dev.mysql.com/doc/refman/8.0/en/integer-types.html)文档。 + +字段说明: + +| 语法元素 | 说明 | +| ---- | --------| +| M | 类型显示宽度,可选 | +| UNSIGNED | 无符号数,如果不加这个标识,则为有符号数 | +| ZEROFILL | 补零标识,如果有这个标识,TiDB 会自动给类型增加 UNSIGNED 标识,但是没有做补零的操作 | + +### 类型定义 + +#### `BIT` 类型 + +比特值类型。M 表示比特位的长度,取值范围从 1 到 64,其默认值是 1。 + +```sql +BIT[(M)] +``` + +#### `BOOLEAN` 类型 + +布尔类型,别名为 `BOOL`,和 `TINYINT(1)` 等价。零值被认为是 `False`,非零值认为是 `True`。在 TiDB 内部,`True` 存储为 `1`,`False` 存储为 `0`。 + +```sql +BOOLEAN +``` + +#### `TINYINT` 类型 + +`TINYINT` 类型。有符号数的范围是 `[-128, 127]`。无符号数的范围是 `[0, 255]`。 + +```sql +TINYINT[(M)] [UNSIGNED] [ZEROFILL] +``` + +#### `SMALLINT` 类型 + +`SMALLINT` 类型。有符号数的范围是 `[-32768, 32767]`。无符号数的范围是 `[0, 65535]`。 + +```sql +SMALLINT[(M)] [UNSIGNED] [ZEROFILL] +``` + +#### `MEDIUMINT` 类型 + +`MEDIUMINT` 类型。有符号数的范围是 `[-8388608, 8388607]`。无符号数的范围是 `[0, 16777215]`。 + +```sql +MEDIUMINT[(M)] [UNSIGNED] [ZEROFILL] +``` + +### `INTEGER` 类型 + +`INTEGER` 类型,别名 `INT`。有符号数的范围是 `[-2147483648, 2147483647]`。无符号数的范围是 `[0, 4294967295]`。 + +```sql +INT[(M)] [UNSIGNED] [ZEROFILL] +``` + +或者: + +```sql +INTEGER[(M)] [UNSIGNED] [ZEROFILL] +``` + +### `BIGINT` 类型 + +`BIGINT` 类型。有符号数的范围是 `[-9223372036854775808, 9223372036854775807]`。无符号数的范围是 `[0, 18446744073709551615]`。 + +```sql +BIGINT[(M)] [UNSIGNED] [ZEROFILL] +``` + +### 存储空间以及取值范围 + +每种类型对存储空间的需求以及最大/最小值如下表所示: + +| 类型 | 存储空间 | 最小值(有符号/无符号) | 最大值(有符号/无符号) | +| ----------- |----------|-----------------------| --------------------- | +| `TINYINT` | 1 | -128 / 0 | 127 / 255 | +| `SMALLINT` | 2 | -32768 / 0 | 32767 / 65535 | +| `MEDIUMINT` | 3 | -8388608 / 0 | 8388607 / 16777215 | +| `INT` | 4 | -2147483648 / 0 | 2147483647 / 4294967295 | +| `BIGINT` | 8 | -9223372036854775808 / 0 | 9223372036854775807 / 18446744073709551615 | + +## 浮点类型 + +TiDB 支持 MySQL 所有的浮点类型,包括 `FLOAT`、`DOUBLE`,完整信息参考[这篇](https://dev.mysql.com/doc/refman/8.0/en/floating-point-types.html)文档。 + +字段说明: + +| 语法元素 | 说明 | +| -------- | ------------------------------- | +| M | 小数总位数 | +| D | 小数点后位数 | +| UNSIGNED | 无符号数,如果不加这个标识,则为有符号数 | +| ZEROFILL | 补零标识,如果有这个标识,TiDB 会自动给类型增加 UNSIGNED 标识 | + +### 类型定义 + +#### `FLOAT` 类型 + +单精度浮点数。允许的值范围为 -2^128 ~ +2^128,也即 -3.402823466E+38 到 -1.175494351E-38、0 和 1.175494351E-38 到 3.402823466E+38。这些是基于 IEEE 标准的理论限制。实际的范围根据硬件或操作系统的不同可能稍微小些。 + +`FLOAT(p)` 类型中,`p` 表示精度(以位数表示)。只使用该值来确定是否结果列的数据类型为 `FLOAT` 或 `DOUBLE`。如果 `p` 为从 0 到 24,数据类型变为没有 M 或 D 值的 `FLOAT`。如果 `p` 为从 25 到 53,数据类型变为没有 M 或 D 值的 `DOUBLE`。结果列范围与本节前面描述的单精度 `FLOAT` 或双精度 `DOUBLE` 数据类型相同。 + +```sql +FLOAT[(M,D)] [UNSIGNED] [ZEROFILL] +FLOAT(p) [UNSIGNED] [ZEROFILL] +``` + +> **注意:** +> +> + 与在 MySQL 中一样,`FLOAT` 数据类型用于存储近似值。对于类似货币的精确值,建议使用 `DECIMAL` 类型。 +> + 在 TiDB 中,`FLOAT` 数据类型默认的精度是 8 位,这与 MySQL 不同。在 MySQL 中,`FLOAT` 数据类型默认的精度是 6 位。例如,同时往 MySQL 和 TiDB 中类型为 `FLOAT` 的列中插入数据 `123456789` 和 `1.23456789`。在 MySQL 中查询对应的值,将会得到结果 `123457000` 和 `1.23457`。而在 TiDB 中查询对应的值,将会得到 `123456790` 和 `1.2345679`。 + +#### `DOUBLE` 类型 + +双精度浮点数,别名为 `DOUBLE PRECISION`。允许的值范围为:-2^1024 ~ +2^1024,也即是 -1.7976931348623157E+308 到 -2.2250738585072014E-308、0 和 2.2250738585072014E-308 到 1.7976931348623157E+308。这些是基于 IEEE 标准的理论限制。实际的范围根据硬件或操作系统的不同可能稍微小些。 + +```sql +DOUBLE[(M,D)] [UNSIGNED] [ZEROFILL] +DOUBLE PRECISION [(M,D)] [UNSIGNED] [ZEROFILL], REAL[(M,D)] [UNSIGNED] [ZEROFILL] +``` + +> **警告:** +> +> 与在 MySQL 中一样,`DOUBLE` 数据类型存储近似值。对于货币之类的精确值,建议使用 `DECIMAL` 类型。 + +> **注意:** +> +> 当 TiDB 将用科学计数法表示的双精度浮点数转换到 `CHAR` 类型时,其结果在显示上与 MySQL 不一致,详情参见 [Cast 函数和操作符](/functions-and-operators/cast-functions-and-operators.md)。 + +### 存储空间 + +每种类型对存储空间的需求如下表所示: + +| 类型 | 存储空间 | +| ----------- |----------| +| `FLOAT` | 4 | +| `FLOAT(p)` | 如果 0 <= p <= 24 为 4 个字节,如果 25 <= p <= 53 为 8 个字节| +| `DOUBLE` | 8 | + +## 定点类型 + +TiDB 支持 MySQL 所有的定点类型,包括 `DECIMAL`、`NUMERIC`,完整信息参考[这篇](https://dev.mysql.com/doc/refman/8.0/en/fixed-point-types.html)文档。 + +字段说明: + +| 语法元素 | 说明 | +| -------- | ------------------------------- | +| M | 小数总位数 | +| D | 小数点后位数 | +| UNSIGNED | 无符号数,如果不加这个标识,则为有符号数 | +| ZEROFILL | 补零标识,如果有这个标识,TiDB 会自动给类型增加 UNSIGNED 标识 | + +### 类型定义 + +#### `DECIMAL` 类型 + +定点数,别名为 `NUMERIC`。M 是小数位数(精度)的总数,D 是小数点(标度)后面的位数。小数点和 `-`(负数)符号不包括在 M 中。如果 D 是 0,则值没有小数点或分数部分。如果 D 被省略,默认是 0。如果 M 被省略,默认是 10。 + +```sql +DECIMAL[(M[,D])] [UNSIGNED] [ZEROFILL] +NUMERIC[(M[,D])] [UNSIGNED] [ZEROFILL] +``` diff --git a/markdown-pages/zh/tidb/master/data-type-overview.md b/markdown-pages/zh/tidb/master/data-type-overview.md new file mode 100644 index 0000000..038ab9b --- /dev/null +++ b/markdown-pages/zh/tidb/master/data-type-overview.md @@ -0,0 +1,16 @@ +--- +title: 数据类型概述 +aliases: ['/docs-cn/dev/data-type-overview/','/docs-cn/dev/reference/sql/data-types/overview/'] +summary: TiDB 支持除了空间类型(SPATIAL)之外的所有 MySQL 数据类型,包括数值型类型、字符串类型、时间和日期类型、JSON 类型。数据类型定义一般为 T(M[, D]),其中 T 表示具体的类型,M 在整数类型中表示最大显示长度,在浮点数或者定点数中表示精度,在字符类型中表示最大长度,D 表示浮点数、定点数的小数位长度,fsp 在时间和日期类型里的 TIME、DATETIME 以及 TIMESTAMP 中表示秒的精度,其取值范围是 0 到 6,值为 0 表示没有小数部分,如果省略,则默认精度为 0。 +--- + +# 数据类型概述 + +TiDB 支持除空间类型 (`SPATIAL`) 之外的所有 MySQL 数据类型,包括[数值型类型](/data-type-numeric.md)、[字符串类型](/data-type-string.md)、[时间和日期类型](/data-type-date-and-time.md)、[JSON 类型](/data-type-json.md)。 + +数据类型定义一般为 `T(M[, D])`,其中: + +* `T` 表示具体的类型。 +* `M` 在整数类型中表示最大显示长度;在浮点数或者定点数中表示精度;在字符类型中表示最大长度。`M` 的最大值取决于具体的类型。 +* `D` 表示浮点数、定点数的小数位长度。 +* `fsp` 在时间和日期类型里的 `TIME`、`DATETIME` 以及 `TIMESTAMP` 中表示秒的精度,其取值范围是 0 到 6。值为 0 表示没有小数部分。如果省略,则默认精度为 0。 diff --git a/markdown-pages/zh/tidb/master/data-type-string.md b/markdown-pages/zh/tidb/master/data-type-string.md new file mode 100644 index 0000000..d2ebb8a --- /dev/null +++ b/markdown-pages/zh/tidb/master/data-type-string.md @@ -0,0 +1,179 @@ +--- +title: 字符串类型 +aliases: ['/docs-cn/dev/data-type-string/','/docs-cn/dev/reference/sql/data-types/string/'] +summary: TiDB 支持 MySQL 所有字符串类型,包括 CHAR、VARCHAR、BINARY、VARBINARY、BLOB、TEXT、ENUM 和 SET。CHAR 是定长字符串,长度固定为创建表时声明的长度。VARCHAR 是变长字符串,空间占用大小不得超过 65535 字节。TEXT 是文本串,最大列长为 65535 字节。TINYTEXT 最大列长度为 255。MEDIUMTEXT 最大列长度为 16777215。LONGTEXT 最大列长度为 4294967295。BINARY 存储二进制字符串。VARBINARY 存储二进制字符串。BLOB 是二进制大文件,最大列长度为 65535 字节。TINYBLOB 最大列长度为 255。MEDIUMBLOB 最大列长度为 16777215。LONGBLOB 最大列长度为 4294967295。ENUM 是枚举类型,值必须从固定集合中选取。SET 是集合类型,包含零个或多个值的字符串。 +--- + +# 字符串类型 + +TiDB 支持 MySQL 所有的字符串类型,包括 `CHAR`、`VARCHAR`、`BINARY`、`VARBINARY`、`BLOB`、`TEXT`、`ENUM` 以及 `SET`,完整信息参考[这篇](https://dev.mysql.com/doc/refman/8.0/en/string-types.html)文档。 + +## 类型定义 + +### `CHAR` 类型 + +定长字符串。`CHAR` 列的长度固定为创建表时声明的长度。M 表示列长度(字符的个数,不是字节的个数)。长度可以为从 0 到 255 的任何值。和 `VARCHAR` 类型不同,`CHAR` 列在写入时会对数据末尾的空格进行截断。 + +```sql +[NATIONAL] CHAR[(M)] [CHARACTER SET charset_name] [COLLATE collation_name] +``` + +### `VARCHAR` 类型 + +变长字符串。M 表示最大列长度(字符的最大个数)。`VARCHAR` 的空间占用大小不得超过 65535 字节。在选择 `VARCHAR` 长度时,应当根据最长的行的大小和使用的字符集确定。 + +对于不同的字符集,单个字符所占用的空间可能有所不同。以下表格是各个字符集下单个字符占用的字节数,以及 `VARCHAR` 列长度的取值范围: + +| 字符集 | 单个字符字节数 | VARCHAR 最大列长度的取值范围 | +| ----- | ---- | ---- | +| ascii | 1 | (0, 65535] | +| latin1 | 1 | (0, 65535] | +| binary | 1 | (0, 65535] | +| utf8 | 3 | (0, 21845] | +| utf8mb4 | 4 | (0, 16383] | + +```sql +[NATIONAL] VARCHAR(M) [CHARACTER SET charset_name] [COLLATE collation_name] +``` + +### `TEXT` 类型 + +文本串。最大列长为 65,535 字节。可选的 M 参数以字符为单位,用于自动选择 `TEXT` 列的最合适类型。例如 `TEXT(60)` 会产生一个 `TINYTEXT` 数据类型,最多可容纳 255 字节,即容纳一个 60 字符的 UTF-8 字符串,每个字符最多包含 4 字节(即 4×60=240)。不推荐使用 M 参数。 + +```sql +TEXT[(M)] [CHARACTER SET charset_name] [COLLATE collation_name] +``` + +### `TINYTEXT` 类型 + +类似于 [`TEXT`](#text-类型),区别在于最大列长度为 255。 + +```sql +TINYTEXT [CHARACTER SET charset_name] [COLLATE collation_name] +``` + +### `MEDIUMTEXT` 类型 + +类似于 [`TEXT`](#text-类型),区别在于最大列长度为 16,777,215。但由于 [`txn-entry-size-limit`](/tidb-configuration-file.md#txn-entry-size-limit-从-v50-版本开始引入) 的限制,TiDB 中默认单行存储最大不超过 6 MiB,可通过配置项将该限制调整至 120 MiB。 + +```sql +MEDIUMTEXT [CHARACTER SET charset_name] [COLLATE collation_name] +``` + +### `LONGTEXT` 类型 + +类似于 [`TEXT`](#text-类型),区别在于最大列长度为 4,294,967,295。但由于 [`txn-entry-size-limit`](/tidb-configuration-file.md#txn-entry-size-limit-从-v50-版本开始引入) 的限制,TiDB 中默认单行存储最大不超过 6 MiB,可通过配置项将该限制调整至 120 MiB。 + +```sql +LONGTEXT [CHARACTER SET charset_name] [COLLATE collation_name] +``` + +### `BINARY` 类型 + +类似于 [`CHAR`](#char-类型),区别在于 `BINARY` 存储的是二进制字符串。 + +```sql +BINARY(M) +``` + +### `VARBINARY` 类型 + +类似于 [`VARCHAR`](#varchar-类型),区别在于 `VARBINARY` 存储的是二进制字符串。 + +```sql +VARBINARY(M) +``` + +### `BLOB` 类型 + +二进制大文件。M 表示最大列长度,单位是字节,范围是 0 到 65535。 + +```sql +BLOB[(M)] +``` + +### `TINYBLOB` 类型 + +类似于 [`BLOB`](#blob-类型),区别在于最大列长度为 255。 + +```sql +TINYBLOB +``` + +### `MEDIUMBLOB` 类型 + +类似于 [`BLOB`](#blob-类型),区别在于最大列长度为 16,777,215。但由于 [`txn-entry-size-limit`](/tidb-configuration-file.md#txn-entry-size-limit-从-v50-版本开始引入) 的限制,TiDB 中默认单行存储最大不超过 6 MiB,可通过配置项将该限制调整至 120 MiB。 + +```sql +MEDIUMBLOB +``` + +### `LONGBLOB` 类型 + +类似于 [`BLOB`](#blob-类型),区别在于最大列长度为 4,294,967,295。但由于 [`txn-entry-size-limit`](/tidb-configuration-file.md#txn-entry-size-limit-从-v50-版本开始引入) 的限制,TiDB 中默认单行存储最大不超过 6 MiB,可通过配置项将该限制调整至 120 MiB。 + +```sql +LONGBLOB +``` + +### `ENUM` 类型 + +枚举类型是一个字符串,它只能有一个值的字符串对象。其值必须是从一个固定集合中选取,这个固定集合在创建表的时候定义,语法是: + +```sql +ENUM('value1','value2',...) [CHARACTER SET charset_name] [COLLATE collation_name] +``` + +例如: + +```sql +ENUM('apple', 'orange', 'pear') +``` + +枚举类型的值在 TiDB 内部使用数值来存储,每个值会按照定义的顺序转换为一个数字,比如上面的例子中,每个字符串值都会映射为一个数字: + +| 值 | 数字 | +| ---- | ---- | +| NULL | NULL | +| '' | 0 | +| 'apple' | 1 | +| 'orange' | 2 | +| 'pear' | 3 | + +更多信息参考 [MySQL 枚举文档](https://dev.mysql.com/doc/refman/8.0/en/enum.html)。 + +### `SET` 类型 + +集合类型是一个包含零个或多个值的字符串,其中每个值必须是从一个固定集合中选取,这个固定集合在创建表的时候定义,语法是: + +```sql +SET('value1','value2',...) [CHARACTER SET charset_name] [COLLATE collation_name] +``` + +例如: + +```sql +SET('1', '2') NOT NULL +``` + +上面的例子中,这列的有效值可以是: + +``` +'' +'1' +'2' +'1,2' +``` + +集合类型的值在 TiDB 内部会转换为一个 Int64 数值,每个元素是否存在用一个二进制位的 0/1 值来表示,比如这个例子 `SET('a','b','c','d')`,每一个元素都被映射为一个数字,且每个数字的二进制表示只会有一位是 1: + +| 成员 | 十进制表示 | 二进制表示 | +| ---- | ---- | ------ | +| 'a' | 1 | 0001 | +| 'b' | 2 | 0010 | +| 'c' | 4 | 0100 | +| 'd' | 8 | 1000 | + +这样对于值为 `('a', 'c')` 的元素,其二进制表示即为 0101。 + +更多信息参考 [MySQL 集合文档](https://dev.mysql.com/doc/refman/8.0/en/set.html)。 diff --git a/markdown-pages/zh/tidb/master/deploy-monitoring-services.md b/markdown-pages/zh/tidb/master/deploy-monitoring-services.md new file mode 100644 index 0000000..ae23dba --- /dev/null +++ b/markdown-pages/zh/tidb/master/deploy-monitoring-services.md @@ -0,0 +1,261 @@ +--- +title: 集群监控部署 +aliases: ['/docs-cn/dev/deploy-monitoring-services/','/docs-cn/dev/monitor-a-tidb-cluster/','/docs-cn/dev/how-to/monitor/monitor-a-cluster/'] +summary: 本文适用于手动部署 TiDB 监控报警系统的用户。假设 TiDB 的拓扑结构如下:Node1 主机 IP 为 192.168.199.113,服务包括 PD1、TiDB、node_export、Prometheus、Grafana;Node2 主机 IP 为 192.168.199.114,服务包括 PD2、node_export;Node3 主机 IP 为 192.168.199.115,服务包括 PD3、node_export;Node4 主机 IP 为 192.168.199.116,服务包括 TiKV1、node_export;Node5 主机 IP 为 192.168.199.117,服务包括 TiKV2、node_export;Node6 主机 IP 为 192.168.199.118,服务包括 TiKV3、node_export。具体部署步骤包括下载二进制包、启动 node_exporter 服务、启动 Prometheus 服务、启动 Grafana 服务、配置 Grafana 数据源和导入 Grafana 面板。可查看 TiDB Server、PD Server 和 TiKV Server 的监控信息。 +--- + +# TiDB 集群监控部署 + +本文档适用于希望手动部署 TiDB 监控报警系统的用户。TiUP 部署方式,会同时自动部署监控报警系统,无需手动部署。 + +## 部署 Prometheus 和 Grafana + +假设 TiDB 的拓扑结构如下: + +| 节点 | 主机 IP | 服务 | +| :-- | :-- | :-------------- | +| Node1 | 192.168.199.113| PD1, TiDB, node_export, Prometheus, Grafana | +| Node2 | 192.168.199.114| PD2, node_export | +| Node3 | 192.168.199.115| PD3, node_export | +| Node4 | 192.168.199.116| TiKV1, node_export | +| Node5 | 192.168.199.117| TiKV2, node_export | +| Node6 | 192.168.199.118| TiKV3, node_export | + +### 第 1 步:下载二进制包 + +下载二进制包: + +```bash +wget https://download.pingcap.org/prometheus-2.27.1.linux-amd64.tar.gz +wget https://download.pingcap.org/node_exporter-v1.3.1-linux-amd64.tar.gz +wget https://download.pingcap.org/grafana-7.5.11.linux-amd64.tar.gz +``` + +解压二进制包: + +```bash +tar -xzf prometheus-2.27.1.linux-amd64.tar.gz +tar -xzf node_exporter-v1.3.1-linux-amd64.tar.gz +tar -xzf grafana-7.5.11.linux-amd64.tar.gz +``` + +### 第 2 步:在 Node1,Node2,Node3,Node4 上启动 `node_exporter` + +```bash +cd node_exporter-v1.3.1-linux-amd64 +``` + +启动 node_exporter 服务: + +```bash +./node_exporter --web.listen-address=":9100" \ + --log.level="info" & +``` + +### 第 3 步:在 Node1 上启动 Prometheus + +编辑 Prometheus 的配置文件: + +```bash +cd prometheus-2.27.1.linux-amd64 && +vi prometheus.yml +``` + +```ini +... + +global: + scrape_interval: 15s + evaluation_interval: 15s + # scrape_timeout 设置为全局默认值 (10s) + external_labels: + cluster: 'test-cluster' + monitor: "prometheus" + +scrape_configs: + - job_name: 'overwritten-nodes' + honor_labels: true # 不要覆盖 job 和实例的 label + static_configs: + - targets: + - '192.168.199.113:9100' + - '192.168.199.114:9100' + - '192.168.199.115:9100' + - '192.168.199.116:9100' + - '192.168.199.117:9100' + - '192.168.199.118:9100' + + - job_name: 'tidb' + honor_labels: true # 不要覆盖 job 和实例的 label + static_configs: + - targets: + - '192.168.199.113:10080' + + - job_name: 'pd' + honor_labels: true # 不要覆盖 job 和实例的 label + static_configs: + - targets: + - '192.168.199.113:2379' + - '192.168.199.114:2379' + - '192.168.199.115:2379' + + - job_name: 'tikv' + honor_labels: true # 不要覆盖 job 和实例的 label + static_configs: + - targets: + - '192.168.199.116:20180' + - '192.168.199.117:20180' + - '192.168.199.118:20180' + +... +``` + +启动 Prometheus 服务: + +```bash +./prometheus \ + --config.file="./prometheus.yml" \ + --web.listen-address=":9090" \ + --web.external-url="http://192.168.199.113:9090/" \ + --web.enable-admin-api \ + --log.level="info" \ + --storage.tsdb.path="./data.metrics" \ + --storage.tsdb.retention="15d" & +``` + +### 第 4 步:在 Node1 上启动 Grafana + +编辑 Grafana 的配置文件: + +```bash +cd grafana-7.5.11 && +vi conf/grafana.ini +``` + +```ini +... + +[paths] +data = ./data +logs = ./data/log +plugins = ./data/plugins +[server] +http_port = 3000 +domain = 192.168.199.113 +[database] +[session] +[analytics] +check_for_updates = true +[security] +admin_user = admin +admin_password = admin +[snapshots] +[users] +[auth.anonymous] +[auth.basic] +[auth.ldap] +[smtp] +[emails] +[log] +mode = file +[log.console] +[log.file] +level = info +format = text +[log.syslog] +[event_publisher] +[dashboards.json] +enabled = false +path = ./data/dashboards +[metrics] +[grafana_net] +url = https://grafana.net + +... + +``` + +启动 Grafana 服务: + +```bash +./bin/grafana-server \ + --config="./conf/grafana.ini" & +``` + +## 配置 Grafana + +本小节介绍如何配置 Grafana。 + +### 第 1 步:添加 Prometheus 数据源 + +1. 登录 Grafana 界面。 + + - 默认地址:`http://localhost:3000` + - 默认账户:admin + - 默认密码:admin + + > **注意:** + > + > **Change Password** 步骤可以选择 **Skip**。 + +2. 点击 Grafana 侧边栏菜单 **Configuration** 中的 **Data Source**。 + +3. 点击 **Add data source**。 + +4. 指定数据源的相关信息: + + - 在 **Name** 处,为数据源指定一个名称。 + - 在 **Type** 处,选择 **Prometheus**。 + - 在 **URL** 处,指定 Prometheus 的 IP 地址。 + - 根据需求指定其它字段。 + +5. 点击 **Add** 保存新的数据源。 + +### 第 2 步:导入 Grafana 面板 + +执行以下步骤,为 PD Server、TiKV Server 和 TiDB Server 分别导入 Grafana 面板: + +1. 点击侧边栏的 Grafana 图标。 + +2. 在侧边栏菜单中,依次点击 **Dashboards** > **Import** 打开 **Import Dashboard** 窗口。 + +3. 点击 **Upload .json File** 上传对应的 JSON 文件(从 [pingcap/tidb](https://github.com/pingcap/tidb/tree/master/pkg/metrics/grafana)、[tikv/tikv](https://github.com/tikv/tikv/tree/master/metrics/grafana) 和 [tikv/pd](https://github.com/tikv/pd/tree/master/metrics/grafana) 下载 TiDB Grafana 配置文件)。 + + > **注意:** + > + > TiKV、PD 和 TiDB 面板对应的 JSON 文件分别为 `tikv_summary.json`,`tikv_details.json`,`tikv_trouble_shooting.json`,`pd.json`,`tidb.json`,`tidb_summary.json`。 + +4. 点击 **Load**。 + +5. 选择一个 Prometheus 数据源。 + +6. 点击 **Import**,Prometheus 面板即导入成功。 + +## 查看组件 metrics + +在顶部菜单中,点击 **New dashboard**,选择要查看的面板。 + +![view dashboard](/media/view-dashboard.png) + +可查看以下集群组件信息: + ++ **TiDB Server:** + + query 处理时间,可以看到延迟和吞吐 + + ddl 过程监控 + + TiKV client 相关的监控 + + PD client 相关的监控 + ++ **PD Server:** + + 命令执行的总次数 + + 某个命令执行失败的总次数 + + 某个命令执行成功的耗时统计 + + 某个命令执行失败的耗时统计 + + 某个命令执行完成并返回结果的耗时统计 + ++ **TiKV Server:** + + GC 监控 + + 执行 KV 命令的总次数 + + Scheduler 执行命令的耗时统计 + + Raft propose 命令的总次数 + + Raft 执行命令的耗时统计 + + Raft 执行命令失败的总次数 + + Raft 处理 ready 状态的总次数 diff --git a/markdown-pages/zh/tidb/master/develop/dev-guide-playground-gitpod.md b/markdown-pages/zh/tidb/master/develop/dev-guide-playground-gitpod.md new file mode 100644 index 0000000..e6ed35e --- /dev/null +++ b/markdown-pages/zh/tidb/master/develop/dev-guide-playground-gitpod.md @@ -0,0 +1,168 @@ +--- +title: Gitpod +summary: Gitpod 是一个开源 Kubernetes 应用程序,可在浏览器中获得完整的开发环境,并立即编写代码。它能够为云中的每个任务提供全新的自动化开发环境,无需本地配置。Gitpod 提供了完整的、自动化的、预配置的云原生开发环境,让你可以直接在浏览器中开发、运行、测试代码。 +--- + + + +# Gitpod + +使用 [Gitpod](https://www.gitpod.io/),只需单击一个按钮或链接即可在浏览器中获得完整的开发环境,并且可以立即编写代码。 + +Gitpod 是一个开源 Kubernetes 应用程序(GitHub 仓库地址 ),适用于可直接编写代码的开发环境,可为云中的每个任务提供全新的自动化开发环境,非常迅速。此外,Gitpod 能够将你的开发环境描述为代码,并直接从你的浏览器或桌面 IDE 启动即时、远程和基于云的开发环境。 + +## 快速开始 + +1. Fork 出 TiDB 应用开发的示例代码仓库 [pingcap-inc/tidb-example-java](https://github.com/pingcap-inc/tidb-example-java)。 + +2. 通过浏览器的地址栏,在示例代码仓库的 URL 前加上 `https://gitpod.io/#` 来启动你的 gitpod 工作区。 + + - 例如,`https://gitpod.io/#https://github.com/pingcap-inc/tidb-example-java`。 + + - 支持在 URL 中配置环境变量。例如,`https://gitpod.io/#targetFile=spring-jpa-hibernate_Makefile,targetMode=spring-jpa-hibernate/https://github.com/pingcap-inc/tidb-example-java`。 + +3. 使用列出的提供商之一登录并启动工作区,例如,`Github`。 + +## 使用默认的 Gitpod 配置和环境 + +完成[快速开始](#快速开始) 的步骤之后,Gitpod 会需要一段时间来设置你的工作区。 + +以 [Spring Boot Web](/develop/dev-guide-sample-application-java-spring-boot.md) 应用程序为例,通过 URL `https://gitpod.io/#targetFile=spring-jpa-hibernate_Makefile,targetMode=spring-jpa-hibernate/https://github.com/pingcap-inc/tidb-example-java` 可以创建一个新工作区。 + +完成后,你将看到如下所示的页面。 + +![playground gitpod workspace init](/media/develop/playground-gitpod-workspace-init.png) + +页面中的这个场景使用了 [TiUP](https://docs.pingcap.com/zh/tidb/stable/tiup-overview) 来搭建一个 TiDB Playground。你可以在终端的左侧查看进度。 + +一旦 TiDB Playground 准备就绪,另一个 `Spring JPA Hibernate` 任务将运行。 你可以在终端的右侧查看进度。 + +完成所有任务后,你可以看到如下所示的页面,并在左侧导航栏的 `REMOTE EXPLORER` 中找到你的端口 `8080` URL(Gitpod 支持基于 URL 的端口转发)。 + +![playground gitpod workspace ready](/media/develop/playground-gitpod-workspace-ready.png) + +## 使用自定义的 Gitpod 配置和 Docker 镜像 + +### 自定义 Gitpod 配置 + +在项目的根目录中,参考[示例 .gitpod.yml](https://github.com/pingcap-inc/tidb-example-java/blob/main/.gitpod.yml),创建一个 `.gitpod.yml` 文件用于配置 Gitpod 工作空间。 + +```yml +# This configuration file was automatically generated by Gitpod. +# Please adjust to your needs (see https://www.gitpod.io/docs/config-gitpod-file) +# and commit this file to your remote git repository to share the goodness with others. + +# image: +# file: .gitpod.Dockerfile + +tasks: + - name: Open Target File + command: | + if [ -n "$targetFile" ]; then code ${targetFile//[_]//}; fi + - name: TiUP init playground + command: | + $HOME/.tiup/bin/tiup playground + - name: Test Case + openMode: split-right + init: echo "*** Waiting for TiUP Playground Ready! ***" + command: | + gp await-port 3930 + if [ "$targetMode" == "plain-java-jdbc" ] + then + cd plain-java-jdbc + code src/main/resources/dbinit.sql + code src/main/java/com/pingcap/JDBCExample.java + make mysql + elif [ "$targetMode" == "plain-java-hibernate" ] + then + cd plain-java-hibernate + make + elif [ "$targetMode" == "spring-jpa-hibernate" ] + then + cd spring-jpa-hibernate + make + fi +ports: + - port: 8080 + visibility: public + - port: 4000 + visibility: public + - port: 2379-36663 + onOpen: ignore +``` + +### 自定义 Gitpod Docker 镜像 + +默认情况下,Gitpod 使用名为 Workspace-Full 的标准 Docker 镜像作为工作空间的基础。 基于此默认镜像启动的工作区预装了 Docker、Go、Java、Node.js、C/C++、Python、Ruby、Rust、PHP 以及 Homebrew、Tailscale、Nginx 等工具。 + +你可以提供公共 Docker 镜像或 Dockerfile。 并为你的项目安装所需的任何依赖项。 + +这是一个 Dockerfile 示例:[示例 .gitpod.Dockerfile](https://github.com/pingcap-inc/tidb-example-java/blob/main/.gitpod.Dockerfile) + +```dockerfile +FROM gitpod/workspace-java-17 + +RUN sudo apt install mysql-client -y +RUN curl --proto '=https' --tlsv1.2 -sSf https://tiup-mirrors.pingcap.com/install.sh | sh +``` + +然后需要更新`.gitpod.yml`: + +```yml +# This configuration file was automatically generated by Gitpod. +# Please adjust to your needs (see https://www.gitpod.io/docs/config-gitpod-file) +# and commit this file to your remote git repository to share the goodness with others. + +image: + # 在这里导入你的 Dockerfile + file: .gitpod.Dockerfile + +tasks: + - name: Open Target File + command: | + if [ -n "$targetFile" ]; then code ${targetFile//[_]//}; fi + - name: TiUP init playground + command: | + $HOME/.tiup/bin/tiup playground + - name: Test Case + openMode: split-right + init: echo "*** Waiting for TiUP Playground Ready! ***" + command: | + gp await-port 3930 + if [ "$targetMode" == "plain-java-jdbc" ] + then + cd plain-java-jdbc + code src/main/resources/dbinit.sql + code src/main/java/com/pingcap/JDBCExample.java + make mysql + elif [ "$targetMode" == "plain-java-hibernate" ] + then + cd plain-java-hibernate + make + elif [ "$targetMode" == "spring-jpa-hibernate" ] + then + cd spring-jpa-hibernate + make + fi +ports: + - port: 8080 + visibility: public + - port: 4000 + visibility: public + - port: 2379-36663 + onOpen: ignore +``` + +### 应用更改 + +完成对 `.gitpod.yml` 文件配置后,请保证最新的代码已在你对应的 GitHub 代码仓库中可用。 + +访问 `https://gitpod.io/#` 以建立新的 Gitpod 工作区,新工作区会应用最新的代码。 + +访问 `https://gitpod.io/workspaces` 以获取所有建立的工作区。 + +## 总结 + +Gitpod 提供了完整的、自动化的、预配置的云原生开发环境。无需本地配置,你可以直接在浏览器中开发、运行、测试代码。 + +![playground gitpod summary](/media/develop/playground-gitpod-summary.png) diff --git a/markdown-pages/zh/tidb/master/develop/dev-guide-third-party-support.md b/markdown-pages/zh/tidb/master/develop/dev-guide-third-party-support.md new file mode 100644 index 0000000..2a908c9 --- /dev/null +++ b/markdown-pages/zh/tidb/master/develop/dev-guide-third-party-support.md @@ -0,0 +1,192 @@ +--- +title: TiDB 支持的第三方工具 +aliases: ['/zh/tidb/dev/supported-by-pingcap'] +summary: TiDB 支持的第三方工具主要包括驱动、ORM 框架和 GUI。支持等级分为 Full 和 Compatible,其中 Full 表示绝大多数功能兼容性已得到支持,Compatible 表示大部分功能可使用但未经完整验证。对于支持的 Driver 或 ORM 框架并不包括应用端事务重试和错误处理。如果在使用工具连接 TiDB 时出现问题,可在 GitHub 上提交包含详细信息的 issue 以获得进展。 +--- + +# TiDB 支持的第三方工具 + +> **注意:** +> +> 本文档仅列举了常见的 TiDB 支持的[第三方工具](https://en.wikipedia.org/wiki/Third-party_source),未被列入其中的第三方工具并非代表不支持,但 PingCAP 无法了解其是否使用到 TiDB 不支持的特性,从而无法保证兼容性。 + +TiDB [高度兼容 MySQL 协议](/mysql-compatibility.md),使得大部分适配 MySQL 的 Driver、ORM 及其他工具与 TiDB 兼容。本文主要介绍这些工具和它们的支持等级。 + +## 支持等级 + +PingCAP 与开源社区合作,通过三方工具提供以下支持: + +- Full:表明 PingCAP 已经支持该工具的绝大多数功能兼容性,并且在新版本中对其保持兼容,将定期地对下表中记录的新版本进行兼容性测试。 +- Compatible:表明由于该工具已适配 MySQL,而 TiDB 高度兼容 MySQL 协议,因此可以使用此工具的大部分功能。但 PingCAP 并未对该工具作出完整的兼容性验证,有可能出现一些意外的行为。 + +> **注意:** +> +> 除非明确说明,否则对于支持的 Driver 或者 ORM 框架并不包括[应用端事务重试和错误处理](/develop/dev-guide-transaction-troubleshoot.md#应用端重试和错误处理)。 + +如果在使用本文列出的工具连接 TiDB 时出现问题,请在 GitHub 上提交包含详细信息的 [issue](https://github.com/pingcap/tidb/issues/new?assignees=&labels=type%2Fquestion&template=general-question.md),以帮助在此工具的支持上得到进展。 + +## Driver + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
编程语言驱动最新已测试版本支持等级TiDB 适配器教程
GoGo-MySQL-Driverv1.6.0FullN/A使用 Go-MySQL-Driver 连接到 TiDB
JavaJDBC8.0Full + + 使用 JDBC 连接到 TiDB
+ +## ORM + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
编程语言ORM 框架最新已测试版本支持等级TiDB 适配器教程
Gogormv1.23.5FullN/A使用 GORM 连接到 TiDB
beegov2.0.3FullN/AN/A
upper/dbv4.5.2FullN/AN/A
xormv1.3.1FullN/AN/A
JavaHibernate6.1.0.FinalFullN/A使用 Hibernate 连接到 TiDB
MyBatisv3.5.10FullN/A使用 MyBatis 连接到 TiDB
Spring Data JPA2.7.2FullN/A使用 Spring Boot 连接到 TiDB
jOOQv3.16.7 (Open Source)FullN/AN/A
RubyActive Recordv7.0FullN/A使用 Rails 框架和 ActiveRecord ORM 连接到 TiDB
JavaScript / TypeScriptSequelizev6.20.1FullN/AN/A
Prisma4.16.2FullN/A使用 Prisma 连接到 TiDB
TypeORMv0.3.17FullN/A使用 TypeORM 连接到 TiDB
PythonDjangov4.2Fulldjango-tidb使用 Django 连接到 TiDB
SQLAlchemyv1.4.37FullN/A使用 SQLAlchemy 连接到 TiDB
+ +## GUI + +| GUI | 最新已测试版本 | 支持等级 | 教程 | +|-----------------------------------------------------------|-----------------------|---------------|-----| +| [JetBrains DataGrip](https://www.jetbrains.com/datagrip/) | 2023.2.1 | Full | N/A | +| [DBeaver](https://dbeaver.io/) | 23.0.3 | Full | N/A | +| [Visual Studio Code](https://code.visualstudio.com/) | 1.72.0 | Full | N/A | \ No newline at end of file diff --git a/markdown-pages/zh/tidb/master/dm/deploy-a-dm-cluster-using-binary.md b/markdown-pages/zh/tidb/master/dm/deploy-a-dm-cluster-using-binary.md new file mode 100644 index 0000000..8eb379b --- /dev/null +++ b/markdown-pages/zh/tidb/master/dm/deploy-a-dm-cluster-using-binary.md @@ -0,0 +1,200 @@ +--- +title: 使用 DM binary 部署 DM 集群 +aliases: ['/docs-cn/tidb-data-migration/dev/deploy-a-dm-cluster-using-binary/'] +summary: 本文介绍了如何使用 DM binary 快速部署 DM 集群。首先需要下载 DM 安装包,然后在五台服务器上部署两个 DM-worker 实例和三个 DM-master 实例。对于 DM-master 的部署,可以使用命令行参数或配置文件两种方式。而对于 DM-worker 的部署,也可以使用命令行参数或配置文件两种方式。部署完成后,需要确保各组件间端口可正常连通。 +--- + +# 使用 DM binary 部署 DM 集群 + +本文将介绍如何使用 DM binary 快速部署 DM 集群。 + +> **注意:** +> +> 对于生产环境,推荐[使用 TiUP 部署 DM 集群及相关监控组件](/dm/deploy-a-dm-cluster-using-tiup.md)。 + +## 下载 DM 安装包 + +DM 安装包位于 TiDB 离线工具包中。下载方式,请参考 [TiDB 工具下载](/download-ecosystem-tools.md)。 + +## 使用样例 + +假设在五台服务器上部署两个 DM-worker 实例和三个 DM-master 实例。各个节点的信息如下: + +| 实例 | 服务器地址 | 端口 | +| :---------- | :----------- | :-- | +| DM-master1 | 192.168.0.4 | 8261 | +| DM-master2 | 192.168.0.5 | 8261 | +| DM-master3 | 192.168.0.6 | 8261 | +| DM-worker1 | 192.168.0.7 | 8262 | +| DM-worker2 | 192.168.0.8 | 8262 | + +下面以此为例,说明如何部署 DM。 + +> **注意:** +> +> - 在单机部署多个 DM-master 或 DM-worker 时,需要确保每个实例的端口以及运行命令的当前目录各不相同。 +> +> - 如果不需要确保 DM 集群高可用,则可只部署 1 个 DM-master 节点,且部署的 DM-worker 节点数量不少于上游待迁移的 MySQL/MariaDB 实例数。 +> +> - 如果需要确保 DM 集群高可用,则推荐部署 3 个 DM-master 节点,且部署的 DM-worker 节点数量大于上游待迁移的 MySQL/MariaDB 实例数(如 DM-worker 节点数量比上游实例数多 2 个)。 +> +> - 需要确保以下组件间端口可正常连通: +> +> - 各 DM-master 节点间的 `8291` 端口可互相连通。 +> +> - 各 DM-master 节点可连通所有 DM-worker 节点的 `8262` 端口。 +> +> - 各 DM-worker 节点可连通所有 DM-master 节点的 `8261` 端口。 + +### 部署 DM-master + +DM-master 提供[命令行参数](#使用命令行参数部署-dm-master)和[配置文件](#使用配置文件部署-dm-master)两种配置方式。 + +#### 使用命令行参数部署 DM-master + +DM-master 的命令行参数说明: + +```bash +./dm-master --help +``` + +``` +Usage of dm-master: + -L string + log level: debug, info, warn, error, fatal (default "info") + -V prints version and exit + -advertise-addr string + advertise address for client traffic (default "${master-addr}") + -advertise-peer-urls string + advertise URLs for peer traffic (default "${peer-urls}") + -config string + path to config file + -data-dir string + path to the data directory (default "default.${name}") + -initial-cluster string + initial cluster configuration for bootstrapping, e.g. dm-master=http://127.0.0.1:8291 + -join string + join to an existing cluster (usage: cluster's "${master-addr}" list, e.g. "127.0.0.1:8261,127.0.0.1:18261" + -log-file string + log file path + -master-addr string + master API server and status addr + -name string + human-readable name for this DM-master member + -peer-urls string + URLs for peer traffic (default "http://127.0.0.1:8291") + -print-sample-config + print sample config file of dm-worker +``` + +> **注意:** +> +> 某些情况下,无法使用命令行参数来配置 DM-master,因为有的配置并未暴露给命令行。 + +#### 使用配置文件部署 DM-master + +推荐使用配置文件,把以下配置文件内容写入到 `conf/dm-master1.toml` 中。 + +DM-master 的配置文件: + +```toml +# Master Configuration. + +name = "master1" + +# 日志配置 +log-level = "info" +log-file = "dm-master.log" + +# DM-master 监听地址 +master-addr = "192.168.0.4:8261" + +# DM-master 节点的对等 URL +peer-urls = "192.168.0.4:8291" + +# 初始集群中所有 DM-master 的 advertise-peer-urls 的值 +initial-cluster = "master1=http://192.168.0.4:8291,master2=http://192.168.0.5:8291,master3=http://192.168.0.6:8291" +``` + +在终端中使用下面的命令运行 DM-master: + +> **注意:** +> +> 执行该命令后控制台不会输出日志,可以通过 `tail -f dm-master.log` 查看运行日志。 + +```bash +./dm-master -config conf/dm-master1.toml +``` + +对于 DM-master2 和 DM-master3,修改配置文件中的 `name` 为 `master2` 和 `master3`,并将 `peer-urls` 的值改为 `192.168.0.5:8291` 和 `192.168.0.6:8291` 即可。 + +### 部署 DM-worker + +DM-worker 提供[命令行参数](#使用命令行参数部署-dm-worker)和[配置文件](#使用配置文件部署-dm-worker)两种配置方式。 + +#### 使用命令行参数部署 DM-worker + +查看 DM-worker 的命令行参数说明: + +```bash +./dm-worker --help +``` + +``` +Usage of worker: + -L string + log level: debug, info, warn, error, fatal (default "info") + -V prints version and exit + -advertise-addr string + advertise address for client traffic (default "${worker-addr}") + -config string + path to config file + -join string + join to an existing cluster (usage: dm-master cluster's "${master-addr}") + -keepalive-ttl int + dm-worker's TTL for keepalive with etcd (in seconds) (default 10) + -log-file string + log file path + -name string + human-readable name for DM-worker member + -print-sample-config + print sample config file of dm-worker + -worker-addr string + listen address for client traffic +``` + +> **注意:** +> +> 某些情况下,无法使用命令行参数的方法来配置 DM-worker,因为有的配置并未暴露给命令行。 + +#### 使用配置文件部署 DM-worker + +推荐使用配置文件来配置 DM-worker,把以下配置文件内容写入到 `conf/dm-worker1.toml` 中。 + +DM-worker 的配置文件: + +```toml +# Worker Configuration. + +name = "worker1" + +# 日志配置 +log-level = "info" +log-file = "dm-worker.log" + +# DM-worker 的地址 +worker-addr = ":8262" + +# 对应集群中 DM-master 配置中的 master-addr +join = "192.168.0.4:8261,192.168.0.5:8261,192.168.0.6:8261" +``` + +在终端中使用下面的命令运行 DM-worker: + +```bash +./dm-worker -config conf/dm-worker1.toml +``` + +对于 DM-worker2,修改配置文件中的 `name` 为 `worker2` 即可。 + +这样,DM 集群就部署成功了。 diff --git a/markdown-pages/zh/tidb/master/dm/dm-arch.md b/markdown-pages/zh/tidb/master/dm/dm-arch.md new file mode 100644 index 0000000..7f369a7 --- /dev/null +++ b/markdown-pages/zh/tidb/master/dm/dm-arch.md @@ -0,0 +1,48 @@ +--- +title: Data Migration 架构 +summary: Data Migration 架构包括三个组件:DM-master,DM-worker 和 dmctl。DM-master 负责管理和调度数据迁移任务的各项操作。DM-worker 执行具体的数据迁移任务。dmctl 是用来控制 DM 集群的命令行工具。 DM 集群的拓扑信息、数据迁移任务的运行状态和管理统一入口都由 DM-master 负责。DM-worker 负责持久化保存 binlog 数据、保存数据迁移子任务的配置信息和监控数据迁移子任务的运行状态。dmctl 用来创建、更新或删除数据迁移任务、查看数据迁移任务状态、处理数据迁移任务错误和校验数据迁移任务配置的正确性。 Data Migration 高可用机制可以进一步探索。 +--- + +# Data Migration 架构 + +DM 主要包括三个组件:DM-master,DM-worker 和 dmctl。 + +![Data Migration architecture](/media/dm/dm-architecture-2.0.png) + +## 架构组件 + +### DM-master + +DM-master 负责管理和调度数据迁移任务的各项操作。 + +- 保存 DM 集群的拓扑信息 +- 监控 DM-worker 进程的运行状态 +- 监控数据迁移任务的运行状态 +- 提供数据迁移任务管理的统一入口 +- 协调分库分表场景下各个实例分表的 DDL 迁移 + +### DM-worker + +DM-worker 负责执行具体的数据迁移任务。 + +- 将 binlog 数据持久化保存在本地 +- 保存数据迁移子任务的配置信息 +- 编排数据迁移子任务的运行 +- 监控数据迁移子任务的运行状态 + +有关于 DM-worker 的更多介绍,详见 [DM-worker 简介](/dm/dm-worker-intro.md)。 + +### dmctl + +dmctl 是用来控制 DM 集群的命令行工具。 + +- 创建、更新或删除数据迁移任务 +- 查看数据迁移任务状态 +- 处理数据迁移任务错误 +- 校验数据迁移任务配置的正确性 + +有关于 dmctl 的使用介绍,详见 [dmctl 使用](/dm/dmctl-introduction.md)。 + +## 探索更多 + +- [Data Migration 高可用机制](/dm/dm-high-availability.md) \ No newline at end of file diff --git a/markdown-pages/zh/tidb/master/dm/dm-config-overview.md b/markdown-pages/zh/tidb/master/dm/dm-config-overview.md new file mode 100644 index 0000000..404de13 --- /dev/null +++ b/markdown-pages/zh/tidb/master/dm/dm-config-overview.md @@ -0,0 +1,35 @@ +--- +title: DM 配置简介 +aliases: ['/docs-cn/tidb-data-migration/dev/config-overview/'] +summary: 本文简要介绍了 DM(数据迁移)的配置文件和数据迁移任务的配置。配置文件包括 dm-master.toml、dm-worker.toml 和 source.yaml,分别用于配置 DM-master 进程、DM-worker 进程和上游数据库 MySQL/MariaDB。创建数据迁移任务的具体步骤包括使用 dmctl 加载数据源配置、参考数据任务配置向导创建 your_task.yaml 文件,以及使用 dmctl 创建数据迁移任务。关键概念包括 source-id、DM-master ID 和 DM-worker ID,分别用于唯一确定 MySQL 或 MariaDB 实例、DM-master 和 DM-worker。 +--- + +# DM 配置简介 + +本文档简要介绍 DM (Data Migration) 的配置文件和数据迁移任务的配置。 + +## 配置文件 + +- `dm-master.toml`:DM-master 进程的配置文件,包括 DM-master 的拓扑信息、日志等各项配置。配置说明详见 [DM-master 配置文件介绍](/dm/dm-master-configuration-file.md)。 +- `dm-worker.toml`:DM-worker 进程的配置文件,包括 DM-worker 的拓扑信息、日志等各项配置。配置说明详见 [DM-worker 配置文件介绍](/dm/dm-worker-configuration-file.md)。 +- `source.yaml`:上游数据库 MySQL/MariaDB 相关配置。配置说明详见[上游数据库配置文件介绍](/dm/dm-source-configuration-file.md)。 + +## 迁移任务配置 + +### 创建数据迁移任务 + +具体步骤如下: + +1. [使用 dmctl 将数据源配置加载到 DM 集群](/dm/dm-manage-source.md#数据源操作); +2. 参考[数据任务配置向导](/dm/dm-task-configuration-guide.md)来创建 `your_task.yaml`; +3. [使用 dmctl 创建数据迁移任务](/dm/dm-create-task.md)。 + +### 关键概念 + +DM 配置的关键概念如下: + +| 概念 | 解释 | 配置文件 | +| :------------ | :------------ | :------------------ | +| source-id | 唯一确定一个 MySQL 或 MariaDB 实例,或者一个具有主从结构的复制组,字符串长度不大于 32 | `source.yaml` 的 `source-id`;
`task.yaml` 的 `source-id` | +| DM-master ID | 唯一确定一个 DM-master(取值于 `dm-master.toml` 的 `master-addr` 参数) | `dm-master.toml` 的 `master-addr` | +| DM-worker ID | 唯一确定一个 DM-worker(取值于 `dm-worker.toml` 的 `worker-addr` 参数) | `dm-worker.toml` 的 `worker-addr` | diff --git a/markdown-pages/zh/tidb/master/dm/dm-ddl-compatible.md b/markdown-pages/zh/tidb/master/dm/dm-ddl-compatible.md new file mode 100644 index 0000000..2684525 --- /dev/null +++ b/markdown-pages/zh/tidb/master/dm/dm-ddl-compatible.md @@ -0,0 +1,143 @@ +--- +title: Data Migration DDL 特殊处理说明 +summary: 数据迁移中,根据不同的 DDL 语句和场景,采用不同处理方式。DM 不支持的 DDL 语句会直接跳过。部分 DDL 语句在同步到下游前会进行改写。在合库合表迁移任务中,DDL 同步行为存在变更。Online DDL 特性也会对 DDL 事件进行特殊处理。 +--- + +# Data Migration DDL 特殊处理说明 + +DM 同步过程中,根据 DDL 语句以及所处场景的不同,将采用不同的处理方式。 + +## 忽略的 DDL 语句 + +以下语句 DM 并未支持,因此解析之后直接跳过。 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
描述SQL
transaction^SAVEPOINT
skip all flush sqls^FLUSH
table maintenance^OPTIMIZE\\s+TABLE
^ANALYZE\\s+TABLE
^REPAIR\\s+TABLE
temporary table^DROP\\s+(\\/\\*\\!40005\\s+)?TEMPORARY\\s+(\\*\\/\\s+)?TABLE
trigger^CREATE\\s+(DEFINER\\s?=.+?)?TRIGGER
^DROP\\s+TRIGGER
procedure^DROP\\s+PROCEDURE
^CREATE\\s+(DEFINER\\s?=.+?)?PROCEDURE
^ALTER\\s+PROCEDURE
view^CREATE\\s*(OR REPLACE)?\\s+(ALGORITHM\\s?=.+?)?(DEFINER\\s?=.+?)?\\s+(SQL SECURITY DEFINER)?VIEW
^DROP\\s+VIEW
^ALTER\\s+(ALGORITHM\\s?=.+?)?(DEFINER\\s?=.+?)?(SQL SECURITY DEFINER)?VIEW
function^CREATE\\s+(AGGREGATE)?\\s*?FUNCTION
^CREATE\\s+(DEFINER\\s?=.+?)?FUNCTION
^ALTER\\s+FUNCTION
^DROP\\s+FUNCTION
tableSpace^CREATE\\s+TABLESPACE
^ALTER\\s+TABLESPACE
^DROP\\s+TABLESPACE
event^CREATE\\s+(DEFINER\\s?=.+?)?EVENT
^ALTER\\s+(DEFINER\\s?=.+?)?EVENT
^DROP\\s+EVENT
account management^GRANT
^REVOKE
^CREATE\\s+USER
^ALTER\\s+USER
^RENAME\\s+USER
^DROP\\s+USER
^DROP\\s+USER
+ +## 改写的 DDL 语句 + +以下语句在同步到下游前会进行改写。 + +|原始语句|实际执行语句| +|-|-| +|`^CREATE DATABASE...`|`^CREATE DATABASE...IF NOT EXISTS`| +|`^CREATE TABLE...`|`^CREATE TABLE..IF NOT EXISTS`| +|`^DROP DATABASE...`|`^DROP DATABASE...IF EXISTS`| +|`^DROP TABLE...`|`^DROP TABLE...IF EXISTS`| +|`^DROP INDEX...`|`^DROP INDEX...IF EXISTS`| + +## 合库合表迁移任务 + +当使用悲观协调模式和乐观协调模式进行分库分表合并迁移时,DDL 同步的行为存在变更,具体请参考[悲观模式](/dm/feature-shard-merge-pessimistic.md)和[乐观模式](/dm/feature-shard-merge-optimistic.md)。 + +## Online DDL + +Online DDL 特性也会对 DDL 事件进行特殊处理,详情可参考[迁移使用 GH-ost/PT-osc 的源数据库](/dm/feature-online-ddl.md)。 diff --git a/markdown-pages/zh/tidb/master/dm/dm-faq.md b/markdown-pages/zh/tidb/master/dm/dm-faq.md new file mode 100644 index 0000000..e9965f7 --- /dev/null +++ b/markdown-pages/zh/tidb/master/dm/dm-faq.md @@ -0,0 +1,374 @@ +--- +title: Data Migration 常见问题 +aliases: ['/docs-cn/tidb-data-migration/dev/faq/'] +summary: 数据迁移常见问题包括:DM 是否支持迁移阿里 RDS 和其他云数据库的数据、task 配置中的黑白名单的正则表达式是否支持非获取匹配、处理不兼容的 DDL 语句、重置数据迁移任务、全量导入过程中遇到报错等。 +--- + +# Data Migration 常见问题 + +## DM 是否支持迁移阿里 RDS 以及其他云数据库的数据? + +DM 仅支持解析标准版本的 MySQL/MariaDB 的 binlog,对于阿里云 RDS 以及其他云数据库没有进行过测试,如果确认其 binlog 为标准格式,则可以支持。 + +已知问题的兼容情况: + +- 阿里云 RDS + - 即使上游表没有主键,阿里云 RDS 的 binlog 中也会包含隐藏的主键列,与上游表结构不一致。 +- 华为云 RDS + - 不支持,详见:[华为云数据库 RDS 是否支持直接读取 Binlog 备份文件](https://support.huaweicloud.com/rds_faq/rds_faq_0210.html)。 + +## task 配置中的黑白名单的正则表达式是否支持`非获取匹配`(?!)? + +目前不支持,DM 仅支持 golang 标准库的正则,可以通过 [re2-syntax](https://github.com/google/re2/wiki/Syntax) 了解 golang 支持的正则表达式。 + +## 如果在上游执行的一个 statement 包含多个 DDL 操作,DM 是否支持迁移? + +DM 会尝试将包含多个 DDL 变更操作的单条语句拆分成只包含一个 DDL 操作的多条语句,但是可能没有覆盖所有的场景。建议在上游执行的一条 statement 中只包含一个 DDL 操作,或者在测试环境中验证一下,如果不支持,可以给 `pingcap/tiflow` 提 [issue](https://github.com/pingcap/tiflow/issues)。 + +## 如何处理不兼容的 DDL 语句? + +你需要使用 dmctl 手动处理 TiDB 不兼容的 DDL 语句(包括手动跳过该 DDL 语句或使用用户指定的 DDL 语句替换原 DDL 语句,详见[处理出错的 DDL 语句](/dm/handle-failed-ddl-statements.md))。 + +> **注意:** +> +> TiDB 目前并不兼容 MySQL 支持的所有 DDL 语句。 + +## DM 是否会将视图的 DDL 语句和对视图的 DML 语句同步到下游的 TiDB 中? + +目前 DM 不会将视图的 DDL 语句同步到下游的 TiDB 集群,也不会将针对视图的 DML 语句同步到下游。 + +## 如何重置数据迁移任务? + +当数据迁移过程中发生异常且无法恢复时,需要重置数据迁移任务,对数据重新进行迁移: + +1. 使用 `stop-task` 停止异常的数据迁移任务。 + +2. 清理下游已迁移的数据。 + +3. 从下面两种方式中选择其中一种重启数据迁移任务: + + - 修改任务配置文件以指定新的任务名,然后使用 `start-task {task-config-file}` 重启迁移任务。 + - 使用 `start-task --remove-meta {task-config-file}` 重启数据迁移任务。 + +## 设置了 `online-ddl: true`,gh-ost 表相关的 DDL 报错该如何处理? + +``` +[unit=Sync] ["error information"="{\"msg\":\"[code=36046:class=sync-unit:scope=internal:level=high] online ddls on ghost table `xxx`.`_xxxx_gho`\\ngithub.com/pingcap/tiflow/pkg/terror.(*Error).Generate ...... +``` + +出现上述错误可能有以下原因: + +DM 在最后 `rename ghost_table to origin table` 的步骤会把内存的 DDL 信息读出,并且还原为 origin table 的 DDL。而内存中的 DDL 信息是在 `alter ghost_table` 的时候进行[处理](/dm/feature-online-ddl.md#online-schema-change-gh-ost),记录 ghost_table DDL 的信息;或者是在重启 dm-worker 启动 task 的时候,从 `dm_meta.{task_name}_onlineddl` 中读取出来。 + +因此,如果在增量复制过程中,指定的 Pos 跳过了 `alter ghost_table` 的 DDL,但是该 Pos 仍在 gh-ost 的 online-ddl 的过程中,就会因为 ghost_table 没有正确写入到内存以及 `dm_meta.{task_name}_onlineddl`,而导致该问题。 + +可以通过以下方式绕过这个问题: + +1. 取消 task 的 `online-ddl-schema` 或 `online-ddl` 的配置。 + +2. 把 `_{table_name}_gho`、`_{table_name}_ghc`、`_{table_name}_del` 配置到 `block-allow-list.ignore-tables` 中。 + +3. 手工在下游的 TiDB 执行上游的 DDL。 + +4. 待 Pos 复制到 gh-ost 整体流程后的位置,再重新启用 `online-ddl-schema` 或 `online-ddl` 以及注释掉 `block-allow-list.ignore-tables`。 + +## 如何为已有迁移任务增加需要迁移的表? + +假如已有数据迁移任务正在运行,但又有其他的表需要添加到该迁移任务中,可根据当前数据迁移任务所处的阶段按下列方式分别进行处理。 + +> **注意:** +> +> 向已有数据迁移任务中增加需要迁移的表操作较复杂,请仅在确有强烈需求时进行。 + +### 迁移任务当前处于 `Dump` 阶段 + +由于 MySQL 不支持指定 snapshot 来进行导出,因此在导出过程中不支持更新迁移任务并重启以通过断点继续导出,故无法支持在该阶段动态增加需要迁移的表。 + +如果确实需要增加其他的表用于迁移,建议直接使用新的配置文件重新启动迁移任务。 + +### 迁移任务当前处于 `Load` 阶段 + +多个不同的数据迁移任务在导出时,通常对应于不同的 binlog position,如将它们在 `Load` 阶段合并导入,则无法就 binlog position 达成一致,因此不建议在 `Load` 阶段向数据迁移任务中增加需要迁移的表。 + +### 迁移任务当前处于 `Sync` 阶段 + +当数据迁移任务已经处于 `Sync` 阶段时,在配置文件中增加额外的表并重启任务,DM 并不会为新增的表重新执行全量导出与导入,而是会继续从之前的断点进行增量复制。 + +因此,如果需要新增的表对应的全量数据尚未导入到下游,则需要先使用单独的数据迁移任务将其全量数据导出并导入到下游。 + +将已有迁移任务对应的全局 checkpoint (`is_global=1`)中的 position 信息记为 `checkpoint-T`,如 `(mysql-bin.000100, 1234)`。将需要增加到迁移任务的表在全量导出的 `metedata`(或另一个处于 `Sync` 阶段的数据迁移任务的 checkpoint)的 position 信息记为 `checkpoint-S`,如 `(mysql-bin.000099, 5678)`。则可通过以下步骤将表增加到迁移任务中: + +1. 使用 `stop-task` 停止已有迁移任务。如果需要增加的表属于另一个运行中的迁移任务,则也将其停止。 + +2. 使用 MySQL 客户连接到下游 TiDB 数据库,手动更新已有迁移任务对应的 checkpoint 表中的信息为 `checkpoint-T` 与 `checkpoint-S` 中的较小值(在本例中,为 `(mysql-bin.000099, 5678)`)。 + + - 需要更新的 checkpoint 表为 `{dm_meta}` 库中的 `{task-name}_syncer_checkpoint`。 + + - 需要更新的 checkpoint 行为 `id={source-id}` 且 `is_global=1`。 + + - 需要更新的 checkpoint 列为 `binlog_name` 与 `binlog_pos`。 + +3. 在迁移任务配置中为 `syncers` 部分设置 `safe-mode: true` 以保证可重入执行。 + +4. 通过 `start-task` 启动迁移任务。 + +5. 通过 `query-status` 观察迁移任务状态,当 `syncerBinlog` 超过 `checkpoint-T` 与 `checkpoint-S` 中的较大值后(在本例中,为 `(mysql-bin.000100, 1234)`),即可还原 `safe-mode` 为原始值并重启迁移任务。 + +## 全量导入过程中遇到报错 `packet for query is too large. Try adjusting the 'max_allowed_packet' variable` + +尝试将 + +- TiDB Server 的全局变量 `max_allowed_packet` +- 任务配置文件中的配置项 `target-database.max-allowed-packet`(详情参见 [DM 任务完整配置文件介绍](/dm/task-configuration-file-full.md)) + +设置为比默认 67108864 (64M) 更大的值。 + +## 2.0+ 集群运行 1.0 已有数据迁移任务时报错 `Error 1054: Unknown column 'binlog_gtid' in 'field list'` + +在 DM 2.0 之后,为 checkpoint 等元信息表引入了更多的字段。如果通过 `start-task` 直接使用 1.0 集群的任务配置文件从增量复制阶段继续运行,则会出现 `Error 1054: Unknown column 'binlog_gtid' in 'field list'` 错误。 + +对于此错误,可[手动将 DM 1.0 的数据迁移任务导入到 2.0+ 集群](/dm/manually-upgrade-dm-1.0-to-2.0.md)。 + +## TiUP 无法部署 DM 的某个版本(如 v2.0.0-hotfix) + +你可以通过 `tiup list dm-master` 命令查看 TiUP 支持部署的 DM 版本。该命令未展示的版本不能由 TiUP 管理。 + +## DM 同步报错 `parse mydumper metadata error: EOF` + +该错误需要查看报错信息以及日志进一步分析。报错原因可能是 dump 单元由于缺少权限没有产生正确的 metadata 文件。 + +## DM 分库分表同步中没有明显报错,但是下游数据丢失 + +需要检查配置项 `block-allow-list` 和 `table-route`: + +- `block-allow-list` 填写的是上游数据库表,可以在 `do-tables` 前通过加 “~” 来进行正则匹配。 +- `table-route` 不支持正则,采用的是通配符模式,所以 `table_parttern_[0-63]` 只会匹配 table_parttern_0 到 table_pattern_6 这 7 张表。 + +## DM 上游无写入,replicate lag 监控无数据 + +在 DM v1.0 中,需要开启 `enable-heartbeat` 才会产生该监控数据。v2.0 及以后版本中,尚未启用该功能,replicate lag 监控无数据是预期行为。 + +## DM v2.0.0 启动任务时出现 `fail to initial unit Sync of subtask`,报错信息的 `RawCause` 显示 `context deadline exceeded` + +该问题是 DM v2.0.0 的已知问题,在同步任务的表数目较多时触发,将在 v2.0.1 修复。使用 TiUP 部署的用户可以升级到开发版 nightly 解决该问题,或者访问 GitHub 上 [DM 仓库的 release 页面](https://github.com/pingcap/tiflow/releases)下载 v2.0.0-hotfix 版本手动替换可执行文件。 + +## DM 同步中报错 `duplicate entry` + +用户需要首先确认任务中没有配置 `disable-detect`(v2.0.7 及之前版本),没有其他同步程序或手动插入数据,表中没有配置相关的 DML 过滤器。 + +为了便于排查问题,用户收集到下游 TiDB 相关 general log 后可以在 [AskTUG 社区](https://asktug.com/tags/dm) 联系专家进行排查。收集 general log 的方式如下: + +```bash +# 开启 general log +curl -X POST -d "tidb_general_log=1" http://{TiDBIP}:10080/settings +# 关闭 general log +curl -X POST -d "tidb_general_log=0" http://{TiDBIP}:10080/settings +``` + +在发生 `duplicate entry` 报错时,确认日志中包含冲突数据的记录。 + +## 监控中部分面板显示 `No data point` + +请参照 [DM 监控指标](/dm/monitor-a-dm-cluster.md)查看各面板含义,部分面板没有数据是正常现象。例如没有发生错误、不存在 DDL lock、没有启用 relay 功能等情况,均可能使得对应面板没有数据。 + +## DM v1.0 在任务出错时使用 `sql-skip` 命令无法跳过某些语句 + +首先需要检查执行 `sql-skip` 之后 binlog 位置是否在推进,如果是的话表示 `sql-skip` 已经生效。重复出错的原因是上游发送了多个不支持的 DDL,可以通过 `sql-skip -s ` 进行模式匹配。 + +对于类似下面这种报错(报错中包含 `parse statement`): + +``` +if the DDL is not needed, you can use a filter rule with \"*\" schema-pattern to ignore it.\n\t : parse statement: line 1 column 11 near \"EVENT `event_del_big_table` \r\nDISABLE\" %!!(MISSING)(EXTRA string=ALTER EVENT `event_del_big_table` \r\nDISABLE +``` + +出现报错的原因是 TiDB parser 无法解析上游的 DDL,例如 `ALTER EVENT`,所以 `sql-skip` 不会按预期生效。可以在任务配置文件中添加 [Binlog 过滤规则](/dm/dm-binlog-event-filter.md)进行过滤,并设置 `schema-pattern: "*"`。从 DM 2.0.1 版本开始,已预设过滤了 `EVENT` 相关语句。 + +在 DM v6.0 版本之后 `sql-skip`、`handle-error` 均已经被 `binlog` 替代,使用 `binlog` 命令可以跳过该类错误。 + +## DM 同步时下游长时间出现 REPLACE 语句 + +请检查是否符合 [safe mode 触发条件](/dm/dm-glossary.md#safe-mode)。如果任务发生错误并自动恢复,或者发生高可用调度,会满足“启动或恢复任务的前 1 分钟”这一条件,因此启用 safe mode。 + +可以检查 DM-worker 日志,在其中搜索包含 `change count` 的行,该行的 `new count` 非零时会启用 safe mode。检查 safe mode 启用时间以及启用前是否有报错,以定位启用原因。 + +## 使用 DM v2.0 同步数据时重启 DM 进程,出现全量数据导入失败错误 + +在 DM v2.0.1 及更早版本中,如果全量导入操作未完成时发生重启,重启后的上游数据源与 DM worker 的绑定关系可能会发生变化。例如,可能出现 dump 单元的中间数据在 DM worker A 机器上,但却由 DM worker B 进行 load 单元的情况,进而导致操作失败。 + +该情况有两种解决方案: + +- 如果数据量较小(TB 级以下)或任务有合库合表:清空下游数据库的已导入数据,同时清空导出数据目录,使用 dmctl 删除并 `start-task --remove-meta` 重建任务。后续尽量保证全量导出导入阶段 DM 没有冗余 worker 以及避免在该时段内重启或升级 DM 集群。 +- 如果数据量较大(数 TB 或更多):清空下游数据库的已导入数据,将 lightning 部署到数据所在的 DM worker 节点,使用 [lightning local backend 模式](/tidb-lightning/deploy-tidb-lightning.md) 导入 DM dump 单元导出的数据。全量导入完成后,修改任务的 `task-mode` 为 `incremental`,修改 `mysql-instance.meta.pos` 为 dump 单元导出数据 `metadata` 中记录的位置,启动一个增量任务。 + +## 使用 DM 同步数据时重启 DM 进程,增量任务出现 `ERROR 1236 (HY000): The slave is connecting using CHANGE MASTER TO MASTER_AUTO_POSITION = 1, but the master has purged binary logs containing GTIDs that the slave requires.` 错误 + +该错误表明全量迁移期间,dump 单元记录 metadata 中的 binlog 位置已经被上游清理。 + +解决方案:出现该问题时只能清空下游数据库已同步数据,并在停止任务后加上 `--remove-meta` 参数重建任务。 + +如要提前避免该问题,需要进行以下配置: + +1. 在 DM 全量迁移未完成时调大上游 MySQL 的 `expire_logs_days` 变量,保证全量进行结束时 metadata 中的 binlog 位置到当前时间的 binlog 都还没有被清理掉。如果数据量较大,应该使用 dumpling + lightning 的方式加快全量迁移速度。 +2. DM 任务开启 relay log 选项,保证 binlog 被清理后 DM 仍有 relay log 可读取。 + +## 使用 TiUP v1.3.0, v1.3.1 部署 DM 集群,DM 集群的 grafana 监控报错显示 `failed to fetch dashboard` + +该问题为 TiUP 已知 bug,在 TiUP v1.3.2 中已进行修复。可采取以下任一方法解决: + +- 方法一:使用 `tiup update --self && tiup update dm` 升级 TiUP 到更新版本,随后先缩容再扩容集群中的 grafana 节点,重建 grafana 服务。 +- 方法二: + 1. 备份 `deploy/grafana-$port/bin/public` 文件夹。 + 2. 下载 [TiUP DM 离线镜像包](https://download.pingcap.org/tidb-dm-v2.0.1-linux-amd64.tar.gz),并进行解压,将其中的 grafana-v4.0.3-**.tar.gz 文件解压后,用解压出的 public/ 文件夹替换前面所描述的文件夹,运行 `tiup dm restart $cluster_name -R grafana` 重启 grafana 服务监控。 + +## 在 DM v2.0 中,同时开启 relay 与 gtid 同步 MySQL 时,运行 `query-status` 发现 syncer checkpoint 中 GTID 不连续 + +该问题为 DM 已知 bug,在完全满足以下两个条件时将会触发,DM 将在 v2.0.2 修复该问题: + +1. DM 配置的 source 同时设置了 `enable-relay` 与 `enable-gtid` 为 `true` +2. DM 同步上游为 **MySQL 从库**,并且该从库通过 `show binlog events in '' limit 2` 查询出的 `previous_gtids` 区间不连续,例如: + +``` +mysql> show binlog events in 'mysql-bin.000005' limit 2; ++------------------+------+----------------+-----------+-------------+--------------------------------------------------------------------+ +| Log_name | Pos | Event_type | Server_id | End_log_pos | Info | ++------------------+------+----------------+-----------+-------------+--------------------------------------------------------------------+ +| mysql-bin.000005 | 4 | Format_desc | 123452 | 123 | Server ver: 5.7.32-35-log, Binlog ver: 4 | +| mysql-bin.000005 | 123 | Previous_gtids | 123452 | 194 | d3618e68-6052-11eb-a68b-0242ac110002:6-7 | ++------------------+------+----------------+-----------+-------------+--------------------------------------------------------------------+ +``` + +使用 dmctl 的 `query-status ` 指令查询任务信息,如果已经出现 `subTaskStatus.sync.syncerBinlogGtid` 不连续但 `subTaskStatus.sync.masterBinlogGtid` 连续的情况,例如下述例子: + +``` +query-status test +{ + ... + "sources": [ + { + ... + "sourceStatus": { + "source": "mysql1", + ... + "relayStatus": { + "masterBinlog": "(mysql-bin.000006, 744)", + "masterBinlogGtid": "f8004e25-6067-11eb-9fa3-0242ac110003:1-50", + ... + } + }, + "subTaskStatus": [ + { + ... + "sync": { + ... + "masterBinlog": "(mysql-bin.000006, 744)", + "masterBinlogGtid": "f8004e25-6067-11eb-9fa3-0242ac110003:1-50", + "syncerBinlog": "(mysql-bin|000001.000006, 738)", + "syncerBinlogGtid": "f8004e25-6067-11eb-9fa3-0242ac110003:1-20:40-49", + ... + "synced": false, + "binlogType": "local" + } + } + ] + }, + { + ... + "sourceStatus": { + "source": "mysql2", + ... + "relayStatus": { + "masterBinlog": "(mysql-bin.000007, 1979)", + "masterBinlogGtid": "ddb8974e-6064-11eb-8357-0242ac110002:1-25", + ... + } + }, + "subTaskStatus": [ + { + ... + "sync": { + "masterBinlog": "(mysql-bin.000007, 1979)", + "masterBinlogGtid": "ddb8974e-6064-11eb-8357-0242ac110002:1-25", + "syncerBinlog": "(mysql-bin|000001.000008, 1979)", + "syncerBinlogGtid": "ddb8974e-6064-11eb-8357-0242ac110002:1-25", + ... + "synced": true, + "binlogType": "local" + } + } + ] + } + ] +} +``` + +其中 mysql1 的 `syncerBinlogGtid` 不连续,已有数据丢失需要按下述方案之一处理: + +- 如果全量导出任务 metadata 中的 position 到当前时间的上游数据库的 binlog 仍未被清理: + 1. 停止当前任务并删除所有 GTID 不连续的 source + 2. 设置所有 source 的 `enable-relay` 为 `false` + 3. 针对 GTID 不连续的 source(上例 mysql1),在对应的任务配置文件 `task.yaml` 中,把 `task-mode` 修改为 `incremental` 并配置增量任务起始点 `mysql-instances.meta` 为各个全量导出任务 metadata 的 binlog name,position 和 gtid 信息 + 4. 配置 `task.yaml` 中的 `syncers.safe-mode` 为 `true` 并重启任务 + 5. 待增量同步追上后,停止任务并在任务配置文件中设置 `safe-mode` 为 `false` + 6. 再次重启任务 +- 如果上游数据库 binlog 已被清理但是本地 relay log 仍未被清理: + 1. 停止当前任务 + 2. 针对 GTID 不连续的 source(上例 mysql1),在对应的任务配置文件 `task.yaml` 中,把 `task-mode` 修改为 `incremental` 并配置增量任务起始点 `mysql-instances.meta` 为各个全量导出任务 metadata 的 binlog name,position 和 gtid 信息 + 3. 修改其中的 GTID 信息的 `1-y` 为 `previous_gtids` 的前段值,例如,上述例子需要改为 `6-y` + 4. 配置 `task.yaml` 中的 `syncers.safe-mode` 为 `true` 并重启任务 + 5. 待增量同步追上后,停止任务并在任务配置文件中设置 `safe-mode` 为 `false` + 6. 再次重启任务 + 7. 重启 source 并关闭 gtid 或 relay +- 如果上述条件均不满足或任务同步数据量较小: + 1. 清空下游数据库中数据 + 2. 重启 source 并关闭 gtid 或 relay + 3. 重建任务并通过 `start-task task.yaml --remove-meta` 重新同步 + +上述处理方案中,针对正常同步的 source(如上例 mysql2),重设增量任务时起始点需设置 `mysql-instances.meta` 为 `subTaskStatus.sync` 的 `syncerBinlog` 与 `syncerBinlogGtid`。 + +## 在 DM 2.0 中开启 heartbeat,虚拟 IP 环境下切换 DM-worker 与 MySQL 实例的连接,遇到 "heartbeat config is different from previous used: serverID not equal" 错误 + +`heartbeat` 功能在 DM v2.0 及之后版本已经默认关闭,如果用户在同步任务配置文件中开启会干扰高可用特性,在配置文件中关闭该项(通过设置 `enable-heartbeat: false`,然后更新任务配置)即可解决。DM 将会在后续版本强制关闭该功能。 + +## DM-master 在重启后无法加入集群,报错信息为 "fail to start embed etcd, RawCause: member xxx has already been bootstrapped" + +DM-master 会在启动时将 etcd 信息记录在当前目录。如果重启后当前目录发生变化,会导致 DM 缺失 etcd 信息,从而启动失败。 + +推荐使用 TiUP 运维 DM 避免这一问题。在需要使用二进制部署的场合,需要在 DM-master 配置文件中使用绝对路径配置 data-dir 项,或者注意运行命令的当前目录。 + +## 使用 dmctl 执行命令时无法连接 DM-master + +在使用 dmctl 执行相关命令时,发现连接 DM-master 失败(即使已在命令中指定 `--master-addr` 的参数值),报错内容类似 `RawCause: context deadline exceeded, Workaround: please check your network connection.`,但使用 `telnet ` 之类的命令检查网络却没有发现异常。 + +这种情况可以检查下环境变量 `https_proxy`(注意,这里是 **https** )。如果配置了该环境变量,dmctl 会自动去连接 `https_proxy` 指定的主机及端口,而如果该主机没有相应的 `proxy` 转发服务,则会导致连接失败。 + +解决方案:确认 `https_proxy` 是否必须要配置,如果不是必须的,取消该设置即可。如果环境必须,那么在原命令前加环境变量设置 `https_proxy="" ./dmctl --master-addr "x.x.x.x:8261"` 即可。 + +> **注意:** +> +> 关于 `proxy` 的环境变量有 `http_proxy`,`https_proxy`,`no_proxy` 等。如果依据上述解决方案处理后仍无法连接,可以考虑检查 `http_proxy` 和 `no_proxy` 的参数配置是否有影响。 + +## v2.0.2 - v2.0.6 版本执行 start-relay 命令报错该如何处理? + +``` +flush local meta, Rawcause: open relay-dir/xxx.000001/relay.metayyyy: no such file or directory +``` + +上述报错在以下情况下有可能会被触发: + +- DM 从 v2.0.1 及之前的版本升级到 v2.0.2 - v2.0.6 版本,且升级之前曾开启过 relay log,升级完后重新开启。 +- 使用 stop-relay 命令暂停 relay log 后重新开启 relay log。 + +可以通过以下方式解决该问题: + +- 重启 relay log: + + ``` + » stop-relay -s sourceID workerName + » start-relay -s sourceID workerName + ``` + +- 升级 DM 至 v2.0.7 或之后版本。 + +## Load 单元报错 `Unknown character set` + +由于 TiDB 只支持部分 MySQL 字符集,因此,在全量导入中,如果创建表结构时使用了 TiDB 不支持的字符集,DM 会报这个错误。你可以结合数据内容选择 [TiDB 支持的字符集](/character-set-and-collation.md),预先在下游创建表结构以绕过这个错误。 diff --git a/markdown-pages/zh/tidb/master/dm/dm-master-configuration-file.md b/markdown-pages/zh/tidb/master/dm/dm-master-configuration-file.md new file mode 100644 index 0000000..b639a19 --- /dev/null +++ b/markdown-pages/zh/tidb/master/dm/dm-master-configuration-file.md @@ -0,0 +1,61 @@ +--- +title: DM-master 配置文件介绍 +aliases: ['/docs-cn/tidb-data-migration/dev/dm-master-configuration-file/'] +summary: 本文介绍了 DM-master 的配置文件,包括示例配置和配置项说明。示例配置包括日志配置、DM-master 监听地址、集群配置等。配置项说明包括全局配置,如标识 DM-master、日志级别、日志文件、地址等。另外还包括 SSL 证书路径、证书检查 Common Name 列表和加解密密钥路径等内容。 +--- + +# DM-master 配置文件介绍 + +本文介绍 DM-master 的配置文件,包括配置文件示例与配置项说明。 + +## 配置文件示例 + +DM-master 的示例配置文件如下所示: + +```toml +name = "dm-master" + +# log configuration +log-level = "info" +log-file = "dm-master.log" + +# DM-master listening address +master-addr = ":8261" +advertise-addr = "127.0.0.1:8261" + +# URLs for peer traffic +peer-urls = "http://127.0.0.1:8291" +advertise-peer-urls = "http://127.0.0.1:8291" + +# cluster configuration +initial-cluster = "master1=http://127.0.0.1:8291,master2=http://127.0.0.1:8292,master3=http://127.0.0.1:8293" +join = "" + +ssl-ca = "/path/to/ca.pem" +ssl-cert = "/path/to/cert.pem" +ssl-key = "/path/to/key.pem" +cert-allowed-cn = ["dm"] + +secret-key-path = "/path/to/secret/key" +``` + +## 配置项说明 + +### Global 配置 + +| 配置项 | 说明 | +| :------------ | :--------------------------------------- | +| `name` | 标识一个 DM-master。| +| `log-level` | 日志级别:debug、info、warn、error、fatal。默认为 info。| +| `log-file` | 日志文件,如果不配置,日志会输出到标准输出中。| +| `master-addr` | DM-master 服务的地址,可以省略 IP 信息,例如:":8261"。| +| `advertise-addr` | DM-master 向外界宣告的地址。| +| `peer-urls` | DM-master 节点的对等 URL。| +| `advertise-peer-urls` | DM-master 向外界宣告的对等 URL。默认为 `peer-urls` 的值。| +| `initial-cluster` | 初始集群中所有 DM-master 的 `advertise-peer-urls` 的值。| +| `join` | 集群里已有的 DM-master 的 `advertise-peer-urls` 的值。如果是新加入的 DM-master 节点,使用 `join` 替代 `initial-cluster`。| +| `ssl-ca` | DM-master 组件用于与其它组件连接的 SSL CA 证书所在的路径 | +| `ssl-cert` | DM-master 组件用于与其它组件连接的 PEM 格式的 X509 证书所在的路径 | +| `ssl-key` | DM-master 组件用于与其它组件连接的 PEM 格式的 X509 密钥所在的路径 | +| `cert-allowed-cn` | 证书检查 Common Name 列表 | +| `secret-key-path` | 用来加解密上下游密码的密钥所在的路径,该文件内容必须是长度为 64 个字符的十六进制的 AES-256 密钥 | diff --git a/markdown-pages/zh/tidb/master/dm/dm-release-notes.md b/markdown-pages/zh/tidb/master/dm/dm-release-notes.md new file mode 100644 index 0000000..ec0ae33 --- /dev/null +++ b/markdown-pages/zh/tidb/master/dm/dm-release-notes.md @@ -0,0 +1,37 @@ +--- +title: TiDB Data Migration 版本发布历史 +summary: TiDB Data Migration 版本发布历史从 DM v5.4.0 起,TiDB Data Migration 的 Release Notes 合并入相同版本号的 TiDB Release Notes。如需阅读 v5.4.0 及之后版本的 DM Release Notes,请查看对应版本的 TiDB Release Notes 中 DM 相关的内容。如需阅读 v5.3.0 及更早版本的 DM Release Notes,请参考以下链接:5.3.0, 2.0.7, 2.0.6, 2.0.5, 2.0.4, 2.0.3, 2.0.2, 2.0.1, 2.0 GA, 2.0.0-rc.2, 2.0.0-rc, 1.0.7, 1.0.6, 1.0.5, 1.0.4, 1.0.3, 1.0.2. +--- + +# TiDB Data Migration 版本发布历史 + +从 DM v5.4.0 起,TiDB Data Migration 的 Release Notes 合并入相同版本号的 TiDB Release Notes。 + +- 如需阅读 v5.4.0 及之后版本的 DM Release Notes,请查看对应版本的 TiDB Release Notes 中 DM 相关的内容。 +- 如需阅读 v5.3.0 及更早版本的 DM Release Notes,请参考以下链接: + +## 5.3 + +- [5.3.0](https://docs.pingcap.com/zh/tidb-data-migration/v5.3/5.3.0/) + +## 2.0 + +- [2.0.7](https://docs.pingcap.com/zh/tidb-data-migration/v5.3/2.0.7/) +- [2.0.6](https://docs.pingcap.com/zh/tidb-data-migration/v5.3/2.0.6/) +- [2.0.5](https://docs.pingcap.com/zh/tidb-data-migration/v5.3/2.0.5/) +- [2.0.4](https://docs.pingcap.com/zh/tidb-data-migration/v5.3/2.0.4/) +- [2.0.3](https://docs.pingcap.com/zh/tidb-data-migration/v5.3/2.0.3/) +- [2.0.2](https://docs.pingcap.com/zh/tidb-data-migration/v5.3/2.0.2/) +- [2.0.1](https://docs.pingcap.com/zh/tidb-data-migration/v5.3/2.0.1/) +- [2.0 GA](https://docs.pingcap.com/zh/tidb-data-migration/v5.3/2.0.0-ga/) +- [2.0.0-rc.2](https://docs.pingcap.com/zh/tidb-data-migration/v5.3/2.0.0-rc.2/) +- [2.0.0-rc](https://docs.pingcap.com/zh/tidb-data-migration/v5.3/2.0.0-rc/) + +## 1.0 + +- [1.0.7](https://docs.pingcap.com/zh/tidb-data-migration/v5.3/1.0.7/) +- [1.0.6](https://docs.pingcap.com/zh/tidb-data-migration/v5.3/1.0.6/) +- [1.0.5](https://docs.pingcap.com/zh/tidb-data-migration/v5.3/1.0.5/) +- [1.0.4](https://docs.pingcap.com/zh/tidb-data-migration/v5.3/1.0.4/) +- [1.0.3](https://docs.pingcap.com/zh/tidb-data-migration/v5.3/1.0.3/) +- [1.0.2](https://docs.pingcap.com/zh/tidb-data-migration/v5.3/1.0.2/) \ No newline at end of file diff --git a/markdown-pages/zh/tidb/master/dm/dm-source-configuration-file.md b/markdown-pages/zh/tidb/master/dm/dm-source-configuration-file.md new file mode 100644 index 0000000..22e7384 --- /dev/null +++ b/markdown-pages/zh/tidb/master/dm/dm-source-configuration-file.md @@ -0,0 +1,111 @@ +--- +title: TiDB Data Migration 上游数据库配置文件介绍 +aliases: ['/docs-cn/tidb-data-migration/dev/source-configuration-file/'] +summary: TiDB Data Migration (DM) 上游数据库配置文件包括示例与配置项说明。示例配置文件包括上游数据库的配置项,如是否开启 GTID、是否开启 relay log、拉取上游 binlog 的起始文件名等。配置项说明包括全局配置、relay log 清理策略配置、任务状态检查配置和 Binlog event filter。配置项包括标识一个 MySQL 实例、是否使用 GTID 方式、是否开启 relay log、存储 relay log 的目录等。从 DM v2.0.2 开始,Binlog event filter 也可以在上游数据库配置文件中进行配置。 +--- + +# TiDB Data Migration 上游数据库配置文件介绍 + +本文介绍 TiDB Data Migration (DM) 上游数据库的配置文件,包括配置文件示例与配置项说明。 + +## 配置文件示例 + +上游数据库的示例配置文件如下所示: + +```yaml +source-id: "mysql-replica-01" + +# 是否开启 GTID +enable-gtid: false + +# 是否开启 relay log +enable-relay: false # 该配置项从 DM v2.0.2 版本起弃用,使用 `start-relay` 命令开启 relay log +relay-binlog-name: "" # 拉取上游 binlog 的起始文件名 +relay-binlog-gtid: "" # 拉取上游 binlog 的起始 GTID +# relay-dir: "relay-dir" # 存储 relay log 的目录,默认值为 "relay-dir"。从 v6.1 版本起该配置标记为弃用,被 worker 配置中的同名参数取代 + +from: + host: "127.0.0.1" + port: 3306 + user: "root" + password: "ZqMLjZ2j5khNelDEfDoUhkD5aV5fIJOe0fiog9w=" # 推荐使用 dmctl 对上游数据库的用户密码加密之后的密码 + security: # 上游数据库 TLS 相关配置 + ssl-ca: "/path/to/ca.pem" + ssl-cert: "/path/to/cert.pem" + ssl-key: "/path/to/key.pem" + +# purge: +# interval: 3600 +# expires: 0 +# remain-space: 15 + +# checker: +# check-enable: true +# backoff-rollback: 5m0s +# backoff-max: 5m0s # backoff 的最大值,不能小于 1s + +# 从 DM v2.0.2 开始,Binlog event filter 也可以在上游数据库配置文件中进行配置 +# case-sensitive: false +# filters: +# - schema-pattern: dmctl +# table-pattern: t_1 +# events: [] +# sql-pattern: +# - alter table .* add column `aaa` int +# action: Ignore +``` + +> **注意:** +> +> 在 DM v2.0.1 版本中,请勿同时配置 `enable-gtid` 与 `enable-relay` 为 `true`,否则可能引发增量数据丢失问题。 + +## 配置项说明 + +### Global 配置 + +| 配置项 | 说明 | +| :------------ | :--------------------------------------- | +| `source-id` | 标识一个 MySQL 实例。| +| `enable-gtid` | 是否使用 GTID 方式从上游拉取 binlog,默认值为 false。一般情况下不需要手动配置,如果上游数据库启用了 GTID 支持,且需要做主从切换,则将该配置项设置为 true。 | +| `enable-relay` | 是否开启 relay log,默认值为 false。自 DM v2.0.2 版本起,该配置项弃用,需使用 `start-relay` 命令[开启 relay log](/dm/relay-log.md#开启关闭-relay-log)。 | +| `relay-binlog-name` | 拉取上游 binlog 的起始文件名,例如 "mysql-bin.000002",该配置在 `enable-gtid` 为 false 的情况下生效。如果不配置该项,DM-worker 将从正在同步的最早的 binlog 文件开始拉取,一般情况下不需要手动配置。 | +| `relay-binlog-gtid` | 拉取上游 binlog 的起始 GTID,例如 "e9a1fc22-ec08-11e9-b2ac-0242ac110003:1-7849",该配置在 `enable-gtid` 为 true 的情况下生效。如果不配置该项,DM-worker 将从正在同步的最早 binlog GTID 开始拉取 binlog,一般情况下不需要手动配置。 | +| `relay-dir` | 存储 relay log 的目录,默认值为 "./relay_log"。| +| `host` | 上游数据库的 host。| +| `port` | 上游数据库的端口。| +| `user` | 上游数据库使用的用户名。| +| `password` | 上游数据库的用户密码。注意:推荐使用 dmctl 加密后的密码。| +| `security` | 上游数据库 TLS 相关配置。配置的证书文件路径需能被所有节点访问。若配置为本地路径,则集群所有节点需要将证书文件拷贝一份放在各节点机器相同的路径位置上。| + +### relay log 清理策略配置(purge 配置项) + +一般情况下不需要手动配置,如果 relay log 数据量较大,磁盘空间不足,则可以通过设置该配置项来避免 relay log 写满磁盘。 + +| 配置项 | 说明 | +| :------------ | :--------------------------------------- | +| `interval` | 定期检查 relay log 是否过期的间隔时间,默认值:3600,单位:秒。 | +| `expires` | relay log 的过期时间,默认值为 0,单位:小时。未由 relay 处理单元进行写入、或已有数据迁移任务当前或未来不需要读取的 relay log 在超过过期时间后会被 DM 删除。如果不设置则 DM 不会自动清理过期的 relay log。 | +| `remain-space` | 设置最小的可用磁盘空间。当磁盘可用空间小于这个值时,DM-worker 会尝试删除 relay log,默认值:15,单位:GB。 | + +> **注意:** +> +> 仅在 `interval` 不为 0 且 `expires` 和 `remain-space` 两个配置项中至少有一个不为 0 的情况下 DM 的自动清理策略才会生效。 + +### 任务状态检查配置(checker 配置项) + +DM 会定期检查当前任务状态以及错误信息,判断恢复任务能否消除错误,并自动尝试恢复任务进行重试。DM 会使用指数回退策略调整检查间隔。这些行为可以通过如下配置进行调整: + +| 配置项 | 说明 | +| :------------ | :--------------------------------------- | +| `check-enable` | 启用自动重试功能。 | +| `backoff-rollback` | 如果指数回退策略的间隔大于该值,且任务处于正常状态,尝试减小间隔。 | +| `backoff-max` | 指数回退策略的间隔的最大值,该值必须大于 1 秒。 | + +### Binlog event filter + +从 DM v2.0.2 开始,Binlog event filter 也可以在上游数据库配置文件中进行配置。 + +| 配置项 | 说明 | +| :------------ | :--------------------------------------- | +| `case-sensitive` | Binlog event filter 标识符是否大小写敏感。默认值:false。| +| `filters` | 配置 Binlog event filter,含义见 [Binlog event filter 参数解释](/dm/dm-binlog-event-filter.md#参数解释)。 | diff --git a/markdown-pages/zh/tidb/master/dm/dm-task-configuration-guide.md b/markdown-pages/zh/tidb/master/dm/dm-task-configuration-guide.md new file mode 100644 index 0000000..f66f3d8 --- /dev/null +++ b/markdown-pages/zh/tidb/master/dm/dm-task-configuration-guide.md @@ -0,0 +1,235 @@ +--- +title: TiDB Data Migration 数据迁移任务配置向导 +summary: 本文介绍了如何配置 TiDB Data Migration (DM) 的数据迁移任务。包括配置数据源、目标 TiDB 集群、需要迁移的表、需要过滤的操作、数据源表到目标 TiDB 表的映射以及分库分表合并等配置。详细配置规则可参考相关链接。 +--- + +# TiDB Data Migration 数据迁移任务配置向导 + +本文档介绍如何配置 TiDB Data Migration (DM) 的数据迁移任务。 + +## 配置需要迁移的数据源 + +配置需要迁移的数据源之前,首先应该确认已经在 DM 创建相应数据源: + +- 查看数据源可以参考[查看数据源配置](/dm/dm-manage-source.md#查看数据源配置) +- 创建数据源可以参考[在 DM 创建数据源](/dm/migrate-data-using-dm.md#第-3-步创建数据源) +- 数据源配置可以参考[数据源配置文件介绍](/dm/dm-source-configuration-file.md) + +仿照下面的 `mysql-instances:` 示例定义数据迁移任务需要同步的单个或者多个数据源。 + +```yaml +--- + +## ********* 任务信息配置 ********* +name: test # 任务名称,需要全局唯一 + +## ******** 数据源配置 ********** +mysql-instances: + - source-id: "mysql-replica-01" # 从 source-id = mysql-replica-01 的数据源迁移数据 + - source-id: "mysql-replica-02" # 从 source-id = mysql-replica-02 的数据源迁移数据 +``` + +## 配置迁移的目标 TiDB 集群 + +仿照下面的 `target-database:` 示例定义迁移的目标 TiDB 集群。 + +```yaml +--- + +## ********* 任务信息配置 ********* +name: test # 任务名称,需要全局唯一 + +## ******** 数据源配置 ********** +mysql-instances: + - source-id: "mysql-replica-01" # 从 source-id = mysql-replica-01 的数据源迁移数据 + - source-id: "mysql-replica-02" # 从 source-id = mysql-replica-02 的数据源迁移数据 + +## ******** 目标 TiDB 配置 ********** +target-database: # 目标 TiDB 配置 + host: "127.0.0.1" + port: 4000 + user: "root" + password: "" # 如果密码不为空,则推荐使用经过 dmctl 加密的密文 +``` + +## 配置需要迁移的表 + +如果不需要过滤或迁移特定表,可以跳过该项配置。 + +配置从数据源迁移表的黑白名单,则需要添加两个定义,详细配置规则参考 [Block & Allow Lists](/dm/dm-block-allow-table-lists.md): + +1. 定义全局的黑白名单规则 + + ```yaml + block-allow-list: + bw-rule-1: # 规则名称 + do-dbs: ["test.*", "user"] # 迁移哪些库,支持通配符 "*" 和 "?",do-dbs 和 ignore-dbs 只需要配置一个,如果两者同时配置只有 do-dbs 会生效 + # ignore-dbs: ["mysql", "account"] # 忽略哪些库,支持通配符 "*" 和 "?" + do-tables: # 迁移哪些表,do-tables 和 ignore-tables 只需要配置一个,如果两者同时配置只有 do-tables 会生效 + - db-name: "test.*" + tbl-name: "t.*" + - db-name: "user" + tbl-name: "information" + bw-rule-2: # 规则名称 + ignore-tables: # 忽略哪些表 + - db-name: "user" + tbl-name: "log" + ``` + +2. 在数据源配置中引用黑白名单规则,过滤该数据源需要迁移的表 + + ```yaml + mysql-instances: + - source-id: "mysql-replica-01" # 从 source-id = mysql-replica-01 的数据源迁移数据 + block-allow-list: "bw-rule-1" # 黑白名单配置名称,如果 DM 版本早于 v2.0.0-beta.2 则使用 black-white-list + - source-id: "mysql-replica-02" # 从 source-id = mysql-replica-02 的数据源迁移数据 + block-allow-list: "bw-rule-2" # 黑白名单配置名称,如果 DM 版本早于 v2.0.0-beta.2 则使用 black-white-list + ``` + +## 配置需要过滤的操作 + +如果不需要过滤特定库或者特定表的特定操作,可以跳过该项配置。 + +配置过滤特定操作,则需要添加两个定义,详细配置规则参考 [Binlog Event Filter](/dm/dm-binlog-event-filter.md): + +1. 定义全局的数据源操作过滤规则 + + ```yaml + filters: # 定义过滤数据源特定操作的规则,可以定义多个规则 + filter-rule-1: # 规则名称 + schema-pattern: "test_*" # 匹配数据源的库名,支持通配符 "*" 和 "?" + table-pattern: "t_*" # 匹配数据源的表名,支持通配符 "*" 和 "?" + events: ["truncate table", "drop table"] # 匹配上 schema-pattern 和 table-pattern 的库或者表的操作类型 + action: Ignore # 迁移(Do)还是忽略(Ignore) + filter-rule-2: + schema-pattern: "test" + events: ["all dml"] + action: Do + ``` + +2. 在数据源配置中引用数据源操作过滤规则,过滤该数据源的指定库或表的指定操作 + + ```yaml + mysql-instances: + - source-id: "mysql-replica-01" # 从 source-id = mysql-replica-01 的数据源迁移数据 + block-allow-list: "bw-rule-1" # 黑白名单配置名称,如果 DM 版本早于 v2.0.0-beta.2 则使用 black-white-list + filter-rules: ["filter-rule-1"] # 过滤数据源特定操作的规则,可以配置多个过滤规则 + - source-id: "mysql-replica-02" # 从 source-id = mysql-replica-02 的数据源迁移数据 + block-allow-list: "bw-rule-2" # 黑白名单配置名称,如果 DM 版本早于 v2.0.0-beta.2 则使用 black-white-list + filter-rules: ["filter-rule-2"] # 过滤数据源特定操作的规则,可以配置多个过滤规则 + ``` + +## 配置需要数据源表到目标 TiDB 表的映射 + +如果不需要将数据源表路由到不同名的目标 TiDB 表,可以跳过该项配置。分库分表合并迁移的场景必须配置该规则。 + +配置数据源表迁移到目标 TiDB 表的路由规则,则需要添加两个定义,详细配置规则参考 [Table Routing](/dm/dm-table-routing.md): + +1. 定义全局的路由规则 + + ```yaml + routes: # 定义数据源表迁移到目标 TiDB 表的路由规则,可以定义多个规则 + route-rule-1: # 规则名称 + schema-pattern: "test_*" # 匹配数据源的库名,支持通配符 "*" 和 "?" + table-pattern: "t_*" # 匹配数据源的表名,支持通配符 "*" 和 "?" + target-schema: "test" # 目标 TiDB 库名 + target-table: "t" # 目标 TiDB 表名 + route-rule-2: + schema-pattern: "test_*" + target-schema: "test" + ``` + +2. 在数据源配置中引用路由规则,过滤该数据源需要迁移的表 + + ```yaml + mysql-instances: + - source-id: "mysql-replica-01" # 从 source-id = mysql-replica-01 的数据源迁移数据 + block-allow-list: "bw-rule-1" # 黑白名单配置名称,如果 DM 版本早于 v2.0.0-beta.2 则使用 black-white-list + filter-rules: ["filter-rule-1"] # 过滤数据源特定操作的规则,可以配置多个过滤规则 + route-rules: ["route-rule-1", "route-rule-2"] # 数据源表迁移到目标 TiDB 表的路由规则,可以定义多个规则 + - source-id: "mysql-replica-02" # 从 source-id = mysql-replica-02 的数据源迁移数据 + block-allow-list: "bw-rule-2" # 黑白名单配置名称,如果 DM 版本早于 v2.0.0-beta.2 则使用 black-white-list + filter-rules: ["filter-rule-2"] # 过滤数据源特定操作的规则,可以配置多个过滤规则 + ``` + +## 配置是否进行分库分表合并 + +如果是分库分表合并的数据迁移场景,并且需要同步分库分表的 DDL,则必须显式配置 `shard-mode`,否则不要配置该选项。 + +分库分表 DDL 同步问题特别多,请确认了解 DM 同步分库分表 DDL 的原理和限制后,谨慎使用。 + +```yaml +--- + +## ********* 任务信息配置 ********* +name: test # 任务名称,需要全局唯一 +shard-mode: "pessimistic" # 默认值为 "" 即无需协调。如果为分库分表合并任务,请设置为悲观协调模式 "pessimistic"。在深入了解乐观协调模式的原理和使用限制后,也可以设置为乐观协调模式 "optimistic" +``` + +## 其他配置 + +下面是本数据迁移任务配置向导的完整示例。完整的任务配置参见 [DM 任务完整配置文件介绍](/dm/task-configuration-file-full.md)。 + +```yaml +--- + +## ********* 任务信息配置 ********* +name: test # 任务名称,需要全局唯一 +shard-mode: "pessimistic" # 默认值为 "" 即无需协调。如果为分库分表合并任务,请设置为悲观协调模式 "pessimistic"。在深入了解乐观协调模式的原理和使用限制后,也可以设置为乐观协调模式 "optimistic" +task-mode: all # 任务模式,可设为 "full" - "只进行全量数据迁移"、"incremental" - "Binlog 实时同步"、"all" - "全量 + Binlog 迁移" +# timezone: "UTC" # 指定数据迁移任务时 SQL Session 使用的时区。DM 默认使用目标库的全局时区配置进行数据迁移,并且自动确保同步数据的正确性。使用自定义时区依然可以确保整个流程的正确性,但一般不需要手动指定。 + +## ******** 数据源配置 ********** +mysql-instances: + - source-id: "mysql-replica-01" # 从 source-id = mysql-replica-01 的数据源迁移数据 + block-allow-list: "bw-rule-1" # 黑白名单配置名称,如果 DM 版本早于 v2.0.0-beta.2 则使用 black-white-list + filter-rules: ["filter-rule-1"] # 过滤数据源特定操作的规则,可以配置多个过滤规则 + route-rules: ["route-rule-1", "route-rule-2"] # 数据源表迁移到目标 TiDB 表的路由规则,可以定义多个规则 + - source-id: "mysql-replica-02" # 从 source-id = mysql-replica-02 的数据源迁移数据 + block-allow-list: "bw-rule-2" # 黑白名单配置名称,如果 DM 版本早于 v2.0.0-beta.2 则使用 black-white-list + filter-rules: ["filter-rule-2"] # 过滤数据源特定操作的规则,可以配置多个过滤规则 + route-rules: ["route-rule-2"] # 数据源表迁移到目标 TiDB 表的路由规则,可以定义多个规则 + +## ******** 目标 TiDB 配置 ********** +target-database: # 目标 TiDB 配置 + host: "127.0.0.1" + port: 4000 + user: "root" + password: "" # 如果密码不为空,则推荐使用经过 dmctl 加密的密文 + +## ******** 功能配置 ********** +block-allow-list: # 定义数据源迁移表的过滤规则,可以定义多个规则。如果 DM 版本早于 v2.0.0-beta.2 则使用 black-white-list + bw-rule-1: # 规则名称 + do-dbs: ["test.*", "user"] # 迁移哪些库,支持通配符 "*" 和 "?",do-dbs 和 ignore-dbs 只需要配置一个,如果两者同时配置只有 do-dbs 会生效 + # ignore-dbs: ["mysql", "account"] # 忽略哪些库,支持通配符 "*" 和 "?" + do-tables: # 迁移哪些表,do-tables 和 ignore-tables 只需要配置一个,如果两者同时配置只有 do-tables 会生效 + - db-name: "test.*" + tbl-name: "t.*" + - db-name: "user" + tbl-name: "information" + bw-rule-2: # 规则名称 + ignore-tables: # 忽略哪些表 + - db-name: "user" + tbl-name: "log" + +filters: # 定义过滤数据源特定操作的规则,可以定义多个规则 + filter-rule-1: # 规则名称 + schema-pattern: "test_*" # 匹配数据源的库名,支持通配符 "*" 和 "?" + table-pattern: "t_*" # 匹配数据源的表名,支持通配符 "*" 和 "?" + events: ["truncate table", "drop table"] # 匹配上 schema-pattern 和 table-pattern 的库或者表的操作类型 + action: Ignore # 迁移(Do)还是忽略(Ignore) + filter-rule-2: + schema-pattern: "test" + events: ["all dml"] + action: Do + +routes: # 定义数据源表迁移到目标 TiDB 表的路由规则,可以定义多个规则 + route-rule-1: # 规则名称 + schema-pattern: "test_*" # 匹配数据源的库名,支持通配符 "*" 和 "?" + table-pattern: "t_*" # 匹配数据源的表名,支持通配符 "*" 和 "?" + target-schema: "test" # 目标 TiDB 库名 + target-table: "t" # 目标 TiDB 表名 + route-rule-2: + schema-pattern: "test_*" + target-schema: "test" +``` diff --git a/markdown-pages/zh/tidb/master/dm/dm-worker-configuration-file.md b/markdown-pages/zh/tidb/master/dm/dm-worker-configuration-file.md new file mode 100644 index 0000000..497a061 --- /dev/null +++ b/markdown-pages/zh/tidb/master/dm/dm-worker-configuration-file.md @@ -0,0 +1,55 @@ +--- +title: DM-worker 配置文件介绍 +aliases: ['/docs-cn/tidb-data-migration/dev/dm-worker-configuration-file/'] +summary: 本文介绍了 DM-worker 的配置文件,包括配置文件示例和配置项说明。配置文件示例包括了 worker 的名称、日志配置、worker 的地址等内容。配置项说明包括了全局配置中的各个配置项的说明,如 name、log-level、log-file 等。同时还介绍了一些新增的配置项,如 relay-keepalive-ttl 和 relay-dir。SSL 相关的配置项也有详细说明。 +--- + +# DM-worker 配置文件介绍 + +本文介绍 DM-worker 的配置文件,包括配置文件示例与配置项说明。 + +## 配置文件示例 + +```toml +# Worker Configuration. + +name = "worker1" + +# Log configuration. +log-level = "info" +log-file = "dm-worker.log" + +# DM-worker listen address. +worker-addr = ":8262" +advertise-addr = "127.0.0.1:8262" +join = "http://127.0.0.1:8261,http://127.0.0.1:8361,http://127.0.0.1:8461" + +keepalive-ttl = 60 +relay-keepalive-ttl = 1800 # 版本 2.0.2 新增 +# relay-dir = "relay_log" # 版本 5.4.0 新增。使用相对路径时注意结合部署、启动方式确认路径位置。 + +ssl-ca = "/path/to/ca.pem" +ssl-cert = "/path/to/cert.pem" +ssl-key = "/path/to/key.pem" +cert-allowed-cn = ["dm"] +``` + +## 配置项说明 + +### Global 配置 + +| 配置项 | 说明 | +| :------------ | :--------------------------------------- | +| `name` | 标识一个 DM-worker。 | +| `log-level` | 日志级别:debug、info、warn、error、fatal。默认为 info。 | +| `log-file` | 日志文件,如果不配置日志会输出到标准输出中。 | +| `worker-addr` | DM-worker 服务的地址,可以省略 IP 信息,例如:":8262"。| +| `advertise-addr` | DM-worker 向外界宣告的地址。 | +| `join` | 对应一个或多个 DM-master 配置中的 [`master-addr`](/dm/dm-master-configuration-file.md#global-配置)。 | +| `keepalive-ttl` | 当绑定的上游数据源没有启用 relay log 时,DM-worker 向 DM-master 保持存活的周期,单位为秒。默认是 60 秒。 | +| `relay-keepalive-ttl` | 当绑定的上游数据源启用 relay log 时,DM-worker 向 DM-master 保持存活的周期,单位为秒。默认是 1800 秒。在版本 2.0.2 新增。 | +| `relay-dir` | 当绑定的上游数据源启用 relay log 时,DM-worker 将 relay log 保存在该路径下。该配置优先级比上游数据源配置更高。在版本 5.4.0 新增。 | +| `ssl-ca` | DM-worker 组件用于与其它组件连接的 SSL CA 证书所在的路径 | +| `ssl-cert` | DM-worker 组件用于与其它组件连接的 PEM 格式的 X509 证书所在的路径 | +| `ssl-key` | DM-worker 组件用于与其它组件连接的 PEM 格式的 X509 密钥所在的路径 | +| `cert-allowed-cn` | 证书检查 Common Name 列表 | diff --git a/markdown-pages/zh/tidb/master/dm/dm-worker-intro.md b/markdown-pages/zh/tidb/master/dm/dm-worker-intro.md new file mode 100644 index 0000000..0e7f6dc --- /dev/null +++ b/markdown-pages/zh/tidb/master/dm/dm-worker-intro.md @@ -0,0 +1,97 @@ +--- +title: DM-worker 简介 +aliases: ['/docs-cn/tidb-data-migration/dev/dm-worker-intro/'] +summary: DM-worker 是 DM (Data Migration) 的一个组件,负责执行数据迁移任务。主要功能包括注册为 MySQL 或 MariaDB 服务器的 slave,读取 binlog event 并持久化保存在本地,支持迁移一个 MySQL 或 MariaDB 实例的数据到多个 TiDB 实例,以及支持迁移多个 MySQL 或 MariaDB 实例的数据到一个 TiDB 实例。处理单元包括 Relay log、dump、load 和 Binlog replication/sync。上游数据库用户需具有 SELECT、RELOAD、REPLICATION SLAVE 和 REPLICATION CLIENT 权限,下游数据库用户需具有 SELECT、INSERT、UPDATE、DELETE、CREATE、DROP 和 INDEX 权限。处理单元所需的最小权限根据具体情况可能会改变。 +--- + +# DM-worker 简介 + +DM-worker 是 DM (Data Migration) 的一个组件,负责执行具体的数据迁移任务。 + +其主要功能如下: + +- 注册为一台 MySQL 或 MariaDB 服务器的 slave。 +- 读取 MySQL 或 MariaDB 的 binlog event,并将这些 event 持久化保存在本地 (relay log)。 +- 单个 DM-worker 支持迁移一个 MySQL 或 MariaDB 实例的数据到下游的多个 TiDB 实例。 +- 多个 DM-Worker 支持迁移多个 MySQL 或 MariaDB 实例的数据到下游的一个 TiDB 实例。 + +## DM-worker 处理单元 + +DM-worker 任务包含如下多个逻辑处理单元。 + +### Relay log + +Relay log 持久化保存从上游 MySQL 或 MariaDB 读取的 binlog,并对 binlog replication 处理单元提供读取 binlog event 的功能。 + +其原理和功能与 MySQL relay log 类似,详见 [MySQL Relay Log](https://dev.mysql.com/doc/refman/8.0/en/replica-logs-relaylog.html)。 + +### dump 处理单元 + +dump 处理单元从上游 MySQL 或 MariaDB 导出全量数据到本地磁盘。 + +### load 处理单元 + +load 处理单元读取 dump 处理单元导出的数据文件,然后加载到下游 TiDB。 + +### Binlog replication/sync 处理单元 + +Binlog replication/sync 处理单元读取上游 MySQL/MariaDB 的 binlog event 或 relay log 处理单元的 binlog event,将这些 event 转化为 SQL 语句,再将这些 SQL 语句应用到下游 TiDB。 + +## DM-worker 所需权限 + +本小节主要介绍使用 DM-worker 时所需的上下游数据库用户权限以及各处理单元所需的用户权限。 + +### 上游数据库用户权限 + +上游数据库 (MySQL/MariaDB) 用户必须拥有以下权限: + +| 权限 | 作用域 | +|:----|:----| +| `SELECT` | Tables | +| `RELOAD` | Global | +| `REPLICATION SLAVE` | Global | +| `REPLICATION CLIENT` | Global | + +如果要迁移 `db1` 的数据到 TiDB,可执行如下的 `GRANT` 语句: + +```sql +GRANT RELOAD,REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'your_user'@'your_wildcard_of_host' +GRANT SELECT ON db1.* TO 'your_user'@'your_wildcard_of_host'; +``` + +如果还要迁移其他数据库的数据到 TiDB,请确保已赋予这些库跟 `db1` 一样的权限。 + +### 下游数据库用户权限 + +下游数据库 (TiDB) 用户必须拥有以下权限: + +| 权限 | 作用域 | +|:----|:----| +| `SELECT` | Tables | +| `INSERT` | Tables | +| `UPDATE` | Tables | +| `DELETE` | Tables | +| `CREATE` | Databases,tables | +| `DROP` | Databases,tables | +| `ALTER` | Tables | +| `INDEX` | Tables | + +对要执行迁移操作的数据库或表执行下面的 `GRANT` 语句: + +```sql +GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP,ALTER,INDEX ON db.table TO 'your_user'@'your_wildcard_of_host'; +GRANT ALL ON dm_meta.* TO 'your_user'@'your_wildcard_of_host'; +``` + +### 处理单元所需的最小权限 + +| 处理单元 | 最小上游 (MySQL/MariaDB) 权限 | 最小下游 (TiDB) 权限 | 最小系统权限 | +|:----|:--------------------|:------------|:----| +| Relay log | `REPLICATION SLAVE` (读取 binlog)
`REPLICATION CLIENT` (`show master status`, `show slave status`) | 无 | 本地读/写磁盘 | +| Dump | `SELECT`
`RELOAD`(获取读锁将表数据刷到磁盘,进行一些操作后,再释放读锁对表进行解锁)| 无 | 本地写磁盘 | +| Load | 无 | `SELECT`(查询 checkpoint 历史)
`CREATE`(创建数据库或表)
`DELETE`(删除 checkpoint)
`INSERT`(插入 dump 数据)| 读/写本地文件 | +| Binlog replication | `REPLICATION SLAVE`(读 binlog)
`REPLICATION CLIENT` (`show master status`, `show slave status`) | `SELECT`(显示索引和列)
`INSERT` (DML)
`UPDATE` (DML)
`DELETE` (DML)
`CREATE`(创建数据库或表)
`DROP`(删除数据库或表)
`ALTER`(修改表)
`INDEX`(创建或删除索引)| 本地读/写磁盘 | + +> **注意:** +> +> 这些权限并非一成不变。随着需求改变,这些权限也可能会改变。 diff --git a/markdown-pages/zh/tidb/master/dm/feature-expression-filter.md b/markdown-pages/zh/tidb/master/dm/feature-expression-filter.md new file mode 100644 index 0000000..4896b2d --- /dev/null +++ b/markdown-pages/zh/tidb/master/dm/feature-expression-filter.md @@ -0,0 +1,12 @@ +--- +title: 通过 SQL 表达式过滤 DML +summary: 增量数据迁移时可通过 SQL 表达式过滤 binlog event,例如不向下游迁移 `DELETE` 事件。从 v2.0.5 起,DM 支持使用 `binlog value filter` 过滤迁移数据。在 `ROW` 格式的 binlog 中,可以基于列的值配置 SQL 表达式。如果表达式结果为 `TRUE`,DM 就不会向下游迁移该条行变更。具体操作步骤和实现细节,请参考如何通过 SQL 表达式过滤 DML。 +--- + +# 通过 SQL 表达式过滤 DML + +在进行增量数据迁移时,可以通过[如何过滤 binlog 事件](/filter-binlog-event.md)功能过滤某些类型的 binlog event,例如不向下游迁移 `DELETE` 事件以达到归档、审计等目的。但是 binlog event filter 无法以更细粒度判断某一行的 `DELETE` 事件是否要被过滤。 + +为了解决上述问题,从 v2.0.5 起,DM 支持在增量数据同步阶段使用`binlog value filter`过滤迁移数据。DM 支持的 `ROW` 格式的 binlog 中,binlog event 带有所有列的值。你可以基于这些值配置 SQL 表达式。如果该表达式对于某条行变更的计算结果是 `TRUE`,DM 就不会向下游迁移该条行变更。 + +具体操作步骤和实现细节,请参考[如何通过 SQL 表达式过滤 DML](/filter-dml-event.md)。 diff --git a/markdown-pages/zh/tidb/master/dm/feature-online-ddl.md b/markdown-pages/zh/tidb/master/dm/feature-online-ddl.md new file mode 100644 index 0000000..6f88a5c --- /dev/null +++ b/markdown-pages/zh/tidb/master/dm/feature-online-ddl.md @@ -0,0 +1,221 @@ +--- +title: 迁移使用 GH-ost/PT-osc 的源数据库 +aliases: ['/docs-cn/tidb-data-migration/dev/feature-online-ddl-scheme/','/zh/tidb-data-migration/stable/feature-online-ddl-scheme'] +summary: 使用 GH-ost/PT-osc 进行在线 DDL 工具执行 DDL 时,会产生锁表操作,阻塞数据库读写。为降低影响,可选择在线 DDL 工具 gh-ost 和 pt-osc。在 DM 迁移 MySQL 到 TiDB 时,可开启 `online-ddl` 配置,实现 DM 工具与 gh-ost 或 pt-osc 的协同。 DM 与 online DDL 工具协作细节包括 gh-ost 和 pt-osc 的实现过程,以及自定义规则配置。 +--- + +# 迁移使用 GH-ost/PT-osc 的源数据库 + +在生产业务中执行 DDL 时,产生的锁表操作会一定程度阻塞数据库的读取或者写入。为了把对读写的影响降到最低,用户往往会选择 online DDL 工具执行 DDL。常见的 Online DDL 工具有 [gh-ost](https://github.com/github/gh-ost) 和 [pt-osc](https://www.percona.com/doc/percona-toolkit/3.0/pt-online-schema-change.html)。 + +在使用 DM 完成 MySQL 到 TiDB 的数据迁移时,可以开启`online-ddl`配置,实现 DM 工具与 gh-ost 或 pt-osc 的协同。关于如何开启 `online-ddl`配置及开启该配置后的工作流程,请参考[上游使用 pt-osc/gh-ost 工具的持续同步场景](/migrate-with-pt-ghost.md)。本文仅介绍 DM 与 online DDL 工具协作的细节。 + +## DM 与 online DDL 工具协作细节 + +DM 与 online DDL 工具 [gh-ost](https://github.com/github/gh-ost) 和 [pt-osc](https://www.percona.com/doc/percona-toolkit/3.0/pt-online-schema-change.html) 在实现 online-schema-change 过程中的协作细节如下。 + +### online-schema-change: gh-ost + +gh-ost 在实现 online-schema-change 的过程会产生 3 种 table: + +- `gho`:用于应用 DDL,待 `gho` 表中数据迁移到与 origin table 一致后,通过 rename 的方式替换 origin table。 +- `ghc`:用于存放 online-schema-change 相关的信息。 +- `del`:对 origin table 执行 rename 操作而生成。 + +DM 在迁移过程中会把上述 table 分成 3 类: + +- ghostTable : `_*_gho` +- trashTable : `_*_ghc`、`_*_del` +- realTable : 执行 online-ddl 的 origin table + +**gh-ost** 涉及的主要 SQL 以及 DM 的处理: + +1. 创建 `_ghc` 表: + + ```sql + Create /* gh-ost */ table `test`.`_test4_ghc` ( + id bigint auto_increment, + last_update timestamp not null DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + hint varchar(64) charset ascii not null, + value varchar(4096) charset ascii not null, + primary key(id), + unique key hint_uidx(hint) + ) auto_increment=256 ; + ``` + + DM:不执行 `_test4_ghc` 的创建操作。 + +2. 创建 `_gho` 表: + + ```sql + Create /* gh-ost */ table `test`.`_test4_gho` like `test`.`test4` ; + ``` + + DM:不执行 `_test4_gho` 的创建操作,根据 ghost_schema、ghost_table 以及 dm_worker 的 `server_id`,删除下游 `dm_meta.{task_name}_onlineddl` 的记录,清理内存中的相关信息。 + + ```sql + DELETE FROM dm_meta.{task_name}_onlineddl WHERE id = {server_id} and ghost_schema = {ghost_schema} and ghost_table = {ghost_table}; + ``` + +3. 在 `_gho` 表应用需要执行的 DDL: + + ```sql + Alter /* gh-ost */ table `test`.`_test4_gho` add column cl1 varchar(20) not null ; + ``` + + DM:不执行 `_test4_gho` 的 DDL 操作,而是把该 DDL 记录到 `dm_meta.{task_name}_onlineddl` 以及内存中。 + + ```sql + REPLACE INTO dm_meta.{task_name}_onlineddl (id, ghost_schema , ghost_table , ddls) VALUES (......); + ``` + +4. 往 `_ghc` 表写入数据,以及往 `_gho` 表同步 origin table 的数据: + + ```sql + INSERT /* gh-ost */ INTO `test`.`_test4_ghc` VALUES (......); + + INSERT /* gh-ost `test`.`test4` */ ignore INTO `test`.`_test4_gho` (`id`, `date`, `account_id`, `conversion_price`, `ocpc_matched_conversions`, `ad_cost`, `cl2`) + (SELECT `id`, `date`, `account_id`, `conversion_price`, `ocpc_matched_conversions`, `ad_cost`, `cl2` FROM `test`.`test4` FORCE INDEX (`PRIMARY`) + WHERE (((`id` > _binary'1') OR ((`id` = _binary'1'))) AND ((`id` < _binary'2') OR ((`id` = _binary'2')))) lock IN share mode + ) ; + ``` + + DM:只要不是 **realtable** 的 DML 全部不执行。 + +5. 数据同步完成后 origin table 与 `_gho` 一起改名,完成 online DDL 操作: + + ```sql + Rename /* gh-ost */ table `test`.`test4` to `test`.`_test4_del`, `test`.`_test4_gho` to `test`.`test4`; + ``` + + DM 执行以下两个操作: + + - 把 rename 语句拆分成两个 SQL: + + ```sql + rename test.test4 to test._test4_del; + rename test._test4_gho to test.test4; + ``` + + - 不执行 `rename to _test4_del`。当要执行 `rename ghost_table to origin table` 的时候,并不执行 rename 语句,而是把步骤 3 记录在内存中的 DDL 读取出来,然后把 ghost_table、ghost_schema 替换为 origin_table 以及对应的 schema,再执行替换后的 DDL。 + + ```sql + alter table test._test4_gho add column cl1 varchar(20) not null; + --替换为 + alter table test.test4 add column cl1 varchar(20) not null; + ``` + +> **注意:** +> +> 具体 gh-ost 的 SQL 会根据工具执行时所带的参数而变化。本文只列出主要的 SQL,具体可以参考 [gh-ost 官方文档](https://github.com/github/gh-ost#gh-ost)。 + +### online-schema-change: pt + +pt-osc 在实现 online-schema-change 的过程会产生 2 种 table: + +- `new`:用于应用 DDL,待表中数据同步到与 origin table 一致后,再通过 rename 的方式替换 origin table。 +- `old`:对 origin table 执行 rename 操作后生成。 +- 3 种 **trigger**:`pt_osc_*_ins`、`pt_osc_*_upd`、`pt_osc_*_del`,用于在 pt_osc 过程中,同步 origin table 新产生的数据到 `new`。 + +DM 在迁移过程中会把上述 table 分成 3 类: + +- ghostTable : `_*_new` +- trashTable : `_*_old` +- realTable : 执行的 online-ddl 的 origin table + +pt-osc 主要涉及的 SQL 以及 DM 的处理: + +1. 创建 `_new` 表: + + ```sql + CREATE TABLE `test`.`_test4_new` (id int(11) NOT NULL AUTO_INCREMENT, + date date DEFAULT NULL, account_id bigint(20) DEFAULT NULL, conversion_price decimal(20,3) DEFAULT NULL, ocpc_matched_conversions bigint(20) DEFAULT NULL, ad_cost decimal(20,3) DEFAULT NULL,cl2 varchar(20) COLLATE utf8mb4_bin NOT NULL,cl1 varchar(20) COLLATE utf8mb4_bin NOT NULL,PRIMARY KEY (id) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ; + ``` + + DM: 不执行 `_test4_new` 的创建操作。根据 ghost_schema、ghost_table 以及 dm_worker 的 `server_id`,删除下游 `dm_meta.{task_name}_onlineddl` 的记录,清理内存中的相关信息。 + + ```sql + DELETE FROM dm_meta.{task_name}_onlineddl WHERE id = {server_id} and ghost_schema = {ghost_schema} and ghost_table = {ghost_table}; + ``` + +2. 在 `_new` 表上执行 DDL: + + ```sql + ALTER TABLE `test`.`_test4_new` add column c3 int; + ``` + + DM: 不执行 `_test4_new` 的 DDL 操作,而是把该 DDL 记录到 `dm_meta.{task_name}_onlineddl` 以及内存中。 + + ```sql + REPLACE INTO dm_meta.{task_name}_onlineddl (id, ghost_schema , ghost_table , ddls) VALUES (......); + ``` + +3. 创建用于同步数据的 3 个 Trigger: + + ```sql + CREATE TRIGGER `pt_osc_test_test4_del` AFTER DELETE ON `test`.`test4` ...... ; + CREATE TRIGGER `pt_osc_test_test4_upd` AFTER UPDATE ON `test`.`test4` ...... ; + CREATE TRIGGER `pt_osc_test_test4_ins` AFTER INSERT ON `test`.`test4` ...... ; + ``` + + DM: 不执行 TiDB 不支持的相关 Trigger 操作。 + +4. 往 `_new` 表同步 origin table 的数据: + + ```sql + INSERT LOW_PRIORITY IGNORE INTO `test`.`_test4_new` (`id`, `date`, `account_id`, `conversion_price`, `ocpc_matched_conversions`, `ad_cost`, `cl2`, `cl1`) SELECT `id`, `date`, `account_id`, `conversion_price`, `ocpc_matched_conversions`, `ad_cost`, `cl2`, `cl1` FROM `test`.`test4` LOCK IN SHARE MODE /*pt-online-schema-change 3227 copy table*/ + ``` + + DM: 只要不是 **realTable** 的 DML 全部不执行。 + +5. 数据同步完成后 origin table 与 `_new` 一起改名,完成 online DDL 操作: + + ```sql + RENAME TABLE `test`.`test4` TO `test`.`_test4_old`, `test`.`_test4_new` TO `test`.`test4` + ``` + + DM 执行以下两个操作: + + - 把 rename 语句拆分成两个 SQL。 + + ```sql + rename test.test4 to test._test4_old; + rename test._test4_new to test.test4; + ``` + + - 不执行 `rename to _test4_old`。当要执行 `rename ghost_table to origin table` 的时候,并不执行 rename,而是把步骤 2 记录在内存中的 DDL 读取出来,然后把 ghost_table、ghost_schema 替换为 origin_table 以及对应的 schema,再执行替换后的 DDL。 + + ```sql + ALTER TABLE `test`.`_test4_new` add column c3 int; + --替换为 + ALTER TABLE `test`.`test4` add column c3 int; + ``` + +6. 删除 `_old` 表以及 online DDL 的 3 个 Trigger: + + ```sql + DROP TABLE IF EXISTS `test`.`_test4_old`; + DROP TRIGGER IF EXISTS `pt_osc_test_test4_del` AFTER DELETE ON `test`.`test4` ...... ; + DROP TRIGGER IF EXISTS `pt_osc_test_test4_upd` AFTER UPDATE ON `test`.`test4` ...... ; + DROP TRIGGER IF EXISTS `pt_osc_test_test4_ins` AFTER INSERT ON `test`.`test4` ...... ; + ``` + + DM: 不执行 `_test4_old` 以及 Trigger 的删除操作。 + +> **注意:** +> +> 具体 pt-osc 的 SQL 会根据工具执行时所带的参数而变化。本文只列出主要的 SQL,具体可以参考 [pt-osc 官方文档](https://www.percona.com/doc/percona-toolkit/2.2/pt-online-schema-change.html)。 + +## 其他 Online Schema Change 工具 + +在某些场景下,你可能需要变更 online schema change 工具的默认行为,自定义 `ghost table` 和 `trash table` 的名称;或者期望使用 `gh-ost` 和 `pt-osc` 之外的工具(原理和变更流程仍然保持一致)。此时则需要自行编写正则表达式以匹配`ghost table` 和 `trash table`。 + +自 v2.0.7 起,DM 实验性支持修改过的 online schema change 工具。在 DM 任务配置中设置 `online-ddl=true` 后,配合 `shadow-table-rules` 和 `trash-table-rules` 即可支持通过正则表达式来匹配修改过的临时表。 + +假设自定义 pt-osc 的 `ghost table` 规则为 `_{origin_table}_pcnew`,`trash table` 规则为 `_{origin_table}_pcold`,那么自定义规则需配置如下: + +```yaml +online-ddl: true +shadow-table-rules: ["^_(.+)_(?:pcnew)$"] +trash-table-rules: ["^_(.+)_(?:pcold)$"] +``` diff --git a/markdown-pages/zh/tidb/master/dm/feature-shard-merge.md b/markdown-pages/zh/tidb/master/dm/feature-shard-merge.md new file mode 100644 index 0000000..f80752f --- /dev/null +++ b/markdown-pages/zh/tidb/master/dm/feature-shard-merge.md @@ -0,0 +1,36 @@ +--- +title: 分库分表合并迁移 +aliases: ['/docs-cn/tidb-data-migration/dev/feature-shard-merge/'] +summary: DM 提供了分库分表的合并迁移功能,可将上游 MySQL/MariaDB 实例中的表迁移到下游 TiDB 的同一个表中。支持悲观协调和乐观协调两种模式。悲观模式保证数据不出错,但可能会阻塞迁移;乐观模式处理 DDL 时不会阻塞数据迁移,但可能导致数据不一致。 +--- + +# 分库分表合并迁移 + +本文介绍了 DM 提供的分库分表的合并迁移功能,此功能可用于将上游 MySQL/MariaDB 实例中结构相同/不同的表迁移到下游 TiDB 的同一个表中。DM 不仅支持迁移上游的 DML 数据,也支持协调迁移多个上游分表的 DDL 表结构变更。 + +## 简介 + +DM 支持对上游多个分表的数据合并迁移到 TiDB 的一个表中,在迁移过程中需要协调各个分表的 DDL,以及该 DDL 前后的 DML。针对用户的使用场景,DM 支持悲观协调和乐观协调两种不同的模式。 + +> **注意:** +> +> - 要执行分库分表合并迁移任务,必须在任务配置文件中设置 `shard-mode`。 +> - DM 对分库分表的合并默认使用悲观协调模式,在文档中如果没特殊说明则默认为悲观协调模式。 +> - 在没有深入了解乐观模式的原理和使用限制的情况下不建议使用该模式,否则可能造成迁移中断甚至数据不一致的严重后果。 + +### 悲观协调模式 + +当上游一个分表执行某一 DDL 后,这个分表的迁移会暂停,并等待其他所有分表都执行了同样的 DDL 才在下游执行该 DDL 并继续数据迁移。“悲观协调”模式的优点是可以保证迁移到下游的数据不会出错,详细的介绍请参考[悲观模式下分库分表合并迁移](/dm/feature-shard-merge-pessimistic.md)。 + +### 乐观协调模式 + +在一个分表上执行的 DDL,DM 会自动修改成兼容其他分表的语句,并立即迁移到下游,不会阻挡任何分表 DML 的迁移。“乐观协调”模式的优点是处理 DDL 时不会阻塞数据的迁移,但是使用不当会有迁移中断甚至数据不一致的风险,详细的介绍请参考[乐观模式下分库分表合并迁移](/dm/feature-shard-merge-optimistic.md)。 + +### 悲观协调模式与乐观协调模式的对比 + +| 悲观协调模式 | 乐观协调模式 | +| :----------- | :----------- | +| 发起 DDL 的分表会暂停 DML 迁移 | 发起 DDL 的分表会继续 DML 迁移 | +| 每个分表的 DDL 执行次序和语句必须相同 | 每个分表只需保持表结构互相兼容即可 | +| DDL 在整个分表群达成一致后才迁移到下游 | 每个分表的 DDL 会即时影响下游 | +| 错误的 DDL 操作在侦测到后可以被拦截 | 错误的 DDL 操作也会被迁移到下游,可能在侦测到之前已使部分上下游数据不一致 | diff --git a/markdown-pages/zh/tidb/master/dm/manually-handling-sharding-ddl-locks.md b/markdown-pages/zh/tidb/master/dm/manually-handling-sharding-ddl-locks.md new file mode 100644 index 0000000..7055e0b --- /dev/null +++ b/markdown-pages/zh/tidb/master/dm/manually-handling-sharding-ddl-locks.md @@ -0,0 +1,380 @@ +--- +title: 手动处理 Sharding DDL Lock +aliases: ['/docs-cn/tidb-data-migration/dev/manually-handling-sharding-ddl-locks/','/docs-cn/tidb-data-migration/dev/feature-manually-handling-sharding-ddl-locks/'] +summary: DM 使用 sharding DDL lock 来确保分库分表的 DDL 操作可以正确执行。在异常情况下,需要手动处理异常的 DDL lock。使用 shard-ddl-lock 命令查看 DDL lock 信息,使用 shard-ddl-lock unlock 命令请求 DM-master 解除指定的 DDL lock。支持处理部分 MySQL source 被移除和 unlock 过程中部分 DM-worker 异常停止或网络中断的情况。 +--- + +# 手动处理 Sharding DDL Lock + +DM (Data Migration) 使用 sharding DDL lock 来确保分库分表的 DDL 操作可以正确执行。绝大多数情况下,该锁定机制可自动完成;但在部分异常情况发生时,需要使用 `shard-ddl-lock` 手动处理异常的 DDL lock。 + +> **注意:** +> +> - 本文档只适用于悲观协调模式下 sharding DDL lock 的处理。 +> - 本文档的命令在交互模式中进行,因此在以下命令示例中未添加转义字符。在命令行模式中,你需要添加转义字符,防止报错。 +> - 不要轻易使用 `shard-ddl-lock unlock` 命令,除非完全明确当前场景下使用这些命令可能会造成的影响,并能接受这些影响。 +> - 在手动处理异常的 DDL lock 前,请确保已经了解 DM 的[分库分表合并迁移原理](/dm/feature-shard-merge-pessimistic.md#实现原理)。 + +## 命令介绍 + +### `shard-ddl-lock` + +该命令用于查看 DDL lock 和主动请求 DM-master 解除指定的 DDL lock。命令仅在 DM v6.0 及其以后版本支持,之前版本可使用 `show-ddl-locks` 和 `unlock-ddl-lock` 命令。 + +```bash +shard-ddl-lock -h +``` + +``` +maintain or show shard-ddl locks information + +Usage: + dmctl shard-ddl-lock [task] [flags] + dmctl shard-ddl-lock [command] + +Available Commands: + unlock Unlock un-resolved DDL locks forcely + +Flags: + -h, --help help for shard-ddl-lock + +Global Flags: + -s, --source strings MySQL Source ID. + +Use "dmctl shard-ddl-lock [command] --help" for more information about a command. +``` + +#### 参数解释 + ++ `shard-ddl-lock [task] [flags]`: + - 用于查询当前 DM-master 上存在的 DDL lock 信息 + ++ `shard-ddl-lock [command]` + - 用于主动请求 DM-master 解除指定的 DDL lock, `command` 只支持 `unlock` + +## 命令示例 + +### `shard-ddl-lock [task] [flags]` + +使用 `shard-ddl-lock [task] [flags]` 命令,查询当前 DM-master 上存在的 DDL lock 信息。 + +例如: + +```bash +shard-ddl-lock test +``` + +
+期望输出 + +``` +{ + "result": true, # 查询 lock 操作本身是否成功 + "msg": "", # 查询 lock 操作失败时的原因或其它描述信息(如不存在任务 lock) + "locks": [ # 当前存在的 lock 信息列表 + { + "ID": "test-`shard_db`.`shard_table`", # lock 的 ID 标识,当前由任务名与 DDL 对应的 schema/table 信息组成 + "task": "test", # lock 所属的任务名 + "mode": "pessimistic" # shard DDL 协调模式,可为悲观模式 "pessimistic" 或乐观模式 "optimistic" + "owner": "mysql-replica-01", # lock 的 owner(在悲观模式时为第一个遇到该 DDL 的 source ID),在乐观模式时总为空 + "DDLs": [ # 在悲观模式时为 lock 对应的 DDL 列表,在乐观模式时总为空 + "USE `shard_db`; ALTER TABLE `shard_db`.`shard_table` DROP COLUMN `c2`;" + ], + "synced": [ # 已经收到对应 MySQL 实例内所有分表 DDL 的 source 列表 + "mysql-replica-01" + ], + "unsynced": [ # 尚未收到对应 MySQL 实例内所有分表 DDL 的 source 列表 + "mysql-replica-02" + ] + } + ] +} +``` + +
+ +### `shard-ddl-lock unlock` + +用于主动请求 DM-master 解除指定的 DDL lock,包括的操作:请求 owner 执行 DDL 操作,请求其他非 owner 的 DM-worker 跳过 DDL 操作,移除 DM-master 上的 lock 信息。 + +> **注意:** +> +> `shard-ddl-lock unlock` 当前仅对悲观协调模式 (`pessimistic`) 下产生的 lock 有效。 + +```bash +shard-ddl-lock unlock -h +``` + +``` +Unlock un-resolved DDL locks forcely + +Usage: + dmctl shard-ddl-lock unlock [flags] + +Flags: + -a, --action string accept skip/exec values which means whether to skip or execute ddls (default "skip") + -d, --database string database name of the table + -f, --force-remove force to remove DDL lock + -h, --help help for unlock + -o, --owner string source to replace the default owner + -t, --table string table name + +Global Flags: + -s, --source strings MySQL Source ID. +``` + +`shard-ddl-lock unlock` 命令支持以下参数: + ++ `-o, --owner`: + - flag 参数,string,可选 + - 不指定时,请求默认的 owner(`shard-ddl-lock` 返回结果中的 `owner`)执行 DDL 操作;指定时,请求该 MySQL source(替代默认的 owner)执行 DDL 操作 + - 除非原 owner 已经从集群中移除,否则不应该指定新的 owner + ++ `-f, --force-remove`: + - flag 参数,boolean,可选 + - 不指定时,仅在 owner 执行 DDL 成功时移除 lock 信息;指定时,即使 owner 执行 DDL 失败也强制移除 lock 信息(此后将无法再次查询或操作该 lock) + ++ `lock-id`: + - 非 flag 参数,string,必选 + - 指定需要执行 unlock 操作的 DDL lock ID(即 `shard-ddl-lock` 返回结果中的 `ID`) + +以下是一个使用 `shard-ddl-lock unlock` 命令的示例: + +```bash +shard-ddl-lock unlock test-`shard_db`.`shard_table` +``` + +``` +{ + "result": true, # unlock lock 操作是否成功 + "msg": "", # unlock lock 操作失败时的原因 +} +``` + +## 支持场景 + +目前,使用 `shard-ddl-lock unlock` 命令仅支持处理以下两种 sharding DDL lock 异常情况。 + +### 场景一:部分 MySQL source 被移除 + +#### Lock 异常原因 + +在 DM-master 尝试自动 unlock sharding DDL lock 之前,需要等待所有 MySQL source 的 sharding DDL events 全部到达(详见[分库分表合并迁移原理](/dm/feature-shard-merge-pessimistic.md#实现原理))。如果 sharding DDL 已经在迁移过程中,同时有部分 MySQL source 被移除,且不再计划重新加载它们(按业务需求移除了这部分 MySQL source),则会由于永远无法等齐所有的 DDL 而造成 lock 无法自动 unlock。 + +#### 手动处理示例 + +假设上游有 MySQL-1(`mysql-replica-01`)和 MySQL-2(`mysql-replica-02`)两个实例,其中 MySQL-1 中有 `shard_db_1`.`shard_table_1` 和 `shard_db_1`.`shard_table_2` 两个表,MySQL-2 中有 `shard_db_2`.`shard_table_1` 和 `shard_db_2`.`shard_table_2` 两个表。现在需要将这 4 个表合并后迁移到下游 TiDB 的 `shard_db`.`shard_table` 表中。 + +初始表结构如下: + +```sql +SHOW CREATE TABLE shard_db_1.shard_table_1; +``` + +``` ++---------------+------------------------------------------+ +| Table | Create Table | ++---------------+------------------------------------------+ +| shard_table_1 | CREATE TABLE `shard_table_1` ( + `c1` int(11) NOT NULL, + PRIMARY KEY (`c1`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 | ++---------------+------------------------------------------+ +``` + +上游分表将执行以下 DDL 语句变更表结构: + +```sql +ALTER TABLE shard_db_*.shard_table_* ADD COLUMN c2 INT; +``` + +MySQL 及 DM 操作与处理流程如下: + +1. `mysql-replica-01` 对应的两个分表执行了对应的 DDL 操作进行表结构变更。 + + ```sql + ALTER TABLE shard_db_1.shard_table_1 ADD COLUMN c2 INT; + ``` + + ```sql + ALTER TABLE shard_db_1.shard_table_2 ADD COLUMN c2 INT; + ``` + +2. DM-worker 接受到 `mysql-replica-01` 两个分表的 DDL 之后,将对应的 DDL 信息发送给 DM-master,DM-master 创建相应的 DDL lock。 +3. 使用 `shard-ddl-lock` 查看当前的 DDL lock 信息。 + + ```bash + shard-ddl-lock test + ``` + + ``` + { + "result": true, + "msg": "", + "locks": [ + { + "ID": "test-`shard_db`.`shard_table`", + "task": "test", + "mode": "pessimistic" + "owner": "mysql-replica-01", + "DDLs": [ + "USE `shard_db`; ALTER TABLE `shard_db`.`shard_table` ADD COLUMN `c2` int(11);" + ], + "synced": [ + "mysql-replica-01" + ], + "unsynced": [ + "mysql-replica-02" + ] + } + ] + } + ``` + +4. 由于业务需要,`mysql-replica-02` 对应的数据不再需要迁移到下游 TiDB,对 `mysql-replica-02` 执行了移除操作。 +5. DM-master 上 ID 为 ```test-`shard_db`.`shard_table` ``` 的 lock 无法等到 `mysql-replica-02` 的 DDL 操作信息。 + + `shard-ddl-lock` 返回的 `unsynced` 中一直包含 `mysql-replica-02` 的信息。 + +6. 使用 `shard-ddl-lock unlock` 来请求 DM-master 主动 unlock 该 DDL lock。 + + - 如果 DDL lock 的 owner 也已经被移除,可以使用 `--owner` 参数指定其他 MySQL source 作为新 owner 来执行 DDL。 + - 当存在任意 MySQL source 报错时,`result` 将为 `false`,此时请仔细检查各 MySQL source 的错误是否是预期可接受的。 + + ```bash + shard-ddl-lock unlock test-`shard_db`.`shard_table` + ``` + + ``` + { + "result": true, + "msg": "" + ``` + +7. 使用 `shard-ddl-lock` 确认 DDL lock 是否被成功 unlock。 + + ```bash + shard-ddl-lock test + ``` + + ``` + { + "result": true, + "msg": "no DDL lock exists", + "locks": [ + ] + } + ``` + +8. 查看下游 TiDB 中的表结构是否变更成功。 + + ```sql + SHOW CREATE TABLE shard_db.shard_table; + ``` + + ``` + +-------------+--------------------------------------------------+ + | Table | Create Table | + +-------------+--------------------------------------------------+ + | shard_table | CREATE TABLE `shard_table` ( + `c1` int(11) NOT NULL, + `c2` int(11) DEFAULT NULL, + PRIMARY KEY (`c1`) + ) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_bin | + +-------------+--------------------------------------------------+ + ``` + +9. 使用 `query-status` 确认迁移任务是否正常。 + +#### 手动处理后的影响 + +使用 `shard-ddl-lock unlock` 手动执行 unlock 操作后,由于该任务的配置信息中仍然包含了已下线的 MySQL source,如果不进行处理,则当下次 sharding DDL 到达时,仍会出现 lock 无法自动完成迁移的情况。 + +因此,在手动解锁 DDL lock 后,需要再执行以下操作: + +1. 使用 `stop-task` 停止运行中的任务。 +2. 更新任务配置文件,将已下线 MySQL source 对应的信息从配置文件中移除。 +3. 使用 `start-task` 及新任务配置文件重新启动任务。 + +> **注意:** +> +> 在 `shard-ddl-lock unlock` 之后,如果已下线的 MySQL source 重新加载并尝试对其中的分表进行数据迁移,则会由于数据与下游的表结构不匹配而发生错误。 + +### 场景二:unlock 过程中部分 DM-worker 异常停止或网络中断 + +#### Lock 异常原因 + +在 DM-master 收到所有 DM-worker 的 DDL 信息后,执行自动 unlock DDL lock 的操作主要包括以下步骤: + +1. 请求 lock owner 执行 DDL 操作,并更新对应分表的 checkpoint。 +2. 在 owner 执行 DDL 操作成功后,移除 DM-master 上保存的 DDL lock 信息。 +3. 在 owner 执行 DDL 操作成功后,请求其他所有非 owner 跳过 DDL 操作并更新对应分表的 checkpoint。 +4. DM-master 在所有 owner/非 owner 操作成功后,移除对应的 DDL lock 信息。 + +上述 unlock DDL lock 的操作不是原子的。如果非 owner 跳过 DDL 操作成功后,所在的 DM-worker 异常停止或与下游 TiDB 发生网络异常,造成无法成功更新 checkpoint。 + +当非 owner 对应的 MySQL source 恢复数据迁移时,会尝试请求 DM-master 重新协调异常发生前已经协调过的 DDL、且永远无法等到其他 MySQL source 的对应 DDL,造成该 DDL 操作对应 lock 的自动 unlock。 + +#### 手动处理示例 + +仍然假设是[部分 MySQL source 被移除](#场景一部分-mysql-source-被移除)示例中的上下游表结构及合表迁移需求。 + +当在 DM-master 自动执行 unlock 操作的过程中,owner (`mysql-replica-01`) 成功执行了 DDL 操作且开始继续进行后续迁移,但在请求非 owner (`mysql-replica-02`) 跳过 DDL 操作的过程中,由于对应的 DM-worker 发生了重启在跳过 DDL 后未能更新 checkpoint。 + +`mysql-replica-02` 对应的数据迁移子任务恢复后,将在 DM-master 上创建一个新的 lock,但其他 MySQL source 此时已经执行或跳过 DDL 操作并在进行后续迁移。 + +处理流程如下: + +1. 使用 `shard-ddl-lock` 确认 DM-master 上存在该 DDL 操作对应的 lock。 + + 应该仅有 `mysql-replica-02` 处于 `synced` 状态: + + ```bash + shard-ddl-lock + ``` + + ``` + { + "result": true, + "msg": "", + "locks": [ + { + "ID": "test-`shard_db`.`shard_table`", + "task": "test", + "mode": "pessimistic" + "owner": "mysql-replica-02", + "DDLs": [ + "USE `shard_db`; ALTER TABLE `shard_db`.`shard_table` ADD COLUMN `c2` int(11);" + ], + "synced": [ + "mysql-replica-02" + ], + "unsynced": [ + "mysql-replica-01" + ] + } + ] + } + ``` + +2. 使用 `shard-ddl-lock unlock` 请求 DM-master unlock 该 lock。 + + - Lock 过程中会尝试再次向下游执行该 DDL 操作(重启前的原 owner 已向下游执行过该 DDL 操作),需要确保该 DDL 操作可被多次执行。 + + ```bash + shard-ddl-lock unlock test-`shard_db`.`shard_table` + ``` + + ``` + { + "result": true, + "msg": "", + } + ``` + +3. 使用 `shard-ddl-lock` 确认 DDL lock 是否被成功 unlock。 +4. 使用 `query-status` 确认迁移任务是否正常。 + +#### 手动处理后的影响 + +手动 unlock sharding DDL lock 后,后续的 sharding DDL 将可以自动正常迁移。 diff --git a/markdown-pages/zh/tidb/master/dm/migrate-data-using-dm.md b/markdown-pages/zh/tidb/master/dm/migrate-data-using-dm.md new file mode 100644 index 0000000..49f9d22 --- /dev/null +++ b/markdown-pages/zh/tidb/master/dm/migrate-data-using-dm.md @@ -0,0 +1,180 @@ +--- +title: 使用 DM 迁移数据 +aliases: ['/docs-cn/tidb-data-migration/dev/replicate-data-using-dm/'] +summary: 本文介绍如何使用 DM 工具迁移数据。首先部署 DM 集群,然后检查集群信息和创建数据源。配置任务后,启动任务并查询任务状态。最后,停止任务并监控任务与查看日志。 +--- + +# 使用 DM 迁移数据 + +本文介绍如何使用 DM 工具迁移数据。 + +## 第 1 步:部署 DM 集群 + +推荐[使用 TiUP 部署 DM 集群](/dm/deploy-a-dm-cluster-using-tiup.md);也可以[使用 binary 部署 DM 集群](/dm/deploy-a-dm-cluster-using-binary.md)用于体验或测试。 + +> **注意:** +> +> - 在 DM 所有的配置文件中,对于数据库密码推荐使用 dmctl 加密后的密文。如果数据库密码为空,则不需要加密。关于如何使用 dmctl 加密明文密码,参考[使用 dmctl 加密数据库密码](/dm/dm-manage-source.md#加密数据库密码)。 +> - 上下游数据库用户必须拥有相应的读写权限。 + +## 第 2 步:检查集群信息 + +使用 TiUP 部署 DM 集群后,相关配置信息如下: + +- DM 集群相关组件配置信息 + + | 组件 | 主机 | 端口 | + |:------|:---- |:---- | + | dm_worker1 | 172.16.10.72 | 8262 | + | dm_worker2 | 172.16.10.73 | 8262 | + | dm_master | 172.16.10.71 | 8261 | + +- 上下游数据库实例相关信息 + + | 数据库实例 | 主机 | 端口 | 用户名 | 加密密码 | + |:-------- |:--- | :--- | :--- | :--- | + | 上游 MySQL-1 | 172.16.10.81 | 3306 | root | VjX8cEeTX+qcvZ3bPaO4h0C80pe/1aU= | + | 上游 MySQL-2 | 172.16.10.82 | 3306 | root | VjX8cEeTX+qcvZ3bPaO4h0C80pe/1aU= | + | 下游 TiDB | 172.16.10.83 | 4000 | root | | + +上游 MySQL 数据库实例用户所需权限参见[上游 MySQL 实例配置前置检查](/dm/dm-precheck.md)介绍。 + +## 第 3 步:创建数据源 + +1. 将 MySQL-1 的相关信息写入到 `conf/source1.yaml` 中: + + ```yaml + # MySQL1 Configuration. + + source-id: "mysql-replica-01" + + # DM-worker 是否使用全局事务标识符 (GTID) 拉取 binlog。使用前提是在上游 MySQL 已开启 GTID 模式。 + enable-gtid: false + + from: + host: "172.16.10.81" + user: "root" + password: "VjX8cEeTX+qcvZ3bPaO4h0C80pe/1aU=" + port: 3306 + ``` + +2. 在终端中执行下面的命令,使用 `tiup dmctl` 将 MySQL-1 的数据源配置加载到 DM 集群中: + + ```bash + tiup dmctl --master-addr 172.16.10.71:8261 operate-source create conf/source1.yaml + ``` + +3. 对于 MySQL-2,修改配置文件中的相关信息,并执行相同的 dmctl 命令。 + +## 第 4 步:配置任务 + +假设需要将 MySQL-1 和 MySQL-2 实例的 `test_db` 库的 `test_table` 表以**全量+增量**的模式迁移到下游 TiDB 的 `test_db` 库的 `test_table` 表。 + +编辑任务配置文件 `task.yaml`: + +```yaml +# 任务名,多个同时运行的任务不能重名。 +name: "test" +# 全量+增量 (all) 迁移模式。 +task-mode: "all" +# 下游 TiDB 配置信息。 +target-database: + host: "172.16.10.83" + port: 4000 + user: "root" + password: "" + +# 当前数据迁移任务需要的全部上游 MySQL 实例配置。 +mysql-instances: +- + # 上游实例或者复制组 ID,参考 `inventory.ini` 的 `source_id` 或者 `dm-master.toml` 的 `source-id 配置`。 + source-id: "mysql-replica-01" + # 需要迁移的库名或表名的黑白名单的配置项名称,用于引用全局的黑白名单配置,全局配置见下面的 `block-allow-list` 的配置。 + block-allow-list: "global" # 如果 DM 版本早于 v2.0.0-beta.2 则使用 black-white-list。 + # dump 处理单元的配置项名称,用于引用全局的 dump 处理单元配置。 + mydumper-config-name: "global" + +- + source-id: "mysql-replica-02" + block-allow-list: "global" # 如果 DM 版本早于 v2.0.0-beta.2 则使用 black-white-list。 + mydumper-config-name: "global" + +# 黑白名单全局配置,各实例通过配置项名引用。 +block-allow-list: # 如果 DM 版本早于 v2.0.0-beta.2 则使用 black-white-list。 + global: + do-tables: # 需要迁移的上游表的白名单。 + - db-name: "test_db" # 需要迁移的表的库名。 + tbl-name: "test_table" # 需要迁移的表的名称。 + +# dump 处理单元全局配置,各实例通过配置项名引用。 +mydumpers: + global: + extra-args: "" +``` + +## 第 5 步:启动任务 + +为了提前发现数据迁移任务的一些配置错误,DM 中增加了[前置检查](/dm/dm-precheck.md)功能: + +- 启动数据迁移任务时,DM 自动检查相应的权限和配置。 +- 也可使用 `check-task` 命令手动前置检查上游的 MySQL 实例配置是否符合 DM 的配置要求。 + +> **注意:** +> +> 第一次启动数据迁移任务时,必须确保上游数据库已配置。否则,启动任务时会报错。 + +使用 `tiup dmctl` 执行以下命令启动数据迁移任务。其中,`task.yaml` 是之前编辑的配置文件。 + +```bash +tiup dmctl --master-addr 172.16.10.71:8261 start-task ./task.yaml +``` + +- 如果执行该命令后返回的结果如下,则表明任务已成功启动。 + + ```json + { + "result": true, + "msg": "", + "workers": [ + { + "result": true, + "worker": "172.16.10.72:8262", + "msg": "" + }, + { + "result": true, + "worker": "172.16.10.73:8262", + "msg": "" + } + ] + } + ``` + +- 如果任务启动失败,可根据返回结果的提示进行配置变更后执行 `start-task task.yaml` 命令重新启动任务。 + +## 第 6 步:查询任务 + +如需了解 DM 集群中是否存在正在运行的迁移任务及任务状态等信息,可使用 `tiup dmctl` 执行以下命令进行查询: + +```bash +tiup dmctl --master-addr 172.16.10.71:8261 query-status +``` + +## 第 7 步:停止任务 + +如果不再需要进行数据迁移,可以使用 `tiup dmctl` 执行以下命令停止迁移任务: + +```bash +tiup dmctl --master-addr 172.16.10.71:8261 stop-task test +``` + +其中的 `test` 是 `task.yaml` 配置文件中 `name` 配置项设置的任务名。 + +## 第 8 步:监控任务与查看日志 + +如果使用 TiUP 部署 DM 集群时,正确部署了 Prometheus、Alertmanager 与 Grafana,且其地址均为 `172.16.10.71`。可在浏览器中打开 进入 Alertmanager 查看 DM 告警信息;可在浏览器中打开 进入 Grafana,选择 DM 的 dashboard 查看 DM 相关监控项。 + +DM 在运行过程中,DM-worker、DM-master 及 dmctl 都会通过日志输出相关信息。各组件的日志目录如下: + +- DM-master 日志目录:通过 DM-master 进程参数 `--log-file` 设置。如果使用 TiUP 部署 DM,则日志目录位于 `{log_dir}`。 +- DM-worker 日志目录:通过 DM-worker 进程参数 `--log-file` 设置。如果使用 TiUP 部署 DM,则日志目录位于 `{log_dir}`。 diff --git a/markdown-pages/zh/tidb/master/dm/task-configuration-file-full.md b/markdown-pages/zh/tidb/master/dm/task-configuration-file-full.md new file mode 100644 index 0000000..28384d5 --- /dev/null +++ b/markdown-pages/zh/tidb/master/dm/task-configuration-file-full.md @@ -0,0 +1,275 @@ +--- +title: DM 任务完整配置文件介绍 +aliases: ['/docs-cn/tidb-data-migration/dev/task-configuration-file-full/','/docs-cn/tidb-data-migration/dev/dm-portal/','/zh/tidb/dev/task-configuration-file'] +summary: 本文介绍了 Data Migration (DM) 的任务完整配置文件,包括全局配置和实例配置两部分。全局配置包括任务基本信息配置和功能配置集,功能配置集包括路由规则、过滤规则、block-allow-list、mydumpers、loaders 和 syncers。实例配置定义了具体的数据迁移子任务,包括路由规则、过滤规则、block-allow-list、mydumpers、loaders 和 syncers 的配置名称。 +--- + +# DM 任务完整配置文件介绍 + +本文档主要介绍 Data Migration (DM) 的任务完整的配置文件,包含[全局配置](#全局配置) 和[实例配置](#实例配置) 两部分。 + +## 关键概念 + +关于包括 `source-id` 和 DM-worker ID 在内的关键概念的介绍,请参阅[关键概念](/dm/dm-config-overview.md#关键概念)。 + +## 完整配置文件示例 + +下面是一个完整的配置文件示例,通过该示例可以完成复杂的数据迁移功能。 + +```yaml +--- + +# ----------- 全局配置 ----------- +## ********* 基本信息配置 ********* +name: test # 任务名称,需要全局唯一 +task-mode: all # 任务模式,可设为 "full" - "只进行全量数据迁移"、"incremental" - "Binlog 实时同步"、"all" - "全量 + Binlog 实时同步" +shard-mode: "pessimistic" # 任务协调模式,可选的模式有 ""、"pessimistic、"optimistic"。默认值为 "" 即无需协调。如果是分库分表合并任务,请设置为悲观协调模式 "pessimistic"。 + # 在 v2.0.6 版本后乐观模式逐渐成熟,深入了解乐观协调模式的原理和使用限制后,也可以设置为乐观协调模式 "optimistic" +strict-optimistic-shard-mode: false # 仅在乐观协调模式下生效,限制乐观协调模式的行为,默认值为 false。在 v7.2.0 中引入,详见 https://docs.pingcap.com/zh/tidb/v7.2/feature-shard-merge-optimistic +meta-schema: "dm_meta" # 下游储存 `meta` 信息的数据库 +# timezone: "Asia/Shanghai" # 指定数据迁移任务时 SQL Session 使用的时区。DM 默认使用目标库的全局时区配置进行数据迁移,并且自动确保同步数据的正确性。使用自定义时区依然可以确保整个流程的正确性,但一般不需要手动指定。 + +case-sensitive: false # schema/table 是否大小写敏感 +online-ddl: true # 支持上游 "gh-ost" 、"pt" 的自动处理 +online-ddl-scheme: "gh-ost" # `online-ddl-scheme` 已被弃用,建议使用 `online-ddl`。 +clean-dump-file: true # 是否清理 dump 阶段产生的文件,包括 metadata 文件、建库建表 SQL 文件以及数据导入 SQL 文件 +collation_compatible: "loose" # 同步 CREATE 语句中缺省 Collation 的方式,可选 "loose" 和 "strict",默认为 "loose"。"loose" 模式不会显式补充上游缺省的 Collation,"strict" 会显式补充上游缺省的 Collation。当使用 "strict" 模式,但下游不支持上游缺省的 Collation 时,下游可能会报错。 +ignore-checking-items: [] # 忽略检查项。可用值请参考 precheck 说明:https://docs.pingcap.com/zh/tidb/stable/dm-precheck。 + +target-database: # 下游数据库实例配置 + host: "192.168.0.1" + port: 4000 + user: "root" + password: "/Q7B9DizNLLTTfiZHv9WoEAKamfpIUs=" # 推荐使用经 `dmctl encrypt` 加密后的密码 + max-allowed-packet: 67108864 # 设置 DM 内部连接 TiDB 服务器时,TiDB 客户端的 "max_allowed_packet" 限制(即接受的最大数据包限制),单位为字节,默认 67108864 (64 MB) + # 该配置项从 DM v2.0.0 起弃用,DM 会自动获取连接 TiDB 的 "max_allowed_packet" + session: # 设置 TiDB 的 session 变量,在 v1.0.6 版本引入。更多变量及解释参见 `https://docs.pingcap.com/zh/tidb/stable/system-variables` + sql_mode: "ANSI_QUOTES,NO_ZERO_IN_DATE,NO_ZERO_DATE" # 从 DM v2.0.0 起,如果配置文件中没有出现该项,DM 会自动从下游 TiDB 中获得适合用于 "sql_mode" 的值。手动配置该项具有更高优先级 + tidb_skip_utf8_check: 1 # 从 DM v2.0.0 起,如果配置文件中没有出现该项,DM 会自动从下游 TiDB 中获得适合用于 "tidb_skip_utf8_check" 的值。手动配置该项具有更高优先级 + tidb_constraint_check_in_place: 0 + sql_require_primary_key: OFF # 在 session 级别控制表是否必须有主键。DM 任务创建期间,会在 TiDB 创建几个元数据表,其中有些表是无主键表。如果开启该参数,这些无主键的元数据表就无法被创建出来,导致 DM 任务创建失败。因此,需要将该参数设置为 `OFF`。 + security: # 下游 TiDB TLS 相关配置 + ssl-ca: "/path/to/ca.pem" + ssl-cert: "/path/to/cert.pem" + ssl-key: "/path/to/key.pem" + +## ******** 功能配置集 ********** + +routes: # 上游和下游表之间的路由 table routing 规则集 + route-rule-1: # 配置名称 + schema-pattern: "test_*" # 库名匹配规则,支持通配符 "*" 和 "?" + table-pattern: "t_*" # 表名匹配规则,支持通配符 "*" 和 "?" + target-schema: "test" # 目标库名称 + target-table: "t" # 目标表名称 + # 可选配置:提取各分库分表的源信息,并写入下游用户自建的列,用于标识合表中各行数据的来源。如果配置该项,需要提前在下游手动创建合表,具体可参考 “table routing 文档” 。 + # extract-table: # 提取分表去除 t_ 的后缀信息,并写入下游合表 c_table 列,例如,t_01 分表的数据会提取 01 写入下游 c_table 列 + # table-regexp: "t_(.*)" + # target-column: "c_table" + # extract-schema: # 提取分库去除 test_ 的后缀信息,并写入下游合表 c_schema 列,例如,test_02 分库的数据会提取 02 写入下游 c_schema 列 + # schema-regexp: "test_(.*)" + # target-column: "c_schema" + # extract-source: # 提取数据库源实例信息写入 c_source 列,例如,mysql-replica-01 数据源实例的数据会提取 mysql-replica-01 写入下游 c_source 列 + # source-regexp: "(.*)" + # target-column: "c_source" + route-rule-2: + schema-pattern: "test_*" + target-schema: "test" + +filters: # 上游数据库实例匹配的表的 binlog event filter 规则集 + filter-rule-1: # 配置名称 + schema-pattern: "test_*" # 库名匹配规则,支持通配符 "*" 和 "?" + table-pattern: "t_*" # 表名匹配规则,支持通配符 "*" 和 "?" + events: ["truncate table", "drop table"] # 匹配哪些 event 类型 + action: Ignore # 对与符合匹配规则的 binlog 迁移(Do)还是忽略(Ignore) + filter-rule-2: + schema-pattern: "test_*" + events: ["all dml"] + action: Do + +expression-filter: # 定义数据源迁移行变更的过滤规则,可以定义多个规则 + # 过滤 `expr_filter`.`tbl` 的 c 为偶数的插入 + even_c: # 规则名称 + schema: "expr_filter" # 要匹配的上游数据库库名,不支持通配符匹配或正则匹配 + table: "tbl" # 要匹配的上游表名,不支持通配符匹配或正则匹配 + insert-value-expr: "c % 2 = 0" + +block-allow-list: # 定义数据源迁移表的过滤规则,可以定义多个规则。如果 DM 版本早于 v2.0.0-beta.2 则使用 black-white-list + bw-rule-1: # 规则名称 + do-dbs: ["~^test.*", "user"] # 迁移哪些库 + ignore-dbs: ["mysql", "account"] # 忽略哪些库 + do-tables: # 迁移哪些表 + - db-name: "~^test.*" + tbl-name: "~^t.*" + - db-name: "user" + tbl-name: "information" + bw-rule-2: # 规则名称 + ignore-tables: # 忽略哪些表 + - db-name: "user" + tbl-name: "log" + +mydumpers: # dump 处理单元的运行配置参数 + global: # 配置名称 + threads: 4 # dump 处理单元从上游数据库实例导出数据和 check-task 访问上游的线程数量,默认值为 4 + chunk-filesize: 64 # dump 处理单元生成的数据文件大小,默认值为 64,单位为 MB + extra-args: "--consistency none" # dump 处理单元的其他参数,不需要在 extra-args 中配置 table-list,DM 会自动生成 + +loaders: # load 处理单元的运行配置参数 + global: # 配置名称 + pool-size: 16 # load 处理单元并发执行 dump 处理单元的 SQL 文件的线程数量,默认值为 16,当有多个实例同时向 TiDB 迁移数据时可根据负载情况适当调小该值 + + # 保存上游全量导出数据的目录。该配置项的默认值为 "./dumped_data"。 + # 支持配置为本地文件系统路径,也支持配置为 Amazon S3 路径,如: s3://dm_bucket/dumped_data?endpoint=s3-website.us-east-2.amazonaws.com&access_key=s3accesskey&secret_access_key=s3secretkey&force_path_style=true + dir: "./dumped_data" + + # 全量阶段数据导入的模式。可以设置为如下几种模式: + # - "logical"(默认)。使用 TiDB Lightning 逻辑导入模式进行导入。文档:https://docs.pingcap.com/zh/tidb/stable/tidb-lightning-logical-import-mode + # - "physical"。使用 TiDB Lightning 物理导入模式进行导入。文档:https://docs.pingcap.com/zh/tidb/stable/tidb-lightning-physical-import-mode + # 当前 "physical" 为实验特性,不建议在生产环境中使用。 + import-mode: "logical" + # 逻辑导入模式针对冲突数据的解决方式: + # - "replace"(默认值)。表示用最新数据替代已有数据。 + # - "ignore"。保留已有数据,忽略新数据。 + # - "error"。插入重复数据时报错并停止同步任务。 + on-duplicate-logical: "replace" + # 物理导入模式针对冲突数据的解决方式: + # - "none"(默认)。对应 TiDB Lightning 物理导入模式冲突数据检测的 "none" 选项 + # (https://docs.pingcap.com/zh/tidb/stable/tidb-lightning-physical-import-mode-usage#冲突数据检测), + # 表示遇到冲突数据时不进行处理。该模式性能最佳,但下游数据库会遇到数据索引不一致的问题。 + # - "manual"。对应 TiDB Lightning 物理导入模式冲突数据检测的 "remove" 选项 + # (https://docs.pingcap.com/zh/tidb/stable/tidb-lightning-physical-import-mode-usage#冲突数据检测)。 + # 在遇到冲突数据时将所有相互冲突的数据删除,并记录在 ${meta-schema}_${name}.conflict_error_v1 表中。 + # 在本配置文件中,会记录在 dm_meta_test.conflict_error_v1 表中。全量导入阶段结束后,任务 + # 会暂停并提示用户查询这张表并按照文档进行手动处理。使用 resume-task 命令让任务恢复运行并 + # 进入到增量同步阶段。 + on-duplicate-physical: "none" + # 物理导入模式用作本地排序的目录位置,该选项的默认值与 dir 配置项一致。具体说明可以参见 TiDB Lightning 对存储空间的需求:https://docs.pingcap.com/zh/tidb/stable/tidb-lightning-physical-import-mode#运行环境需求 + sorting-dir-physical: "./dumped_data" + # 磁盘空间限制,对应 TiDB Lightning disk-quota 配置。具体说明参见文档:https://docs.pingcap.com/zh/tidb/stable/tidb-lightning-physical-import-mode-usage#磁盘资源配额-从-v620-版本开始引入 + disk-quota-physical: "0" + # 物理导入模式在导入完成一张表后,对每一个表执行 `ADMIN CHECKSUM TABLE ` 进行数据校验的配置: + # - "required"(默认值)。表示导入完成后进行数据校验,如果校验失败会让任务暂停,需要用户手动处理。 + # - "optional"。表示导入完成后进行数据校验,如果校验失败会打印 warn 日志,任务不会暂停。 + # - "off"。表示导入完成后不进行数据校验。 + # Checksum 对比失败通常表示导入异常(数据丢失或数据不一致),因此建议总是开启 Checksum。 + checksum-physical: "required" + # 配置在 CHECKSUM 结束后是否对所有表执行 `ANALYZE TABLE
` 操作。 + # - "required"(默认值)。表示导入完成后进行 ANALYZE 操作,ANALYZE 操作失败时任务暂停,需要用户手动处理。 + # - "optional"。表示导入完成后进行 ANALYZE 操作,ANALYZE 操作失败时输出警告日志,任务不会暂停。 + # - "off"。表示导入完成后不进行 ANALYZE 操作。 + # ANALYZE 只影响统计数据,在大部分场景下建议不开启 ANALYZE。 + analyze: "off" + # 物理导入模式向 TiKV 写入 KV 数据的并发度。当 dm-worker 和 TiKV 网络传输速度超过万兆时,可适当增加这个值。 + # range-concurrency: 16 + # 物理导入模式向 TiKV 发送 KV 数据时是否启用压缩。目前仅支持 Gzip 压缩算法,可填写 "gzip" 或 "gz"。默认不启用压缩。 + # compress-kv-pairs: "" + # PD server 的地址,填一个即可。该值为空时,默认使用 TiDB 查询到的 PD 地址信息。 + # pd-addr: "192.168.0.1:2379" + +syncers: # sync 处理单元的运行配置参数 + global: # 配置名称 + worker-count: 16 # 应用已传输到本地的 binlog 的并发线程数量,默认值为 16。调整此参数不会影响上游拉取日志的并发,但会对下游产生显著压力。 + batch: 100 # sync 迁移到下游数据库的一个事务批次 SQL 语句数,默认值为 100,建议一般不超过 500。 + enable-ansi-quotes: true # 若 `session` 中设置 `sql-mode: "ANSI_QUOTES"`,则需开启此项 + + # 设置为 true,则将来自上游的 `INSERT` 改写为 `REPLACE`,将 `UPDATE` 改写为 `DELETE` 与 `REPLACE`,保证在表结构中存在主键或唯一索引的条件下迁移数据时可以重复导入 DML。 + safe-mode: false + # 自动安全模式的持续时间 + # 如不设置或者设置为 "",则默认为 `checkpoint-flush-interval`(默认为 30s)的两倍,即 60s。 + # 如设置为 "0s",则在 DM 自动进入安全模式的时候报错。 + # 如设置为正常值,例如 "1m30s",则在该任务异常暂停、记录 `safemode_exit_point` 失败、或是 DM 进程异常退出时,把安全模式持续时间调整为 1 分 30 秒。详情可见[自动开启安全模式](https://docs.pingcap.com/zh/tidb/stable/dm-safe-mode#自动开启)。 + safe-mode-duration: "60s" + # 设置为 true,DM 会在不增加延迟的情况下,尽可能地将上游对同一条数据的多次操作压缩成一次操作。 + # 如 INSERT INTO tb(a,b) VALUES(1,1); UPDATE tb SET b=11 WHERE a=1; 会被压缩成 INSERT INTO tb(a,b) VALUES(1,11); 其中 a 为主键 + # 如 UPDATE tb SET b=1 WHERE a=1; UPDATE tb(a,b) SET b=2 WHERE a=1; 会被压缩成 UPDATE tb(a,b) SET b=2 WHERE a=1; 其中 a 为主键 + # 如 DELETE FROM tb WHERE a=1; INSERT INTO tb(a,b) VALUES(1,1); 会被压缩成 REPLACE INTO tb(a,b) VALUES(1,1); 其中 a 为主键 + compact: false + # 设置为 true,DM 会尽可能地将多条同类型的语句合并到一条语句中,生成一条带多行数据的 SQL 语句。 + # 如 INSERT INTO tb(a,b) VALUES(1,1); INSERT INTO tb(a,b) VALUES(2,2); 会变成 INSERT INTO tb(a,b) VALUES(1,1),(2,2); + # 如 UPDATE tb SET b=11 WHERE a=1; UPDATE tb(a,b) set b=22 WHERE a=2; 会变成 INSERT INTO tb(a,b) VALUES(1,11),(2,22) ON DUPLICATE KEY UPDATE a=VALUES(a), b=VALUES(b); 其中 a 为主键 + # 如 DELETE FROM tb WHERE a=1; DELETE FROM tb WHERE a=2 会变成 DELETE FROM tb WHERE (a) IN (1),(2);其中 a 为主键 + multiple-rows: false + +validators: # 增量数据校验的运行配置参数 + global: # 配置名称 + # full:校验每一行中每一列数据是否正确 + # fast:仅校验这一行是否有成功迁移到下游 + # none:不校验 + mode: full # 可选填 full,fast 和 none,默认是 none,即不开启校验。 + worker-count: 4 # 后台校验的 validation worker 数量,默认是 4 个 + row-error-delay: 30m # 某一行多久没有校验通过会被标记为 error row,默认是 30 分钟 + +# ----------- 实例配置 ----------- +mysql-instances: + - + source-id: "mysql-replica-01" # 对应 source.toml 中的 `source-id` + meta: # `task-mode` 为 `incremental` 且下游数据库的 `checkpoint` 不存在时 binlog 迁移开始的位置; 如果 checkpoint 存在,则以 `checkpoint` 为准。如果 `meta` 项和下游数据库的 `checkpoint` 都不存在,则从上游当前最新的 binlog 位置开始迁移 + binlog-name: binlog.000001 + binlog-pos: 4 + binlog-gtid: "03fc0263-28c7-11e7-a653-6c0b84d59f30:1-7041423,05474d3c-28c7-11e7-8352-203db246dd3d:1-170" # 对于 source 中指定了 `enable-gtid: true` 的增量任务,需要指定该值 + + route-rules: ["route-rule-1", "route-rule-2"] # 该上游数据库实例匹配的表到下游数据库的 table routing 规则名称 + filter-rules: ["filter-rule-1", "filter-rule-2"] # 该上游数据库实例匹配的表的 binlog event filter 规则名称 + block-allow-list: "bw-rule-1" # 该上游数据库实例匹配的表的 block-allow-list 过滤规则名称,如果 DM 版本早于 v2.0.0-beta.2 则使用 black-white-list + expression-filters: ["even_c"] # 使用名为 even_c 的表达式过滤规则 + + mydumper-config-name: "global" # mydumpers 配置的名称 + loader-config-name: "global" # loaders 配置的名称 + syncer-config-name: "global" # syncers 配置的名称 + validator-config-name: "global" # validators 配置的名称 + - + source-id: "mysql-replica-02" # 对应 source.toml 中的 `source-id` + mydumper-thread: 4 # dump 处理单元用于导出数据的线程数量,等同于 mydumpers 配置中的 `threads`,当同时指定它们时 `mydumper-thread` 优先级更高 + loader-thread: 16 # load 处理单元用于导入数据的线程数量,等同于 loaders 配置中的 `pool-size`,当同时指定它们时 `loader-thread` 优先级更高。当有多个实例同时向 TiDB 迁移数据时可根据负载情况适当调小该值 + syncer-thread: 16 # sync 处理单元用于复制增量数据的线程数量,等同于 syncers 配置中的 `worker-count`,当同时指定它们时 `syncer-thread` 优先级更高。当有多个实例同时向 TiDB 迁移数据时可根据负载情况适当调小该值 +``` + +## 配置顺序 + +通过上面的配置文件示例,可以看出配置文件总共分为两个部分:`全局配置`和`实例配置`,其中`全局配置`又分为`基本信息配置`和`功能配置集`。配置顺序如下: + +1. 编辑[全局配置](#全局配置)。 +2. 根据全局配置编辑[实例配置](#实例配置)。 + +## 全局配置 + +### 任务基本信息配置 + +配置任务的基本信息,配置项的说明参见以上示例配置文件中的注释。其中 `task-mode` 需要特殊说明: + +`task-mode` + +- 描述:任务模式,可以通过任务模式来指定需要执行的数据迁移工作。 +- 值为字符串(`full`,`incremental` 或 `all`)。 + - `full`:只全量备份上游数据库,然后将数据全量导入到下游数据库。 + - `incremental`:只通过 binlog 把上游数据库的增量修改复制到下游数据库,可以设置实例配置的 `meta` 配置项来指定增量复制开始的位置。 + - `all`:`full` + `incremental`。先全量备份上游数据库,将数据全量导入到下游数据库,然后从全量数据备份时导出的位置信息 (binlog position) 开始通过 binlog 增量复制数据到下游数据库。 + +### 功能配置集 + +全局配置主要包含下列功能配置集: + +| 配置项 | 说明 | +| :------------ | :--------------------------------------- | +| `routes` | 上游和下游表之间的路由 table routing 规则集。如果上游与下游的库名、表名一致,则不需要配置该项。使用场景及示例配置参见 [Table Routing](/dm/dm-table-routing.md) | +| `filters` | 上游数据库实例匹配的表的 binlog event filter 规则集。如果不需要对 binlog 进行过滤,则不需要配置该项。使用场景及示例配置参见 [Binlog Event Filter](/dm/dm-binlog-event-filter.md) | +| `block-allow-list` | 该上游数据库实例匹配的表的 block & allow lists 过滤规则集。建议通过该项指定需要迁移的库和表,否则会迁移所有的库和表。使用场景及示例配置参见 [Block & Allow Lists](/dm/dm-block-allow-table-lists.md) | +| `mydumpers` | dump 处理单元的运行配置参数。如果默认配置可以满足需求,则不需要配置该项,也可以只使用 `mydumper-thread` 对 `thread` 配置项单独进行配置。 | +| `loaders` | load 处理单元的运行配置参数。如果默认配置可以满足需求,则不需要配置该项,也可以只使用 `loader-thread` 对 `pool-size` 配置项单独进行配置。 | +| `syncers` | sync 处理单元的运行配置参数。如果默认配置可以满足需求,则不需要配置该项,也可以只使用 `syncer-thread` 对 `worker-count` 配置项单独进行配置。 | + +各个功能配置集的参数及解释参见[完整配置文件示例](#完整配置文件示例)中的注释说明。 + +## 实例配置 + +本小节定义具体的数据迁移子任务,DM 支持从单个或者多个上游 MySQL 实例迁移数据到同一个下游数据库实例。 + +在该项配置中设置数据迁移子任务中各个功能对应的配置集中的配置名称,关于这些配置项的更多配置细节,参见[功能配置集](#功能配置集)的相关配置项,对应关系如下: + +| 配置项 | 相关配置项 | +| :------ | :------------------ | +| `route-rules` | `routes` | +| `filter-rules` | `filters` | +| `block-allow-list` | `block-allow-list` | +| `mydumper-config-name` | `mydumpers` | +| `loader-config-name` | `loaders` | +| `syncer-config-name` | `syncers` | diff --git a/markdown-pages/zh/tidb/master/download-ecosystem-tools.md b/markdown-pages/zh/tidb/master/download-ecosystem-tools.md new file mode 100644 index 0000000..966fb3c --- /dev/null +++ b/markdown-pages/zh/tidb/master/download-ecosystem-tools.md @@ -0,0 +1,53 @@ +--- +title: TiDB 工具下载 +aliases: ['/docs-cn/dev/download-ecosystem-tools/','/docs-cn/dev/reference/tools/download/'] +summary: 本文介绍如何下载 TiDB 工具包。TiDB 工具包包含常用工具如 Dumpling、TiDB Lightning、BR 等。如果部署环境能访问互联网,可直接通过 TiUP 命令一键部署所需的 TiDB 工具。操作系统需为 Linux,架构为 amd64 或 arm64。下载步骤包括访问 TiDB 社区版页面,找到 TiDB-community-toolkit 软件包并点击立即下载。注意,点击立即下载后默认下载当前 TiDB 的最新发布版本。根据要使用的工具选择安装对应的离线包。 +--- + +# TiDB 工具下载 + +本文介绍如何下载 TiDB 工具包。关于 TiDB 工具包的内容,请查看 [TiDB 离线包](/binary-package.md)。 + +## TiDB 工具包下载 + +TiDB 工具包中包含了一些常用的 TiDB 工具,例如数据导出工具 Dumpling、数据导入工具 TiDB Lightning、备份恢复工具 BR。 + +> **建议:** +> +> 如果你的部署环境能访问互联网,无需单独下载 TiDB 工具包,可以直接通过使用 [TiUP 命令一键部署](/tiup/tiup-component-management.md)所需的 TiDB 工具。 + +### 环境要求 + +- 操作系统:Linux +- 架构:amd64 或 arm64 + +### 下载步骤 + +1. 访问 [TiDB 社区版](https://pingcap.com/zh/product-community/)页面。 +2. 找到 **TiDB-community-toolkit 软件包**,点击**立即下载**。 + +> **注意:** +> +> - 点击**立即下载**后,默认下载当前 TiDB 的最新发布版本。如需下载其它版本,请在 [TiDB 社区版](https://pingcap.com/zh/product-community/)页面底部查看其它版本下载信息。 +> - 如需在 Kubernetes 上部署运维 TiDB,无需下载 TiDB-community-toolkit 软件包,请参考[离线安装 TiDB Operator](https://docs.pingcap.com/zh/tidb-in-kubernetes/stable/deploy-tidb-operator#离线安装-tidb-operator)。 +> - 如需使用 [PD Control](/pd-control.md) 工具 `pd-ctl`,请下载 **TiDB-community-server 软件包**。 + +### TiDB 工具包说明 + +在 TiDB 工具包中,你可以依据要使用的工具,选择安装对应的离线包。 + +| 工具 | 离线包名称 | +|:------|:----------| +| [TiUP](/tiup/tiup-overview.md) | `tiup-linux-{arch}.tar.gz`
`tiup-{tiup-version}-linux-{arch}.tar.gz`
`dm-{tiup-version}-linux-{arch}.tar.gz`
`server-{version}-linux-{arch}.tar.gz` | +| [Dumpling](/dumpling-overview.md) | `dumpling-{version}-linux-{arch}.tar.gz` | +| [TiDB Lightning](/tidb-lightning/tidb-lightning-overview.md) | `tidb-lightning-ctl`
`tidb-lightning-{version}-linux-{arch}.tar.gz` | +| [TiDB DM (Data Migration)](/dm/dm-overview.md) | `dm-worker-{version}-linux-{arch}.tar.gz`
`dm-master-{version}-linux-{arch}.tar.gz`
`dmctl-{version}-linux-{arch}.tar.gz` | +| [TiCDC](/ticdc/ticdc-overview.md) | `cdc-{version}-linux-{arch}.tar.gz` | +| [TiDB Binlog](/tidb-binlog/tidb-binlog-overview.md) | `pump-{version}-linux-{arch}.tar.gz`
`drainer-{version}-linux-{arch}.tar.gz`
`binlogctl`
`reparo` | +| [Backup & Restore (BR)](/br/backup-and-restore-overview.md) | `br-{version}-linux-{arch}.tar.gz` | +| [sync-diff-inspector](/sync-diff-inspector/sync-diff-inspector-overview.md) | `sync_diff_inspector` | +| [PD Recover](/pd-recover.md) | `pd-recover-{version}-linux-{arch}.tar.gz` | + +> **注意:** +> +> 以上离线包名称中,`{version}` 取决于离线包中工具的版本号,`{arch}` 取决于离线包对应的架构(amd64 或 arm64)。 diff --git a/markdown-pages/zh/tidb/master/ecosystem-tool-user-guide.md b/markdown-pages/zh/tidb/master/ecosystem-tool-user-guide.md new file mode 100644 index 0000000..ea125f6 --- /dev/null +++ b/markdown-pages/zh/tidb/master/ecosystem-tool-user-guide.md @@ -0,0 +1,147 @@ +--- +title: TiDB 工具功能概览 +aliases: ['/docs-cn/dev/ecosystem-tool-user-guide/','/docs-cn/dev/reference/tools/user-guide/','/docs-cn/dev/how-to/migrate/from-mysql/', '/docs-cn/dev/how-to/migrate/incrementally-from-mysql/', '/docs-cn/dev/how-to/migrate/overview/', '/docs-cn/dev/reference/tools/use-guide/'] +summary: TiDB 提供了丰富的工具,包括部署运维工具 TiUP 和 TiDB Operator,数据管理工具如 TiDB Data Migration(DM)、Dumpling、TiDB Lightning、Backup & Restore(BR)、TiCDC、TiDB Binlog、sync-diff-inspector,以及 OLAP 分析工具 TiSpark。这些工具可用于部署、数据迁移、备份恢复、数据校验等多种操作,满足不同需求。 +--- + +# TiDB 工具功能概览 + +TiDB 提供了丰富的工具,可以帮助你进行部署运维、数据管理(例如,数据迁移、备份恢复、数据校验)、在 TiKV 上运行 Spark SQL。请根据需要选择适用的工具。 + +## 部署运维工具 + +TiDB 提供了 TiUP 和 TiDB Operator 部署运维工具,满足你在不同系统环境下的部署运维需求。 + +### 在物理机或虚拟机上部署运维 TiDB + +#### TiUP + +[TiUP](/tiup/tiup-overview.md) 是在物理机或虚拟机上的 TiDB 包管理器,管理着 TiDB 的众多的组件,如 TiDB、PD、TiKV 等。当你想要运行 TiDB 生态中任何组件时,只需要执行一行 TiUP 命令即可。 + +[TiUP cluster](https://github.com/pingcap/tiup/tree/master/components/cluster) 是 TiUP 提供的使用 Golang 编写的集群管理组件,通过 TiUP cluster 组件就可以进行日常的运维工作,包括部署、启动、关闭、销毁、弹性扩缩容、升级 TiDB 集群,以及管理 TiDB 集群参数。 + +基本信息: + +- [术语及核心概念](/tiup/tiup-terminology-and-concepts.md) +- [使用 TiUP 部署 TiDB 集群](/production-deployment-using-tiup.md) +- [TiUP 组件管理](/tiup/tiup-component-management.md) +- 适用 TiDB 版本:v4.0 及以上 + +### 在 Kubernetes 上部署运维 TiDB - TiDB Operator + +[TiDB Operator](https://docs.pingcap.com/zh/tidb-in-kubernetes/stable) 是 Kubernetes 上的 TiDB 集群自动运维系统,提供包括部署、升级、扩缩容、备份恢复、配置变更的 TiDB 全生命周期管理。借助 TiDB Operator,TiDB 可以无缝运行在公有云或自托管的 Kubernetes 集群上。 + +基本信息: + +- [TiDB Operator 架构](https://docs.pingcap.com/zh/tidb-in-kubernetes/stable/architecture) +- [在 Kubernetes 上部署运维 TiDB 快速上手](https://docs.pingcap.com/zh/tidb-in-kubernetes/stable/get-started/) +- 适用 TiDB 版本:v2.1 及以上 + +## 数据管理工具 + + TiDB 提供了丰富的数据管理工具,例如数据迁移、导入导出、备份恢复、增量同步、数据校验等。 + +### 数据迁入 - TiDB Data Migration (DM) + +[TiDB Data Migration (DM)](/dm/dm-overview.md) 是将 MySQL/MariaDB 数据迁移到 TiDB 的工具,支持全量数据的迁移和增量数据的复制。 + +基本信息: + +- TiDB DM 的输入:MySQL/MariaDB +- TiDB DM 的输出:TiDB 集群 +- 适用 TiDB 版本:所有版本 +- Kubernetes 支持:使用 [TiDB Operator](https://docs.pingcap.com/zh/tidb-in-kubernetes/dev/deploy-tidb-dm) 在 Kubernetes 上部署 TiDB DM。 + +如果数据量在 TB 级别以下,推荐直接使用 TiDB DM 迁移 MySQL/MariaDB 数据到 TiDB(迁移的过程包括全量数据的导出导入和增量数据的复制)。 + +如果数据量在 TB 级别,推荐的迁移步骤如下: + +1. 使用 [Dumpling](/dumpling-overview.md) 导出 MySQL/MariaDB 全量数据。 +2. 使用 [TiDB Lightning](/tidb-lightning/tidb-lightning-overview.md) 将全量导出数据导入 TiDB 集群。 +3. 使用 TiDB DM 复制 MySQL/MariaDB 增量数据到 TiDB。 + +> **注意:** +> +> - 原 Syncer 工具已停止维护,不再推荐使用,相关场景请使用 TiDB DM 的增量复制模式进行替代。 + +### 全量导出 - Dumpling + +[Dumpling](/dumpling-overview.md) 是一个用于从 MySQL/TiDB 进行全量逻辑导出的工具。 + +基本信息: + +- Dumpling 的输入:MySQL/TiDB 集群 +- Dumpling 的输出:SQL/CSV 文件 +- 适用 TiDB 版本:所有版本 +- Kubernetes 支持:尚未支持 + +> **注意:** +> +> PingCAP 之前维护的 Mydumper 工具 fork 自 [mydumper project](https://github.com/maxbube/mydumper),针对 TiDB 的特性进行了优化。从 v7.5.0 开始,[Mydumper](https://docs.pingcap.com/tidb/v4.0/mydumper-overview) 废弃,其绝大部分功能已经被 [Dumpling](/dumpling-overview.md) 取代,强烈建议切换到 Dumpling。 + +### 全量导入 - TiDB Lightning + +[TiDB Lightning](/tidb-lightning/tidb-lightning-overview.md) 是一个用于将全量数据导入到 TiDB 集群的工具。 + +使用 TiDB Lightning 导入数据到 TiDB 时,有以下模式: + +- [物理导入模式](/tidb-lightning/tidb-lightning-physical-import-mode.md):TiDB Lightning 将数据解析为有序的键值对,并直接将其导入 TiKV。这种模式一般用于导入大量的数据(TB 级别)到新集群,但在数据导入过程中集群无法提供正常的服务。 +- [逻辑导入模式](/tidb-lightning/tidb-lightning-logical-import-mode.md):以 TiDB/MySQL 作为后端,这种模式相比物理导入模式,导入速度较慢,但是可以在线导入,同时也支持将数据导入到 MySQL。 + +基本信息: + +- TiDB Lightning 的输入: + - Dumpling 输出文件 + - 其他格式兼容的 CSV 文件 + - 从 Aurora 或者 Hive 导出的 Parquet 文件 +- 适用 TiDB 版本:v2.1 及以上 +- Kubernetes 支持:[使用 TiDB Lightning 快速恢复 Kubernetes 上的 TiDB 集群数据](https://docs.pingcap.com/zh/tidb-in-kubernetes/stable/restore-data-using-tidb-lightning) + +> **注意:** +> +> 原 Loader 工具已停止维护,不再推荐使用。相关场景请使用 TiDB Lightning 的 `tidb` 模式进行替代。 + +### 备份和恢复 - Backup & Restore + +[Backup & Restore (BR)](/br/backup-and-restore-overview.md) 是一个对 TiDB 进行分布式备份和恢复的工具,可以高效地对大数据量的 TiDB 集群进行数据备份和恢复。 + +基本信息: + +- [备份输出和恢复输入的文件类型](/br/backup-and-restore-design.md) +- 适用 TiDB 版本:v4.0 及以上 +- Kubernetes 支持:[使用 BR 工具备份 TiDB 集群数据到兼容 S3 的存储](https://docs.pingcap.com/zh/tidb-in-kubernetes/stable/backup-to-aws-s3-using-br),[使用 BR 工具恢复 S3 兼容存储上的备份数据](https://docs.pingcap.com/zh/tidb-in-kubernetes/stable/restore-from-aws-s3-using-br) + +### TiDB 增量数据同步 - TiCDC + +[TiCDC](/ticdc/ticdc-overview.md) 是一款通过拉取 TiKV 变更日志实现的 TiDB 增量数据同步工具,具有将数据还原到与上游任意 TSO 一致状态的能力,同时提供开放数据协议 (TiCDC Open Protocol),支持其他系统订阅数据变更。 + +基本信息: + +- TiCDC 的输入:TiDB 集群 +- TiCDC 的输出:TiDB 集群、MySQL、Kafka、Confluent +- 适用 TiDB 版本:v4.0.6 及以上 + +### TiDB 增量日志同步 - TiDB Binlog + +[TiDB Binlog](/tidb-binlog/tidb-binlog-overview.md) 是收集 TiDB 的增量 binlog 数据,并提供准实时同步和备份的工具。该工具可用于 TiDB 集群间的增量数据同步,如将其中一个 TiDB 集群作为另一个 TiDB 集群的从集群。 + +基本信息: + +- TiDB Binlog 的输入:TiDB 集群 +- TiDB Binlog 的输出:TiDB 集群、MySQL、Kafka 或者增量备份文件 +- 适用 TiDB 版本:v2.1 及以上 +- Kubernetes 支持:[TiDB Binlog 运维文档](https://docs.pingcap.com/zh/tidb-in-kubernetes/stable/deploy-tidb-binlog),[Kubernetes 上的 TiDB Binlog Drainer 配置](https://docs.pingcap.com/zh/tidb-in-kubernetes/stable/configure-tidb-binlog-drainer) + +### 数据校验 - sync-diff-inspector + +[sync-diff-inspector](/sync-diff-inspector/sync-diff-inspector-overview.md) 是一个用于校验 MySQL/TiDB 中两份数据是否一致的工具。该工具还提供了修复数据的功能,可用于修复少量不一致的数据。 + +基本信息: + +- sync-diff-inspector 的输入:TiDB、MySQL +- sync-diff-inspector 的输出:TiDB、MySQL +- 适用 TiDB 版本:所有版本 + +## OLAP 分析工具 - TiSpark + +[TiSpark](/tispark-overview.md) 是 PingCAP 为解决用户复杂 OLAP 需求而推出的产品。它借助 Spark 平台,同时融合 TiKV 分布式集群的优势,和 TiDB 一起为用户一站式解决 HTAP (Hybrid Transactional/Analytical Processing) 的需求。 diff --git a/markdown-pages/zh/tidb/master/enable-tls-between-clients-and-servers.md b/markdown-pages/zh/tidb/master/enable-tls-between-clients-and-servers.md new file mode 100644 index 0000000..1a157fc --- /dev/null +++ b/markdown-pages/zh/tidb/master/enable-tls-between-clients-and-servers.md @@ -0,0 +1,183 @@ +--- +title: 为 TiDB 客户端服务端间通信开启加密传输 +aliases: ['/docs-cn/dev/enable-tls-between-clients-and-servers/','/docs-cn/dev/how-to/secure/enable-tls-clients/','/docs-cn/dev/encrypted-connections-with-tls-protocols/','/docs-cn/dev/enable-tls-between-clients/'] +summary: TiDB 服务端与客户端间默认采用非加密连接,容易造成信息泄露。建议使用加密连接确保安全性。要开启 TLS 加密传输,需要在服务端配置开启 TLS 支持,并在客户端应用程序中配置使用 TLS 加密连接。可以通过配置系统变量或在创建 / 修改用户时指定要求加密连接。可通过命令检查当前连接是否是加密连接。TLS 版本为 TLSv1.2 和 TLSv1.3,支持的加密算法包括 AES 和 CHACHA20_POLY1305。 +--- + +# 为 TiDB 客户端服务端间通信开启加密传输 + +TiDB 服务端与客户端之间默认采用非加密连接,因而具备监视信道流量能力的第三方可以知悉 TiDB 服务端与客户端之间发送和接受的数据,包括但不限于查询语句内容、查询结果等。若信道是不可信的,例如客户端是通过公网连接到 TiDB 服务端的,则非加密连接容易造成信息泄露,建议使用加密连接确保安全性。 + +TiDB 服务端支持启用基于 TLS(传输层安全)协议的加密连接,协议与 MySQL 加密连接一致,现有 MySQL Client 如 MySQL Shell 和 MySQL 驱动等能直接支持。TLS 的前身是 SSL,因而 TLS 有时也被称为 SSL,但由于 SSL 协议有已知安全漏洞,TiDB 实际上并未支持。TiDB 支持的 TLS/SSL 协议版本为 TLSv1.2 和 TLSv1.3。 + +使用加密连接后,连接将具有以下安全性质: + +- 保密性:流量明文被加密,无法被窃听; +- 完整性:流量明文无法被篡改; +- 身份验证(可选):客户端和服务端能验证双方身份,避免中间人攻击。 + +要为 TiDB 客户端与服务端间的通信开启 TLS 加密传输,首先需要在 TiDB 服务端通过配置开启 TLS 加密连接的支持,然后通过配置客户端应用程序使用 TLS 加密连接。一般情况下,如果服务端正确配置了 TLS 加密连接支持,客户端库都会自动启用 TLS 加密传输。 + +另外,与 MySQL 相同,TiDB 也支持在同一 TCP 端口上开启 TLS 连接或非 TLS 连接。对于开启了 TLS 连接支持的 TiDB 服务端,客户端既可以选择通过加密连接安全地连接到该 TiDB 服务端,也可以选择使用普通的非加密连接。如需使用加密连接,你可以通过以下方式进行配置: + ++ 通过配置系统变量 `require_secure_transport` 要求所有用户必须使用加密连接来连接到 TiDB。 ++ 通过在创建用户 (`create user`),或修改已有用户 (`alter user`) 时指定 `REQUIRE SSL` 要求指定用户必须使用加密连接来连接 TiDB。以创建用户为例: + + ```sql + CREATE USER 'u1'@'%' IDENTIFIED BY 'my_random_password' REQUIRE SSL; + ``` + +> **注意:** +> +> 如果登录用户已配置使用 [TiDB 证书鉴权功能](/certificate-authentication.md#配置登录时需要校验的用户证书信息)校验用户证书,也会隐式要求对应用户必须使用加密连接连接 TiDB。 + +## 配置 TiDB 服务端启用安全连接 + +要启用安全连接,请参考以下相关参数说明: + +- [`auto-tls`](/tidb-configuration-file.md#auto-tls):启用证书自动生成功能(从 v5.2.0 开始) +- [`ssl-cert`](/tidb-configuration-file.md#ssl-cert):指定 SSL 证书文件路径 +- [`ssl-key`](/tidb-configuration-file.md#ssl-key):指定证书文件对应的私钥 +- [`ssl-ca`](/tidb-configuration-file.md#ssl-ca):可选,指定受信任的 CA 证书文件路径 +- [`tls-version`](/tidb-configuration-file.md#tls-version):可选,指定最低 TLS 版本,例如 `TLSv1.2` + +`auto-tls` 支持安全连接,但不提供客户端证书验证。有关证书验证和控制证书生成方式的说明,请参考下面配置 `ssl-cert`,`ssl-key` 和 `ssl-ca` 变量的建议: + +- 在启动 TiDB 时,至少需要在配置文件中同时指定 `ssl-cert` 和 `ssl-key` 参数,才能在 TiDB 服务端开启安全连接。还可以指定 `ssl-ca` 参数进行客户端身份验证(请参见[配置启用身份验证](#配置启用身份验证)章节)。 +- 参数指定的文件都为 PEM 格式。另外目前 TiDB 尚不支持加载有密码保护的私钥,因此必须提供一个没有密码的私钥文件。若提供的证书或私钥无效,则 TiDB 服务端将照常启动,但并不支持客户端加密连接到 TiDB 服务端。 +- 若证书参数无误,则 TiDB 在启动时将会输出 `secure connection is enabled`,否则 TiDB 会输出 `secure connection is NOT ENABLED`。 + +> **注意:** +> +> v5.2.0 版本之前,你可以使用 `mysql_ssl_rsa_setup --datadir=./certs` 生成证书。`mysql_ssl_rsa_setup` 工具是 MySQL Server 的一部分。 + +## 配置 MySQL Client 使用安全连接 + +MySQL 5.7 及以上版本自带的客户端默认尝试使用安全连接,若服务端不支持安全连接则自动退回到使用非安全连接;MySQL 5.7 以下版本自带的客户端默认采用非安全连接。 + +可以通过命令行参数修改客户端的连接行为,包括: + +- 强制使用安全连接,若服务端不支持安全连接则连接失败 (`--ssl-mode=REQUIRED`) +- 尝试使用安全连接,若服务端不支持安全连接则退回使用不安全连接 +- 使用不安全连接 (`--ssl-mode=DISABLED`) + +除此参数外,MySQL 8.0 客户端有两种 SSL 模式: + +- `--ssl-mode=VERIFY_CA`:根据 `--ssl-ca` 签发的 CA 验证来自服务器的证书。 +- `--ssl-mode=VERIFY_IDENTITY`:与 `VERIFY_CA` 相同,但也验证所连接的主机名是否与证书匹配。 + +详细信息请参阅 MySQL 文档中关于[客户端配置安全连接](https://dev.mysql.com/doc/refman/8.0/en/using-encrypted-connections.html#using-encrypted-connections-client-side-configuration)的部分。 + +## 配置启用身份验证 + +若在 TiDB 服务端或 MySQL Client 中未指定 `ssl-ca` 参数,则默认不会进行客户端或服务端身份验证,无法抵御中间人攻击,例如客户端可能会“安全地”连接到了一个伪装的服务端。可以在服务端和客户端中配置 `ssl-ca` 参数进行身份验证。一般情况下只需验证服务端身份,但也可以验证客户端身份进一步增强安全性。 + +- 若要使 MySQL Client 验证 TiDB 服务端身份,TiDB 服务端需至少配置 `ssl-cert` 和 `ssl-key` 参数,客户端需至少指定 `--ssl-ca` 参数,且 `--ssl-mode` 至少为 `VERIFY_CA`。必须确保 TiDB 服务端配置的证书 (`ssl-cert`) 是由客户端 `--ssl-ca` 参数所指定的 CA 所签发的,否则身份验证失败。 +- 若要使 TiDB 服务端验证 MySQL Client 身份,TiDB 服务端需配置 `ssl-cert`、`ssl-key`、`ssl-ca` 参数,客户端需至少指定 `--ssl-cert`、`--ssl-key` 参数。必须确保服务端配置的证书和客户端配置的证书都是由服务端配置指定的 `ssl-ca` 签发的。 +- 若要进行双向身份验证,请同时满足上述要求。 + +默认情况,服务端对客户端的身份验证是可选的。若客户端在 TLS 握手时未出示自己的身份证书,也能正常建立 TLS 连接。但也可以通过在创建用户 (`create user`),赋予权限 (`grant`) 或修改已有用户 (`alter user`) 时指定 `require x509` 要求客户端需进行身份验证,以创建用户为例: + +```sql +create user 'u1'@'%' require x509; +``` + +> **注意:** +> +> 如果登录用户已配置使用 [TiDB 证书鉴权功能](/certificate-authentication.md#配置登录时需要校验的用户证书信息)校验用户证书,也会隐式要求对应用户需进行身份验证。 + +## 检查当前连接是否是加密连接 + +可以通过 `SHOW STATUS LIKE "%Ssl%";` 了解当前连接的详细情况,包括是否使用了安全连接、安全连接采用的加密协议、TLS 版本号等。 + +以下是一个安全连接中执行该语句的结果。由于客户端支持的 TLS 版本号和加密协议会有所不同,执行结果相应地也会有所变化。 + +```sql +SHOW STATUS LIKE "%Ssl%"; +``` + +``` +...... +| Ssl_verify_mode | 5 | +| Ssl_version | TLSv1.2 | +| Ssl_cipher | ECDHE-RSA-AES128-GCM-SHA256 | +...... +``` + +除此以外,对于 MySQL 自带客户端,还可以使用 `STATUS` 或 `\s` 语句查看连接情况: + +```sql +\s +``` + +``` +... +SSL: Cipher in use is ECDHE-RSA-AES128-GCM-SHA256 +... +``` + +## 支持的 TLS 版本及密钥交换协议和加密算法 + +TiDB 支持的 TLS 版本及密钥交换协议和加密算法由 Golang 官方库决定。 + +你使用的客户端库和操作系统加密策略也可能会影响到支持的协议版本和密码套件。 + +### 支持的 TLS 版本 + +- TLSv1.2 +- TLSv1.3 + +可以使用配置项 `tls-version` 来限制 TLS 版本。 + +实际可用的 TLS 版本取决于操作系统的加密策略、MySQL 客户端版本和客户端的 SSL/TLS 库。 + +### 支持的密钥交换协议及加密算法 + +- TLS\_RSA\_WITH\_AES\_128\_CBC\_SHA +- TLS\_RSA\_WITH\_AES\_256\_CBC\_SHA +- TLS\_RSA\_WITH\_AES\_128\_CBC\_SHA256 +- TLS\_RSA\_WITH\_AES\_128\_GCM\_SHA256 +- TLS\_RSA\_WITH\_AES\_256\_GCM\_SHA384 +- TLS\_ECDHE\_ECDSA\_WITH\_AES\_128\_CBC\_SHA +- TLS\_ECDHE\_ECDSA\_WITH\_AES\_256\_CBC\_SHA +- TLS\_ECDHE\_RSA\_WITH\_AES\_128\_CBC\_SHA +- TLS\_ECDHE\_RSA\_WITH\_AES\_256\_CBC\_SHA +- TLS\_ECDHE\_ECDSA\_WITH\_AES\_128\_CBC\_SHA256 +- TLS\_ECDHE\_RSA\_WITH\_AES\_128\_CBC\_SHA256 +- TLS\_ECDHE\_RSA\_WITH\_AES\_128\_GCM\_SHA256 +- TLS\_ECDHE\_ECDSA\_WITH\_AES\_128\_GCM\_SHA256 +- TLS\_ECDHE\_RSA\_WITH\_AES\_256\_GCM\_SHA384 +- TLS\_ECDHE\_ECDSA\_WITH\_AES\_256\_GCM\_SHA384 +- TLS\_ECDHE\_RSA\_WITH\_CHACHA20\_POLY1305\_SHA256 +- TLS\_ECDHE\_ECDSA\_WITH\_CHACHA20\_POLY1305\_SHA256 +- TLS\_AES\_128\_GCM\_SHA256 +- TLS\_AES\_256\_GCM\_SHA384 +- TLS\_CHACHA20\_POLY1305\_SHA256 + +## 重加载证书、密钥和 CA + +在需要替换证书、密钥或 CA 时,可以在完成对应文件替换后,对运行中的 TiDB 实例执行 [`ALTER INSTANCE RELOAD TLS`](/sql-statements/sql-statement-alter-instance.md) 语句从原配置的证书 ([`ssl-cert`](/tidb-configuration-file.md#ssl-cert))、密钥 ([`ssl-key`](/tidb-configuration-file.md#ssl-key)) 和 CA ([`ssl-ca`](/tidb-configuration-file.md#ssl-ca)) 的路径重新加证书、密钥和 CA,而无需重启 TiDB 实例。 + +新加载的证书密钥和 CA 将在语句执行成功后对新建立的连接生效,不会影响语句执行前已建立的连接。 + +## 监控 + +自 TiDB v5.2.0 版本起,你可以使用 `Ssl_server_not_after` 和 `Ssl_server_not_before` 状态变量监控证书有效期的起止时间。 + +```sql +SHOW GLOBAL STATUS LIKE 'Ssl\_server\_not\_%'; +``` + +``` ++-----------------------+--------------------------+ +| Variable_name | Value | ++-----------------------+--------------------------+ +| Ssl_server_not_after | Nov 28 06:42:32 2021 UTC | +| Ssl_server_not_before | Aug 30 06:42:32 2021 UTC | ++-----------------------+--------------------------+ +2 rows in set (0.0076 sec) +``` + +## 另请参阅 + +- [为 TiDB 组件间通信开启加密传输](/enable-tls-between-components.md) diff --git a/markdown-pages/zh/tidb/master/error-codes.md b/markdown-pages/zh/tidb/master/error-codes.md new file mode 100644 index 0000000..930b39d --- /dev/null +++ b/markdown-pages/zh/tidb/master/error-codes.md @@ -0,0 +1,551 @@ +--- +title: 错误码与故障诊断 +aliases: ['/docs-cn/dev/error-codes/','/docs-cn/dev/reference/error-codes/'] +summary: TiDB 错误码包括 MySQL 兼容的错误码和 TiDB 特有的错误码。如果遇到错误码,请参考官方文档或社区获取支持。常见错误码包括内存使用超限、写入冲突、表数据损坏、事务过大、写入冲突等。另外,TiDB 还提供了故障诊断文档供参考。 +--- + +# 错误码与故障诊断 + +本篇文档描述在使用 TiDB 过程中会遇到的问题以及解决方法。 + +## 错误码 + +TiDB 兼容 MySQL 的错误码,在大多数情况下,返回和 MySQL 一样的错误码。关于 MySQL 的错误码列表,详见 [MySQL 8.0 Error Message Reference](https://dev.mysql.com/doc/mysql-errors/8.0/en/)。另外还有一些 TiDB 特有的错误码: + +> **注意:** +> +> 有一部分错误码属于内部错误,正常情况下 TiDB 会自行处理不会直接返回给用户,故没有在此列出。 +> +> 如果你遇到了这里没有列出的错误码,请从 PingCAP 官方或 TiDB 社区[获取支持](/support.md)。 + +* Error Number: 8001 + + 请求使用的内存超过 TiDB 内存使用的阈值限制。出现这种错误,可以通过调整系统变量 [`tidb_mem_quota_query`](/system-variables.md#tidb_mem_quota_query) 来增大单个 SQL 使用的内存上限。 + +* Error Number: 8002 + + 带有 `SELECT FOR UPDATE` 语句的事务,在遇到写入冲突时,为保证一致性无法进行重试,事务将进行回滚并返回该错误。出现这种错误,应用程序可以安全地重新执行整个事务。 + +* Error Number: 8003 + + [`ADMIN CHECK TABLE`](/sql-statements/sql-statement-admin-check-table-index.md) 命令在遇到行数据跟索引不一致的时候返回该错误,在检查表中数据是否有损坏时常出现。出现该错误时,请向 PingCAP 工程师或通过官方论坛寻求帮助。 + +* Error Number: 8004 + + 单个事务过大,原因及解决方法请参考[这里](/faq/migration-tidb-faq.md#transaction-too-large-是什么原因怎么解决) + +* Error Number: 8005 + + 完整的报错信息为 `ERROR 8005 (HY000) : Write Conflict, txnStartTS is stale`。 + + 事务在 TiDB 中遇到了写入冲突。请检查业务逻辑,重试写入操作。 + +* Error Number: 8018 + + 当执行重新载入插件时,如果之前插件没有载入过,则会出现该错误。出现该错误,进行插件首次载入即可。 + +* Error Number: 8019 + + 重新载入的插件版本与之前的插件版本不一致,无法重新载入插件并报告该错误。可重新载入插件,确保插件的版本与之前载入的插件版本一致。 + +* Error Number: 8020 + + 当表被加锁时,如果对该表执行写入操作,将出现该错误。请将表解锁后,再进行尝试写入。 + +* Error Number: 8021 + + 当向 TiKV 读取的 key 不存在时将出现该错误,该错误用于内部使用,对外表现为读到的结果为空。 + +* Error Number: 8022 + + 事务提交失败,已经回滚,应用程序可以安全的重新执行整个事务。 + +* Error Number: 8023 + + 在事务内,写入事务缓存时,设置了空值,将返回该错误。这是一个内部使用的错误,将由内部进行处理,不会返回给应用程序。 + +* Error Number: 8024 + + 非法的事务。当事务执行时,发现没有获取事务的 ID (Start Timestamp),代表正在执行的事务是一个非法的事务,将返回该错误。通常情况下不会出现该问题,当发生时,请向 PingCAP 工程师或通过官方论坛寻求帮助。 + +* Error Number: 8025 + + 写入的单条键值对过大。TiDB 默认支持最大 6MB 的单个键值对,超过该限制可适当调整 [`txn-entry-size-limit`](/tidb-configuration-file.md#txn-entry-size-limit-从-v50-版本开始引入) 配置项以放宽限制。 + +* Error Number: 8026 + + 使用了没有实现的接口函数。该错误仅用于数据库内部,应用程序不会收到这个错误。 + +* Error Number: 8027 + + 表结构版本过期。TiDB 采用在线变更表结构的方法。当 TiDB server 表结构版本落后于整个系统的时,执行 SQL 将遇到该错误。遇到该错误,请检查该 TiDB server 与 PD leader 之间的网络。 + +* Error Number: 8028 + + TiDB v6.3.0 引入了[元数据锁](/metadata-lock.md)特性。在关闭元数据锁的情况下,当事务执行时,事务无法感知到 TiDB 的表结构发生了变化。因此,TiDB 在事务提交时,会对事务涉及表的结构进行检查。如果事务执行中表结构发生了变化,则事务将提交失败,并返回该错误。遇到该错误,应用程序可以安全地重新执行整个事务。 + + 在打开元数据锁的情况下,非 RC 隔离级别中,如果从事务开始到初次访问一个表之间,该表进行了有损的列类型变更操作(例如 `INT` 类型变成 `CHAR` 类型是有损的,`TINYINT` 类型变成 `INT` 类型这种不需要重写数据的则是无损的),则访问该表的语句报错,事务不会自动回滚。用户可以继续执行其他语句,并决定是否回滚或者提交事务。 + +* Error Number: 8029 + + 当数据库内部进行数值转换发生错误时,将会出现该错误,该错误仅在内部使用,对外部应用将转换为具体类型的错误。 + +* Error Number: 8030 + + 将值转变为带符号正整数时发生了越界,将结果显示为负数。多在告警信息里出现。 + +* Error Number: 8031 + + 将负数转变为无符号数时,将负数转变为了正数。多在告警信息里出现。 + +* Error Number: 8032 + + 使用了非法的 year 格式。year 只允许 1 位、2 位和 4 位数。 + +* Error Number: 8033 + + 使用了非法的 year 值。year 的合法范围是 (1901, 2155)。 + +* Error Number: 8037 + + week 函数中使用了非法的 mode 格式。mode 必须是一位数字,范围 [0, 7]。 + +* Error Number: 8038 + + 字段无法获取到默认值。一般作为内部错误使用,转换成其他具体错误类型后,返回给应用程序。 + +* Error Number: 8040 + + 尝试进行不支持的操作,比如在 View 和 Sequence 上进行 lock table。 + +* Error Number: 8047 + + 设置了不支持的系统变量值,通常在用户设置了数据库不支持的变量值后的告警信息里出现。 + +* Error Number: 8048 + + 设置了不支持的隔离级别,如果是使用第三方工具或框架等无法修改代码进行适配的情况,可以考虑通过 [`tidb_skip_isolation_level_check`](/system-variables.md#tidb_skip_isolation_level_check) 来绕过这一检查。 + + ```sql + set @@tidb_skip_isolation_level_check = 1; + ``` + +* Error Number: 8050 + + 设置了不支持的权限类型,遇到该错误请参考 [TiDB 权限说明](/privilege-management.md#tidb-各操作需要的权限)进行调整。 + +* Error Number: 8051 + + TiDB 在解析客户端发送的 Exec 参数列表时遇到了未知的数据类型。如果遇到这个错误,请检查客户端是否正常,如果客户端正常请向 PingCAP 工程师或通过官方论坛寻求帮助。 + +* Error Number: 8052 + + 来自客户端的数据包的序列号错误。如果遇到这个错误,请检查客户端是否正常,如果客户端正常请向 PingCAP 工程师或通过官方论坛寻求帮助。 + +* Error Number: 8055 + + 当前快照过旧,数据可能已经被 GC。可以调大 [`tidb_gc_life_time`](/system-variables.md#tidb_gc_life_time-从-v50-版本开始引入) 的值来避免该问题。从 TiDB v4.0.8 版本起,TiDB 会自动为长时间运行的事务保留数据,一般不会遇到该错误。 + + 有关 GC 的介绍和配置可以参考 [GC 机制简介](/garbage-collection-overview.md)和 [GC 配置](/garbage-collection-configuration.md)文档。 + +* Error Number: 8059 + + 自动随机量可用次数用尽无法进行分配。当前没有恢复这类错误的方法。建议在使用 auto random 功能时使用 bigint 以获取最大的可分配次数,并尽量避免手动给 auto random 列赋值。相关的介绍和使用建议可以参考 [auto random 功能文档](/auto-random.md)。 + +* Error Number: 8060 + + 非法的自增列偏移量。请检查 `auto_increment_increment` 和 `auto_increment_offset` 的取值是否符合要求。 + +* Error Number: 8061 + + 不支持的 SQL Hint。请参考 [Optimizer Hints](/optimizer-hints.md) 检查和修正 SQL Hint。 + +* Error Number: 8062 + + SQL Hint 中使用了非法的 token,与 Hint 的保留字冲突。请参考 [Optimizer Hints](/optimizer-hints.md) 检查和修正 SQL Hint。 + +* Error Number: 8063 + + SQL Hint 中限制内存使用量超过系统设置的上限,设置被忽略。请参考 [Optimizer Hints](/optimizer-hints.md) 检查和修正 SQL Hint。 + +* Error Number: 8064 + + 解析 SQL Hint 失败。请参考 [Optimizer Hints](/optimizer-hints.md) 检查和修正 SQL Hint。 + +* Error Number: 8065 + + SQL Hint 中使用了非法的整数。请参考 [Optimizer Hints](/optimizer-hints.md) 检查和修正 SQL Hint。 + +* Error Number: 8066 + + JSON_OBJECTAGG 函数的第二个参数是非法参数。 + +* Error Number: 8101 + + 插件 ID 格式错误,正确的格式是 `[name]-[version]` 并且 name 和 version 中不能带有 '-'。 + +* Error Number: 8102 + + 无法读取插件定义信息。请检查插件相关的配置。 + +* Error Number: 8103 + + 插件名称错误,请检查插件的配置。 + +* Error Number: 8104 + + 插件版本不匹配,请检查插件的配置。 + +* Error Number: 8105 + + 插件被重复载入。 + +* Error Number: 8106 + + 插件定义的系统变量名称没有以插件名作为开头,请联系插件的开发者进行修复。 + +* Error Number: 8107 + + 载入的插件未指定版本或指定的版本过低,请检查插件的配置。 + +* Error Number: 8108 + + 不支持的执行计划类型。该错误为内部处理的错误,如果遇到该报错请向 PingCAP 工程师或通过官方论坛寻求帮助。 + +* Error Number: 8109 + + analyze 索引时找不到指定的索引。 + +* Error Number: 8110 + + 不能进行笛卡尔积运算,需要将配置文件里的 `cross-join` 设置为 `true`。 + +* Error Number: 8111 + + execute 语句执行时找不到对应的 prepare 语句。 + +* Error Number: 8112 + + execute 语句的参数个数与 prepare 语句不符合。 + +* Error Number: 8113 + + execute 语句涉及的表结构在 prepare 语句执行后发生了变化。 + +* Error Number: 8115 + + 不支持 prepare 多行语句。 + +* Error Number: 8116 + + 不支持 prepare DDL 语句。 + +* Error Number: 8120 + + 获取不到事务的 start tso,请检查 PD Server 状态/监控/日志以及 TiDB Server 与 PD Server 之间的网络。 + +* Error Number: 8121 + + 权限检查失败,请检查数据库的权限配置。 + +* Error Number: 8122 + + 指定了通配符,但是找不到对应的表名。 + +* Error Number: 8123 + + 带聚合函数的 SQL 中返回非聚合的列,违反了 `only_full_group_by` 模式。请修改 SQL 或者考虑关闭 `only_full_group_by` 模式。 + +* Error Number: 8129 + + TiDB 尚不支持键长度 >= 65536 的 JSON 对象。 + +* Error Number: 8130 + + 完整的报错信息为 `ERROR 8130 (HY000): client has multi-statement capability disabled`。 + + 从早期版本的 TiDB 升级后,可能会出现该问题。为了减少 SQL 注入攻击的影响,TiDB 目前默认不允许在同一 `COM_QUERY` 调用中执行多个查询。 + + 可通过系统变量 [`tidb_multi_statement_mode`](/system-variables.md#tidb_multi_statement_mode-从-v4011-版本开始引入) 控制是否在同一 `COM_QUERY` 调用中执行多个查询。 + +* Error Number: 8138 + + 事务试图写入的行值有误,请参考[数据索引不一致报错](/troubleshoot-data-inconsistency-errors.md#error-8138)。 + +* Error Number: 8139 + + 事务试图写入的行和索引的 handle 值不一致,请参考[数据索引不一致报错](/troubleshoot-data-inconsistency-errors.md#error-8139)。 + +* Error Number: 8140 + + 事务试图写入的行和索引的值不一致,请参考[数据索引不一致报错](/troubleshoot-data-inconsistency-errors.md#error-8140)。 + +* Error Number: 8141 + + 事务写入时,对 key 的存在性断言报错,请参考[数据索引不一致报错](/troubleshoot-data-inconsistency-errors.md#error-8141)。 + +* Error Number: 8143 + + 非事务 DML 语句的一个 batch 报错,语句中止,请参考[非事务 DML 语句](/non-transactional-dml.md) + +* Error Number: 8147 + + 当 [`tidb_constraint_check_in_place_pessimistic`](/system-variables.md#tidb_constraint_check_in_place_pessimistic-从-v630-版本开始引入) 设置为 `OFF` 时,为保证事务的正确性,SQL 语句执行时产生的任何错误都可能导致 TiDB 返回 `8147` 报错并中止当前事务。具体的错误原因,请参考对应的报错信息。详见[约束](/constraints.md#悲观事务)。 + +* Error Number: 8154 + + 目前 `LOAD DATA` 不支持从 TiDB 服务器本地导入数据,可以指定 `LOCAL` 从客户端导入,或者将数据上传到 S3/GCS 再进行导入。请参考 [`LOAD DATA`](/sql-statements/sql-statement-load-data.md)。 + +* Error Number: 8156 + + 传入的文件路径不能为空。需要设置正确的路径再进行导入。 + +* Error Number: 8157 + + 不支持的文件格式。请参考 [`IMPORT INTO`](/sql-statements/sql-statement-import-into.md#format) 查看支持的格式。 + +* Error Number: 8158 + + 传入的文件路径不合法。请根据具体的错误提示进行处理。S3 和 GCS 路径设置可参考[外部存储服务的 URI 格式](/external-storage-uri.md)。 + +* Error Number: 8159 + + TiDB 无法访问传入的 S3/GCS 路径。请确保填写的 S3/GCS bucket 存在,且输入了正确的 Access Key 和 Secret Access Key 以让 TiDB 服务器有权限访问 S3/GCS 对应的 bucket。 + +* Error Number: 8160 + + 读取数据文件失败。请根据具体的错误提示进行处理。 + +* Error Number: 8162 + + 语句存在错误。请根据具体的错误提示进行处理。 + +* Error Number: 8163 + + 未知的选项。请参考 [`IMPORT INTO`](/sql-statements/sql-statement-import-into.md#参数说明) 查看支持的选项。 + +* Error Number: 8164 + + 选项取值无效。请参考 [`IMPORT INTO`](/sql-statements/sql-statement-import-into.md#参数说明) 查看有效的取值。 + +* Error Number: 8165 + + 重复指定了选项,每个选项只能指定一次。 + +* Error Number: 8166 + + 某些选项只能在特定的条件下才可以使用。请根据具体的错误提示进行处理。请参考 [`IMPORT INTO`](/sql-statements/sql-statement-import-into.md#参数说明) 查看支持的选项。 + +* Error Number: 8170 + + 指定的 job 不存在。 + +* Error Number: 8171 + + 该 job 的状态不能进行当前操作。请根据具体的错误提示进行处理。 + +* Error Number: 8173 + + 执行 `IMPORT INTO` 时,TiDB 会对当前环境进行检查,比如检查下游表是否为空等。请根据具体的错误提示进行处理。 + +* Error Number: 8200 + + 尚不支持的 DDL 语法。请参考[与 MySQL DDL 的兼容性](/mysql-compatibility.md#ddl-的限制)。 + +* Error Number: 8214 + + DDL 操作被 admin cancel 操作终止。 + +* Error Number: 8215 + + Admin Repair 表失败,如果遇到该报错请向 PingCAP 工程师或通过官方论坛寻求帮助。 + +* Error Number: 8216 + + 自动随机列使用的方法不正确,请参考 [auto random 功能文档](/auto-random.md)进行修改。 + +* Error Number: 8223 + + 检测出数据与索引不一致的错误,如果遇到该报错请向 PingCAP 工程师或通过官方论坛寻求帮助。 + +* Error Number: 8224 + + 找不到 DDL job,请检查 restore 操作指定的 job id 是否存在。 + +* Error Number: 8225 + + DDL 已经完成,无法被取消。 + +* Error Number: 8226 + + DDL 几乎要完成了,无法被取消。 + +* Error Number: 8227 + + 创建 Sequence 时使用了不支持的选项,支持的选项的列表可以参考 [Sequence 使用文档](/sql-statements/sql-statement-create-sequence.md#参数说明)。 + +* Error Number: 8228 + + 在 Sequence 上使用 `setval` 时指定了不支持的类型,该函数的示例可以在 [Sequence 使用文档](/sql-statements/sql-statement-create-sequence.md#示例)中找到。 + +* Error Number: 8229 + + 事务超过存活时间,遇到该问题可以提交或者回滚当前事务,开启一个新事务。 + +* Error Number: 8230 + + TiDB 目前不支持在新添加的列上使用 Sequence 作为默认值,如果尝试进行这类操作会返回该错误。 + +* Error Number: 8248 + + 资源组已存在。在重复创建资源组时返回该错误。 + +* Error Number: 8249 + + 资源组不存在。在修改或绑定不存在的资源组时返回该错误。请参考[创建资源组](/tidb-resource-control.md#创建资源组)。 + +* Error Number: 8250 + + 完整的报错信息如下: + + `ERROR 8250 (HY000) : Resource control feature is disabled. Run "SET GLOBAL tidb_enable_resource_control='on'" to enable the feature` + + 资源控制的功能没有打开时,使用资源管控 (Resource Control) 相关功能会返回该错误。你可以开启全局变量 [`tidb_enable_resource_control`](/system-variables.md#tidb_enable_resource_control-从-v660-版本开始引入) 启用资源管控。 + +* Error Number: 8251 + + `Resource Control` 组件在 TiDB 启动时进行初始化,相关配置会从 `Resource Control` 的服务端 `Resource Manager` 上获取,如果此过程中出错,则会返回此错误。 + +* Error Number: 8252 + + 完整的报错信息如下: + + `ERROR 8252 (HY000) : Exceeded resource group quota limitation` + + 在尝试消耗超过资源组的限制时返回该错误。一般出现该错误,是由于单次事务太大或者并发太多导致,需调整事务大小或减少客户端并发数。 + +* Error Number: 8253 + + 查询终止,因为满足 Runaway Queries 的条件。请参考 [Runaway Queries](/tidb-resource-control.md#管理资源消耗超出预期的查询-runaway-queries)。 + +* Error Number: 8254 + + 查询终止,因为被 Runaway Queries 免疫命中。请参考 [Runaway Queries](/tidb-resource-control.md#管理资源消耗超出预期的查询-runaway-queries)。 + +* Error Number: 8260 + + DDL 操作无法被 `ADMIN PAUSE` 暂停运行。 + +* Error Number: 8261 + + DDL 操作无法被 `ADMIN RESUME` 恢复运行。 + +* Error Number: 8262 + + DDL 已经被 `ADMIN PAUSE` 暂停,无法再次执行。 + +* Error Number: 8263 + + 该 DDL 无法在特定的 BDR role 下执行。请确定该集群是否处于[双向复制](/ticdc/ticdc-bidirectional-replication.md) 中。如果集群没有在双向复制中,可以通过 `ADMIN UNSET BDR ROLE;` 使 DDL 恢复正常使用。 + +* Error Number: 9001 + + 完整的报错信息为 `ERROR 9001 (HY000) : PD Server Timeout`。 + + 请求 PD 超时,请检查 PD Server 状态/监控/日志以及 TiDB Server 与 PD Server 之间的网络。 + +* Error Number: 9002 + + 完整的报错信息为 `ERROR 9002 (HY000) : TiKV Server Timeout`。 + + 请求 TiKV 超时,请检查 TiKV Server 状态/监控/日志以及 TiDB Server 与 TiKV Server 之间的网络。 + +* Error Number: 9003 + + 完整的报错信息为 `ERROR 9003 (HY000) : TiKV Server is Busy`。 + + TiKV 操作繁忙,一般出现在数据库负载比较高时,请检查 TiKV Server 状态/监控/日志。 + +* Error Number: 9004 + + 完整的报错信息为 `ERROR 9004 (HY000) : Resolve Lock Timeout`。 + + 清理锁超时,当数据库上承载的业务存在大量的事务冲突时,会遇到这种错误,请检查业务代码是否有锁争用。 + +* Error Number: 9005 + + 完整的报错信息为 `ERROR 9005 (HY000) : Region is unavailable`。 + + 访问的 Region 不可用,某个 Raft Group 不可用,如副本数目不足,出现在 TiKV 比较繁忙或者是 TiKV 节点停机的时候,请检查 TiKV Server 状态/监控/日志。 + +* Error Number: 9006 + + 完整的报错信息为 `ERROR 9006 (HY000) : GC life time is shorter than transaction duration`。 + + GC Life Time 间隔时间过短,长事务本应读到的数据可能被清理了。你可以使用如下命令修改 [`tidb_gc_life_time`](/system-variables.md#tidb_gc_life_time-从-v50-版本开始引入) 的值: + + ```sql + SET GLOBAL tidb_gc_life_time = '30m'; + ``` + + 其中 30m 代表仅清理 30 分钟前的数据,这可能会额外占用一定的存储空间。 + +* Error Number: 9007 + + 报错信息以 `ERROR 9007 (HY000) : Write conflict` 开头。 + + 如果报错信息中含有 "reason=LazyUniquenessCheck",说明是悲观事务并且设置了 `@@tidb_constraint_check_in_place_pessimistic=OFF`,业务中存在唯一索引上的写冲突,此时悲观事务不能保证执行成功。可以在应用测重试事务,或将该变量设置成 `ON` 绕过。详见[约束](/constraints.md#悲观事务)。 + +* Error Number: 9008 + + 同时向 TiKV 发送的请求过多,超过了限制。请调大 `tidb_store_limit` 或将其设置为 `0` 来取消对请求流量的限制。 + +* Error Number: 9010 + + TiKV 无法处理这条 raft log,请检查 TiKV Server 状态/监控/日志。 + +* Error Number: 9012 + + 请求 TiFlash 超时。请检查 TiFlash Server 状态/监控/日志以及 TiDB Server 与 TiFlash Server 之间的网络。 + +* Error Number: 9013 + + TiFlash 操作繁忙。该错误一般出现在数据库负载比较高时。请检查 TiFlash Server 的状态/监控/日志。 + +### MySQL 原生报错汇总 + +* Error Number: 2013 (HY000) + + 完整的报错信息为 `ERROR 2013 (HY000): Lost connection to MySQL server during query`。 + + 排查方法如下: + + - log 中是否有 panic + - dmesg 中是否有 oom,命令:`dmesg -T | grep -i oom` + - 长时间没有访问,也会收到这个报错,一般是 tcp 超时导致的,tcp 长时间不用,会被操作系统 kill。 + +* Error Number: 1105 (HY000) + + 完整的报错信息为 `ERROR 1105 (HY000): other error: unknown error Wire Error(InvalidEnumValue(4004))` + + 这类问题一般是 TiDB 和 TiKV 版本不匹配,在升级过程尽量一起升级,避免版本 mismatch。 + +* Error Number: 1148 (42000) + + 完整的报错信息为 `ERROR 1148 (42000): the used command is not allowed with this TiDB version`。 + + 这个问题是因为在执行 `LOAD DATA LOCAL` 语句的时候,MySQL 客户端不允许执行此语句(即 `local_infile` 选项为 0)。解决方法是在启动 MySQL 客户端时,用 `--local-infile=1` 选项。具体启动指令类似:`mysql --local-infile=1 -u root -h 127.0.0.1 -P 4000`。有些 MySQL 客户端需要设置而有些不需要设置,原因是不同版本的 MySQL 客户端对 `local-infile` 的默认值不同。 + +* Error Number: 9001 (HY000) + + 完整的报错信息为 `ERROR 9001 (HY000): PD server timeout start timestamp may fall behind safe point` + + 这个报错一般是 TiDB 访问 PD 出了问题,TiDB 后台有个 worker 会不断地从 PD 查询 safepoint,如果超过 100s 查不成功就会报这个错。一般是因为 PD 磁盘操作过忙、反应过慢,或者 TiDB 和 PD 之间的网络有问题。TiDB 常见错误码请参考[错误码与故障诊断](/error-codes.md)。 + +* TiDB 日志中的报错信息:EOF + + 当客户端或者 proxy 断开连接时,TiDB 不会立刻察觉连接已断开,而是等到开始往连接返回数据时,才发现连接已断开,此时日志会打印 EOF 错误。 + +## 故障诊断 + +参见[故障诊断文档](/troubleshoot-tidb-cluster.md)。 diff --git a/markdown-pages/zh/tidb/master/faq/tidb-faq.md b/markdown-pages/zh/tidb/master/faq/tidb-faq.md new file mode 100644 index 0000000..94bef7b --- /dev/null +++ b/markdown-pages/zh/tidb/master/faq/tidb-faq.md @@ -0,0 +1,119 @@ +--- +title: TiDB 产品常见问题 +aliases: ['/docs-cn/dev/faq/tidb-faq/','/docs-cn/dev/faq/tidb/'] +summary: TiDB 是 PingCAP 公司自主设计、研发的开源分布式关系型数据库,支持在线事务处理与在线分析处理,具备水平扩容、高可用、实时 HTAP、云原生的特性。TiDB 不是基于 MySQL 开发的,而是由 PingCAP 团队完全自主开发的产品。TiDB 易用性很高,支持绝大部分 MySQL 8.0 的语法,但不支持触发器、存储过程、自定义函数等。TiDB 支持分布式事务,兼容 MySQL Client/Driver 的编程语言,支持其他存储引擎,如 TiKV、UniStore 和 MockTiKV。获取 TiDB 知识的途径包括官方文档、官方博客、AskTUG 社区论坛和 PingCAP Education。用户名长度限制为 32 个字符,最大列数为 1017,单行大小不超过 6MB。TiDB 不支持 XA,但支持对列存储引擎的高并发 INSERT 或 UPDATE 操作。 +--- + +# TiDB 产品常见问题 + +## 1.1 TiDB 介绍及整体架构 + +### 1.1.1 TiDB 是什么? + +[TiDB](https://github.com/pingcap/tidb) 是 [PingCAP](https://pingcap.com/about-cn/) 公司自主设计、研发的开源分布式关系型数据库,是一款同时支持在线事务处理与在线分析处理 (Hybrid Transactional and Analytical Processing, HTAP) 的融合型分布式数据库产品,具备水平扩容或者缩容、金融级高可用、实时 HTAP、云原生的分布式数据库、兼容 MySQL 协议和 MySQL 生态等重要特性。目标是为用户提供一站式 OLTP (Online Transactional Processing)、OLAP (Online Analytical Processing)、HTAP 解决方案。TiDB 适合高可用、强一致要求较高、数据规模较大等各种应用场景。更多详细信息,请参阅 [TiDB 简介](/overview.md)。 + +### 1.1.2 TiDB 整体架构 + +参见 [TiDB 整体架构](/tidb-architecture.md),以及 TiDB 数据库的[存储](/tidb-storage.md)、[计算](/tidb-computing.md)与[调度](/tidb-scheduling.md)。 + +### 1.1.3 TiDB 是基于 MySQL 开发的吗? + +不是。虽然 TiDB 支持 MySQL 语法和协议,但是 TiDB 是由 PingCAP 团队完全自主开发的产品。 + +### 1.1.4 TiDB、TiKV、Placement Driver (PD) 主要作用? + +- TiDB 是 Server 计算层,主要负责 SQL 的解析、制定查询计划、生成执行器。 +- TiKV 是分布式 Key-Value 存储引擎,用来存储真正的数据,简而言之,TiKV 是 TiDB 的存储引擎。 +- PD 是 TiDB 集群的管理组件,负责存储 TiKV 的元数据,同时也负责分配时间戳以及对 TiKV 做负载均衡调度。 + +### 1.1.5 TiDB 易用性如何? + +TiDB 使用起来很简单,可以将 TiDB 集群当成 MySQL 来用。你可以将 TiDB 用在任何以 MySQL 作为后台存储服务的应用中,并且基本上不需要修改应用代码,同时你可以用大部分流行的 MySQL 管理工具来管理 TiDB。 + +### 1.1.6 TiDB 和 MySQL 兼容性如何? + +TiDB 支持绝大部分 MySQL 8.0 的语法,但目前还不支持触发器、存储过程、自定义函数等。详情参见[与 MySQL 兼容性对比](/mysql-compatibility.md)。 + +### 1.1.7 TiDB 支持分布式事务吗? + +支持。无论是一个地方的几个节点,还是[跨多个数据中心的多个节点](/multi-data-centers-in-one-city-deployment.md),TiDB 均支持 ACID 分布式事务。 + +TiDB 事务模型灵感源自 Google Percolator 模型,主体是一个两阶段提交协议,并进行了一些实用的优化。该模型依赖于一个时间戳分配器,为每个事务分配单调递增的时间戳,这样就检测到事务冲突。在 TiDB 集群中,[PD](/tidb-scheduling.md) 承担时间戳分配器的角色。 + +### 1.1.8 TiDB 支持哪些编程语言? + +只要支持 MySQL Client/Driver 的编程语言,都可以直接使用 TiDB。 + +### 1.1.9 TiDB 是否支持其他存储引擎? + +是的,除了 TiKV 之外,TiDB 还支持一些单机存储引擎,比如 UniStore 和 MockTiKV。注意,TiDB 后续版本可能不再支持 MockTiKV。 + +要查看 TiDB 支持的存储引擎,可使用以下命令: + +```shell +./bin/tidb-server -h +``` + +返回结果如下: + +```shell +Usage of ./bin/tidb-server: + -L string + log level: info, debug, warn, error, fatal (default "info") + -P string + tidb server port (default "4000") + -V print version information and exit (default false) +......... + -store string + registered store name, [tikv, mocktikv, unistore] (default "unistore") + ...... +``` + +### 1.1.10 除了官方文档,有没有其他 TiDB 知识获取途径? + +- [官方文档](https://docs.pingcap.com/zh/):获取 TiDB 相关知识最主要、最及时的途径。 +- [官方博客](https://cn.pingcap.com/blog/):了解产品技术解读、观点洞察、案例实践。 +- [AskTUG 社区论坛](https://asktug.com):与社区用户、技术专家互动交流。 +- [PingCAP Education](https://cn.pingcap.com/education/):学习线上课程,获得数据库能力认证。 + +### 1.1.11 TiDB 用户名长度限制? + +在 TiDB 中,用户名最长为 32 个字符。 + +### 1.1.12 TiDB 中列数和行大小的限制是多少? + +- TiDB 中默认的最大列数为 1017。你可以调整这个限制,最大可调整到 4096 列。 +- TiDB 中默认单行大小不超过 6 MB。你可以调整这个限制,最大可调整到 120 MB。 + +更多信息,请参考 [TiDB 限制](/tidb-limitations.md)。 + +### 1.1.13 TiDB 是否支持 XA? + +虽然 TiDB 的 JDBC 驱动用的就是 MySQL Connector/J,但是当使用 Atomikos 的时候,数据源要配置成类似这样的配置:`type="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource"`。MySQL JDBC XADataSource 连接 TiDB 的模式目前是不支持的。MySQL JDBC 中配置好的 XADataSource 模式,只对 MySQL 数据库起作用(DML 去修改 redo 等)。 + +Atomikos 配好两个数据源后,JDBC 驱动都要设置成 XA 模式,然后 Atomikos 在操作 TM 和 RM (DB) 的时候,会通过数据源的配置,发起带有 XA 指令到 JDBC 层。JDBC 层 XA 模式启用的情况下,会对 InnoDB(如果是 MySQL 的话)下发操作一连串 XA 逻辑的动作,包括 DML 去变更 redo log 等,就是两阶段递交的那些操作。TiDB 目前的引擎版本中,没有对上层应用层 JTA/XA 的支持,不解析这些 Atomikos 发过来的 XA 类型的操作。 + +MySQL 是单机数据库,只能通过 XA 来满足跨数据库事务,而 TiDB 本身就通过 Google 的 Percolator 事务模型支持分布式事务,性能稳定性比 XA 要高出很多,所以不会也不需要支持 XA。 + +### 1.1.14 TiDB 如何在不影响性能的情况下支持对列存储引擎 (TiFlash) 的高并发 `INSERT` 或 `UPDATE` 操作? + +- [TiFlash](/tiflash/tiflash-overview.md) 引入了 DeltaTree 这种特殊结构来处理列存引擎的修改。 +- TiFlash 作为 Raft Group 中的 Learner 角色,不参与 log commit 选举,也不会写入数据。这意味着 DML 操作不需要等待 TiFlash 的确认,所以 TiFlash 不会影响 OLTP 的性能。另外,TiFlash 和 TiKV 分开部署在不同的实例上,不会相互影响。 + +### 1.1.15 TiFlash 提供什么样的一致性保证? + +TiFlash 默认保持数据强一致性。Raft Learner 流程会更新数据。此外 TSO 检查可以确保查询中的数据与事务完全一致。更多信息,请参考[异步复制](/tiflash/tiflash-overview.md#异步复制)和[一致性](/tiflash/tiflash-overview.md#一致性)。 + +## 1.2 TiDB 原理 + +### 1.2.1 存储 TiKV 详细解读 + +[三篇文章了解 TiDB 技术内幕 - 说存储](https://cn.pingcap.com/blog/tidb-internal-1) + +### 1.2.2 计算 TiDB 详细解读 + +[三篇文章了解 TiDB 技术内幕 - 说计算](https://cn.pingcap.com/blog/tidb-internal-2) + +### 1.2.3 调度 PD 详细解读 + +[三篇文章了解 TiDB 技术内幕 - 谈调度](https://cn.pingcap.com/blog/tidb-internal-3) diff --git a/markdown-pages/zh/tidb/master/functions-and-operators/aggregate-group-by-functions.md b/markdown-pages/zh/tidb/master/functions-and-operators/aggregate-group-by-functions.md new file mode 100644 index 0000000..3ebcb74 --- /dev/null +++ b/markdown-pages/zh/tidb/master/functions-and-operators/aggregate-group-by-functions.md @@ -0,0 +1,169 @@ +--- +title: GROUP BY 聚合函数 +aliases: ['/docs-cn/dev/functions-and-operators/aggregate-group-by-functions/','/docs-cn/dev/reference/sql/functions-and-operators/aggregate-group-by-functions/'] +summary: TiDB支持的聚合函数包括 COUNT、COUNT(DISTINCT)、SUM、AVG、MAX、MIN、GROUP_CONCAT、VARIANCE、VAR_POP、STD、STDDEV、VAR_SAMP、STDDEV_SAMP 和 JSON_OBJECTAGG。除了 GROUP_CONCAT 和 APPROX_PERCENTILE 外,这些聚合函数可以作为窗口函数使用。另外,TiDB 的 GROUP BY 子句支持 WITH ROLLUP 修饰符,还支持 SQL 模式 ONLY_FULL_GROUP_BY。与 MySQL 的区别在于 TiDB 对标准 SQL 有一些扩展,允许在 HAVING 子句中使用别名和非列表达式。 +--- + +# GROUP BY 聚合函数 + +本文将详细介绍 TiDB 支持的聚合函数。 + +## TiDB 支持的聚合函数 + +TiDB 支持的 MySQL `GROUP BY` 聚合函数如下所示: + +| 函数名 | 功能描述 | +|:---------|:--------------------| +| [`COUNT()`](https://dev.mysql.com/doc/refman/8.0/en/aggregate-functions.html#function_count) | 返回检索到的行的数目| +| [`COUNT(DISTINCT)`](https://dev.mysql.com/doc/refman/8.0/en/aggregate-functions.html#function_count-distinct) | 返回不同值的数目 | +| [`SUM()`](https://dev.mysql.com/doc/refman/8.0/en/aggregate-functions.html#function_sum) | 返回和 | +| [`AVG()`](https://dev.mysql.com/doc/refman/8.0/en/aggregate-functions.html#function_avg) | 返回平均值 | +| [`MAX()`](https://dev.mysql.com/doc/refman/8.0/en/aggregate-functions.html#function_max) | 返回最大值 | +| [`MIN()`](https://dev.mysql.com/doc/refman/8.0/en/aggregate-functions.html#function_min) | 返回最小值 | +| [`GROUP_CONCAT()`](https://dev.mysql.com/doc/refman/8.0/en/aggregate-functions.html#function_group-concat) | 返回连接的字符串 | +| [`VARIANCE()`,`VAR_POP()`](https://dev.mysql.com/doc/refman/8.0/en/aggregate-functions.html#function_var-pop) | 返回总体标准方差 | +| [`STD()`,`STDDEV()`,`STDDEV_POP`](https://dev.mysql.com/doc/refman/8.0/en/aggregate-functions.html#function_std) | 返回总体标准差 | +| [`VAR_SAMP()`](https://dev.mysql.com/doc/refman/8.0/en/aggregate-functions.html#function_var-samp) | 返回采样方差 | +| [`STDDEV_SAMP()`](https://dev.mysql.com/doc/refman/8.0/en/aggregate-functions.html#function_stddev-samp) | 返回采样标准方差 | +| [`JSON_OBJECTAGG(key, value)`](https://dev.mysql.com/doc/refman/8.0/en/aggregate-functions.html#function_json-objectagg) | 将结果集返回为单个含 (key, value) 键值对的 JSON object | + +> **注意:** +> +> - 除非另有说明,否则聚合函数默认忽略 `NULL` 值。 +> - 如果在不包含 `GROUP BY` 子句的语句中使用聚合函数,则相当于对所有行进行分组。 + +另外,TiDB 还支持以下聚合函数: + ++ `APPROX_PERCENTILE(expr, constant_integer_expr)` + + 该函数用于计算 `expr` 值的百分位数。参数 `constant_integer_expr` 是一个取值为区间 `[1,100]` 内整数的常量表达式,表示百分数。一个百分位数 Pk(`k`为百分数)表示数据集中至少有 `k%` 的数据小于等于 Pk。 + + 该函数中,表达式的返回结果必须为[数值类型](/data-type-numeric.md)或[日期与时间类型](/data-type-date-and-time.md)。函数不支持计算其他类型的返回结果,并直接返回 `NULL`。 + + 以下是一个计算第 50 百分位数的例子: + + ```sql + drop table if exists t; + create table t(a int); + insert into t values(1), (2), (3); + ``` + + ```sql + select approx_percentile(a, 50) from t; + ``` + + ```sql + +--------------------------+ + | approx_percentile(a, 50) | + +--------------------------+ + | 2 | + +--------------------------+ + 1 row in set (0.00 sec) + ``` + +上述聚合函数除 `GROUP_CONCAT()` 和 `APPROX_PERCENTILE()` 以外,均可作为[窗口函数](/functions-and-operators/window-functions.md)使用。 + +## GROUP BY 修饰符 + +自 v7.4.0 起,TiDB 的 `GROUP BY` 子句支持 `WITH ROLLUP` 修饰符。详情请参阅 [GROUP BY 修饰符](/functions-and-operators/group-by-modifier.md)。 + +## 对 SQL 模式的支持 + +TiDB 支持 SQL 模式 `ONLY_FULL_GROUP_BY`,当启用该模式时,TiDB 拒绝不明确的非聚合列的查询。例如,以下查询在启用 `ONLY_FULL_GROUP_BY` 时是不合规的,因为 `SELECT` 列表中的非聚合列 "b" 在 `GROUP BY` 语句中不显示: + +```sql +drop table if exists t; +create table t(a bigint, b bigint, c bigint); +insert into t values(1, 2, 3), (2, 2, 3), (3, 2, 3); +``` + +```sql +select a, b, sum(c) from t group by a; +``` + +``` ++------+------+--------+ +| a | b | sum(c) | ++------+------+--------+ +| 1 | 2 | 3 | +| 2 | 2 | 3 | +| 3 | 2 | 3 | ++------+------+--------+ +3 rows in set (0.01 sec) +``` + +```sql +set sql_mode = 'ONLY_FULL_GROUP_BY'; +``` + +``` +Query OK, 0 rows affected (0.00 sec) +``` + +```sql +select a, b, sum(c) from t group by a; +``` + +``` +ERROR 1055 (42000): Expression #2 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'b' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by +``` + +目前,TiDB 默认开启 SQL 模式 [`ONLY_FULL_GROUP_BY`](/mysql-compatibility.md#sql-模式)。 + +### 与 MySQL 的区别 + +TiDB 目前实现的 `ONLY_FULL_GROUP_BY` 没有 MySQL 5.7 严格。例如,假设我们执行以下查询,希望结果按 "c" 排序: + +```sql +drop table if exists t; +create table t(a bigint, b bigint, c bigint); +insert into t values(1, 2, 1), (1, 2, 2), (1, 3, 1), (1, 3, 2); +select distinct a, b from t order by c; +``` + +要对结果进行排序,必须先清除重复。但选择保留哪一行会影响 `c` 的保留值,也会影响排序,并使其具有任意性。 + +在 MySQL 中,`ORDER BY` 表达式需至少满足以下条件之一,否则 `DISTINCT` 和 `ORDER BY` 查询将因不合规而被拒绝: + +- 表达式等同于 `SELECT` 列表中的一个。 +- 表达式引用并属于查询选择表的所有列都是 `SELECT` 列表的元素。 + +但是在 TiDB 中,上述查询是合规的,详情参阅 [#4254](https://github.com/pingcap/tidb/issues/4254)。 + +TiDB 中另一个标准 SQL 的扩展允许 `HAVING` 子句中的引用使用 `SELECT` 列表中的别名表达式。例如:以下查询返回在 `orders` 中只出现一次的 `name` 值 + +```sql +select name, count(name) from orders +group by name +having count(name) = 1; +``` + +这个 TiDB 扩展允许在聚合列的 `HAVING` 子句中使用别名: + +```sql +select name, count(name) as c from orders +group by name +having c = 1; +``` + +标准 SQL 只支持 `GROUP BY` 子句中的列表达式,以下语句不合规,因为 `FLOOR(value/100)` 是一个非列表达式: + +```sql +select id, floor(value/100) +from tbl_name +group by id, floor(value/100); +``` + +TiDB 对标准 SQL 的扩展支持 `GROUP BY` 子句中非列表达式,认为上述语句合规。 + +标准 SQL 也不支持 `GROUP BY` 子句中使用别名。TiDB 对标准 SQL 的扩展支持使用别名,查询的另一种写法如下: + +```sql +select id, floor(value/100) as val +from tbl_name +group by id, val; +``` + +## 相关系统变量 + +`group_concat_max_len` 变量设置 `GROUP_CONCAT()` 函数缓冲区的最大长度。 diff --git a/markdown-pages/zh/tidb/master/functions-and-operators/bit-functions-and-operators.md b/markdown-pages/zh/tidb/master/functions-and-operators/bit-functions-and-operators.md new file mode 100644 index 0000000..93299ce --- /dev/null +++ b/markdown-pages/zh/tidb/master/functions-and-operators/bit-functions-and-operators.md @@ -0,0 +1,21 @@ +--- +title: 位函数和操作符 +aliases: ['/docs-cn/dev/functions-and-operators/bit-functions-and-operators/','/docs-cn/dev/reference/sql/functions-and-operators/bit-functions-and-operators/'] +summary: TiDB 支持 MySQL 5.7 中的所有位函数和操作符,包括BIT_COUNT()、&、~、|、^、<<和>>。BIT_COUNT() 返回参数二进制表示中为 1 的个数,& 表示位与,~ 表示按位取反,| 表示位或,^ 表示位亦或,<< 表示左移,>> 表示右移。 +--- + +# 位函数和操作符 + +TiDB 支持使用 MySQL 5.7 中提供的所有[位函数和操作符](https://dev.mysql.com/doc/refman/5.7/en/bit-functions.html)。 + +**位函数和操作符表** + +| 函数和操作符名 | 功能描述 | +| -------------- | ------------------------------------- | +| [`BIT_COUNT()`](https://dev.mysql.com/doc/refman/8.0/en/bit-functions.html#function_bit-count) | 返回参数二进制表示中为 1 的个数 | +| [&](https://dev.mysql.com/doc/refman/8.0/en/bit-functions.html#operator_bitwise-and) | 位与 | +| [~](https://dev.mysql.com/doc/refman/8.0/en/bit-functions.html#operator_bitwise-invert) | 按位取反 | +| [\|](https://dev.mysql.com/doc/refman/8.0/en/bit-functions.html#operator_bitwise-or) | 位或 | +| [^](https://dev.mysql.com/doc/refman/8.0/en/bit-functions.html#operator_bitwise-xor) | 位亦或 | +| [<<](https://dev.mysql.com/doc/refman/8.0/en/bit-functions.html#operator_left-shift) | 左移 | +| [>>](https://dev.mysql.com/doc/refman/8.0/en/bit-functions.html#operator_right-shift) | 右移 | diff --git a/markdown-pages/zh/tidb/master/functions-and-operators/cast-functions-and-operators.md b/markdown-pages/zh/tidb/master/functions-and-operators/cast-functions-and-operators.md new file mode 100644 index 0000000..fa3c1c5 --- /dev/null +++ b/markdown-pages/zh/tidb/master/functions-and-operators/cast-functions-and-operators.md @@ -0,0 +1,21 @@ +--- +title: Cast 函数和操作符 +aliases: ['/docs-cn/dev/functions-and-operators/cast-functions-and-operators/','/docs-cn/dev/reference/sql/functions-and-operators/cast-functions-and-operators/'] +summary: Cast 函数和操作符用于将某种数据类型的值转换为另一种数据类型。TiDB 支持使用 MySQL 5.7 中提供的所有 Cast 函数和操作符。包括 BINARY,将一个字符串转换成一个二进制字符串;CAST(),将一个值转换成一个确定类型;CONVERT(),将一个值转换成一个确定类型。TiDB 和 MySQL 对于 SELECT CAST(MeN AS CHAR) 的结果显示不一致,其中 MeN 是用科学计数法表示的双精度浮点数。MySQL 在 -15<=N<=14 时显示完整数值,在 N<-15 或 N>14 时显示科学计数法。而 TiDB 始终显示完整数值。例如,MySQL 对于 SELECT CAST(3.1415e15 AS CHAR) 的显示结果为 3.1415e15,而 TiDB 的显示结果为 3141500000000000。 +--- + +# Cast 函数和操作符 + +Cast 函数和操作符用于将某种数据类型的值转换为另一种数据类型。TiDB 支持使用 MySQL 5.7 中提供的所有 [Cast 函数和操作符](https://dev.mysql.com/doc/refman/5.7/en/cast-functions.html)。 + +## Cast 函数和操作符表 + +| 函数和操作符名 | 功能描述 | +| --------------- | ----------------------------------- | +| [`BINARY`](https://dev.mysql.com/doc/refman/8.0/en/cast-functions.html#operator_binary) | 将一个字符串转换成一个二进制字符串 | +| [`CAST()`](https://dev.mysql.com/doc/refman/8.0/en/cast-functions.html#function_cast) | 将一个值转换成一个确定类型 | +| [`CONVERT()`](https://dev.mysql.com/doc/refman/8.0/en/cast-functions.html#function_convert) | 将一个值转换成一个确定类型 | + +> **注意:** +> +> TiDB 和 MySQL 对于 `SELECT CAST(MeN AS CHAR)`(或者等价的 `SELECT CONVERT(MeM, CHAR)`)的结果显示不一致,其中 `MeN` 是用科学计数法表示的双精度浮点数。MySQL 在 `-15 <= N <= 14` 时显示完整数值,在 `N < -15` 或 `N > 14` 时显示科学计数法。而 TiDB 始终显示完整数值。例如,MySQL 对于 `SELECT CAST(3.1415e15 AS CHAR)` 的显示结果为 `3.1415e15`,而 TiDB 的显示结果为 `3141500000000000`。 diff --git a/markdown-pages/zh/tidb/master/functions-and-operators/control-flow-functions.md b/markdown-pages/zh/tidb/master/functions-and-operators/control-flow-functions.md new file mode 100644 index 0000000..66d2ed8 --- /dev/null +++ b/markdown-pages/zh/tidb/master/functions-and-operators/control-flow-functions.md @@ -0,0 +1,16 @@ +--- +title: 控制流程函数 +aliases: ['/docs-cn/dev/functions-and-operators/control-flow-functions/','/docs-cn/dev/reference/sql/functions-and-operators/control-flow-functions/'] +summary: TiDB 支持 MySQL 5.7 中的控制流程函数,包括 CASE、IF()、IFNULL() 和 NULLIF()。这些函数可以用于构建 if/else 语句和处理 NULL 值。 +--- + +# 控制流程函数 + +TiDB 支持使用 MySQL 5.7 中提供的所有[控制流程函数](https://dev.mysql.com/doc/refman/5.7/en/flow-control-functions.html)。 + +| 函数名 | 功能描述 | +|:--------------------------------------------------------------------------------------------------|:----------------------------------| +| [`CASE`](https://dev.mysql.com/doc/refman/8.0/en/flow-control-functions.html#operator_case) | Case 操作符 | +| [`IF()`](https://dev.mysql.com/doc/refman/8.0/en/flow-control-functions.html#function_if) | 构建 if/else | +| [`IFNULL()`](https://dev.mysql.com/doc/refman/8.0/en/flow-control-functions.html#function_ifnull) | 构建 Null if/else | +| [`NULLIF()`](https://dev.mysql.com/doc/refman/8.0/en/flow-control-functions.html#function_nullif) | 如果 expr1 = expr2,返回 `NULL` | diff --git a/markdown-pages/zh/tidb/master/functions-and-operators/date-and-time-functions.md b/markdown-pages/zh/tidb/master/functions-and-operators/date-and-time-functions.md new file mode 100644 index 0000000..22c57ae --- /dev/null +++ b/markdown-pages/zh/tidb/master/functions-and-operators/date-and-time-functions.md @@ -0,0 +1,102 @@ +--- +title: 日期和时间函数 +aliases: ['/docs-cn/dev/functions-and-operators/date-and-time-functions/','/docs-cn/dev/reference/sql/functions-and-operators/date-and-time-functions/'] +summary: TiDB 支持 MySQL 5.7 中的所有日期和时间函数。但是 TiDB 可能无法完全匹配 MySQL 的行为,建议使用正确的日期格式。TiDB 支持 str_to_date() 函数,但无法解析所有日期和时间值。此外,TiDB 不支持特定的日期和时间格式化选项。系统变量 default_week_format 影响 WEEK() 函数。更多信息,请参见 GitHub Issue #30082。 +--- + +# 日期和时间函数 + +TiDB 支持使用 MySQL 5.7 中提供的所有[日期和时间函数](https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html)。 + +> **注意:** +> +> - MySQL 常常会接受格式不正确的日期和时间值。例如,`'2020-01-01\n\t01:01:01'` 和 `'2020-01_01\n\t01:01'` 被视为有效的日期和时间值。 +> - TiDB 会尽量与 MySQL 的行为保持一致,但可能无法在所有情况下完全匹配。建议使用正确的格式化日期,TiDB 文档中未记录将如何处理格式不正确的值。 + +## 日期时间函数表 + +| 函数名 | 功能描述 | +| ------ | ---------------------------------------- | +| [`ADDDATE()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_adddate) | 将时间间隔添加到日期上 | +| [`ADDTIME()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_addtime) | 时间数值相加 | +| [`CONVERT_TZ()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_convert-tz) | 转换时区 | +| [`CURDATE()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_curdate) | 返回当前日期 | +| [`CURRENT_DATE()`, `CURRENT_DATE`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_current-date) | 与 CURDATE() 同义 | +| [`CURRENT_TIME()`, `CURRENT_TIME`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_current-time) | 与 CURTIME() 同义 | +| [`CURRENT_TIMESTAMP()`, `CURRENT_TIMESTAMP`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_current-timestamp) | 与 NOW() 同义 | +| [`CURTIME()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_curtime) | 返回当前时间 | +| [`DATE()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_date) | 从日期或日期/时间表达式中提取日期部分| +| [`DATE_ADD()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_date-add) | 将时间间隔添加到日期上| +| [`DATE_FORMAT()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_date-format) | 返回满足指定格式的日期/时间 | +| [`DATE_SUB()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_date-sub) | 从日期减去指定的时间间隔 | +| [`DATEDIFF()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_datediff) | 返回两个日期间隔的天数| +| [`DAY()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_day) | 与 DAYOFMONTH() 同义| +| [`DAYNAME()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_dayname) | 返回星期名称 | +| [`DAYOFMONTH()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_dayofmonth) | 返回参数对应的天数部分(1-31)| +| [`DAYOFWEEK()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_dayofweek) | 返回参数对应的星期下标| +| [`DAYOFYEAR()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_dayofyear) | 返回参数代表一年的哪一天 (1-366) | +| [`EXTRACT()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_extract) | 提取日期/时间中的单独部分| +| [`FROM_DAYS()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_from-days) | 将天数转化为日期 | +| [`FROM_UNIXTIME()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_from-unixtime) | 将 Unix 时间戳格式化为日期 | +| [`GET_FORMAT()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_get-format) | 返回满足日期格式的字符串 | +| [`HOUR()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_hour) | 提取日期/时间表达式中的小时部分 | +| [`LAST_DAY`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_last-day) | 返回参数中月份的最后一天 | +| [`LOCALTIME()`, `LOCALTIME`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_localtime) | 与 NOW() 同义 | +| [`LOCALTIMESTAMP`, `LOCALTIMESTAMP()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_localtimestamp) | 与 NOW() 同义 | +| [`MAKEDATE()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_makedate) | 根据给定的年份和一年中的天数生成一个日期 | +| [`MAKETIME()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_maketime) | 根据给定的时、分、秒生成一个时间 | +| [`MICROSECOND()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_microsecond) | 返回参数的微秒部分| +| [`MINUTE()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_minute) | 返回参数的分钟部分| +| [`MONTH()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_month) | 返回参数的月份部分| +| [`MONTHNAME()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_monthname) | 返回参数的月份名称| +| [`NOW()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_now) | 返回当前日期和时间| +| [`PERIOD_ADD()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_period-add) | 在年-月表达式上添加一段时间(数个月)| +| [`PERIOD_DIFF()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_period-diff) | 返回间隔的月数| +| [`QUARTER()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_quarter) | 返回参数对应的季度(1-4) | +| [`SEC_TO_TIME()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_sec-to-time) | 将秒数转化为 'HH:MM:SS' 的格式| +| [`SECOND()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_second) | 返回秒数(0-59) | +| [`STR_TO_DATE()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_str-to-date) | 将字符串转化为日期| +| [`SUBDATE()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_subdate) | 当传入三个参数时作为 DATE_SUB() 的同义| +| [`SUBTIME()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_subtime) | 从一个时间中减去一段时间 | +| [`SYSDATE()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_sysdate) | 返回该方法执行时的时间| +| [`TIME()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_time) | 返回参数的时间表达式部分 | +| [`TIME_FORMAT()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_time-format) | 格式化时间| +| [`TIME_TO_SEC()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_time-to-sec) | 返回参数对应的秒数| +| [`TIMEDIFF()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_timediff) | 返回时间间隔 | +| [`TIMESTAMP()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_timestamp) | 传入一个参数时候,该方法返回日期或日期/时间表达式,传入两个参数时候,返回参数的和 | +| [`TIMESTAMPADD()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_timestampadd) | 在日期/时间表达式上增加一段时间间隔 | +| [`TIMESTAMPDIFF()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_timestampdiff) | 从日期/时间表达式中减去一段时间间隔 | +| [`TO_DAYS()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_to-days) | 将参数转化对应的天数(从第 0 年开始) | +| [`TO_SECONDS()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_to-seconds) | 将日期或日期/时间参数转化为秒数(从第 0 年开始) | +| [`UNIX_TIMESTAMP()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_unix-timestamp) | 返回一个 Unix 时间戳| +| [`UTC_DATE()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_utc-date) | 返回当前的 UTC 日期 | +| [`UTC_TIME()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_utc-time) | 返回当前的 UTC 时间 | +| [`UTC_TIMESTAMP()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_utc-timestamp) | 返回当前的 UTC 日期和时间| +| [`WEEK()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_week) | 返回参数所在的一年中的星期数 | +| [`WEEKDAY()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_weekday) | 返回星期下标 | +| [`WEEKOFYEAR()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_weekofyear) | 返回参数在日历中对应的一年中的星期数 | +| [`YEAR()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_year) | 返回参数对应的年数| +| [`YEARWEEK()`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_yearweek) | 返回年数和星期数 | + +## MySQL 兼容性 + +TiDB 支持 `str_to_date()` 函数,但是无法解析所有的日期和时间值。此外,TiDB 不支持以下日期和时间格式化选项: + +| 格式 | 说明 | +|--------|---------------------------------------------------------------------------------------| +| "%a" | 星期名的缩写(例如 Sun..Sat) | +| "%D" | 带英文后缀的月份日期(例如 0th,1st,2nd,3rd) | +| "%U" | 星期 (00..53),星期日是每周的第一天;WEEK() mode 0 | +| "%u" | 星期 (00..53),星期一是每周的第一天;WEEK() mode 1 | +| "%V" | 星期 (01..53),星期日是每周的第一天;WEEK() mode 2;和 "%X" 一起使用 | +| "%v" | 星期 (01..53),星期一是每周的第一天;WEEK() mode 3;和 "%x" 一起使用 | +| "%W" | 星期名(例如 Sunday..Saturday) | +| "%w" | 一周中的天名 (0=Sunday..6=Saturday) | +| "%X" | 星期天是每周第一天的年份,数字类型,四位数字 | +| "%x" | 星期一是每周第一天的年份,数字类型,四位数字 | + +更多信息,参见 [GitHub Issue #30082](https://github.com/pingcap/tidb/issues/30082)。 + +## 相关系统变量 + +`default_week_format` 变量影响 `WEEK()` 函数。 diff --git a/markdown-pages/zh/tidb/master/functions-and-operators/encryption-and-compression-functions.md b/markdown-pages/zh/tidb/master/functions-and-operators/encryption-and-compression-functions.md new file mode 100644 index 0000000..27557c9 --- /dev/null +++ b/markdown-pages/zh/tidb/master/functions-and-operators/encryption-and-compression-functions.md @@ -0,0 +1,35 @@ +--- +title: 加密和压缩函数 +aliases: ['/docs-cn/dev/functions-and-operators/encryption-and-compression-functions/','/docs-cn/dev/reference/sql/functions-and-operators/encryption-and-compression-functions/'] +summary: TiDB 支持大部分 MySQL 5.7 中提供的加密和压缩函数,包括MD5、PASSWORD、RANDOM_BYTES、SHA1、SHA2、AES_DECRYPT、AES_ENCRYPT、COMPRESS、UNCOMPRESS、UNCOMPRESSED_LENGTH 和 VALIDATE_PASSWORD_STRENGTH。相关系统变量 block_encryption_mode 用于设置 AES_ENCRYPT 和 AES_DECRYPT 的加密模式。不支持的函数包括 DES_DECRYPT、DES_ENCRYPT、OLD_PASSWORD 和 ENCRYPT,以及仅在 MySQL 企业版中支持的函数。 +--- + +# 加密和压缩函数 + +TiDB 支持使用 MySQL 5.7 中提供的大部分[加密和压缩函数](https://dev.mysql.com/doc/refman/5.7/en/encryption-functions.html)。 + +## 支持的函数 + +| 函数名 | 功能描述 | +|:-----------|:----------------------------| +| [`MD5()`](https://dev.mysql.com/doc/refman/8.0/en/encryption-functions.html#function_md5)                                                             | 计算字符串的 MD5 校验和       | +| [`PASSWORD()`](https://dev.mysql.com/doc/refman/8.0/en/encryption-functions.html#function_password) | 计算并返回密码字符串 | +| [`RANDOM_BYTES()`](https://dev.mysql.com/doc/refman/8.0/en/encryption-functions.html#function_random-bytes) | 返回随机字节向量 | +| [`SHA1()`, `SHA()`](https://dev.mysql.com/doc/refman/8.0/en/encryption-functions.html#function_sha1)                                                   | 计算 SHA-1 160 位校验和               | +| [`SHA2()`](https://dev.mysql.com/doc/refman/8.0/en/encryption-functions.html#function_sha2)                                                           | 计算 SHA-2 校验和                       | +| [`SM3()`](https://zh.m.wikipedia.org/zh-hans/SM3)                                                           | 计算 SM3 校验和(MySQL 中暂不支持该函数)           | +| [`AES_DECRYPT()`](https://dev.mysql.com/doc/refman/8.0/en/encryption-functions.html#function_aes-decrypt) | 使用 AES 解密 | +| [`AES_ENCRYPT()`](https://dev.mysql.com/doc/refman/8.0/en/encryption-functions.html#function_aes-encrypt) | 使用 AES 加密 | +| [`COMPRESS()`](https://dev.mysql.com/doc/refman/8.0/en/encryption-functions.html#function_compress) | 返回经过压缩的二进制字符串 | +| [`UNCOMPRESS()`](https://dev.mysql.com/doc/refman/8.0/en/encryption-functions.html#function_uncompress) | 解压缩字符串 | +| [`UNCOMPRESSED_LENGTH()`](https://dev.mysql.com/doc/refman/8.0/en/encryption-functions.html#function_uncompressed-length)                             | 返回字符串解压后的长度 | +| [`VALIDATE_PASSWORD_STRENGTH()`](https://dev.mysql.com/doc/refman/8.0/en/encryption-functions.html#function_validate-password-strength) | 确定密码强度 | + +## 相关系统变量 + +`block_encryption_mode` 变量设置 `AES_ENCRYPT()` 和 `AES_DECRYPT()` 所使用的加密模式。 + +## 不支持的函数 + +* `DES_DECRYPT()`、`DES_ENCRYPT()`、`OLD_PASSWORD()` 和 `ENCRYPT()`:这些函数在 MySQL 5.7 中被废弃,并且已在 MySQL 8.0 中移除。 +* 只在 MySQL 企业版中支持的函数。见 [Issue #2632](https://github.com/pingcap/tidb/issues/2632)。 diff --git a/markdown-pages/zh/tidb/master/functions-and-operators/functions-and-operators-overview.md b/markdown-pages/zh/tidb/master/functions-and-operators/functions-and-operators-overview.md new file mode 100644 index 0000000..180b320 --- /dev/null +++ b/markdown-pages/zh/tidb/master/functions-and-operators/functions-and-operators-overview.md @@ -0,0 +1,13 @@ +--- +title: 函数和操作符概述 +aliases: ['/docs-cn/dev/functions-and-operators/functions-and-operators-overview/','/docs-cn/dev/reference/sql/functions-and-operators/reference/'] +summary: TiDB 中的函数和操作符使用方法与 MySQL 基本一致。在 SQL 语句中,表达式可用于诸如 SELECT 语句的 ORDER BY 或 HAVING 子句,SELECT/DELETE/UPDATE 语句的 WHERE 子句,或 SET 语句之类的地方。可使用字面值,列名,NULL,内置函数,操作符等来书写表达式。其中有些表达式下推到 TiKV 上执行,详见下推到 TiKV 的表达式列表。 +--- + +# 函数和操作符概述 + +TiDB 中函数和操作符使用方法与 MySQL 基本一致,详情参见:[Functions and Operators](https://dev.mysql.com/doc/refman/8.0/en/functions.html)。 + +在 SQL 语句中,表达式可用于诸如 `SELECT` 语句的 `ORDER BY` 或 `HAVING` 子句,`SELECT`/`DELETE`/`UPDATE` 语句的 `WHERE` 子句,或 `SET` 语句之类的地方。 + +可使用字面值,列名,NULL,内置函数,操作符等来书写表达式。其中有些表达式下推到 TiKV 上执行,详见[下推到 TiKV 的表达式列表](/functions-and-operators/expressions-pushed-down.md)。 diff --git a/markdown-pages/zh/tidb/master/functions-and-operators/information-functions.md b/markdown-pages/zh/tidb/master/functions-and-operators/information-functions.md new file mode 100644 index 0000000..48c6b06 --- /dev/null +++ b/markdown-pages/zh/tidb/master/functions-and-operators/information-functions.md @@ -0,0 +1,40 @@ +--- +title: 信息函数 +aliases: ['/docs-cn/dev/functions-and-operators/information-functions/','/docs-cn/dev/reference/sql/functions-and-operators/information-functions/'] +summary: TiDB 支持大部分 MySQL 5.7 的信息函数,包括 BENCHMARK(), CONNECTION_ID(), CURRENT_USER(), DATABASE(), FOUND_ROWS(), LAST_INSERT_ID(), ROW_COUNT(), SCHEMA(), SESSION_USER(), SYSTEM_USER(), USER(), 和 VERSION()。此外,TiDB 还有一个特有的信息函数 CURRENT_RESOURCE_GROUP(),而不支持 CHARSET(), COERCIBILITY(), 和 COLLATION() 函数。 +--- + +# 信息函数 + +TiDB 支持使用 MySQL 5.7 中提供的大部分[信息函数](https://dev.mysql.com/doc/refman/5.7/en/information-functions.html)。 + +## TiDB 支持的 MySQL 信息函数 + +| 函数名 | 功能描述 | +| ------ | ---------------------------------------- | +| [`BENCHMARK()`](https://dev.mysql.com/doc/refman/8.0/en/information-functions.html#function_benchmark) | 循环执行一个表达式 | +| [`CONNECTION_ID()`](https://dev.mysql.com/doc/refman/8.0/en/information-functions.html#function_connection-id) | 返回当前连接的连接 ID (线程 ID) | +| [`CURRENT_USER()`, `CURRENT_USER`](https://dev.mysql.com/doc/refman/8.0/en/information-functions.html#function_current-user) | 返回当前用户的用户名和主机名 | +| [`DATABASE()`](https://dev.mysql.com/doc/refman/8.0/en/information-functions.html#function_database) | 返回默认(当前)的数据库名 | +| [`FOUND_ROWS()`](https://dev.mysql.com/doc/refman/8.0/en/information-functions.html#function_found-rows) | 该函数返回对于一个包含 LIMIT 的 SELECT 查询语句,在不包含 LIMIT 的情况下回返回的记录数 | +| [`LAST_INSERT_ID()`](https://dev.mysql.com/doc/refman/8.0/en/information-functions.html#function_last-insert-id) | 返回最后一条 INSERT 语句中自增列的值 | +| [`ROW_COUNT()`](https://dev.mysql.com/doc/refman/8.0/en/information-functions.html#function_row-count) | 影响的行数 | +| [`SCHEMA()`](https://dev.mysql.com/doc/refman/8.0/en/information-functions.html#function_schema) | 与 DATABASE() 同义 | +| [`SESSION_USER()`](https://dev.mysql.com/doc/refman/8.0/en/information-functions.html#function_session-user) | 与 USER() 同义 | +| [`SYSTEM_USER()`](https://dev.mysql.com/doc/refman/8.0/en/information-functions.html#function_system-user) | 与 USER() 同义 | +| [`USER()`](https://dev.mysql.com/doc/refman/8.0/en/information-functions.html#function_user) | 返回客户端提供的用户名和主机名 | +| [`VERSION()`](https://dev.mysql.com/doc/refman/8.0/en/information-functions.html#function_version) | 返回当前 MySQL 服务器的版本信息 | + +## TiDB 特有的信息函数 + +下列函数为 TiDB 中特有的信息函数,MySQL 中无对应的函数。 + +| 函数名 | 功能描述 | +| ------ | ---------------------------------------- | +| [`CURRENT_RESOURCE_GROUP()`](/functions-and-operators/tidb-functions.md#current_resource_group) | 返回当前连接的资源组名 | + +## TiDB 不支持的信息函数 + +* `CHARSET()` +* `COERCIBILITY()` +* `COLLATION()` diff --git a/markdown-pages/zh/tidb/master/functions-and-operators/json-functions.md b/markdown-pages/zh/tidb/master/functions-and-operators/json-functions.md new file mode 100644 index 0000000..c55d4a4 --- /dev/null +++ b/markdown-pages/zh/tidb/master/functions-and-operators/json-functions.md @@ -0,0 +1,78 @@ +--- +title: JSON 函数 +aliases: ['/docs-cn/dev/functions-and-operators/json-functions/','/docs-cn/dev/reference/sql/functions-and-operators/json-functions/'] +summary: TiDB 支持 MySQL 5.7 GA 版本发布的大多数 JSON 函数,包括创建、搜索、修改、返回属性和效用函数。这些函数可用于处理 JSON 值,如创建 JSON 文档、搜索 JSON 文档中的值、修改 JSON 文档、返回 JSON 值属性和聚合函数。此外,还有其他相关函数可供参考。 +--- + +# JSON 函数 + +TiDB 支持 MySQL 5.7 GA 版本发布的大多数 JSON 函数。 + +## 创建 JSON 值的函数 + +| 函数 | 功能描述 | +| ------------------------------------------------------------------ | ---------------------------------------------------------- | +| [JSON_ARRAY([val[, val] ...])](https://dev.mysql.com/doc/refman/8.0/en/json-creation-functions.html#function_json-array) | 根据一系列元素创建一个 JSON 文档 | +| [JSON_OBJECT(key, val[, key, val] ...)](https://dev.mysql.com/doc/refman/8.0/en/json-creation-functions.html#function_json-object) | 根据一系列 K/V 对创建一个 JSON 文档 | +| [JSON_QUOTE(string)](https://dev.mysql.com/doc/refman/8.0/en/json-creation-functions.html#function_json-quote) | 返回一个字符串,该字符串为带引号的 JSON 值 | + +## 搜索 JSON 值的函数 + +| 函数 | 功能描述 | +| ------------------------------------------------------------ | ------------------------------------------------------------ | +| [JSON_CONTAINS(target, candidate[, path])](https://dev.mysql.com/doc/refman/8.0/en/json-search-functions.html#function_json-contains) | 通过返回 1 或 0 来表示目标 JSON 文档中是否包含给定的 candidate JSON 文档 | +| [JSON_CONTAINS_PATH(json_doc, one_or_all, path[, path] ...)](https://dev.mysql.com/doc/refman/8.0/en/json-search-functions.html#function_json-contains-path) | 通过返回 0 或 1 来表示一个 JSON 文档在给定路径是否包含数据 | +| [JSON_EXTRACT(json_doc, path[, path] ...)](https://dev.mysql.com/doc/refman/8.0/en/json-search-functions.html#function_json-extract) | 从 JSON 文档中解出某一路径对应的子文档 | +| [->](https://dev.mysql.com/doc/refman/8.0/en/json-search-functions.html#operator_json-column-path) | 返回执行路径后面的 JSON 列的值;`JSON_EXTRACT(doc, path_literal)` 的别名 | +| [->>](https://dev.mysql.com/doc/refman/8.0/en/json-search-functions.html#operator_json-inline-path) | 返回执行路径后面的 JSON 列的值和转义后的结果; `JSON_UNQUOTE(JSON_EXTRACT(doc, path_literal))` 的别名 | +| [JSON_KEYS(json_doc[, path])](https://dev.mysql.com/doc/refman/8.0/en/json-search-functions.html#function_json-keys) | 返回从 JSON 对象的顶级值作为 JSON array 的键,如果给定了路径参数,则从选定路径中获取顶级键 | +| [JSON_SEARCH(json_doc, one_or_all, search_str[, escape_char[, path] ...])](https://dev.mysql.com/doc/refman/8.0/en/json-search-functions.html#function_json-search) | 返回指定字符在 JSON 文档中的路径 | +| [value MEMBER OF(json_array)](https://dev.mysql.com/doc/refman/8.0/en/json-search-functions.html#operator_member-of) | 如果传入值是 JSON array 中的一个元素,返回 1,否则返回 0 | +| [JSON_OVERLAPS(json_doc1, json_doc2)](https://dev.mysql.com/doc/refman/8.0/en/json-search-functions.html#function_json-overlaps) | 表示两个 JSON 文档中是否包含公共部分。返回 1 表示两个 JSON 文档中包含公共部分,否则返回 0 | + +## 修改 JSON 值的函数 + +| 函数 | 功能描述 | +| --------------------------------- | ----------- | +| [JSON_APPEND(json_doc, path, value)](https://dev.mysql.com/doc/refman/8.0/en/json-modification-functions.html#function_json-append) | `JSON_ARRAY_APPEND` 的别名 | +| [JSON_ARRAY_APPEND(json_doc, path, value)](https://dev.mysql.com/doc/refman/8.0/en/json-modification-functions.html#function_json-array-append) | 将值追加到指定路径的 JSON 数组的末尾 | +| [JSON_ARRAY_INSERT(json_doc, path, val[, path, val] ...)](https://dev.mysql.com/doc/refman/8.0/en/json-modification-functions.html#function_json-array-insert) | 将数组插入 JSON 文档,并返回修改后的文档 | +| [JSON_INSERT(json_doc, path, val[, path, val] ...)](https://dev.mysql.com/doc/refman/8.0/en/json-modification-functions.html#function_json-insert) | 在 JSON 文档中在某一路径下插入子文档 | +| [JSON_MERGE(json_doc, json_doc[, json_doc] ...)](https://dev.mysql.com/doc/refman/8.0/en/json-modification-functions.html#function_json-merge) | 已废弃的 `JSON_MERGE_PRESERVE` 别名 | +| [JSON_MERGE_PATCH(json_doc, json_doc[, json_doc] ...)](https://dev.mysql.com/doc/refman/8.0/en/json-modification-functions.html#function_json-merge-patch) | 合并 JSON 文档 | +| [JSON_MERGE_PRESERVE(json_doc, json_doc[, json_doc] ...)](https://dev.mysql.com/doc/refman/8.0/en/json-modification-functions.html#function_json-merge-preserve) | 将两个或多个 JSON 文档合并成一个文档,并返回合并结果 | +| [JSON_REMOVE(json_doc, path[, path] ...)](https://dev.mysql.com/doc/refman/8.0/en/json-modification-functions.html#function_json-remove) | 移除 JSON 文档中某一路径下的子文档 | +| [JSON_REPLACE(json_doc, path, val[, path, val] ...)](https://dev.mysql.com/doc/refman/8.0/en/json-modification-functions.html#function_json-replace) | 替换 JSON 文档中的某一路径下的子文档 | +| [JSON_SET(json_doc, path, val[, path, val] ...)](https://dev.mysql.com/doc/refman/8.0/en/json-modification-functions.html#function_json-set) | 在 JSON 文档中为某一路径设置子文档 | +| [JSON_UNQUOTE(json_val)](https://dev.mysql.com/doc/refman/8.0/en/json-modification-functions.html#function_json-unquote) | 去掉 JSON 值外面的引号,返回结果为字符串 | +| [JSON_ARRAY_APPEND(json_doc, path, val[, path, val] ...)](https://dev.mysql.com/doc/refman/8.0/en/json-modification-functions.html#function_json-array-append) | 将值添加到 JSON 文档指定数组的末尾,并返回添加结果 | +| [JSON_ARRAY_INSERT(json_doc, path, val[, path, val] ...)](https://dev.mysql.com/doc/refman/8.0/en/json-modification-functions.html#function_json-array-insert) | 将值插入到 JSON 文档的指定位置,并返回插入结果 | + +## 返回 JSON 值属性的函数 + +| 函数 | 功能描述 | +| --------------------------------- | ----------- | +| [JSON_DEPTH(json_doc)](https://dev.mysql.com/doc/refman/8.0/en/json-attribute-functions.html#function_json-depth) | 返回 JSON 文档的最大深度 | +| [JSON_LENGTH(json_doc[, path])](https://dev.mysql.com/doc/refman/8.0/en/json-attribute-functions.html#function_json-length) | 返回 JSON 文档的长度;如果路径参数已定,则返回该路径下值的长度 | +| [JSON_TYPE(json_val)](https://dev.mysql.com/doc/refman/8.0/en/json-attribute-functions.html#function_json-type) | 检查某 JSON 文档内部内容的类型 | +| [JSON_VALID(json_doc)](https://dev.mysql.com/doc/refman/8.0/en/json-attribute-functions.html#function_json-valid) | 检查 JSON 文档内容是否有效;用于将列转换为 JSON 类型之前对该列进行检查 | + +## 效用函数 + +| 函数 | 功能描述 | +| --------------------------------- | ----------- | +| [JSON_PRETTY(json_doc)](https://dev.mysql.com/doc/refman/8.0/en/json-utility-functions.html#function_json-pretty) |格式化 JSON 文档 | +| [JSON_STORAGE_FREE(json_doc)](https://dev.mysql.com/doc/refman/8.0/en/json-utility-functions.html#function_json-storage-free) | 返回该 JSON 对象的存储空间中空闲的字节数。由于 TiDB 采用与 MySQL 完全不同的存储结构,本函数对合法的 JSON 值总是返回 0,主要用于兼容 MySQL 8.0 | +| [JSON_STORAGE_SIZE(json_doc)](https://dev.mysql.com/doc/refman/8.0/en/json-utility-functions.html#function_json-storage-size) | 返回存储 JSON 值所需的大致字节大小,由于不考虑 TiKV 压缩的字节大小,因此函数的输出与 MySQL 不严格兼容 | + +## 聚合函数 + +| 函数 | 功能描述 | +| --------------------------------- | ----------- | +| [JSON_ARRAYAGG(key)](https://dev.mysql.com/doc/refman/8.0/en/aggregate-functions.html#function_json-arrayagg) | 提供指定列 key 的聚合 | +| [JSON_OBJECTAGG(key, value)](https://dev.mysql.com/doc/refman/8.0/en/aggregate-functions.html#function_json-objectagg) | 提供给定两列键值对的聚合 | + +## 另请参阅 + +* [JSON Function Reference](https://dev.mysql.com/doc/refman/8.0/en/json-function-reference.html) +* [JSON Data Type](/data-type-json.md) diff --git a/markdown-pages/zh/tidb/master/functions-and-operators/miscellaneous-functions.md b/markdown-pages/zh/tidb/master/functions-and-operators/miscellaneous-functions.md new file mode 100644 index 0000000..6ed80bd --- /dev/null +++ b/markdown-pages/zh/tidb/master/functions-and-operators/miscellaneous-functions.md @@ -0,0 +1,37 @@ +--- +title: 其他函数 +aliases: ['/docs-cn/dev/functions-and-operators/miscellaneous-functions/','/docs-cn/dev/reference/sql/functions-and-operators/miscellaneous-functions/'] +summary: TiDB 支持大部分 MySQL 5.7 中的其他函数,包括 ANY_VALUE()、BIN_TO_UUID()、DEFAULT()、INET_ATON()、INET_NTOA()、INET6_ATON()、INET6_NTOA()、IS_IPV4()、IS_IPV4_COMPAT()、IS_IPV4_MAPPED()、IS_IPV6()、NAME_CONST()、SLEEP()、UUID()、UUID_TO_BIN()和VALUES()。不支持的函数有 UUID_SHORT() 和 MASTER_WAIT_POS()。 +--- + +# 其他函数 + +TiDB 支持使用 MySQL 5.7 中提供的大部分[其他函数](https://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html)。 + +## 支持的函数 + +| 函数名 | 功能描述 | +|:------|:-----------| +| [`ANY_VALUE()`](https://dev.mysql.com/doc/refman/8.0/en/miscellaneous-functions.html#function_any-value) | 在 `ONLY_FULL_GROUP_BY` 模式下,防止带有 `GROUP BY` 的语句报错 | +| [`BIN_TO_UUID()`](https://dev.mysql.com/doc/refman/8.0/en/miscellaneous-functions.html#function_bin-to-uuid) | 将通用唯一识别码 (UUID) 从二进制格式转换为文本格式 | +| [`DEFAULT()`](https://dev.mysql.com/doc/refman/8.0/en/miscellaneous-functions.html#function_default) | 返回表的某一列的默认值 | +| [`INET_ATON()`](https://dev.mysql.com/doc/refman/8.0/en/miscellaneous-functions.html#function_inet-aton) | 将 IP 地址转换为数值 | +| [`INET_NTOA()`](https://dev.mysql.com/doc/refman/8.0/en/miscellaneous-functions.html#function_inet-ntoa) | 将数值转换为 IP 地址 | +| [`INET6_ATON()`](https://dev.mysql.com/doc/refman/8.0/en/miscellaneous-functions.html#function_inet6-aton) | 将 IPv6 地址转换为数值 | +| [`INET6_NTOA()`](https://dev.mysql.com/doc/refman/8.0/en/miscellaneous-functions.html#function_inet6-ntoa) | 将数值转换为 IPv6 地址 | +| [`IS_IPV4()`](https://dev.mysql.com/doc/refman/8.0/en/miscellaneous-functions.html#function_is-ipv4) | 判断参数是否为 IPv4 地址 | +| [`IS_IPV4_COMPAT()`](https://dev.mysql.com/doc/refman/8.0/en/miscellaneous-functions.html#function_is-ipv4-compat) | 判断参数是否为兼容 IPv4 的地址 | +| [`IS_IPV4_MAPPED()`](https://dev.mysql.com/doc/refman/8.0/en/miscellaneous-functions.html#function_is-ipv4-mapped) | 判断参数是否为 IPv4 映射的地址 | +| [`IS_IPV6()`](https://dev.mysql.com/doc/refman/8.0/en/miscellaneous-functions.html#function_is-ipv6) | 判断参数是否为 IPv6 地址 | +| [`NAME_CONST()`](https://dev.mysql.com/doc/refman/8.0/en/miscellaneous-functions.html#function_name-const) | 可以用于重命名列名 | +| [`SLEEP()`](https://dev.mysql.com/doc/refman/8.0/en/miscellaneous-functions.html#function_sleep) | 让语句暂停执行几秒时间 | +| [`UUID()`](https://dev.mysql.com/doc/refman/8.0/en/miscellaneous-functions.html#function_uuid) | 返回一个通用唯一识别码 (UUID) | +| [`UUID_TO_BIN()`](https://dev.mysql.com/doc/refman/8.0/en/miscellaneous-functions.html#function_uuid-to-bin) | 将 UUID 从文本格式转换为二进制格式 | +| [`VALUES()`](https://dev.mysql.com/doc/refman/8.0/en/miscellaneous-functions.html#function_values) | 定义 `INSERT` 语句使用的值 | + +## 不支持的函数 + +| 函数名 | 功能描述 | +|:------|:-----------| +| [`UUID_SHORT()`](https://dev.mysql.com/doc/refman/8.0/en/miscellaneous-functions.html#function_uuid-short) | 基于特定假设提供唯一的 UUID,目前这些假设在 TiDB 中不存在,详见 [TiDB #4620](https://github.com/pingcap/tidb/issues/4620) | +| [`MASTER_WAIT_POS()`](https://dev.mysql.com/doc/refman/8.0/en/miscellaneous-functions.html#function_master-pos-wait) | 与 MySQL 同步相关 | diff --git a/markdown-pages/zh/tidb/master/functions-and-operators/numeric-functions-and-operators.md b/markdown-pages/zh/tidb/master/functions-and-operators/numeric-functions-and-operators.md new file mode 100644 index 0000000..cae19a6 --- /dev/null +++ b/markdown-pages/zh/tidb/master/functions-and-operators/numeric-functions-and-operators.md @@ -0,0 +1,56 @@ +--- +title: 数值函数与操作符 +aliases: ['/docs-cn/dev/functions-and-operators/numeric-functions-and-operators/','/docs-cn/dev/reference/sql/functions-and-operators/numeric-functions-and-operators/'] +summary: TiDB 支持 MySQL 5.7 中的所有数值函数和操作符。包括加减乘除、整数除法、模运算、改变参数符号等算术操作符,以及返回乘方、自然对数、对数、正切值、余切值、正弦值、余弦值等数学函数。 +--- + +# 数值函数与操作符 + +TiDB 支持使用 MySQL 5.7 中提供的所有[数值函数与操作符](https://dev.mysql.com/doc/refman/5.7/en/numeric-functions.html)。 + +## 算术操作符 + +| 操作符名 | 功能描述 | +|:-------------|:--------------------------------| +| [`+`](https://dev.mysql.com/doc/refman/8.0/en/arithmetic-functions.html#operator_plus) | 加号 | +| [`-`](https://dev.mysql.com/doc/refman/8.0/en/arithmetic-functions.html#operator_minus) | 减号 | +| [`*`](https://dev.mysql.com/doc/refman/8.0/en/arithmetic-functions.html#operator_times) | 乘号 | +| [`/`](https://dev.mysql.com/doc/refman/8.0/en/arithmetic-functions.html#operator_divide) | 除号 | +| [`DIV`](https://dev.mysql.com/doc/refman/8.0/en/arithmetic-functions.html#operator_div) | 整数除法 | +| [`%`, `MOD`](https://dev.mysql.com/doc/refman/8.0/en/arithmetic-functions.html#operator_mod) | 模运算,取余 | +| [`-`](https://dev.mysql.com/doc/refman/8.0/en/arithmetic-functions.html#operator_unary-minus) | 更改参数符号 | + +## 数学函数 + +| 函数名 | 功能描述 | +|:----------------------------------------------------------------------------------------------------------|:------------------------------------------------------------------| +| [`POW()`](https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_pow) | 返回参数的指定乘方的结果值 | +| [`POWER()`](https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_power) | 返回参数的指定乘方的结果值 | +| [`EXP()`](https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_exp) | 返回 e(自然对数的底)的指定乘方后的值 | +| [`SQRT()`](https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_sqrt) | 返回非负数的二次方根 | +| [`LN()`](https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_ln) | 返回参数的自然对数 | +| [`LOG()`](https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_log) | 返回第一个参数的自然对数 | +| [`LOG2()`](https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_log2) | 返回参数以 2 为底的对数 | +| [`LOG10()`](https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_log10) | 返回参数以 10 为底的对数 | +| [`PI()`](https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_pi) | 返回 pi 的值 | +| [`TAN()`](https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_tan) | 返回参数的正切值 | +| [`COT()`](https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_cot) | 返回参数的余切值 | +| [`SIN()`](https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_sin) | 返回参数的正弦值 | +| [`COS()`](https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_cos) | 返回参数的余弦值 | +| [`ATAN()`](https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_atan) | 返回参数的反正切值 | +| [`ATAN2(), ATAN()`](https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_atan2) | 返回两个参数的反正切值 | +| [`ASIN()`](https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_asin) | 返回参数的反正弦值 | +| [`ACOS()`](https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_acos) | 返回参数的反余弦值 | +| [`RADIANS()`](https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_radians) | 返回由度转化为弧度的参数 | +| [`DEGREES()`](https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_degrees) | 返回由弧度转化为度的参数 | +| [`MOD()`](https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_mod) | 返回余数 | +| [`ABS()`](https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_abs) | 返回参数的绝对值 | +| [`CEIL()`](https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_ceil) | 返回不小于参数的最小整数值 | +| [`CEILING()`](https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_ceiling) | 返回不小于参数的最小整数值 | +| [`FLOOR()`](https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_floor) | 返回不大于参数的最大整数值 | +| [`ROUND()`](https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_round) | 返回参数最近似的整数或指定小数位数的数值 | +| [`RAND()`](https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_rand) | 返回一个随机浮点值 | +| [`SIGN()`](https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_sign) | 返回参数的符号 | +| [`CONV()`](https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_conv) | 不同数基间转换数字,返回数字的字符串表示 | +| [`TRUNCATE()`](https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_truncate) | 返回被舍位至指定小数位数的数字 | +| [`CRC32()`](https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_crc32)           | 计算循环冗余码校验值并返回一个 32 位无符号值                     | diff --git a/markdown-pages/zh/tidb/master/functions-and-operators/operators.md b/markdown-pages/zh/tidb/master/functions-and-operators/operators.md new file mode 100644 index 0000000..723dc03 --- /dev/null +++ b/markdown-pages/zh/tidb/master/functions-and-operators/operators.md @@ -0,0 +1,135 @@ +--- +title: 操作符 +aliases: ['/docs-cn/dev/functions-and-operators/operators/','/docs-cn/dev/reference/sql/functions-and-operators/operators/'] +summary: 操作符是用于在 MySQL 中执行各种操作的关键元素。它们包括逻辑操作符(如 AND、OR、NOT、XOR)、赋值操作符(如 =、:=)、比较操作符(如 =、<、>、LIKE、BETWEEN)、以及其他操作符(如 +、-、*、/)。操作符具有不同的优先级,可以用于执行各种复杂的操作。需要注意的是,MySQL 不支持 ILIKE 操作符。 +--- + +# 操作符 + +| 操作符名 | 功能描述 | +| ------- | -------------------------------- | +| [`AND`, &&](https://dev.mysql.com/doc/refman/8.0/en/logical-operators.html#operator_and) | 逻辑与 | +| [`=`](https://dev.mysql.com/doc/refman/8.0/en/assignment-operators.html#operator_assign-equal) | 赋值(可用于 [`SET`](https://dev.mysql.com/doc/refman/8.0/en/set-variable.html) 语句中,或用于 [`UPDATE`](https://dev.mysql.com/doc/refman/8.0/en/update.html) 语句的 `SET` 中) | +| [`:=`](https://dev.mysql.com/doc/refman/8.0/en/assignment-operators.html#operator_assign-value) | 赋值 | +| [`BETWEEN ... AND ...`](https://dev.mysql.com/doc/refman/8.0/en/comparison-operators.html#operator_between) | 判断值满足范围 | +| [`BINARY`](https://dev.mysql.com/doc/refman/8.0/en/cast-functions.html#operator_binary) | 将一个字符串转换为一个二进制字符串 | +| [&](https://dev.mysql.com/doc/refman/8.0/en/bit-functions.html#operator_bitwise-and) | 位与 | +| [~](https://dev.mysql.com/doc/refman/8.0/en/bit-functions.html#operator_bitwise-invert) | 位非 | +| [\|](https://dev.mysql.com/doc/refman/8.0/en/bit-functions.html#operator_bitwise-or) | 位或 | +| [`^`](https://dev.mysql.com/doc/refman/8.0/en/bit-functions.html#operator_bitwise-xor) | 按位异或 | +| [`CASE`](https://dev.mysql.com/doc/refman/8.0/en/flow-control-functions.html#operator_case) | case 操作符 | +| [`DIV`](https://dev.mysql.com/doc/refman/8.0/en/arithmetic-functions.html#operator_div) | 整数除 | +| [`/`](https://dev.mysql.com/doc/refman/8.0/en/arithmetic-functions.html#operator_divide) | 除法 | +| [`=`](https://dev.mysql.com/doc/refman/8.0/en/comparison-operators.html#operator_equal) | 相等比较 | +| [`<=>`](https://dev.mysql.com/doc/refman/8.0/en/comparison-operators.html#operator_equal-to) | 空值安全型相等比较 | +| [`>`](https://dev.mysql.com/doc/refman/8.0/en/comparison-operators.html#operator_greater-than) | 大于 | +| [`>=`](https://dev.mysql.com/doc/refman/8.0/en/comparison-operators.html#operator_greater-than-or-equal) | 大于或等于 | +| [`IS`](https://dev.mysql.com/doc/refman/8.0/en/comparison-operators.html#operator_is) | 判断一个值是否等于一个布尔值 | +| [`IS NOT`](https://dev.mysql.com/doc/refman/8.0/en/comparison-operators.html#operator_is-not) | 判断一个值是否不等于一个布尔值 | +| [`IS NOT NULL`](https://dev.mysql.com/doc/refman/8.0/en/comparison-operators.html#operator_is-not-null) | 非空判断 | +| [`IS NULL`](https://dev.mysql.com/doc/refman/8.0/en/comparison-operators.html#operator_is-null) | 空值判断 | +| [`<<`](https://dev.mysql.com/doc/refman/8.0/en/bit-functions.html#operator_left-shift) | 左移 | +| [`<`](https://dev.mysql.com/doc/refman/8.0/en/comparison-operators.html#operator_less-than) | 小于 | +| [`<=`](https://dev.mysql.com/doc/refman/8.0/en/comparison-operators.html#operator_less-than-or-equal) | 小于或等于 | +| [`LIKE`](https://dev.mysql.com/doc/refman/8.0/en/string-comparison-functions.html#operator_like) | 简单模式匹配 | +| [`ILIKE`](https://www.postgresql.org/docs/current/functions-matching.html) | 大小写不敏感的简单模式匹配(TiDB 支持但 MySQL 不支持) | +| [`-`](https://dev.mysql.com/doc/refman/8.0/en/arithmetic-functions.html#operator_minus) | 减 | +| [`%`, `MOD`](https://dev.mysql.com/doc/refman/8.0/en/arithmetic-functions.html#operator_mod) | 求余 | +| [`NOT`, `!`](https://dev.mysql.com/doc/refman/8.0/en/logical-operators.html#operator_not) | 取反 | +| [`NOT BETWEEN ... AND ...`](https://dev.mysql.com/doc/refman/8.0/en/comparison-operators.html#operator_not-between) | 判断值是否不在范围内 | +| [`!=`, `<>`](https://dev.mysql.com/doc/refman/8.0/en/comparison-operators.html#operator_not-equal) | 不等于 | +| [`NOT LIKE`](https://dev.mysql.com/doc/refman/8.0/en/string-comparison-functions.html#operator_not-like) | 不符合简单模式匹配 | +| [`NOT REGEXP`](https://dev.mysql.com/doc/refman/8.0/en/regexp.html#operator_not-regexp) | 不符合正则表达式模式匹配 | +| [\|\|, `OR`](https://dev.mysql.com/doc/refman/8.0/en/logical-operators.html#operator_or) | 逻辑或 | +| [`+`](https://dev.mysql.com/doc/refman/8.0/en/arithmetic-functions.html#operator_plus) | 加 | +| [`REGEXP`](https://dev.mysql.com/doc/refman/8.0/en/regexp.html#operator_regexp) | 使用正则表达式进行模式匹配 | +| [`>>`](https://dev.mysql.com/doc/refman/8.0/en/bit-functions.html#operator_right-shift) | 右移 | +| [`RLIKE`](https://dev.mysql.com/doc/refman/8.0/en/regexp.html#operator_regexp) | REGEXP 同义词 | +| [`*`](https://dev.mysql.com/doc/refman/8.0/en/arithmetic-functions.html#operator_times) | 乘 | +| [`-`](https://dev.mysql.com/doc/refman/8.0/en/arithmetic-functions.html#operator_unary-minus) | 取反符号 | +| [`XOR`](https://dev.mysql.com/doc/refman/8.0/en/logical-operators.html#operator_xor) | 逻辑亦或 | + +## 不支持的操作符 + +* [`SOUNDS LIKE`](https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#operator_sounds-like) + +## 操作符优先级 + +操作符优先级显示在以下列表中,从最高优先级到最低优先级。同一行显示的操作符具有相同的优先级。 + +```sql +INTERVAL +BINARY +! +- (unary minus), ~ (unary bit inversion) +^ +*, /, DIV, %, MOD +-, + +<<, >> +& +| += (comparison), <=>, >=, >, <=, <, <>, !=, IS, LIKE, REGEXP, IN +BETWEEN, CASE, WHEN, THEN, ELSE +NOT +AND, && +XOR +OR, || += (assignment), := +``` + +详情参见[这里](https://dev.mysql.com/doc/refman/8.0/en/operator-precedence.html)。 + +## 比较方法和操作符 + +| 操作符名 | 功能描述 | +| ------- | -------------------------------- | +| [`BETWEEN ... AND ...`](https://dev.mysql.com/doc/refman/8.0/en/comparison-operators.html#operator_between) | 判断值是否在范围内 | +| [`COALESCE()`](https://dev.mysql.com/doc/refman/8.0/en/comparison-operators.html#function_coalesce) | 返回第一个非空值 | +| [`=`](https://dev.mysql.com/doc/refman/8.0/en/comparison-operators.html#operator_equal) | 相等比较 | +| [`<=>`](https://dev.mysql.com/doc/refman/8.0/en/comparison-operators.html#operator_equal-to) | 空值安全型相等比较 | +| [`>`](https://dev.mysql.com/doc/refman/8.0/en/comparison-operators.html#operator_greater-than) | 大于 | +| [`>=`](https://dev.mysql.com/doc/refman/8.0/en/comparison-operators.html#operator_greater-than-or-equal) | 大于或等于 | +| [`GREATEST()`](https://dev.mysql.com/doc/refman/8.0/en/comparison-operators.html#function_greatest) | 返回最大值 | +| [`IN()`](https://dev.mysql.com/doc/refman/8.0/en/comparison-operators.html#operator_in) | 判断值是否在一个值的集合内 | +| [`INTERVAL()`](https://dev.mysql.com/doc/refman/8.0/en/comparison-operators.html#function_interval) | 返回一个小于第一个参数的参数的下标 | +| [`IS`](https://dev.mysql.com/doc/refman/8.0/en/comparison-operators.html#operator_is) | 判断是否等于一个布尔值 | +| [`IS NOT`](https://dev.mysql.com/doc/refman/8.0/en/comparison-operators.html#operator_is-not) | 判断是否不等于一个布尔值 | +| [`IS NOT NULL`](https://dev.mysql.com/doc/refman/8.0/en/comparison-operators.html#operator_is-not-null) | 非空判断 | +| [`IS NULL`](https://dev.mysql.com/doc/refman/8.0/en/comparison-operators.html#operator_is-null) | 空值判断 | +| [`ISNULL()`](https://dev.mysql.com/doc/refman/8.0/en/comparison-operators.html#function_isnull) | 判断参数是否为空 | +| [`LEAST()`](https://dev.mysql.com/doc/refman/8.0/en/comparison-operators.html#function_least) | 返回最小值 | +| [`<`](https://dev.mysql.com/doc/refman/8.0/en/comparison-operators.html#operator_less-than) | 小于 | +| [`<=`](https://dev.mysql.com/doc/refman/8.0/en/comparison-operators.html#operator_less-than-or-equal) | 小于或等于 | +| [`LIKE`](https://dev.mysql.com/doc/refman/8.0/en/string-comparison-functions.html#operator_like) | 简单模式匹配 | +| [`ILIKE`](https://www.postgresql.org/docs/current/functions-matching.html) | 大小写不敏感的简单模式匹配(TiDB 支持但 MySQL 不支持) | +| [`NOT BETWEEN ... AND ...`](https://dev.mysql.com/doc/refman/8.0/en/comparison-operators.html#operator_not-between) | 判断值是否不在范围内 | +| [`!=`, `<>`](https://dev.mysql.com/doc/refman/8.0/en/comparison-operators.html#operator_not-equal) | 不等于 | +| [`NOT IN()`](https://dev.mysql.com/doc/refman/8.0/en/comparison-operators.html#operator_not-in) | 判断值是否不在一个值的集合内 | +| [`NOT LIKE`](https://dev.mysql.com/doc/refman/8.0/en/string-comparison-functions.html#operator_not-like) | 不满足简单模式匹配 | +| [`STRCMP()`](https://dev.mysql.com/doc/refman/8.0/en/string-comparison-functions.html#function_strcmp) | 比较两个字符串 | + +详情参见[这里](https://dev.mysql.com/doc/refman/8.0/en/comparison-operators.html)。 + +## 逻辑操作符 + +| 操作符名 | 功能描述 | +| ------- | -------------------------------- | +| [`AND`, &&](https://dev.mysql.com/doc/refman/8.0/en/logical-operators.html#operator_and) | 逻辑与 | +| [`NOT`, `!`](https://dev.mysql.com/doc/refman/8.0/en/logical-operators.html#operator_not) | 逻辑非 | +| [\|\|, `OR`](https://dev.mysql.com/doc/refman/8.0/en/logical-operators.html#operator_or) | 逻辑或 | +| [`XOR`](https://dev.mysql.com/doc/refman/8.0/en/logical-operators.html#operator_xor) | 逻辑异或 | + +详情参见[这里](https://dev.mysql.com/doc/refman/8.0/en/group-by-handling.html)。 + +## 赋值操作符 + +| 操作符名 | 功能描述 | +| ------- | -------------------------------- | +| [`=`](https://dev.mysql.com/doc/refman/8.0/en/assignment-operators.html#operator_assign-equal) | 赋值(可用于 [`SET`](https://dev.mysql.com/doc/refman/8.0/en/set-variable.html) 语句中,或用于 [`UPDATE`](https://dev.mysql.com/doc/refman/8.0/en/update.html) 语句的 `SET` 中) | +| [`:=`](https://dev.mysql.com/doc/refman/8.0/en/assignment-operators.html#operator_assign-value) | 赋值 | + +详情参见[这里](https://dev.mysql.com/doc/refman/8.0/en/group-by-functional-dependence.html)。 + +## MySQL 兼容性 + +* MySQL 不支持 `ILIKE` 操作符。 diff --git a/markdown-pages/zh/tidb/master/functions-and-operators/precision-math.md b/markdown-pages/zh/tidb/master/functions-and-operators/precision-math.md new file mode 100644 index 0000000..e0d1193 --- /dev/null +++ b/markdown-pages/zh/tidb/master/functions-and-operators/precision-math.md @@ -0,0 +1,163 @@ +--- +title: 精度数学 +aliases: ['/docs-cn/dev/functions-and-operators/precision-math/','/docs-cn/dev/reference/sql/functions-and-operators/precision-math/'] +summary: TiDB 中的精确数值运算与 MySQL 基本一致。精确数值运算包括整型和 DECIMAL 类型,以及精确值数字字面量。DECIMAL 数据类型是定点数类型,其运算是精确计算。在表达式计算中,TiDB 会尽可能不做任何修改的使用每个输入的数值。数值修约时,`round()` 函数将使用四舍五入的规则。向 DECIMAL 或整数类型列插入数据时,round 的规则将采用 round half away from zero 的方式。 +--- + +# 精度数学 + +TiDB 中精度数学计算与 MySQL 中基本一致。详情请参见:[Precision Math](https://dev.mysql.com/doc/refman/8.0/en/precision-math.html) + +- 数值类型 +- DECIMAL 数据类型的特性 + +## 数值类型 + +精确数值运算的范围包括精确值数据类型(整型和 DECIMAL 类型),以及精确值数字字面量。近似值数据类型和近似值数字字面量被作为浮点数来处理。 + +精确值数字字面量包含整数部分或小数部分,或二者都包含。精确值数字字面量可以包含符号位。例如:`1`, `.2`, `3.4`, `-5`, `-6.78`, `+9.10`。 + +近似值数字字面量以一个包含尾数和指数的科学计数法表示(基数为 10)。其中尾数和指数可以分别或同时带有符号位。例如:`1.2E3`, `1.2E-3`, `-1.2E3`, `-1.2E-3`。 + +两个看起来相似的数字可能会被以不同的方式进行处理。例如:`2.34` 是精确值(定点数),而 `2.3E0` 是近似值(浮点数)。 + +DECIMAL 数据类型是定点数类型,其运算是精确计算。FLOAT 和 DOUBLE 数据类型是浮点类型,其运算是近似计算。 + +## DECIMAL 数据类型的特性 + +本节讨论 DECIMAL 数据类型的特性,主要涉及以下几点: + +1. 最大位数 +2. 存储格式 +3. 存储要求 + +DECIMAL 列的声明语法为 DECIMAL(M, D)。其中参数值意义及其范围如下: + +- M 表示最大的数字位数(精度),1<= M <= 65。 +- D 表示小数点右边数字的位数(标度)。1 <= D <= 30 且不大于 M。 + +M 的最大值 65 表示 DECIMAL 值的计算精确到 65 位数字。该精度同样适用于其精确值字面量。 + +DECIMAL 列的值采用二进制进行存储,其将每 9 位十进制数字包装成 4 个字节。其中整数和小数部分分别确定所需的存储空间。如果数字位数为 9 的倍数,则每 9 位十进制数字各采用 4 个字节进行存储,对于剩余不足 9 位的数字,所需的存储空间如下表所示 + +| 剩余数字位数 | 存储所需字节数 | +| --- | --- | +| 0 | 0 | +| 1–2 | 1 | +| 3–4 | 2 | +| 5–6 | 3 | +| 7–9 | 4 | + +例如: + ++ 定义类型为 DECIMAL(18, 9) 的列,其小数点两侧均各包含 9 位十进制数字。因此,分别需要 4 个字节的存储空间。 + ++ 定义类型为 DECIMAL(20, 6) 的列,其小数部分包含 6 位十进制数字,整数部分包含 14 位十进制数字。整数部分中 9 位数字需要 4 个字节进行存储,其余 5 位数字需要 3 个字节进行存储。小数部分 6 位数字需要 3 个字节进行存储。 + +DECIMAL 列不存储前导的字符 `+` 或字符 `-` 或数字 `0`。如果将 `+0003.1` 插入到 DECIMAL(5, 1) 列中,则将其存储为 `3.1`。对于负数,不存储字符 `-` 的字面值。 + +DECIMAL 列不允许插入大于列定义的隐含范围的值。例如:DECIMAL(3, 0) 列范围为`-999` 到 `999`。DECIMAL(M, D) 列小数点左边部分最多支持 M-D 位数字。 + +有关 DECIMAL 值的内部格式完整说明,请参阅 TiDB 源码文件 [`types/mydecimal.go`](https://github.com/pingcap/tidb/blob/master/pkg/types/mydecimal.go)。 + +## 表达式计算 + +在涉及精度数学计算的表达式中,TiDB 会尽可能不做任何修改的使用每个输入的数值。比如:在计算比较函数时,参与运算的数字将不做任何改变。在严格 SQL 模式下,向一个数据列插入一个值时,如果该值处于这一列的值域范围内,这个值将直接不做任何修改的直接插入进去,提取这个值的时候,取得的值和插入的值将会是同一个值。当处于非严格 SQL 模式时,TiDB 会允许数据插入过程中发生的数据截断。 + +处理数值类型表达式取决于这个表达式参数的具体值: + +* 当表达式参数中包含近似值时,这个表达式的结果也是近似值,TiDB 会使用浮点数对应的计算逻辑返回一个浮点数的结果。 +* 当表达式参数中不包含任何近似值时(也就是说表达式的参数全部是精确值),如果某个精确值包含小数部分,TIDB 会对这个表达式使用 `DECIMAL` 对应的计算逻辑,返回一个 `DECIMAL` 的结果,精确到 65 位数字。 +* 其他情况下,表达式只会包含整数参数,这个表达式的结果也是精确的,TiDB 会使用整数对应的计算逻辑返回一个整数结果,精度和 `BIGINT` 保持一致(64 位)。 + +如果数值类型表达式中包含字符串参数,这些字符串参数将被转换成双精度浮点数,这个表达式的计算结果将是个近似值。 + +向一个数值类型列插入数据的具体行为会受到 SQL 模式的影响。接下来的讨论将围绕严格模式以及 `ERROR_FOR_DIVISION_BY_ZERO` 模式展开,如果要打开所有的限制,可以简单的使用 `TRADITIONAL` 模式,这个模式将同时使用严格模式以及 `ERROR_FOR_DIVISION_BY_ZERO` 模式: + +```sql +SET sql_mode = 'TRADITIONAL'; +``` + +向一个具有精确值类型(`DECIMAL` 或者整数类型)的列插入数据时,如果插入的数据位于该列的值域范围内将使用该数据的精确值。如果该数据的小数部分太长,将会发生数值修约,这时会有 warning 产生,具体内容可以看"数值修约"。 + +如果该数据整数部分太长: + +* 如果没有开启严格模式,这个值会被截断并产生一个 warning。 +* 如果开启了严格模式,将会产生一个数据溢出的 error。 + +如果向一个数值类型列插入字符串,如果该字符串中包含非数值部分,TiDB 将这样做类型转换: + +* 在严格模式下,没有以数字开头的字符串(即使是一个空字符串)不能被被用作数字值并会返回一个 error 或者是 warning。 +* 以数字开头的字符串可以被转换,不过末尾的非数字部分会被截断。如果被截断的部分包含的不全是空格,在严格模式下这回产生一个 error 或者 warning。 + +默认情况下,如果计算的过程中发生了除数是 0 的现象将会得到一个 `NULL` 结果,并且不会有 warning 产生。通过设置适当的 SQL 模式,除以 0 的操作可以被限制。当设置 `ERROR_FOR_DIVISION_BY_ZERO` SQL 模式时,TiDB 的行为是: + +* 如果设置了严格 SQL 模式,`INSERT` 和 `UPDATE` 的过程中如果发生了除以 0 的操作,正在进行的 `INSERT` 或者 `UPDATE` 操作会被禁止,并且会返回一个 error。 +* 如果没有设置严格 SQL 模式,除以 0 的操作仅会返回一个 warning。 + +假设我们有如下的 SQL 语句: + +```sql +INSERT INTO t SET i = 1/0; +``` + +不同的 SQL 模式将会导致不同的结果如下: + +| `sql_mode` 的值 | 结果 | +| :--- | :--- | +| '' | 没有 warning,没有 error,i 被设为 NULL | +| strict | 没有 warning,没有 error,i 被设为 NULL | +| `ERROR_FOR_DIVISION_BY_ZERO` | 有 warning,没有 error,i 被设为 NULL | +| strict, `ERROR_FOR_DIVISION_BY_ZERO` | 有 error,插入失败 | + +## 数值修约 + +`round()` 函数的结果取决于他的参数是否是精确值: + +* 如果参数是精确值,`round()` 函数将使用四舍五入的规则。 +* 如果参数是一个近似值,`round()` 表达式的结果可能和 MySQL 不太一样。 + +```sql +SELECT ROUND(2.5), ROUND(25E-1); +``` + +``` ++------------+--------------+ +| ROUND(2.5) | ROUND(25E-1) | ++------------+--------------+ +| 3 | 3 | ++------------+--------------+ +1 row in set (0.00 sec) +``` + +向一个 `DECIMAL` 或者整数类型列插入数据时,round 的规则将采用 [round half away from zero](https://en.wikipedia.org/wiki/Rounding#Round_half_away_from_zero) 的方式: + +```sql +CREATE TABLE t (d DECIMAL(10,0)); +``` + +``` +Query OK, 0 rows affected (0.01 sec) +``` + +```sql +INSERT INTO t VALUES(2.5),(2.5E0); +``` + +``` +Query OK, 2 rows affected, 2 warnings (0.00 sec) +``` + +```sql +SELECT d FROM t; +``` + +``` ++------+ +| d | ++------+ +| 3 | +| 3 | ++------+ +2 rows in set (0.00 sec) +``` diff --git a/markdown-pages/zh/tidb/master/functions-and-operators/string-functions.md b/markdown-pages/zh/tidb/master/functions-and-operators/string-functions.md new file mode 100644 index 0000000..bce4d7c --- /dev/null +++ b/markdown-pages/zh/tidb/master/functions-and-operators/string-functions.md @@ -0,0 +1,1500 @@ +--- +title: 字符串函数 +aliases: ['/docs-cn/dev/functions-and-operators/string-functions/','/docs-cn/dev/reference/sql/functions-and-operators/string-functions/','/docs-cn/dev/sql/string-functions/'] +summary: TiDB 支持大部分 MySQL 5.7 和部分 MySQL 8.0 字符串函数,以及部分 Oracle 21 函数。不支持的函数包括 LOAD_FILE()、MATCH() 和 SOUNDEX()。正则函数与 MySQL 的语法和数据类型存在一些差异,需要注意。 +--- + +# 字符串函数 + +TiDB 支持使用大部分 MySQL 5.7 中提供的[字符串函数](https://dev.mysql.com/doc/refman/5.7/en/string-functions.html)、一部分 MySQL 8.0 中提供的[字符串函数](https://dev.mysql.com/doc/refman/8.0/en/string-functions.html)和一部分 Oracle 21 所提供的[函数](https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlqr/SQL-Functions.html#GUID-93EC62F8-415D-4A7E-B050-5D5B2C127009)。 + +关于 Oracle 函数和 TiDB 函数的对照关系,请参考 [Oracle 与 TiDB 函数和语法差异对照](/oracle-functions-to-tidb.md)。 + +## 支持的函数 + +### [`ASCII()`](https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_ascii) + +`ASCII()` 函数用于获取输入的参数中最左字符的 ASCII 值。该参数可以为字符串或数字。 + +- 如果输入参数不为空,该函数返回参数中最左字符的 ASCII 值。 +- 如果输入参数为空字符串,该函数返回 `0`。 +- 如果输入参数为 `NULL`,该函数返回 `NULL`。 + +> **注意:** +> +> `ASCII()` 只能处理那些用 8 个二进制数字(即单个字节)来表示的字符。 + +查询示例: + +```sql +SELECT ASCII('A'), ASCII('TiDB'), ASCII(23); +``` + +返回结果: + +```sql ++------------+---------------+-----------+ +| ASCII('A') | ASCII('TiDB') | ASCII(23) | ++------------+---------------+-----------+ +| 65 | 84 | 50 | ++------------+---------------+-----------+ +``` + +### [`BIN()`](https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_bin) + +`BIN()` 函数用于将输入的参数转换为其二进制值的字符串表示形式。该参数可以为字符串或数字。 + +- 如果输入参数为正数,该函数返回该参数的二进制值的字符串表示形式。 +- 如果输入参数为负数,该函数会将该参数的绝对值转换为其二进制值,然后对二进制值的每位取反(`0` 变为 `1`,`1` 变为 `0`),最后加上 `1`。 +- 如果输入参数为字符串,且该字符串中只包含数字,该函数将按照该数字返回结果。例如,`"123"` 与 `123` 的返回结果相同。 +- 如果输入参数为字符串,且该字符串第一个字符不是数字(如 `"q123"`),该函数返回 `0`。 +- 如果输入参数为字符串,且该字符串由数字和非数字组成,该函数将按照该参数中最前面连续的数字返回结果。例如,`'123q123'` 与 `123` 的返回结果相同,但 `BIN('123q123')` 会产生一个 `Truncated incorrect INTEGER value: '123q123'` 的警告。 +- 如果输入参数为 `NULL`,该函数返回 `NULL`。 + +查询示例 1: + +```sql +SELECT BIN(123), BIN('123q123'); +``` + +返回结果 1: + +```sql ++----------+----------------+ +| BIN(123) | BIN('123q123') | ++----------+----------------+ +| 1111011 | 1111011 | ++----------+----------------+ +``` + +查询示例 2: + +```sql +SELECT BIN(-7); +``` + +返回结果 2: + +```sql ++------------------------------------------------------------------+ +| BIN(-7) | ++------------------------------------------------------------------+ +| 1111111111111111111111111111111111111111111111111111111111111001 | ++------------------------------------------------------------------+ +``` + +### [`BIT_LENGTH()`](https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_bit-length) + +`BIT_LENGTH()` 函数用于返回输入参数的长度,单位为 bit。 + +示例: + +```sql +SELECT BIT_LENGTH("TiDB"); + ++--------------------+ +| BIT_LENGTH("TiDB") | ++--------------------+ +| 32 | ++--------------------+ +``` + +每个字符 8 位 x 4 个字符 = 32 位 + +```sql +SELECT BIT_LENGTH("PingCAP 123"); + ++---------------------------+ +| BIT_LENGTH("PingCAP 123") | ++---------------------------+ +| 88 | ++---------------------------+ +``` + +每个字符 8 位(空格也会被计算在内,因为它是非字母数字字符) x 11 个字符 = 88 位 + +```sql +SELECT CustomerName, BIT_LENGTH(CustomerName) AS BitLengthOfName FROM Customers; + ++--------------------+-----------------+ +| CustomerName | BitLengthOfName | ++--------------------+-----------------+ +| Albert Einstein | 120 | +| Robert Oppenheimer | 144 | ++--------------------+-----------------+ +``` + +> **注意:** +> +> 上面这个示例假设数据库中存在一个名为 `Customers` 的表,表中有一个名为 `CustomerName` 的列。 + +### [`CHAR()`](https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_char) + +`CHAR()` 函数用于获取指定 ASCII 值的对应字符。该函数执行的操作与 `ASCII()` 相反,`ASCII()` 用于返回指定字符的 ASCII 值。 + +示例: + +```sql +SELECT CHAR(65); + ++------------+ +| CHAR(65) | ++------------+ +| A | ++------------+ +``` + +```sql +SELECT CHAR(84); + ++------------+ +| CHAR(84) | ++------------+ +| T | ++------------+ +``` + +`CHAR()` 函数还可用于获取超出标准 ASCII 范围(`0` - `127`)的 ASCII 值的对应字符。 + +```sql +/*For extended ASCII: */ + +SELECT CHAR(128); + ++------------+ +| CHAR(128) | ++------------+ +| 0x80 | ++------------+ +``` + +`CHAR()` 函数还可用于获取 Unicode 值的对应字符。 + +```sql +/* For Unicode: */ + +--skip-binary-as-hex + +SELECT CHAR(50089); + ++--------------+ +| CHAR(50089) | ++--------------+ +| é | ++--------------+ +``` + +### [`CHAR_LENGTH()`](https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_char-length) + +`CHAR_LENGTH()` 函数用于获取输入参数中字符的总数。 + +示例: + +```sql +SELECT CHAR_LENGTH("TiDB") AS LengthOfString; + ++----------------+ +| LengthOfString | ++----------------+ +| 4 | ++----------------+ +``` + +```sql +SELECT CustomerName, CHAR_LENGTH(CustomerName) AS LenghtOfName FROM Customers; + ++--------------------+--------------+ +| CustomerName | LenghtOfName | ++--------------------+--------------+ +| Albert Einstein | 15 | +| Robert Oppenheimer | 18 | ++--------------------+--------------+ +``` + +> **注意:** +> +> 上面这个示例假设数据库中存在一个名为 `Customers` 的表,表中有一个名为 `CustomerName` 的列。 + +### [`CHARACTER_LENGTH()`](https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_character-length) + +`CHARACTER_LENGTH()` 函数与 `CHAR_LENGTH()` 函数功能相同,返回结果相同,可以互换使用。 + +### [`CONCAT()`](https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_concat) + +`CONCAT()` 函数用于将输入的参数连接成一个字符串。 + +语法: + +```sql +CONCAT(str1,str2,...) +``` + +`str1, str2, ...` 为要连接的参数。该参数可以是字符串或数字。 + +查询示例: + +```sql +SELECT CONCAT('TiDB', ' ', 'Server', '-', 1, TRUE); +``` + +返回结果: + +```sql ++---------------------------------------------+ +| CONCAT('TiDB', ' ', 'Server', '-', 1, TRUE) | ++---------------------------------------------+ +| TiDB Server-11 | ++---------------------------------------------+ +``` + +如果任一参数的值为 `NULL`, 则 `CONCAT()` 返回 `NULL`。 + +查询示例: + +```sql +SELECT CONCAT('TiDB', NULL, 'Server'); +``` + +返回结果: + +```sql ++--------------------------------+ +| CONCAT('TiDB', NULL, 'Server') | ++--------------------------------+ +| NULL | ++--------------------------------+ +``` + +除了使用 `CONCAT()` 函数外,你也可以通过字符串彼此相邻的方式获取拼接字符串,但是该方式不支持数字类型。例如: + +```sql +SELECT 'Ti' 'DB' ' ' 'Server'; +``` + +返回结果: + +```sql ++-------------+ +| Ti | ++-------------+ +| TiDB Server | ++-------------+ +``` + +### [`CONCAT_WS()`](https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_concat-ws) + +`CONCAT_WS()` 函数是一种带分隔符的 [`CONCAT()`](#concat),返回由分隔符连接的字符串。 + +语法: + +```sql +CONCAT_WS(separator,str1,str2,...) +``` + +- `separator`:第一个参数为分隔符,用于连接其余的不为 `NULL` 的参数。 +- `str1, str2, ...`:要连接的参数。该参数可以为字符串或数字。 + +查询示例: + +```sql +SELECT CONCAT_WS(',', 'TiDB Server', 'TiKV', 'PD'); +``` + +返回结果: + +```sql ++---------------------------------------------+ +| CONCAT_WS(',', 'TiDB Server', 'TiKV', 'PD') | ++---------------------------------------------+ +| TiDB Server,TiKV,PD | ++---------------------------------------------+ +``` + +- 如果分隔符为空,则 `CONCAT_WS()` 等效于 `CONCAT()`,返回其余参数连接后的字符串。 + + 查询示例: + + ```sql + SELECT CONCAT_WS('', 'TiDB Server', 'TiKV', 'PD'); + ``` + + 返回结果: + + ```sql + +--------------------------------------------+ + | CONCAT_WS('', 'TiDB Server', 'TiKV', 'PD') | + +--------------------------------------------+ + | TiDB ServerTiKVPD | + +--------------------------------------------+ + ``` + +- 如果分隔符为 `NULL`,则 `CONCAT_WS()`返回 `NULL`。 + + 查询示例: + + ```sql + SELECT CONCAT_WS(NULL, 'TiDB Server', 'TiKV', 'PD'); + ``` + + 返回结果: + + ```sql + +----------------------------------------------+ + | CONCAT_WS(NULL, 'TiDB Server', 'TiKV', 'PD') | + +----------------------------------------------+ + | NULL | + +----------------------------------------------+ + ``` + +- 如果用于连接的参数中只有一个不为 `NULL`,则 `CONCAT_WS()` 返回此参数。 + + 查询示例: + + ```sql + SELECT CONCAT_WS(',', 'TiDB Server', NULL); + ``` + + 返回结果: + + ```sql + +-------------------------------------+ + | CONCAT_WS(',', 'TiDB Server', NULL) | + +-------------------------------------+ + | TiDB Server | + +-------------------------------------+ + ``` + +- 如果用于连接的参数中有 `NULL`,`CONCAT_WS()`会忽略 `NULL`。 + + 查询示例: + + ```sql + SELECT CONCAT_WS(',', 'TiDB Server', NULL, 'PD'); + ``` + + 返回结果: + + ```sql + +-------------------------------------------+ + | CONCAT_WS(',', 'TiDB Server', NULL, 'PD') | + +-------------------------------------------+ + | TiDB Server,PD | + +-------------------------------------------+ + ``` + +- 如果用于连接的参数中有空字符串,`CONCAT_WS()` 不会忽略该字符串。 + + 查询示例: + + ```sql + SELECT CONCAT_WS(',', 'TiDB Server', '', 'PD'); + ``` + + 返回结果: + + ```sql + +-----------------------------------------+ + | CONCAT_WS(',', 'TiDB Server', '', 'PD') | + +-----------------------------------------+ + | TiDB Server,,PD | + +-----------------------------------------+ + ``` + +### [`ELT()`](https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_elt) + +返回指定位置的字符串 + +### [`EXPORT_SET()`](https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_export-set) + +返回一个字符串,其中值位中设置的每个位,可以得到一个 on 字符串,而每个未设置的位,可以得到一个 off 字符串 + +### [`FIELD()`](https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_field) + +返回参数在后续参数中出现的第一个位置 + +### [`FIND_IN_SET()`](https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_find-in-set) + +返回第一个参数在第二个参数中出现的位置 + +### [`FORMAT()`](https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_format) + +`FORMAT(X,D[,locale])` 函数用于将数字 `X` 格式化为类似于 `“#,###,###.##”` 的格式,四舍五入保留 `D` 位小数,并将结果作为字符串返回。 + +参数: + +- `X`:要格式化的数字。可以是直接的数字值、数字字符串、或科学记数法格式的数字。 +- `D`:指定返回值的小数位数。该函数根据 `D` 对 `X` 进行四舍五入。如果 `D` 大于 `X` 的实际小数位数,则会在结果中填充相应长度的零。 +- `[locale]`:指定一个区域设置,用于结果中数字的小数点、千位分隔符和分隔符之间的分组。合法的区域设置值与 [`lc_time_names`](https://dev.mysql.com/doc/refman/8.3/en/server-system-variables.html#sysvar_lc_time_names) 系统变量的合法值相同。如果未指定或者设置为 `NULL`,则默认使用 `'en_US'` 区域设置。该参数可选。 + +行为细节: + +- 如果输入的第一个参数为字符串,且该字符串中只包含数字时,该函数将按照该数字返回结果。例如,`FORMAT('12.36', 1)` 与 `FORMAT(12.36, 1)` 的返回结果相同。 +- 如果输入的第一个参数为科学计数法(`E/e`)表示的数字时,该函数将按照该数字返回结果。例如,`FORMAT('1E2', 3)`),函数返回 `100.000`。 +- 如果输入的第一个参数为非数字开头的字符串时,该函数除了返回零值外,还返回一个警告 `(Code 1292)`。例如,`FORMAT('q12.36', 5)` 函数返回 `0.00000`,还会包含一个警告 `Warning (Code 1292): Truncated incorrect DOUBLE value: 'q12.36'`。 +- 如果输入的第一个参数为数字和非数字混合的字符串时,该函数将基于该参数中开头连续的数字部分返回结果,还返回一个警告 `(Code 1292)`。例如,`FORMAT('12.36q56.78', 1)` 与 `FORMAT('12.36', 1)` 的返回的数字结果相同,但 `FORMAT('12.36q56.78', 1)` 还会包含一个警告 `Warning (Code 1292): Truncated incorrect DOUBLE value: '12.36q56.78'`。 +- 如果输入的第二个参数为零或负数,该函数将四舍五入小数部分并返回整数。 +- 如果输入的任意参数为 `NULL`,函数将返回 `NULL`。 + +示例: + +格式化数字 12.36 到不同的小数位数: + +```sql +mysql> SELECT FORMAT(12.36, 1); ++------------------+ +| FORMAT(12.36, 1) | ++------------------+ +| 12.4 | ++------------------+ +``` + +```sql +mysql> SELECT FORMAT(12.36, 5); ++------------------+ +| FORMAT(12.36, 5) | ++------------------+ +| 12.36000 | ++------------------+ +``` + +```sql +mysql> SELECT FORMAT(1234.56, 1, 'en_US'); ++-----------------------------+ +| FORMAT(1234.56, 1, 'en_US') | ++-----------------------------+ +| 1,234.6 | ++-----------------------------+ +``` + +### [`FROM_BASE64()`](https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_from-base64) + +`FROM_BASE64(str)` 函数用于对 [Base64](https://datatracker.ietf.org/doc/html/rfc4648) 编码的字符串进行解码,并将解码结果以十六进制字符串的形式返回。 + +- 此函数接受一个单一参数,即需要解码的 Base64 编码字符串。 +- 如果输入参数为 `NULL` 或无效的 Base64 编码字符串,`FROM_BASE64()` 函数将返回 `NULL`。 + +示例: + +以下示例解码 Base64 编码的字符串 `'SGVsbG8gVGlEQg=='`,该字符串是 `'Hello TiDB'` 经过 [`TO_BASE64()`](#to_base64) 函数编码的结果。 + +```sql +mysql> SELECT TO_BASE64('Hello TiDB'); ++-------------------------+ +| TO_BASE64('Hello TiDB') | ++-------------------------+ +| SGVsbG8gVGlEQg== | ++-------------------------+ + +mysql> SELECT FROM_BASE64('SGVsbG8gVGlEQg=='); ++------------------------------------------------------------------+ +| FROM_BASE64('SGVsbG8gVGlEQg==') | ++------------------------------------------------------------------+ +| 0x48656C6C6F2054694442 | ++------------------------------------------------------------------+ +``` + +```sql +mysql> SELECT CONVERT(FROM_BASE64('SGVsbG8gVGlEQg==') USING utf8mb4); ++--------------------------------------------------------+ +| CONVERT(FROM_BASE64('SGVsbG8gVGlEQg==') USING utf8mb4) | ++--------------------------------------------------------+ +| Hello TiDB | ++--------------------------------------------------------+ +``` + +以下示例解码 Base64 编码的数字 `MTIzNDU2`,该字符串是 `123456` 经过 [`TO_BASE64()`](#to_base64) 函数编码的结果。 + +```sql +mysql> SELECT FROM_BASE64('MTIzNDU2'); ++--------------------------------------------------+ +| FROM_BASE64('MTIzNDU2') | ++--------------------------------------------------+ +| 0x313233343536 | ++--------------------------------------------------+ +``` + +### [`HEX()`](https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_hex) + +`HEX()` 函数用于将输入的参数转换为其十六进制值的字符串表示形式。该参数可以为字符串或数字。 + +- 如果输入参数为字符串,`HEX(str)` 返回 `str` 的十六进制字符串表示。该函数将 `str` 中每个字符的每个字节转换为两个十六进制数字。例如,在 UTF-8 或 ASCII 字符集中,字符 `a` 的二进制表示为 `00111101`,十六进制表示为 `61`。 +- 如果输入参数为数字,`HEX(n)` 返回 `n` 的十六进制字符串表示。该函数将参数 `n` 视为 `BIGINT` 数字,相当于 `CONV(n, 10, 16)`。 +- 如果输入参数为 `NULL`,该函数返回 `NULL`。 + +示例: + +```sql +SELECT X'616263', HEX('abc'), UNHEX(HEX('abc')), 0x616263; ++-----------+------------+-------------------+----------+ +| X'616263' | HEX('abc') | UNHEX(HEX('abc')) | 0x616263 | ++-----------+------------+-------------------+----------+ +| abc | 616263 | abc | abc | ++-----------+------------+-------------------+----------+ +``` + +```sql +SELECT X'F09F8DA3', HEX('🍣'), UNHEX(HEX('🍣')), 0xF09F8DA3; ++-------------+-------------+--------------------+------------+ +| X'F09F8DA3' | HEX('🍣') | UNHEX(HEX('🍣')) | 0xF09F8DA3 | ++-------------+-------------+--------------------+------------+ +| 🍣 | F09F8DA3 | 🍣 | 🍣 | ++-------------+-------------+--------------------+------------+ +``` + +```sql +SELECT HEX(255), CONV(HEX(255), 16, 10); ++----------+------------------------+ +| HEX(255) | CONV(HEX(255), 16, 10) | ++----------+------------------------+ +| FF | 255 | ++----------+------------------------+ +``` + +```sql +SELECT HEX(NULL); ++-----------+ +| HEX(NULL) | ++-----------+ +| NULL | ++-----------+ +``` + +### [`INSERT()`](https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_insert) + +`INSERT(str, pos, len, newstr)` 函数用于将字符串 `str` 中的一个子字符串(从位置 `pos` 开始,长度为 `len`)替换为字符串 `newstr`。该函数是多字节安全的。 + +- 如果 `pos` 超过了 `str` 的长度,函数返回原始字符串 `str` 而不做修改。 +- 如果 `len` 超过了从位置 `pos` 开始的 `str` 的剩余长度,函数将从位置 `pos` 开始替换字符串的其余部分。 +- 如果任一参数为 `NULL`,该函数返回 `NULL`。 + +示例: + +```sql +SELECT INSERT('He likes tennis', 4, 5, 'plays'); ++------------------------------------------+ +| INSERT('He likes tennis', 4, 5, 'plays') | ++------------------------------------------+ +| He plays tennis | ++------------------------------------------+ +``` + +```sql +SELECT INSERT('He likes tennis', -1, 5, 'plays'); ++-------------------------------------------+ +| INSERT('He likes tennis', -1, 5, 'plays') | ++-------------------------------------------+ +| He likes tennis | ++-------------------------------------------+ +``` + +```sql +SELECT INSERT('He likes tennis', 4, 100, 'plays'); ++--------------------------------------------+ +| INSERT('He likes tennis', 4, 100, 'plays') | ++--------------------------------------------+ +| He plays | ++--------------------------------------------+ +``` + +```sql +SELECT INSERT('He likes tennis', 10, 100, '🍣'); ++-------------------------------------------+ +| INSERT('He likes tennis', 10, 100, '🍣') | ++-------------------------------------------+ +| He likes 🍣 | ++-------------------------------------------+ +``` + +```sql +SELECT INSERT('PingCAP 数据库', 1, 7, 'TiDB'); ++-------------------------------------------+ +| INSERT('PingCAP 数据库', 1, 7, 'TiDB') | ++-------------------------------------------+ +| TiDB 数据库 | ++-------------------------------------------+ +``` + +### [`INSTR()`](https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_instr) + +`INSTR(str, substr)` 函数用于获取子字符串 `substr` 在字符串 `str` 中第一次出现的位置。`substr` 和 `str` 均可以为字符串或数字。该函数与 [`LOCATE(substr, str)`](#locate) 函数的两参数版本功能相同,但参数顺序相反。 + +> **注意:** +> +> `INSTR(str, substr)` 函数是否区分大小取决于 TiDB 所使用的[排序规则](/character-set-and-collation.md)。二进制排序规则(以 `_bin` 为后缀)区分大小写,而通用排序规则(以 `_general_ci` 或 `_ai_ci` 为后缀)不区分大小写。 + +- 如果任一输入参数为数字,该函数将数字视为字符串处理。 +- 如果 `substr` 不在 `str` 中,函数返回 `0`。否则,返回 `substr` 在 `str` 中第一次出现的位置。 +- 如果任一参数为 `NULL`,该函数返回 `NULL`。 + +示例: + +```sql +SELECT INSTR("pingcap.com", "tidb"); ++------------------------------+ +| INSTR("pingcap.com", "tidb") | ++------------------------------+ +| 0 | ++------------------------------+ +``` + +```sql +SELECT INSTR("pingcap.com/tidb", "tidb"); ++-----------------------------------+ +| INSTR("pingcap.com/tidb", "tidb") | ++-----------------------------------+ +| 13 | ++-----------------------------------+ +``` + +```sql +SELECT INSTR("pingcap.com/tidb" COLLATE utf8mb4_bin, "TiDB"); ++-------------------------------------------------------+ +| INSTR("pingcap.com/tidb" COLLATE utf8mb4_bin, "TiDB") | ++-------------------------------------------------------+ +| 0 | ++-------------------------------------------------------+ +``` + +```sql +SELECT INSTR("pingcap.com/tidb" COLLATE utf8mb4_general_ci, "TiDB"); ++--------------------------------------------------------------+ +| INSTR("pingcap.com/tidb" COLLATE utf8mb4_general_ci, "TiDB") | ++--------------------------------------------------------------+ +| 13 | ++--------------------------------------------------------------+ +``` + +```sql +SELECT INSTR(0123, "12"); ++-------------------+ +| INSTR(0123, "12") | ++-------------------+ +| 1 | ++-------------------+ +``` + +### [`LCASE()`](https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_lcase) + +`LCASE(str)`函数与 [`LOWER(str)`](#lower) 函数功能相同,都是返回输入参数的小写形式。 + +### [`LEFT()`](https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_left) + +`LEFT()` 函数用于返回字符串左侧指定数量的字符。 + +语法: + +```sql +LEFT(`str`, `len`) +``` + +- `str`:要提取字符的原始字符串。如果 `str` 包含一个多字节字符,该函数将其视为一个字符。 +- `len`:要返回的字符长度。 + - 如果 `len` 小于或等于 0,该函数返回空字符串。 + - 如果 `len` 大于或等于 `str` 的长度,该函数将返回原始的 `str`。 +- 如果任何参数为 `NULL`,该函数返回 `NULL`。 + +示例: + +```sql +SELECT LEFT('ABCED', 3); ++------------------+ +| LEFT('ABCED', 3) | ++------------------+ +| ABC | ++------------------+ + +SELECT LEFT('ABCED', 6); ++------------------+ +| LEFT('ABCED', 6) | ++------------------+ +| ABCED | ++------------------+ +``` + +```sql +SELECT LEFT('ABCED', 0); ++------------------+ +| LEFT('ABCED', 0) | ++------------------+ +| | ++------------------+ + +SELECT LEFT('ABCED', -1); ++-------------------+ +| LEFT('ABCED', -1) | ++-------------------+ +| | ++-------------------+ +``` + +```sql +SELECT LEFT('🍣ABC', 3); ++--------------------+ +| LEFT('🍣ABC', 3) | ++--------------------+ +| 🍣AB | ++--------------------+ +``` + +```sql +SELECT LEFT('ABC', NULL); ++-------------------+ +| LEFT('ABC', NULL) | ++-------------------+ +| NULL | ++-------------------+ + +SELECT LEFT(NULL, 3); ++------------------------------+ +| LEFT(NULL, 3) | ++------------------------------+ +| NULL | ++------------------------------+ +``` + +### [`LENGTH()`](https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_length) + +`LENGTH()` 函数用于返回字符串的字节长度。`LENGTH()` 将单个多字节字符视为多个字节,而 `CHAR_LENGTH()` 将单个多字节字符视为单个字符。 + +如果输入参数为 `NULL`,该函数将返回 `NULL`。 + +示例: + +```sql +SELECT LENGTH('ABC'); ++---------------+ +| LENGTH('ABC') | ++---------------+ +| 3 | ++---------------+ + +SELECT LENGTH('🍣ABC'); ++-------------------+ +| LENGTH('🍣ABC') | ++-------------------+ +| 7 | ++-------------------+ + +SELECT CHAR_LENGTH('🍣ABC'); ++------------------------+ +| CHAR_LENGTH('🍣ABC') | ++------------------------+ +| 4 | ++------------------------+ +``` + +```sql +SELECT LENGTH(NULL); ++--------------+ +| LENGTH(NULL) | ++--------------+ +| NULL | ++--------------+ +``` + +### [`LIKE`](https://dev.mysql.com/doc/refman/8.0/en/string-comparison-functions.html#operator_like) + +`LIKE` 用于进行简单字符串匹配。表达式 `expr LIKE pat [ESCAPE 'escape_char']` 返回 `1` (`TRUE`) 或 `0` (`FALSE`)。如果 `expr` 或 `pat` 中任一个为 `NULL`,结果为 `NULL`。 + +你可以在 `LIKE` 中使用以下两个通配符: + +- `%` 匹配任意数量的字符,包括零个字符。 +- `_` 精确匹配一个字符。 + +以下示例使用 `utf8mb4_bin` 排序规则: + +```sql +SET collation_connection='utf8mb4_bin'; +SHOW VARIABLES LIKE 'collation_connection'; ++----------------------+-------------+ +| Variable_name | Value | ++----------------------+-------------+ +| collation_connection | utf8mb4_bin | ++----------------------+-------------+ +``` + +```sql +SELECT NULL LIKE '%' as result; ++--------+ +| result | ++--------+ +| NULL | ++--------+ +``` + +```sql +SELECT 'sushi!!!' LIKE 'sushi_' AS result; ++--------+ +| result | ++--------+ +| 0 | ++--------+ +``` + +```sql +SELECT '🍣🍺sushi🍣🍺' LIKE '%sushi%' AS result; ++--------+ +| result | ++--------+ +| 1 | ++--------+ +``` + +```sql +SELECT '🍣🍺sushi🍣🍺' LIKE '%SUSHI%' AS result; ++--------+ +| result | ++--------+ +| 0 | ++--------+ +``` + +```sql +SELECT '🍣🍺sushi🍣🍺' LIKE '%🍣%' AS result; ++--------+ +| result | ++--------+ +| 1 | ++--------+ +``` + +默认的转义字符是 `\`: + +```sql +SELECT 'sushi!!!' LIKE 'sushi\_' AS result; ++--------+ +| result | ++--------+ +| 0 | ++--------+ +``` + +```sql +SELECT 'sushi_' LIKE 'sushi\_' AS result; ++--------+ +| result | ++--------+ +| 1 | ++--------+ +``` + +你可以使用 `ESCAPE` 子句指定一个不同的转义字符,例如 `*`: + +```sql +SELECT 'sushi_' LIKE 'sushi*_' ESCAPE '*' AS result; ++--------+ +| result | ++--------+ +| 1 | ++--------+ +``` + +```sql +SELECT 'sushi!' LIKE 'sushi*_' ESCAPE '*' AS result; ++--------+ +| result | ++--------+ +| 0 | ++--------+ +``` + +你可以使用 `LIKE` 匹配一个数字: + +```sql +SELECT 10 LIKE '1%' AS result; ++--------+ +| result | ++--------+ +| 1 | ++--------+ +``` + +```sql +SELECT 10000 LIKE '12%' AS result; ++--------+ +| result | ++--------+ +| 0 | ++--------+ +``` + +你可以使用 `COLLATE` 显式指定一个排序规则,例如 `utf8mb4_unicode_ci`: + +```sql +SELECT '🍣🍺Sushi🍣🍺' COLLATE utf8mb4_unicode_ci LIKE '%SUSHI%' AS result; ++--------+ +| result | ++--------+ +| 1 | ++--------+ +``` + +### [`LOCATE()`](https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_locate) + +`LOCATE(substr, str[, pos])` 函数用于返回子字符串 `substr` 在字符串 `str` 中第一次出现的位置。`pos` 参数是可选的,用于指定查找的起始位置。 + +- 如果子字符串 `substr` 不在字符串 `str` 中,该函数返回 `0`。 +- 如果任一参数为 `NULL`,该函数返回 `NULL`。 +- 该函数是多字节安全的,并且只有当至少一个参数是二进制字符串时,才执行区分大小写的查找。 + +以下示例使用 `utf8mb4_bin` 排序规则: + +```sql +SET collation_connection='utf8mb4_bin'; +SHOW VARIABLES LIKE 'collation_connection'; ++----------------------+-------------+ +| Variable_name | Value | ++----------------------+-------------+ +| collation_connection | utf8mb4_bin | ++----------------------+-------------+ +``` + +```sql +SELECT LOCATE('bar', 'foobarbar'); ++----------------------------+ +| LOCATE('bar', 'foobarbar') | ++----------------------------+ +| 4 | ++----------------------------+ +``` + +```sql +SELECT LOCATE('baz', 'foobarbar'); ++----------------------------+ +| LOCATE('baz', 'foobarbar') | ++----------------------------+ +| 0 | ++----------------------------+ +``` + +```sql +SELECT LOCATE('bar', 'fooBARBAR'); ++----------------------------+ +| LOCATE('bar', 'fooBARBAR') | ++----------------------------+ +| 0 | ++----------------------------+ +``` + +```sql +SELECT LOCATE('bar', 'foobarBAR', 100); ++---------------------------------+ +| LOCATE('bar', 'foobarBAR', 100) | ++---------------------------------+ +| 0 | ++---------------------------------+ +``` + +```sql +SELECT LOCATE('bar', 'foobarbar', 5); ++-------------------------------+ +| LOCATE('bar', 'foobarbar', 5) | ++-------------------------------+ +| 7 | ++-------------------------------+ +``` + +```sql +SELECT LOCATE('bar', NULL); ++---------------------+ +| LOCATE('bar', NULL) | ++---------------------+ +| NULL | ++---------------------+ +``` + +```sql +SELECT LOCATE('DB', 'TiDB tidb 数据库'); ++-------------------------------------+ +| LOCATE('DB', 'TiDB tidb 数据库') | ++-------------------------------------+ +| 3 | ++-------------------------------------+ +``` + +```sql +SELECT LOCATE('DB', 'TiDB tidb 数据库', 4); ++----------------------------------------+ +| LOCATE('DB', 'TiDB tidb 数据库', 4) | ++----------------------------------------+ +| 0 | ++----------------------------------------+ +``` + +以下示例使用 `utf8mb4_unicode_ci` 排序规则: + +```sql +SET collation_connection='utf8mb4_unicode_ci'; +SHOW VARIABLES LIKE 'collation_connection'; ++----------------------+--------------------+ +| Variable_name | Value | ++----------------------+--------------------+ +| collation_connection | utf8mb4_unicode_ci | ++----------------------+--------------------+ +``` + +```sql +SELECT LOCATE('DB', 'TiDB tidb 数据库', 4); ++----------------------------------------+ +| LOCATE('DB', 'TiDB tidb 数据库', 4) | ++----------------------------------------+ +| 8 | ++----------------------------------------+ +``` + +```sql +SELECT LOCATE('🍺', '🍣🍣🍣🍺🍺'); ++----------------------------------------+ +| LOCATE('🍺', '🍣🍣🍣🍺🍺') | ++----------------------------------------+ +| 1 | ++----------------------------------------+ +``` + +以下多字节和二进制字符串示例使用 `utf8mb4_bin` 排序规则: + +```sql +SET collation_connection='utf8mb4_bin'; +SHOW VARIABLES LIKE 'collation_connection'; ++----------------------+-------------+ +| Variable_name | Value | ++----------------------+-------------+ +| collation_connection | utf8mb4_bin | ++----------------------+-------------+ +``` + +```sql +SELECT LOCATE('🍺', '🍣🍣🍣🍺🍺'); ++----------------------------------------+ +| LOCATE('🍺', '🍣🍣🍣🍺🍺') | ++----------------------------------------+ +| 4 | ++----------------------------------------+ +``` + +```sql +SELECT LOCATE('b', _binary'aBcde'); ++-----------------------------+ +| LOCATE('b', _binary'aBcde') | ++-----------------------------+ +| 0 | ++-----------------------------+ +``` + +```sql +SELECT LOCATE('B', _binary'aBcde'); ++-----------------------------+ +| LOCATE('B', _binary'aBcde') | ++-----------------------------+ +| 2 | ++-----------------------------+ +``` + +```sql +SELECT LOCATE(_binary'b', 'aBcde'); ++-----------------------------+ +| LOCATE(_binary'b', 'aBcde') | ++-----------------------------+ +| 0 | ++-----------------------------+ +``` + +```sql +SELECT LOCATE(_binary'B', 'aBcde'); ++-----------------------------+ +| LOCATE(_binary'B', 'aBcde') | ++-----------------------------+ +| 2 | ++-----------------------------+ +``` + +### [`LOWER()`](https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_lower) + +`LOWER(str)` 函数用于将输入的参数 `str` 中的所有字符转换为小写。该参数可以为字符串或数字。 + +- 如果输入参数为字符串,该函数返回字符串的小写形式。 +- 如果输入参数为数字,该函数将会去掉该数字中的前导零。 +- 如果输入参数为 `NULL`,该函数返回 `NULL`。 + +示例: + +```sql +SELECT LOWER("TiDB"); + ++---------------+ +| LOWER("TiDB") | ++---------------+ +| tidb | ++---------------+ +``` + +```sql +SELECT LOWER(-012); + ++-------------+ +| LOWER(-012) | ++-------------+ +| -12 | ++-------------+ +``` + +### [`LPAD()`](https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_lpad) + +返回字符串参数,左侧添加指定字符串 + +### [`LTRIM()`](https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_ltrim) + +去掉前缀空格 + +### [`MAKE_SET()`](https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_make-set) + +返回一组用逗号分隔的字符串,这些字符串的位数与给定的 bits 参数对应 + +### [`MID()`](https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_mid) + +返回一个以指定位置开始的子字符串 + +### [`NOT LIKE`](https://dev.mysql.com/doc/refman/8.0/en/string-comparison-functions.html#operator_not-like) + +否定简单模式匹配 + +### [`NOT REGEXP`](https://dev.mysql.com/doc/refman/8.0/en/regexp.html#operator_not-regexp) + +`REGEXP` 的否定形式 + +### [`OCT()`](https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_oct) + +返回一个数值的八进制表示,形式为字符串 + +### [`OCTET_LENGTH()`](https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_octet-length) + +与 `LENGTH()` 功能相同 + +### [`ORD()`](https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_ord) + +返回该参数最左侧字符的字符编码 + +### [`POSITION()`](https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_position) + +与 `LOCATE()` 功能相同 + +### [`QUOTE()`](https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_quote) + +使参数逃逸,为了在 SQL 语句中使用 + +### [`REGEXP`](https://dev.mysql.com/doc/refman/8.0/en/regexp.html#operator_regexp) + +使用正则表达式匹配模式 + +### [`REGEXP_INSTR()`](https://dev.mysql.com/doc/refman/8.0/en/regexp.html#function_regexp-instr) + +返回满足正则的子字符串的第一个索引位置(与 MySQL 不完全兼容,具体请参考[正则函数与 MySQL 的兼容性](#正则函数与-mysql-的兼容性)) + +### [`REGEXP_LIKE()`](https://dev.mysql.com/doc/refman/8.0/en/regexp.html#function_regexp-like) + +判断字符串是否满足正则表达式(与 MySQL 不完全兼容,具体请参考[正则函数与 MySQL 的兼容性](#正则函数与-mysql-的兼容性)) + +### [`REGEXP_REPLACE()`](https://dev.mysql.com/doc/refman/8.0/en/regexp.html#function_regexp-replace) + +替换满足正则表达式的子字符串(与 MySQL 不完全兼容,具体请参考[正则函数与 MySQL 的兼容性](#正则函数与-mysql-的兼容性)) + +### [`REGEXP_SUBSTR()`](https://dev.mysql.com/doc/refman/8.0/en/regexp.html#function_regexp-substr) + +返回满足正则表达式的子字符串(与 MySQL 不完全兼容,具体请参考[正则函数与 MySQL 的兼容性](#正则函数与-mysql-的兼容性)) + +### [`REPEAT()`](https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_repeat) + +以指定次数重复一个字符串 + +### [`REPLACE()`](https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_replace) + +替换所有出现的指定字符串 + +### [`REVERSE()`](https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_reverse) + +反转字符串里的所有字符 + +### [`RIGHT()`](https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_right) + +返回指定数量的最右侧的字符 + +### [`RLIKE`](https://dev.mysql.com/doc/refman/8.0/en/regexp.html#operator_regexp) + +与 `REGEXP` 功能相同 + +### [`RPAD()`](https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_rpad) + +以指定次数添加字符串 + +### [`RTRIM()`](https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_rtrim) + +去掉后缀空格 + +### [`SPACE()`](https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_space) + +返回指定数量的空格,形式为字符串 + +### [`STRCMP()`](https://dev.mysql.com/doc/refman/8.0/en/string-comparison-functions.html#function_strcmp) + +比较两个字符串 + +### [`SUBSTR()`](https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_substr) + +返回指定的子字符串 + +### [`SUBSTRING()`](https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_substring) + +返回指定的子字符串 + +### [`SUBSTRING_INDEX()`](https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_substring-index) + +`SUBSTRING_INDEX()` 函数用于按照指定的分隔符和次数从字符串中提取子字符串。该函数在处理以特定分隔符分隔的数据时特别有用,例如解析 CSV 数据或处理日志文件。 + +语法: + +```sql +SUBSTRING_INDEX(str, delim, count) +``` + +- `str`:要处理的字符串。 +- `delim`:指定字符串中的分隔符,大小写敏感。 +- `count`:指定分隔符出现的次数。 + - 如果 `count` 为正数,该函数返回从字符串左边开始的第 `count` 个分隔符之前的子字符串。 + - 如果 `count` 为负数,该函数返回从字符串右边开始的第 `count` 个分隔符之后的子字符串。 + - 如果 `count` 为 `0`,该函数返回一个空字符串。 + +查询示例 1: + +```sql +SELECT SUBSTRING_INDEX('www.tidbcloud.com', '.', 2); +``` + +返回结果 1: + +```sql ++-----------------------------------------+ +| SUBSTRING_INDEX('www.tidbcloud.com', '.', 2) | ++-----------------------------------------+ +| www.tidbcloud | ++-----------------------------------------+ +``` + +查询示例 2: + +```sql +SELECT SUBSTRING_INDEX('www.tidbcloud.com', '.', -1); +``` + +返回结果 2: + +```sql ++------------------------------------------+ +| SUBSTRING_INDEX('www.tidbcloud.com', '.', -1) | ++------------------------------------------+ +| com | ++------------------------------------------+ +``` + +### [`TO_BASE64()`](https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_to-base64) + +`TO_BASE64()` 函数用于将输入的参数转换为 base-64 编码形式的字符串,并按照当前连接的字符集和排序规则返回结果。base-64 编码的字符串可以使用 [`FROM_BASE64()`](#from_base64) 函数进行解码。 + +语法: + +```sql +TO_BASE64(str) +``` + +- 如果输入参数不是字符串,该函数会将其转换为字符串后再进行 base-64 编码。 +- 如果输入参数为 `NULL`,该函数返回 `NULL`。 + +查询示例 1: + +```sql +SELECT TO_BASE64('abc'); +``` + +返回结果 1: + +```sql ++------------------+ +| TO_BASE64('abc') | ++------------------+ +| YWJj | ++------------------+ +``` + +查询示例 2: + +```sql +SELECT TO_BASE64(6); +``` + +返回结果 2: + +```sql ++--------------+ +| TO_BASE64(6) | ++--------------+ +| Ng== | ++--------------+ +``` + +### [`TRANSLATE()`](https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/TRANSLATE.html#GUID-80F85ACB-092C-4CC7-91F6-B3A585E3A690) + +将字符串中出现的所有指定字符替换为其它字符。这个函数不会像 Oracle 一样将空字符串视为`NULL` + +### [`TRIM()`](https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_trim) + +去掉前缀和后缀空格 + +### [`UCASE()`](https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_ucase) + +`UCASE()` 函数将字符串转换为大写字母,此函数等价于 `UPPER()` 函数。 + +> **注意:** +> +> 当字符串为 null 时,则返回 `NULL`。 + +查询示例: + +```sql +SELECT UCASE('bigdata') AS result_upper, UCASE(null) AS result_null; +``` + +返回结果: + +```sql ++--------------+-------------+ +| result_upper | result_null | ++--------------+-------------+ +| BIGDATA | NULL | ++--------------+-------------+ +``` + +### [`UNHEX()`](https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_unhex) + +`UNHEX()` 函数执行 `HEX()` 函数的逆运算,将参数中的每对字符视为十六进制数字,并将其转换为该数字表示的字符,返回值为二进制字符串。 + +> **注意:** +> +> 传入的字符串必须是合法的十六进制数值,包含 `0~9`、`A~F`、`a~f`,如果为 `NULL` 或超出该范围,则返回 `NULL`。 + +查询示例: + +```sql +SELECT UNHEX('54694442'); +``` + +返回结果: + +```sql ++--------------------------------------+ +| UNHEX('54694442') | ++--------------------------------------+ +| 0x54694442 | ++--------------------------------------+ +``` + +### [`UPPER()`](https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_upper) + +`UPPER()` 函数将字符串转换为大写字母,此函数等价于 `UCASE()` 函数。 + +> **注意:** +> +> 当字符串为 null 时,则返回 `NULL`。 + +查询示例: + +```sql +SELECT UPPER('bigdata') AS result_upper, UPPER(null) AS result_null; +``` + +返回结果: + +```sql ++--------------+-------------+ +| result_upper | result_null | ++--------------+-------------+ +| BIGDATA | NULL | ++--------------+-------------+ +``` + +### [`WEIGHT_STRING()`](https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_weight-string) + +`WEIGHT_STRING()` 函数返回字符串的权重(二进制字符),主要用于多字符集场景下的排序和比较操作。如果参数为 `NULL`,则返回 `NULL`。语法示例如下: + +```sql +WEIGHT_STRING(str [AS {CHAR|BINARY}(N)]) +``` + +* `str`:字符串表达式。如果是非二进制字符串,例如 CHAR、VARCHAR 或 TEXT 值,则返回值包含该字符串的排序规则权重;如果是二进制字符串,例如 BINARY、VARBINARY 或 BLOB 值,则返回值与输入相同。 +* `AS {CHAR|BINARY}(N)`:可选参数,用于指定输出结果的类型和长度。`CHAR` 表示字符数据类型,而 `BINARY` 表示二进制数据类型;`N` 指定输出的长度,取值为大于等于 1 的整数。 + +> **注意:** +> +> 当 `N` 小于字符串长度时,字符串将被截断;当 `N` 超过字符串长度时,`CHAR` 类型将用空格来填充以达到指定长度,`BINARY` 类型将以 `0x00` 来填充以达到指定长度。 + +查询示例: + +```sql +SET NAMES 'utf8mb4'; +SELECT HEX(WEIGHT_STRING('ab' AS CHAR(3))) AS char_result, HEX(WEIGHT_STRING('ab' AS BINARY(3))) AS binary_result; +``` + +返回结果: + +```sql ++-------------+---------------+ +| char_result | binary_result | ++-------------+---------------+ +| 6162 | 616200 | ++-------------+---------------+ +``` + +## 不支持的函数 + +* `LOAD_FILE()` +* `MATCH()` +* `SOUNDEX()` + +## 正则函数与 MySQL 的兼容性 + +本节介绍 TiDB 中正则函数 `REGEXP_INSTR()`、`REGEXP_LIKE()`、`REGEXP_REPLACE()`、`REGEXP_SUBSTR()` 与 MySQL 的兼容情况。 + +### 语法兼容性 + +MySQL 的实现使用的是 [ICU](https://github.com/unicode-org/icu) (International Components for Unicode) 库,TiDB 的实现使用的是 [RE2](https://github.com/google/re2) 库,两个库之间的语法差异可以查阅 [ICU 文档](https://unicode-org.github.io/icu/userguide/)和 [RE2 文档](https://github.com/google/re2/wiki/Syntax)。 + +### 匹配模式 `match_type` 兼容性 + +TiDB 与 MySQL 在 `match_type` 上的差异: + +- TiDB 中 `match_type` 可选值为:`"c"`、`"i"`、`"m"`、`"s"`。MySQL 中 `match_type` 可选值为:`"c"`、`"i"`、`"m"`、`"n"`、`"u"`。 +- TiDB 中 `"s"` 对应 MySQL 中的 `"n"`,即 `.` 字符匹配行结束符。 + + 例如:MySQL 中 `SELECT REGEXP_LIKE(a, b, "n") FROM t1;` 在 TiDB 中需要修改为 `SELECT REGEXP_LIKE(a, b, "s") FROM t1;`。 + +- TiDB 不支持 `match_type` 为 `"u"`。 + +### 数据类型兼容性 + +TiDB 与 MySQL 在二进制字符串 (binary string) 数据类型上的差异: + +- MySQL 8.0.22 及以上版本中正则函数不支持二进制字符串,具体信息可查看 [MySQL 文档](https://dev.mysql.com/doc/refman/8.0/en/regexp.html)。但在实际使用过程中,如果所有参数或者返回值的数据类型都是二进制字符串,则正则函数可以正常使用,否则报错。 +- TiDB 目前完全禁止使用二进制字符串,无论什么情况都会报错。 + +### 其它兼容性 + +- TiDB 与 MySQL 在替换空字符串上存在差异,下面以 `REGEXP_REPLACE("", "^$", "123")` 为例: + + - MySQL 不会对空串进行替换,其结果为 `""`。 + - TiDB 会对空串进行替换,其结果为 `"123"`。 + +- TiDB 与 MySQL 在捕获组的关键字上存在差异。MySQL 的捕获组关键字为`$`,而 TiDB 的捕获组关键字为`\\`。此外,TiDB 只支持编号为 `0` 到 `9` 的捕获组。 + + 例如,以下 SQL 语句在 TiDB 中的返回结果为 `ab`。 + + ```sql + SELECT REGEXP_REPLACE('abcd','(.*)(.{2})$','\\1') AS s; + ``` diff --git a/markdown-pages/zh/tidb/master/functions-and-operators/type-conversion-in-expression-evaluation.md b/markdown-pages/zh/tidb/master/functions-and-operators/type-conversion-in-expression-evaluation.md new file mode 100644 index 0000000..83380e7 --- /dev/null +++ b/markdown-pages/zh/tidb/master/functions-and-operators/type-conversion-in-expression-evaluation.md @@ -0,0 +1,9 @@ +--- +title: 表达式求值的类型转换 +aliases: ['/docs-cn/dev/functions-and-operators/type-conversion-in-expression-evaluation/','/docs-cn/dev/reference/sql/functions-and-operators/type-conversion/'] +summary: TiDB 中的表达式求值类型转换与 MySQL 基本一致。详情请参见 MySQL 表达式求值类型转换文档。 +--- + +# 表达式求值的类型转换 + +TiDB 中表达式求值的类型转换与 MySQL 基本一致,详情参见 [MySQL 表达式求值的类型转换](https://dev.mysql.com/doc/refman/8.0/en/type-conversion.html)。 diff --git a/markdown-pages/zh/tidb/master/functions-and-operators/window-functions.md b/markdown-pages/zh/tidb/master/functions-and-operators/window-functions.md new file mode 100644 index 0000000..fe59564 --- /dev/null +++ b/markdown-pages/zh/tidb/master/functions-and-operators/window-functions.md @@ -0,0 +1,27 @@ +--- +title: 窗口函数 +aliases: ['/docs-cn/dev/functions-and-operators/window-functions/','/docs-cn/dev/reference/sql/functions-and-operators/window-functions/'] +summary: TiDB 中的窗口函数与 MySQL 8.0 基本一致。可以将 `tidb_enable_window_function` 设置为 `0` 来解决升级后无法解析语法的问题。TiDB 支持除 `GROUP_CONCAT()` 和 `APPROX_PERCENTILE()` 以外的所有 `GROUP BY` 聚合函数。其他支持的窗口函数包括 `CUME_DIST()`、`DENSE_RANK()`、`FIRST_VALUE()`、`LAG()`、`LAST_VALUE()`、`LEAD()`、`NTH_VALUE()`、`NTILE()`、`PERCENT_RANK()`、`RANK()` 和 `ROW_NUMBER()`。这些函数可以下推到 TiFlash。 +--- + +# 窗口函数 + +TiDB 中窗口函数的使用方法与 MySQL 8.0 基本一致,详情可参见 [MySQL 窗口函数](https://dev.mysql.com/doc/refman/8.0/en/window-functions.html)。由于窗口函数会使用一些保留关键字,可能导致原先可以正常执行的 SQL 语句在升级 TiDB 后无法被解析语法,此时可以将 `tidb_enable_window_function` 设置为 `0`,该参数的默认值为 `1`。 + +[本页](/tiflash/tiflash-supported-pushdown-calculations.md)列出的窗口函数可以下推到 TiFlash。 + +TiDB 支持除 `GROUP_CONCAT()` 和 `APPROX_PERCENTILE()` 以外的所有 [`GROUP BY` 聚合函数](/functions-and-operators/aggregate-group-by-functions.md)。此外,TiDB 支持的其他窗口函数如下: + +| 函数名 | 功能描述 | +| :-------------- | :------------------------------------- | +| [`CUME_DIST()`](https://dev.mysql.com/doc/refman/8.0/en/window-function-descriptions.html#function_cume-dist) | 返回一组值中的累积分布 | +| [`DENSE_RANK()`](https://dev.mysql.com/doc/refman/8.0/en/window-function-descriptions.html#function_dense-rank) | 返回分区中当前行的排名,并且排名是连续的| +| [`FIRST_VALUE()`](https://dev.mysql.com/doc/refman/8.0/en/window-function-descriptions.html#function_first-value) | 当前窗口中第一行的表达式值 | +| [`LAG()`](https://dev.mysql.com/doc/refman/8.0/en/window-function-descriptions.html#function_lag) | 分区中当前行前面第 N 行的表达式值| +| [`LAST_VALUE()`](https://dev.mysql.com/doc/refman/8.0/en/window-function-descriptions.html#function_last-value) | 当前窗口中最后一行的表达式值 | +| [`LEAD()`](https://dev.mysql.com/doc/refman/8.0/en/window-function-descriptions.html#function_lead) | 分区中当前行后面第 N 行的表达式值 | +| [`NTH_VALUE()`](https://dev.mysql.com/doc/refman/8.0/en/window-function-descriptions.html#function_nth-value) | 当前窗口中第 N 行的表达式值 | +| [`NTILE()`](https://dev.mysql.com/doc/refman/8.0/en/window-function-descriptions.html#function_ntile)| 将分区划分为 N 桶,为分区中的每一行分配桶号 | +| [`PERCENT_RANK()`](https://dev.mysql.com/doc/refman/8.0/en/window-function-descriptions.html#function_percent-rank)|返回分区中小于当前行的百分比 | +| [`RANK()`](https://dev.mysql.com/doc/refman/8.0/en/window-function-descriptions.html#function_rank)| 返回分区中当前行的排名,排名可能不连续 | +| [`ROW_NUMBER()`](https://dev.mysql.com/doc/refman/8.0/en/window-function-descriptions.html#function_row-number)| 返回分区中当前行的编号 | diff --git a/markdown-pages/zh/tidb/master/garbage-collection-configuration.md b/markdown-pages/zh/tidb/master/garbage-collection-configuration.md new file mode 100644 index 0000000..54abf0f --- /dev/null +++ b/markdown-pages/zh/tidb/master/garbage-collection-configuration.md @@ -0,0 +1,87 @@ +--- +title: GC 配置 +aliases: ['/docs-cn/dev/garbage-collection-configuration/','/docs-cn/dev/reference/garbage-collection/configuration/'] +summary: TiDB 的 GC 配置可以通过系统变量进行设置,包括启用 GC、运行间隔、数据保留时限、并发线程数量等。此外,TiDB 还支持 GC 流控,可以限制每秒数据写入量。从 TiDB 5.0 版本开始,建议使用系统变量进行配置,避免异常行为。在 TiDB 6.1.0 版本引入了新的系统变量 `tidb_gc_max_wait_time`,用于控制活跃事务阻塞 GC safe point 推进的最长时间。另外,GC in Compaction Filter 机制可以通过配置文件或在线配置开启,但可能会影响 TiKV 扫描性能。 +--- + +# GC 配置 + +你可以通过以下系统变量进行 GC 配置: + +* [`tidb_gc_enable`](/system-variables.md#tidb_gc_enable-从-v50-版本开始引入):控制是否启用 TiKV 的垃圾回收 (GC) 机制。 +* [`tidb_gc_run_interval`](/system-variables.md#tidb_gc_run_interval-从-v50-版本开始引入):指定垃圾回收 (GC) 运行的时间间隔。 +* [`tidb_gc_life_time`](/system-variables.md#tidb_gc_life_time-从-v50-版本开始引入):指定每次进行垃圾回收 (GC) 时保留数据的时限。 +* [`tidb_gc_concurrency`](/system-variables.md#tidb_gc_concurrency-从-v50-版本开始引入):指定 GC 在 [Resolve Locks(清理锁)](/garbage-collection-overview.md#resolve-locks清理锁)步骤中线程的数量。 +* [`tidb_gc_scan_lock_mode`](/system-variables.md#tidb_gc_scan_lock_mode-从-v50-版本开始引入):指定垃圾回收 (GC) 的 Resolve Locks(清理锁)步骤中扫描锁的方式。 +* [`tidb_gc_max_wait_time`](/system-variables.md#tidb_gc_max_wait_time-从-v610-版本开始引入):指定活跃事务阻碍 GC safe point 推进的最大时间。 + +关于如何修改系统变量的值,请参考[系统变量](/system-variables.md)。 + +## 流控 + +TiDB 支持 GC 流控,可通过配置 `gc.max-write-bytes-per-sec` 限制 GC worker 每秒数据写入量,降低对正常请求的影响,`0` 为关闭该功能。该配置可通过 tikv-ctl 动态修改: + +```bash +tikv-ctl --host=ip:port modify-tikv-config -n gc.max-write-bytes-per-sec -v 10MB +``` + +## TiDB 5.0 引入的变化 + +在 TiDB 5.0 之前的版本中,GC 是通过系统表 `mysql.tidb` 进行配置的。从 TiDB 5.0 版本起,GC 仍然可以通过系统表 `mysql.tidb` 进行配置,但建议你使用系统变量进行配置,这样可以确保对配置的任何更改都能得到验证,防止造成异常行为 ([#20655](https://github.com/pingcap/tidb/issues/20655))。 + +TiDB 5.0 及之后的版本不再需要向各个 TiKV Region 都发送触发 GC 的请求,因此不再提供 `CENTRAL` GC 模式的支持,取而代之的是效率更高的 `DISTRIBUTED` GC 模式 (自 TiDB 3.0 起的默认 GC 模式)。 + +如果要了解 TiDB 历史版本中 GC 配置的变化信息,请使用左侧导航栏中的 _"TIDB 版本选择器"_ 切换到本文档的历史版本。 + +## TiDB 6.1.0 引入的变化 + +在 TiDB 6.1.0 之前的版本中,TiDB 内部事务不会影响 GC safe point 推进。从 TiDB 6.1.0 版本起,计算 safe point 时会考虑内部事务的 startTS,从而解决内部事务因访问的数据被清理掉而导致失败的问题。带来的负面影响是如果内部事务运行时间过长,会导致 safe point 长时间不推进,进而会影响业务性能。 + +TiDB v6.1.0 引入了系统变量 [`tidb_gc_max_wait_time`](/system-variables.md#tidb_gc_max_wait_time-从-v610-版本开始引入) 控制活跃事务阻塞 GC safe point 推进的最长时间,超过该值后 GC safe point 会强制向后推进。 + +## GC in Compaction Filter 机制 + +GC in Compaction Filter 机制是在分布式 GC 模式 (`DISTRIBUTED` GC mode) 的基础上,由 RocksDB 的 Compaction 过程来进行 GC,而不再使用一个单独的 GC worker 线程。这样做的好处是避免了 GC 引起的额外磁盘读取,以及避免清理掉的旧版本残留大量删除标记影响顺序扫描性能。可以由 TiKV 配置文件中的以下开关控制: + +```toml +[gc] +enable-compaction-filter = true +``` + +该 GC 机制可通过在线配置变更开启: + +```sql +show config where type = 'tikv' and name like '%enable-compaction-filter%'; +``` + +```sql ++------+-------------------+-----------------------------+-------+ +| Type | Instance | Name | Value | ++------+-------------------+-----------------------------+-------+ +| tikv | 172.16.5.37:20163 | gc.enable-compaction-filter | false | +| tikv | 172.16.5.36:20163 | gc.enable-compaction-filter | false | +| tikv | 172.16.5.35:20163 | gc.enable-compaction-filter | false | ++------+-------------------+-----------------------------+-------+ +``` + +```sql +set config tikv gc.enable-compaction-filter = true; +show config where type = 'tikv' and name like '%enable-compaction-filter%'; +``` + +```sql ++------+-------------------+-----------------------------+-------+ +| Type | Instance | Name | Value | ++------+-------------------+-----------------------------+-------+ +| tikv | 172.16.5.37:20163 | gc.enable-compaction-filter | true | +| tikv | 172.16.5.36:20163 | gc.enable-compaction-filter | true | +| tikv | 172.16.5.35:20163 | gc.enable-compaction-filter | true | ++------+-------------------+-----------------------------+-------+ +``` + +> **注意:** +> +> 在使用 Compaction Filter 机制时,可能会出现 GC 进度延迟的情况,从而影响 TiKV 扫描性能。当你的负载中含有大量 coprocessor 请求,并且在 [**TiKV-Details > Coprocessor Detail**](/grafana-tikv-dashboard.md#coprocessor-detail) 面板中发现 Total Ops Details 的 `next()` 或 `prev()` 调用次数远远超过 `processed_keys` 调用的三倍时,可以采取以下措施: +> +> - 对于 TiDB v7.1.3 之前版本,建议尝试关闭 Compaction Filter,以加快 GC 速度。 +> - 从 v7.1.3 开始,TiDB 会根据每个 Region 的冗余版本数量 [`region-compact-min-redundant-rows`](/tikv-configuration-file.md#region-compact-min-redundant-rows-从-v710-版本开始引入) 和比例 [`region-compact-redundant-rows-percent`](/tikv-configuration-file.md#region-compact-redundant-rows-percent-从-v710-版本开始引入) 自动触发 compaction,从而提高 Compaction Filter 的 GC 速度。因此,在 v7.1.3 及之后的版本中,如果遇到上述情况,建议调整这两个参数,无需关闭 Compaction Filter。 diff --git a/markdown-pages/zh/tidb/master/garbage-collection-overview.md b/markdown-pages/zh/tidb/master/garbage-collection-overview.md new file mode 100644 index 0000000..bf69491 --- /dev/null +++ b/markdown-pages/zh/tidb/master/garbage-collection-overview.md @@ -0,0 +1,54 @@ +--- +title: GC 机制简介 +aliases: ['/docs-cn/dev/garbage-collection-overview/','/docs-cn/dev/reference/garbage-collection/overview/'] +summary: TiDB 的事务实现采用了 MVCC 机制,GC 的任务是清理不再需要的旧数据。整体流程包括 GC leader 控制 GC 的运行,定期触发 GC,以及三个步骤:Resolve Locks 清理锁,Delete Ranges 删除区间,Do GC 进行 GC 清理。Resolve Locks 清理锁有两种执行模式:LEGACY 和 PHYSICAL。Delete Ranges 删除区间会快速物理删除待删除的区间及删除操作的时间戳。Do GC 进行 GC 清理会删除所有 key 的过期版本。GC 每 10 分钟触发一次,默认保留最近 10 分钟内的数据。 +--- + +# GC 机制简介 + +TiDB 的事务的实现采用了 MVCC(多版本并发控制)机制,当新写入的数据覆盖旧的数据时,旧的数据不会被替换掉,而是与新写入的数据同时保留,并以时间戳来区分版本。Garbage Collection (GC) 的任务便是清理不再需要的旧数据。 + +## 整体流程 + +一个 TiDB 集群中会有一个 TiDB 实例被选举为 GC leader,GC 的运行由 GC leader 来控制。 + +GC 会被定期触发。每次 GC 时,首先,TiDB 会计算一个称为 safe point 的时间戳,接下来 TiDB 会在保证 safe point 之后的快照全部拥有正确数据的前提下,删除更早的过期数据。每一轮 GC 分为以下三个步骤: + +1. "Resolve Locks" 阶段会对所有 Region 扫描 safe point 之前的锁,并清理这些锁。 +2. "Delete Ranges" 阶段快速地删除由于 `DROP TABLE`/`DROP INDEX` 等操作产生的整区间的废弃数据。 +3. "Do GC" 阶段每个 TiKV 节点将会各自扫描该节点上的数据,并对每一个 key 删除其不再需要的旧版本。 + +默认配置下,GC 每 10 分钟触发一次,每次 GC 会保留最近 10 分钟内的数据(即默认 GC life time 为 10 分钟,safe point 的计算方式为当前时间减去 GC life time)。如果一轮 GC 运行时间太久,那么在一轮 GC 完成之前,即使到了下一次触发 GC 的时间也不会开始下一轮 GC。另外,为了使持续时间较长的事务能在超过 GC life time 之后仍然可以正常运行,safe point 不会超过正在执行中的事务的开始时间 (start_ts)。 + +## 实现细节 + +### Resolve Locks(清理锁) + +TiDB 的事务是基于 [Google Percolator](https://ai.google/research/pubs/pub36726) 模型实现的,事务的提交是一个两阶段提交的过程。第一阶段完成时,所有涉及的 key 都会上锁,其中一个锁会被选为 Primary,其余的锁 (Secondary) 则会存储一个指向 Primary 的指针;第二阶段会将 Primary 锁所在的 key 加上一个 Write 记录,并去除锁。这里的 Write 记录就是历史上对该 key 进行写入或删除,或者该 key 上发生事务回滚的记录。Primary 锁被替换为何种 Write 记录标志着该事务提交成功与否。接下来,所有 Secondary 锁也会被依次替换。如果因为某些原因(如发生故障等),这些 Secondary 锁没有完成替换、残留了下来,那么也可以根据锁中的信息找到 Primary,并根据 Primary 是否提交来判断整个事务是否提交。但是,如果 Primary 的信息在 GC 中被删除了,而该事务又存在未成功提交的 Secondary 锁,那么就永远无法得知该锁是否可以提交。这样,数据的正确性就无法保证。 + +Resolve Locks 这一步的任务即对 safe point 之前的锁进行清理。即如果一个锁对应的 Primary 已经提交,那么该锁也应该被提交;反之,则应该回滚。而如果 Primary 仍然是上锁的状态(没有提交也没有回滚),则应当将该事务视为超时失败而回滚。 + +Resolve Locks 有两种执行模式: + +- `LEGACY` (默认模式):由 GC leader 对所有的 Region 发送请求扫描过期的锁,并对扫到的锁查询 Primary 的状态,再发送请求对其进行提交或回滚。 +- `PHYSICAL`:TiDB 绕过 Raft 层直接扫描每个 TiKV 节点上的数据。 + +> **警告:** +> +> `PHYSICAL`模式(即启用 Green GC)目前是实验性功能,不建议在生产环境中使用。 + +你可以通过修改系统变量 [`tidb_gc_scan_lock_mode`](/system-variables.md#tidb_gc_scan_lock_mode-从-v50-版本开始引入) 的值切换 Resolve Locks 的执行模式。 + +### Delete Ranges(删除区间) + +在执行 `DROP TABLE/INDEX` 等操作时,会有大量连续的数据被删除。如果对每个 key 都进行删除操作、再对每个 key 进行 GC 的话,那么执行效率和空间回收速度都可能非常的低下。事实上,这种时候 TiDB 并不会对每个 key 进行删除操作,而是将这些待删除的区间及删除操作的时间戳记录下来。Delete Ranges 会将这些时间戳在 safe point 之前的区间进行快速的物理删除。 + +### Do GC(进行 GC 清理) + +这一步即删除所有 key 的过期版本。为了保证 safe point 之后的任何时间戳都具有一致的快照,这一步删除 safe point 之前提交的数据,但是会对每个 key 保留 safe point 前的最后一次写入(除非最后一次写入是删除)。 + +在进行这一步时,TiDB 只需要将 safe point 发送给 PD,即可结束整轮 GC。TiKV 会自行检测到 safe point 发生了更新,会对当前节点上所有作为 Region leader 进行 GC。与此同时,GC leader 可以继续触发下一轮 GC。 + +> **注意:** +> +> 从 TiDB 5.0 版本起,`CENTRAL` GC 模式(需要 TiDB 服务器发送 GC 请求到各个 Region)已经废弃,Do GC 这一步将只以 `DISTRIBUTED` GC 模式(从 TiDB 3.0 版起的默认模式)运行。 diff --git a/markdown-pages/zh/tidb/master/generate-self-signed-certificates.md b/markdown-pages/zh/tidb/master/generate-self-signed-certificates.md new file mode 100644 index 0000000..32239d9 --- /dev/null +++ b/markdown-pages/zh/tidb/master/generate-self-signed-certificates.md @@ -0,0 +1,155 @@ +--- +title: 生成自签名证书 +aliases: ['/docs-cn/dev/generate-self-signed-certificates/','/docs-cn/dev/how-to/secure/generate-self-signed-certificates/'] +summary: 本文介绍了使用 openssl 生成自签名证书的示例。用户可以根据需要生成符合要求的证书和密钥。首先安装 OpenSSL,然后生成 CA 证书和各个组件的证书,最后为客户端签发证书。证书的作用是为各个组件和客户端验证身份。 +--- + +# 生成自签名证书 + +> **注意:** +> +> 要在 TiDB 客户端与服务端间通信开启加密传输,你只需配置 `auto-tls` 参数。 + +本文档提供使用 `openssl` 生成自签名证书的一个示例,用户也可以根据自己的需求生成符合要求的证书和密钥。 + +假设实例集群拓扑如下: + +| Name | Host IP | Services | +| ----- | ----------- | ---------- | +| node1 | 172.16.10.11 | PD1, TiDB1 | +| node2 | 172.16.10.12 | PD2 | +| node3 | 172.16.10.13 | PD3 | +| node4 | 172.16.10.14 | TiKV1 | +| node5 | 172.16.10.15 | TiKV2 | +| node6 | 172.16.10.16 | TiKV3 | + +## 安装 OpenSSL + +对于 Debian 或 Ubuntu 操作系统: + +```bash +apt install openssl +``` + +对于 RedHat 或 CentOS 操作系统: + +```bash +yum install openssl +``` + +也可以参考 OpenSSL 官方的[下载文档](https://www.openssl.org/source/)进行安装。 + +## 生成 CA 证书 + +CA 的作用是签发证书。实际情况中,请联系你的管理员签发证书或者使用信任的 CA 机构。CA 会管理多个证书对,这里只需生成原始的一对证书,步骤如下: + +1. 生成 root 密钥: + + ```bash + openssl genrsa -out root.key 4096 + ``` + +2. 生成 root 证书: + + ```bash + openssl req -new -x509 -days 1000 -key root.key -out root.crt + ``` + +3. 验证 root 证书: + + ```bash + openssl x509 -text -in root.crt -noout + ``` + +## 签发各个组件的证书 + +### 集群中可能使用到的证书 + +- tidb certificate 由 TiDB 使用,为其他组件和客户端验证 TiDB 身份。 +- tikv certificate 由 TiKV 使用,为其他组件和客户端验证 TiKV 身份。 +- pd certificate 由 PD 使用,为其他组件和客户端验证 PD 身份。 +- client certificate 用于 PD、TiKV、TiDB 验证客户端。例如 `pd-ctl`,`tikv-ctl` 等。 + +### 给 TiKV 实例签发证书 + +给 TiKV 实例签发证书的步骤如下: + +1. 生成该证书对应的私钥: + + ```bash + openssl genrsa -out tikv.key 2048 + ``` + +2. 拷贝一份 OpenSSL 的配置模板文件。 + + 模板文件可能存在多个位置,请以实际位置为准: + + ```bash + cp /usr/lib/ssl/openssl.cnf . + ``` + + 如果不知道实际位置,请在根目录下查找: + + ```bash + find / -name openssl.cnf + ``` + +3. 编辑 `openssl.cnf`,在 `[ req ]` 字段下加入 `req_extensions = v3_req`,然后在 `[ v3_req ]` 字段下加入 `subjectAltName = @alt_names`。最后新建一个字段,并编辑 SAN 的信息: + + ``` + [ alt_names ] + IP.1 = 127.0.0.1 + IP.2 = 172.16.10.14 + IP.3 = 172.16.10.15 + IP.4 = 172.16.10.16 + ``` + +4. 保存 `openssl.cnf` 文件后,生成证书请求文件(在这一步也可以为该证书指定 Common Name,其作用是让服务端验证接入的客户端的身份,各个组件默认不会开启验证,需要在配置文件中启用该功能才生效): + + ```bash + openssl req -new -key tikv.key -out tikv.csr -config openssl.cnf + ``` + +5. 签发生成证书: + + ```bash + openssl x509 -req -days 365 -CA root.crt -CAkey root.key -CAcreateserial -in tikv.csr -out tikv.crt -extensions v3_req -extfile openssl.cnf + ``` + +6. 验证证书携带 SAN 字段信息(可选): + + ```bash + openssl x509 -text -in tikv.crt -noout + ``` + +7. 确认在当前目录下得到如下文件: + + ``` + root.crt + tikv.crt + tikv.key + ``` + +为其它 TiDB 组件签发证书的过程类似,此文档不再赘述。 + +### 为客户端签发证书 + +为客户端签发证书的步骤如下。 + +1. 生成该证书对应的私钥: + + ```bash + openssl genrsa -out client.key 2048 + ``` + +2. 生成证书请求文件(在这一步也可以为该证书指定 Common Name,其作用是让服务端验证接入的客户端的身份,默认不会开启对各个组件的验证,需要在配置文件中启用该功能才生效) + + ```bash + openssl req -new -key client.key -out client.csr + ``` + +3. 签发生成证书: + + ```bash + openssl x509 -req -days 365 -CA root.crt -CAkey root.key -CAcreateserial -in client.csr -out client.crt + ``` diff --git a/markdown-pages/zh/tidb/master/generated-columns.md b/markdown-pages/zh/tidb/master/generated-columns.md new file mode 100644 index 0000000..1a4dc71 --- /dev/null +++ b/markdown-pages/zh/tidb/master/generated-columns.md @@ -0,0 +1,148 @@ +--- +title: 生成列 +aliases: ['/docs-cn/dev/generated-columns/','/docs-cn/dev/reference/sql/generated-columns/'] +summary: 生成列是由列定义中的表达式计算得到的值。它包括存储生成列和虚拟生成列,存储生成列会将计算得到的值存储起来,而虚拟生成列不会存储其值。生成列可以用于从 JSON 数据类型中解出数据,并为该数据建立索引。在 INSERT 和 UPDATE 语句中,会检查生成列计算得到的值是否满足生成列的定义。生成列的局限性包括不能增加存储生成列,不能转换存储生成列为普通列,不能修改存储生成列的生成列表达式,以及不支持所有的 JSON 函数。 +--- + +# 生成列 + +本文介绍生成列的概念以及用法。 + +## 生成列的基本概念 + +与一般的列不同,生成列的值由列定义中表达式计算得到。对生成列进行插入或更新操作时,并不能对之赋值,只能使用 `DEFAULT`。 + +生成列包括存储生成列和虚拟生成列。存储生成列会将计算得到的值存储起来,在读取时不需要重新计算。虚拟生成列不会存储其值,在读取时会重新计算。存储生成列和虚拟生成列相比,前者在读取时性能更好,但是要占用更多的磁盘空间。 + +无论是存储生成列还是虚拟列,都可以在其上面建立索引。 + +## 生成列的应用 + +生成列的主要的作用之一:从 JSON 数据类型中解出数据,并为该数据建立索引。 + +MySQL 8.0 及 TiDB 都不能直接为 JSON 类型的列添加索引,即不支持在如下表结构中的 `address_info` 上建立索引: + +```sql +CREATE TABLE person ( + id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(255) NOT NULL, + address_info JSON, + KEY (address_info) +); +``` + +如果要为 JSON 列某个字段添加索引,可以抽取该字段为生成列。 + +以 `city` 这一 `address_info` 中的字段为例,可以为其建立一个虚拟生成列并添加索引: + +```sql +CREATE TABLE person ( + id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(255) NOT NULL, + address_info JSON, + city VARCHAR(64) AS (JSON_UNQUOTE(JSON_EXTRACT(address_info, '$.city'))), -- 虚拟生成列 + -- city VARCHAR(64) AS (JSON_UNQUOTE(JSON_EXTRACT(address_info, '$.city'))) VIRTUAL, -- 虚拟生成列 + -- city VARCHAR(64) AS (JSON_UNQUOTE(JSON_EXTRACT(address_info, '$.city'))) STORED, -- 存储生成列 + KEY (city) +); +``` + +该表中,`city` 列是一个虚拟生成列。并且在该列上建立了索引。以下语句能够利用索引加速语句的执行速度: + +```sql +SELECT name, id FROM person WHERE city = 'Beijing'; +``` + +```sql +EXPLAIN SELECT name, id FROM person WHERE city = 'Beijing'; +``` + +``` ++---------------------------------+---------+-----------+--------------------------------+-------------------------------------------------------------+ +| id | estRows | task | access object | operator info | ++---------------------------------+---------+-----------+--------------------------------+-------------------------------------------------------------+ +| Projection_4 | 10.00 | root | | test.person.name, test.person.id | +| └─IndexLookUp_10 | 10.00 | root | | | +| ├─IndexRangeScan_8(Build) | 10.00 | cop[tikv] | table:person, index:city(city) | range:["Beijing","Beijing"], keep order:false, stats:pseudo | +| └─TableRowIDScan_9(Probe) | 10.00 | cop[tikv] | table:person | keep order:false, stats:pseudo | ++---------------------------------+---------+-----------+--------------------------------+-------------------------------------------------------------+ +``` + +从执行计划中,可以看出使用了 `city` 这个索引来读取满足 `city = 'Beijing'` 这个条件的行的 `HANDLE`,再用这个 `HANDLE` 来读取该行的数据。 + +如果 `$.city` 路径中无数据,则 `JSON_EXTRACT` 返回 `NULL`。如果想增加约束,`city` 列必须是 `NOT NULL`,则可按照以下方式定义虚拟生成列: + +```sql +CREATE TABLE person ( + id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(255) NOT NULL, + address_info JSON, + city VARCHAR(64) AS (JSON_UNQUOTE(JSON_EXTRACT(address_info, '$.city'))) NOT NULL, + KEY (city) +); +``` + +## 生成列在 INSERT 和 UPDATE 语句中的行为 + +`INSERT` 和 `UPDATE` 语句都会检查生成列计算得到的值是否满足生成列的定义。未通过有效性检测的行会返回错误: + +```sql +INSERT INTO person (name, address_info) VALUES ('Morgan', JSON_OBJECT('Country', 'Canada')); +``` + +``` +ERROR 1048 (23000): Column 'city' cannot be null +``` + +## 索引生成列替换 + +当查询中出现的某个表达式与一个含索引的生成列严格同等时,TiDB 会将这个表达式替换为对应的生成列,这样就可以在生成查询计划时考虑使用这个索引。 + +下面的例子为 `a+1` 这个表达式创建生成列并添加索引,从而加速查询。其中,`a` 的列类型是 int,而 `a+1` 的列类型是 bigint。如果将生成列的类型改为 int,就不会发生替换。关于类型转换的规则,可以参见[表达式求值的类型转换](/functions-and-operators/type-conversion-in-expression-evaluation.md)。 + +```sql +create table t(a int); +desc select a+1 from t where a+1=3; +``` + +```sql ++---------------------------+----------+-----------+---------------+--------------------------------+ +| id | estRows | task | access object | operator info | ++---------------------------+----------+-----------+---------------+--------------------------------+ +| Projection_4 | 8000.00 | root | | plus(test.t.a, 1)->Column#3 | +| └─TableReader_7 | 8000.00 | root | | data:Selection_6 | +| └─Selection_6 | 8000.00 | cop[tikv] | | eq(plus(test.t.a, 1), 3) | +| └─TableFullScan_5 | 10000.00 | cop[tikv] | table:t | keep order:false, stats:pseudo | ++---------------------------+----------+-----------+---------------+--------------------------------+ +4 rows in set (0.00 sec) +``` + +```sql +alter table t add column b bigint as (a+1) virtual; +alter table t add index idx_b(b); +desc select a+1 from t where a+1=3; +``` + +```sql ++------------------------+---------+-----------+-------------------------+---------------------------------------------+ +| id | estRows | task | access object | operator info | ++------------------------+---------+-----------+-------------------------+---------------------------------------------+ +| IndexReader_6 | 10.00 | root | | index:IndexRangeScan_5 | +| └─IndexRangeScan_5 | 10.00 | cop[tikv] | table:t, index:idx_b(b) | range:[3,3], keep order:false, stats:pseudo | ++------------------------+---------+-----------+-------------------------+---------------------------------------------+ +2 rows in set (0.01 sec) +``` + +> **注意:** +> +> 若待替换的表达式类型和生成列类型都是字符类型,但两种类型长度不同时,仍可通过将系统变量 [`tidb_enable_unsafe_substitute`](/system-variables.md#tidb_enable_unsafe_substitute-从-v630-版本开始引入) 设置为 `ON` 来允许其替换。配置该系统变量时,需要保证生成列计算得到的值严格满足生成列的定义,否则,可能因为长度不同,导致数据截断得到错误的结果。详情见 GitHub issue [#35490](https://github.com/pingcap/tidb/issues/35490#issuecomment-1211658886)。 + +## 生成列的局限性 + +目前生成列有以下局限性: + +- 不能通过 `ALTER TABLE` 增加存储生成列; +- 不能通过 `ALTER TABLE` 将存储生成列转换为普通列,也不能将普通列转换成存储生成列; +- 不能通过 `ALTER TABLE` 修改存储生成列的生成列表达式; +- 并未支持所有的 [JSON 函数](/functions-and-operators/json-functions.md); +- 目前仅当生成列是虚拟生成列时索引生成列替换规则有效,暂不支持将表达式替换为存储生成列,但仍然可以通过直接使用该生成列本身来使用索引。 diff --git a/markdown-pages/zh/tidb/master/get-started-with-tidb-lightning.md b/markdown-pages/zh/tidb/master/get-started-with-tidb-lightning.md new file mode 100644 index 0000000..303a771 --- /dev/null +++ b/markdown-pages/zh/tidb/master/get-started-with-tidb-lightning.md @@ -0,0 +1,116 @@ +--- +title: TiDB Lightning 快速上手 +aliases: ['/docs-cn/dev/get-started-with-tidb-lightning/','/docs-cn/dev/how-to/get-started/tidb-lightning/'] +summary: TiDB Lightning 可快速将 MySQL 数据导入到 TiDB 集群中。首先使用 Dumpling 导出数据,然后部署 TiDB 集群。安装最新版本的 TiDB Lightning 并启动,最后检查数据导入情况。详细功能和使用请参考 TiDB Lightning 简介。 +--- + +# TiDB Lightning 快速上手 + +本文档介绍如何快速上手 TiDB Lightning,将 MySQL 数据导入到 TiDB 集群中。 + +> **警告:** +> +> 本教程中的部署方法只适用于测试及功能体验,并不适用于生产或开发环境。 + +## 第 1 步:准备全量备份数据 + +你可以使用 [Dumpling](/dumpling-overview.md) 从 MySQL 导出数据。 + +1. 运行 `tiup --version` 检查是否已安装 TiUP。如果已经安装 TiUP,跳过这一步。如果没有安装 TiUP,运行以下命令: + + ``` + curl --proto '=https' --tlsv1.2 -sSf https://tiup-mirrors.pingcap.com/install.sh | sh + ``` + +2. 使用 TiUP 安装 Dumpling: + + ```shell + tiup install dumpling + ``` + +3. 从 MySQL 导出数据,详细步骤可参考[使用 Dumpling 导出数据](/dumpling-overview.md#导出为-sql-文件): + + ```sh + tiup dumpling -h 127.0.0.1 -P 3306 -u root -t 16 -F 256MB -B test -f 'test.t[12]' -o /data/my_database/ + ``` + + 其中: + + - `-t 16`:使用 16 个线程导出数据。 + - `-F 256MB`:将每张表切分成多个文件,每个文件大小约为 256 MB。 + - `-B test`:从 `test` 数据库导出。 + - `-f 'test.t[12]'`:只导出 `test.t1` 和 `test.t2` 这两个表。 + + 导出的全量备份数据将保存在 `/data/my_database` 目录中。 + +## 第 2 步:部署 TiDB 集群 + +在开始导入数据之前,你需要先部署一个要进行导入的 TiDB 集群。如果你已经有 TiDB 集群,可以跳过这一步。 + +关于部署 TiDB 集群的步骤,请参考 [TiDB 数据库快速上手指南](/quick-start-with-tidb.md)。 + +## 第 3 步:安装 TiDB Lightning + +运行如下命令,安装 TiDB Lightning 的最新版本: + +```shell +tiup install tidb-lightning +``` + +## 第 4 步:启动 TiDB Lightning + +> **注意:** +> +> 本节的导入方法只适用于测试及功能体验,生产环境请参考[从大数据量 MySQL 迁移数据到 TiDB](/migrate-large-mysql-to-tidb.md#第-2-步导入全量数据到-tidb)。 + +1. 创建配置文件 `tidb-lightning.toml`,并根据你的集群信息填写如下配置: + + ```toml + [lightning] + # 日志 + level = "info" + file = "tidb-lightning.log" + + [tikv-importer] + # 选择使用的导入模式 + backend = "local" + # 设置排序的键值对的临时存放地址,目标路径需要是一个空目录 + sorted-kv-dir = "/mnt/ssd/sorted-kv-dir" + + [mydumper] + # 源数据目录。 + data-source-dir = "/data/my_datasource/" + + # 配置通配符规则,默认规则会过滤 mysql、sys、INFORMATION_SCHEMA、PERFORMANCE_SCHEMA、METRICS_SCHEMA、INSPECTION_SCHEMA 系统数据库下的所有表 + # 若不配置该项,导入系统表时会出现“找不到 schema”的异常 + filter = ['*.*', '!mysql.*', '!sys.*', '!INFORMATION_SCHEMA.*', '!PERFORMANCE_SCHEMA.*', '!METRICS_SCHEMA.*', '!INSPECTION_SCHEMA.*'] + [tidb] + # 目标集群的信息 + host = "172.16.31.2" + port = 4000 + user = "root" + password = "rootroot" + # 表架构信息在从 TiDB 的“状态端口”获取。 + status-port = 10080 + # 集群 pd 的地址。从 v7.6.0 开始支持设置多个地址。 + pd-addr = "172.16.31.3:2379,56.78.90.12:3456" + ``` + +2. 运行 `tidb-lightning`。为避免直接在命令行使用 `nohup` 启动程序时因 `SIGHUP` 信号导致的程序退出,建议将 `nohup` 命令放入脚本中。示例如下: + + ```shell + #!/bin/bash + nohup tiup tidb-lightning -config tidb-lightning.toml > nohup.out & + ``` + +### 第 5 步:检查数据 + +导入完毕后,TiDB Lightning 会自动退出。若导入成功,日志的最后一行会显示 `tidb lightning exit`。 + +如果出错,请参见 [TiDB Lightning 常见问题](/tidb-lightning/tidb-lightning-faq.md)。 + +## 总结 + +本教程对 TiDB Lightning 进行了简单的介绍,并快速部署了一套简单的 TiDB Lightning 集群,将全量备份数据导入到 TiDB 集群中。 + +关于 TiDB Lightning 的详细功能和使用,参见 [TiDB Lightning 简介](/tidb-lightning/tidb-lightning-overview.md)。 diff --git a/markdown-pages/zh/tidb/master/grafana-overview-dashboard.md b/markdown-pages/zh/tidb/master/grafana-overview-dashboard.md new file mode 100644 index 0000000..2163209 --- /dev/null +++ b/markdown-pages/zh/tidb/master/grafana-overview-dashboard.md @@ -0,0 +1,87 @@ +--- +title: Overview 面板重要监控指标详解 +aliases: ['/docs-cn/dev/grafana-overview-dashboard/','/docs-cn/dev/reference/key-monitoring-metrics/overview-dashboard/'] +summary: TiUP 部署 TiDB 集群时,一键部署监控系统 (Prometheus & Grafana)。Grafana Dashboard 分为 PD、TiDB、TiKV、Node_exporter、Overview、Performance_overview。重要监控指标包括服务在线节点数量、PD 角色、存储容量、Region 数量、TiDB 执行数量、CPU 使用率、内存大小、网络流量等。详细监控说明可参见文章。 +--- + +# Overview 面板重要监控指标详解 + +使用 TiUP 部署 TiDB 集群时,一键部署监控系统 (Prometheus & Grafana),监控架构参见 [TiDB 监控框架概述](/tidb-monitoring-framework.md)。 + +目前 Grafana Dashboard 整体分为 PD、TiDB、TiKV、Node\_exporter、Overview、Performance\_overview 等。 + +对于日常运维,我们单独挑选出重要的 Metrics 放在 Overview 页面,方便日常运维人员观察集群组件 (PD, TiDB, TiKV) 使用状态以及集群使用状态。 + +以下为 Overview Dashboard 监控说明: + +## Services Port Status + +- Services Up:各服务在线节点数量 + +## PD + +- PD role:当前 PD 的角色 +- Storage capacity:TiDB 集群总可用数据库空间大小 +- Current storage size:TiDB 集群目前已用数据库空间大小,TiKV 多副本的空间占用也会包含在内 +- Normal stores:处于正常状态的节点数目 +- Abnormal stores:处于异常状态的节点数目,正常情况应当为 0 +- Number of Regions:当前集群的 Region 总量,请注意 Region 数量与副本数无关 +- 99% completed\_cmds\_duration\_seconds:单位时间内,99% 的 pd-server 请求执行时间小于监控曲线的值,一般 <= 5ms +- Handle\_requests\_duration\_seconds:PD 发送请求的网络耗时 +- Region health:每个 Region 的状态,通常情况下,pending 的 peer 应该少于 100,miss 的 peer 不能一直大于 0 +- Hot write Region's leader distribution:每个 TiKV 实例上是写入热点的 leader 的数量 +- Hot read Region's leader distribution:每个 TiKV 实例上是读取热点的 leader 的数量 +- Region heartbeat report:TiKV 向 PD 发送的心跳个数 +- 99% Region heartbeat latency:99% 的情况下,心跳的延迟 + +## TiDB + +- Statement OPS:不同类型 SQL 语句每秒执行的数量。按 `SELECT`、`INSERT`、`UPDATE` 等来统计 +- Duration:执行的时间 + - 客户端网络请求发送到 TiDB,到 TiDB 执行结束后返回给客户端的时间。一般情况下,客户端请求都是以 SQL 语句的形式发送,但也可以包含 `COM_PING`、`COM_SLEEP`、`COM_STMT_FETCH`、`COM_SEND_LONG_DATA` 之类的命令执行的时间 + - 由于 TiDB 支持 Multi-Query,因此,可以接受客户端一次性发送的多条 SQL 语句,如:`select 1; select 1; select 1;`。此时,统计的执行时间是所有 SQL 执行完之后的总时间 +- CPS By Instance:每个 TiDB 实例上的命令统计。按照命令和执行结果成功或失败来统计 +- Failed Query OPM:每个 TiDB 实例上,每秒钟执行 SQL 语句发生错误按照错误类型的统计(例如语法错误、主键冲突等)。包含了错误所属的模块和错误码 +- Connection count:每个 TiDB 的连接数 +- Memory Usage:每个 TiDB 实例的内存使用统计,分为进程占用内存和 Golang 在堆上申请的内存 +- Transaction OPS:每秒事务执行数量统计 +- Transaction Duration:事务执行的时间 +- KV Cmd OPS:KV 命令执行数量统计 +- KV Cmd Duration 99:KV 命令执行的时间 +- PD TSO OPS:TiDB 每秒从 PD 获取 TSO 的数量 +- PD TSO Wait Duration:TiDB 等待从 PD 获取 TS 的时间 +- TiClient Region Error OPS:TiKV 返回 Region 相关错误信息的数量 +- Lock Resolve OPS:TiDB 清理锁操作的数量。当 TiDB 的读写请求遇到锁时,会尝试进行锁清理 +- Load Schema Duration:TiDB 从 TiKV 获取 Schema 的时间 +- KV Backoff OPS:TiKV 返回错误信息的数量 + +## TiKV + +- leader:各个 TiKV 节点上 Leader 的数量分布 +- region:各个 TiKV 节点上 Region 的数量分布 +- CPU:各个 TiKV 节点的 CPU 使用率 +- Memory:各个 TiKV 节点的内存使用量 +- store size:每个 TiKV 实例的使用的存储空间的大小 +- cf size:每个列族的大小 +- channel full:每个 TiKV 实例上 channel full 错误的数量,正常情况下应当为 0 +- server report failures:每个 TiKV 实例上报错的消息个数,正常情况下应当为 0 +- scheduler pending commands:每个 TiKV 实例上 pending 命令的个数 +- coprocessor executor count:TiKV 每秒收到的 coprocessor 操作数量,按照 coprocessor 类型统计 +- coprocessor request duration:处理 coprocessor 读请求所花费的时间 +- raft store CPU:raftstore 线程的 CPU 使用率,线程数量默认为 2(通过 `raftstore.store-pool-size` 配置)。如果单个线程使用率超过 80%,说明使用率很高 +- Coprocessor CPU:coprocessor 线程的 CPU 使用率 + +## System Info + +- Vcores:CPU 核心数量 +- Memory:内存总大小 +- CPU Usage:CPU 使用率,最大为 100% +- Load [1m]:1 分钟的负载情况 +- Memory Available:剩余内存大小 +- Network Traffic:网卡流量统计 +- TCP Retrans:TCP 重传数量统计 +- IO Util:磁盘使用率,最高为 100%,一般到 80% - 90% 就需要考虑加节点 + +## 图例 + +![overview](/media/grafana_monitor_overview.png) diff --git a/markdown-pages/zh/tidb/master/grafana-pd-dashboard.md b/markdown-pages/zh/tidb/master/grafana-pd-dashboard.md new file mode 100644 index 0000000..6fdf0c3 --- /dev/null +++ b/markdown-pages/zh/tidb/master/grafana-pd-dashboard.md @@ -0,0 +1,156 @@ +--- +title: PD 重要监控指标详解 +aliases: ['/docs-cn/dev/grafana-pd-dashboard/','/docs-cn/dev/reference/key-monitoring-metrics/pd-dashboard/'] +summary: PD 重要监控指标详解:使用 TiUP 部署 TiDB 集群时,一键部署监控系统 (Prometheus & Grafana),监控架构参见 [TiDB 监控框架概述]。Grafana Dashboard 分为 PD、TiDB、TiKV、Node_exporter、Overview、Performance_overview 等。通过观察 PD 面板上的 Metrics,可以了解 PD 当前的状态。监控包括 PD role、Storage capacity、Current storage size、Current storage usage、Normal stores、Number of Regions、Abnormal stores、Region health、Current peer count 等。Cluster、Operator、Statistics - Balance、Statistics - hot write、Statistics - hot read、Scheduler、gRPC、etcd、TiDB、Heartbeat、Region storage 等指标也很重要。 +--- + +# PD 重要监控指标详解 + +使用 TiUP 部署 TiDB 集群时,一键部署监控系统 (Prometheus & Grafana),监控架构参见 [TiDB 监控框架概述](/tidb-monitoring-framework.md)。 + +目前 Grafana Dashboard 整体分为 PD、TiDB、TiKV、Node\_exporter、Overview、Performance\_overview 等。 + +对于日常运维,我们通过观察 PD 面板上的 Metrics,可以了解 PD 当前的状态。 + +以下为 PD Dashboard 监控说明: + +- PD role:当前 PD 的角色 +- Storage capacity:TiDB 集群总可用数据库空间大小 +- Current storage size:TiDB 集群目前已用数据库空间大小 +- Current storage usage:TiDB 集群存储空间的使用率 +- Normal stores:处于正常状态的节点数目 +- Number of Regions:当前集群的 Region 总量 +- Abnormal stores:处于异常状态的节点数目,正常情况应当为 0 +- Region health:集群所有 Region 的状态。通常情况下,pending 或 down 的 peer 应该少于 100,miss 的 peer 不能一直大于 0,empty Region 过多需及时打开 Region Merge +- Current peer count:当前集群 peer 的总量 +![PD Dashboard - Header](/media/pd-dashboard-header-v4.png) + +## Cluster + +- PD scheduler config:PD 调度配置列表 +- Cluster ID:集群的 cluster id,唯一标识 +- Current TSO:当前分配 TSO 的物理时间戳部分 +- Current ID allocation:当前可分配 ID 的最大值 +- Region label isolation level:不同 label 所在的 level 的 Region 数量 +- Label distribution:集群中 TiKV 节点的 label 分布情况 +- Store Limit:Store 的调度限流状态 + +![PD Dashboard - Cluster metrics](/media/pd-dashboard-cluster-v4.png) + +## Operator + +- Schedule operator create:新创建的不同 operator 的数量,单位 opm 代表一分钟内创建的个数 +- Schedule operator check:已检查的 operator 的次数,主要检查是否当前步骤已经执行完成,如果是,则执行下一个步骤 +- Schedule operator finish:已完成调度的 operator 的数量 +- Schedule operator timeout:已超时的 operator 的数量 +- Schedule operator replaced or canceled:已取消或者被替换的 operator 的数量 +- Schedule operators count by state:不同状态的 operator 的数量 +- Operator finish duration:已完成的 operator 所花费的最长时间 +- Operator step duration:已完成的 operator 的步骤所花费的最长时间 + +![PD Dashboard - Operator metrics](/media/pd-dashboard-operator-v4.png) + +## Statistics - Balance + +- Store capacity:每个 TiKV 实例的总的空间大小 +- Store available:每个 TiKV 实例的可用空间大小 +- Store used:每个 TiKV 实例的已使用空间大小 +- Size amplification:每个 TiKV 实例的空间放大比率 +- Size available ratio:每个 TiKV 实例的可用空间比率 +- Store leader score:每个 TiKV 实例的 leader 分数 +- Store Region score:每个 TiKV 实例的 Region 分数 +- Store leader size:每个 TiKV 实例上所有 leader 的大小 +- Store Region size:每个 TiKV 实例上所有 Region 的大小 +- Store leader count:每个 TiKV 实例上所有 leader 的数量 +- Store Region count:每个 TiKV 实例上所有 Region 的数量 + +![PD Dashboard - Balance metrics](/media/pd-dashboard-balance-v4.png) + +## Statistics - hot write + +- Hot Region's leader distribution:每个 TiKV 实例上成为写入热点的 leader 的数量 +- Total written bytes on hot leader Regions:每个 TiKV 实例上所有成为写入热点的 leader 的总的写入流量大小 +- Hot write Region's peer distribution:每个 TiKV 实例上成为写入热点的 peer 的数量 +- Total written bytes on hot peer Regions:每个 TiKV 实例上所有成为写入热点的 peer 的写入流量大小 +- Store Write rate bytes:每个 TiKV 实例总的写入的流量 +- Store Write rate keys:每个 TiKV 实例总的写入 keys +- Hot cache write entry number:每个 TiKV 实例进入热点统计模块的 peer 的数量 +- Selector events:热点调度中选择器的事件发生次数 +- Direction of hotspot move leader:热点调度中 leader 的调度方向,正数代表调入,负数代表调出 +- Direction of hotspot move peer:热点调度中 peer 的调度方向,正数代表调入,负数代表调出 + +![PD Dashboard - Hot write metrics](/media/pd-dashboard-hotwrite-v4.png) + +## Statistics - hot read + +- Hot Region's peer distribution:每个 TiKV 实例上成为读取热点的 peer 的数量 +- Total read bytes on hot peer Regions:每个 TiKV 实例上所有成为读取热点的 peer 的总的读取流量大小 +- Store read rate bytes:每个 TiKV 实例总的读取的流量 +- Store read rate keys:每个 TiKV 实例总的读取 keys +- Hot cache read entry number:每个 TiKV 实例进入热点统计模块的 peer 的数量 + +![PD Dashboard - Hot read metrics](/media/pd-dashboard-hotread-v4.png) + +## Scheduler + +- Scheduler is running:所有正在运行的 scheduler +- Balance leader movement:leader 移动的详细情况 +- Balance Region movement:Region 移动的详细情况 +- Balance leader event:balance leader 的事件数量 +- Balance Region event:balance Region 的事件数量 +- Balance leader scheduler:balance-leader scheduler 的状态 +- Balance Region scheduler:balance-region scheduler 的状态 +- Replica checker:replica checker 的状态 +- Rule checker:rule checker 的状态 +- Region merge checker:merge checker 的状态 +- Filter target:尝试选择 Store 作为调度 taget 时没有通过 Filter 的计数 +- Filter source:尝试选择 Store 作为调度 source 时没有通过 Filter 的计数 +- Balance Direction:Store 被选作调度 target 或 source 的次数 + +![PD Dashboard - Scheduler metrics](/media/pd-dashboard-scheduler-v4.png) + +## gRPC + +- Completed commands rate:gRPC 命令的完成速率 +- 99% Completed commands duration:99% 命令的最长消耗时间 + +![PD Dashboard - gRPC metrics](/media/pd-dashboard-grpc-v2.png) + +## etcd + +- Handle transactions count:etcd 的事务个数 +- 99% Handle transactions duration:99% 的情况下,处理 etcd 事务所需花费的时间 +- 99% WAL fsync duration:99% 的情况下,持久化 WAL 所需花费的时间,这个值通常应该小于 1s +- 99% Peer round trip time seconds:99% 的情况下,etcd 的网络延时,这个值通常应该小于 1s +- etcd disk WAL fsync rate:etcd 持久化 WAL 的速率 +- Raft term:当前 Raft 的 term +- Raft committed index:最后一次 commit 的 Raft index +- Raft applied index:最后一次 apply 的 Raft index + +![PD Dashboard - etcd metrics](/media/pd-dashboard-etcd-v2.png) + +## TiDB + +- PD Server TSO handle time and Client recv time:从 PD 开始处理 TSO 请求到 client 端接收到 TSO 的总耗时 +- Handle requests count:TiDB 的请求数量 +- Handle requests duration:每个请求所花费的时间,99% 的情况下,应该小于 100ms + +![PD Dashboard - TiDB metrics](/media/pd-dashboard-tidb-v4.png) + +## Heartbeat + +- Heartbeat region event QPS:心跳处理 region 的 QPS,包括更新缓存和持久化 +- Region heartbeat report:TiKV 向 PD 发送的心跳个数 +- Region heartbeat report error:TiKV 向 PD 发送的异常的心跳个数 +- Region heartbeat report active:TiKV 向 PD 发送的正常的心跳个数 +- Region schedule push:PD 向 TiKV 发送的调度命令的个数 +- 99% Region heartbeat latency:99% 的情况下,心跳的延迟 + +![PD Dashboard - Heartbeat metrics](/media/pd-dashboard-heartbeat-v4.png) + +## Region storage + +- Syncer Index:Leader 记录 Region 变更历史的最大 index +- history last index:Follower 成功同步的 Region 变更历史的 index + +![PD Dashboard - Region storage](/media/pd-dashboard-region-storage.png) diff --git a/markdown-pages/zh/tidb/master/hardware-and-software-requirements.md b/markdown-pages/zh/tidb/master/hardware-and-software-requirements.md new file mode 100644 index 0000000..29872d4 --- /dev/null +++ b/markdown-pages/zh/tidb/master/hardware-and-software-requirements.md @@ -0,0 +1,208 @@ +--- +title: TiDB 软件和硬件环境建议配置 +aliases: ['/docs-cn/dev/hardware-and-software-requirements/','/docs-cn/dev/how-to/deploy/hardware-recommendations/'] +summary: TiDB 是一款开源的一站式实时 HTAP 数据库,支持部署在多种硬件环境和操作系统上。软件和硬件环境建议配置包括操作系统要求、编译和运行依赖库、Docker 镜像依赖、软件配置要求、服务器建议配置、网络要求、磁盘空间要求、客户端 Web 浏览器要求以及 TiFlash 存算分离架构的软硬件要求。 +--- + +# TiDB 软件和硬件环境建议配置 + + + +TiDB 作为一款开源一栈式实时 HTAP 数据库,可以很好地部署和运行在 Intel 架构服务器环境、ARM 架构的服务器环境及主流虚拟化环境,并支持绝大多数的主流硬件网络。作为一款高性能数据库系统,TiDB 支持主流的 Linux 操作系统环境。 + +## 操作系统及平台要求 + +| 操作系统 | 支持的 CPU 架构 | +| :--- | :--- | +| Red Hat Enterprise Linux 8.4 及以上的 8.x 版本 |
  • x86_64
  • ARM 64
| +|
  • Red Hat Enterprise Linux 7.3 及以上的 7.x 版本
  • CentOS 7.3 及以上的 7.x 版本
|
  • x86_64
  • ARM 64
| +| Amazon Linux 2 |
  • x86_64
  • ARM 64
| +| Rocky Linux 9.1 及以上的版本 |
  • x86_64
  • ARM 64
| +| 麒麟欧拉版 V10 SP1/SP2 |
  • x86_64
  • ARM 64
| +| 统信操作系统 (UOS) V20 |
  • x86_64
  • ARM 64
| +| openEuler 22.03 LTS SP1 |
  • x86_64
  • ARM 64
| +| macOS 12 (Monterey) 及以上的版本 |
  • x86_64
  • ARM 64
| +| Oracle Enterprise Linux 8 及以上的版本 | x86_64 | +| Ubuntu LTS 20.04 及以上的版本 | x86_64 | +| CentOS 8 Stream |
  • x86_64
  • ARM 64
| +| Debian 10 (Buster) 及以上的版本 | x86_64 | +| Fedora 38 及以上的版本 | x86_64 | +| openSUSE Leap 15.5 以上的版本(不包含 Tumbleweed) | x86_64 | +| SUSE Linux Enterprise Server 15 | x86_64 | + +> **注意:** +> +> - TiDB 只支持 Red Hat 兼容内核 (RHCK) 的 Oracle Enterprise Linux,不支持 Oracle Enterprise Linux 提供的 Unbreakable Enterprise Kernel。 +> - 根据 [CentOS Linux EOL](https://www.centos.org/centos-linux-eol/),CentOS Linux 8 的上游支持已于 2021 年 12 月 31 日终止,但 CentOS 将继续提供对 CentOS Stream 8 的支持。 +> - TiDB 将不再支持 Ubuntu 16.04。强烈建议升级到 Ubuntu 18.04 或更高版本。 +> - 对于以上表格中所列操作系统的 32 位版本,TiDB 在这些 32 位操作系统以及对应的 CPU 架构上**不保障**可编译、可构建以及可部署,或 TiDB 不主动适配这些 32 位的操作系统。 +> - 以上未提及的操作系统版本**也许可以**运行 TiDB,但尚未得到 TiDB 官方支持。 + +### 编译和运行 TiDB 所依赖的库 + +| 编译和构建 TiDB 所需的依赖库 | 版本 | +| :--- | :--- | +| Golang | 1.21 及以上版本 | +| Rust | nightly-2022-07-31 及以上版本 | +| GCC | 7.x | +| LLVM | 13.0 及以上版本 | + +运行时所需的依赖库:glibc(2.28-151.el8 版本) + +### Docker 镜像依赖 + +支持的 CPU 架构如下: + +- x86_64,从 TiDB v6.6.0 开始,需要 [x86-64-v2 指令集](https://developers.redhat.com/blog/2021/01/05/building-red-hat-enterprise-linux-9-for-the-x86-64-v2-microarchitecture-level) +- ARM 64 + +## 软件配置要求 + +### 中控机软件配置 + +| 软件 | 版本 | +| :----------------------- | :----------: | +| sshpass | 1.06 及以上 | +| TiUP | 1.5.0 及以上 | + +> **注意:** +> +> 中控机需要部署 [TiUP 软件](/tiup/tiup-documentation-guide.md)来完成 TiDB 集群运维管理。 + +### 目标主机建议配置软件 + +| 软件 | 版本 | +| :----- | :----------: | +| sshpass | 1.06 及以上 | +| numa | 2.0.12 及以上 | +| tar | 任意 | + +## 服务器建议配置 + +TiDB 支持部署和运行在 Intel x86-64 架构的 64 位通用硬件服务器平台或者 ARM 架构的硬件服务器平台。对于开发、测试及生产环境的服务器硬件配置(不包含操作系统 OS 本身的占用)有以下要求和建议: + +### 开发及测试环境 + +| **组件** | **CPU** | **内存** | **本地存储** | **网络** | **实例数量(最低要求)** | +| --- | --- | --- | --- | --- | --- | +| TiDB | 8 核+ | 16 GB+ | [磁盘空间要求](#磁盘空间要求) | 千兆网卡 | 1(可与 PD 同机器) | +| PD | 4 核+ | 8 GB+ | SAS, 200 GB+ | 千兆网卡 | 1(可与 TiDB 同机器) | +| TiKV | 8 核+ | 32 GB+ | SSD, 200 GB+ | 千兆网卡 | 3 | +| TiFlash | 32 核+ | 64 GB+ | SSD, 200 GB+ | 千兆网卡 | 1 | +| TiCDC | 8 核+ | 16 GB+ | SAS, 200 GB+ | 千兆网卡 | 1 | + +> **注意:** +> +> - 验证测试环境中的 TiDB 和 PD 可以部署在同一台服务器上。 +> - 如进行性能相关的测试,避免采用低性能存储和网络硬件配置,防止对测试结果的正确性产生干扰。 +> - TiKV 的 SSD 盘推荐使用 NVME 接口以保证读写更快。 +> - 如果仅验证功能,建议使用 [TiDB 数据库快速上手指南](/quick-start-with-tidb.md)进行单机功能测试。 +> - 从 v6.3.0 开始,在 Linux AMD64 架构的硬件平台部署 TiFlash 时,CPU 必须支持 AVX2 指令集。确保命令 `cat /proc/cpuinfo | grep avx2` 有输出。而在 Linux ARM64 架构的硬件平台部署 TiFlash 时,CPU 必须支持 ARMv8 架构。确保命令 `cat /proc/cpuinfo | grep 'crc32' | grep 'asimd'` 有输出。通过使用向量扩展指令集,TiFlash 的向量化引擎能提供更好的性能。 + +### 生产环境 + +| **组件** | **CPU** | **内存** | **硬盘类型** | **网络** | **实例数量(最低要求)** | +| --- | --- | --- | --- | --- | --- | +| TiDB | 16 核+ | 48 GB+ | SSD | 万兆网卡(2 块最佳) | 2 | +| PD | 8 核+ | 16 GB+ | SSD | 万兆网卡(2 块最佳) | 3 | +| TiKV | 16 核+ | 64 GB+ | SSD | 万兆网卡(2 块最佳) | 3 | +| TiFlash | 48 核+ | 128 GB+ | 1 or more SSDs | 万兆网卡(2 块最佳) | 2 | +| TiCDC | 16 核+ | 64 GB+ | SSD | 万兆网卡(2 块最佳) | 2 | +| 监控 | 8 核+ | 16 GB+ | SAS | 千兆网卡 | 1 | + +> **注意:** +> +> - 生产环境中的 TiDB 和 PD 可以部署和运行在同一台服务器上,如对性能和可靠性有更高的要求,应尽可能分开部署。 +> - 强烈建议分别为生产环境中的 TiDB、TiKV 和 TiFlash 配置至少 8 核的 CPU。强烈推荐使用更高的配置,以获得更好的性能。 +> - TiKV 硬盘大小配置建议 PCIe SSD 不超过 4 TB,普通 SSD 不超过 1.5 TB。 +> - TiFlash 支持[多盘部署](/tiflash/tiflash-configuration.md#多盘部署)。 +> - TiFlash 数据目录的第一块磁盘推荐用高性能 SSD 来缓冲 TiKV 同步数据的实时写入,该盘性能应不低于 TiKV 所使用的磁盘,比如 PCIe SSD。并且该磁盘容量建议不小于总容量的 10%,否则它可能成为这个节点的能承载的数据量的瓶颈。而其他磁盘可以根据需求部署多块普通 SSD,当然更好的 PCIe SSD 硬盘会带来更好的性能。 +> - TiFlash 推荐与 TiKV 部署在不同节点,如果条件所限必须将 TiFlash 与 TiKV 部署在相同节点,则需要适当增加 CPU 核数和内存,且尽量将 TiFlash 与 TiKV 部署在不同的磁盘,以免互相干扰。 +> - TiFlash 硬盘总容量大致为:`整个 TiKV 集群的需同步数据容量 / TiKV 副本数 * TiFlash 副本数`。例如整体 TiKV 的规划容量为 1 TB、TiKV 副本数为 3、TiFlash 副本数为 2,则 TiFlash 的推荐总容量为 `1024 GB / 3 * 2`。用户可以选择同步部分表数据而非全部,具体容量可以根据需要同步的表的数据量具体分析。 +> - TiCDC 硬盘配置建议 500 GB+ PCIe SSD。 + +## 网络要求 + + + +TiDB 作为开源一栈式实时 HTAP 数据库,其正常运行需要网络环境提供如下的网络端口配置要求,管理员可根据实际环境中 TiDB 组件部署的方案,在网络侧和主机侧开放相关端口: + +| 组件 | 默认端口 | 说明 | +| :-- | :-- | :-- | +| TiDB | 4000 | 应用及 DBA 工具访问通信端口 | +| TiDB | 10080 | TiDB 状态信息上报通信端口 | +| TiKV | 20160 | TiKV 通信端口 | +| TiKV | 20180 | TiKV 状态信息上报通信端口 | +| PD | 2379 | 提供 TiDB 和 PD 通信端口 | +| PD | 2380 | PD 集群节点间通信端口 | +|TiFlash|9000|TiFlash TCP 服务端口| +|TiFlash|3930|TiFlash RAFT 服务和 Coprocessor 服务端口| +|TiFlash|20170|TiFlash Proxy 服务端口| +|TiFlash|20292|Prometheus 拉取 TiFlash Proxy metrics 端口| +|TiFlash|8234|Prometheus 拉取 TiFlash metrics 端口| +| Pump | 8250 | Pump 通信端口 | +| Drainer | 8249 | Drainer 通信端口 | +| CDC | 8300 | CDC 通信接口 | +| Monitoring | 9090 | Prometheus 服务通信端口 | +| Monitoring | 12020 | NgMonitoring 服务通信端口 | +| Node_exporter | 9100 | TiDB 集群每个节点的系统信息上报通信端口 | +| Blackbox_exporter | 9115 | Blackbox_exporter 通信端口,用于 TiDB 集群端口监控 | +| Grafana | 3000 | Web 监控服务对外服务和客户端(浏览器)访问端口 | +| Alertmanager | 9093 | 告警 web 服务端口 | +| Alertmanager | 9094 | 告警通信端口 | + +## 磁盘空间要求 + +| 组件 | 磁盘空间要求 | 健康水位使用率 | +| :-- | :-- | :-- | +| TiDB |
  • 日志盘建议最少预留 30 GB。
  • v6.5.0 及以上版本默认启用了 Fast Online DDL 对添加索引等 DDL 操作进行加速(通过变量 [`tidb_ddl_enable_fast_reorg`](/system-variables.md#tidb_ddl_enable_fast_reorg-从-v630-版本开始引入) 控制)。如果业务中可能存在针对大对象的 DDL 操作,或需要使用 [IMPORT INTO](/sql-statements/sql-statement-import-into.md) SQL 语句导入数据,推荐为 TiDB 准备额外的 SSD 磁盘空间(建议 100 GB+)。配置方式详见[设置 TiDB 节点的临时空间](/check-before-deployment.md#设置-tidb-节点的临时空间推荐)。
| 低于 90% | +| PD | 数据盘和日志盘建议最少各预留 20 GB | 低于 90% | +| TiKV | 数据盘和日志盘建议最少各预留 100 GB | 低于 80% | +| TiFlash | 数据盘建议最少预留 100 GB,日志盘建议最少预留 30 GB | 低于 80% | +| TiUP |
  • 中控机:部署一个版本的 TiDB 集群占用不超过 1 GB 空间,部署多个版本集群所占用的空间会相应增加
  • 部署服务器(实际运行 TiDB 各组件的机器):TiFlash 占用约 700 MB 空间,其他组件(PD、TiDB、TiKV 等)各占用约 200 MB 空间。同时,部署过程会占用小于 1 MB 临时空间(/tmp)存放临时文件
| 不涉及| +| Ngmonitoring |
  • Conprof:3 x 1 GB x 组件数量(表示每个组件每天占用约 1 GB,总共 3 天) + 20 GB 预留空间
  • Top SQL:30 x 50 MB x 组件数量(每个组件每天占用约 50 MB,总共 30 天)
  • Top SQL 和 Conprof 共享预留空间
| 不涉及 | + +## 客户端 Web 浏览器要求 + +TiDB 提供了基于 [Grafana](https://grafana.com/) 的技术平台,对数据库集群的各项指标进行可视化展现。采用支持 Javascript 的微软 Edge、Apple Safari、Google Chrome、Mozilla Firefox 的较新版本即可访问监控入口。 + +## TiFlash 存算分离架构的软硬件要求 + +上面的 TiFlash 软硬件要求是针对存算一体架构的。从 v7.0.0 开始,TiFlash 支持[存算分离架构](/tiflash/tiflash-disaggregated-and-s3.md),该架构下 TiFlash 分为 Write Node 和 Compute Node 两个角色,对应的软硬件要求如下: + +- 软件:与存算一体架构一致,详见[操作系统及平台要求](#操作系统及平台要求)。 +- 网络端口:与存算一体架构一致,详见[网络要求](#网络要求)。 +- 磁盘空间: + - TiFlash Write Node:推荐 200 GB+,用作增加 TiFlash 副本、Region 副本迁移时向 Amazon S3 上传数据前的本地缓冲区。此外,还需要一个与 Amazon S3 兼容的对象存储。 + - TiFlash Compute Node:推荐 100 GB+,主要用于缓存从 Write Node 读取的数据以提升性能。Compute Node 的缓存可能会被完全使用,这是正常现象。 +- CPU 以及内存等要求参考下文。 + +### 开发及测试环境 + +| 组件 | CPU | 内存 | 本地存储 | 网络 | 实例数量(最低要求) | +| --- | --- | --- | --- | --- | --- | +| TiFlash Write Node | 16 核+ | 32 GB+ | SSD, 200 GB+ | 千兆网卡 | 1 | +| TiFlash Compute Node | 16 核+ | 32 GB+ | SSD, 100 GB+ | 千兆网卡 | 0(参见下文“注意”说明) | + +### 生产环境 + +| 组件 | CPU | 内存 | 硬盘类型 | 网络 | 实例数量(最低要求) | +| --- | --- | --- | --- | --- | --- | +| TiFlash Write Node | 32 核+ | 64 GB+ | SSD, 200 GB+ | 万兆网卡(2 块最佳) | 2 | +| TiFlash Compute Node | 32 核+ | 64 GB+ | SSD, 100 GB+ | 万兆网卡(2 块最佳) | 0(参见下文“注意”说明) | + +> **注意:** +> +> TiFlash Compute Node 可以使用 TiUP 等部署工具快速扩缩容,扩缩容范围是 `[0, +inf]`。 diff --git a/markdown-pages/zh/tidb/master/identify-expensive-queries.md b/markdown-pages/zh/tidb/master/identify-expensive-queries.md new file mode 100644 index 0000000..41bc091 --- /dev/null +++ b/markdown-pages/zh/tidb/master/identify-expensive-queries.md @@ -0,0 +1,53 @@ +--- +title: 定位消耗系统资源多的查询 +aliases: ['/docs-cn/dev/identify-expensive-queries/','/docs-cn/dev/how-to/maintain/identify-abnormal-queries/identify-expensive-queries/','/docs-cn/how-to/maintain/identify-abnormal-queries/identify-aborted-queries/','/docs-cn/dev/how-to/maintain/identify-abnormal-queries/identify-aborted-queries/'] +summary: TiDB 会将执行时间超过 tidb_expensive_query_time_threshold 限制(默认值为 60s),或使用内存超过 tidb_mem_quota_query 限制(默认值为 1 GB)的语句输出到 tidb-server 日志文件中,用于定位消耗系统资源多的查询语句。expensive query 日志和慢查询日志的区别在于,expensive query 日志可以将正在执行的语句的相关信息打印出来。当一条语句在执行过程中达到资源使用阈值时,TiDB 会即时将这条语句的相关信息写入日志。 +--- + +# 定位消耗系统资源多的查询 + +TiDB 会将执行时间超过 [`tidb_expensive_query_time_threshold`](/system-variables.md#tidb_expensive_query_time_threshold) 限制(默认值为 60s),或使用内存超过 [`tidb_mem_quota_query`](/system-variables.md#tidb_mem_quota_query) 限制(默认值为 1 GB)的语句输出到 [tidb-server 日志文件](/tidb-configuration-file.md#logfile)(默认文件为 "tidb.log")中,用于在语句执行结束前定位消耗系统资源多的查询语句(以下简称为 expensive query),帮助用户分析和解决语句执行的性能问题。 + +注意,expensive query 日志和[慢查询日志](/identify-slow-queries.md)的区别是,慢查询日志是在语句执行完后才打印,expensive query 日志可以将正在执行的语句的相关信息打印出来。当一条语句在执行过程中达到资源使用阈值时(执行时间/使用内存量),TiDB 会即时将这条语句的相关信息写入日志。 + +## Expensive query 日志示例 + +```sql +[2020/02/05 15:32:25.096 +08:00] [WARN] [expensivequery.go:167] [expensive_query] [cost_time=60.008338935s] [wait_time=0s] [request_count=1] [total_keys=70] [process_keys=65] [num_cop_tasks=1] [process_avg_time=0s] [process_p90_time=0s] [process_max_time=0s] [process_max_addr=10.0.1.9:20160] [wait_avg_time=0.002s] [wait_p90_time=0.002s] [wait_max_time=0.002s] [wait_max_addr=10.0.1.9:20160] [stats=t:pseudo] [conn_id=60026] [user=root] [database=test] [table_ids="[122]"] [txn_start_ts=414420273735139329] [mem_max="1035 Bytes (1.0107421875 KB)"] [sql="insert into t select sleep(1) from t"] +``` + +## 字段含义说明 + +基本字段: + +* `cost_time`:日志打印时语句已经花费的执行时间。 +* `stats`:语句涉及到的表或索引使用的统计信息版本。值为 `pseudo` 时表示无可用统计信息,需要对表或索引进行 analyze。 +* `table_ids`:语句涉及到的表的 ID。 +* `txn_start_ts`:事务的开始时间戳,也是事务的唯一 ID,可以用这个值在 TiDB 日志中查找事务相关的其他日志。 +* `sql`:SQL 语句。 + +和内存使用相关的字段: + +* `mem_max`:日志打印时语句已经使用的内存空间。该项使用两种单位标识内存使用量,分别为 Bytes 以及易于阅读的自适应单位(比如 MB、GB 等)。 + +和 SQL 执行的用户相关的字段: + +* `user`:执行语句的用户名。 +* `conn_id`:用户的连接 ID,可以用类似 `con:60026` 的关键字在 TiDB 日志中查找该连接相关的其他日志。 +* `database`:执行语句时使用的 database。 + +和 TiKV Coprocessor Task 相关的字段: + +* `wait_time`:该语句在 TiKV 的等待时间之和,因为 TiKV 的 Coprocessor 线程数是有限的,当所有的 Coprocessor 线程都在工作的时候,请求会排队;当队列中有某些请求耗时很长的时候,后面的请求的等待时间都会增加。 +* `request_count`:该语句发送的 Coprocessor 请求的数量。 +* `total_keys`:Coprocessor 扫过的 key 的数量。 +* `processed_keys`:Coprocessor 处理的 key 的数量。与 total_keys 相比,processed_keys 不包含 MVCC 的旧版本。如果 processed_keys 和 total_keys 相差很大,说明旧版本比较多。 +* `num_cop_tasks`:该语句发送的 Coprocessor 请求的数量。 +* `process_avg_time`:Coprocessor 执行 task 的平均执行时间。 +* `process_p90_time`:Coprocessor 执行 task 的 P90 分位执行时间。 +* `process_max_time`:Coprocessor 执行 task 的最长执行时间。 +* `process_max_addr`:task 执行时间最长的 Coprocessor 所在地址。 +* `wait_avg_time`:Coprocessor 上 task 的等待时间。 +* `wait_p90_time`:Coprocessor 上 task 的 P90 分位等待时间。 +* `wait_max_time`:Coprocessor 上 task 的最长等待时间。 +* `wait_max_addr`:task 等待时间最长的 Coprocessor 所在地址。 diff --git a/markdown-pages/zh/tidb/master/information-schema/information-schema.md b/markdown-pages/zh/tidb/master/information-schema/information-schema.md new file mode 100644 index 0000000..2143beb --- /dev/null +++ b/markdown-pages/zh/tidb/master/information-schema/information-schema.md @@ -0,0 +1,103 @@ +--- +title: Information Schema +aliases: ['/docs-cn/dev/reference/system-databases/information-schema/','/docs-cn/dev/reference/system-databases/information-schema/','/docs-cn/dev/system-tables/system-table-information-schema/','/zh/tidb/dev/system-table-information-schema/'] +summary: Information Schema 是一种查看系统元数据的 ANSI 标准方法。TiDB 提供了许多自定义的 `INFORMATION_SCHEMA` 表,包括与 MySQL 兼容的表和 TiDB 中的扩展表。这些表提供了关于字符集、排序规则、列、存储引擎、索引、表大小、慢查询等信息,帮助用户进行系统监控和优化。 +--- + +# Information Schema + +Information Schema 提供了一种查看系统元数据的 ANSI 标准方法。除了包含与 MySQL 兼容的表外,TiDB 还提供了许多自定义的 `INFORMATION_SCHEMA` 表。 + +许多 `INFORMATION_SCHEMA` 表都有相应的 `SHOW` 命令。查询 `INFORMATION_SCHEMA` 的好处是可以在表之间进行 `join` 操作。 + +## 与 MySQL 兼容的表 + +| 表名 | 描述 | +| -------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- | +| [`CHARACTER_SETS`](/information-schema/information-schema-character-sets.md) | 提供 TiDB 支持的字符集列表。 | +| [`CHECK_CONSTRAINTS`](/information-schema/information-schema-check-constraints.md) | 提供关于表上 [`CHECK` 约束](/constraints.md#check-约束)的信息。 | +| [`COLLATIONS`](/information-schema/information-schema-collations.md) | 提供 TiDB 支持的排序规则列表。 | +| [`COLLATION_CHARACTER_SET_APPLICABILITY`](/information-schema/information-schema-collation-character-set-applicability.md) | 说明哪些排序规则适用于哪些字符集。 | +| [`COLUMNS`](/information-schema/information-schema-columns.md) | 提供所有表中列的列表。 | +| `COLUMN_PRIVILEGES` | TiDB 未实现,返回零行。 | +| `COLUMN_STATISTICS` | TiDB 未实现,返回零行。 | +| [`ENGINES`](/information-schema/information-schema-engines.md) | 提供支持的存储引擎列表。 | +| `EVENTS` | TiDB 未实现,返回零行。 | +| `FILES` | TiDB 未实现,返回零行。 | +| `GLOBAL_STATUS` | TiDB 未实现,返回零行。 | +| `GLOBAL_VARIABLES` | TiDB 未实现,返回零行。 | +| [`KEYWORDS`](/information-schema/information-schema-keywords.md) | 提供关键字列表。 | +| [`KEY_COLUMN_USAGE`](/information-schema/information-schema-key-column-usage.md) | 描述列的键约束,例如主键约束。 | +| `OPTIMIZER_TRACE` | TiDB 未实现,返回零行。 | +| `PARAMETERS` | TiDB 未实现,返回零行。 | +| [`PARTITIONS`](/information-schema/information-schema-partitions.md) | 提供表分区的列表。 | +| `PLUGINS` | TiDB 未实现,返回零行。 | +| [`PROCESSLIST`](/information-schema/information-schema-processlist.md) | 提供与 `SHOW PROCESSLIST` 命令类似的信息。 | +| `PROFILING` | TiDB 未实现,返回零行。 | +| `REFERENTIAL_CONSTRAINTS` | 提供有关 `FOREIGN KEY` 约束的信息。 | +| `ROUTINES` | TiDB 未实现,返回零行。 | +| [`SCHEMATA`](/information-schema/information-schema-schemata.md) | 提供与 `SHOW DATABASES` 命令类似的信息。 | +| `SCHEMA_PRIVILEGES` | TiDB 未实现,返回零行。 | +| `SESSION_STATUS` | TiDB 未实现,返回零行。 | +| [`SESSION_VARIABLES`](/information-schema/information-schema-session-variables.md) | 提供与 `SHOW SESSION VARIABLES` 命令类似的功能。 | +| [`STATISTICS`](/information-schema/information-schema-statistics.md) | 提供有关表索引的信息。 | +| [`TABLES`](/information-schema/information-schema-tables.md) | 提供当前用户可见的表的列表。 类似于 `SHOW TABLES`。 | +| `TABLESPACES` | TiDB 未实现,返回零行。 | +| [`TABLE_CONSTRAINTS`](/information-schema/information-schema-table-constraints.md) | 提供有关主键、唯一索引和外键的信息。 | +| `TABLE_PRIVILEGES` | TiDB 未实现,返回零行。 | +| `TRIGGERS` | TiDB 未实现,返回零行。 | +| [`USER_ATTRIBUTES`](/information-schema/information-schema-user-attributes.md) | 汇总用户的注释和属性信息。 | +| [`USER_PRIVILEGES`](/information-schema/information-schema-user-privileges.md) | 汇总与当前用户相关的权限。 | +| [`VARIABLES_INFO`](/information-schema/information-schema-variables-info.md) | 提供 TiDB 系统变量的信息。 | +| [`VIEWS`](/information-schema/information-schema-views.md) | 提供当前用户可见的视图列表。类似于 `SHOW FULL TABLES WHERE table_type = 'VIEW'`。 | + +## TiDB 中的扩展表 + +| 表名 | 描述 | +| --------------------------------------------------------------------------------------- | -------------------------------------------------------------- | +| [`ANALYZE_STATUS`](/information-schema/information-schema-analyze-status.md) | 提供有关收集统计信息的任务的信息。 | +| [`CLIENT_ERRORS_SUMMARY_BY_HOST`](/information-schema/client-errors-summary-by-host.md) | 汇总由客户端请求生成并返回给客户端的错误和警告。 | +| [`CLIENT_ERRORS_SUMMARY_BY_USER`](/information-schema/client-errors-summary-by-user.md) | 汇总由客户端产生的错误和警告。 | +| [`CLIENT_ERRORS_SUMMARY_GLOBAL`](/information-schema/client-errors-summary-global.md) | 汇总由客户端产生的错误和警告。 | +| [`CLUSTER_CONFIG`](/information-schema/information-schema-cluster-config.md) | 提供有关整个 TiDB 集群的配置设置的详细信息。 | +| `CLUSTER_DEADLOCKS` | 提供 `DEADLOCKS` 表的集群级别的视图。 | +| [`CLUSTER_HARDWARE`](/information-schema/information-schema-cluster-hardware.md) | 提供在每个 TiDB 组件上发现的底层物理硬件的详细信息。 | +| [`CLUSTER_INFO`](/information-schema/information-schema-cluster-info.md) | 提供当前集群拓扑的详细信息。 | +| [`CLUSTER_LOAD`](/information-schema/information-schema-cluster-load.md) | 提供集群中 TiDB 服务器的当前负载信息。 | +| [`CLUSTER_LOG`](/information-schema/information-schema-cluster-log.md) | 提供整个 TiDB 集群的日志。 | +| `CLUSTER_MEMORY_USAGE` | 提供 `MEMORY_USAGE` 表的集群级别的视图。 | +| `CLUSTER_MEMORY_USAGE_OPS_HISTORY` | 提供 `MEMORY_USAGE_OPS_HISTORY` 表的集群级别的视图。 | +| `CLUSTER_PROCESSLIST` | 提供 `PROCESSLIST` 表的集群级别的视图。 | +| `CLUSTER_SLOW_QUERY` | 提供 `SLOW_QUERY` 表的集群级别的视图。 | +| `CLUSTER_STATEMENTS_SUMMARY` | 提供 `STATEMENTS_SUMMARY` 表的集群级别的视图。 | +| `CLUSTER_STATEMENTS_SUMMARY_HISTORY` | 提供 `STATEMENTS_SUMMARY_HISTORY` 表的集群级别的视图。 | +| `CLUSTER_TIDB_INDEX_USAGE` | 提供 `TIDB_INDEX_USAGE` 表的集群级别的视图。 | +| `CLUSTER_TIDB_TRX` | 提供 `TIDB_TRX` 表的集群级别的视图。 | +| [`CLUSTER_SYSTEMINFO`](/information-schema/information-schema-cluster-systeminfo.md) | 提供集群中服务器的内核参数配置的详细信息。 | +| [`DATA_LOCK_WAITS`](/information-schema/information-schema-data-lock-waits.md) | 提供 TiKV 服务器上的等锁信息。 | +| [`DDL_JOBS`](/information-schema/information-schema-ddl-jobs.md) | 提供与 `ADMIN SHOW DDL JOBS` 类似的输出。 | +| [`DEADLOCKS`](/information-schema/information-schema-deadlocks.md) | 提供 TiDB 节点上最近发生的数次死锁错误的信息。 | +| [`INSPECTION_RESULT`](/information-schema/information-schema-inspection-result.md) | 触发内部诊断检查。 | +| [`INSPECTION_RULES`](/information-schema/information-schema-inspection-rules.md) | 进行的内部诊断检查的列表。 | +| [`INSPECTION_SUMMARY`](/information-schema/information-schema-inspection-summary.md) | 重要监视指标的摘要报告。 | +| [`MEMORY_USAGE`](/information-schema/information-schema-memory-usage.md) | 提供当前 TiDB 实例的内存使用情况。 | +| [`MEMORY_USAGE_OPS_HISTORY`](/information-schema/information-schema-memory-usage-ops-history.md) | 提供当前 TiDB 实例内存相关的历史操作和执行依据。 | +| [`METRICS_SUMMARY`](/information-schema/information-schema-metrics-summary.md) | 从 Prometheus 获取的指标的摘要。 | +| `METRICS_SUMMARY_BY_LABEL` | 参见 `METRICS_SUMMARY` 表。 | +| [`METRICS_TABLES`](/information-schema/information-schema-metrics-tables.md) | 为 `METRICS_SCHEMA` 中的表提供 PromQL 定义。 | +| [`PLACEMENT_POLICIES`](/information-schema/information-schema-placement-policies.md) | 提供所有放置策略的定义信息。 | +| [`SEQUENCES`](/information-schema/information-schema-sequences.md) | 描述了基于 MariaDB 实现的 TiDB 序列。 | +| [`SLOW_QUERY`](/information-schema/information-schema-slow-query.md) | 提供当前 TiDB 服务器上慢查询的信息。 | +| [`STATEMENTS_SUMMARY`](/statement-summary-tables.md) | 类似于 MySQL 中的 performance_schema 语句摘要。 | +| [`STATEMENTS_SUMMARY_HISTORY`](/statement-summary-tables.md) | 类似于 MySQL 中的 performance_schema 语句摘要历史。 | +| [`TABLE_STORAGE_STATS`](/information-schema/information-schema-table-storage-stats.md) | 提供存储的表的大小的详细信息。 | +| [`TIDB_HOT_REGIONS`](/information-schema/information-schema-tidb-hot-regions.md) | 提供有关哪些 Region 访问次数最多的统计信息。 | +| [`TIDB_HOT_REGIONS_HISTORY`](/information-schema/information-schema-tidb-hot-regions-history.md)| 提供有关哪些 Region 访问次数最多的历史统计信息。 | +| [`TIDB_INDEXES`](/information-schema/information-schema-tidb-indexes.md) | 提供有关 TiDB 表的索引信息。 | +| [`TIDB_INDEX_USAGE`](/information-schema/information-schema-tidb-index-usage.md) | 提供 TiDB 节点上有关访问索引的统计信息。 | +| [`TIDB_SERVERS_INFO`](/information-schema/information-schema-tidb-servers-info.md) | 提供 TiDB 服务器的列表 | +| [`TIDB_TRX`](/information-schema/information-schema-tidb-trx.md) | 提供 TiDB 节点上正在执行的事务的信息。 | +| [`TIFLASH_REPLICA`](/information-schema/information-schema-tiflash-replica.md) | 提供有关 TiFlash 副本的详细信息。 | +| [`TIKV_REGION_PEERS`](/information-schema/information-schema-tikv-region-peers.md) | 提供 Region 存储位置的详细信息。 | +| [`TIKV_REGION_STATUS`](/information-schema/information-schema-tikv-region-status.md) | 提供 Region 的统计信息。 | +| [`TIKV_STORE_STATUS`](/information-schema/information-schema-tikv-store-status.md) | 提供 TiKV 服务器的基本信息。 | diff --git a/markdown-pages/zh/tidb/master/join-reorder.md b/markdown-pages/zh/tidb/master/join-reorder.md new file mode 100644 index 0000000..beb0a98 --- /dev/null +++ b/markdown-pages/zh/tidb/master/join-reorder.md @@ -0,0 +1,52 @@ +--- +title: Join Reorder 算法简介 +aliases: ['/docs-cn/dev/join-reorder/','/docs-cn/dev/reference/performance/join-reorder/'] +summary: Join Reorder 算法决定了多表 Join 的顺序,影响执行效率。TiDB 中有贪心算法和动态规划算法两种实现。贪心算法选择行数最小的表与其他表做 Join,直到所有节点完成 Join。动态规划算法枚举所有可能的 Join 顺序,选择最优的。算法受系统变量控制,且存在一些限制,如无法保证一定选到合适的 Join 顺序。 +--- + +# Join Reorder 算法简介 + +在实际的业务场景中,多个表的 Join 语句是很常见的,而 Join 的执行效率和各个表参与 Join 的顺序有关系。如 `select * from t1, t2, t3 where t1.a=t2.a and t3.a=t2.a`,这个 SQL 中可能的执行顺序有“t1 和 t2 先做 Join,然后再和 t3 做 Join”以及“t2 和 t3 先做 Join,然后再和 t1 做 Join”两种情况。根据 `t1` 和 `t3` 的数据量及数据分布,这两种执行顺序会有不同的性能表现。 + +因此优化器需要实现一种决定 Join 顺序的算法。目前 TiDB 中存在两种 Join Reorder 算法,贪心算法和动态规划算法。 + +- Join Reorder 贪心算法:在所有参与 Join 的节点中,选择行数最小的表与其他各表分别做一次 Join 的结果估算,然后选择其中结果最小的一对进行 Join,再继续这个过程进入下一轮的选择和 Join,直到所有的节点都完成 Join。 +- Join Reorder 动态规划算法:在所有参与 Join 的节点中,枚举所有可能的 Join 顺序,然后选择最优的 Join 顺序。 + +## Join Reorder 贪心算法实例 + +以三个表 t1、t2、t3 的 Join 为例。首先获取所有参与 Join 的节点,将所有节点按照行数多少,从少到多进行排序。 + +![join-reorder-1](/media/join-reorder-1.png) + +之后选定其中最小的表,将其与其他两个表分别做一次 Join,观察输出的结果集大小,选择其中结果更小的一对。 + +![join-reorder-2](/media/join-reorder-2.png) + +然后进入下一轮的选择,如果这时是四个表,那么就继续比较输出结果集的大小,进行选择。这里只有三个表,因此就直接得到了最终的 Join 结果。 + +![join-reorder-3](/media/join-reorder-3.png) + +## Join Reorder 动态规划算法实例 + +仍然以上述例子为例。动态规划算法会枚举所有的可能性,因此相对贪心算法必须从 `t1` 表开始枚举,动态规划算法可以枚举如下的 Join 顺序。 + +![join-reorder-4](/media/join-reorder-4.png) + +当该选择比贪心算法更优时,动态规划算法便可以选择到更优的 Join 顺序。 + +相应地,因为会枚举所有的可能性,动态规划算法会消耗更多的时间,也会更容易受统计信息影响。 + +## Join Reorder 算法的控制 + +目前 Join Reorder 算法由变量 [`tidb_opt_join_reorder_threshold`](/system-variables.md#tidb_opt_join_reorder_threshold) 控制,当参与 Join Reorder 的节点个数大于该阈值时选择贪心算法,反之选择动态规划算法。 + +## Join Reorder 算法限制 + +当前的 Join Reorder 算法存在如下限制: + +- 受结果集的计算算法所限并不会保证一定会选到合适的 Join order +- 是否启用 Outer Join 的 Join Reorder 功能由系统变量 [`tidb_enable_outer_join_reorder`](/system-variables.md#tidb_enable_outer_join_reorder-从-v610-版本开始引入) 控制。 +- 目前动态规划算法无法进行 Outer Join 的 Join Reorder。 + +目前 TiDB 中支持使用 `STRAIGHT_JOIN` 语法来强制指定一种 Join 顺序,参见[语法元素说明](/sql-statements/sql-statement-select.md#语法元素说明)。 diff --git a/markdown-pages/zh/tidb/master/maintain-tidb-using-tiup.md b/markdown-pages/zh/tidb/master/maintain-tidb-using-tiup.md new file mode 100644 index 0000000..ede2b51 --- /dev/null +++ b/markdown-pages/zh/tidb/master/maintain-tidb-using-tiup.md @@ -0,0 +1,234 @@ +--- +title: TiUP 常见运维操作 +aliases: ['/docs-cn/dev/maintain-tidb-using-tiup/','/docs-cn/dev/how-to/maintain/tiup-operations/'] +summary: TiUP 是用于管理 TiDB 集群的工具,可以进行查看集群列表、启动、关闭、修改配置参数、查看状态等常见运维操作。操作简单方便,适合用于 TiDB 集群的管理。 +--- + +# TiUP 常见运维操作 + +本文介绍了使用 TiUP 运维 TiDB 集群的常见操作,包括查看集群列表、启动集群、查看集群状态、修改配置参数、关闭集群、销毁集群等。 + +## 查看集群列表 + +TiUP cluster 组件可以用来管理多个 TiDB 集群,在每个 TiDB 集群部署完毕后,该集群会出现在 TiUP 的集群列表里,可以使用 list 命令来查看。 + +```bash +tiup cluster list +``` + +## 启动集群 + +启动集群操作会按 PD -> TiKV -> Pump -> TiDB -> TiFlash -> Drainer -> TiCDC -> Prometheus -> Grafana -> Alertmanager 的顺序启动整个 TiDB 集群所有组件: + +```bash +tiup cluster start ${cluster-name} +``` + +> **注意:** +> +> 你需要将 `${cluster-name}` 替换成实际的集群名字,若忘记集群名字,可通过 `tiup cluster list` 查看。 + +该命令支持通过 `-R` 和 `-N` 参数来只启动部分组件。 + +例如,下列命令只启动 PD 组件: + +```bash +tiup cluster start ${cluster-name} -R pd +``` + +下列命令只启动 `1.2.3.4` 和 `1.2.3.5` 这两台机器上的 PD 组件: + +```bash +tiup cluster start ${cluster-name} -N 1.2.3.4:2379,1.2.3.5:2379 +``` + +> **注意:** +> +> 若通过 `-R` 和 `-N` 启动指定组件,需要保证启动顺序正确(例如需要先启动 PD 才能启动 TiKV),否则可能导致启动失败。 + +## 查看集群状态 + +集群启动之后需要检查每个组件的运行状态,以确保每个组件工作正常。TiUP 提供了 display 命令,节省了登录到每台机器上去查看进程的时间。 + +```bash +tiup cluster display ${cluster-name} +``` + +## 修改配置参数 + +集群运行过程中,如果需要调整某个组件的参数,可以使用 `edit-config` 命令来编辑参数。具体的操作步骤如下: + +1. 以编辑模式打开该集群的配置文件: + + ```bash + tiup cluster edit-config ${cluster-name} + ``` + +2. 设置参数: + + 首先确定配置的生效范围,有以下两种生效范围: + + - 如果配置的生效范围为该组件全局,则配置到 `server_configs`。例如: + + ``` + server_configs: + tidb: + log.slow-threshold: 300 + ``` + + - 如果配置的生效范围为某个节点,则配置到具体节点的 `config` 中。例如: + + ``` + tidb_servers: + - host: 10.0.1.11 + port: 4000 + config: + log.slow-threshold: 300 + ``` + + 参数的格式参考 [TiUP 配置参数模版](https://github.com/pingcap/tiup/blob/master/embed/examples/cluster/topology.example.yaml)。 + + **配置项层次结构使用 `.` 表示**。 + + 关于组件的更多配置参数说明,可参考 [tidb `config.toml.example`](https://github.com/pingcap/tidb/blob/master/pkg/config/config.toml.example)、[tikv `config.toml.example`](https://github.com/tikv/tikv/blob/master/etc/config-template.toml) 和 [pd `config.toml.example`](https://github.com/tikv/pd/blob/master/conf/config.toml)。 + +3. 执行 `reload` 命令滚动分发配置、重启相应组件: + + ```bash + tiup cluster reload ${cluster-name} [-N ] [-R ] + ``` + +### 示例 + +如果要调整 tidb-server 中事务大小限制参数 `txn-total-size-limit` 为 `1G`,该参数位于 [performance](https://github.com/pingcap/tidb/blob/master/pkg/config/config.toml.example) 模块下,调整后的配置如下: + +``` +server_configs: + tidb: + performance.txn-total-size-limit: 1073741824 +``` + +然后执行 `tiup cluster reload ${cluster-name} -R tidb` 命令滚动重启。 + +## Hotfix 版本替换 + +常规的升级集群请参考[升级文档](/upgrade-tidb-using-tiup.md),但是在某些场景下(例如 Debug),可能需要用一个临时的包替换正在运行的组件,此时可以用 `patch` 命令: + +```bash +tiup cluster patch --help +``` + +``` +Replace the remote package with a specified package and restart the service + +Usage: + tiup cluster patch [flags] + +Flags: + -h, --help 帮助信息 + -N, --node strings 指定被替换的节点 + --overwrite 在未来的 scale-out 操作中使用当前指定的临时包 + -R, --role strings 指定被替换的服务类型 + --transfer-timeout int transfer leader 的超时时间 + +Global Flags: + --native-ssh 使用系统默认的 SSH 客户端 + --wait-timeout int 等待操作超时的时间 + --ssh-timeout int SSH 连接的超时时间 + -y, --yes 跳过所有的确认步骤 +``` + +例如,有一个 TiDB 实例的 hotfix 包放在 `/tmp/tidb-hotfix.tar.gz` 目录下。如果此时想要替换集群上的所有 TiDB 实例,则可以执行以下命令: + +```bash +tiup cluster patch test-cluster /tmp/tidb-hotfix.tar.gz -R tidb +``` + +或者只替换其中一个 TiDB 实例: + +```bash +tiup cluster patch test-cluster /tmp/tidb-hotfix.tar.gz -N 172.16.4.5:4000 +``` + +## 重命名集群 + +部署并启动集群后,可以通过 `tiup cluster rename` 命令来对集群重命名: + +```bash +tiup cluster rename ${cluster-name} ${new-name} +``` + +> **注意:** +> +> + 重命名集群会重启监控(Prometheus 和 Grafana)。 +> + 重命名集群之后 Grafana 可能会残留一些旧集群名的面板,需要手动删除这些面板。 + +## 关闭集群 + +关闭集群操作会按 Alertmanager -> Grafana -> Prometheus -> TiCDC -> Drainer -> TiFlash -> TiDB -> Pump -> TiKV -> PD 的顺序关闭整个 TiDB 集群所有组件(同时也会关闭监控组件): + +```bash +tiup cluster stop ${cluster-name} +``` + +和 `start` 命令类似,`stop` 命令也支持通过 `-R` 和 `-N` 参数来只停止部分组件。 + +例如,下列命令只停止 TiDB 组件: + +```bash +tiup cluster stop ${cluster-name} -R tidb +``` + +下列命令只停止 `1.2.3.4` 和 `1.2.3.5` 这两台机器上的 TiDB 组件: + +```bash +tiup cluster stop ${cluster-name} -N 1.2.3.4:4000,1.2.3.5:4000 +``` + +## 清除集群数据 + +此操作会关闭所有服务,并清空其数据目录或/和日志目录,并且无法恢复,需要**谨慎操作**。 + +清空集群所有服务的数据,但保留日志: + +```bash +tiup cluster clean ${cluster-name} --data +``` + +清空集群所有服务的日志,但保留数据: + +```bash +tiup cluster clean ${cluster-name} --log +``` + +清空集群所有服务的数据和日志: + +```bash +tiup cluster clean ${cluster-name} --all +``` + +清空 Prometheus 以外的所有服务的日志和数据: + +```bash +tiup cluster clean ${cluster-name} --all --ignore-role prometheus +``` + +清空节点 `172.16.13.11:9000` 以外的所有服务的日志和数据: + +```bash +tiup cluster clean ${cluster-name} --all --ignore-node 172.16.13.11:9000 +``` + +清空部署在 `172.16.13.12` 以外的所有服务的日志和数据: + +```bash +tiup cluster clean ${cluster-name} --all --ignore-node 172.16.13.12 +``` + +## 销毁集群 + +销毁集群操作会关闭服务,清空数据目录和部署目录,并且无法恢复,需要**谨慎操作**。 + +```bash +tiup cluster destroy ${cluster-name} +``` diff --git a/markdown-pages/zh/tidb/master/max-min-eliminate.md b/markdown-pages/zh/tidb/master/max-min-eliminate.md new file mode 100644 index 0000000..49c0f87 --- /dev/null +++ b/markdown-pages/zh/tidb/master/max-min-eliminate.md @@ -0,0 +1,108 @@ +--- +title: Max/Min 函数消除规则 +aliases: ['/docs-cn/dev/max-min-eliminate/','/docs-cn/dev/reference/performance/max-min-eliminate/'] +summary: SQL 中的 max/min 函数消除规则能够将 max/min 聚合函数转换为 TopN 算子,利用索引进行查询。当只有一个 max/min 函数时,会重写为 select max(a) from (select a from t where a is not null order by a desc limit 1) t,利用索引只扫描一行数据。存在多个 max/min 函数时,会先检查列是否有索引能够保序,然后重写为两个子查询的笛卡尔积,最终避免对整个表的扫描。 +--- + +# Max/Min 函数消除规则 + +在 SQL 中包含了 `max`/`min` 函数时,查询优化器会尝试使用 `max`/`min` 消除优化规则来将 `max`/`min` 聚合函数转换为 TopN 算子,从而能够有效地利用索引进行查询。 + +根据 `select` 语句中 `max`/`min` 函数的个数,这一优化规则有以下两种表现形式: + ++ [只有一个 max/min 函数时的优化规则](#只有一个-maxmin-函数时的优化规则) ++ [存在多个 max/min 函数时的优化规则](#存在多个-maxmin-函数时的优化规则) + +## 只有一个 max/min 函数时的优化规则 + +当一个 SQL 满足以下条件时,就会应用这个规则: + ++ 只有一个聚合函数,且为 `max` 或者 `min` 函数。 ++ 聚合函数没有相应的 `group by` 语句。 + +例如: + +```sql +select max(a) from t +``` + +这时 `max`/`min` 消除优化规则会将其重写为: + +```sql +select max(a) from (select a from t where a is not null order by a desc limit 1) t +``` + +这个新的 SQL 语句在 `a` 列存在索引(或 `a` 列是某个联合索引的前缀)时,能够利用索引只扫描一行数据来得到最大或者最小值,从而避免对整个表的扫描。 + +上述例子最终得到的执行计划如下: + +``` +mysql> explain select max(a) from t; ++------------------------------+---------+-----------+-------------------------+-------------------------------------+ +| id | estRows | task | access object | operator info | ++------------------------------+---------+-----------+-------------------------+-------------------------------------+ +| StreamAgg_13 | 1.00 | root | | funcs:max(test.t.a)->Column#4 | +| └─Limit_17 | 1.00 | root | | offset:0, count:1 | +| └─IndexReader_27 | 1.00 | root | | index:Limit_26 | +| └─Limit_26 | 1.00 | cop[tikv] | | offset:0, count:1 | +| └─IndexFullScan_25 | 1.00 | cop[tikv] | table:t, index:idx_a(a) | keep order:true, desc, stats:pseudo | ++------------------------------+---------+-----------+-------------------------+-------------------------------------+ +5 rows in set (0.00 sec) +``` + +## 存在多个 max/min 函数时的优化规则 + +当一个 SQL 满足以下条件时,就会应用这个规则: + ++ 有多个聚合函数,且所有的聚合函数都是 max/min ++ 聚合函数没有相应的 `group by` 语句。 ++ 每个 `max`/`min` 聚合函数参数中的列都有索引能够保序。 + +下面是一个简单的例子: + +```sql +select max(a) - min(a) from t +``` + +优化规则会先检查 `a` 列是否存在索引能够为其保序,如果存在,这个 SQL 会先被重写为两个子查询的笛卡尔积: + +```sql +select max_a - min_a +from + (select max(a) as max_a from t) t1, + (select min(a) as min_a from t) t2 +``` + +这样,两个子句中的 `max`/`min` 函数就可以使用上述“只有一个 `max`/`min` 函数时的优化规则”分别进行优化,最终重写为: + +```sql +select max_a - min_a +from + (select max(a) as max_a from (select a from t where a is not null order by a desc limit 1) t) t1, + (select min(a) as min_a from (select a from t where a is not null order by a asc limit 1) t) t2 +``` + +同样的,如果 `a` 列能够使用索引保序,那这个优化只会扫描两行数据,避免了对整个表的扫描。但如果 `a` 列没有可以保序的索引,这个变换会使原本只需一次的全表扫描变成两次,因此这个规则就不会被应用。 + +最后得到的执行计划: + +``` +mysql> explain select max(a)-min(a) from t; ++------------------------------------+---------+-----------+-------------------------+-------------------------------------+ +| id | estRows | task | access object | operator info | ++------------------------------------+---------+-----------+-------------------------+-------------------------------------+ +| Projection_17 | 1.00 | root | | minus(Column#4, Column#5)->Column#6 | +| └─HashJoin_18 | 1.00 | root | | CARTESIAN inner join | +| ├─StreamAgg_45(Build) | 1.00 | root | | funcs:min(test.t.a)->Column#5 | +| │ └─Limit_49 | 1.00 | root | | offset:0, count:1 | +| │ └─IndexReader_59 | 1.00 | root | | index:Limit_58 | +| │ └─Limit_58 | 1.00 | cop[tikv] | | offset:0, count:1 | +| │ └─IndexFullScan_57 | 1.00 | cop[tikv] | table:t, index:idx_a(a) | keep order:true, stats:pseudo | +| └─StreamAgg_24(Probe) | 1.00 | root | | funcs:max(test.t.a)->Column#4 | +| └─Limit_28 | 1.00 | root | | offset:0, count:1 | +| └─IndexReader_38 | 1.00 | root | | index:Limit_37 | +| └─Limit_37 | 1.00 | cop[tikv] | | offset:0, count:1 | +| └─IndexFullScan_36 | 1.00 | cop[tikv] | table:t, index:idx_a(a) | keep order:true, desc, stats:pseudo | ++------------------------------------+---------+-----------+-------------------------+-------------------------------------+ +12 rows in set (0.01 sec) +``` diff --git a/markdown-pages/zh/tidb/master/overview.md b/markdown-pages/zh/tidb/master/overview.md new file mode 100644 index 0000000..c1ae44f --- /dev/null +++ b/markdown-pages/zh/tidb/master/overview.md @@ -0,0 +1,72 @@ +--- +title: TiDB 简介 +aliases: ['/docs-cn/dev/overview/','/docs-cn/dev/key-features/','/docs-cn/overview','/docs-cn/stable/overview/','/docs-cn/stable/key-features/'] +summary: TiDB 是 PingCAP 公司自主设计、研发的开源分布式关系型数据库,支持在线事务处理与在线分析处理 (HTAP)。具有水平扩容、金融级高可用、实时 HTAP、云原生的分布式数据库、兼容 MySQL 协议和 MySQL 生态等特性。适用于高可用、强一致性要求高、数据规模大等各种应用场景。具有一键水平扩缩容、金融级高可用、实时 HTAP、云原生的分布式数据库、兼容 MySQL 协议和 MySQL 生态等五大核心特性,以及金融行业、海量数据及高并发的 OLTP、实时 HTAP、数据汇聚、二次加工处理等四大核心应用场景。 +--- + +# TiDB 简介 + + + +[TiDB](https://github.com/pingcap/tidb) 是 [PingCAP](https://pingcap.com/about-cn/) 公司自主设计、研发的开源分布式关系型数据库,是一款同时支持在线事务处理与在线分析处理 (Hybrid Transactional and Analytical Processing, HTAP) 的融合型分布式数据库产品,具备水平扩容或者缩容、金融级高可用、实时 HTAP、云原生的分布式数据库、兼容 MySQL 协议和 MySQL 生态等重要特性。目标是为用户提供一站式 OLTP (Online Transactional Processing)、OLAP (Online Analytical Processing)、HTAP 解决方案。TiDB 适合高可用、强一致要求较高、数据规模较大等各种应用场景。 + +关于 TiDB 的关键技术创新,请观看以下视频。 + + + +## 五大核心特性 + +- 一键水平扩缩容 + + 得益于 TiDB 存储计算分离的架构的设计,可按需对计算、存储分别进行在线扩容或者缩容,扩容或者缩容过程中对应用运维人员透明。 + +- 金融级高可用 + + 数据采用多副本存储,数据副本通过 Multi-Raft 协议同步事务日志,多数派写入成功事务才能提交,确保数据强一致性且少数副本发生故障时不影响数据的可用性。可按需配置副本地理位置、副本数量等策略,满足不同容灾级别的要求。 + +- 实时 HTAP + + 提供行存储引擎 [TiKV](/tikv-overview.md)、列存储引擎 [TiFlash](/tiflash/tiflash-overview.md) 两款存储引擎,TiFlash 通过 Multi-Raft Learner 协议实时从 TiKV 复制数据,确保行存储引擎 TiKV 和列存储引擎 TiFlash 之间的数据强一致。TiKV、TiFlash 可按需部署在不同的机器,解决 HTAP 资源隔离的问题。 + +- 云原生的分布式数据库 + + 专为云而设计的分布式数据库,通过 [TiDB Operator](https://docs.pingcap.com/zh/tidb-in-kubernetes/stable/tidb-operator-overview) 可在公有云、私有云、混合云中实现部署工具化、自动化。 + +- 兼容 MySQL 协议和 MySQL 生态 + + 兼容 MySQL 协议、MySQL 常用的功能、MySQL 生态,应用无需或者修改少量代码即可从 MySQL 迁移到 TiDB。提供丰富的[数据迁移工具](/ecosystem-tool-user-guide.md)帮助应用便捷完成数据迁移。 + +## 四大核心应用场景 + +- 金融行业场景 + + 金融行业对数据一致性及高可靠、系统高可用、可扩展性、容灾要求较高。传统的解决方案的资源利用率低,维护成本高。TiDB 采用多副本 + Multi-Raft 协议的方式将数据调度到不同的机房、机架、机器,确保系统的 RTO <= 30s 及 RPO = 0。 + +- 海量数据及高并发的 OLTP 场景 + + 传统的单机数据库无法满足因数据爆炸性的增长对数据库的容量要求。TiDB 是一种性价比高的解决方案,采用计算、存储分离的架构,可对计算、存储分别进行扩缩容,计算最大支持 512 节点,每个节点最大支持 1000 并发,集群容量最大支持 PB 级别。 + +- 实时 HTAP 场景 + + TiDB 适用于需要实时处理的大规模数据和高并发场景。TiDB 在 4.0 版本中引入列存储引擎 TiFlash,结合行存储引擎 TiKV 构建真正的 HTAP 数据库,在增加少量存储成本的情况下,可以在同一个系统中做联机交易处理、实时数据分析,极大地节省企业的成本。 + +- 数据汇聚、二次加工处理的场景 + + TiDB 适用于将企业分散在各个系统的数据汇聚在同一个系统,并进行二次加工处理生成 T+0 或 T+1 的报表。与 Hadoop 相比,TiDB 要简单得多,业务通过 ETL 工具或者 TiDB 的同步工具将数据同步到 TiDB,在 TiDB 中可通过 SQL 直接生成报表。 + +关于 TiDB 典型应用场景和用户案例的介绍,请观看以下视频。 + + + +## 另请参阅 + +- [TiDB 整体架构](/tidb-architecture.md) +- [TiDB 数据库的存储](/tidb-storage.md) +- [TiDB 数据库的计算](/tidb-computing.md) +- [TiDB 数据库的调度](/tidb-scheduling.md) diff --git a/markdown-pages/zh/tidb/master/pd-configuration-file.md b/markdown-pages/zh/tidb/master/pd-configuration-file.md new file mode 100644 index 0000000..2749276 --- /dev/null +++ b/markdown-pages/zh/tidb/master/pd-configuration-file.md @@ -0,0 +1,519 @@ +--- +title: PD 配置文件描述 +aliases: ['/docs-cn/dev/pd-configuration-file/','/docs-cn/dev/reference/configuration/pd-server/configuration-file/'] +summary: PD 配置文件包含了许多参数,如节点名称、数据路径、客户端 URL、广告客户端 URL、节点 URL 等。还包括了一些实验性特性的配置项,如内存限制、GC 触发阈值、GOGC Tuner 等。此外,还有监控、调度、副本、标签、Dashboard、同步模式和资源控制等相关配置项。 +--- + +# PD 配置文件描述 + + + +PD 配置文件比命令行参数支持更多的选项。你可以在 [conf/config.toml](https://github.com/pingcap/pd/blob/master/conf/config.toml) 找到默认的配置文件。 + +本文档只阐述未包含在命令行参数中的参数,命令行参数参见 [PD 配置参数](/command-line-flags-for-pd-configuration.md)。 + +> **Tip:** +> +> 如果你需要调整配置项的值,请参考[修改配置参数](/maintain-tidb-using-tiup.md#修改配置参数)进行操作。 + +### `name` + ++ PD 节点名称。 ++ 默认值:`"pd"` ++ 如果你需要启动多个 PD,一定要给 PD 使用不同的名字。 + +### `data-dir` + ++ PD 存储数据路径。 ++ 默认值:`"default.${name}"` + +### `client-urls` + ++ PD 监听的客户端 URL 列表。 ++ 默认值:`"http://127.0.0.1:2379"` ++ 如果部署一个集群,client URLs 必须指定当前主机的 IP 地址,例如 `"http://192.168.100.113:2379"`,如果是运行在 Docker 则需要指定为 `"http://0.0.0.0:2379"`。 + +### `advertise-client-urls` + ++ 用于外部访问 PD 的 URL 列表。 ++ 默认值:`"${client-urls}"` ++ 在某些情况下,例如 Docker 或者 NAT 网络环境,客户端并不能通过 PD 自己监听的 client URLs 来访问到 PD,这时候,你就可以设置 advertise URLs 来让客户端访问。 ++ 例如,Docker 内部 IP 地址为 `172.17.0.1`,而宿主机的 IP 地址为 `192.168.100.113` 并且设置了端口映射 `-p 2379:2379`,那么可以设置为 `advertise-client-urls="http://192.168.100.113:2379"`,客户端可以通过 `http://192.168.100.113:2379` 来找到这个服务。 + +### `peer-urls` + ++ PD 节点监听其他 PD 节点的 URL 列表。 ++ 默认:`"http://127.0.0.1:2380"` ++ 如果部署一个集群,peer URLs 必须指定当前主机的 IP 地址,例如 `"http://192.168.100.113:2380"`,如果是运行在 Docker 则需要指定为 `"http://0.0.0.0:2380"`。 + +### `advertise-peer-urls` + ++ 用于其他 PD 节点访问某个 PD 节点的 URL 列表。 ++ 默认值:`"${peer-urls}"` ++ 在某些情况下,例如 Docker 或者 NAT 网络环境,其他节点并不能通过 PD 自己监听的 peer URLs 来访问到 PD,这时候,你就可以设置 advertise URLs 来让其他节点访问 ++ 例如,Docker 内部 IP 地址为 `172.17.0.1`,而宿主机的 IP 地址为 `192.168.100.113` 并且设置了端口映射 `-p 2380:2380`,那么可以设置为 `advertise-peer-urls="http://192.168.100.113:2380"`,其他 PD 节点可以通过 `http://192.168.100.113:2380` 来找到这个服务。 + +### `initial-cluster` + ++ 初始化 PD 集群配置。 ++ 默认值:`"{name}=http://{advertise-peer-url}"` ++ 例如,如果 name 是 "pd",并且 `advertise-peer-urls` 是 `"http://192.168.100.113:2380"`,那么 `initial-cluster` 就是 `"pd=http://192.168.100.113:2380"`。 ++ 如果启动三台 PD,那么 `initial-cluster` 可能就是 `pd1=http://192.168.100.113:2380, pd2=http://192.168.100.114:2380, pd3=192.168.100.115:2380`。 + +### `initial-cluster-state` + ++ 集群初始状态 ++ 默认值:"new" + +### `initial-cluster-token` + ++ 用于在集群初始化阶段标识不同的集群。 ++ 默认值:"pd-cluster" ++ 如果先后部署多个集群,且多个集群有相同配置的节点,应指定不同的 token 来隔离不同的集群。 + +### `lease` + ++ PD Leader Key 租约超时时间,超时系统重新选举 Leader。 ++ 默认值:3 ++ 单位:秒 + +### `quota-backend-bytes` + ++ 元信息数据库存储空间的大小,默认 8GiB。 ++ 默认值:8589934592 + +### `auto-compaction-mod` + ++ 元信息数据库自动压缩的模式,可选项为 periodic(按周期),revision(按版本数)。 ++ 默认值:periodic + +### `auto-compaction-retention` + ++ compaction-mode 为 periodic 时为元信息数据库自动压缩的间隔时间;compaction-mode 设置为 revision 时为自动压缩的版本数。 ++ 默认值:1h + +### `force-new-cluster` + ++ 强制让该 PD 以一个新集群启动,且修改 raft 成员数为 1。 ++ 默认值:false + +### `tso-update-physical-interval` + ++ TSO 物理时钟更新周期。 ++ 在默认的一个 TSO 物理时钟更新周期内 (50ms),PD 最多提供 262144 个 TSO。如果需要更多的 TSO,可以将这个参数调小。最小值为 `1ms`。 ++ 缩短这个参数会增加 PD 的 CPU 消耗。根据测试,相比 `50ms` 更新周期,更新周期为 `1ms` 时,PD 的 CPU 占用率 ([CPU usage](https://man7.org/linux/man-pages/man1/top.1.html)) 将增加约 10%。 ++ 默认值:50ms ++ 最小值:1ms + +## pd-server + +pd-server 相关配置项。 + +### `server-memory-limit` 从 v6.6.0 版本开始引入 + +> **警告:** +> +> 在当前版本中,该配置项为实验特性,不建议在生产环境中使用。 + ++ PD 实例的内存限制比例。`0` 值表示不设内存限制。 ++ 默认值:`0` ++ 最小值:`0` ++ 最大值:`0.99` + +### `server-memory-limit-gc-trigger` 从 v6.6.0 版本开始引入 + +> **警告:** +> +> 在当前版本中,该配置项为实验特性,不建议在生产环境中使用。 + ++ PD 尝试触发 GC 的阈值比例。当 PD 的内存使用达到 `server-memory-limit` 值 * `server-memory-limit-gc-trigger` 值时,则会主动触发一次 Golang GC。在一分钟之内只会主动触发一次 GC。 ++ 默认值:`0.7` ++ 最小值:`0.5` ++ 最大值:`0.99` + +### `enable-gogc-tuner` 从 v6.6.0 版本开始引入 + +> **警告:** +> +> 在当前版本中,该配置项为实验特性,不建议在生产环境中使用。 + ++ 是否开启 GOGC Tuner。 ++ 默认值:`false` + +### `gc-tuner-threshold` 从 v6.6.0 版本开始引入 + +> **警告:** +> +> 在当前版本中,该配置项为实验特性,不建议在生产环境中使用。 + ++ GOGC Tuner 自动调节的最大内存阈值比例,即 `server-memory-limit` 值 * `server-memory-limit-gc-trigger` 值,超过阈值后 GOGC Tuner 会停止工作。 ++ 默认值:`0.6` ++ 最小值:`0` ++ 最大值:`0.9` + +### `flow-round-by-digit` 从 v5.1 版本开始引入 + ++ 默认值:3 ++ PD 会对流量信息的末尾数字进行四舍五入处理,减少 Region 流量信息变化引起的统计信息更新。该配置项用于指定对 Region 流量信息的末尾进行四舍五入的位数。例如流量 `100512` 会归约到 `101000`。默认值为 `3`。该配置替换了 `trace-region-flow`。 + +> **注意:** +> +> 如果是从 v4.0 升级至当前版本,升级后的 `flow-round-by-digit` 行为和升级前的 `trace-region-flow` 行为默认保持一致:如果升级前 `trace-region-flow` 为 false,则升级后 `flow-round-by-digit` 为 127;如果升级前 `trace-region-flow` 为 true,则升级后 `flow-round-by-digit` 为 3。 + +### `min-resolved-ts-persistence-interval` 从 v6.0.0 版本开始引入 + ++ 设置 PD leader 对集群中 Resolved TS 最小值进行持久化的间隔时间。如果该值设置为 `0`,表示禁用该功能。 ++ 默认值:在 v6.3.0 之前版本中为 `"0s"`,在 v6.3.0 及之后的版本中为 `"1s"`,即最小正值。 ++ 最小值:`"0s"` ++ 单位:秒 + +> **注意:** +> +> 对于从 v6.0.0~v6.2.0 升级上来的集群,`min-resolved-ts-persistence-interval` 的默认值在升级后将不会发生变化,即仍然为 `"0s"`。若要开启该功能,需要手动修改该配置项的值。 + +## security + +安全相关配置项。 + +### `cacert-path` + ++ CA 文件路径 ++ 默认值:"" + +### `cert-path` + ++ 包含 X509 证书的 PEM 文件路径 ++ 默认值:"" + +### `key-path` + ++ 包含 X509 key 的 PEM 文件路径 ++ 默认值:"" + +### `redact-info-log` 从 v5.0 版本开始引入 + ++ 控制 PD 日志脱敏的开关 ++ 该配置项值设为 true 时将对 PD 日志脱敏,遮蔽日志中的用户信息。 ++ 默认值:false + +## log + +日志相关的配置项。 + +### `level` + ++ 指定日志的输出级别。 ++ 可选值:"debug","info","warn","error","fatal" ++ 默认值:"info" + +### `format` + ++ 日志格式。 ++ 可选值:"text","json" ++ 默认值:"text" + +### `disable-timestamp` + ++ 是否禁用日志中自动生成的时间戳。 ++ 默认值:false + +## log.file + +日志文件相关的配置项。 + +### `max-size` + ++ 单个日志文件最大大小,超过该值系统自动切分成多个文件。 ++ 默认值:300 ++ 单位:MiB ++ 最小值为 1 + +### `max-days` + ++ 日志保留的最长天数。 ++ 如果未设置本参数或把本参数设置为默认值 `0`,PD 不清理日志文件。 ++ 默认:0 + +### `max-backups` + ++ 日志文件保留的最大个数。 ++ 如果未设置本参数或把本参数设置为默认值 `0`,PD 会保留所有的日志文件。 ++ 默认:0 + +## metric + +监控相关的配置项。 + +### `interval` + ++ 向 Prometheus 推送监控指标数据的间隔时间。 ++ 默认:15s + +## schedule + +调度相关的配置项。 + +### `max-merge-region-size` + ++ 控制 Region Merge 的 size 上限,当 Region Size 大于指定值时 PD 不会将其与相邻的 Region 合并。 ++ 默认:20 ++ 单位:MiB + +### `max-merge-region-keys` + ++ 控制 Region Merge 的 key 上限,当 Region key 大于指定值时 PD 不会将其与相邻的 Region 合并。 ++ 默认:200000 + +### `patrol-region-interval` + ++ 控制 replicaChecker 检查 Region 健康状态的运行频率,越短则运行越快,通常状况不需要调整 ++ 默认:10ms + +### `split-merge-interval` + ++ 控制对同一个 Region 做 split 和 merge 操作的间隔,即对于新 split 的 Region 一段时间内不会被 merge。 ++ 默认:1h + +### `max-snapshot-count` + ++ 控制单个 store 最多同时接收或发送的 snapshot 数量,调度受制于这个配置来防止抢占正常业务的资源。 ++ 默认:64 + +### `max-pending-peer-count` + ++ 控制单个 store 的 pending peer 上限,调度受制于这个配置来防止在部分节点产生大量日志落后的 Region。 ++ 默认值:64 + +### `max-store-down-time` + ++ PD 认为失联 store 无法恢复的时间,当超过指定的时间没有收到 store 的心跳后,PD 会在其他节点补充副本。 ++ 默认值:30m + +### `max-store-preparing-time` 从 v6.1.0 版本开始引入 + ++ 控制 store 上线阶段的最长等待时间。在 store 的上线阶段,PD 可以查询该 store 的上线进度。当超过该配置项指定的时间后,PD 会认为该 store 已完成上线,无法再次查询这个 store 的上线进度,但是不影响 Region 向这个新上线 store 的迁移。通常用户无需修改该配置项。 ++ 默认值:48h + +### `leader-schedule-limit` + ++ 同时进行 leader 调度的任务个数。 ++ 默认值:4 + +### `region-schedule-limit` + ++ 同时进行 Region 调度的任务个数 ++ 默认值:2048 + +### `hot-region-schedule-limit` + ++ 控制同时进行的 hot Region 任务。该配置项独立于 Region 调度。 ++ 默认值:4 + +### `hot-region-cache-hits-threshold` + ++ 设置识别热点 Region 所需的分钟数。只有当 Region 处于热点状态持续时间超过此分钟数时,PD 才会参与热点调度。 ++ 默认值:3 + +### `replica-schedule-limit` + ++ 同时进行 replica 调度的任务个数。 ++ 默认值:64 + +### `merge-schedule-limit` + ++ 同时进行的 Region Merge 调度的任务,设置为 0 则关闭 Region Merge。 ++ 默认值:8 + +### `high-space-ratio` + ++ 设置 store 空间充裕的阈值。当节点的空间占用比例小于该阈值时,PD 调度时会忽略节点的剩余空间,主要根据实际数据量进行均衡。此配置仅在 `region-score-formula-version = v1` 时生效。 ++ 默认值:0.7 ++ 最小值:大于 0 ++ 最大值:小于 1 + +### `low-space-ratio` + ++ 设置 store 空间不足的阈值。当某个节点的空间占用比例超过该阈值时,PD 会尽可能避免往该节点迁移数据,同时主要根据节点剩余空间大小进行调度,避免对应节点的磁盘空间被耗尽。 ++ 默认值:0.8 ++ 最小值:大于 0 ++ 最大值:小于 1 + +### `tolerant-size-ratio` + ++ 控制 balance 缓冲区大小。 ++ 默认值:0(为 0 为自动调整缓冲区大小) ++ 最小值:0 + +### `enable-cross-table-merge` + ++ 设置是否开启跨表 merge。 ++ 默认值:true + +### `region-score-formula-version` 从 v5.0 版本开始引入 + ++ 设置 Region 算分公式版本。 ++ 默认值:v2 ++ 可选值:v1,v2。v2 相比于 v1,变化会更平滑,空间回收引起的调度抖动情况会得到改善。 + +> **注意:** +> +> 如果是从 v4.0 升级至当前版本,默认不自动开启该算分公式新版本,以保证升级前后 PD 行为一致。若想切换算分公式的版本,使用需要手动通过 `pd-ctl` 设置切换,详见 [PD Control](/pd-control.md#config-show--set-option-value--placement-rules) 文档。 + +### `enable-joint-consensus` 从 v5.0 版本开始引入 + ++ 是否使用 Joint Consensus 进行副本调度。关闭该特性时,PD 将采用一次调度一个副本的方式进行调度。 ++ 默认值:true + +### `enable-diagnostic` 从 v6.3.0 版本开始引入 + ++ 是否开启诊断功能。开启特性时,PD 将会记录调度中的一些状态来帮助诊断。开启时会略微影响调度速度,在 Store 数量较多时会消耗较大内存。 ++ 默认值:从 v7.1.0 起,默认值从 `false` 变更为 `true`。如果从 v7.1.0 之前版本的集群升级至 v7.1.0 及之后的版本,该默认值不发生变化。 + +### `hot-regions-write-interval` 从 v5.4.0 版本开始引入 + +* 设置 PD 存储 Hot Region 信息时间间隔。 +* 默认值:10m + +> **注意:** +> +> Hot Region 的信息一般 3 分钟更新一次。如果设置时间间隔小于 3 分钟,中间部分的更新可能没有意义。 + +### `hot-regions-reserved-days` 从 v5.4.0 版本开始引入 + +* 设置 PD 保留的 Hot Region 信息的最长时间。单位为天。 +* 默认值: 7 + +## replication + +副本相关的配置项。 + +### `max-replicas` + ++ 所有副本数量,即 leader 与 follower 数量之和。默认为 `3`,即 1 个 leader 和 2 个 follower。当此配置被在线修改后,PD 会在后台通过调度使得 Region 的副本数量符合配置。 ++ 默认值:3 + +### `location-labels` + ++ TiKV 集群的拓扑信息。 ++ 默认值:[] ++ [配置集群拓扑](/schedule-replicas-by-topology-labels.md) + +### `isolation-level` + ++ TiKV 集群的最小强制拓扑隔离级别。 ++ 默认值:"" ++ [配置集群拓扑](/schedule-replicas-by-topology-labels.md) + +### `strictly-match-label` + ++ 打开强制 TiKV Label 和 PD 的 location-labels 是否匹配的检查 ++ 默认值:false + +### `enable-placement-rules` + ++ 打开 `placement-rules` ++ 默认值:true ++ 参考 [Placement Rules 使用文档](/configure-placement-rules.md) + +### `store-limit-version` 从 v7.1.0 版本开始引入 + +> **警告:** +> +> 在当前版本中,将该配置项设置为 `"v2"` 为实验特性,不建议在生产环境中使用。 + ++ 设置 `store limit` 工作模式 ++ 默认值:v1 ++ 可选值: + + v1:在 v1 模式下,你可以手动修改 `store limit` 以限制单个 TiKV 调度速度。 + + v2:(实验特性)在 v2 模式下,你无需关注 `store limit` 值,PD 将根据 TiKV Snapshot 执行情况动态调整 TiKV 调度速度。详情请参考 [Store Limit v2 原理](/configure-store-limit.md#store-limit-v2-原理)。 + +## label-property + +标签相关的配置项。 + +### `key` + ++ 拒绝 leader 的 store 带有的 label key。 ++ 默认值:"" + +### `value` + ++ 拒绝 leader 的 store 带有的 label value。 ++ 默认值:"" + +## dashboard + +PD 中内置的 [TiDB Dashboard](/dashboard/dashboard-intro.md) 相关配置项。 + +### `tidb-cacert-path` + ++ CA 根证书文件路径。可配置该路径来使用 TLS 连接 TiDB 的 SQL 服务。 ++ 默认值:"" + +### `tidb-cert-path` + ++ SSL 证书文件路径。可配置该路径来使用 TLS 连接 TiDB 的 SQL 服务。 ++ 默认值:"" + +### `tidb-key-path` + ++ SSL 私钥文件路径。可配置该路径来使用 TLS 连接 TiDB 的 SQL 服务。 ++ 默认值:"" + +### `public-path-prefix` + ++ 通过反向代理访问 TiDB Dashboard 时,配置反向代理提供服务的路径前缀。 ++ 默认值:"/dashboard" ++ 若不通过反向代理访问 TiDB Dashboard,**请勿配置该项**,否则可能导致 TiDB Dashboard 无法正常访问。关于该配置的详细使用场景,参见[通过反向代理使用 TiDB Dashboard](/dashboard/dashboard-ops-reverse-proxy.md)。 + +### `enable-telemetry` + ++ 是否启用 TiDB Dashboard 遥测功能。 ++ 默认值:false ++ 参阅[遥测](/telemetry.md)了解该功能详情。 + +## `replication-mode` + +Region 同步模式相关的配置项。更多详情,请参阅[启用自适应同步模式](/two-data-centers-in-one-city-deployment.md#启用自适应同步模式)。 + +## Controllor + +PD 中内置的 [Resource Control](/tidb-resource-control.md) 相关的配置项。 + +### `degraded-mode-wait-duration` + ++ 触发降级模式需要等待的时间。降级模式是指在 Local Token Bucket (LTB) 和 Global Token Bucket (GTB) 失联的情况下,LTB 将回退到默认的资源组配置,不再有 GTB 授权 token,从而保证在网络隔离或者异常情况下,服务不受影响。 ++ 默认值: 0s ++ 默认为不开启降级模式 + +### `request-unit` + +下面是 [Request Unit (RU)](/tidb-resource-control.md#什么是-request-unit-ru) 相关的配置项。 + +#### `read-base-cost` + ++ 每次读请求转换成 RU 的基准系数 ++ 默认值: 0.25 + +#### `write-base-cost` + ++ 每次写请求转换成 RU 的基准系数 ++ 默认值: 1 + +#### `read-cost-per-byte` + ++ 读流量转换成 RU 的基准系数 ++ 默认值: 1/(64 * 1024) ++ 1 RU = 64 KiB 读取字节 + +#### `write-cost-per-byte` + ++ 写流量转换成 RU 的基准系数 ++ 默认值: 1/1024 ++ 1 RU = 1 KiB 写入字节 + +#### `read-cpu-ms-cost` + ++ CPU 转换成 RU 的基准系数 ++ 默认值: 1/3 ++ 1 RU = 3 毫秒 CPU 时间 diff --git a/markdown-pages/zh/tidb/master/pd-recover.md b/markdown-pages/zh/tidb/master/pd-recover.md new file mode 100644 index 0000000..ef38467 --- /dev/null +++ b/markdown-pages/zh/tidb/master/pd-recover.md @@ -0,0 +1,164 @@ +--- +title: PD Recover 使用文档 +aliases: ['/docs-cn/dev/pd-recover/','/docs-cn/dev/reference/tools/pd-recover/'] +summary: PD Recover 是用于恢复无法正常启动或服务的 PD 集群的工具。安装方式包括从源代码编译和下载 TiDB 工具包。恢复集群的方式有两种:从存活的 PD 节点重建和完全重建。从存活的 PD 节点重建集群需要停止所有节点,启动存活的 PD 节点,并使用 pd-recover 修复元数据。完全重建 PD 集群需要获取 Cluster ID 和已分配 ID,部署新的 PD 集群,使用 pd-recover 修复,然后重启整个集群。 +--- + +# PD Recover 使用文档 + +PD Recover 是对 PD 进行灾难性恢复的工具,用于恢复无法正常启动或服务的 PD 集群。 + +## 安装 PD Recover + +要使用 PD Recover,你可以[从源代码编译](#从源代码编译),也可以直接[下载 TiDB 工具包](#下载-tidb-工具包)。 + +### 从源代码编译 + +* [Go](https://golang.org/):PD Recover 使用了 Go 模块,请安装 Go 1.21 或以上版本。 +* 在 [PD](https://github.com/pingcap/pd) 根目录下,运行 `make pd-recover` 命令来编译源代码并生成 `bin/pd-recover`。 + +> **注意:** +> +> 一般来说,用户不需要编译源代码,因为发布的二进制文件或 Docker 中已包含 PD Recover 工具。开发者可以参考以上步骤来编译源代码。 + +### 下载 TiDB 工具包 + +PD Recover 的安装包位于 TiDB 离线工具包中。下载方式,请参考 [TiDB 工具下载](/download-ecosystem-tools.md)。 + +下面介绍两种重建集群的方式:从存活的 PD 节点重建和完全重建。 + +## 方式一:从存活的 PD 节点重建集群 + +当 PD 集群的大多数节点发生灾难性故障时,集群将无法提供服务。当还有 PD 节点存活时,可以选择一个存活的 PD 节点,通过强制修改 Raft Group 的成员,使该节点重新恢复服务。具体操作步骤如下: + +### 第 1 步:停止所有节点 + +停止集群中的 TiDB、TiKV 和 TiFlash 服务进程,以防止在恢复过程中与 PD 参数交互,造成数据错乱或其他无法挽救的异常状况。 + +### 第 2 步:启动存活的 PD 节点 + +使用启动参数 `--force-new-cluster` 拉起该存活的 PD 节点,如: + +```shell +./bin/pd-server --force-new-cluster --name=pd-127.0.0.10-2379 --client-urls=http://0.0.0.0:2379 --advertise-client-urls=http://127.0.0.1:2379 --peer-urls=http://0.0.0.0:2380 --advertise-peer-urls=http://127.0.0.1:2380 --config=conf/pd.toml +``` + +### 第 3 步:使用 `pd-recover` 修复元数据 + +该方法是利用少数派 PD 节点恢复服务,但由于该节点可能存在数据落后的情况,因此对于 `alloc_id` 和 `tso` 等数据,一旦发生回退,可能导致集群数据错乱或不可用。为确保该节点能提供正确的分配 ID 和 TSO 等服务,需要使用 `pd-recover` 修改元数据。具体命令参考: + +```shell +./bin/pd-recover --from-old-member --endpoints=http://127.0.0.1:2379 # 指定对应的 PD 地址 +``` + +> **注意:** +> +> 该步骤会自动将存储中的 `alloc_id` 增加一个安全值 `100000000`。这将导致后续集群中分配的 ID 偏大。 +> +> 此外,`pd-recover` 不会修改 TSO。因此,在执行此步骤之前,请确保本地时间晚于故障发生时间,并且确认故障前 PD 组件之间已开启 NTP 时钟同步服务。如果未开启,则需要将本地时钟调整到一个未来的时间,以确保 TSO 不会回退。 + +### 第 4 步:重启这个 PD + +当上一步出现 `recovery is successful` 的提示信息后,重启 PD。 + +### 第 5 步:扩容 PD 并启动集群 + +通过部署工具扩容 PD,并启动集群中的其他组件。至此服务恢复。 + +## 方式二:完全重建 PD 集群 + +该方式适用于所有 PD 的数据都丢失,但 TiDB、TiKV 和 TiFlash 等其他组件数据都还存在的情况。 + +### 第 1 步:获取 Cluster ID + +一般在 PD、TiKV 或 TiDB 的日志中都可以获取 Cluster ID。你可以直接在服务器上查看日志以获取 Cluster ID。 + +#### 从 PD 日志获取 Cluster ID(推荐) + +使用以下命令,从 PD 日志中获取 Cluster ID: + +```bash +cat {{/path/to}}/pd.log | grep "init cluster id" +``` + +```bash +[2019/10/14 10:35:38.880 +00:00] [INFO] [server.go:212] ["init cluster id"] [cluster-id=6747551640615446306] +... +``` + +或者也可以从 TiDB 或 TiKV 的日志中获取。 + +#### 从 TiDB 日志获取 Cluster ID + +使用以下命令,从 TiDB 日志中获取 Cluster ID: + +```bash +cat {{/path/to}}/tidb.log | grep "init cluster id" +``` + +```bash +2019/10/14 19:23:04.688 client.go:161: [info] [pd] init cluster id 6747551640615446306 +... +``` + +#### 从 TiKV 日志获取 Cluster ID + +使用以下命令,从 TiKV 日志中获取 Cluster ID: + +```bash +cat {{/path/to}}/tikv.log | grep "connect to PD cluster" +``` + +```bash +[2019/10/14 07:06:35.278 +00:00] [INFO] [tikv-server.rs:464] ["connect to PD cluster 6747551640615446306"] +... +``` + +### 第 2 步:获取已分配 ID + +在指定已分配 ID 时,需指定一个比当前最大的已分配 ID 更大的值。可以从监控中获取已分配 ID,也可以直接在服务器上查看日志。 + +#### 从监控中获取已分配 ID(推荐) + +要从监控中获取已分配的 ID,需要确保你所查看的监控指标是**上一任 PD Leader** 的指标。可从 PD Dashboard 中 **Current ID allocation** 面板获取最大的已分配 ID。 + +#### 从 PD 日志获取已分配 ID + +要从 PD 日志中获取分配的 ID,需要确保你所查看的日志是**上一任 PD Leader** 的日志。运行以下命令获取最大的已分配 ID: + +```bash +cat {{/path/to}}/pd*.log | grep "idAllocator allocates a new id" | awk -F'=' '{print $2}' | awk -F']' '{print $1}' | sort -r -n | head -n 1 +``` + +```bash +4000 +... +``` + +你也可以在所有 PD server 中运行上述命令,找到最大的值。 + +### 第 3 步:部署一套新的 PD 集群 + +部署新的 PD 集群之前,需要停止当前的 PD 集群,然后删除旧的数据目录(或者用 `--data-dir` 指定新的数据目录)。 + +### 第 4 步:使用 pd-recover + +只需在一个 PD 节点上执行 `pd-recover` 即可。 + +```bash +./pd-recover -endpoints http://10.0.1.13:2379 -cluster-id 6747551640615446306 -alloc-id 10000 +``` + +### 第 5 步:重启整个集群 + +当出现 `recovery is successful` 的提示信息时,重启整个集群。 + +## 常见问题 + +### 获取 Cluster ID 时发现有多个 Cluster ID + +新建 PD 集群时,会生成新的 Cluster ID。可以通过日志判断旧集群的 Cluster ID。 + +### 执行 pd-recover 时返回错误 `dial tcp 10.0.1.13:2379: connect: connection refused` + +执行 pd-recover 时需要 PD 提供服务,请先部署并启动 PD 集群。 diff --git a/markdown-pages/zh/tidb/master/predicate-push-down.md b/markdown-pages/zh/tidb/master/predicate-push-down.md new file mode 100644 index 0000000..5ebd316 --- /dev/null +++ b/markdown-pages/zh/tidb/master/predicate-push-down.md @@ -0,0 +1,151 @@ +--- +title: 谓词下推 +aliases: ['/docs-cn/dev/predicate-push-down/'] +summary: TiDB 逻辑优化规则中的谓词下推旨在尽早完成数据过滤,减少数据传输或计算的开销。谓词下推适用于将过滤表达式计算下推到数据源,如示例 1、2、3。但对于存储层不支持的谓词、外连接中的谓词和包含用户变量的谓词则不能下推。 +--- + +# 谓词下推 + +本文档介绍 TiDB 逻辑优化规则中的谓词下推规则,旨在让读者对谓词下推形成理解,并了解常见的谓词下推适用及不适用的场景。 + +谓词下推将查询语句中的过滤表达式计算尽可能下推到距离数据源最近的地方,以尽早完成数据的过滤,进而显著地减少数据传输或计算的开销。 + +## 示例 + +以下通过一些例子对谓词下推优化进行说明,其中示例 1、2、3 为谓词下推适用的案例,示例 4、5、6 为谓词下推不适用的案例。 + +### 示例 1: 谓词下推到存储层 + +```sql +create table t(id int primary key, a int); +explain select * from t where a < 1; ++-------------------------+----------+-----------+---------------+--------------------------------+ +| id | estRows | task | access object | operator info | ++-------------------------+----------+-----------+---------------+--------------------------------+ +| TableReader_7 | 3323.33 | root | | data:Selection_6 | +| └─Selection_6 | 3323.33 | cop[tikv] | | lt(test.t.a, 1) | +| └─TableFullScan_5 | 10000.00 | cop[tikv] | table:t | keep order:false, stats:pseudo | ++-------------------------+----------+-----------+---------------+--------------------------------+ +3 rows in set (0.00 sec) +``` + +在该查询中,将谓词 `a < 1` 下推到 TiKV 上对数据进行过滤,可以减少由于网络传输带来的开销。 + +### 示例 2: 谓词下推到存储层 + +```sql +create table t(id int primary key, a int not null); +explain select * from t where a < substring('123', 1, 1); ++-------------------------+----------+-----------+---------------+--------------------------------+ +| id | estRows | task | access object | operator info | ++-------------------------+----------+-----------+---------------+--------------------------------+ +| TableReader_7 | 3323.33 | root | | data:Selection_6 | +| └─Selection_6 | 3323.33 | cop[tikv] | | lt(test.t.a, 1) | +| └─TableFullScan_5 | 10000.00 | cop[tikv] | table:t | keep order:false, stats:pseudo | ++-------------------------+----------+-----------+---------------+--------------------------------+ +``` + +该查询与示例 1 中的查询生成了完成一样的执行计划,这是因为谓词 `a < substring('123', 1, 1)` 的 `substring` 的入参均为常量,因此可以提前计算,进而简化得到等价的谓词 `a < 1`。进一步的,可以将 `a < 1` 下推至 TiKV 上。 + +### 示例 3: 谓词下推到 join 下方 + +```sql +create table t(id int primary key, a int not null); +create table s(id int primary key, a int not null); +explain select * from t join s on t.a = s.a where t.a < 1; ++------------------------------+----------+-----------+---------------+--------------------------------------------+ +| id | estRows | task | access object | operator info | ++------------------------------+----------+-----------+---------------+--------------------------------------------+ +| HashJoin_8 | 4154.17 | root | | inner join, equal:[eq(test.t.a, test.s.a)] | +| ├─TableReader_15(Build) | 3323.33 | root | | data:Selection_14 | +| │ └─Selection_14 | 3323.33 | cop[tikv] | | lt(test.s.a, 1) | +| │ └─TableFullScan_13 | 10000.00 | cop[tikv] | table:s | keep order:false, stats:pseudo | +| └─TableReader_12(Probe) | 3323.33 | root | | data:Selection_11 | +| └─Selection_11 | 3323.33 | cop[tikv] | | lt(test.t.a, 1) | +| └─TableFullScan_10 | 10000.00 | cop[tikv] | table:t | keep order:false, stats:pseudo | ++------------------------------+----------+-----------+---------------+--------------------------------------------+ +7 rows in set (0.00 sec) +``` + +在该查询中,将谓词 `t.a < 1` 下推到 join 前进行过滤,可以减少 join 时的计算开销。 + +此外,这条 SQL 执行的是内连接,且 `ON` 条件是 `t.a = s.a`,可以由 `t.a < 1` 推导出谓词 `s.a < 1`,并将其下推至 join 运算前对 `s` 表进行过滤,可以进一步减少 join 时的计算开销。 + +### 示例 4: 存储层不支持的谓词无法下推 + +```sql +create table t(id int primary key, a varchar(10) not null); +desc select * from t where truncate(a, " ") = '1'; ++-------------------------+----------+-----------+---------------+---------------------------------------------------+ +| id | estRows | task | access object | operator info | ++-------------------------+----------+-----------+---------------+---------------------------------------------------+ +| Selection_5 | 8000.00 | root | | eq(truncate(cast(test.t.a, double BINARY), 0), 1) | +| └─TableReader_7 | 10000.00 | root | | data:TableFullScan_6 | +| └─TableFullScan_6 | 10000.00 | cop[tikv] | table:t | keep order:false, stats:pseudo | ++-------------------------+----------+-----------+---------------+---------------------------------------------------+ +``` + +在该查询中,存在谓词 `truncate(a, " ") = '1'`。 + +从 explain 结果中可以看到,该谓词没有被下推到 TiKV 上进行计算,这是因为 TiKV coprocessor 中没有对 `truncate` 内置函数进行支持,因此无法将其下推到 TiKV 上。 + +### 示例 5: 外连接中内表上的谓词不能下推 + +```sql +create table t(id int primary key, a int not null); +create table s(id int primary key, a int not null); +explain select * from t left join s on t.a = s.a where s.a is null; ++-------------------------------+----------+-----------+---------------+-------------------------------------------------+ +| id | estRows | task | access object | operator info | ++-------------------------------+----------+-----------+---------------+-------------------------------------------------+ +| Selection_7 | 10000.00 | root | | isnull(test.s.a) | +| └─HashJoin_8 | 12500.00 | root | | left outer join, equal:[eq(test.t.a, test.s.a)] | +| ├─TableReader_13(Build) | 10000.00 | root | | data:TableFullScan_12 | +| │ └─TableFullScan_12 | 10000.00 | cop[tikv] | table:s | keep order:false, stats:pseudo | +| └─TableReader_11(Probe) | 10000.00 | root | | data:TableFullScan_10 | +| └─TableFullScan_10 | 10000.00 | cop[tikv] | table:t | keep order:false, stats:pseudo | ++-------------------------------+----------+-----------+---------------+-------------------------------------------------+ +6 rows in set (0.00 sec) +``` + +在该查询中,内表 s 上存在谓词 `s.a is null`。 + +从 explain 中可以看到,该谓词没有被下推到 join 前进行计算,这是因为外连接在不满足 on 条件时会对内表填充 NULL,而在该查询中 `s.a is null` 用来对 join 后的结果进行过滤,如果将其下推到 join 前在内表上进行过滤,则下推前后不等价,因此不可进行下推。 + +### 示例 6: 谓词中包含用户变量时不能下推 + +```sql +create table t(id int primary key, a char); +set @a = 1; +explain select * from t where a < @a; ++-------------------------+----------+-----------+---------------+--------------------------------+ +| id | estRows | task | access object | operator info | ++-------------------------+----------+-----------+---------------+--------------------------------+ +| Selection_5 | 8000.00 | root | | lt(test.t.a, getvar("a")) | +| └─TableReader_7 | 10000.00 | root | | data:TableFullScan_6 | +| └─TableFullScan_6 | 10000.00 | cop[tikv] | table:t | keep order:false, stats:pseudo | ++-------------------------+----------+-----------+---------------+--------------------------------+ +3 rows in set (0.00 sec) +``` + +在该查询中,表 t 上存在谓词 `a < @a`,其中 `@a` 为值为 1 的用户变量。 + +从 explain 中可以看到,该谓词没有像示例 2 中一样,将谓词简化为 `a < 1` 并下推到 TiKV 上进行计算。这是因为,用户变量 `@a` 的值可能会某些场景下在查询过程中发生改变,且 TiKV 对于用户变量 `@a` 的值不可知,因此 TiDB 不会将 `@a` 替换为 1,且不会下推至 TiKV 上进行计算。 + +一个帮助理解的例子如下: + +```sql +create table t(id int primary key, a int); +insert into t values(1, 1), (2,2); +set @a = 1; +select id, a, @a:=@a+1 from t where a = @a; ++----+------+----------+ +| id | a | @a:=@a+1 | ++----+------+----------+ +| 1 | 1 | 2 | +| 2 | 2 | 3 | ++----+------+----------+ +2 rows in set (0.00 sec) +``` + +可以从在该查询中看到,`@a` 的值会在查询过程中发生改变,因此如果将 `a = @a` 替换为 `a = 1` 并下推至 TiKV,则优化前后不等价。 diff --git a/markdown-pages/zh/tidb/master/privilege-management.md b/markdown-pages/zh/tidb/master/privilege-management.md new file mode 100644 index 0000000..fb3624d --- /dev/null +++ b/markdown-pages/zh/tidb/master/privilege-management.md @@ -0,0 +1,524 @@ +--- +title: 权限管理 +aliases: ['/docs-cn/dev/privilege-management/','/docs-cn/dev/reference/security/privilege-system/'] +summary: TiDB 支持 MySQL 5.7 和 MySQL 8.0 的权限管理系统。权限相关操作包括授予权限、收回权限、查看用户权限和动态权限。权限系统的实现包括授权表和连接验证。权限生效时机是在 TiDB 启动时加载到内存,并且可以手动刷新。 +--- + +# 权限管理 + +TiDB 支持 MySQL 5.7 的权限管理系统,包括 MySQL 的语法和权限类型。同时 TiDB 还支持 MySQL 8.0 的以下特性: + +* 从 TiDB 3.0 开始,支持 SQL 角色。 +* 从 TiDB 5.1 开始,支持动态权限。 + +本文档主要介绍 TiDB 权限相关操作、各项操作需要的权限以及权限系统的实现。 + +## 权限相关操作 + +### 授予权限 + +授予 `xxx` 用户对数据库 `test` 的读权限: + +```sql +GRANT SELECT ON test.* TO 'xxx'@'%'; +``` + +为 `xxx` 用户授予所有数据库,全部权限: + +```sql +GRANT ALL PRIVILEGES ON *.* TO 'xxx'@'%'; +``` + +默认情况下,如果指定的用户不存在,`GRANT` 语句将报错。该行为受 SQL Mode 中的 `NO_AUTO_CREATE_USER` 控制。 + +```sql +SET sql_mode=DEFAULT; +Query OK, 0 rows affected (0.00 sec) + +SELECT @@sql_mode; ++-------------------------------------------------------------------------------------------------------------------------------------------+ +| @@sql_mode | ++-------------------------------------------------------------------------------------------------------------------------------------------+ +| ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION | ++-------------------------------------------------------------------------------------------------------------------------------------------+ +1 row in set (0.00 sec) + +SELECT * FROM mysql.user WHERE user='idontexist'; +Empty set (0.00 sec) + +GRANT ALL PRIVILEGES ON test.* TO 'idontexist'; +ERROR 1105 (HY000): You are not allowed to create a user with GRANT + +SELECT user,host,authentication_string FROM mysql.user WHERE user='idontexist'; +Empty set (0.00 sec) +``` + +在下面的例子中,由于没有将 SQL Mode 设置为 `NO_AUTO_CREATE_USER`,用户 `idontexist` 会被自动创建且密码为空。**不推荐**使用这种方式,因为会带来安全风险:如果用户名拼写错误,会导致新用户被创建且密码为空。 + +```sql +SET @@sql_mode='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'; +Query OK, 0 rows affected (0.00 sec) + +SELECT @@sql_mode; ++-----------------------------------------------------------------------------------------------------------------------+ +| @@sql_mode | ++-----------------------------------------------------------------------------------------------------------------------+ +| ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION | ++-----------------------------------------------------------------------------------------------------------------------+ +1 row in set (0.00 sec) + +SELECT * FROM mysql.user WHERE user='idontexist'; +Empty set (0.00 sec) + +GRANT ALL PRIVILEGES ON test.* TO 'idontexist'; +Query OK, 1 row affected (0.05 sec) + +SELECT user,host,authentication_string FROM mysql.user WHERE user='idontexist'; ++------------+------+-----------------------+ +| user | host | authentication_string | ++------------+------+-----------------------+ +| idontexist | % | | ++------------+------+-----------------------+ +1 row in set (0.01 sec) +``` + +`GRANT` 还可以模糊匹配地授予用户数据库的权限: + +```sql +GRANT ALL PRIVILEGES ON `te%`.* TO genius; +``` + +``` +Query OK, 0 rows affected (0.00 sec) +``` + +```sql +SELECT user,host,db FROM mysql.db WHERE user='genius'; +``` + +``` ++--------|------|-----+ +| user | host | db | ++--------|------|-----+ +| genius | % | te% | ++--------|------|-----+ +1 row in set (0.00 sec) +``` + +这个例子中通过 `%` 模糊匹配,所有 `te` 开头的数据库,都被授予了权限。 + +### 收回权限 + +`REVOKE` 语句与 `GRANT` 对应: + +```sql +REVOKE ALL PRIVILEGES ON `test`.* FROM 'genius'@'localhost'; +``` + +> **注意:** +> +> `REVOKE` 收回权限时只做精确匹配,若找不到记录则报错。而 `GRANT` 授予权限时可以使用模糊匹配。 + +```sql +REVOKE ALL PRIVILEGES ON `te%`.* FROM 'genius'@'%'; +``` + +``` +ERROR 1141 (42000): There is no such grant defined for user 'genius' on host '%' +``` + +关于模糊匹配和转义,字符串和 identifier: + +```sql +GRANT ALL PRIVILEGES ON `te\%`.* TO 'genius'@'localhost'; +``` + +``` +Query OK, 0 rows affected (0.00 sec) +``` + +上述例子是精确匹配名为 `te%` 的数据库,注意使用 `\` 转义字符。 + +以单引号包含的部分,是一个字符串。以反引号包含的部分,是一个 identifier。注意下面的区别: + +```sql +GRANT ALL PRIVILEGES ON 'test'.* TO 'genius'@'localhost'; +``` + +``` +ERROR 1064 (42000): You have an error in your SQL syntax; check the +manual that corresponds to your MySQL server version for the right +syntax to use near ''test'.* to 'genius'@'localhost'' at line 1 +``` + +```sql +GRANT ALL PRIVILEGES ON `test`.* TO 'genius'@'localhost'; +``` + +``` +Query OK, 0 rows affected (0.00 sec) +``` + +如果想将一些特殊的关键字做为表名,可以用反引号包含起来。比如: + +```sql +CREATE TABLE `select` (id int); +``` + +``` +Query OK, 0 rows affected (0.27 sec) +``` + +### 查看为用户分配的权限 + +`SHOW GRANTS` 语句可以查看为用户分配了哪些权限。例如: + +查看当前用户的权限: + +```sql +SHOW GRANTS; +``` + +``` ++-------------------------------------------------------------+ +| Grants for User | ++-------------------------------------------------------------+ +| GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION | ++-------------------------------------------------------------+ +``` + +或者: + +```sql +SHOW GRANTS FOR CURRENT_USER(); +``` + +查看某个特定用户的权限: + +```sql +SHOW GRANTS FOR 'user'@'host'; +``` + +例如,创建一个用户 `rw_user@192.168.%` 并为其授予 `test.write_table` 表的写权限,和全局读权限。 + +```sql +CREATE USER `rw_user`@`192.168.%`; +GRANT SELECT ON *.* TO `rw_user`@`192.168.%`; +GRANT INSERT, UPDATE ON `test`.`write_table` TO `rw_user`@`192.168.%`; +``` + +查看用户 `rw_user@192.168.%` 的权限。 + +```sql +SHOW GRANTS FOR `rw_user`@`192.168.%`; +``` + +``` ++------------------------------------------------------------------+ +| Grants for rw_user@192.168.% | ++------------------------------------------------------------------+ +| GRANT Select ON *.* TO 'rw_user'@'192.168.%' | +| GRANT Insert,Update ON test.write_table TO 'rw_user'@'192.168.%' | ++------------------------------------------------------------------+ +``` + +### 动态权限 + +从 v5.1 开始,TiDB 支持 MySQL 8.0 中的动态权限特性。动态权限用于限制 `SUPER` 权限,实现对某些操作更细粒度的访问。例如,系统管理员可以使用动态权限来创建一个只能执行 `BACKUP` 和 `RESTORE` 操作的用户帐户。 + +动态权限包括: + +* `BACKUP_ADMIN` +* `RESTORE_ADMIN` +* `SYSTEM_USER` +* `SYSTEM_VARIABLES_ADMIN` +* `ROLE_ADMIN` +* `CONNECTION_ADMIN` +* `PLACEMENT_ADMIN` 允许创建、删除和修改放置策略 (placement policy)。 +* `DASHBOARD_CLIENT` 允许登录 TiDB Dashboard。 +* `RESTRICTED_TABLES_ADMIN` 允许在 SEM 打开的情况下查看系统表。 +* `RESTRICTED_STATUS_ADMIN` 允许在 SEM 打开的情况下查看 [`SHOW [GLOBAL|SESSION] STATUS`](/sql-statements/sql-statement-show-status.md) 中的状态变量。 +* `RESTRICTED_VARIABLES_ADMIN` 允许在 SEM 打开的情况下查看所有系统变量。 +* `RESTRICTED_USER_ADMIN` 不允许在 SEM 打开的情况下使用 `SUPER` 用户撤销访问权限。 +* `RESTRICTED_CONNECTION_ADMIN` 允许 KILL 属于 `RESTRICTED_USER_ADMIN` 用户的连接。该权限对 `KILL` 和 `KILL TIDB` 语句生效。 +* `RESTRICTED_REPLICA_WRITER_ADMIN` 允许权限拥有者在 TiDB 集群开启了只读模式的情况下不受影响地执行写入或更新操作,详见 [`tidb_restricted_read_only` 配置项](/system-variables.md#tidb_restricted_read_only-从-v520-版本开始引入)。 + +若要查看全部的动态权限,请执行 `SHOW PRIVILEGES` 语句。由于用户可使用插件来添加新的权限,因此可分配的权限列表可能因用户的 TiDB 安装情况而异。 + +## `SUPER` 权限 + +- 拥有 `SUPER` 权限的用户能完成几乎所有的操作,默认情况下只有 `root` 用户拥有该权限。请谨慎向其它用户授予 `SUPER` 权限。 +- `SUPER` 权限[在 MySQL 8.0 中被认为是过时的](https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html#dynamic-privileges-migration-from-super),可以通过[动态权限](#动态权限)替代 `SUPER` 权限进行更细粒度的权限控制。 + +## TiDB 各操作需要的权限 + +TiDB 用户目前拥有的权限可以在 `INFORMATION_SCHEMA.USER_PRIVILEGES` 表中查找到。例如: + +```sql +SELECT * FROM INFORMATION_SCHEMA.USER_PRIVILEGES WHERE grantee = "'root'@'%'"; ++------------+---------------+-------------------------+--------------+ +| GRANTEE | TABLE_CATALOG | PRIVILEGE_TYPE | IS_GRANTABLE | ++------------+---------------+-------------------------+--------------+ +| 'root'@'%' | def | Select | YES | +| 'root'@'%' | def | Insert | YES | +| 'root'@'%' | def | Update | YES | +| 'root'@'%' | def | Delete | YES | +| 'root'@'%' | def | Create | YES | +| 'root'@'%' | def | Drop | YES | +| 'root'@'%' | def | Process | YES | +| 'root'@'%' | def | References | YES | +| 'root'@'%' | def | Alter | YES | +| 'root'@'%' | def | Show Databases | YES | +| 'root'@'%' | def | Super | YES | +| 'root'@'%' | def | Execute | YES | +| 'root'@'%' | def | Index | YES | +| 'root'@'%' | def | Create User | YES | +| 'root'@'%' | def | Create Tablespace | YES | +| 'root'@'%' | def | Trigger | YES | +| 'root'@'%' | def | Create View | YES | +| 'root'@'%' | def | Show View | YES | +| 'root'@'%' | def | Create Role | YES | +| 'root'@'%' | def | Drop Role | YES | +| 'root'@'%' | def | CREATE TEMPORARY TABLES | YES | +| 'root'@'%' | def | LOCK TABLES | YES | +| 'root'@'%' | def | CREATE ROUTINE | YES | +| 'root'@'%' | def | ALTER ROUTINE | YES | +| 'root'@'%' | def | EVENT | YES | +| 'root'@'%' | def | SHUTDOWN | YES | +| 'root'@'%' | def | RELOAD | YES | +| 'root'@'%' | def | FILE | YES | +| 'root'@'%' | def | CONFIG | YES | +| 'root'@'%' | def | REPLICATION CLIENT | YES | +| 'root'@'%' | def | REPLICATION SLAVE | YES | ++------------+---------------+-------------------------+--------------+ +31 rows in set (0.00 sec) +``` + +### ALTER + +- 对于所有的 `ALTER` 语句,均需要用户对所操作的表拥有 `ALTER` 权限。 +- 除 `ALTER...DROP` 和 `ALTER...RENAME TO` 外,均需要对所操作表拥有 `INSERT` 和 `CREATE` 权限。 +- 对于 `ALTER...DROP` 语句,需要对表拥有 `DROP` 权限。 +- 对于 `ALTER...RENAME TO` 语句,需要对重命名前的表拥有 `DROP` 权限,对重命名后的表拥有 `CREATE` 和 `INSERT` 权限。 + +> **注意:** +> +> 根据 MySQL 5.7 文档中的说明,对表进行 `ALTER` 操作需要 `INSERT` 和 `CREATE` 权限,但在 MySQL 5.7.25 版本实际情况中,该操作仅需要 `ALTER` 权限。目前,TiDB 中的 `ALTER` 权限与 MySQL 实际行为保持一致。 + +### BACKUP + +需要拥有 `SUPER` 或者 `BACKUP_ADMIN` 权限。 + +### CANCEL IMPORT JOB + +需要 `SUPER` 权限来取消属于其他用户的任务,否则只能取消当前用户创建的任务。 + +### CREATE DATABASE + +需要拥有全局 `CREATE` 权限。 + +### CREATE INDEX + +需要对所操作的表拥有 `INDEX` 权限。 + +### CREATE TABLE + +需要对要创建的表所在的数据库拥有 `CREATE` 权限;若使用 `CREATE TABLE...LIKE...` 需要对相关的表拥有 `SELECT` 权限。 + +### CREATE VIEW + +需要拥有 `CREATE VIEW` 权限。 + +> **注意:** +> +> 如果当前登录用户与创建视图的用户不同,除需要 `CREATE VIEW` 权限外,还需要 `SUPER` 权限。 + +### DROP DATABASE + +需要对数据库拥有 `DROP` 权限。 + +### DROP INDEX + +需要对所操作的表拥有 `INDEX` 权限。 + +### DROP TABLES + +需要对所操作的表拥有 `DROP` 权限。 + +### IMPORT INTO + +需要对目标表拥有 `SELECT`、`UPDATE`、`INSERT`、`DELETE` 和 `ALTER` 权限。如果是导入存储在 TiDB 本地的文件,还需要有 `FILE` 权限。 + +### LOAD DATA + +`LOAD DATA` 需要对所操作的表拥有 `INSERT` 权限。执行 `REPLACE INTO` 语句还需要对所操作的表拥有 `DELETE` 权限。 + +### TRUNCATE TABLE + +需要对所操作的表拥有 `DROP` 权限。 + +### RENAME TABLE + +需要对重命名前的表拥有 `ALTER` 和 `DROP` 权限,对重命名后的表拥有 `CREATE` 和 `INSERT` 权限。 + +### ANALYZE TABLE + +需要对所操作的表拥有 `INSERT` 和 `SELECT` 权限。 + +### LOCK STATS + +需要对所操作的表拥有 `INSERT` 和 `SELECT` 权限。 + +### UNLOCK STATS + +需要对所操作的表拥有 `INSERT` 和 `SELECT` 权限。 + +### SHOW + +`SHOW CREATE TABLE` 需要任意一种权限。 + +`SHOW CREATE VIEW` 需要 `SHOW VIEW` 权限。 + +`SHOW GRANTS` 需要拥有对 `mysql` 数据库的 `SELECT` 权限。如果是使用 `SHOW GRANTS` 查看当前用户权限,则不需要任何权限。 + +`SHOW PROCESSLIST` 需要 `SUPER` 权限来显示属于其他用户的连接。 + +`SHOW IMPORT JOB` 需要 `SUPER` 权限来显示属于其他用户的任务,否则只能看到当前用户创建的任务。 + +`SHOW STATS_LOCKED` 需要拥有 `mysql.stats_table_locked` 表的 `SELECT` 权限。 + +### CREATE ROLE/USER + +`CREATE ROLE` 需要 `CREATE ROLE` 权限。 + +`CREATE USER` 需要 `CREATE USER` 权限 + +### DROP ROLE/USER + +`DROP ROLE` 需要 `DROP ROLE` 权限。 + +`DROP USER` 需要 `CREATE USER` 权限 + +### ALTER USER + +`ALTER USER` 需要 `CREATE USER` 权限。 + +### GRANT + +`GRANT` 需要 `GRANT` 权限并且拥有 `GRANT` 所赋予的权限。 + +如果在 `GRANTS` 语句中创建用户,需要有 `CREATE USER` 权限。 + +`GRANT ROLE` 操作需要拥有 `SUPER` 或者 `ROLE_ADMIN` 权限。 + +### REVOKE + +`REVOKE` 需要 `GRANT` 权限并且拥有 `REVOKE` 所指定要撤销的权限。 + +`REVOKE ROLE` 操作需要拥有 `SUPER` 或者 `ROLE_ADMIN` 权限。 + +### SET GLOBAL + +使用 `SET GLOBAL` 设置全局变量需要拥有 `SUPER` 或者 `SYSTEM_VARIABLES_ADMIN` 权限。 + +### ADMIN + +需要拥有 `SUPER` 权限。 + +### SET DEFAULT ROLE + +需要拥有 `SUPER` 权限。 + +### KILL + +使用 `KILL` 终止其他用户的会话需要拥有 `SUPER` 或者 `CONNECTION_ADMIN` 权限。 + +### CREATE RESOURCE GROUP + +需要拥有 `SUPER` 或者 `RESOURCE_GROUP_ADMIN` 权限。 + +### ALTER RESOURCE GROUP + +需要拥有 `SUPER` 或者 `RESOURCE_GROUP_ADMIN` 权限。 + +### DROP RESOURCE GROUP + +需要拥有 `SUPER` 或者 `RESOURCE_GROUP_ADMIN` 权限。 + +### CALIBRATE RESOURCE + +需要拥有 `SUPER` 或者 `RESOURCE_GROUP_ADMIN` 权限。 + +## 权限系统的实现 + +### 授权表 + +以下几张系统表是非常特殊的表,权限相关的数据全部存储在这几张表内。 + +- `mysql.user`:用户账户,全局权限 +- `mysql.db`:数据库级别的权限 +- `mysql.tables_priv`:表级别的权限 +- `mysql.columns_priv`:列级别的权限,当前暂不支持 + +这几张表包含了数据的生效范围和权限信息。例如,`mysql.user` 表的部分数据: + +```sql +SELECT User,Host,Select_priv,Insert_priv FROM mysql.user LIMIT 1; +``` + +``` ++------|------|-------------|-------------+ +| User | Host | Select_priv | Insert_priv | ++------|------|-------------|-------------+ +| root | % | Y | Y | ++------|------|-------------|-------------+ +1 row in set (0.00 sec) +``` + +这条记录中,`Host` 和 `User` 决定了 root 用户从任意主机 (%) 发送过来的连接请求可以被接受,而 `Select_priv` 和 `Insert_priv` 表示用户拥有全局的 `Select` 和 `Insert` 权限。`mysql.user` 这张表里面的生效范围是全局的。 + +`mysql.db` 表里面包含的 `Host` 和 `User` 决定了用户可以访问哪些数据库,权限列的生效范围是数据库。 + +理论上,所有权限管理相关的操作,都可以通过直接对授权表的 CRUD 操作完成。 + +实现层面其实也只是包装了一层语法糖。例如删除用户会执行: + +```sql +DELETE FROM mysql.user WHERE user='test'; +``` + +但是,不推荐手动修改授权表,建议使用 `DROP USER` 语句: + +```sql +DROP USER 'test'; +``` + +### 连接验证 + +当客户端发送连接请求时,TiDB 服务器会对登录操作进行验证。验证过程先检查 `mysql.user` 表,当某条记录的 `User` 和 `Host` 和连接请求匹配上了,再去验证 `authentication_string`。用户身份基于两部分信息,发起连接的客户端的 `Host`,以及用户名 `User`。如果 `User` 不为空,则用户名必须精确匹配。 + +User+Host 可能会匹配 `user` 表里面多行,为了处理这种情况,`user` 表的行是排序过的,客户端连接时会依次去匹配,并使用首次匹配到的那一行做权限验证。排序是按 `Host` 在前,`User` 在后。 + +### 请求验证 + +连接成功之后,请求验证会检测执行操作是否拥有足够的权限。 + +对于数据库相关请求 (`INSERT`, `UPDATE`),先检查 `mysql.user` 表里面的用户全局权限,如果权限够,则直接可以访问。如果全局权限不足,则再检查 `mysql.db` 表。 + +`user` 表的权限是全局的,并且不管默认数据库是哪一个。比如 `user` 里面有 `DELETE` 权限,任何一行,任何的表,任何的数据库。 + +`db`表里面,User 为空是匹配匿名用户,User 里面不能有通配符。Host 和 Db 列里面可以有 `%` 和 `_`,可以模式匹配。 + +`user` 和 `db` 读到内存也是排序的。 + +`tables_priv` 和 `columns_priv` 中使用 `%` 是类似的,但是在`Db`, `Table_name`, `Column_name` 这些列不能包含 `%`。加载进来时排序也是类似的。 + +### 生效时机 + +TiDB 启动时,将一些权限检查的表加载到内存,之后使用缓存的数据来验证权限。系统会周期性的将授权表从数据库同步到缓存,生效则是由同步的周期决定,目前这个值设定的是 5 分钟。 + +修改了授权表,如果需要立即生效,可以手动调用: + +```sql +FLUSH PRIVILEGES; +``` diff --git a/markdown-pages/zh/tidb/master/read-historical-data.md b/markdown-pages/zh/tidb/master/read-historical-data.md new file mode 100644 index 0000000..b20ce46 --- /dev/null +++ b/markdown-pages/zh/tidb/master/read-historical-data.md @@ -0,0 +1,205 @@ +--- +title: 通过系统变量 tidb_snapshot 读取历史数据 +aliases: ['/docs-cn/dev/read-historical-data/','/docs-cn/dev/how-to/get-started/read-historical-data/'] +summary: 本文介绍了通过系统变量 `tidb_snapshot` 读取历史数据的操作流程和历史数据的保留策略。TiDB 实现了通过标准 SQL 接口读取历史数据功能,无需特殊的 client 或者 driver。当数据被更新、删除后,依然可以通过 SQL 接口将更新 / 删除前的数据读取出来。历史数据保留策略使用 MVCC 管理版本,超过一定时间的历史数据会被彻底删除,以减小空间占用以及避免历史版本过多引入的性能开销。 +--- + +# 通过系统变量 tidb_snapshot 读取历史数据 + +本文档介绍如何通过系统变量 `tidb_snapshot` 读取历史数据,包括具体的操作流程以及历史数据的保存策略。 + +> **注意:** +> +> 你还可以使用 [Stale Read](/stale-read.md) 功能读取历史数据。更推荐使用 Stale Read 读取历史数据。 + +## 功能说明 + +TiDB 实现了通过标准 SQL 接口读取历史数据功能,无需特殊的 client 或者 driver。当数据被更新、删除后,依然可以通过 SQL 接口将更新/删除前的数据读取出来。 + +> **注意:** +> +> 读取历史数据时,即使当前数据的表结构相较于历史数据的表结构已经发生改变,历史数据也会使用当时的表结构来返回数据。 + +## 操作流程 + +为支持读取历史版本数据,TiDB 引入了一个新的系统变量 [`tidb_snapshot`](/system-variables.md#tidb_snapshot): + +- 这个变量的作用域为 `SESSION`。 +- 你可以通过标准的 `SET` 语句修改这个变量的值。 +- 这个变量的数据类型为文本类型,能够存储 TSO 和日期时间。TSO 是从 PD 端获取的全局授时的时间戳,日期时间的格式为:"2016-10-08 16:45:26.999",一般来说可以只写到秒,比如”2016-10-08 16:45:26”。 +- 当这个变量被设置时,TiDB 会按照设置的时间戳建立 Snapshot(没有开销,只是创建数据结构),随后所有的 `SELECT` 操作都会从这个 Snapshot 上读取数据。 + +> **注意:** +> +> TiDB 的事务是通过 PD 进行全局授时,所以存储的数据版本也是以 PD 所授时间戳作为版本号。在生成 Snapshot 时,是以 tidb_snapshot 变量的值作为版本号,如果 TiDB Server 所在机器和 PD Server 所在机器的本地时间相差较大,需要以 PD 的时间为准。 + +当读取历史版本操作结束后,可以结束当前 Session 或者是通过 `SET` 语句将 tidb_snapshot 变量的值设为 "",即可读取最新版本的数据。 + +## 历史数据保留策略 + +TiDB 使用 MVCC 管理版本,当更新/删除数据时,不会做真正的数据删除,只会添加一个新版本数据,所以可以保留历史数据。历史数据不会全部保留,超过一定时间的历史数据会被彻底删除,以减小空间占用以及避免历史版本过多引入的性能开销。 + +TiDB 使用周期性运行的 GC(Garbage Collection,垃圾回收)来进行清理,关于 GC 的详细介绍参见 [TiDB 垃圾回收 (GC)](/garbage-collection-overview.md)。 + +这里需要重点关注的是: + +- 使用系统变量 [`tidb_gc_life_time`](/system-variables.md#tidb_gc_life_time-从-v50-版本开始引入) 可以配置历史版本的保留时间(默认值是 `10m0s`)。 +- 使用 SQL 语句 `SELECT * FROM mysql.tidb WHERE variable_name = 'tikv_gc_safe_point'` 可以查询当前的 safePoint,即当前可以读的最旧的快照。在每次 GC 开始运行时,safePoint 将自动更新。 + +## 示例 + +1. 初始化阶段,创建一个表,并插入几行数据: + + ```sql + create table t (c int); + ``` + + ``` + Query OK, 0 rows affected (0.01 sec) + ``` + + ```sql + insert into t values (1), (2), (3); + ``` + + ``` + Query OK, 3 rows affected (0.00 sec) + ``` + +2. 查看表中的数据: + + ```sql + select * from t; + ``` + + ``` + +------+ + | c | + +------+ + | 1 | + | 2 | + | 3 | + +------+ + 3 rows in set (0.00 sec) + ``` + +3. 查看当前时间: + + ```sql + select now(); + ``` + + ``` + +---------------------+ + | now() | + +---------------------+ + | 2016-10-08 16:45:26 | + +---------------------+ + 1 row in set (0.00 sec) + ``` + +4. 更新某一行数据: + + ```sql + update t set c=22 where c=2; + ``` + + ``` + Query OK, 1 row affected (0.00 sec) + ``` + +5. 确认数据已经被更新: + + ```sql + select * from t; + ``` + + ``` + +------+ + | c | + +------+ + | 1 | + | 22 | + | 3 | + +------+ + 3 rows in set (0.00 sec) + ``` + +6. 设置一个特殊的环境变量,这个是一个 session scope 的变量,其意义为读取这个时间之前的最新的一个版本。 + + ```sql + set @@tidb_snapshot="2016-10-08 16:45:26"; + ``` + + ``` + Query OK, 0 rows affected (0.00 sec) + ``` + + > **注意:** + > + > - 这里的时间设置的是 update 语句之前的那个时间。 + > - 在 `tidb_snapshot` 前须使用 `@@` 而非 `@`,因为 `@@` 表示系统变量,`@` 表示用户变量。 + + 这里读取到的内容即为 update 之前的内容,也就是历史版本: + + ```sql + select * from t; + ``` + + ``` + +------+ + | c | + +------+ + | 1 | + | 2 | + | 3 | + +------+ + 3 rows in set (0.00 sec) + ``` + +7. 清空这个变量后,即可读取最新版本数据: + + ```sql + set @@tidb_snapshot=""; + ``` + + ``` + Query OK, 0 rows affected (0.00 sec) + ``` + + ```sql + select * from t; + ``` + + ``` + +------+ + | c | + +------+ + | 1 | + | 22 | + | 3 | + +------+ + 3 rows in set (0.00 sec) + ``` + + > **注意:** + > + > 在 `tidb_snapshot` 前须使用 `@@` 而非 `@`,因为 `@@` 表示系统变量,`@` 表示用户变量。 + +## 历史数据恢复策略 + +在恢复历史版本的数据之前,需要确保在对数据进行操作时,垃圾回收机制 (GC) 不会清除历史数据。如下所示,可以通过设置 `tidb_gc_life_time` 变量来调整 GC 清理的周期。不要忘记在恢复历史数据后将该变量设置回之前的值。 + +```sql +SET GLOBAL tidb_gc_life_time="60m"; +``` + +> **注意:** +> +> 将 GC life time 从默认的 10 分钟增加到半小时及以上,会导致同一行保留有多个版本并占用更多的磁盘空间,也可能会影响某些操作的性能,例如扫描。进行扫描操作时,TiDB 读取数据需要跳过这些有多个版本的同一行,从而影响到扫描性能。 + +如果想要恢复历史版本的数据,可以使用以下任意一种方法进行设置: + +- 对于简单场景,在设置 `tidb_snapshot` 变量后使用 [`SELECT`](/sql-statements/sql-statement-select.md) 语句并复制粘贴输出结果,或者使用 `SELECT ... INTO OUTFILE` 语句并使用 [`LOAD DATA`](/sql-statements/sql-statement-load-data.md) 语句来导入数据。 + +- 使用 [Dumpling](/dumpling-overview.md#导出-tidb-的历史数据快照) 导出 TiDB 的历史数据快照。Dumpling 在导出较大的数据集时有较好的性能。 diff --git a/markdown-pages/zh/tidb/master/role-based-access-control.md b/markdown-pages/zh/tidb/master/role-based-access-control.md new file mode 100644 index 0000000..331a06b --- /dev/null +++ b/markdown-pages/zh/tidb/master/role-based-access-control.md @@ -0,0 +1,351 @@ +--- +title: 基于角色的访问控制 +aliases: ['/docs-cn/dev/role-based-access-control/','/docs-cn/dev/reference/security/role-based-access-control/'] +summary: TiDB 的基于角色的访问控制 (RBAC) 系统类似于 MySQL 8.0 的 RBAC 系统。用户可以创建、删除和授予角色权限,也可以将角色授予其他用户。角色需要在用户启用后才能生效。用户可以通过 `SHOW GRANTS` 查看角色权限,也可以设置默认启用角色。角色授权具有原子性,失败会回滚。除了角色授权外,还有用户管理和权限管理相关操作。 +--- + +# 基于角色的访问控制 + +TiDB 的基于角色的访问控制 (RBAC) 系统的实现类似于 MySQL 8.0 的 RBAC 系统。TiDB 兼容大部分 MySQL RBAC 系统的语法。 + +本文档主要介绍 TiDB 基于角色的访问控制相关操作及实现。 + +## 角色访问控制相关操作 + +角色是一系列权限的集合。用户可以创建角色、删除角色、将权限赋予角色;也可以将角色授予给其他用户,被授予的用户在启用角色后,可以得到角色所包含的权限。 + +### 创建角色 + +创建角色 app_developer,app_read 和 app_write: + +```sql +CREATE ROLE 'app_developer', 'app_read', 'app_write'; +``` + +角色名的格式和规范可以参考 [TiDB 用户账户管理](/user-account-management.md)。 + +角色会被保存在 `mysql.user` 表中,角色名称的主机名部分(如果省略)默认为 `'%'`。如果表中有同名角色或用户,角色会创建失败并报错。创建角色的用户需要拥有 `CREATE ROLE` 或 `CREATE USER` 权限。 + +### 授予角色权限 + +为角色授予权限和为用户授予权限操作相同,可参考 [TiDB 权限管理](/privilege-management.md)。 + +为 `app_read` 角色授予数据库 `app_db` 的读权限: + +```sql +GRANT SELECT ON app_db.* TO 'app_read'@'%'; +``` + +为 `app_write` 角色授予数据库 `app_db` 的写权限: + +```sql +GRANT INSERT, UPDATE, DELETE ON app_db.* TO 'app_write'@'%'; +``` + +为 `app_developer` 角色授予 `app_db` 数据库的全部权限: + +```sql +GRANT ALL ON app_db.* TO 'app_developer'; +``` + +### 将角色授予给用户 + +假设有一个用户拥有开发者角色,可以对 `app_db` 的所有操作权限;另外有两个用户拥有 `app_db` 的只读权限;还有一个用户拥有 `app_db` 的读写权限。 + +首先用 `CREATE USER` 来创建用户。 + +```sql +CREATE USER 'dev1'@'localhost' IDENTIFIED BY 'dev1pass'; +CREATE USER 'read_user1'@'localhost' IDENTIFIED BY 'read_user1pass'; +CREATE USER 'read_user2'@'localhost' IDENTIFIED BY 'read_user2pass'; +CREATE USER 'rw_user1'@'localhost' IDENTIFIED BY 'rw_user1pass'; +``` + +然后使用 `GRANT` 授予用户对应的角色。 + +```sql +GRANT 'app_developer' TO 'dev1'@'localhost'; +GRANT 'app_read' TO 'read_user1'@'localhost', 'read_user2'@'localhost'; +GRANT 'app_read', 'app_write' TO 'rw_user1'@'localhost'; +``` + +用户执行将角色授予给其他用户或者收回角色的命令,需要用户拥有 `SUPER` 权限。将角色授予给用户时并不会启用该角色,启用角色需要额外的操作。 + +以下操作可能会形成一个“关系环”: + +```sql +CREATE USER 'u1', 'u2'; +CREATE ROLE 'r1', 'r2'; + +GRANT 'u1' TO 'u1'; +GRANT 'r1' TO 'r1'; + +GRANT 'r2' TO 'u2'; +GRANT 'u2' TO 'r2'; +``` + +TiDB 允许这种多层授权关系存在,可以使用多层授权关系实现权限继承。 + +### 查看角色拥有的权限 + +可以通过 `SHOW GRANTS` 语句查看用户被授予了哪些角色。当用户查看其他用户权限相关信息时,需要对 `mysql` 数据库拥有 `SELECT` 权限。 + +```sql +SHOW GRANTS FOR 'dev1'@'localhost'; +``` + +``` ++-------------------------------------------------+ +| Grants for dev1@localhost | ++-------------------------------------------------+ +| GRANT USAGE ON *.* TO `dev1`@`localhost` | +| GRANT `app_developer`@`%` TO `dev1`@`localhost` | ++-------------------------------------------------+ +``` + +可以通过使用 `SHOW GRANTS` 的 `USING` 选项来查看角色对应的权限。 + +```sql +SHOW GRANTS FOR 'dev1'@'localhost' USING 'app_developer'; +``` + +``` ++----------------------------------------------------------+ +| Grants for dev1@localhost | ++----------------------------------------------------------+ +| GRANT USAGE ON *.* TO `dev1`@`localhost` | +| GRANT ALL PRIVILEGES ON `app_db`.* TO `dev1`@`localhost` | +| GRANT `app_developer`@`%` TO `dev1`@`localhost` | ++----------------------------------------------------------+ +``` + +```sql +SHOW GRANTS FOR 'rw_user1'@'localhost' USING 'app_read', 'app_write'; +``` + +``` ++------------------------------------------------------------------------------+ +| Grants for rw_user1@localhost | ++------------------------------------------------------------------------------+ +| GRANT USAGE ON *.* TO `rw_user1`@`localhost` | +| GRANT SELECT, INSERT, UPDATE, DELETE ON `app_db`.* TO `rw_user1`@`localhost` | +| GRANT `app_read`@`%`,`app_write`@`%` TO `rw_user1`@`localhost` | ++------------------------------------------------------------------------------+ +``` + +```sql +SHOW GRANTS FOR 'read_user1'@'localhost' USING 'app_read'; +``` + +``` ++--------------------------------------------------------+ +| Grants for read_user1@localhost | ++--------------------------------------------------------+ +| GRANT USAGE ON *.* TO `read_user1`@`localhost` | +| GRANT SELECT ON `app_db`.* TO `read_user1`@`localhost` | +| GRANT `app_read`@`%` TO `read_user1`@`localhost` | ++--------------------------------------------------------+ +``` + +可以使用 `SHOW GRANTS` 或 `SHOW GRANTS FOR CURRENT_USER()` 查看当前用户的权限。这两个语句有细微的差异,`SHOW GRANTS` 会显示当前用户的启用角色的权限,而 `SHOW GRANTS FOR CURRENT_USER()` 则不会显示启用角色的权限。 + +### 设置默认启用角色 + +角色在授予给用户之后,并不会生效;只有在用户启用了某些角色之后,才可以使用角色拥有的权限。 + +可以对用户设置默认启用的角色;用户在登录时,默认启用的角色会被自动启用。 + +```sql +SET DEFAULT ROLE + {NONE | ALL | role [, role ] ...} + TO user [, user ] +``` + +比如将 `app_read` 和 `app_wirte` 设置为 `rw_user1@localhost` 的默认启用角色: + +```sql +SET DEFAULT ROLE app_read, app_write TO 'rw_user1'@'localhost'; +``` + +将 `dev1@localhost` 的所有角色,设为其默认启用角色: + +```sql +SET DEFAULT ROLE ALL TO 'dev1'@'localhost'; +``` + +关闭 `dev1@localhost` 的所有默认启用角色: + +```sql +SET DEFAULT ROLE NONE TO 'dev1'@'localhost'; +``` + +需要注意的是,设置为默认启用角色的角色必须已经授予给那个用户。 + +### 在当前 session 启用角色 + +除了使用 `SET DEFAULT ROLE` 启用角色外,TiDB 还提供让用户在当前 session 启用某些角色的功能。 + +```sql +SET ROLE { + DEFAULT + | NONE + | ALL + | ALL EXCEPT role [, role ] ... + | role [, role ] ... +} +``` + +例如,登录 `rw_user1` 后,为当前用户启用角色 `app_read` 和 `app_write`,仅在当前 session 有效: + +```sql +SET ROLE 'app_read', 'app_write'; +``` + +启用当前用户的默认角色: + +```sql +SET ROLE DEFAULT +``` + +启用授予给当前用户的所有角色: + +```sql +SET ROLE ALL +``` + +不启用任何角色: + +```sql +SET ROLE NONE +``` + +启用除 `app_read` 外的角色: + +```sql +SET ROLE ALL EXCEPT 'app_read' +``` + +> **注意:** +> +> 使用 `SET ROLE` 启用的角色只有在当前 session 才会有效。 + +### 查看当前启用角色 + +当前用户可以通过 `CURRENT_ROLE()` 函数查看当前用户启用了哪些角色。 + +例如,先对 `rw_user1'@'localhost` 设置默认角色: + +```sql +SET DEFAULT ROLE ALL TO 'rw_user1'@'localhost'; +``` + +用 `rw_user1@localhost` 登录后: + +```sql +SELECT CURRENT_ROLE(); +``` + +``` ++--------------------------------+ +| CURRENT_ROLE() | ++--------------------------------+ +| `app_read`@`%`,`app_write`@`%` | ++--------------------------------+ +``` + +```sql +SET ROLE 'app_read'; SELECT CURRENT_ROLE(); +``` + +``` ++----------------+ +| CURRENT_ROLE() | ++----------------+ +| `app_read`@`%` | ++----------------+ +``` + +### 收回角色 + +解除角色 `app_read` 与用户 `read_user1@localhost`、`read_user2@localhost` 的授权关系。 + +```sql +REVOKE 'app_read' FROM 'read_user1'@'localhost', 'read_user2'@'localhost'; +``` + +解除角色 `app_read`、`app_write` 与用户 `rw_user1@localhost` 的授权关系。 + +```sql +REVOKE 'app_read', 'app_write' FROM 'rw_user1'@'localhost'; +``` + +解除角色授权具有原子性,如果在撤销授权操作中失败会回滚。 + +### 收回权限 + +`REVOKE` 语句与 `GRANT` 对应,可以使用 `REVOKE` 来撤销 `app_write` 的权限。 + +```sql +REVOKE INSERT, UPDATE, DELETE ON app_db.* FROM 'app_write'; +``` + +具体可参考 [TiDB 权限管理](/privilege-management.md)。 + +### 删除角色 + +删除角色 `app_read` 和 `app_write`: + +```sql +DROP ROLE 'app_read', 'app_write'; +``` + +这个操作会清除角色在 `mysql.user` 表里面的记录项,并且清除在授权表里面的相关记录,解除和其相关的授权关系。执行删除角色的用户需要拥有 `DROP ROLE` 或 `DROP USER` 权限。 + +### 授权表 + +在原有的四张[系统权限表](/privilege-management.md#授权表)的基础上,角色访问控制引入了两张新的系统表: + +- `mysql.role_edges`:记录角色与用户的授权关系 +- `mysql.default_roles`:记录每个用户默认启用的角色 + +以下是 `mysql.role_edges` 所包含的数据。 + +```sql +select * from mysql.role_edges; +``` + +``` ++-----------+-----------+---------+---------+-------------------+ +| FROM_HOST | FROM_USER | TO_HOST | TO_USER | WITH_ADMIN_OPTION | ++-----------+-----------+---------+---------+-------------------+ +| % | r_1 | % | u_1 | N | ++-----------+-----------+---------+---------+-------------------+ +1 row in set (0.00 sec) +``` + +其中 `FROM_HOST` 和 `FROM_USER` 分别表示角色的主机名和用户名,`TO_HOST` 和 `TO_USER` 分别表示被授予角色的用户的主机名和用户名。 + +`mysql.default_roles` 中包含了每个用户默认启用了哪些角色。 + +```sql +select * from mysql.default_roles; +``` + +``` ++------+------+-------------------+-------------------+ +| HOST | USER | DEFAULT_ROLE_HOST | DEFAULT_ROLE_USER | ++------+------+-------------------+-------------------+ +| % | u_1 | % | r_1 | +| % | u_1 | % | r_2 | ++------+------+-------------------+-------------------+ +2 rows in set (0.00 sec) +``` + +`HOST` 和 `USER` 分别表示用户的主机名和用户名,`DEFAULT_ROLE_HOST` 和 `DEFAULT_ROLE_USER` 分别表示默认启用的角色的主机名和用户名。 + +### 其他 + +由于基于角色的访问控制模块和用户管理以及权限管理结合十分紧密,因此需要参考一些操作的细节: + +- [TiDB 权限管理](/privilege-management.md) +- [TiDB 用户账户管理](/user-account-management.md) diff --git a/markdown-pages/zh/tidb/master/scale-tidb-using-tiup.md b/markdown-pages/zh/tidb/master/scale-tidb-using-tiup.md new file mode 100644 index 0000000..19717f8 --- /dev/null +++ b/markdown-pages/zh/tidb/master/scale-tidb-using-tiup.md @@ -0,0 +1,488 @@ +--- +title: 使用 TiUP 扩容缩容 TiDB 集群 +aliases: ['/docs-cn/dev/scale-tidb-using-tiup/','/docs-cn/dev/how-to/scale/with-tiup/','/docs-cn/dev/reference/tiflash/scale/'] +summary: TiUP 可以在不中断线上服务的情况下扩容和缩容 TiDB 集群。使用 `tiup cluster list` 查看当前集群名称列表。扩容 TiDB/PD/TiKV 节点需要编写扩容拓扑配置,并执行扩容命令。扩容后,使用 `tiup cluster display ` 检查集群状态。缩容 TiDB/PD/TiKV 节点需要查看节点 ID 信息,执行缩容操作,然后检查集群状态。缩容 TiFlash/TiCDC 节点也需要执行相似的操作。 +--- + +# 使用 TiUP 扩容缩容 TiDB 集群 + +TiDB 集群可以在不中断线上服务的情况下进行扩容和缩容。 + +本文介绍如何使用 TiUP 扩容缩容集群中的 TiDB、TiKV、PD、TiCDC 或者 TiFlash 节点。如未安装 TiUP,可参考[部署文档中的步骤](/production-deployment-using-tiup.md#第-2-步在中控机上部署-tiup-组件)。 + +你可以通过 `tiup cluster list` 查看当前的集群名称列表。 + +例如,集群原拓扑结构如下所示: + +| 主机 IP | 服务 | +|:----|:----| +| 10.0.1.3 | TiDB + TiFlash | +| 10.0.1.4 | TiDB + PD | +| 10.0.1.5 | TiKV + Monitor | +| 10.0.1.1 | TiKV | +| 10.0.1.2 | TiKV | + +## 扩容 TiDB/PD/TiKV 节点 + +如果要添加一个 TiDB 节点,IP 地址为 10.0.1.5,可以按照如下步骤进行操作。 + +> **注意:** +> +> 添加 PD 节点和添加 TiDB 节点的步骤类似。添加 TiKV 节点前,建议预先根据集群的负载情况调整 PD 调度参数。 + +### 1. 编写扩容拓扑配置 + +> **注意:** +> +> - 默认情况下,可以不填写端口以及目录信息。但在单机多实例场景下,则需要分配不同的端口以及目录,如果有端口或目录冲突,会在部署或扩容时提醒。 +> +> - 从 TiUP v1.0.0 开始,扩容配置会继承原集群配置的 global 部分。 + +在 scale-out.yml 文件添加扩容拓扑配置: + +```shell +vi scale-out.yml +``` + +```ini +tidb_servers: + - host: 10.0.1.5 + ssh_port: 22 + port: 4000 + status_port: 10080 + deploy_dir: /tidb-deploy/tidb-4000 + log_dir: /tidb-deploy/tidb-4000/log +``` + +TiKV 配置文件参考: + +```ini +tikv_servers: + - host: 10.0.1.5 + ssh_port: 22 + port: 20160 + status_port: 20180 + deploy_dir: /tidb-deploy/tikv-20160 + data_dir: /tidb-data/tikv-20160 + log_dir: /tidb-deploy/tikv-20160/log +``` + +PD 配置文件参考: + +```ini +pd_servers: + - host: 10.0.1.5 + ssh_port: 22 + name: pd-1 + client_port: 2379 + peer_port: 2380 + deploy_dir: /tidb-deploy/pd-2379 + data_dir: /tidb-data/pd-2379 + log_dir: /tidb-deploy/pd-2379/log +``` + +可以使用 `tiup cluster edit-config ` 查看当前集群的配置信息,因为其中的 `global` 和 `server_configs` 参数配置默认会被 `scale-out.yml` 继承,因此也会在 `scale-out.yml` 中生效。 + +### 2. 执行扩容命令 + +执行 scale-out 命令前,先使用 `check` 及 `check --apply` 命令,检查和自动修复集群存在的潜在风险: + +> **注意:** +> +> 针对 scale-out 命令的检查功能在 tiup cluster v1.9.3 及后续版本中支持,请操作前先升级 tiup cluster 版本。 + +(1)检查集群存在的潜在风险: + + ```shell + tiup cluster check scale-out.yml --cluster --user root [-p] [-i /home/root/.ssh/gcp_rsa] + ``` + +(2)自动修复集群存在的潜在风险: + + ```shell + tiup cluster check scale-out.yml --cluster --apply --user root [-p] [-i /home/root/.ssh/gcp_rsa] + ``` + +(3)执行 scale-out 命令扩容 TiDB 集群: + + ```shell + tiup cluster scale-out scale-out.yml [-p] [-i /home/root/.ssh/gcp_rsa] + ``` + +以上操作示例中: + +- 扩容配置文件为 `scale-out.yml`。 +- `--user root` 表示通过 root 用户登录到目标主机完成集群部署,该用户需要有 ssh 到目标机器的权限,并且在目标机器有 sudo 权限。也可以用其他有 ssh 和 sudo 权限的用户完成部署。 +- [-i] 及 [-p] 为可选项,如果已经配置免密登录目标机,则不需填写。否则选择其一即可,[-i] 为可登录到目标机的 root 用户(或 --user 指定的其他用户)的私钥,也可使用 [-p] 交互式输入该用户的密码。 + +预期日志结尾输出 ```Scaled cluster `` out successfully``` 信息,表示扩容操作成功。 + +### 3. 检查集群状态 + +```shell +tiup cluster display +``` + +打开浏览器访问监控平台 ,监控整个集群和新增节点的状态。 + +扩容后,集群拓扑结构如下所示: + +| 主机 IP | 服务 | +|:----|:----| +| 10.0.1.3 | TiDB + TiFlash | +| 10.0.1.4 | TiDB + PD | +| 10.0.1.5 | **TiDB** + TiKV + Monitor | +| 10.0.1.1 | TiKV | +| 10.0.1.2 | TiKV | + +## 扩容 TiFlash 节点 + +如果要添加一个 TiFlash 节点,其 IP 地址为 `10.0.1.4`,可以按照如下步骤进行操作。 + +> **注意:** +> +> 在原有 TiDB 集群上新增 TiFlash 组件需要注意: +> +> 1. 首先确认当前 TiDB 的版本支持 TiFlash,否则需要先升级 TiDB 集群至 v5.0 以上版本。 +> 2. 执行 `tiup ctl:v pd -u http://: config set enable-placement-rules true` 命令,以开启 PD 的 Placement Rules 功能。或通过 [pd-ctl](/pd-control.md) 执行对应的命令。 + +### 1. 添加节点信息到 scale-out.yml 文件 + +编写 scale-out.yml 文件,添加该 TiFlash 节点信息(目前只支持 ip,不支持域名): + +```ini +tiflash_servers: + - host: 10.0.1.4 +``` + +### 2. 运行扩容命令 + +```shell +tiup cluster scale-out scale-out.yml +``` + +> **注意:** +> +> 此处假设当前执行命令的用户和新增的机器打通了互信,如果不满足已打通互信的条件,需要通过 `-p` 来输入新机器的密码,或通过 `-i` 指定私钥文件。 + +### 3. 查看集群状态 + +```shell +tiup cluster display +``` + +打开浏览器访问监控平台 ,监控整个集群和新增节点的状态。 + +扩容后,集群拓扑结构如下所示: + +| 主机 IP | 服务 | +|:----|:----| +| 10.0.1.3 | TiDB + TiFlash | +| 10.0.1.4 | TiDB + PD + **TiFlash** | +| 10.0.1.5 | TiDB+ TiKV + Monitor | +| 10.0.1.1 | TiKV | +| 10.0.1.2 | TiKV | + +## 扩容 TiCDC 节点 + +如果要添加 TiCDC 节点,IP 地址为 10.0.1.3、10.0.1.4,可以按照如下步骤进行操作。 + +### 1. 添加节点信息到 scale-out.yml 文件 + +编写 scale-out.yml 文件: + +```ini +cdc_servers: + - host: 10.0.1.3 + gc-ttl: 86400 + data_dir: /tidb-data/cdc-8300 + - host: 10.0.1.4 + gc-ttl: 86400 + data_dir: /tidb-data/cdc-8300 +``` + +### 2. 运行扩容命令 + +```shell +tiup cluster scale-out scale-out.yml +``` + +> **注意:** +> +> 此处假设当前执行命令的用户和新增的机器打通了互信,如果不满足已打通互信的条件,需要通过 `-p` 来输入新机器的密码,或通过 `-i` 指定私钥文件。 + +### 3. 查看集群状态 + +```shell +tiup cluster display +``` + +打开浏览器访问监控平台 ,监控整个集群和新增节点的状态。 + +扩容后,集群拓扑结构如下所示: + +| 主机 IP | 服务 | +|:----|:----| +| 10.0.1.3 | TiDB + TiFlash + **TiCDC** | +| 10.0.1.4 | TiDB + PD + TiFlash + **TiCDC** | +| 10.0.1.5 | TiDB+ TiKV + Monitor | +| 10.0.1.1 | TiKV | +| 10.0.1.2 | TiKV | + +## 缩容 TiDB/PD/TiKV 节点 + +如果要移除 IP 地址为 10.0.1.5 的一个 TiKV 节点,可以按照如下步骤进行操作。 + +> **注意:** +> +> - 移除 TiDB、PD 节点和移除 TiKV 节点的步骤类似。 +> - 由于 TiKV、TiFlash 和 TiDB Binlog 组件是异步下线的,且下线过程耗时较长,所以 TiUP 对 TiKV、TiFlash 和 TiDB Binlog 组件做了特殊处理,详情参考[下线特殊处理](/tiup/tiup-component-cluster-scale-in.md#下线特殊处理)。 + +> **注意:** +> +> TiKV 中的 PD Client 会缓存 PD 节点的列表。当前版本的 TiKV 有定期自动更新 PD 节点的机制,可以降低 TiKV 缓存的 PD 节点列表过旧这一问题出现的概率。但你应尽量避免在扩容新 PD 后直接一次性缩容所有扩容前就已经存在的 PD 节点。如果需要,请确保在下线所有之前存在的 PD 节点前将 PD 的 leader 切换至新扩容的 PD 节点。 + +### 1. 查看节点 ID 信息 + +```shell +tiup cluster display +``` + +``` +Starting /root/.tiup/components/cluster/v1.12.3/cluster display + +TiDB Cluster: + +TiDB Version: v8.0.0 + +ID Role Host Ports Status Data Dir Deploy Dir + +-- ---- ---- ----- ------ -------- ---------- + +10.0.1.3:8300 cdc 10.0.1.3 8300 Up data/cdc-8300 deploy/cdc-8300 + +10.0.1.4:8300 cdc 10.0.1.4 8300 Up data/cdc-8300 deploy/cdc-8300 + +10.0.1.4:2379 pd 10.0.1.4 2379/2380 Healthy data/pd-2379 deploy/pd-2379 + +10.0.1.1:20160 tikv 10.0.1.1 20160/20180 Up data/tikv-20160 deploy/tikv-20160 + +10.0.1.2:20160 tikv 10.0.1.2 20160/20180 Up data/tikv-20160 deploy/tikv-20160 + +10.0.1.5:20160 tikv 10.0.1.5 20160/20180 Up data/tikv-20160 deploy/tikv-20160 + +10.0.1.3:4000 tidb 10.0.1.3 4000/10080 Up - deploy/tidb-4000 + +10.0.1.4:4000 tidb 10.0.1.4 4000/10080 Up - deploy/tidb-4000 + +10.0.1.5:4000 tidb 10.0.1.5 4000/10080 Up - deploy/tidb-4000 + +10.0.1.3:9000 tiflash 10.0.1.3 9000/8123/3930/20170/20292/8234 Up data/tiflash-9000 deploy/tiflash-9000 + +10.0.1.4:9000 tiflash 10.0.1.4 9000/8123/3930/20170/20292/8234 Up data/tiflash-9000 deploy/tiflash-9000 + +10.0.1.5:9090 prometheus 10.0.1.5 9090 Up data/prometheus-9090 deploy/prometheus-9090 + +10.0.1.5:3000 grafana 10.0.1.5 3000 Up - deploy/grafana-3000 + +10.0.1.5:9093 alertmanager 10.0.1.5 9093/9094 Up data/alertmanager-9093 deploy/alertmanager-9093 +``` + +### 2. 执行缩容操作 + +```shell +tiup cluster scale-in --node 10.0.1.5:20160 +``` + +其中 `--node` 参数为需要下线节点的 ID。 + +预期输出 Scaled cluster `` in successfully 信息,表示缩容操作成功。 + +### 3. 检查集群状态 + +下线需要一定时间,下线节点的状态变为 Tombstone 就说明下线成功。 + +执行如下命令检查节点是否下线成功: + +```shell +tiup cluster display +``` + +打开浏览器访问监控平台 ,监控整个集群的状态。 + +调整后,拓扑结构如下: + +| Host IP | Service | +|:----|:----| +| 10.0.1.3 | TiDB + TiFlash + TiCDC | +| 10.0.1.4 | TiDB + PD + TiFlash + TiCDC | +| 10.0.1.5 | TiDB + Monitor**(TiKV 已删除)** | +| 10.0.1.1 | TiKV | +| 10.0.1.2 | TiKV | + +## 缩容 TiFlash 节点 + +如果要缩容 IP 地址为 10.0.1.4 的一个 TiFlash 节点,可以按照如下步骤进行操作。 + +### 1. 根据 TiFlash 剩余节点数调整数据表的副本数 + +1. 查询是否有数据表的 TiFlash 副本数大于缩容后的 TiFlash 节点数。`tobe_left_nodes` 表示缩容后的 TiFlash 节点数。如果查询结果为空,可以开始执行缩容。如果查询结果不为空,则需要修改相关表的 TiFlash 副本数。 + + ```sql + SELECT * FROM information_schema.tiflash_replica WHERE REPLICA_COUNT > 'tobe_left_nodes'; + ``` + +2. 对所有 TiFlash 副本数大于缩容后的 TiFlash 节点数的表执行以下语句,`new_replica_num` 必须小于等于 `tobe_left_nodes`: + + ```sql + ALTER TABLE . SET tiflash replica 'new_replica_num'; + ``` + +3. 重新执行步骤 1,确保没有数据表的 TiFlash 副本数大于缩容后的 TiFlash 节点数。 + +### 2. 执行缩容操作 + +接下来,请任选下列方案其一进行缩容。 + +#### 方案一:通过 TiUP 缩容 TiFlash 节点 + +1. 通过以下命令确定需要下线的节点名称: + + ```shell + tiup cluster display + ``` + +2. 执行 scale-in 命令来下线节点,假设步骤 1 中获得该节点名为 `10.0.1.4:9000` + + ```shell + tiup cluster scale-in --node 10.0.1.4:9000 + ``` + +#### 方案二:手动缩容 TiFlash 节点 + +在特殊情况下(比如需要强制下线节点),或者 TiUP 操作失败的情况下,可以使用以下方法手动下线 TiFlash 节点。 + +1. 使用 pd-ctl 的 store 命令在 PD 中查看该 TiFlash 节点对应的 store id。 + + * 在 [pd-ctl](/pd-control.md)(tidb-ansible 目录下的 `resources/bin` 包含对应的二进制文件)中输入 store 命令。 + + * 若使用 TiUP 部署,可以调用以下命令代替 `pd-ctl`: + + ```shell + tiup ctl:v pd -u http://: store + ``` + + > **注意:** + > + > 如果集群中有多个 PD 实例,只需在以上命令中指定一个活跃 PD 实例的 `IP:端口`即可。 + +2. 在 pd-ctl 中下线该 TiFlash 节点。 + + * 在 pd-ctl 中输入 `store delete `,其中 `` 为上一步查到的该 TiFlash 节点对应的 store id。 + + * 若通过 TiUP 部署,可以调用以下命令代替 `pd-ctl`: + + ```shell + tiup ctl:v pd -u http://: store delete + ``` + + > **注意:** + > + > 如果集群中有多个 PD 实例,只需在以上命令中指定一个活跃 PD 实例的 `IP:端口`即可。 + +3. 等待该 TiFlash 节点对应的 store 消失或者 state_name 变成 Tombstone 再关闭 TiFlash 进程。 + +4. 手动删除 TiFlash 的数据文件,具体位置可查看在集群拓扑配置文件中 TiFlash 配置部分下的 data_dir 目录。 + +5. 从 TiUP 拓扑信息中删除已经下线的 TiFlash 节点信息: + + ```shell + tiup cluster scale-in --node : --force + ``` + +> **注意:** +> +> 如果在集群中所有的 TiFlash 节点停止运行之前,没有取消所有同步到 TiFlash 的表,则需要手动在 PD 中清除同步规则,否则无法成功完成 TiFlash 节点的下线。 + +手动在 PD 中清除同步规则的步骤如下: + +1. 查询当前 PD 实例中所有与 TiFlash 相关的数据同步规则。 + + ```shell + curl http://:/pd/api/v1/config/rules/group/tiflash + ``` + + ``` + [ + { + "group_id": "tiflash", + "id": "table-45-r", + "override": true, + "start_key": "7480000000000000FF2D5F720000000000FA", + "end_key": "7480000000000000FF2E00000000000000F8", + "role": "learner", + "count": 1, + "label_constraints": [ + { + "key": "engine", + "op": "in", + "values": [ + "tiflash" + ] + } + ] + } + ] + ``` + +2. 删除所有与 TiFlash 相关的数据同步规则。以 `id` 为 `table-45-r` 的规则为例,通过以下命令可以删除该规则。 + + ```shell + curl -v -X DELETE http://:/pd/api/v1/config/rule/tiflash/table-45-r + ``` + +### 3. 查看集群状态 + +```shell +tiup cluster display +``` + +打开浏览器访问监控平台 ,监控整个集群的状态。 + +调整后,拓扑结构如下: + +| Host IP | Service | +|:----|:----| +| 10.0.1.3 | TiDB + TiFlash + TiCDC | +| 10.0.1.4 | TiDB + PD + TiCDC **(TiFlash 已删除)** | +| 10.0.1.5 | TiDB + Monitor | +| 10.0.1.1 | TiKV | +| 10.0.1.2 | TiKV | + +## 缩容 TiCDC 节点 + +如果要缩容 IP 地址为 10.0.1.4 的一个 TiCDC 节点,可以按照如下步骤进行操作。 + +### 1. 下线该 TiCDC 节点 + +```shell +tiup cluster scale-in --node 10.0.1.4:8300 +``` + +### 2. 查看集群状态 + +```shell +tiup cluster display +``` + +打开浏览器访问监控平台 ,监控整个集群的状态。 + +调整后,拓扑结构如下: + +| Host IP | Service | +|:----|:----| +| 10.0.1.3 | TiDB + TiFlash + TiCDC | +| 10.0.1.4 | TiDB + PD + **(TiCDC 已删除)** | +| 10.0.1.5 | TiDB + Monitor | +| 10.0.1.1 | TiKV | +| 10.0.1.2 | TiKV | diff --git a/markdown-pages/zh/tidb/master/schedule-replicas-by-topology-labels.md b/markdown-pages/zh/tidb/master/schedule-replicas-by-topology-labels.md new file mode 100644 index 0000000..0880ded --- /dev/null +++ b/markdown-pages/zh/tidb/master/schedule-replicas-by-topology-labels.md @@ -0,0 +1,245 @@ +--- +title: 通过拓扑 label 进行副本调度 +aliases: ['/docs-cn/dev/schedule-replicas-by-topology-labels/','/docs-cn/dev/how-to/deploy/geographic-redundancy/location-awareness/','/docs-cn/dev/location-awareness/'] +summary: TiDB v5.3.0 引入了通过拓扑 label 进行副本调度的功能。为了提升集群的高可用性和数据容灾能力,推荐让 TiKV 节点在物理层面上尽可能分散。通过设置 TiKV 和 TiFlash 的 labels,可以标识它们的地理位置。同时,需要配置 PD 的 location-labels 和 isolation-level 来使 PD 理解 TiKV 节点拓扑并加强拓扑隔离要求。PD 在副本调度时会保证同一份数据的不同副本尽可能分散,以提高集群容灾能力。 +--- + +# 通过拓扑 label 进行副本调度 + +> **注意:** +> +> TiDB 在 v5.3.0 中引入了 [Placement Rules in SQL](/placement-rules-in-sql.md)。使用该功能,你可以更方便地配置表和分区的位置。在未来版本中,Placement Rules in SQL 可能取代通过 PD 配置放置规则的功能。 + +为了提升 TiDB 集群的高可用性和数据容灾能力,我们推荐让 TiKV 节点尽可能在物理层面上分散,例如让 TiKV 节点分布在不同的机架甚至不同的可用区。PD 调度器根据 TiKV 的拓扑信息,会自动在后台通过调度使得 Region 的各个副本尽可能隔离,从而使得数据容灾能力最大化。 + +要让这个机制生效,需要在部署时进行合理配置,把集群的拓扑信息(特别是 TiKV 的位置)上报给 PD。阅读本章前,请先确保阅读 [TiUP 部署方案](/production-deployment-using-tiup.md)。 + +## 根据集群拓扑配置 labels + +### 设置 TiKV 和 TiFlash 的 `labels` + +TiKV 和 TiFlash 支持在命令行参数或者配置文件中以键值对的形式绑定一些属性,我们把这些属性叫做标签 (label)。TiKV 和 TiFlash 在启动后,会将自身的标签上报给 PD,因此可以使用标签来标识 TiKV 和 TiFlash 节点的地理位置。 + +比如集群的拓扑结构分成四层:可用区 (zone) -> 数据中心 (dc) -> 机架 (rack) -> 主机 (host),就可以使用这 4 个标签来设置 TiKV 和 TiFlash 的位置。 + +使用命令行参数的方式启动一个 TiKV 实例: + +``` +tikv-server --labels zone=,dc=,rack=,host= +``` + +使用配置文件的方式: + +```toml +[server] +[server.labels] +zone = "" +dc = "" +rack = "" +host = "" +``` + +TiFlash 支持通过 tiflash-learner.toml (tiflash-proxy 的配置文件)的方式设置 labels: + +```toml +[server] +[server.labels] +zone = "" +dc = "" +rack = "" +host = "" +``` + +### 设置 TiDB 的 `labels`(可选) + +如果需要使用 [Follower Read](/follower-read.md) 的优先读同一区域副本的功能,需要为 TiDB 节点配置相关的 `labels`。 + +TiDB 支持使用配置文件的方式设置 `labels`: + +``` +[labels] +zone = "" +dc = "" +rack = "" +host = "" +``` + +> **注意:** +> +> 目前,TiDB 依赖 `zone` 标签匹配选择同一区域的副本。如果需要使用此功能,需要在 PD [`location-labels` 配置](#设置-pd-的-isolation-level-配置)中包含 `zone`,并在 TiDB、TiKV 和 TiFlash 设置的 `labels` 中包含 `zone`。关于如何设置 TiKV 和 TiFlash 的 `labels`,可参考[设置 TiKV 和 TiFlash 的 `labels`](#设置-tikv-和-tiflash-的-labels)。 + +### 设置 PD 的 `location-labels` 配置 + +根据前面的描述,标签可以是用来描述 TiKV 属性的任意键值对,但 PD 无从得知哪些标签是用来标识地理位置的,而且也无从得知这些标签的层次关系。因此,PD 也需要一些配置来使得 PD 理解 TiKV 节点拓扑。 + +PD 上的配置叫做 `location-labels`,是一个字符串数组。该配置的每一项与 TiKV `labels` 的 key 是对应的,而且其中每个 key 的顺序代表不同标签的级别关系(从左到右,隔离级别依次递减)。 + +`location-labels` 没有默认值,你可以根据具体需求来设置该值,包括 `zone`、`rack`、`host` 等等。同时,`location-labels` 对标签级别的数量也**没有**限制(即不限定于 3 个),只要其级别与 TiKV 服务器的标签匹配,则可以配置成功。 + +> **注意:** +> +> - 必须同时配置 PD 的 `location-labels` 和 TiKV 的 `labels` 参数,否则 PD 不会根据拓扑结构进行调度。 +> - 如果你使用 Placement Rules in SQL,只需要配置 TiKV 的 `labels` 即可。Placement Rules in SQL 目前不兼容 PD `location-labels` 设置,会忽略该设置。不建议 `location-labels` 与 Placement Rules in SQL 混用,否则可能产生非预期的结果。 + +你可以根据集群状态来选择不同的配置方式: + +- 在集群初始化之前,可以通过 PD 的配置文件进行配置: + + ```toml + [replication] + location-labels = ["zone", "rack", "host"] + ``` + +- 如果需要在 PD 集群初始化完成后进行配置,则需要使用 pd-ctl 工具进行在线更改: + + ```bash + pd-ctl config set location-labels zone,rack,host + ``` + +### 设置 PD 的 `isolation-level` 配置 + +在配置了 `location-labels` 的前提下,用户可以还通过 `isolation-level` 配置来进一步加强对 TiKV 集群的拓扑隔离要求。假设按照上面的说明通过 `location-labels` 将集群的拓扑结构分成三层:可用区 (zone) -> 机架 (rack) -> 主机 (host),并对 `isolation-level` 作如下配置: + +```toml +[replication] +isolation-level = "zone" +``` + +当 PD 集群初始化完成后,需要使用 pd-ctl 工具进行在线更改: + +```bash +pd-ctl config set isolation-level zone +``` + +其中,`isolation-level` 配置是一个字符串,需要与 `location-labels` 的其中一个 key 对应。该参数限制 TiKV 拓扑集群的最小且强制隔离级别要求。 + +> **注意:** +> +> `isolation-level` 默认情况下为空,即不进行强制隔离级别限制,若要对其进行设置,必须先配置 PD 的 `location-labels` 参数,同时保证 `isolation-level` 的值一定为 `location-labels` 中的一个。 + +### 使用 TiUP 进行配置(推荐) + +如果使用 TiUP 部署集群,可以在[初始化配置文件](/production-deployment-using-tiup.md#第-3-步初始化集群拓扑文件)中统一进行 location 相关配置。TiUP 会负责在部署时生成对应的 TiKV、PD 和 TiFlash 配置文件。 + +下面的例子定义了 `zone` 和 `host` 两层拓扑结构。集群的 TiKV 和 TiFlash 分布在三个 zone,z1、z2 和 z3。 + +- 每个 zone 内有两台主机部署 TiKV 实例,z1 每台主机同时部署两个 TiKV 实例,z2 和 z3 每台主机分别独立部署一个 TiKV 实例。 +- 每个 zone 内有两台主机部署 TiFlash 实例,TiFlash 实例均为独占机器部署。 + +以下例子中 `tikv-host-machine-n` 代表第 n 个 TiKV 节点的 IP 地址,`tiflash-host-machine-n` 代表第 n 个 TiFlash 节点的 IP 地址。 + +``` +server_configs: + pd: + replication.location-labels: ["zone", "host"] + +tikv_servers: +# z1 + # machine-1 on z1 + - host: tikv-host-machine-1 + port:20160 + config: + server.labels: + zone: z1 + host: tikv-host-machine-1 + - host: tikv-host-machine-1 + port:20161 + config: + server.labels: + zone: z1 + host: tikv-host-machine-1 + # machine-2 on z1 + - host: tikv-host-machine-2 + port:20160 + config: + server.labels: + zone: z1 + host: tikv-host-machine-2 + - host: tikv-host-machine-2 + port:20161 + config: + server.labels: + zone: z1 + host: tikv-host-machine-2 +# z2 + - host: tikv-host-machine-3 + config: + server.labels: + zone: z2 + host: tikv-host-machine-3 + - host: tikv-host-machine-4 + config: + server.labels: + zone: z2 + host: tikv-host-machine-4 +# z3 + - host: tikv-host-machine-5 + config: + server.labels: + zone: z3 + host: tikv-host-machine-5 + - host: tikv-host-machine-6 + config: + server.labels: + zone: z3 + host: tikv-host-machine-6 + +tiflash_servers: +# z1 + - host: tiflash-host-machine-1 + learner_config: + server.labels: + zone: z1 + host: tiflash-host-machine-1 + - host: tiflash-host-machine-2 + learner_config: + server.labels: + zone: z1 + host: tiflash-host-machine-2 +# z2 + - host: tiflash-host-machine-3 + learner_config: + server.labels: + zone: z2 + host: tiflash-host-machine-3 + - host: tiflash-host-machine-4 + learner_config: + server.labels: + zone: z2 + host: tiflash-host-machine-4 +# z3 + - host: tiflash-host-machine-5 + learner_config: + server.labels: + zone: z3 + host: tiflash-host-machine-5 + - host: tiflash-host-machine-6 + learner_config: + server.labels: + zone: z3 + host: tiflash-host-machine-6 +``` + +详情参阅 [TiUP 跨数据中心部署拓扑](/geo-distributed-deployment-topology.md)。 + +> **注意:** +> +> 如果你未在配置文件中配置 `replication.location-labels` 项,使用该拓扑配置文件部署集群时可能会报错。建议在部署集群前,确认 `replication.location-labels` 已配置。 + +## 基于拓扑 label 的 PD 调度策略 + +PD 在副本调度时,会按照 label 层级,保证同一份数据的不同副本尽可能分散。 + +下面以上一节的拓扑结构为例分析。 + +假设集群副本数设置为 3 (`max-replicas=3`),因为总共有 3 个 zone,PD 会保证每个 Region 的 3 个副本分别放置在 z1/z2/z3,这样当任何一个数据中心发生故障时,TiDB 集群依然是可用的。 + +假如集群副本数设置为 5 (`max-replicas=5`),因为总共只有 3 个 zone,在这一层级 PD 无法保证各个副本的隔离,此时 PD 调度器会退而求其次,保证在 host 这一层的隔离。也就是说,会出现一个 Region 的多个副本分布在同一个 zone 的情况,但是不会出现多个副本分布在同一台主机。 + +在 5 副本配置的前提下,如果 z3 出现了整体故障或隔离,并且 z3 在一段时间后仍然不能恢复(由 `max-store-down-time` 控制),PD 会通过调度补齐 5 副本,此时可用的主机只有 4 个了,故而无法保证 host 级别的隔离,于是可能出现多个副本被调度到同一台主机的情况。 + +但假如 `isolation-level` 设置不为空,值为 `zone`,这样就规定了 Region 副本在物理层面上的最低隔离要求,也就是说 PD 一定会保证同一 Region 的副本分散于不同的 zone 之上。即便遵循此隔离限制会无法满足 `max-replicas` 的多副本要求,PD 也不会进行相应的调度。例如,当前存在 TiKV 集群的三个可用区 z1/z2/z3,在三副本的设置下,PD 会将同一 Region 的三个副本分别分散调度至这三个可用区。若此时 z1 整个可用区发生了停电事故并在一段时间后(由 [`max-store-down-time`](/pd-configuration-file.md#max-store-down-time) 控制,默认为 30 分钟)仍然不能恢复,PD 会认为 z1 上的 Region 副本不再可用。但由于 `isolation-level` 设置为了 `zone`,PD 需要严格保证不同的 Region 副本不会落到同一 zone 上。此时的 z2 和 z3 均已存在副本,则 PD 在 `isolation-level` 的最小强制隔离级别限制下便不会进行任何调度,即使此时仅存在两个副本。 + +类似地,`isolation-level` 为 `rack` 时,最小隔离级别便为同一可用区的不同 rack。在此设置下,如果能在 zone 级别保证隔离,会首先保证 zone 级别的隔离。只有在 zone 级别隔离无法完成时,才会考虑避免出现在同一 zone 同一 rack 的调度,并以此类推。 + +总的来说,PD 能够根据当前的拓扑结构使得集群容灾能力最大化。所以如果用户希望达到某个级别的容灾能力,就需要根据拓扑结构在对应级别提供多于副本数 (`max-replicas`) 的机器。同时 TiDB 也提供了诸如 `isolation-level` 这样的强制隔离级别设置,以便更灵活地根据场景来控制对数据的拓扑隔离级别。 diff --git a/markdown-pages/zh/tidb/master/sql-logical-optimization.md b/markdown-pages/zh/tidb/master/sql-logical-optimization.md new file mode 100644 index 0000000..34df646 --- /dev/null +++ b/markdown-pages/zh/tidb/master/sql-logical-optimization.md @@ -0,0 +1,20 @@ +--- +title: 逻辑优化 +aliases: ['/docs-cn/dev/sql-logical-optimization/'] +summary: 本章节介绍了 TiDB 查询计划的关键逻辑改写,包括子查询优化、列裁剪、关联子查询去关联、Max/Min 消除、谓词下推、分区裁剪、TopN 和 Limit 下推以及 Join 重排序。这些改写帮助 TiDB 生成最终的查询计划,提高查询效率。 +--- + +# 逻辑优化 + +本章节将对一些比较关键的逻辑改写进行说明,帮助大家理解 TiDB 如何生成最终的查询计划。比如在 TiDB 输入 `select * from t where t.a in (select t1.a from t1 where t1.b=t.b)` 这个查询时,在最终的执行计划中将看不到这个 `t.a in (select t1.a from t1 where t1.b=t.b)` 这个 `IN` 子查询的存在,这便是因为 TiDB 对这里进行了一些改写。 + +本章节会介绍如下几个关键改写: + +- [子查询相关的优化](/subquery-optimization.md) +- [列裁剪](/column-pruning.md) +- [关联子查询去关联](/correlated-subquery-optimization.md) +- [Max/Min 消除](/max-min-eliminate.md) +- [谓词下推](/predicate-push-down.md) +- [分区裁剪](/partition-pruning.md) +- [TopN 和 Limit 下推](/topn-limit-push-down.md) +- [Join Reorder](/join-reorder.md) diff --git a/markdown-pages/zh/tidb/master/sql-mode.md b/markdown-pages/zh/tidb/master/sql-mode.md new file mode 100644 index 0000000..2e418c5 --- /dev/null +++ b/markdown-pages/zh/tidb/master/sql-mode.md @@ -0,0 +1,58 @@ +--- +title: SQL 模式 +aliases: ['/docs-cn/dev/sql-mode/','/docs-cn/dev/reference/sql/sql-mode/'] +summary: TiDB 服务器采用不同 SQL 模式来操作,可以使用 `SET [SESSION | GLOBAL] sql_mode='modes'` 语句设置 SQL 模式。`GLOBAL` 级别的 SQL 模式需要 `SUPER` 权限,影响新连接;`SESSION` 级别的 SQL 模式只影响当前客户端。重要的 sql_mode 值包括 `ANSI`、`STRICT_TRANS_TABLES` 和 `TRADITIONAL`。SQL mode 列表包括 `PIPES_AS_CONCAT`、`ANSI_QUOTES`、`IGNORE_SPACE`、`ONLY_FULL_GROUP_BY` 等。 +--- + +# SQL 模式 + +TiDB 服务器采用不同 SQL 模式来操作,且不同客户端可以应用不同模式。SQL 模式定义 TiDB 支持哪些 SQL 语法及执行哪种数据验证检查。 + +TiDB 启动之后,你可以使用 `SET [ SESSION | GLOBAL ] sql_mode='modes'` 语句设置 SQL 模式。 + +- 设置 `GLOBAL` 级别的 SQL 模式时用户需要有 `SUPER` 权限,并且只会影响到从设置 SQL 模式开始后续新建立的连接(注:老连接不受影响)。 +- `SESSION` 级别的 SQL 模式的变化只会影响当前的客户端。 + +在该语句中,`modes` 是用逗号 (`,`) 间隔开的一系列不同的模式。使用 `SELECT @@sql_mode` 语句查询当前 SQL 模式,SQL 模式默认值:`ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION`。 + +## 重要的 sql_mode 值 + +* `ANSI`:符合标准 SQL,对数据进行校验,如果不符合定义类型或长度,对数据类型调整或截断保存,且返回 `warning` 警告。 +* `STRICT_TRANS_TABLES`:严格模式,对数据进行严格校验,当数据出现错误时,无法被插入到表中,并且返回错误。 +* `TRADITIONAL`:采用此模式使 TiDB 的行为像“传统” SQL 数据库系统,当在列中插入不正确的值时“给出错误而不是警告”,一旦发现错误立即放弃 `INSERT` 或 `UPDATE`。 + +## SQL mode 列表,如下 + +| 名称 | 含义 | +| --- | --- | +| `PIPES_AS_CONCAT` | 将 "\|\|" 视为字符串连接操作符 (`+`)(同 `CONCAT()`),而不视为 `OR`(支持)| +| `ANSI_QUOTES` | 将 `"` 视为识别符,如果启用 `ANSI_QUOTES`,只单引号内的会被认为是 String Literals,双引号被解释为识别符,因此不能用双引号来引用字符串(支持)| +| `IGNORE_SPACE` | 若开启该模式,系统忽略空格。例如:“user” 和 “user “ 是相同的(支持)| +| `ONLY_FULL_GROUP_BY` | 如果未被聚合函数处理或未被 `GROUP BY` 的列出现在 `SELECT`、`HAVING`、`ORDER BY` 中,此 SQL 不合法,因为这种列被查询展示出来不合常规(支持)| +| `NO_UNSIGNED_SUBTRACTION` | 在减运算中,如果某个操作数没有符号,不要将结果标记为 `UNSIGNED`(支持)| +| `NO_DIR_IN_CREATE` | 创建表时,忽视所有 `INDEX DIRECTORY` 和 `DATA DIRECTORY` 指令,该选项仅对从复制服务器有用 (仅语法支持)| +| `NO_KEY_OPTIONS` | 使用 `SHOW CREATE TABLE` 时不会输出 MySQL 特有的语法部分,如 `ENGINE`,使用 mysqldump 跨 DB 种类迁移的时需要考虑此选项(仅语法支持)| +| `NO_FIELD_OPTIONS` | 使用 `SHOW CREATE TABLE` 时不会输出 MySQL 特有的语法部分,如 `ENGINE`,使用 mysqldump 跨 DB 种类迁移的时需要考虑此选项(仅语法支持)| +| `NO_TABLE_OPTIONS` | 使用 `SHOW CREATE TABLE` 时不会输出 MySQL 特有的语法部分,如 `ENGINE`,使用 mysqldump 跨 DB 种类迁移的时需要考虑此选项(仅语法支持)| +| `NO_AUTO_VALUE_ON_ZERO` | 若启用该模式,在AUTO_INCREMENT列的处理传入的值是 `0` 或者具体数值时系统直接将该值写入此列,传入 `NULL` 时系统自动生成下一个序列号(支持)| +| `NO_BACKSLASH_ESCAPES` | 若启用该模式,`\` 反斜杠符号仅代表它自己(支持)| +| `STRICT_TRANS_TABLES` | 对于事务存储引擎启用严格模式,insert非法值之后,回滚整条语句(支持)| +| `STRICT_ALL_TABLES` | 对于事务型表,写入非法值之后,回滚整个事务语句(支持)| +| `NO_ZERO_IN_DATE` | 在严格模式,不接受月或日部分为0的日期。如果使用IGNORE选项,我们为类似的日期插入'0000-00-00'。在非严格模式,可以接受该日期,但会生成警告(支持) +| `NO_ZERO_DATE` | 在严格模式,不要将 '0000-00-00'做为合法日期。你仍然可以用 `IGNORE` 选项插入零日期。在非严格模式,可以接受该日期,但会生成警告(支持)| +| `ALLOW_INVALID_DATES` | 不检查全部日期的合法性,仅检查月份值在 1 到 12 及日期值在 1 到 31 之间,仅适用于 `DATE` 和 `DATATIME` 列,`TIMESTAMP` 列需要全部检查其合法性(支持)| +| `ERROR_FOR_DIVISION_BY_ZERO` | 若启用该模式,在 `INSERT` 或 `UPDATE` 过程中,被除数为 `0` 值时,系统产生错误
若未启用该模式,被除数为 0 值时,系统产生警告,并用 `NULL` 代替(支持) | +| `NO_AUTO_CREATE_USER` | 防止 `GRANT` 自动创建新用户,但指定密码除外(支持)| +| `HIGH_NOT_PRECEDENCE` | NOT 操作符的优先级是表达式。例如:`NOT a BETWEEN b AND c` 被解释为 `NOT (a BETWEEN b AND c)`。在部份旧版本 MySQL 中,表达式被解释为 `(NOT a) BETWEEN b AND c`(支持) | +| `NO_ENGINE_SUBSTITUTION` | 如果需要的存储引擎被禁用或未编译,可以防止自动替换存储引擎(仅语法支持)| +| `PAD_CHAR_TO_FULL_LENGTH` | 若启用该模式,系统对于 `CHAR` 类型不会截断尾部空格(仅语法支持。该模式[在 MySQL 8.0 中已废弃](https://dev.mysql.com/doc/refman/8.0/en/sql-mode.html#sqlmode_pad_char_to_full_length)。)| +| `REAL_AS_FLOAT` | 将 `REAL` 视为 `FLOAT` 的同义词,而不是 `DOUBLE` 的同义词(支持)| +| `POSTGRESQL` | 等同于 `PIPES_AS_CONCAT`、`ANSI_QUOTES`、`IGNORE_SPACE`、`NO_KEY_OPTIONS`、`NO_TABLE_OPTIONS`、`NO_FIELD_OPTIONS`(仅语法支持)| +| `MSSQL` | 等同于 `PIPES_AS_CONCAT`、`ANSI_QUOTES`、`IGNORE_SPACE`、`NO_KEY_OPTIONS`、`NO_TABLE_OPTIONS`、 `NO_FIELD_OPTIONS`(仅语法支持)| +| `DB2` | 等同于 `PIPES_AS_CONCAT`、`ANSI_QUOTES`、`IGNORE_SPACE`、`NO_KEY_OPTIONS`、`NO_TABLE_OPTIONS`、`NO_FIELD_OPTIONS`(仅语法支持)| +| `MAXDB` | 等同于 `PIPES_AS_CONCAT`、`ANSI_QUOTES`、`IGNORE_SPACE`、`NO_KEY_OPTIONS`、`NO_TABLE_OPTIONS`、`NO_FIELD_OPTIONS`、`NO_AUTO_CREATE_USER`(支持)| +| `MySQL323` | 等同于 `NO_FIELD_OPTIONS`、`HIGH_NOT_PRECEDENCE`(仅语法支持)| +| `MYSQL40` | 等同于 `NO_FIELD_OPTIONS`、`HIGH_NOT_PRECEDENCE`(仅语法支持)| +| `ANSI` | 等同于 `REAL_AS_FLOAT`、`PIPES_AS_CONCAT`、`ANSI_QUOTES`、`IGNORE_SPACE`(仅语法支持)| +| `TRADITIONAL` | 等同于 `STRICT_TRANS_TABLES`、`STRICT_ALL_TABLES`、`NO_ZERO_IN_DATE`、`NO_ZERO_DATE`、`ERROR_FOR_DIVISION_BY_ZERO`、`NO_AUTO_CREATE_USER`(仅语法支持)| +| `ORACLE` | 等同于 `PIPES_AS_CONCAT`、`ANSI_QUOTES`、`IGNORE_SPACE`、`NO_KEY_OPTIONS`、`NO_TABLE_OPTIONS`、`NO_FIELD_OPTIONS`、`NO_AUTO_CREATE_USER`(仅语法支持)| diff --git a/markdown-pages/zh/tidb/master/sql-optimization-concepts.md b/markdown-pages/zh/tidb/master/sql-optimization-concepts.md new file mode 100644 index 0000000..ece892e --- /dev/null +++ b/markdown-pages/zh/tidb/master/sql-optimization-concepts.md @@ -0,0 +1,17 @@ +--- +title: SQL 优化流程简介 +aliases: ['/docs-cn/dev/sql-optimization-concepts/','/docs-cn/dev/reference/performance/sql-optimizer-overview/'] +summary: TiDB 中的 SQL 优化流程包括查询文本解析、逻辑等价变化和最终执行计划生成。经过 parser 解析和合法性验证后,TiDB 会对查询进行逻辑上的等价变化,使得查询在逻辑执行计划上更易处理。之后根据数据分布和执行开销生成最终执行计划。同时,TiDB 在执行 PREPARE 语句时可以选择开启缓存来降低执行计划生成的开销。 +--- + +# SQL 优化流程简介 + +在 TiDB 中,从输入的查询文本到最终的执行计划执行结果的过程可以见下图。 + +![SQL Optimization](/media/sql-optimization.png) + +在经过了 `parser` 对原始查询文本的解析以及一些简单的合法性验证后,TiDB 首先会对查询做一些逻辑上的等价变化,详细的变化可以查询[逻辑优化](/sql-logical-optimization.md)章节。 + +通过这些等价变化,使得这个查询在逻辑执行计划上可以变得更易于处理。在等价变化结束之后,TiDB 会得到一个与原始查询等价的查询计划结构,之后根据数据分布、以及一个算子具体的执行开销,来获得一个最终的执行计划,这部分内容可以查询[物理优化](/sql-physical-optimization.md)章节。 + +同时,TiDB 在执行 [`PREPARE`](/sql-statements/sql-statement-prepare.md) 语句时,可以选择开启缓存来降低 TiDB 生成执行计划的开销,这部分内容会在[执行计划缓存](/sql-prepared-plan-cache.md)一节中介绍。 \ No newline at end of file diff --git a/markdown-pages/zh/tidb/master/sql-physical-optimization.md b/markdown-pages/zh/tidb/master/sql-physical-optimization.md new file mode 100644 index 0000000..c9102ac --- /dev/null +++ b/markdown-pages/zh/tidb/master/sql-physical-optimization.md @@ -0,0 +1,17 @@ +--- +title: 物理优化 +aliases: ['/docs-cn/dev/sql-physical-optimization/'] +summary: 物理优化是基于代价的优化,为逻辑执行计划制定物理执行计划。优化器根据数据统计信息选择时间复杂度、资源消耗和物理属性最小的物理执行计划。TiDB 执行计划文档介绍了索引选择、统计信息、错误索引解决方案、Distinct 优化和代价模型。 +--- + +# 物理优化 + +物理优化是基于代价的优化,为上一阶段产生的逻辑执行计划制定物理执行计划。这一阶段中,优化器会为逻辑执行计划中的每个算子选择具体的物理实现。逻辑算子的不同物理实现有着不同的时间复杂度、资源消耗和物理属性等。在这个过程中,优化器会根据数据的统计信息来确定不同物理实现的代价,并选择整体代价最小的物理执行计划。 + +[理解 TiDB 执行计划](/explain-overview.md)文档已对每个物理算子进行了一些介绍。在本章我们会重点介绍以下方面: + +- 在[索引的选择](/choose-index.md)中会介绍 TiDB 在一张表有多个索引时,如何选择最优的索引进行表的访问。 +- 在[统计信息简介](/statistics.md)中会介绍 TiDB 收集了哪些统计信息来获得表的数据分布情况 +- 在[错误索引的解决方案](/wrong-index-solution.md)中会介绍当发现 TiDB 索引选错时,你应该使用那些手段来让它使用正确的索引 +- 在 [Distinct 优化](/agg-distinct-optimization.md)中会介绍在物理优化中会做的一个有关 `DISTINCT` 关键字的优化,在这一小节中会介绍它的优缺点以及如何使用它。 +- 在[代价模型](/cost-model.md)中会介绍在物理优化时,TiDB 怎么通过代价模型来选择一个最优的执行计划。 \ No newline at end of file diff --git a/markdown-pages/zh/tidb/master/sql-prepared-plan-cache.md b/markdown-pages/zh/tidb/master/sql-prepared-plan-cache.md new file mode 100644 index 0000000..7ef8112 --- /dev/null +++ b/markdown-pages/zh/tidb/master/sql-prepared-plan-cache.md @@ -0,0 +1,316 @@ +--- +title: Prepare 语句执行计划缓存 +aliases: ['/docs-cn/dev/sql-prepare-plan-cache/','zh/tidb/dev/sql-prepare-plan-cache'] +summary: Prepare 语句执行计划缓存功能默认打开,可通过变量启用或关闭。缓存功能仅针对 Prepare/Execute 请求,对普通查询无效。缓存功能会有一定内存开销,可通过监控查看内存使用情况。可手动清空计划缓存,但不支持一次性清空整个集群的计划缓存。忽略 COM_STMT_CLOSE 指令和 DEALLOCATE PREPARE 语句,可解决计划被立即清理的问题。监控 Queries Using Plan Cache OPS 和 Plan Cache Miss OPS,以确保 SQL 执行计划缓存正常工作。Prepared Statement Count 图表显示非零值,表示应用使用了预处理语句。 +--- + +# Prepare 语句执行计划缓存 + +> **警告:** +> +> 如果已经被缓存的 `UPDATE` 或 `DELETE` 语句在执行过程中,同时遇到 DDL 对相关 schema 进行变更,可能会导致表和索引的数据不一致。详情参考 [Issue #51407](https://github.com/pingcap/tidb/issues/51407)。请关注该 Issue 的修复状态,并升级到[最新的 LTS 版本](https://docs.pingcap.com/zh/tidb/stable)解决该问题。在升级前,你可以尝试以下规避方法: +> +> - 在执行 DDL 前,暂时[关闭 Prepare 语句的执行计划缓存](/system-variables.md#tidb_enable_prepared_plan_cache-从-v610-版本开始引入),DDL 执行完毕后再恢复打开。 +> - 避免在业务高峰期执行 DDL。执行 DDL 后立即运行 [`ADMIN CHECK TABLE`](/sql-statements/sql-statement-admin-check-table-index.md) 检查表和索引的一致性,一旦发现错误则重建相关索引。 + +TiDB 支持对 `Prepare`/`Execute` 请求的执行计划缓存。其中包括以下两种形式的预处理语句: + +- 使用 `COM_STMT_PREPARE` 和 `COM_STMT_EXECUTE` 的协议功能; +- 执行 `Prepare`/`Execute` SQL 语句查询; + +TiDB 优化器对这两类查询的处理是一样的:`Prepare` 时将参数化的 SQL 查询解析成 AST(抽象语法树),每次 `Execute` 时根据保存的 AST 和具体的参数值生成执行计划。 + +当开启执行计划缓存后,每条 `Prepare` 语句的第一次 `Execute` 会检查当前查询是否可以使用执行计划缓存,如果可以则将生成的执行计划放进一个由 LRU 链表构成的缓存中;在后续的 `Execute` 中,会先从缓存中获取执行计划,并检查是否可用,如果获取和检查成功则跳过生成执行计划这一步,否则重新生成执行计划并放入缓存中。 + +对于某些非 `PREPARE` 语句,TiDB 可以像 `Prepare`/`Execute` 语句一样支持执行计划缓存,详情请参考[非 Prepare 语句执行计划缓存](/sql-non-prepared-plan-cache.md)。 + +在当前版本中,当 `Prepare` 语句符合以下条件任何一条,查询或者计划不会被缓存: + +- `SELECT`、`UPDATE`、`INSERT`、`DELETE`、`Union`、`Intersect`、`Except` 以外的 SQL 语句; +- 访问分区表、临时表的查询; +- 查询中包含非关联子查询,例如 `SELECT * FROM t1 WHERE t1.a > (SELECT 1 FROM t2 WHERE t2.b < 1)`; +- 执行计划中带有 `PhysicalApply` 算子的关联子查询,例如 `SELECT * FROM t1 WHERE t1.a > (SELECT a FROM t2 WHERE t1.b > t2.b)`; +- 包含 `ignore_plan_cache` 或 `set_var` 这两个 Hint 的查询,例如 `SELECT /*+ ignore_plan_cache() */ * FROM t` 或 `SELECT /*+ set_var(max_execution_time=1) */ * FROM t`; +- 包含除 `?` 外其他变量(即系统变量或用户自定义变量)的查询,例如 `select * from t where a>? and b>@x`; +- 查询包含无法被缓存函数。目前不能被缓存的函数有:`database()`、`current_user`、`current_role`、`user`、`connection_id`、`last_insert_id`、`row_count`、`version`、`like`; +- `LIMIT` 后面带有变量(例如 `LIMIT ?` 或 `LIMIT 10, ?`)且变量值大于 10000 的执行计划不缓存; +- `?` 直接在 `Order By` 后的查询,如 `Order By ?`,此时 `?` 表示根据 `Order By` 后第几列排序,排序列不同的查询使用同一个计划可能导致错误结果,故不缓存;如果是普通表达式,如 `Order By a+?` 则会缓存; +- `?` 紧跟在 `Group by` 后的查询,如 `Group By ?`,此时 `?` 表示根据 `Group By` 后第几列聚合,聚合列不同的查询使用同一个计划可能导致错误结果,故不缓存;如果是普通表达式,如 `Group By a+?` 则会缓存; +- `?` 出现在窗口函数 `Window Frame` 定义中的查询,如 `(partition by year order by sale rows ? preceding)`;如果 `?` 出现在窗口函数的其他位置,则会缓存; +- 用参数进行 `int` 和 `string` 比较的查询,如 `c_int >= ?` 或者 `c_int in (?, ?)`等,其中 `?` 为字符串类型,如 `set @x='123'`;此时为了保证结果和 MySQL 兼容性,需要每次对参数进行调整,故不会缓存; +- 会访问 `TiFlash` 的计划不会被缓存; +- 大部分情况下计划中含有 `TableDual` 的计划将将不会被缓存,除非当前执行的 `Prepare` 语句不含参数,则对应的 `TableDual` 计划可以被缓存。 +- 访问 TiDB 系统视图的查询,如 `information_schema.columns`。不建议使用 `Prepare`/`Execute` 语句访问系统视图。 + +TiDB 对 `?` 的个数有限制,如果超过了 65535 个,则会报错 `Prepared statement contains too many placeholders`。 + +LRU 链表是设计成 session 级别的缓存,因为 `Prepare`/`Execute` 不能跨 session 执行。LRU 链表的每个元素是一个 key-value 对,value 是执行计划,key 由如下几部分组成: + +- 执行 `Execute` 时所在数据库的名字; +- `Prepare` 语句的标识符,即紧跟在 `PREPARE` 关键字后的名字; +- 当前的 schema 版本,每条执行成功的 DDL 语句会修改 schema 版本; +- 执行 `Execute` 时的 SQL Mode; +- 当前设置的时区,即系统变量 `time_zone` 的值; +- 系统变量 `sql_select_limit` 的值; + +key 中任何一项变动(如切换数据库、重命名 `Prepare` 语句、执行 DDL、修改 SQL Mode/`time_zone` 的值)、或 LRU 淘汰机制触发都会导致 `Execute` 时无法命中执行计划缓存。 + +成功从缓存中获取到执行计划后,TiDB 会先检查执行计划是否依然合法,如果当前 `Execute` 在显式事务里执行,并且引用的表在事务前序语句中被修改,而缓存的执行计划对该表访问不包含 `UnionScan` 算子,则它不能被执行。 + +在通过合法性检测后,会根据当前最新参数值,对执行计划的扫描范围做相应调整,再用它执行获取数据。 + +关于执行计划缓存和查询性能有几点值得注意: + +- 不管计划是否已经被缓存,都会受到 SQL Binding 的影响。对于没有被缓存的计划,即在第一次执行 `Execute` 时,会受到已有 SQL Binding 的影响;而对于已经缓存的计划,如果有新的 SQL Binding 被创建产生,则原有已经被缓存的计划会失效。 +- 已经被缓存的计划不会受到统计信息更新、优化规则和表达式下推黑名单更新的影响,仍然会使用已经保存在缓存中的计划。 +- 重启 TiDB 实例时(如不停机滚动升级 TiDB 集群),`Prepare` 信息会丢失,此时执行 `execute stmt ...` 可能会遇到 `Prepared Statement not found` 的错误,此时需要再执行一次 `prepare stmt ...`。 +- 考虑到不同 `Execute` 的参数会不同,执行计划缓存为了保证适配性会禁止一些和具体参数值密切相关的激进查询优化手段,导致对特定的一些参数值,查询计划可能不是最优。比如查询的过滤条件为 `where a > ? and a < ?`,第一次 `Execute` 时参数分别为 2 和 1,考虑到这两个参数下次执行时可能会是 1 和 2,优化器不会生成对当前参数最优的 `TableDual` 执行计划。 +- 如果不考虑缓存失效和淘汰,一份执行计划缓存会对应各种不同的参数取值,理论上也会导致某些取值下执行计划非最优。比如查询过滤条件为 `where a < ?`,假如第一次执行 `Execute` 时用的参数值为 1,此时优化器生成最优的 `IndexScan` 执行计划放入缓存,在后续执行 `Exeucte` 时参数变为 10000,此时 `TableScan` 可能才是更优执行计划,但由于执行计划缓存,执行时还是会使用先前生成的 `IndexScan`。因此执行计划缓存更适用于查询较为简单(查询编译耗时占比较高)且执行计划较为固定的业务场景。 + +自 v6.1.0 起,执行计划缓存功能默认打开,可以通过变量 [`tidb_enable_prepared_plan_cache`](/system-variables.md#tidb_enable_prepared_plan_cache-从-v610-版本开始引入) 启用或关闭这项功能。 + +> **注意:** +> +> 执行计划缓存功能仅针对 `Prepare`/`Execute` 请求,对普通查询无效。 + +在开启了执行计划缓存功能后,可以通过 SESSION 级别的系统变量 [`last_plan_from_cache`](/system-variables.md#last_plan_from_cache-从-v40-版本开始引入) 查看上一条 `Execute` 语句是否使用了缓存的执行计划,例如: + +```sql +MySQL [test]> create table t(a int); +Query OK, 0 rows affected (0.00 sec) + +MySQL [test]> prepare stmt from 'select * from t where a = ?'; +Query OK, 0 rows affected (0.00 sec) + +MySQL [test]> set @a = 1; +Query OK, 0 rows affected (0.00 sec) + +-- 第一次 execute 生成执行计划放入缓存 +MySQL [test]> execute stmt using @a; +Empty set (0.00 sec) + +MySQL [test]> select @@last_plan_from_cache; ++------------------------+ +| @@last_plan_from_cache | ++------------------------+ +| 0 | ++------------------------+ +1 row in set (0.00 sec) + +-- 第二次 execute 命中缓存 +MySQL [test]> execute stmt using @a; +Empty set (0.00 sec) + +MySQL [test]> select @@last_plan_from_cache; ++------------------------+ +| @@last_plan_from_cache | ++------------------------+ +| 1 | ++------------------------+ +1 row in set (0.00 sec) +``` + +如果发现某一组 `Prepare`/`Execute` 由于执行计划缓存导致了非预期行为,可以通过 SQL Hint `ignore_plan_cache()` 让该组语句不使用缓存。还是用上述的 `stmt` 为例: + +```sql +MySQL [test]> prepare stmt from 'select /*+ ignore_plan_cache() */ * from t where a = ?'; +Query OK, 0 rows affected (0.00 sec) + +MySQL [test]> set @a = 1; +Query OK, 0 rows affected (0.00 sec) + +MySQL [test]> execute stmt using @a; +Empty set (0.00 sec) + +MySQL [test]> select @@last_plan_from_cache; ++------------------------+ +| @@last_plan_from_cache | ++------------------------+ +| 0 | ++------------------------+ +1 row in set (0.00 sec) + +MySQL [test]> execute stmt using @a; +Empty set (0.00 sec) + +MySQL [test]> select @@last_plan_from_cache; ++------------------------+ +| @@last_plan_from_cache | ++------------------------+ +| 0 | ++------------------------+ +1 row in set (0.00 sec) +``` + +## 诊断 Prepared Plan Cache + +对于无法进行缓存的查询或计划,可通过 `SHOW WARNINGS` 语句查看查询或计划是否被缓存。如果未被缓存,则可在结果中查看无法被缓存的原因。示例如下: + +```sql +mysql> PREPARE st FROM 'SELECT * FROM t WHERE a > (SELECT MAX(a) FROM t)'; -- 该查询包含子查询,因此无法被缓存 +Query OK, 0 rows affected, 1 warning (0.01 sec) + +mysql> SHOW WARNINGS; -- 查看查询计划无法被缓存的原因 ++---------+------+-----------------------------------------------+ +| Level | Code | Message | ++---------+------+-----------------------------------------------+ +| Warning | 1105 | skip plan-cache: sub-queries are un-cacheable | ++---------+------+-----------------------------------------------+ +1 row in set (0.00 sec) + +mysql> PREPARE st FROM 'SELECT * FROM t WHERE a SET @a='1'; +Query OK, 0 rows affected (0.00 sec) + +mysql> EXECUTE st USING @a; -- 该优化中进行了非 INT 类型到 INT 类型的转换,产生的执行计划可能随着参数变化而存在风险,因此 TiDB 不缓存该计划 +Empty set, 1 warning (0.01 sec) + +mysql> SHOW WARNINGS; ++---------+------+----------------------------------------------+ +| Level | Code | Message | ++---------+------+----------------------------------------------+ +| Warning | 1105 | skip plan-cache: '1' may be converted to INT | ++---------+------+----------------------------------------------+ +1 row in set (0.00 sec) +``` + +## Prepared Plan Cache 的内存管理 + +使用 Prepared Plan Cache 会有一定的内存开销,可以通过 Grafana 中的 [`Plan Cache Memory Usage` 监控](/grafana-tidb-dashboard.md)查看每台 TiDB 实例上所有 `SESSION` 所缓存的计划占用的总内存。 + +> **注意:** +> +> 考虑到 Golang 的内存回收机制以及部分未统计的内存结构,Grafana 中显示的内存与实际的堆内存使用量并不相等。经过实验验证存在约 ±20% 的误差。 + +对于每台 TiDB 实例上所缓存的执行计划总数量,可以通过 Grafana 中的 [`Plan Cache Plan Num` 监控](/grafana-tidb-dashboard.md)查看。 + +Grafana 中 `Plan Cache Memory Usage` 和 `Plan Cache Plan Num` 监控如下图所示: + +![grafana_panels](/media/planCache-memoryUsage-planNum-panels.png) + +从 v7.1.0 开始,你可以通过变量 [`tidb_session_plan_cache_size`](/system-variables.md#tidb_session_plan_cache_size-从-v710-版本开始引入) 来设置每个 `SESSION` 最多缓存的计划数量。针对不同的环境,推荐的设置如下,你可以结合监控进行调整: + +- TiDB Server 实例内存阈值 <= 64 GiB 时,`tidb_session_plan_cache_size = 50` +- TiDB Server 实例内存阈值 > 64 GiB 时,`tidb_session_plan_cache_size = 100` + +从 v7.1.0 开始,你可以通过变量 [`tidb_plan_cache_max_plan_size`](/system-variables.md#tidb_plan_cache_max_plan_size-从-v710-版本开始引入) 来设置可以缓存的计划的最大大小,默认为 2 MB。超过该值的执行计划将不会被缓存到 Plan Cache 中。 + +当 TiDB Server 的内存余量小于一定阈值时,会触发 Plan Cache 的内存保护机制,此时会对一些缓存的计划进行逐出。 + +目前该阈值由变量 `tidb_prepared_plan_cache_memory_guard_ratio` 控制,默认为 0.1,即 10%,也就是当剩余内存不足 10%(使用内存超过 90%)时,会触发此机制。 + +由于内存限制,Plan Cache 可能出现 Cache Miss 的情况,可以通过 Grafana 中的 [`Plan Cache Miss OPS` 监控](/grafana-tidb-dashboard.md)查看。 + +## 手动清空计划缓存 + +通过执行 `ADMIN FLUSH [SESSION | INSTANCE] PLAN_CACHE` 语句,你可以手动清空计划缓存。 + +该语句中的作用域 `[SESSION | INSTANCE]` 用于指定需要清空的缓存级别,可以为 `SESSION` 或 `INSTANCE`。如果不指定作用域,该语句默认清空 `SESSION` 级别的缓存。 + +下面是一个清空计划缓存的例子: + +```sql +MySQL [test]> create table t (a int); +Query OK, 0 rows affected (0.00 sec) + +MySQL [test]> prepare stmt from 'select * from t'; +Query OK, 0 rows affected (0.00 sec) + +MySQL [test]> execute stmt; +Empty set (0.00 sec) + +MySQL [test]> execute stmt; +Empty set (0.00 sec) + +MySQL [test]> select @@last_plan_from_cache; -- 选择计划缓存 ++------------------------+ +| @@last_plan_from_cache | ++------------------------+ +| 1 | ++------------------------+ +1 row in set (0.00 sec) + +MySQL [test]> admin flush session plan_cache; -- 清空当前 session 的计划缓存 +Query OK, 0 rows affected (0.00 sec) + +MySQL [test]> execute stmt; +Empty set (0.00 sec) + +MySQL [test]> select @@last_plan_from_cache; -- 由于缓存被清空,此时无法再次选中 ++------------------------+ +| @@last_plan_from_cache | ++------------------------+ +| 0 | ++------------------------+ +1 row in set (0.00 sec) +``` + +TiDB 暂不支持清空 `GLOBAL` 级别的计划缓存,即不支持一次性清空整个集群的计划缓存,使用时会报错: + +```sql +MySQL [test]> admin flush global plan_cache; +ERROR 1105 (HY000): Do not support the 'admin flush global scope.' +``` + +## 忽略 `COM_STMT_CLOSE` 指令和 `DEALLOCATE PREPARE` 语句 + +为了减少每次执行 SQL 语句的语法分析,Prepared Statement 推荐的使用方式是,prepare 一次,然后 execute 多次,最后 deallocate prepare。例如: + +```sql +MySQL [test]> prepare stmt from '...'; -- prepare 一次 +MySQL [test]> execute stmt using ...; -- execute 一次 +MySQL [test]> ... +MySQL [test]> execute stmt using ...; -- execute 多次 +MySQL [test]> deallocate prepare stmt; -- 使用完成后释放 +``` + +如果你习惯于在每次 execute 后都立即执行 deallocate prepare,如: + +```sql +MySQL [test]> prepare stmt from '...'; -- 第一次 prepare +MySQL [test]> execute stmt using ...; +MySQL [test]> deallocate prepare stmt; -- 一次使用后立即释放 +MySQL [test]> prepare stmt from '...'; -- 第二次 prepare +MySQL [test]> execute stmt using ...; +MySQL [test]> deallocate prepare stmt; -- 再次释放 +``` + +这样的使用方式会让第一次执行得到的计划被立即清理,不能在第二次被复用。 + +为了兼容这样的使用方式,从 v6.0 起,TiDB 支持 [`tidb_ignore_prepared_cache_close_stmt`](/system-variables.md#tidb_ignore_prepared_cache_close_stmt-从-v600-版本开始引入) 变量。打开该变量后,TiDB 会忽略关闭 Prepare Statement 的信号,解决上述问题,如: + +```sql +mysql> set @@tidb_ignore_prepared_cache_close_stmt=1; -- 打开开关 +Query OK, 0 rows affected (0.00 sec) + +mysql> prepare stmt from 'select * from t'; -- 第一次 prepare +Query OK, 0 rows affected (0.00 sec) + +mysql> execute stmt; -- 第一次 execute +Empty set (0.00 sec) + +mysql> deallocate prepare stmt; -- 第一次 execute 后立即释放 +Query OK, 0 rows affected (0.00 sec) + +mysql> prepare stmt from 'select * from t'; -- 第二次 prepare +Query OK, 0 rows affected (0.00 sec) + +mysql> execute stmt; -- 第二次 execute +Empty set (0.00 sec) + +mysql> select @@last_plan_from_cache; -- 因为开关打开,第二次依旧能复用上一次的计划 ++------------------------+ +| @@last_plan_from_cache | ++------------------------+ +| 1 | ++------------------------+ +1 row in set (0.00 sec) +``` + +### 监控 + +在 [Grafana 面板](/grafana-tidb-dashboard.md)的 TiDB 页面,**Executor** 部分包含“Queries Using Plan Cache OPS”和“Plan Cache Miss OPS”两个图表,用以检查 TiDB 和应用是否正确配置,以便 SQL 执行计划缓存能正常工作。TiDB 页面的 **Server** 部分还提供了“Prepared Statement Count”图表,如果应用使用了预处理语句,这个图表会显示非零值。通过数值变化,可以判断 SQL 执行计划缓存是否正常工作。 + +![`sql_plan_cache`](/media/performance/sql_plan_cache.png) diff --git a/markdown-pages/zh/tidb/master/sql-statements/sql-statement-admin-show-telemetry.md b/markdown-pages/zh/tidb/master/sql-statements/sql-statement-admin-show-telemetry.md new file mode 100644 index 0000000..1ae8af6 --- /dev/null +++ b/markdown-pages/zh/tidb/master/sql-statements/sql-statement-admin-show-telemetry.md @@ -0,0 +1,430 @@ +--- +title:ADMIN SHOW TELEMETRY +summary:TiDB 数据库中 ADMIN SHOW TELEMETRY 的使用概况。 +summary: ADMIN SHOW TELEMETRY 语句用于查看通过遥测功能收集到并分享给 PingCAP 的使用信息。该语句是 TiDB 对 MySQL 语法的扩展。可用于查看硬件信息、实例信息、主机额外信息、特性使用情况和慢查询统计等。 +--- + +# ADMIN SHOW TELEMETRY + +`ADMIN SHOW TELEMETRY` 语句用于查看通过[遥测](/telemetry.md)功能收集到并分享给 PingCAP 的使用信息。 + +## 语法图 + +```ebnf+diagram +AdminStmt ::= + 'ADMIN' ( 'SHOW' ( 'DDL' ( 'JOBS' Int64Num? WhereClauseOptional | 'JOB' 'QUERIES' NumList )? | TableName 'NEXT_ROW_ID' | 'SLOW' AdminShowSlow | 'TELEMETRY' ) | 'CHECK' ( 'TABLE' TableNameList | 'INDEX' TableName Identifier ( HandleRange ( ',' HandleRange )* )? ) | 'RECOVER' 'INDEX' TableName Identifier | 'CLEANUP' ( 'INDEX' TableName Identifier | 'TABLE' 'LOCK' TableNameList ) | 'CHECKSUM' 'TABLE' TableNameList | 'CANCEL' 'DDL' 'JOBS' NumList | 'RELOAD' ( 'EXPR_PUSHDOWN_BLACKLIST' | 'OPT_RULE_BLACKLIST' | 'BINDINGS' ) | 'PLUGINS' ( 'ENABLE' | 'DISABLE' ) PluginNameList | 'REPAIR' 'TABLE' TableName CreateTableStmt | ( 'FLUSH' | 'CAPTURE' | 'EVOLVE' ) 'BINDINGS' ) + +``` + +## 示例 + +```sql +ADMIN SHOW TELEMETRY\G +``` + +```sql +*************************** 1. row *************************** + TRACKING_ID: a1ba1d97-b940-4d5b-a9d5-ddb0f2ac29e7 + LAST_STATUS: { + "check_at": "2021-08-11T08:23:38+02:00", + "is_error": false, + "error_msg": "", + "is_request_sent": true +} +DATA_PREVIEW: { + "hardware": [ + { + "instanceType": "tidb", + "listenHostHash": "4b84b15bff6ee5796152495a230e45e3d7e947d9", + "listenPort": "4000", + "cpu": { + "cache": "8192", + "cpuFrequency": "2301.00MHz", + "cpuLogicalCores": "8", + "cpuPhysicalCores": "4" + }, + "memory": { + "capacity": "16410021888" + }, + "disk": { + "ebbca862689fa9fef7c55c3112e375c4ce575fe4": { + "deviceName": "ebbca862689fa9fef7c55c3112e375c4ce575fe4", + "free": "624438726656", + "freePercent": "0.61", + "fstype": "btrfs", + "opts": "bind,rw,relatime", + "path": "fb365c1216b59e1cfc86950425867007a60f4435", + "total": "1022488477696", + "used": "397115568128", + "usedPercent": "0.39" + }, + "nvme0n1p1": { + "deviceName": "nvme0n1p1", + "free": "582250496", + "freePercent": "0.93", + "fstype": "vfat", + "opts": "rw,relatime", + "path": "0fc8c8d71702d81a02e216fb6ef19f4dda4973df", + "total": "627900416", + "used": "45649920", + "usedPercent": "0.07" + }, + "nvme0n1p2": { + "deviceName": "nvme0n1p2", + "free": "701976576", + "freePercent": "0.74", + "fstype": "ext4", + "opts": "rw,relatime", + "path": "/boot", + "total": "1023303680", + "used": "250863616", + "usedPercent": "0.26" + } + } + }, + { + "instanceType": "pd", + "listenHostHash": "4b84b15bff6ee5796152495a230e45e3d7e947d9", + "listenPort": "2379", + "cpu": { + "cache": "8192", + "cpuFrequency": "2301.00MHz", + "cpuLogicalCores": "8", + "cpuPhysicalCores": "4" + }, + "memory": { + "capacity": "16410021888" + }, + "disk": { + "ebbca862689fa9fef7c55c3112e375c4ce575fe4": { + "deviceName": "ebbca862689fa9fef7c55c3112e375c4ce575fe4", + "free": "624438726656", + "freePercent": "0.61", + "fstype": "btrfs", + "opts": "bind,rw,relatime", + "path": "fb365c1216b59e1cfc86950425867007a60f4435", + "total": "1022488477696", + "used": "397115568128", + "usedPercent": "0.39" + }, + "nvme0n1p1": { + "deviceName": "nvme0n1p1", + "free": "582250496", + "freePercent": "0.93", + "fstype": "vfat", + "opts": "rw,relatime", + "path": "0fc8c8d71702d81a02e216fb6ef19f4dda4973df", + "total": "627900416", + "used": "45649920", + "usedPercent": "0.07" + }, + "nvme0n1p2": { + "deviceName": "nvme0n1p2", + "free": "701976576", + "freePercent": "0.74", + "fstype": "ext4", + "opts": "rw,relatime", + "path": "/boot", + "total": "1023303680", + "used": "250863616", + "usedPercent": "0.26" + } + } + }, + { + "instanceType": "tikv", + "listenHostHash": "4b84b15bff6ee5796152495a230e45e3d7e947d9", + "listenPort": "20160", + "cpu": { + "cpuFrequency": "3730MHz", + "cpuLogicalCores": "8", + "cpuPhysicalCores": "4", + "cpuVendorId": "GenuineIntel", + "l1CacheLineSize": "64", + "l1CacheSize": "32768", + "l2CacheLineSize": "64", + "l2CacheSize": "262144", + "l3CacheLineSize": "64", + "l3CacheSize": "8388608" + }, + "memory": { + "capacity": "16803861504" + }, + "disk": { + "36e7dfacbb83843f83075d78aeb4cf850a4882a1": { + "deviceName": "36e7dfacbb83843f83075d78aeb4cf850a4882a1", + "free": "624438726656", + "freePercent": "0.61", + "fstype": "btrfs", + "path": "fb365c1216b59e1cfc86950425867007a60f4435", + "total": "1022488477696", + "used": "398049751040", + "usedPercent": "0.39" + }, + "nvme0n1p1": { + "deviceName": "nvme0n1p1", + "free": "582250496", + "freePercent": "0.93", + "fstype": "vfat", + "path": "0fc8c8d71702d81a02e216fb6ef19f4dda4973df", + "total": "627900416", + "used": "45649920", + "usedPercent": "0.07" + }, + "nvme0n1p2": { + "deviceName": "nvme0n1p2", + "free": "701976576", + "freePercent": "0.69", + "fstype": "ext4", + "path": "/boot", + "total": "1023303680", + "used": "321327104", + "usedPercent": "0.31" + } + } + }, + { + "instanceType": "tiflash", + "listenHostHash": "4b84b15bff6ee5796152495a230e45e3d7e947d9", + "listenPort": "3930", + "cpu": { + "cpuFrequency": "3400MHz", + "cpuLogicalCores": "8", + "cpuPhysicalCores": "4", + "l1CacheLineSize": "64", + "l1CacheSize": "32768", + "l2CacheLineSize": "64", + "l2CacheSize": "262144", + "l3CacheLineSize": "64", + "l3CacheSize": "8388608" + }, + "memory": { + "capacity": "16410021888" + }, + "disk": { + "36e7dfacbb83843f83075d78aeb4cf850a4882a1": { + "deviceName": "36e7dfacbb83843f83075d78aeb4cf850a4882a1", + "free": "624438726656", + "freePercent": "0.61", + "fstype": "btrfs", + "path": "fb365c1216b59e1cfc86950425867007a60f4435", + "total": "1022488477696", + "used": "398049751040", + "usedPercent": "0.39" + } + } + } + ], + "instances": [ + { + "instanceType": "tidb", + "listenHostHash": "4b84b15bff6ee5796152495a230e45e3d7e947d9", + "listenPort": "4000", + "statusHostHash": "4b84b15bff6ee5796152495a230e45e3d7e947d9", + "statusPort": "10080", + "version": "5.1.1", + "gitHash": "797bddd25310ed42f0791c8eccb78be8cce2f502", + "startTime": "2021-08-11T08:23:38+02:00", + "upTime": "22.210217487s" + }, + { + "instanceType": "pd", + "listenHostHash": "4b84b15bff6ee5796152495a230e45e3d7e947d9", + "listenPort": "2379", + "statusHostHash": "4b84b15bff6ee5796152495a230e45e3d7e947d9", + "statusPort": "2379", + "version": "5.1.1", + "gitHash": "7cba1912b317a533e18b16ea2ba9a14ed2891129", + "startTime": "2021-08-11T08:23:32+02:00", + "upTime": "28.210220368s" + }, + { + "instanceType": "tikv", + "listenHostHash": "4b84b15bff6ee5796152495a230e45e3d7e947d9", + "listenPort": "20160", + "statusHostHash": "4b84b15bff6ee5796152495a230e45e3d7e947d9", + "statusPort": "20180", + "version": "5.1.1", + "gitHash": "4705d7c6e9c42d129d3309e05911ec6b08a25a38", + "startTime": "2021-08-11T08:23:33+02:00", + "upTime": "27.210221447s" + }, + { + "instanceType": "tiflash", + "listenHostHash": "4b84b15bff6ee5796152495a230e45e3d7e947d9", + "listenPort": "3930", + "statusHostHash": "4b84b15bff6ee5796152495a230e45e3d7e947d9", + "statusPort": "20292", + "version": "v5.1.1", + "gitHash": "c8fabfb50fe28db17cc5118133a69be255c40efd", + "startTime": "2021-08-11T08:23:40+02:00", + "upTime": "20.210222452s" + } + ], + "hostExtra": { + "cpuFlags": [ + "fpu", + "vme", + "de", + "pse", + "tsc", + "msr", + "pae", + "mce", + "cx8", + "apic", + "sep", + "mtrr", + "pge", + "mca", + "cmov", + "pat", + "pse36", + "clflush", + "dts", + "acpi", + "mmx", + "fxsr", + "sse", + "sse2", + "ss", + "ht", + "tm", + "pbe", + "syscall", + "nx", + "pdpe1gb", + "rdtscp", + "lm", + "constant_tsc", + "art", + "arch_perfmon", + "pebs", + "bts", + "rep_good", + "nopl", + "xtopology", + "nonstop_tsc", + "cpuid", + "aperfmperf", + "pni", + "pclmulqdq", + "dtes64", + "monitor", + "ds_cpl", + "vmx", + "est", + "tm2", + "ssse3", + "sdbg", + "fma", + "cx16", + "xtpr", + "pdcm", + "pcid", + "sse4_1", + "sse4_2", + "x2apic", + "movbe", + "popcnt", + "tsc_deadline_timer", + "aes", + "xsave", + "avx", + "f16c", + "rdrand", + "lahf_lm", + "abm", + "3dnowprefetch", + "cpuid_fault", + "epb", + "invpcid_single", + "ssbd", + "ibrs", + "ibpb", + "stibp", + "ibrs_enhanced", + "tpr_shadow", + "vnmi", + "flexpriority", + "ept", + "vpid", + "ept_ad", + "fsgsbase", + "tsc_adjust", + "sgx", + "bmi1", + "avx2", + "smep", + "bmi2", + "erms", + "invpcid", + "mpx", + "rdseed", + "adx", + "smap", + "clflushopt", + "intel_pt", + "xsaveopt", + "xsavec", + "xgetbv1", + "xsaves", + "dtherm", + "ida", + "arat", + "pln", + "pts", + "hwp", + "hwp_notify", + "hwp_act_window", + "hwp_epp", + "md_clear", + "flush_l1d", + "arch_capabilities" + ], + "cpuModelName": "Intel(R) Core(TM) i7-10510U CPU @ 1.80GHz", + "os": "linux", + "platform": "fedora", + "platformFamily": "fedora", + "platformVersion": "34", + "kernelVersion": "5.13.5-200.fc34.x86_64", + "kernelArch": "x86_64", + "virtualizationSystem": "kvm", + "virtualizationRole": "host" + }, + "reportTimestamp": 1628663040, + "trackingId": "a1ba1d97-b940-4d5b-a9d5-ddb0f2ac29e7", + "featureUsage": { + "txn": { + "asyncCommitUsed": true, + "onePCUsed": true, + "txnCommitCounter": { + "twoPC": 9, + "asyncCommit": 0, + "onePC": 0 + } + }, + "clusterIndex": {}, + "temporaryTable": false, + "cte": { + "nonRecursiveCTEUsed": 0, + "recursiveUsed": 0, + "nonCTEUsed": 13 + } + }, + "windowedStats": [], + "slowQueryStats": { + "slowQueryBucket": {} + } +} +1 row in set (0.0259 sec) +``` + +## MySQL 兼容性 + +`ADMIN` 语句是 TiDB 对 MySQL 语法的扩展。 + +## 另请参阅 + +* [遥测](/telemetry.md) +* [系统变量 `tidb_enable_telemetry`](/system-variables.md#tidb_enable_telemetry-从-v402-版本开始引入) diff --git a/markdown-pages/zh/tidb/master/sql-statements/sql-statement-admin.md b/markdown-pages/zh/tidb/master/sql-statements/sql-statement-admin.md new file mode 100644 index 0000000..82ecdc7 --- /dev/null +++ b/markdown-pages/zh/tidb/master/sql-statements/sql-statement-admin.md @@ -0,0 +1,219 @@ +--- +title: ADMIN +aliases: ['/docs-cn/dev/sql-statements/sql-statement-admin/','/docs-cn/dev/reference/sql/statements/admin/'] +summary: TiDB的 `ADMIN` 语句是用于查看TiDB状态和对表数据进行校验的扩展语法。其中包括 `ADMIN RELOAD`、`ADMIN PLUGIN`、`ADMIN ... BINDINGS`、`ADMIN REPAIR TABLE` 和 `ADMIN SHOW NEXT_ROW_ID` 等扩展语句。这些语句可以用于重新加载表达式下推的黑名单、启用或禁用插件、持久化 SQL Plan 绑定信息、修复表的元信息以及查看表中特殊列的详情。这些功能对于管理和维护 TiDB 数据库非常有用。 +--- + +# ADMIN + +`ADMIN` 语句是 TiDB 扩展语法,用于查看 TiDB 自身的状态,并对 TiDB 中的表数据进行校验。本文介绍了下列与 ADMIN 相关的扩展语句: + +- [`ADMIN RELOAD`](#admin-reload-语句) +- [`ADMIN PLUGIN`](#admin-plugin-语句) +- [`ADMIN ... BINDINGS`](#admin--bindings-语句) +- [`ADMIN REPAIR TABLE`](#admin-repair-table-语句) +- [`ADMIN SHOW NEXT_ROW_ID`](#admin-show-next_row_id-语句) +- [`ADMIN SHOW SLOW`](#admin-show-slow-语句) + +## ADMIN 与 DDL 相关的扩展语句 + +| 语句 | 功能描述 | +|------------------------------------------------------------------------------------------|-----------------------------| +| [`ADMIN CANCEL DDL JOBS`](/sql-statements/sql-statement-admin-cancel-ddl.md) | 取消当前正在运行的 DDL 作业 | +| [`ADMIN PAUSE DDL JOBS`](/sql-statements/sql-statement-admin-pause-ddl.md) | 暂停当前正在运行的 DDL 作业 | +| [`ADMIN RESUME DDL JOBS`](/sql-statements/sql-statement-admin-resume-ddl.md) | 恢复当前处于暂停中的 DDL 作业 | +| [`ADMIN CHECKSUM TABLE`](/sql-statements/sql-statement-admin-checksum-table.md) | 计算表中所有行和索引的 CRC64 校验和 | +| [ADMIN CHECK [TABLE\|INDEX]](/sql-statements/sql-statement-admin-check-table-index.md) | 校验表中数据和对应索引的一致性 | +| [ADMIN SHOW DDL [JOBS\|QUERIES]](/sql-statements/sql-statement-admin-show-ddl.md) | 显示有关当前正在运行或最近完成的 DDL 作业的详细信息| +| [ADMIN SHOW TELEMETRY](/sql-statements/sql-statement-admin-show-telemetry.md) | 显示通过[遥测](/telemetry.md)功能收集到并分享给 PingCAP 的使用信息。 | + +## `ADMIN RELOAD` 语句 + +```sql +ADMIN RELOAD expr_pushdown_blacklist; +``` + +以上语句用于重新加载表达式下推的黑名单。 + +```sql +ADMIN RELOAD opt_rule_blacklist; +``` + +以上语句用于重新加载逻辑优化规则的黑名单。 + +## `ADMIN PLUGIN` 语句 + +```sql +ADMIN PLUGINS ENABLE plugin_name [, plugin_name] ...; +``` + +以上语句用于启用 `plugin_name` 插件。 + +```sql +ADMIN PLUGINS DISABLE plugin_name [, plugin_name] ...; +``` + +以上语句用于禁用 `plugin_name` 插件。 + +## `ADMIN ... BINDINGS` 语句 + +```sql +ADMIN FLUSH bindings; +``` + +以上语句用于持久化 SQL Plan 绑定的信息。 + +```sql +ADMIN CAPTURE bindings; +``` + +以上语句可以将出现超过一次的 `select`execution-plan 语句生成 SQL Plan 的绑定。 + +```sql +ADMIN EVOLVE bindings; +``` + +开启自动绑定功能后,每隔 `bind-info-lease`(默认值为 `3s`)触发一次 SQL Plan 绑定信息的演进。以上语句用于主动触发此演进,SQL Plan 绑定详情可参考:[执行计划管理](/sql-plan-management.md)。 + +```sql +ADMIN RELOAD bindings; +``` + +以上语句用于重新加载 SQL Plan 绑定的信息。 + +## `ADMIN REPAIR TABLE` 语句 + +```sql +ADMIN REPAIR TABLE tbl_name CREATE TABLE STATEMENT; +``` + +`ADMIN REPAIR TABLE tbl_name CREATE TABLE STATEMENT` 用于在极端情况下,对存储层中的表的元信息进行非可信的覆盖。“非可信”是指需要人为保证原表的元信息可以完全由 `CREATE TABLE STATEMENT` 提供。该语句需要打开配置文件项中的 [`repair-mode`](/tidb-configuration-file.md#repair-mode) 开关,并且需要确保所修复的表名在 [`repair-table-list`](/tidb-configuration-file.md#repair-table-list) 名单中。 + +## `ADMIN SHOW NEXT_ROW_ID` 语句 + +```sql +ADMIN SHOW t NEXT_ROW_ID; +``` + +以上语句可以查看表中某些特殊列的详情。输出结果与 [SHOW TABLE NEXT_ROW_ID](/sql-statements/sql-statement-show-table-next-rowid.md) 相同。 + +## `ADMIN SHOW SLOW` 语句 + +```sql +ADMIN SHOW SLOW RECENT N; +``` + +```sql +ADMIN SHOW SLOW TOP [INTERNAL | ALL] N; +``` + +这两种语句的具体操作详情可参考:[admin show slow 语句](/identify-slow-queries.md#admin-show-slow-命令)。 + +## 语句概览 + +```ebnf+diagram +AdminStmt ::= + 'ADMIN' ( 'SHOW' ( 'DDL' ( 'JOBS' Int64Num? WhereClauseOptional | 'JOB' 'QUERIES' NumList )? | TableName 'NEXT_ROW_ID' | 'SLOW' AdminShowSlow ) | 'CHECK' ( 'TABLE' TableNameList | 'INDEX' TableName Identifier ( HandleRange ( ',' HandleRange )* )? ) | 'RECOVER' 'INDEX' TableName Identifier | 'CLEANUP' ( 'INDEX' TableName Identifier | 'TABLE' 'LOCK' TableNameList ) | 'CHECKSUM' 'TABLE' TableNameList | 'CANCEL' 'DDL' 'JOBS' NumList | 'RELOAD' ( 'EXPR_PUSHDOWN_BLACKLIST' | 'OPT_RULE_BLACKLIST' | 'BINDINGS' ) | 'PLUGINS' ( 'ENABLE' | 'DISABLE' ) PluginNameList | 'REPAIR' 'TABLE' TableName CreateTableStmt | ( 'FLUSH' | 'CAPTURE' | 'EVOLVE' ) 'BINDINGS' ) +``` + +## 使用示例 + +执行以下命令,可查看正在执行的 DDL 任务中最近 10 条已经完成的 DDL 任务。未指定 `NUM` 时,默认只显示最近 10 条已经执行完的 DDL 任务。 + +```sql +ADMIN SHOW DDL jobs; +``` + +``` ++--------+---------+------------+---------------+----------------------+-----------+----------+-----------+-----------------------------------+-----------------------------------+---------------+ +| JOB_ID | DB_NAME | TABLE_NAME | JOB_TYPE | SCHEMA_STATE | SCHEMA_ID | TABLE_ID | ROW_COUNT | START_TIME | END_TIME | STATE | ++--------+---------+------------+---------------+----------------------+-----------+----------+-----------+-----------------------------------+-----------------------------------+---------------+ +| 45 | test | t1 | add index | write reorganization | 32 | 37 | 0 | 2019-01-10 12:38:36.501 +0800 CST | | running | +| 44 | test | t1 | add index | none | 32 | 37 | 0 | 2019-01-10 12:36:55.18 +0800 CST | 2019-01-10 12:36:55.852 +0800 CST | rollback done | +| 43 | test | t1 | add index | public | 32 | 37 | 6 | 2019-01-10 12:35:13.66 +0800 CST | 2019-01-10 12:35:14.925 +0800 CST | synced | +| 42 | test | t1 | drop index | none | 32 | 37 | 0 | 2019-01-10 12:34:35.204 +0800 CST | 2019-01-10 12:34:36.958 +0800 CST | synced | +| 41 | test | t1 | add index | public | 32 | 37 | 0 | 2019-01-10 12:33:22.62 +0800 CST | 2019-01-10 12:33:24.625 +0800 CST | synced | +| 40 | test | t1 | drop column | none | 32 | 37 | 0 | 2019-01-10 12:33:08.212 +0800 CST | 2019-01-10 12:33:09.78 +0800 CST | synced | +| 39 | test | t1 | add column | public | 32 | 37 | 0 | 2019-01-10 12:32:55.42 +0800 CST | 2019-01-10 12:32:56.24 +0800 CST | synced | +| 38 | test | t1 | create table | public | 32 | 37 | 0 | 2019-01-10 12:32:41.956 +0800 CST | 2019-01-10 12:32:43.956 +0800 CST | synced | +| 36 | test | | drop table | none | 32 | 34 | 0 | 2019-01-10 11:29:59.982 +0800 CST | 2019-01-10 11:30:00.45 +0800 CST | synced | +| 35 | test | | create table | public | 32 | 34 | 0 | 2019-01-10 11:29:40.741 +0800 CST | 2019-01-10 11:29:41.682 +0800 CST | synced | +| 33 | test | | create schema | public | 32 | 0 | 0 | 2019-01-10 11:29:22.813 +0800 CST | 2019-01-10 11:29:23.954 +0800 CST | synced | ++--------+---------+------------+---------------------+----------------+-----------+----------+-----------+-----------------------------------+-----------------------------------+---------------+ +``` + +执行以下命令,可查看正在执行的 DDL 任务中最近 5 条已经执行完的 DDL 任务: + +```sql +ADMIN SHOW DDL JOBS 5; +``` + +``` ++--------+---------+------------+---------------+----------------------+-----------+----------+-----------+-----------------------------------+-----------------------------------+---------------+ +| JOB_ID | DB_NAME | TABLE_NAME | JOB_TYPE | SCHEMA_STATE | SCHEMA_ID | TABLE_ID | ROW_COUNT | START_TIME | END_TIME | STATE | ++--------+---------+------------+---------------+----------------------+-----------+----------+-----------+-----------------------------------+-----------------------------------+---------------+ +| 45 | test | t1 | add index | write reorganization | 32 | 37 | 0 | 2019-01-10 12:38:36.501 +0800 CST | | running | +| 44 | test | t1 | add index | none | 32 | 37 | 0 | 2019-01-10 12:36:55.18 +0800 CST | 2019-01-10 12:36:55.852 +0800 CST | rollback done | +| 43 | test | t1 | add index | public | 32 | 37 | 6 | 2019-01-10 12:35:13.66 +0800 CST | 2019-01-10 12:35:14.925 +0800 CST | synced | +| 42 | test | t1 | drop index | none | 32 | 37 | 0 | 2019-01-10 12:34:35.204 +0800 CST | 2019-01-10 12:34:36.958 +0800 CST | synced | +| 41 | test | t1 | add index | public | 32 | 37 | 0 | 2019-01-10 12:33:22.62 +0800 CST | 2019-01-10 12:33:24.625 +0800 CST | synced | +| 40 | test | t1 | drop column | none | 32 | 37 | 0 | 2019-01-10 12:33:08.212 +0800 CST | 2019-01-10 12:33:09.78 +0800 CST | synced | ++--------+---------+------------+---------------------+----------------+-----------+----------+-----------+-----------------------------------+-----------------------------------+---------------+ +``` + +执行以下命令,查看表中某些特殊列的详情。输出结果与 [SHOW TABLE NEXT_ROW_ID](/sql-statements/sql-statement-show-table-next-rowid.md) 相同。 + +```sql +ADMIN SHOW t NEXT_ROW_ID; +``` + +```sql ++---------+------------+-------------+--------------------+----------------+ +| DB_NAME | TABLE_NAME | COLUMN_NAME | NEXT_GLOBAL_ROW_ID | ID_TYPE | ++---------+------------+-------------+--------------------+----------------+ +| test | t | _tidb_rowid | 101 | _TIDB_ROWID | +| test | t | _tidb_rowid | 1 | AUTO_INCREMENT | ++---------+------------+-------------+--------------------+----------------+ +2 rows in set (0.01 sec) +``` + +执行以下命令,可查看 test 数据库中未执行完成的 DDL 任务,包括正在执行中以及最近 5 条已经执行完但是执行失败的 DDL 任务。 + +```sql +ADMIN SHOW DDL JOBS 5 WHERE state != 'synced' AND db_name = 'test'; +``` + +``` ++--------+---------+------------+---------------+----------------------+-----------+----------+-----------+-----------------------------------+-----------------------------------+---------------+ +| JOB_ID | DB_NAME | TABLE_NAME | JOB_TYPE | SCHEMA_STATE | SCHEMA_ID | TABLE_ID | ROW_COUNT | START_TIME | END_TIME | STATE | ++--------+---------+------------+---------------+----------------------+-----------+----------+-----------+-----------------------------------+-----------------------------------+---------------+ +| 45 | test | t1 | add index | write reorganization | 32 | 37 | 0 | 2019-01-10 12:38:36.501 +0800 CST | | running | +| 44 | test | t1 | add index | none | 32 | 37 | 0 | 2019-01-10 12:36:55.18 +0800 CST | 2019-01-10 12:36:55.852 +0800 CST | rollback done | ++--------+---------+------------+---------------------+----------------+-----------+----------+-----------+-----------------------------------+-----------------------------------+---------------+ +``` + +* `JOB_ID`:每个 DDL 操作对应一个 DDL 作业,`JOB_ID` 全局唯一。 +* `DB_NAME`:执行 DDL 操作的数据库的名称。 +* `TABLE_NAME`:执行 DDL 操作的表的名称。 +* `JOB_TYPE`:DDL 操作的类型。 +* `SCHEMA_STATE`:schema 的当前状态。如果 `JOB_TYPE` 是 `add index`,则为 index 的状态;如果是 `add column`,则为 column 的状态,如果是 `create table`,则为 table 的状态。常见的状态有以下几种: + * `none`:表示不存在。一般 `drop` 操作或者 `create` 操作失败回滚后,会变为 `none` 状态。 + * `delete only`、`write only`、`delete reorganization`、`write reorganization`:这四种状态是中间状态。由于中间状态转换很快,一般操作中看不到这几种状态,只有执行 `add index` 操作时能看到处于 `write reorganization` 状态,表示正在添加索引数据。 + * `public`:表示存在且可用。一般 `create table` 和 `add index/column` 等操作完成后,会变为 `public` 状态,表示新建的 table/column/index 可以正常读写了。 +* `SCHEMA_ID`:执行 DDL 操作的数据库的 ID。 +* `TABLE_ID`:执行 DDL 操作的表的 ID。 +* `ROW_COUNT`:执行 `add index` 操作时,当前已经添加完成的数据行数。 +* `START_TIME`:DDL 操作的开始时间。 +* `END_TIME`:DDL 操作的结束时间。 +* `STATE`:DDL 操作的状态。常见的状态有以下几种: + * `none`:表示该操作任务已经进入 DDL 作业队列中,但尚未执行,因为还在排队等待前面的 DDL 作业完成。另一种原因可能是执行 `drop` 操作后,会变为 `none` 状态,但是很快会更新为 `synced` 状态,表示所有 TiDB 实例都已经同步到该状态。 + * `running`:表示该操作正在执行。 + * `synced`:表示该操作已经执行成功,且所有 TiDB 实例都已经同步该状态。 + * `rollback done`:表示该操作执行失败,回滚完成。 + * `rollingback`:表示该操作执行失败,正在回滚。 + * `cancelling`:表示正在取消该操作。这个状态只有在用 [`ADMIN CANCEL DDL JOBS`](/sql-statements/sql-statement-admin-cancel-ddl.md) 命令取消 DDL 作业时才会出现。 + * `paused`:表示 DDL 已被暂停运行。这个状态只有在用 [`ADMIN PAUSED DDL JOBS`](/sql-statements/sql-statement-admin-pause-ddl.md) 命令暂停 DDL 任务时才会出现。可以通过 [`ADMIN RESUME DDL JOBS`](/sql-statements/sql-statement-admin-resume-ddl.md) 命令进行恢复运行。 + +## MySQL 兼容性 + +`ADMIN` 语句是 TiDB 对于 MySQL 语法的扩展。 diff --git a/markdown-pages/zh/tidb/master/sql-statements/sql-statement-flashback-table.md b/markdown-pages/zh/tidb/master/sql-statements/sql-statement-flashback-table.md new file mode 100644 index 0000000..3ffbb71 --- /dev/null +++ b/markdown-pages/zh/tidb/master/sql-statements/sql-statement-flashback-table.md @@ -0,0 +1,93 @@ +--- +title: FLASHBACK TABLE +aliases: ['/docs-cn/dev/sql-statements/sql-statement-flashback-table/','/docs-cn/dev/reference/sql/statements/flashback-table/'] +summary: TiDB 4.0 引入了 `FLASHBACK TABLE` 语法,可在 GC 生命周期内恢复被 `DROP` 或 `TRUNCATE` 删除的表和数据。使用系统变量 `tidb_gc_life_time` 配置历史版本保留时间,默认为 `10m0s`。查询当前`safePoint`:`SELECT * FROM mysql.tidb WHERE variable_name = 'tikv_gc_safe_point'`。注意,过了 GC 生命周期就无法恢复被删除的数据。 +--- + +# FLASHBACK TABLE + +在 TiDB 4.0 中,引入了 `FLASHBACK TABLE` 语法,其功能是在 Garbage Collection (GC) life time 时间内,可以用 `FLASHBACK TABLE` 语句来恢复被 `DROP` 或 `TRUNCATE` 删除的表以及数据。 + +可以使用系统变量 [`tidb_gc_life_time`](/system-variables.md#tidb_gc_life_time-从-v50-版本开始引入) 配置数据的历史版本的保留时间(默认值是 `10m0s`)。可以使用以下 SQL 语句查询当前的 `safePoint`,即 GC 已经清理到的时间点: + + ```sql + SELECT * FROM mysql.tidb WHERE variable_name = 'tikv_gc_safe_point'; + ``` + +只要被 `DROP` 或 `TRUNCATE` 删除的表是在 `tikv_gc_safe_point` 时间之后,都能用 `FLASHBACK TABLE` 语法来恢复。 + +## 语法 + +```sql +FLASHBACK TABLE table_name [TO other_table_name] +``` + +### 语法图 + +```ebnf+diagram +FlashbackTableStmt ::= + 'FLASHBACK' 'TABLE' TableName FlashbackToNewName + +TableName ::= + Identifier ( '.' Identifier )? + +FlashbackToNewName ::= + ( 'TO' Identifier )? +``` + +## 注意事项 + +如果删除了一张表并过了 GC lifetime,就不能再用 `FLASHBACK TABLE` 语句来恢复被删除的数据了,否则会返回错误,错误类似于 `Can't find dropped/truncated table 't' in GC safe point 2020-03-16 16:34:52 +0800 CST`。 + +在开启 TiDB Binlog 时使用 `FLASHBACK TABLE` 需要注意以下情况: + +* 下游从集群也支持 `FLASHBACK TABLE` +* 从集群的 GC lifetime 一定要长于主集群的 GC lifetime。上下游同步存在的延迟可能也会造成下游恢复数据失败。 + +如果 Binlog 同步出错,则需要在 Binlog 过滤掉该表,同时手动全量重新导入该表的数据。 + +## 示例 + +- 恢复被 `DROP` 删除的表数据: + + ```sql + DROP TABLE t; + ``` + + ```sql + FLASHBACK TABLE t; + ``` + +- 恢复被 `TRUNCATE` 的表数据,由于被 `TRUNCATE` 的表还存在,所以需要重命名被恢复的表,否则会报错表 t 已存在。 + + ```sql + TRUNCATE TABLE t; + ``` + + ```sql + FLASHBACK TABLE t TO t1; + ``` + +## 工作原理 + +TiDB 在删除表时,实际上只删除了表的元信息,并将需要删除的表数据(行数据和索引数据)写一条数据到 `mysql.gc_delete_range` 表。TiDB 后台的 GC Worker 会定期从 `mysql.gc_delete_range` 表中取出超过 GC lifetime 相关范围的 key 进行删除。 + +所以,`FLASHBACK TABLE` 只需要在 GC Worker 还没删除表数据前,恢复表的元信息并删除 `mysql.gc_delete_range` 表中相应的行记录即可。恢复表的元信息可以用 TiDB 的快照读实现。具体的快照读内容可以参考[读取历史数据](/read-historical-data.md)文档。下面是 `FLASHBACK TABLE t TO t1` 的工作流程: + +1. 从 DDL History job 中查找 `drop table` 或者 `truncate table` 类型的操作,且操作的表名是 `t` 的第一个 DDL job,若没找到,则返回错误。 +2. 检查 DDL job 的开始时间,是否在 `tikv_gc_safe_point` 之前。如果是`tikv_gc_safe_point` 之前,说明被 `DROP` 或 `TRUNCATE` 删除的表已经被 GC 清理掉,返回错误。 +3. 用 DDL job 的开始时间作为 snapshot 读取历史数据,读取表的元信息。 +4. 删除 `mysql.gc_delete_range` 中和表 `t` 相关的 GC 任务。 +5. 将表的元信息中的 `name` 修改成 `t1`,并用该元信息新建一个表。注意:这里只是修改了表名,但是 table ID 不变,依旧是之前被删除的表 `t` 的 table ID。 + +可以发现,从表 `t` 被删除,到表 `t` 被 `FLASHBACK` 恢复到 `t1`,一直都是对表的元信息进行操作,而表的用户数据一直未被修改过。被恢复的表 `t1` 和之前被删除的表 `t` 的 table ID 相同,所以表 `t1` 才能读取表`t` 的用户数据。 + +> **注意:** +> +> 不能用 `FLASHBACK` 多次恢复同一个被删除的表,因为 `FLASHBACK` 所恢复表的 table ID 还是被删除表的 table ID,而 TiDB 要求所有还存在的表 table ID 必须全局唯一。 + + `FLASHBACK TABLE` 是通过快照读获取表的元信息后,再走一次类似于 `CREATE TABLE` 的建表流程,所以 `FLASHBACK TABLE` 实际上也是一种 DDL 操作。 + +## MySQL 兼容性 + +该语句是 TiDB 对 MySQL 语法的扩展。 diff --git a/markdown-pages/zh/tidb/master/sql-statements/sql-statement-recover-table.md b/markdown-pages/zh/tidb/master/sql-statements/sql-statement-recover-table.md new file mode 100644 index 0000000..1f90f02 --- /dev/null +++ b/markdown-pages/zh/tidb/master/sql-statements/sql-statement-recover-table.md @@ -0,0 +1,114 @@ +--- +title: RECOVER TABLE +aliases: ['/docs-cn/dev/sql-statements/sql-statement-recover-table/','/docs-cn/dev/reference/sql/statements/recover-table/'] +summary: RECOVER TABLE 是用来恢复被删除的表及其数据的功能。在 DROP TABLE 后,在 GC life time 时间内,可以使用 RECOVER TABLE 语句来恢复被删除的表以及其数据。如果删除表后并过了 GC lifetime,就不能再用 RECOVER TABLE 来恢复被删除的表了。 +--- + +# RECOVER TABLE + +`RECOVER TABLE` 的功能是恢复被删除的表及其数据。在 `DROP TABLE` 后,在 GC life time 时间内,可以用 `RECOVER TABLE` 语句恢复被删除的表以及其数据。 + +## 语法 + +```sql +RECOVER TABLE table_name +``` + +```sql +RECOVER TABLE BY JOB JOB_ID +``` + +### 语法图 + +```ebnf+diagram +RecoverTableStmt ::= + 'RECOVER' 'TABLE' ( 'BY' 'JOB' Int64Num | TableName Int64Num? ) + +TableName ::= + Identifier ( '.' Identifier )? + +Int64Num ::= NUM + +NUM ::= intLit +``` + +## 注意事项 + +如果删除表后并过了 GC lifetime,就不能再用 `RECOVER TABLE` 来恢复被删除的表了,执行 `RECOVER TABLE` 语句会返回类似错误:`snapshot is older than GC safe point 2019-07-10 13:45:57 +0800 CST`。 + +对于 3.0.0 及之后的 TiDB 版本,不推荐在使用 TiDB Binlog 的情况下使用 `RECOVER TABLE` 功能。 + +TiDB Binlog 在 3.0.1 支持 `RECOVER TABLE` 后,可在下面的情况下使用 `RECOVER TABLE`: + +* 3.0.1+ 版本的 TiDB Binlog +* 主从集群都使用 TiDB 3.0 +* 从集群 GC lifetime 一定要长于主集群(不过由于上下游同步的延迟,可能也会造成下游 recover 失败) + +### TiDB Binlog 同步错误处理 + +当使用 TiDB Binlog 同步工具时,上游 TiDB 使用 `RECOVER TABLE` 后,TiDB Binlog 可能会因为下面几个原因造成同步中断: + +* 下游数据库不支持 `RECOVER TABLE` 语句。类似错误:`check the manual that corresponds to your MySQL server version for the right syntax to use near 'RECOVER TABLE table_name'`。 + +* 上下游数据库的 GC lifetime 不一样。类似错误:`snapshot is older than GC safe point 2019-07-10 13:45:57 +0800 CST`。 + +* 上下游数据库的同步延迟。类似错误:`snapshot is older than GC safe point 2019-07-10 13:45:57 +0800 CST`。 + +只能通过重新[全量导入被删除的表](/ecosystem-tool-user-guide.md#备份和恢复---backup--restore)来恢复 TiDB Binlog 的数据同步。 + +## 示例 + +- 根据表名恢复被删除的表。 + + ```sql + DROP TABLE t; + ``` + + ```sql + RECOVER TABLE t; + ``` + + 根据表名恢复被删除的表需满足以下条件: + + - 最近 DDL JOB 历史中找到的第一个 `DROP TABLE` 操作,且 + - `DROP TABLE` 所删除的表的名称与 `RECOVER TABLE` 语句指定表名相同 + +- 根据删除表时的 DDL JOB ID 恢复被删除的表。 + + 如果第一次删除表 t 后,又新建了一个表 t,然后又把新建的表 t 删除了,此时如果想恢复最开始删除的表 t,就需要用到指定 DDL JOB ID 的语法了。 + + ```sql + DROP TABLE t; + ``` + + ```sql + ADMIN SHOW DDL JOBS 1; + ``` + + 上面这个语句用来查找删除表 t 时的 DDL JOB ID,这里是 53: + + ``` + +--------+---------+------------+------------+--------------+-----------+----------+-----------+-----------------------------------+--------+ + | JOB_ID | DB_NAME | TABLE_NAME | JOB_TYPE | SCHEMA_STATE | SCHEMA_ID | TABLE_ID | ROW_COUNT | START_TIME | STATE | + +--------+---------+------------+------------+--------------+-----------+----------+-----------+-----------------------------------+--------+ + | 53 | test | | drop table | none | 1 | 41 | 0 | 2019-07-10 13:23:18.277 +0800 CST | synced | + +--------+---------+------------+------------+--------------+-----------+----------+-----------+-----------------------------------+--------+ + ``` + + ```sql + RECOVER TABLE BY JOB 53; + ``` + + 根据删除表时的 DDL JOB ID 恢复被删除的表,会直接用 DDL JOB ID 找到被删除表进行恢复。如果指定的 DDL JOB ID 的 DDL JOB 不是 `DROP TABLE` 类型,会报错。 + +## 原理 + +TiDB 在删除表时,实际上只删除了表的元信息,并将需要删除的表数据(行数据和索引数据)写一条数据到 `mysql.gc_delete_range` 表。TiDB 后台的 GC Worker 会定期从 `mysql.gc_delete_range` 表中取出超过 GC lifetime 相关范围的 key 进行删除。 + +所以,RECOVER TABLE 只需要在 GC Worker 还没删除表数据前,恢复表的元信息并删除 `mysql.gc_delete_range` 表中相应的行记录就可以了。恢复表的元信息可以用 TiDB 的快照读实现。具体的快照读内容可以参考[读取历史数据](/read-historical-data.md)文档。 + +TiDB 中表的恢复是通过快照读获取表的元信息后,再走一次类似于 `CREATE TABLE` 的建表流程,所以 `RECOVER TABLE` 实际上也是一种 DDL。 + +## MySQL 兼容性 + +该语句是 TiDB 对 MySQL 语法的扩展。 diff --git a/markdown-pages/zh/tidb/master/sql-statements/sql-statement-split-region.md b/markdown-pages/zh/tidb/master/sql-statements/sql-statement-split-region.md new file mode 100644 index 0000000..dba1d59 --- /dev/null +++ b/markdown-pages/zh/tidb/master/sql-statements/sql-statement-split-region.md @@ -0,0 +1,400 @@ +--- +title: Split Region 使用文档 +aliases: ['/docs-cn/dev/sql-statements/sql-statement-split-region/','/docs-cn/dev/reference/sql/statements/split-region/'] +summary: TiDB 中的 Split Region 功能可以解决表数据超过默认 Region 大小限制后的热点问题。预切分 Region 可以根据指定的参数,预先为某个表切分出多个 Region,并打散到各个 TiKV 上去。使用 `SPLIT` 语句可以实现均匀切分和不均匀切分,返回结果包括新增预切分的 Region 数量和打散完成的比率。需要注意 `tidb_wait_split_region_finish` 和 `tidb_wait_split_region_timeout` 会影响 `SPLIT` 语句的行为。 +--- + +# Split Region 使用文档 + +在 TiDB 中新建一个表后,默认会单独切分出 1 个 [Region](/tidb-storage.md#region) 来存储这个表的数据,这个默认行为由配置文件中的 `split-table` 控制。当这个 Region 中的数据超过默认 Region 大小限制后,这个 Region 会开始分裂成 2 个 Region。 + +上述情况中,如果在新建的表上发生大批量写入,则会造成热点,因为开始只有一个 Region,所有的写请求都发生在该 Region 所在的那台 TiKV 上。 + +为解决上述场景中的热点问题,TiDB 引入了预切分 Region 的功能,即可以根据指定的参数,预先为某个表切分出多个 Region,并打散到各个 TiKV 上去。 + +## 语法图 + +**SplitRegionStmt:** + +![SplitRegionStmt](/media/sqlgram/SplitRegionStmt.png) + +**SplitSyntaxOption:** + +![SplitSyntaxOption](/media/sqlgram/SplitSyntaxOption.png) + +**TableName:** + +![TableName](/media/sqlgram/TableName.png) + +**PartitionNameListOpt:** + +![PartitionNameListOpt](/media/sqlgram/PartitionNameListOpt.png) + +**SplitOption:** + +![SplitOption](/media/sqlgram/SplitOption.png) + +**RowValue:** + +![RowValue](/media/sqlgram/RowValue.png) + +**Int64Num:** + +![Int64Num](/media/sqlgram/Int64Num.png) + +## Split Region 的使用 + +Split Region 有 2 种不同的语法,具体如下: + +- 均匀切分的语法: + + ```sql + SPLIT TABLE table_name [INDEX index_name] BETWEEN (lower_value) AND (upper_value) REGIONS region_num + ``` + + `BETWEEN lower_value AND upper_value REGIONS region_num` 语法是通过指定数据的上、下边界和 Region 数量,然后在上、下边界之间均匀切分出 `region_num` 个 Region。 + +- 不均匀切分的语法: + + ```sql + SPLIT TABLE table_name [INDEX index_name] BY (value_list) [, (value_list)] ... + ``` + + `BY value_list…` 语法将手动指定一系列的点,然后根据这些指定的点切分 Region,适用于数据不均匀分布的场景。 + +`SPLIT` 语句的返回结果示例如下: + +```sql ++--------------------+----------------------+ +| TOTAL_SPLIT_REGION | SCATTER_FINISH_RATIO | ++--------------------+----------------------+ +| 4 | 1.0 | ++--------------------+----------------------+ +``` + +* `TOTAL_SPLIT_REGION`:表示新增预切分的 Region 数量。 +* `SCATTER_FINISH_RATIO`:表示新增预切分 Region 中,打散完成的比率。如 `1.0` 表示全部完成。`0.5`表示只有一半的 Region 已经打散完成,剩下的还在打散过程中。 + +> **注意:** +> +> 以下会话变量会影响 `SPLIT` 语句的行为,需要特别注意: +> +> * `tidb_wait_split_region_finish`:打散 Region 的时间可能较长,由 PD 调度以及 TiKV 的负载情况所决定。这个变量用来设置在执行 `SPLIT REGION` 语句时,是否同步等待所有 Region 都打散完成后再返回结果给客户端。默认 `1` 代表等待打散完成后再返回结果。`0` 代表不等待 Region 打散完成就返回结果。 +> * `tidb_wait_split_region_timeout`:这个变量用来设置 `SPLIT REGION` 语句的执行超时时间,单位是秒,默认值是 300 秒,如果超时还未完成 `Split` 操作,就返回一个超时错误。 + +### Split Table Region + +表中行数据的 key 由 `table_id` 和 `row_id` 编码组成,格式如下: + +```go +t[table_id]_r[row_id] +``` + +例如,当 `table_id` 是 22,`row_id` 是 11 时: + +```go +t22_r11 +``` + +同一表中行数据的 `table_id` 是一样的,但 `row_id` 肯定不一样,所以可以根据 `row_id` 来切分 Region。 + +#### 均匀切分 + +由于 `row_id` 是整数,所以根据指定的 `lower_value`、`upper_value` 以及 `region_num`,可以推算出需要切分的 key。TiDB 先计算 step (`step = (upper_value - lower_value)/region_num`),然后在 `lower_value` 和 `upper_value` 之间每隔 step 区间切一次,最终切出 `region_num` 个 Region。 + +例如,对于表 t,如果想要从 `minInt64`~`maxInt64` 之间均匀切割出 16 个 Region,可以用以下语句: + +```sql +SPLIT TABLE t BETWEEN (-9223372036854775808) AND (9223372036854775807) REGIONS 16; +``` + +该语句会把表 t 从 minInt64 到 maxInt64 之间均匀切割出 16 个 Region。如果已知主键的范围没有这么大,比如只会在 0~1000000000 之间,那可以用 0 和 1000000000 分别代替上面的 minInt64 和 maxInt64 来切分 Region。 + +```sql +SPLIT TABLE t BETWEEN (0) AND (1000000000) REGIONS 16; +``` + +#### 不均匀切分 + +如果已知数据不是均匀分布的,比如想要 -inf ~ 10000 切一个 Region,10000 ~ 90000 切一个 Region,90000 ~ +inf 切一个 Region,可以通过手动指定点来切分 Region,示例如下: + +```sql +SPLIT TABLE t BY (10000), (90000); +``` + +### Split Index Region + +表中索引数据的 key 由 `table_id`、`index_id` 以及索引列的值编码组成,格式如下: + +```go +t[table_id]_i[index_id][index_value] +``` + +例如,当 `table_id` 是 22,`index_id` 是 5,`index_value` 是 abc 时: + +```go +t22_i5abc +``` + +同一表中同一索引数据的 `table_id` 和 `index_id` 是一样的,所以要根据 `index_value` 切分索引 Region。 + +#### 均匀切分 + +索引均匀切分与行数据均匀切分的原理一样,只是计算 step 的值较为复杂,因为 `index_value` 可能不是整数。 + +`upper` 和 `lower` 的值会先编码成 byte 数组,去掉 `lower` 和 `upper` byte 数组的最长公共前缀后,从 `lower` 和 `upper` 各取前 8 字节转成 uint64,再计算 `step = (upper - lower)/num`。计算出 step 后再将 step 编码成 byte 数组,添加到之前 `upper`和 `lower`的最长公共前缀后面组成一个 key 后去做切分。示例如下: + +如果索引 idx 的列也是整数类型,可以用如下 SQL 语句切分索引数据: + +```sql +SPLIT TABLE t INDEX idx BETWEEN (-9223372036854775808) AND (9223372036854775807) REGIONS 16; +``` + +该语句会把表 t 中 idx 索引数据 Region 从 `minInt64` 到 `maxInt64` 之间均匀切割出 16 个 Region。 + +如果索引 idx1 的列是 varchar 类型,希望根据前缀字母来切分索引数据: + +```sql +SPLIT TABLE t INDEX idx1 BETWEEN ("a") AND ("z") REGIONS 25; +``` + +该语句会把表 t 中 idx1 索引数据的 Region 从 a~z 切成 25 个 Region,region1 的范围是 [minIndexValue, b),region2 的范围是 [b, c),……,region25 的范围是 [y, maxIndexValue)。对于 idx1 索引以 a 为前缀的数据都会写到 region1,以 b 为前缀的索引数据都会写到 region2,以此类推。 + +上面的切分方法,以 y 和 z 前缀的索引数据都会写到 region 25,因为 `z` 并不是一个上界,真正的上界是 `z` 在 ASCII 码中的下一位 `{`,所以更准确的切分方法如下: + +```sql +SPLIT TABLE t INDEX idx1 BETWEEN ("a") AND ("{") REGIONS 26; +``` + +该语句会把表 t 中 idx1 索引数据的 Region 从 a~`{` 切成 26 个 Region,region1 的范围是 [minIndexValue, b),region2 的范围是 [b, c),……,region25 的范围是 [y,z),region26 的范围是 [z, maxIndexValue)。 + +如果索引 idx2 的列是 timestamp/datetime 等时间类型,希望根据时间区间,按年为间隔切分索引数据,示例如下: + +```sql +SPLIT TABLE t INDEX idx2 BETWEEN ("2010-01-01 00:00:00") AND ("2020-01-01 00:00:00") REGIONS 10; +``` + +该语句会把表 t 中 idx2 的索引数据 Region 从 `2010-01-01 00:00:00` 到 `2020-01-01 00:00:00` 切成 10 个 Region。region1 的范围是从 `[minIndexValue, 2011-01-01 00:00:00)`,region2 的范围是 `[2011-01-01 00:00:00, 2012-01-01 00:00:00)`…… + +如果希望按照天为间隔切分索引,示例如下: + +```sql +SPLIT TABLE t INDEX idx2 BETWEEN ("2020-06-01 00:00:00") AND ("2020-07-01 00:00:00") REGIONS 30; +``` + +该语句会将表 `t` 中 `idx2` 索引位于 2020 年 6 月份的数据按天为间隔切分成 30 个 Region。 + +其他索引列类型的切分方法也是类似的。 + +对于联合索引的数据 Region 切分,唯一不同的是可以指定多个 column 的值。 + +比如索引 `idx3 (a, b)` 包含 2 列,a 是 timestamp,b 是 int。如果只想根据 a 列做时间范围的切分,可以用切分单列时间索引的 SQL 语句来切分,`lower_value` 和 `upper_velue` 中不指定 b 列的值即可。 + +```sql +SPLIT TABLE t INDEX idx3 BETWEEN ("2010-01-01 00:00:00") AND ("2020-01-01 00:00:00") REGIONS 10; +``` + +如果想在时间相同的情况下,根据 b 列再做一次切分,在切分时指定 b 列的值即可。 + +```sql +SPLIT TABLE t INDEX idx3 BETWEEN ("2010-01-01 00:00:00", "a") AND ("2010-01-01 00:00:00", "z") REGIONS 10; +``` + +该语句在 a 列时间前缀相同的情况下,根据 b 列的值从 a~z 切了 10 个 Region。如果指定的 a 列的值不相同,那么可能不会用到 b 列的值。 + +如果表的主键为非聚簇索引 [`NONCLUSTERED`](/clustered-indexes.md),切分 Region 时需要用反引号 ``` ` ``` 来转义 `PRIMARY` 关键字。例如: + +```sql +SPLIT TABLE t INDEX `PRIMARY` BETWEEN (-9223372036854775808) AND (9223372036854775807) REGIONS 16; +``` + +#### 不均匀切分 + +索引数据也可以根据用户指定的索引值来做切分。 + +假如有 idx4 (a,b),其中 a 列是 varchar 类型,b 列是 timestamp 类型。 + +```sql +SPLIT TABLE t1 INDEX idx4 BY ("a", "2000-01-01 00:00:01"), ("b", "2019-04-17 14:26:19"), ("c", ""); +``` + +该语句指定了 3 个值,会切分出 4 个 Region,每个 Region 的范围如下。 + +``` +region1 [ minIndexValue , ("a", "2000-01-01 00:00:01")) +region2 [("a", "2000-01-01 00:00:01") , ("b", "2019-04-17 14:26:19")) +region3 [("b", "2019-04-17 14:26:19") , ("c", "") ) +region4 [("c", "") , maxIndexValue ) +``` + +### Split 分区表的 Region + +预切分分区表的 Region 在使用上和普通表一样,差别是会为每一个 partition 都做相同的切分。 + +- 均匀切分的语法如下: + + ```sql + SPLIT [PARTITION] TABLE t [PARTITION] [(partition_name_list...)] [INDEX index_name] BETWEEN (lower_value) AND (upper_value) REGIONS region_num + ``` + +- 不均匀切分的语法如下: + + ```sql + SPLIT [PARTITION] TABLE table_name [PARTITION (partition_name_list...)] [INDEX index_name] BY (value_list) [, (value_list)] ... + ``` + +#### Split 分区表的 Region 示例 + +1. 首先创建一个分区表。如果你要建一个 Hash 分区表,分成 2 个 partition,示例语句如下: + + ```sql + create table t (a int,b int,index idx(a)) partition by hash(a) partitions 2; + ``` + + 此时建完表后会为每个 partition 都单独 split 一个 Region,用 `SHOW TABLE REGIONS` 语法查看该表的 Region 如下: + + ```sql + show table t regions; + ``` + + ```sql + +-----------+-----------+---------+-----------+-----------------+------------------+------------+---------------+------------+----------------------+------------------+ + | REGION_ID | START_KEY | END_KEY | LEADER_ID | LEADER_STORE_ID | PEERS | SCATTERING | WRITTEN_BYTES | READ_BYTES | APPROXIMATE_SIZE(MB) | APPROXIMATE_KEYS | + +-----------+-----------+---------+-----------+-----------------+------------------+------------+---------------+------------+----------------------+------------------+ + | 1978 | t_1400_ | t_1401_ | 1979 | 4 | 1979, 1980, 1981 | 0 | 0 | 0 | 1 | 0 | + | 6 | t_1401_ | | 17 | 4 | 17, 18, 21 | 0 | 223 | 0 | 1 | 0 | + +-----------+-----------+---------+-----------+-----------------+------------------+------------+---------------+------------+----------------------+------------------+ + ``` + +2. 用 `SPLIT` 语法为每个 partition 切分 Region。如果你要将各个 partition 的 [0,10000] 范围内的数据切分成 4 个 Region,示例语句如下: + + ```sql + split partition table t between (0) and (10000) regions 4; + ``` + + 其中,`0` 和 `10000` 分别代表你想要打散的热点数据对应的上、下边界的 `row_id`。 + + > **注意:** + > + > 此示例仅适用于数据热点均匀分布的场景。如果热点数据在你指定的数据范围内是不均匀分布的,请参考 [Split 分区表的 Region](#split-分区表的-region) 中不均匀切分的语法。 + +3. 用 `SHOW TABLE REGIONS` 语法查看该表的 Region。如下会发现该表现在一共有 10 个 Region,每个 partition 分别有 5 个 Region,其中 4 个 Region 是表的行数据,1 个 Region 是表的索引数据。 + + ```sql + show table t regions; + ``` + + ```sql + +-----------+---------------+---------------+-----------+-----------------+------------------+------------+---------------+------------+----------------------+------------------+ + | REGION_ID | START_KEY | END_KEY | LEADER_ID | LEADER_STORE_ID | PEERS | SCATTERING | WRITTEN_BYTES | READ_BYTES | APPROXIMATE_SIZE(MB) | APPROXIMATE_KEYS | + +-----------+---------------+---------------+-----------+-----------------+------------------+------------+---------------+------------+----------------------+------------------+ + | 1998 | t_1400_r | t_1400_r_2500 | 2001 | 5 | 2000, 2001, 2015 | 0 | 132 | 0 | 1 | 0 | + | 2006 | t_1400_r_2500 | t_1400_r_5000 | 2016 | 1 | 2007, 2016, 2017 | 0 | 35 | 0 | 1 | 0 | + | 2010 | t_1400_r_5000 | t_1400_r_7500 | 2012 | 2 | 2011, 2012, 2013 | 0 | 35 | 0 | 1 | 0 | + | 1978 | t_1400_r_7500 | t_1401_ | 1979 | 4 | 1979, 1980, 1981 | 0 | 621 | 0 | 1 | 0 | + | 1982 | t_1400_ | t_1400_r | 2014 | 3 | 1983, 1984, 2014 | 0 | 35 | 0 | 1 | 0 | + | 1990 | t_1401_r | t_1401_r_2500 | 1992 | 2 | 1991, 1992, 2020 | 0 | 120 | 0 | 1 | 0 | + | 1994 | t_1401_r_2500 | t_1401_r_5000 | 1997 | 5 | 1996, 1997, 2021 | 0 | 129 | 0 | 1 | 0 | + | 2002 | t_1401_r_5000 | t_1401_r_7500 | 2003 | 4 | 2003, 2023, 2022 | 0 | 141 | 0 | 1 | 0 | + | 6 | t_1401_r_7500 | | 17 | 4 | 17, 18, 21 | 0 | 601 | 0 | 1 | 0 | + | 1986 | t_1401_ | t_1401_r | 1989 | 5 | 1989, 2018, 2019 | 0 | 123 | 0 | 1 | 0 | + +-----------+---------------+---------------+-----------+-----------------+------------------+------------+---------------+------------+----------------------+------------------+ + ``` + +4. 如果你要给每个分区的索引切分 Region,如将索引 `idx` 的 [1000,10000] 范围切分成 2 个 Region,示例语句如下: + + ```sql + split partition table t index idx between (1000) and (10000) regions 2; + ``` + +#### Split 单个分区的 Region 示例 + +可以单独指定要切分的 partition,示例如下: + +1. 首先创建一个分区表。如果你要建一个 Range 分区表,分成 3 个 partition,示例语句如下: + + ```sql + create table t ( a int, b int, index idx(b)) partition by range( a ) ( + partition p1 values less than (10000), + partition p2 values less than (20000), + partition p3 values less than (MAXVALUE) ); + ``` + +2. 如果你要将 `p1` 分区的 [0,10000] 范围内的数据预切分 2 个 Region,示例语句如下: + + ```sql + split partition table t partition (p1) between (0) and (10000) regions 2; + ``` + +3. 如果你要将 `p2` 分区的 [10000,20000] 范围内的数据预切分 2 个 Region,示例语句如下: + + ```sql + split partition table t partition (p2) between (10000) and (20000) regions 2; + ``` + +4. 用 `SHOW TABLE REGIONS` 语法查看该表的 Region 如下: + + ```sql + show table t regions; + ``` + + ```sql + +-----------+----------------+----------------+-----------+-----------------+------------------+------------+---------------+------------+----------------------+------------------+ + | REGION_ID | START_KEY | END_KEY | LEADER_ID | LEADER_STORE_ID | PEERS | SCATTERING | WRITTEN_BYTES | READ_BYTES | APPROXIMATE_SIZE(MB) | APPROXIMATE_KEYS | + +-----------+----------------+----------------+-----------+-----------------+------------------+------------+---------------+------------+----------------------+------------------+ + | 2040 | t_1406_ | t_1406_r_5000 | 2045 | 3 | 2043, 2045, 2044 | 0 | 0 | 0 | 1 | 0 | + | 2032 | t_1406_r_5000 | t_1407_ | 2033 | 4 | 2033, 2034, 2035 | 0 | 0 | 0 | 1 | 0 | + | 2046 | t_1407_ | t_1407_r_15000 | 2048 | 2 | 2047, 2048, 2050 | 0 | 35 | 0 | 1 | 0 | + | 2036 | t_1407_r_15000 | t_1408_ | 2037 | 4 | 2037, 2038, 2039 | 0 | 0 | 0 | 1 | 0 | + | 6 | t_1408_ | | 17 | 4 | 17, 18, 21 | 0 | 214 | 0 | 1 | 0 | + +-----------+----------------+----------------+-----------+-----------------+------------------+------------+---------------+------------+----------------------+------------------+ + ``` + +5. 如果你要将 `p1` 和 `p2` 分区的索引 `idx` 的 [0,20000] 范围预切分 2 个 Region,示例语句如下: + + ```sql + split partition table t partition (p1,p2) index idx between (0) and (20000) regions 2; + ``` + +## pre_split_regions + +使用带有 `SHARD_ROW_ID_BITS` 的表时,如果希望建表时就均匀切分 Region,可以考虑配合 `PRE_SPLIT_REGIONS` 一起使用,用来在建表成功后就开始预均匀切分 `2^(PRE_SPLIT_REGIONS)` 个 Region。 + +> **注意:** +> +> `PRE_SPLIT_REGIONS` 必须小于等于 `SHARD_ROW_ID_BITS`。 + +以下全局变量会影响 `PRE_SPLIT_REGIONS` 的行为,需要特别注意: + +* `tidb_scatter_region`:该变量用于控制建表完成后是否等待预切分和打散 Region 完成后再返回结果。如果建表后有大批量写入,需要设置该变量值为 `1`,表示等待所有 Region 都切分和打散完成后再返回结果给客户端。否则未打散完成就进行写入会对写入性能影响有较大的影响。 + +### pre_split_regions 示例 + +```sql +create table t (a int, b int,index idx1(a)) shard_row_id_bits = 4 pre_split_regions=2; +``` + +该语句在建表后,会对这个表 t 预切分出 4 + 1 个 Region。4 (2^2) 个 Region 是用来存 table 的行数据的,1 个 Region 是用来存 idx1 索引的数据。 + +4 个 table Region 的范围区间如下: + +``` +region1: [ -inf , 1<<61 ) +region2: [ 1<<61 , 2<<61 ) +region3: [ 2<<61 , 3<<61 ) +region4: [ 3<<61 , +inf ) +``` + +## 注意事项 + +Split Region 语句切分的 Region 会受到 PD 中 [Region merge](/best-practices/pd-scheduling-best-practices.md#region-merge) 调度的控制,需要[动态修改](/pd-control.md) Region merge 相关的配置项,避免新切分的 Region 不久后又被 PD 重新合并的情况。 + +## MySQL 兼容性 + +该语句是 TiDB 对 MySQL 语法的扩展。 + +## 另请参阅 + +* [SHOW TABLE REGIONS](/sql-statements/sql-statement-show-table-regions.md) + +* Session 变量:[`tidb_scatter_region`](/system-variables.md#tidb_scatter_region),[`tidb_wait_split_region_finish`](/system-variables.md#tidb_wait_split_region_finish) 和[`tidb_wait_split_region_timeout`](/system-variables.md#tidb_wait_split_region_timeout). diff --git a/markdown-pages/zh/tidb/master/sql-tuning-overview.md b/markdown-pages/zh/tidb/master/sql-tuning-overview.md new file mode 100644 index 0000000..69d969c --- /dev/null +++ b/markdown-pages/zh/tidb/master/sql-tuning-overview.md @@ -0,0 +1,17 @@ +--- +title: SQL 性能调优 +aliases: ['/docs-cn/dev/sql-tuning-overview/'] +summary: SQL 性能调优是重要的,TiDB 会优化 SQL 语句的执行,以最省时的方式返回结果。这个过程类似于 GPS 导航,利用统计信息和实时交通信息规划最佳路线。了解 TiDB 执行计划、SQL 优化流程和控制执行计划可以帮助提高查询性能。 +--- + +# SQL 性能调优 + +SQL 是一种声明性语言。一条 SQL 语句描述的是最终结果应该如何,而非按顺序执行的步骤。TiDB 会优化 SQL 语句的执行,语义上允许以任何顺序执行查询的各部分,前提是能正确返回语句所描述的最终结果。 + +SQL 性能优化的过程,可以理解为 GPS 导航的过程。你提供地址后,GPS 软件利用各种统计信息(例如以前的行程、速度限制等元数据,以及实时交通信息)规划出一条最省时的路线。这与 TiDB 中的 SQL 性能优化过程相对应。 + +本章节包括以下文档,可帮助你更好地理解查询执行计划: + +- [理解 TiDB 执行计划](/explain-overview.md)介绍如何使用 `EXPLAIN` 语句来理解 TiDB 是如何执行某个查询的。 +- [SQL 优化流程概览](/sql-optimization-concepts.md)介绍 TiDB 可以使用的几种优化,以提高查询性能。 +- [控制执行计划](/control-execution-plan.md)介绍如何控制执行计划的生成。TiDB 的执行计划非最优时,建议控制执行计划。 diff --git a/markdown-pages/zh/tidb/master/statement-summary-tables.md b/markdown-pages/zh/tidb/master/statement-summary-tables.md new file mode 100644 index 0000000..9ce94c8 --- /dev/null +++ b/markdown-pages/zh/tidb/master/statement-summary-tables.md @@ -0,0 +1,367 @@ +--- +title: Statement Summary Tables +aliases: ['/docs-cn/dev/statement-summary-tables/','/docs-cn/dev/reference/performance/statement-summary/'] +summary: MySQL 的 `performance_schema` 提供了 `statement summary tables`,用于监控和统计 SQL 性能。TiDB 在 `information_schema` 中提供了类似功能的系统表,包括 `statements_summary`、`statements_summary_history`、`cluster_statements_summary` 和 `cluster_statements_summary_history`。这些表用于保存 SQL 监控指标聚合后的结果,帮助用户定位 SQL 问题。同时,还提供了参数配置来控制 statement summary 的功能,如清空周期、保存历史的数量等。 +--- + +# Statement Summary Tables + +针对 SQL 性能相关的问题,MySQL 在 `performance_schema` 提供了 [statement summary tables](https://dev.mysql.com/doc/refman/8.0/en/performance-schema-statement-summary-tables.html),用来监控和统计 SQL。例如其中的一张表 `events_statements_summary_by_digest`,提供了丰富的字段,包括延迟、执行次数、扫描行数、全表扫描次数等,有助于用户定位 SQL 问题。 + +为此,从 4.0.0-rc.1 版本开始,TiDB 在 `information_schema`(_而不是_ `performance_schema`)中提供与 `events_statements_summary_by_digest` 功能相似的系统表: + +- `statements_summary` +- `statements_summary_history` +- `cluster_statements_summary` +- `cluster_statements_summary_history` + +本文将详细介绍这些表,以及如何利用它们来排查 SQL 性能问题。 + +## `statements_summary` + +`statements_summary` 是 `information_schema` 里的一张系统表,它把 SQL 按 所属资源组、SQL digest 和 plan digest 分组,统计每一组的 SQL 信息。 + +此处的 SQL digest 与 slow log 里的 SQL digest 一样,是把 SQL 规一化后算出的唯一标识符。SQL 的规一化会忽略常量、空白符、大小写的差别。即语法一致的 SQL 语句,其 digest 也相同。 + +例如: + +```sql +SELECT * FROM employee WHERE id IN (1, 2, 3) AND salary BETWEEN 1000 AND 2000; +select * from EMPLOYEE where ID in (4, 5) and SALARY between 3000 and 4000; +``` + +归一化后都是: + +```sql +select * from employee where id in (...) and salary between ? and ?; +``` + +此处的 plan digest 是把执行计划规一化后算出的唯一标识符。执行计划的规一化会忽略常量的差别。由于相同的 SQL 可能产生不同的执行计划,所以可能分到多个组,同一个组内的执行计划是相同的。 + +`statements_summary` 用于保存 SQL 监控指标聚合后的结果。一般来说,每一项监控指标都包含平均值和最大值。例如执行延时对应 `AVG_LATENCY` 和 `MAX_LATENCY` 两个字段,分别是平均延时和最大延时。 + +为了监控指标的即时性,`statements_summary` 里的数据定期被清空,只展现最近一段时间内的聚合结果。清空周期由系统变量 `tidb_stmt_summary_refresh_interval` 设置。如果刚好在清空之后进行查询,显示的数据可能很少。 + +以下为查询 `statements_summary` 的部分结果: + +``` + SUMMARY_BEGIN_TIME: 2020-01-02 11:00:00 + SUMMARY_END_TIME: 2020-01-02 11:30:00 + STMT_TYPE: Select + SCHEMA_NAME: test + DIGEST: 0611cc2fe792f8c146cc97d39b31d9562014cf15f8d41f23a4938ca341f54182 + DIGEST_TEXT: select * from employee where id = ? + TABLE_NAMES: test.employee + INDEX_NAMES: NULL + SAMPLE_USER: root + EXEC_COUNT: 3 + SUM_LATENCY: 1035161 + MAX_LATENCY: 399594 + MIN_LATENCY: 301353 + AVG_LATENCY: 345053 + AVG_PARSE_LATENCY: 57000 + MAX_PARSE_LATENCY: 57000 + AVG_COMPILE_LATENCY: 175458 + MAX_COMPILE_LATENCY: 175458 + ........... + AVG_MEM: 103 + MAX_MEM: 103 + AVG_DISK: 65535 + MAX_DISK: 65535 + AVG_AFFECTED_ROWS: 0 + FIRST_SEEN: 2020-01-02 11:12:54 + LAST_SEEN: 2020-01-02 11:25:24 + QUERY_SAMPLE_TEXT: select * from employee where id=3100 + PREV_SAMPLE_TEXT: + PLAN_DIGEST: f415b8d52640b535b9b12a9c148a8630d2c6d59e419aad29397842e32e8e5de3 + PLAN: Point_Get_1 root 1 table:employee, handle:3100 +``` + +> **注意:** +> +> - 在 TiDB 中,statement summary tables 中字段的时间单位是纳秒 (ns),而 MySQL 中的时间单位是皮秒 (ps)。 +> - 从 v7.5.1 和 v7.6.0 版本开始,对于开启[资源管控](/tidb-resource-control.md)的集群,`statements_summary` 会分资源组进行聚合,即在不同资源组执行的相同语句会被收集为不同的记录。 + +## `statements_summary_history` + +`statements_summary_history` 的表结构与 `statements_summary` 完全相同,用于保存历史时间段的数据。通过历史数据,可以排查过去出现的异常,也可以对比不同时间的监控指标。 + +字段 `SUMMARY_BEGIN_TIME` 和 `SUMMARY_END_TIME` 代表历史时间段的开始时间和结束时间。 + +## `statements_summary_evicted` + +`statements_summary` 表的容量受 `tidb_stmt_summary_max_stmt_count` 配置控制,内部使用 LRU 算法,一旦接收到的 SQL 种类超过了 `tidb_stmt_summary_max_stmt_count`,表中最久未被命中的记录就会被驱逐出表。TiDB 引入了 `statements_summary_evicted` 表,该表记录了各个时段被驱逐 SQL 语句的具体数量。 + +只有当 SQL 语句被 `statement summary` 表驱逐的时候,`statements_summary_evicted` 表的内容才会更新。`statements_summary_evicted` 表记录发生驱逐的时间段和被驱逐 SQL 的数量。 + +## statement summary 的 cluster 表 + +`statements_summary`、`statements_summary_history` 和 `statements_summary_evicted` 仅显示单台 TiDB server 的 statement summary 数据。若要查询整个集群的数据,需要查询 `cluster_statements_summary`、`cluster_statements_summary_history` 或 `cluster_statements_summary_evicted` 表。 + +`cluster_statements_summary` 显示各台 TiDB server 的 `statements_summary` 数据,`cluster_statements_summary_history` 显示各台 TiDB server 的 `statements_summary_history` 数据,而 `cluster_statements_summary_evicted` 则显示各台 TiDB server 的 `statements_summary_evicted` 数据。这三张表用字段 `INSTANCE` 表示 TiDB server 的地址,其他字段与 `statements_summary`、`statements_summary_history` 和 `statements_summary_evicted` 表相同。 + +## 参数配置 + +以下系统变量用于控制 statement summary: + +- `tidb_enable_stmt_summary`:是否打开 statement summary 功能。1 代表打开,0 代表关闭,默认打开。statement summary 关闭后,系统表里的数据会被清空,下次打开后重新统计。经测试,打开后对性能几乎没有影响。 +- `tidb_stmt_summary_refresh_interval`:`statements_summary` 的清空周期,单位是秒 (s),默认值是 `1800`。 +- `tidb_stmt_summary_history_size`:`statements_summary_history` 保存每种 SQL 的历史的数量,也是 `statements_summary_evicted` 的表容量,默认值是 `24`。 +- `tidb_stmt_summary_max_stmt_count`:statement summary tables 保存的 SQL 种类数量,默认 3000 条。当 SQL 种类超过该值时,会移除最近没有使用的 SQL。这些 SQL 将会被 `DIGEST` 为 `NULL` 的行和 `statements_summary_evicted` 统计记录。`DIGEST` 为 `NULL` 的行数据在 [TiDB Dashboard SQL 语句分析列表页面](/dashboard/dashboard-statement-list.md#others) 中显示为 `Others`。 +- `tidb_stmt_summary_max_sql_length`:字段 `DIGEST_TEXT` 和 `QUERY_SAMPLE_TEXT` 的最大显示长度,默认值是 4096。 +- `tidb_stmt_summary_internal_query`:是否统计 TiDB 的内部 SQL。1 代表统计,0 代表不统计,默认不统计。 + +> **注意:** +> +> 当一种 SQL 因为达到 `tidb_stmt_summary_max_stmt_count` 限制要被移除时,TiDB 会移除该 SQL 语句种类在所有时间段的数据。因此,即使一个时间段内的 SQL 种类数量没有达到上限,显示的 SQL 语句数量也会比实际的少。如遇到该情况,对性能也有一些影响,建议调大 `tidb_stmt_summary_max_stmt_count` 的值。 + +statement summary 配置示例如下: + +```sql +set global tidb_stmt_summary_max_stmt_count = 3000; +set global tidb_enable_stmt_summary = true; +set global tidb_stmt_summary_refresh_interval = 1800; +set global tidb_stmt_summary_history_size = 24; +``` + +以上配置生效后,`statements_summary` 每 30 分钟清空一次,`statements_summary_history` 最多保存 3000 种 SQL 种类的数据,每种类型的 SQL 保存最近出现过的 24 个时间段的数据。`statements_summary_evicted` 保存最近 24 个发生了 evict 的时间段记录;`statements_summary_evicted` 则以 30 分钟为一个记录周期,表容量为 24 个时间段。 + +> **注意:** +> +> - 假设某种 SQL 每分钟都出现,那 `statements_summary_history` 中会保存这种 SQL 最近 12 个小时的数据。但如果某种 SQL 只在每天 00:00 ~ 00:30 出现,则 `statements_summary_history` 中会保存这种 SQL 24 个时间段的数据,每个时间段的间隔都是 1 天,所以会有这种 SQL 最近 24 天的数据。 +> - `tidb_stmt_summary_history_size`、`tidb_stmt_summary_max_stmt_count`、`tidb_stmt_summary_max_sql_length` 这些配置都影响内存占用,建议根据实际情况调整(取决于 SQL 大小、SQL 数量、机器配置)不宜设置得过大。内存大小可通过 `tidb_stmt_summary_history_size` \* `tidb_stmt_summary_max_stmt_count` \* `tidb_stmt_summary_max_sql_length` \* `3` 来进行估算。 + +### 为 statement summary 设定合适的大小 + +在系统运行一段时间后(视系统负载而定),可以查看 `statements_summary` 表检查是否发生了 evict,例如: + +```sql +select @@global.tidb_stmt_summary_max_stmt_count; +select count(*) from information_schema.statements_summary; +``` + +``` ++-------------------------------------------+ +| @@global.tidb_stmt_summary_max_stmt_count | ++-------------------------------------------+ +| 3000 | ++-------------------------------------------+ +1 row in set (0.001 sec) + ++----------+ +| count(*) | ++----------+ +| 3001 | ++----------+ +1 row in set (0.001 sec) +``` + +可以发现 `statements_summary` 表已经满了。再查看 `statements_summary_evicted` 表检查 evict 的数据。 + +```sql +select * from information_schema.statements_summary_evicted; +``` + +``` ++---------------------+---------------------+---------------+ +| BEGIN_TIME | END_TIME | EVICTED_COUNT | ++---------------------+---------------------+---------------+ +| 2020-01-02 16:30:00 | 2020-01-02 17:00:00 | 59 | ++---------------------+---------------------+---------------+ +| 2020-01-02 16:00:00 | 2020-01-02 16:30:00 | 45 | ++---------------------+---------------------+---------------+ +2 row in set (0.001 sec) +``` + +由上可知,对最多 59 种 SQL 发生了 evict。此时,建议将 `statements_summary` 表的容量至少增大 59 条记录,即至少增大至 3059 条。 + +## 目前的限制 + +由于 statement summary tables 默认都存储在内存中,TiDB server 重启后,statement summary 会全部丢失。 + +为解决该问题,TiDB v6.6.0 实验性地引入了 [statement summary 持久化](#持久化-statements-summary)功能,该功能默认为关闭。开启该功能后,历史数据不再存储在内存内,而是直接写入磁盘。TiDB server 重启后,历史数据也依然可用。 + +## 持久化 statements summary + +> **警告:** +> +> statements summary 持久化目前为实验特性,不建议在生产环境中使用。该功能可能会在未事先通知的情况下发生变化或删除。如果发现 bug,请在 GitHub 上提 [issue](https://github.com/pingcap/tidb/issues) 反馈。 + +如[目前的限制](#目前的限制)一节所描述,默认情况下 statements summary 只在内存中维护,一旦 TiDB server 发生重启,所有 statements summary 数据都会丢失。自 v6.6.0 起,TiDB 实验性地提供了配置项 [`tidb_stmt_summary_enable_persistent`](/tidb-configuration-file.md#tidb_stmt_summary_enable_persistent-从-v660-版本开始引入) 来允许用户控制是否开启 statements summary 持久化。 + +如果要开启 statements summary 持久化,可以在 TiDB 配置文件中添加如下配置: + +```toml +[instance] +tidb_stmt_summary_enable_persistent = true +# 以下配置为默认值,可根据需求调整。 +# tidb_stmt_summary_filename = "tidb-statements.log" +# tidb_stmt_summary_file_max_days = 3 +# tidb_stmt_summary_file_max_size = 64 # MiB +# tidb_stmt_summary_file_max_backups = 0 +``` + +开启 statements summary 持久化后,内存中只维护当前的实时数据,不再维护历史数据。历史数据生成后直接被写入磁盘文件,写入周期参考[参数配置](#参数配置)一节所描述的 `tidb_stmt_summary_refresh_interval`。后续针对 `statements_summary_history` 或 `cluster_statements_summary_history` 表的查询将结合内存和磁盘两处数据返回结果。 + +> **注意:** +> +> - 当开启持久化后,由于不再于内存中维护历史数据,因此[参数配置](#参数配置)一节所描述的 `tidb_stmt_summary_history_size` 将不再生效,而是由 [`tidb_stmt_summary_file_max_days`](/tidb-configuration-file.md#tidb_stmt_summary_file_max_days-从-v660-版本开始引入)、[`tidb_stmt_summary_file_max_size`](/tidb-configuration-file.md#tidb_stmt_summary_file_max_size-从-v660-版本开始引入) 和 [`tidb_stmt_summary_file_max_backups`](/tidb-configuration-file.md#tidb_stmt_summary_file_max_backups-从-v660-版本开始引入) 这三项配置来决定历史数据在磁盘上的保留数量和时间。 +> - `tidb_stmt_summary_refresh_interval` 取值越小,数据写入到磁盘就越实时,但写入磁盘的冗余数据也会随之增多。 + +## 排查示例 + +下面用两个示例问题演示如何利用 statement summary 来排查。 + +### SQL 延迟比较大,是不是服务端的问题? + +例如客户端显示 employee 表的点查比较慢,那么可以按 SQL 文本来模糊查询: + +```sql +SELECT avg_latency, exec_count, query_sample_text + FROM information_schema.statements_summary + WHERE digest_text LIKE 'select * from employee%'; +``` + +结果如下,`avg_latency` 是 1 ms 和 0.3 ms,在正常范围,所以可以判定不是服务端的问题,继而排查客户端或网络问题。 + +``` ++-------------+------------+------------------------------------------+ +| avg_latency | exec_count | query_sample_text | ++-------------+------------+------------------------------------------+ +| 1042040 | 2 | select * from employee where name='eric' | +| 345053 | 3 | select * from employee where id=3100 | ++-------------+------------+------------------------------------------+ +2 rows in set (0.00 sec) +``` + +### 哪类 SQL 的总耗时最高? + +假如上午 10:00 到 10:30 的 QPS 明显下降,可以从历史表中找出当时耗时最高的三类 SQL: + +```sql +SELECT sum_latency, avg_latency, exec_count, query_sample_text + FROM information_schema.statements_summary_history + WHERE summary_begin_time='2020-01-02 10:00:00' + ORDER BY sum_latency DESC LIMIT 3; +``` + +结果显示以下三类 SQL 的总延迟最高,所以这些 SQL 需要重点优化。 + +``` ++-------------+-------------+------------+-----------------------------------------------------------------------+ +| sum_latency | avg_latency | exec_count | query_sample_text | ++-------------+-------------+------------+-----------------------------------------------------------------------+ +| 7855660 | 1122237 | 7 | select avg(salary) from employee where company_id=2013 | +| 7241960 | 1448392 | 5 | select * from employee join company on employee.company_id=company.id | +| 2084081 | 1042040 | 2 | select * from employee where name='eric' | ++-------------+-------------+------------+-----------------------------------------------------------------------+ +3 rows in set (0.00 sec) +``` + +## 表的字段介绍 + +### `statements_summary` 字段介绍 + +下面介绍 `statements_summary` 表中各个字段的含义。 + +SQL 的基础信息: + +- `STMT_TYPE`:SQL 语句的类型 +- `SCHEMA_NAME`:执行这类 SQL 的当前 schema +- `DIGEST`:这类 SQL 的 digest +- `DIGEST_TEXT`:规一化后的 SQL +- `QUERY_SAMPLE_TEXT`:这类 SQL 的原 SQL 语句,多条语句只取其中一条 +- `TABLE_NAMES`:SQL 中涉及的所有表,多张表用 `,` 分隔 +- `INDEX_NAMES`:SQL 中使用的索引名,多个索引用 `,` 分隔 +- `SAMPLE_USER`:执行这类 SQL 的用户名,多个用户名只取其中一个 +- `PLAN_DIGEST`:执行计划的 digest +- `PLAN`:原执行计划,多条语句只取其中一条的执行计划 +- `BINARY_PLAN`:以二进制格式编码后的原执行计划,存在多条语句时,只取其中一条语句的执行计划。用 `select tidb_decode_binary_plan('xxx...')` SQL 语句可以解析出具体的执行计划。 +- `PLAN_CACHE_HITS`:这类 SQL 语句命中 plan cache 的总次数 +- `PLAN_IN_CACHE`:这类 SQL 语句的上次执行是否命中了 plan cache + +执行时间相关的信息: + +- `SUMMARY_BEGIN_TIME`:当前统计的时间段的开始时间 +- `SUMMARY_END_TIME`:当前统计的时间段的结束时间 +- `FIRST_SEEN`:这类 SQL 的首次出现时间 +- `LAST_SEEN`:这类 SQL 的最后一次出现时间 + +在 TiDB server 上的执行数据: + +- `EXEC_COUNT`:这类 SQL 的总执行次数 +- `SUM_ERRORS`:执行过程中遇到的 error 的总数 +- `SUM_WARNINGS`:执行过程中遇到的 warning 的总数 +- `SUM_LATENCY`:这类 SQL 的总延时 +- `MAX_LATENCY`:这类 SQL 的最大延时 +- `MIN_LATENCY`:这类 SQL 的最小延时 +- `AVG_LATENCY`:这类 SQL 的平均延时 +- `AVG_PARSE_LATENCY`:解析器的平均延时 +- `MAX_PARSE_LATENCY`:解析器的最大延时 +- `AVG_COMPILE_LATENCY`:优化器的平均延时 +- `MAX_COMPILE_LATENCY`:优化器的最大延时 +- `AVG_MEM`:使用的平均内存,单位 byte +- `MAX_MEM`:使用的最大内存,单位 byte +- `AVG_DISK`:使用的平均硬盘空间,单位 byte +- `MAX_DISK`:使用的最大硬盘空间,单位 byte + +和 TiKV Coprocessor Task 相关的字段: + +- `SUM_COP_TASK_NUM`:发送 Coprocessor 请求的总数 +- `MAX_COP_PROCESS_TIME`:cop-task 的最大处理时间 +- `MAX_COP_PROCESS_ADDRESS`:执行时间最长的 cop-task 所在地址 +- `MAX_COP_WAIT_TIME`:cop-task 的最大等待时间 +- `MAX_COP_WAIT_ADDRESS`:等待时间最长的 cop-task 所在地址 +- `AVG_PROCESS_TIME`:SQL 在 TiKV 的平均处理时间 +- `MAX_PROCESS_TIME`:SQL 在 TiKV 的最大处理时间 +- `AVG_WAIT_TIME`:SQL 在 TiKV 的平均等待时间 +- `MAX_WAIT_TIME`:SQL 在 TiKV 的最大等待时间 +- `AVG_BACKOFF_TIME`:SQL 遇到需要重试的错误时在重试前的平均等待时间 +- `MAX_BACKOFF_TIME`:SQL 遇到需要重试的错误时在重试前的最大等待时间 +- `AVG_TOTAL_KEYS`:Coprocessor 扫过的 key 的平均数量 +- `MAX_TOTAL_KEYS`:Coprocessor 扫过的 key 的最大数量 +- `AVG_PROCESSED_KEYS`:Coprocessor 处理的 key 的平均数量。相比 `avg_total_keys`,`avg_processed_keys` 不包含 MVCC 的旧版本。如果 `avg_total_keys` 和 `avg_processed_keys` 相差很大,说明旧版本比较多 +- `MAX_PROCESSED_KEYS`:Coprocessor 处理的 key 的最大数量 + +和事务相关的字段: + +- `AVG_PREWRITE_TIME`:prewrite 阶段消耗的平均时间 +- `MAX_PREWRITE_TIME` prewrite 阶段消耗的最大时间 +- `AVG_COMMIT_TIME`:commit 阶段消耗的平均时间 +- `MAX_COMMIT_TIME`:commit 阶段消耗的最大时间 +- `AVG_GET_COMMIT_TS_TIME`:获取 commit_ts 的平均时间 +- `MAX_GET_COMMIT_TS_TIME`:获取 commit_ts 的最大时间 +- `AVG_COMMIT_BACKOFF_TIME`:commit 时遇到需要重试的错误时在重试前的平均等待时间 +- `MAX_COMMIT_BACKOFF_TIME`:commit 时遇到需要重试的错误时在重试前的最大等待时间 +- `AVG_RESOLVE_LOCK_TIME`:解决事务的锁冲突的平均时间 +- `MAX_RESOLVE_LOCK_TIME`:解决事务的锁冲突的最大时间 +- `AVG_LOCAL_LATCH_WAIT_TIME`:本地事务等待的平均时间 +- `MAX_LOCAL_LATCH_WAIT_TIME`:本地事务等待的最大时间 +- `AVG_WRITE_KEYS`:写入 key 的平均数量 +- `MAX_WRITE_KEYS`:写入 key 的最大数量 +- `AVG_WRITE_SIZE`:写入的平均数据量,单位 byte +- `MAX_WRITE_SIZE`:写入的最大数据量,单位 byte +- `AVG_PREWRITE_REGIONS`:prewrite 涉及的平均 Region 数量 +- `MAX_PREWRITE_REGIONS`:prewrite 涉及的最大 Region 数量 +- `AVG_TXN_RETRY`:事务平均重试次数 +- `MAX_TXN_RETRY`:事务最大重试次数 +- `SUM_BACKOFF_TIMES`:这类 SQL 遇到需要重试的错误后的总重试次数 +- `BACKOFF_TYPES`:遇到需要重试的错误时的所有错误类型及每种类型重试的次数,格式为 `类型:次数`。如有多种错误则用 `,` 分隔,例如 `txnLock:2,pdRPC:1` +- `AVG_AFFECTED_ROWS`:平均影响行数 +- `PREV_SAMPLE_TEXT`:当 SQL 是 `COMMIT` 时,该字段为 `COMMIT` 的前一条语句;否则该字段为空字符串。当 SQL 是 `COMMIT` 时,按 digest 和 `prev_sample_text` 一起分组,即不同 `prev_sample_text` 的 `COMMIT` 也会分到不同的行 + +和资源管控相关的字段: + +- `AVG_REQUEST_UNIT_WRITE`:执行 SQL 语句平均消耗的写 RU +- `MAX_REQUEST_UNIT_WRITE`:执行 SQL 语句最大消耗的写 RU +- `AVG_REQUEST_UNIT_READ`:执行 SQL 语句平均消耗的读 RU +- `MAX_REQUEST_UNIT_READ`:执行 SQL 语句最大消耗的读 RU +- `AVG_QUEUED_RC_TIME`:执行 SQL 语句等待可用 RU 的平均耗时 +- `MAX_QUEUED_RC_TIME`:执行 SQL 语句等待可用 RU 的最大耗时 +- `RESOURCE_GROUP`:执行 SQL 语句绑定的资源组 + +### `statements_summary_evicted` 字段介绍 + +- `BEGIN_TIME`: 记录的开始时间; +- `END_TIME`: 记录的结束时间; +- `EVICTED_COUNT`:在记录的时间段内 evict 了多少种 SQL。 diff --git a/markdown-pages/zh/tidb/master/storage-engine/rocksdb-overview.md b/markdown-pages/zh/tidb/master/storage-engine/rocksdb-overview.md new file mode 100644 index 0000000..acb3682 --- /dev/null +++ b/markdown-pages/zh/tidb/master/storage-engine/rocksdb-overview.md @@ -0,0 +1,59 @@ +--- +title: RocksDB 简介 +aliases: ['/docs-cn/dev/storage-engine/rocksdb-overview/','/docs-cn/dev/rocksdb/rocksdb-overview/'] +summary: RocksDB 是 Facebook 基于 LevelDB 开发的 LSM-tree 架构引擎,提供键值存储与读写功能。数据先写入磁盘上的 WAL,再写入内存中的跳表。内存数据达到阈值后刷到磁盘生成 SST 文件,分为多层,90% 数据存储在最后一层。RocksDB 允许创建多个 ColumnFamily,共享同一个 WAL 文件。为提高读取性能,文件按大小切分成 block,存在 BlockCache 中。后台线程执行 MemTable 转化为 SST 文件和合并操作。L0 文件数量过多会触发 WriteStall 阻塞写入。 +--- + +# RocksDB 简介 + +[RocksDB](https://github.com/facebook/rocksdb) 是由 Facebook 基于 LevelDB 开发的一款提供键值存储与读写功能的 LSM-tree 架构引擎。用户写入的键值对会先写入磁盘上的 WAL (Write Ahead Log),然后再写入内存中的跳表(SkipList,这部分结构又被称作 MemTable)。LSM-tree 引擎由于将用户的随机修改(插入)转化为了对 WAL 文件的顺序写,因此具有比 B 树类存储引擎更高的写吞吐。 + +内存中的数据达到一定阈值后,会刷到磁盘上生成 SST 文件 (Sorted String Table),SST 又分为多层(默认至多 6 层),每一层的数据达到一定阈值后会挑选一部分 SST 合并到下一层,每一层的数据是上一层的 10 倍(因此 90% 的数据存储在最后一层)。 + +RocksDB 允许用户创建多个 ColumnFamily,这些 ColumnFamily 各自拥有独立的内存跳表以及 SST 文件,但是共享同一个 WAL 文件,这样的好处是可以根据应用特点为不同的 ColumnFamily 选择不同的配置,但是又没有增加对 WAL 的写次数。 + +## TiKV 架构 + +TiKV 的系统架构如下图所示: + +![TiKV RocksDB](/media/tikv-rocksdb.png) + +RocksDB 作为 TiKV 的核心存储引擎,用于存储 Raft 日志以及用户数据。每个 TiKV 实例中有两个 RocksDB 实例,一个用于存储 Raft 日志(通常被称为 raftdb),另一个用于存储用户数据以及 MVCC 信息(通常被称为 kvdb)。kvdb 中有四个 ColumnFamily:raft、lock、default 和 write: + +* raft 列:用于存储各个 Region 的元信息。仅占极少量空间,用户可以不必关注。 +* lock 列:用于存储悲观事务的悲观锁以及分布式事务的一阶段 Prewrite 锁。当用户的事务提交之后,lock cf 中对应的数据会很快删除掉,因此大部分情况下 lock cf 中的数据也很少(少于 1GB)。如果 lock cf 中的数据大量增加,说明有大量事务等待提交,系统出现了 bug 或者故障。 +* write 列:用于存储用户真实的写入数据以及 MVCC 信息(该数据所属事务的开始时间以及提交时间)。当用户写入了一行数据时,如果该行数据长度小于 255 字节,那么会被存储 write 列中,否则的话该行数据会被存入到 default 列中。由于 TiDB 的非 unique 索引存储的 value 为空,unique 索引存储的 value 为主键索引,因此二级索引只会占用 writecf 的空间。 +* default 列:用于存储超过 255 字节长度的数据。 + +## RocksDB 的内存占用 + +为了提高读取性能以及减少对磁盘的读取,RocksDB 将存储在磁盘上的文件都按照一定大小切分成 block(默认是 64KB),读取 block 时先去内存中的 BlockCache 中查看该块数据是否存在,存在的话则可以直接从内存中读取而不必访问磁盘。 + +BlockCache 按照 LRU 算法淘汰低频访问的数据,TiKV 默认将系统总内存大小的 45% 用于 BlockCache,用户也可以自行修改 `storage.block-cache.capacity` 配置设置为合适的值,但是不建议超过系统总内存的 60%。 + +写入 RocksDB 中的数据会写入 MemTable,当一个 MemTable 的大小超过 128MB 时,会切换到一个新的 MemTable 来提供写入。TiKV 中一共有 2 个 RocksDB 实例,合计 4 个 ColumnFamily,每个 ColumnFamily 的单个 MemTable 大小限制是 128MB,最多允许 5 个 MemTable 存在,否则会阻塞前台写入,因此这部分占用的内存最多为 4 x 5 x 128MB = 2.5GB。这部分占用内存较少,不建议用户自行更改。 + +## RocksDB 的空间占用 + +* 多版本:RocksDB 作为一个 LSM-tree 结构的键值存储引擎,MemTable 中的数据会首先被刷到 L0。L0 层的 SST 之间的范围可能存在重叠(因为文件顺序是按照生成的顺序排列),因此同一个 key 在 L0 中可能存在多个版本。当文件从 L0 合并到 L1 的时候,会按照一定大小(默认是 8MB)切割为多个文件,同一层的文件的范围互不重叠,所以 L1 及其以后的层每一层的 key 都只有一个版本。 +* 空间放大:RocksDB 的每一层文件总大小都是上一层的 x 倍,在 TiKV 中这个配置默认是 10,因此 90% 的数据存储在最后一层,这也意味着 RocksDB 的空间放大不超过 1.11(L0 层的数据较少,可以忽略不计)。 +* TiKV 的空间放大:TiKV 在 RocksDB 之上还有一层自己的 MVCC,当用户写入一个 key 的时候,实际上写入到 RocksDB 的是 key + commit_ts,也就是说,用户的更新和删除都是会写入新的 key 到 RocksDB。TiKV 每隔一段时间会删除旧版本的数据(通过 RocksDB 的 Delete 接口),因此可以认为用户存储在 TiKV 上的数据的实际空间放大为,1.11 加最近 10 分钟内写入的数据(假设 TiKV 回收旧版本数据足够及时)。详情见[《TiDB in Action》](https://github.com/pingcap-incubator/tidb-in-action/blob/master/session4/chapter7/compact.md#tikv-%E7%9A%84%E7%A9%BA%E9%97%B4%E6%94%BE%E5%A4%A7)。 + +## RocksDB 后台线程与 Compact + +RocksDB 中,将内存中的 MemTable 转化为磁盘上的 SST 文件,以及合并各个层级的 SST 文件等操作都是在后台线程池中执行的。后台线程池的默认大小是 8,当机器 CPU 数量小于等于 8 时,则后台线程池默认大小为 CPU 数量减一。通常来说,用户不需要更改这个配置。如果用户在一个机器上部署了多个 TiKV 实例,或者机器的读负载比较高而写负载比较低,那么可以适当调低 `rocksdb/max-background-jobs` 至 3 或者 4。 + +## WriteStall + +RocksDB 的 L0 与其他层不同,L0 的各个 SST 是按照生成顺序排列,各个 SST 之间的 key 范围存在重叠,因此查询的时候必须依次查询 L0 中的每一个 SST。为了不影响查询性能,当 L0 中的文件数量过多时,会触发 WriteStall 阻塞写入。 + +如果用户遇到了写延迟突然大幅度上涨,可以先查看 Grafana RocksDB KV 面板 WriteStall Reason 指标,如果是 L0 文件数量过多引起的 WriteStall,可以调整下面几个配置到 64,详细见[《TiDB in Action》](https://github.com/pingcap-incubator/tidb-in-action/blob/master/session4/chapter8/threadpool-optimize.md#5-rocksdb)。 + +``` +rocksdb.defaultcf.level0-slowdown-writes-trigger +rocksdb.writecf.level0-slowdown-writes-trigger +rocksdb.lockcf.level0-slowdown-writes-trigger +rocksdb.defaultcf.level0-stop-writes-trigger +rocksdb.writecf.level0-stop-writes-trigger +rocksdb.lockcf.level0-stop-writes-trigger +``` diff --git a/markdown-pages/zh/tidb/master/storage-engine/titan-configuration.md b/markdown-pages/zh/tidb/master/storage-engine/titan-configuration.md new file mode 100644 index 0000000..01c3c92 --- /dev/null +++ b/markdown-pages/zh/tidb/master/storage-engine/titan-configuration.md @@ -0,0 +1,195 @@ +--- +title: Titan 配置 +aliases: ['/docs-cn/dev/storage-engine/titan-configuration/','/docs-cn/dev/reference/titan/configuration/','/docs-cn/dev/titan-configuration/'] +summary: Titan 配置介绍了如何开启、关闭 Titan、数据迁移原理、相关参数以及 Level Merge 功能。从 TiDB v7.6.0 开始,默认启用 Titan,支持宽表写入场景和 JSON。开启 Titan 方法包括使用 TiUP 部署集群、直接编辑 TiKV 配置文件、编辑 TiDB Operator 配置文件。数据迁移是逐步进行的,可以通过全量 Compaction 提高迁移速度。常用配置参数包括 `min-blob-size`、`blob-file-compression`、`blob-cache-size` 等。关闭 Titan 可通过设置 `blob-run-mode` 参数。Level Merge 是实验功能,可提升范围查询性能并降低 Titan GC 对前台写入性能的影响。 +--- + +# Titan 配置 + +本文档介绍如何通过 [Titan](/storage-engine/titan-overview.md) 配置项来开启、关闭 Titan、数据迁移原理、相关参数以及 Level Merge 功能。 + +## 开启 Titan + +> **注意:** +> +> - 从 TiDB v7.6.0 开始,新集群将默认启用 Titan,以更好地支持 TiDB 宽表写入场景和 JSON。阈值 [`min-blob-size`](/tikv-configuration-file.md#min-blob-size) 的默认值也由之前的 `1KB` 调整为 `32KB`。 +> - 如果集群在升级到 TiDB v7.6.0 或更高版本之前未启用 Titan,则升级后将保持原有配置,继续使用 RocksDB。 +> - 如果集群在升级到 TiDB v7.6.0 或更高版本之前已经启用了 Titan,则升级后将维持原有配置,保持启用 Titan,并保留升级前 [`min-blob-size`](/tikv-configuration-file.md#min-blob-size) 的配置。如果升级前没有显式配置该值,则升级后仍然保持老版本的默认值 `1KB`,以确保升级后集群配置的稳定性。 + +Titan 对 RocksDB 兼容,也就是说,使用 RocksDB 存储引擎的现有 TiKV 实例可以直接开启 Titan。 + +开启 Titan 的方法如下。 + ++ 方法一:如果使用 TiUP 部署的集群,开启的方法是执行 `tiup cluster edit-config ${cluster-name}` 命令,再编辑 TiKV 的配置文件。编辑 TiKV 配置文件示例如下: + + ```shell + tikv: + rocksdb.titan.enabled: true + ``` + + 重新加载配置,同时也会在线滚动重启 TiKV: + + ```shell + tiup cluster reload ${cluster-name} -R tikv + ``` + + 具体命令,可参考[通过 TiUP 修改配置参数](/maintain-tidb-using-tiup.md#修改配置参数)。 + ++ 方法二:直接编辑 TiKV 配置文件开启 Titan(不建议在生产环境中使用)。 + + ```toml + [rocksdb.titan] + enabled = true + ``` + ++ 方法三:编辑 TiDB Operator 的 `${cluster_name}/tidb-cluster.yaml` 配置文件,编辑示例如下: + + ```yaml + spec: + tikv: + ## Base image of the component + baseImage: pingcap/tikv + ## tikv-server configuration + ## Ref: https://docs.pingcap.com/zh/tidb/stable/tikv-configuration-file + config: | + log-level = "info" + [rocksdb] + [rocksdb.titan] + enabled = true + ``` + + 应用配置时,触发在线滚动重启 TiDB 集群让配置生效: + + ```shell + kubectl apply -f ${cluster_name} -n ${namespace} + ``` + + 更多信息请参考[在 Kubernetes 中配置 TiDB 集群](https://docs.pingcap.com/zh/tidb-in-kubernetes/stable/configure-a-tidb-cluster)。 + +## 数据迁移 + +> **警告:** +> +> 在关闭 Titan 功能的情况下,RocksDB 无法读取已经迁移到 Titan 的数据。如果在打开过 Titan 的 TiKV 实例上错误地关闭了 Titan(误设置 `rocksdb.titan.enabled = false`),启动 TiKV 会失败,TiKV log 中出现 `You have disabled titan when its data directory is not empty` 的错误。如需要关闭 Titan,请参考[关闭 Titan](#关闭-titan) 。 + +开启 Titan 以后,原有的数据并不会马上迁移到 Titan 引擎,而是随着前台写入和 RocksDB Compaction 的进行,**逐步进行 key-value 分离并写入 Titan**。同样的,无论是通过 [BR](/br/backup-and-restore-overview.md) 快照或日志恢复的数据或扩缩容过程中产生的数据搬迁,还是通过 [TiDB Lightning](/tidb-lightning/tidb-lightning-overview.md) 物理导入模式导入的数据,都会首先写入 RocksDB。然后,随着 RocksDB Compaction 的进行,超过 [`min-blob-size`](/tikv-configuration-file.md#min-blob-size) 默认值 `32KB` 的大 value 会逐步分离到 Titan 中。你可以通过观察 **TiKV Details** > **Titan kv** > **blob file size** 监控面板中文件的大小来确认存储在 Titan 中的数据大小。 + +为了更快地将数据转移到 Titan,建议使用 tikv-ctl 工具执行一次全量 Compaction,以提高迁移速度。具体操作步骤请参考[手动 compact](/tikv-control.md#手动-compact-整个-tikv-集群的数据)。由于 RocksDB 具备 Block Cache,并且在将数据从 RocksDB 迁移到 Titan 时,数据访问是连续的,这使得在迁移过程中 Block Cache 能够更有效地提升迁移速度。在我们的测试中,通过 tikv-ctl 在单个 TiKV 节点上执行全量 Compaction,仅需 1 小时就能将 670 GiB 的数据迁移到 Titan。 + +需要注意的是,由于 Titan Blob 文件中的 Value 并非连续的,而且 Titan 的缓存是基于 Value 级别的,因此 Blob Cache 无法在 Compaction 过程中提供帮助。相较于从 RocksDB 转向 Titan 的速度,从 Titan 转回 RocksDB 的速度则会慢一个数量级。在测试中,通过 tikv-ctl 将 TiKV 节点上的 800 GiB Titan 数据进行全量 Compaction 转为 RocksDB,需要花费 12 个小时。 + +## 常用配置参数 + +通过合理配置 Titan 参数,可以有效提升数据库性能和资源利用率。本节介绍了一些常见的参数。 + +### `min-blob-size` + +你可以通过设置 [`min-blob-size`](/tikv-configuration-file.md#min-blob-size) 来调整 value 的大小阈值,决定哪些数据保存在 RocksDB 中,哪些数据保存在 Titan 的 blob file 中。`32KB` 是个折中的值,它能确保 Titan 的性能相对 RocksDB 没有回退。但在很多场景中,该值并不是最佳值。建议参考 [`min-blob-size` 对性能的影响](/storage-engine/titan-overview.md#min-blob-size-对性能的影响)来选择合适的值。如果你想进一步提升写性能,并能接受扫描性能的下降,你可以将该值最低调整为 `1KB`。 + +### `blob-file-compression` 和 `zstd-dict-size` + +可以使用 [`blob-file-compression`](/tikv-configuration-file.md#blob-file-compression) 参数指定 Titan 中 value 所使用的压缩算法,也可以配置 [`zstd-dict-size`](/tikv-configuration-file.md#zstd-dict-size) 启用 `zstd` 字典压缩来提高压缩率。 + +### `blob-cache-size` + +可以使用 [`blob-cache-size`](/tikv-configuration-file.md#blob-cache-size) 控制 Titan 中 value 的缓存大小。更大的缓存能提高 Titan 读性能,但过大的缓存会造成 OOM。 + +建议在数据库稳定运行后,根据监控把 RocksDB block cache (`storage.block-cache.capacity`) 设置为 store size 减去 blob file size 的大小,`blob-cache-size` 设置为内存大小 * 50% 减去 block cache 的大小。这是为了保证 block cache 足够缓存整个 RocksDB 的前提下,blob cache 尽量大。 + +### `discardable-ratio` 和 `max-background-gc` + +[`discardable-ratio`](/tikv-configuration-file.md#discardable-ratio) 和 [`max-background-gc`](/tikv-configuration-file.md#max-background-gc) 的设置对于 Titan 的读性能和垃圾回收过程都有重要影响。 + +当一个 blob file 中无用数据(相应的 key 已经被更新或删除)比例超过 [`discardable-ratio`](/tikv-configuration-file.md#discardable-ratio) 设置的阈值时,将会触发 Titan GC。减少这个阈值可以减少空间放大,但是会造成 Titan 更频繁 GC;增加这个值可以减少 Titan GC,减少相应的 I/O 带宽和 CPU 消耗,但是会增加磁盘空间占用。 + +若果你通过**TiKV Details** - **Thread CPU** - **RocksDB CPU** 监控中观察到 Titan GC 线程长期处于满负荷状态时,应该考虑调整 [`max-background-gc`](/tikv-configuration-file.md#max-background-gc) 增加 Titan GC 线程池大小。 + +### `rate-bytes-per-sec` + +通过调整 [`rate-bytes-per-sec`](/tikv-configuration-file.md#rate-bytes-per-sec),你可以限制 RocksDB compaction 的 I/O 速率,从而在高流量时减少对前台读写性能的影响。 + +### `shared-blob-cache`(从 v8.0.0 版本开始引入) + +你可以通过 [`shared-blob-cache`](/tikv-configuration-file.md#shared-blob-cache从-v800-版本开始引入) 控制是否启用 Titan Blob 文件和 RocksDB Block 文件的共享缓存,默认值为 `true`。当开启共享缓存时,Block 文件具有更高的优先级,TiKV 将优先满足 Block 文件的缓存需求,然后将剩余的缓存用于 Blob 文件。 + +### Titan 配置文件示例 + +下面是一个 Titan 配置文件的样例,更多的参数说明,请参考 [TiKV 配置文件描述](/tikv-configuration-file.md)。你可以使用 TiUP [修改配置参数](/maintain-tidb-using-tiup.md#修改配置参数),也可以通过[在 Kubernetes 中配置 TiDB 集群](https://docs.pingcap.com/zh/tidb-in-kubernetes/stable/configure-a-tidb-cluster)修改配置参数。 + +```toml +[rocksdb] +rate-bytes-per-sec = 0 + +[rocksdb.titan] +enabled = true +max-background-gc = 1 + +[rocksdb.defaultcf.titan] +min-blob-size = "32KB" +blob-file-compression = "zstd" +zstd-dict-size = "16KB" +discardable-ratio = 0.5 +blob-run-mode = "normal" +level-merge = false +``` + +## 关闭 Titan + +通过设置 `rocksdb.defaultcf.titan.blob-run-mode` 参数可以关闭 Titan。`blob-run-mode` 可以设置为以下几个值之一: + +- 当设置为 `normal` 时,Titan 处于正常读写的状态。 +- 当设置为 `read-only` 时,新写入的 value 不论大小均会写入 RocksDB。 +- 当设置为 `fallback` 时,新写入的 value 不论大小均会写入 RocksDB,并且当 RocksDB 进行 compaction 时,会自动把所碰到的存储在 Titan blob file 中的 value 移回 RocksDB。 + +如果现有数据和未来数据均不再需要 Titan,可执行以下步骤完全关闭 Titan。一般情况下,只需要执行以下步骤 1 和步骤 3、步骤 4 即可。步骤 2 虽然可以加快数据迁移速度,但会严重影响用户 SQL 的性能。事实上,即使跳过步骤 2,由于在 Compaction 过程中会将数据从 Titan 迁移到 RocksDB,会占用额外的 I/O 和 CPU 资源,因此仍然可以观察到一定的性能损失,在资源紧张的情况下吞吐可以下降 50% 以上。 + +1. 更新需要关闭 Titan 的 TiKV 节点的配置。你可以通过以下两种方式之一更新 TiKV 配置: + + - 执行 `tiup cluster edit-config`,编辑配置文件,再执行 `tiup cluster reload -R tikv`。 + - 手动修改 TiKV 配置文件,然后重启 TiKV。 + + ```toml + [rocksdb.defaultcf.titan] + blob-run-mode = "fallback" + discardable-ratio = 1.0 + ``` + + > **注意:** + > + > 在磁盘空间不足以同时保持 Titan 和 RocksDB 数据时,应该使用 [`discardable-ratio`](/tikv-configuration-file.md#discardable-ratio) 的默认值 `0.5`。一般来说,如果磁盘可用空间小于 50% 时,推荐使用默认值。因为当 `discardable-ratio = 1.0` 时,RocksDB 数据一方面在不断增加,同时 Titan 原有的 blob 文件回收需要该文件所有数据都迁移至 RocksDB 才会发生,这个过程会比较缓慢。如果磁盘空间足够大,设置 `discardable-ratio = 1.0` 可以减小 compaction 过程中 Blob 文件自身的 GC,从而节省带宽。 + +2. (可选)使用 `tikv-ctl` 执行全量数据整理 (Compaction)。这一步骤将消耗大量 I/O 和 CPU 资源。 + + > **警告:** + > + > 如果在磁盘空间不足时执行以下命令,可能会导致整个集群无可用空间从而无法写入数据。 + + ```bash + tikv-ctl --pd compact-cluster --bottommost force + ``` + +3. 等待数据整理结束,通过 **TiKV-Details**/**Titan - kv** 监控面板确认 **Blob file count** 指标降为 0。 + +4. 更新 TiKV 节点的配置,关闭 Titan。 + + ```toml + [rocksdb.titan] + enabled = false + ``` + +## Level Merge(实验功能) + +TiKV 4.0 中 Titan 提供新的算法提升范围查询性能并降低 Titan GC 对前台写入性能的影响。这个新的算法称为 [Level Merge](/storage-engine/titan-overview.md#level-merge)。Level Merge 可以通过以下选项开启: + +```toml +[rocksdb.defaultcf.titan] +level-merge = true +``` + +开启 Level Merge 的好处如下: + +- 大幅提升 Titan 的范围查询性能。 +- 减少了 Titan GC 对前台写入性能的影响,提升写入性能。 +- 减少 Titan 空间放大,减少磁盘空间占用(默认配置下的比较)。 + +相应地,Level Merge 的写放大会比 Titan 稍高,但依然低于原生的 RocksDB。 diff --git a/markdown-pages/zh/tidb/master/storage-engine/titan-overview.md b/markdown-pages/zh/tidb/master/storage-engine/titan-overview.md new file mode 100644 index 0000000..4ec0019 --- /dev/null +++ b/markdown-pages/zh/tidb/master/storage-engine/titan-overview.md @@ -0,0 +1,147 @@ +--- +title: Titan 介绍 +aliases: ['/docs-cn/dev/storage-engine/titan-overview/','/docs-cn/dev/reference/titan/overview/'] +summary: Titan 是基于 RocksDB 的高性能单机 key-value 存储引擎插件。它支持将 value 从 LSM-tree 中分离出来单独存储,以降低写放大。Titan 适合前台写入量较大的场景,但不适合范围查询或对范围查询性能敏感的情况。开启 Titan 需要考虑 value 大小、范围查询敏感性和磁盘空间。从 v7.6.0 开始,TiDB 对 Titan 性能进行了优化,并将其作为默认的存储引擎。Titan 的 GC 方式有传统 GC 和 Level Merge,而 `min-blob-size` 的大小会影响性能。 +--- + +# Titan 介绍 + +[Titan](https://github.com/pingcap/rocksdb/tree/titan-5.15) 是基于 [RocksDB](https://github.com/facebook/rocksdb) 的高性能单机 key-value 存储引擎插件。 + +当 value 较大(1 KB 以上或 512 B 以上)的时候,Titan 在写、更新和点读等场景下性能都优于 RocksDB。但与此同时,Titan 会占用更多硬盘空间和部分舍弃范围查询。随着 SSD 价格的降低,Titan 的优势会更加突出,让用户更容易做出选择。 + +## 核心特性 + +- 支持将 value 从 LSM-tree 中分离出来单独存储,以降低写放大。 +- 已有 RocksDB 实例可以平滑地升级到 Titan,这意味着升级过程不需要人工干预,并且不会影响线上服务。 +- 100% 兼容目前 TiKV 所使用的所有 RocksDB 的特性。 + +## 适用场景 + +Titan 适合在以下场景中使用: + +- 前台写入量较大,RocksDB 大量触发 compaction 消耗大量 I/O 带宽或者 CPU 资源,造成 TiKV 前台读写性能较差。 +- 前台写入量较大,由于 I/O 带宽瓶颈或 CPU 瓶颈的限制,RocksDB compaction 进度落后较多频繁造成 write stall。 +- 前台写入量较大,RocksDB 大量触发 compaction 造成 I/O 写入量较大,影响 SSD 盘的寿命。 + +开启 Titan 需要考虑以下前提条件: + +- Value 较大。即 value 平均大小比较大,或者数据中大 value 的数据总大小占比比较大。目前 Titan 默认 1KB 以上大小的 value 是大 value,根据实际情况 512B 以上大小的 value 也可以看作是大 value。注:由于 TiKV Raft 层的限制,写入 TiKV 的 value 大小还是无法超过 8MB 的限制,可通过 [`raft-entry-max-size`](/tikv-configuration-file.md#raft-entry-max-size) 配置项调整该限制。 +- 没有范围查询或者对范围查询性能不敏感。Titan 存储数据的顺序性较差,所以相比 RocksDB 范围查询的性能较差,尤其是大范围查询。在测试中 Titan 范围查询性能相比 RocksDB 下降 40% 到数倍不等。 +- 磁盘剩余空间足够,推荐为相同数据量下 RocksDB 磁盘占用的两倍。Titan 降低写放大是通过牺牲空间放大达到的。另外由于 Titan 逐个压缩 value,压缩率比 RocksDB(逐个压缩 block)要差。这两个因素一起造成 Titan 占用磁盘空间比 RocksDB 要多,这是正常现象。根据实际情况和不同的配置,Titan 磁盘空间占用可能会比 RocksDB 多一倍。 + +从 v7.6.0 开始,TiDB 对 Titan 性能进行了优化,并将 Titan 作为默认的存储引擎。由于 TiKV 在 Value 较小时会直接存在 RocksDB 中,因此即便是小 Value 也可以打开 Titan。 + +性能提升请参考 [Titan 的设计与实现](https://pingcap.com/blog-cn/titan-design-and-implementation/#%E5%9F%BA%E5%87%86%E6%B5%8B%E8%AF%95)。 + +## 架构与实现 + +Titan 的基本架构如下图所示: + +![Architecture](/media/titan/titan-1.png) + +Titan 在 Flush 和 Compaction 的时候将 value 分离出 LSM-tree,这样写入流程可以和 RocksDB 保持一致,减少对 RocksDB 的侵入性改动。 + +### BlobFile + +BlobFile 是用来存放从 LSM-tree 中分离出来的 value 的文件,其格式如下图所示: + +![BlobFile](/media/titan/titan-2.png) + +BlobFile 由 blob record 、meta block、meta index block 和 footer 组成。其中每个 blob record 用于存放一个 key-value 对;meta block 支持可扩展性,可以用来存放和 BlobFile 相关的一些属性;meta index block 用于检索 meta block。 + +BlobFile 的实现上有几点值得关注的地方: + ++ BlobFile 中的 key-value 是有序存放的,目的是在实现 iterator 的时候可以通过 prefetch 的方式提高顺序读取的性能。 ++ 每个 blob record 都保留了 value 对应的 user key 的拷贝,这样做的目的是在进行 GC 的时候,可以通过查询 user key 是否更新来确定对应 value 是否已经过期,但同时也带来了一定的写放大。 ++ BlobFile 支持 blob record 粒度的压缩,并且支持多种压缩算法,包括 [Snappy](https://github.com/google/snappy)、[`lz4`](https://github.com/lz4/lz4) 和 [`zstd`](https://github.com/facebook/zstd)。在 v7.6.0 之前的版本,Titan 默认使用的压缩算法是 `lz4`。v7.6.0 之后,默认使用 `zstd`。 + +> **注意:** +> +> Snappy 压缩文件必须遵循[官方 Snappy 格式](https://github.com/google/snappy)。不支持其他非官方压缩格式。 + +### TitanTableBuilder + +![TitanTableBuilder](/media/titan/titan-3.png) + +TitanTableBuilder 是实现分离 key-value 的关键,它通过判断 value size 的大小来决定是否将 value 分离到 BlobFile 中去。如果 value size 大于等于 `min_blob_size` 则将 value 分离到 BlobFile,并生成 index 写入 SST;如果 value size 小于 `min_blob_size` 则将 value 直接写入 SST。 + +该流程还支持将 Titan 降级回 RocksDB。在 RocksDB 做 compaction 的时候,将分离出来的 value 重新写回新生成的 SST 文件中。 + +## Garbage Collection + +Garbage Collection (GC) 的目的是回收空间。由于在 LSM-tree compaction 进行回收 key 时,储存在 blob 文件中的 value 并不会一同被删除,因此需要 GC 定期来将已经作废的 value 删除掉。在 Titan 中有两种 GC 方式可供选择: + +- 定期整合重写 Blob 文件将作废的 value 剔除(传统 GC) +- 在 LSM-tree compaction 的时候同时进行 blob 文件的重写 (Level-Merge) + +### 传统 GC + +Titan 使用 RocksDB 的 TablePropertiesCollector 和 EventListener 来收集 GC 所需的统计信息。 + +#### TablePropertiesCollector + +RocksDB 允许使用自定义的 TablePropertiesCollector 来搜集 SST 上的 properties 并写入到对应文件中去。Titan 通过一个自定义的 TablePropertiesCollector —— BlobFileSizeCollector 来搜集每个 SST 中有多少数据是存放在哪些 BlobFile 上的,将它收集到的 properties 命名为 BlobFileSizeProperties,它的工作流程和数据格式如下图所示: + +![BlobFileSizeProperties](/media/titan/titan-4.png) + +左边 SST 中 Index 的格式为:第一列代表 BlobFile 的文件 ID,第二列代表 blob record 在 BlobFile 中的 offset,第三列代表 blob record 的 size。右边 BlobFileSizeProperties 中的每一行代表一个 BlobFile 以及 SST 中有多少数据保存在这个 BlobFile 中,第一列代表 BlobFile 的文件 ID,第二列代表数据大小。 + +#### EventListener + +RocksDB 是通过 Compaction 来丢弃旧版本数据以回收空间的,因此每次 Compaction 完成后 Titan 中的某些 BlobFile 中便可能有部分或全部数据过期。因此便可以通过监听 Compaction 事件来触发 GC,搜集比对 Compaction 中输入输出 SST 的 BlobFileSizeProperties 来决定挑选哪些 BlobFile 进行 GC。其流程大概如下图所示: + +![EventListener](/media/titan/titan-5.png) + +inputs 代表参与 Compaction 的所有 SST 的 BlobFileSizeProperties,outputs 代表 Compaction 生成的所有 SST 的 BlobFileSizeProperties,discardable size 是通过计算 inputs 和 outputs 得出的每个 BlobFile 被丢弃的数据大小,第一列代表 BlobFile 的文件 ID,第二列代表被丢弃的数据大小。 + +Titan 会为每个有效的 BlobFile 在内存中维护一个 discardable size 变量,每次 Compaction 结束之后都对相应的 BlobFile 的 discardable size 变量进行累加。注意,在每次重启后会扫描一遍所有的 SST 的 BlobFileSizeProperties 重新构建每个有效 BlobFile 的 discardable size 变量。每次 GC 开始时就可以通过挑选 discardable size 最大的几个 BlobFile 来作为候选的文件。为了减小写放大,我们可以容忍一定的空间放大,所以 Titan 只有在 BlobFile 可丢弃的数据达到一定比例之后才会对其进行 GC。 + +GC 的方式就是对于这些选中的 BlobFile 文件,依次通过查询其中每个 value 相应的 key 的 blob index 是否存在或者更新来确定该 value 是否作废,最终将未作废的 value 归并排序生成新的 BlobFile,并将这些 value 更新后的 blob index 通过 WriteCallback 或者 MergeOperator 的方式写回到 SST 中。在完成 GC 后,这些原来的 BlobFile 文件并不会立即被删除,Titan 会在写回 blob index 后记录 RocksDB 最新的 sequence number,等到最旧 snapshot 的 sequence 超过这个记录的 sequence number 时 BlobFile 才能被删除。这个是因为在写回 blob index 后,还是可能通过之前的 snapshot 访问到老的 blob index,因此需要确保没有 snapshot 会访问到这个老的 blob index 后才能安全删除相应 BlobFile。 + +### Level Merge + +Level Merge 是 Titan 新加入的一种策略,它的核心思想是 LSM-tree 在进行 Compaction 的同时,对 SST 文件对应的 BlobFile 进行归并重写产生新的 BlobFile。其流程大概如下图所示: + +![LevelMerge](/media/titan/titan-6.png) + +Level z-1 和 Level z 的 SST 进行 Compaction 时会对 KV 对有序读写一遍,这时就可以对这些 SST 中所涉及的 BlobFile 的 value 有序写到新的 BlobFile 中,并在生成新的 SST 时将 key 的 blob index 进行更新。对于 Compaction 中被删除的 key,相应的 value 也不会写到新的 BlobFile 中,相当于完成了 GC。 + +相比于传统 GC,Level Merge 这种方式在 LSM-tree 进行 Compaction 的同时就完成了 Blob GC,不再需要查询 LSM-tree 的 blob index 情况和写回新 blob index 到 LSM-tree 中,减小了 GC 对前台操作影响。同时通过不断的重写 BlobFile,减小了 BlobFile 之间的相互重叠,提高系统整体有序性,也就是提高了 Scan 性能。当然将 BlobFile 以类似 tiering compaction 的方式分层会带来写放大,考虑到 LSM-tree 中 99% 的数据都落在最后两层,因此 Titan 仅对 LSM-tree 中 Compaction 到最后两层数据对应的 BlobFile 进行 Level Merge。 + +#### Range Merge + +Range Merge 是基于 Level Merge 的一个优化。考虑如下两种情况,会导致最底层的有序性越来越差: + +- 开启 `level_compaction_dynamic_level_bytes`,此时 LSM-tree 各层动态增长,随数据量增大最后一层的 sorted run 会越来越多。 + +- 某个 range 被频繁 Compaction 导致该 range 的 sorted runs 较多。 + +![RangeMerge](/media/titan/titan-7.png) + +因此需要通过 Range Merge 操作维持 sorted run 在一定水平,即在 OnCompactionComplete 时统计该 range 的 sorted run 数量,若数量过多则将涉及的 BlobFile 标记为 ToMerge,在下一次的 Compaction 中进行重写。 + +### 扩容与缩容 + +基于向后兼容的考虑,TiKV 在扩缩容时的 Snapshot 仍然是 RocksDB 的格式。因此扩容后的节点由于一开始全部来自 RocksDB,因此会显示 RocksDB 的特征,比如压缩率会高于老的 TiKV 节点、Store Size 会较小、同时 Compaction 的写放大会相对较大。后续这些 RocksDB 格式的 SST 参与 Compaction 之后逐步转换为 Titan 格式。 + +### `min-blob-size` 对性能的影响 + +[`min-blob-size`](/tikv-configuration-file.md#min-blob-size) 是决定一个 Value 是否用 Titan 存储的依据。如果 Value 大于或等于 `min-blob-size`,会用 Titan 存储,反之则用 RocksDB 的原生格式存储。`min-blob-size` 太小或太大都会导致性能下降。 + +下表格列举了 YCSB 这个负载在不同 `min-blob-size` 值时的 QPS 对比。每一轮测试中测试数据的行宽和 `min-blob-size` 相等,从而确保 Titan 启用时数据保存在 Titan 中。 + +| 行宽 (Bytes) | `Point_Get` | `Point_Get` (Titan)| scan100 | scan100 (Titan)| scan10000 | scan10000 (Titan)| `UPDATE` | `UPDATE` (Titan) | +| ---------------- | ---------| -------------- | --------| ------------- | --------- | --------------- | ------ | ------------ | +| 1KB | 139255 | 140486 | 25171 | 21854 | 533 | 175 | 17913 | 30767 | +| 2KB | 114201 |124075 | 12466 |11552 |249 |131 |10369 | 27188 | +| 4KB | 92385 | 103811 | 7918 | 5937 | 131 | 87 | 5327 | 22653 | +| 8KB |104380 | 130647 | 7365 | 5402 | 86.6 | 68 | 3180 | 16745 | +| 16KB | 54234 | 54600 | 4937 | 5174 | 55.4 | 58.9 |1753 | 10120 | +| 32KB | 31035 |31052 | 2705 | 3422 | 38 | 45.3 | 984 | 5844 | + +> **注意:** +> +> `scan100` 是指扫描 100 条记录,`scan10000` 是指扫描 10000 条记录。 + +以上可见,当行宽是 `16KB` 时,Titan 在所有 YCSB 细分负载下上都超过了 RocksDB。然而在一些极端重度扫描场景下,如运行 Dumpling,`16KB` 行宽下 Titan 的性能会有约 10% 的回退。因此,如果负载是以写和点查为主,建议将 `min-blob-size` 调整为 `1KB`;如果负载有大量扫描,建议将 `min-blob-size` 调整为至少 `16KB`。 \ No newline at end of file diff --git a/markdown-pages/zh/tidb/master/sync-diff-inspector/route-diff.md b/markdown-pages/zh/tidb/master/sync-diff-inspector/route-diff.md new file mode 100644 index 0000000..7876246 --- /dev/null +++ b/markdown-pages/zh/tidb/master/sync-diff-inspector/route-diff.md @@ -0,0 +1,196 @@ +--- +title: 不同库名或表名的数据校验 +aliases: ['/docs-cn/dev/sync-diff-inspector/route-diff/','/docs-cn/dev/reference/tools/sync-diff-inspector/route-diff/'] +summary: TiDB DM 等同步工具可以使用 route-rules 设置数据同步到下游指定表中。sync-diff-inspector 通过设置 rules 提供了校验不同库名、表名的表的功能。可以通过 rules 设置映射关系来简化配置,校验大量的不同库名或者表名的表。表路由的初始化和示例包括规则中存在 target-schema/target-table 表名为 schema.table 的行为,规则中只存在 target-schema 的行为,以及规则中不存在 target-schema.target-table 的行为。 +--- + +# 不同库名或表名的数据校验 + +当你在使用 [TiDB DM](/dm/dm-overview.md) 等同步工具时,可以设置 `route-rules` 将数据同步到下游指定表中。sync-diff-inspector 通过设置 `rules` 提供了校验不同库名、表名的表的功能。 + +下面是一个简单的配置文件说明,要了解完整配置,请参考 [sync-diff-inspector 用户文档](/sync-diff-inspector/sync-diff-inspector-overview.md)。 + +```toml +######################### Datasource config ######################### +[data-sources.mysql1] + host = "127.0.0.1" + port = 3306 + user = "root" + password = "" + + route-rules = ["rule1"] + +[data-sources.tidb0] + host = "127.0.0.1" + port = 4000 + user = "root" + password = "" + +########################### Routes ########################### +[routes.rule1] +schema-pattern = "test_1" # 匹配数据源的库名,支持通配符 "*" 和 "?" +table-pattern = "t_1" # 匹配数据源的表名,支持通配符 "*" 和 "?" +target-schema = "test_2" # 目标库名 +target-table = "t_2" # 目标表名 +``` + +使用该配置会对下游的 `test_2.t_2` 与实例 `mysql1` 中的 `test_1.t_1` 进行校验。 + +如果需要校验大量的不同库名或者表名的表,也可以通过 `rules` 设置映射关系来简化配置。可以只配置 schema 或者 table 的映射关系,也可以都配置。例如上游库 `test_1` 中的所有表都同步到了下游的 `test_2` 库中,可以使用如下配置进行校验: + +```toml +######################### Datasource config ######################### +[data-sources.mysql1] + host = "127.0.0.1" + port = 3306 + user = "root" + password = "" + + route-rules = ["rule1"] + +[data-sources.tidb0] + host = "127.0.0.1" + port = 4000 + user = "root" + password = "" + +########################### Routes ########################### +[routes.rule1] +schema-pattern = "test_1" # 匹配数据源的库名,支持通配符 "*" 和 "?" +table-pattern = "*" # 匹配数据源的表名,支持通配符 "*" 和 "?" +target-schema = "test_2" # 目标库名 +target-table = "t_2" # 目标表名 +``` + +## Table Router 的初始化和示例 + +### Table Router 的初始化 + +- 如果规则中存在 `target-schema/target-table` 表名为 `schema.table`,sync-diff-inspector 的行为如下: + + - 如果存在一条规则将 `schema.table` 匹配到 `schema.table`,sync-diff-inspector 不做任何处理。 + - 如果不存在将 `schema.table` 匹配到 `schema.table` 的规则,sync-diff-inspector 会在表路由中添加一条新的规则 `schema.table -> _no__exists__db_._no__exists__table_`。之后,sync-diff-inspector 会将表 `schema.table` 视为表 `_no__exists__db_._no__exists__table_`。 + +- 如果规则中只存在 `target-schema`,如下所示: + + ```toml + [routes.rule1] + schema-pattern = "schema_2" # 匹配数据源的库名,支持通配符 "*" 和 "?" + target-schema = "schema" # 目标库名 + ``` + + - 如果上游中不存在库 `schema`,sync-diff-inspector 不做任何处理。 + - 如果上游中存在库 `schema`,且存在一条规则将该库匹配到其他库,sync-diff-inspector 不做任何处理。 + - 如果上游中存在库 `schema`,但不存在将该库匹配到其他库的规则,sync-diff-inspector 会在表路由中添加一条新的规则 `schema -> _no__exists__db_`。之后,sync-diff-inspector 会将库 `schema` 视为库 `_no__exists__db_`。 + +- 如果规则中不存在 `target-schema.target-table`,sync-diff-inspector 会添加一条规则将 `target-schema.target-table` 匹配到 `target-schema.target-table`,使其大小写不敏感,因为表路由是大小写不敏感的。 + +### 示例 + +假设在上游集群中有下列七张表: + +- `inspector_mysql_0.tb_emp1` +- `Inspector_mysql_0.tb_emp1` +- `inspector_mysql_0.Tb_emp1` +- `inspector_mysql_1.tb_emp1` +- `Inspector_mysql_1.tb_emp1` +- `inspector_mysql_1.Tb_emp1` +- `Inspector_mysql_1.Tb_emp1` + +在配置示例中,上游集群有一条规则 `Source.rule1`,目标表为 `inspector_mysql_1.tb_emp1`。 + +#### 示例 1 + +如果配置如下: + +```toml +[Source.rule1] +schema-pattern = "inspector_mysql_0" +table-pattern = "tb_emp1" +target-schema = "inspector_mysql_1" +target-table = "tb_emp1" +``` + +那么路由结果如下: + +- `inspector_mysql_0.tb_emp1` 将被路由到 `inspector_mysql_1.tb_emp1` +- `Inspector_mysql_0.tb_emp1` 将被路由到 `inspector_mysql_1.tb_emp1` +- `inspector_mysql_0.Tb_emp1` 将被路由到 `inspector_mysql_1.tb_emp1` +- `inspector_mysql_1.tb_emp1` 将被路由到 `_no__exists__db_._no__exists__table_` +- `Inspector_mysql_1.tb_emp1` 将被路由到 `_no__exists__db_._no__exists__table_` +- `inspector_mysql_1.Tb_emp1` 将被路由到 `_no__exists__db_._no__exists__table_` +- `Inspector_mysql_1.Tb_emp1` 将被路由到 `_no__exists__db_._no__exists__table_` + +#### 示例 2 + +如果配置如下: + +```toml +[Source.rule1] +schema-pattern = "inspector_mysql_0" +target-schema = "inspector_mysql_1" +``` + +那么路由结果如下: + +- `inspector_mysql_0.tb_emp1` 将被路由到 `inspector_mysql_1.tb_emp1` +- `Inspector_mysql_0.tb_emp1` 将被路由到 `inspector_mysql_1.tb_emp1` +- `inspector_mysql_0.Tb_emp1` 将被路由到 `inspector_mysql_1.Tb_emp1` +- `inspector_mysql_1.tb_emp1` 将被路由到 `_no__exists__db_._no__exists__table_` +- `Inspector_mysql_1.tb_emp1` 将被路由到 `_no__exists__db_._no__exists__table_` +- `inspector_mysql_1.Tb_emp1` 将被路由到 `_no__exists__db_._no__exists__table_` +- `Inspector_mysql_1.Tb_emp1` 将被路由到 `_no__exists__db_._no__exists__table_` + +#### 示例 3 + +如果配置如下: + +```toml +[Source.rule1] +schema-pattern = "other_schema" +target-schema = "other_schema" +``` + +那么路由结果如下: + +- `inspector_mysql_0.tb_emp1` 将被路由到 `inspector_mysql_0.tb_emp1` +- `Inspector_mysql_0.tb_emp1` 将被路由到 `Inspector_mysql_0.tb_emp1` +- `inspector_mysql_0.Tb_emp1` 将被路由到 `inspector_mysql_0.Tb_emp1` +- `inspector_mysql_1.tb_emp1` 将被路由到 `inspector_mysql_1.tb_emp1` +- `Inspector_mysql_1.tb_emp1` 将被路由到 `inspector_mysql_1.tb_emp1` +- `inspector_mysql_1.Tb_emp1` 将被路由到 `inspector_mysql_1.tb_emp1` +- `Inspector_mysql_1.Tb_emp1` 将被路由到 `inspector_mysql_1.tb_emp1` + +#### 示例 4 + +如果配置如下: + +```toml +[Source.rule1] +schema-pattern = "inspector_mysql_?" +table-pattern = "tb_emp1" +target-schema = "inspector_mysql_1" +target-table = "tb_emp1" +``` + +那么路由结果如下: + +- `inspector_mysql_0.tb_emp1` 将被路由到 `inspector_mysql_1.tb_emp1` +- `Inspector_mysql_0.tb_emp1` 将被路由到 `inspector_mysql_1.tb_emp1` +- `inspector_mysql_0.Tb_emp1` 将被路由到 `inspector_mysql_1.tb_emp1` +- `inspector_mysql_1.tb_emp1` 将被路由到 `inspector_mysql_1.tb_emp1` +- `Inspector_mysql_1.tb_emp1` 将被路由到 `inspector_mysql_1.tb_emp1` +- `inspector_mysql_1.Tb_emp1` 将被路由到 `inspector_mysql_1.tb_emp1` +- `Inspector_mysql_1.Tb_emp1` 将被路由到 `inspector_mysql_1.tb_emp1` + +#### 示例 5 + +如果你不设置任何规则,那么路由结果如下: + +- `inspector_mysql_0.tb_emp1` 将被路由到 `inspector_mysql_0.tb_emp1` +- `Inspector_mysql_0.tb_emp1` 将被路由到 `Inspector_mysql_0.tb_emp1` +- `inspector_mysql_0.Tb_emp1` 将被路由到 `inspector_mysql_0.Tb_emp1` +- `inspector_mysql_1.tb_emp1` 将被路由到 `inspector_mysql_1.tb_emp1` +- `Inspector_mysql_1.tb_emp1` 将被路由到 `inspector_mysql_1.tb_emp1` +- `inspector_mysql_1.Tb_emp1` 将被路由到 `inspector_mysql_1.tb_emp1` +- `Inspector_mysql_1.Tb_emp1` 将被路由到 `inspector_mysql_1.tb_emp1` diff --git a/markdown-pages/zh/tidb/master/sync-diff-inspector/shard-diff.md b/markdown-pages/zh/tidb/master/sync-diff-inspector/shard-diff.md new file mode 100644 index 0000000..fba7c66 --- /dev/null +++ b/markdown-pages/zh/tidb/master/sync-diff-inspector/shard-diff.md @@ -0,0 +1,147 @@ +--- +title: 分库分表场景下的数据校验 +aliases: ['/docs-cn/dev/sync-diff-inspector/shard-diff/','/docs-cn/dev/reference/tools/sync-diff-inspector/shard-diff/'] +summary: sync-diff-inspector 支持对分库分表场景进行数据校验。使用 Datasource config 进行配置,设置对应 rules,配置上游表与下游表的映射关系。当上游分表较多且符合一定规则时,可以使用 table-rules 进行配置。注意事项:如果上游数据库有 test.table-0 也会被下游数据库匹配到。 +--- + +# 分库分表场景下的数据校验 + +sync-diff-inspector 支持对分库分表场景进行数据校验。例如有多个 MySQL 实例,当你使用同步工具 [TiDB DM](/dm/dm-overview.md) 同步到一个 TiDB 时,可以使用 sync-diff-inspector 对上下游数据进行校验。 + +## 使用 datasource config 进行配置 + +使用 `Datasource config` 对 `table-0` 进行特殊配置,设置对应 `rules`,配置上游表与下游表的映射关系。这种配置方式需要对所有分表进行设置,适合上游分表数量较少,且分表的命名规则没有规律的场景。场景如图所示: + +![shard-table-sync-1](/media/shard-table-sync-1.png) + +sync-diff-inspector 完整的示例配置如下: + +```toml +# Diff Configuration. + +######################### Global config ######################### + +# 检查数据的线程数量,上下游数据库的连接数会略大于该值 +check-thread-count = 4 + +# 如果开启,若表存在不一致,则输出用于修复的 SQL 语句 +export-fix-sql = true + +# 只对比表结构而不对比数据 +check-struct-only = false + + +######################### Datasource config ######################### +[data-sources.mysql1] + host = "127.0.0.1" + port = 3306 + user = "root" + password = "" + + route-rules = ["rule1"] + +[data-sources.mysql2] + host = "127.0.0.1" + port = 3306 + user = "root" + password = "" + + route-rules = ["rule2"] + +[data-sources.tidb0] + host = "127.0.0.1" + port = 4000 + user = "root" + password = "" + +########################### Routes ########################### +[routes.rule1] +schema-pattern = "test" # 匹配数据源的库名,支持通配符 "*" 和 "?" +table-pattern = "table-[1-2]" # 匹配数据源的表名,支持通配符 "*" 和 "?" +target-schema = "test" # 目标库名 +target-table = "table-0" # 目标表名 + +[routes.rule2] +schema-pattern = "test" # 匹配数据源的库名,支持通配符 "*" 和 "?" +table-pattern = "table-3" # 匹配数据源的表名,支持通配符 "*" 和 "?" +target-schema = "test" # 目标库名 +target-table = "table-0" # 目标表名 + +######################### Task config ######################### +[task] + output-dir = "./output" + + source-instances = ["mysql1", "mysql2"] + + target-instance = "tidb0" + + # 需要比对的下游数据库的表,每个表需要包含数据库名和表名,两者由 `.` 隔开 + target-check-tables = ["test.table-0"] +``` + +当上游分表较多,且所有分表的命名都符合一定的规则时,则可以使用 `table-rules` 进行配置。场景如图所示: + +![shard-table-sync-2](/media/shard-table-sync-2.png) + +sync-diff-inspector 完整的示例配置如下: + +```toml +# Diff Configuration. + +######################### Global config ######################### + +# 检查数据的线程数量,上下游数据库的连接数会略大于该值 +check-thread-count = 4 + +# 如果开启,若表存在不一致,则输出用于修复的 SQL 语句 +export-fix-sql = true + +# 只对比表结构而不对比数据 +check-struct-only = false + + +######################### Datasource config ######################### +[data-sources.mysql1] + host = "127.0.0.1" + port = 3306 + user = "root" + password = "" + + route-rules = ["rule1"] + +[data-sources.mysql2] + host = "127.0.0.1" + port = 3306 + user = "root" + password = "" + + route-rules = ["rule1"] + +[data-sources.tidb0] + host = "127.0.0.1" + port = 4000 + user = "root" + password = "" + +########################### Routes ########################### +[routes.rule1] +schema-pattern = "test" # 匹配数据源的库名,支持通配符 "*" 和 "?" +table-pattern = "table-*" # 匹配数据源的表名,支持通配符 "*" 和 "?" +target-schema = "test" # 目标库名 +target-table = "table-0" # 目标表名 + +######################### Task config ######################### +[task] + output-dir = "./output" + + source-instances = ["mysql1", "mysql2"] + + target-instance = "tidb0" + + # 需要比对的下游数据库的表,每个表需要包含数据库名和表名,两者由 `.` 隔开 + target-check-tables = ["test.table-0"] +``` + +## 注意事项 + +如果上游数据库有 `test`.`table-0` 也会被下游数据库匹配到。 \ No newline at end of file diff --git a/markdown-pages/zh/tidb/master/sync-diff-inspector/sync-diff-inspector-overview.md b/markdown-pages/zh/tidb/master/sync-diff-inspector/sync-diff-inspector-overview.md new file mode 100644 index 0000000..5b7423a --- /dev/null +++ b/markdown-pages/zh/tidb/master/sync-diff-inspector/sync-diff-inspector-overview.md @@ -0,0 +1,301 @@ +--- +title: sync-diff-inspector 用户文档 +aliases: ['/docs-cn/dev/sync-diff-inspector/sync-diff-inspector-overview/','/docs-cn/dev/reference/tools/sync-diff-inspector/overview/'] +summary: sync-diff-inspector 是一个用于校验 MySQL/TiDB 中数据一致性的工具,提供修复数据的功能。它支持对比表结构和数据,生成用于修复数据的 SQL 语句。需要注意的是,在校验数据时会消耗一定的服务器资源,需要避免在业务高峰期间校验。生成的 SQL 文件仅作为修复数据的参考,需要确认后再执行这些 SQL 修复数据。 +--- + +# sync-diff-inspector 用户文档 + +[sync-diff-inspector](https://github.com/pingcap/tidb-tools/tree/master/sync_diff_inspector) 是一个用于校验 MySQL/TiDB 中两份数据是否一致的工具。该工具提供了修复数据的功能(适用于修复少量不一致的数据)。 + +主要功能: + +* 对比表结构和数据 +* 如果数据不一致,则生成用于修复数据的 SQL 语句 +* 支持[不同库名或表名的数据校验](/sync-diff-inspector/route-diff.md) +* 支持[分库分表场景下的数据校验](/sync-diff-inspector/shard-diff.md) +* 支持 [TiDB 主从集群的数据校验](/ticdc/ticdc-upstream-downstream-check.md) +* 支持[从 TiDB DM 拉取配置的数据校验](/sync-diff-inspector/dm-diff.md) + +你可通过以下方式下载 sync-diff-inspector: + ++ Binary 包。sync-diff-inspector 的安装包位于 TiDB 离线工具包中。下载方式,请参考 [TiDB 工具下载](/download-ecosystem-tools.md)。 ++ Docker 镜像。执行以下命令进行下载: + + ```shell + docker pull pingcap/tidb-tools:latest + ``` + +## sync-diff-inspector 的使用限制 + +* 对于 MySQL 和 TiDB 之间的数据同步不支持在线校验,需要保证上下游校验的表中没有数据写入,或者保证某个范围内的数据不再变更,通过配置 `range` 来校验这个范围内的数据。 + +* FLOAT、DOUBLE 等浮点数类型在 TiDB 和 MySQL 中的实现方式不同,在计算 checksum 时会分别取 6 位和 15 位有效数字。如果不使用该特性,需要设置 `ignore-columns` 忽略这些列的检查。 + +* 支持对不包含主键或者唯一索引的表进行校验,但是如果数据不一致,生成的用于修复的 SQL 可能无法正确修复数据。 + +## sync-diff-inspector 所需的数据库权限 + +sync-diff-inspector 需要获取表结构信息、查询数据,需要的数据库权限如下: + +- 上游数据库 + + - SELECT(查数据进行对比) + + - SHOW_DATABASES(查看库名) + + - RELOAD(查看表结构) + +- 下游数据库 + + - SELECT(查数据进行对比) + + - SHOW_DATABASES(查看库名) + + - RELOAD(查看表结构) + +## 配置文件说明 + +sync-diff-inspector 的配置总共分为五个部分: + +- Global config:通用配置,包括校验的线程数量、是否输出修复 SQL、是否比对数据、是否跳过校验上游或下游不存在的表等。 +- Datasource config:配置上下游数据库实例。 +- Routes:上游多表名通过正则匹配下游单表名的规则。**(可选)** +- Task config:配置校验哪些表,如果有的表在上下游有一定的映射关系或者有一些特殊要求,则需要对指定的表进行配置。 +- Table config:对具体表的特殊配置,例如指定范围、忽略的列等等。**(可选)** + +下面是一个完整配置文件的说明: + +- 提示:配置名后带 `s` 的配置项允许拥有多个配置值,因此需要使用方括号 `[]` 来包含配置值。 + +```toml +# Diff Configuration. + +######################### Global config ######################### + +# 检查数据的线程数量,上下游数据库的连接数会略大于该值 +check-thread-count = 4 + +# 如果开启,若表存在不一致,则输出用于修复的 SQL 语句。 +export-fix-sql = true + +# 只对比表结构而不对比数据 +check-struct-only = false + +# 如果开启,会跳过校验上游或下游不存在的表。 +skip-non-existing-table = false + +######################### Datasource config ######################### +[data-sources] +[data-sources.mysql1] # mysql1 是该数据库实例唯一标识的自定义 id,用于下面 task.source-instances/task.target-instance 中 + host = "127.0.0.1" + port = 3306 + user = "root" + password = "" # 设置连接上游数据库的密码,可为明文或 Base64 编码。 + + #(可选)使用映射规则来匹配上游多个分表,其中 rule1 和 rule2 在下面 Routes 配置栏中定义 + route-rules = ["rule1", "rule2"] + +[data-sources.tidb0] + host = "127.0.0.1" + port = 4000 + user = "root" + password = "" # 设置连接下游数据库的密码,可为明文或 Base64 编码。 + + #(可选)使用 TLS 连接 TiDB + # security.ca-path = ".../ca.crt" + # security.cert-path = ".../cert.crt" + # security.key-path = ".../key.crt" + + #(可选)使用 TiDB 的 snapshot 功能,如果开启的话会使用历史数据进行对比 + # snapshot = "386902609362944000" + # 当 snapshot 设置为 "auto" 时,使用 TiCDC 在上下游的同步时间点,具体参考 + # snapshot = "auto" + +########################### Routes ########################### +# 如果需要对比大量的不同库名或者表名的表的数据,或者用于校验上游多个分表与下游总表的数据,可以通过 table-rule 来设置映射关系 +# 可以只配置 schema 或者 table 的映射关系,也可以都配置 +[routes] +[routes.rule1] # rule1 是该配置的唯一标识的自定义 id,用于上面 data-sources.route-rules 中 +schema-pattern = "test_*" # 匹配数据源的库名,支持通配符 "*" 和 "?" +table-pattern = "t_*" # 匹配数据源的表名,支持通配符 "*" 和 "?" +target-schema = "test" # 目标库名 +target-table = "t" # 目标表名 + +[routes.rule2] +schema-pattern = "test2_*" # 匹配数据源的库名,支持通配符 "*" 和 "?" +table-pattern = "t2_*" # 匹配数据源的表名,支持通配符 "*" 和 "?" +target-schema = "test2" # 目标库名 +target-table = "t2" # 目标表名 + +######################### Task config ######################### +# 配置需要对比的*目标数据库*中的表 +[task] + # output-dir 会保存如下信息 + # 1 sql:检查出错误后生成的修复 SQL 文件,并且一个 chunk 对应一个文件 + # 2 log:sync-diff.log 保存日志信息 + # 3 summary:summary.txt 保存总结 + # 4 checkpoint:a dir 保存断点续传信息 + output-dir = "./output" + + # 上游数据库,内容是 data-sources 声明的唯一标识 id + source-instances = ["mysql1"] + + # 下游数据库,内容是 data-sources 声明的唯一标识 id + target-instance = "tidb0" + + # 需要比对的下游数据库的表,每个表需要包含数据库名和表名,两者由 `.` 隔开 + # 使用 ? 来匹配任意一个字符;使用 * 来匹配任意;详细匹配规则参考 golang regexp pkg: https://github.com/google/re2/wiki/Syntax + target-check-tables = ["schema*.table*", "!c.*", "test2.t2"] + + #(可选)对部分表的额外配置,其中 config1 在下面 Table config 配置栏中定义 + target-configs = ["config1"] + +######################### Table config ######################### +# 对部分表进行特殊的配置,配置的表必须包含在 task.target-check-tables 中 +[table-configs.config1] # config1 是该配置的唯一标识自定义 id,用于上面 task.target-configs 中 +# 目标表名称,可以使用正则来匹配多个表,但不允许存在一个表同时被多个特殊配置匹配。 +target-tables = ["schema*.test*", "test2.t2"] +#(可选)指定检查的数据的范围,需要符合 sql 中 where 条件的语法 +range = "age > 10 AND age < 20" +#(可选)指定用于划分 chunk 的列,如果不配置该项,sync-diff-inspector 会选取一些合适的列(主键/唯一键/索引) +index-fields = ["col1","col2"] +#(可选)忽略某些列的检查,例如 sync-diff-inspector 目前还不支持的一些类型(json,bit,blob 等), +# 或者是浮点类型数据在 TiDB 和 MySQL 中的表现可能存在差异,可以使用 ignore-columns 忽略检查这些列 +ignore-columns = ["",""] +#(可选)指定划分该表的 chunk 的大小,若不指定可以删去或者将其配置为 0。 +chunk-size = 0 +#(可选)指定该表的 collation,若不指定可以删去或者将其配置为空字符串。 +collation = "" + +``` + +## 运行 sync-diff-inspector + +执行如下命令: + +```bash +./sync_diff_inspector --config=./config.toml +``` + +该命令最终会在 `config.toml` 中的 `output-dir` 输出目录输出本次比对的检查报告 `summary.txt` 和日志 `sync_diff.log`。在输出目录下还会生成由 `config.toml` 文件内容哈希值命名的文件夹,该文件夹下包括断点续传 checkpoint 结点信息以及数据存在不一致时生成的 SQL 修复数据。 + +### 前台输出 + +sync-diff-inspector 在执行过程中会往 `stdout` 发送进度信息。进度信息包括表的结构比较结果、表的数据比较结果以及进度条。 + +> **注意:** +> +> 为了达成显示效果,请保持显示窗口宽度在 80 字符以上。 + +```progress +A total of 2 tables need to be compared + +Comparing the table structure of ``sbtest`.`sbtest96`` ... equivalent +Comparing the table structure of ``sbtest`.`sbtest99`` ... equivalent +Comparing the table data of ``sbtest`.`sbtest96`` ... failure +Comparing the table data of ``sbtest`.`sbtest99`` ... +_____________________________________________________________________________ +Progress [==========================================================>--] 98% 193/200 +``` + +```progress +A total of 2 tables need to be compared + +Comparing the table structure of ``sbtest`.`sbtest96`` ... equivalent +Comparing the table structure of ``sbtest`.`sbtest99`` ... equivalent +Comparing the table data of ``sbtest`.`sbtest96`` ... failure +Comparing the table data of ``sbtest`.`sbtest99`` ... failure +_____________________________________________________________________________ +Progress [============================================================>] 100% 0/0 +The data of `sbtest`.`sbtest99` is not equal +The data of `sbtest`.`sbtest96` is not equal + +The rest of tables are all equal. + +A total of 2 tables have been compared, 0 tables finished, 2 tables failed, 0 tables skipped. +The patch file has been generated in + 'output/fix-on-tidb2/' +You can view the comparison details through 'output/sync_diff.log' +``` + +### 输出文件 + +输出文件目录结构如下: + +``` +output/ +|-- checkpoint # 保存断点续传信息 +| |-- bbfec8cc8d1f58a5800e63aa73e5 # config hash 占位文件,标识该输出目录(output/)对应的配置文件 +│ |-- DO_NOT_EDIT_THIS_DIR +│ └-- sync_diff_checkpoints.pb # 断点续传信息 +| +|-- fix-on-target # 保存用于修复不一致的 SQL 文件 +| |-- xxx.sql +| |-- xxx.sql +| └-- xxx.sql +| +|-- summary.txt # 保存校验结果的总结 +└-- sync_diff.log # 保存 sync-diff-inspector 执行过程中输出的日志信息 +``` + +#### 日志 + +sync-diff-inspector 的日志存放在 `${output}/sync_diff.log` 中,其中 `${output}` 是 `config.toml` 文件中 `output-dir` 的值。 + +#### 校验进度 + +sync-diff-inspector 会在运行时定期(间隔 10s)输出校验进度到 checkpoint 中(位于 `${output}/checkpoint/sync_diff_checkpoints.pb` 中,其中 `${output}` 是 `config.toml` 文件中 `output-dir` 的值。 + +#### 校验结果 + +当校验结束时,sync-diff-inspector 会输出一份校验报告,位于 `${output}/summary.txt` 中,其中 `${output}` 是 `config.toml` 文件中 `output-dir` 的值。 + +```summary ++---------------------+---------+--------------------+----------------+---------+-----------+ +| TABLE | RESULT | STRUCTURE EQUALITY | DATA DIFF ROWS | UPCOUNT | DOWNCOUNT | ++---------------------+---------+--------------------+----------------+---------+-----------+ +| `sbtest`.`sbtest99` | succeed | true | +97/-97 | 999999 | 999999 | +| `sbtest`.`sbtest96` | succeed | true | +0/-101 | 999999 | 1000100 | +| `sbtest`.`sbtest97` | skipped | false | +999999/-0 | 999999 | 0 | ++---------------------+---------+--------------------+----------------+---------+-----------+ +Time Cost: 16.75370462s +Average Speed: 113.277149MB/s +``` + +- `TABLE`:该列表示对应的数据库及表名 +- `RESULT`:校验是否完成。如果设置了 `skip-non-existing-table = true`,对于上游或下游不存在的表,该列的值将为 `skipped` +- `STRUCTURE EQUALITY`:表结构是否相同 +- `DATA DIFF ROWS`:即 `rowAdd`/`rowDelete`,表示该表修复需要增加/删除的行数 + +#### SQL 修复 + +校验过程中遇到不同的行,会生成修复数据的 SQL 语句。一个 chunk 如果出现数据不一致,就会生成一个以 `chunk.Index` 命名的 SQL 文件。文件位于 `${output}/fix-on-${instance}` 文件夹下。其中 `${instance}` 为 `config.toml` 中 `task.target-instance` 的值。 + +一个 SQL 文件会包含该 chunk 的所属表以及表示的范围信息。对每个修复 SQL 语句,有三种情况: + +- 下游数据库缺失行,则是 REPLACE 语句 +- 下游数据库冗余行,则是 DELETE 语句 +- 下游数据库行部分数据不一致,则是 REPLACE 语句,但会在 SQL 文件中通过注释的方法标明不同的列 + +```SQL +-- table: sbtest.sbtest99 +-- range in sequence: (3690708) < (id) <= (3720581) +/* + DIFF COLUMNS ╏ `K` ╏ `C` ╏ `PAD` +╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╋╍╍╍╍╍╍╍╍╍╋╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╋╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍ + source data ╏ 2501808 ╏ 'hello' ╏ 'world' +╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╋╍╍╍╍╍╍╍╍╍╋╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╋╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍ + target data ╏ 5003616 ╏ '0709824117-9809973320-4456050422' ╏ '1714066100-7057807621-1425865505' +╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╋╍╍╍╍╍╍╍╍╍╋╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╋╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍ +*/ +REPLACE INTO `sbtest`.`sbtest99`(`id`,`k`,`c`,`pad`) VALUES (3700000,2501808,'hello','world'); +``` + +## 注意事项 + +* sync-diff-inspector 在校验数据时会消耗一定的服务器资源,需要避免在业务高峰期间校验。 +* 在数据对比前,需要注意表中的 collation 设置。如果表的主键或唯一键为 varchar 类型,且上下游数据库中 collation 设置不同,可能会因为排序问题导致最终校验结果不正确,需要在 sync-diff-inspector 的配置文件中增加 collation 设置。 +* sync-diff-inspector 会优先使用 TiDB 的统计信息来划分 chunk,需要尽量保证统计信息精确,可以在**业务空闲期**手动执行 `analyze table {table_name}`。 +* table-rule 的规则需要特殊注意,例如设置了 `schema-pattern="test1"`,`table-pattern = "t_1"`,`target-schema="test2"`,`target-table = "t_2"`,会对比 source 中的表 `test1`.`t_1` 和 target 中的表 `test2`.`t_2`。sync-diff-inspector 默认开启 sharding,如果 source 中还有表 `test2`.`t_2`,则会把 source 端的表 `test1`.`t_1` 和表 `test2`.`t_2` 作为 sharding 与 target 中的表 `test2`.`t_2` 进行一致性校验。 +* 生成的 SQL 文件仅作为修复数据的参考,需要确认后再执行这些 SQL 修复数据。 diff --git a/markdown-pages/zh/tidb/master/ticdc/ticdc-overview.md b/markdown-pages/zh/tidb/master/ticdc/ticdc-overview.md new file mode 100644 index 0000000..4bd69d9 --- /dev/null +++ b/markdown-pages/zh/tidb/master/ticdc/ticdc-overview.md @@ -0,0 +1,87 @@ +--- +title: TiCDC 简介 +aliases: ['/docs-cn/dev/ticdc/ticdc-overview/','/docs-cn/dev/reference/tools/ticdc/overview/'] +summary: TiCDC 是一款 TiDB 增量数据同步工具,适用于多 TiDB 集群的高可用和容灾方案,以及实时同步变更数据到异构系统。其主要特性包括数据容灾复制、双向复制、低延迟的增量数据同步能力等。TiCDC 架构包括 TiKV Server、TiCDC 和 PD,支持将数据同步到 TiDB、MySQL 数据库、Kafka 以及存储服务。目前暂不支持单独使用 RawKV 的 TiKV 集群,创建 SEQUENCE 的 DDL 操作和在同步过程中对 TiCDC 正在同步的表和库进行 BR 数据恢复和 TiDB Lightning 导入。 +--- + +# TiCDC 简介 + +[TiCDC](https://github.com/pingcap/tiflow/tree/master/cdc) 是一款 TiDB 增量数据同步工具,通过拉取上游 TiKV 的数据变更日志,TiCDC 可以将数据解析为有序的行级变更数据输出到下游。 + +## TiCDC 适用场景 + +TiCDC 适用于以下场景: + +- 提供多 TiDB 集群,跨区域数据高可用和容灾方案,保证在灾难发生时保证主备集群数据的最终一致性。 +- 提供同步实时变更数据到异构系统的服务,为监控、缓存、全文索引、数据分析、异构数据库使用等场景提供数据源。 + +## TiCDC 主要特性 + +### 核心能力 + +TiCDC 提供了以下核心能力: + +- 提供 TiDB -> TiDB 之间数据容灾复制的能力,实现秒级别 RPO 和分钟级别 RTO +- 提供 TiDB 之间双向复制的能力,支持通过 TiCDC 构建多写多活的 TiDB 集群 +- 提供 TiDB -> MySQL(或其他兼容 MySQL 协议的数据库)的低延迟的增量数据同步能力 +- 提供 TiDB -> Kafka 增量数据同步能力,推荐的数据格式包含 [Canal-JSON](/ticdc/ticdc-canal-json.md),[Avro](/ticdc/ticdc-avro-protocol.md),[Debezium](/ticdc/ticdc-debezium.md) 等 +- 提供 TiDB -> 存储服务(如:Amazon S3、GCS、Azure Blob Storage 和 NFS)增量数据同步能力 +- 提供表级别数据同步能力,支持同步过程中过滤数据库、表、DML、DDL 的能力 +- 高可用架构,无单点故障;支持动态添加、删除 TiCDC 节点 +- 支持通过 [Open API](/ticdc/ticdc-open-api-v2.md) 进行集群管理,包括查询任务状态;动态修改任务配置;动态创建、删除任务等 + +### 数据同步顺序性 + +- TiCDC 对于所有的 DDL/DML 都能对外输出**至少一次**。 +- TiCDC 在 TiKV/TiCDC 集群故障期间可能会重复发相同的 DDL/DML。对于重复的 DDL/DML: + - MySQL sink 可以重复执行 DDL,对于在下游可重入的 DDL(譬如 `TRUNCATE TABLE`)直接执行成功;对于在下游不可重入的 DDL(譬如 `CREATE TABLE`),执行失败,TiCDC 会忽略错误继续同步。 + - Kafka sink 提供不同的数据分发策略: + - 可以按照表、主键或 ts 等策略分发数据到不同 Kafka partition。使用表、主键分发策略,可以保证某一行的更新数据被顺序的发送到相同 partition。 + - 对所有的分发策略,TiCDC 都会定期发送 Resolved TS 消息到所有的 topic/partition,表示早于该 Resolved TS 的消息都已经发送到 topic/partition,消费程序可以利用 Resolved TS 对多个 topic/partition 的消息进行排序。 + - Kafka sink 会发送重复的消息,但重复消息不会破坏 Resolved TS 的约束,比如在 changefeed 暂停重启后,可能会按顺序发送 msg1、msg2、msg3、msg2、msg3。你可以在 Kafka 消费端进行过滤。 + +### 数据同步一致性 + +- MySQL sink + + - TiCDC 开启 redo log 后保证数据复制的最终一致性 + - TiCDC **保证**单行的更新与上游更新顺序一致。 + - TiCDC **不保证**下游事务的执行顺序和上游完全一致。 + +> **注意:** +> +> 从 v6.2 版本起,你可以通过配置 sink URI 参数 [`transaction-atomicity`](/ticdc/ticdc-sink-to-mysql.md#sink-uri-配置-mysqltidb) 来控制 TiCDC 是否拆分单表事务。拆分事务可以大幅降低 MySQL sink 同步大事务的延时和内存消耗。 + +## TiCDC 架构 + +TiCDC 作为 TiDB 的增量数据同步工具,通过 PD 内部的 etcd 实现高可用,通过多个 TiCDC 进程获取 TiKV 节点上的数据改变,在内部进行排序、合并等处理之后,通过多个同步任务 (Changefeed),同时向多个下游系统进行数据同步。 + +![TiCDC architecture](/media/ticdc/cdc-architecture.png) + +在以上架构图中: + +- TiKV Server:代表 TiDB 集群中的 TiKV 节点,当数据发生改变时 TiKV 节点会主动将发生的数据改变以变更日志(KV change logs,简称 change logs)的方式发送给 TiCDC 节点。当然,当 TiCDC 节点发现收到的 change logs 并不是连续的,也会主动发起请求,获得需要的 change logs。 +- TiCDC:代表运行了运行 TiCDC 进程的各个节点。每个节点都运行一个 TiCDC 进程,每个进程会从 TiKV 节点中拉取一个或者多个表中的数据改变,并通过 Sink 模块同步到下游系统。 +- PD:代表 TiDB 集群中的调度模块,负责集群数据的事实调度,这个模块通常是由 3 个 PD 节点构成的,内部通过 etcd 集群来实现选举等高可用相关的能力。 TiCDC 集群使用了 PD 集群内置的 etcd 集群来保存自己的元数据信息,例如:节点的状态信息,changefeed 配置信息等。 + +另外,从上面的架构图中也可以看到,目前 TiCDC 支持将数据同步到 TiDB、MySQL 数据库、Kafka 以及存储服务等。 + +## 最佳实践 + +- 使用 TiCDC 在两个 TiDB 集群间同步数据时,如果上下游的延迟超过 100 ms: + - 对于 v6.5.2 之前的版本,推荐将 TiCDC 部署在下游 TiDB 集群所在的区域 (IDC, region) + - 经过优化后,对于 v6.5.2 及之后的版本,推荐将 TiCDC 部署在上游集群所在的区域 (IDC, region)。 +- TiCDC 同步的表需要至少存在一个**有效索引**的表,**有效索引**的定义如下: + + - 主键 (`PRIMARY KEY`) 为有效索引。 + - 唯一索引 (`UNIQUE INDEX`) 中每一列在表结构中明确定义非空 (`NOT NULL`) 且不存在虚拟生成列 (`VIRTUAL GENERATED COLUMNS`)。 + +- 在使用 TiCDC 实现容灾的场景下,为实现最终一致性,需要配置 [redo log](/ticdc/ticdc-sink-to-mysql.md#灾难场景的最终一致性复制) 并确保 redo log 写入的存储系统在上游发生灾难时可以正常读取。 + +### 暂不支持的场景 + +目前 TiCDC 暂不支持的场景如下: + +- 暂不支持单独使用 RawKV 的 TiKV 集群。 +- 暂不支持在 TiDB 中[创建 SEQUENCE 的 DDL 操作](/sql-statements/sql-statement-create-sequence.md)和 [SEQUENCE 函数](/sql-statements/sql-statement-create-sequence.md#sequence-函数)。在上游 TiDB 使用 SEQUENCE 时,TiCDC 将会忽略掉上游执行的 SEQUENCE DDL 操作/函数,但是使用 SEQUENCE 函数的 DML 操作可以正确地同步。 +- 暂不支持在同步的过程中对 TiCDC 正在同步的表和库进行 [BR 数据恢复](/br/backup-and-restore-overview.md) 和 [TiDB Lightning](/tidb-lightning/tidb-lightning-overview.md) 导入。详情请参考[为什么在上游使用了 TiDB Lightning 和 BR 恢复了数据之后,TiCDC 同步会出现卡顿甚至卡住](/ticdc/ticdc-faq.md#为什么在上游使用了-tidb-lightning-和-br-恢复了数据之后ticdc-同步会出现卡顿甚至卡住)。 \ No newline at end of file diff --git a/markdown-pages/zh/tidb/master/ticdc/ticdc-upstream-downstream-check.md b/markdown-pages/zh/tidb/master/ticdc/ticdc-upstream-downstream-check.md new file mode 100644 index 0000000..7980f04 --- /dev/null +++ b/markdown-pages/zh/tidb/master/ticdc/ticdc-upstream-downstream-check.md @@ -0,0 +1,104 @@ +--- +title: 主从集群一致性读和数据校验 +aliases: ['/docs-cn/dev/sync-diff-inspector/upstream-downstream-diff/','/docs-cn/dev/reference/tools/sync-diff-inspector/tidb-diff/', '/zh/tidb/dev/upstream-downstream-diff'] +summary: TiCDC 提供了 Syncpoint 功能,通过利用 TiDB 的 snapshot 特性,在同步过程中维护了一个上下游具有一致性 snapshot 的 `ts-map`。启用 Syncpoint 功能后,可以进行一致性快照读和数据一致性校验。要开启 Syncpoint 功能,只需在创建同步任务时把 TiCDC 的配置项 `enable-sync-point` 设置为 `true`。通过配置 `snapshot` 可以对 TiDB 主从集群的数据进行校验。 +--- + +# TiDB 主从集群数据校验和快照读 + +当你使用 TiCDC 搭建 TiDB 的主从集群时,可能会需要在不停止同步的情况下对上下游进行一致性的快照读或者对数据进行一致性验证。在普通的同步模式中,TiCDC 只提供数据的最终一致性的保证,而无法确保在同步的过程中数据的一致性。因此,对动态变更的数据进行一致性读非常困难,为了满足这一需求,TiCDC 提供了 Syncpoint 功能。 + +Syncpoint 通过利用 TiDB 提供的 snapshot 特性,让 TiCDC 在同步过程中维护了一个上下游具有一致性 snapshot 的 `ts-map`。把校验动态数据的一致性问题转化为了校验静态 snapshot 数据的一致性问题,达到了接近数据一致性实时校验的效果。 + +## 启用 Syncpoint + +启用 Syncpoint 功能后,你可以使用[一致性快照读](#一致性快照读)和[数据一致性校验](#数据一致性校验)。 + +要开启 Syncpoint 功能,只需在创建同步任务时把 TiCDC 的配置项 `enable-sync-point` 设置为 `true`。开启 Syncpoint 功能后,TiCDC 会向下游 TiDB 集群写入如下信息: + +1. 在数据的同步过程中,TiCDC 会定期(使用 `sync-point-interval` 参数配置)对齐上下游的快照,并将上下游的 TSO 的对应关系保存在下游的 `tidb_cdc.syncpoint_v1` 表中。 + +2. 同步过程中,TiCDC 还会定期(使用 `sync-point-interval` 参数配置)通过执行 `SET GLOBAL tidb_external_ts = @@tidb_current_ts` ,在备用集群中设置已复制完成的一致性快照点。 + +以下是 TiCDC 配置示例,用于在创建同步任务时启用 Syncpoint 功能: + +```toml +# 开启 SyncPoint +enable-sync-point = true + +# 每隔 5 分钟对齐一次上下游的 snapshot +sync-point-interval = "5m" + +# 每隔 1 小时清理一次下游 tidb_cdc.syncpoint_v1 表中的 ts-map 数据 +sync-point-retention = "1h" +``` + +## 一致性快照读 + +> **注意:** +> +> 使用一致性快照读之前,请先[启用 TiCDC 的 Syncpoint 功能](#启用-syncpoint)。如果多个同步任务使用同一个下游 TiDB 集群且都开启了 Syncpoint 功能,那么这些同步任务都将根据各自的同步进度来更新 `tidb_external_ts` 和 `ts-map`。此时,你需要使用读取 `ts-map` 表中记录的方式来设置同步任务级别的一致性快照读,同时应避免下游应用程序使用 `tidb_enable_external_ts_read` 的方式读数据,因为多个同步任务之间可能存在互相干扰导致无法获得一致性的结果。 + +当你需要从备用集群查询数据的时候,在业务应用中设置 `SET GLOBAL|SESSION tidb_enable_external_ts_read = ON;` 就可以在备用集群上获得事务状态完成的数据。 + +除此之外,你也可以通过查询 `ts-map` 的方式选取之前的时间点进行快照读。 + +## 数据一致性校验 + +> **注意:** +> +> 使用数据一致性校验之前,请先[启用 TiCDC 的 Syncpoint 功能](#启用-syncpoint)。 + +你只需要在 sync-diff-inspector 中配置 `snapshot` 即可对 TiDB 主从集群的数据进行校验。 + +### 获取 ts-map + +在下游 TiDB 中执行以下 SQL 语句,从结果中可以获取上游 TSO (primary_ts) 和下游 TSO (secondary_ts) 信息。 + +```sql +select * from tidb_cdc.syncpoint_v1; +``` + +``` ++------------------+----------------+--------------------+--------------------+---------------------+ +| ticdc_cluster_id | changefeed | primary_ts | secondary_ts | created_at | ++------------------+----------------+--------------------+--------------------+---------------------+ +| default | test-2 | 435953225454059520 | 435953235516456963 | 2022-09-13 08:40:15 | ++------------------+----------------+--------------------+--------------------+---------------------+ +``` + +以上 `syncpoint_v1` 表中各列所代表的信息如下: + +- `ticdc_cluster_id`:插入该条记录的 TiCDC 集群的 ID。 +- `changefeed`:插入该条记录的 Changefeed 的 ID。由于不同的 TiCDC 集群可能会存在重名的 Changefeed,所以需要通过 TiCDC 集群 ID 和 Changefeed 的 ID 来确认一个 Changefeed 所插入的 `ts-map`。 +- `primary_ts`:上游数据库 snapshot 的时间戳。 +- `secondary_ts`:下游数据库 snapshot 的时间戳。 +- `created_at`:插入该条记录的时间。 + +### 配置 snapshot + +使用上一步骤获取的 ts-map 信息来配置上下游数据库的 snapshot 信息。其中的 `Datasource config` 部分示例配置如下: + +```toml +######################### Datasource config ######################## +[data-sources.uptidb] + host = "172.16.0.1" + port = 4000 + user = "root" + password = "" + snapshot = "435953225454059520" + +[data-sources.downtidb] + host = "172.16.0.2" + port = 4000 + user = "root" + password = "" + snapshot = "435953235516456963" +``` + +## 注意事项 + +- TiCDC 在创建 Changefeed 前,请确保 TiCDC 的配置项 `enable-sync-point` 已设置为 `true`,这样才会开启 Syncpoint 功能,在下游保存 `ts-map`。完整的配置请参考 [TiCDC 同步任务配置文件描述](/ticdc/ticdc-changefeed-config.md)。 +- 在使用 Syncpoint 功能进行数据校验时,需要调整 TiKV 的 GC 时间,保证在校验时 snapshot 对应的历史数据不会被执行 GC。建议调整为 1 个小时,在校验后再还原 GC 设置。 +- 以上配置只展示了 `Datasource config` 部分,完整配置请参考 [sync-diff-inspector 用户文档](/sync-diff-inspector/sync-diff-inspector-overview.md)。 +- 从 v6.4.0 开始,TiCDC 使用 Syncpoint 功能需要同步任务拥有下游集群的 `SYSTEM_VARIABLES_ADMIN` 或者 `SUPER` 权限。 diff --git a/markdown-pages/zh/tidb/master/tidb-binlog/bidirectional-replication-between-tidb-clusters.md b/markdown-pages/zh/tidb/master/tidb-binlog/bidirectional-replication-between-tidb-clusters.md new file mode 100644 index 0000000..cad7a3e --- /dev/null +++ b/markdown-pages/zh/tidb/master/tidb-binlog/bidirectional-replication-between-tidb-clusters.md @@ -0,0 +1,121 @@ +--- +title: 集群间双向同步 +aliases: ['/docs-cn/dev/tidb-binlog/bidirectional-replication-between-tidb-clusters/','/docs-cn/dev/reference/tidb-binlog/bidirectional-replication/','/docs-cn/dev/reference/tidb-binlog/bi-repl/'] +summary: 本文介绍了如何使用 TiDB Binlog 实现集群间双向同步,包括使用场景、实现原理、标识表、同步 DDL 和配置开启双向同步。双向同步需保证数据写入两个集群不会发生冲突,且 DDL 操作采用单向同步。配置上需要设置相同的 channel-id,并在下游配置 sync-ddl 为 false。TiDB Binlog 在未来版本中将被废弃,建议使用 TiCDC 作为数据同步的替代方案。 +--- + +# 集群间双向同步 + +> **警告:** +> +> - 目前双向同步属于实验特性,尚未经过完备的测试,不建议在生产环境中使用该功能。 +> - TiDB Binlog 与 TiDB v5.0 开始引入的一些特性不兼容,无法一起使用,详情参照[注意事项](/tidb-binlog/tidb-binlog-overview.md#注意事项)。 +> - 从 TiDB v7.5.0 开始,TiDB Binlog 组件的数据同步功能不再提供技术支持,强烈建议使用 [TiCDC](/ticdc/ticdc-overview.md) 作为数据同步的替代方案。 +> - 尽管 TiDB v7.5.0 仍支持 TiDB Binlog 组件的实时备份和恢复,但该组件在未来版本中将被完全废弃,推荐使用 [PITR](/br/br-pitr-guide.md) 作为数据恢复的替代方案。 + +本文档介绍如何将一个 TiDB 集群的数据双向同步到另一个 TiDB 集群、双向同步的实现原理、如何开启双向同步、以及如何同步 DDL 操作。 + +## 使用场景 + +当用户需要在两个 TiDB 集群之间双向同步数据时,可使用 TiDB Binlog 进行操作。例如要将集群 A 的数据同步到集群 B,而且要将集群 B 的数据同步到集群 A。 + +> **注意:** +> +> 集群间双向同步的前提条件是,写入两个集群的数据必须保证无冲突,即在两个集群中,不会同时修改同一张表的同一主键和具有唯一索引的行。 + +使用场景示例图如下: + +![使用场景示例图](/media/binlog/bi-repl1.jpg) + +## 实现原理 + +![原理示例图](/media/binlog/bi-repl2.png) + +在 A 和 B 两个集群间开启双向同步,则写入集群 A 的数据会同步到集群 B 中,然后这部分数据又会继续同步到集群 A,这样就会出现无限循环同步的情况。如上图所示,在同步数据的过程中 Drainer 对 binlog 加上标记,通过过滤掉有标记的 binlog 来避免循环同步。详细的实现流程如下: + +1. 为两个集群分别启动 TiDB Binlog 同步程序。 +2. 待同步的事务经过 A 的 Drainer 时,Drainer 为事务加入 [`_drainer_repl_mark` 标识表](#标识表),并在表中写入本次 DML event 更新,将事务同步至集群 B。 +3. 集群 B 向集群 A 返回带有 `_drainer_repl_mark` 标识表的 binlog event。集群 B 的 Drainer 在解析该 binlog event 时发现带有 DML event 的标识表,放弃同步该 binlog event 到集群 A。 + +将集群 B 中的数据同步到集群 A 的流程与以上流程相同,两个集群可以互为上下游。 + +> **注意:** +> +> * 更新 `_drainer_repl_mark` 标识表时,一定要有数据改动才会产生 binlog。 +> * DDL 操作没有事务概念,因此采取单向同步的方案,见[同步 DDL](#同步-ddl)。 + +Drainer 与下游的每个连接可以使用一个 ID 以避免冲突。`channel_id` 用来表示进行双向同步的一个通道。A 和 B 两个集群进行双向同步的配置应使用相同的值。 + +当有添加或者删除列时,要同步到下游的数据可能会出现多列或者少列的情况。Drainer 通过添加配置来允许这种情况,会忽略多了的列值或者给少了的列写入默认值。 + +## 标识表 + +`_drainer_repl_mark` 标识表的结构如下: + +```sql +CREATE TABLE `_drainer_repl_mark` ( + `id` bigint(20) NOT NULL, + `channel_id` bigint(20) NOT NULL DEFAULT '0', + `val` bigint(20) DEFAULT '0', + `channel_info` varchar(64) DEFAULT NULL, + PRIMARY KEY (`id`,`channel_id`) +); +``` + +Drainer 使用如下 SQL 语句更新 `_drainer_repl_mark` 可保证数据改动,从而保证产生 binlog: + +```sql +update drainer_repl_mark set val = val + 1 where id = ? && channel_id = ?; +``` + +## 同步 DDL + +因为 Drainer 无法为 DDL 操作加入标识表,所以采用单向同步的方式来同步 DDL 操作。 + +比如集群 A 到集群 B 开启了 DDL 同步,则集群 B 到集群 A 会关闭 DDL 同步。即 DDL 操作全部在 A 上执行。 + +> **注意:** +> +> DDL 操作无法在两个集群上同时执行。执行 DDL 时,若同时有 DML 操作或者 DML binlog 没同步完,会可能出现 DML 同步的上下游表结构不一致的情况。 + +## 配置并开启双向同步 + +若要在集群 A 和集群 B 间进行双向同步,假设统一在集群 A 上执行 DDL。在集群 A 到集群 B 的同步路径上,向 Drainer 添加以下配置: + +```toml +[syncer] +loopback-control = true +channel-id = 1 # 互相同步的两个集群配置相同的 ID。 +sync-ddl = true # 需要同步 DDL 操作 + +[syncer.to] +# 1 表示 SyncFullColumn,2 表示 SyncPartialColumn。 +# 若设为 SyncPartialColumn,Drainer 会允许下游表结构比当前要同步的数据多或者少列 +# 并且去掉 SQL mode 的 STRICT_TRANS_TABLES,来允许少列的情况,并插入零值到下游。 +sync-mode = 2 + +# 忽略 checkpoint 表。 +[[syncer.ignore-table]] +db-name = "tidb_binlog" +tbl-name = "checkpoint" +``` + +在集群 B 到集群 A 的同步路径上,向 Drainer 添加以下配置: + +```toml +[syncer] +loopback-control = true +channel-id = 1 # 互相同步的两个集群配置相同的 ID。 +sync-ddl = false # 不需要同步 DDL 操作。 + +[syncer.to] +# 1 表示 SyncFullColumn,2 表示 SyncPartialColumn。 +# 若设为 SyncPartialColumn,Drainer 会允许下游表结构比当前要同步的数据多或者少列 +# 并且去掉 SQL mode 的 STRICT_TRANS_TABLES,来允许少列的情况,并插入零值到下游。 +sync-mode = 2 + +# 忽略 checkpoint 表。 +[[syncer.ignore-table]] +db-name = "tidb_binlog" +tbl-name = "checkpoint" +``` diff --git a/markdown-pages/zh/tidb/master/tidb-binlog/binlog-consumer-client.md b/markdown-pages/zh/tidb/master/tidb-binlog/binlog-consumer-client.md new file mode 100644 index 0000000..308d241 --- /dev/null +++ b/markdown-pages/zh/tidb/master/tidb-binlog/binlog-consumer-client.md @@ -0,0 +1,148 @@ +--- +title: Binlog Consumer Client 用户文档 +aliases: ['/zh/tidb/dev/binlog-slave-client','/docs-cn/dev/tidb-binlog/binlog-slave-client/','/docs-cn/dev/reference/tidb-binlog/binlog-slave-client/','/docs-cn/dev/reference/tools/tidb-binlog/binlog-slave-client/'] +summary: Drainer 现在支持将 binlog 数据输出到 Kafka,用户可以根据自定义需求从 Kafka 中读取数据进行处理。用户需要修改 Drainer 配置文件,设置输出为 Kafka,并了解 Drainer 写入到 Kafka 中的数据格式。TiDB-Tools 项目提供了用于读取 Kafka 中 binlog 数据的 Driver,用户可以配置相关信息并以包的形式引用 Driver 的代码来使用。目前仅提供了 golang 版本的 Driver 以及示例代码,如果需要使用其他语言,用户需要自行开发程序读取 Kafka 中的 binlog 数据、解析数据、输出到下游。 +--- + +# Binlog Consumer Client 用户文档 + +目前 Drainer 提供了多种输出方式,包括 MySQL、TiDB、file 等。但是用户往往有一些自定义的需求,比如输出到 Elasticsearch、Hive 等,这些需求 Drainer 现在还没有实现,因此 Drainer 增加了输出到 Kafka 的功能,将 binlog 数据解析后按一定的格式再输出到 Kafka 中,用户编写代码从 Kafka 中读出数据再进行处理。 + +## 配置 Kafka Drainer + +修改 Drainer 的配置文件,设置输出为 Kafka,相关配置如下: + +``` +[syncer] +db-type = "kafka" + +[syncer.to] +# Kafka 地址 +kafka-addrs = "127.0.0.1:9092" +# Kafka 版本号 +kafka-version = "2.4.0" +``` + +## 自定义开发 + +### 数据格式 + +首先需要了解 Drainer 写入到 Kafka 中的数据格式: + +``` +// Column 保存列的数据,针对数据的类型,保存在对应的变量中 +message Column { + // 数据是否为 null + optional bool is_null = 1 [ default = false ]; + // 保存 int 类型的数据 + optional int64 int64_value = 2; + // 保存 uint、enum, set 类型的数据 + optional uint64 uint64_value = 3; + // 保存 float、double 类型的数据 + optional double double_value = 4; + // 保存 bit、blob、binary、json 类型的数据 + optional bytes bytes_value = 5; + // 保存 date、time、decimal、text、char 类型的数据 + optional string string_value = 6; +} + +// ColumnInfo 保存列的信息,包括列名、类型、是否为主键 +message ColumnInfo { + optional string name = 1 [ (gogoproto.nullable) = false ]; + // MySQL 中小写的列字段类型 + // https://dev.mysql.com/doc/refman/8.0/en/data-types.html + // numeric 类型:int bigint smallint tinyint float double decimal bit + // string 类型:text longtext mediumtext char tinytext varchar + // blob longblob mediumblob binary tinyblob varbinary + // enum set + // json 类型:json + optional string mysql_type = 2 [ (gogoproto.nullable) = false ]; + optional bool is_primary_key = 3 [ (gogoproto.nullable) = false ]; +} + +// Row 保存一行的具体数据 +message Row { repeated Column columns = 1; } + +// MutationType 表示 DML 的类型 +enum MutationType { + Insert = 0; + Update = 1; + Delete = 2; +} + +// Table 包含一个表的数据变更 +message Table { + optional string schema_name = 1; + optional string table_name = 2; + repeated ColumnInfo column_info = 3; + repeated TableMutation mutations = 4; +} + +// TableMutation 保存一行数据的变更 +message TableMutation { + required MutationType type = 1; + // 修改后的数据 + required Row row = 2; + // 修改前的数据,只对 Update MutationType 有效 + optional Row change_row = 3; +} + +// DMLData 保存一个事务所有的 DML 造成的数据变更 +message DMLData { + // `tables` 包含事务中所有表的数据变更 + repeated Table tables = 1; +} + +// DDLData 保存 DDL 的信息 +message DDLData { + // 当前使用的数据库 + optional string schema_name = 1; + // 相关表 + optional string table_name = 2; + // `ddl_query` 是原始的 DDL 语句 query + optional bytes ddl_query = 3; +} + +// BinlogType 为 Binlog 的类型,分为 DML 和 DDL +enum BinlogType { + DML = 0; // Has `dml_data` + DDL = 1; // Has `ddl_query` +} + +// Binlog 保存一个事务所有的变更,Kafka 中保存的数据为该结构数据序列化后的结果 +message Binlog { + optional BinlogType type = 1 [ (gogoproto.nullable) = false ]; + optional int64 commit_ts = 2 [ (gogoproto.nullable) = false ]; + optional DMLData dml_data = 3; + optional DDLData ddl_data = 4; +} +``` + +查看数据格式的具体定义,参见 [`secondary_binlog.proto`](https://github.com/pingcap/tidb/blob/master/pkg/tidb-binlog/proto/proto/secondary_binlog.proto)。 + +### Driver + +TiDB-Tools 项目提供了用于读取 Kafka 中 binlog 数据的 Driver,具有如下功能: + +* 读取 Kafka 的数据 +* 根据 commit ts 查找 binlog 在 kafka 中的储存位置 + +使用该 Driver 时,用户需要配置如下信息: + +* KafkaAddr:Kafka 集群的地址 +* CommitTS:从哪个 commit ts 开始读取 binlog +* Offset:从 Kafka 哪个 offset 开始读取,如果设置了 CommitTS 就不用配置该参数 +* ClusterID:TiDB 集群的 cluster ID +* Topic: Kafka Topic 名称,如果 Topic 名称为空,将会使用 drainer `_obinlog` 中的默认名称 + +用户以包的形式引用 Driver 的代码即可使用,可以参考 Driver 中提供的示例代码来学习如何使用 Driver 以及 binlog 数据的解析,目前提供了两个例子: + +* 使用该 Driver 将数据同步到 MySQL,该示例包含将 binlog 转化为 SQL 的具体方法 +* 使用该 Driver 将数据打印出来 + +Driver 项目地址:[Binlog Slave Driver](https://github.com/pingcap/tidb/tree/master/pkg/tidb-binlog/driver)。 + +> **注意:** +> +> - 示例代码仅仅用于示范如何使用 Driver,如果需要用于生产环境需要优化代码。 +> - 目前仅提供了 golang 版本的 Driver 以及示例代码。如果需要使用其他语言,用户需要根据 binlog 的 proto 文件生成相应语言的代码文件,并自行开发程序读取 Kafka 中的 binlog 数据、解析数据、输出到下游。也欢迎用户优化 example 代码,以及提交其他语言的示例代码到 [TiDB-Tools](https://github.com/pingcap/tidb-tools)。 diff --git a/markdown-pages/zh/tidb/master/tidb-binlog/deploy-tidb-binlog.md b/markdown-pages/zh/tidb/master/tidb-binlog/deploy-tidb-binlog.md new file mode 100644 index 0000000..85d4817 --- /dev/null +++ b/markdown-pages/zh/tidb/master/tidb-binlog/deploy-tidb-binlog.md @@ -0,0 +1,360 @@ +--- +title: TiDB Binlog 集群部署 +aliases: ['/docs-cn/dev/tidb-binlog/deploy-tidb-binlog/','/docs-cn/dev/reference/tidb-binlog/deploy/','/docs-cn/dev/how-to/deploy/tidb-binlog/','/docs-cn/dev/reference/tools/tidb-binlog/deploy/'] +summary: TiDB Binlog 集群部署需要满足服务器硬件配置要求。推荐使用 TiUP 部署 TiDB Binlog,也可以使用 Binary 部署。部署过程中需要注意配置参数和启动命令。在运行 TiDB 时,需要保证至少一个 Pump 正常运行。Drainer 不支持对 ignore schemas 的 table 进行 rename DDL 操作。 +--- + +# TiDB Binlog 集群部署 + +## 服务器要求 + +Pump 和 Drainer 均可部署和运行在 Intel x86-64 架构的 64 位通用硬件服务器平台上。在开发、测试和生产环境下,对服务器硬件配置的要求和建议如下: + +| 服务 | 部署数量 | CPU | 磁盘 | 内存 | +| :-------- | :-------- | :--------| :--------------- | :------ | +| Pump | 3 | 8核+ | SSD, 200 GB+ | 16G | +| Drainer | 1 | 8核+ | SAS, 100 GB+ (如果输出 binlog 为本地文件,磁盘大小视保留数据天数而定) | 16G | + +## 使用 TiUP 部署 TiDB Binlog + +推荐使用 TiUP 部署 TiDB Binlog。即在使用 TiUP 部署 TiDB 时,在[拓扑文件](/tidb-binlog-deployment-topology.md)中添加 TiDB Binlog 的 `drainer` 和 `pump` 节点信息后,再随 TiDB 一起部署。详细部署方式参考 [TiUP 部署 TiDB 集群](/production-deployment-using-tiup.md)。 + +## 使用 Binary 部署 TiDB Binlog + +### 下载 TiDB Binlog 安装包 + +TiDB Binlog 安装包位于 TiDB 离线工具包中。下载方式,请参考 [TiDB 工具下载](/download-ecosystem-tools.md)。 + +### 使用样例 + +假设有三个 PD,一个 TiDB,另外有两台机器用于部署 Pump,一台机器用于部署 Drainer。各个节点信息如下: + +``` +TiDB="192.168.0.10" +PD1="192.168.0.16" +PD2="192.168.0.15" +PD3="192.168.0.14" +Pump="192.168.0.11" +Pump="192.168.0.12" +Drainer="192.168.0.13" +``` + +下面以此为例,说明 Pump/Drainer 的使用。 + +1. 使用 binary 部署 Pump + + - Pump 命令行参数说明(以在 “192.168.0.11” 上部署为例) + + ```bash + Usage of Pump: + -L string + 日志输出信息等级设置:debug,info,warn,error,fatal (默认 "info") + -V + 打印版本信息 + -addr string + Pump 提供服务的 RPC 地址(-addr="192.168.0.11:8250") + -advertise-addr string + Pump 对外提供服务的 RPC 地址(-advertise-addr="192.168.0.11:8250") + -config string + 配置文件路径,如果你指定了配置文件,Pump 会首先读取配置文件的配置; + 如果对应的配置在命令行参数里面也存在,Pump 就会使用命令行参数的配置来覆盖配置文件里的配置。 + -data-dir string + Pump 数据存储位置路径 + -gc int + Pump 只保留多少天以内的数据 (默认 7) + -heartbeat-interval int + Pump 向 PD 发送心跳间隔 (单位 秒) + -log-file string + log 文件路径 + -log-rotate string + log 文件切换频率,hour/day + -metrics-addr string + Prometheus Pushgateway 地址,不设置则禁止上报监控信息 + -metrics-interval int + 监控信息上报频率 (默认 15,单位 秒) + -node-id string + Pump 节点的唯一识别 ID,如果不指定,程序会根据主机名和监听端口自动生成 + -pd-urls string + PD 集群节点的地址 (-pd-urls="http://192.168.0.16:2379,http://192.168.0.15:2379,http://192.168.0.14:2379") + -fake-binlog-interval int + Pump 节点生成 fake binlog 的频率 (默认 3,单位 秒) + ``` + + - Pump 配置文件(以在 “192.168.0.11” 上部署为例) + + ```toml + # Pump Configuration + + # Pump 绑定的地址 + addr = "192.168.0.11:8250" + + # Pump 对外提供服务的地址 + advertise-addr = "192.168.0.11:8250" + + # Pump 只保留多少天以内的数据 (默认 7) + gc = 7 + + # Pump 数据存储位置路径 + data-dir = "data.pump" + + # Pump 向 PD 发送心跳的间隔 (单位 秒) + heartbeat-interval = 2 + + # PD 集群节点的地址 (英文逗号分割,中间不加空格) + pd-urls = "http://192.168.0.16:2379,http://192.168.0.15:2379,http://192.168.0.14:2379" + + # [security] + # 如无特殊安全设置需要,该部分一般都注解掉 + # 包含与集群连接的受信任 SSL CA 列表的文件路径 + # ssl-ca = "/path/to/ca.pem" + # 包含与集群连接的 PEM 形式的 X509 certificate 的路径 + # ssl-cert = "/path/to/drainer.pem" + # 包含与集群链接的 PEM 形式的 X509 key 的路径 + # ssl-key = "/path/to/drainer-key.pem" + + # [storage] + # 设置为 true(默认值)来保证可靠性,确保 binlog 数据刷新到磁盘 + # sync-log = true + + # 当可用磁盘容量小于该设置值时,Pump 将停止写入数据 + # 42 MB -> 42000000, 42 mib -> 44040192 + # default: 10 gib + # stop-write-at-available-space = "10 gib" + + # Pump 内嵌的 LSM DB 设置,除非对该部分很了解,否则一般注解掉 + # [storage.kv] + # block-cache-capacity = 8388608 + # block-restart-interval = 16 + # block-size = 4096 + # compaction-L0-trigger = 8 + # compaction-table-size = 67108864 + # compaction-total-size = 536870912 + # compaction-total-size-multiplier = 8.0 + # write-buffer = 67108864 + # write-L0-pause-trigger = 24 + # write-L0-slowdown-trigger = 17 + ``` + + - 启动示例 + + ```bash + ./pump -config pump.toml + ``` + + 如果命令行参数与配置文件中的参数重合,则使用命令行设置的参数的值。 + +2. 使用 binary 部署 Drainer + + - Drainer 命令行参数说明(以在 “192.168.0.13” 上部署为例) + + ```bash + Usage of Drainer + -L string + 日志输出信息等级设置:debug,info,warn,error,fatal (默认 "info") + -V + 打印版本信息 + -addr string + Drainer 提供服务的地址(-addr="192.168.0.13:8249") + -c int + 同步下游的并发数,该值设置越高同步的吞吐性能越好 (default 1) + -cache-binlog-count int + 缓存中的 binlog 数目限制(默认 8) + 如果上游的单个 binlog 较大导致 Drainer 出现 OOM 时,可尝试调小该值减少内存使用 + -config string + 配置文件路径,Drainer 会首先读取配置文件的配置; + 如果对应的配置在命令行参数里面也存在,Drainer 就会使用命令行参数的配置来覆盖配置文件里面的配置 + -data-dir string + Drainer 数据存储位置路径 (默认 "data.drainer") + -dest-db-type string + Drainer 下游服务类型 (默认为 mysql,支持 tidb、kafka、file) + -detect-interval int + 向 PD 查询在线 Pump 的时间间隔 (默认 10,单位 秒) + -disable-detect + 是否禁用冲突监测 + -disable-dispatch + 是否禁用拆分单个 binlog 的 SQL 的功能,如果设置为 true,则每个 binlog + 按顺序依次还原成单个事务进行同步(下游服务类型为 MySQL,该项设置为 False) + -ignore-schemas string + db 过滤列表 (默认 "INFORMATION_SCHEMA,PERFORMANCE_SCHEMA,mysql,test"), + 不支持对 ignore schemas 的 table 进行 rename DDL 操作 + -initial-commit-ts(默认为 `-1`) + 如果 Drainer 没有相关的断点信息,可以通过该项来设置相关的断点信息 + 该参数值为 `-1` 时,Drainer 会自动从 PD 获取一个最新的时间戳 + -log-file string + log 文件路径 + -log-rotate string + log 文件切换频率,hour/day + -metrics-addr string + Prometheus Pushgateway 地址,不设置则禁止上报监控信息 + -metrics-interval int + 监控信息上报频率(默认 15,单位:秒) + -node-id string + drainer 节点的唯一识别 ID,如果不指定,程序会根据主机名和监听端口自动生成 + -pd-urls string + PD 集群节点的地址 (-pd-urls="http://192.168.0.16:2379,http://192.168.0.15:2379,http://192.168.0.14:2379") + -safe-mode + 是否开启安全模式使得下游 MySQL/TiDB 可被重复写入 + 即将 insert 语句换为 replace 语句,将 update 语句拆分为 delete + replace 语句 + -txn-batch int + 输出到下游数据库一个事务的 SQL 数量(默认 1) + ``` + + - Drainer 配置文件(以在 “192.168.0.13” 上部署为例) + + ```toml + # Drainer Configuration. + + # Drainer 提供服务的地址("192.168.0.13:8249") + addr = "192.168.0.13:8249" + + # Drainer 对外提供服务的地址 + advertise-addr = "192.168.0.13:8249" + + # 向 PD 查询在线 Pump 的时间间隔 (默认 10,单位 秒) + detect-interval = 10 + + # Drainer 数据存储位置路径 (默认 "data.drainer") + data-dir = "data.drainer" + + # PD 集群节点的地址 (英文逗号分割,中间不加空格) + pd-urls = "http://192.168.0.16:2379,http://192.168.0.15:2379,http://192.168.0.14:2379" + + # log 文件路径 + log-file = "drainer.log" + + # Drainer 从 Pump 获取 binlog 时对数据进行压缩,值可以为 "gzip",如果不配置则不进行压缩 + # compressor = "gzip" + + # [security] + # 如无特殊安全设置需要,该部分一般都注解掉 + # 包含与集群连接的受信任 SSL CA 列表的文件路径 + # ssl-ca = "/path/to/ca.pem" + # 包含与集群连接的 PEM 形式的 X509 certificate 的路径 + # ssl-cert = "/path/to/pump.pem" + # 包含与集群链接的 PEM 形式的 X509 key 的路径 + # ssl-key = "/path/to/pump-key.pem" + + # Syncer Configuration + [syncer] + # 如果设置了该项,会使用该 sql-mode 解析 DDL 语句,此时如果下游是 MySQL 或 TiDB 则 + # 下游的 sql-mode 也会被设置为该值 + # sql-mode = "STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION" + + # 输出到下游数据库一个事务的 SQL 语句数量 (默认 20) + txn-batch = 20 + + # 同步下游的并发数,该值设置越高同步的吞吐性能越好 (默认 16) + worker-count = 16 + + # 是否禁用拆分单个 binlog 的 SQL 的功能,如果设置为 true,则按照每个 binlog + # 顺序依次还原成单个事务进行同步(下游服务类型为 MySQL, 该项设置为 False) + disable-dispatch = false + + # safe mode 会使写下游 MySQL/TiDB 可被重复写入 + # 会用 replace 替换 insert 语句,用 delete + replace 替换 update 语句 + safe-mode = false + + # Drainer 下游服务类型(默认为 mysql) + # 参数有效值为 "mysql","tidb","file","kafka" + db-type = "mysql" + + # 事务的 commit ts 若在该列表中,则该事务将被过滤,不会同步至下游 + ignore-txn-commit-ts = [] + + # db 过滤列表 (默认 "INFORMATION_SCHEMA,PERFORMANCE_SCHEMA,mysql,test"), + # 不支持对 ignore schemas 的 table 进行 rename DDL 操作 + ignore-schemas = "INFORMATION_SCHEMA,PERFORMANCE_SCHEMA,mysql" + + # replicate-do-db 配置的优先级高于 replicate-do-table。如果配置了相同的库名,支持使用正则表达式进行配置。 + # 以 '~' 开始声明使用正则表达式 + + # replicate-do-db = ["~^b.*","s1"] + + # [syncer.relay] + # 保存 relay log 的目录,空值表示不开启。 + # 只有下游是 TiDB 或 MySQL 时该配置才生效。 + # log-dir = "" + # 每个文件的大小上限 + # max-file-size = 10485760 + + # [[syncer.replicate-do-table]] + # db-name ="test" + # tbl-name = "log" + + # [[syncer.replicate-do-table]] + # db-name ="test" + # tbl-name = "~^a.*" + + # 忽略同步某些表 + # [[syncer.ignore-table]] + # db-name = "test" + # tbl-name = "log" + + # db-type 设置为 mysql 时,下游数据库服务器参数 + [syncer.to] + host = "192.168.0.13" + user = "root" + # 如果你不想在配置文件中写明文密码,则可以使用 `./binlogctl -cmd encrypt -text string` 生成加密的密码 + # 如果配置了 encrypted_password 且非空,那么配置的 password 不生效。encrypted_password 和 password 无法同时生效。 + password = "" + encrypted_password = "" + port = 3306 + + [syncer.to.checkpoint] + # 当 checkpoint type 是 mysql 或 tidb 时可以开启该选项,以改变保存 checkpoint 的数据库 + # schema = "tidb_binlog" + # 目前只支持 mysql 或者 tidb 类型。可以去掉注释来控制 checkpoint 保存的位置。 + # db-type 默认的 checkpoint 保存方式是: + # mysql/tidb -> 对应的下游 mysql/tidb + # file/kafka -> file in `data-dir` + # type = "mysql" + # host = "127.0.0.1" + # user = "root" + # password = "" + # 使用 `./binlogctl -cmd encrypt -text string` 加密的密码 + # encrypted_password 非空时 password 会被忽略 + # encrypted_password = "" + # port = 3306 + + # db-type 设置为 file 时,存放 binlog 文件的目录 + # [syncer.to] + # dir = "data.drainer" + + # db-type 设置为 kafka 时,Kafka 相关配置 + # [syncer.to] + # kafka-addrs 和 zookeeper-addrs 只需要一个,两者都有时程序会优先用 zookeeper 中的 kafka 地址 + # zookeeper-addrs = "127.0.0.1:2181" + # kafka-addrs = "127.0.0.1:9092" + # kafka-version = "0.8.2.0" + # 配置单条 broker request 中的最大 message 数(即 binlog 数),不配置或配置小于等于 0 时会使用默认值 1024 + # kafka-max-messages = 1024 + # 配置单条 broker request 的最大 size(单位为 Byte),默认为 1 GiB,最大可配置为 2 GiB + # kafka-max-message-size = 1073741824 + + # 保存 binlog 数据的 Kafka 集群的 topic 名称,默认值为 _obinlog + # 如果运行多个 Drainer 同步数据到同一个 Kafka 集群,每个 Drainer 的 topic-name 需要设置不同的名称 + # topic-name = "" + ``` + + - 启动示例 + + > **注意:** + > + > 如果下游为 MySQL/TiDB,为了保证数据的完整性,在 Drainer 初次启动前需要获取 `initial-commit-ts` 的值,并进行全量数据的备份与恢复。 + + 初次启动时使用参数 `initial-commit-ts`,命令如下: + + ```bash + ./drainer -config drainer.toml -initial-commit-ts {initial-commit-ts} + ``` + + 如果命令行参数与配置文件中的参数重合,则使用命令行设置的参数的值。 + +> **注意:** +> +> - 在运行 TiDB 时,需要保证至少一个 Pump 正常运行。 +> - 通过给 TiDB 增加启动参数 `enable-binlog` 来开启 binlog 服务。尽量保证同一集群的所有 TiDB 都开启了 binlog 服务,否则在同步数据时可能会导致上下游数据不一致。如果要临时运行一个不开启 binlog 服务的 TiDB 实例,需要在 TiDB 的配置文件中设置 `run_ddl= false`。 +> - Drainer 不支持对 ignore schemas(在过滤列表中的 schemas)的 table 进行 rename DDL 操作。 +> - 在已有的 TiDB 集群中启动 Drainer,一般需要全量备份并且获取**快照时间戳**,然后导入全量备份,最后启动 Drainer 从对应的快照时间戳开始同步增量数据。 +> - 下游使用 MySQL 或 TiDB 时应当保证上下游数据库的 sql_mode 具有一致性,即下游数据库同步每条 SQL 语句时的 sql_mode 应当与上游数据库执行该条 SQL 语句时的 sql_mode 保持一致。可以在上下游分别执行 `select @@sql_mode;` 进行查询和比对。 +> - 如果存在上游 TiDB 能运行但下游 MySQL 不支持的 DDL 语句时(例如下游 MySQL 使用 InnoDB 引擎时同步语句 `CREATE TABLE t1(a INT) ROW_FORMAT=FIXED;`),Drainer 也会同步失败,此时可以在 Drainer 配置中跳过该事务,同时在下游手动执行兼容的语句,详见[跳过事务](/tidb-binlog/tidb-binlog-faq.md#同步时出现上游数据库支持但是下游数据库执行会出错的-ddl应该怎么办)。 diff --git a/markdown-pages/zh/tidb/master/tidb-binlog/get-started-with-tidb-binlog.md b/markdown-pages/zh/tidb/master/tidb-binlog/get-started-with-tidb-binlog.md new file mode 100644 index 0000000..aa710fa --- /dev/null +++ b/markdown-pages/zh/tidb/master/tidb-binlog/get-started-with-tidb-binlog.md @@ -0,0 +1,463 @@ +--- +title: TiDB Binlog 教程 +aliases: ['/docs-cn/dev/tidb-binlog/get-started-with-tidb-binlog/','/docs-cn/dev/how-to/get-started/tidb-binlog/','/docs-cn/dev/get-started-with-tidb-binlog/'] +summary: TiDB Binlog 是用于将数据从 TiDB 推送到 MariaDB 实例的工具。它包含 Pump 和 Drainer 两个组件,用于实时数据备份和同步。用户需要对 TiDB 架构有一定了解,并在现代 Linux 发行版本中的 x86-64上使用。安装和配置过程需要按照指导进行,以确保成功启动各个组件。使用 binlogctl 可以查询和修改集群中 Pump 和 Drainer 的状态信息。 +--- + +# TiDB Binlog 教程 + +本文档主要介绍如何使用 TiDB Binlog 将数据从 TiDB 推送到 MariaDB 实例。文中的 TiDB Binlog 集群包含 Pump 和 Drainer 的单个节点,TiDB 集群包含 TiDB、TiKV 和 Placement Driver (PD) 各组件的单个节点。 + +希望上手实践 TiDB Binlog 工具的用户需要对 [TiDB 架构](/tidb-architecture.md)有一定的了解,最好有创建过 TiDB 集群的经验。该文档也有助于简单快速了解 TiDB Binlog 架构以及相关概念。 + +> **警告:** +> +> 该文档中部署 TiDB 的操作指导**不适用于**在生产或研发环境中部署 TiDB 的情况。 + +该文档假设用户使用的是现代 Linux 发行版本中的 x86-64。示例中使用的是 VMware 中运行的 CentOS 7 最小化安装。建议在一开始就进行清洁安装,以避免受现有环境中未知情况的影响。如果不想使用本地虚拟环境,也可以使用云服务启动 CentOS 7 VM。 + +## TiDB Binlog 简介 + +TiDB Binlog 用于收集 TiDB 中二进制日志数据、提供实时数据备份和同步以及将 TiDB 集群的数据增量同步到下游。 + +TiDB Binlog 支持以下功能场景: + +- 增量备份,将 TiDB 集群中的数据增量同步到另一个集群,或通过 Kafka 增量同步到选择的下游。 +- 当使用 TiDB DM (Data Migration) 将数据从上游 MySQL 或者 MariaDB 迁移到 TiDB 集群时,可使用 TiDB Binlog 保持 TiDB 集群与其一个独立下游 MySQL 或 MariaDB 实例或集群同步。当 TiDB 集群上游数据迁移过程中出现问题,下游数据同步过程中可使用 TiDB Binlog 恢复数据到原先的状态。 + +更多信息参考 [TiDB Binlog Cluster 版本用户文档](/tidb-binlog/tidb-binlog-overview.md)。 + +## 架构 + +TiDB Binlog 集群由 **Pump** 和 **Drainer** 两个组件组成。一个 Pump 集群中有若干个 Pump 节点。TiDB 实例连接到各个 Pump 节点并发送 binlog 数据到 Pump 节点。Pump 集群连接到 Drainer 节点,Drainer 将接收到的更新数据转换到某个特定下游(例如 Kafka、另一个 TiDB 集群或 MySQL 或 MariaDB Server)指定的正确格式。 + +![TiDB Binlog architecture](/media/tidb-binlog-cluster-architecture.png) + +Pump 的集群架构能确保 TiDB 或 Pump 集群中有新的实例加入或退出时更新数据不会丢失。 + +## 安装 + +由于 RHEL/CentOS 7 的默认包装库中包括 MariaDB Server,本示例选择的是 MariaDB Server。后续除了安装服务器,也需要安装客户端。安装指令如下: + +```bash +sudo yum install -y mariadb-server +``` + +```bash +curl -LO https://download.pingcap.org/tidb-community-server-v8.0.0-linux-amd64.tar.gz | tar xzf - && +cd tidb-latest-linux-amd64 +``` + +预期输出: + +``` + % Total % Received % Xferd Average Speed Time Time Time Current + Dload Upload Total Spent Left Speed +100 368M 100 368M 0 0 8394k 0 0:00:44 0:00:44 --:--:-- 11.1M +``` + +## 配置 + +通过执行以下步骤配置一个 TiDB 集群,该集群包括 `pd-server`、`tikv-server` 和 `tidb-server` 各组件的单个实例。 + +1. 填充配置文件: + + ```bash + printf > pd.toml %s\\n 'log-file="pd.log"' 'data-dir="pd.data"' && + printf > tikv.toml %s\\n 'log-file="tikv.log"' '[storage]' 'data-dir="tikv.data"' '[pd]' 'endpoints=["127.0.0.1:2379"]' '[rocksdb]' max-open-files=1024 '[raftdb]' max-open-files=1024 && + printf > pump.toml %s\\n 'log-file="pump.log"' 'data-dir="pump.data"' 'addr="127.0.0.1:8250"' 'advertise-addr="127.0.0.1:8250"' 'pd-urls="http://127.0.0.1:2379"' && + printf > tidb.toml %s\\n 'store="tikv"' 'path="127.0.0.1:2379"' '[log.file]' 'filename="tidb.log"' '[binlog]' 'enable=true' && + printf > drainer.toml %s\\n 'log-file="drainer.log"' '[syncer]' 'db-type="mysql"' '[syncer.to]' 'host="127.0.0.1"' 'user="root"' 'password=""' 'port=3306' + ``` + +2. 查看配置细节: + + ```bash + for f in *.toml; do echo "$f:"; cat "$f"; echo; done + ``` + + 预期输出: + + ``` + drainer.toml: + log-file="drainer.log" + [syncer] + db-type="mysql" + [syncer.to] + host="127.0.0.1" + user="root" + password="" + port=3306 + + pd.toml: + log-file="pd.log" + data-dir="pd.data" + + pump.toml: + log-file="pump.log" + data-dir="pump.data" + addr="127.0.0.1:8250" + advertise-addr="127.0.0.1:8250" + pd-urls="http://127.0.0.1:2379" + + tidb.toml: + store="tikv" + path="127.0.0.1:2379" + [log.file] + filename="tidb.log" + [binlog] + enable=true + + tikv.toml: + log-file="tikv.log" + [storage] + data-dir="tikv.data" + [pd] + endpoints=["127.0.0.1:2379"] + [rocksdb] + max-open-files=1024 + [raftdb] + max-open-files=1024 + ``` + +## 启动程序 + +现在可启动各个组件。推荐启动顺序依次为 Placement Driver (PD)、TiKV、Pump(TiDB 发送 binlog 日志必须连接 Pump 服务)、TiDB。 + +1. 启动所有服务: + + ```bash + ./bin/pd-server --config=pd.toml &>pd.out & + ``` + + ``` + [1] 20935 + ``` + + ```bash + ./bin/tikv-server --config=tikv.toml &>tikv.out & + ``` + + ``` + [2] 20944 + ``` + + ```bash + ./pump --config=pump.toml &>pump.out & + ``` + + ``` + [3] 21050 + ``` + + ```bash + sleep 3 && + ./bin/tidb-server --config=tidb.toml &>tidb.out & + ``` + + ``` + [4] 21058 + ``` + +2. 如果执行 `jobs`,可以看到后台正在运行的程序,列表如下: + + ```bash + jobs + ``` + + ``` + [1] Running ./bin/pd-server --config=pd.toml &>pd.out & + [2] Running ./bin/tikv-server --config=tikv.toml &>tikv.out & + [3]- Running ./pump --config=pump.toml &>pump.out & + [4]+ Running ./bin/tidb-server --config=tidb.toml &>tidb.out & + ``` + + 如果有服务启动失败(例如出现 “`Exit 1`” 而不是 “`Running`”),尝试重启单个组件。 + +## 连接 + +按以上步骤操作后,TiDB 的 4 个组件开始运行。接下来可以使用以下 MariaDB 或 MySQL 命令行客户端,通过 4000 端口连接到 TiDB 服务: + +```bash +mysql -h 127.0.0.1 -P 4000 -u root -e 'select tidb_version();' +``` + +预期输出: + +``` +*************************** 1. row *************************** +tidb_version(): Release Version: v3.0.0-beta.1-154-gd5afff70c +Git Commit Hash: d5afff70cdd825d5fab125c8e52e686cc5fb9a6e +Git Branch: master +UTC Build Time: 2019-04-24 03:10:00 +GoVersion: go version go1.12 linux/amd64 +Race Enabled: false +TiKV Min Version: 2.1.0-alpha.1-ff3dd160846b7d1aed9079c389fc188f7f5ea13e +Check Table Before Drop: false +``` + +连接后 TiDB 集群已开始运行,`pump` 读取集群中的 binlog 数据,并在其数据目录中将 binlog 数据存储为 relay log。下一步是启动一个可供 `drainer` 写入的 MariaDB Server。 + +1. 启动 `drainer`: + + ```bash + sudo systemctl start mariadb && + ./drainer --config=drainer.toml &>drainer.out & + ``` + + 如果你的操作系统更易于安装 MySQL,只需保证监听 3306 端口。另外,可使用密码为空的 "root" 用户连接到 MySQL,或调整 `drainer.toml` 连接到 MySQL。 + + ```bash + mysql -h 127.0.0.1 -P 3306 -u root + ``` + + 预期输出: + + ``` + Welcome to the MariaDB monitor. Commands end with ; or \g. + Your MariaDB connection id is 20 + Server version: 5.5.60-MariaDB MariaDB Server + + Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others. + + Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. + + MariaDB [(none)]> + ``` + + ```sql + show databases; + ``` + + 预期输出: + + ``` + +--------------------+ + | Database | + +--------------------+ + | information_schema | + | mysql | + | performance_schema | + | test | + | tidb_binlog | + +--------------------+ + 5 rows in set (0.01 sec) + ``` + + 如下表格是包含 `checkpoint` 表格的 `tidb_binlog` 数据库。`drainer` 使用 `checkpoint` 表格,记录 TiDB 集群中的 binlog 已经更新到了哪个位置。 + + ```sql + use tidb_binlog; + ``` + + ``` + Database changed + ``` + + ```sql + select * from checkpoint; + ``` + + ``` + +---------------------+---------------------------------------------+ + | clusterID | checkPoint | + +---------------------+---------------------------------------------+ + | 6678715361817107733 | {"commitTS":407637466476445697,"ts-map":{}} | + +---------------------+---------------------------------------------+ + 1 row in set (0.00 sec) + ``` + + 打开另一个连接到 TiDB 的客户端,创建一个表格并插入几行数据。建议在 GNU Screen 软件中操作,从而同时打开多个客户端。 + + ```bash + mysql -h 127.0.0.1 -P 4000 --prompt='TiDB [\d]> ' -u root + ``` + + ```sql + create database tidbtest; + ``` + + ``` + Query OK, 0 rows affected (0.12 sec) + ``` + + ```sql + use tidbtest; + ``` + + ``` + Database changed + ``` + + ```sql + create table t1 (id int unsigned not null AUTO_INCREMENT primary key); + ``` + + ``` + Query OK, 0 rows affected (0.11 sec) + ``` + + ```sql + insert into t1 () values (),(),(),(),(); + ``` + + ``` + Query OK, 5 rows affected (0.01 sec) + Records: 5 Duplicates: 0 Warnings: 0 + ``` + + ```sql + select * from t1; + ``` + + ``` + +----+ + | id | + +----+ + | 1 | + | 2 | + | 3 | + | 4 | + | 5 | + +----+ + 5 rows in set (0.00 sec) + ``` + + 切换回 MariaDB 客户端可看到新的数据库、新的表格和最近插入的行数据。 + + ```sql + use tidbtest; + ``` + + ``` + Reading table information for completion of table and column names + You can turn off this feature to get a quicker startup with -A + + Database changed + ``` + + ```sql + show tables; + ``` + + ``` + +--------------------+ + | Tables_in_tidbtest | + +--------------------+ + | t1 | + +--------------------+ + 1 row in set (0.00 sec) + ``` + + ```sql + select * from t1; + ``` + + ``` + +----+ + | id | + +----+ + | 1 | + | 2 | + | 3 | + | 4 | + | 5 | + +----+ + 5 rows in set (0.00 sec) + ``` + + 可看到查询 MariaDB 时插入到 TiDB 相同的行数据,表明 TiDB Binlog 安装成功。 + +## binlogctl + +加入到集群的 Pump 和 Drainer 的数据存储在 Placement Driver (PD) 中。binlogctl 可用于查询和修改状态信息。更多信息请参考 [binlogctl guide](/tidb-binlog/binlog-control.md)。 + +使用 `binlogctl` 查看集群中 Pump 和 Drainer 的当前状态: + +```bash +./binlogctl -cmd drainers +``` + +``` +[2019/04/11 17:44:10.861 -04:00] [INFO] [nodes.go:47] ["query node"] [type=drainer] [node="{NodeID: localhost.localdomain:8249, Addr: 192.168.236.128:8249, State: online, MaxCommitTS: 407638907719778305, UpdateTime: 2019-04-11 17:44:10 -0400 EDT}"] +``` + +```bash +./binlogctl -cmd pumps +``` + +``` +[2019/04/11 17:44:13.904 -04:00] [INFO] [nodes.go:47] ["query node"] [type=pump] [node="{NodeID: localhost.localdomain:8250, Addr: 192.168.236.128:8250, State: online, MaxCommitTS: 407638914024079361, UpdateTime: 2019-04-11 17:44:13 -0400 EDT}"] +``` + +如果结束 Drainer 进程,集群会改进程设置“已暂停(即集群等待 Drainer 重新加入)”的状态。 + +```bash +pkill drainer && +./binlogctl -cmd drainers +``` + +预期输出: + +``` +[2019/04/11 17:44:22.640 -04:00] [INFO] [nodes.go:47] ["query node"] [type=drainer] [node="{NodeID: localhost.localdomain:8249, Addr: 192.168.236.128:8249, State: paused, MaxCommitTS: 407638915597467649, UpdateTime: 2019-04-11 17:44:18 -0400 EDT}"] +``` + +使用 binlogctl 的 "NodeIDs" 可控制单个对应节点。在该情况下,Drainer 的节点 ID 是 "localhost.localdomain:8249",Pump 的节点 ID 是 "localhost.localdomain:8250"。 + +本文档中的 binlogctl 主要用于集群重启。如果在 TiDB 集群中终止并尝试重启所有的进程,由于 Pump 无法连接 Drainer 且认为 Drainer 依旧“在线”,Pump 会拒绝启动。这里的进程并不包括下游的 MySQL 或 MariaDB 或 Drainer。 + +以下有三个方案可解决上述问题: + +- 使用 binlogctl 停止 Drainer,而不是结束进程: + + ```bash + ./binlogctl --pd-urls=http://127.0.0.1:2379 --cmd=drainers && + ./binlogctl --pd-urls=http://127.0.0.1:2379 --cmd=pause-drainer --node-id=localhost.localdomain:8249 + ``` + +- 在启动 Pump **之前**先启动 Drainer。 + +- 在启动 PD 之后但在启动 Drainer 和 Pump 之前,使用 binlogctl 更新已暂定 Drainer 的状态。 + + ```bash + ./binlogctl --pd-urls=http://127.0.0.1:2379 --cmd=update-drainer --node-id=localhost.localdomain:8249 --state=paused + ``` + +## 清理 + +在 shell 终端里可启动创建集群的所有进程(`pd-server` 、`tikv-server`、`pump`、`tidb-server`、`drainer`)。可通过在 shell 终端中执行 `pkill -P $$` 停止 TiDB 集群服务和 TiDB Binlog 进程。按一定的顺序停止这些进程有利于留出足够的时间彻底关闭每个组件。 + +```bash +for p in tidb-server drainer pump tikv-server pd-server; do pkill "$p"; sleep 1; done +``` + +预期输出: + +``` +[4]- Done ./bin/tidb-server --config=tidb.toml &>tidb.out +[5]+ Done ./drainer --config=drainer.toml &>drainer.out +[3]+ Done ./pump --config=pump.toml &>pump.out +[2]+ Done ./bin/tikv-server --config=tikv.toml &>tikv.out +[1]+ Done ./bin/pd-server --config=pd.toml &>pd.out +``` + +如果需要所有服务退出后重启集群,可以使用一开始启动服务的命令。如以上 [`binlogctl`](#binlogctl) 部分所述,需要先启动 Drainer 再启动 Pump,最后启动 `tidb-server`。 + +```bash +./bin/pd-server --config=pd.toml &>pd.out & +./bin/tikv-server --config=tikv.toml &>tikv.out & +./drainer --config=drainer.toml &>drainer.out & +sleep 3 +./pump --config=pump.toml &>pump.out & +sleep 3 +./bin/tidb-server --config=tidb.toml &>tidb.out & +``` + +如果有组件启动失败,请尝试单独重启该组件。 + +## 总结 + +本文档介绍了如何通过设置 TiDB Binlog,使用单个 Pump 和 Drainer 组成的集群同步 TiDB 集群数据到下游的 MariaDB。可以发现,TiDB Binlog 是用于获取处理 TiDB 集群中更新数据的综合性平台工具。 + +在更稳健的开发、测试或生产部署环境中,可以使用多个 TiDB 服务以实现高可用性和扩展性。使用多个 Pump 实例可以避免 Pump 集群中的问题影响发送到 TiDB 实例的应用流量。或者可以使用增加的 Drainer 实例同步数据到不同的下游或实现数据增量备份。 diff --git a/markdown-pages/zh/tidb/master/tidb-binlog/handle-tidb-binlog-errors.md b/markdown-pages/zh/tidb/master/tidb-binlog/handle-tidb-binlog-errors.md new file mode 100644 index 0000000..f43c64e --- /dev/null +++ b/markdown-pages/zh/tidb/master/tidb-binlog/handle-tidb-binlog-errors.md @@ -0,0 +1,46 @@ +--- +title: TiDB Binlog 常见错误修复 +aliases: ['/docs-cn/dev/tidb-binlog/handle-tidb-binlog-errors/','/docs-cn/dev/reference/tidb-binlog/troubleshoot/error-handling/'] +summary: TiDB Binlog 常见错误修复:介绍了 Drainer 同步数据到 Kafka 时报错的解决方法,Pump 报错 "no space left on device" 的原因和解决方法,以及 Drainer 输出 file 格式的增量数据的清理机制。需要确认 TiDB 实例是否开启了 TiDB Binlog 并且状态正常,以及调整 Pump 的 gRPC message 最大大小。 +--- + +# TiDB Binlog 常见错误修复 + +本文档介绍 TiDB Binlog 中常见的错误以及修复方法。 + +## Drainer 同步数据到 Kafka 时报错 "kafka server: Message was too large, server rejected it to avoid allocation error" + +报错原因:如果在 TiDB 中执行了大事务,则生成的 binlog 数据会比较大,可能超过了 Kafka 的消息大小限制。 + +解决方法:需要调整 Kafka 的配置参数,如下所示。 + +``` +message.max.bytes=1073741824 +replica.fetch.max.bytes=1073741824 +fetch.message.max.bytes=1073741824 +``` + +## Pump 报错 "no space left on device" + +报错原因:本地磁盘空间不足,Pump 无法正常写 binlog 数据。 + +解决方法:需要清理磁盘空间,然后重启 Pump。 + +## Pump 启动时报错 "fail to notify all living drainer" + +报错原因:Pump 启动时需要通知所有 Online 状态的 Drainer,如果通知失败则会打印该错误日志。 + +解决方法:可以使用 [binlogctl 工具](/tidb-binlog/binlog-control.md)查看所有 Drainer 的状态是否有异常,保证 Online 状态的 Drainer 都在正常工作。如果某个 Drainer 的状态和实际运行情况不一致,则使用 binlogctl 修改状态,然后再重启 Pump。 + +## TiDB Binlog 同步中发现数据丢失 + +需要确认所有 TiDB 实例均开启了 TiDB Binlog,并且运行状态正常。如果集群版本大于 v3.0,可以使用 `curl {TiDB_IP}:{STATUS_PORT}/info/all` 命令确认所有 TiDB 实例上的 TiDB Binlog 状态。 + +## 当上游事务较大时,Pump 报错 `rpc error: code = ResourceExhausted desc = trying to send message larger than max (2191430008 vs. 2147483647)` + +出现该错误的原因是 TiDB 发送给 Pump 的 gRPC message 超过限值。可以在启动 Pump 时通过指定 `max-message-size` 来调整 Pump 可接受 gRPC message 的最大大小。 + +## Drainer 输出 file 格式的增量数据,数据有什么清理机制吗?数据会被删除吗? + ++ 在 v3.0.x 版本的 Drainer 中,file 格式的增量数据没有任何清理机制。 ++ 在 v4.0.x 版本中,有基于时间的数据清理机制,详见 [Drainer 的 `retention-time` 配置项](https://github.com/pingcap/tidb-binlog/blob/v4.0.9/cmd/drainer/drainer.toml#L153)。 diff --git a/markdown-pages/zh/tidb/master/tidb-binlog/maintain-tidb-binlog-cluster.md b/markdown-pages/zh/tidb/master/tidb-binlog/maintain-tidb-binlog-cluster.md new file mode 100644 index 0000000..6fa3de6 --- /dev/null +++ b/markdown-pages/zh/tidb/master/tidb-binlog/maintain-tidb-binlog-cluster.md @@ -0,0 +1,124 @@ +--- +title: TiDB Binlog 集群运维 +aliases: ['/docs-cn/dev/tidb-binlog/maintain-tidb-binlog-cluster/','/docs-cn/dev/reference/tidb-binlog/maintain/','/docs-cn/dev/how-to/maintain/tidb-binlog/','/docs-cn/dev/reference/tools/tidb-binlog/maintain/'] +summary: TiDB Binlog 集群运维包括了 Pump 和 Drainer 的状态管理和启动、退出流程。通过 binlogctl 工具或 TiDB SQL 操作可以管理集群状态。具体操作方法请参考 binlogctl 工具的使用方法介绍。 +--- + +# TiDB Binlog 集群运维 + +本文首先介绍 Pump 和 Drainer 的状态及启动、退出的内部处理流程,然后说明如何通过 binlogctl 工具或者直接在 TiDB 执行 SQL 操作来管理 binlog 集群,最后的 FAQ 部分会介绍一些常见问题以及处理方法。 + +## Pump/Drainer 的状态 + +Pump/Drainer 中状态的定义: + +* online:正常运行中 +* pausing:暂停中 +* paused:已暂停 +* closing:下线中 +* offline:已下线 + +这些状态由 Pump/Drainer 服务自身进行维护,并定时将状态信息更新到 PD 中。 + +## Pump/Drainer 的启动、退出流程 + +### Pump + +* 启动:Pump 启动时会通知所有 online 状态的 Drainer,如果通知成功,则 Pump 将状态设置为 online,否则 Pump 将报错,然后将状态设置为 paused 并退出进程。 +* 退出:Pump 进程正常退出前要选择进入暂停或者下线状态;非正常退出(kill -9、进程 panic、宕机)都依然保持 online 状态。 + + * 暂停:使用 kill(非 kill -9)、Ctrl+C 或者使用 binlogctl 的 pause-pump 命令都可以暂停 Pump。接收到暂停指令后,Pump 会变更状态为 pausing,并停止接受 binlog 的写请求,也停止向 Drainer 提供 binlog 数据。安全退出所有线程后,更新状态为 paused 然后退出进程。 + * 下线:仅在使用 binlogctl 的 offline-pump 命令的情况下才会下线 Pump。接收到下线指令后,Pump 会变更状态为 closing,并停止接受 binlog 的写请求。Pump 继续向 Drainer 提供 binlog,等待所有 binlog 数据都被 Drainer 消费后再将状态设置为 offline 并退出进程。 + +### Drainer + +* 启动:Drainer 启动时将状态设置为 online,并尝试从所有非 offline 状态的 Pump 获取 binlog,如果获取 binlog 失败,会不断尝试重新获取。 +* 退出:Drainer 进程正常退出前要选择进入暂停或者下线状态;非正常退出(kill -9 、进程 panic、宕机)都依然保持 online 状态。 + + * 暂停:使用 kill(非 kill -9)、Ctrl+C 或者使用 binlogctl 的 pause-drainer 命令都可以暂停 Drainer。接收到指令后,Drainer 会变更状态为 pausing,并停止从 Pump 获取 binlog。安全退出所有线程后,更新状态为 paused 然后退出进程。 + * 下线:仅在使用 binlogctl 的 offline-drainer 命令的情况下才会下线 Drainer。接收到下线指令后,Drainer 变更状态为 closing,并停止从 Pump 获取 binlog。安全退出所有线程后,更新状态为 offline 然后退出进程。 + +关于 Pump/Drainer 暂停、下线、状态查询、状态修改等具体的操作方法,参考如下 binlogctl 工具的使用方法介绍。 + +## 使用 binlogctl 工具管理 Pump/Drainer + +binlogctl 支持如下这些功能: + +* 查看 Pump/Drainer 状态 +* 暂停/下线 Pump/Drainer +* Pump/Drainer 异常状态处理 + +详细的介绍和使用方法请参考 [binlogctl 工具](/tidb-binlog/binlog-control.md)。 + +## 使用 TiDB SQL 管理 Pump/Drainer + +要查看和管理 binlog 相关的状态,可在 TiDB 中执行相应的 SQL 语句。 + +- 查看 TiDB 是否开启 binlog,0 代表关闭,1 代表开启 + + ```sql + show variables like "log_bin"; + ``` + + ``` + +---------------+-------+ + | Variable_name | Value | + +---------------+-------+ + | log_bin | 0 | + +---------------+-------+ + ``` + +- 查看 Pump/Drainer 状态 + + ```sql + show pump status; + ``` + + ``` + +--------|----------------|--------|--------------------|---------------------| + | NodeID | Address | State | Max_Commit_Ts | Update_Time | + +--------|----------------|--------|--------------------|---------------------| + | pump1 | 127.0.0.1:8250 | Online | 408553768673342237 | 2019-05-01 00:00:01 | + +--------|----------------|--------|--------------------|---------------------| + | pump2 | 127.0.0.2:8250 | Online | 408553768673342335 | 2019-05-01 00:00:02 | + +--------|----------------|--------|--------------------|---------------------| + ``` + + ```sql + show drainer status; + ``` + + ``` + +----------|----------------|--------|--------------------|---------------------| + | NodeID | Address | State | Max_Commit_Ts | Update_Time | + +----------|----------------|--------|--------------------|---------------------| + | drainer1 | 127.0.0.3:8249 | Online | 408553768673342532 | 2019-05-01 00:00:03 | + +----------|----------------|--------|--------------------|---------------------| + | drainer2 | 127.0.0.4:8249 | Online | 408553768673345531 | 2019-05-01 00:00:04 | + +----------|----------------|--------|--------------------|---------------------| + ``` + +- 异常情况下修改 Pump/Drainer 状态 + + ```sql + change pump to node_state ='paused' for node_id 'pump1'; + ``` + + ``` + Query OK, 0 rows affected (0.01 sec) + ``` + + ```sql + change drainer to node_state ='paused' for node_id 'drainer1'; + ``` + + ``` + Query OK, 0 rows affected (0.01 sec) + ``` + + 该 SQL 的功能和 binlogctl 中的 update-pump 和 update-drainer 命令的功能一样,因此也只有在 Pump/Drainer 异常的情况下使用。 + +> **注意:** +> +> 1. 查看 binlog 开启状态以及 Pump/Drainer 状态的功能在 TiDB v2.1.7 及以上版本中支持。 +> 2. 修改 Pump/Drainer 状态的功能在 TiDB v3.0.0-rc.1 及以上版本中支持。该功能只修改 PD 中存储的 Pump/Drainer 状态,如果需要暂停/下线节点,仍然需要使用 `binlogctl`。 diff --git a/markdown-pages/zh/tidb/master/tidb-binlog/monitor-tidb-binlog-cluster.md b/markdown-pages/zh/tidb/master/tidb-binlog/monitor-tidb-binlog-cluster.md new file mode 100644 index 0000000..3164e5b --- /dev/null +++ b/markdown-pages/zh/tidb/master/tidb-binlog/monitor-tidb-binlog-cluster.md @@ -0,0 +1,165 @@ +--- +title: TiDB Binlog 集群监控 +aliases: ['/docs-cn/dev/tidb-binlog/monitor-tidb-binlog-cluster/','/docs-cn/dev/reference/tidb-binlog/monitor/','/docs-cn/dev/how-to/monitor/tidb-binlog-monitor/','/docs-cn/dev/reference/tools/tidb-binlog/monitor/','/docs-cn/dev/how-to/monitor/tidb-binlog/'] +summary: TiDB Binlog 集群监控包括 Pump 和 Drainer 的监控指标,以及紧急、重要和警告级别的监控报警规则。监控指标包括 Pump 的存储大小、写 Binlog QPS、写 Binlog 延迟等,以及 Drainer 的同步延迟、处理 SQL 耗时等。报警规则包括紧急级别的 Pump 存储错误、重要级别的 Drainer 同步延迟超过1小时、警告级别的 Pump 写 Binlog 耗时过大等。 +--- + +# TiDB Binlog 集群监控 + +成功部署 TiDB Binlog 集群后,可以进入 Grafana Web 界面(默认地址: ,默认账号:admin,密码:admin)查看 Pump 和 Drainer 的运行状态。 + +## 监控指标 + +### Pump + +| metric 名称 | 说明 | +|:----|:------------| +| Storage Size | 记录磁盘的总空间大小 (capacity),以及可用磁盘空间大小 (available) | +| Metadata | 记录每个 Pump 的可删除 binlog 的最大 tso (gc_tso),以及保存的 binlog 的最大的 commit tso (max_commit_tso)。 | +| Write Binlog QPS by Instance | 每个 Pump 接收到的写 binlog 请求的 QPS | +| Write Binlog Latency | 记录每个 Pump 写 binlog 的延迟时间 | +| Storage Write Binlog Size | Pump 写 binlog 数据的大小 | +| Storage Write Binlog Latency | Pump 中的 storage 模块写 binlog 数据的延迟 | +| Pump Storage Error By Type | Pump 遇到的 error 数量,按照 error 的类型进行统计 | +| Query TiKV | Pump 通过 TiKV 查询事务状态的次数 | + +### Drainer + +| metric 名称 | 说明 | +|:----|:------------| +| Checkpoint TSO | Drainer 已经同步到下游的 binlog 的最大 TSO 对应的时间。可以通过该指标估算同步延迟时间 | +| Pump Handle TSO | 记录 Drainer 从各个 Pump 获取到的 binlog 的最大 TSO 对应的时间 | +| Pull Binlog QPS by Pump NodeID | Drainer 从每个 Pump 获取 binlog 的 QPS | +| 95% Binlog Reach Duration By Pump | 记录 binlog 从写入 Pump 到被 Drainer 获取到这个过程的延迟时间 | +| Error By Type | Drainer 遇到的 error 数量,按照 error 的类型进行统计 | +| SQL Query Time| Drainer 在下游执行 SQL 的耗时 | +| Drainer Event | 各种类型 event 的数量,event 包括 ddl、insert、delete、update、flush、savepoint | +| Execute Time | 写入 binlog 到同步下游模块所消耗的时间 | +| 95% Binlog Size | Drainer 从各个 Pump 获取到 binlog 数据的大小 | +| DDL Job Count | Drainer 处理的 DDL 的数量| +| Queue Size | Drainer 内部工作队列大小 | + +## 监控报警规则 + +本节介绍了 TiDB Binlog 组件的报警项及相应的报警规则。根据严重级别,报警项可分为三类,按照严重程度由高到低依次为:紧急级别 (Emergency)、重要级别 (Critical)、警告级别 (Warning)。 + +### 紧急级别报警项 + +紧急级别的报警通常由于服务停止或节点故障导致,此时需要马上进行人工干预操作。 + +#### `binlog_pump_storage_error_count` + +* 报警规则: + + `changes(binlog_pump_storage_error_count[1m]) > 0` + +* 规则描述: + + Pump 写 binlog 到本地存储时失败。 + +* 处理方法: + + 确认 `pump_storage_error` 监控是否存在错误,查看 Pump 日志确认原因。 + +### 重要级别报警项 + +对于重要级别的报警,需要密切关注异常指标。 + +#### `binlog_drainer_checkpoint_high_delay` + +* 报警规则: + + `(time() - binlog_drainer_checkpoint_tso / 1000) > 3600` + +* 规则描述: + + Drainer 同步落后延迟超过 1 个小时。 + +* 处理方法: + + * 判断从 Pump 获取数据是否太慢: + + 监控 Pump handle tso 可以看每个 Pump 最近一条消息的时间,是不是有延迟特别大的 Pump,确认对应 Pump 正常运行。 + + * 根据 Drainer event 和 Drainer execute latency 来判断是否下游同步太慢: + + * 如果 Drainer execute time 过大,则检查到目标库网络带宽和延迟,以及目标库状态。 + * 如果 Drainer execute time 不大,Drainer event 过小,则增加 work count 和 batch 进行重试。 + + * 如果上面都不满足或者操作后没有改观,请从 PingCAP 官方或 TiDB 社区[获取支持](/support.md)。 + +### 警告级别报警项 + +警告级别的报警是对某一问题或错误的提醒。 + +#### `binlog_pump_write_binlog_rpc_duration_seconds_bucket` + +* 报警规则: + + `histogram_quantile(0.9, rate(binlog_pump_rpc_duration_seconds_bucket{method="WriteBinlog"}[5m])) > 1` + +* 规则描述: + + Pump 处理 TiDB 写 Binlog 请求耗时过大。 + +* 处理方法: + + * 确认磁盘性能压力,通过 `node exported` 查看 disk performance 监控。 + * 如果 `disk latency` 和 `util` 都很低,请从 PingCAP 官方或 TiDB 社区[获取支持](/support.md)。 + +#### `binlog_pump_storage_write_binlog_duration_time_bucket` + +* 报警规则: + + `histogram_quantile(0.9, rate(binlog_pump_storage_write_binlog_duration_time_bucket{type="batch"}[5m])) > 1` + +* 规则描述: + + Pump 写本地 binlog 到本地盘的耗时。 + +* 处理方法: + + 确认 Pump 本地盘情况,进行修复。 + +#### `binlog_pump_storage_available_size_less_than_20G` + +* 报警规则: + + `binlog_pump_storage_storage_size_bytes{type="available"} < 20 * 1024 * 1024 * 1024` + +* 规则描述: + + Pump 剩余可用磁盘空间不足 20 G。 + +* 处理方法: + + 监控确认 Pump 的 `gc_tso` 是否正常。如果不正常,调整 Pump 的 GC 时间配置或者下线对应 Pump。 + +#### `binlog_drainer_checkpoint_tso_no_change_for_1m` + +* 报警规则: + + `changes(binlog_drainer_checkpoint_tso[1m]) < 1` + +* 规则描述: + + Drainer 的 `checkpoint` 在 1 分钟内没有更新。 + +* 处理方法: + + 确认所有非下线的 Pump 是否正常运行。 + +#### `binlog_drainer_execute_duration_time_more_than_10s` + +* 报警规则: + + `histogram_quantile(0.9, rate(binlog_drainer_execute_duration_time_bucket[1m])) > 10` + +* 规则描述: + + Drainer 同步到 TiDB 的事务耗时。如果这个值过大,会影响 Drainer 同步。 + +* 处理方法: + + * 查看 TiDB 集群的状态。 + * 查看 Drainer 日志或监控,如果是 DDL 操作导致了该问题,则忽略。 diff --git a/markdown-pages/zh/tidb/master/tidb-binlog/tidb-binlog-configuration-file.md b/markdown-pages/zh/tidb/master/tidb-binlog/tidb-binlog-configuration-file.md new file mode 100644 index 0000000..93b8f1f --- /dev/null +++ b/markdown-pages/zh/tidb/master/tidb-binlog/tidb-binlog-configuration-file.md @@ -0,0 +1,349 @@ +--- +title: TiDB Binlog 配置说明 +aliases: ['/docs-cn/dev/tidb-binlog/tidb-binlog-configuration-file/','/docs-cn/dev/reference/tidb-binlog/configs/'] +summary: TiDB Binlog 配置说明:介绍 Pump 和 Drainer 的配置项,包括地址、存储、安全和同步相关配置。 Pump 包括 addr、advertise-addr、socket、pd-urls、data-dir、heartbeat-interval、gen-binlog-interval、gc、log-file、log-level、node-id、security 和 storage 配置。 Drainer 包括 addr、advertise-addr、log-file、log-level、node-id、data-dir、detect-interval、pd-urls、initial-commit-ts、synced-check-time、compressor、security 和 syncer 配置。 +--- + +# TiDB Binlog 配置说明 + +本文档介绍 TiDB Binlog 的各项配置说明。 + +## Pump + +本节介绍 Pump 的配置项。可以在 [Pump Configuration](https://github.com/pingcap/tidb-binlog/blob/master/cmd/pump/pump.toml) 中查看完整的 Pump 配置文件示例。 + +### addr + +* HTTP API 的监听地址,格式为 `host:port`。 +* 默认:`"127.0.0.1:8250"` + +### advertise-addr + +* 对外可访问的 HTTP API 地址。这个地址会被注册到 PD,格式为 `host:port`。 +* 默认:与 `addr` 的配置相同。 + +### socket + +* HTTP API 监听的 Unix socket 地址。 +* 默认:`""` + +### pd-urls + +* 由逗号分隔的 PD URL 列表。如果指定了多个地址,PD 客户端在连接一个地址时出错时会自动尝试连接另一个地址。 +* 默认:`"http://127.0.0.1:2379"` + +### data-dir + +* 本地存放 binlog 及其索引的目录。 +* 默认:`"data.pump"` + +### heartbeat-interval + +* 心跳间隔,即每隔指定秒数向 PD 汇报最新的状态。 +* 默认:`2` + +### gen-binlog-interval + +* 指定写入 fake binlog 的间隔秒数。 +* 默认:`3` + +### gc + +* 指定 binlog 可在本地存储的天数(整型)。超过指定天数的 binlog 会被自动删除。 +* 默认:`7` + +### log-file + +* 保存日志文件的路径。如果为空,日志不会被保存。 +* 默认:`""` + +### log-level + +* Log 等级。 +* 默认:`"info"` + +### node-id + +* Pump 节点的 ID,用于在集群中识别这个进程。 +* 默认:`主机名:端口号`,例如 `node-1:8250`。 + +### security + +以下是与安全相关的配置项。 + +#### ssl-ca + +* 包含可信 SSL 证书或 CA 证书列表的文件路径,例如 `/path/to/ca.pem`。 +* 默认:`""` + +#### ssl-cert + +* 包含 PEM 格式编码的 X509 证书文件路径,例如 `/path/to/pump.pem`。 +* 默认:`""` + +#### ssl-key + +* 包含 PEM 格式编码的 X509 Key 文件路径,例如 `/path/to/pump-key.pem`。 +* 默认:`""` + +### storage + +以下是与存储相关的配置项。 + +#### sync-log + +* 指定是否在每次**批量**写入 binlog 后使用 `fsync` 以确保数据安全。 +* 默认:`true` + +#### kv_chan_cap + +* 在 Pump 接收写入请求时会先将请求放入一个缓冲区,该项指定缓冲区能存放的请求数量。 +* 默认:`1048576`(即 2 的 20 次方) + +#### slow_write_threshold + +* 写入单个 binlog 的耗时超过该项设定的秒数就被认为是慢写入,并输出一条包含 `"take a long time to write binlog"` 的日志。 +* 默认:`1` + +#### stop-write-at-available-space + +* 可用存储空间低于指定值时不再接收 binlog 写入请求。可以用例如 `900 MB`、`5 GB`、`12 GiB` 的格式指定空间大小。如果集群中 Pump 节点多于一个,那么在某个 Pump 节点因为空间不足而拒绝写入时,TiDB 端会自动写入到其他 Pump 节点。 +* 默认:`10 GiB` + +#### kv + +目前 Pump 的存储是基于 [GoLevelDB](https://github.com/syndtr/goleveldb) 实现的。`storage` 下还有一个 kv 子分组可以用于调整 GoLevelDB 的配置,支持的配置项包括: + +* block-cache-capacity +* block-restart-interval +* block-size +* compaction-L0-trigger +* compaction-table-size +* compaction-total-size +* compaction-total-size-multiplier +* write-buffer +* write-L0-pause-trigger +* write-L0-slowdown-trigger + +配置具体含义可在 [GoLevelDB 文档](https://godoc.org/github.com/syndtr/goleveldb/leveldb/opt#Options)中查看。 + +## Drainer + +本节介绍 Drainer 的配置项。可以在 [Drainer Configuration](https://github.com/pingcap/tidb-binlog/blob/master/cmd/drainer/drainer.toml) 中查看完整的配置文件示例。 + +### addr + +* HTTP API 的监听的地址,格式为 `host:port`。 +* 默认:`"127.0.0.1:8249"` + +### advertise-addr + +* 对外可访问的 HTTP API 地址,这个地址会被注册到 PD,格式为 `host:port`。 +* 默认:设定成与 `addr` 相同的配置 + +### log-file + +* 日志的文件保存路径。如果为空,日志不会被保存。 +* 默认:`""` + +### log-level + +* Log 等级。 +* 默认:`"info"` + +### node-id + +* Drainer 节点 ID,用于在集群中识别这个进程。 +* 默认:`主机名:端口号`,例如 `node-1:8249`。 + +### data-dir + +* 用于存放 Drainer 运行中需要保存的文件的目录。 +* 默认:`"data.drainer"` + +### detect-interval + +* 每隔指定秒数从 PD 更新一次 Pumps 信息,以获取节点加入或离开等事件。 +* 默认:`5` + +### pd-urls + +* 由逗号分隔的 PD URL 列表。如果指定了多个地址,PD 客户端在连接一个地址出错时会自动尝试连接另一个地址。 +* 默认:`"http://127.0.0.1:2379"` + +### initial-commit-ts + +* 指定从哪个事务提交时间点(事务的 commit ts) 之后开始同步。这个配置仅适用于初次开始同步的 Drainer 节点。如果下游已经有 checkpoint 存在,则会根据 checkpoint 里记录的时间进行同步。 +* commit ts(即 commit timestamp)是 TiDB [事务](/transaction-overview.md)的提交时间点。该时间点是从 PD 获取的全局唯一递增的时间戳,作为当前事务的唯一 ID。典型的 `initial-commit-ts` 配置可以通过以下方式获得: + - BR 备份的元信息(即 backupmeta)中记录的 backup TS + - Dumpling 备份的元信息(即 metadata)中记录的 Pos + - PD Control 中 `tso` 命令返回的结果 +* 默认:`-1`。Drainer 会从 PD 得到一个最新的 timestamp 作为初始时间。即从当前的时间点开始同步。 + +### synced-check-time + +* 通过 HTTP API 访问 `/status` 路径可以查询 Drainer 同步的状态。`synced-check-time` 指定距离上次成功同步的时间超过多少分钟可以认为是 `synced`,即同步完成。 +* 默认:`5` + +### compressor + +* 指定 Pump 与 Drainer 间的数据传输所用的压缩算法。目前仅支持一种算法,即 `gzip`。 +* 默认:`""`,表示不压缩。 + +### security + +以下是与 Drainer 安全相关的配置。 + +#### ssl-ca + +* 包含可信 SSL 证书或 CA 证书列表的文件路径,例如 `/path/to/ca.pem`。 +* 默认:`""` + +#### ssl-cert + +* 包含 PEM 格式编码的 X509 证书文件路径,例如 `/path/to/drainer.pem`。 +* 默认:`""` + +#### ssl-key + +* 包含 PEM 格式编码的 X509 Key 文件路径,例如 `/path/to/drainer-key.pem`。 +* 默认:`""` + +### syncer + +syncer 分组包含一些与同步下游相关的配置项。 + +#### db-type + +下游类型,目前支持的选项有: + +* `mysql` +* `tidb` +* `kafka` +* `file` + +默认:`mysql` + +#### sql-mode + +* 当下游为 `mysql`/`tidb` 类型时,可以指定 SQL mode,如果超过一个 mode,则用逗号隔开。 +* 默认:`""` + +#### ignore-txn-commit-ts + +* 同步时,该项所指定的 commit timestamp 的 binlog 会被忽略,例如 `[416815754209656834, 421349811963822081]`。 +* 默认:`[]` + +#### ignore-schemas + +* 同步时忽略指定数据库的变更。如果超过一个需忽略的数据库,则用逗号隔开。如果一个 binlog 中的变更全部被过滤掉,则忽略整个 binlog。 +* 默认:`"INFORMATION_SCHEMA,PERFORMANCE_SCHEMA,mysql"` + +#### ignore-table + +同步时忽略指定表格的变更。在 `toml` 中可以用以下方式指定多个需忽略的表格: + +```toml +[[syncer.ignore-table]] +db-name = "test" +tbl-name = "log" + +[[syncer.ignore-table]] +db-name = "test" +tbl-name = "audit" +``` + +如果一个 binlog 中的变更全部被过滤掉,则忽略整个 binlog。 + +默认:`[]` + +#### replicate-do-db + +* 指定要同步的数据库,例如 `[db1, db2]`。 +* 默认:`[]` + +#### replicate-do-table + +指定要同步的表格,示例如下: + +```toml +[[syncer.replicate-do-table]] +db-name ="test" +tbl-name = "log" + +[[syncer.replicate-do-table]] +db-name ="test" +tbl-name = "~^a.*" +``` + +默认:`[]` + +#### txn-batch + +* 当下游为 `mysql`/`tidb` 类型时,会将 DML 分批执行。这个配置可以用于设置每个事务中包含多少个 DML。 +* 默认:`20` + +#### worker-count + +* 当下游为 `mysql`/`tidb` 类型时,会并发执行 DML,`worker-count` 可以指定并发数。 +* 默认:`16` + +#### disable-dispatch + +* 关掉并发,强制将 `worker-count` 置为 `1`。 +* 默认:`false` + +#### safe-mode + +如果打开 Safe mode,Drainer 会对同步的变更作以下修改,使其变成可重入的操作: + +* `Insert` 变为 `Replace Into` +* `Update` 变为 `Delete` 和 `Replace Into` + +默认:`false` + +### syncer.to + +不同类型的下游配置都在 `syncer.to` 分组。以下按配置类型进行介绍。 + +#### mysql/tidb + +用于连接下游数据库的配置项: + +* `host`:如果没有设置,会尝试检查环境变量 `MYSQL_HOST`,默认值为 `"localhost"`。 +* `port`:如果没有设置,会尝试检查环境变量 `MYSQL_PORT`,默认值为 `3306`。 +* `user`:如果没有设置,会尝试检查环境变量 `MYSQL_USER`,默认值为 `"root"`。 +* `password`:如果没有设置,会尝试检查环境变量 `MYSQL_PSWD`,默认值为 `""`。 +* `read-timeout`:指定下游数据库连接的 IO 读取超时时间,默认值为 `1m`。如果 drainer 在一些耗时长的 DDL 上不断失败,你可以将这个变量设置为更大的值。 + +#### file + +* `dir`:指定用于保存 binlog 的目录。如果不指定该项,则使用 `data-dir`。 + +#### kafka + +当下游为 `kafka` 时,有效的配置包括: + +* `zookeeper-addrs` +* `kafka-addrs` +* `kafka-version` +* `kafka-max-messages` +* `kafka-max-message-size` +* `topic-name` + +### syncer.to.checkpoint + +* `type`:指定用哪种方式保存同步进度,目前支持的选项为 `mysql`、`tidb` 和 `file`。 + + 该配置选项默认与下游类型相同。例如 `file` 类型的下游 checkpoint 进度保存在本地文件 `/savepoint` 中,`mysql` 类型的下游进度保存在下游数据库。当明确指定要使用 `mysql` 或 `tidb` 保存同步进度时,需要指定以下配置项: + +* `schema`:默认为 `"tidb_binlog"`。 + + > **注意:** + > + > 在同个 TiDB 集群中部署多个 Drainer 时,需要为每个 Drainer 节点指定不同的 checkpoint schema,否则两个实例的同步进度会互相覆盖。 + +* `host` +* `user` +* `password` +* `port` diff --git a/markdown-pages/zh/tidb/master/tidb-binlog/tidb-binlog-faq.md b/markdown-pages/zh/tidb/master/tidb-binlog/tidb-binlog-faq.md new file mode 100644 index 0000000..4b32ba8 --- /dev/null +++ b/markdown-pages/zh/tidb/master/tidb-binlog/tidb-binlog-faq.md @@ -0,0 +1,237 @@ +--- +title: TiDB Binlog 常见问题 +aliases: ['/docs-cn/dev/tidb-binlog/tidb-binlog-faq/','/docs-cn/dev/reference/tidb-binlog/faq/','/docs-cn/dev/faq/tidb-binlog/','/docs-cn/dev/reference/tools/tidb-binlog/faq/'] +summary: TiDB Binlog 常见问题解决方案:性能影响、同步延迟、Drainer 权限、Pump 磁盘处理、同步中断处理、同步慢处理、Pump crash 处理、checkpoint 作用、Drainer 故障处理、全量+binlog 备份恢复、ignore-error 处理、DDL 执行错误处理、Pump/Drainer 暂停和下线处理。 +--- + +# TiDB Binlog 常见问题 + +本文介绍 TiDB Binlog 使用过程中的常见问题及解决方案。 + +## 开启 binog 对 TiDB 的性能有何影响? + +- 对于查询无影响。 + +- 对于有写入或更新数据的事务有一点性能影响。延迟上,在 Prewrite 阶段要并发写一条 p-binlog 成功后才可以提交事务,一般写 binlog 比 KV Prewrite 快,所以不会增加延迟。可以在 Pump 的监控面板看到写 binlog 的响应时间。 + +## TiDB Binlog 的同步延迟一般为多少? + +TiDB Binlog 的同步延迟为秒级别,在非业务高峰时延迟一般为 3 秒左右。 + +## Drainer 同步下游 TiDB/MySQL 的账号需要哪些权限? + +Drainer 同步账号需要有如下权限: + +* Insert +* Update +* Delete +* Create +* Drop +* Alter +* Execute +* Index +* Select +* Create View + +## Pump 磁盘快满了怎么办? + +确认 GC 正常: + +- 确认 pump 监控面板 **gc_tso** 时间是否与配置一致。 + +如 gc 正常以下调整可以降低单个 pump 需要的空间大小: + +- 调整 pump **GC** 参数减少保留数据天数。 +- 添加 pump 结点。 + +## Drainer 同步中断怎么办? + +使用以下 binlogctl 命令查看 Pump 状态是否正常,以及是否全部非 `offline` 状态的 Pump 都在正常运行。 + +```bash +binlogctl -cmd pumps +``` + +查看 Drainer 监控与日志是否有对应报错,根据具体问题进行处理。 + +## Drainer 同步下游 TiDB/MySQL 慢怎么办? + +特别关注以下监控项: + +- 通过 Drainer 监控 **drainer event**,可以看到 Drainer 当前每秒同步 Insert/Update/Delete 事件到下游的速度。 +- 通过 Drainer 监控 **sql query time**,可以看到 Drainer 在下游执行 SQL 的响应时间。 + +同步慢的可能原因与解决方案: + +- 同步的数据库包含没有主键或者唯一索引的表,需要给表加上主键。 +- Drainer 与下游之间延迟大,可以调大 Drainer `worker-count` 参数(跨机房同步建议将 Drainer 部署在下游)。 +- 下游负载不高,可以尝试调大 Drainer `worker-count` 参数。 + +## 假如有一个 Pump crash 了会怎样? + +Drainer 会因为获取不到这个 Pump 的数据没法同步数据到下游。如果这个 Pump 能恢复,Drainer 就能恢复同步。 + +如果 Pump 没法恢复,可采用以下方式进行处理: + +1. 使用 [binlogctl 将该 Pump 状态修改为 `offline`](/tidb-binlog/maintain-tidb-binlog-cluster.md)(丢失这个 Pump 的数据) +2. Drainer 获取到的数据会丢失这个 Pump 上的数据,下游跟上游数据会不一致,需要重新做全量 + 增量同步。具体步骤如下: + 1. 停止当前 Drainer。 + 2. 上游做全量备份。 + 3. 清理掉下游数据,包括 checkpoint 表 `tidb_binlog.checkpoint`。 + 4. 使用上游的全量备份恢复下游数据。 + 5. 部署 Drainer,使用 `initialCommitTs`= {从全量备份获取快照的时间戳}。 + +## 什么是 checkpoint? + +Checkpoint 记录了 Drainer 同步到下游的 commit-ts,Drainer 重启时可以读取 checkpoint 接着从对应 commit-ts 同步数据到下游。Drainer 日志 `["write save point"] [ts=411222863322546177]` 表示保存对应时间戳的 checkpoint。 + +下游类型不同,checkpoint 的保存方式也不同: + +- 下游 MySQL/TiDB 保存在 `tidb_binlog.checkpoint` 表。 +- 下游 kafka/file 保存在对应配置目录里的文件。 + +因为 kafka/file 的数据内容包含了 commit-ts,所以如果 checkpoint 丢失,可以消费下游最新的一条数据看写到下游数据的最新 commit-ts。 + +Drainer 启动的时候会去读取 checkpoint,如果读取不到,就会使用配置的 `initial-commit-ts` 做为初次启动开始的同步时间点。 + +## Drainer 机器发生故障,下游数据还在,如何在新机器上重新部署 Drainer? + +如果下游数据还在,只要保证能从对应 checkpoint 接着同步即可。 + +假如 checkpoint 还在,可采用以下方式进行处理: + +1. 部署新的 Drainer 并启动即可(参考 checkpoint 介绍,Drainer 可以读取 checkpoint 接着同步)。 +2. 使用 [binlogctl 将老的 Drainer 状态修改成 `offline`](/tidb-binlog/maintain-tidb-binlog-cluster.md)。 + +假如 checkpoint 不在,可以如下处理: + +1. 获取之前 Drainer 的 checkpoint `commit-ts`,做为新部署 Drainer 的 `initial-commit-ts` 配置来部署新的 Drainer。 +2. 使用 [binlogctl 将老的 Drainer 状态修改成 `offline`](/tidb-binlog/maintain-tidb-binlog-cluster.md)。 + +## 如何用全量 + binlog 备份文件来恢复一个集群? + +1. 清理集群数据并使用全部备份恢复数据。 +2. 使用 reparo 设置 `start-tso` = {全量备份文件快照时间戳+1},`end-ts` = 0(或者指定时间点),恢复到备份文件最新的数据。 + +## 主从同步开启 `ignore-error` 触发 critical error 后如何重新部署? + +TiDB 配置开启 `ignore-error` 写 binlog 失败后触发 critical error 告警,后续都不会再写 binlog,所以会有 binlog 数据丢失。如果要恢复同步,需要如下处理: + +1. 停止当前 Drainer。 +2. 重启触发 critical error 的 `tidb-server` 实例重新开始写 binlog(触发 critical error 后不会再写 binlog 到 pump)。 +3. 上游做全量备份。 +4. 清理掉下游数据包括 checkpoint 表 `tidb_binlog.checkpoint`。 +5. 使用上游的全量备份恢复下游。 +6. 部署 Drainer,使用 `initialCommitTs`= {从全量备份获取快照的时间戳}。 + +## 同步时出现上游数据库支持但是下游数据库执行会出错的 DDL,应该怎么办? + +1. 查看 drainer.log 日志,查找 `exec failed` 找到 Drainer 退出前最后一条执行失败的 DDL。 +2. 将 DDL 改为下游兼容支持的版本,在下游数据库中手动执行。 +3. 查看 drainer.log 日志,查找执行失败的 DDL 语句,可以查询到该 DDL 的 commit-ts。例如: + + ``` + [2020/05/21 09:51:58.019 +08:00] [INFO] [syncer.go:398] ["add ddl item to syncer, you can add this commit ts to `ignore-txn-commit-ts` to skip this ddl if needed"] [sql="ALTER TABLE `test` ADD INDEX (`index1`)"] ["commit ts"=416815754209656834]。 + ``` + +4. 编辑 `drainer.toml` 配置文件,在 `ignore-txn-commit-ts` 项中添加该 commit-ts,重启 Drainer。 + +在绝大部分情况下,TiDB 和 MySQL 的语句都是兼容的。用户需要注意的是上下游的 `sql_mode` 应当保持一致。 + +## 在什么情况下暂停和下线 Pump/Drainer? + +首先需要通过以下内容来了解 Pump/Drainer 的状态定义和启动、退出的流程。 + +暂停主要针对临时需要停止服务的场景,例如: + +- 版本升级:停止进程后使用新的 binary 启动服务。 +- 服务器维护:需要对服务器进行停机维护。退出进程,等维护完成后重启服务。 + +下线主要针对永久(或长时间)不再使用该服务的场景,例如: + +- Pump 缩容:不再需要那么多 Pump 服务了,所以下线部分服务。 +- 同步任务取消:不再需要将数据同步到某个下游,所以下线对应的 Drainer。 +- 服务器迁移:需要将服务迁移到其他服务器。下线服务,在新的服务器上重新部署。 + +## 可以通过哪些方式暂停 Pump/Drainer? + +- 直接 kill 进程。 + + >**注意:** + > + > 不能使用 `kill -9` 命令,否则 Pump/Drainer 无法对信号进行处理。 + +- 如果 Pump/Drainer 运行在前台,则可以通过按下 Ctrl+C 来暂停。 +- 使用 binlogctl 的 `pause-pump` 或 `pause-drainer` 命令。 + +## 可以使用 binlogctl 的 `update-pump`/`update-drainer` 命令来下线 Pump/Drainer 服务吗? + +不可以。使用 `update-pump`/`update-drainer` 命令会直接修改 PD 中保存的状态信息,并且不会通知 Pump/Drainer 做相应的操作。使用不当时,可能会干扰数据同步,某些情况下还可能会造成**数据不一致**的严重后果。例如: + +- 当 Pump 正常运行或者处于暂停状态时,如果使用 `update-pump` 将该 Pump 设置为 `offline`,那么 Drainer 会放弃获取处于 `offline` 状态的 Pump 的 binlog 数据,导致该 Pump 最新的 binlog 数据没有同步到 Drainer,造成上下游数据不一致。 +- 当 Drainer 正常运行时,使用 `update-drainer` 命令将该 Drainer 设置为 `offline`。如果这时启动一个 Pump 节点,Pump 只会通知 `online` 状态的 Drainer,导致该 Drainer 没有及时获取到该 Pump 的 binlog 数据,造成上下游数据不一致。 + +## 可以使用 binlogctl 的 `update-pump`/`update-drainer` 命令来暂停 Pump/Drainer 服务吗? + +不可以。`update-pump`/`update-drainer` 命令直接修改 PD 中保存的状态信息。执行这个命令并不会通知 Pump/Drainer 做相应的操作,**而且使用不当会使数据同步中断,甚至造成数据丢失。** + +## 什么情况下使用 binlogctl 的 `update-pump` 命令设置 Pump 状态为 `paused`? + +在某些异常情况下,Pump 没有正确维护自己的状态,实际上状态应该为 `paused`。这时可以使用 `update-pump` 对状态进行修正,例如: + +- Pump 异常退出(可能由 panic 或者误操作执行 `kill -9` 命令直接 kill 掉进程导致),Pump 保存在 PD 中的状态仍然为 `online`。如果暂时不需要重启 Pump 恢复服务,可以使用 `update-pump` 把该 Pump 状态设置为 `paused`,避免对 TiDB 写 binlog 和 Drainer 获取 binlog 造成干扰。 + +## 什么情况下使用 binlogctl 的 `update-drainer` 命令设置 Drainer 状态为 `paused`? + +在某些异常情况下,Drainer 没有正确维护自己的状态,,对数据同步造成了影响,实际上状态应该为 `paused`。这时可以使用 `update-drainer` 对状态进行修正,例如: + +- Drainer 异常退出(出现 panic 直接退出进程,或者误操作执行 `kill -9` 命令直接 kill 掉进程),Drainer 保存在 PD 中的状态仍然为 `online`。当 Pump 启动时无法正常通知该 Drainer(报错 `notify drainer ...`),导致 Pump 无法正常运行。这个时候可以使用 `update-drainer` 将 Drainer 状态更新为 `paused`,再启动 Pump。 + +## 可以通过哪些方式下线 Pump/Drainer? + +目前只可以使用 binlogctl 的 `offline-pump` 和 `offline-drainer` 命令来下线 Pump 和 Drainer。 + +## 什么情况下使用 binlogctl 的 `update-pump` 命令设置 Pump 状态为 `offline`? + +> **警告:** +> +> 仅在可以容忍 binlog **数据丢失、上下游数据不一致**或者确认不再需要使用该 Pump 存储的 binlog 数据的情况下,才能使用 `update-pump` 修改 Pump 状态为 `offline`。 + +可以使用 `update-pump` 修改 Pump 状态为 `offline` 的情况有: + +- 在某些情况下,Pump 异常退出进程,且无法恢复服务,同步就会中断。如果希望恢复同步且可以容忍部分 binlog 数据丢失,可以使用 `update-pump` 命令将该 Pump 状态设置为 `offline`,则 Drainer 会放弃拉取该 Pump 的 binlog 然后继续同步数据。 +- 有从历史任务遗留下来且不再使用的 Pump 且进程已经退出(例如测试使用的服务),之后不再需要使用该服务,使用 `update-pump` 将该 Pump 设置为 `offline`。 + +在其他情况下一定要使用 `offline-pump` 命令让 Pump 走正常的下线处理流程。 + +## Pump 进程已经退出,且状态为 `paused`,现在不想使用这个 Pump 节点了,能否用 binlogctl 的 `update-pump` 命令设置节点状态为 `offline`? + +Pump 以 `paused` 状态退出进程时,不保证所有 binlog 数据被下游 Drainer 消费。所以这样做会有上下游数据不一致的风险。正确的做法是重新启动 Pump,然后使用 `offline-pump` 下线该 Pump。 + +## 什么情况下使用 binlogctl 的 `update-drainer` 命令设置 Drainer 状态为 `offline`? + +- 有从历史任务遗留下来且不再使用的 Drainer 且进程已经退出(例如测试使用的服务),之后不再需要使用该服务,使用 `update-drainer` 将该 Drainer 设置为 `offline`。 + +## 可以使用 `change pump`、`change drainer` 等 SQL 操作来暂停或者下线 Pump/Drainer 服务吗? + +目前还不支持。这种 SQL 操作会直接修改 PD 中保存的状态,在功能上等同于使用 binlogctl 的 `update-pump`、`update-drainer` 命令。如果需要暂停或者下线,仍然要使用 binlogctl。 + +## TiDB 写入 binlog 失败导致 TiDB 卡住,日志中出现 `listener stopped, waiting for manual stop` + +在 TiDB v3.0.12 以及之前,binlog 写入失败会导致 TiDB 报 fatal error。但是 TiDB 不会自动退出只是停止服务,看起来像服务卡住。TiDB 日志中可看到 `listener stopped, waiting for manual stop`。 + +遇到该问题需要根据具体情况判断是什么原因导致 binlog 写入失败。如果是 binlog 写入下游缓慢导致的,可以考虑扩容 Pump 或增加写 binlog 的超时时间。 + +TiDB 在 v3.0.13 版本中已优化此逻辑,写入 binlog 失败将使事务执行失败返回报错,而不会导致 TiDB 卡住。 + +## TiDB 向 Pump 写入了重复的 binlog? + +TiDB 在写入 binlog 失败或者超时的情况下,会重试将 binlog 写入到下一个可用的 Pump 节点直到写入成功。所以如果写入到某个 Pump 节点较慢,导致 TiDB 超时(默认 15s),此时 TiDB 判定写入失败并尝试写入下一个 Pump 节点。如果超时的 Pump 节点实际也写入成功,则会出现同一条 binlog 被写入到多个 Pump 节点。Drainer 在处理 binlog 的时候,会自动去重 TSO 相同的 binlog,所以这种重复的写入对下游无感知,不会对同步逻辑产生影响。 + +## 在使用全量 + 增量方式恢复的过程中,Reparo 中断了,可以使用日志里面最后一个 TSO 恢复同步吗? + +可以。Reparo 不会在启动时自动开启 safe-mode 模式,需要手动操作: + +1. Reparo 中断后,记录日志中最后一个 TSO,记为 `checkpoint-tso`。 +2. 修改 Reparo 配置文件,将配置项 `start-tso` 设为 `checkpoint-tso + 1`,将 `stop-tso` 设为 `checkpoint-tso + 80,000,000,000`(大概是 `checkpoint-tso` 延后 5 分钟),将 `safe-mode` 设置为 `true`。启动 Reparo,Reparo 会将数据同步到 `stop-tso` 后自动停止。 +3. Reparo 自动停止后,将 `start-tso` 设置为 `checkpoint tso + 80,000,000,001`,将 `stop-tso` 设置为 `0`,将 `safe-mode` 设为 `false`。启动 Reparo 继续同步。 diff --git a/markdown-pages/zh/tidb/master/tidb-binlog/tidb-binlog-overview.md b/markdown-pages/zh/tidb/master/tidb-binlog/tidb-binlog-overview.md new file mode 100644 index 0000000..cb00ff2 --- /dev/null +++ b/markdown-pages/zh/tidb/master/tidb-binlog/tidb-binlog-overview.md @@ -0,0 +1,79 @@ +--- +title: TiDB Binlog 简介 +aliases: ['/docs-cn/dev/tidb-binlog/tidb-binlog-overview/','/docs-cn/dev/reference/tidb-binlog/overview/','/docs-cn/dev/reference/tidb-binlog-overview/','/docs-cn/dev/reference/tools/tidb-binlog/overview/'] +summary: TiDB Binlog 是用于收集 TiDB 的 binlog 并提供实时备份和同步功能的商业工具。它支持数据同步和实时备份恢复功能。从 TiDB v7.5.0 开始,数据同步功能不再提供技术支持,建议使用 TiCDC 作为替代方案。TiDB Binlog 集群主要包括 Pump 和 Drainer 两个组件,以及 binlogctl 工具。Pump 用于记录并排序 Binlog,Drainer 用于归并排序并将 Binlog 同步到下游。TiDB Binlog 还有一些注意事项,包括与 TiDB v5.0 版本引入的一些特性不兼容,以及 Drainer 支持将 Binlog 同步到 MySQL、TiDB、Kafka 或本地文件。 +--- + +# TiDB Binlog 简介 + +TiDB Binlog 是一个用于收集 TiDB 的 binlog,并提供准实时备份和同步功能的商业工具。 + +TiDB Binlog 支持以下功能场景: + +- **数据同步**:同步 TiDB 集群数据到其他数据库。 +- **实时备份和恢复**:备份 TiDB 集群数据,同时可以用于 TiDB 集群故障时恢复。 + +> **注意:** +> +> - TiDB Binlog 与 TiDB v5.0 开始引入的一些特性不兼容,无法一起使用,详情参照[注意事项](#注意事项)。 +> - 从 TiDB v7.5.0 开始,TiDB Binlog 组件的数据同步功能不再提供技术支持,强烈建议使用 [TiCDC](/ticdc/ticdc-overview.md) 作为数据同步的替代方案。 +> - 尽管 TiDB v7.5.0 仍支持 TiDB Binlog 组件的实时备份和恢复,但该组件在未来版本中将被完全废弃,推荐使用 [PITR](/br/br-pitr-guide.md) 作为数据恢复的替代方案。 + +要快速了解 Binlog 的基本原理和使用方法,建议先观看下面的培训视频(时长 32 分钟)。注意本视频只为学习参考,具体操作步骤和最新功能,请以文档内容为准。 + + + +## TiDB Binlog 整体架构 + +![TiDB Binlog 架构](/media/tidb-binlog-cluster-architecture.png) + +TiDB Binlog 集群主要分为 Pump 和 Drainer 两个组件,以及 binlogctl 工具: + +### Pump + +[Pump](https://github.com/pingcap/tidb-binlog/blob/master/pump) 用于实时记录 TiDB 产生的 Binlog,并将 Binlog 按照事务的提交时间进行排序,再提供给 Drainer 进行消费。 + +### Drainer + +[Drainer](https://github.com/pingcap/tidb-binlog/tree/master/drainer) 从各个 Pump 中收集 Binlog 进行归并,再将 Binlog 转化成 SQL 或者指定格式的数据,最终同步到下游。 + +### binlogctl 工具 + +[`binlogctl`](https://github.com/pingcap/tidb-binlog/tree/master/binlogctl) 是一个 TiDB Binlog 配套的运维工具,具有如下功能: + +* 获取 TiDB 集群当前的 TSO +* 查看 Pump/Drainer 状态 +* 修改 Pump/Drainer 状态 +* 暂停/下线 Pump/Drainer + +## 主要特性 + +* 多个 Pump 形成一个集群,可以水平扩容。 +* TiDB 通过内置的 Pump Client 将 Binlog 分发到各个 Pump。 +* Pump 负责存储 Binlog,并将 Binlog 按顺序提供给 Drainer。 +* Drainer 负责读取各个 Pump 的 Binlog,归并排序后发送到下游。 +* Drainer 支持 [relay log](/tidb-binlog/tidb-binlog-relay-log.md) 功能,通过 relay log 保证下游集群的一致性状态。 + +## 注意事项 + +* TiDB Binlog 和 TiDB 在 v5.1 版本中解决了 v5.0 版本中引入的聚簇索引与 TiDB Binlog 不兼容问题。在升级 TiDB Binlog 和 TiDB Server 到 v5.1 版本后:开启 TiDB Binlog 后,TiDB 支持创建聚簇索引表;聚簇索引表的数据插入、删除和更新操作支持通过 TiDB Binlog 同步到下游。对于同步聚簇索引表时需注意: + + - 如果从 v5.0 版本手动控制组件升级顺序进行升级,请确保先将 TiDB Binlog 升级至 v5.1 版本后再将 TiDB Server 升级至 v5.1 版本。 + - 推荐将上下游的 TiDB 系统变量 [`tidb_enable_clustered_index`](/system-variables.md#tidb_enable_clustered_index-从-v50-版本开始引入) 配置为一致的值来保证上下游 TiDB 聚簇索引表结构一致。 + +* TiDB Binlog 与 TiDB v5.0 版本开始引入的以下特性不兼容,无法一起使用: + + - [TiDB 聚簇索引特性](/clustered-indexes.md#限制):开启 TiDB Binlog 后 TiDB 不允许创建非单个整数列作为主键的聚簇索引;已创建的聚簇索引表的数据插入、删除和更新动作不会通过 TiDB Binlog 同步到下游。如需同步聚簇索引表,请升级至 v5.1 版本或使用 [TiCDC](/ticdc/ticdc-overview.md); + - TiDB 系统变量 [tidb_enable_async_commit](/system-variables.md#tidb_enable_async_commit-从-v50-版本开始引入):启用 TiDB Binlog 后,开启该选项无法获得性能提升。要获得性能提升,建议使用 [TiCDC](/ticdc/ticdc-overview.md) 替代 TiDB Binlog。 + - TiDB 系统变量 [tidb_enable_1pc](/system-variables.md#tidb_enable_1pc-从-v50-版本开始引入):启用 TiDB Binlog 后,开启该选项无法获得性能提升。要获得性能提升,建议使用 [TiCDC](/ticdc/ticdc-overview.md) 替代 TiDB Binlog。 + +* Drainer 支持将 Binlog 同步到 MySQL、TiDB、Kafka 或者本地文件。如果需要将 Binlog 同步到其他 Drainer 不支持的类型的系统中,可以设置 Drainer 将 Binlog 同步到 Kafka,然后根据 binlog consumer protocol 进行定制处理,参考 [Binlog Consumer Client 用户文档](/tidb-binlog/binlog-consumer-client.md)。 + +* 如果 TiDB Binlog 用于增量恢复,可以设置配置项 `db-type="file"`,Drainer 会将 binlog 转化为指定的 [proto buffer 格式](https://github.com/pingcap/tidb-binlog/blob/master/proto/pb_binlog.proto)的数据,再写入到本地文件中。这样就可以使用 [Reparo](/tidb-binlog/tidb-binlog-reparo.md) 恢复增量数据。 + + 关于 `db-type` 的取值,应注意: + + - 如果 TiDB 版本 < 2.1.9,则 `db-type="pb"`。 + - 如果 TiDB 版本 > = 2.1.9,则 `db-type="file"` 或 `db-type="pb"`。 + +* 如果下游为 MySQL/TiDB,数据同步后可以使用 [sync-diff-inspector](/sync-diff-inspector/sync-diff-inspector-overview.md) 进行数据校验。 diff --git a/markdown-pages/zh/tidb/master/tidb-binlog/tidb-binlog-relay-log.md b/markdown-pages/zh/tidb/master/tidb-binlog/tidb-binlog-relay-log.md new file mode 100644 index 0000000..1741447 --- /dev/null +++ b/markdown-pages/zh/tidb/master/tidb-binlog/tidb-binlog-relay-log.md @@ -0,0 +1,56 @@ +--- +title: TiDB Binlog Relay Log +aliases: ['/docs-cn/dev/tidb-binlog/tidb-binlog-relay-log/','/docs-cn/dev/reference/tidb-binlog/relay-log/','/docs-cn/dev/reference/tools/tidb-binlog/relay-log/'] +summary: TiDB Binlog Relay Log 是用于确保下游集群与上游集群数据一致的工具。Drainer 同步时会拆分上游事务并并发同步到下游,使用 relay log 来恢复下游集群到一致状态。Drainer 会将 binlog event 写入磁盘并同步给下游,同时会清理已完成同步的 relay log 文件。配置中需指定保存 relay log 的目录和单个文件大小限制。 +--- + +# TiDB Binlog Relay Log + +Drainer 同步 binlog 时会拆分上游的事务,并将拆分的事务并发同步到下游。在极端情况下,上游集群不可用并且 Drainer 异常退出后,下游集群(MySQL 或 TiDB)可能处于数据不一致的中间状态。在此场景下,Drainer 借助 relay log 可以确保将下游集群同步到一个一致的状态。 + +## Drainer 同步时的一致性状态 + +下游集群达到一致的状态是指:下游集群的数据等同于上游设置了 `tidb_snapshot = ts` 的快照。 + +checkpoint 状态一致性是指:Drainer checkpoint 通过 `consistent` 保存了同步的一致性状态。Drainer 运行时 `consistent` 为 `false`,Drainer 正常退出后 `consistent` 更新为 `true`。 + +查询下游 checkpoint 表的示例如下: + +``` +mysql> select * from tidb_binlog.checkpoint; ++---------------------+----------------------------------------------------------------+ +| clusterID | checkPoint | ++---------------------+----------------------------------------------------------------+ +| 6791641053252586769 | {"consistent":false,"commitTS":414529105591271429,"ts-map":{}} | ++---------------------+----------------------------------------------------------------+ +``` + +## 工作原理 + +Drainer 开启 relay log 后会先将 binlog event 写到磁盘上,然后再同步给下游集群。如果上游集群不可用,Drainer 可以通过读取 relay log 把下游集群恢复到一个一致的状态。 + +> **注意:** +> +> 若同时丢失 relay log 数据,该方法将不可用,不过这是概率极小的事件。此外可以使用 NFS 等网络文件系统来保证 relay log 的数据安全。 + +### Drainer 从 relay log 消费 binlog 的触发场景 + +如果 Drainer 启动时无法连接到上游集群的 PD,并且探测到 checkpoint 的 `consistent = false`,此时会尝试读取 relay log,并将下游集群恢复到一致的状态。然后 Drainer 进程将 checkpoint 的 `consistent` 设置为 `true` 后主动退出。 + +### Relay log 的清理(GC)机制 + +Drainer 在将数据同步到下游之前,会先将数据写入到 relay log 文件中。当一个 relay log 文件大小达到 10MB(默认)并且当前事务的 binlog 数据被写入完成后,Drainer 就会开始将数据写入到下一个 relay log 文件中。当 Drainer 将数据成功同步到下游后,就会自动清除当前正在写入的 relay log 文件以外其他已完成同步的 relay log 文件。 + +## 配置 + +在 Drainer 中添加以下配置来开启 relay log 功能: + +``` +[syncer.relay] +# 保存 relay log 的目录,空值表示不开启。 +# 只有下游是 TiDB 或 MySQL 时该配置才有生效。 +log-dir = "/dir/to/save/log" +# 单个 relay log 文件大小限制(单位:字节)。 +# 超出该值后会将 binlog 数据写入到下一个 relay log 文件。 +max-file-size = 10485760 +``` diff --git a/markdown-pages/zh/tidb/master/tidb-binlog/tidb-binlog-reparo.md b/markdown-pages/zh/tidb/master/tidb-binlog/tidb-binlog-reparo.md new file mode 100644 index 0000000..be9ca62 --- /dev/null +++ b/markdown-pages/zh/tidb/master/tidb-binlog/tidb-binlog-reparo.md @@ -0,0 +1,105 @@ +--- +title: Reparo 使用文档 +aliases: ['/docs-cn/dev/tidb-binlog/tidb-binlog-reparo/','/docs-cn/dev/reference/tidb-binlog/reparo/','/docs-cn/dev/reference/tools/tidb-binlog/reparo/'] +summary: Reparo 是 TiDB Binlog 的配套工具,用于增量恢复。通过 Drainer 将 binlog 输出到文件,使用 Reparo 解析并应用到 TiDB/MySQL 中。安装包位于 TiDB 离线工具包中。使用命令行参数设置日志输出信息等级、同步下游的并发数等。配置文件可设置存储路径、日志等级、恢复时间范围、下游服务类型等。启动示例为 ./reparo -config reparo.toml。 +--- + +# Reparo 使用文档 + +Reparo 是 TiDB Binlog 的一个配套工具,用于增量的恢复。使用 TiDB Binlog 中的 Drainer 将 binlog 按照 protobuf 格式输出到文件,通过这种方式来备份增量数据。当需要恢复增量数据时,使用 Reparo 解析文件中的 binlog,并将其应用到 TiDB/MySQL 中。 + +Reparo 的安装包 `reparo` 位于 TiDB 离线工具包中。下载方式,请参考 [TiDB 工具下载](/download-ecosystem-tools.md)。 + +## Reparo 使用 + +### 命令行参数说明 + +``` +Usage of Reparo: +-L string + 日志输出信息等级设置:debug, info, warn, error, fatal(默认值:info)。 +-V 打印版本信息。 +-c int + 同步下游的并发数,该值设置越高同步的吞吐性能越好(默认 16)。 +-config string + 配置文件路径,如果指定了配置文件,Reparo 会首先读取配置文件的配置;如果对应的配置在命令行参数里面也存在,Reparo 就会使用命令行参数的配置来覆盖配置文件里面的。 +-data-dir string + Drainer 输出的 protobuf 格式 binlog 文件的存储路径 (默认值: data.drainer)。 +-dest-type string + 下游服务类型。 取值为 print, mysql(默认值:print)。当值为 print 时,只做解析打印到标准输出,不执行 SQL;如果为 mysql,则需要在配置文件内配置 host、port、user、password 等信息。 +-log-file string + log 文件路径。 +-log-rotate string + log 文件切换频率,取值为 hour、day。 +-start-datetime string + 用于指定开始恢复的时间点,格式为 “2006-01-02 15:04:05”。如果不设置该参数则从最早的 binlog 文件开始恢复。 +-stop-datetime string + 用于指定结束恢复的时间点,格式同上。如果不设置该参数则恢复到最后一个 binlog 文件。 +-safe-mode bool + 指定是否开启安全模式,开启后可支持反复同步。 +-txn-batch int + 输出到下游数据库一个事务的 SQL 语句数量(默认 20)。 +``` + +### 配置文件说明 + +```toml +# Drainer 输出的 protobuf 格式 binlog 文件的存储路径。 +data-dir = "./data.drainer" + +# 日志输出信息等级设置:debug, info, warn, error, fatal (默认值:info)。 +log-level = "info" + +# 使用 start-datetime 和 stop-datetime 来选择恢复指定时间范围内的 binlog,格式为 “2006-01-02 15:04:05”。 +# start-datetime = "" +# stop-datetime = "" + +# start-tso、stop-tso 分别对应 start-datetime 和 stop-datetime,也是用于恢复指定时间范围内的 binlog,用 tso 的值来设置。如果已经设置了 start-datetime 和 stop-datetime,就不需要再设置 start-tso 和 stop-tso。 +# 在从全量或者上次增量位置继续同步时,start-tso 应当指定为全量 tso + 1 或者上次增量的 stop-tso + 1 +# start-tso = 0 +# stop-tso = 0 + +# 下游服务类型。 取值为 print, mysql(默认值:print)。当值为 print 时,只做解析打印到标准输出,不执行 SQL;如果为 mysql,则需要在 [dest-db] 中配置 host、port、user、password 等信息。 +dest-type = "mysql" + +# 输出到下游数据库一个事务的 SQL 语句数量(默认 20)。 +txn-batch = 20 + +# 同步下游的并发数,该值设置越高同步的吞吐性能越好(默认 16)。 +worker-count = 16 + +# 安全模式配置。取值为 true 或 false(默认值:false)。当值为 true 时,Reparo 会将 update 语句拆分为 delete + replace 语句。 +safe-mode = false + +# replicate-do-db 和 replicate-do-table 用于指定恢复的库和表,replicate-do-db 的优先级高于 replicate-do-table。支持使用正则表达式来配置,需要以 '~' 开始声明使用正则表达式。 +# 注:replicate-do-db 和 replicate-do-table 使用方式与 Drainer 的使用方式一致。 +# replicate-do-db = ["~^b.*","s1"] +# [[replicate-do-table]] +# db-name ="test" +# tbl-name = "log" +# [[replicate-do-table]] +# db-name ="test" +# tbl-name = "~^a.*" + +# 如果 dest-type 设置为 mysql, 需要配置 dest-db。 +[dest-db] +host = "127.0.0.1" +port = 3309 +user = "root" +password = "" +``` + +### 启动示例 + +```bash +./reparo -config reparo.toml +``` + +> **注意:** +> +> - data-dir 用于指定 Drainer 输出的 binlog 文件目录。 +> - start-datatime 和 start-tso 效果一样,只是时间格式上的区别,用于指定开始恢复的时间点;如果不指定,则默认在第一个 binlog 文件开始恢复。 +> - stop-datetime 和 stop-tso 效果一样,只是时间格式上的区别,用于指定结束恢复的时间点;如果不指定,则恢复到最后一个 binlog 文件的结尾。 +> - dest-type 指定目标类型,取值为 `mysql`、`print`。 当值为 `mysql` 时,可以恢复到 MySQL/TiDB 等使用或兼容 MySQL 协议的数据库,需要在配置下面的 [dest-db] 填写数据库信息;当取值为 `print` 的时候,只是打印 binlog 信息,通常用于 debug,以及查看 binlog 的内容,此时不需要填写 `[dest-db]`。 +> - replicate-do-db 用于指定恢复的库,不指定的话,则全部都恢复。 +> - replicate-do-table 用于指定要恢复的表,不指定的话,则全部都恢复。 diff --git a/markdown-pages/zh/tidb/master/tidb-binlog/troubleshoot-tidb-binlog.md b/markdown-pages/zh/tidb/master/tidb-binlog/troubleshoot-tidb-binlog.md new file mode 100644 index 0000000..d636d5a --- /dev/null +++ b/markdown-pages/zh/tidb/master/tidb-binlog/troubleshoot-tidb-binlog.md @@ -0,0 +1,19 @@ +--- +title: TiDB Binlog 故障诊断 +aliases: ['/docs-cn/dev/tidb-binlog/troubleshoot-tidb-binlog/','/docs-cn/dev/reference/tidb-binlog/troubleshoot/binlog/','/docs-cn/dev/how-to/troubleshoot/tidb-binlog/'] +summary: TiDB Binlog 故障诊断总结了使用过程中遇到问题的诊断流程,并指引用户通过监控、状态、日志等信息查找解决方案。排查问题的方式包括查看监控指标、使用 binlogctl 工具查看 Pump、Drainer 状态,以及查看日志中的 ERROR 和 WARN 信息。定位到问题后,在 FAQ 和常见错误及修复中查找解决方案,如无法解决问题可提交 issue 或获取支持。 +--- + +# TiDB Binlog 故障诊断 + +本文总结了在 TiDB Binlog 的使用过程中遇到问题的诊断流程,并指引用户通过监控、状态、日志等信息查找相应的解决方案。 + +如果你在使用 TiDB Binlog 时出现了异常,请尝试以下方式排查问题: + +1. 查看各个监控指标是否异常,参见[TiDB Binlog 集群监控](/tidb-binlog/monitor-tidb-binlog-cluster.md)。 + +2. 使用 [binlogctl 工具](/tidb-binlog/binlog-control.md)查看各个 Pump、Drainer 的状态是否有异常。 + +3. 查看 Pump、Drainer 日志中是否有 `ERROR`、`WARN`,并根据详细的日志信息初步判断问题原因。 + +通过以上方式定位到问题后,在 [FAQ](/tidb-binlog/tidb-binlog-faq.md) 以及[常见错误及修复](/tidb-binlog/handle-tidb-binlog-errors.md) 中查找解决方案,如果没有查找到解决方案或者提供的解决方案无法解决问题,请提交 [issue](https://github.com/pingcap/tidb-binlog/issues),或从 PingCAP 官方或 TiDB 社区[获取支持](/support.md)。 diff --git a/markdown-pages/zh/tidb/master/tidb-binlog/upgrade-tidb-binlog.md b/markdown-pages/zh/tidb/master/tidb-binlog/upgrade-tidb-binlog.md new file mode 100644 index 0000000..4db8918 --- /dev/null +++ b/markdown-pages/zh/tidb/master/tidb-binlog/upgrade-tidb-binlog.md @@ -0,0 +1,72 @@ +--- +title: TiDB Binlog 版本升级方法 +aliases: ['/docs-cn/dev/tidb-binlog/upgrade-tidb-binlog/','/docs-cn/dev/reference/tidb-binlog/upgrade/','/docs-cn/dev/how-to/upgrade/tidb-binlog/','/docs-cn/dev/reference/tools/tidb-binlog/upgrade/'] +summary: TiDB Binlog 版本升级方法介绍了手动部署的步骤,包括升级 Pump 和 Drainer。同时,还介绍了从 Kafka/Local 版本升级到 Cluster 版本的流程,以及如何确认数据同步完成后启动新版本的 Drainer。强烈建议使用 PITR 作为数据恢复的替代方案。 +--- + +# TiDB Binlog 版本升级方法 + +如未特别指明,文中出现的 TiDB Binlog 均指最新的 [Cluster](/tidb-binlog/tidb-binlog-overview.md) 版本。 + +> **注意:** +> +> - TiDB Binlog 与 TiDB v5.0 开始引入的一些特性不兼容,无法一起使用,详情参照[注意事项](/tidb-binlog/tidb-binlog-overview.md#注意事项)。 +> - 从 TiDB v7.5.0 开始,TiDB Binlog 组件的数据同步功能不再提供技术支持,强烈建议使用 [TiCDC](/ticdc/ticdc-overview.md) 作为数据同步的替代方案。 +> - 尽管 TiDB v7.5.0 仍支持 TiDB Binlog 组件的实时备份和恢复,但该组件在未来版本中将被完全废弃,推荐使用 [PITR](/br/br-pitr-guide.md) 作为数据恢复的替代方案。 + +本文介绍通过手动部署的 TiDB Binlog 的版本升级方法,另外有一小节介绍如何从更早的不兼容版本(Kafka/Local 版本)升级到最新版本。 + +## 手动部署 + +### 升级 Pump + +对集群里的每个 Pump 逐一升级,确保集群中总有 Pump 可以接收 TiDB 发来的 Binlog。 + +1. 用新版本的 `pump` 替换原来的文件 +2. 重启 Pump 进程 + +### 升级 Drainer + +1. 用新版本的 `drainer` 替换原来的文件 +2. 重启 Drainer 进程 + +## 从 Kafka/Local 版本升级到 Cluster 版本 + +新版本的 TiDB(v2.0.8-binlog、v2.1.0-rc.5 及以上版本)不兼容 [Kafka 版本](https://pingcap.com/docs-cn/v2.1/reference/tidb-binlog/tidb-binlog-kafka/)以及 [Local 版本](https://pingcap.com/docs-cn/v2.1/reference/tidb-binlog/tidb-binlog-local/)的 TiDB Binlog,集群升级到新版本后只能使用 Cluster 版本的 TiDB Binlog。如果在升级前已经使用了 Kafka/Local 版本的 TiDB Binlog,必须将其升级到 Cluster 版本。 + +TiDB Binlog 版本与 TiDB 版本的对应关系如下: + +| TiDB Binlog 版本 | TiDB 版本 | 说明 | +|---|---|---| +| Local | TiDB 1.0 及更低版本 || +| Kafka | TiDB 1.0 ~ TiDB 2.1 RC5 | TiDB 1.0 支持 local 版本和 Kafka 版本的 TiDB Binlog。 | +| Cluster | TiDB v2.0.8-binlog,TiDB 2.1 RC5 及更高版本 | TiDB v2.0.8-binlog 是一个支持 Cluster 版本 TiDB Binlog 的 2.0 特殊版本。 | + +### 升级流程 + +> **注意:** +> +> 如果能接受重新导全量数据,则可以直接废弃老版本,按 [TiDB Binlog 集群部署](/tidb-binlog/deploy-tidb-binlog.md)中的步骤重新部署。 + +如果想从原来的 checkpoint 继续同步,使用以下升级流程: + +1. 部署新版本 Pump。 +2. 暂停 TiDB 集群业务。 +3. 更新 TiDB 以及配置,写 Binlog 到新的 Pump Cluster。 +4. TiDB 集群重新接入业务。 +5. 确认老版本的 Drainer 已经将老版本的 Pump 的数据完全同步到下游。 + + 查询 Drainer 的 `status` 接口,示例命令如下: + + ```bash + curl 'http://172.16.10.49:8249/status' + ``` + + ``` + {"PumpPos":{"172.16.10.49:8250":{"offset":32686}},"Synced": true ,"DepositWindow":{"Upper":398907800202772481,"Lower":398907799455662081}} + ``` + + 如果返回的 `Synced` 为 true,则可以认为 Binlog 数据已经全部同步到了下游。 + +6. 启动新版本 Drainer; +7. 下线老版本的 Pump、Drainer 以及依赖的 Kafka 和 ZooKeeper。 diff --git a/markdown-pages/zh/tidb/master/tidb-control.md b/markdown-pages/zh/tidb/master/tidb-control.md new file mode 100644 index 0000000..883aec6 --- /dev/null +++ b/markdown-pages/zh/tidb/master/tidb-control.md @@ -0,0 +1,342 @@ +--- +title: TiDB Control 使用说明 +aliases: ['/docs-cn/dev/tidb-control/','/docs-cn/dev/reference/tools/tidb-control/','/docs-cn/tools/tidb-controller/'] +summary: TiDB Control 是 TiDB 的命令行工具,用于获取 TiDB 状态信息和调试。可通过 TiUP 安装或从源代码编译安装。使用介绍包括命令、选项和参数组成,以及全局参数和各子命令的功能。其中包括获取帮助信息、解码 base64 数据、解码 row key 和 value、操作 etcd、格式化日志文件,以及查询关键 key range 信息。注意:TiDB Control 主要用于诊断调试,不保证和 TiDB 未来引入的新特性完全兼容。 +--- + +# TiDB Control 使用说明 + +TiDB Control 是 TiDB 的命令行工具,用于获取 TiDB 状态信息,多用于调试。本文介绍了 TiDB Control 的主要功能和各个功能的使用方法。 + +> **注意:** +> +> TiDB Control 主要用于诊断调试,不保证和 TiDB 未来引入的新特性完全兼容。因此不推荐客户在应用程序开发或工具开发中利用 TiDB Control 获取结果。 + +## 获取 TiDB Control + +本节提供了两种方式获取 TiDB Control 工具。 + +> **注意:** +> +> 建议使用的 Control 工具版本与集群版本保持一致。 + +### 通过 TiUP 安装 + +在安装 TiUP 之后,可以使用 `tiup ctl:v tidb` 命令来获取 TiDB Control 的二进制程序以及运行 TiDB Control。 + +### 从源代码编译安装 + +编译环境要求:[Go](https://golang.org/) 1.21 或以上版本 + +编译步骤:在 [TiDB Control 项目](https://github.com/pingcap/tidb-ctl)根目录,使用 `make` 命令进行编译,生成 tidb-ctl。 + +编译文档:帮助文档在 doc 文件夹下,如丢失或需要更新,可通过 `make doc` 命令生成帮助文档。 + +## 使用介绍 + +`tidb-ctl` 的使用由命令(包括子命令)、选项和参数组成。命令即不带 `-` 或者 `--` 的字符,选项即带有 `-` 或者 `--` 的字符,参数即命令或选项字符后紧跟的传递给命令和选项的字符。 + +如:`tidb-ctl schema in mysql -n db` + +* schema: 命令 +* in: schema 的子命令 +* mysql: in 的参数 +* -n: 选项 +* db: -n 的参数 + +目前,TiDB Control 包含以下子命令。 + +* `tidb-ctl base64decode` 用于 BASE64 解码 +* `tidb-ctl decoder` 用于 KEY 解码 +* `tidb-ctl etcd` 用于操作 etcd +* `tidb-ctl log` 用于格式化日志文件,将单行的堆栈信息展开 +* `tidb-ctl mvcc` 用于获取 MVCC 信息 +* `tidb-ctl region` 用于获取 Region 信息 +* `tidb-ctl schema` 用于获取 Schema 信息 +* `tidb-ctl table` 用于获取 Table 信息 + +### 获取帮助 + +`tidb-ctl -h/--help` 用于获取帮助信息。tidb-ctl 由多层命令组成,tidb-ctl 及其所有子命令都可以通过 `-h/--help` 来获取使用帮助。 + +以获取 Schema 信息为例: + +通过 `tidb-ctl schema -h` 可以获取这个子命令的使用帮助。schema 有两个子命令——in 和 tid。in 用来通过数据库名获取数据库中所有表的表结构,tid 用来通过全数据库唯一的 table_id 获取表的表结构。 + +### 全局参数 + +`tidb-ctl` 有 4 个与连接相关的全局参数,分别为: + +- `--host` TiDB 服务地址 +- `--port` TiDB status 端口 +- `--pdhost` PD 服务地址 +- `--pdport` PD 服务端口 +- `--ca` 连接使用的 TLS CA 文件路径 +- `--ssl-key` 连接使用的 TLS 密钥文件路径 +- `--ssl-cert` 连接使用的 TLS 证书文件路径 + +其中 `--pdhost` 和 `--pdport` 主要是用于 `etcd` 子命令,例如:`tidb-ctl etcd ddlinfo`。如不添加地址和端口将使用默认值,TiDB/PD 服务默认的地址是 127.0.0.1(服务地址只能使用 IP 地址),TiDB 服务端口默认的端口是 10080,PD 服务端口默认的端口是 2379 **连接选项是全局选项,适用于以下所有命令。** + +### schema 命令 + +#### in 子命令 + +in 子命令用来通过数据库名获取数据库中所有表的表结构。 + +`tidb-ctl schema in {数据库名}` + +如:`tidb-ctl schema in mysql` 将得到以下结果 + +```json +[ + { + "id": 13, + "name": { + "O": "columns_priv", + "L": "columns_priv" + }, + ... + "update_timestamp": 399494726837600268, + "ShardRowIDBits": 0, + "Partition": null + } +] +``` + +结果将以 json 形式展示,内容较长,这里做了截断。 + +如希望指定表名,可以使用 `tidb-ctl schema in {数据库名} -n {表名}` 进行过滤。 + +如:`tidb-ctl schema in mysql -n db` 将得到 mysql 库中 db 表的表结构。结果如下: + +```json +{ + "id": 9, + "name": { + "O": "db", + "L": "db" + }, + ... + "Partition": null +} +``` + +这里同样做了截断。 + +如使用的 TiDB 地址不为默认地址和端口,可以使用命令行参数 `--host`, `--port` 选项,如:`tidb-ctl --host 172.16.55.88 --port 8898 schema in mysql -n db`。 + +#### tid 子命令 + +tid 子命令用来通过表的 id 获取数据库中表的表结构。 + +通过使用 in 子命令查询到数据库中表的 id,之后可以通过 tid 子命令查看表的详细信息。 + +例如,查询到 `mysql.stat_meta` 表的 id 是 21,可以通过 `tidb-ctl schema tid -i 21` 查看表的详细信息。 + +```json +{ + "id": 21, + "name": { + "O": "stats_meta", + "L": "stats_meta" + }, + "charset": "utf8mb4", + "collate": "utf8mb4_bin", + ... +} +``` + +同 in 子命令一样,如果使用的 TiDB 地址不是默认的地址和端口,需要通过 `--host` 和 `--port` 参数指定 TiDB 的地址和 status 端口。 + +### base64decode 命令 + +`base64decode` 用来解码 base64 数据。 + +基本用法: + +```shell +tidb-ctl base64decode [base64_data] +tidb-ctl base64decode [db_name.table_name] [base64_data] +tidb-ctl base64decode [table_id] [base64_data] +``` + +1. 准备环境,执行以下 SQL + + ```sql + use test; + create table t (a int, b varchar(20),c datetime default current_timestamp , d timestamp default current_timestamp, unique index(a)); + insert into t (a,b,c) values(1,"哈哈 hello",NULL); + alter table t add column e varchar(20); + ``` + +2. 用 HTTP API 接口获取 MVCC 数据 + + ```shell + curl "http://$IP:10080/mvcc/index/test/t/a/1?a=1" + ``` + + ``` + { + "info": { + "writes": [ + { + "start_ts": 407306449994645510, + "commit_ts": 407306449994645513, + "short_value": "AAAAAAAAAAE=" # unique index a 存的值是对应行的 handle id. + } + ] + } + }% + ``` + + ```shell + curl "http://$IP:10080/mvcc/key/test/t/1" + ``` + + ``` + { + "info": { + "writes": [ + { + "start_ts": 407306588892692486, + "commit_ts": 407306588892692489, + "short_value": "CAIIAggEAhjlk4jlk4ggaGVsbG8IBgAICAmAgIDwjYuu0Rk=" # handle id 为 1 的行数据。 + } + ] + } + }% + ``` + +3. 用 `base64decode` 解码 handle id (uint64). + + ```shell + tidb-ctl base64decode AAAAAAAAAAE= + ``` + + ``` + hex: 0000000000000001 + uint64: 1 + ``` + +4. 用 `base64decode` 解码行数据。 + + ```shell + ./tidb-ctl base64decode test.t CAIIAggEAhjlk4jlk4ggaGVsbG8IBgAICAmAgIDwjYuu0Rk= + ``` + + ``` + a: 1 + b: 哈哈 hello + c is NULL + d: 2019-03-28 05:35:30 + e not found in data + ``` + + 如果 `test.t` 的 table id 是 60,你也可以使用下列命令获得同样结果: + + ```shell + ./tidb-ctl base64decode 60 CAIIAggEAhjlk4jlk4ggaGVsbG8IBgAICAmAgIDwjYuu0Rk= + ``` + + ``` + a: 1 + b: 哈哈 hello + c is NULL + d: 2019-03-28 05:35:30 + e not found in data + ``` + +### decoder 命令 + +* 以下示例解码 row key,index key 类似。 + + ```shell + ./tidb-ctl decoder "t\x00\x00\x00\x00\x00\x00\x00\x1c_r\x00\x00\x00\x00\x00\x00\x00\xfa" + ``` + + ``` + format: table_row + table_id: -9223372036854775780 + row_id: -9223372036854775558 + ``` + +* 以下示例解码 value + + ```shell + ./tidb-ctl decoder AhZoZWxsbyB3b3JsZAiAEA== + ``` + + ``` + format: index_value + index_value[0]: {type: bytes, value: hello world} + index_value[1]: {type: bigint, value: 1024} + ``` + +### etcd 命令 + +* `tidb-ctl etcd ddlinfo` 获取 DDL 信息。 +* `tidb-ctl etcd putkey KEY VALUE` 添加 KEY VALUE 到 etcd(所有的 KEY 会添加到 `/tidb/ddl/all_schema_versions/` 之下)。 + + ```shell + tidb-ctl etcd putkey "foo" "bar" + ``` + + 实际是添加 KEY 为 `/tidb/ddl/all_schema_versions/foo`,VALUE 为 `bar` 的键值对到 etcd 中。 + +* `tidb-ctl etcd delkey` 删除 etcd 中的 KEY,只有前缀以 `/tidb/ddl/fg/owner/` 和 `/tidb/ddl/all_schema_versions/` 开头才允许被删除。 + + ```shell + tidb-ctl etcd delkey "/tidb/ddl/fg/owner/foo" && + tidb-ctl etcd delkey "/tidb/ddl/all_schema_versions/bar" + ``` + +### log 命令 + +TiDB 错误日志的堆栈信息是一行的格式,可以使用 `tidb-ctl log` 将堆栈信息格式化成多行形式。 + +### keyrange 命令 + +`keyrange` 子命令用于查询全局或表相关的关键 key range 信息,以十六进制形式输出。 + +* 使用 `tidb-ctl keyrange` 命令查看全局的关键 key range。 + + ```shell + tidb-ctl keyrange + ``` + + ``` + global ranges: + meta: (6d, 6e) + table: (74, 75) + ``` + +* 添加 `--encode` 选项可以显示 encode 过的 key(与 TiKV 及 PD 中的格式相同)。 + + ```shell + tidb-ctl keyrange --encode + ``` + + ``` + global ranges: + meta: (6d00000000000000f8, 6e00000000000000f8) + table: (7400000000000000f8, 7500000000000000f8) + ``` + +* 使用 `tidb-ctl keyrange --database={db} --table={tbl}` 命令查看全局和表相关的关键 key range。 + + ```shell + tidb-ctl keyrange --database test --table ttt + ``` + + ``` + global ranges: + meta: (6d, 6e) + table: (74, 75) + table ttt ranges: (NOTE: key range might be changed after DDL) + table: (74800000000000002f, 748000000000000030) + table indexes: (74800000000000002f5f69, 74800000000000002f5f72) + index c2: (74800000000000002f5f698000000000000001, 74800000000000002f5f698000000000000002) + index c3: (74800000000000002f5f698000000000000002, 74800000000000002f5f698000000000000003) + index c4: (74800000000000002f5f698000000000000003, 74800000000000002f5f698000000000000004) + table rows: (74800000000000002f5f72, 748000000000000030) + ``` diff --git a/markdown-pages/zh/tidb/master/tidb-in-kubernetes.md b/markdown-pages/zh/tidb/master/tidb-in-kubernetes.md new file mode 100644 index 0000000..bd468ee --- /dev/null +++ b/markdown-pages/zh/tidb/master/tidb-in-kubernetes.md @@ -0,0 +1,12 @@ +--- +title: 在 Kubernetes 上部署 TiDB +summary: 你可以使用 TiDB Operator 在 Kubernetes 上部署 TiDB。TiDB Operator 是 Kubernetes 上的 TiDB 集群自动运维系统,提供部署、升级、扩缩容、备份恢复、配置变更的 TiDB 全生命周期管理。借助 TiDB Operator,TiDB 可以无缝运行在公有云或自托管的 Kubernetes 集群上。TiDB Operator 的文档目前独立于 TiDB 文档。要查看如何在 Kubernetes 上部署 TiDB 的详细步骤,请参阅对应版本的 TiDB Operator 文档。 +--- + +# 在 Kubernetes 上部署 TiDB + +你可以使用 [TiDB Operator](https://github.com/pingcap/tidb-operator) 在 Kubernetes 上部署 TiDB。TiDB Operator 是 Kubernetes 上的 TiDB 集群自动运维系统,提供包括部署、升级、扩缩容、备份恢复、配置变更的 TiDB 全生命周期管理。借助 TiDB Operator,TiDB 可以无缝运行在公有云或自托管的 Kubernetes 集群上。 + +TiDB Operator 的文档目前独立于 TiDB 文档。要查看如何在 Kubernetes 上部署 TiDB 的详细步骤,请参阅对应版本的 TiDB Operator 文档: + +- [TiDB on Kubernetes 用户文档](https://docs.pingcap.com/zh/tidb-in-kubernetes/stable/) diff --git a/markdown-pages/zh/tidb/master/tidb-lightning/monitor-tidb-lightning.md b/markdown-pages/zh/tidb/master/tidb-lightning/monitor-tidb-lightning.md new file mode 100644 index 0000000..92a708f --- /dev/null +++ b/markdown-pages/zh/tidb/master/tidb-lightning/monitor-tidb-lightning.md @@ -0,0 +1,243 @@ +--- +title: TiDB Lightning 监控告警 +aliases: ['/docs-cn/dev/tidb-lightning/monitor-tidb-lightning/','/docs-cn/dev/reference/tools/tidb-lightning/monitor/'] +summary: TiDB Lightning 支持使用Prometheus采集监控指标。监控配置需手动部署,配置方法在 tidb-lightning.toml 中。Grafana 面板可用于监控速度、进度、资源使用和存储空间。监控指标包括计数器和直方图,用于计算引擎文件数量、闲置 worker、KV 编码器、处理过的表、引擎文件和 Chunks的状态,以及导入每个表所需时间等。 +--- + +# TiDB Lightning 监控告警 + +`tidb-lightning` 支持使用 [Prometheus](https://prometheus.io/) 采集监控指标 (metrics)。本文主要介绍 TiDB Lightning 的监控配置与监控指标。 + +## 监控配置 + +如果是手动部署 TiDB Lightning,则参照以下步骤进行配置。 + +只要 Prometheus 能发现 `tidb-lightning` 和 `tikv-importer` 的监控地址,就能收集对应的监控指标。 + +监控的端口可在 `tidb-lightning.toml` 中配置: + +```toml +[lightning] +# 用于调试和 Prometheus 监控的 HTTP 端口。输入 0 关闭。 +pprof-port = 8289 + +... +``` + +配置 Prometheus 后,`tidb-lightning` 才能发现服务器。配置方法如下,将服务器地址直接添加至 `scrape_configs` 部分: + +```yaml +... +scrape_configs: + - job_name: 'tidb-lightning' + static_configs: + - targets: ['192.168.20.10:8289'] +``` + +## Grafana 面板 + +[Grafana](https://grafana.com/) 的可视化面板可以让你在网页上监控 Prometheus 指标。 + +### 第一行:速度面板 + +![第一行速度面板](/media/lightning-grafana-row-1.png) + +| 面板名称 | 序列 | 描述 | +|:-----|:-----|:-----| +| Import speed | write from lightning | 从 TiDB Lightning 向 TiKV Importer 发送键值对的速度,取决于每个表的复杂性 | +| Import speed | upload to tikv | 从 TiKV Importer 上传 SST 文件到所有 TiKV 副本的总体速度 | +| Chunk process duration | | 完全编码单个数据文件所需的平均时间 | + +有时导入速度会降到 0,这是为了平衡其他部分的速度,属于正常现象。 + +### 第二行:进度面板 + +![第二行进度面板](/media/lightning-grafana-row-2.png) + +| 面板名称 | 描述 | +|:-----|:-----| +| Import progress | 已编码的文件所占百分比 | +| Checksum progress | 已导入的表所占百分比 | +| Failures | 导入失败的表的数量以及故障点,通常为空 | + +### 第三行:资源使用面板 + +![第三行资源使用面板](/media/lightning-grafana-row-3.png) + +| 面板名称 | 描述 | +|:-----|:-----| +| Memory usage | 每个服务占用的内存 | +| Number of Lightning Goroutines | TiDB Lightning 使用的运行中的 goroutines 数量 | +| CPU% | 每个服务使用的逻辑 CPU 数量 | + +### 第四行:配额使用面板 + +![第四行配额使用面板](/media/lightning-grafana-row-4.png) + +| 面板名称 | 序列 | 描述 | +|:-----|:-----|:-----| +| Idle workers | io | 未使用的 `io-concurrency` 的数量,通常接近配置值(默认为 5),接近 0 时表示磁盘运行太慢 | +| Idle workers | closed-engine | 已关闭但未清理的引擎数量,通常接近 `index-concurrency` 与 `table-concurrency` 的和(默认为 8),接近 0 时表示 TiDB Lightning 比 TiKV Importer 快,导致 TiDB Lightning 延迟 | +| Idle workers | table | 未使用的 `table-concurrency` 的数量,通常为 0,直到进程结束 | +| Idle workers | index | 未使用的 `index-concurrency` 的数量,通常为 0,直到进程结束 | +| Idle workers | region | 未使用的 `region-concurrency` 的数量,通常为 0,直到进程结束 | +| External resources | KV Encoder | 已激活的 KV encoder 的数量,通常与 `region-concurrency` 的数量相同,直到进程结束 | +| External resources | Importer Engines | 打开的引擎文件数量,不应超过 `max-open-engines` 的设置 | + +### 第五行:读取速度面板 + +![第五行读取速度面板](/media/lightning-grafana-row-5.png) + +| 面板名称 | 序列 | 描述 | +|:-----|:-----|:-----| +| Chunk parser read block duration | read block | 读取一个字节块来准备解析时所消耗的时间 | +| Chunk parser read block duration | apply worker | 等待 `io-concurrency` 空闲所消耗的时间 | +| SQL process duration | row encode | 解析和编码单行所消耗的时间 | +| SQL process duration | block deliver | 将一组键值对发送到 TiKV Importer 所消耗的时间 | + +如果上述项的持续时间过长,则表示 TiDB Lightning 使用的磁盘运行太慢或 I/O 太忙。 + +### 第六行:存储空间面板 + +![第六行存储空间面板](/media/lightning-grafana-row-6.png) + +| 面板名称 | 序列 |描述 | +|:-----|:-----|:-----| +| SQL process rate | data deliver rate | 向 TiKV Importer 发送数据键值对的速度 | +| SQL process rate | index deliver rate | 向 TiKV Importer 发送索引键值对的速度 | +| SQL process rate | total deliver rate | 发送数据键值对及索引键值对的速度之和 | +| Total bytes | parser read size | TiDB Lightning 正在读取的字节数 | +| Total bytes | data deliver size | 已发送到 TiKV Importer 的数据键值对的字节数 | +| Total bytes | index deliver size | 已发送到 TiKV Importer 的索引键值对的字节数 | +| Total bytes | storage_size/3 | TiKV 集群占用的存储空间大小的 1/3(3 为默认的副本数量)| + +### 第七行:导入速度面板 + +![第七行导入速度面板](/media/lightning-grafana-row-7.png) + +| 面板名称 | 序列 | 描述 | +|:-----|:-----|:-----| +| Delivery duration | Range delivery | 将一个 range 的键值对上传到 TiKV 集群所消耗的时间 | +| Delivery duration | SST delivery | 将单个 SST 文件上传到 TiKV 集群所消耗的时间 | +| SST process duration | Split SST | 将键值对流切分成若干 SST 文件所消耗的时间 | +| SST process duration | SST upload | 上传单个 SST 文件所消耗的时间 | +| SST process duration | SST ingest | ingest 单个 SST 文件所消耗的时间 | +| SST process duration | SST size | 单个 SST 文件的大小 | + +## 监控指标 + +本节将详细描述 `tidb-lightning` 的监控指标。 + +`tidb-lightning` 的监控指标皆以 `lightning_*` 为前缀。 + +- **`lightning_importer_engine`**(计数器) + + 计算已开启及关闭的引擎文件数量。标签: + + - **type**: + * `open` + * `closed` + +- **`lightning_idle_workers`**(计量表盘) + + 计算闲置的 worker。标签: + + - **name**: + * `table` — 未使用的 `table-concurrency` 的数量,通常为 0,直到进程结束 + * `index` — 未使用的 `index-concurrency` 的数量,通常为 0,直到进程结束 + * `region` — 未使用的 `region-concurrency` 的数量,通常为 0,直到进程结束 + * `io` — 未使用的 `io-concurrency` 的数量,通常接近配置值(默认为 5),接近 0 时表示磁盘运行太慢 + * `closed-engine` — 已关闭但未清理的引擎数量,通常接近 `index-concurrency` 与 `table-concurrency` 的和(默认为 8),接近 0 时表示 TiDB Lightning 比 TiKV Importer 快,导致 TiDB Lightning 延迟 + +- **`lightning_kv_encoder`**(计数器) + + 计算已开启及关闭的 KV 编码器。KV 编码器是运行于内存的 TiDB 实例,用于将 SQL 的 `INSERT` 语句转换成键值对。此度量的净值(开启减掉关闭)在正常情况下不应持续增长。标签: + + - **type**: + * `open` + * `closed` + +- **`lightning_tables`**(计数器) + + 计算处理过的表及其状态。标签: + + - **state**:表的状态,表明当前应执行的操作 + * `pending` — 等待处理 + * `written` — 所有数据已编码和传输 + * `closed` — 所有对应的引擎文件已关闭 + * `imported` — 所有引擎文件已上传到目标集群 + * `altered_auto_inc` — 自增 ID 已改 + * `checksum` — 已计算校验和 + * `analyzed` — 已进行统计信息分析 + * `completed` — 表格已完全导入并通过验证 + - **result**:当前操作的执行结果 + * `success` — 成功 + * `failure` — 失败(未完成) + +- **`lightning_engines`**(计数器) + + 计算处理后引擎文件的数量以及其状态。标签: + + - **state**:引擎文件的状态,表明当前应执行的操作 + * `pending` — 等待处理 + * `written` — 所有数据已编码和传输 + * `closed` — 引擎文件已关闭 + * `imported` — 当前引擎文件已上传到目标集群 + * `completed` — 当前引擎文件已完全导入 + - **result**:当前操作的执行结果 + * `success` — 成功 + * `failure` — 失败(未完成) + +- **`lightning_chunks`**(计数器) + + 计算处理过的 Chunks 及其状态。标签: + + - **state**: 单个 Chunk 的状态,表明该 Chunk 当前所处的阶段 + * `estimated` — (非状态)当前任务中 Chunk 的数量 + * `pending` — 已载入但未执行 + * `running` — 正在编码和发送数据 + * `finished` — 该 Chunk 已处理完毕 + * `failed` — 处理过程中发生错误 + +- **`lightning_import_seconds`**(直方图) + + 导入每个表所需时间的直方图。 + +- **`lightning_row_read_bytes`**(直方图) + + 单行 SQL 数据大小的直方图。 + +- **`lightning_row_encode_seconds`**(直方图) + + 解码单行 SQL 数据到键值对所需时间的直方图。 + +- **`lightning_row_kv_deliver_seconds`**(直方图) + + 发送一组与单行 SQL 数据对应的键值对所需时间的直方图。 + +- **`lightning_block_deliver_seconds`**(直方图) + + 每个键值对中的区块传送到 `tikv-importer` 所需时间的直方图。 + +- **`lightning_block_deliver_bytes`**(直方图) + + 发送到 Importer 的键值对中区块(未压缩)的大小的直方图。 + +- **`lightning_chunk_parser_read_block_seconds`**(直方图) + + 数据文件解析每个 SQL 区块所需时间的直方图。 + +- **`lightning_checksum_seconds`**(直方图) + + 计算表中 Checksum 所需时间的直方图。 + +- **`lightning_apply_worker_seconds`**(直方图) + + 获取闲置 worker 等待时间的直方图 (参见 `lightning_idle_workers` 计量表盘)。标签: + + - **name**: + * `table` + * `index` + * `region` + * `io` + * `closed-engine` diff --git a/markdown-pages/zh/tidb/master/tidb-lightning/tidb-lightning-checkpoints.md b/markdown-pages/zh/tidb/master/tidb-lightning/tidb-lightning-checkpoints.md new file mode 100644 index 0000000..4f65bc1 --- /dev/null +++ b/markdown-pages/zh/tidb/master/tidb-lightning/tidb-lightning-checkpoints.md @@ -0,0 +1,109 @@ +--- +title: TiDB Lightning 断点续传 +aliases: ['/docs-cn/dev/tidb-lightning/tidb-lightning-checkpoints/','/docs-cn/dev/reference/tools/tidb-lightning/checkpoints/'] +summary: TiDB Lightning 提供了“断点续传”的功能,即使 `tidb-lightning` 崩溃,在重启时仍然接着之前的进度继续工作。断点续传可通过配置启用,存储方式包括本地文件和 MySQL 数据库。在出现不可恢复的错误时,可以使用 `tidb-lightning-ctl` 工具来控制断点的处理,包括重置断点状态、清除出错状态和移除断点。 +--- + +# TiDB Lightning 断点续传 + +大量的数据导入一般耗时数小时至数天,长时间运行的进程会有一定机率发生非正常中断。如果每次重启都从头开始,就会浪费掉之前已成功导入的数据。为此,TiDB Lightning 提供了“断点续传”的功能,即使 `tidb-lightning` 崩溃,在重启时仍然接着之前的进度继续工作。 + +本文主要介绍 TiDB Lightning 断点续传的启用与配置、断点的存储,以及断点续传的控制。 + +## 断点续传的启用与配置 + +```toml +[checkpoint] +# 启用断点续传。 +# 导入时,TiDB Lightning 会记录当前进度。 +# 若 TiDB Lightning 或其他组件异常退出,在重启时可以避免重复再导入已完成的数据。 +enable = true + +# 存储断点的方式 +# - file:存放在本地文件系统(要求 v2.1.1 或以上) +# - mysql:存放在兼容 MySQL 的数据库服务器 +driver = "file" + +# 存储断点的架构名称(数据库名称) +# 仅在 driver = "mysql" 时生效 +# schema = "tidb_lightning_checkpoint" + +# 断点的存放位置 +# +# 若 driver = "file",此参数为断点信息存放的文件路径。 +# 如果不设置该参数则默认为 `/tmp/CHECKPOINT_SCHEMA.pb` +# +# 若 driver = "mysql",此参数为数据库连接参数 (DSN),格式为“用户:密码@tcp(地址:端口)/”。 +# 默认会重用 [tidb] 设置目标数据库来存储断点。 +# 为避免加重目标集群的压力,建议另外使用一个兼容 MySQL 的数据库服务器。 +# dsn = "/tmp/tidb_lightning_checkpoint.pb" + +# 导入成功后是否保留断点。默认为删除。 +# 保留断点可用于调试,但有可能泄漏数据源的元数据。 +# keep-after-success = false +``` + +## 断点的存储 + +TiDB Lightning 支持两种存储方式:本地文件或 MySQL 数据库。 + +* 若 `driver = "file"`,断点会存放在一个本地文件,其路径由 `dsn` 参数指定。由于断点会频繁更新,建议将这个文件放到写入次数不受限制的盘上,例如 RAM disk。 + +* 若 `driver = "mysql"`,断点可以存放在任何兼容 MySQL 5.7 或以上的数据库中,包括 MariaDB 和 TiDB。在没有选择的情况下,默认会存在目标数据库里。 + +目标数据库在导入期间会有大量的操作,若使用目标数据库来存储断点会加重其负担,甚至有可能造成通信超时丢失数据。因此,**强烈建议另外部署一台兼容 MySQL 的临时数据库服务器**。此数据库也可以安装在 `tidb-lightning` 的主机上。导入完毕后可以删除。 + +## 断点续传的控制 + +若 `tidb-lightning` 因不可恢复的错误而退出(例如数据出错),重启时不会使用断点,而是直接报错离开。为保证已导入的数据安全,这些错误必须先解决掉才能继续。使用 `tidb-lightning-ctl` 工具可以标示已经恢复。 + +### `--checkpoint-error-destroy` + +```shell +tidb-lightning-ctl --checkpoint-error-destroy='`schema`.`table`' +``` + +该命令会让失败的表从头开始整个导入过程。选项中的架构和表名必须以反引号 (`` ` ``) 包裹,而且区分大小写。 + +- 如果导入 `` `schema`.`table` `` 这个表曾经出错,这条命令会: + + 1. 从目标数据库移除 (DROP) 这个表,清除已导入的数据。 + 2. 将断点重设到“未开始”的状态。 + +- 如果 `` `schema`.`table` `` 没有出错,则无操作。 + +传入 "all" 会对所有表进行上述操作。这是最方便、安全但保守的断点错误解决方法: + +```shell +tidb-lightning-ctl --checkpoint-error-destroy=all +``` + +### `--checkpoint-error-ignore` + +```shell +tidb-lightning-ctl --checkpoint-error-ignore='`schema`.`table`' && +tidb-lightning-ctl --checkpoint-error-ignore=all +``` + +如果导入 `` `schema`.`table` `` 这个表曾经出错,这条命令会清除出错状态,如同没事发生过一样。传入 "all" 会对所有表进行上述操作。 + +> **注意:** +> +> 除非确定错误可以忽略,否则不要使用这个选项。如果错误是真实的话,可能会导致数据不完全。启用校验和 (CHECKSUM) 可以防止数据出错被忽略。 + +### `--checkpoint-remove` + +```shell +tidb-lightning-ctl --checkpoint-remove='`schema`.`table`' && +tidb-lightning-ctl --checkpoint-remove=all +``` + +无论是否有出错,把表的断点清除。 + +### `--checkpoint-dump` + +```shell +tidb-lightning-ctl --checkpoint-dump=output/directory +``` + +将所有断点备份到传入的文件夹,主要用于技术支持。此选项仅于 `driver = "mysql"` 时有效。 diff --git a/markdown-pages/zh/tidb/master/tidb-lightning/tidb-lightning-faq.md b/markdown-pages/zh/tidb/master/tidb-lightning/tidb-lightning-faq.md new file mode 100644 index 0000000..fa2fe80 --- /dev/null +++ b/markdown-pages/zh/tidb/master/tidb-lightning/tidb-lightning-faq.md @@ -0,0 +1,215 @@ +--- +title: TiDB Lightning 常见问题 +aliases: ['/docs-cn/dev/tidb-lightning/tidb-lightning-faq/','/docs-cn/dev/faq/tidb-lightning/'] +summary: TiDB Lightning 常见问题的摘要:TiDB Lightning 对TiDB/TiKV/PD 的最低版本要求,支持导入多个库,对下游数据库的账号权限要求,导数据过程中某个表报错不会影响其他表,正确重启 TiDB Lightning 的步骤,校验导入数据的正确性方法,支持的数据源格式,禁止导入不合规数据的方法,结束 tidb-lightning 进程的操作,使用千兆网卡的建议,TiDB Lightning 预留空间的原因,清除与 TiDB Lightning 相关的中间数据的步骤,获取 TiDB Lightning 运行时的 goroutine 信息的方法,TiDB Lightning 不兼容 Placement Rules in SQL 的原因,使用 TiDB Lightning 和 Dumpling 复制 schema 的步骤。 +--- + +# TiDB Lightning 常见问题 + +本文列出了一些使用 TiDB Lightning 时可能会遇到的问题与答案。 + +## TiDB Lightning 对 TiDB/TiKV/PD 的最低版本要求是多少? + +TiDB Lightning 的版本应与集群相同。如果使用 Local-backend 模式,最低版本要求为 4.0.0。如果使用 Importer-backend 或 TiDB-backend 模式最低版本要求是 2.0.9,但建议使用最新的稳定版本 3.0。 + +## TiDB Lightning 支持导入多个库吗? + +支持。 + +## TiDB Lightning 对下游数据库的账号权限要求是怎样的? + +详细权限描述参考 [TiDB Lightning 使用前提](/tidb-lightning/tidb-lightning-requirements.md)。 + +## TiDB Lightning 在导数据过程中某个表报错了,会影响其他表吗?进程会马上退出吗? + +如果只是个别表报错,不会影响整体。报错的那个表会停止处理,继续处理其他的表。 + +## 如何正确重启 TiDB Lightning? + +1. [结束 `tidb-lightning` 进程](#如何正确结束-tidb-lightning-进程)。 +2. 启动一个新的 `tidb-lightning` 任务:执行之前的启动命令,例如 `nohup tiup tidb-lightning -config tidb-lightning.toml`。 + +## 如何校验导入的数据的正确性? + +TiDB Lightning 默认会对导入数据计算校验和 (checksum),如果校验和不一致就会停止导入该表。可以在日志看到相关的信息。 + +TiDB 也支持从 MySQL 命令行运行 [`ADMIN CHECKSUM TABLE`](/sql-statements/sql-statement-admin-check-table-index.md) 指令来计算校验和。 + +```sql +ADMIN CHECKSUM TABLE `schema`.`table`; +``` + +``` ++---------+------------+---------------------+-----------+-------------+ +| Db_name | Table_name | Checksum_crc64_xor | Total_kvs | Total_bytes | ++---------+------------+---------------------+-----------+-------------+ +| schema | table | 5505282386844578743 | 3 | 96 | ++---------+------------+---------------------+-----------+-------------+ +1 row in set (0.01 sec) +``` + +## TiDB Lightning 支持哪些格式的数据源? + +目前,TiDB Lightning 支持: + +- 导入 [Dumpling](/dumpling-overview.md)、CSV 或 [Amazon Aurora Parquet](/migrate-aurora-to-tidb.md) 输出格式的数据源。 +- 从本地盘或 Amazon S3 云盘读取数据。 + +## 我已经在下游创建好库和表了,TiDB Lightning 可以忽略建库建表操作吗? + +自 v5.1 起,TiDB Lightning 可以自动识别下游的库和表。如果你使用低于 v5.1 的 TiDB Lightning,需在配置文档中的 `[mydumper]` 部分将 `no-schema` 设置为 `true` 即可。`no-schema=true` 会默认下游已经创建好所需的数据库和表,如果没有创建,会报错。 + +## 如何禁止导入不合规的数据? + +可以通过开启严格 SQL 模式 (Strict SQL Mode) 来实现。 + +TiDB Lightning 默认的 [`sql_mode`](https://dev.mysql.com/doc/refman/8.0/en/sql-mode.html) 为 `"ONLY_FULL_GROUP_BY,NO_AUTO_CREATE_USER"`,允许导入某些不合规的数值,例如 `1970-00-00` 这样的日期。 + +如果要禁止导入不合规的数据,需要修改配置文件 `[tidb]` 下的 `sql-mode` 值为 `"STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION"`。 + +```toml +... +[tidb] +sql-mode = "STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION" +... +``` + +## 如何正确结束 `tidb-lightning` 进程? + +根据部署方式,选择相应操作结束进程。 + +手动部署:如果 `tidb-lightning` 正在前台运行,可直接按 Ctrl+C 退出。否则,可通过 `ps aux | grep tidb-lightning` 获取进程 ID,然后通过 `kill -2 «pid»` 结束进程。 + +## TiDB Lightning 可以使用千兆网卡吗? + +使用 TiDB Lightning 的 SST Mode 建议配置万兆网卡。 + +千兆网卡的总带宽只有 120 MB/s,而且需要与整个 TiKV 集群共享。在使用 TiDB Lightning 物理导入模式导入时,极易用尽所有带宽,继而因 PD 无法联络集群使集群断连。 + +## 为什么 TiDB Lightning 需要在 TiKV 集群预留这么多空间? + +当使用默认的 3 副本设置时,TiDB Lightning 需要 TiKV 集群预留数据源大小 6 倍的空间。多出来的 2 倍是算上下列没储存在数据源的因素的保守估计: + +- 索引会占据额外的空间 +- RocksDB 的空间放大效应 + +## 如何清除所有与 TiDB Lightning 相关的中间数据? + +1. 删除断点文件。 + + ```sh + tidb-lightning-ctl --config conf/tidb-lightning.toml --checkpoint-remove=all + ``` + + 如果出于某些原因而无法运行该命令,你可以尝试手动删除 `/tmp/tidb_lightning_checkpoint.pb` 文件。 + +2. 如果使用 Local-backend,删除配置中 `sorted-kv-dir` 对应的目录。 + +3. 如果需要的话,删除 TiDB 集群上创建的所有表和库。 + +4. 清理残留的元信息。如果存在以下任意一种情况,需要手动清理元信息库: + + - 对于 v5.1.x 和 v5.2.x 版本的 TiDB Lightning, tidb-lightning-ctl 命令没有同时清理存储在目标集群的 metadata 库,需要手动清理。 + - 如果手动删除过断点文件,则需要手动清理下游的元信息库,否则可能影响后续导入的正确性。 + + 使用下面命令清理元信息: + + ```sql + DROP DATABASE IF EXISTS `lightning_metadata`; + ``` + +## 如何获取 TiDB Lightning 运行时的 goroutine 信息 + +1. 如果 TiDB Lightning 的配置文件中已经指定了 [`status-port`](/tidb-lightning/tidb-lightning-configuration.md#tidb-lightning-全局配置),可以跳过此步骤。否则,需要向 TiDB Lightning 发送 USR1 信号以开启 `status-port`。 + + 首先通过 `ps` 等命令获取 TiDB Lightning 的进程 PID,然后运行如下命令: + + ```sh + kill -USR1 + ``` + + 查看 TiDB Lightning 的日志,其中 `starting HTTP server` / `start HTTP server` / `started HTTP server` 的日志会显示新开启的 `status-port`。 + +2. 访问 `http://:/debug/pprof/goroutine?debug=2` 可获取 goroutine 信息。 + +## 为什么 TiDB Lightning 不兼容 Placement Rules in SQL? + +TiDB Lightning 不兼容 [Placement Rules in SQL](/placement-rules-in-sql.md)。当 TiDB Lightning 导入的数据中包含放置策略 (placement policy) 时,TiDB Lightning 会报错。 + +不兼容的原因如下: + +使用 Placement Rules in SQL,你可以从表或分区级别控制某些 TiKV 节点的数据存储位置。TiDB Lightning 从文本文件中读取数据,并导入到目标 TiDB 集群中。如果导出的数据文件中包含了放置规则 (placement rules) 的定义,在导入过程中,TiDB Lightning 必须根据该定义在目标集群中创建相应的放置规则策略。然而,当源集群和目标集群的拓扑结构不同时,这可能会导致问题。 + +假设源集群有如下拓扑结构: + +![TiDB Lightning FAQ - 源集群拓扑结构](/media/lightning-faq-source-cluster-topology.jpg) + +源集群中设置了这样的放置策略: + +```sql +CREATE PLACEMENT POLICY p1 PRIMARY_REGION="us-east" REGIONS="us-east,us-west"; +``` + +**场景 1:**目标集群中有 3 个副本,且拓扑结构与源集群不同。在这种情况下,当 TiDB Lightning 在目标集群中创建放置策略时,TiDB Lightning 不会报错,但目标集群中的语义是错误的。 + +![TiDB Lightning FAQ - 场景 1](/media/lightning-faq-situation-1.jpg) + +**场景 2:**目标集群将 Follower 副本放置在区域 "us-mid" 的另一个 TiKV 节点上,且在拓扑结构中没有节点位于区域 "us-west" 中。在这种情况下,当 TiDB Lightning 在目标集群中创建放置策略时,TiDB Lightning 将报错。 + +![TiDB Lightning FAQ - 场景 2](/media/lightning-faq-situation-2.jpg) + +**解决方法:** + +如果要在使用 TiDB Lightning 同时使用 Placement Rules in SQL,你需要在导入数据到目标表**之前**,确保已经在目标 TiDB 集群中创建了相关的 label 和对象。因为 Placement Rules in SQL 作用于 PD 和 TiKV 层,TiDB Lightning 可以根据获取到的信息,决定应该使用哪个 TiKV 来存储导入的数据。使用这种方法后,Placement Rules in SQL 对 TiDB Lightning 是透明无感的。 + +具体操作步骤如下: + +1. 规划数据分布的拓扑结构。 +2. 为 TiKV 和 PD 配置必要的 label。 +3. 创建放置规则策略,并将策略应用到目标表上。 +4. 使用 TiDB Lightning 导入数据到目标表。 + +## 如何使用 TiDB Lightning 和 Dumpling 复制 schema? + +如果你想要将一个 schema 的定义和表数据复制到一个新的 schema 中,可以按照以下步骤进行操作。通过下面的示例,你可以了解如何将 `test` schema 复制到一个名为 `test2` 的新 schema 中。 + +1. 创建原 schema 的备份,使用 `-B test` 来选定需要的 schema。 + + ``` + tiup dumpling -B test -o /tmp/bck1 + ``` + +2. 创建 `/tmp/tidb-lightning.toml` 文件,内容如下: + + ```toml + [tidb] + host = "127.0.0.1" + port = 4000 + user = "root" + + [tikv-importer] + backend = "tidb" + + [mydumper] + data-source-dir = "/tmp/bck1" + + [[mydumper.files]] + pattern = '^[a-z]*\.(.*)\.[0-9]*\.sql$' + schema = 'test2' + table = '$1' + type = 'sql' + + [[mydumper.files]] + pattern = '^[a-z]*\.(.*)\-schema\.sql$' + schema = 'test2' + table = '$1' + type = 'table-schema' + ``` + + 在上述配置文件中,如要使用一个和原始备份中不同的 schema 名称,设置 `schema = 'test2'`。文件名用于确定表的名称。 + +3. 使用上述配置文件运行导入。 + + ``` + tiup tidb-lightning -config /tmp/tidb-lightning.toml + ``` diff --git a/markdown-pages/zh/tidb/master/tidb-monitoring-api.md b/markdown-pages/zh/tidb/master/tidb-monitoring-api.md new file mode 100644 index 0000000..b9a62e6 --- /dev/null +++ b/markdown-pages/zh/tidb/master/tidb-monitoring-api.md @@ -0,0 +1,134 @@ +--- +title: TiDB 集群监控 API +aliases: ['/docs-cn/dev/tidb-monitoring-api/'] +summary: TiDB 提供状态接口和 Metrics 接口来监控集群状态。状态接口可获取 TiDB Server 的运行状态和存储信息,PD 的状态接口可查看整个 TiKV 集群的详细信息。Metrics 接口用于监控整个集群的状态和性能。部署 Prometheus 和 Grafana 后,配置 Grafana 即可使用 Metrics 接口。 +--- + +# TiDB 集群监控 API + +TiDB 提供了以下几种接口来监控集群状态: + +- [状态接口](#使用状态接口):通过 HTTP 接口对外汇报组件的信息。通过状态接口,你可获取当前 TiDB Server 的[运行状态](#运行状态)以及表的[存储信息](#存储信息)。 +- [Metrics 接口](#使用-metrics-接口):使用 Prometheus 记录组件中各种操作的详细信息,使用 Grafana 进行可视化展示。 + +## 使用状态接口 + +状态接口用于监控组件的一些基本信息,并且可以作为 keepalive 的监测接口。另外,通过 PD 的状态接口可以看到整个 TiKV 集群的详细信息。 + +### TiDB Server + +- TiDB API 地址:`http://${host}:${port}` +- 默认端口:10080 + +#### 运行状态 + +以下示例中,通过访问 `http://${host}:${port}/status` 获取当前 TiDB Server 的状态,并判断该 TiDB Server 是否存活。结果以 **JSON** 格式返回: + +```bash +curl http://127.0.0.1:10080/status +``` + +``` +{ + connections: 0, # 当前 TiDB Server 上的客户端连接数 + version: "8.0.11-TiDB-v8.0.0", # TiDB 版本号 + git_hash: "7267747ae0ec624dffc3fdedb00f1ed36e10284b" # TiDB 当前代码的 Git Hash +} +``` + +#### 存储信息 + +以下示例中,通过访问 `http://${host}:${port}/schema_storage/${db}/${table}` 获取指定数据表的存储信息。结果以 **JSON** 格式返回: + +```bash +curl http://127.0.0.1:10080/schema_storage/mysql/stats_histograms +``` + +``` +{ + "table_schema": "mysql", + "table_name": "stats_histograms", + "table_rows": 0, + "avg_row_length": 0, + "data_length": 0, + "max_data_length": 0, + "index_length": 0, + "data_free": 0 +} +``` + +```bash +curl http://127.0.0.1:10080/schema_storage/test +``` + +``` +[ + { + "table_schema": "test", + "table_name": "test", + "table_rows": 0, + "avg_row_length": 0, + "data_length": 0, + "max_data_length": 0, + "index_length": 0, + "data_free": 0 + } +] +``` + +### PD Server + +- PD API 地址:`http://${host}:${port}/pd/api/v1/${api_name}` +- 默认端口:2379 +- 各类 `api_name` 详细信息:参见 [PD API Doc](https://download.pingcap.com/pd-api-doc.html) + +通过该接口可以获取当前所有 TiKV 节点的状态以及负载均衡信息。下面以一个单节点的 TiKV 集群为例,说明用户需要了解的信息: + +```bash +curl http://127.0.0.1:2379/pd/api/v1/stores +``` + +``` +{ + "count": 1, # TiKV 节点数量 + "stores": [ # TiKV 节点的列表 + # 集群中单个 TiKV 节点的信息 + { + "store": { + "id": 1, + "address": "127.0.0.1:20160", + "version": "4.0.0-rc.2", + "status_address": "172.16.5.90:20382", + "git_hash": "2fdb2804bf8ffaab4b18c4996970e19906296497", + "start_timestamp": 1590029618, + "deploy_path": "/data2/tidb_test/v4.0.rc.2/tikv-20372/bin", + "last_heartbeat": 1590030038949235439, + "state_name": "Up" + }, + "status": { + "capacity": "3.581TiB", # 存储总容量 + "available": "3.552TiB", # 存储剩余容量 + "used_size": "31.77MiB", + "leader_count": 174, + "leader_weight": 1, + "leader_score": 174, + "leader_size": 174, + "region_count": 531, + "region_weight": 1, + "region_score": 531, + "region_size": 531, + "start_ts": "2020-05-21T10:53:38+08:00", + "last_heartbeat_ts": "2020-05-21T11:00:38.949235439+08:00", + "uptime": "7m0.949235439s" + } + } + ] +``` + +## 使用 metrics 接口 + +Metrics 接口用于监控整个集群的状态和性能。 + +- 如果使用其他方式部署 TiDB 集群,在使用 metrics 接口前,需先[部署 Prometheus 和 Grafana](/deploy-monitoring-services.md)。 + +成功部署 Prometheus 和 Grafana 之后,[配置 Grafana](/deploy-monitoring-services.md)。 diff --git a/markdown-pages/zh/tidb/master/tidb-monitoring-framework.md b/markdown-pages/zh/tidb/master/tidb-monitoring-framework.md new file mode 100644 index 0000000..c80c0c2 --- /dev/null +++ b/markdown-pages/zh/tidb/master/tidb-monitoring-framework.md @@ -0,0 +1,58 @@ +--- +title: TiDB 监控框架概述 +aliases: ['/docs-cn/dev/tidb-monitoring-framework/','/docs-cn/dev/how-to/monitor/overview/'] +summary: TiDB 使用 Prometheus 作为监控和性能指标存储,Grafana 用于可视化展示。Prometheus 提供多个组件,包括 Prometheus Server、Client 代码库和 Alertmanager。Grafana 展示 TiDB 集群各组件的相关监控,分组包括备份恢复、Binlog、网络探活、磁盘性能、Kafka、TiDB Lightning 等。每个分组包含多个监控项页签,以及详细的监控指标看板。观看培训视频可快速了解监控与报警系统的体系、数据流转方式、系统管理方法和常用监控指标。 +--- + +# TiDB 监控框架概述 + +TiDB 使用开源时序数据库 [Prometheus](https://prometheus.io) 作为监控和性能指标信息存储方案,使用 [Grafana](https://grafana.com/grafana) 作为可视化组件进行展示。 + +## Prometheus 在 TiDB 中的应用 + +Prometheus 是一个拥有多维度数据模型的、灵活的查询语句的时序数据库。Prometheus 作为热门的开源项目,拥有活跃的社区及众多的成功案例。 + +Prometheus 提供了多个组件供用户使用。目前,TiDB 使用了以下组件: + +- Prometheus Server:用于收集和存储时间序列数据。 +- Client 代码库:用于定制程序中需要的 Metric。 +- Alertmanager:用于实现报警机制。 + +其结构如下图所示: + +![Prometheus in TiDB](/media/prometheus-in-tidb.png) + +## Grafana 在 TiDB 中的应用 + +Grafana 是一个开源的 metric 分析及可视化系统。TiDB 使用 Grafana 来展示 TiDB 集群各组件的相关监控,监控项分组如下图所示: + +![Grafana monitored_groups](/media/grafana_monitored_groups.png) + +- {TiDB_Cluster_name}-Backup-Restore:备份恢复相关的监控项。 +- {TiDB_Cluster_name}-Binlog:TiDB Binlog 相关的监控项。 +- {TiDB_Cluster_name}-Blackbox_exporter:网络探活相关监控项。 +- {TiDB_Cluster_name}-Disk-Performance:磁盘性能相关监控项。 +- {TiDB_Cluster_name}-Kafka-Overview:Kafka 相关监控项。 +- {TiDB_Cluster_name}-Lightning:TiDB Lightning 组件相关监控项。 +- {TiDB_Cluster_name}-Node_exporter:操作系统相关监控项。 +- {TiDB_Cluster_name}-Overview:重要组件监控概览。 +- {TiDB_Cluster_name}-PD:PD server 组件相关监控项。 +- {TiDB_Cluster_name}-Performance-Read:读性能相关监控项。 +- {TiDB_Cluster_name}-Performance-Write:写性能相关监控项。 +- {TiDB_Cluster_name}-TiDB:TiDB server 组件详细监控项。 +- {TiDB_Cluster_name}-TiDB-Summary:TiDB server 相关监控项概览。 +- {TiDB_Cluster_name}-TiFlash-Proxy-Summary:数据同步到 TiFlash 的代理 server 监控项概览。 +- {TiDB_Cluster_name}-TiFlash-Summary:TiFlash server 相关监控项概览。 +- {TiDB_Cluster_name}-TiKV-Details:TiKV server 组件详细监控项。 +- {TiDB_Cluster_name}-TiKV-Summary:TiKV server 监控项概览。 +- {TiDB_Cluster_name}-TiKV-Trouble-Shooting:TiKV 错误诊断相关监控项。 +- {TiDB_Cluster_name}-TiCDC:TiCDC 组件详细监控项。 +- {TiDB_Cluster_name}-TiProxy-Summary:TiProxy 监控项概览。 + +每个分组包含多个监控项页签,页签中包含多个详细的监控项信息。以 Overview 监控组为例,其中包含 5 个页签,每个页签内有相应的监控指标看板,如下图所示: + +![Grafana Overview](/media/grafana_monitor_overview.png) + +要快速了解 TiDB 监控与报警系统的体系、该系统背后的数据流转方式、系统管理方法、系统使用方法和常用监控指标,建议观看下面的培训视频(时长 29 分钟)。注意本视频只作为学习参考,具体的[监控指标与相关报警规则](/alert-rules.md#tidb-报警规则),请以文档内容为准。 + + diff --git a/markdown-pages/zh/tidb/master/tidb-scheduling.md b/markdown-pages/zh/tidb/master/tidb-scheduling.md new file mode 100644 index 0000000..b1b15f6 --- /dev/null +++ b/markdown-pages/zh/tidb/master/tidb-scheduling.md @@ -0,0 +1,154 @@ +--- +title: TiDB 数据库的调度 +aliases: ['/docs-cn/dev/tidb-scheduling/'] +summary: TiDB 数据库的调度由 PD(Placement Driver)模块负责管理和实时调度集群数据。PD 需要收集节点和 Region 的状态信息,并根据调度策略制定调度计划,包括增加 / 删除副本、迁移 Leader 角色等基本操作。调度需满足副本数量、位置分布、负载均衡、存储空间利用等需求。PD 通过心跳包收集信息,并根据策略生成调度操作序列,但具体执行由 Region Leader 决定。 +--- + +# TiDB 数据库的调度 + +[PD](https://github.com/tikv/pd) (Placement Driver) 是 TiDB 集群的管理模块,同时也负责集群数据的实时调度。本文档介绍一下 PD 的设计思想和关键概念。 + +## 场景描述 + +TiKV 集群是 TiDB 数据库的分布式 KV 存储引擎,数据以 Region 为单位进行复制和管理,每个 Region 会有多个副本 (Replica),这些副本会分布在不同的 TiKV 节点上,其中 Leader 负责读/写,Follower 负责同步 Leader 发来的 Raft log。 + +需要考虑以下场景: + +* 为了提高集群的空间利用率,需要根据 Region 的空间占用对副本进行合理的分布。 +* 集群进行跨机房部署的时候,要保证一个机房掉线,不会丢失 Raft Group 的多个副本。 +* 添加一个节点进入 TiKV 集群之后,需要合理地将集群中其他节点上的数据搬到新增节点。 +* 当一个节点掉线时,需要考虑快速稳定地进行容灾。 + * 从节点的恢复时间来看 + * 如果节点只是短暂掉线(重启服务),是否需要进行调度。 + * 如果节点是长时间掉线(磁盘故障,数据全部丢失),如何进行调度。 + * 假设集群需要每个 Raft Group 有 N 个副本,从单个 Raft Group 的副本个数来看 + * 副本数量不够(例如节点掉线,失去副本),需要选择适当的机器的进行补充。 + * 副本数量过多(例如掉线的节点又恢复正常,自动加入集群),需要合理的删除多余的副本。 +* 读/写通过 Leader 进行,Leader 的分布只集中在少量几个节点会对集群造成影响。 +* 并不是所有的 Region 都被频繁的访问,可能访问热点只在少数几个 Region,需要通过调度进行负载均衡。 +* 集群在做负载均衡的时候,往往需要搬迁数据,这种数据的迁移可能会占用大量的网络带宽、磁盘 IO 以及 CPU,进而影响在线服务。 + +以上问题和场景如果多个同时出现,就不太容易解决,因为需要考虑全局信息。同时整个系统也是在动态变化的,因此需要一个中心节点,来对系统的整体状况进行把控和调整,所以有了 PD 这个模块。 + +## 调度的需求 + +对以上的问题和场景进行分类和整理,可归为以下两类: + +**第一类:作为一个分布式高可用存储系统,必须满足的需求,包括几种** + +* 副本数量不能多也不能少 +* 副本需要根据拓扑结构分布在不同属性的机器上 +* 节点宕机或异常能够自动合理快速地进行容灾 + +**第二类:作为一个良好的分布式系统,需要考虑的地方包括** + +* 维持整个集群的 Leader 分布均匀 +* 维持每个节点的储存容量均匀 +* 维持访问热点分布均匀 +* 控制负载均衡的速度,避免影响在线服务 +* 管理节点状态,包括手动上线/下线节点 + +满足第一类需求后,整个系统将具备强大的容灾功能。满足第二类需求后,可以使得系统整体的资源利用率更高且合理,具备良好的扩展性。 + +为了满足这些需求,首先需要收集足够的信息,比如每个节点的状态、每个 Raft Group 的信息、业务访问操作的统计等;其次需要设置一些策略,PD 根据这些信息以及调度的策略,制定出尽量满足前面所述需求的调度计划;最后需要一些基本的操作,来完成调度计划。 + +## 调度的基本操作 + +调度的基本操作指的是为了满足调度的策略。上述调度需求可整理为以下三个操作: + +* 增加一个副本 +* 删除一个副本 +* 将 Leader 角色在一个 Raft Group 的不同副本之间 transfer(迁移) + +刚好 Raft 协议通过 `AddReplica`、`RemoveReplica`、`TransferLeader` 这三个命令,可以支撑上述三种基本操作。 + +## 信息收集 + +调度依赖于整个集群信息的收集,简单来说,调度需要知道每个 TiKV 节点的状态以及每个 Region 的状态。TiKV 集群会向 PD 汇报两类消息,TiKV 节点信息和 Region 信息: + +**每个 TiKV 节点会定期向 PD 汇报节点的状态信息** + +TiKV 节点 (Store) 与 PD 之间存在心跳包,一方面 PD 通过心跳包检测每个 Store 是否存活,以及是否有新加入的 Store;另一方面,心跳包中也会携带这个 [Store 的状态信息](https://github.com/pingcap/kvproto/blob/master/proto/pdpb.proto#L473),主要包括: + +* 总磁盘容量 +* 可用磁盘容量 +* 承载的 Region 数量 +* 数据写入/读取速度 +* 发送/接受的 Snapshot 数量(副本之间可能会通过 Snapshot 同步数据) +* 是否过载 +* labels 标签信息(标签是具备层级关系的一系列 Tag,能够[感知拓扑信息](/schedule-replicas-by-topology-labels.md)) + +通过使用 `pd-ctl` 可以查看到 TiKV Store 的状态信息。TiKV Store 的状态具体分为 Up,Disconnect,Offline,Down,Tombstone。各状态的关系如下: + ++ **Up**:表示当前的 TiKV Store 处于提供服务的状态。 ++ **Disconnect**:当 PD 和 TiKV Store 的心跳信息丢失超过 20 秒后,该 Store 的状态会变为 Disconnect 状态,当时间超过 `max-store-down-time` 指定的时间后,该 Store 会变为 Down 状态。 ++ **Down**:表示该 TiKV Store 与集群失去连接的时间已经超过了 `max-store-down-time` 指定的时间,默认 30 分钟。超过该时间后,对应的 Store 会变为 Down,并且开始在存活的 Store 上补足各个 Region 的副本。 ++ **Offline**:当对某个 TiKV Store 通过 PD Control 进行手动下线操作,该 Store 会变为 Offline 状态。该状态只是 Store 下线的中间状态,处于该状态的 Store 会将其上的所有 Region 搬离至其它满足搬迁条件的 Up 状态 Store。当该 Store 的 `leader_count` 和 `region_count` (在 PD Control 中获取) 均显示为 0 后,该 Store 会由 Offline 状态变为 Tombstone 状态。在 Offline 状态下,禁止关闭该 Store 服务以及其所在的物理服务器。下线过程中,如果集群里不存在满足搬迁条件的其它目标 Store(例如没有足够的 Store 能够继续满足集群的副本数量要求),该 Store 将一直处于 Offline 状态。 ++ **Tombstone**:表示该 TiKV Store 已处于完全下线状态,可以使用 `remove-tombstone` 接口安全地清理该状态的 TiKV。 + +![TiKV store status relationship](/media/tikv-store-status-relationship.png) + +**每个 Raft Group 的 Leader 会定期向 PD 汇报 Region 的状态信息** + +每个 Raft Group 的 Leader 和 PD 之间存在心跳包,用于汇报这个 [Region 的状态](https://github.com/pingcap/kvproto/blob/master/proto/pdpb.proto#L312),主要包括下面几点信息: + +* Leader 的位置 +* Followers 的位置 +* 掉线副本的个数 +* 数据写入/读取的速度 + +PD 不断的通过这两类心跳消息收集整个集群的信息,再以这些信息作为决策的依据。 + +除此之外,PD 还可以通过扩展的接口接受额外的信息,用来做更准确的决策。比如当某个 Store 的心跳包中断的时候,PD 并不能判断这个节点是临时失效还是永久失效,只能经过一段时间的等待(默认是 30 分钟),如果一直没有心跳包,就认为该 Store 已经下线,再决定需要将这个 Store 上面的 Region 都调度走。 + +但是有的时候,是运维人员主动将某台机器下线,这个时候,可以通过 PD 的管理接口通知 PD 该 Store 不可用,PD 就可以马上判断需要将这个 Store 上面的 Region 都调度走。 + +## 调度的策略 + +PD 收集了这些信息后,还需要一些策略来制定具体的调度计划。 + +**一个 Region 的副本数量正确** + +当 PD 通过某个 Region Leader 的心跳包发现这个 Region 的副本数量不满足要求时,需要通过 Add/Remove Replica 操作调整副本数量。出现这种情况的可能原因是: + +* 某个节点掉线,上面的数据全部丢失,导致一些 Region 的副本数量不足 +* 某个掉线节点又恢复服务,自动接入集群,这样之前已经补足了副本的 Region 的副本数量过多,需要删除某个副本 +* 管理员调整副本策略,修改了 [max-replicas](https://github.com/pingcap/pd/blob/v4.0.0-beta/conf/config.toml#L95) 的配置 + +**一个 Raft Group 中的多个副本不在同一个位置** + +注意这里用的是『同一个位置』而不是『同一个节点』。在一般情况下,PD 只会保证多个副本不落在一个节点上,以避免单个节点失效导致多个副本丢失。在实际部署中,还可能出现下面这些需求: + +* 多个节点部署在同一台物理机器上 +* TiKV 节点分布在多个机架上,希望单个机架掉电时,也能保证系统可用性 +* TiKV 节点分布在多个 IDC 中,希望单个机房掉电时,也能保证系统可用性 + +这些需求本质上都是某一个节点具备共同的位置属性,构成一个最小的『容错单元』,希望这个单元内部不会存在一个 Region 的多个副本。这个时候,可以给节点配置 [labels](https://github.com/tikv/tikv/blob/v4.0.0-beta/etc/config-template.toml#L140) 并且通过在 PD 上配置 [location-labels](https://github.com/pingcap/pd/blob/v4.0.0-beta/conf/config.toml#L100) 来指名哪些 label 是位置标识,需要在副本分配的时候尽量保证一个 Region 的多个副本不会分布在具有相同的位置标识的节点上。 + +**副本在 Store 之间的分布均匀分配** + +由于每个 Region 的副本中存储的数据容量上限是固定的,通过维持每个节点上面副本数量的均衡,使得各节点间承载的数据更均衡。 + +**Leader 数量在 Store 之间均匀分配** + +Raft 协议要求读取和写入都通过 Leader 进行,所以计算的负载主要在 Leader 上面,PD 会尽可能将 Leader 在节点间分散开。 + +**访问热点数量在 Store 之间均匀分配** + +每个 Store 以及 Region Leader 在上报信息时携带了当前访问负载的信息,比如 Key 的读取/写入速度。PD 会检测出访问热点,且将其在节点之间分散开。 + +**各个 Store 的存储空间占用大致相等** + +每个 Store 启动的时候都会指定一个 `Capacity` 参数,表明这个 Store 的存储空间上限,PD 在做调度的时候,会考虑节点的存储空间剩余量。 + +**控制调度速度,避免影响在线服务** + +调度操作需要耗费 CPU、内存、磁盘 IO 以及网络带宽,需要避免对线上服务造成太大影响。PD 会对当前正在进行的操作数量进行控制,默认的速度控制是比较保守的,如果希望加快调度(比如停服务升级或者增加新节点,希望尽快调度),那么可以通过调节 PD 参数动态加快调度速度。 + +## 调度的实现 + +本节介绍调度的实现 + +PD 不断地通过 Store 或者 Leader 的心跳包收集整个集群信息,并且根据这些信息以及调度策略生成调度操作序列。每次收到 Region Leader 发来的心跳包时,PD 都会检查这个 Region 是否有待进行的操作,然后通过心跳包的回复消息,将需要进行的操作返回给 Region Leader,并在后面的心跳包中监测执行结果。 + +注意这里的操作只是给 Region Leader 的建议,并不保证一定能得到执行,具体是否会执行以及什么时候执行,由 Region Leader 根据当前自身状态来定。 diff --git a/markdown-pages/zh/tidb/master/tiflash/maintain-tiflash.md b/markdown-pages/zh/tidb/master/tiflash/maintain-tiflash.md new file mode 100644 index 0000000..42ae635 --- /dev/null +++ b/markdown-pages/zh/tidb/master/tiflash/maintain-tiflash.md @@ -0,0 +1,53 @@ +--- +title: TiFlash 集群运维 +aliases: ['/docs-cn/dev/tiflash/maintain-tiflash/','/docs-cn/dev/reference/tiflash/maintain/'] +summary: TiFlash 集群运维包括查看版本、重要日志和系统表。查看版本有两种方法:通过命令或在日志中查看。重要日志包括数据同步和处理请求的信息。系统表包括数据库名、表名、副本数、位置标签、可用性和同步进度。 +--- + +# TiFlash 集群运维 + +本文介绍 [TiFlash](/tiflash/tiflash-overview.md) 集群运维的一些常见操作,包括查看 TiFlash 版本、TiFlash 重要日志及系统表。 + +## 查看 TiFlash 版本 + +查看 TiFlash 版本有以下两种方法: + +- 假设 TiFlash 的二进制文件名为 `tiflash`,则可以通过 `./tiflash version` 方式获取 TiFlash 版本。 + + 但是由于 TiFlash 的运行依赖于动态库 `libtiflash_proxy.so`,因此需要将包含动态库 `libtiflash_proxy.so` 的目录路径添加到环境变量 `LD_LIBRARY_PATH` 后,上述命令才能正常执行。 + + 例如,当 `tiflash` 和 `libtiflash_proxy.so` 在同一个目录下时,切换到该目录后,可以通过如下命令查看 TiFlash 版本: + + ```shell + LD_LIBRARY_PATH=./ ./tiflash version + ``` + +- 在 TiFlash 日志(日志路径见[配置文件 tiflash.toml [logger] 部分](/tiflash/tiflash-configuration.md#配置文件-tiflashtoml))中查看 TiFlash 版本,例如: + + ``` + : TiFlash version: TiFlash 0.2.0 master-375035282451103999f3863c691e2fc2 + ``` + +## TiFlash 重要日志介绍 + +| 日志信息 | 日志含义 | +|---------------|-------------------| +| `[INFO] [] ["KVStore: Start to persist [region 47, applied: term 6 index 10]"] [thread_id=23]` | 在 TiFlash 中看到类似日志代表数据开始同步 | +| `[DEBUG] [] ["CoprocessorHandler: grpc::Status DB::CoprocessorHandler::execute(): Handling DAG request"] [thread_id=30]` | 该日志代表 TiFlash 开始处理一个 Coprocessor 请求 | +| `[DEBUG] [] ["CoprocessorHandler: grpc::Status DB::CoprocessorHandler::execute(): Handle DAG request done"] [thread_id=30]` | 该日志代表 TiFlash 完成 Coprocessor 请求的处理 | + +你可以找到一个 Coprocessor 请求的开始或结束,然后通过日志前面打印的线程号找到该 Coprocessor 请求的其他相关日志。 + +## TiFlash 系统表 + +`information_schema.tiflash_replica` 系统表的列名及含义如下: + +| 列名 | 含义 | +|-----------------|-------------------------------------------------------------------------| +| TABLE_SCHEMA | 数据库名 | +| TABLE_NAME | 表名 | +| TABLE_ID | 表 ID | +| REPLICA_COUNT | TiFlash 副本数 | +| LOCATION_LABELS | 给 PD 的 hint,让 Region 的多个副本尽可能按照 LOCATION_LABELS 里的设置分散 | +| AVAILABLE | 是否可用(0/1) | +| PROGRESS | 同步进度 [0.0~1.0] | diff --git a/markdown-pages/zh/tidb/master/tiflash/monitor-tiflash.md b/markdown-pages/zh/tidb/master/tiflash/monitor-tiflash.md new file mode 100644 index 0000000..c9e6bec --- /dev/null +++ b/markdown-pages/zh/tidb/master/tiflash/monitor-tiflash.md @@ -0,0 +1,105 @@ +--- +title: TiFlash 集群监控 +aliases: ['/docs-cn/dev/tiflash/monitor-tiflash/','/docs-cn/dev/reference/tiflash/monitor/'] +summary: TiFlash 集群监控包括 TiFlash-Summary、TiFlash-Proxy-Summary 和 TiFlash-Proxy-Details。监控指标包括存储、内存、CPU 使用率、请求处理、错误数量、线程数、任务调度、DDL、写入、读取、Raft 等信息。注意低版本监控信息不完善,建议使用 v4.0.5 或更高版本的 TiDB 集群。 +--- + +# TiFlash 集群监控 + +使用 TiUP 部署 TiDB 集群时,一键部署监控系统 (Prometheus & Grafana),监控架构参见 [TiDB 监控框架概述](/tidb-monitoring-framework.md)。 + +目前 Grafana Dashboard 整体分为 PD、TiDB、TiKV、Node\_exporter、Overview 等。 + +TiFlash 面板一共包括 **TiFlash-Summary**、**TiFlash-Proxy-Summary**、**TiFlash-Proxy-Details**。通过面板上的指标,可以了解 TiFlash 当前的状态。其中 **TiFlash-Proxy-Summary**、**TiFlash-Proxy-Details** 主要为 TiFlash 的 Raft 层信息,其监控指标信息可参考 [TiKV 监控指标详解](/grafana-tikv-dashboard.md)。 + +> **注意:** +> +> 低版本的 TiFlash 监控信息较不完善,如有需要推荐使用 v4.0.5 或更高版本的 TiDB 集群。 + +以下为 **TiFlash-Summary** 默认的监控信息: + +## Server + +- Store size:每个 TiFlash 实例的使用的存储空间的大小。 +- Available size:每个 TiFlash 实例的可用的存储空间的大小。 +- Capacity size:每个 TiFlash 实例的存储容量的大小。 +- Uptime:自上次重启以来 TiFlash 正常运行的时间。 +- Memory:每个 TiFlash 实例内存的使用情况。 +- CPU Usage:每个 TiFlash 实例 CPU 的使用率。 +- FSync OPS:每个 TiFlash 实例每秒进行 fsync 操作的次数。 +- File Open OPS:每个 TiFlash 实例每秒进行 open 操作的次数。 +- Opened File Count:当前每个 TiFlash 实例打开的文件句柄数。 + +> **注意:** +> +> Store size、FSync OPS、File Open OPS、Opened File Count 目前仅包含了 TiFlash 存储层的统计指标,未包括 TiFlash-Proxy 内的信息。 + +## Coprocessor + +- Request QPS:所有 TiFlash 实例收到的 coprocessor 请求数量。其中 batch 是 batch 请求数量,batch_cop 是 batch 请求中的 coprocessor 请求数量,cop 是直接通过 coprocessor 接口发送的 coprocessor 请求数量,cop_dag 是所有 coprocessor 请求中 dag 请求数量,super_batch 是开启 super batch 特性的请求数量。 +- Executor QPS:所有 TiFlash 实例收到的请求中,每种 dag 算子的数量,其中 table_scan 是扫表算子,selection 是过滤算子,aggregation 是聚合算子,top_n 是 TopN 算子,limit 是 limit 算子。 +- Request Duration:所有 TiFlash 实例处理 coprocessor request 总时间,总时间为接收到该 coprocessor 请求至请求应答完毕的时间。 +- Error QPS:所有 TiFlash 实例处理 coprocessor 请求的错误数量。其中 meet_lock 为读取的数据有锁,region_not_found 为 Region 不存在,epoch_not_match 为读取的 Region epoch 与本地不一致,kv_client_error 为与 TiKV 通信产生的错误,internal_error 为 TiFlash 内部系统错误,other 为其他错误。 +- Request Handle Duration:所有 TiFlash 实例处理 coprocessor 请求处理时间,处理时间为该 coprocessor 请求开始执行到执行结束的时间。 +- Response Bytes/Seconds:所有 TiFlash 实例应答总字节数。 +- Cop task memory usage:所有 TiFlash 实例处理 coprocessor 请求占用的总内存。 +- Handling Request Number:所有 TiFlash 实例正在处理的 coprocessor 请求数量之和。请求的分类与 Request QPS 中的分类相同。 +- Threads of RPC:每个 TiFlash 实例使用的实时 RPC 线程数。 +- Max Threads of RPC:最近一段时间每个 TiFlash 实例使用的 RPC 线程数峰值。 +- Threads:每个 TiFlash 实例使用的实时线程数。 +- Max Threads:最近一段时间每个 TiFlash 实例使用的线程数峰值。 + +## Task Scheduler + +- Min TSO:每个 TiFlash 实例上正在运行的查询语句中的最小 TSO,该值确保具有最小 TSO 的查询可以被调度。如果当前没有正在运行的查询,则该值为 `uint64` 整数型最大值。 +- Estimated Thread Usage and Limit:每个 TiFlash 实例上正在运行的所有任务占用的线程估值,以及该实例上任务调度器设置的估算线程用量的软限制和硬限制。 +- Active and Waiting Queries Count:每个 TiFlash 实例上正在运行的查询数量和正在等待的查询数量。 +- Active and Waiting Tasks Count:每个 TiFlash 实例上正在运行的任务数量和正在等待的任务数量。 +- Hard Limit Exceeded Count:每个 TiFlash 实例上运行中任务的估算线程用量超过了设置的硬限制的次数。 +- Task Waiting Duration:每个 TiFlash 实例上任务从初始化到被调度的等待时长。 + +## DDL + +- Schema Version:每个 TiFlash 实例目前缓存的 schema 版本。 +- Schema Apply OPM:所有 TiFlash 实例每分钟 apply 同步 TiDB schema diff 的次数。diff apply 是正常的单次 apply 过程,如果 diff apply 失败,则 failed apply +1,并回退到 full apply,拉取最新的 schema 信息以更新 TiFlash 的 schema 版本。 +- Schema Internal DDL OPM:所有 TiFlash 实例每分钟执行的内部 DDL 次数。 +- Schema Apply Duration:所有 TiFlash 实例 apply schema 消耗的时间。 + +## Storage + +- Write Command OPS:所有 TiFlash 实例存储层每秒收到的写请求数量。 +- Write Amplification:每个 TiFlash 实例写放大倍数(实际磁盘写入量/逻辑数据写入量)。total 为自此次启动以来的写放大倍数,5min 为最近 5 分钟内的写放大倍数。 +- Read Tasks OPS:每个 TiFlash 实例每秒存储层内部读取任务的数量。 +- Rough Set Filter Rate:每个 TiFlash 实例最近 1 分钟内读取的 packet 数被存储层粗糙索引过滤的比例。 +- Internal Tasks OPS:所有 TiFlash 实例每秒进行内部数据整理任务的次数。 +- Internal Tasks Duration:所有 TiFlash 实例进行内部数据整理任务消耗的时间。 +- Page GC Tasks OPM:所有 TiFlash 实例每分钟进行 Delta 部分数据整理任务的次数。 +- Page GC Tasks Duration:所有 TiFlash 实例进行 Delta 部分数据整理任务消耗的时间分布。 +- Disk Write OPS:所有 TiFlash 实例每秒进行磁盘写入的次数。 +- Disk Read OPS:所有 TiFlash 实例每秒进行磁盘读取的次数。 +- Write flow:所有 TiFlash 实例磁盘写操作的流量。 +- Read flow:所有 TiFlash 实例磁盘读操作的流量。 + +> **注意:** +> +> 目前这部分监控指标仅包含了 TiFlash 存储层的统计指标,未包括 TiFlash-Proxy 内的信息。 + +## Storage Write Stall + +- Write & Delta Management Throughput:所有实例写入及数据整理的吞吐量。 + - `throughput_write` 表示通过 Raft 进行数据同步的吞吐量。 + - `throughput_delta-management` 表示数据整理的吞吐量。 + - `total_write` 表示自上次启动以来的总写入字节数。 + - `total_delta-management` 表示自上次启动以来数据整理的总字节数。 +- Write Stall Duration:每个实例写入和移除 Region 数据产生的卡顿时长。 +- Write Throughput By Instance:每个实例写入数据的吞吐量,包括 apply Raft 数据日志以及 Raft 快照的写入吞吐量。 +- Write Command OPS By Instance:每个实例收到各种命令的总计数。 + - `write block` 表示通过 Raft 同步数据日志。 + - `delete_range` 表示从该实例中删除一些 Region 或移动一些 Region 到该实例中。 + - `ingest` 表示这些 Region 的快照被应用到这个实例中。 + +## Raft + +- Read Index OPS:每个 TiFlash 实例每秒触发 read_index 请求的次数,等于请求触发的 Region 总数。 +- Read Index Duration:所有 TiFlash 实例在进行 read_index 消耗的时间,主要消耗在于和 Region leader 的交互和重试时间。 +- Wait Index Duration:所有 TiFlash 实例在进行 wait_index 消耗的时间,即拿到 read_index 请求后,等待本地的 Region index >= read_index 所花费的时间。 diff --git a/markdown-pages/zh/tidb/master/tiflash/tiflash-alert-rules.md b/markdown-pages/zh/tidb/master/tiflash/tiflash-alert-rules.md new file mode 100644 index 0000000..4253966 --- /dev/null +++ b/markdown-pages/zh/tidb/master/tiflash/tiflash-alert-rules.md @@ -0,0 +1,69 @@ +--- +title: TiFlash 报警规则 +aliases: ['/docs-cn/dev/tiflash/tiflash-alert-rules/','/docs-cn/dev/reference/tiflash/alert-rules/'] +summary: TiFlash 报警规则介绍了 TiFlash 集群的报警规则。包括了TiFlash_schema_error、TiFlash_schema_apply_duration、TiFlash_raft_read_index_duration 和 TiFlash_raft_wait_index_duration 四种报警规则,以及它们的规则描述和处理方法。报警规则主要用于监控TiFlash集群的运行状态,及时发现问题并联系 TiFlash 开发人员进行处理。 +--- + +# TiFlash 报警规则 + +本文介绍了 TiFlash 集群的报警规则。 + +## `TiFlash_schema_error` + +- 报警规则: + + `increase(tiflash_schema_apply_count{type="failed"}[15m]) > 0` + +- 规则描述: + + 出现 schema apply 错误时报警。 + +- 处理方法: + + 可能是逻辑问题,联系 TiFlash 开发人员。 + +## `TiFlash_schema_apply_duration` + +- 报警规则: + + `histogram_quantile(0.99, sum(rate(tiflash_schema_apply_duration_seconds_bucket[1m])) BY (le, instance)) > 20` + +- 规则描述: + + apply 时间超过 20 秒的概率超过 99% 时报警。 + +- 处理方法: + + 可能是 TiFlash 存储引擎内部问题,联系 TiFlash 开发人员。 + +## `TiFlash_raft_read_index_duration` + +- 报警规则: + + `histogram_quantile(0.99, sum(rate(tiflash_raft_read_index_duration_seconds_bucket[1m])) BY (le, instance)) > 3` + +- 规则描述: + + read index 时间超过 3 秒的概率超过 99% 时报警。 + + > **注意:** + > + > read index 请求是发送给 TiKV leader 的 kvproto 请求,TiKV region 的重试,或 Store 的繁忙/网络问题都可能导致 read index 请求时间过长。 + +- 处理方法: + + 可能 TiKV 集群分裂/迁移频繁,导致频繁重试,可以查看 TiKV 集群状态确认。 + +## `TiFlash_raft_wait_index_duration` + +- 报警规则: + + `histogram_quantile(0.99, sum(rate(tiflash_raft_wait_index_duration_seconds_bucket[1m])) BY (le, instance)) > 2` + +- 规则描述: + + TiFlash 等待 Region Raft Index 的时间超过 2 秒的概率超过 99% 时报警。 + +- 处理方法: + + 可能 TiKV 和 Proxy 的通信出现问题,联系 TiFlash 开发人员确认。 diff --git a/markdown-pages/zh/tidb/master/tiflash/tiflash-command-line-flags.md b/markdown-pages/zh/tidb/master/tiflash/tiflash-command-line-flags.md new file mode 100644 index 0000000..20dfd26 --- /dev/null +++ b/markdown-pages/zh/tidb/master/tiflash/tiflash-command-line-flags.md @@ -0,0 +1,77 @@ +--- +title: TiFlash 命令行参数 +aliases: ['/docs-cn/dev/tiflash/tiflash-command-line-flags/'] +summary: TiFlash 的命令行启动参数包括 server --config-file、dttool migrate、dttool bench 和 dttool inspect。server --config-file 用于指定配置文件路径,dttool migrate 用于迁移 DTFile 的文件格式,dttool bench 用于提供 DTFile 的简单 IO 速度测试,dttool inspect 用于检查 DTFile 的完整性。每个命令都有对应的参数,可以根据需求进行配置。警告:TiFlash 目前只支持默认压缩等级的 LZ4 算法,自定义压缩参数并未经过大量测试。注意:为保证安全,DTTool 在迁移模式下会尝试对工作目录进行加锁。 +--- + +# TiFlash 命令行参数 + +本文介绍了 TiFlash 的命令行启动参数。 + +## `server --config-file` + ++ 指定 TiFlash 的配置文件路径 ++ 默认:"" ++ 必须指定配置文件,详细的配置项请参阅 [TiFlash 配置参数](/tiflash/tiflash-configuration.md) + +## `dttool migrate` + +- 迁移 DTFile 的文件格式 (用于测试和原地降级)。数据迁移的单位为单个 DTFile。如果想进行整表迁移,通常需要定位到所有形如 `/t_
/stable/dmf_` 的路径,逐一进行迁移。可以结合脚本来自动进行这一操作。 + +- 使用场景: + - 当需要从开启了数据校验功能 (`storage.format_version` >= 3) 的 TiFlash v5.4 及以上版本降级回以前的版本时,可以使用此工具完成数据格式降级。 + - 当升级到 TiFlash v5.4 及以上,并希望对存量数据也加上数据校验功能以加固数据检验时,可以使用此工具完成数据格式升级。 + - 测试不同配置的 DTFile 空间占用和读取速度。 + - 当需要从开启了合并小文件功能 (`storage.format_version` >= 5) 的 TiFlash v7.3 及以上版本降级回以前的版本时,可以使用此工具完成数据格式的降级。 + +- 参数: + - `--imitative`:当不使用 DTFile 的加密功能时,可以使用本选项避免使用配置文件和连接 PD。 + - `--version`:DTFile 的目标版本,可选值为 1、2、3,默认为 2。1 为传统格式,2 为 checksum 对应的 DTFile 格式,3 为合并小文件后的 DTFile 格式。 + - `--algorithm`:检验哈希算法,可选值为 xxh3,city128,crc32,crc64,none,默认为 xxh3,仅在 version=2 时有用。 + - `--frame`:校验帧大小,默认为 1048576,仅在 version=2 时有用。 + - `--compression`:目标压缩算法,可选值为 LZ4(默认)、LZ4HC、zstd 和 none。 + - `--level`:目标压缩等级,不指定则根据压缩算法默认使用推荐的压缩级别。如果 `compression` 设置为 `LZ4` 或 `zstd`,则默认设置为 1;如果 `compression` 设置为 `LZ4HC`,则默认设置为 9。 + - `--config-file`:dttool migrate 的配置文件应当与 server 模式下的[配置文件](/tiflash/tiflash-command-line-flags.md#server---config-file)保持一致。见 `--imitative` 选项。 + - `--file-id`:对应 DTFile 的 ID,如 `dmf_123` 对应的 ID 是 123。 + - `--workdir`:指向 `dmf_xxx` 的父级目录。 + - `--dry`:空跑模式,只输出迁移过程。 + - `--nokeep`:不保留原数据。不开启该选项时,会产生 `dmf_xxx.old` 文件。 + +> **警告:** +> +> 虽然 TiFlash 可以读取自定义压缩算法和压缩等级的 DTFile,但目前正式支持的只有默认压缩等级的 LZ4 算法。自定义压缩参数并未经过大量测试,仅作实验。 + +> **注意:** +> +> 为保证安全 DTTool 在迁移模式下会尝试对工作目录进行加锁,因此同一工作目录下同一时间只能有一个 DTTool 执行迁移工作。如果您在中途强制停止 DTTool,可能会因锁未释放导致后面在运行 DTTool 时工具拒绝进行迁移工作。 +> 如果您遇到这种情况,在保证安全的前提下,可以手动删除工作目录下的 LOCK 文件来释放锁。 + +## `dttool bench` + +- 提供 DTFile 的简单 IO 速度测试。 +- 参数: + - `--version`:DTFile 的版本,见 [dttool migrate](#dttool-migrate) 对应参数。 + - `--algorithm`:检验哈希算法,见 [dttool migrate](#dttool-migrate) 对应参数。 + - `--frame`:校验帧大小,见 [dttool migrate](#dttool-migrate) 对应参数。 + - `--column`:测试表宽度,默认为 100。 + - `--size`:测试表长度,默认为 1000。 + - `--field`:测试表字段长度上限,默认为 1024。 + - `--random`:随机数种子。如未提供,该值从系统熵池抽取。 + - `--encryption`:启用加密功能。 + - `--repeat`:性能测试采样次数,默认为 5。 + - `--workdir`:临时数据文件夹,应指向需要测试的文件系统下的路径,默认为 /tmp/test。 + +## `dttool inspect` + +- 检查 DTFile 的完整性。数据校验的单位为单个 DTFile。如果想进行整表校验,通常需要定位到所有形如 `/t_
/stable/dmf_` 的路径,逐一进行校验。可以结合脚本来自动进行这一操作。 + +- 使用场景: + - 完成格式升降级后进行完整性检测。 + - 将原有数据文件搬迁至新环境后进行完整性检测。 + +- 参数: + - `--config-file`:dttool bench 的配置文件,见 [dttool migrate](#dttool-migrate) 对应参数。 + - `--check`:进行哈希校验。 + - `--file-id`:对应 DTFile 的 ID,见 [dttool migrate](#dttool-migrate) 对应参数。 + - `--imitative`:模拟数据库上下文,见 [dttool migrate](#dttool-migrate) 对应参数。 + - `--workdir`:数据文件夹,见 [dttool migrate](#dttool-migrate) 对应参数。 diff --git a/markdown-pages/zh/tidb/master/tiflash/tiflash-configuration.md b/markdown-pages/zh/tidb/master/tiflash/tiflash-configuration.md new file mode 100644 index 0000000..62d6014 --- /dev/null +++ b/markdown-pages/zh/tidb/master/tiflash/tiflash-configuration.md @@ -0,0 +1,325 @@ +--- +title: TiFlash 配置参数 +aliases: ['/docs-cn/dev/tiflash/tiflash-configuration/','/docs-cn/dev/reference/tiflash/configuration/'] +summary: TiFlash 配置参数包括 PD 调度参数和 TiFlash 配置参数。PD 调度参数可通过 pd-ctl 调整,包括 replica-schedule-limit 和 store-balance-rate。TiFlash 配置参数包括 tiflash.toml 和 tiflash-learner.toml,用于配置 TiFlash TCP/HTTP 服务的监听和存储路径。另外,通过拓扑 label 进行副本调度和多盘部署也是可行的。 +--- + +# TiFlash 配置参数 + +本文介绍了与部署使用 TiFlash 相关的配置参数。 + +## PD 调度参数 + +可通过 [pd-ctl](/pd-control.md) 调整参数。如果你使用 TiUP 部署,可以用 `tiup ctl:v pd` 代替 `pd-ctl -u ` 命令。 + +- [`replica-schedule-limit`](/pd-configuration-file.md#replica-schedule-limit):用来控制 replica 相关 operator 的产生速度(涉及到下线、补副本的操作都与该参数有关) + + > **注意:** + > + > 不要超过 `region-schedule-limit`,否则会影响正常 TiKV 之间的 Region 调度。 + +- `store-balance-rate`:用于限制每个 TiKV store 或 TiFlash store 的 Region 调度速度。注意这个参数只对新加入集群的 store 有效,如果想立刻生效请用下面的方式。 + + > **注意:** + > + > 4.0.2 版本之后(包括 4.0.2 版本)废弃了 `store-balance-rate` 参数且 `store limit` 命令有部分变化。该命令变化的细节请参考 [store-limit 文档](/configure-store-limit.md)。 + + - 使用 `pd-ctl -u store limit ` 命令单独设置某个 store 的 Region 调度速度。(`store_id` 可通过 `pd-ctl -u store` 命令获得)如果没有单独设置,则继承 `store-balance-rate` 的设置。你也可以使用 `pd-ctl -u store limit` 命令查看当前设置值。 + +- [`replication.location-labels`](/pd-configuration-file.md#location-labels):用来表示 TiKV 实例的拓扑关系,其中 key 的顺序代表了不同标签的层次关系。在 TiFlash 开启的情况下需要使用 [`pd-ctl config placement-rules`](/pd-control.md#config-show--set-option-value--placement-rules) 来设置默认值,详细可参考 [geo-distributed-deployment-topology](/geo-distributed-deployment-topology.md)。 + +## TiFlash 配置参数 + +> **Tip:** +> +> 如果你需要调整配置项的值,请参考[修改配置参数](/maintain-tidb-using-tiup.md#修改配置参数)进行操作。 + +### 配置文件 tiflash.toml + +```toml +## TiFlash TCP/HTTP 等辅助服务的监听 host。建议配置成 0.0.0.0,即监听本机所有 IP 地址。 +listen_host = "0.0.0.0" +## TiFlash TCP 服务的端口。TCP 服务为内部测试接口,默认使用 9000 端口。在 TiFlash v7.1.0 之前的版本中,该端口默认开启,但存在安全风险。为了提高安全性,建议对该端口进行访问控制,只允许白名单 IP 访问。从 TiFlash v7.1.0 起,可以通过注释掉该端口的配置避免安全风险。当 TiFlash 配置文件未声明该端口时,该端口也不会开启。 +## 建议在任何 TiFlash 的部署中都不配置该端口。(注: 从 TiFlash v7.1.0 起,由 TiUP >= v1.12.5 或 TiDB Operator >= v1.5.0 部署的 TiFlash 默认为安全版本,即默认未开启该端口) +# tcp_port = 9000 +## 数据块元信息的内存 cache 大小限制,通常不需要修改 +mark_cache_size = 1073741824 +## 数据块 min-max 索引的内存 cache 大小限制,通常不需要修改 +minmax_index_cache_size = 1073741824 +## DeltaIndex 内存 cache 大小限制,默认为 0,代表没有限制 +delta_index_cache_size = 0 + +## TiFlash 数据的存储路径。如果有多个目录,以英文逗号分隔。 +## 从 v4.0.9 版本开始,不推荐使用 path 及 path_realtime_mode 参数。推荐使用 [storage] 下的配置项代替,这样在多盘部署的场景下能更好地利用节点性能。 +## 从 v5.2.0 版本开始,如果要使用配置项 storage.io_rate_limit,需要同时将 TiFlash 的数据存储路径设置为 storage.main.dir。 +## 当 [storage] 配置项存在的情况下,path 和 path_realtime_mode 两个配置会被忽略。 +# path = "/tidb-data/tiflash-9000" +## 或 +# path = "/ssd0/tidb-data/tiflash,/ssd1/tidb-data/tiflash,/ssd2/tidb-data/tiflash" +## 默认为 false。如果设为 true,且 path 配置了多个目录,表示在第一个目录存放最新数据,在其他目录存放较旧的数据。 +# path_realtime_mode = false + +## TiFlash 临时文件的存放路径。默认使用 [`path` 或者 `storage.latest.dir` 的第一个目录] + "/tmp" +# tmp_path = "/tidb-data/tiflash-9000/tmp" + +## 存储路径相关配置,从 v4.0.9 开始生效 +[storage] + + ## DTFile 储存文件格式 + ## * format_version = 2 v6.0.0 以前版本的默认文件格式 + ## * format_version = 3 v6.0.0 及 v6.1.x 版本的默认文件格式,具有更完善的检验功能 + ## * format_version = 4 v7.3.0 及以前版本的默认文件格式,优化了写放大问题,同时减少了后台线程消耗。 + ## * format_version = 5 v7.4.0 及以后版本的默认文件格式(从 v7.3.0 开始引入),该格式可以合并小文件从而减少了物理文件数量。 + # format_version = 5 + + [storage.main] + ## 用于存储主要的数据,该目录列表中的数据占总数据的 90% 以上。 + dir = [ "/tidb-data/tiflash-9000" ] + ## 或 + # dir = [ "/ssd0/tidb-data/tiflash", "/ssd1/tidb-data/tiflash" ] + + ## storage.main.dir 存储目录列表中每个目录的最大可用容量。 + ## * 在未定义配置项,或者列表中全填 0 时,会使用目录所在的硬盘容量 + ## * 以 byte 为单位。目前不支持如 "10GB" 的设置 + ## * capacity 列表的长度应当与 dir 列表长度保持一致 + ## 例如: + # capacity = [ 10737418240, 10737418240 ] + + [storage.latest] + ## 用于存储最新的数据,大约占总数据量的 10% 以内,需要较高的 IOPS。 + ## 默认情况该项可留空。在未配置或者为空列表的情况下,会使用 storage.main.dir 的值。 + # dir = [ ] + ## storage.latest.dir 存储目录列表中,每个目录的最大可用容量。 + # capacity = [ 10737418240, 10737418240 ] + + ## [storage.io_rate_limit] 相关配置从 v5.2.0 开始引入。 + [storage.io_rate_limit] + ## 该配置项是 I/O 限流功能的开关,默认关闭。TiFlash 的 I/O 限流功能适用于磁盘带宽较小且磁盘带宽大小明确的云盘场景。 + ## I/O 限流功能限制下的读写流量总带宽,单位为 Byte,默认值为 0,即默认关闭 I/O 限流功能。 + # max_bytes_per_sec = 0 + ## max_read_bytes_per_sec 和 max_write_bytes_per_sec 的含义和 max_bytes_per_sec 类似,分别指 I/O 限流功能限制下的读流量总带宽和写流量总带宽。 + ## 分别用两个配置项控制读写带宽限制,适用于一些读写带宽限制分开计算的云盘,例如 Google Cloud 上的 persistent disk。 + ## 当 max_bytes_per_sec 配置不为 0 时,优先使用 max_bytes_per_sec。 + # max_read_bytes_per_sec = 0 + # max_write_bytes_per_sec = 0 + + ## 下面的参数用于控制不同 I/O 流量类型分配到的带宽权重,一般不需要调整。 + ## TiFlash 内部将 I/O 请求分成 4 种类型:前台写、后台写、前台读、后台读。 + ## I/O 限流初始化时,TiFlash 会根据下面的权重 (weight) 比例分配带宽。 + ## 以下默认配置表示每一种流量将获得 25 / (25 + 25 + 25 + 25) = 25% 的权重。 + ## 如果将 weight 配置为 0,则对应的 I/O 操作不会被限流。 + # foreground_write_weight = 25 + # background_write_weight = 25 + # foreground_read_weight = 25 + # background_read_weight = 25 + ## TiFlash 支持根据当前的 I/O 负载情况自动调整各种 I/O 类型的限流带宽,有可能会超过设置的权重。 + ## auto_tune_sec 表示自动调整的执行间隔,单位为秒。设为 0 表示关闭自动调整。 + # auto_tune_sec = 5 + + ## 下面的配置只针对存算分离模式生效,详细请参考 TiFlash 存算分离架构与 S3 支持文档 https://docs.pingcap.com/zh/tidb/dev/tiflash-disaggregated-and-s3 + # [storage.s3] + # endpoint: http://s3.{region}.amazonaws.com # S3 的 endpoint 地址 + # bucket: mybucket # TiFlash 的所有数据存储在这个 bucket 中 + # root: /cluster1_data # S3 bucket 中存储数据的根目录 + # access_key_id: {ACCESS_KEY_ID} # 访问 S3 的 ACCESS_KEY_ID + # secret_access_key: {SECRET_ACCESS_KEY} # 访问 S3 的 SECRET_ACCESS_KEY + + # [storage.remote.cache] + # dir: /data1/tiflash/cache # TiFlash Compute Node 的本地数据缓存目录 + # capacity: 858993459200 # 800 GiB + +[flash] + ## TiFlash coprocessor 服务监听地址 + service_addr = "0.0.0.0:3930" + + ## 从 v7.4.0 引入,在当前 Raft 状态机推进的 applied_index 和上次落盘时的 applied_index 的差值高于 compact_log_min_gap 时, + ## TiFlash 将执行来自 TiKV 的 CompactLog 命令,并进行数据落盘。调大该差值可能降低 TiFlash 的落盘频率,从而减少随机写场景下的读延迟,但会增大内存开销。调小该差值可能提升 TiFlash 的落盘频率,从而缓解 TiFlash 内存压力。但无论如何,在目前阶段,TiFlash 的落盘频率不会高于 TiKV,即使设置该差值为 0。 + ## 建议保持默认值。 + # compact_log_min_gap = 200 + ## 从 v5.0 引入,当 TiFlash 缓存的 Region 行数或者大小超过以下任一阈值时,TiFlash 将执行来自 TiKV 的 CompactLog 命令,并进行落盘。 + ## 建议保持默认值。 + # compact_log_min_rows = 40960 # 40k + # compact_log_min_bytes = 33554432 # 32MB + + ## 下面的配置只针对存算分离模式生效,详情请参考 TiFlash 存算分离架构与 S3 支持文档 https://docs.pingcap.com/zh/tidb/dev/tiflash-disaggregated-and-s3 + # disaggregated_mode = tiflash_write # 可选值为 tiflash_write 或者 tiflash_compute + +[flash.proxy] + ## proxy 监听地址,不填则默认是 127.0.0.1:20170 + addr = "127.0.0.1:20170" + ## 外部访问 addr 的地址,不填则默认使用 "addr" 的值 + ## 当集群部署在多个节点时,需要保证 `advertise-addr` 的地址可以从其他节点连接 + advertise-addr = "" + ## 拉取 proxy metrics 或 status 信息的监听地址,不填则默认是 127.0.0.1:20292 + status-addr = "127.0.0.1:20292" + ## 外部访问 status-addr 的地址,不填则默认使用 "status-addr" 的值 + ## 当集群部署在多个节点时,需要保证 `advertise-addr` 的地址可以从其他节点连接 + advertise-status-addr = "" + ## proxy 数据存储路径 + data-dir = "/tidb-data/tiflash-9000/flash" + ## proxy 配置文件路径 + config = "/tidb-deploy/tiflash-9000/conf/tiflash-learner.toml" + ## proxy log 路径 + log-file = "/tidb-deploy/tiflash-9000/log/tiflash_tikv.log" + ## proxy 的 log 级别 (支持 "trace"、"debug"、"info"、"warn"、"error"). 默认是 "info" + # log-level = "info" + +[logger] + ## log 级别(支持 "trace"、"debug"、"info"、"warn"、"error"),默认是 "info" + level = "info" + log = "/tidb-deploy/tiflash-9000/log/tiflash.log" + errorlog = "/tidb-deploy/tiflash-9000/log/tiflash_error.log" + ## 单个日志文件的大小,默认是 "100M" + size = "100M" + ## 最多保留日志文件个数,默认是 10 + count = 10 + +[raft] + ## PD 服务地址. 多个地址以逗号隔开 + pd_addr = "10.0.1.11:2379,10.0.1.12:2379,10.0.1.13:2379" + +[status] + ## Prometheus 拉取 metrics 信息的端口,默认是 8234 + metrics_port = 8234 + +[profiles] + +[profiles.default] + ## 存储引擎的 segment 分裂是否使用逻辑分裂。使用逻辑分裂可以减小写放大,但是会造成一定程度的硬盘空间回收不及时。默认为 false。 + ## 在 v6.2.0 以及后续版本,强烈建议保留默认值 `false`,不要将其修改为 `true`。具体请参考已知问题 [#5576](https://github.com/pingcap/tiflash/issues/5576)。 + # dt_enable_logical_split = false + + ## 单次查询过程中,节点对中间数据的内存限制 + ## 设置为整数时,单位为 byte,比如 34359738368 表示 32 GiB 的内存限制,0 表示无限制 + ## 设置为 [0.0, 1.0) 之间的浮点数时,指节点总内存的比值,比如 0.8 表示总内存的 80%,0.0 表示无限制 + ## 默认值为 0,表示不限制 + ## 当查询试图申请超过限制的内存时,查询终止执行并且报错 + max_memory_usage = 0 + + ## 所有查询过程中,节点对中间数据的内存限制 + ## 设置为整数时,单位为 byte,比如 34359738368 表示 32 GiB 的内存限制,0 表示无限制 + ## 设置为 [0.0, 1.0) 之间的浮点数时,指节点总内存的比值,比如 0.8 表示总内存的 80%,0.0 表示无限制 + ## 默认值为 0.8,表示总内存的 80% + ## 当查询试图申请超过限制的内存时,查询终止执行并且报错 + max_memory_usage_for_all_queries = 0.8 + + ## 从 v5.0 引入,表示 TiFlash Coprocessor 最多同时执行的 cop 请求数量。如果请求数量超过了该配置指定的值,多出的请求会排队等待。如果设为 0 或不设置,则使用默认值,即物理核数的两倍。 + cop_pool_size = 0 + + ## 从 v5.0 引入,表示 TiFlash Coprocessor 最多同时执行的 batch 请求数量。如果请求数量超过了该配置指定的值,多出的请求会排队等待。如果设为 0 或不设置,则使用默认值,即物理核数的两倍。 + batch_cop_pool_size = 0 + + ## 从 v6.1 引入,指定 TiFlash 执行来自 TiDB 的 ALTER TABLE ... COMPACT 请求时,能同时并行处理的请求数量。 + ## 如果这个值没有设置或设为了 0,则会采用默认值(1)。 + manual_compact_pool_size = 1 + + ## 从 v5.4.0 引入,表示是否启用弹性线程池,这项功能可以显著提高 TiFlash 在高并发场景的 CPU 利用率。默认为 true。 + # enable_elastic_threadpool = true + + ## TiFlash 存储引擎的压缩算法,支持 LZ4、zstd 和 LZ4HC,大小写不敏感。默认使用 LZ4 算法。 + dt_compression_method = "LZ4" + + ## TiFlash 存储引擎的压缩级别,默认为 1。 + ## 如果 dt_compression_method 设置为 LZ4,推荐将该值设为 1; + ## 如果 dt_compression_method 设置为 zstd,推荐将该值设为 -1 或 1,设置为 -1 的压缩率更小,但是读性能会更好; + ## 如果 dt_compression_method 设置为 LZ4HC,推荐将该值设为 9。 + dt_compression_level = 1 + + ## 从 v6.2.0 引入,表示 PageStorage 单个数据文件中有效数据的最低比例。当某个数据文件的有效数据比例低于该值时,会触发 GC 对该文件的数据进行整理。默认为 0.5。 + dt_page_gc_threshold = 0.5 + + ## 从 v7.0.0 引入,表示带 group by key 的 HashAggregation 算子在触发 spill 之前的最大可用内存,超过该阈值之后 HashAggregation 会采用 spill to disk 的方式来减小内存使用。默认值为 0,表示内存使用无限制,即不会触发 spill。 + max_bytes_before_external_group_by = 0 + + ## 从 v7.0.0 引入,表示 sort/topN 算子在触发 spill 之前的最大可用内存,超过该阈值之后 sort/TopN 会采用 spill to disk 的方式来减小内存使用。默认值为 0,表示内存使用无限制,即不会触发 spill。 + max_bytes_before_external_sort = 0 + + ## 从 v7.0.0 引入,表示带等值 join 条件的 HashJoin 算子在触发 spill 之前的最大可用内存,超过该阈值之后 HashJoin 算子会采用 spill to disk 的方式来减小内存使用。默认值为 0,表示内存使用无限制,即不会触发 spill。 + max_bytes_before_external_join = 0 + + ## 从 v7.4.0 引入,表示是否开启 TiFlash 资源管控功能。当设置为 true 时,TiFlash 会使用 Pipeline Model 执行模型。 + enable_resource_control = true + +## 安全相关配置,从 v4.0.5 开始生效 +[security] + ## 从 v5.0 引入,控制是否开启日志脱敏 + ## 若开启该选项,日志中的用户数据会以 `?` 代替显示 + ## 注意,tiflash-learner 对应的安全配置选项为 `security.redact-info-log`,需要在 tiflash-learner.toml 中另外开启 + # redact_info_log = false + + ## 包含可信 SSL CA 列表的文件路径。如果你设置了该值,`cert_path` 和 `key_path` 中的路径也需要填写 + # ca_path = "/path/to/ca.pem" + ## 包含 PEM 格式的 X509 certificate 文件路径 + # cert_path = "/path/to/tiflash-server.pem" + ## 包含 PEM 格式的 X509 key 文件路径 + # key_path = "/path/to/tiflash-server-key.pem" +``` + +### 配置文件 tiflash-learner.toml + +```toml +[server] + engine-addr = 外部访问 TiFlash coprocessor 服务的地址 + +[raftstore] + ## 处理 Raft 数据落盘的线程池中线程的数量 + apply-pool-size = 4 + ## 处理 Raft 的线程池中线程的数量,即 Raftstore 线程池的大小。 + store-pool-size = 4 + ## 控制处理 snapshot 的线程数,默认为 2。设为 0 则关闭多线程优化 + snap-handle-pool-size = 2 + ## 控制 raft store 持久化 WAL 的最小间隔。通过适当增大延迟以减少 IOPS 占用,默认为 "4ms",设为 "0ms" 则关闭该优化。 + store-batch-retry-recv-timeout = "4ms" + +[security] + ## 从 v5.0 引入,控制是否开启日志脱敏 + ## 若开启该选项,日志中的用户数据会以 `?` 代替显示 + ## 默认值为 false + redact-info-log = false + +[security.encryption] + ## 数据文件的加密方法。 + ## 可选值为 "aes128-ctr"、"aes192-ctr"、"aes256-ctr"、"sm4-ctr" (仅 v6.4.0 及之后版本) 和 "plaintext"。 + ## 默认值为 "plaintext",即默认不开启加密功能。选择 "plaintext" 以外的值则表示启用加密功能。此时必须指定主密钥。 + data-encryption-method = "aes128-ctr" + ## 轮换密钥的频率,默认值:`7d`。 + data-key-rotation-period = "168h" # 7 days + +[security.encryption.master-key] + ## 指定启用加密时的主密钥。若要了解如何配置主密钥,可以参考《静态加密 - 配置加密》:https://docs.pingcap.com/zh/tidb/dev/encryption-at-rest#配置加密 + +[security.encryption.previous-master-key] + ## 指定轮换新主密钥时的旧主密钥。旧主密钥的配置格式与主密钥相同。若要了解如何配置主密钥,可以参考《静态加密 - 配置加密》:https://docs.pingcap.com/zh/tidb/dev/encryption-at-rest#配置加密 +``` + +除以上几项外,其余功能参数和 TiKV 的配置相同。需要注意的是:`key` 为 `engine` 的 `label` 是保留项,不可手动配置。 + +### 通过拓扑 label 进行副本调度 + +[TiFlash 设置可用区](/tiflash/create-tiflash-replicas.md#设置可用区) + +### 多盘部署 + +TiFlash 支持单节点多盘部署。如果你的部署节点上有多块硬盘,可以通过以下的方式配置参数,提高节点的硬盘 I/O 利用率。TiUP 中参数配置格式参照[详细 TiFlash 配置模版](/tiflash-deployment-topology.md#拓扑模版)。 + +#### TiDB 集群版本低于 v4.0.9 + +TiDB v4.0.9 之前的版本中,TiFlash 只支持将存储引擎中的主要数据分布在多盘上。通过 `path`(TiUP 中为 `data_dir`)和 `path_realtime_mode` 这两个参数配置多盘部署。 + +多个数据存储目录在 `path` 中以英文逗号分隔,比如 `/nvme_ssd_a/data/tiflash,/sata_ssd_b/data/tiflash,/sata_ssd_c/data/tiflash`。如果你的节点上有多块硬盘,推荐把性能最好的硬盘目录放在最前面,以更好地利用节点性能。 + +如果节点上有多块相同规格的硬盘,可以把 `path_realtime_mode` 参数留空(或者把该值明确地设为 `false`)。这表示数据会在所有的存储目录之间进行均衡。但由于最新的数据仍然只会被写入到第一个目录,因此该目录所在的硬盘会较其他硬盘繁忙。 + +如果节点上有多块规格不一致的硬盘,推荐把 `path_relatime_mode` 参数设置为 `true`,并且把性能最好的硬盘目录放在 `path` 参数内的最前面。这表示第一个目录只会存放最新数据,较旧的数据会在其他目录之间进行均衡。注意此情况下,第一个目录规划的容量大小需要占总容量的约 10%。 + +#### TiDB 集群版本为 v4.0.9 及以上 + +TiDB v4.0.9 及之后的版本中,TiFlash 支持将存储引擎的主要数据和新数据都分布在多盘上。多盘部署时,推荐使用 `[storage]` 中的参数,以更好地利用节点的 I/O 性能。但 TiFlash 仍然支持 [TiDB 集群版本低于 v4.0.9](#tidb-集群版本低于-v409) 中的参数。 + +如果节点上有多块相同规格的硬盘,推荐把硬盘目录填到 `storage.main.dir` 列表中,`storage.latest.dir` 列表留空。TiFlash 会在所有存储目录之间分摊 I/O 压力以及进行数据均衡。 + +如果节点上有多块规格不同的硬盘,推荐把 I/O 性能较好的硬盘目录配置在 `storage.latest.dir` 中,把 I/O 性能较一般的硬盘目录配置在 `storage.main.dir` 中。例如节点上有一块 NVMe-SSD 硬盘加上两块 SATA-SSD 硬盘,你可以把 `storage.latest.dir` 设为 `["/nvme_ssd_a/data/tiflash"]` 以及把 `storage.main.dir` 设为 `["/sata_ssd_b/data/tiflash", "/sata_ssd_c/data/tiflash"]`。TiFlash 会根据两个目录列表分别进行 I/O 压力分摊及数据均衡。需要注意此情况下,`storage.latest.dir` 中规划的容量大小需要占总规划容量的约 10%。 + +> **警告:** +> +> `[storage]` 参数从 TiUP v1.2.5 版本开始支持。如果你的 TiDB 版本为 v4.0.9 及以上,请确保你的 TiUP 版本不低于 v1.2.5,否则 `[storage]` 中定义的数据目录不会被 TiUP 纳入管理。 diff --git a/markdown-pages/zh/tidb/master/tiflash/tiflash-overview.md b/markdown-pages/zh/tidb/master/tiflash/tiflash-overview.md new file mode 100644 index 0000000..9d9bb4e --- /dev/null +++ b/markdown-pages/zh/tidb/master/tiflash/tiflash-overview.md @@ -0,0 +1,82 @@ +--- +title: TiFlash 简介 +aliases: ['/docs-cn/dev/tiflash/tiflash-overview/','/docs-cn/dev/reference/tiflash/overview/','/docs-cn/dev/tiflash/use-tiflash/','/docs-cn/dev/reference/tiflash/use-tiflash/','/zh/tidb/dev/use-tiflash'] +summary: TiFlash 是 TiDB HTAP 形态的关键组件,提供了良好的隔离性和强一致性。它使用列存扩展和 Raft Learner 协议异步复制,通过 Raft 校对索引配合 MVCC 实现一致性隔离级别。TiFlash 架构解决了 HTAP 场景的隔离性和列存同步问题。它提供列式存储和借助 ClickHouse 高效实现的协处理器层。TiFlash 可以兼容 TiDB 和 TiSpark,推荐与 TiKV 不同节点部署以实现 Workload 隔离。具有异步复制、一致性、智能选择和计算加速等核心特性。部署完成后需要手动指定需要同步的表。 +--- + +# TiFlash 简介 + +[TiFlash](https://github.com/pingcap/tiflash) 是 TiDB HTAP 形态的关键组件,它是 TiKV 的列存扩展,在提供了良好的隔离性的同时,也兼顾了强一致性。列存副本通过 Raft Learner 协议异步复制,但是在读取的时候通过 Raft 校对索引配合 MVCC 的方式获得 Snapshot Isolation 的一致性隔离级别。这个架构很好地解决了 HTAP 场景的隔离性以及列存同步的问题。 + +## 整体架构 + +![TiFlash 架构](/media/tidb-storage-architecture-1.png) + +上图为 TiDB HTAP 形态架构,其中包含 TiFlash 节点。 + +TiFlash 提供列式存储,且拥有借助 ClickHouse 高效实现的协处理器层。除此以外,它与 TiKV 非常类似,依赖同样的 Multi-Raft 体系,以 Region 为单位进行数据复制和分散(详情见[《说存储》](https://pingcap.com/blog-cn/tidb-internal-1/)一文)。 + +TiFlash 以低消耗不阻塞 TiKV 写入的方式,实时复制 TiKV 集群中的数据,并同时提供与 TiKV 一样的一致性读取,且可以保证读取到最新的数据。TiFlash 中的 Region 副本与 TiKV 中完全对应,且会跟随 TiKV 中的 Leader 副本同时进行分裂与合并。 + +在 Linux AMD64 架构的硬件平台部署 TiFlash 时,CPU 必须支持 AVX2 指令集。确保命令 `cat /proc/cpuinfo | grep avx2` 有输出。而在 Linux ARM64 架构的硬件平台部署 TiFlash 时,CPU 必须支持 ARMv8 架构。确保命令 `cat /proc/cpuinfo | grep 'crc32' | grep 'asimd'` 有输出。通过使用向量扩展指令集,TiFlash 的向量化引擎能提供更好的性能。 + +TiFlash 可以兼容 TiDB 与 TiSpark,用户可以选择使用不同的计算引擎。 + +TiFlash 推荐使用和 TiKV 不同的节点以做到 Workload 隔离,但在无业务隔离的前提下,也可以选择与 TiKV 同节点部署。 + +TiFlash 暂时无法直接接受数据写入,任何数据必须先写入 TiKV 再同步到 TiFlash。TiFlash 以 learner 角色接入 TiDB 集群,TiFlash 支持表粒度的数据同步,部署后默认情况下不会同步任何数据,需要按照[按表构建 TiFlash 副本](/tiflash/create-tiflash-replicas.md#按表构建-tiflash-副本)一节完成指定表的数据同步。 + +TiFlash 主要包含三个组件,除了主要的存储引擎组件,另外包含 tiflash proxy 和 pd buddy 组件,其中 tiflash proxy 主要用于处理 Multi-Raft 协议通信的相关工作,pd buddy 负责与 PD 协同工作,将 TiKV 数据按表同步到 TiFlash。 + +对于按表构建 TiFlash 副本的流程,TiDB 接收到相应的 DDL 命令后 pd buddy 组件会通过 TiDB 的 status 端口获取到需要同步的数据表信息,然后会将需要同步的数据信息发送到 PD,PD 根据该信息进行相关的数据调度。 + +## 核心特性 + +TiFlash 主要有异步复制、一致性、智能选择、计算加速等几个核心特性。 + +### 异步复制 + +TiFlash 中的副本以特殊角色 (Raft Learner) 进行异步的数据复制。这表示当 TiFlash 节点宕机或者网络高延迟等状况发生时,TiKV 的业务仍然能确保正常进行。 + +这套复制机制也继承了 TiKV 体系的自动负载均衡和高可用:并不用依赖附加的复制管道,而是直接以多对多方式接收 TiKV 的数据传输;且只要 TiKV 中数据不丢失,就可以随时恢复 TiFlash 的副本。 + +### 一致性 + +TiFlash 提供与 TiKV 一样的快照隔离支持,且保证读取数据最新(确保之前写入的数据能被读取)。这个一致性是通过对数据进行复制进度校验做到的。 + +每次收到读取请求,TiFlash 中的 Region 副本会向 Leader 副本发起进度校对(一个非常轻的 RPC 请求),只有当进度确保至少所包含读取请求时间戳所覆盖的数据之后才响应读取。 + +### 智能选择 + +TiDB 可以自动选择使用 TiFlash 列存或者 TiKV 行存,甚至在同一查询内混合使用提供最佳查询速度。这个选择机制与 TiDB 选取不同索引提供查询类似:根据统计信息判断读取代价并作出合理选择。 + +### 计算加速 + +TiFlash 对 TiDB 的计算加速分为两部分:列存本身的读取效率提升以及为 TiDB 分担计算。其中分担计算的原理和 TiKV 的协处理器一致:TiDB 会将可以由存储层分担的计算下推。能否下推取决于 TiFlash 是否可以支持相关下推。具体介绍请参阅[“TiFlash 支持的计算下推”](/tiflash/tiflash-supported-pushdown-calculations.md)一节。 + +## 使用 TiFlash + +TiFlash 部署完成后并不会自动同步数据,而需要手动指定需要同步的表。 + +你可以使用 TiDB 或者 TiSpark 读取 TiFlash,TiDB 适合用于中等规模的 OLAP 计算,而 TiSpark 适合大规模的 OLAP 计算,你可以根据自己的场景和使用习惯自行选择。具体参见: + +- [构建 TiFlash 副本](/tiflash/create-tiflash-replicas.md) +- [使用 TiDB 读取 TiFlash](/tiflash/use-tidb-to-read-tiflash.md) +- [使用 TiSpark 读取 TiFlash](/tiflash/use-tispark-to-read-tiflash.md) +- [使用 MPP 模式](/tiflash/use-tiflash-mpp-mode.md) + +如果需要快速体验以 TPC-H 为例子,从导入到查询的完整流程,可以参考 [HTAP 快速上手指南](/quick-start-with-htap.md)。 + +## 另请参阅 + +- 全新部署一个包含 TiFlash 节点的集群,请参考[使用 TiUP 部署 TiDB 集群](/production-deployment-using-tiup.md) +- 已有集群新增一个 TiFlash 节点,请参考[扩容 TiFlash 节点](/scale-tidb-using-tiup.md#扩容-tiflash-节点) +- [TiFlash 常见运维操作](/tiflash/maintain-tiflash.md) +- [TiFlash 性能调优](/tiflash/tune-tiflash-performance.md) +- [TiFlash 配置参数介绍](/tiflash/tiflash-configuration.md) +- [TiFlash 监控说明](/tiflash/monitor-tiflash.md) +- [TiFlash 报警规则](/tiflash/tiflash-alert-rules.md) +- [TiFlash 常见问题处理](/tiflash/troubleshoot-tiflash.md) +- [TiFlash 支持的计算下推](/tiflash/tiflash-supported-pushdown-calculations.md) +- [TiFlash 数据校验](/tiflash/tiflash-data-validation.md) +- [TiFlash 兼容性说明](/tiflash/tiflash-compatibility.md) diff --git a/markdown-pages/zh/tidb/master/tikv-overview.md b/markdown-pages/zh/tidb/master/tikv-overview.md new file mode 100644 index 0000000..e28f1de --- /dev/null +++ b/markdown-pages/zh/tidb/master/tikv-overview.md @@ -0,0 +1,37 @@ +--- +title: TiKV 简介 +aliases: ['/docs-cn/dev/tikv-overview/'] +summary: TiKV 是一个分布式事务型的键值数据库,通过 Raft 协议保证了多副本数据一致性和高可用。整体架构采用 multi-raft-group 的副本机制,保证数据和读写负载均匀分散在各个 TiKV 上。TiKV 支持分布式事务,通过两阶段提交保证了 ACID 约束。同时,通过协处理器可以为 TiDB 分担一部分计算。 +--- + +# TiKV 简介 + +TiKV 是一个分布式事务型的键值数据库,提供了满足 ACID 约束的分布式事务接口,并且通过 [Raft 协议](https://raft.github.io/raft.pdf)保证了多副本数据一致性以及高可用。TiKV 作为 TiDB 的存储层,为用户写入 TiDB 的数据提供了持久化以及读写服务,同时还存储了 TiDB 的统计信息数据。 + +## 整体架构 + +与传统的整节点备份方式不同,TiKV 参考 Spanner 设计了 multi-raft-group 的副本机制。将数据按照 key 的范围划分成大致相等的切片(下文统称为 Region),每一个切片会有多个副本(通常是 3 个),其中一个副本是 Leader,提供读写服务。TiKV 通过 PD 对这些 Region 以及副本进行调度,以保证数据和读写负载都均匀地分散在各个 TiKV 上,这样的设计保证了整个集群资源的充分利用并且可以随着机器数量的增加水平扩展。 + +![TiKV 架构](/media/tikv-arch.png) + +### Region 与 RocksDB + +虽然 TiKV 将数据按照范围切割成了多个 Region,但是同一个节点的所有 Region 数据仍然是不加区分地存储于同一个 RocksDB 实例上,而用于 Raft 协议复制所需要的日志则存储于另一个 RocksDB 实例。这样设计的原因是因为随机 I/O 的性能远低于顺序 I/O,所以 TiKV 使用同一个 RocksDB 实例来存储这些数据,以便不同 Region 的写入可以合并在一次 I/O 中。 + +### Region 与 Raft 协议 + +Region 与副本之间通过 Raft 协议来维持数据一致性,任何写请求都只能在 Leader 上写入,并且需要写入多数副本后(默认配置为 3 副本,即所有请求必须至少写入两个副本成功)才会返回客户端写入成功。 + +TiKV 会尽量保持每个 Region 中保存的数据在一个合适的大小,目前默认是 96 MB,这样更有利于 PD 进行调度决策。当某个 Region 的大小超过一定限制(默认是 144 MiB)后,TiKV 会将它分裂为两个或者更多个 Region。同样,当某个 Region 因为大量的删除请求而变得太小时(默认是 20 MiB),TiKV 会将比较小的两个相邻 Region 合并为一个。 + +当 PD 需要把某个 Region 的一个副本从一个 TiKV 节点调度到另一个上面时,PD 会先为这个 Raft Group 在目标节点上增加一个 Learner 副本(虽然会复制 Leader 的数据,但是不会计入写请求的多数副本中)。当这个 Learner 副本的进度大致追上 Leader 副本时,Leader 会将它变更为 Follower,之后再移除操作节点的 Follower 副本,这样就完成了 Region 副本的一次调度。 + +Leader 副本的调度原理也类似,不过需要在目标节点的 Learner 副本变为 Follower 副本后,再执行一次 Leader Transfer,让该 Follower 主动发起一次选举成为新 Leader,之后新 Leader 负责删除旧 Leader 这个副本。 + +## 分布式事务 + +TiKV 支持分布式事务,用户(或者 TiDB)可以一次性写入多个 key-value 而不必关心这些 key-value 是否处于同一个数据切片 (Region) 上,TiKV 通过两阶段提交保证了这些读写请求的 ACID 约束,详见 [TiDB 乐观事务模型](/optimistic-transaction.md)。 + +## 计算加速 + +TiKV 通过协处理器 (Coprocessor) 可以为 TiDB 分担一部分计算:TiDB 会将可以由存储层分担的计算下推。能否下推取决于 TiKV 是否可以支持相关下推。计算单元仍然是以 Region 为单位,即 TiKV 的一个 Coprocessor 计算请求中不会计算超过一个 Region 的数据。 diff --git a/markdown-pages/zh/tidb/master/tiup/tiup-command-mirror-genkey.md b/markdown-pages/zh/tidb/master/tiup/tiup-command-mirror-genkey.md new file mode 100644 index 0000000..b23a1ba --- /dev/null +++ b/markdown-pages/zh/tidb/master/tiup/tiup-command-mirror-genkey.md @@ -0,0 +1,56 @@ +--- +title: tiup mirror genkey +summary: TiUP 镜像命令 genkey 用于生成私钥。管理员有 root.json、index.json、snapshot.json 和 timestamp.json 的修改权限。组件管理员有相关组件的修改权限。普通用户可以下载并使用组件。私钥名默认为 private,可以显示对应的公钥。可以将公钥信息储存为文件。输出包括私钥已存在或已写入,以及公钥内容。 +--- + +# tiup mirror genkey + +在 TiUP [镜像](/tiup/tiup-mirror-reference.md)的定义中,有三类角色: + +- 镜像管理员:拥有 `root.json`、`index.json`、`snapshot.json` 以及 `timestamp.json` 的修改权限 +- 组件管理员:拥有相关组件的修改权限 +- 普通用户:可以下载并使用组件 + +由于修改文件需要相关的管理员进行签名,因此管理员必须拥有自己的私钥。命令 `tiup mirror genkey` 就是用于生成私钥的。 + +> **警告:** +> +> 请勿通过网络传输私钥。 + +## 语法 + +```shell +tiup mirror genkey [flags] +``` + +## 选项 + +### -n, --name + +- 密钥的名字,该名字决定最终生成的文件名。生成的私钥文件路径为:`${TIUP_HOME}/keys/{name}.json`,其中 `TIUP_HOME` 为 TiUP 的 Home 目录,默认路径为 `$HOME/.tiup`,`name` 为 `-n/--name` 指定的密钥名字。 +- 数据类型:`STRING` +- 如果不指定该选项,密钥名默认为 `private`。 + +### -p, --public + +- 显示当前私钥对应的公钥,当前私钥名字由 `-n/--name` 选项指定。 +- 当指定了 `-p/--public` 时,不会创建新的私钥。若 `-n/--name` 指定的私钥不存在,则报错。 +- 数据类型:`BOOLEAN` +- 该选项默认关闭,默认值为 `false`。在命令中添加该选项,并传入 `true` 值或不传值,均可开启此功能。 + +### --save + +- 将公钥信息储存为文件放置于当前目录,文件名称为 `{hash-prefix}-public.json`,其中 `hash-prefix` 为该密钥 ID 的前 16 位。 +- 数据类型:`BOOLEAN` +- 该选项默认关闭,默认值为 `false`。在命令中添加该选项,并传入 `true` 值或不传值,均可开启此功能。 + +## 输出 + +- 若未指定 `-p/--public`: + - 若指定的密钥已存在:`Key already exists, skipped` + - 若指定的密钥不存在:`private key have been write to ${TIUP_HOME}/keys/{name}.json` +- 若指定 `-p/--public`: + - 若指定的密钥不存在:`Error: open ${TIUP_HOME}/keys/{name}.json: no such file or directory` + - 若指定的密钥存在:输出该密钥对应的公钥内容 + +[<< 返回上一页 - TiUP Mirror 命令清单](/tiup/tiup-command-mirror.md#命令清单) \ No newline at end of file diff --git a/markdown-pages/zh/tidb/master/tiup/tiup-component-dm-disable.md b/markdown-pages/zh/tidb/master/tiup/tiup-component-dm-disable.md new file mode 100644 index 0000000..5859710 --- /dev/null +++ b/markdown-pages/zh/tidb/master/tiup/tiup-component-dm-disable.md @@ -0,0 +1,48 @@ +--- +title: tiup dm disable +summary: tiup dm disable 命令用于关闭集群服务重启后的自启动。语法为 tiup dm disable ,其中 为要关闭自启的集群。选项包括 -N, --node 和 -R, --role,分别用于指定要关闭自启的节点和角色。若不指定选项,默认关闭所有节点和角色的自启。执行该命令将输出 tiup-dm 的执行日志。 +--- + +# tiup dm disable + +集群服务所在的机器重启之后会自启动,命令 `tiup dm disable` 用于关闭该自启动。该命令会在指定的节点上执行 `systemctl disable ` 来关闭服务的自启动。 + +## 语法 + +```shell +tiup dm disable [flags] +``` + +`` 为要关闭自启的集群。 + +## 选项 + +### -N, --node + +- 指定要关闭自启的节点,该选项的值为以逗号分割的节点 ID 列表,节点 ID 为[集群状态](/tiup/tiup-component-dm-display.md)表格的第一列。 +- 数据类型:`STRINGS` +- 如果不指定该选项,默认关闭所有节点的自启。 + +> **注意:** +> +> 若同时指定了 `-R, --role`,那么将关闭它们的交集中的服务自启。 + +### -R, --role + +- 指定要关闭自启的角色,该选项的值为以逗号分割的节点角色列表,角色为[集群状态](/tiup/tiup-component-dm-display.md)表格的第二列。 +- 数据类型:`STRINGS` +- 如果不指定该选项,默认关闭所有角色的自启。 + +> **注意:** +> +> 若同时指定了 `-N, --node`,那么将关闭它们的交集中的服务自启。 + +### -h, --help + +输出帮助信息。 + +## 输出 + +tiup-dm 的执行日志。 + +[<< 返回上一页 - TiUP DM 命令清单](/tiup/tiup-component-dm.md#命令清单) diff --git a/markdown-pages/zh/tidb/master/tiup/tiup-component-dm-start.md b/markdown-pages/zh/tidb/master/tiup/tiup-component-dm-start.md new file mode 100644 index 0000000..a0be1a0 --- /dev/null +++ b/markdown-pages/zh/tidb/master/tiup/tiup-component-dm-start.md @@ -0,0 +1,46 @@ +--- +title: tiup dm start +summary: tiup dm start 命令用于启动指定集群的所有或部分服务。命令语法为 tiup dm start 。选项包括 -N, --node(指定要启动的节点),-R, --role(指定要启动的角色),-h, --help(输出帮助信息)。输出为启动日志。 +--- + +# tiup dm start + +命令 `tiup dm start` 用于启动指定集群的所有或部分服务。 + +## 语法 + +```shell +tiup dm start [flags] +``` + +`` 为要操作的集群名字,如果忘记集群名字可查看[集群列表](/tiup/tiup-component-dm-list.md)。 + +## 选项 + +### -N, --node(strings,默认为 [],表示所有节点) + +指定要启动的节点,不指定则表示所有节点。该选项的值为以逗号分割的节点 ID 列表,节点 ID 为[集群状态](/tiup/tiup-component-dm-display.md)表格的第一列。 + +> **注意:** +> +> 若同时指定了 `-R, --role`,那么将启动它们的交集中的服务。 + +### -R, --role(strings,默认为 [],表示所有角色) + +指定要启动的角色,不指定则表示所有角色。该选项的值为以逗号分割的节点角色列表,角色为[集群状态](/tiup/tiup-component-dm-display.md)表格的第二列。 + +> **注意:** +> +> 若同时指定了 `-N, --node`,那么将启动它们的交集中的服务。 + +### -h, --help + +- 输出帮助信息。 +- 数据类型:`BOOLEAN` +- 该选项默认关闭,默认值为 `false`。在命令中添加该选项,并传入 `true` 值或不传值,均可开启此功能。 + +## 输出 + +启动日志。 + +[<< 返回上一页 - TiUP DM 命令清单](/tiup/tiup-component-dm.md#命令清单) \ No newline at end of file diff --git a/markdown-pages/zh/tidb/master/topn-limit-push-down.md b/markdown-pages/zh/tidb/master/topn-limit-push-down.md new file mode 100644 index 0000000..83a91c7 --- /dev/null +++ b/markdown-pages/zh/tidb/master/topn-limit-push-down.md @@ -0,0 +1,117 @@ +--- +title: TopN 和 Limit 下推 +aliases: ['/docs-cn/dev/topn-limit-push-down/'] +summary: TiDB 中的 LIMIT 子句对应 Limit 算子节点,ORDER BY 子句对应 Sort 算子节点。相邻的 Limit 和 Sort 算子组合成 TopN 算子节点,表示按排序规则提取记录的前 N 项。TopN 下推将尽可能下推到数据源附近,减少数据传输或计算的开销。可参考 [优化规则及表达式下推的黑名单](/blocklist-control-plan.md) 中的关闭方法。TopN 可下推到存储层 Coprocessor,减少计算开销。TopN 无法下推过 Join,排序规则仅依赖于外表列时可下推。TopN 也可转换成 Limit,简化排序操作。 +--- + +# TopN 和 Limit 下推 + +SQL 中的 LIMIT 子句在 TiDB 查询计划树中对应 Limit 算子节点,ORDER BY 子句在查询计划树中对应 Sort 算子节点,此外,我们会将相邻的 Limit 和 Sort 算子组合成 TopN 算子节点,表示按某个排序规则提取记录的前 N 项。从另一方面来说,Limit 节点等价于一个排序规则为空的 TopN 节点。 + +和谓词下推类似,TopN(及 Limit,下同)下推将查询计划树中的 TopN 计算尽可能下推到距离数据源最近的地方,以尽早完成数据的过滤,进而显著地减少数据传输或计算的开销。 + +如果要关闭这个规则,可参照[优化规则及表达式下推的黑名单](/blocklist-control-plan.md)中的关闭方法。 + +## 示例 + +以下通过一些例子对 TopN 下推进行说明。 + +### 示例 1:下推到存储层 Coprocessor + +```sql +create table t(id int primary key, a int not null); +explain select * from t order by a limit 10; +``` + +``` ++----------------------------+----------+-----------+---------------+--------------------------------+ +| id | estRows | task | access object | operator info | ++----------------------------+----------+-----------+---------------+--------------------------------+ +| TopN_7 | 10.00 | root | | test.t.a, offset:0, count:10 | +| └─TableReader_15 | 10.00 | root | | data:TopN_14 | +| └─TopN_14 | 10.00 | cop[tikv] | | test.t.a, offset:0, count:10 | +| └─TableFullScan_13 | 10000.00 | cop[tikv] | table:t | keep order:false, stats:pseudo | ++----------------------------+----------+-----------+---------------+--------------------------------+ +4 rows in set (0.00 sec) +``` + +在该查询中,将 TopN 算子节点下推到 TiKV 上对数据进行过滤,每个 Coprocessor 只向 TiDB 传输 10 条记录。在 TiDB 将数据整合后,再进行最终的过滤。 + +### 示例 2:TopN 下推过 Join 的情况(排序规则仅依赖于外表中的列) + +```sql +create table t(id int primary key, a int not null); +create table s(id int primary key, a int not null); +explain select * from t left join s on t.a = s.a order by t.a limit 10; +``` + +``` ++----------------------------------+----------+-----------+---------------+-------------------------------------------------+ +| id | estRows | task | access object | operator info | ++----------------------------------+----------+-----------+---------------+-------------------------------------------------+ +| TopN_12 | 10.00 | root | | test.t.a, offset:0, count:10 | +| └─HashJoin_17 | 12.50 | root | | left outer join, equal:[eq(test.t.a, test.s.a)] | +| ├─TopN_18(Build) | 10.00 | root | | test.t.a, offset:0, count:10 | +| │ └─TableReader_26 | 10.00 | root | | data:TopN_25 | +| │ └─TopN_25 | 10.00 | cop[tikv] | | test.t.a, offset:0, count:10 | +| │ └─TableFullScan_24 | 10000.00 | cop[tikv] | table:t | keep order:false, stats:pseudo | +| └─TableReader_30(Probe) | 10000.00 | root | | data:TableFullScan_29 | +| └─TableFullScan_29 | 10000.00 | cop[tikv] | table:s | keep order:false, stats:pseudo | ++----------------------------------+----------+-----------+---------------+-------------------------------------------------+ +8 rows in set (0.01 sec) +``` + +在该查询中,TopN 算子的排序规则仅依赖于外表 t 中的列,可以将 TopN 下推到 Join 之前进行一次计算,以减少 Join 时的计算开销。除此之外,TiDB 同样将 TopN 下推到了存储层中。 + +### 示例 3:TopN 不能下推过 Join 的情况 + +```sql +create table t(id int primary key, a int not null); +create table s(id int primary key, a int not null); +explain select * from t join s on t.a = s.a order by t.id limit 10; +``` + +``` ++-------------------------------+----------+-----------+---------------+--------------------------------------------+ +| id | estRows | task | access object | operator info | ++-------------------------------+----------+-----------+---------------+--------------------------------------------+ +| TopN_12 | 10.00 | root | | test.t.id, offset:0, count:10 | +| └─HashJoin_16 | 12500.00 | root | | inner join, equal:[eq(test.t.a, test.s.a)] | +| ├─TableReader_21(Build) | 10000.00 | root | | data:TableFullScan_20 | +| │ └─TableFullScan_20 | 10000.00 | cop[tikv] | table:s | keep order:false, stats:pseudo | +| └─TableReader_19(Probe) | 10000.00 | root | | data:TableFullScan_18 | +| └─TableFullScan_18 | 10000.00 | cop[tikv] | table:t | keep order:false, stats:pseudo | ++-------------------------------+----------+-----------+---------------+--------------------------------------------+ +6 rows in set (0.00 sec) +``` + +TopN 无法下推过 Inner Join。以上面的查询为例,如果先 Join 得到 100 条记录,再做 TopN 可以剩余 10 条记录。而如果在 TopN 之前就过滤到剩余 10 条记录,做完 Join 之后可能就剩下 5 条了,导致了结果的差异。 + +同理,TopN 无法下推到 Outer Join 的内表上。在 TopN 的排序规则涉及多张表上的列时,也无法下推,如 `t.a+s.a`。只有当 TopN 的排序规则仅依赖于外表上的列时,才可以下推。 + +### 示例 4:TopN 转换成 Limit 的情况 + +```sql +create table t(id int primary key, a int not null); +create table s(id int primary key, a int not null); +explain select * from t left join s on t.a = s.a order by t.id limit 10; +``` + +``` ++----------------------------------+----------+-----------+---------------+-------------------------------------------------+ +| id | estRows | task | access object | operator info | ++----------------------------------+----------+-----------+---------------+-------------------------------------------------+ +| TopN_12 | 10.00 | root | | test.t.id, offset:0, count:10 | +| └─HashJoin_17 | 12.50 | root | | left outer join, equal:[eq(test.t.a, test.s.a)] | +| ├─Limit_21(Build) | 10.00 | root | | offset:0, count:10 | +| │ └─TableReader_31 | 10.00 | root | | data:Limit_30 | +| │ └─Limit_30 | 10.00 | cop[tikv] | | offset:0, count:10 | +| │ └─TableFullScan_29 | 10.00 | cop[tikv] | table:t | keep order:true, stats:pseudo | +| └─TableReader_35(Probe) | 10000.00 | root | | data:TableFullScan_34 | +| └─TableFullScan_34 | 10000.00 | cop[tikv] | table:s | keep order:false, stats:pseudo | ++----------------------------------+----------+-----------+---------------+-------------------------------------------------+ +8 rows in set (0.00 sec) + +``` + +在上面的查询中,TopN 首先推到了外表 t 上。然后因为它要对 `t.id` 进行排序,而 `t.id` 是表 t 的主键,可以直接按顺序读出 (`keep order:true`),从而省略了 TopN 中的排序,将其简化为 Limit。 diff --git a/markdown-pages/zh/tidb/master/troubleshoot-data-inconsistency-errors.md b/markdown-pages/zh/tidb/master/troubleshoot-data-inconsistency-errors.md new file mode 100644 index 0000000..3b74176 --- /dev/null +++ b/markdown-pages/zh/tidb/master/troubleshoot-data-inconsistency-errors.md @@ -0,0 +1,91 @@ +--- +title: 数据索引一致性错误 +summary: TiDB 在执行事务或执行 ADMIN CHECK 命令时会检查数据索引的一致性。如果发现不一致,会报错并记录相关错误日志。报错处理可通过改写 SQL 或关闭错误检查来绕过。对于特定错误代码,可通过设置 @@tidb_enable_mutation_checker=0 或 @@tidb_txn_assertion_level=OFF 来跳过检查。需注意关闭开关会关闭所有 SQL 语句的对应检查。 +--- + +# 数据索引一致性报错 + +当执行事务或执行 [`ADMIN CHECK [TABLE|INDEX]`](/sql-statements/sql-statement-admin-check-table-index.md) 命令时,TiDB 会对数据索引的一致性进行检查。如果检查发现 record key-value 和 index key-value 不一致,即存储行数据的键值对和存储其对应索引的键值对之间不一致(例如多索引或缺索引),TiDB 会报数据索引一致性错误,并在日志文件中打印相关错误日志。 + +本文对数据索引一致性的报错信息进行了说明,并提供了一些绕过检查的方法。遇到报错时,你可以前往 [AskTUG 论坛](https://asktug.com/),与社区用户交流;如果是订阅用户,请联系 [PingCAP 服务与支持](https://cn.pingcap.com/support/)。 + +## 错误样例解读 + +当数据索引不一致时,你可以通过查看 TiDB 的报错信息了解行数据和索引数据在哪一项不一致,或者查看相关错误日志进行判断。 + +### 执行事务中的报错 + +本节列出了 TiDB 在执行事务过程中可能出现的数据索引不一致性的报错,并通过举例对这些信息的含义进行了解释。 + +#### Error 8133 + +`ERROR 8133 (HY000): data inconsistency in table: t, index: k2, index-count:1 != record-count:0` + +上述错误表明,对于表 `t` 中的 `k2` 索引,表中索引数量为 1,行记录的数量为 0,数量不一致。 + +#### Error 8138 + +`ERROR 8138 (HY000): writing inconsistent data in table: t, expected-values:{KindString green} != record-values:{KindString GREEN}` + +上述错误表明,事务试图写入的行值有误。即将写入的数据中,编码后的行数据与编码前的原始数据不符。 + +#### Error 8139 + +`ERROR 8139 (HY000): writing inconsistent data in table: t, index: i1, index-handle:4 != record-handle:3, index: tables.mutation{key:kv.Key{0x74, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x49, 0x5f, 0x69, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x0, 0x0, 0x0, 0xfc, 0x1, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x0, 0x0, 0x0, 0xfc, 0x3, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4}, flags:0x0, value:[]uint8{0x30}, indexID:1}, record: tables.mutation{key:kv.Key{0x74, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x49, 0x5f, 0x72, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3}, flags:0xd, value:[]uint8{0x80, 0x0, 0x2, 0x0, 0x0, 0x0, 0x1, 0x2, 0x5, 0x0, 0xa, 0x0, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x68, 0x65, 0x6c, 0x6c, 0x6f}, indexID:0}` + +上述错误表明,即将写入的数据中,handle(即行数据的 key)值不一致。对于表 `t` 中的 `i1` 索引,该事务即将写入的某行在索引键值对中的 handle 值是 4,在行记录键值对中的 handle 值是 3。这行数据将不会被写入。 + +#### Error 8140 + +`ERROR 8140 (HY000): writing inconsistent data in table: t, index: i2, col: c1, indexed-value:{KindString hellp} != record-value:{KindString hello}` + +上述错误表明,事务试图写入的行和索引的值不一致。对于表 `t` 中的 `i2` 索引,该事务即将写入的某行在索引键值对中的数据是 `hellp`,在行记录键值对中的数据是`hello`。这行数据将不会被写入。 + +#### Error 8141 + +`ERROR 8141 (HY000): assertion failed: key: 7480000000000000405f72013300000000000000f8, assertion: NotExist, start_ts: 430590532931813377, existing start ts: 430590532931551233, existing commit ts: 430590532931551234` + +上述错误表明,事务提交时断言失败。根据数据索引一致的假设,TiDB 断言 key `7480000000000000405f72013300000000000000f8` 不存在,提交事务时发现该 key 存在,是由 start ts 为 `430590532931551233` 的事务写入的。TiDB 会将该 key 的 MVCC (Multi-Version Concurrency Control) 历史输出到日志。 + +### Admin check 中的报错 + +本节列出了执行 [`ADMIN CHECK [TABLE|INDEX]`](/sql-statements/sql-statement-admin-check-table-index.md) 系列语句时 TiDB 可能出现的数据索引不一致报错,并通过举例对这些信息的含义进行了解释。 + +#### Error 8003 + +`ERROR 8003 (HY000): table count 3 != index(idx) count 2` + +上述错误表明,在 [`ADMIN CHECK`](/sql-statements/sql-statement-admin-check-table-index.md) 语句所执行的表上有 3 个行键值对,但只有 2 个索引键值对。 + +#### Error 8134 + +`ERROR 8134 (HY000): data inconsistency in table: t, index: c2, col: c2, handle: "2", index-values:"KindInt64 13" != record-values:"KindInt64 12", compare err:` + +上述错误表明,对于表 `t` 中的 `c2` 索引,handle 为 2 的行对应的索引键值对中列 c2 的值是 13,行记录键值对中列 c2 的值是 12。 + +#### Error 8223 + +`ERROR 8223 (HY000): data inconsistency in table: t2, index: i1, handle: {hello, hello}, index-values:"" != record-values:"handle: {hello, hello}, values: [KindString hello KindString hello]"` + +上述错误表明,`index-values` 为空,`record-values` 不为空,说明不存在对应的索引,但存在对应的行。 + +## 报错处理 + +发生报错时,不要自行处理,请从 PingCAP 官方或 TiDB 社区[获取支持](/support.md)。如果业务急需跳过此类报错,可以使用以下方法绕过检查。 + +### 改写 SQL + +如果只有某一条 SQL 语句报错,可以尝试将其改写为其它等价的 SQL 形式,以使用不同的执行算子来尝试绕过。 + +### 关闭错误检查 + +对于事务执行中出现的一些报错,可以使用以下方法绕过检查: + +- 对于错误代码为 8138、8139 和 8140 的错误,可以通过设置 `set @@tidb_enable_mutation_checker=0` 跳过检查。 +- 对于错误代码为 8141 的错误,可以通过设置 `set @@tidb_txn_assertion_level=OFF` 跳过检查。 + +> **注意:** +> +> 关闭 `tidb_enable_mutation_checker` 和 `tidb_txn_assertion_level` 开关会关闭对所有 SQL 语句的对应检查。 + +对于其它错误代码,包括执行 [`ADMIN CHECK [TABLE|INDEX]`](/sql-statements/sql-statement-admin-check-table-index.md) 系列语句或执行事务中的报错,由于数据中已经存在不一致,无法跳过对应的检查。 diff --git a/markdown-pages/zh/tidb/master/troubleshoot-stale-read.md b/markdown-pages/zh/tidb/master/troubleshoot-stale-read.md new file mode 100644 index 0000000..8fa3924 --- /dev/null +++ b/markdown-pages/zh/tidb/master/troubleshoot-stale-read.md @@ -0,0 +1,237 @@ +--- +title: 理解 TiKV 中的 Stale Read 和 safe-ts +summary: TiKV 中的 Stale Read 依赖于 safe-ts,保证读取历史数据版本的安全性。safe-ts 由每个 Region 中的 peer 维护,resolved-ts 则由 Region leader 维护。诊断 Stale Read 问题可通过 Grafana、tikv-ctl 和日志。常见原因包括事务提交时间过长、事务存在时间过长以及 CheckLeader 信息推送延迟。处理慢事务提交可通过识别锁所属的事务和检查应用程序逻辑。处理长事务可通过识别事务、检查应用程序逻辑和处理慢查询。解决 CheckLeader 问题可通过检查网络和监控面板指标。 +--- + +# 理解 TiKV 中的 Stale Read 和 safe-ts + +在本文档中,你可以了解 TiKV 中 Stale Read 和 safe-ts 的原理以及如何诊断与 Stale Read 相关的常见问题。 + +## Stale Read 和 safe-ts 概述 + +[Stale Read](/stale-read.md) 是一种读取历史数据版本的机制,读取 TiDB 中存储的历史数据版本。在 TiKV 中,Stale Read 依赖 [safe-ts](#什么是-safe-ts)。如果一个 Region peer 上的读请求的时间戳 (timestamp, ts) 小于等于 Region 的 safe-ts,TiDB 可以安全地从 peer 上读取数据。TiKV 通过保证 safe-ts 总是小于等于 [resolved-ts](#什么是-resolved-ts) 来保证这种安全性。 + +## 理解 safe-ts 和 resolved-ts + +本章节介绍 safe-ts 和 resolved-ts 的概念和维护方式。 + +### 什么是 safe-ts? + +safe-ts 是一个由 Region 中的每个 peer 维护的时间戳,它保证所有时间戳小于等于 safe-ts 的事务已经被 peer apply,从而实现本地 Stale Read。 + +### 什么是 resolved-ts? + +resolved-ts 是一个时间戳,它保证所有时间戳小于该值的事务已经被 leader apply。与 safe-ts 不同,resolved-ts 只由 Region leader 维护。Follower 可能有一个比 leader 更小的 apply index,因此 resolved-ts 不能直接被当作 safe-ts。 + +### safe-ts 的维护 + +`RegionReadProgress` 模块维护 safe-ts。Region leader 维护 resolved-ts,并定期通过 CheckLeader RPC 将 resolved-ts、最小的(使 resolved-ts 生效的)apply index和 Region 本身发送给所有副本的 `RegionReadProgerss` 模块。 + +当一个 peer apply 数据时,它会更新 apply index,并检查是否有 pending resolved-ts 可以成为新的 safe-ts。 + +### resolved-ts 的维护 + +Region leader 使用一个 resolver 来管理 resolved-ts。该 resolver 通过接收 Raft apply 时的变更日志来跟踪 LOCK CF (Column Family) 中的锁。当初始化时,resolver 会扫描整个 Region 来跟踪锁。 + +## 诊断 Stale Read 问题 + +本章节介绍如何使用 Grafana、`tikv-ctl` 和日志诊断 Stale Read 问题。 + +### 识别问题 + +在 [Grafana > TiDB dashboard > **KV Request** 监控面板](/grafana-tidb-dashboard.md#kv-request)中,以下面板显示了 Stale Read 的命中率、OPS 和流量: + +![Stale Read Hit/Miss OPS](/media/stale-read/metrics-hit-miss.png) + +![Stale Read Req OPS](/media/stale-read/metrics-ops.png) + +![Stale Read Req Traffic](/media/stale-read/traffic.png) + +关于上述监控项的更多信息,参考 [TiDB 监控指标](/grafana-tidb-dashboard.md#kv-request)。 + +当 Stale Read 问题发生时,你可能会注意到上述监控项的变化。最直接的指标是 TiDB 的 WARN 日志,它会报告 `DataIsNotReady` 和 Region ID,以及它遇到的 `safe-ts`。 + +### 常见原因 + +下面是影响 Stale Read 有效性的常见原因: + +- 事务提交时间过长。 +- 事务在提交前存在太长时间。 +- 从 leader 到 follower 推送 CheckLeader 信息的延迟。 + +### 使用 Grafana 诊断 + +在 [**TiKV-Details** > **Resolved-TS** 监控面板](/grafana-tikv-dashboard.md#resolved-ts)中,你可以识别每个 TiKV 上 resolved-ts 和 safe-ts 最小的 Region。如果这些时间戳明显落后于实时时间,你需要使用 `tikv-ctl` 检查这些 Region 的详细信息。 + +### 使用 `tikv-ctl` 诊断 + +`tikv-ctl` 提供了 resolver 和 `RegionReadProgress` 的最新详细信息。更多信息,参考[获取 Region 的 `RegionReadProgress` 状态](/tikv-control.md#获取一个-region-的-regionreadprogress-状态)。 + +下面是一个使用示例: + +```bash +./tikv-ctl --host 127.0.0.1:20160 get-region-read-progress -r 14 --log --min-start-ts 0 +``` + +输出结果如下: + +```log +Region read progress: + exist: true, + safe_ts: 0, + applied_index: 92, + pending front item (oldest) ts: 0, + pending front item (oldest) applied index: 0, + pending back item (latest) ts: 0, + pending back item (latest) applied index: 0, + paused: false, +Resolver: + exist: true, + resolved_ts: 0, + tracked index: 92, + number of locks: 0, + number of transactions: 0, + stopped: false, +``` + +上面的输出结果可以帮助你判断: + +- 锁是否阻塞了 resolved-ts。 +- apply index 是否太小而无法更新 safe-ts。 +- 当存在 follower peer 时,leader 是否发送了更新的 resolved-ts。 + +### 使用日志诊断 + +TiKV 每 10 秒检查以下监控项: + +- resolved-ts 最小的 Region leader +- resolved-ts 最小的 Region follower +- safe-ts 最小的 Region follower + +如果这些时间戳中的任何一个异常地小,TiKV 就会打印日志。 + +当你想要诊断一个已经不存在的历史问题时,这些日志尤其有用。 + +下面是日志的示例: + +```log +[2023/08/29 16:48:18.118 +08:00] [INFO] [endpoint.rs:505] ["the max gap of leader resolved-ts is large"] [last_resolve_attempt="Some(LastAttempt { success: false, ts: TimeStamp(443888082736381953), reason: \"lock\", lock: Some(7480000000000000625F728000000002512B5C) })"] [duration_to_last_update_safe_ts=10648ms] [min_memory_lock=None] [txn_num=0] [lock_num=0] [min_lock=None] [safe_ts=443888117326544897] [gap=110705ms] [region_id=291] + +[2023/08/29 16:48:18.118 +08:00] [INFO] [endpoint.rs:526] ["the max gap of follower safe-ts is large"] [oldest_candidate=None] [latest_candidate=None] [applied_index=3276] [duration_to_last_consume_leader=11460ms] [resolved_ts=443888117117353985] [safe_ts=443888117117353985] [gap=111503ms] [region_id=273] + +[2023/08/29 16:48:18.118 +08:00] [INFO] [endpoint.rs:547] ["the max gap of follower resolved-ts is large; it's the same region that has the min safe-ts"] +``` + +## 诊断建议 + +### 处理慢事务提交 + +提交时间长的事务通常是大事务。这个慢事务的 prewrite 阶段会留下一些锁,但是在 commit 阶段清理掉锁之前需要很长时间。为了解决这个问题,你可以尝试识别锁所属的事务,并找出它们存在的原因,例如使用日志。 + +下面是一些你可以采取的措施: + +- 在 `tikv-ctl` 命令中指定 `--log` 选项,并在 TiKV 日志中通过 start_ts 查找相应的锁。 +- 在 TiDB 和 TiKV 日志中搜索 start_ts,以识别事务的问题。 + + 如果一个查询花费超过 60 秒,就会打印一个带有 SQL 语句的 `expensive_query` 日志。你可以使用 start_ts 值匹配日志。下面是一个示例: + + ```log + [2023/07/17 19:32:09.403 +08:00] [WARN] [expensivequery.go:145] [expensive_query] [cost_time=60.025022732s] [cop_time=0.00346666s] [process_time=8.358409508s] [wait_time=0.013582596s] [request_count=278] [total_keys=9943616] [process_keys=9943360] [num_cop_tasks=278] [process_avg_time=0.030066221s] [process_p90_time=0.045296042s] [process_max_time=0.052828934s] [process_max_addr=192.168.31.244:20160] [wait_avg_time=0.000048858s] [wait_p90_time=0.00006057s] [wait_max_time=0.00040991s] [wait_max_addr=192.168.31.244:20160] [stats=t:442916666913587201] [conn=2826881778407440457] [user=root] [database=test] [table_ids="[100]"] [**txn_start_ts**=442916790435840001] [mem_max="2514229289 Bytes (2.34 GB)"] [sql="update t set b = b + 1"] + ``` + +- 如果你无法从日志中获取关于锁的足够信息,可以使用 [`CLUSTER_TIDB_TRX`](/information-schema/information-schema-tidb-trx.md#cluster_tidb_trx) 表查找活跃的事务。 +- 执行 [`SHOW PROCESSLIST`](/sql-statements/sql-statement-show-processlist.md) 查看当前连接到同一个 TiDB 服务器的会话及其在当前语句上花费的时间。但是它不会显示 start_ts。 + +如果锁是由于正在进行的大事务而存在的,考虑修改你的应用程序逻辑,因为这些锁会阻碍 resolve-ts 的进度。 + +如果锁不属于任何正在进行的事务,可能是由于协调器 (TiDB) 在预写锁之后崩溃。在这种情况下,TiDB 会自动解决锁。除非问题持续存在,否则不需要采取任何措施。 + +### 处理长事务 + +长时间保持活跃的事务,即使最终提交了,也可能会阻塞 resolved-ts 的进度。这是因为这些长期存在的事务的 start-ts 用于计算 resolved-ts。 + +要解决这个问题,你可以: + +- 识别事务:首先识别与锁相关的事务,了解它们存在的原因。你可以使用日志帮助识别。 + +- 检查应用程序逻辑:如果长时间的事务持续时间是由于应用程序逻辑导致的,考虑修改应用程序以防止这种情况发生。 + +- 处理慢查询:如果事务的持续时间由于慢查询而延长,优先解决这些查询以缓解问题。 + +### 解决 CheckLeader 问题 + +为了解决 CheckLeader 问题,你可以检查网络和 [**TiKV-Details** > **Resolved-TS** 监控面板](/grafana-tikv-dashboard.md#resolved-ts)中的 **Check Leader Duration** 指标。 + +## 示例 + +如果你观察到 **Stale Read OPS** 的 miss rate 增加,如下所示: + +![Example: Stale Read OPS](/media/stale-read/example-ops.png) + +首先,你可以检查 [**TiKV-Details** > **Resolved-TS** 监控面板](/grafana-tikv-dashboard.md#resolved-ts)中的 **Max Resolved TS gap** 和 **Min Resolved TS Region** 指标: + +![Example: Max Resolved TS gap](/media/stale-read/example-ts-gap.png) + +从上述指标中,你可以发现 Region `3121` 和其他一些 Region 没有及时更新 resolved-ts。 + +为了获取 Region `3121` 的更多详细信息,你可以执行以下命令: + +```bash +./tikv-ctl --host 127.0.0.1:20160 get-region-read-progress -r 3121 --log +``` + +输出结果如下: + +```log +Region read progress: + exist: true, + safe_ts: 442918444145049601, + applied_index: 2477, + read_state.ts: 442918444145049601, + read_state.apply_index: 1532, + pending front item (oldest) ts: 0, + pending front item (oldest) applied index: 0, + pending back item (latest) ts: 0, + pending back item (latest) applied index: 0, + paused: false, + discarding: false, +Resolver: + exist: true, + resolved_ts: 442918444145049601, + tracked index: 2477, + number of locks: 480000, + number of transactions: 1, + stopped: false, +``` + +值得注意的是,`applied_index` 等于 resolver 中的 `tracked index`,均为 `2477`。因此,resolver 可能是这个问题的根源。你还可以看到,有 1 个事务在这个 Region 中留下了 480000 个锁,这可能是问题的原因。 + +为了获取确切的事务和一些锁的 keys,你可以检查 TiKV 日志并搜索 `locks with`。输出结果如下: + +```log +[2023/07/17 21:16:44.257 +08:00] [INFO] [resolver.rs:213] ["locks with the minimum start_ts in resolver"] [keys="[74800000000000006A5F7280000000000405F6, ... , 74800000000000006A5F72800000000000EFF6, 74800000000000006A5F7280000000000721D9, 74800000000000006A5F72800000000002F691]"] [start_ts=442918429687808001] [region_id=3121] +``` + +从 TiKV 日志中,你可以获取事务的 start_ts,即 `442918429687808001`。为了获取关于语句和事务的更多信息,你可以在 TiDB 日志中搜索这个时间戳。找到结果如下: + +```log +[2023/07/17 21:16:18.287 +08:00] [INFO] [2pc.go:685] ["[BIG_TXN]"] [session=2826881778407440457] ["key sample"=74800000000000006a5f728000000000000000] [size=319967171] [keys=10000000] [puts=10000000] [dels=0] [locks=0] [checks=0] [txnStartTS=442918429687808001] + +[2023/07/17 21:16:22.703 +08:00] [WARN] [expensivequery.go:145] [expensive_query] [cost_time=60.047172498s] [cop_time=0.004575113s] [process_time=15.356963423s] [wait_time=0.017093811s] [request_count=397] [total_keys=20000398] [process_keys=10000000] [num_cop_tasks=397] [process_avg_time=0.038682527s] [process_p90_time=0.082608262s] [process_max_time=0.116321331s] [process_max_addr=192.168.31.244:20160] [wait_avg_time=0.000043057s] [wait_p90_time=0.00004007s] [wait_max_time=0.00075014s] [wait_max_addr=192.168.31.244:20160] [stats=t:442918428521267201] [conn=2826881778407440457] [user=root] [database=test] [table_ids="[106]"] [txn_start_ts=442918429687808001] [mem_max="2513773983 Bytes (2.34 GB)"] [sql="update t set b = b + 1"] +``` + +接着,你可以基本定位导致问题的语句。为了进一步检查,你可以执行 [`SHOW PROCESSLIST`](/sql-statements/sql-statement-show-processlist.md) 语句。输出结果如下: + +```sql ++---------------------+------+---------------------+--------+---------+------+------------+---------------------------+ +| Id | User | Host | db | Command | Time | State | Info | ++---------------------+------+---------------------+--------+---------+------+------------+---------------------------+ +| 2826881778407440457 | root | 192.168.31.43:58641 | test | Query | 48 | autocommit | update t set b = b + 1 | +| 2826881778407440613 | root | 127.0.0.1:45952 | test | Execute | 0 | autocommit | select * from t where a=? | +| 2826881778407440619 | root | 192.168.31.43:60428 | | Query | 0 | autocommit | show processlist | ++---------------------+------+---------------------+--------+---------+------+------------+---------------------------+ +``` + +输出结果显示,有程序正在执行一个意外的 `UPDATE` 语句 (`update t set b = b + 1`),这导致了一个大事务并阻塞了 Stale Read。 + +你可以停止执行这个 `UPDATE` 语句的应用程序来解决这个问题。 diff --git a/markdown-pages/zh/tidb/master/troubleshoot-tidb-cluster.md b/markdown-pages/zh/tidb/master/troubleshoot-tidb-cluster.md new file mode 100644 index 0000000..6d6a4e3 --- /dev/null +++ b/markdown-pages/zh/tidb/master/troubleshoot-tidb-cluster.md @@ -0,0 +1,143 @@ +--- +title: TiDB 集群故障诊断 +aliases: ['/docs-cn/dev/troubleshoot-tidb-cluster/','/docs-cn/dev/how-to/troubleshoot/cluster-setup/'] +summary: TiDB 集群故障诊断包括收集出错信息、组件状态、日志信息、机器配置和 dmesg 中的问题。解决数据库连接问题需要确认服务是否启动,查看 tidb-server 日志并清空数据重新部署服务。解决 tidb-server 启动报错需检查参数、端口占用和 pd-server 连接。解决 tikv-server 启动报错需检查参数、端口占用和 pd-server 连接。解决 pd-server 启动报错需检查参数和端口占用。进程异常退出需检查是否在前台启动,使用 nohup+& 方式运行或写在脚本中。TiKV 进程异常重启需检查 OOM 信息和 panic log。连接被拒绝需确保网络参数正确。解决文件打开过多问题需确保 ulimit -n 足够大。数据库访问超时需检查拓扑结构、硬件配置、其他服务、操作、CPU 线程、网络 /IO 监控数据。 +--- + +# TiDB 集群故障诊断 + +当试用 TiDB 遇到问题时,请先参考本篇文档。如果问题未解决,请收集以下信息并通过 [TiDB 支持资源](/support.md)解决: + ++ 具体的出错信息以及正在执行的操作 ++ 当前所有组件的状态 ++ 出问题组件 log 中的 error/fatal/panic 信息 ++ 机器配置以及部署拓扑 ++ dmesg 中 TiDB 组件相关的问题 + +## 数据库连接不上 + +首先请确认集群的各项服务是否已经启动,包括 tidb-server、pd-server、tikv-server。请用 ps 命令查看所有进程是否在。如果某个组件的进程已经不在了,请参考对应的章节排查错误。 + +如果所有的进程都在,请查看 tidb-server 的日志,看是否有报错?常见的错误包括: + ++ InformationSchema is out of date + + 无法连接 tikv-server,请检查 pd-server 以及 tikv-server 的状态和日志。 + ++ panic + + 程序有错误,请将具体的 panic log [提供给 TiDB 开发者](https://github.com/pingcap/tidb/issues/new/choose)。 + + 如果是清空数据并重新部署服务,请确认以下信息: + ++ pd-server、tikv-server 数据都已清空 + + tikv-server 存储具体的数据,pd-server 存储 tikv-server 中数据的元信息。如果只清空 pd-server 或只清空 tikv-server 的数据,会导致两边数据不匹配。 + ++ 清空 pd-server 和 tikv-server 的数据并重启后,也需要重启 tidb-server + + 集群 ID 是由 pd-server 在集群初始化时随机分配,所以重新部署集群后,集群 ID 会发生变化。tidb-server 业务需要重启以获取新的集群 ID。 + +## tidb-server 启动报错 + +tidb-server 无法启动的常见情况包括: + ++ 启动参数错误 + + 请参考 [TiDB 命令行参数](/command-line-flags-for-tidb-configuration.md)。 + ++ 端口被占用:`lsof -i:port` + + 请确保 tidb-server 启动所需要的端口未被占用。 + ++ 无法连接 pd-server + + 首先检查 pd-server 的进程状态和日志,确保 pd-server 成功启动,对应端口已打开:`lsof -i:port`。 + + 若 pd-server 正常,则需要检查 tidb-server 机器和 pd-server 对应端口之间的连通性,确保网段连通且对应服务端口已添加到防火墙白名单中,可通过 nc 或 curl 工具检查。 + + 例如,假设 tidb 服务位于 `192.168.1.100`,无法连接的 pd 位于 `192.168.1.101`,且 2379 为其 client port,则可以在 tidb 机器上执行 `nc -v -z 192.168.1.101 2379`,测试是否可以访问端口。或使用 `curl -v 192.168.1.101:2379/pd/api/v1/leader` 直接检查 pd 是否正常服务。 + +## tikv-server 启动报错 + ++ 启动参数错误 + + 请参考 [TiKV 启动参数](/command-line-flags-for-tikv-configuration.md)文档。 + ++ 端口被占用:`lsof -i:port` + + 请确保 tikv-server 启动所需要的端口未被占用:`lsof -i:port`。 + ++ 无法连接 pd-server + + 首先检查 pd-server 的进程状态和日志。确保 pd-server 成功启动,对应端口已打开:`lsof -i:port`。 + + 若 pd-server 正常,则需要检查 tikv-server 机器和 pd-server 对应端口之间的连通性,确保网段连通且对应服务端口已添加到防火墙白名单中,可通过 nc 或 curl 工具检查。具体命令参考上一节。 + ++ 文件被占用 + + 不要在一个数据库文件目录上打开两个 tikv。 + +## pd-server 启动报错 + ++ 启动参数错误 + + 请参考 [PD 命令行参数](/command-line-flags-for-pd-configuration.md)文档。 + ++ 端口被占用:`lsof -i:port` + + 请确保 pd-server 启动所需要的端口未被占用:`lsof -i:port`。 + +## TiDB/TiKV/PD 进程异常退出 + ++ 进程是否是启动在前台 + + 当前终端退出给其所有子进程发送 HUP 信号,从而导致进程退出。 + ++ 是否是在命令行用过 `nohup+&` 方式直接运行 + + 这样依然可能导致进程因终端连接突然中断,作为终端 SHELL 的子进程被杀掉。 + + 推荐将启动命令写在脚本中,通过脚本运行(相当于二次 fork 启动)。 + +## TiKV 进程异常重启 + ++ 检查 dmesg 或者 syslog 里面是否有 OOM 信息 + + 如果有 OOM 信息并且杀掉的进程为 TiKV,请减少 TiKV 的 RocksDB 的各个 CF 的 `block-cache-size` 值。 + ++ 检查 TiKV 日志是否有 panic 的 log + + 提交 Issue 并附上 panic 的 log。 + +## TiDB panic + +请提供 panic 的 log。 + +## 连接被拒绝 + ++ 请确保操作系统的网络参数正确,包括但不限于 + - 连接字符串中的端口和 tidb-server 启动的端口需要一致 + - 请保证防火墙的配置正确 + +## Too many open files + +在启动进程之前,请确保 `ulimit -n` 的结果足够大,推荐设为 unlimited 或者是大于 1000000。 + +## 数据库访问超时,系统负载高 + +首先检查 [SLOW-QUERY](/identify-slow-queries.md) 日志,判断是否是因为某条 SQL 语句导致。如果未能解决,请提供如下信息: + ++ 部署的拓扑结构 + - tidb-server/pd-server/tikv-server 部署了几个实例 + - 这些实例在机器上是如何分布的 ++ 机器的硬件配置 + - CPU 核数 + - 内存大小 + - 硬盘类型(SSD 还是机械硬盘) + - 是实体机还是虚拟机 ++ 机器上除了 TiDB 集群之外是否还有其他服务 ++ pd-server 和 tikv-server 是否分开部署 ++ 目前正在进行什么操作 ++ 用 `top -H` 命令查看当前占用 CPU 的线程名 ++ 最近一段时间的网络/IO 监控数据是否有异常 diff --git a/markdown-pages/zh/tidb/master/troubleshoot-tidb-oom.md b/markdown-pages/zh/tidb/master/troubleshoot-tidb-oom.md new file mode 100644 index 0000000..d83f686 --- /dev/null +++ b/markdown-pages/zh/tidb/master/troubleshoot-tidb-oom.md @@ -0,0 +1,198 @@ +--- +title: TiDB OOM 故障排查 +summary: TiDB OOM 故障排查总结了 OOM 常见问题的解决思路、故障现象、原因、解决方法和需要收集的诊断信息。排查思路包括确认是否属于 OOM 问题和进一步排查触发 OOM 的原因。常见故障原因包括部署问题、数据库问题和客户端问题。处理 OOM 问题需要收集操作系统内存配置、数据库版本和内存配置、Grafana TiDB 内存使用情况等信息。详细排查方法请参考相关章节。 +--- + +# TiDB OOM 故障排查 + +本文总结了 TiDB Out of Memory (OOM) 常见问题的解决思路、故障现象、故障原因、解决方法,以及需要收集的诊断信息。在遇到 OOM 问题时,你可以参考本文档来排查错误原因并进行处理。 + +## 常见故障现象 + +OOM 常见的故障现象包括(但不限于): + +- 客户端报错:`SQL error, errno = 2013, state = 'HY000': Lost connection to MySQL server during query` + +- 查看 Grafana 监控,发现以下现象: + - **TiDB** > **Server** > **Memory Usage** 显示 process/heapInUse 持续升高,达到阈值后掉零 + - **TiDB** > **Server** > **Uptime** 显示为掉零 + - **TiDB-Runtime** > **Memory Usage** 显示 estimate-inuse 持续升高 + +- 查看 `tidb.log`,可发现如下日志条目: + - OOM 相关的 Alarm:`[WARN] [memory_usage_alarm.go:139] ["tidb-server has the risk of OOM because of memory usage exceeds alarm ratio. Running SQLs and heap profile will be recorded in record path"]`。关于该日志的详细说明,请参考 [`memory-usage-alarm-ratio`](/system-variables.md#tidb_memory_usage_alarm_ratio)。 + - 重启相关的日志条目:`[INFO] [printer.go:33] ["Welcome to TiDB."]`。 + +## 整体排查思路 + +在排查 OOM 问题时,整体遵循以下排查思路: + +1. 确认是否属于 OOM 问题。 + + 执行以下命令查看操作系统日志。如果故障发生的时间点附近存在 `oom-killer` 的日志,则可以确定是 OOM 问题。 + + ```shell + dmesg -T | grep tidb-server + ``` + + 下面是包含 `oom-killer` 的日志输出示例: + + ```shell + ...... + Mar 14 16:55:03 localhost kernel: tidb-server invoked oom-killer: gfp_mask=0x201da, order=0, oom_score_adj=0 + Mar 14 16:55:03 localhost kernel: tidb-server cpuset=/ mems_allowed=0 + Mar 14 16:55:03 localhost kernel: CPU: 14 PID: 21966 Comm: tidb-server Kdump: loaded Not tainted 3.10.0-1160.el7.x86_64 #1 + Mar 14 16:55:03 localhost kernel: Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.14.0-0-g155821a1990b-prebuilt.qemu.org 04/01/2014 + ...... + Mar 14 16:55:03 localhost kernel: Out of memory: Kill process 21945 (tidb-server) score 956 or sacrifice child + Mar 14 16:55:03 localhost kernel: Killed process 21945 (tidb-server), UID 1000, total-vm:33027492kB, anon-rss:31303276kB, file-rss:0kB, shmem-rss:0kB + Mar 14 16:55:07 localhost systemd: tidb-4000.service: main process exited, code=killed, status=9/KILL + ...... + ``` + +2. 确认是 OOM 问题之后,可以进一步排查触发 OOM 的原因是部署问题还是数据库问题。 + + - 如果是部署问题触发 OOM,需要排查资源配置、混合部署的影响。 + - 如果是数据库问题触发 OOM,常见原因有: + - TiDB 处理较大的数据流量,如:大查询、大写入、数据导入等。 + - TiDB 的高并发场景,多条 SQL 并发消耗资源,或者算子并发高。 + - TiDB 内存泄露,资源没有释放。 + + 具体排查方法请参考下面的章节。 + +## 常见故障原因和解决方法 + +根据 OOM 出现的原因,一般可以分为以下几种情况: + +- [部署问题](#部署问题) +- [数据库问题](#数据库问题) +- [客户端问题](#客户端问题) + +### 部署问题 + +如果是由于部署不当导致的 OOM 问题,常见的原因有: + +- 操作系统内存容量规划偏小,导致内存不足。 +- TiUP [`resource_control`](/tiup/tiup-cluster-topology-reference.md#global) 配置不合理。 +- 在混合部署的情况下(指 TiDB 和其他应用程序部署在同一台服务器上),其他应用程序抢占资源导致 TiDB 被 `oom-killer` 关闭。 + +### 数据库问题 + +本节介绍由数据库问题导致的 OOM 问题和解决办法。 + +> **注意:** +> +> 如果 SQL 返回 `ERROR 1105 (HY000): Out Of Memory Quota![conn_id=54]`,是由于配置了 [`tidb_mem_quota_query`](/system-variables.md#tidb_mem_quota_query) 导致,数据库的内存使用控制行为会触发该报错。此报错为正常行为。 + +#### 执行 SQL 语句时消耗太多内存 + +可以根据以下不同的触发 OOM 的原因,采取相应的措施减少 SQL 的内存使用: + +- 如果 SQL 的执行计划不优,比如由于缺少合适的索引、统计信息过期、优化器 bug 等原因,会导致选错 SQL 的执行计划,进而出现巨大的中间结果集累积在内存中。这种情况下可以考虑采取以下措施: + - 添加合适的索引 + - 使用[算子的数据落盘功能](/configure-memory-usage.md#数据落盘) + - 调整表之间的 JOIN 顺序 + - 使用 hint 进行调优 + +- 一些算子和函数不支持下推到存储层,导致出现巨大的中间结果集累积。此时可能需要改写业务 SQL,或使用 hint 进行调优,来使用可下推的函数或算子。 + +- 执行计划中存在算子 HashAgg。HashAgg 是多线程并发执行,虽然执行速度较快,但会消耗较多内存。可以尝试使用 `STREAM_AGG()` 替代。 + +- 调小同时读取的 Region 的数量,或降低算子并发度,以避免因高并发导致的内存问题。对应的系统变量包括: + - [`tidb_distsql_scan_concurrency`](/system-variables.md#tidb_distsql_scan_concurrency) + - [`tidb_index_serial_scan_concurrency`](/system-variables.md#tidb_index_serial_scan_concurrency) + - [`tidb_executor_concurrency`](/system-variables.md#tidb_executor_concurrency-从-v50-版本开始引入) + +- 问题发生时间附近,session 的并发度过高,此时可能需要添加节点进行扩容。 + +#### 大事务或大写入消耗太多内存 + +需要提前进行内存的容量规划,这是因为执行事务时 TiDB 进程的内存消耗相对于事务大小会存在一定程度的放大,最大可能达到提交事务大小的 2 到 3 倍以上。 + +针对单个大事务,可以通过拆分的方式调小事务大小。 + +#### 收集和加载统计信息的过程中消耗太多内存 + +TiDB 节点启动后需要加载统计信息到内存中。统计信息的收集过程会消耗内存,可以通过以下方式控制内存使用量: + +- 使用指定采样率、指定只收集特定列的统计信息、减少 `ANALYZE` 并发度等手段减少内存使用。 +- TiDB v6.1.0 开始引入了系统变量 [`tidb_stats_cache_mem_quota`](/system-variables.md#tidb_stats_cache_mem_quota-从-v610-版本开始引入),可以对统计信息的内存使用进行限制。 +- TiDB v6.1.0 开始引入了系统变量 [`tidb_mem_quota_analyze`](/system-variables.md#tidb_mem_quota_analyze-从-v610-版本开始引入),用于控制 TiDB 更新统计信息时的最大总内存占用。 + +更多信息请参见[统计信息简介](/statistics.md)。 + +#### 预处理语句 (Prepared Statement) 使用过量 + +客户端不断创建预处理语句但未执行 [`deallocate prepare stmt`](/sql-prepared-plan-cache.md#忽略-com_stmt_close-指令和-deallocate-prepare-语句) 会导致内存持续上涨,最终触发 TiDB OOM。原因是预处理语句占用的内存要在 session 关闭后才会释放。这一点在长连接下尤需注意。 + +要解决该问题,可以考虑采取以下措施: + +- 调整 session 的生命周期。 +- 调整[连接池的 `wait_timeout` 和 `max_execution_time` 时长](/develop/dev-guide-connection-parameters.md#超时参数)。 +- 使用系统变量 [`max_prepared_stmt_count`](/system-variables.md#max_prepared_stmt_count) 进行限制。 + +#### 系统变量配置不当 + +系统变量 [`tidb_enable_rate_limit_action`](/system-variables.md#tidb_enable_rate_limit_action) 在单条查询仅涉及读数据的情况下,对内存控制效果较好。若还存在额外的计算操作(如连接、聚合等),启动该变量可能会导致内存不受 [`tidb_mem_quota_query`](/system-variables.md#tidb_mem_quota_query) 控制,加剧 OOM 风险。 + +建议关闭该变量。从 TiDB v6.3.0 开始,该变量默认关闭。 + +### 客户端问题 + +若客户端发生 OOM,则需要排查以下方面: + +- 观察 **Grafana TiDB Details** > **Server** > **Client Data Traffic** 的趋势和速度,查看是否存在网络阻塞。 +- 检查是否存在错误的 JDBC 配置参数导致的应用 OOM。例如流式读取的相关参数 `defaultFetchSize` 配置有误,会造成数据在客户端大量缓存。 + +## 处理 OOM 问题需要收集的诊断信息 + +为定位 OOM 故障,通常需要收集以下信息: + +- 操作系统的内存相关配置: + - TiUP 上的配置:`resource_control.memory_limit` + - 操作系统的配置: + - 内存信息:`cat /proc/meminfo` + - 相关内核参数:`vm.overcommit_memory` + - NUMA 相关信息: + - `numactl --hardware` + - `numactl --show` + +- 数据库的版本和内存相关配置: + - TiDB 版本 + - `tidb_mem_quota_query` + - `memory-usage-alarm-ratio` + - `mem-quota-query` + - `oom-action` + - `tidb_enable_rate_limit_action` + - `tidb_server_memory_limit` + - `oom-use-tmp-storage` + - `tmp-storage-path` + - `tmp-storage-quota` + - `tidb_analyze_version` + +- 在 Grafana 查看 TiDB 内存的日常使用情况:**TiDB** > **Server** > **Memory Usage** + +- 查看内存消耗较多的 SQL 语句: + + - 可以从 TiDB Dashboard 中查看 SQL 语句分析、慢查询,查看内存使用量 + - 查看 `INFORMATION_SCHEMA` 中的 `SLOW_QUERY` 和 `CLUSTER_SLOW_QUERY` + - 各个 TiDB 节点的 `tidb_slow_query.log` + - 执行 `grep "expensive_query" tidb.log` 查看对应的日志条目 + - 执行 `EXPLAIN ANALYZE` 查看算子的内存消耗 + - 执行 `SELECT * FROM information_schema.processlist;` 查看 SQL 对应的 `MEM` 列的值 + +- 执行以下命令收集内存使用率高的时候 TiDB 的 Profile 信息: + + ```shell + curl -G http://{TiDBIP}:10080/debug/zip?seconds=10" > profile.zip + ``` + +- 执行 `grep "tidb-server has the risk of OOM" tidb.log` 查看 TiDB Server 收集的告警文件路径,例如: + + ```shell + ["tidb-server has the risk of OOM because of memory usage exceeds alarm ratio. Running SQLs and heap profile will be recorded in record path"] ["is tidb_server_memory_limit set"=false] ["system memory total"=14388137984] ["system memory usage"=11897434112] ["tidb-server memory usage"=11223572312] [memory-usage-alarm-ratio=0.8] ["record path"="/tmp/0_tidb/MC4wLjAuMDo0MDAwLzAuMC4wLjA6MTAwODA=/tmp-storage/record"] + ``` + +## 探索更多 + +- [TiDB 内存调优](/configure-memory-usage.md) +- [TiKV 内存调优](/tune-tikv-memory-performance.md) diff --git a/markdown-pages/zh/tidb/master/tune-tikv-memory-performance.md b/markdown-pages/zh/tidb/master/tune-tikv-memory-performance.md new file mode 100644 index 0000000..3c7d204 --- /dev/null +++ b/markdown-pages/zh/tidb/master/tune-tikv-memory-performance.md @@ -0,0 +1,248 @@ +--- +title: TiKV 内存参数性能调优 +aliases: ['/docs-cn/dev/tune-tikv-memory-performance/','/docs-cn/dev/reference/performance/tune-tikv/', '/docs-cn/dev/tune-tikv-performance/'] +summary: TiKV 内存参数性能调优,根据机器配置情况调整参数以达到最佳性能。TiKV 使用 RocksDB 作为持久化存储,配置项包括 block-cache 大小和 write-buffer 大小。除此之外,系统内存还会被用于 page cache 和处理大查询时的数据结构生成。推荐将 TiKV 部署在 CPU 核数不低于 8 或内存不低于 32GB 的机器上,对写入吞吐要求高时使用吞吐能力较好的磁盘,对读写延迟要求高时使用 IOPS 较高的 SSD 盘。 +--- + +# TiKV 内存参数性能调优 + +本文档用于描述如何根据机器配置情况来调整 TiKV 的参数,使 TiKV 的性能达到最优。你可以在 [etc/config-template.toml](https://github.com/tikv/tikv/blob/master/etc/config-template.toml) 找到配置文件模版,参考[使用 TiUP 修改配置参数](/maintain-tidb-using-tiup.md#修改配置参数)进行操作,部分配置项可以通过[在线修改 TiKV 配置](/dynamic-config.md#在线修改-tikv-配置)方式在线更新。具体配置项的含义可参考 [TiKV 配置文件描述](/tikv-configuration-file.md)。 + +TiKV 最底层使用的是 RocksDB 做为持久化存储,所以 TiKV 的很多性能相关的参数都是与 RocksDB 相关的。TiKV 使用了两个 RocksDB 实例,默认 RocksDB 实例存储 KV 数据,Raft RocksDB 实例(简称 RaftDB)存储 Raft 数据。 + +TiKV 使用了 RocksDB 的 `Column Families` (CF) 特性。 + +- 默认 RocksDB 实例将 KV 数据存储在内部的 `default`、`write` 和 `lock` 3 个 CF 内。 + + - `default` CF 存储的是真正的数据,与其对应的参数位于 `[rocksdb.defaultcf]` 项中; + - `write` CF 存储的是数据的版本信息 (MVCC) 以及索引相关的数据,相关的参数位于 `[rocksdb.writecf]` 项中; + - `lock` CF 存储的是锁信息,系统使用默认参数。 + +- Raft RocksDB 实例存储 Raft log。 + + - `default` CF 主要存储的是 Raft log,与其对应的参数位于 `[raftdb.defaultcf]` 项中。 + +所有的 CF 默认共同使用一个 block cache 实例。通过在 `[storage.block-cache]` 下设置 `capacity` 参数,你可以配置该 block cache 的大小。block cache 越大,能够缓存的热点数据越多,读取数据越容易,同时占用的系统内存也越多。 + +> **注意:** +> +> 在 TiKV 3.0 之前的版本中,不支持使用 `shared block cache`,需要为每个 CF 单独配置 block cache。 + +每个 CF 有各自的 `write-buffer`,大小通过 `write-buffer-size` 控制。 + +## 参数说明 + +```toml +# 日志级别,可选值为:trace,debug,warn,error,info,off +log-level = "info" + +[server] +# 监听地址 +# addr = "127.0.0.1:20160" + +# gRPC 线程池大小 +# grpc-concurrency = 4 +# TiKV 每个实例之间的 gRPC 连接数 +# grpc-raft-conn-num = 10 + +# TiDB 过来的大部分读请求都会发送到 TiKV 的 Coprocessor 进行处理,该参数用于设置 +# coprocessor 线程的个数,如果业务是读请求比较多,增加 coprocessor 的线程数,但应比系统的 +# CPU 核数小。例如:TiKV 所在的机器有 32 core,在重读的场景下甚至可以将该参数设置为 30。在没有 +# 设置该参数的情况下,TiKV 会自动将该值设置为 CPU 总核数乘以 0.8。 +# end-point-concurrency = 8 + +# 可以给 TiKV 实例打标签,用于副本的调度 +# labels = {zone = "cn-east-1", host = "118", disk = "ssd"} + +[storage] +# 数据目录 +# data-dir = "/tmp/tikv/store" + +# 通常情况下使用默认值就可以了。在导数据的情况下建议将该参数设置为 1024000。 +# scheduler-concurrency = 102400 +# 该参数控制写入线程的个数,当写入操作比较频繁的时候,需要把该参数调大。使用 top -H -p tikv-pid +# 发现名称为 sched-worker-pool 的线程都特别忙,这个时候就需要将 scheduler-worker-pool-size +# 参数调大,增加写线程的个数。 +# scheduler-worker-pool-size = 4 + +[storage.block-cache] +## 是否为 RocksDB 的所有 CF 都创建一个 `shared block cache`。 +## +## RocksDB 使用 block cache 来缓存未压缩的数据块。较大的 block cache 可以加快读取速度。 +## 推荐开启 `shared block cache` 参数。这样只需要设置全部缓存大小,使配置过程更加方便。 +## 在大多数情况下,可以通过 LRU 算法在各 CF 间自动平衡缓存用量。 +## +## `storage.block-cache` 会话中的其余配置仅在开启 `shared block cache` 时起作用。 +## 从 v6.6.0 开始,该选项永远开启且无法关闭。 +# shared = true +## `shared block cache` 的大小。正常情况下应设置为系统全部内存的 30%-50%。 +## 如果未设置该参数,则由以下字段或其默认值的总和决定。 +## +## * rocksdb.defaultcf.block-cache-size 或系统全部内存的 25% +## * rocksdb.writecf.block-cache-size 或系统全部内存的 15% +## * rocksdb.lockcf.block-cache-size 或系统全部内存的 2% +## * raftdb.defaultcf.block-cache-size 或系统全部内存的 2% +## +## 要在单个物理机上部署多个 TiKV 节点,需要显式配置该参数。 +## 否则,TiKV 中可能会出现 OOM 错误。 +# capacity = "1GB" + +[pd] +# pd 的地址 +# endpoints = ["127.0.0.1:2379","127.0.0.2:2379","127.0.0.3:2379"] + +[metric] +# 将 metrics 推送给 Prometheus pushgateway 的时间间隔 +interval = "15s" +# Prometheus pushgateway 的地址 +address = "" +job = "tikv" + +[raftstore] +# Raft RocksDB 目录。默认值是 [storage.data-dir] 的 raft 子目录。 +# 如果机器上有多块磁盘,可以将 Raft RocksDB 的数据放在不同的盘上,提高 TiKV 的性能。 +# raftdb-path = "/tmp/tikv/store/raft" + +# 当 Region 写入的数据量超过该阈值的时候,TiKV 会检查该 Region 是否需要分裂。为了减少检查过程 +# 中扫描数据的成本,导入数据过程中可以将该值设置为 32 MB,正常运行状态下使用默认值即可。 +region-split-check-diff = "32MB" + +[coprocessor] + +## 当区间为 [a,e) 的 Region 的大小超过 `region_max_size`,TiKV 会尝试分裂该 Region,例如分裂成 [a,b)、[b,c)、[c,d)、[d,e) 等区间的 Region 后 +## 这些 Region [a,b), [b,c), [c,d) 的大小为 `region_split_size` (或者稍大于 `region_split_size`) +# region-max-size = "144MB" +# region-split-size = "96MB" + +[rocksdb] +# RocksDB 进行后台任务的最大线程数,后台任务包括 compaction 和 flush。具体 RocksDB 为什么需要进行 compaction, +# 请参考 RocksDB 的相关资料。在写流量比较大的时候(例如导数据),建议开启更多的线程, +# 但应小于 CPU 的核数。例如在导数据的时候,32 核 CPU 的机器,可以设置成 28。 +# max-background-jobs = 8 + +# RocksDB 能够打开的最大文件句柄数。 +# max-open-files = 40960 + +# RocksDB MANIFEST 文件的大小限制.# 更详细的信息请参考:https://github.com/facebook/rocksdb/wiki/MANIFEST +max-manifest-file-size = "20MB" + +# RocksDB write-ahead logs 目录。如果机器上有两块盘,可以将 RocksDB 的数据和 WAL 日志放在 +# 不同的盘上,提高 TiKV 的性能。 +# wal-dir = "/tmp/tikv/store" + +# 下面两个参数用于怎样处理 RocksDB 归档 WAL。 +# 更多详细信息请参考:https://github.com/facebook/rocksdb/wiki/How-to-persist-in-memory-RocksDB-database%3F +# wal-ttl-seconds = 0 +# wal-size-limit = 0 + +# RocksDB WAL 日志的最大总大小,通常情况下使用默认值就可以了。 +# max-total-wal-size = "4GB" + +# 开启 RocksDB compaction 过程中的预读功能,如果使用的是机械磁盘,建议该值至少为2MB。 +# compaction-readahead-size = "2MB" + +[rocksdb.defaultcf] +# 数据块大小。RocksDB 是按照 block 为单元对数据进行压缩的,同时 block 也是缓存在 block-cache +# 中的最小单元(类似其他数据库的 page 概念)。 +block-size = "64KB" + +# RocksDB 每一层数据的压缩方式,可选的值为:no,snappy,zlib,bzip2,lz4,lz4hc,zstd。注意 Snappy 压缩文件必须遵循[官方 Snappy 格式](https://github.com/google/snappy)。不支持其他非官方压缩格式。 +# no:no:lz4:lz4:lz4:zstd:zstd 表示 level0 和 level1 不压缩,level2 到 level4 采用 lz4 压缩算法, +# level5 和 level6 采用 zstd 压缩算法,。 +# no 表示没有压缩,lz4 是速度和压缩比较为中庸的压缩算法,zlib 的压缩比很高,对存储空间比较友 +# 好,但是压缩速度比较慢,压缩的时候需要占用较多的 CPU 资源。不同的机器需要根据 CPU 以及 I/O 资 +# 源情况来配置怎样的压缩方式。例如:如果采用的压缩方式为"no:no:lz4:lz4:lz4:zstd:zstd",在大量 +# 写入数据的情况下(导数据),发现系统的 I/O 压力很大(使用 iostat 发现 %util 持续 100% 或者使 +# 用 top 命令发现 iowait 特别多),而 CPU 的资源还比较充裕,这个时候可以考虑将 level0 和 +# level1 开启压缩,用 CPU 资源换取 I/O 资源。如果采用的压缩方式 +# 为"no:no:lz4:lz4:lz4:zstd:zstd",在大量写入数据的情况下,发现系统的 I/O 压力不大,但是 CPU +# 资源已经吃光了,top -H 发现有大量的 bg 开头的线程(RocksDB 的 compaction 线程)在运行,这 +# 个时候可以考虑用 I/O 资源换取 CPU 资源,将压缩方式改成"no:no:no:lz4:lz4:zstd:zstd"。总之,目 +# 的是为了最大限度地利用系统的现有资源,使 TiKV 的性能在现有的资源情况下充分发挥。 +compression-per-level = ["no", "no", "lz4", "lz4", "lz4", "zstd", "zstd"] + +# RocksDB memtable 的大小。 +write-buffer-size = "128MB" + +# 最多允许几个 memtable 存在。写入到 RocksDB 的数据首先会记录到 WAL 日志里面,然后会插入到 +# memtable 里面,当 memtable 的大小到达了 write-buffer-size 限定的大小的时候,当前的 +# memtable 会变成只读的,然后生成一个新的 memtable 接收新的写入。只读的 memtable 会被 +# RocksDB 的 flush 线程(max-background-flushes 参数能够控制 flush 线程的最大个数) +# flush 到磁盘,成为 level0 的一个 sst 文件。当 flush 线程忙不过来,导致等待 flush 到磁盘的 +# memtable 的数量到达 max-write-buffer-number 限定的个数的时候,RocksDB 会将新的写入 +# stall 住,stall 是 RocksDB 的一种流控机制。在导数据的时候可以将 max-write-buffer-number +# 的值设置的更大一点,例如 10。 +max-write-buffer-number = 5 + +# 当 level0 的 sst 文件个数到达 level0-slowdown-writes-trigger 指定的限度的时候, +# RocksDB 会尝试减慢写入的速度。因为 level0 的 sst 太多会导致 RocksDB 的读放大上升。 +# level0-slowdown-writes-trigger 和 level0-stop-writes-trigger 是 RocksDB 进行流控的 +# 另一个表现。当 level0 的 sst 的文件个数到达 4(默认值),level0 的 sst 文件会和 level1 中 +# 有 overlap 的 sst 文件进行 compaction,缓解读放大的问题。 +level0-slowdown-writes-trigger = 20 + +# 当 level0 的 sst 文件个数到达 level0-stop-writes-trigger 指定的限度的时候,RocksDB 会 +# stall 住新的写入。 +level0-stop-writes-trigger = 36 + +# 当 level1 的数据量大小达到 max-bytes-for-level-base 限定的值的时候,会触发 level1 的 +# sst 和 level2 种有 overlap 的 sst 进行 compaction。 +# 黄金定律:max-bytes-for-level-base 的设置的第一参考原则就是保证和 level0 的数据量大致相 +# 等,这样能够减少不必要的 compaction。例如压缩方式为"no:no:lz4:lz4:lz4:lz4:lz4",那么 +# max-bytes-for-level-base 的值应该是 write-buffer-size 的大小乘以 4,因为 level0 和 +# level1 都没有压缩,而且 level0 触发 compaction 的条件是 sst 的个数到达 4(默认值)。在 +# level0 和 level1 都采取了压缩的情况下,就需要分析下 RocksDB 的日志,看一个 memtable 的压 +# 缩成一个 sst 文件的大小大概是多少,例如 32MB,那么 max-bytes-for-level-base 的建议值就应 +# 该是 32MB * 4 = 128MB。 +max-bytes-for-level-base = "512MB" + +# sst 文件的大小。level0 的 sst 文件的大小受 write-buffer-size 和 level0 采用的压缩算法的 +# 影响,target-file-size-base 参数用于控制 level1-level6 单个 sst 文件的大小。 +target-file-size-base = "32MB" + +[rocksdb.writecf] +# 保持和 rocksdb.defaultcf.compression-per-level 一致。 +compression-per-level = ["no", "no", "lz4", "lz4", "lz4", "zstd", "zstd"] + +# 保持和 rocksdb.defaultcf.write-buffer-size 一致。 +write-buffer-size = "128MB" +max-write-buffer-number = 5 +min-write-buffer-number-to-merge = 1 + +# 保持和 rocksdb.defaultcf.max-bytes-for-level-base 一致。 +max-bytes-for-level-base = "512MB" +target-file-size-base = "32MB" + +[raftdb] +# RaftDB 能够打开的最大文件句柄数。 +# max-open-files = 40960 + +# 开启 RaftDB compaction 过程中的预读功能,如果使用的是机械磁盘,建议该值至少为2MB。 +# compaction-readahead-size = "2MB" + +[raftdb.defaultcf] +# 保持和 rocksdb.defaultcf.compression-per-level 一致。 +compression-per-level = ["no", "no", "lz4", "lz4", "lz4", "zstd", "zstd"] + +# 保持和 rocksdb.defaultcf.write-buffer-size 一致。 +write-buffer-size = "128MB" +max-write-buffer-number = 5 +min-write-buffer-number-to-merge = 1 + +# 保持和 rocksdb.defaultcf.max-bytes-for-level-base 一致。 +max-bytes-for-level-base = "512MB" +target-file-size-base = "32MB" +``` + +## TiKV 内存使用情况 + +除了以上列出的 `block-cache` 以及 `write-buffer` 会占用系统内存外: + +1. 需预留一些内存作为系统的 page cache +2. TiKV 在处理大的查询的时候(例如 `select * from ...`)会读取数据然后在内存中生成对应的数据结构返回给 TiDB,这个过程中 TiKV 会占用一部分内存 + +## TiKV 机器配置推荐 + +1. 生产环境中,不建议将 TiKV 部署在 CPU 核数小于 8 或内存低于 32GB 的机器上 +2. 如果对写入吞吐要求比较高,建议使用吞吐能力比较好的磁盘 +3. 如果对读写的延迟要求非常高,建议使用 IOPS 比较高的 SSD 盘 diff --git a/markdown-pages/zh/tidb/master/upgrade-tidb-using-tiup.md b/markdown-pages/zh/tidb/master/upgrade-tidb-using-tiup.md new file mode 100644 index 0000000..a062f50 --- /dev/null +++ b/markdown-pages/zh/tidb/master/upgrade-tidb-using-tiup.md @@ -0,0 +1,322 @@ +--- +title: 使用 TiUP 升级 TiDB +aliases: ['/docs-cn/dev/upgrade-tidb-using-tiup/','/docs-cn/dev/how-to/upgrade/using-tiup/','/docs-cn/dev/upgrade-tidb-using-tiup-offline/', '/zh/tidb/dev/upgrade-tidb-using-tiup-offline'] +summary: TiUP 可用于将 TiDB 4.0 版本及更高版本升级至 TiDB 8.0。升级过程中需注意不支持 TiFlash 组件从 5.3 之前的老版本在线升级至 5.3 及之后的版本,只能采用停机升级。在升级过程中,不要执行 DDL 语句,避免出现行为未定义的问题。升级前需查看集群中是否有正在进行的 DDL Job,并等待其完成或取消后再进行升级。升级完成后,可使用 TiUP 安装对应版本的 `ctl` 组件来更新相关工具版本。 +--- + +# 使用 TiUP 升级 TiDB + +本文档适用于以下升级路径: + +- 使用 TiUP 从 TiDB 4.0 版本升级至 TiDB 8.0。 +- 使用 TiUP 从 TiDB 5.0-5.4 版本升级至 TiDB 8.0。 +- 使用 TiUP 从 TiDB 6.0-6.6 版本升级至 TiDB 8.0。 +- 使用 TiUP 从 TiDB 7.0-7.6 版本升级至 TiDB 8.0。 + +> **警告:** +> +> 1. 不支持将 TiFlash 组件从 5.3 之前的老版本在线升级至 5.3 及之后的版本,只能采用停机升级。如果集群中其他组件(如 tidb,tikv)不能停机升级,参考[不停机升级](#不停机升级)中的注意事项。 +> 2. 在升级 TiDB 集群的过程中,**请勿执行** DDL 语句,否则可能会出现行为未定义的问题。 +> 3. 集群中有 DDL 语句正在被执行时(通常为 `ADD INDEX` 和列类型变更等耗时较久的 DDL 语句),**请勿进行**升级操作。在升级前,建议使用 [`ADMIN SHOW DDL`](/sql-statements/sql-statement-admin-show-ddl.md) 命令查看集群中是否有正在进行的 DDL Job。如需升级,请等待 DDL 执行完成或使用 [`ADMIN CANCEL DDL`](/sql-statements/sql-statement-admin-cancel-ddl.md) 命令取消该 DDL Job 后再进行升级。 +> +> 从 TiDB v7.1 版本升级至更高的版本时,可以不遵循上面的限制 2 和 3,建议参考[平滑升级 TiDB 的限制](/smooth-upgrade-tidb.md#使用限制)。 + +> **注意:** +> +> - 如果原集群是 3.0 或 3.1 或更早的版本,不支持直接升级到 v8.0.0 及后续修订版本。你需要先从早期版本升级到 4.0 后,再从 4.0 升级到 v8.0.0 及后续修订版本。 +> - 如果原集群是 6.2 之前的版本,升级到 6.2 及以上版本时,部分场景会遇到升级卡住的情况,你可以参考[如何解决升级卡住的问题](#42-升级到-v620-及以上版本时如何解决升级卡住的问题)。 +> - 配置参数 [`server-version`](/tidb-configuration-file.md#server-version) 的值会被 TiDB 节点用于验证当前 TiDB 的版本。因此在进行 TiDB 集群升级前,请将 `server-version` 的值设置为空或者当前 TiDB 真实的版本值,避免出现非预期行为。 +> - 配置项 [`performance.force-init-stats`](/tidb-configuration-file.md#force-init-stats-从-v657-和-v710-版本开始引入) 设置为 `ON` 会延长 TiDB 的启动时间,这可能会造成启动超时,升级失败。为避免这种情况,建议为 TiUP 设置更长的等待超时。 +> - 可能受影响的场景: +> - 原集群版本低于 v6.5.7、v7.1.0(尚未支持 `performance.force-init-stats`),目标版本为 v7.2.0 及更高。 +> - 原集群版本高于或等于 v6.5.7、v7.1.0,且配置项 `performance.force-init-stats` 被设置为 `ON`。 +> - 查看配置项 `performance.force-init-stats` 的值: +> +> ``` +> SHOW CONFIG WHERE type = 'tidb' AND name = 'performance.force-init-stats'; +> ``` +> +> - 通过增加命令行选项 [`--wait-timeout`](/tiup/tiup-component-cluster.md#--wait-timeoutuint默认-120) 可以延长 TiUP 超时等待。如下命令可将超时等待设置为 1200 秒(即 20 分钟)。 +> +> ```shell +> tiup update cluster --wait-timeout 1200 [other options] +> ``` +> +> 通常情况下,20 分钟超时等待能满足绝大部分场景的需求。如果需要更准确的预估,可以在 TiDB 日志中搜索 `init stats info time` 关键字,获取上次启动的统计信息加载时间作为参考。例如: +> +> ``` +> [domain.go:2271] ["init stats info time"] [lite=true] ["take time"=2.151333ms] +> ``` +> +> 如果原集群是 v7.1.0 或更早的版本,升级到 v7.2.0 或以上版本时,由于 [`performance.lite-init-stats`](/tidb-configuration-file.md#lite-init-stats-从-v710-版本开始引入) 的引入,统计信息加载时间会大幅减少。这个情况下,升级前的 `init stats info time` 会比升级后加载所需的时间偏长。 +> - 如果想要缩短 TiDB 滚动升级的时间,并且在升级过程中能够承受初始统计信息缺失带来的潜在性能影响,可以在升级前[用 TiUP 修改目标实例的配置](/maintain-tidb-using-tiup.md#修改配置参数),将 `performance.force-init-stats` 设置为 `OFF`。升级完成后可酌情改回。 + +## 1. 升级兼容性说明 + +- TiDB 目前暂不支持版本降级或升级后回退。 +- 使用 TiDB Ansible 管理的 4.0 版本集群,需要先按照 [4.0 版本文档的说明](https://docs.pingcap.com/zh/tidb/v4.0/upgrade-tidb-using-tiup)将集群导入到 TiUP (`tiup cluster`) 管理后,再按本文档说明升级到 v8.0.0 版本。 +- 若要将 v3.0 之前的版本升级至 v8.0.0 版本: + 1. 首先[通过 TiDB Ansible 升级到 3.0 版本](https://docs.pingcap.com/zh/tidb/v3.0/upgrade-tidb-using-ansible)。 + 2. 然后按照 [4.0 版本文档的说明](https://docs.pingcap.com/zh/tidb/v4.0/upgrade-tidb-using-tiup),使用 TiUP (`tiup cluster`) 将 TiDB Ansible 配置导入。 + 3. 将集群升级至 v4.0 版本。 + 4. 按本文档说明将集群升级到 v8.0.0 版本。 +- 支持 TiDB Binlog,TiCDC,TiFlash 等组件版本的升级。 +- 将 v6.3.0 之前的 TiFlash 升级至 v6.3.0 及之后的版本时,需要特别注意:在 Linux AMD64 架构的硬件平台部署 TiFlash 时,CPU 必须支持 AVX2 指令集。而在 Linux ARM64 架构的硬件平台部署 TiFlash 时,CPU 必须支持 ARMv8 架构。具体请参考 [6.3.0 版本 Release Notes](/releases/release-6.3.0.md#其他) 中的描述。 +- 具体不同版本的兼容性说明,请查看各个版本的 [Release Note](/releases/release-notes.md)。请根据各个版本的 Release Note 的兼容性更改调整集群的配置。 +- 升级 v5.3 之前版本的集群到 v5.3 及后续版本时,默认部署的 Prometheus 会从 v2.8.1 升级到 v2.27.1,v2.27.1 提供更多的功能并解决了安全风险。Prometheus v2.27.1 相对于 v2.8.1 存在 Alert 时间格式变化,详情见 [Prometheus commit](https://github.com/prometheus/prometheus/commit/7646cbca328278585be15fa615e22f2a50b47d06)。 + +## 2. 升级前准备 + +本部分介绍实际开始升级前需要进行的更新 TiUP 和 TiUP Cluster 组件版本等准备工作。 + +### 2.1 查阅兼容性变更 + +查阅 TiDB v8.0.0 release notes 中的[兼容性变更](/releases/release-8.0.0.md#兼容性变更)。如果有任何变更影响到了你的升级,请采取相应的措施。 + +### 2.2 升级 TiUP 或更新 TiUP 离线镜像 + +#### 升级 TiUP 和 TiUP Cluster + +> **注意:** +> +> 如果原集群中控机不能访问 `https://tiup-mirrors.pingcap.com` 地址,可跳过本步骤,然后[更新 TiUP 离线镜像](#更新-tiup-离线镜像)。 + +1. 先升级 TiUP 版本(建议 `tiup` 版本不低于 `1.11.3`): + + ```shell + tiup update --self + tiup --version + ``` + +2. 再升级 TiUP Cluster 版本(建议 `tiup cluster` 版本不低于 `1.11.3`): + + ```shell + tiup update cluster + tiup cluster --version + ``` + +#### 更新 TiUP 离线镜像 + +> **注意:** +> +> 如果原集群不是通过离线部署方式部署的,可忽略此步骤。 + +可以参考[使用 TiUP 部署 TiDB 集群](/production-deployment-using-tiup.md)的步骤下载部署新版本的 TiUP 离线镜像,上传到中控机。在执行 `local_install.sh` 后,TiUP 会完成覆盖升级。 + +```shell +tar xzvf tidb-community-server-${version}-linux-amd64.tar.gz +sh tidb-community-server-${version}-linux-amd64/local_install.sh +source /home/tidb/.bash_profile +``` + +> **建议:** +> +> 关于 `TiDB-community-server` 软件包和 `TiDB-community-toolkit` 软件包的内容物,请查阅 [TiDB 离线包](/binary-package.md)。 + +覆盖升级完成后,需将 server 和 toolkit 两个离线镜像合并,执行以下命令合并离线组件到 server 目录下。 + +```bash +tar xf tidb-community-toolkit-${version}-linux-amd64.tar.gz +ls -ld tidb-community-server-${version}-linux-amd64 tidb-community-toolkit-${version}-linux-amd64 +cd tidb-community-server-${version}-linux-amd64/ +cp -rp keys ~/.tiup/ +tiup mirror merge ../tidb-community-toolkit-${version}-linux-amd64 +``` + +离线镜像合并后,执行下列命令升级 Cluster 组件: + +```shell +tiup update cluster +``` + +此时离线镜像已经更新成功。如果覆盖后发现 TiUP 运行报错,可能是 manifest 未更新导致,可尝试 `rm -rf ~/.tiup/manifests/*` 后再使用。 + +### 2.3 编辑 TiUP Cluster 拓扑配置文件 + +> **注意:** +> +> 以下情况可跳过此步骤: +> +> - 原集群没有修改过配置参数,或通过 tiup cluster 修改过参数但不需要调整。 +> - 升级后对未修改过的配置项希望使用 `8.0.0` 默认参数。 + +1. 进入拓扑文件的 `vi` 编辑模式: + + ```shell + tiup cluster edit-config + ``` + +2. 参考 [topology](https://github.com/pingcap/tiup/blob/master/embed/examples/cluster/topology.example.yaml) 配置模板的格式,将希望修改的参数填到拓扑文件的 `server_configs` 下面。 + +修改完成后 `:wq` 保存并退出编辑模式,输入 `Y` 确认变更。 + +> **注意:** +> +> 升级到 v8.0.0 版本前,请确认已在 4.0 修改的参数在 v8.0.0 版本中是兼容的,可参考 [TiKV 配置文件描述](/tikv-configuration-file.md)。 + +### 2.4 检查当前集群的 DDL 和 Backup 情况 + +为避免升级过程中出现未定义行为或其他故障,建议检查以下指标后再进行升级操作。 + +- 集群 DDL 情况:建议使用 [`ADMIN SHOW DDL`](/sql-statements/sql-statement-admin-show-ddl.md) 命令查看集群中是否有正在进行的 DDL Job。如需升级,请等待 DDL 执行完成或使用 [`ADMIN CANCEL DDL`](/sql-statements/sql-statement-admin-cancel-ddl.md) 命令取消该 DDL Job 后再进行升级。 +- 集群 Backup 情况:建议使用 [`SHOW [BACKUPS|RESTORES]`](/sql-statements/sql-statement-show-backups.md) 命令查看集群中是否有正在进行的 Backup 或者 Restore 任务。如需升级,请等待 Backup 执行完成后,得到一个有效的备份后再执行升级。 + +### 2.5 检查当前集群的健康状况 + +为避免升级过程中出现未定义行为或其他故障,建议在升级前对集群当前的 region 健康状态进行检查,此操作可通过 `check` 子命令完成。 + +```shell +tiup cluster check --cluster +``` + +执行结束后,最后会输出 region status 检查结果。如果结果为 "All regions are healthy",则说明当前集群中所有 region 均为健康状态,可以继续执行升级;如果结果为 "Regions are not fully healthy: m miss-peer, n pending-peer" 并提示 "Please fix unhealthy regions before other operations.",则说明当前集群中有 region 处在异常状态,应先排除相应异常状态,并再次检查结果为 "All regions are healthy" 后再继续升级。 + +## 3. 升级 TiDB 集群 + +本部分介绍如何滚动升级 TiDB 集群以及如何进行升级后的验证。 + +### 3.1 将集群升级到指定版本 + +升级的方式有两种:不停机升级和停机升级。TiUP Cluster 默认的升级 TiDB 集群的方式是不停机升级,即升级过程中集群仍然可以对外提供服务。升级时会对各节点逐个迁移 leader 后再升级和重启,因此对于大规模集群需要较长时间才能完成整个升级操作。如果业务有维护窗口可供数据库停机维护,则可以使用停机升级的方式快速进行升级操作。 + +#### 不停机升级 + +```shell +tiup cluster upgrade +``` + +以升级到 v8.0.0 版本为例: + +``` +tiup cluster upgrade v8.0.0 +``` + +> **注意:** +> +> - 滚动升级会逐个升级所有的组件。升级 TiKV 期间,会逐个将 TiKV 上的所有 leader 切走再停止该 TiKV 实例。默认超时时间为 5 分钟(300 秒),超时后会直接停止该实例。 +> - 使用 `--force` 参数可以在不驱逐 leader 的前提下快速升级集群至新版本,但是该方式会忽略所有升级中的错误,在升级失败后得不到有效提示,请谨慎使用。 +> - 如果希望保持性能稳定,则需要保证 TiKV 上的所有 leader 驱逐完成后再停止该 TiKV 实例,可以指定 `--transfer-timeout` 为一个更大的值,如 `--transfer-timeout 3600`,单位为秒。 +> - 若想将 TiFlash 从 5.3 之前的版本升级到 5.3 及之后的版本,必须进行 TiFlash 的停机升级。参考如下步骤,可以在确保其他组件正常运行的情况下升级 TiFlash: +> 1. 关闭 TiFlash 实例:`tiup cluster stop -R tiflash` +> 2. 使用 `--offline` 参数在不重启(只更新文件)的情况下升级集群:`tiup cluster upgrade --offline`,例如 `tiup cluster upgrade v6.3.0 --offline` +> 3. reload 整个集群:`tiup cluster reload `。此时,TiFlash 也会正常启动,无需额外操作。 +> - 在对使用 TiDB Binlog 的集群进行滚动升级过程中,请避免新创建聚簇索引表。 + +#### 升级时指定组件版本 + +从 tiup-cluster v1.14.0 开始,支持在升级集群的时候指定其中某些组件到特定版本。指定的组件在后续升级中保持固定版本,除非重新指定版本。 + +> **注意:** +> +> 对于 TiDB、TiKV、PD、TiCDC 等共用版本号的组件,尚未有完整的测试保证它们在跨版本混合部署的场景下能正常工作。请仅在测试场景或在[获取支持](/support.md)的情况下使用此配置。 + +```shell +tiup cluster upgrade -h | grep "version" + --alertmanager-version string Fix the version of alertmanager and no longer follows the cluster version. + --blackbox-exporter-version string Fix the version of blackbox-exporter and no longer follows the cluster version. + --cdc-version string Fix the version of cdc and no longer follows the cluster version. + --ignore-version-check Ignore checking if target version is bigger than current version. + --node-exporter-version string Fix the version of node-exporter and no longer follows the cluster version. + --pd-version string Fix the version of pd and no longer follows the cluster version. + --tidb-dashboard-version string Fix the version of tidb-dashboard and no longer follows the cluster version. + --tiflash-version string Fix the version of tiflash and no longer follows the cluster version. + --tikv-cdc-version string Fix the version of tikv-cdc and no longer follows the cluster version. + --tikv-version string Fix the version of tikv and no longer follows the cluster version. + --tiproxy-version string Fix the version of tiproxy and no longer follows the cluster version. +``` + +#### 停机升级 + +在停机升级前,首先需要将整个集群关停。 + +```shell +tiup cluster stop +``` + +之后通过 `upgrade` 命令添加 `--offline` 参数来进行停机升级,其中 `` 为集群名,`` 为升级的目标版本,例如 `v8.0.0`。 + +```shell +tiup cluster upgrade --offline +``` + +升级完成后集群不会自动启动,需要使用 `start` 命令来启动集群。 + +```shell +tiup cluster start +``` + +### 3.2 升级后验证 + +执行 `display` 命令来查看最新的集群版本 `TiDB Version`: + +```shell +tiup cluster display +``` + +``` +Cluster type: tidb +Cluster name: +Cluster version: v8.0.0 +``` + +## 4. 升级 FAQ + +本部分介绍使用 TiUP 升级 TiDB 集群遇到的常见问题。 + +### 4.1 升级时报错中断,处理完报错后,如何继续升级 + +重新执行 `tiup cluster upgrade` 命令进行升级,升级操作会重启之前已经升级完成的节点。如果不希望重启已经升级过的节点,可以使用 `replay` 子命令来重试操作,具体方法如下: + +1. 使用 `tiup cluster audit` 命令查看操作记录: + + ```shell + tiup cluster audit + ``` + + 在其中找到失败的升级操作记录,并记下该操作记录的 ID,下一步中将使用 `` 表示操作记录 ID 的值。 + +2. 使用 `tiup cluster replay ` 命令重试对应操作: + + ```shell + tiup cluster replay + ``` + +### 4.2 升级到 v6.2.0 及以上版本时,如何解决升级卡住的问题 + +从 v6.2.0 开始,TiDB 默认开启[并发 DDL 框架](/ddl-introduction.md#tidb-在线-ddl-异步变更的原理)执行并发 DDL。该框架改变了 DDL 作业存储方式,由 KV 队列变为表队列。这一变化可能会导致部分升级场景卡住。下面是一些会触发该问题的场景及解决方案: + +- 加载插件导致的卡住 + + 升级过程中加载部分插件时需要执行 DDL 语句,此时会卡住升级。 + + **解决方案**:升级过程中避免加载插件。待升级完成后再执行插件加载。 + +- 使用 `kill -9` 命令停机升级导致的卡住 + + - 预防措施:避免使用 `kill -9` 命令停机升级。如需使用,应在 2 分钟后再启动新版本 TiDB 节点。 + - 如果升级已经被卡住:重启受影响的 TiDB 节点。如果问题刚发生,建议等待 2 分钟后再重启。 + +- DDL Owner 变更导致的卡住 + + 在多 TiDB 实例场景升级时,网络或机器故障可能引起 DDL Owner 变更。如果此时存在未完成的升级阶段 DDL 语句,升级可能会卡住。 + + **解决方案**: + + 1. 先 Kill 卡住的 TiDB 节点(避免使用 `kill -9`)。 + 2. 重新启动新版本 TiDB 节点。 + +### 4.3 升级过程中 evict leader 等待时间过长,如何跳过该步骤快速升级 + +可以指定 `--force`,升级时会跳过 `PD transfer leader` 和 `TiKV evict leader` 过程,直接重启并升级版本,对线上运行的集群性能影响较大。命令如下,其中 `` 为升级的目标版本,例如 `v8.0.0`: + +```shell +tiup cluster upgrade --force +``` + +### 4.4 升级完成后,如何更新 pd-ctl 等周边工具版本 + +可通过 TiUP 安装对应版本的 `ctl` 组件来更新相关工具版本: + +``` +tiup install ctl:v8.0.0 +``` diff --git a/markdown-pages/zh/tidb/master/user-account-management.md b/markdown-pages/zh/tidb/master/user-account-management.md new file mode 100644 index 0000000..54317e3 --- /dev/null +++ b/markdown-pages/zh/tidb/master/user-account-management.md @@ -0,0 +1,215 @@ +--- +title: TiDB 用户账户管理 +aliases: ['/docs-cn/dev/user-account-management/','/docs-cn/dev/reference/security/user-account-management/'] +summary: TiDB 用户账户管理主要包括用户名和密码设置、添加用户、删除用户、保留用户账户、设置资源限制、设置密码、忘记密码处理和刷新权限。用户可以通过 SQL 语句或图形化界面工具进行用户管理,同时可以使用 `FLUSH PRIVILEGES` 命令立即生效修改。 TiDB 在数据库初始化时会生成一个默认账户。 +--- + +# TiDB 用户账户管理 + +本文档主要介绍如何管理 TiDB 用户账户。 + +要快速了解 TiDB 如何进行认证与赋权并创建与管理用户账户,建议先观看下面的培训视频(时长 22 分钟)。注意本视频只作为学习参考,如需了解具体的用户账户管理方法,请参考本文档的内容。 + + + +## 用户名和密码 + +TiDB 将用户账户存储在 `mysql.user` 系统表里面。每个账户由用户名和 host 作为标识。每个账户可以设置一个密码。每个用户名最长为 32 个字符。 + +通过 MySQL 客户端连接到 TiDB 服务器,通过指定的账户和密码登录: + +``` +mysql --port 4000 --user xxx --password +``` + +使用缩写的命令行参数则是: + +``` +mysql -P 4000 -u xxx -p +``` + +## 添加用户 + +添加用户有两种方式: + +* 通过标准的用户管理的 SQL 语句创建用户以及授予权限,比如 `CREATE USER` 和 `GRANT`。 +* 直接通过 `INSERT`、`UPDATE` 和 `DELETE` 操作授权表。不推荐使用这种方式添加用户,因为容易导致修改不完整。 + +除以上两种方法外,你还可以使用第三方图形化界面工具来添加用户。 + +```sql +CREATE USER [IF NOT EXISTS] user [IDENTIFIED BY 'auth_string']; +``` + +设置登录密码后,`auth_string` 会被 TiDB 经过加密存储在 `mysql.user` 表中。 + +```sql +CREATE USER 'test'@'127.0.0.1' IDENTIFIED BY 'xxx'; +``` + +TiDB 的用户账户名由一个用户名和一个主机名组成。账户名的语法为 `'user_name'@'host_name'`。 + +- `user_name` 大小写敏感。 +- `host_name` 可以是一个主机名或 IP 地址。主机名或 IP 地址中允许使用通配符 `%` 和 `_`。例如,名为 `'%'` 的主机名可以匹配所有主机,`'192.168.1.%'` 可以匹配子网中的所有主机。 + +host 支持模糊匹配,比如: + +```sql +CREATE USER 'test'@'192.168.10.%'; +``` + +允许 `test` 用户从 `192.168.10` 子网的任何一个主机登录。 + +如果没有指定 host,则默认是所有 IP 均可登录。如果没有指定密码,默认为空: + +```sql +CREATE USER 'test'; +``` + +等价于: + +```sql +CREATE USER 'test'@'%' IDENTIFIED BY ''; +``` + +为一个不存在的用户授权时,是否会自动创建用户的行为受 `sql_mode` 影响。如果 `sql_mode` 中包含 `NO_AUTO_CREATE_USER`,则 `GRANT` 不会自动创建用户并报错。 + +假设 `sql_mode` 不包含 `NO_AUTO_CREATE_USER`,下面的例子用 `CREATE USER` 和 `GRANT` 语句创建了四个账户: + +```sql +CREATE USER 'finley'@'localhost' IDENTIFIED BY 'some_pass'; +``` + +```sql +GRANT ALL PRIVILEGES ON *.* TO 'finley'@'localhost' WITH GRANT OPTION; +``` + +```sql +CREATE USER 'finley'@'%' IDENTIFIED BY 'some_pass'; +``` + +```sql +GRANT ALL PRIVILEGES ON *.* TO 'finley'@'%' WITH GRANT OPTION; +``` + +```sql +CREATE USER 'admin'@'localhost' IDENTIFIED BY 'admin_pass'; +``` + +```sql +GRANT RELOAD,PROCESS ON *.* TO 'admin'@'localhost'; +``` + +```sql +CREATE USER 'dummy'@'localhost'; +``` + +使用 `SHOW GRANTS` 可以看到为一个用户授予的权限: + +```sql +SHOW GRANTS FOR 'admin'@'localhost'; +``` + +``` ++-----------------------------------------------------+ +| Grants for admin@localhost | ++-----------------------------------------------------+ +| GRANT RELOAD, PROCESS ON *.* TO 'admin'@'localhost' | ++-----------------------------------------------------+ +``` + +## 删除用户 + +使用 `DROP USER` 语句可以删除用户,例如: + +```sql +DROP USER 'test'@'localhost'; +``` + +这个操作会清除用户在 `mysql.user` 表里面的记录项,并且清除在授权表里面的相关记录。 + +## 保留用户账户 + +TiDB 在数据库初始化时会生成一个 `'root'@'%'` 的默认账户。 + +## 设置资源限制 + +暂不支持。 + +## 设置密码 + +TiDB 将密码存在 `mysql.user` 系统数据库里面。只有拥有 `CREATE USER` 权限,或者拥有 `mysql` 数据库权限(`INSERT` 权限用于创建,`UPDATE` 权限用于更新)的用户才能够设置或修改密码。 + +- 在 `CREATE USER` 创建用户时通过 `IDENTIFIED BY` 指定密码: + + ```sql + CREATE USER 'test'@'localhost' IDENTIFIED BY 'mypass'; + ``` + +- 为一个已存在的账户修改密码,可以通过 `SET PASSWORD FOR` 或者 `ALTER USER` 语句完成: + + ```sql + SET PASSWORD FOR 'root'@'%' = 'xxx'; + ``` + + 或者: + + ```sql + ALTER USER 'test'@'localhost' IDENTIFIED BY 'mypass'; + ``` + +## 忘记 `root` 密码 + +1. 修改 TiDB 配置文件: + + 1. 登录其中一台 tidb-server 实例所在的机器。 + 2. 进入 TiDB 节点的部署目录下的 `conf` 目录,找到 `tidb.toml` 配置文件。 + 3. 在配置文件的 `security` 部分添加配置项 `skip-grant-table`。如无 `security` 部分,则将以下两行内容添加至 tidb.toml 配置文件尾部: + + ``` + [security] + skip-grant-table = true + ``` + +2. 终止该 tidb-server 的进程: + + 1. 查看 tidb-server 的进程: + + ```bash + ps aux | grep tidb-server + ``` + + 2. 找到 tidb-server 对应的进程 ID (PID) 并使用 `kill` 命令停掉该进程: + + ```bash + kill -9 + ``` + +3. 使用修改之后的配置启动 TiDB: + + > **注意:** + > + > 设置 `skip-grant-table` 之后,启动 TiDB 进程会增加操作系统用户检查,只有操作系统的 `root` 用户才能启动 TiDB 进程。 + + 1. 进入 TiDB 节点部署目录下的 `scripts` 目录。 + 2. 切换到操作系统 `root` 账号。 + 3. 在前台执行目录中的 `run_tidb.sh` 脚本。 + 4. 在新的终端窗口中使用 `root` 登录后修改密码: + + ```bash + mysql -h 127.0.0.1 -P 4000 -u root + ``` + +4. 停止运行 `run_tidb.sh` 脚本,并去掉第 1 步中在 TiDB 配置文件中添加的内容,等待 tidb-server 自启动。 + +## `FLUSH PRIVILEGES` + +用户以及权限相关的信息都存储在 TiKV 服务器中,TiDB 在进程内部会缓存这些信息。一般通过 `CREATE USER`,`GRANT` 等语句来修改相关信息时,可在整个集群迅速生效。如果遇到网络或者其它因素影响,由于 TiDB 会周期性地更新缓存信息,正常情况下,最多 15 分钟左右生效。 + +如果授权表已被直接修改,则不会通知 TiDB 节点更新缓存,运行如下命令可使改动立即生效: + +```sql +FLUSH PRIVILEGES; +``` + +详情参见[权限管理](/privilege-management.md)。 diff --git a/markdown-pages/zh/tidb/master/views.md b/markdown-pages/zh/tidb/master/views.md new file mode 100644 index 0000000..a006779 --- /dev/null +++ b/markdown-pages/zh/tidb/master/views.md @@ -0,0 +1,225 @@ +--- +title: 视图 +aliases: ['/docs-cn/dev/views/','/docs-cn/dev/reference/sql/view/'] +summary: TiDB 支持视图,视图是虚拟表,结构由创建时的 SELECT 语句定义。使用视图可保证数据安全,简化复杂查询。查询视图类似查询表,TiDB 执行查询时会展开视图。可通过 SHOW CREATE TABLE 或 SHOW CREATE VIEW 查看视图创建语句及相关信息。也可查询 INFORMATION_SCHEMA.VIEWS 表或访问 HTTP API 获取视图元信息。视图有局限性,不支持物化视图,且为只读视图,不支持写入操作。已创建的视图仅支持 DROP 操作。 +--- + +# 视图 + +TiDB 支持视图,视图是一张虚拟表,该虚拟表的结构由创建视图时的 `SELECT` 语句定义。使用视图一方面可以对用户只暴露安全的字段及数据,进而保证底层表的敏感字段及数据的安全。另一方面,将频繁出现的复杂查询定义为视图,可以使复杂查询更加简单便捷。 + +## 查询视图 + +查询一个视图和查询一张普通表类似。但是 TiDB 在真正执行查询视图时,会将视图展开成创建视图时定义的 `SELECT` 语句,进而执行展开后的查询语句。 + +## 查看视图的相关信息 + +通过以下方式,可以查看 view 相关的信息。 + +### 使用 `SHOW CREATE TABLE view_name` 或 `SHOW CREATE VIEW view_name` 语句 + +示例: + +```sql +show create view v; +``` + +使用该语句可以查看 view 对应的创建语句,及创建 view 时对应的 `character_set_client` 及 `collation_connection` 系统变量值。 + +```sql ++------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+----------------------+ +| View | Create View | character_set_client | collation_connection | ++------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+----------------------+ +| v | CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`127.0.0.1` SQL SECURITY DEFINER VIEW `v` (`a`) AS SELECT `s`.`a` FROM `test`.`t` LEFT JOIN `test`.`s` ON `t`.`a`=`s`.`a` | utf8 | utf8_general_ci | ++------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+----------------------+ +1 row in set (0.00 sec) +``` + +### 查询 `INFORMATION_SCHEMA.VIEWS` 表 + +示例: + +```sql +select * from information_schema.views; +``` + +通过查询该表可以查看 view 的相关元信息,如 `TABLE_CATALOG`、`TABLE_SCHEMA`、`TABLE_NAME`、`VIEW_DEFINITION`、`CHECK_OPTION`、`IS_UPDATABLE`、`DEFINER`、`SECURITY_TYPE`、`CHARACTER_SET_CLIENT`、`COLLATION_CONNECTION` 等。 + +```sql ++---------------+--------------+------------+------------------------------------------------------------------------+--------------+--------------+----------------+---------------+----------------------+----------------------+ +| TABLE_CATALOG | TABLE_SCHEMA | TABLE_NAME | VIEW_DEFINITION | CHECK_OPTION | IS_UPDATABLE | DEFINER | SECURITY_TYPE | CHARACTER_SET_CLIENT | COLLATION_CONNECTION | ++---------------+--------------+------------+------------------------------------------------------------------------+--------------+--------------+----------------+---------------+----------------------+----------------------+ +| def | test | v | SELECT `s`.`a` FROM `test`.`t` LEFT JOIN `test`.`s` ON `t`.`a`=`s`.`a` | CASCADED | NO | root@127.0.0.1 | DEFINER | utf8 | utf8_general_ci | ++---------------+--------------+------------+------------------------------------------------------------------------+--------------+--------------+----------------+---------------+----------------------+----------------------+ +1 row in set (0.00 sec) +``` + +### 查询 HTTP API + +示例: + +``` +curl http://127.0.0.1:10080/schema/test/v +``` + +通过访问 `http://{TiDBIP}:10080/schema/{db}/{view}` 可以得到对应 view 的所有元信息。 + +``` +{ + "id": 122, + "name": { + "O": "v", + "L": "v" + }, + "charset": "utf8", + "collate": "utf8_general_ci", + "cols": [ + { + "id": 1, + "name": { + "O": "a", + "L": "a" + }, + "offset": 0, + "origin_default": null, + "default": null, + "default_bit": null, + "default_is_expr": false, + "generated_expr_string": "", + "generated_stored": false, + "dependences": null, + "type": { + "Tp": 0, + "Flag": 0, + "Flen": 0, + "Decimal": 0, + "Charset": "", + "Collate": "", + "Elems": null + }, + "state": 5, + "comment": "", + "hidden": false, + "version": 0 + } + ], + "index_info": null, + "fk_info": null, + "state": 5, + "pk_is_handle": false, + "is_common_handle": false, + "comment": "", + "auto_inc_id": 0, + "auto_id_cache": 0, + "auto_rand_id": 0, + "max_col_id": 1, + "max_idx_id": 0, + "update_timestamp": 416801600091455490, + "ShardRowIDBits": 0, + "max_shard_row_id_bits": 0, + "auto_random_bits": 0, + "pre_split_regions": 0, + "partition": null, + "compression": "", + "view": { + "view_algorithm": 0, + "view_definer": { + "Username": "root", + "Hostname": "127.0.0.1", + "CurrentUser": false, + "AuthUsername": "root", + "AuthHostname": "%" + }, + "view_security": 0, + "view_select": "SELECT `s`.`a` FROM `test`.`t` LEFT JOIN `test`.`s` ON `t`.`a`=`s`.`a`", + "view_checkoption": 1, + "view_cols": null + }, + "sequence": null, + "Lock": null, + "version": 3, + "tiflash_replica": null +} +``` + +## 示例 + +以下例子将创建一个视图,并在该视图上进行查询,最后删除该视图。 + +```sql +create table t(a int, b int); +``` + +``` +Query OK, 0 rows affected (0.01 sec) +``` + +```sql +insert into t values(1, 1),(2,2),(3,3); +``` + +``` +Query OK, 3 rows affected (0.00 sec) +Records: 3 Duplicates: 0 Warnings: 0 +``` + +```sql +create table s(a int); +``` + +``` +Query OK, 0 rows affected (0.01 sec) +``` + +```sql +insert into s values(2),(3); +``` + +``` +Query OK, 2 rows affected (0.01 sec) +Records: 2 Duplicates: 0 Warnings: 0 +``` + +```sql +create view v as select s.a from t left join s on t.a = s.a; +``` + +``` +Query OK, 0 rows affected (0.01 sec) +``` + +```sql +select * from v; +``` + +``` ++------+ +| a | ++------+ +| NULL | +| 2 | +| 3 | ++------+ +3 rows in set (0.00 sec) +``` + +```sql +drop view v; +``` + +``` +Query OK, 0 rows affected (0.02 sec) +``` + +## 局限性 + +目前 TiDB 中的视图有以下局限性: + +- 不支持物化视图。 +- TiDB 中视图为只读视图,不支持对视图进行 `UPDATE`、`INSERT`、`DELETE`、`TRUNCATE` 等写入操作。 +- 对已创建的视图仅支持 `DROP` 的 DDL 操作,即 `DROP [VIEW | TABLE]`。 + +## 扩展阅读 + +- [创建视图](/sql-statements/sql-statement-create-view.md) +- [删除视图](/sql-statements/sql-statement-drop-view.md)