<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" xmlns:content="http://purl.org/rss/1.0/modules/content/" version="2.0">
  <!-- Source: https://percona.community/blog/index.xml -->
  <channel>
    <title>Percona Community Blog - learn about MySQL, MariaDB, PostgreSQL, and MongoDB</title>
    <link>https://siftrss.com/f/rWW3L1jz0m</link>
    <description>Percona Community Blog is a place where you can learn and get best from the community knowledge about open source databases (MySQL, PostgreSQL, MariaDB, and MongoDB) and various tools. Check out some of the great free content and contribute and share your experience with other community members.</description>
    <atom:link href="https://siftrss.com/f/rWW3L1jz0m" rel="self" type="application/rss+xml"/>
    <generator>Hugo</generator>
    <language>en-us</language>
    <copyright>© Percona Community. MySQL, InnoDB, MariaDB and MongoDB are trademarks of their respective owners.</copyright>
    <lastBuildDate>Thu, 16 Apr 2026 06:22:20 PDT</lastBuildDate>
    <item>
      <title>InnoDB Buffer Pool Tuning: From Rule-of-Thumb to Real Signals</title>
      <link>https://percona.community/blog/2026/04/02/innodb-buffer-pool-tuning-from-rule-of-thumb-to-real-signals/</link>
      <guid>https://percona.community/blog/2026/04/02/innodb-buffer-pool-tuning-from-rule-of-thumb-to-real-signals/</guid>
      <pubDate>Thu, 02 Apr 2026 00:00:00 UTC</pubDate>
      <description>Introduction Many MySQL setups begin life with a familiar incantation:</description>
      <content:encoded>&lt;h2 id="introduction"&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Many MySQL setups begin life with a familiar incantation:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;innodb_buffer_pool_size = 70% of RAM&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;…and then nothing changes.&lt;/p&gt;
&lt;p&gt;That’s not tuning. That’s a starting guess.&lt;/p&gt;
&lt;p&gt;Real tuning starts when the workload pushes back.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="visual-overview"&gt;Visual Overview&lt;/h2&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2026/04/innodb_buffer_pool_diagram.png" alt="InnoDB Buffer Pool Diagram" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;The InnoDB buffer pool is where database performance is quietly decided. It determines whether your workload hums along in memory or drags itself across disk. If you’re not actively observing and tuning it, you’re leaving performance on the table.&lt;/p&gt;
&lt;p&gt;This guide walks through how to monitor, understand, and tune the buffer pool using real signals instead of guesswork.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="what-the-buffer-pool-really-is"&gt;What the Buffer Pool Really Is&lt;/h2&gt;
&lt;p&gt;The buffer pool isn’t just “memory for MySQL.” It’s a living system under constant pressure:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A cache of data and indexes&lt;/li&gt;
&lt;li&gt;A write staging area (dirty pages)&lt;/li&gt;
&lt;li&gt;A contention zone between reads, writes, and eviction&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Think of it as your database’s working memory. If your working set fits, queries glide. If it doesn’t, pages are constantly evicted and reloaded, introducing latency that rarely announces itself clearly.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="a-simple-mental-model"&gt;A Simple Mental Model&lt;/h2&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-1"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; +---------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; | Buffer Pool |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; |---------------------------|
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Reads ---&gt; | Cached Pages |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; | |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Writes ---&gt; | Dirty Pages (pending IO) |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; | |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Eviction -&gt; | LRU / Free List |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; +---------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; v
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Disk (slow)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Three forces are always competing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Reads want hot data in memory&lt;/li&gt;
&lt;li&gt;Writes generate dirty pages&lt;/li&gt;
&lt;li&gt;Eviction makes room under pressure&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Your job is to keep this system balanced.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="how-to-monitor-the-buffer-pool"&gt;How to Monitor the Buffer Pool&lt;/h2&gt;
&lt;h3 id="option-1-quick-snapshot"&gt;Option 1: Quick Snapshot&lt;/h3&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-2" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-2"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SHOW&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ENGINE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;INNODB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;STATUS&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="k"&gt;G&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Useful for human inspection. Look for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Buffer pool size&lt;/li&gt;
&lt;li&gt;Free buffers&lt;/li&gt;
&lt;li&gt;Database pages&lt;/li&gt;
&lt;li&gt;Modified (dirty) pages&lt;/li&gt;
&lt;li&gt;Page read/write rates&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Great for debugging. Not ideal for automation.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="option-2-structured-metrics-recommended"&gt;Option 2: Structured Metrics (Recommended)&lt;/h3&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-3" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-3"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pool_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;free_buffers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;database_pages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;modified_database_pages&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;information_schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;INNODB_BUFFER_POOL_STATS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Key fields:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;free_buffers&lt;/code&gt; → Available pages (breathing room)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;database_pages&lt;/code&gt; → Pages holding data&lt;/li&gt;
&lt;li&gt;&lt;code&gt;modified_database_pages&lt;/code&gt; → Dirty pages waiting to flush&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Great for automation.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="the-5-signals-that-actually-matter"&gt;The 5 Signals That Actually Matter&lt;/h2&gt;
&lt;h3 id="1-buffer-pool-hit-ratio-handle-with-care"&gt;1. Buffer Pool Hit Ratio (Handle With Care)&lt;/h3&gt;
&lt;p&gt;Yes, it’s widely used. No, it’s not enough.&lt;/p&gt;
&lt;p&gt;A high hit ratio does not mean your system is healthy. It does not capture:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Page churn&lt;/li&gt;
&lt;li&gt;Eviction pressure&lt;/li&gt;
&lt;li&gt;Access patterns&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can have a 99% hit ratio and still be IO-bound.&lt;/p&gt;
&lt;p&gt;Use it as a sanity check, not a decision-maker.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="2-free-buffers"&gt;2. Free Buffers&lt;/h3&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-4" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-4"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;free_buffers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;free_buffers&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;information_schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;INNODB_BUFFER_POOL_STATS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Interpretation:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Near zero during steady load → normal&lt;/li&gt;
&lt;li&gt;Near zero + rising disk reads → pressure&lt;/li&gt;
&lt;li&gt;Near zero while mostly idle → suspicious (possible misread or config issue)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="3-dirty-page-percentage"&gt;3. Dirty Page Percentage&lt;/h3&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-5" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-5"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;modified_database_pages&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;database_pages&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dirty_pct&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;information_schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;INNODB_BUFFER_POOL_STATS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Interpretation (context matters):&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;0–5% → Very clean&lt;/li&gt;
&lt;li&gt;5–20% → Typical&lt;/li&gt;
&lt;li&gt;20–30%+ → Potential flushing lag&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="4-disk-read-pressure-critical-signal"&gt;4. Disk Read Pressure (Critical Signal)&lt;/h3&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-6" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-6"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SHOW&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;GLOBAL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;STATUS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;LIKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'Innodb_buffer_pool_reads'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="c1"&gt;-- Take two samples 60s apart and compare&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Track the rate of change (reads/sec), not the absolute value.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Interpretation:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Rising reads → Working set does not fit in memory&lt;/li&gt;
&lt;li&gt;Flat reads → Memory is absorbing the workload&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="5-read-ahead--eviction-pressure"&gt;5. Read Ahead / Eviction Pressure&lt;/h3&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-7" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-7"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SHOW&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;GLOBAL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;STATUS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;LIKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'Innodb_buffer_pool_read_ahead%'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="k"&gt;SHOW&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;GLOBAL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;STATUS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;LIKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'Innodb_buffer_pool_pages_evicted'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="k"&gt;SHOW&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;GLOBAL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;STATUS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;LIKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'Innodb_buffer_pool_reads'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Interpretation:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Efficient read-ahead:
&lt;ul&gt;
&lt;li&gt;read_ahead increases&lt;/li&gt;
&lt;li&gt;read_ahead_evicted remains low&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Inefficient read-ahead (wasted IO):
&lt;ul&gt;
&lt;li&gt;High read_ahead_evicted / read_ahead&lt;/li&gt;
&lt;li&gt;Indicates access patterns defeating prefetching&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Buffer pool churn:
&lt;ul&gt;
&lt;li&gt;pages_evicted rising&lt;/li&gt;
&lt;li&gt;buffer_pool_reads rising&lt;/li&gt;
&lt;li&gt;Indicates pages are evicted and re-read from disk&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Healthy vs unhealthy eviction:
&lt;ul&gt;
&lt;li&gt;High evictions + stable reads → normal turnover&lt;/li&gt;
&lt;li&gt;High evictions + rising reads → memory pressure&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Focus on rates of change over time, not absolute values.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="detecting-thrashing"&gt;Detecting Thrashing&lt;/h2&gt;
&lt;p&gt;Thrashing is when the buffer pool constantly evicts and reloads pages.&lt;/p&gt;
&lt;h3 id="classic-symptoms"&gt;Classic Symptoms&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Low or zero free buffers&lt;/li&gt;
&lt;li&gt;Increasing disk reads&lt;/li&gt;
&lt;li&gt;Stable (but misleading) hit ratio&lt;/li&gt;
&lt;li&gt;Spiky query latency&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="visualizing-thrash"&gt;Visualizing Thrash&lt;/h3&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-8" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-8"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Time ---&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Memory: [FULL][FULL][FULL][FULL]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Reads: ↑ ↑↑ ↑↑↑ ↑↑↑↑
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Latency: - ^ ^^ ^^^
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Evictions: ↑ ↑↑ ↑↑↑ ↑↑↑↑&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;If you see this pattern, your working set does not fit in memory.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="tuning-the-buffer-pool"&gt;Tuning the Buffer Pool&lt;/h2&gt;
&lt;h3 id="step-1-size-it-intentionally"&gt;Step 1: Size It Intentionally&lt;/h3&gt;
&lt;p&gt;Instead of blindly assigning 70% of RAM:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Observe working set behavior&lt;/li&gt;
&lt;li&gt;Monitor free buffers and reads&lt;/li&gt;
&lt;li&gt;Increase gradually&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Avoid starving the OS or filesystem cache.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="step-2-tune-flushing-behavior"&gt;Step 2: Tune Flushing Behavior&lt;/h3&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-9" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-9"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;innodb_max_dirty_pages_pct = 75
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;innodb_io_capacity = 1000
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;innodb_io_capacity_max = 2000&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Sustained IO spikes → increase innodb_io_capacity&lt;/li&gt;
&lt;li&gt;Dirty pages climbing → flushing lag&lt;/li&gt;
&lt;li&gt;Sudden stalls → checkpoint pressure&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;What they control:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;innodb_io_capacity&lt;/code&gt; → Expected steady-state IO throughput&lt;/li&gt;
&lt;li&gt;&lt;code&gt;innodb_io_capacity_max&lt;/code&gt; → Burst flushing capacity&lt;/li&gt;
&lt;li&gt;&lt;code&gt;innodb_max_dirty_pages_pct&lt;/code&gt; → Threshold for aggressive flushing&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;⚠️ These values should reflect real hardware capability.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="step-3-buffer-pool-instancesreduce-contention"&gt;Step 3: Buffer Pool Instances:Reduce Contention&lt;/h3&gt;
&lt;p&gt;A practical, battle-tested guideline:&lt;/p&gt;
&lt;p&gt;Use 1 instance per ~1GB of buffer pool, up to a reasonable limit.&lt;/p&gt;
&lt;p&gt;Buffer Pool Instances: Reducing Contention&lt;/p&gt;
&lt;p&gt;The buffer pool can be split into multiple instances, each managing its own internal structures. This helps reduce contention under high concurrency.&lt;/p&gt;
&lt;p&gt;Without this, all threads compete for the same buffer pool internals. With multiple instances, that load is distributed.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="when-it-matters"&gt;When It Matters&lt;/h3&gt;
&lt;p&gt;Buffer pool instances only help when contention exists. You’ll see benefits if your system has:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;High concurrency (many active threads)&lt;/li&gt;
&lt;li&gt;CPU-bound workloads&lt;/li&gt;
&lt;li&gt;Mutex contention in InnoDB&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If your workload is primarily IO-bound, this setting will have little impact.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="sizing-guidelines"&gt;Sizing Guidelines&lt;/h3&gt;
&lt;p&gt;General guidance:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt; 1GB buffer pool → 1 instance&lt;/li&gt;
&lt;li&gt;1GB–8GB → 2–4 instances&lt;/li&gt;
&lt;li&gt;8GB–64GB → 4–8 instances&lt;/li&gt;
&lt;li&gt;64GB+ → 8–16 instances&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="keep-instances-large-enough"&gt;Keep Instances Large Enough&lt;/h3&gt;
&lt;p&gt;Each instance needs enough memory to function efficiently.&lt;/p&gt;
&lt;p&gt;Avoid going below ~1GB per instance.&lt;/p&gt;
&lt;p&gt;If instances are too small:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;LRU efficiency drops&lt;/li&gt;
&lt;li&gt;Eviction becomes more aggressive&lt;/li&gt;
&lt;li&gt;Cache locality suffers&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Example&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-10" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-10"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;innodb_buffer_pool_size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="k"&gt;G&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="n"&gt;innodb_buffer_pool_instances&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This gives ~4GB per instance, which is well-balanced.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="common-mistakes"&gt;Common Mistakes&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Increasing instances without evidence of contention&lt;/li&gt;
&lt;li&gt;Matching instance count to CPU cores&lt;/li&gt;
&lt;li&gt;Using many instances with a small buffer pool&lt;/li&gt;
&lt;li&gt;Expecting this to fix IO bottlenecks&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="step-4-understand-resizing-behavior"&gt;Step 4: Understand Resizing Behavior&lt;/h3&gt;
&lt;p&gt;Buffer pool resizing is online in modern MySQL versions, but:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It happens in chunks&lt;/li&gt;
&lt;li&gt;Controlled by &lt;code&gt;innodb_buffer_pool_chunk_size&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="real-world-scenarios"&gt;Real-World Scenarios&lt;/h2&gt;
&lt;h3 id="scenario-1-everything-looks-fine-but-its-slow"&gt;Scenario 1: “Everything Looks Fine… But It’s Slow”&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;High hit ratio&lt;/li&gt;
&lt;li&gt;Low free buffers&lt;/li&gt;
&lt;li&gt;Rising disk reads&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Cause:&lt;/strong&gt; Working set barely fits&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; Increase buffer pool size gradually&lt;/p&gt;
&lt;p&gt;If increasing the buffer pool size does not reduce disk reads, the problem is not memory.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="scenario-2-write-heavy-workload"&gt;Scenario 2: Write-Heavy Workload&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Dirty pages increasing&lt;/li&gt;
&lt;li&gt;Periodic IO spikes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Cause:&lt;/strong&gt; Flushing cannot keep up&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Increase &lt;code&gt;innodb_io_capacity&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Adjust dirty page thresholds&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="scenario-3-sudden-latency-spikes"&gt;Scenario 3: Sudden Latency Spikes&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Sharp performance drops&lt;/li&gt;
&lt;li&gt;Disk activity surges&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Cause:&lt;/strong&gt; Checkpoint pressure&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Improve IO capacity tuning&lt;/li&gt;
&lt;li&gt;Reduce dirty page buildup&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="practical-monitoring-queries"&gt;Practical Monitoring Queries&lt;/h2&gt;
&lt;h3 id="buffer-pool-usage-mb"&gt;Buffer Pool Usage (MB)&lt;/h3&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-11" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-11"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;database_pages&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mb_used&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;information_schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;INNODB_BUFFER_POOL_STATS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Assumes default 16KB page size (innodb_page_size).&lt;/p&gt;
&lt;h3 id="dirty-page-percentage"&gt;Dirty Page Percentage&lt;/h3&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-12" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-12"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;modified_database_pages&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;database_pages&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dirty_pct&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;information_schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;INNODB_BUFFER_POOL_STATS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="free-buffer-check"&gt;Free Buffer Check&lt;/h3&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-13" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-13"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;free_buffers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;free_buffers&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;information_schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;INNODB_BUFFER_POOL_STATS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h2 id="common-mistakes-1"&gt;Common Mistakes&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Treating 70% as a rule instead of a starting point&lt;/li&gt;
&lt;li&gt;Blindly trusting hit ratio&lt;/li&gt;
&lt;li&gt;Ignoring disk read trends&lt;/li&gt;
&lt;li&gt;Oversizing and starving the OS&lt;/li&gt;
&lt;li&gt;Not tuning IO capacity&lt;/li&gt;
&lt;li&gt;Leaving defaults in write-heavy systems&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="quick-checklist"&gt;Quick Checklist&lt;/h2&gt;
&lt;p&gt;If you remember nothing else:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Reads increasing? → working set too big&lt;/li&gt;
&lt;li&gt;Free buffers always ~0? → pressure&lt;/li&gt;
&lt;li&gt;Dirty pages high? → flushing lag&lt;/li&gt;
&lt;li&gt;Latency spiking? → checkpoint or IO saturation&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="final-thoughts"&gt;Final Thoughts&lt;/h2&gt;
&lt;p&gt;The InnoDB buffer pool doesn’t fail loudly. It degrades quietly until your disk becomes the bottleneck.&lt;/p&gt;
&lt;p&gt;By the time you notice, you’re debugging latency instead of preventing it.&lt;/p&gt;
&lt;p&gt;Monitor the right signals, and you’ll see problems forming before users do.&lt;/p&gt;
&lt;p&gt;That’s the difference between reacting to performance… and controlling it.&lt;/p&gt;</content:encoded>
      <author>Wayne Leutwyler</author>
      <category>Opensource</category>
      <category>Percona</category>
      <category>MySQL</category>
      <category>Community</category>
      <category>Percona Server</category>
      <category>innodb bufferpool</category>
      <category>tuning</category>
      <media:thumbnail url="https://percona.community/blog/2026/04/bufferpool-tuning_hu_7481b328ae6e02da.jpg"/>
      <media:content url="https://percona.community/blog/2026/04/bufferpool-tuning_hu_1ac592e54c20c4ce.jpg" medium="image"/>
    </item>
    <item>
      <title>Hardening MySQL: Practical Security Strategies for DBAs</title>
      <link>https://percona.community/blog/2026/03/02/hardening-mysql-practical-security-strategies-for-dbas/</link>
      <guid>https://percona.community/blog/2026/03/02/hardening-mysql-practical-security-strategies-for-dbas/</guid>
      <pubDate>Mon, 02 Mar 2026 00:00:00 UTC</pubDate>
      <description>MySQL Security Best Practices: A Practical Guide for Locking Down Your Database Introduction MySQL runs just about everywhere. I’ve seen it behind small personal projects, internal tools, SaaS platforms, and large enterprise systems handling serious transaction volume. When your database sits at the center of everything, it becomes part of your security perimeter whether you planned it that way or not. And that makes it a target.</description>
      <content:encoded>&lt;h1 id="mysql-security-best-practices-a-practical-guide-for-locking-down-your-database"&gt;MySQL Security Best Practices: A Practical Guide for Locking Down Your Database&lt;/h1&gt;
&lt;h2 id="introduction"&gt;Introduction&lt;/h2&gt;
&lt;p&gt;MySQL runs just about everywhere. I’ve seen it behind small personal projects, internal tools, SaaS platforms, and large enterprise systems handling serious transaction volume. When your database sits at the center of everything, it becomes part of your security perimeter whether you planned it that way or not. And that makes it a target.&lt;/p&gt;
&lt;p&gt;Securing MySQL isn’t about flipping one magical setting and calling it done. It’s about layers. Tight access control. Encrypted connections. Clear visibility into what’s happening on the server. And operational discipline that doesn’t drift over time.&lt;/p&gt;
&lt;p&gt;In this guide, I’m going to walk through practical MySQL security best practices that you can apply right away. These are the kinds of checks and hardening steps that reduce real risk in real environments, and help build a database platform that stays resilient under pressure.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="1-principle-of-least-privilege"&gt;1. Principle of Least Privilege&lt;/h2&gt;
&lt;p&gt;One of the most common security mistakes is over-granting privileges.
Applications and users should have only the permissions they absolutely
need.&lt;/p&gt;
&lt;h3 id="bad-practice"&gt;Bad Practice&lt;/h3&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GRANT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PRIVILEGES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'appuser'&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="s1"&gt;'10.%'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="better-approach"&gt;Better Approach&lt;/h3&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-1"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GRANT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;appdb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'appuser'&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="s1"&gt;'10.%'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="recommendations"&gt;Recommendations&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Avoid global privileges unless absolutely required&lt;/li&gt;
&lt;li&gt;Restrict users by host whenever possible&lt;/li&gt;
&lt;li&gt;Separate admin accounts from application accounts&lt;/li&gt;
&lt;li&gt;Use different credentials for read-only vs write operations&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="audit-existing-privileges"&gt;Audit Existing Privileges&lt;/h3&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-2" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-2"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Select_priv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Insert_priv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Update_priv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Delete_priv&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;user&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h2 id="2-strong-authentication--password-policies"&gt;2. Strong Authentication &amp; Password Policies&lt;/h2&gt;
&lt;p&gt;Weak credentials remain one of the easiest attack vectors.&lt;/p&gt;
&lt;h3 id="enable-password-validation"&gt;Enable Password Validation&lt;/h3&gt;
&lt;p&gt;component_validate_password is MySQL’s modern password policy engine. Think of it as a gatekeeper for credential quality. Every time someone tries to set or change a password, it checks whether that password meets your defined security standards before letting it in.&lt;/p&gt;
&lt;p&gt;It replaces the older validate_password plugin with a component-based architecture that is more flexible and better aligned with MySQL 8.x design.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-3" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-3"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;INSTALL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;COMPONENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'file://component_validate_password'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="what-it-does"&gt;What It Does&lt;/h3&gt;
&lt;p&gt;When enabled, it enforces rules such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Minimum password length&lt;/li&gt;
&lt;li&gt;Required mix of character types&lt;/li&gt;
&lt;li&gt;Dictionary file checks&lt;/li&gt;
&lt;li&gt;Strength scoring&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If a password fails policy, the statement is rejected before the credential is stored.&lt;/p&gt;
&lt;h3 id="why-it-matters"&gt;Why It Matters&lt;/h3&gt;
&lt;p&gt;Weak passwords remain one of the most common entry points in database breaches. This component reduces risk by enforcing baseline credential hygiene automatically, instead of relying on developer discipline.&lt;/p&gt;
&lt;h3 id="recommended-policies"&gt;Recommended Policies&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Minimum length: 14+ characters&lt;/li&gt;
&lt;li&gt;Require mixed case, numbers, and symbols&lt;/li&gt;
&lt;li&gt;Enable dictionary checks&lt;/li&gt;
&lt;li&gt;Enable username checks&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="remove-anonymous-accounts"&gt;Remove Anonymous Accounts&lt;/h3&gt;
&lt;h4 id="find-anonymous-users"&gt;Find Anonymous Users&lt;/h4&gt;
&lt;p&gt;Anonymous users have an empty User field.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-4" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-4"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;user&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;If you see rows returned, those are anonymous accounts.&lt;/p&gt;
&lt;h3 id="drop-anonymous-users"&gt;Drop Anonymous Users&lt;/h3&gt;
&lt;p&gt;In modern MySQL versions:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-5" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-5"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;DROP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="s1"&gt;'localhost'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="k"&gt;DROP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="s1"&gt;'%'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Adjust the Host value based on what your query returned.&lt;/p&gt;
&lt;h3 id="why-this-matters"&gt;Why This Matters&lt;/h3&gt;
&lt;p&gt;Anonymous users:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Allow login without credentials&lt;/li&gt;
&lt;li&gt;May have default privileges in some distributions&lt;/li&gt;
&lt;li&gt;Increase the attack surface unnecessarily&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In hardened environments, there should be zero accounts with an empty username. Every identity should be explicit, accountable, and least-privileged.&lt;/p&gt;
&lt;h2 id="3-encryption-everywhere"&gt;3. Encryption Everywhere&lt;/h2&gt;
&lt;p&gt;Encryption protects data both in transit and at rest.&lt;/p&gt;
&lt;h3 id="enable-transparent-data-encryption-tde"&gt;Enable Transparent Data Encryption (TDE)&lt;/h3&gt;
&lt;p&gt;See my January 13 post for a deep dive into Transparent Data Encryption:
&lt;a href="https://percona.community/blog/2026/01/13/configuring-the-component-keyring-in-percona-server-and-pxc-8.4/" target="_blank" rel="noopener noreferrer"&gt;Configuring the Component Keyring in Percona Server and PXC 8.4&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="enable-tls-for-connections"&gt;Enable TLS for Connections&lt;/h3&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-6" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-6"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;require_secure_transport&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="verify-ssl-usage"&gt;Verify SSL Usage&lt;/h3&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-7" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-7"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SHOW&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;STATUS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;LIKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'Ssl_cipher'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="encryption-areas-to-consider"&gt;Encryption Areas to Consider&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Client-server connections&lt;/li&gt;
&lt;li&gt;Replication channels&lt;/li&gt;
&lt;li&gt;Backups and snapshot storage&lt;/li&gt;
&lt;li&gt;Disk-level encryption&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="4-patch-management--version-hygiene"&gt;4. Patch Management &amp; Version Hygiene&lt;/h2&gt;
&lt;p&gt;Running outdated MySQL versions is equivalent to leaving known
vulnerabilities exposed.&lt;/p&gt;
&lt;h3 id="maintenance-strategy"&gt;Maintenance Strategy&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Track vendor security advisories&lt;/li&gt;
&lt;li&gt;Apply minor updates regularly&lt;/li&gt;
&lt;li&gt;Test patches in staging before production rollout&lt;/li&gt;
&lt;li&gt;Avoid unsupported MySQL versions&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="check-version"&gt;Check Version&lt;/h3&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-8" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-8"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;VERSION&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="5-logging-auditing-and-monitoring"&gt;5. Logging, Auditing, and Monitoring&lt;/h2&gt;
&lt;p&gt;Security without visibility is blind defense, enable Audit Logging.&lt;/p&gt;
&lt;h3 id="1-audit_log-plugin-legacy-model"&gt;1. audit_log Plugin (Legacy Model)&lt;/h3&gt;
&lt;h4 id="installation"&gt;Installation&lt;/h4&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-9" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-9"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;INSTALL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PLUGIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;audit_log&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SONAME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'audit_log.so'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h4 id="verify"&gt;Verify&lt;/h4&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-10" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-10"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SHOW&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PLUGINS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;LIKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'audit%'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="2-audit_log_filter-component-modern-model"&gt;2. audit_log_filter Component (Modern Model)&lt;/h3&gt;
&lt;p&gt;Introduced in MySQL 8 to provide a more flexible and granular alternative to the older plugin model.&lt;/p&gt;
&lt;h4 id="installation-1"&gt;Installation&lt;/h4&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-11" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-11"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;INSTALL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;COMPONENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'file://component_audit_log_filter'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h4 id="verify-1"&gt;Verify&lt;/h4&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-12" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-12"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;component&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h4 id="architecture-difference"&gt;Architecture Difference&lt;/h4&gt;
&lt;p&gt;Instead of a single global policy, you create:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Filters (define what to log)&lt;/li&gt;
&lt;li&gt;Users assigned to filters&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It’s granular and rule-driven.&lt;/p&gt;
&lt;h3 id="auditing-key-events"&gt;Auditing Key Events&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Failed logins&lt;/li&gt;
&lt;li&gt;Privilege changes&lt;/li&gt;
&lt;li&gt;Schema modifications&lt;/li&gt;
&lt;li&gt;Unusual query activity&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="references"&gt;References:&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://percona.community/blog/2025/09/18/audit-log-filter-component/" target="_blank" rel="noopener noreferrer"&gt;Audit Log Filter Component
&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://percona.community/blog/2025/10/08/audit-log-filters-part-ii/" target="_blank" rel="noopener noreferrer"&gt;Audit Log Filters Part II
&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="useful-metrics"&gt;Useful Metrics&lt;/h3&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-13" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-13"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SHOW&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;GLOBAL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;STATUS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;LIKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'Aborted_connects'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="k"&gt;SHOW&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;GLOBAL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;STATUS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;LIKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'Connections'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="6-secure-configuration-hardening"&gt;6. Secure Configuration Hardening&lt;/h2&gt;
&lt;p&gt;A secure baseline configuration reduces risk from common attack
patterns.&lt;/p&gt;
&lt;h3 id="recommended-settings"&gt;Recommended Settings&lt;/h3&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;ini&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-14" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-14"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ini" data-lang="ini"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;local_infile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;OFF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;secure_file_priv&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/var/lib/mysql-files&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;sql_mode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"STRICT_ALL_TABLES"&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;secure-log-path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/var/log/mysql&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="why-these-matter"&gt;Why These Matter&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Prevent arbitrary file imports&lt;/li&gt;
&lt;li&gt;Reduce filesystem abuse&lt;/li&gt;
&lt;li&gt;Restrict data export/import locations&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="7-backup-security"&gt;7. Backup Security&lt;/h2&gt;
&lt;p&gt;Backups often contain everything an attacker wants.&lt;/p&gt;
&lt;h3 id="backup-best-practices"&gt;Backup Best Practices&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Encrypt backups&lt;/li&gt;
&lt;li&gt;Restrict filesystem permissions&lt;/li&gt;
&lt;li&gt;Store offsite copies securely&lt;/li&gt;
&lt;li&gt;Rotate backup credentials&lt;/li&gt;
&lt;li&gt;Verify restore procedures regularly&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="example-permission-check"&gt;Example Permission Check&lt;/h3&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-15" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-15"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ls -l /backup/mysql&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="8-replication--cluster-security"&gt;8. Replication &amp; Cluster Security&lt;/h2&gt;
&lt;p&gt;Replication is not just a data distribution feature. It is a persistent, privileged communication channel between servers. If misconfigured, it can become a lateral movement pathway inside your infrastructure. Treat every replication link as a trusted but tightly controlled corridor.&lt;/p&gt;
&lt;p&gt;Principle: Replication Is a Privileged Service Account&lt;/p&gt;
&lt;p&gt;Replication users require elevated capabilities. They must be isolated, tightly scoped, and monitored like any other service identity.&lt;/p&gt;
&lt;h3 id="secure-replication-users"&gt;Secure Replication Users&lt;/h3&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-16" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-16"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'repl'&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="s1"&gt;'10.%'&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;IDENTIFIED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'strongpassword'&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;REQUIRE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SSL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="k"&gt;GRANT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;REPLICATION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;REPLICA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'repl'&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="s1"&gt;'10.%'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Hardening considerations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Restrict host patterns as narrowly as possible. Avoid % whenever feasible.&lt;/li&gt;
&lt;li&gt;Require SSL or X.509 certificate authentication.&lt;/li&gt;
&lt;li&gt;Enforce strong password policies or use a secrets manager.&lt;/li&gt;
&lt;li&gt;Disable interactive login capability if applicable.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="encrypt-replication-traffic"&gt;Encrypt Replication Traffic&lt;/h3&gt;
&lt;p&gt;Replication traffic may include sensitive row data, DDL statements, and metadata. Always encrypt it.&lt;/p&gt;
&lt;p&gt;At minimum:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Enable require_secure_transport=ON&lt;/li&gt;
&lt;li&gt;Configure TLS certificates on source and replica&lt;/li&gt;
&lt;li&gt;Set replication channel to use SSL:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-17" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-17"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;CHANGE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;REPLICATION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SOURCE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SOURCE_SSL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SOURCE_SSL_CA&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'/path/ca.pem'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SOURCE_SSL_CERT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'/path/client-cert.pem'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SOURCE_SSL_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'/path/client-key.pem'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;For MySQL Group Replication or InnoDB Cluster:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Enable group communication SSL&lt;/li&gt;
&lt;li&gt;Validate certificate identity&lt;/li&gt;
&lt;li&gt;Use dedicated replication networks&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="binary-log-and-relay-log-protection"&gt;Binary Log and Relay Log Protection&lt;/h3&gt;
&lt;p&gt;Replication relies on binary logs. Protect them.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Set binlog_encryption=ON&lt;/li&gt;
&lt;li&gt;Set relay_log_info_repository=TABLE&lt;/li&gt;
&lt;li&gt;Restrict filesystem access to log directories&lt;/li&gt;
&lt;li&gt;Monitor log retention policies&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Compromised binary logs can reveal historical data changes.&lt;/p&gt;
&lt;h2 id="9-continuous-security-reviews"&gt;9. Continuous Security Reviews&lt;/h2&gt;
&lt;p&gt;Security is not a one-time checklist. Regular audits help catch
configuration drift and evolving threats.&lt;/p&gt;
&lt;h3 id="suggested-review-cadence"&gt;Suggested Review Cadence&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Weekly: failed login review&lt;/li&gt;
&lt;li&gt;Monthly: privilege audits&lt;/li&gt;
&lt;li&gt;Quarterly: configuration review&lt;/li&gt;
&lt;li&gt;Semiannually: full security assessment&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="security-checklist-summary"&gt;Security Checklist Summary&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Area&lt;/th&gt;
&lt;th&gt;Key Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Access Control&lt;/td&gt;
&lt;td&gt;Least privilege grants&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Authentication&lt;/td&gt;
&lt;td&gt;Strong password policies&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Encryption&lt;/td&gt;
&lt;td&gt;TLS + encrypted storage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Updates&lt;/td&gt;
&lt;td&gt;Regular patching&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Monitoring&lt;/td&gt;
&lt;td&gt;Audit logging enabled&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Configuration&lt;/td&gt;
&lt;td&gt;Harden defaults&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Backups&lt;/td&gt;
&lt;td&gt;Encrypt and protect&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Replication&lt;/td&gt;
&lt;td&gt;Secure replication users&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="final-thoughts"&gt;Final Thoughts&lt;/h2&gt;
&lt;p&gt;Strong MySQL security doesn’t come from one feature or one tool. It comes from layers working together. Hardened configuration. Tight, intentional privilege design. Encryption everywhere it makes sense. And monitoring that actually gets reviewed instead of just written to disk.&lt;/p&gt;
&lt;p&gt;In my experience, the strongest environments aren’t the ones trying to be unbreakable. They’re the ones built to detect, contain, and respond. Every layer should either reduce blast radius or increase visibility. If an attacker gets through one control, the next one slows them down. And while they’re slowing down, your logging and monitoring should already be telling you something isn’t right.&lt;/p&gt;
&lt;p&gt;That’s what a mature security posture looks like in practice.&lt;/p&gt;</content:encoded>
      <author>Wayne Leutwyler</author>
      <category>Opensource</category>
      <category>Percona</category>
      <category>MySQL</category>
      <category>Community</category>
      <category>Percona Server</category>
      <category>security</category>
      <category>auditing</category>
      <media:thumbnail url="https://percona.community/blog/2026/03/mysql-security_hu_2e3482c9b216e342.jpg"/>
      <media:content url="https://percona.community/blog/2026/03/mysql-security_hu_5d7a0d72bf4766b.jpg" medium="image"/>
    </item>
    <item>
      <title>Configuring the Component Keyring in Percona Server and PXC 8.4</title>
      <link>https://percona.community/blog/2026/01/13/configuring-the-component-keyring-in-percona-server-and-pxc-8.4/</link>
      <guid>https://percona.community/blog/2026/01/13/configuring-the-component-keyring-in-percona-server-and-pxc-8.4/</guid>
      <pubDate>Tue, 13 Jan 2026 00:00:00 UTC</pubDate>
      <description>Configuring the Component Keyring in Percona Server and PXC 8.4 (Or: how to make MySQL encryption boring, which is the goal)</description>
      <content:encoded>&lt;h1 id="configuring-the-component-keyring-in-percona-server-and-pxc-84"&gt;Configuring the Component Keyring in Percona Server and PXC 8.4&lt;/h1&gt;
&lt;p&gt;&lt;em&gt;(Or: how to make MySQL encryption boring, which is the goal)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Encryption is one of those things everyone agrees is important, right up until MySQL refuses to start and you’re staring at a JSON file wondering which brace ruined your evening.&lt;/p&gt;
&lt;p&gt;With &lt;strong&gt;MySQL 8.4&lt;/strong&gt;, encryption has firmly moved into the &lt;strong&gt;component world&lt;/strong&gt;, and if you’re running &lt;strong&gt;Percona Server 8.4&lt;/strong&gt; or &lt;strong&gt;Percona XtraDB Cluster (PXC) 8.4&lt;/strong&gt;, the supported path forward is the &lt;code&gt;component_keyring_file&lt;/code&gt; component.&lt;/p&gt;
&lt;p&gt;The good news: the setup is mostly identical for Percona Server and PXC.&lt;br&gt;
The bad news: PXC 8.4.4 and 8.4.5 shipped with a bug that makes this less fun than it should be.&lt;/p&gt;
&lt;p&gt;Let’s walk through a setup that works, keeps your keys locked down, and avoids the usual landmines.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="step-1-tell-mysql-which-component-to-load"&gt;Step 1: Tell MySQL Which Component to Load&lt;/h2&gt;
&lt;p&gt;Components are registered using &lt;strong&gt;JSON&lt;/strong&gt;, not traditional MySQL configuration syntax. This is important, because MySQL will not politely warn you if you get it wrong. It will simply refuse to start.&lt;/p&gt;
&lt;p&gt;Create the file:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo vi /usr/sbin/mysqld.my&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Add:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;json&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-1"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;"components"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"file://component_keyring_file"&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Take a second to double-check the formatting. One missing quote here will cost you more time than you want to admit.&lt;/p&gt;
&lt;p&gt;Now lock it down:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-2" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-2"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo chown root:root /usr/sbin/mysqld.my
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo chmod &lt;span class="m"&gt;644&lt;/span&gt; /usr/sbin/mysqld.my&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This is configuration, not data. MySQL only needs to read it.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="step-2-prepare-the-keyring-directory-handle-with-care"&gt;Step 2: Prepare the Keyring Directory (Handle With Care)&lt;/h2&gt;
&lt;p&gt;This directory will hold encryption keys. Treat it accordingly.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-3" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-3"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /var/lib
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo mkdir mysql-keyring
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo chown mysql:mysql mysql-keyring
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo chmod &lt;span class="m"&gt;750&lt;/span&gt; mysql-keyring&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;A simple rule that saves headaches:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;mysql owns the keys&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MySQL is allowed to access them&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Nobody else gets any ideas&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="step-3-configure-the-keyring-component-itself"&gt;Step 3: Configure the Keyring Component Itself&lt;/h2&gt;
&lt;p&gt;Next, move to the plugin directory:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-4" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-4"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /usr/lib64/mysql/plugin&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Create the component configuration file:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-5" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-5"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo vi component_keyring_file.cnf&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Add:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;json&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-6" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-6"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"/var/lib/mysql-keyring/component_keyring_file"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;"read_only"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This file tells MySQL where the keyring lives and ensures it can’t be casually modified at runtime.&lt;/p&gt;
&lt;p&gt;Set ownership and permissions:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-7" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-7"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo chown root:root component_keyring_file.cnf
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo chmod &lt;span class="m"&gt;640&lt;/span&gt; component_keyring_file.cnf&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Again: configuration belongs to root. MySQL just reads it.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="step-4-the-pxc-844--845-bug-yes-theres-one"&gt;Step 4: The PXC 8.4.4 / 8.4.5 Bug (Yes, There’s One)&lt;/h2&gt;
&lt;p&gt;If you’re running &lt;strong&gt;Percona Server&lt;/strong&gt;, you can skip this entire section and enjoy your day.&lt;/p&gt;
&lt;p&gt;If you’re running &lt;strong&gt;Percona XtraDB Cluster 8.4.4 or 8.4.5&lt;/strong&gt;, there is a known issue with plugin paths that prevents the component keyring from loading correctly. This was fixed in &lt;strong&gt;PXC 8.4.6&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;If upgrading isn’t an option yet, you’ll need one of the following workarounds.&lt;/p&gt;
&lt;h3 id="option-a-create-a-symlink-preferred"&gt;Option A: Create a Symlink (Preferred)&lt;/h3&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-8" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-8"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo ln -s &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;/usr/bin/pxc_extra/pxb-8.4/lib/lib64/xtrabackup/plugin &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;/usr/bin/pxc_extra/pxb-8.4/lib/plugin&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="option-b-copy-the-plugin-directory"&gt;Option B: Copy the Plugin Directory&lt;/h3&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-9" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-9"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo cp -ar &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;/usr/bin/pxc_extra/pxb-8.4/lib/lib64/xtrabackup/plugin &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;/usr/bin/pxc_extra/pxb-8.4/lib&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;If you’re on &lt;strong&gt;PXC 8.4.6 or newer&lt;/strong&gt;, this problem is already behind you and you can safely pretend it never existed.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="step-5-restart-mysql"&gt;Step 5: Restart MySQL&lt;/h2&gt;
&lt;p&gt;Time for the moment of truth:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-10" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-10"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl restart mysql&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Or &lt;code&gt;mysqld&lt;/code&gt;, depending on your system.&lt;/p&gt;
&lt;p&gt;If MySQL starts cleanly, you’re doing well. If not, go back and check your JSON files. It’s almost always the JSON.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="step-6-verify-the-keyring-is-actually-loaded"&gt;Step 6: Verify the Keyring Is Actually Loaded&lt;/h2&gt;
&lt;p&gt;Never assume. Always verify.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-11" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-11"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;performance_schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keyring_component_status&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;You should see the &lt;code&gt;component_keyring_file&lt;/code&gt; listed and active. If it’s there, the keyring is live.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-12" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-12"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;---------------------+-----------------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;STATUS_KEY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;STATUS_VALUE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;---------------------+-----------------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Component_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;component_keyring_file&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Author&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Oracle&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Corporation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;License&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GPL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Implementation_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;component_keyring_file&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;Version&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Component_status&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Active&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Data_file&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;keyring&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;component_keyring_file&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Read_only&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Yes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;---------------------+-----------------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;rows&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h2 id="a-note-for-percona-server-users"&gt;A Note for Percona Server Users&lt;/h2&gt;
&lt;p&gt;Percona Server may still include &lt;strong&gt;legacy keyring plugins&lt;/strong&gt; such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;keyring_file&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;keyring_vault&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Do not mix legacy keyring plugins with component keyrings. They come from different eras of MySQL design and do not coexist peacefully.&lt;/p&gt;
&lt;p&gt;Choose one model. For MySQL 8.4 and forward, &lt;strong&gt;components are the future&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id="additional-steps-for-percona-xtradb-cluster-pxc"&gt;Additional Steps for Percona XtraDB Cluster (PXC)&lt;/h2&gt;
&lt;p&gt;Percona XtraDB Cluster introduces one critical difference compared to standalone Percona Server: the keyring file itself is not replicated by Galera. Only metadata and transactional state are replicated. The encryption keys remain node-local filesystem artifacts and must be handled deliberately.&lt;/p&gt;
&lt;h3 id="node-1-establish-the-authoritative-keyring"&gt;Node 1: Establish the Authoritative Keyring&lt;/h3&gt;
&lt;p&gt;Choose a single node to initialize the keyring. This is typically Node1, but the choice itself is not important as long as you are consistent.&lt;/p&gt;
&lt;p&gt;On this node:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Complete all previous steps in this document&lt;/li&gt;
&lt;li&gt;Start MySQL successfully&lt;/li&gt;
&lt;li&gt;Verify the keyring component is loaded:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-13" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-13"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;performance_schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keyring_component_status&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Once this node is running, the file below will be created and populated:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;swift&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-14" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-14"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;keyring&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;component_keyring_file&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This file becomes the authoritative source of encryption keys for the entire cluster.&lt;/p&gt;
&lt;h3 id="why-the-keyring-file-must-be-copied"&gt;Why the Keyring File Must Be Copied&lt;/h3&gt;
&lt;p&gt;PXC ensures that encrypted data remains readable on all nodes, but it does not distribute encryption keys themselves. Each node must have access to the same key material, or encrypted tablespaces will fail to open.&lt;/p&gt;
&lt;p&gt;If a node starts without the correct keyring file, you may see:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tablespace open failures&lt;/li&gt;
&lt;li&gt;Startup errors related to encryption&lt;/li&gt;
&lt;li&gt;Inconsistent behavior during SST or IST&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is expected behavior and not a bug.&lt;/p&gt;
&lt;h3 id="distribute-the-keyring-file-to-other-nodes"&gt;Distribute the Keyring File to Other Nodes&lt;/h3&gt;
&lt;p&gt;On each remaining PXC node:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Ensure MySQL is stopped&lt;/li&gt;
&lt;li&gt;Create the keyring directory if it does not exist:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-15" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-15"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo mkdir -p /var/lib/mysql-keyring
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo chown mysql:mysql /var/lib/mysql-keyring
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo chmod &lt;span class="m"&gt;750&lt;/span&gt; /var/lib/mysql-keyring&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;Securely copy the keyring file from Node1:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-16" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-16"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;scp /var/lib/mysql-keyring/component_keyring_file node2:/var/lib/mysql-keyring/component_keyring_file&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt;
Do not modify the file. Do not recreate it. Do not allow MySQL to generate a new one on secondary nodes.&lt;/p&gt;
&lt;h3 id="start-mysql-on-each-node-and-verify"&gt;Start MySQL on Each Node and Verify&lt;/h3&gt;
&lt;p&gt;After the keyring file is in place:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-17" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-17"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl start mysqld&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Verify the component is active:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-18" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-18"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;performance_schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keyring_component_status&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Each node should report the component_keyring_file as loaded and active.&lt;/p&gt;
&lt;p&gt;At this point:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Encrypted tablespaces will open correctly&lt;/li&gt;
&lt;li&gt;SST and IST operations will succeed&lt;/li&gt;
&lt;li&gt;The cluster will behave consistently during restarts&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="operational-notes-and-best-practices"&gt;Operational Notes and Best Practices&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Treat the keyring file like a secret, not configuration&lt;/li&gt;
&lt;li&gt;Restrict access to root only&lt;/li&gt;
&lt;li&gt;Include the keyring file in your secure backup strategy&lt;/li&gt;
&lt;li&gt;When provisioning new nodes, copy the keyring file before first startup&lt;/li&gt;
&lt;li&gt;Never rotate or regenerate the keyring independently on individual nodes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If the keyring is lost and encrypted data exists, recovery is not possible.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="final-thoughts"&gt;Final Thoughts&lt;/h2&gt;
&lt;p&gt;This setup works reliably for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Percona Server 8.4&lt;/li&gt;
&lt;li&gt;Percona XtraDB Cluster 8.4&lt;br&gt;
(with the known exception of 8.4.4–8.4.5)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Most failures come down to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Treating JSON like a &lt;code&gt;.cnf&lt;/code&gt; file&lt;/li&gt;
&lt;li&gt;Loose ownership on sensitive files&lt;/li&gt;
&lt;li&gt;Forgetting the PXC-specific workaround&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once those are handled, the component keyring fades into the background where it belongs. And when it comes to encryption, boring, quiet, and uneventful is exactly the outcome you want.&lt;/p&gt;</content:encoded>
      <author>Wayne Leutwyler</author>
      <author>Stan Lipinski</author>
      <category>Opensource</category>
      <category>Percona</category>
      <category>key ring</category>
      <category>MySQL</category>
      <category>Community</category>
      <category>Percona Server</category>
      <category>PXC</category>
      <category>Security</category>
      <media:thumbnail url="https://percona.community/blog/2026/01/keyring-component_hu_55d2689b19226a60.jpg"/>
      <media:content url="https://percona.community/blog/2026/01/keyring-component_hu_248d0e8fdd379cd5.jpg" medium="image"/>
    </item>
    <item>
      <title>MySQL Replication Best Practices: How to Keep Your Replicas Sane (and Your Nights Quiet)</title>
      <link>https://percona.community/blog/2025/12/03/mysql-replication-best-practices-how-to-keep-your-replicas-sane-and-your-nights-quiet/</link>
      <guid>https://percona.community/blog/2025/12/03/mysql-replication-best-practices-how-to-keep-your-replicas-sane-and-your-nights-quiet/</guid>
      <pubDate>Wed, 03 Dec 2025 00:00:00 UTC</pubDate>
      <description>MySQL replication has been around forever, and yet… people still manage to set it up in ways that break at the worst possible moment. Even in 2025, you can get burned by tiny schema differences, missing primary keys, or one forgotten config flag. I’ve seen replicas drift so far out of sync they might as well live in a different universe.</description>
      <content:encoded>&lt;p&gt;MySQL replication has been around forever, and yet… people still manage to set it up in ways that break at the worst possible moment. Even in 2025, you can get burned by tiny schema differences, missing primary keys, or one forgotten config flag. I’ve seen replicas drift so far out of sync they might as well live in a different universe.&lt;/p&gt;
&lt;p&gt;This guide covers the practical best practices—the stuff real DBAs use every day to keep replication stable, predictable, and boring. (Boring is a compliment in database land.)&lt;/p&gt;
&lt;h3 id="always-use-gtids-yes-always"&gt;Always Use GTIDs. Yes, Always.&lt;/h3&gt;
&lt;p&gt;GTID-based replication is one of those features that people resist turning on, and then once they do, they never want to go back.&lt;/p&gt;
&lt;p&gt;Why GTIDs?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Failover become sane&lt;/li&gt;
&lt;li&gt;Reparenting replicas stops being a headache&lt;/li&gt;
&lt;li&gt;Missing transactions are easy to detect&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Your my.cnf should absolutely include:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gtid_mode=ON
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;enforce_gtid_consistency=ON
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;log_replica_updates=ON&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Once GTIDs are enabled, do not mix in old-style replication. That path leads straight to confusion.&lt;/p&gt;
&lt;h3 id="use-row-based-replication-rbr"&gt;Use Row-Based Replication (RBR)&lt;/h3&gt;
&lt;p&gt;Statement-based replication is a nostalgia trip that nobody asked for. It breaks on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;NOW(), UUID(), and similar functions&lt;/li&gt;
&lt;li&gt;Floating point differences&lt;/li&gt;
&lt;li&gt;Collation mismatches&lt;/li&gt;
&lt;li&gt;Triggers behaving differently&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Just skip the pain and use:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-1"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;binlog_format=ROW&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;RBR is slightly more verbose, but 100× more predictable. When something breaks, it’s never because you chose ROW.&lt;/p&gt;
&lt;h3 id="every-table-needs-a-primary-key-no-exceptions"&gt;Every Table Needs a Primary Key. No Exceptions.&lt;/h3&gt;
&lt;p&gt;If you take nothing else from this guide, take this:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Replication without primary keys is a bad time.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Row-based replication needs a way to find the row that changed. Without a PK (or at least a UNIQUE index), the server has to use every column as a lookup. That’s slow, error-prone, and sometimes impossible.&lt;/p&gt;
&lt;p&gt;The usual symptoms:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Replication lag slowly creeping up&lt;/li&gt;
&lt;li&gt;Replica doing full table scans on updates&lt;/li&gt;
&lt;li&gt;Rows failing to apply&lt;/li&gt;
&lt;li&gt;Errors like:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-2" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-2"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Error 1032: Can't find record in table&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Save yourself hours of debugging and just make sure every table has a primary key.&lt;/p&gt;
&lt;h3 id="keep-the-schema-identical-everywhere"&gt;Keep the Schema Identical Everywhere&lt;/h3&gt;
&lt;p&gt;Replication assumes that everyone’s using the same schema. MySQL will happily keep going even if your schemas don’t match—and then quietly drift out of sync.&lt;/p&gt;
&lt;p&gt;Here are the practical ways to keep schemas aligned:&lt;/p&gt;
&lt;h4 id="approach-a--mysqldump-most-common"&gt;Approach A — mysqldump (most common)&lt;/h4&gt;
&lt;p&gt;Export schemas only:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-3" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-3"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mysqldump --no-data mydb &gt; schema.sql&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;From both servers, then:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-4" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-4"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;diff source-schema.sql replica-schema.sql&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h4 id="approach-b--information_schema-metadata"&gt;Approach B — information_schema metadata&lt;/h4&gt;
&lt;p&gt;This approach is great for automaton:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-5" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-5"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;SELECT table_name, column_name, column_type, is_nullable, column_default
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;FROM information_schema.columns
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;WHERE table_schema = 'mydb'
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ORDER BY table_name, ordinal_position;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Execute this query on each server and diff the results. Update mydb to match the database whose schema metadata you want to examine.&lt;/p&gt;
&lt;h4 id="approach-c--pt-table-checksum-data-only"&gt;Approach C — pt-table-checksum (data only)&lt;/h4&gt;
&lt;p&gt;This doesn’t compare schemas — it catches data drift.
You should consider running it on a schedule such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;high-change OLTP DBs run weekly or even daily&lt;/li&gt;
&lt;li&gt;huge multi-TB DBs run quarterly&lt;/li&gt;
&lt;li&gt;some sensitive systems avoid running it during peak hours&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-6" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-6"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pt-table-checksum --replicate=percona.checksums&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;You can fix drift with:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-7" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-7"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pt-table-sync --execute --replicate=percona.checksums&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Schema checks + data checks = safe replication.&lt;/p&gt;
&lt;h3 id="harden-your-binary-log-settings"&gt;Harden Your Binary Log Settings&lt;/h3&gt;
&lt;p&gt;Your binlogs are the backbone of replication. Treat them carefully.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-8" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-8"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sync_binlog=1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;binlog_row_image=FULL
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;binlog_expire_logs_seconds=604800 # 7 days&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;sync_binlog=1 is the big one—without it, a crash can corrupt binlogs or the GTID position, and that leads to a very bad day.&lt;/p&gt;
&lt;h3 id="protect-your-replicas-with-super_read_only"&gt;Protect Your Replicas with super_read_only&lt;/h3&gt;
&lt;p&gt;Never allow accidental writes to replicas, in your my.cnf set:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-9" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-9"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;read_only=ON
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;super_read_only=ON&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;super_read_only&lt;/strong&gt; closes the loophole that even SUPER users could previously use to write to replicas.&lt;/p&gt;
&lt;h3 id="use-a-dedicated-replication-user"&gt;Use a Dedicated Replication User&lt;/h3&gt;
&lt;p&gt;Give the minimal permissions:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-10" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-10"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;CREATE USER 'repl'@'%' IDENTIFIED BY 'strong_password';
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;GRANT REPLICATION REPLICA ON *.* TO 'repl'@'%';&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This user should do exactly one thing: replicate.
Don’t reuse app users—you’re just begging for trouble.&lt;/p&gt;
&lt;h3 id="replication-lag-watch-it-like-a-hawk"&gt;Replication Lag: Watch It Like a Hawk&lt;/h3&gt;
&lt;p&gt;Seconds_Behind_Source lies more often than you’d expect. It’s okay for a quick glance but don’t rely on it.&lt;/p&gt;
&lt;p&gt;Better options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Performance Schema: replication_applier_status_by_worker&lt;/li&gt;
&lt;li&gt;Percona Monitoring and Management (PMM)&lt;/li&gt;
&lt;li&gt;Custom heartbeat tables&lt;/li&gt;
&lt;li&gt;pt-heartbeat&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Lag is one of the biggest causes of outages—monitor it continuously. Lag is usually the first sign something is wrong—catch it early.&lt;/p&gt;
&lt;h3 id="use-parallel-replication-but-dont-overdo-it"&gt;Use Parallel Replication (But Don’t Overdo It)&lt;/h3&gt;
&lt;p&gt;If your primary has multiple writers or many concurrent transactions, in your my.cnf enable parallel workers:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-11" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-11"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;replica_parallel_type=LOGICAL_CLOCK
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;replica_parallel_workers=4&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;4–8 workers is a sweet spot for most systems. More workers ≠ more speed; after a point it just increases memory footprint without real benefit.&lt;/p&gt;
&lt;p&gt;But when it helps, it really helps—like cutting lag by 80–90%.&lt;/p&gt;
&lt;h3 id="use-ssl-anywhere-outside-the-lan"&gt;Use SSL Anywhere Outside the LAN&lt;/h3&gt;
&lt;p&gt;Replication traffic isn’t something you want exposed.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-12" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-12"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;source_ssl=1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;source_ssl_ca=/path/ca.pem&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Earlier versions used the master_ssl_* variables, but the idea is the same: encrypt the connection when it leaves your trusted network.&lt;/p&gt;
&lt;h2 id="final-thoughts"&gt;Final Thoughts&lt;/h2&gt;
&lt;p&gt;MySQL replication can be rock-solid, but only if you follow a handful of rules that experienced DBAs know by heart:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use GTIDs&lt;/li&gt;
&lt;li&gt;Use RBR&lt;/li&gt;
&lt;li&gt;Always have primary keys&lt;/li&gt;
&lt;li&gt;Keep schemas aligned&lt;/li&gt;
&lt;li&gt;Check for data drift&lt;/li&gt;
&lt;li&gt;Harden binlog settings&lt;/li&gt;
&lt;li&gt;Protect replicas from accidental writes&lt;/li&gt;
&lt;li&gt;Monitor lag properly&lt;/li&gt;
&lt;li&gt;Use parallel workers when appropriate&lt;/li&gt;
&lt;li&gt;Encrypt connections over untrusted networks&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Follow these, and your replicas will stay healthy, consistent, and (mostly) invisible—which is exactly how you want them.&lt;/p&gt;</content:encoded>
      <author>Wayne Leutwyler</author>
      <category>Opensource</category>
      <category>Percona</category>
      <category>replication</category>
      <category>MySQL</category>
      <category>Community</category>
      <category>Percona Server</category>
      <category>toolkit</category>
      <media:thumbnail url="https://percona.community/blog/2025/12/mysql-replication-best-practice_hu_fdef2ac6195fc52b.jpg"/>
      <media:content url="https://percona.community/blog/2025/12/mysql-replication-best-practice_hu_401bb1385cddcf3a.jpg" medium="image"/>
    </item>
    <item>
      <title>Percona Operator for MySQL Is Now GA, More MySQL Options for the Community on Kubernetes</title>
      <link>https://percona.community/blog/2025/11/19/percona-operator-for-mysql-is-now-ga-more-mysql-options-for-the-community-on-kubernetes/</link>
      <guid>https://percona.community/blog/2025/11/19/percona-operator-for-mysql-is-now-ga-more-mysql-options-for-the-community-on-kubernetes/</guid>
      <pubDate>Wed, 19 Nov 2025 11:00:00 UTC</pubDate>
      <description>We’re excited to share that the new Percona Operator for MySQL (based on Percona Server for MySQL) is officially in General Availability (GA)!</description>
      <content:encoded>&lt;p&gt;We’re excited to share that the new &lt;strong&gt;&lt;a href="https://docs.percona.com/percona-operator-for-mysql/ps/index.html" target="_blank" rel="noopener noreferrer"&gt;Percona Operator for MySQL (based on Percona Server for MySQL)&lt;/a&gt;&lt;/strong&gt; is officially in General Availability (GA)!&lt;/p&gt;
&lt;p&gt;This release introduces native &lt;strong&gt;MySQL Group Replication&lt;/strong&gt; support for &lt;strong&gt;Kubernetes&lt;/strong&gt;, providing our community with another open-source option for running reliable, consistent MySQL clusters at scale.&lt;/p&gt;
&lt;p&gt;This is about more choices for the community. Each MySQL replication technology addresses different real-world needs, and now you can choose the one that best fits your workloads.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2025/11/introm.jpeg" alt="MySQL Operator for MySQL Intro" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h2 id="what-this-means-for-the-community"&gt;What This Means for the Community&lt;/h2&gt;
&lt;p&gt;With this release, Percona now supports two &lt;strong&gt;fully open-source MySQL Operators&lt;/strong&gt;:&lt;/p&gt;
&lt;h3 id="1-percona-operator-for-mysql-percona-server-for-mysql-new-and-ga"&gt;1. &lt;a href="https://docs.percona.com/percona-operator-for-mysql/ps/index.html" target="_blank" rel="noopener noreferrer"&gt;Percona Operator for MySQL (Percona Server for MySQL)&lt;/a&gt;, New and GA&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Group Replication (synchronous)&lt;/li&gt;
&lt;li&gt;Asynchronous replication (Technical Preview)&lt;/li&gt;
&lt;li&gt;Native MySQL experience&lt;/li&gt;
&lt;li&gt;Auto-failover&lt;/li&gt;
&lt;li&gt;Kubernetes-native design&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2-percona-xtradb-cluster-operator-pxc"&gt;2. &lt;a href="https://docs.percona.com/percona-operator-for-mysql/pxc/index.html" target="_blank" rel="noopener noreferrer"&gt;Percona XtraDB Cluster Operator (PXC)&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Galera-based synchronous replication&lt;/li&gt;
&lt;li&gt;Strong high availability&lt;/li&gt;
&lt;li&gt;Auto-failover&lt;/li&gt;
&lt;li&gt;Battle-tested for mission-critical workloads&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;These Operators complement each other; they are not replacements&lt;/strong&gt;. They give users the freedom to choose the right replication model for their business and technical priorities.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This GA release is a step in that direction, and we will continue publishing technical blog posts to explain when to use each Operator, how Group Replication works, and how this all fits into real-world Kubernetes environments&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2025/11/two-operators_hu_e3d8f6c73604ca02.png 480w, https://percona.community/blog/2025/11/two-operators_hu_d68c37cdeea667e6.png 768w, https://percona.community/blog/2025/11/two-operators_hu_300c39d76a6bdf0a.png 1400w"
src="https://percona.community/blog/2025/11/two-operators.png" alt="MySQL Operator for MySQL Intro Chart" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h2 id="call-for-community-testing-and-feedback"&gt;Call for Community Testing and Feedback&lt;/h2&gt;
&lt;p&gt;Asynchronous replication is now available in Technical Preview, we invite you to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Test it in your clusters&lt;/li&gt;
&lt;li&gt;Share your feedback&lt;/li&gt;
&lt;li&gt;Open GitHub issues&lt;/li&gt;
&lt;li&gt;Contribute docs or examples&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Your feedback will guide the next features we bring to the Operator.&lt;/p&gt;
&lt;h3 id="explore-percona-operator-for-mysql"&gt;Explore Percona Operator for MySQL:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.percona.com/percona-operator-for-mysql/ps/ReleaseNotes/Kubernetes-Operator-for-PS-RN1.0.0.html" target="_blank" rel="noopener noreferrer"&gt;Docs Percona Operator for MySQL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/percona/percona-server-mysql-operator" target="_blank" rel="noopener noreferrer"&gt;GitHub: Try it, test it, open issues, or contribute&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/posts/percona_the-percona-cloud-native-team-is-happy-activity-7396585512536473600-bFZR/?utm_source=share&amp;utm_medium=member_ios&amp;rcm=ACoAAA_uTn0BQWSwnqQ-mUMcVZ7icaVGYa4mlVs" target="_blank" rel="noopener noreferrer"&gt;Announcement Percona Blog&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded>
      <author>Edith Puclla</author>
      <category>MySQL</category>
      <category>Opensource</category>
      <category>Cloud</category>
      <category>Kubernetes</category>
      <category>Operators</category>
      <media:thumbnail url="https://percona.community/blog/2025/11/init_hu_93b48671fe9b894f.jpg"/>
      <media:content url="https://percona.community/blog/2025/11/init_hu_9b71a12a7bfbff67.jpg" medium="image"/>
    </item>
    <item>
      <title>MySQL Memory Usage: A Guide to Optimization</title>
      <link>https://percona.community/blog/2025/11/11/mysql-memory-usage-a-guide-to-optimization/</link>
      <guid>https://percona.community/blog/2025/11/11/mysql-memory-usage-a-guide-to-optimization/</guid>
      <pubDate>Tue, 11 Nov 2025 00:00:00 UTC</pubDate>
      <description>Struggling with MySQL memory spikes? Knowing how and where memory is allocated can make all the difference in maintaining a fast, reliable database. From global buffers to session-specific allocations, understanding the details of MySQL’s memory management can help you optimize performance and avoid slowdowns. Let’s explore the core elements of MySQL memory usage with best practices for trimming excess in demanding environments.</description>
      <content:encoded>&lt;p&gt;Struggling with MySQL memory spikes? Knowing how and where memory is allocated can make all the difference in maintaining a fast, reliable database. From global buffers to session-specific allocations, understanding the details of MySQL’s memory management can help you optimize performance and avoid slowdowns. Let’s explore the core elements of MySQL memory usage with best practices for trimming excess in demanding environments.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2025/11/mysql_memory_usage_graph_hu_182833534dd8f7b.png 480w, https://percona.community/blog/2025/11/mysql_memory_usage_graph_hu_565e9bc65d1675a2.png 768w, https://percona.community/blog/2025/11/mysql_memory_usage_graph_hu_d497e9659ccf47c0.png 1400w"
src="https://percona.community/blog/2025/11/mysql_memory_usage_graph.png" alt="Releem Dashboard - RAM usage" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h2 id="how-mysql-uses-memory"&gt;How MySQL Uses Memory&lt;/h2&gt;
&lt;p&gt;MySQL dynamically manages memory across several areas to process queries, handle connections, and optimize performance. The two primary areas of memory usage include:&lt;/p&gt;
&lt;h3 id="global-buffers"&gt;Global Buffers&lt;/h3&gt;
&lt;p&gt;These are shared by the entire MySQL server and include components like the InnoDB buffer pool, key buffer, and query cache. The InnoDB buffer pool is particularly memory-intensive, especially in data-heavy applications, as it stores frequently accessed data and indexes to speed up queries.&lt;/p&gt;
&lt;h3 id="connection-per-thread-buffers"&gt;Connection (per thread) Buffers&lt;/h3&gt;
&lt;p&gt;When a client connects, MySQL allocates memory specifically for that session. This includes sort buffers, join buffers, and temporary table memory. The more concurrent connections you have, the more memory is consumed. Session buffers are critical to monitor in high-traffic environments.&lt;/p&gt;
&lt;h2 id="why-mysql-memory-usage-might-surge"&gt;Why MySQL Memory Usage Might Surge&lt;/h2&gt;
&lt;p&gt;Memory spikes in MySQL often result from specific scenarios or misconfigurations. Here are a few examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;High Traffic with Large Connection Buffers&lt;/strong&gt;: A surge in concurrent connections can quickly exhaust memory if sort or join buffers are set too large.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Complex Queries&lt;/strong&gt;: Queries with large joins, subqueries, or extensive temporary table usage can temporarily allocate significant memory, especially when poorly optimized.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Oversized InnoDB Buffer Pool&lt;/strong&gt; : Setting the &lt;a href="https://releem.com/docs/mysql-performance-tuning/innodb_buffer_pool_size" target="_blank" rel="noopener noreferrer"&gt;InnoDB buffer pool size&lt;/a&gt; too large for the server’s available memory can trigger swapping, severely degrading database and server performance.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Large Temporary Tables&lt;/strong&gt; : When temporary tables exceed the in-memory limit ( &lt;a href="https://releem.com/docs/mysql-performance-tuning/tmp_table_size" target="_blank" rel="noopener noreferrer"&gt;tmp_table_size&lt;/a&gt; ), they are written to disk, consuming additional resources and slowing down operations.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inefficient Indexing&lt;/strong&gt; : A lack of proper indexes forces MySQL to perform full table scans, increasing memory and CPU usage for even moderately complex queries.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="best-practices-for-controlling-mysql-memory-usage"&gt;Best Practices for Controlling MySQL Memory Usage&lt;/h2&gt;
&lt;p&gt;When you notice MySQL using more memory than expected, consider the following strategies:&lt;/p&gt;
&lt;h3 id="1-set-limits-on-global-buffers"&gt;1. Set Limits on Global Buffers&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Configure &lt;a href="https://releem.com/docs/mysql-performance-tuning/innodb_buffer_pool_size" target="_blank" rel="noopener noreferrer"&gt;innodb_buffer_pool_size&lt;/a&gt; to 60-70% of available memory for InnoDB-heavy workloads. For smaller workloads, scale it down to avoid overcommitting memory.&lt;/li&gt;
&lt;li&gt;Keep &lt;a href="https://releem.com/docs/mysql-performance-tuning/innodb_log_buffer_size" target="_blank" rel="noopener noreferrer"&gt;innodb_log_buffer_size&lt;/a&gt; at a practical level (e.g., 16MB) unless write-heavy workloads demand more.&lt;/li&gt;
&lt;li&gt;Adjust &lt;a href="https://releem.com/docs/mysql-performance-tuning/key_buffer_size" target="_blank" rel="noopener noreferrer"&gt;key_buffer_size&lt;/a&gt; for MyISAM tables, ensuring it remains proportionate to table usage to avoid unnecessary memory allocation.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2-adjust-connection-buffer-sizes"&gt;2. Adjust Connection Buffer Sizes&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Reduce &lt;a href="https://releem.com/docs/mysql-performance-tuning/sort_buffer_size" target="_blank" rel="noopener noreferrer"&gt;sort_buffer_size&lt;/a&gt; and &lt;a href="https://releem.com/docs/mysql-performance-tuning/join_buffer_size" target="_blank" rel="noopener noreferrer"&gt;join_buffer_size&lt;/a&gt; to balance memory usage with query performance, especially in environments with high concurrency.&lt;/li&gt;
&lt;li&gt;Optimize &lt;a href="https://releem.com/docs/mysql-performance-tuning/tmp_table_size" target="_blank" rel="noopener noreferrer"&gt;tmp_table_size&lt;/a&gt; and &lt;a href="https://releem.com/docs/mysql-performance-tuning/max_heap_table_size" target="_blank" rel="noopener noreferrer"&gt;max_heap_table_size&lt;/a&gt; to control in-memory temporary table allocation and avoid excessive disk usage.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="3-fine-tune-table-caches"&gt;3. Fine-Tune Table Caches&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Adjust &lt;a href="https://releem.com/docs/mysql-performance-tuning/table_open_cache" target="_blank" rel="noopener noreferrer"&gt;table_open_cache&lt;/a&gt; to avoid bottlenecks while considering OS file descriptor limits.&lt;/li&gt;
&lt;li&gt;Configure &lt;a href="https://releem.com/docs/mysql-performance-tuning/table_definition_cache" target="_blank" rel="noopener noreferrer"&gt;table_definition_cache&lt;/a&gt; to manage table metadata efficiently, especially in environments with many tables or foreign key relationships.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="4-control-thread-cache-and-connection-limits"&gt;4. Control Thread Cache and Connection Limits&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Use &lt;a href="https://releem.com/docs/mysql-performance-tuning/thread_cache_size" target="_blank" rel="noopener noreferrer"&gt;thread_cache_size&lt;/a&gt; to reuse threads effectively and reduce overhead from frequent thread creation.&lt;/li&gt;
&lt;li&gt;Adjust &lt;a href="https://releem.com/docs/mysql-performance-tuning/thread_stack" target="_blank" rel="noopener noreferrer"&gt;thread_stack&lt;/a&gt; and &lt;strong&gt;net_buffer_length&lt;/strong&gt; to suit your workload while keeping memory usage scalable.&lt;/li&gt;
&lt;li&gt;Limit &lt;a href="https://releem.com/docs/mysql-performance-tuning/max_connections" target="_blank" rel="noopener noreferrer"&gt;max_connections&lt;/a&gt; to a level appropriate for your workload, preventing excessive session buffers from overwhelming server memory.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="5-track-temporary-table-usage"&gt;5. Track Temporary Table Usage&lt;/h3&gt;
&lt;p&gt;Monitor temporary table usage and reduce memory pressure by optimizing queries that rely on GROUP BY, ORDER BY, or UNION.&lt;/p&gt;
&lt;h3 id="6-use-mysql-memory-calculator"&gt;6. Use MySQL Memory Calculator&lt;/h3&gt;
&lt;p&gt;Incorporate tools like the &lt;a href="https://releem.com/tools/mysql-memory-calculator" target="_blank" rel="noopener noreferrer"&gt;MySQL Memory Calculator by Releem&lt;/a&gt; to estimate memory usage. Input your MySQL configuration values, and the calculator will provide real-time insights into maximum memory usage. This prevents overcommitting your server’s memory and helps allocate resources effectively.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2025/11/mysql_memory_usage_calc_hu_ab941316c0d444f0.png 480w, https://percona.community/blog/2025/11/mysql_memory_usage_calc_hu_b4753a1fcc563d24.png 768w, https://percona.community/blog/2025/11/mysql_memory_usage_calc_hu_49c89ec803b47b54.png 1400w"
src="https://percona.community/blog/2025/11/mysql_memory_usage_calc.png" alt="MySQL Memory Calculator" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h3 id="7-monitor-query-performance"&gt;7. Monitor Query Performance&lt;/h3&gt;
&lt;p&gt;High-memory-consuming queries, such as those with large joins or sorts, queries without indexes, can affect memory usage. Use &lt;a href="https://releem.com/query-analytics" target="_blank" rel="noopener noreferrer"&gt;Releem’s Query Analytics and Optimization feature&lt;/a&gt; to determine inefficient queries and gain insights on further tuning opportunities.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2025/11/mysql_memory_usage_query_analytics_hu_2e76ea22e4cb632d.png 480w, https://percona.community/blog/2025/11/mysql_memory_usage_query_analytics_hu_7f5e70dfeff93692.png 768w, https://percona.community/blog/2025/11/mysql_memory_usage_query_analytics_hu_a17d852be60cc80.png 1400w"
src="https://percona.community/blog/2025/11/mysql_memory_usage_query_analytics.png" alt="Releem Dashboard - Query Analytics" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h2 id="simplifying-mysql-memory-tuning-with-releem"&gt;Simplifying MySQL Memory Tuning with Releem&lt;/h2&gt;
&lt;p&gt;Releem takes the guesswork out of MySQL optimization by automatically analyzing your setup and suggesting configuration changes that align with your memory limits and performance needs. Whether you’re dealing with complex workloads or simply don’t have time for manual adjustments, Releem makes it easier to keep MySQL running smoothly.&lt;/p&gt;</content:encoded>
      <author>Roman Agabekov</author>
      <category>MySQL</category>
      <category>MariaDB</category>
      <category>Percona</category>
      <category>DBA Tools</category>
      <media:thumbnail url="https://percona.community/blog/2025/11/mysql_memory_usage_badge_hu_cc1a4044f70f1723.jpg"/>
      <media:content url="https://percona.community/blog/2025/11/mysql_memory_usage_badge_hu_a3243c5f91ca16a8.jpg" medium="image"/>
    </item>
    <item>
      <title>A thread through my 2025 Postgres events</title>
      <link>https://percona.community/blog/2025/11/10/thread-through-2025-pgconfs/</link>
      <guid>https://percona.community/blog/2025/11/10/thread-through-2025-pgconfs/</guid>
      <pubDate>Mon, 10 Nov 2025 07:00:00 UTC</pubDate>
      <description>I recently got back from PostgreSQL Conference Europe in Riga, marking the end of my conference activities for 2025. The speakers were great. The audience, for the Extensions Showcase on Community Day on Tuesday and my Kubernetes from the database out talk, were great. The event team was great. The singing at karaoke was terrible, but it’s supposed to be.</description>
      <content:encoded>&lt;p&gt;I recently got back from PostgreSQL Conference Europe in Riga, marking the end of my conference activities for 2025. The speakers were great. The audience, for the Extensions Showcase on Community Day on Tuesday and my Kubernetes from the database out talk, were great. The event team was great. The singing at karaoke was terrible, but it’s supposed to be.&lt;/p&gt;
&lt;p&gt;After attending a good few events this year, starting with CERN PGDay in mid-January, I wanted to write something about more than just the most recent event. I see a common thread across presentations and sessions at a number of events over the year, that is, scale-out Postgres and particularly, its use in non-profit scientific environments.&lt;/p&gt;
&lt;h3 id="the-beginning-and-end-users"&gt;The (beginning and) end users&lt;/h3&gt;
&lt;p&gt;Far fewer data processing challenges require pooling the resources of many physical servers these days, with servers getting bigger and storage faster. Scientific data analysis and managing large, complex scientific facilities still do. I saw three presentations on this: Rafal Kulaga, Antonin Kveton and Martin Zemko’s on &lt;a href="https://indico.cern.ch/event/1471762/contributions/6280212/" target="_blank" rel="noopener noreferrer"&gt;managing CERN’s SCADA data&lt;/a&gt;; Daniel Krefl and Krzysztof Nienartowicz at CERN on &lt;a href="https://indico.cern.ch/event/1471762/contributions/6280216/" target="_blank" rel="noopener noreferrer"&gt;how Sendai queries variable star data&lt;/a&gt;; and Jaoquim Oliveira in Riga on &lt;a href="https://www.postgresql.eu/events/pgconfeu2025/schedule/session/7138-from-stars-to-storage-engines-migrating-big-science-workloads-beyond-greenplum/" target="_blank" rel="noopener noreferrer"&gt;managing the European Space Agency’s (ESA’s) survey mission data&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I admit a fondness for ESA’s GAIA catalog dataset. After I was lucky enough to do a proof of concept project on joining it with other catalog data, it has provided significant intellectual interest. Don’t let me get started on the possible ways to optimise computationally expensive inequality joins on horribly skewed data, unless you really care about the problem. My interest in a dataset discussed in two of these talks is not why the thread connecting them is worth commenting on. All three presentations had a lot of content on selecting or developing database technologies for the work they were doing. That’s worth discussing a bit further.&lt;/p&gt;
&lt;h3 id="getting-the-details-right"&gt;Getting the details right&lt;/h3&gt;
&lt;p&gt;The thread of sharded, scale out, or Massively Parallel Processing (MPP) Postgres connects end user stories at my first event of the year and my last, along with stories of building this software at events in between. At PGConf.dev in Montreal David Wein gave a very condensed explanation of how AWS’s Aurora Limitless handles distributed snapshot isolation (&lt;a href="https://www.youtube.com/watch?v=UrRkHSxP2xE&amp;t=378s" target="_blank" rel="noopener noreferrer"&gt;watch the lightning talk at on YouTube&lt;/a&gt;), there was also an unconference session on handling the issue in core Postgres the next day. For an in-depth explanation of of what the distributed snapshot problem is and how it may be addressed, see &lt;a href="https://www.postgresql.eu/events/pgconfeu2024/schedule/session/5710-high-concurrency-distributed-snapshots/" target="_blank" rel="noopener noreferrer"&gt;Ants Aasma’s talk from PGConf.EU 2024&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The organisations with the data are looking for open source software solutions and bumping into issues around open core licensing, project contribution breadth, project activity levels, project governance. The Postgres developer community is working on the knottiest of the problems in this space, trying to get it absolutely right. In the mean-time, various forks and extensions are delivering useful functionality for the owners of these big, complex datasets.
Useful, but could do better&lt;/p&gt;
&lt;p&gt;If this were working out for everyone, there wouldn’t be a story to tell. Sednai are building Potgres-XZ, which builds on TBase, which built on Postgres-XL. The ESAC Science Data Centre (ESDC) is facing a decision between two single-vendor projects, where one vendor doesn’t provide support for on-premises deployments. CERN procurement sought written assurances over license terms for TimescaleDB, since the CERN facilities organisation may be viewed as a service provider to their hosted scientific projects.&lt;/p&gt;
&lt;p&gt;This pattern of licenses built specifically to avoid “AWS stealing our innovation/lunch/…”, (and it is always AWS set up as the bogeyman in these stories), is particularly unfortunate here, because it just isn’t true for Postgres. AWS, and Azure, employ big teams of community contributors to work on open source Postgres. The progress on statistics management, asynchronous IO, and vacuum in Postgres 18 are, among others, thanks to these teams’ efforts.&lt;/p&gt;
&lt;p&gt;No matter how positive the involvement of the hyperscalers may be for Postgres, there are organisations who will prefer to run their own databases. On-premises hosting is a clear choice for organisations with big facilities capabilities, capital-centric budgeting, extreme requirements and predictable, always on workloads. Many of these organisations are publicly funded scientific projects. It would be great if there were broad-based open source solutions to meet their data management needs.&lt;/p&gt;
&lt;h3 id="doing-better-together"&gt;Doing better, together&lt;/h3&gt;
&lt;p&gt;At PGConf in Riga the Percona team took a few, early steps towards building a joint effort to deliver the components of such a solution. I hope that the big, open managers of structured scientific data (or their subcontractors, depending on their engagement model) and a few vendors can come together to build event data compression, columnar storage, and all the other bits which can be implemented as extensions.&lt;/p&gt;
&lt;p&gt;The current Postgres extensions and forks for scale out systems were built on older versions of Postgres, so they had to build features which now exist in core Postgres. Their implementation of partitioning, for instance, differs subtly from the capabilities now available in modern Postgres. As feature-specific extensions can take over capabilities which are currently intertwined with sharding (like compression in Timescale or columnar storage in Citus), users will be less locked in to vertical stacks of features, some useful to them and some not. Simple sharding can then become a proxy (like pgDog), an automation on DDL on a gateway server or even a core Postgres feature.&lt;/p&gt;
&lt;p&gt;Which leaves those special cases where moving data between shards during execution is key to performance. This is mattering less with ever bigger servers, improving Postgres parallelism and tools like DuckDB - but when it matters it still really matters. Here the sons of the ‘plum - CloudberryDB and WarehousePG, forked from Greenplum when it closed source - work their magic (hat tip to Jimmy Angelakos for the “the ‘plum” contraction). Managing that particular capability will always be a big, complex code base. If the patches carried to make it happen shrink as Postgres and extensions fill the gap, we’ll have a more sustainable route to all good database things being openly available.&lt;/p&gt;</content:encoded>
      <author>Alastair Turner</author>
      <category>PostgreSQL</category>
      <category>Opensource</category>
      <category>pg_alastair</category>
      <category>Community</category>
      <media:thumbnail url="https://percona.community/blog/2025/11/cover-map-blue_hu_209117837932fc65.jpg"/>
      <media:content url="https://percona.community/blog/2025/11/cover-map-blue_hu_bdfd6ce3de2b5882.jpg" medium="image"/>
    </item>
    <item>
      <title>Encryption support in PMM Dump</title>
      <link>https://percona.community/blog/2025/10/30/encryption-support-in-pmm-dump/</link>
      <guid>https://percona.community/blog/2025/10/30/encryption-support-in-pmm-dump/</guid>
      <pubDate>Thu, 30 Oct 2025 11:00:00 UTC</pubDate>
      <description>The pmm-dump client utility performs a logical backup of the performance metrics collected by the PMM Server and imports them into a different PMM Server instance. PMM Dump allows you to share monitoring data collected by your PMM server with the Percona Support team securely.</description>
      <content:encoded>&lt;p&gt;The &lt;code&gt;pmm-dump&lt;/code&gt; client utility performs a logical backup of the performance metrics collected by the PMM Server and imports them into a different PMM Server instance. PMM Dump allows you to share monitoring data collected by your PMM server with the Percona Support team securely.&lt;/p&gt;
&lt;p&gt;Up until now dumps, created by the tool, were not encrypted. It was possible to encrypt them after they are done but this required additional actions from the user.&lt;/p&gt;
&lt;p&gt;Starting from the upcoming PMM Dump version 0.8.0-ga released on October 29, 2025, dumps are encrypted by default.&lt;/p&gt;
&lt;h2 id="key-points"&gt;Key points&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Dump files are encrypted by default with AES-256-based encryption.&lt;/li&gt;
&lt;li&gt;An auto-generated password is produced for each encrypted dump; it is printed at the end of the export operation or can be written to a file with &lt;code&gt;--pass-filepath&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;You can provide a custom password with &lt;code&gt;--pass&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Disable encryption with &lt;code&gt;--no-encryption&lt;/code&gt; only when you understand the risks.&lt;/li&gt;
&lt;li&gt;By default, for encrypted dumps, export logging to STDOUT is suppressed; use &lt;code&gt;--no-just-key&lt;/code&gt; to override.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="why-this-matters"&gt;Why this matters&lt;/h2&gt;
&lt;p&gt;Encrypting PMM dumps prevents accidental exposure of monitoring and query data that may contain sensitive information (query text, hostnames, metrics). It brings PMM Dump in line with secure data-handling best practices and simplifies safe sharing with Percona Support.&lt;/p&gt;
&lt;h2 id="quick-examples"&gt;Quick examples&lt;/h2&gt;
&lt;p&gt;Export (encryption enabled by default):&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pmm-dump export --pmm-url='https://admin:admin@127.0.0.1' --allow-insecure-certs
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Password: ****************
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ ls pmm-dump-&lt;TIMESTAMP&gt;.tar.gz.enc&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Provide a custom password:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-1"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pmm-dump export --pmm-url='https://admin:admin@127.0.0.1' --pass='My$trongP@ss'&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Save auto-generated password to file:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-2" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-2"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pmm-dump export --pmm-url='https://admin:admin@127.0.0.1' --pass-filepath=/tmp/pmm-dump.pass&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Disable encryption (not recommended):&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-3" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-3"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pmm-dump export --pmm-url='https://admin:admin@127.0.0.1' --no-encryption&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Import an encrypted dump:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-4" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-4"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pmm-dump import --pmm-url='https://admin:admin@127.0.0.1' --allow-insecure-certs \
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;--dump-path=pmm-dump-1758017090.tar.gz.enc --pass='My$trongP@ss'&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Decrypt an encrypted dump (if needed):&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-5" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-5"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ openssl enc -d -aes-256-ctr -pbkdf2 -in dump.tar.gz.enc -out dump.tar.gz&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="recommendations"&gt;Recommendations&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Prefer leaving encryption enabled.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;--pass-filepath&lt;/code&gt; to store passwords securely rather than relying on terminal output.&lt;/li&gt;
&lt;li&gt;Transfer encrypted archives over secure channels (SCP/SFTP) and share passwords via secure out-of-band channels.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="availability"&gt;Availability&lt;/h2&gt;
&lt;p&gt;Encryption support is included starting in the recent PMM Dump 0.8.0-ga release. Check your PMM Dump version (&lt;code&gt;pmm-dump version&lt;/code&gt;) and the docs for exact version details.&lt;/p&gt;
&lt;h2 id="additional-information"&gt;Additional information&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://percona.com/get/pmm-dump" target="_blank" rel="noopener noreferrer"&gt;Latest version for x86_64 platforms&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Percona-Lab/percona-on-arm/releases/tag/v0.12" target="_blank" rel="noopener noreferrer"&gt;ARM binaries&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.percona.com/pmm-dump-documentation/" target="_blank" rel="noopener noreferrer"&gt;PMM Dump Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/percona/pmm-dump" target="_blank" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded>
      <author>Sveta Smirnova</author>
      <category>PMM Dump</category>
      <category>PMM</category>
      <category>monitoring</category>
      <media:thumbnail url="https://percona.community/blog/2025/10/Sveta-PMM-Dump_hu_4169866126775b73.jpg"/>
      <media:content url="https://percona.community/blog/2025/10/Sveta-PMM-Dump_hu_b118ee6552823d62.jpg" medium="image"/>
    </item>
    <item>
      <title>Audit Log Filters Part II</title>
      <link>https://percona.community/blog/2025/10/08/audit-log-filters-part-ii/</link>
      <guid>https://percona.community/blog/2025/10/08/audit-log-filters-part-ii/</guid>
      <pubDate>Wed, 08 Oct 2025 00:00:00 UTC</pubDate>
      <description>In my first post on the MySQL 8.4 Audit Log Filter component, I covered how to install the component and configure a basic filter that captures all events. The Audit Log Filter framework offers a highly granular and configurable auditing mechanism, enabling administrators to log specific events based on criteria such as user, host, or event type. This selective approach enhances observability, supports compliance initiatives, and minimizes unnecessary logging overhead.</description>
      <content:encoded>&lt;p&gt;In my first post on the &lt;a href="https://percona.community/blog/2025/09/18/audit-log-filter-component/" target="_blank" rel="noopener noreferrer"&gt;MySQL 8.4 Audit Log Filter component&lt;/a&gt;, I covered how to install the component and configure a basic filter that captures all events. The Audit Log Filter framework offers a highly granular and configurable auditing mechanism, enabling administrators to log specific events based on criteria such as user, host, or event type. This selective approach enhances observability, supports compliance initiatives, and minimizes unnecessary logging overhead.&lt;/p&gt;
&lt;p&gt;In this follow-up, we’ll take a deeper technical look at defining and optimizing audit log filters to capture only the most relevant database activities—delivering actionable audit data while significantly reducing noise and log volume.&lt;/p&gt;
&lt;h3 id="example-1"&gt;Example 1&lt;/h3&gt;
&lt;p&gt;Audit all events:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;SELECT audit_log_filter_set_filter('log_all_events', '{
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "filter": {"log": true}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}');&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Once this filter is created and assigned to a user (for example, with SELECT audit_log_filter_set_user(’%’, ’log_all_events’);), every database event triggered by that user—or by all users if % is used—will be written to the audit log file.&lt;/p&gt;
&lt;p&gt;In short:&lt;/p&gt;
&lt;p&gt;This is the most permissive audit configuration possible. It’s typically used:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;As a baseline test to verify that the audit log component is working.&lt;/li&gt;
&lt;li&gt;In diagnostic or forensic scenarios where full visibility is required.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For production environments, however, it’s recommended to create more selective filters (e.g., by event class, command type, or user) to reduce log volume and improve performance. Which we will go into more detail in the upcoming examples.&lt;/p&gt;
&lt;h3 id="example-2"&gt;Example 2&lt;/h3&gt;
&lt;p&gt;Log table access:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-1"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;select audit_log_filter_set_filter('log_table_access', '{
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "filter": {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "class": [
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; { "name": "table_access" },
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; { "name": "connection" },
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; { "name": "general" }
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}');&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h4 id="included-event-classes"&gt;Included Event Classes&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;table_access
Logs events when MySQL reads from or writes to tables.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Useful for tracking which users or applications are accessing specific tables.&lt;/li&gt;
&lt;li&gt;Helps in auditing data access patterns and detecting unauthorized data reads/writes.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;connection
Logs connection-related events such as user logins, logouts, and failed authentication attempts.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Important for tracking session activity and security auditing.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;general
Logs general query execution events—like statements sent to the server (e.g., SELECT, INSERT, UPDATE, etc.).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Useful for general SQL activity auditing.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="what-it-does-functionally"&gt;What It Does Functionally&lt;/h4&gt;
&lt;p&gt;After this filter is defined and assigned to a user or host (for example, with
SELECT audit_log_filter_set_user(’%’, ’log_table_access’);), MySQL will only log events that fall into one of these three classes.&lt;/p&gt;
&lt;p&gt;All other event types—like administrative commands, stored program executions, or system-level actions—will be excluded from the audit log.&lt;/p&gt;
&lt;h4 id="why-use-this-filter"&gt;Why use this filter&lt;/h4&gt;
&lt;p&gt;This configuration strikes a balance between completeness and efficiency:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Captures key operational and access-related activity.&lt;/li&gt;
&lt;li&gt;Avoids excessive log volume from irrelevant events.&lt;/li&gt;
&lt;li&gt;Suitable for data access auditing, security monitoring, and compliance logging.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In short, log_table_access provides targeted visibility into table usage, connections, and general query activity—ideal for environments where tracking who accessed what data is more important than recording every internal event.&lt;/p&gt;
&lt;h3 id="example-3"&gt;Example 3&lt;/h3&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-2" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-2"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;SELECT audit_log_filter_set_filter('log_minimum', '{
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "filter": {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "class":
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; [ { "name": "connection" }, { "name": "table_access", "event": [
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; { "name": "delete"}, { "name": "insert"}, { "name": "update"} ]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; } ]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}');&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h4 id="included-event-classes-1"&gt;Included Event Classes&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;“class”: “connection”
&lt;ul&gt;
&lt;li&gt;Logs all connection-level events:&lt;/li&gt;
&lt;li&gt;connect: when a user logs in.&lt;/li&gt;
&lt;li&gt;disconnect: when a session ends.&lt;/li&gt;
&lt;li&gt;Failed logins and other connection-related actions.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Purpose: provides visibility into who connected, from where, and when.&lt;/p&gt;
&lt;ol start="2"&gt;
&lt;li&gt;“class”: “table_access” with “event”:
&lt;ul&gt;
&lt;li&gt;Limits logging to specific table access events:
&lt;ul&gt;
&lt;li&gt;“delete” when rows are deleted.&lt;/li&gt;
&lt;li&gt;“insert” when new rows are added.&lt;/li&gt;
&lt;li&gt;“update” when existing rows are modified.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Read operations (like SELECT) and metadata queries are excluded.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="what-it-does-functionally-1"&gt;What It Does Functionally&lt;/h4&gt;
&lt;p&gt;Once assigned to a user or host (e.g.
SELECT audit_log_filter_set_user(’%’, ’log_minimum’);), this filter will produce audit entries only when:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A user connects or disconnects from MySQL.&lt;/li&gt;
&lt;li&gt;A user performs a DML (Data Manipulation Language) operation that changes data in a table.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All other events — such as simple SELECT queries, schema reads, or administrative commands — will be ignored.&lt;/p&gt;
&lt;h4 id="why-use-this-filter-1"&gt;Why Use This Filter&lt;/h4&gt;
&lt;p&gt;This is a minimalist, high-value audit configuration. It’s designed to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Track security-relevant activity (connections and data changes).&lt;/li&gt;
&lt;li&gt;Meet compliance requirements with low performance overhead.&lt;/li&gt;
&lt;li&gt;Prevent excessive logging and disk usage.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In Short log_minimum is an efficient auditing strategy for production environments where you only need to know:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Who accessed the database, and&lt;/li&gt;
&lt;li&gt;What data they changed.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It gives you essential accountability and change tracking without the overhead of logging every read or administrative event.&lt;/p&gt;
&lt;h3 id="example-4"&gt;Example 4&lt;/h3&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-3" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-3"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;SELECT audit_log_filter_set_filter('log_connections', '{
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "filter": {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "class": [
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; { "name": "connection",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "event": [
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; { "name": "connect"},
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; { "name": "disconnect"}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}');&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h4 id="included-event-classes-2"&gt;Included Event Classes&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;“class”: “connection”&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;This class captures events related to user sessions and authentication.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;“event”: [“connect”, “disconnect”]&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;connect, Logged when a client establishes a connection to the MySQL server.
Includes details like username, host, client program, IP address, and connection method.&lt;/li&gt;
&lt;li&gt;disconnect, Logged when that client session ends or times out.
Useful for tracking session duration and identifying abnormal terminations.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Important Note on pre_authenticate Events&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The pre_authenticate events are not included in the examples above.&lt;/li&gt;
&lt;li&gt;These events occur before the MySQL server has received authentication information from the client—meaning no user account details are available at this stage of the connection lifecycle. Because of that, if a filter that includes pre_authenticate events is assigned to a specific user (rather than a wildcard like %) using audit_log_filter_set_user(), those events will not be filtered or logged.&lt;/li&gt;
&lt;li&gt;This behavior often leads to confusion, as users may expect pre_authenticate events to appear in user-specific logs. Several reports and support cases have been filed on this topic, but it is expected behavior due to the timing of authentication during connection initialization.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="why-use-this-filter-2"&gt;Why Use This Filter&lt;/h4&gt;
&lt;p&gt;This filter is particularly useful when you need to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Monitor user logins and logouts without recording query activity.&lt;/li&gt;
&lt;li&gt;Audit connection patterns (e.g., who connected, from where, and when).&lt;/li&gt;
&lt;li&gt;Maintain minimal log size and low overhead.&lt;/li&gt;
&lt;li&gt;Support security investigations or session tracking without performance impact.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In short the log_connections filter provides a focused, low-overhead auditing strategy that records only connection lifecycle events. It’s ideal for environments where you primarily need to know who connected to the database, when, and from where without capturing every SQL statement or table access.&lt;/p&gt;
&lt;h3 id="example-5"&gt;Example 5&lt;/h3&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-4" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-4"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;SELECT audit_log_filter_set_filter('log_full_table_access', '{
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "filter": {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "class": [
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "name": "connection",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "event": [
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; { "name": "connect"},
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; { "name": "disconnect"}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "name": "query",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "event": [
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "name": "start",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "log": {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "or": [
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; { "field": { "name": "sql_command_id", "value": "select"} },
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; { "field": { "name": "sql_command_id", "value": "insert"} },
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; { "field": { "name": "sql_command_id", "value": "update"} },
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; { "field": { "name": "sql_command_id", "value": "delete"} },
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; { "field": { "name": "sql_command_id", "value": "truncate"} },
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; { "field": { "name": "sql_command_id", "value": "create_table"} },
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; { "field": { "name": "sql_command_id", "value": "alter_table"} },
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; { "field": { "name": "sql_command_id", "value": "drop_table"} }
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}');&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This statement defines a MySQL Audit Log Filter called log_full_table_access, which is designed to capture both connection activity and all table-related SQL operations — including reads, writes, and schema changes. It provides broad visibility into how users interact with tables in the database while filtering out unrelated or low-value events.&lt;/p&gt;
&lt;h4 id="included-event-classes-3"&gt;Included Event Classes&lt;/h4&gt;
&lt;p&gt;After assigning it to users or hosts (e.g.
SELECT audit_log_filter_set_user(’%’, ’log_full_table_access’);), MySQL will log:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Connection lifecycle events (connect, disconnect)&lt;/li&gt;
&lt;li&gt;All DML statements (SELECT, INSERT, UPDATE, DELETE, TRUNCATE)&lt;/li&gt;
&lt;li&gt;All DDL statements that create, modify, or remove tables (CREATE TABLE, ALTER TABLE, DROP TABLE)&lt;/li&gt;
&lt;li&gt;A full list of SQL_COMMANDS can be obtained from:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-5" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-5"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;SELECT NAME FROM performance_schema.setup_instruments WHERE NAME LIKE 'statement/sql/%' ORDER BY NAME;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-6" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-6"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+-----------------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| NAME |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+-----------------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| statement/sql/alter_db |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| statement/sql/alter_event |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| statement/sql/alter_function |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| statement/sql/alter_instance |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| statement/sql/alter_procedure |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| statement/sql/alter_resource_group |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| statement/sql/alter_server |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| statement/sql/alter_table |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| statement/sql/alter_tablespace |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| statement/sql/alter_user |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| statement/sql/alter_user_default_role |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| statement/sql/analyze |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| statement/sql/assign_to_keycache |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| statement/sql/begin |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| statement/sql/binlog |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| statement/sql/call_procedure |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| statement/sql/change_db |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| statement/sql/change_repl_filter |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| statement/sql/change_replication_source |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| statement/sql/check |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| statement/sql/checksum |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| statement/sql/commit |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| statement/sql/create_compression_dictionary |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[...]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+-----------------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;168 rows in set (0.07 sec)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Everything else — administrative commands, stored procedure calls, replication control, etc. — will be excluded.&lt;/p&gt;
&lt;h4 id="why-use-this-filter-3"&gt;Why Use This Filter&lt;/h4&gt;
&lt;p&gt;This filter offers a comprehensive audit view of how users interact with data and schema structures — perfect for compliance, forensic analysis, or access accountability.
It ensures that all table reads, writes, and structure changes are tracked without overwhelming the log with irrelevant internal events.&lt;/p&gt;
&lt;p&gt;In Short, log_full_table_access provides a broad but targeted audit scope:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tracks connections for user session context.&lt;/li&gt;
&lt;li&gt;Logs all table-level operations, both data and schema-related.&lt;/li&gt;
&lt;li&gt;Delivers complete visibility into how data is accessed and changed, making it ideal for security auditing and regulatory compliance scenarios.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="final-summary"&gt;Final Summary&lt;/h3&gt;
&lt;p&gt;The MySQL 8.4 Audit Log Filter component provides a powerful and flexible framework for controlling how database activity is captured and logged. By allowing administrators to define granular filters based on event class, event type, user, or host, it transforms auditing from an all-or-nothing process into a precisely tuned observability tool.&lt;/p&gt;
&lt;p&gt;In this post, we explored a range of filter examples—from the most permissive (log_all_events) to more focused configurations like log_minimum, log_connections, and log_full_table_access. Each serves a different operational or compliance purpose:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;log_all_events – Captures every event for baseline validation or forensic debugging.&lt;/li&gt;
&lt;li&gt;log_table_access – Balances visibility and performance by logging table, connection, and general query activity.&lt;/li&gt;
&lt;li&gt;log_minimum – Targets critical actions such as connections and data modifications, providing essential accountability with minimal overhead.&lt;/li&gt;
&lt;li&gt;log_connections – Focuses solely on login and logout events, ideal for lightweight session auditing.&lt;/li&gt;
&lt;li&gt;log_full_table_access – Delivers comprehensive insight into all table-level DML and DDL operations along with connection tracking, suitable for compliance and change auditing.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By tailoring filters to specific operational needs, administrators can significantly reduce log volume, improve performance, and focus on high-value security and compliance events. The result is a leaner, more informative audit log that provides actionable insight into how users and applications interact with your MySQL environment—without the burden of unnecessary data.&lt;/p&gt;
&lt;h3 id="reference"&gt;Reference&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.percona.com/percona-server/8.4/audit-log-filter-overview.html" target="_blank" rel="noopener noreferrer"&gt;Audit Log Filter Overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.percona.com/percona-server/8.4/write-filter-definitions.html" target="_blank" rel="noopener noreferrer"&gt;Write audit_log_filter definitons&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.percona.com/percona-server/8.4/audit-log-filter-variables.html#audit-log-filter-functions" target="_blank" rel="noopener noreferrer"&gt;Audit log filter functions, options, and variables&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="special-thanks"&gt;Special Thanks&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Yura Sorokin&lt;/strong&gt; for the collaboration that made this blog post possible.&lt;/p&gt;</content:encoded>
      <author>Wayne Leutwyler</author>
      <category>Opensource</category>
      <category>Audit Log</category>
      <category>filter</category>
      <category>component</category>
      <category>MySQL</category>
      <category>Community</category>
      <category>Percona Server</category>
      <category>PXC</category>
      <media:thumbnail url="https://percona.community/blog/2025/10/audit-log-filters_hu_a18f51ff6cb4cc34.jpg"/>
      <media:content url="https://percona.community/blog/2025/10/audit-log-filters_hu_c2edeb7c9bc7446a.jpg" medium="image"/>
    </item>
    <item>
      <title>Audit Log Filter Component</title>
      <link>https://percona.community/blog/2025/09/18/audit-log-filter-component/</link>
      <guid>https://percona.community/blog/2025/09/18/audit-log-filter-component/</guid>
      <pubDate>Thu, 18 Sep 2025 00:00:00 UTC</pubDate>
      <description>The audit log filter component in MySQL 8.4 provides administrators with a powerful mechanism for auditing database activity at a fine-grained level. While it offers significant flexibility—such as selectively logging events based on users, hosts, or event types—it can also be challenging to understand and configure correctly.</description>
      <content:encoded>&lt;p&gt;The audit log filter component in MySQL 8.4 provides administrators with a powerful mechanism for auditing database activity at a fine-grained level. While it offers significant flexibility—such as selectively logging events based on users, hosts, or event types—it can also be challenging to understand and configure correctly.&lt;/p&gt;
&lt;p&gt;In this article, we will examine how the audit log filter component works, walk through its core concepts, and share practical tips for configuring and managing audit filters effectively. Our goal is to help you leverage this feature to improve observability, meet compliance requirements, and reduce unnecessary logging overhead.&lt;/p&gt;
&lt;h3 id="enabling-audit-log-filter"&gt;Enabling Audit Log Filter&lt;/h3&gt;
&lt;p&gt;We will be using Percona Server 8.4.4 or higher in the examples below. First, we need to enable the audit log filter component. To install the audit log filter component, we need to run the following command:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mysql -u root -p &lt; /usr/share/percona-server/mysql/share/audit_log_filter_linux_install.sql&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Verify that the audit log filter component is enabled by running:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-1"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;select * from mysql.component;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+--------------+--------------------+-----------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| component_id | component_group_id | component_urn |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+--------------+--------------------+-----------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| 2 | 1 | file://component_audit_log_filter |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+--------------+--------------------+-----------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;1 row in set (0.00 sec)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Installing the component creates two new tables in the mysql system database: audit_log_filter and audit_log_user. These tables store the audit log filter definitions and the user-to-filter mappings. Together, they are referred to as the audit log filter tables.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-2" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-2"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+------------------------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| Tables_in_mysql |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+------------------------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| audit_log_filter |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| audit_log_user |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+------------------------------------------------------+&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Although the configuration is persisted in these tables, they are not usually modified directly with INSERT or UPDATE statements. Instead, MySQL provides built-in functions such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;audit_log_filter_set_filter()&lt;/li&gt;
&lt;li&gt;audit_log_filter_set_user()&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To manage filter definitions and user assignments safely.&lt;/p&gt;
&lt;p&gt;Configure the my.cnf file to define the desired audit log output format and specify the location of the audit.log file. In the example below, the log format is set to JSON, but other formats (e.g., NEW or OLD) can also be configured depending on your requirements. The audit log file can be written to any path accessible to the MySQL server process.&lt;/p&gt;
&lt;p&gt;Example Changes:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-3" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-3"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[mysqld]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# auditlog
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;audit_log_filter.format=JSON
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;audit_log_filter.file=/var/lib/mysql/audit.log&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Restart mysql server to apply the changes:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-4" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-4"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl restart mysqld&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The audit log filter install is complete. Now we can start using the audit log filter component.&lt;/p&gt;
&lt;h3 id="creating-audit-log-filters"&gt;Creating Audit Log Filters&lt;/h3&gt;
&lt;p&gt;The audit log filter component in MySQL 8.4 provides fine-grained control over database auditing. Instead of logging all events indiscriminately, administrators can define audit log filters, which are rule sets that determine exactly which events should be captured and which should be excluded.&lt;/p&gt;
&lt;p&gt;This allows you to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Log only the activity relevant to security, compliance, or troubleshooting.&lt;/li&gt;
&lt;li&gt;Reduce unnecessary noise and audit log volume.&lt;/li&gt;
&lt;li&gt;Apply different filters to specific users, hosts, or accounts for tailored auditing.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Because filters can be customized and assigned at the user or host level, the audit log filter component offers both flexibility and efficiency, making it a powerful mechanism for monitoring and securing database activity while minimizing overhead.&lt;/p&gt;
&lt;p&gt;Lets create a rule that will log all events:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-5" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-5"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;SELECT audit_log_filter_set_filter('log_all_events', '{ "filter": {"log": true } }');&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Lets assign the rule to the user:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-6" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-6"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;SELECT audit_log_filter_set_user('%', 'log_all_events');
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;SELECT audit_log_filter_flush();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Now all users will have all their events logged.&lt;/p&gt;
&lt;p&gt;Before proceeding, ensure that the jq utility is installed on your system. The installation commands provided in the examples below are compatible with both RHEL-based and Debian-based distributions.&lt;/p&gt;
&lt;p&gt;RHEL builds&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-7" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-7"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo yum install jq&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Debian builds&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-8" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-8"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt install jq&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;To validate that the audit log filter is functioning as expected, we can inspect the raw contents of the audit.log file. Since the log entries are in JSON format, using jq provides an efficient way to query and extract specific events. For example, to filter and display only connection-related events, run:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-9" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-9"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat audit.log | jq '.[]|select(.class=="connection")'&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This command streams the log file, parses the JSON structure, and returns only entries where the “class” field is equal to “connection”. This approach allows for targeted analysis, making it easier to verify filter behavior, troubleshoot issues, or monitor specific event classes without manually parsing large volumes of log data.&lt;/p&gt;
&lt;p&gt;Example Output:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-10" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-10"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "timestamp": "2025-07-24 07:18:00",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "id": 27110,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "class": "connection",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "event": "connect",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "connection_id": 415,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "account": {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "user": "wayne",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "host": "localhost"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "login": {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "user": "wayne",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "os": "",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "ip": "",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "proxy": ""
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "connection_data": {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "connection_type": "socket",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "status": 0,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "db": ""
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "connection_attributes": {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "_pid": "717914",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "_platform": "aarch64",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "_os": "Linux",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "_client_name": "libmysql",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "os_user": "wayne",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "_client_version": "8.4.5-5",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "program_name": "mysql"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;I’ll cover more advanced filter configurations in a follow-up post—stay tuned for Part 2 of the Audit Log Filter Component series.&lt;/p&gt;
&lt;p&gt;In summary, the audit log filter component in MySQL 8.4 provides administrators with a flexible and fine-grained approach to database auditing. By tailoring filters to specific users, hosts, and event types, you can ensure that only the most relevant activity is logged, making it easier to meet compliance requirements while reducing overhead. With proper configuration and careful use of filters, you can transform the audit log from a noisy data dump into a precise monitoring tool that strengthens both security and observability in your MySQL environment.&lt;/p&gt;</content:encoded>
      <author>Wayne Leutwyler</author>
      <category>Opensource</category>
      <category>Audit Log</category>
      <category>filter</category>
      <category>component</category>
      <category>MySQL</category>
      <category>Community</category>
      <category>Percona Server</category>
      <category>PXC</category>
      <media:thumbnail url="https://percona.community/blog/2025/09/audit-log-filter_hu_a21f707e924f3dd4.jpg"/>
      <media:content url="https://percona.community/blog/2025/09/audit-log-filter_hu_555048615921e7a5.jpg" medium="image"/>
    </item>
    <item>
      <title>GitOps Journey: Part 4 – Observability and Monitoring with Coroot in Kubernetes</title>
      <link>https://percona.community/blog/2025/07/22/gitops-journey-part-4-observability-and-monitoring-with-coroot-in-kubernetes/</link>
      <guid>https://percona.community/blog/2025/07/22/gitops-journey-part-4-observability-and-monitoring-with-coroot-in-kubernetes/</guid>
      <pubDate>Tue, 22 Jul 2025 00:01:00 UTC</pubDate>
      <description>Our PostgreSQL cluster is running, and the demo app is generating traffic — but we have no visibility into the health of the Kubernetes cluster, services, or applications.</description>
      <content:encoded>&lt;p&gt;Our PostgreSQL cluster is running, and the demo app is generating traffic — but we have no visibility into the health of the Kubernetes cluster, services, or applications.&lt;/p&gt;
&lt;p&gt;What happens when disk space runs out? What if the database is under heavy load and needs scaling? What if errors are buried in application logs? How busy are the network and storage layers? What’s the actual cost of the infrastructure?&lt;/p&gt;
&lt;p&gt;This is where &lt;a href="https://coroot.com/" target="_blank" rel="noopener noreferrer"&gt;Coroot&lt;/a&gt; comes in.&lt;/p&gt;
&lt;p&gt;Coroot is an open-source observability platform that provides dashboards for profiling, logs, service maps, and resource usage — helping you track system health and diagnose issues quickly.&lt;/p&gt;
&lt;p&gt;We’ll deploy it using &lt;strong&gt;Helm via ArgoCD&lt;/strong&gt;, continuing with our GitOps workflow.&lt;/p&gt;
&lt;p&gt;This is Part 4 in our series. Previously, we:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Set up ArgoCD and a GitHub repository for declarative manifests (&lt;a href="https://percona.community/blog/2025/07/22/gitops-journey-part-1-getting-started-with-argocd-and-github/"&gt;Part 1&lt;/a&gt;)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Installed a PostgreSQL cluster using Percona Operator&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Deployed a demo application to simulate traffic and interact with the database&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;All infrastructure is defined declaratively and deployed from the GitHub repository, following GitOps practices.&lt;/p&gt;
&lt;p&gt;So far, we’ve explored cluster scaling, user management, and dynamic configuration — and now it’s time for observability.&lt;/p&gt;
&lt;p&gt;We’ll install Coroot by following the &lt;a href="https://docs.coroot.com/installation/kubernetes/" target="_blank" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt; for Kubernetes.&lt;/p&gt;
&lt;p&gt;Steps ahead:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Install the Coroot Operator&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Install the Coroot Community Edition&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Let’s get started.&lt;/p&gt;
&lt;h2 id="project-structure"&gt;Project Structure&lt;/h2&gt;
&lt;p&gt;We already have a &lt;code&gt;postgres/&lt;/code&gt; directory for PostgreSQL manifests and an &lt;code&gt;apps/&lt;/code&gt; directory for ArgoCD applications.&lt;/p&gt;
&lt;p&gt;We’ll preserve this layout and add a new &lt;code&gt;coroot/&lt;/code&gt; folder for clarity. You can use a different structure if preferred.&lt;/p&gt;
&lt;h2 id="create-manifest-for-installing-the-coroot-operator"&gt;Create Manifest for Installing the Coroot Operator&lt;/h2&gt;
&lt;p&gt;The documentation recommends installing via Helm.&lt;br&gt;
Since we use ArgoCD, we’ll create a manifest that installs via Helm.&lt;/p&gt;
&lt;p&gt;Create file: &lt;code&gt;coroot/operator.yaml&lt;/code&gt;&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;apiVersion: argoproj.io/v1alpha1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kind: Application
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;metadata:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; name: coroot-operator
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; namespace: argocd
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;spec:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; project: default
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; source:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; repoURL: https://coroot.github.io/helm-charts
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; chart: coroot-operator
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; targetRevision: 0.4.2
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; destination:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; server: https://kubernetes.default.svc
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; namespace: coroot
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; syncPolicy:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; automated:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; prune: true
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; selfHeal: true
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; syncOptions:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - CreateNamespace=true&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Note: I’m using version &lt;code&gt;0.4.2&lt;/code&gt;, which was current at the time of writing.&lt;br&gt;
To check available versions, use &lt;a href="https://github.com/coroot/helm-charts/pkgs/container/charts%2Fcoroot-operator" target="_blank" rel="noopener noreferrer"&gt;this GitHub link&lt;/a&gt; or Helm CLI:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-1"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;helm repo add coroot https://coroot.github.io/helm-charts
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;helm repo update
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;helm search repo coroot-operator --versions&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="create-manifest-for-installing-coroot-community-edition"&gt;Create Manifest for Installing Coroot Community Edition&lt;/h2&gt;
&lt;p&gt;Create file: &lt;code&gt;coroot/coroot.yaml&lt;/code&gt;&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-2" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-2"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;apiVersion: argoproj.io/v1alpha1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kind: Application
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;metadata:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; name: coroot
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; namespace: argocd
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;spec:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; project: default
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; source:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; repoURL: https://coroot.github.io/helm-charts
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; chart: coroot-ce
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; targetRevision: 0.3.1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; helm:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; parameters:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - name: clickhouse.shards
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; value: "2"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - name: clickhouse.replicas
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; value: "2"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - name: service.type
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; value: LoadBalancer
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; destination:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; server: https://kubernetes.default.svc
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; namespace: coroot
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; syncPolicy:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; automated:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; prune: true
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; selfHeal: true&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This chart creates a minimal Coroot Custom Resource.&lt;br&gt;
I’ve added &lt;code&gt;service.type: LoadBalancer&lt;/code&gt; to expose a public IP.&lt;/p&gt;
&lt;p&gt;If you don’t use LoadBalancer, you’ll need to forward the Coroot port after installation:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-3" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-3"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl port-forward -n coroot service/coroot-coroot 8080:8080&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="create-argocd-application-manifest"&gt;Create ArgoCD Application Manifest&lt;/h2&gt;
&lt;p&gt;Since we manage our infrastructure via a GitHub repository, we need an ArgoCD Application that tracks changes in the &lt;code&gt;coroot/&lt;/code&gt; folder.&lt;/p&gt;
&lt;p&gt;Create file: &lt;code&gt;apps/argocd-coroot.yaml&lt;/code&gt;&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-4" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-4"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;apiVersion: argoproj.io/v1alpha1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kind: Application
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;metadata:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; name: coroot-sync-app
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; namespace: argocd
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;spec:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; project: default
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; source:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; repoURL: https://github.com/dbazhenov/percona-argocd-pg-coroot.git
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; targetRevision: main
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; path: coroot
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; destination:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; server: https://kubernetes.default.svc
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; namespace: coroot
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; syncPolicy:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; automated:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; prune: true
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; selfHeal: true
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; syncOptions:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - CreateNamespace=true&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This lightweight app will monitor the folder and apply updates automatically if a change is detected (e.g. chart version bump).&lt;/p&gt;
&lt;h2 id="define-chart-installation-order"&gt;Define Chart Installation Order&lt;/h2&gt;
&lt;p&gt;We have two charts: &lt;code&gt;operator.yaml&lt;/code&gt; and &lt;code&gt;coroot.yaml&lt;/code&gt;, and the operator must be installed first.&lt;/p&gt;
&lt;p&gt;Create &lt;code&gt;coroot/kustomization.yaml&lt;/code&gt; to specify resource order:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-5" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-5"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;apiVersion: kustomize.config.k8s.io/v1beta1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kind: Kustomization
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;resources:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - operator.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - coroot.yaml&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="publish-manifests-to-github"&gt;Publish Manifests to GitHub&lt;/h2&gt;
&lt;p&gt;Check which files were changed:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-6" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-6"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git status&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Add changes:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-7" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-7"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git add .&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Verify staged files:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-8" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-8"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git status&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Commit:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-9" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-9"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git commit -m "Installing Coroot Operator and Coroot with ArgoCD"&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Push:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-10" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-10"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git push origin main&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="apply-argocd-application"&gt;Apply ArgoCD Application&lt;/h2&gt;
&lt;p&gt;Deploy the ArgoCD app that installs Coroot from our GitHub repository:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-11" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-11"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl apply -f apps/argocd-coroot.yaml -n argocd&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Validate installation and sync:&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2025/07/gitops-argocd-coroot-coroot-sync-app_hu_d9da7980b8ef31d3.png 480w, https://percona.community/blog/2025/07/gitops-argocd-coroot-coroot-sync-app_hu_d1e3781de9c86bc8.png 768w, https://percona.community/blog/2025/07/gitops-argocd-coroot-coroot-sync-app_hu_d5fb881b1069f790.png 1400w"
src="https://percona.community/blog/2025/07/gitops-argocd-coroot-coroot-sync-app.png" alt="GitOps - ArgoCD and Coroot" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;We now see &lt;code&gt;coroot&lt;/code&gt;, &lt;code&gt;coroot-operator&lt;/code&gt;, and &lt;code&gt;coroot-sync-app&lt;/code&gt; deployed.&lt;/p&gt;
&lt;h2 id="access-coroot-ui"&gt;Access Coroot UI&lt;/h2&gt;
&lt;p&gt;Since we deployed Coroot using LoadBalancer, retrieve its external IP:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-12" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-12"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl get svc -n coroot&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Open EXTERNAL-IP on port 8080.&lt;br&gt;
For example: &lt;code&gt;http://35.202.140.216:8080/&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;If you didn’t use LoadBalancer, run port-forward:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-13" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-13"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl port-forward -n coroot service/coroot-coroot 8080:8080&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Then visit &lt;code&gt;http://localhost:8080&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;You’ll be prompted to set an admin password on first login.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2025/07/gitops-argocd-coroot-welcome_hu_e5a5227526a9ab37.png 480w, https://percona.community/blog/2025/07/gitops-argocd-coroot-welcome_hu_6263ca8ac8ccabda.png 768w, https://percona.community/blog/2025/07/gitops-argocd-coroot-welcome_hu_17c070d92b90032a.png 1400w"
src="https://percona.community/blog/2025/07/gitops-argocd-coroot-welcome.png" alt="GitOps - ArgoCD and Coroot" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h2 id="exploring-coroot-ui"&gt;Exploring Coroot UI&lt;/h2&gt;
&lt;p&gt;On the home page, we see a list of applications running in the cluster and resource usage.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2025/07/gitops-argocd-coroot-home-dashboard_hu_19c1882d484471cf.png 480w, https://percona.community/blog/2025/07/gitops-argocd-coroot-home-dashboard_hu_fa34cad47b7230fc.png 768w, https://percona.community/blog/2025/07/gitops-argocd-coroot-home-dashboard_hu_41013580bea140af.png 1400w"
src="https://percona.community/blog/2025/07/gitops-argocd-coroot-home-dashboard.png" alt="GitOps - ArgoCD and Coroot - Home" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;I increased the load on the PostgreSQL cluster using the Demo App to test observability.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2025/07/gitops-argocd-coroot-demo-load_hu_e6e7de6b8f0d14f4.png 480w, https://percona.community/blog/2025/07/gitops-argocd-coroot-demo-load_hu_a6ae4e8000dffd0e.png 768w, https://percona.community/blog/2025/07/gitops-argocd-coroot-demo-load_hu_8dcb75a909611a2d.png 1400w"
src="https://percona.community/blog/2025/07/gitops-argocd-coroot-demo-load.png" alt="GitOps - ArgoCD and Coroot - Demo App" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;The PostgreSQL cluster dashboard offers several tabs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CPU&lt;/li&gt;
&lt;li&gt;Memory&lt;/li&gt;
&lt;li&gt;Storage&lt;/li&gt;
&lt;li&gt;Instances&lt;/li&gt;
&lt;li&gt;Logs&lt;/li&gt;
&lt;li&gt;Profiling&lt;/li&gt;
&lt;li&gt;Tracing&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2025/07/gitops-argocd-coroot-cluster_hu_4d649a08378d2d1a.png 480w, https://percona.community/blog/2025/07/gitops-argocd-coroot-cluster_hu_6875265d603fa92d.png 768w, https://percona.community/blog/2025/07/gitops-argocd-coroot-cluster_hu_c144b4e4c765ae76.png 1400w"
src="https://percona.community/blog/2025/07/gitops-argocd-coroot-cluster.png" alt="GitOps - ArgoCD and Coroot - PG Cluster" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Coroot displays a visual map of service interactions — showing which app connects to the PostgreSQL cluster.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2025/07/gitops-argocd-coroot-cluster-map_hu_50412503e22d3551.png 480w, https://percona.community/blog/2025/07/gitops-argocd-coroot-cluster-map_hu_9f70cf4209e1dfbc.png 768w, https://percona.community/blog/2025/07/gitops-argocd-coroot-cluster-map_hu_fb80a6a605f0035e.png 1400w"
src="https://percona.community/blog/2025/07/gitops-argocd-coroot-cluster-map.png" alt="GitOps - ArgoCD and Coroot - PG Cluster" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;Profiling&lt;/strong&gt; tab looks excellent and intuitive. Here’s the Demo App profiling view:&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2025/07/gitops-argocd-coroot-demo-profiling_hu_2e9cfe6701a6f254.png 480w, https://percona.community/blog/2025/07/gitops-argocd-coroot-demo-profiling_hu_23528748fdc62126.png 768w, https://percona.community/blog/2025/07/gitops-argocd-coroot-demo-profiling_hu_6d91351cd2ccedd3.png 1400w"
src="https://percona.community/blog/2025/07/gitops-argocd-coroot-demo-profiling.png" alt="GitOps - ArgoCD and Coroot - Demo App Profiling" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;I also triggered an intentional error in the demo app.&lt;br&gt;
Coroot correctly displayed it in both the home view and the app details page.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2025/07/gitops-argocd-coroot-demo-profiling_hu_2e9cfe6701a6f254.png 480w, https://percona.community/blog/2025/07/gitops-argocd-coroot-demo-profiling_hu_23528748fdc62126.png 768w, https://percona.community/blog/2025/07/gitops-argocd-coroot-demo-profiling_hu_6d91351cd2ccedd3.png 1400w"
src="https://percona.community/blog/2025/07/gitops-argocd-coroot-demo-profiling.png" alt="GitOps - ArgoCD and Coroot - Demo App Logs" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;I especially liked the &lt;strong&gt;Logs&lt;/strong&gt; and &lt;strong&gt;Costs&lt;/strong&gt; sections in the sidebar — very well implemented.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2025/07/gitops-argocd-coroot-cluster-logs_hu_d4bb6db723fa13df.png 480w, https://percona.community/blog/2025/07/gitops-argocd-coroot-cluster-logs_hu_d753bf1ff228ccdc.png 768w, https://percona.community/blog/2025/07/gitops-argocd-coroot-cluster-logs_hu_5c35d225e551d55f.png 1400w"
src="https://percona.community/blog/2025/07/gitops-argocd-coroot-cluster-logs.png" alt="GitOps - ArgoCD and Coroot - Demo App Logs" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2025/07/gitops-argocd-coroot-cluster-costs_hu_2381727e8e34df66.png 480w, https://percona.community/blog/2025/07/gitops-argocd-coroot-cluster-costs_hu_1e37d17c340e011.png 768w, https://percona.community/blog/2025/07/gitops-argocd-coroot-cluster-costs_hu_ecfa20d83bd0892.png 1400w"
src="https://percona.community/blog/2025/07/gitops-argocd-coroot-cluster-costs.png" alt="GitOps - ArgoCD and Coroot - Demo App Costs" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h2 id="first-incident-storage-usage-in-postgresql-turns-yellow"&gt;First Incident: Storage Usage in PostgreSQL Turns Yellow&lt;/h2&gt;
&lt;p&gt;While exploring Coroot and the cluster, I increased the load on the PostgreSQL cluster using the Demo App.&lt;/p&gt;
&lt;p&gt;After a short while, I noticed that the Postgres disk was full.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2025/07/gitops-argocd-coroot-cluster-storage_hu_c5a7d8ed00eca3ab.png 480w, https://percona.community/blog/2025/07/gitops-argocd-coroot-cluster-storage_hu_6fd7989d44e7f1da.png 768w, https://percona.community/blog/2025/07/gitops-argocd-coroot-cluster-storage_hu_bf845b4e99005994.png 1400w"
src="https://percona.community/blog/2025/07/gitops-argocd-coroot-cluster-storage.png" alt="GitOps - ArgoCD and Coroot - PG Storage" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;I opened the cluster details and went to the &lt;strong&gt;Storage&lt;/strong&gt; tab.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2025/07/gitops-argocd-coroot-cluster-storage-details_hu_d68091fe4936a452.png 480w, https://percona.community/blog/2025/07/gitops-argocd-coroot-cluster-storage-details_hu_ed95998788d09a8.png 768w, https://percona.community/blog/2025/07/gitops-argocd-coroot-cluster-storage-details_hu_23d67d75d90e808b.png 1400w"
src="https://percona.community/blog/2025/07/gitops-argocd-coroot-cluster-storage-details.png" alt="GitOps - ArgoCD and Coroot - PG Storage Details" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;By default, the &lt;code&gt;cr.yaml&lt;/code&gt; file allocates just 1Gi of disk space — which is fine for a test setup.&lt;/p&gt;
&lt;p&gt;Let’s increase disk size the GitOps way.&lt;/p&gt;
&lt;h2 id="increase-storage-size"&gt;Increase Storage Size&lt;/h2&gt;
&lt;p&gt;Open the file &lt;code&gt;postgres/cr.yaml&lt;/code&gt; and locate the section:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-14" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-14"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; dataVolumeClaimSpec:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# storageClassName: standard
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; accessModes:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - ReadWriteOnce
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; resources:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; requests:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; storage: 1Gi&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Change &lt;code&gt;storage&lt;/code&gt; from &lt;code&gt;1Gi&lt;/code&gt; to &lt;code&gt;5Gi&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Note: Backup volumes (pgBackRest) are also enabled by default and set to &lt;code&gt;1Gi&lt;/code&gt;.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-15" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-15"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; manual:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; repoName: repo1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; options:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - --type=full
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# initialDelaySeconds: 120
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; repos:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - name: repo1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; schedules:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; full: "0 0 * * 6"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# differential: "0 1 * * 1-6"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# incremental: "0 1 * * 1-6"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; volume:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; volumeClaimSpec:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# storageClassName: standard
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; accessModes:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - ReadWriteOnce
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; resources:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; requests:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; storage: 1Gi&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Increase this storage to &lt;code&gt;5Gi&lt;/code&gt; as well.&lt;/p&gt;
&lt;p&gt;Save changes to &lt;code&gt;cr.yaml&lt;/code&gt;, then commit and push to the GitHub repository.&lt;/p&gt;
&lt;p&gt;ArgoCD will automatically apply the changes. Pure GitOps magic.&lt;/p&gt;
&lt;p&gt;Check the result in Coroot — everything looks great. The disk is increased to &lt;code&gt;5Gi&lt;/code&gt; and the issue is resolved.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2025/07/gitops-argocd-coroot-cluster-storage-details-result_hu_3ada1633dcf9a61b.png 480w, https://percona.community/blog/2025/07/gitops-argocd-coroot-cluster-storage-details-result_hu_6161ad5c0039ad47.png 768w, https://percona.community/blog/2025/07/gitops-argocd-coroot-cluster-storage-details-result_hu_31967d7a0ec33710.png 1400w"
src="https://percona.community/blog/2025/07/gitops-argocd-coroot-cluster-storage-details-result.png" alt="GitOps - ArgoCD and Coroot - PG Storage Details Results" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2025/07/gitops-argocd-coroot-cluster-storage-home-result_hu_75b2bce9c4bf908d.png 480w, https://percona.community/blog/2025/07/gitops-argocd-coroot-cluster-storage-home-result_hu_ed09977afbd8979a.png 768w, https://percona.community/blog/2025/07/gitops-argocd-coroot-cluster-storage-home-result_hu_b39a70f347ba25be.png 1400w"
src="https://percona.community/blog/2025/07/gitops-argocd-coroot-cluster-storage-home-result.png" alt="GitOps - ArgoCD and Coroot - PG Storage Results" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;We’ve installed and tested a solid monitoring tool, and it really makes a difference.&lt;/p&gt;
&lt;p&gt;Across this 4-part series, we walked through the GitOps journey step by step:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://percona.community/blog/2025/07/22/gitops-journey-part-1-getting-started-with-argocd-and-github/"&gt;Part 1&lt;/a&gt; - Created a Kubernetes cluster, installed ArgoCD, and set up a GitHub repository.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://percona.community/blog/2025/07/22/gitops-journey-part-2-deploying-postgresql-with-gitops-and-argocd/"&gt;Part 2&lt;/a&gt; - Deployed a PostgreSQL cluster using Percona Operator for PostgreSQL.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://percona.community/blog/2025/07/22/gitops-journey-part-3-deploying-a-load-generator-and-connecting-to-postgresql/"&gt;Part 3&lt;/a&gt; - Deployed a demo app via ArgoCD using Helm.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Installed and tested &lt;strong&gt;Coroot&lt;/strong&gt;, an excellent open-source observability tool.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Managed the PG cluster through GitHub and ArgoCD — scaled replicas, created users, resized volumes, configured access, and more.&lt;/p&gt;
&lt;p&gt;Thank you for reading — I hope this series was helpful.&lt;/p&gt;
&lt;p&gt;The project files are available in my repository &lt;a href="https://github.com/dbazhenov/percona-argocd-pg-coroot" target="_blank" rel="noopener noreferrer"&gt;https://github.com/dbazhenov/percona-argocd-pg-coroot&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I’d love to hear your questions, feedback, and suggestions for improvement.&lt;/p&gt;</content:encoded>
      <author>Daniil Bazhenov</author>
      <category>PostgreSQL</category>
      <category>Coroot</category>
      <category>GitOps</category>
      <category>ArgoCD</category>
      <media:thumbnail url="https://percona.community/blog/2025/07/gitops-part-4_hu_2013b3b0cf1fac01.jpg"/>
      <media:content url="https://percona.community/blog/2025/07/gitops-part-4_hu_df439a8a73d324e6.jpg" medium="image"/>
    </item>
    <item>
      <title>GitOps Journey: Part 3 – Deploying a Load Generator and Connecting to PostgreSQL</title>
      <link>https://percona.community/blog/2025/07/22/gitops-journey-part-3-deploying-a-load-generator-and-connecting-to-postgresql/</link>
      <guid>https://percona.community/blog/2025/07/22/gitops-journey-part-3-deploying-a-load-generator-and-connecting-to-postgresql/</guid>
      <pubDate>Tue, 22 Jul 2025 00:00:50 UTC</pubDate>
      <description>We’ll deploy a demo application into the Kubernetes cluster using ArgoCD to simulate load on the PostgreSQL cluster.</description>
      <content:encoded>&lt;p&gt;We’ll deploy a demo application into the Kubernetes cluster using ArgoCD to simulate load on the PostgreSQL cluster.&lt;/p&gt;
&lt;p&gt;This is a series of articles, in previous parts we:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://percona.community/blog/2025/07/22/gitops-journey-part-1-getting-started-with-argocd-and-github/"&gt;Part 1&lt;/a&gt; - Prepared the environment and installed ArgoCD and GitHub repository.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://percona.community/blog/2025/07/22/gitops-journey-part-2-deploying-postgresql-with-gitops-and-argocd/"&gt;Part 2&lt;/a&gt; - Installed Percona Operator for Postgres and created a Postgres cluster.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The application is a custom Go-based service that generates traffic for PostgreSQL, MongoDB, or MySQL.&lt;/p&gt;
&lt;p&gt;It uses a dataset of GitHub repositories and pull requests, and mimics real-world operations like fetching, creating, updating, and deleting records.&lt;br&gt;
Load intensity is configurable through a browser-based control panel.&lt;/p&gt;
&lt;p&gt;We’ll install it using Helm, tracked and deployed via ArgoCD.&lt;/p&gt;
&lt;p&gt;Reference repository: &lt;a href="https://github.com/dbazhenov/github-stat" target="_blank" rel="noopener noreferrer"&gt;github-stat&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="create-the-argocd-application-manifest"&gt;Create the ArgoCD Application Manifest&lt;/h2&gt;
&lt;p&gt;Create a file named &lt;code&gt;argocd-demo-app.yaml&lt;/code&gt; in the &lt;code&gt;apps/&lt;/code&gt; directory.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;apiVersion: argoproj.io/v1alpha1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kind: Application
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;metadata:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; name: demo-app
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; namespace: argocd
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;spec:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; project: default
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; source:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; repoURL: https://github.com/dbazhenov/github-stat
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; targetRevision: main
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; path: k8s/helm
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; destination:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; server: https://kubernetes.default.svc
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; namespace: demo-app
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; syncPolicy:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; automated:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; prune: true
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; selfHeal: true
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; syncOptions:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - CreateNamespace=true&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This will install the Helm chart from&lt;br&gt;
&lt;code&gt;https://github.com/dbazhenov/github-stat/tree/main/k8s/helm&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;By default, the service is configured as &lt;code&gt;LoadBalancer&lt;/code&gt;, making it accessible from the internet.&lt;/p&gt;
&lt;p&gt;To switch to &lt;code&gt;NodePort&lt;/code&gt; (if needed), override the Helm value:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-1"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;source:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; helm:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; parameters:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - name: controlPanelService.type
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; value: NodePort&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;We’ll keep default settings in this example.&lt;/p&gt;
&lt;h2 id="push-the-application-manifest-to-github"&gt;Push the Application Manifest to GitHub&lt;/h2&gt;
&lt;p&gt;Track and commit your changes:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-2" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-2"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git status&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-3" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-3"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git add .&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-4" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-4"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git commit -m "Installing Demo Application in ArgoCD by HELM"&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-5" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-5"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git push origin main &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Expected Git output:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-6" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-6"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;➜ percona-argocd-pg-coroot git:(main) git status
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;On branch main
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Your branch is up to date with 'origin/main'.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Untracked files:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; (use "git add &lt;file&gt;..." to include in what will be committed)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; apps/argocd-demo-app.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nothing added to commit but untracked files present (use "git add" to track)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;➜ percona-argocd-pg-coroot git:(main) ✗ git add .
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;➜ percona-argocd-pg-coroot git:(main) ✗ git commit -m "Installing Demo Application in ArgoCD by HELM"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[main 03ce175] Installing Demo Application in ArgoCD by HELM
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 1 file changed, 20 insertions(+)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; create mode 100644 apps/argocd-demo-app.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;➜ percona-argocd-pg-coroot git:(main) git push origin main
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Enumerating objects: 6, done.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Counting objects: 100% (6/6), done.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Delta compression using up to 10 threads
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Compressing objects: 100% (4/4), done.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Writing objects: 100% (4/4), 686 bytes | 686.00 KiB/s, done.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Total 4 (delta 0), reused 0 (delta 0), pack-reused 0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;To github.com:dbazhenov/percona-argocd-pg-coroot.git
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 6b2dc98..03ce175 main -&gt; main
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;➜ percona-argocd-pg-coroot git:(main)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="apply-the-argocd-application"&gt;Apply the ArgoCD Application&lt;/h2&gt;
&lt;p&gt;Deploy the app via:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-7" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-7"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl apply -f apps/argocd-demo-app.yaml -n argocd&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;ArgoCD will install the app and has started tracking the app’s HELM chart&lt;/p&gt;
&lt;h2 id="validate-the-deployment"&gt;Validate the Deployment&lt;/h2&gt;
&lt;p&gt;Confirm the app status in ArgoCD UI:&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2025/07/gitops-github-argo-demo-app_hu_f7e82c9783a43d91.png 480w, https://percona.community/blog/2025/07/gitops-github-argo-demo-app_hu_8ecf80945d756a3a.png 768w, https://percona.community/blog/2025/07/gitops-github-argo-demo-app_hu_e5087321ad96287d.png 1400w"
src="https://percona.community/blog/2025/07/gitops-github-argo-demo-app.png" alt="GitOps - Percona Operator for Postgres and PG Cluster" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Check running pods:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-8" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-8"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl get pods -n demo-app&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Expected pods:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-9" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-9"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;➜ percona-argocd-pg-coroot git:(main) kubectl get pods -n demo-app
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NAME READY STATUS RESTARTS AGE
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;demo-app-dataset-6d886f67-j648w 1/1 Running 0 2m52s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;demo-app-load-577cff97c9-d8j99 1/1 Running 0 2m52s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;demo-app-valkey-74989c9bf7-gjp4x 1/1 Running 0 2m52s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;demo-app-web-5b98d4c65c-xmkq9 1/1 Running 0 2m52s&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;demo-app-dataset - loads dataset&lt;/li&gt;
&lt;li&gt;demo-app-load - generates traffic&lt;/li&gt;
&lt;li&gt;demo-app-valkey - Redis-compatible DB backend&lt;/li&gt;
&lt;li&gt;demo-app-web - UI dashboard&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="open-the-application-dashboard"&gt;Open the Application Dashboard&lt;/h2&gt;
&lt;p&gt;Retrieve the external IP:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-10" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-10"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl get svc -n demo-app&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Find the &lt;code&gt;EXTERNAL-IP&lt;/code&gt; of &lt;code&gt;demo-app-web-service&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Sample output:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-11" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-11"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;➜ percona-argocd-pg-coroot git:(main) kubectl get svc -n demo-app
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;demo-app-valkey-service ClusterIP 34.118.235.203 &lt;none&gt; 6379/TCP 4m59s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;demo-app-web-service LoadBalancer 34.118.232.144 34.28.221.107 80:31308/TCP 4m59s&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Access the app in your browser:&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2025/07/gitops-demo-app-ui_hu_a5216002601d44a.png 480w, https://percona.community/blog/2025/07/gitops-demo-app-ui_hu_ecc6617f019380e0.png 768w, https://percona.community/blog/2025/07/gitops-demo-app-ui_hu_43937f9d77a63202.png 1400w"
src="https://percona.community/blog/2025/07/gitops-demo-app-ui.png" alt="GitOps - ArgoCD Demo App UI" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Navigate to the &lt;strong&gt;Settings&lt;/strong&gt; tab to configure a PostgreSQL connection.&lt;/p&gt;
&lt;h2 id="postgresql-credentials-setup"&gt;PostgreSQL Credentials Setup&lt;/h2&gt;
&lt;p&gt;Percona Operator has already (&lt;a href="https://docs.percona.com/percona-operator-for-postgresql/2.0/users.html" target="_blank" rel="noopener noreferrer"&gt;Application and system users&lt;/a&gt;):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Created schema and database &lt;code&gt;cluster1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Created user &lt;code&gt;cluster1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Stored credentials in &lt;code&gt;cluster1-pguser-cluster1&lt;/code&gt; secret&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Extract the password:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-12" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-12"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl get secret cluster1-pguser-cluster1 -n postgres-operator --template='{{.data.password | base64decode}}{{"\n"}}'&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Let’s connect to the database from the Demo application using the given user and cluster1-pgbouncer.postgres-operator.svc host&lt;/p&gt;
&lt;p&gt;In the Connection String field enter&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-13" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-13"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;user=cluster1 password='[PASSWORD]' dbname=cluster1 host=cluster1-pgbouncer.postgres-operator.svc port=5432&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2025/07/gitops-demo-app-ui-connect_hu_af293f7503ec6a79.png 480w, https://percona.community/blog/2025/07/gitops-demo-app-ui-connect_hu_44e6451a426458aa.png 768w, https://percona.community/blog/2025/07/gitops-demo-app-ui-connect_hu_d38c2f7dd717129a.png 1400w"
src="https://percona.community/blog/2025/07/gitops-demo-app-ui-connect.png" alt="GitOps - ArgoCD Demo App UI - Connect" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;The connection has been successfully created, this is good.&lt;/p&gt;
&lt;p&gt;To start generating the load, we need to import the Dataset using the Import Dataset button.&lt;/p&gt;
&lt;h2 id="dataset-import-error-create-schema-denied"&gt;Dataset Import Error: Create Schema Denied&lt;/h2&gt;
&lt;p&gt;During import, the app tries to create a schema.&lt;br&gt;
By default, pgBouncer limits user privileges, preventing this action.&lt;/p&gt;
&lt;p&gt;Percona &lt;a href="https://docs.percona.com/percona-operator-for-postgresql/2.0/users.html#superuser-and-pgbouncer" target="_blank" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; suggests enabling &lt;code&gt;proxy.pgBouncer.exposeSuperusers&lt;/code&gt; and creating a privileged user.&lt;/p&gt;
&lt;p&gt;We’ll handle this via GitOps. It seems cool that we’ll be doing this with tracking in Git, as these are important settings and we shouldn’t forget about them and turn them off in the future.&lt;/p&gt;
&lt;h2 id="define-a-new-postgresql-user"&gt;Define a New PostgreSQL User&lt;/h2&gt;
&lt;p&gt;We will make changes to postgres/cr.yaml that will add a new user and also enable the proxy.pgBouncer.exposeSuperusers option.&lt;/p&gt;
&lt;p&gt;In the postgres/cr.yaml file I found the users section, uncommented and added my user data.&lt;/p&gt;
&lt;p&gt;In &lt;code&gt;postgres/cr.yaml&lt;/code&gt;, add:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-14" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-14"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; users:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - name: daniil
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; databases:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - demo
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; options: "SUPERUSER"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; password:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; type: ASCII
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; secretName: "daniil-credentials"&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Note: In production, use scoped permissions like &lt;code&gt;"LOGIN CREATE CREATEDB"&lt;/code&gt; rather than &lt;code&gt;SUPERUSER&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I also found the proxy.pgBouncer.exposeSuperusers setting and set it to true&lt;/p&gt;
&lt;p&gt;Update pgBouncer config:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-15" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-15"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; proxy:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; pgBouncer:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; replicas: 3
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; image: docker.io/percona/percona-pgbouncer:1.24.1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; exposeSuperusers: true&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Commit and push:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-16" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-16"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git status&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-17" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-17"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git add .&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-18" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-18"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git commit -m "Postgres cluster: Creating a new user and pgBouncer.exposeSuperusers"&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-19" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-19"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git push origin main&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;After a couple of minutes, ArgoCD will synchronize the changes and Percona Operator will create the user and change the configuration.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2025/07/gitops-argocd-pg-new-user_hu_5517ec3b89a13b26.png 480w, https://percona.community/blog/2025/07/gitops-argocd-pg-new-user_hu_132730d99fb3819b.png 768w, https://percona.community/blog/2025/07/gitops-argocd-pg-new-user_hu_799bfdf42374359f.png 1400w"
src="https://percona.community/blog/2025/07/gitops-argocd-pg-new-user.png" alt="GitOps - ArgoCD Demo App UI" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h2 id="connect-with-the-new-user"&gt;Connect With the New User&lt;/h2&gt;
&lt;p&gt;Get the password:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-20" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-20"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl get secret daniil-credentials -n postgres-operator --template='{{.data.password | base64decode}}{{"\n"}}'&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Let’s replace Connection String in Demo application, I got the following string&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-21" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-21"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;user=daniil password='iKj:e[wT3*g]OF5+f' dbname=dataset host=cluster1-pgbouncer.postgres-operator.svc port=5432&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2025/07/gitops-argocs-demo-app-new-user_hu_e28b8a3338806aa3.png 480w, https://percona.community/blog/2025/07/gitops-argocs-demo-app-new-user_hu_2f0a7cf452382a41.png 768w, https://percona.community/blog/2025/07/gitops-argocs-demo-app-new-user_hu_d7f241e5df838cdf.png 1400w"
src="https://percona.community/blog/2025/07/gitops-argocs-demo-app-new-user.png" alt="GitOps - ArgoCD Demo App UI - Connection" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Click the “Import Dataset” button and wait a few minutes until the import is in Done status in the Dataset tab.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2025/07/gitops-argocs-demo-app-dataset_hu_b05be9189ce8a29c.png 480w, https://percona.community/blog/2025/07/gitops-argocs-demo-app-dataset_hu_feaa2ca204a6ed74.png 768w, https://percona.community/blog/2025/07/gitops-argocs-demo-app-dataset_hu_bd097498f5e03155.png 1400w"
src="https://percona.community/blog/2025/07/gitops-argocs-demo-app-dataset.png" alt="GitOps - ArgoCD Demo App UI - Connection" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h2 id="enable-load-generation"&gt;Enable Load Generation&lt;/h2&gt;
&lt;p&gt;Activate the load generator:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Toggle &lt;strong&gt;Enable Load&lt;/strong&gt; in the connection settings&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Update Connection&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2025/07/gitops-argocd-demo-app-enable-load_hu_8e0c4a5db276fb85.png 480w, https://percona.community/blog/2025/07/gitops-argocd-demo-app-enable-load_hu_52432bdb768937d6.png 768w, https://percona.community/blog/2025/07/gitops-argocd-demo-app-enable-load_hu_a82212f4c1e5503a.png 1400w"
src="https://percona.community/blog/2025/07/gitops-argocd-demo-app-enable-load.png" alt="GitOps - ArgoCD Demo App UI - Enable Load" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Open the &lt;strong&gt;Load Generator Control Panel&lt;/strong&gt; and adjust sliders and toggles as needed:&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2025/07/gitops-argocd-demo-app-panel_hu_8f57f1fa04e0ebdf.png 480w, https://percona.community/blog/2025/07/gitops-argocd-demo-app-panel_hu_7a50876dac856935.png 768w, https://percona.community/blog/2025/07/gitops-argocd-demo-app-panel_hu_255f70a0ce31e068.png 1400w"
src="https://percona.community/blog/2025/07/gitops-argocd-demo-app-panel.png" alt="GitOps - ArgoCD Demo App UI - Load Generator" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this part, we:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Deployed a demo application via Helm in ArgoCD&lt;/li&gt;
&lt;li&gt;Connected it to our PostgreSQL cluster&lt;/li&gt;
&lt;li&gt;Managed PostgreSQL users and access via GitHub and GitOps&lt;/li&gt;
&lt;li&gt;Imported a dataset and activated the traffic generator through the web UI&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In &lt;a href="https://percona.community/blog/2025/07/22/gitops-journey-part-4-observability-and-monitoring-with-coroot-in-kubernetes/"&gt;Part 4&lt;/a&gt;, we’ll deploy &lt;strong&gt;Coroot&lt;/strong&gt; for observability and profiling.&lt;br&gt;
It’s an impressive tool for diagnosing behavior across services in the Kubernetes cluster.&lt;/p&gt;</content:encoded>
      <author>Daniil Bazhenov</author>
      <category>PostgreSQL</category>
      <category>Opensource</category>
      <category>GitOps</category>
      <category>ArgoCD</category>
      <media:thumbnail url="https://percona.community/blog/2025/07/gitops-part-3_hu_89d6e1d2addde317.jpg"/>
      <media:content url="https://percona.community/blog/2025/07/gitops-part-3_hu_c3ba448f33f9a74f.jpg" medium="image"/>
    </item>
    <item>
      <title>GitOps Journey: Part 1 – Getting Started with ArgoCD and GitHub</title>
      <link>https://percona.community/blog/2025/07/22/gitops-journey-part-1-getting-started-with-argocd-and-github/</link>
      <guid>https://percona.community/blog/2025/07/22/gitops-journey-part-1-getting-started-with-argocd-and-github/</guid>
      <pubDate>Tue, 22 Jul 2025 00:00:10 UTC</pubDate>
      <description>Welcome to GitOps Journey — a hands-on guide to setting up infrastructure in Kubernetes using Git and automation.</description>
      <content:encoded>&lt;p&gt;Welcome to &lt;strong&gt;GitOps Journey&lt;/strong&gt; — a hands-on guide to setting up infrastructure in Kubernetes using Git and automation.&lt;/p&gt;
&lt;p&gt;GitOps has gained traction alongside Kubernetes, CI/CD, and declarative provisioning.&lt;br&gt;
You’ve probably seen it mentioned in blog posts, tech talks, or conference slides — but what does it actually look like in practice?&lt;/p&gt;
&lt;p&gt;We’ll start from scratch: prepare a cluster, deploy a PostgreSQL database, run a demo app, and set up observability — all managed via Git and GitHub using ArgoCD.&lt;/p&gt;
&lt;h2 id="what-well-build"&gt;What We’ll Build&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;ArgoCD&lt;/strong&gt; — syncs manifests from a GitHub repository to your cluster&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;PostgreSQL&lt;/strong&gt; — a production-ready database using Percona Operator&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Demo App&lt;/strong&gt; — a real Go-based web app connected to the database&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Coroot&lt;/strong&gt; — an open-source tool for monitoring performance, logs, and service behavior&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This series is for anyone new to GitOps or Kubernetes.&lt;br&gt;
Each part includes clear steps, real-world YAML, and examples you can run yourself.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;This is Part 1 of the GitOps Journey.&lt;/strong&gt;&lt;br&gt;
If you already have ArgoCD and a working Kubernetes cluster, you can skip ahead:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://percona.community/blog/2025/07/22/gitops-journey-part-2-deploying-postgresql-with-gitops-and-argocd/"&gt;Part 2 – Deploying PostgreSQL with Percona Operator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://percona.community/blog/2025/07/22/gitops-journey-part-3-deploying-a-load-generator-and-connecting-to-postgresql/"&gt;Part 3 – Connecting a Real App to the Cluster&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://percona.community/blog/2025/07/22/gitops-journey-part-4-observability-and-monitoring-with-coroot-in-kubernetes/"&gt;Part 4 – Observability with Coroot&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Copilot assisted with formatting, Markdown structure, and translation.&lt;br&gt;
All ideas, architecture decisions, and hands-on implementation were created by Daniil Bazhenov.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Otherwise, let’s start by preparing the cluster and setting up ArgoCD.&lt;/p&gt;
&lt;h2 id="creating-a-kubernetes-cluster"&gt;Creating a Kubernetes Cluster&lt;/h2&gt;
&lt;p&gt;I’ll be using Google Kubernetes Engine (GKE), but you can use AWS, DigitalOcean, or even run Minikube locally.&lt;/p&gt;
&lt;p&gt;You’ll also need these CLI tools installed on your machine:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://kubernetes.io/docs/tasks/tools/#kubectl" target="_blank" rel="noopener noreferrer"&gt;kubectl&lt;/a&gt; - The official CLI tool for Kubernetes — used to manage clusters, view resources, apply manifests, and more.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://helm.sh/docs/intro/install/" target="_blank" rel="noopener noreferrer"&gt;helm&lt;/a&gt; - A package manager for Kubernetes — lets you install complex apps using reusable charts (like PostgreSQL, monitoring tools, etc.)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I use the following command to create a cluster in GKE&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gcloud container clusters create dbazhenov-demo \
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --project percona-product \
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --zone us-central1-a \
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --cluster-version 1.30 \
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --machine-type n1-standard-8 \
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --num-nodes=3&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;To delete the cluster:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-1"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gcloud container clusters delete dbazhenov-demo --zone us-central1-a&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;Note: This command doesn’t remove your LoadBalancers, so I prefer deleting them manually in Google Cloud’s web console to ensure no resources are left running post-experiment.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Here’s the resulting setup:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-2" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-2"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;➜ community git:(blog_argocd_pg) ✗ kubectl get nodes
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NAME STATUS ROLES AGE VERSION
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gke-dbazhenov-demo-default-pool-b1b48316-8nrj Ready &lt;none&gt; 6m7s v1.30.12-gke.1279000
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gke-dbazhenov-demo-default-pool-b1b48316-8v14 Ready &lt;none&gt; 6m6s v1.30.12-gke.1279000
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gke-dbazhenov-demo-default-pool-b1b48316-zg6z Ready &lt;none&gt; 6m7s v1.30.12-gke.1279000
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;➜ community git:(blog_argocd_pg) ✗&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="installing-argocd"&gt;Installing ArgoCD&lt;/h2&gt;
&lt;p&gt;We’ll begin with ArgoCD, the GitOps engine that will deploy:&lt;/p&gt;
&lt;p&gt;PostgreSQL database cluster&lt;/p&gt;
&lt;p&gt;A demo app to simulate real usage&lt;/p&gt;
&lt;p&gt;Coroot for monitoring and profiling workloads&lt;/p&gt;
&lt;p&gt;ArgoCD supports multiple deployment methods — we’ll experiment with different ones during this series.&lt;/p&gt;
&lt;p&gt;Install ArgoCD (&lt;a href="https://argo-cd.readthedocs.io/en/stable/getting_started/" target="_blank" rel="noopener noreferrer"&gt;based on official docs&lt;/a&gt;):&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create namespace:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-3" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-3"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl create namespace argocd&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ol start="2"&gt;
&lt;li&gt;Deploy ArgoCD:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-4" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-4"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Check the pods:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-5" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-5"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl get pods -n argocd&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Expected output: ArgoCD components running (server, repo, redis, controllers, etc.)&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-6" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-6"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;➜ community git:(blog_argocd_pg) ✗ kubectl get pods -n argocd
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NAME READY STATUS RESTARTS AGE
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;argocd-application-controller-0 1/1 Running 0 57s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;argocd-applicationset-controller-6d569f7895-89kgk 1/1 Running 0 64s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;argocd-dex-server-5b44d67df9-p42z5 1/1 Running 0 62s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;argocd-notifications-controller-5865dfbc8-gqzwt 1/1 Running 0 61s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;argocd-redis-6bb7987874-99j59 1/1 Running 0 61s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;argocd-repo-server-df8b9fd78-64czj 1/1 Running 0 60s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;argocd-server-6d896f6785-82tf2 1/1 Running 0 59s&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ol start="3"&gt;
&lt;li&gt;Access ArgoCD UI&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You have two options (or more):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Port forwarding (local only)&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-7" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-7"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl port-forward svc/argocd-server -n argocd 8080:443&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Internet-accessible LoadBalancer&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-8" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-8"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl patch svc argocd-server -n argocd -p '{"spec": {"type": "LoadBalancer"}}'&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;I will use Load Balancer by executing the command above, you need to wait a few minutes to get the IP address.&lt;/p&gt;
&lt;p&gt;Let’s get the IP address of the ArgoCD service in the EXTERNAL-IP field.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-9" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-9"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl get svc argocd-server -n argocd&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-10" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-10"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;➜ community git:(blog_argocd_pg) ✗ kubectl get svc argocd-server -n argocd
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;argocd-server LoadBalancer 34.118.234.162 34.132.39.194 80:30549/TCP,443:32146/TCP 9m51s&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Access the UI in your browser using the IP.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2025/07/gitops-argocd-login_hu_2b8e3a18d84ec798.png 480w, https://percona.community/blog/2025/07/gitops-argocd-login_hu_8c25a58ba7500700.png 768w, https://percona.community/blog/2025/07/gitops-argocd-login_hu_e3a7c94ed685b7da.png 1400w"
src="https://percona.community/blog/2025/07/gitops-argocd-login.png" alt="GitOps - ArgoCD UI" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;ol start="4"&gt;
&lt;li&gt;Getting Started with ArgoCD Login&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Download Argo CD CLI&lt;/p&gt;
&lt;p&gt;Install ArgoCD CLI (&lt;a href="https://argo-cd.readthedocs.io/en/stable/getting_started/#2-download-argo-cd-cli" target="_blank" rel="noopener noreferrer"&gt;see instructions&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Get the initial password:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-11" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-11"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;argocd admin initial-password -n argocd&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;ArgoCD recommends changing it to a new secure password, which we will do.&lt;/p&gt;
&lt;p&gt;Log in via CLI:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-12" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-12"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;argocd login 34.132.39.194 --insecure&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Authorize using initial-password and user admin and execute the password update command&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-13" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-13"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;argocd account update-password&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;All the steps to get and update your password are below.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-14" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-14"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;➜ community git:(blog_argocd_pg) ✗ argocd admin initial-password -n argocd
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;0mxV6IVcF3qZDR-O
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; This password must be only used for first time login. We strongly recommend you update the password using `argocd account update-password`.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;➜ community git:(blog_argocd_pg) ✗ argocd login 34.132.39.194 --insecure
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Username: admin
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Password:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;'admin:login' logged in successfully
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Context '34.132.39.194' updated
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;➜ community git:(blog_argocd_pg) ✗ argocd account update-password
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;*** Enter password of currently logged in user (admin):
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;*** Enter new password for user admin:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;*** Confirm new password for user admin:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Password updated
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Context '34.132.39.194' updated
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;➜ community git:(blog_argocd_pg) ✗&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ol start="5"&gt;
&lt;li&gt;Now log into the ArgoCD web UI using admin and your new password.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2025/07/gitops-argocd-dashboard_hu_23c44b0339a87aa8.png 480w, https://percona.community/blog/2025/07/gitops-argocd-dashboard_hu_654e20efe0754008.png 768w, https://percona.community/blog/2025/07/gitops-argocd-dashboard_hu_f0fa19e2c0e740a7.png 1400w"
src="https://percona.community/blog/2025/07/gitops-argocd-dashboard.png" alt="GitOps: ArgoCD web UI" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Welcome to the ArgoCD interface, we don’t have any applications right now, we will install them later.&lt;/p&gt;
&lt;h2 id="setting-up-github-repo"&gt;Setting Up GitHub Repo&lt;/h2&gt;
&lt;p&gt;We’ll need a GitHub repo to store infrastructure manifests. ArgoCD will sync from this repo and apply changes.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Install git and create a GitHub account&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add your SSH key to your GitHub profile. &lt;a href="https://github.com/settings/keys" target="_blank" rel="noopener noreferrer"&gt;GitHub SSH settings&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a new GitHub repository&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I recommend a public repo for this educational project — no secrets will be committed, and it simplifies ArgoCD setup. Plus, it earns you some green squares on GitHub. If you go with a private repo, make sure it’s properly linked in ArgoCD.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2025/07/gitops-github-new-repo_hu_c1092ea410e1d482.png 480w, https://percona.community/blog/2025/07/gitops-github-new-repo_hu_2d70c7b49bae26ee.png 768w, https://percona.community/blog/2025/07/gitops-github-new-repo_hu_cb106e4582611ded.png 1400w"
src="https://percona.community/blog/2025/07/gitops-github-new-repo.png" alt="GitOps: GitHub Repo Creation" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;ol start="4"&gt;
&lt;li&gt;Clone the repo:&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2025/07/gitops-github-clone_hu_82856ab44db43d16.png 480w, https://percona.community/blog/2025/07/gitops-github-clone_hu_7aa24a16af6a42c2.png 768w, https://percona.community/blog/2025/07/gitops-github-clone_hu_3e1e4f2077b9bd3c.png 1400w"
src="https://percona.community/blog/2025/07/gitops-github-clone.png" alt="GitOps: GitHub Clone" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Clone the repository using an SSH address.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-15" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-15"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git clone git@github.com:dbazhenov/percona-argocd-pg-coroot.git&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Navigate to the project directory&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-16" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-16"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cd percona-argocd-pg-coroot&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Expected output:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-17" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-17"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;➜ gitops git clone git@github.com:dbazhenov/percona-argocd-pg-coroot.git
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Cloning into 'percona-argocd-pg-coroot'...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;remote: Enumerating objects: 3, done.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;remote: Counting objects: 100% (3/3), done.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;remote: Compressing objects: 100% (2/2), done.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Receiving objects: 100% (3/3), done.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;➜ gitops cd percona-argocd-pg-coroot
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;➜ percona-argocd-pg-coroot git:(main) ls
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;README.md
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;➜ percona-argocd-pg-coroot git:(main)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="summary"&gt;Summary&lt;/h2&gt;
&lt;p&gt;We’ve prepared everything to launch our GitOps-powered infrastructure:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Kubernetes cluster&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;ArgoCD deployed&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;GitHub repo ready&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the next posts, we’ll deploy &lt;a href="https://percona.community/blog/2025/07/22/gitops-journey-part-2-deploying-postgresql-with-gitops-and-argocd/"&gt;the PostgreSQL cluster&lt;/a&gt;, &lt;a href="https://percona.community/blog/2025/07/22/gitops-journey-part-3-deploying-a-load-generator-and-connecting-to-postgresql/"&gt;the demo app&lt;/a&gt;, and add &lt;a href="https://percona.community/blog/2025/07/22/gitops-journey-part-4-observability-and-monitoring-with-coroot-in-kubernetes/"&gt;Coroot monitoring&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Stay tuned!&lt;/p&gt;</content:encoded>
      <author>Daniil Bazhenov</author>
      <category>PostgreSQL</category>
      <category>Opensource</category>
      <category>GitOps</category>
      <category>ArgoCD</category>
      <media:thumbnail url="https://percona.community/blog/2025/07/gitops-part-1_hu_1404141b76c22066.jpg"/>
      <media:content url="https://percona.community/blog/2025/07/gitops-part-1_hu_4e4052d3f7870720.jpg" medium="image"/>
    </item>
    <item>
      <title>Using replicaSetHorizons in MongoDB</title>
      <link>https://percona.community/blog/2025/07/22/using-replicasethorizons-in-mongodb/</link>
      <guid>https://percona.community/blog/2025/07/22/using-replicasethorizons-in-mongodb/</guid>
      <pubDate>Tue, 22 Jul 2025 00:00:00 UTC</pubDate>
      <description>When running MongoDB replica sets in containerized environments like Docker or Kubernetes, making nodes reachable from inside the cluster as well as from external clients can be a challenge. To solve this problem, this post is going to explain the horizons feature of Percona Server for MongoDB.</description>
      <content:encoded>&lt;p&gt;When running MongoDB replica sets in containerized environments like Docker or Kubernetes, making nodes reachable from inside the cluster as well as from external clients can be a challenge. To solve this problem, this post is going to explain the horizons feature of &lt;a href="https://docs.percona.com/percona-server-for-mongodb" target="_blank" rel="noopener noreferrer"&gt;Percona Server for MongoDB&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2025/07/ivan_cover.png" alt="Using_replicaSetHorizons_in_MongoDB" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Let’s start by looking at what happens behind the scenes when you connect to a replicaset URI.&lt;/p&gt;
&lt;h2 id="node-auto-discovery"&gt;Node auto-discovery&lt;/h2&gt;
&lt;p&gt;After connecting with a replset URI, the driver discovers the list of actual members by running the db.hello() command:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mongosh "mongodb://mongo1-internal:27017/?replicaSet=rs0"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rs0 [direct: primary] test&gt; db.hello()
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; topologyVersion: {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; processId: ObjectId('6877b5e18a13d54b752ff25c'),
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; counter: Long('6')
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; hosts: [ 'mongo1-internal:27017', 'mongo2-internal:27017', 'mongo3-internal:27017' ],
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The list of hosts returned contains the name of each member as you provided it to the rs.initialize() command.&lt;/p&gt;
&lt;h2 id="the-node-identity-crisis"&gt;The node identity crisis&lt;/h2&gt;
&lt;p&gt;The names are resolvable inside the same network, so all is well in this case. But what happens when connecting from outside?&lt;/p&gt;
&lt;p&gt;Typically you would be using names like mongo1-external.mydomain.com that correctly point to the external IP addresses of the members. The problem is that after the initial connection is made, the driver will perform auto-discovery and try to connect to the names as reported by db.hello(). These are not resolvable from outside.&lt;/p&gt;
&lt;p&gt;What if we connect by IP address directly? again, the driver will get the names from the list above, try to reach those and fail after the initial connection is made:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-1"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ mongosh mongodb://user:pass@10.30.50.155:32768/?replicaSet=rs0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Current Mongosh Log ID: 6849eb15ba228be45a69e327
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Connecting to: mongodb://&lt;credentials&gt;@10.30.50.155:32768/?replicaSet=rs0&amp;appName=mongosh+2.5.2
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;MongoNetworkError: getaddrinfo ENOTFOUND mongo1-internal&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Even though mongo1-internal is not part of the connection string, the driver tries to reach it. So if the replica set members advertise their internal IPs or DNS names, clients outside can’t connect unless they can resolve that same name. We could work around that, but there’s another issue: the ports.&lt;/p&gt;
&lt;h2 id="the-port-issue"&gt;The port issue&lt;/h2&gt;
&lt;p&gt;In the containerized world, it is likely that you set up your containers to use default port 27017. However they might be mapped to a different external port, since you have to avoid port collisions (think about the case where containers are co-located in the same host).&lt;/p&gt;
&lt;p&gt;We need a way for replica set members to identify themselves with different names and ports, depending on whether the client is in the same network or outside. A concept similar to split-brain DNS.&lt;/p&gt;
&lt;h2 id="what-is-horizons"&gt;What is Horizons?&lt;/h2&gt;
&lt;p&gt;Horizons is a MongoDB feature that allows replica set members to advertise different identities depending on the client’s access context, such as internal versus external networks.&lt;/p&gt;
&lt;p&gt;With this, you can make the same MongoDB replica set usable from:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Internal container network (using internal hostnames/IPs)&lt;/li&gt;
&lt;li&gt;External applications (using public IPs or DNS names)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;MongoDB’s horizons rely on Server Name Indication (SNI) during the TLS handshake to determine which hostname and port to advertise. At connection time, clients present the hostname they used, and MongoDB uses that to return the proper set of endpoints. For that reason TLS is required in order for horizons to work.&lt;/p&gt;
&lt;p&gt;Let’s walk through an example.&lt;/p&gt;
&lt;h2 id="example-scenario-mongodb-replica-set-in-docker"&gt;Example Scenario: MongoDB Replica Set in Docker&lt;/h2&gt;
&lt;p&gt;You can run the following steps on your local machine to test the feature.&lt;/p&gt;
&lt;h3 id="get-your-certificates-ready"&gt;Get your certificates ready&lt;/h3&gt;
&lt;p&gt;Let’s start by creating the required CA and certificates using &lt;a href="https://github.com/cloudflare/cfssl" target="_blank" rel="noopener noreferrer"&gt;Cloudflare’s PKI and TLS toolkit&lt;/a&gt;.&lt;/p&gt;
&lt;h4 id="step-1-create-ca-csrjson"&gt;Step 1: Create ca-csr.json&lt;/h4&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-2" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-2"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkdir certs
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cd certs
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tee ca-csr.json &lt;&lt;EOF
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "CN": "MyTestCA",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "key": { "algo": "rsa", "size": 2048 },
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "names": [{ "C": "US", "ST": "CA", "L": "SF", "O": "Acme", "OU": "MongoDB CA" }]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;EOF&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Generate the CA:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-3" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-3"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ cfssl gencert -initca ca-csr.json | cfssljson -bare ca&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This creates:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ca.pem — CA certificate&lt;/li&gt;
&lt;li&gt;ca-key.pem — CA private key&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="step-2-create-server-csrjson-for-each-server-specifying-both-internal-and-external-names-in-the-hosts-section-so-that-our-certificate-is-valid-for-everything"&gt;Step 2: Create server-csr.json for each server, specifying both internal and external names in the “hosts” section so that our certificate is valid for everything.&lt;/h4&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-4" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-4"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;for i in 1 2 3; do
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; name="mongo$i"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; tee "${name}-csr.json" &lt;&lt;EOF
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "CN": "${name}",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "hosts": ["${name}", "${name}.internal", "localhost", "127.0.0.1"],
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "key": { "algo": "rsa", "size": 2048 },
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "names": [
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; { "O": "MongoDB", "OU": "Database", "L": "Internal", "ST": "DC", "C": "US" }
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;EOF
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;done&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h4 id="step-3-generate-certificates-using-cfssl"&gt;Step 3: Generate certificates using CFSSL&lt;/h4&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-5" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-5"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;for i in 1 2 3; do
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; name="mongo$i"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; cfssl gencert \
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -ca=ca.pem -ca-key=ca-key.pem \
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -config=&lt;(cat &lt;&lt;'JSON'
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "signing": {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "default": {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "expiry": "8760h",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "usages": [
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "signing",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "key encipherment",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "server auth",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "client auth"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;JSON
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;) "${name}-csr.json" | cfssljson -bare "${name}"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat "${name}.pem" "${name}-key.pem" &gt; "${name}-combined.pem"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;done
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cd ..&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Resulting files:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;mongo{1,2,3}.pem — cert for server&lt;/li&gt;
&lt;li&gt;mongo{1,2,3}-key.pem, key for server&lt;/li&gt;
&lt;li&gt;mongo{1,2,3}-combined.pem, both in a single file as expected by mongo&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="docker-compose-setup"&gt;Docker Compose Setup&lt;/h3&gt;
&lt;p&gt;Create a file with docker compose configuration:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-6" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-6"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tee test-horizons.yml &lt;&lt;EOF
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;name: horizons
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;services:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; mongo1:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; container_name: mongo1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; image: percona/percona-server-mongodb:latest
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; volumes:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - ./certs:/certs
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ports:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - "27017:27017"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; command: &gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; mongod --replSet rs0 --bind_ip_all
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --tlsMode requireTLS
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --tlsCertificateKeyFile /certs/mongo1-combined.pem
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --tlsCAFile /certs/ca.pem
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; mongo2:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; container_name: mongo2
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; image: percona/percona-server-mongodb:latest
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; volumes:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - ./certs:/certs
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ports:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - "27018:27017"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; command: &gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; mongod --replSet rs0 --bind_ip_all
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --tlsMode requireTLS
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --tlsCertificateKeyFile /certs/mongo2-combined.pem
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --tlsCAFile /certs/ca.pem
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; mongo3:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; container_name: mongo3
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; image: percona/percona-server-mongodb:latest
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; volumes:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - ./certs:/certs
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ports:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - "27019:27017"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; command: &gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; mongod --replSet rs0 --bind_ip_all
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --tlsMode requireTLS
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --tlsCertificateKeyFile /certs/mongo3-combined.pem
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --tlsCAFile /certs/ca.pem
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;networks:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; default:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; driver: bridge
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;EOF&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Here we are mapping our containers to ports 27017, 27018 and 27109 externally.&lt;/p&gt;
&lt;p&gt;Now, start the services:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-7" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-7"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ docker-compose -f test-horizons.yml up -d&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="initiate-the-replica-set-with-horizons"&gt;Initiate the Replica Set with Horizons&lt;/h3&gt;
&lt;p&gt;Now let’s initiate the replica set with different host names and ports for external access.&lt;/p&gt;
&lt;p&gt;Launch a shell into one of the containers:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-8" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-8"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ docker exec -it mongo1 /bin/bash&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Authenticate and initialize the replica set with this config:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-9" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-9"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ mongosh --tls --tlsCertificateKeyFile /certs/mongo1-combined.pem --tlsAllowInvalidCertificates
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rs.initiate({
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; _id: "rs0",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; members: [
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; _id: 0,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; host: "mongo1:27017",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; horizons: { external: "localhost:27017" }
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; _id: 1,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; host: "mongo2:27017",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; horizons: { external: "localhost:27018" }
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; _id: 2,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; host: "mongo3:27017",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; horizons: { external: "localhost:27019" }
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;})&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Note: The “horizon” field here maps the external context to a different address than the internal one. Since we are going to test connecting from the local machine directly to the containers, set the horizons to localhost and the mapped ports.&lt;/p&gt;
&lt;h3 id="connect-from-inside-docker"&gt;Connect from Inside Docker&lt;/h3&gt;
&lt;p&gt;Spin up a new containerized client, or use one of the existing MongoDB containers:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-10" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-10"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ docker exec -it mongo1 mongosh --host rs0/mongo1:27017,mongo2:27017,mongo3:27017 --tls --tlsCertificateKeyFile /certs/mongo1-combined.pem --tlsCAFile /certs/ca.pem
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Current Mongosh Log ID: 6877deab6568339f46dfd9c4
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Connecting to: mongodb://mongo1:27017,mongo2:27017,mongo3:27017/?replicaSet=rs0&amp;tls=true&amp;tlsCertificateKeyFile=%2Fcerts%2Fmongo1-combined.pem&amp;tlsCAFile=%2Fcerts%2Fca.pem&amp;appName=mongosh+2.5.0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Using MongoDB: 8.0.8-3
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Using Mongosh: 2.5.0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rs0 [primary] test&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;It connects using internal Docker hostnames.&lt;/p&gt;
&lt;h3 id="connect-from-outside-docker"&gt;Connect from Outside Docker&lt;/h3&gt;
&lt;p&gt;From your local machine:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-11" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-11"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ mongosh "mongodb://localhost:27017,localhost:27018,localhost:27019/?replicaSet=rs0" --tls --tlsCertificateKeyFile /certs/mongo1-combined.pem --tlsCAFile /certs/ca.pem
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Current Mongosh Log ID: 6877defabc3f9a2d054a1296
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Connecting to: mongodb://localhost:27017,localhost:27018,localhost:27019/?replicaSet=rs0&amp;serverSelectionTimeoutMS=2000&amp;tls=true&amp;tlsCertificateKeyFile=certs%2Fmongo1-combined.pem&amp;tlsCAFile=certs%2Fca.pem&amp;appName=mongosh+2.3.1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Using MongoDB: 8.0.8-3
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Using Mongosh: 2.3.1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rs0 [primary] test&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="check-the-identities-returned"&gt;Check the identities returned&lt;/h3&gt;
&lt;p&gt;As we have seen, MongoDB will resolve the external horizon names and connect successfully in both cases. You can verify the advertised hostnames and ports for the external connection:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-12" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-12"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rs0 [primary] test&gt; db.hello()
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; topologyVersion: {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; processId: ObjectId('6877de4c632adf89fb590f38'),
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; counter: Long('6')
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; hosts: [ 'localhost:27017', 'localhost:27018', 'localhost:27019' ],
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; setName: 'rs0',
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; setVersion: 1,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; isWritablePrimary: true,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; secondary: false,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; primary: 'localhost:27017',
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; me: 'localhost:27017',
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Versus the internal case:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-13" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-13"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rs0 [primary] test&gt; db.hello()
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; topologyVersion: {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; processId: ObjectId('6877de4c632adf89fb590f38'),
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; counter: Long('6')
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; hosts: [ 'mongo1:27017', 'mongo2:27017', 'mongo3:27017' ],
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; setName: 'rs0',
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; setVersion: 1,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; isWritablePrimary: true,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; secondary: false,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; primary: 'mongo1:27017',
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; me: 'mongo1:27017',
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;The horizons feature in MongoDB is a powerful tool to bridge the gap between internal and external connectivity, especially in containerized or multi-network deployments.&lt;/p&gt;
&lt;p&gt;Horizon also has following limitations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Using horizons is only possible with TLS connections&lt;/li&gt;
&lt;li&gt;Duplicating domain names in horizons is not allowed by MongoDB&lt;/li&gt;
&lt;li&gt;Using IP addresses in horizons definitions is not allowed by MongoDB&lt;/li&gt;
&lt;li&gt;Horizons should be set for all members of a replica set, or not set at all&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This feature is not listed in the official MongoDB documentation for some reason, however it is available in both Percona Server for MongoDB and MongoDB Community Edition. Also, Kubernetes users rejoice! &lt;a href="https://docs.percona.com/percona-operator-for-mongodb/expose.html?h=split#exposing-replica-set-with-split-horizon-dns" target="_blank" rel="noopener noreferrer"&gt;Percona Operator for MongoDB supports horizons&lt;/a&gt; since version 1.16.&lt;/p&gt;</content:encoded>
      <author>Ivan Groenewold</author>
      <category>MongoDB</category>
      <category>Opensource</category>
      <media:thumbnail url="https://percona.community/blog/2025/07/ivan_cover_hu_252d99e16859146e.jpg"/>
      <media:content url="https://percona.community/blog/2025/07/ivan_cover_hu_51c601d52e2aec6.jpg" medium="image"/>
    </item>
    <item>
      <title>What's new in PMM 3.2.0: Five major improvements you need to know</title>
      <link>https://percona.community/blog/2025/06/03/percona-monitoring-management-3-2-five-improvements/</link>
      <guid>https://percona.community/blog/2025/06/03/percona-monitoring-management-3-2-five-improvements/</guid>
      <pubDate>Tue, 03 Jun 2025 00:00:00 UTC</pubDate>
      <description>PMM 3.2.0 brings some long-awaited fixes and new capabilities. You can now install PMM Client on Amazon Linux 2023 with proper RPM packages, get complete MySQL 8.4 replication monitoring, and track MongoDB backups directly in PMM.</description>
      <content:encoded>&lt;p&gt;PMM 3.2.0 brings some long-awaited fixes and new capabilities. You can now install PMM Client on Amazon Linux 2023 with proper RPM packages, get complete MySQL 8.4 replication monitoring, and track MongoDB backups directly in PMM.&lt;/p&gt;
&lt;p&gt;Here’s what’s most important in this release:&lt;/p&gt;
&lt;h2 id="1-native-amazon-linux-2023-support---no-more-workarounds"&gt;1. Native Amazon Linux 2023 support - no more workarounds&lt;/h2&gt;
&lt;p&gt;What’s new: If you’ve been running PMM Client on AL2023 and dealing with complex manual installations, those days are over. You can now install PMM Client through &lt;a href="https://repo.percona.com" target="_blank" rel="noopener noreferrer"&gt;native RPM packages&lt;/a&gt; just like any other supported platform.&lt;/p&gt;
&lt;p&gt;What this means for you: Streamlined setup means you can get your Amazon Linux 2023 environments monitored faster.&lt;/p&gt;
&lt;h2 id="2-complete-mysql-84-replication-monitoring"&gt;2. Complete MySQL 8.4 replication monitoring&lt;/h2&gt;
&lt;p&gt;What’s new: PMM now fully supports replication monitoring for MySQL 8.4, including key metrics like IO Thread status, SQL Thread status, and Replication Lag. MySQL 8.4 changed how these metrics are exposed, and earlier PMM versions couldn’t track them accurately.&lt;/p&gt;
&lt;p&gt;What this means for you: With the upgraded MySQL Exporter (v0.17.2), you now get complete replication monitoring across all supported MySQL versions (5.7, 8.0, and 8.4) without any visibility gaps.&lt;/p&gt;
&lt;h2 id="3-mongodb-backup-monitoring-dashboard"&gt;3. MongoDB backup monitoring dashboard&lt;/h2&gt;
&lt;p&gt;What’s new: The new &lt;a href="https://docs.percona.com/percona-monitoring-and-management/3/reference/dashboards/dashboard-mongodb-PBM-details.html" target="_blank" rel="noopener noreferrer"&gt;PBM Details dashboard &lt;/a&gt;lets you monitor MongoDB backups directly in PMM using the PBM collector. Instead of switching between PMM and separate backup tools, you now get a real-time, unified view of backup activity across replica sets and sharded clusters.&lt;/p&gt;
&lt;p&gt;What this means for you: Easily track backup status, configuration, size, duration, PITR status, and recent successful backups—all in one place. No more tool-hopping to stay on top of your backup operations.&lt;/p&gt;
&lt;h2 id="4-grafana-116-upgrade-with-enhanced-capabilities"&gt;4. Grafana 11.6 upgrade with enhanced capabilities&lt;/h2&gt;
&lt;p&gt;What’s new: PMM now ships with Grafana 11.6, delivering enhanced visualization capabilities and improved alerting workflows.&lt;/p&gt;
&lt;p&gt;Key features include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Alert state history for reviewing historical changes in alert statuses&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Improved panel features and visualization actions&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Simplified alert creation with better UI workflows&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Recording rules for creating pre-computed metrics&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Navigation bookmarks for quick dashboard access&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What this means for you: These enhancements make your monitoring dashboards more interactive, your alerting more sophisticated, and your overall monitoring workflow more efficient.&lt;/p&gt;
&lt;h2 id="5-dramatically-improved-query-analytics-performance"&gt;5. Dramatically improved Query Analytics performance&lt;/h2&gt;
&lt;p&gt;What’s new: We’ve optimized QAN filter loading performance to reduce the number of processed rows by up to 95% in large environments.&lt;/p&gt;
&lt;p&gt;What this means for you: Filters on the &lt;a href="https://docs.percona.com/percona-monitoring-and-management/3/use/qan/index.html?h=query+ana" target="_blank" rel="noopener noreferrer"&gt;PMM Query Analytics page&lt;/a&gt; now load much faster, making the interface more responsive to improve your troubleshooting efficiency.&lt;/p&gt;
&lt;h2 id="additional-improvements-worth-noting"&gt;Additional improvements worth noting&lt;/h2&gt;
&lt;p&gt;Beyond these five major enhancements, PMM 3.2.0 also introduces:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Secure ClickHouse connections with authenticated credential support&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;MongoDB Feature Compatibility Version (FCV) panels for better cluster version visibility&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Nomad integration laying groundwork for future extensibility&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Numerous bug fixes improving stability across ProxySQL, PostgreSQL, and MySQL monitoring&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="getting-started-with-pmm-320"&gt;Getting started with PMM 3.2.0&lt;/h2&gt;
&lt;p&gt;Ready to experience these improvements? Set up your PMM 3.2.0 instance using our &lt;a href="https://docs.percona.com/percona-monitoring-and-management/3/quickstart/quickstart.html" target="_blank" rel="noopener noreferrer"&gt;quickstart guide&lt;/a&gt; or upgrade your existing installation following our &lt;a href="https://docs.percona.com/percona-monitoring-and-management/3/pmm-upgrade/migrating_from_pmm_2.html" target="_blank" rel="noopener noreferrer"&gt;migration documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For existing users with external PostgreSQL databases, make sure to review the &lt;a href="https://docs.percona.com/percona-monitoring-and-management/3/pmm-upgrade/external_postgres_pmm_upgrade.html" target="_blank" rel="noopener noreferrer"&gt;external PostgreSQL configuration migration guide&lt;/a&gt; before upgrading.&lt;/p&gt;
&lt;p&gt;Questions or feedback? We’d love to hear from you! Connect with the Percona community through our &lt;a href="https://forums.percona.com/c/percona-monitoring-and-management-pmm/30/none" target="_blank" rel="noopener noreferrer"&gt;forums&lt;/a&gt; or join the conversation on our community channels.&lt;/p&gt;</content:encoded>
      <author>Catalina Adam</author>
      <category>PMM</category>
      <category>Monitoring</category>
      <category>Percona</category>
      <category>Databases</category>
      <media:thumbnail url="https://percona.community/blog/2025/06/PMM-32-five_hu_b44082c6b85bf6ef.jpg"/>
      <media:content url="https://percona.community/blog/2025/06/PMM-32-five_hu_9306982df4fa628.jpg" medium="image"/>
    </item>
    <item>
      <title>OS Platform End of Life (EOL) Announcement for Ubuntu 20.04 LTS</title>
      <link>https://percona.community/blog/2025/05/22/os-platform-end-of-life-eol-announcement-for-ubuntu-20.04-lts/</link>
      <guid>https://percona.community/blog/2025/05/22/os-platform-end-of-life-eol-announcement-for-ubuntu-20.04-lts/</guid>
      <pubDate>Thu, 22 May 2025 00:00:00 UTC</pubDate>
      <description>Ubuntu 20.04 LTS (Focal Fossa) is scheduled to reach its official end of life on May 31, 2025. In alignment with the upstream vendor’s lifecycle, we are also ending platform support for Ubuntu 20.04 for all our MySQL related product offerings. This date and others are published in advance on our Percona Release Lifecycle Overview page.</description>
      <content:encoded>&lt;p&gt;&lt;a href="https://ubuntu.com/blog/ubuntu-20-04-lts-end-of-life-standard-support-is-coming-to-an-end-heres-how-to-prepare" target="_blank" rel="noopener noreferrer"&gt;Ubuntu 20.04 LTS&lt;/a&gt; (Focal Fossa) is scheduled to reach its official end of life on &lt;strong&gt;May 31, 2025&lt;/strong&gt;. In alignment with the upstream vendor’s lifecycle, we are also ending platform support for Ubuntu 20.04 for all our MySQL related product offerings. This date and others are published in advance on our &lt;a href="https://www.percona.com/services/policies/percona-software-support-lifecycle" target="_blank" rel="noopener noreferrer"&gt;Percona Release Lifecycle Overview&lt;/a&gt; page.&lt;/p&gt;
&lt;p&gt;As part of our support policy, &lt;strong&gt;Percona will continue to provide advisory support for databases running on EOL platforms&lt;/strong&gt;, but effective &lt;strong&gt;April 1, 2025&lt;/strong&gt;, we have discontinued:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Delivery of new packages or binary builds&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Distribution of hotfixes or bug fixes for Percona software on Ubuntu 20.04&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;OS-level support for issues not related to the database itself&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;However, all existing packages will remain available for download.&lt;/p&gt;
&lt;p&gt;We are committed to ensuring a smooth and seamless experience for our users. Migrating to a supported operating system will ensure that you continue to receive security updates, bug fixes, and new features for our products.&lt;/p&gt;
&lt;p&gt;We encourage you to take action promptly and plan your migration from Ubuntu Focal to a supported operating system. Each operating system vendor has different supported migration or upgrade paths to their next major release. Please &lt;a href="https://www.percona.com/services" target="_blank" rel="noopener noreferrer"&gt;contact us&lt;/a&gt; if you need assistance migrating your database to a different supported OS platform – we will be happy to assist you!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; If requested by a customer, we may provide updated Percona packages for up to six months beyond the Percona EOL date, as a courtesy grace period.&lt;/p&gt;</content:encoded>
      <author>Julia Vural</author>
      <category>Ubuntu</category>
      <category>Opensource</category>
      <media:thumbnail url="https://percona.community/blog/2025/05/eol-ubuntu_hu_d33ab1f53ade240d.jpg"/>
      <media:content url="https://percona.community/blog/2025/05/eol-ubuntu_hu_78dbe9450f5c4a1.jpg" medium="image"/>
    </item>
    <item>
      <title>Setting Up and Monitoring MongoDB 8 Replica Sets with PMM 3 Using Docker: A Beginner-Friendly Guide</title>
      <link>https://percona.community/blog/2025/03/18/setting-up-and-monitoring-mongodb-8-replica-sets-with-pmm-3-using-docker-a-beginner-friendly-guide/</link>
      <guid>https://percona.community/blog/2025/03/18/setting-up-and-monitoring-mongodb-8-replica-sets-with-pmm-3-using-docker-a-beginner-friendly-guide/</guid>
      <pubDate>Tue, 18 Mar 2025 00:00:00 UTC</pubDate>
      <description>This guide explains how to set up a MongoDB 8 Replica Set and monitor it using PMM 3, all within Docker. We’ll guide you through the steps to create a local environment, configure the necessary components, and connect them for effective monitoring and management.</description>
      <content:encoded>&lt;p&gt;This guide explains how to set up a MongoDB 8 Replica Set and monitor it using PMM 3, all within Docker. We’ll guide you through the steps to create a local environment, configure the necessary components, and connect them for effective monitoring and management.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The guide is written in detail for beginners. In &lt;a href="#conclusion"&gt;the conclusion&lt;/a&gt; section there are ready configurations for the experienced.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;The recent &lt;a href="https://docs.percona.com/percona-monitoring-and-management/3/release-notes/3.0.0.html" target="_blank" rel="noopener noreferrer"&gt;release&lt;/a&gt; of &lt;a href="https://docs.percona.com/percona-monitoring-and-management/3/index.html" target="_blank" rel="noopener noreferrer"&gt;Percona Monitoring and Management 3&lt;/a&gt; introduces several new features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Upgraded Grafana version for an improved user experience.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Rootless containers for enhanced security.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;ARM support for the pmm-client.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Monitoring capabilities for MongoDB 8, along with &lt;a href="https://docs.percona.com/percona-monitoring-and-management/3/reference/dashboards/dashboard-mongodb-router-summary.html" target="_blank" rel="noopener noreferrer"&gt;new dashboards&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This article is intended for developers and DBAs who want to experiment with these tools locally using Docker. We will cover the following steps to set everything up and test the functionality:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Launch the PMM 3 pmm-server for monitoring and open it in a browser.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Install MongoDB, starting with a standalone server, and then convert it into a Replica Set with three nodes. &lt;a href="https://www.percona.com/mongodb/software/percona-server-for-mongodb" target="_blank" rel="noopener noreferrer"&gt;Percona Server for MongoDB&lt;/a&gt; images are used in this article.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Configure the pmm-client for MongoDB to send metrics to the pmm-server.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Explore the PMM 3 &lt;a href="https://docs.percona.com/percona-monitoring-and-management/3/reference/dashboards/dashboard-mongodb-router-summary.html" target="_blank" rel="noopener noreferrer"&gt;dashboards&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2025/03/pmm-mongodb-rs_hu_8e877e10d43414f4.png 480w, https://percona.community/blog/2025/03/pmm-mongodb-rs_hu_4f9758ca9365ee98.png 768w, https://percona.community/blog/2025/03/pmm-mongodb-rs_hu_42d0c424fcd5e4b8.png 1400w"
src="https://percona.community/blog/2025/03/pmm-mongodb-rs.png" alt="Percona Monitoring and Management (PMM) 3.0.0 - Dashboard - MongoDB Replica Set Overview" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;We will use Docker Compose to define and run multiple containers efficiently through a single &lt;code&gt;docker-compose.yaml&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;If you’re ready to dive into the world of Dockerized database monitoring and management, let’s get started!&lt;/p&gt;
&lt;h2 id="step-zero-preparation"&gt;Step Zero: Preparation&lt;/h2&gt;
&lt;p&gt;To get started, you need a terminal to run Docker commands and a text editor to modify the docker-compose.yaml file.&lt;/p&gt;
&lt;p&gt;You also need Docker installed on your system. If Docker is not installed, follow these instructions to set it up:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Docker Desktop: This application includes both Docker and Docker Compose. It is available for multiple operating systems. This guide uses Docker Desktop on macOS with an Apple Silicon ARM processor. &lt;a href="https://www.docker.com/products/docker-desktop/" target="_blank" rel="noopener noreferrer"&gt;Download Docker Desktop&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Docker and Docker Compose (separately): If preferred, install Docker and Docker Compose individually. Use the following links for guidance:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://www.docker.com/get-started/" target="_blank" rel="noopener noreferrer"&gt;Download Docker for your OS&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://docs.docker.com/compose/install/" target="_blank" rel="noopener noreferrer"&gt;Download Docker Compose&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="command-to-verify-installation"&gt;Command to Verify Installation:&lt;/h3&gt;
&lt;p&gt;Verify Docker Compose Installation: If you’re using Docker Desktop, Docker Compose is included. If you installed Docker Compose separately, you can verify the installation with:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sh&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker-compose --version&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This should return the version of Docker Compose installed.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sh&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-1"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;➜ community git:&lt;span class="o"&gt;(&lt;/span&gt;main&lt;span class="o"&gt;)&lt;/span&gt; ✗ docker-compose --version
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Docker Compose version v2.21.0-desktop.1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Once Docker and Docker Compose are installed and verified, you are ready to move on to the next steps of deploying PMM 3 and MongoDB in Docker.&lt;/p&gt;
&lt;h3 id="project-directory"&gt;Project Directory&lt;/h3&gt;
&lt;p&gt;Create a directory where we’ll store the configuration and necessary files. For example, I created a directory named pmm-mongodb-setup and navigated into it.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-2" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-2"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkdir pmm-mongodb-setup
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; pmm-mongodb-setup&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="step-one-starting-pmm-3-using-docker-compose"&gt;Step One: Starting PMM 3 Using Docker Compose&lt;/h2&gt;
&lt;p&gt;To start with, we will launch PMM 3, specifically the pmm-server, which we will later access via a browser.&lt;/p&gt;
&lt;h3 id="create-the-docker-compose-configuration-file"&gt;Create the Docker Compose Configuration File&lt;/h3&gt;
&lt;p&gt;First, create a file named &lt;code&gt;docker-compose.yaml&lt;/code&gt; in your project directory. Then, copy and paste the following configuration into the file to set up PMM 3:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;yaml&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-3" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-3"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'3'&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;services&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;pmm-server&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;percona/pmm-server:3&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;platform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"linux/amd64"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# Specifies that Docker should use the image for the amd64 architecture, which is necessary if the container doesn't support ARM and your host system is ARM (e.g., Mac with Apple Silicon).&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;container_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;pmm-server&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="m"&gt;8080&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;80&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="m"&gt;443&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;8443&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;healthcheck&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# Defines a command to check the container's health and sets the timing for executions and retries.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;test&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"CMD-SHELL"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"curl -k -f -L https://pmm-server:8443 &gt; /dev/null 2&gt;&amp;1 || exit 1"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;30s&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;10s&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;retries&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;p&gt;We define the first &lt;code&gt;pmm-server&lt;/code&gt; service to use the &lt;code&gt;percona/pmm-server:3&lt;/code&gt; image&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;platform&lt;/code&gt;: This parameter ensures compatibility with ARM-based processors, such as my Mac with Apple Silicon, by instructing Docker to use the image for the amd64 architecture.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;healthcheck&lt;/code&gt;: This parameter performs a check to confirm that the container has started successfully.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;/blockquote&gt;
&lt;h3 id="start-the-pmm-3-container"&gt;Start the PMM 3 Container&lt;/h3&gt;
&lt;p&gt;Save the &lt;code&gt;docker-compose.yaml&lt;/code&gt; file, and then use the following command to start the PMM 3 container:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;shell&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-4" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-4"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker-compose up -d&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This command will download the PMM 3 image if it is not already available locally and start the container in detached mode.&lt;/p&gt;
&lt;p&gt;Expected result in the terminal:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;shell&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-5" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-5"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;➜ pmm-mongodb-setup docker-compose up -d
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;+&lt;span class="o"&gt;]&lt;/span&gt; Running 2/2
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ✔ Network pmm-mongodb-setup_default Created 0.1s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ✔ Container pmm-server Started 0.9s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;➜ pmm-mongodb-setup&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Expected result in Docker Desktop:
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2025/03/docker-pmm-start_hu_3909e5a4671f6495.png 480w, https://percona.community/blog/2025/03/docker-pmm-start_hu_898ccea59f593e2b.png 768w, https://percona.community/blog/2025/03/docker-pmm-start_hu_ad0659857f814903.png 1400w"
src="https://percona.community/blog/2025/03/docker-pmm-start.png" alt="Percona Monitoring and Management (PMM) 3.0.0 - Docker Desktop Start" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h3 id="open-pmm-in-a-browser"&gt;Open PMM in a browser&lt;/h3&gt;
&lt;p&gt;Now you can open PMM in your browser at http://localhost. Use admin/admin as the username and password to log in. When prompted to change the password, skip this step by clicking the Skip button. Since this is a test setup, we need a simple password for other containers.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2025/03/pmm-login.png" alt="Percona Monitoring and Management (PMM) 3.0.0 - Login" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2025/03/pmm-home_hu_6f0a507496133b77.png 480w, https://percona.community/blog/2025/03/pmm-home_hu_1406d5f6bdc98fc6.png 768w, https://percona.community/blog/2025/03/pmm-home_hu_6568e254d94ccb86.png 1400w"
src="https://percona.community/blog/2025/03/pmm-home.png" alt="Percona Monitoring and Management (PMM) 3.0.0 - Home Page" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Now, PMM 3 is successfully running using Docker Compose.&lt;/p&gt;
&lt;h2 id="step-two-starting-mongodb"&gt;Step Two: Starting MongoDB&lt;/h2&gt;
&lt;p&gt;We start by launching a standalone MongoDB service. This simple configuration allows us to quickly understand how it operates before moving on to a more advanced setup with a Replica Set.&lt;/p&gt;
&lt;p&gt;To keep the database data persistent, even after a restart, a &lt;code&gt;volume&lt;/code&gt; is used for MongoDB data storage. Add the following configuration to the &lt;code&gt;docker-compose.yaml&lt;/code&gt; file under the &lt;code&gt;pmm-server&lt;/code&gt; service:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;yaml&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-6" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-6"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;mongodb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"percona/percona-server-mongodb:8.0-multi"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;mongodb-data:/data/db&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;MONGO_INITDB_ROOT_USERNAME&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;databaseAdmin&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;MONGO_INITDB_ROOT_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;password&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s2"&gt;"27017:27017"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"mongod"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"--port"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"27017"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"--bind_ip_all"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"--profile"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"--slowms"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"200"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"--rateLimit"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"100"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;healthcheck&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;test&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"CMD-SHELL"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mongosh --eval 'db.adminCommand(\"ping\")' --quiet"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;30s&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;10s&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;retries&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;mongodb-data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# MongoDB data storage volume&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;environment&lt;/code&gt;: Configures the root user’s credentials (username and password).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;command&lt;/code&gt;: Sets additional parameters for MongoDB:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;bind_ip_all&lt;/code&gt;: Allows external access to the database, for instance, through MongoDB Compass.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;profile&lt;/code&gt;: Enables profiling settings to support Query Analytics (QAN) in PMM.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;healthcheck&lt;/code&gt;: Ensures the container starts successfully by executing a health check command.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;volumes:&lt;/code&gt;: Creates the specified volume for MongoDB data storage. Defines a Docker volume to store MongoDB data persistently.&lt;/li&gt;
&lt;/ul&gt;&lt;/blockquote&gt;
&lt;h3 id="launching-the-configuration"&gt;Launching the Configuration&lt;/h3&gt;
&lt;p&gt;Save the updated &lt;code&gt;docker-compose.yaml&lt;/code&gt; file and launch the MongoDB service by running the following command:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sh&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-7" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-7"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker-compose up -d&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Docker Compose checks the configuration and starts the MongoDB container.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sh&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-8" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-8"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;➜ pmm-mongodb-setup docker-compose up -d
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;+&lt;span class="o"&gt;]&lt;/span&gt; Running 3/3
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ✔ Volume &lt;span class="s2"&gt;"pmm-mongodb-setup_mongodb-data"&lt;/span&gt; Created 0.0s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ✔ Container pmm-mongodb-setup-mongodb-1 Started 0.1s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ✔ Container pmm-server Running 0.0s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;➜ pmm-mongodb-setup&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Verifying MongoDB in Docker Desktop:&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2025/03/docker-pmm-mongodb_hu_bb9842f0502a5d59.png 480w, https://percona.community/blog/2025/03/docker-pmm-mongodb_hu_171053abe6d42b2.png 768w, https://percona.community/blog/2025/03/docker-pmm-mongodb_hu_33937ddce310b985.png 1400w"
src="https://percona.community/blog/2025/03/docker-pmm-mongodb.png" alt="Percona Monitoring and Management (PMM) 3.0.0 - Docker Desktop MongoDB" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h2 id="step-three-pmm-client"&gt;Step Three: PMM Client&lt;/h2&gt;
&lt;p&gt;At this point, we have both the PMM Server, which is accessible in the browser, and MongoDB running. To transfer metrics from MongoDB to the PMM Server, a container with &lt;code&gt;pmm-client&lt;/code&gt; needs to be started.&lt;/p&gt;
&lt;p&gt;Add another service &lt;code&gt;pmm-client&lt;/code&gt; to the &lt;code&gt;docker-compose.yaml&lt;/code&gt; file, right after &lt;code&gt;mongodb&lt;/code&gt;. Note that `volumes:`` must remain at the bottom of the file.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;yaml&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-9" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-9"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;pmm-client&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;percona/pmm-client:3&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;container_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;pmm-client&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;depends_on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;pmm-server&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;condition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;service_healthy&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;mongodb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;condition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;service_healthy&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;PMM_AGENT_SERVER_ADDRESS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;pmm-server:8443&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;PMM_AGENT_SERVER_USERNAME&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;admin&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;PMM_AGENT_SERVER_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;admin&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;PMM_AGENT_SERVER_INSECURE_TLS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;PMM_AGENT_CONFIG_FILE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;config/pmm-agent.yaml&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;PMM_AGENT_SETUP&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;PMM_AGENT_SETUP_FORCE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;PMM_AGENT_PRERUN_SCRIPT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&gt;&lt;/span&gt;&lt;span class="sd"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; pmm-admin status --wait=10s &amp;&amp;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; pmm-admin add mongodb --username=databaseAdmin --password=password --host=mongodb --port=27017 --query-source=profiler&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;depends_on&lt;/code&gt;: Ensures that pmm-client starts only after pmm-server and mongodb have started successfully and passed the healthcheck.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PMM_AGENT_PRERUN_SCRIPT&lt;/code&gt;: The pmm-admin add mongodb command adds the MongoDB service to PMM for monitoring.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PMM_AGENT_SERVER_ADDRESS&lt;/code&gt;: Specifies the PMM Server address and uses port 8443.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PMM_AGENT_SERVER_USERNAME&lt;/code&gt; and &lt;code&gt;PMM_AGENT_SERVER_PASSWORD&lt;/code&gt;: Update these values if you have changed the PMM login credentials.&lt;/li&gt;
&lt;/ul&gt;&lt;/blockquote&gt;
&lt;h3 id="applying-the-updated-configuration"&gt;Applying the Updated Configuration&lt;/h3&gt;
&lt;p&gt;Run the following command to apply the updated docker-compose.yaml configuration and start the pmm-client service:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sh&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-10" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-10"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker-compose up -d&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;After running the command, you should see the pmm-client container start successfully:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sh&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-11" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-11"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;➜ pmm-mongodb-setup docker-compose up -d
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;+&lt;span class="o"&gt;]&lt;/span&gt; Running 3/3
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ✔ Container pmm-mongodb-setup-mongodb-1 Healthy 0.0s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ✔ Container pmm-server Healthy 0.0s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ✔ Container pmm-client Started 0.1s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;➜ pmm-mongodb-setup&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Open PMM in your browser. On the homepage, you should now see MongoDB listed as a monitored service:&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2025/03/pmm-home-mongodb_hu_b6fcfc17c39e35b2.png 480w, https://percona.community/blog/2025/03/pmm-home-mongodb_hu_45fe2e0cc9332840.png 768w, https://percona.community/blog/2025/03/pmm-home-mongodb_hu_7c396f8ba7d7098.png 1400w"
src="https://percona.community/blog/2025/03/pmm-home-mongodb.png" alt="Percona Monitoring and Management (PMM) 3.0.0 - PMM MongoDB" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h2 id="step-four-convert-a-standalone-mongodb-to-a-replica-set"&gt;Step Four: Convert a Standalone MongoDB to a Replica Set&lt;/h2&gt;
&lt;p&gt;A single MongoDB instance works well for development and testing. At this point, you can already connect to the database from your application or tools such as MongoDB Compass and run various NoSQL queries.&lt;/p&gt;
&lt;p&gt;However, the goal is to deploy a Replica Set consisting of three replicas, which is recommended for production and operational setups. For now, we set up the Replica Set on a single machine with a single docker-compose, which is intended for testing and development purposes only.&lt;/p&gt;
&lt;p&gt;Both the mongodb and pmm-client services need to be updated.&lt;/p&gt;
&lt;h3 id="stopping-all-services"&gt;Stopping All Services&lt;/h3&gt;
&lt;p&gt;First, stop all the currently running services:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sh&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-12" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-12"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker-compose down &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Result:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sh&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-13" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-13"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;➜ pmm-mongodb-setup docker-compose down
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;+&lt;span class="o"&gt;]&lt;/span&gt; Running 4/4
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ✔ Container pmm-client Removed 0.3s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ✔ Container pmm-mongodb-setup-mongodb-1 Removed 0.4s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ✔ Container pmm-server Removed 4.5s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ✔ Network pmm-mongodb-setup_default Removed&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="generating-a-key-file"&gt;Generating a Key File&lt;/h3&gt;
&lt;p&gt;To run three MongoDB replicas that can securely communicate with each other, a key file is required.&lt;/p&gt;
&lt;p&gt;Create a &lt;code&gt;secrets&lt;/code&gt; folder next to the &lt;code&gt;docker-compose.yaml&lt;/code&gt; file and generate the &lt;code&gt;mongodb-keyfile&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sh&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-14" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-14"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkdir secrets
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;openssl rand -base64 &lt;span class="m"&gt;128&lt;/span&gt; &gt; secrets/mongodb-keyfile
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;chmod &lt;span class="m"&gt;600&lt;/span&gt; secrets/mongodb-keyfile&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;In this case, the mongodb-keyfile will be generated inside the secrets folder. If your operating system does not support these commands, manually create the secrets folder and add a mongodb-keyfile with the following content:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-15" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-15"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rVLhIK2PhZKGxysjwMR4t1OmNppqdAzEs408hrbzg95D146mn9YENixId6pvIGCA
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Cy9hc1k6OKKabbv7Rm347NwSFxbdPPx0/jnaO80U/a6/mv0XqSmEl8wdR91b4jIm
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;d98LobplwRs4b7g9cnLMUAIULr0WG+J36NtKIA6q4eE=&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="add-three-mongodb-services-for-replica-set"&gt;Add three mongodb services for Replica Set&lt;/h3&gt;
&lt;p&gt;Remove the existing mongodb service from the docker-compose.yaml file and replace it with three Replica Set services:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;yaml&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-16" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-16"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;mongodb-rs101&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;percona/percona-server-mongodb:8.0-multi&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;container_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;mongodb-rs101&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s2"&gt;"27017:27017"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"mongod"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"--port"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"27017"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"--replSet"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"rs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"--keyFile"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/etc/secrets/mongodb-keyfile"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"--bind_ip_all"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"--profile"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"--slowms"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"200"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"--rateLimit"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"100"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;MONGO_INITDB_ROOT_USERNAME&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;databaseAdmin&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;MONGO_INITDB_ROOT_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;password&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;mongodb-data-101:/data/db&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;./secrets:/etc/secrets:ro&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;healthcheck&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;test&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"CMD-SHELL"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mongosh --host localhost --port 27017 --username databaseAdmin --password password --authenticationDatabase admin --eval 'rs.status().ok || 1'"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;30s&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;10s&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;retries&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;mongodb-rs102&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;percona/percona-server-mongodb:8.0-multi&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;container_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;mongodb-rs102&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s2"&gt;"28017:28017"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"mongod"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"--port"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"28017"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"--replSet"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"rs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"--keyFile"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/etc/secrets/mongodb-keyfile"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"--bind_ip_all"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"--profile"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"--slowms"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"200"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"--rateLimit"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"100"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;MONGO_INITDB_ROOT_USERNAME&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;databaseAdmin&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;MONGO_INITDB_ROOT_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;password&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;mongodb-data-102:/data/db&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;./secrets:/etc/secrets:ro&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;healthcheck&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;test&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"CMD-SHELL"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mongosh --host localhost --port 28017 --username databaseAdmin --password password --authenticationDatabase admin --eval 'rs.status().ok || 1'"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;30s&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;10s&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;retries&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;mongodb-rs103&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;percona/percona-server-mongodb:8.0-multi&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;container_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;mongodb-rs103&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s2"&gt;"29017:29017"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"mongod"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"--port"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"29017"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"--replSet"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"rs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"--keyFile"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/etc/secrets/mongodb-keyfile"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"--bind_ip_all"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"--profile"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"--slowms"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"200"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"--rateLimit"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"100"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;MONGO_INITDB_ROOT_USERNAME&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;databaseAdmin&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;MONGO_INITDB_ROOT_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;password&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;mongodb-data-103:/data/db&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;./secrets:/etc/secrets:ro&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;healthcheck&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;test&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"CMD-SHELL"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mongosh --host localhost --port 29017 --username databaseAdmin --password password --authenticationDatabase admin --eval 'rs.status().ok || 1'"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;30s&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;10s&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;retries&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;Key Points:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;./secrets:/etc/secrets:ro:&lt;/code&gt; Mounts the key file from your disk into the container.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;ports:&lt;/code&gt;: Each replica runs on a separate port since they are hosted on the same machine.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;command:&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;--keyFile&lt;/code&gt;: Enables replication and uses the key file for secure communication between replicas.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;--replSet&lt;/code&gt;: Defines a Replica set parameter named rs.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;healthcheck:&lt;/code&gt;: Ensures that pmm-client starts only after the Replica Set is initialized.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;/blockquote&gt;
&lt;h3 id="adding-volumes"&gt;Adding Volumes&lt;/h3&gt;
&lt;p&gt;Define three separate volumes for data storage:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;yaml&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-17" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-17"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;mongodb-data-101&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;mongodb-data-102&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;mongodb-data-103:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="initializing-the-replica-set"&gt;Initializing the Replica Set&lt;/h3&gt;
&lt;p&gt;Add another service to initialize the Replica Set (after &lt;code&gt;mongodb-rs103&lt;/code&gt;):&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;yaml&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-18" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-18"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;mongodb-rs-init&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;percona/percona-server-mongodb:8.0-multi&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;container_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;rs-init&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;depends_on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;mongodb-rs101&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;mongodb-rs102&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;mongodb-rs103&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;entrypoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sh"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"-c"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"until mongosh --host mongodb-rs101 --port 27017 --username databaseAdmin --password password --authenticationDatabase admin --eval 'print(\"waited for connection\")'; do sleep 5; done &amp;&amp; \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; mongosh --host mongodb-rs101 --port 27017 --username databaseAdmin --password password --authenticationDatabase admin --eval 'config={\"_id\":\"rs\",\"members\":[{\"_id\":0,\"host\":\"mongodb-rs101:27017\"},{\"_id\":1,\"host\":\"mongodb-rs102:28017\"},{\"_id\":2,\"host\":\"mongodb-rs103:29017\"}],\"settings\":{\"keyFile\":\"/etc/secrets/mongodb-keyfile\"}};rs.initiate(config);'"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;./secrets:/etc/secrets:ro&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This service connects to one of the replicas and initializes the Replica Set configuration.&lt;/p&gt;
&lt;h3 id="updating-pmm-client"&gt;Updating pmm-client&lt;/h3&gt;
&lt;p&gt;Finally, modify the pmm-client service to register all three Replica Set nodes:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;yaml&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-19" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-19"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;pmm-client&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;percona/pmm-client:3&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;container_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;pmm-client&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;depends_on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;pmm-server&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;condition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;service_healthy&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;mongodb-rs101&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;condition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;service_healthy&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;mongodb-rs102&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;condition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;service_healthy&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;mongodb-rs103&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;condition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;service_healthy&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;PMM_AGENT_SERVER_ADDRESS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;pmm-server:8443&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;PMM_AGENT_SERVER_USERNAME&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;admin&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;PMM_AGENT_SERVER_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;admin&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;PMM_AGENT_SERVER_INSECURE_TLS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;PMM_AGENT_CONFIG_FILE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;config/pmm-agent.yaml&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;PMM_AGENT_SETUP&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;PMM_AGENT_SETUP_FORCE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;PMM_AGENT_PRERUN_SCRIPT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&gt;&lt;/span&gt;&lt;span class="sd"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; pmm-admin status --wait=10s &amp;&amp;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; pmm-admin add mongodb --service-name=mongodb-rs101 --username=databaseAdmin --password=password --host=mongodb-rs101 --port=27017 --query-source=profiler &amp;&amp;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; pmm-admin add mongodb --service-name=mongodb-rs102 --username=databaseAdmin --password=password --host=mongodb-rs102 --port=28017 --query-source=profiler &amp;&amp;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; pmm-admin add mongodb --service-name=mongodb-rs103 --username=databaseAdmin --password=password --host=mongodb-rs103 --port=29017 --query-source=profiler&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;depends_on&lt;/code&gt;: Ensures pmm-client waits until all replicas and pmm-server are initialized.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;PMM_AGENT_PRERUN_SCRIPT&lt;/code&gt;: Adds all three replicas to PMM monitoring with the pmm-admin add mongodb command.&lt;/p&gt;&lt;/blockquote&gt;
&lt;h3 id="launching-the-configuration-1"&gt;Launching the Configuration&lt;/h3&gt;
&lt;p&gt;Start all services with:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sh&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-20" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-20"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker-compose up -d &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Expected Output:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sh&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-21" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-21"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;➜ pmm-mongodb-setup docker-compose up -d
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;+&lt;span class="o"&gt;]&lt;/span&gt; Running 10/10
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ✔ Network pmm-mongodb-setup_default Created 0.0s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ✔ Volume &lt;span class="s2"&gt;"pmm-mongodb-setup_mongodb-data-101"&lt;/span&gt; Created 0.0s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ✔ Volume &lt;span class="s2"&gt;"pmm-mongodb-setup_mongodb-data-102"&lt;/span&gt; Created 0.0s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ✔ Volume &lt;span class="s2"&gt;"pmm-mongodb-setup_mongodb-data-103"&lt;/span&gt; Created 0.0s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ✔ Container mongodb-rs103 Healthy 0.1s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ✔ Container pmm-server Healthy 1.1s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ✔ Container mongodb-rs101 Healthy 0.1s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ✔ Container mongodb-rs102 Healthy 0.1s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ✔ Container rs-init Started 0.1s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ✔ Container pmm-client Started 0.0s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;➜ pmm-mongodb-setup&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Expected Output in Docker Desktop:&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2025/03/docker-desktop-rs_hu_c171901a96bf081a.png 480w, https://percona.community/blog/2025/03/docker-desktop-rs_hu_efaca3ac6ebcd41b.png 768w, https://percona.community/blog/2025/03/docker-desktop-rs_hu_1b33539b6c1a7e52.png 1400w"
src="https://percona.community/blog/2025/03/docker-desktop-rs.png" alt="Percona Monitoring and Management (PMM) 3.0.0 - Docker Desktop MongoDB" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h3 id="verifying-in-pmm"&gt;Verifying in PMM&lt;/h3&gt;
&lt;p&gt;Open PMM and explore dashboards such as the MongoDB Replica Set Summary, which displays information about your replicas and various metrics:&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2025/03/pmm-rs-services_hu_d0ad375de0dc8708.png 480w, https://percona.community/blog/2025/03/pmm-rs-services_hu_362f4b685a1025ac.png 768w, https://percona.community/blog/2025/03/pmm-rs-services_hu_447ef5090f685c71.png 1400w"
src="https://percona.community/blog/2025/03/pmm-rs-services.png" alt="Percona Monitoring and Management (PMM) 3.0.0 - PMM MongoDB" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;For example, I experimented by restarting one of the MongoDB services in Docker Desktop. The Replica Set switched the Primary replica, and when I simulated a failure by stopping a service, the monitoring dashboard reflected this event:&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2025/03/pmm-rs-statuses_hu_152c5a5848d218c0.png 480w, https://percona.community/blog/2025/03/pmm-rs-statuses_hu_a41e7ee71109cd35.png 768w, https://percona.community/blog/2025/03/pmm-rs-statuses_hu_9c7cef99e95ae73e.png 1400w"
src="https://percona.community/blog/2025/03/pmm-rs-statuses.png" alt="Percona Monitoring and Management (PMM) 3.0.0 - PMM MongoDB" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h2 id="connecting-to-mongodb-and-useful-commands"&gt;Connecting to MongoDB and Useful Commands&lt;/h2&gt;
&lt;h3 id="connecting-to-mongodb"&gt;Connecting to MongoDB&lt;/h3&gt;
&lt;p&gt;There are several ways to connect to MongoDB depending on your setup and tools:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Using Docker Desktop&lt;/p&gt;
&lt;p&gt;If you are using Docker Desktop, you can select a container and open the Exec tab. This opens a terminal within the container.&lt;/p&gt;
&lt;p&gt;From there, you can connect to MongoDB using the mongosh shell with the following command:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sh&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-22" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-22"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mongosh --host localhost --port &lt;span class="m"&gt;27017&lt;/span&gt; -u databaseAdmin -p password --authenticationDatabase admin&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2025/03/mongodb-connect_hu_1993f455a7ac9c0d.png 480w, https://percona.community/blog/2025/03/mongodb-connect_hu_d494614723a4a044.png 768w, https://percona.community/blog/2025/03/mongodb-connect_hu_c87f2510dcd2bf5e.png 1400w"
src="https://percona.community/blog/2025/03/mongodb-connect.png" alt="Percona Monitoring and Management (PMM) 3.0.0 - Docker Desktop MongoDB Connect" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Using Docker CLI&lt;/p&gt;
&lt;p&gt;If you’re running Docker without Docker Desktop, you can connect to the container using the following command:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-23" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-23"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; -it &lt;container_name&gt; bash&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;when you connect to the container, connect to MongoDB&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sh&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-24" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-24"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mongosh --host localhost --port &lt;span class="m"&gt;27017&lt;/span&gt; -u databaseAdmin -p password --authenticationDatabase admin&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connecting from Applications or Tools&lt;/p&gt;
&lt;p&gt;If you are connecting through an application or a tool like MongoDB Compass, you can use connection strings tailored to your setup:&lt;/p&gt;
&lt;p&gt;Here are the MongoDB connection strings tailored for your use cases:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Standalone MongoDB: Connects directly to a single MongoDB instance.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sh&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-25" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-25"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mongodb://databaseAdmin:password@localhost:27017&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Primary Node: Forces a direct connection to the primary node in the Replica Set using the directConnection=true option.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sh&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-26" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-26"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mongodb://databaseAdmin:password@localhost:27017/?directConnection&lt;span class="o"&gt;=&lt;/span&gt;true&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Full Replica Set: Lists all Replica Set members and enables automatic failover using replicaSet=rs&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sh&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-27" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-27"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mongodb://databaseAdmin:password@localhost:27017,localhost:28017,localhost:29017/?replicaSet&lt;span class="o"&gt;=&lt;/span&gt;rs&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="useful-commands"&gt;Useful Commands&lt;/h3&gt;
&lt;p&gt;Here are some helpful commands for managing and troubleshooting your MongoDB setup:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Check the status of the Replica Set. After connecting to MongoDB, use the following command to retrieve the status of the Replica Set:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sh&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-28" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-28"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rs.status&lt;span class="o"&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Check MongoDB runtime configuration. Use this command to view the configuration options for the running MongoDB instance:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sh&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-29" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-29"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;db.adminCommand&lt;span class="o"&gt;({&lt;/span&gt; getCmdLineOpts: &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="o"&gt;})&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this article, we explored deploying MongoDB using Docker and Docker Compose. We covered both a Single Instance MongoDB for simple setups and a MongoDB Replica Set for high availability, while integrating them with Percona Monitoring and Management (PMM) for monitoring.&lt;/p&gt;
&lt;p&gt;Here are the final configurations you can download:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Single Instance MongoDB + PMM 3: &lt;a href="https://gist.github.com/dbazhenov/fc954c9bd7f21e2ad17dffb4acfd7142" target="_blank" rel="noopener noreferrer"&gt;Link&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Replica Set MongoDB + PMM 3: &lt;a href="https://gist.github.com/dbazhenov/fd47167734230d294a4aa10da623d1f2" target="_blank" rel="noopener noreferrer"&gt;Link&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Thank you for reading! I look forward to your comments and questions.&lt;/p&gt;</content:encoded>
      <author>Daniil Bazhenov</author>
      <category>MongoDB</category>
      <category>Docker</category>
      <category>Opensource</category>
      <category>PMM</category>
      <media:thumbnail url="https://percona.community/blog/2025/03/pmm-mongodb-cover_hu_4a7029d1f994dce1.jpg"/>
      <media:content url="https://percona.community/blog/2025/03/pmm-mongodb-cover_hu_3b760685321d77d.jpg" medium="image"/>
    </item>
    <item>
      <title>Join Us Online: Stream About Percona Toolkit for MySQL!</title>
      <link>https://percona.community/blog/2025/03/14/join-us-online-stream-about-percona-toolkit-for-mysql/</link>
      <guid>https://percona.community/blog/2025/03/14/join-us-online-stream-about-percona-toolkit-for-mysql/</guid>
      <pubDate>Fri, 14 Mar 2025 00:00:00 UTC</pubDate>
      <description>Are you passionate about databases and want to stay on top of the latest advancements in MySQL and Percona Toolkit? You’re in luck! We are excited to invite you to our upcoming online stream, where we’ll delve into some exciting changes and updates.</description>
      <content:encoded>&lt;p&gt;Are you passionate about databases and want to stay on top of the latest advancements in MySQL and Percona Toolkit? You’re in luck! We are excited to invite you to our upcoming online stream, where we’ll delve into some exciting changes and updates.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Date:&lt;/strong&gt; March 27, 2025&lt;br&gt;
&lt;strong&gt;Time:&lt;/strong&gt; 13:30 GMT / 9:30 ET&lt;br&gt;
&lt;strong&gt;Streaming Live on:&lt;/strong&gt; &lt;a href="https://www.linkedin.com/events/removingoffensivelanguagefrompe7307408691371077632/theater/" target="_blank" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; and &lt;a href="https://www.youtube.com/live/JOEpIQL7cXM" target="_blank" rel="noopener noreferrer"&gt;YouTube&lt;/a&gt;&lt;/p&gt;
&lt;h4 id="about-the-event"&gt;About the Event&lt;/h4&gt;
&lt;p&gt;Our featured speaker, Sveta Smirnova, Principal Support Engineering Coordinator at Percona, will share her insights on the recent updates in MySQL, focusing on the removal of offensive replication statements like START/STOP SLAVE. As the maintainer of the Percona Toolkit, Sveta had to rewrite numerous tools and libraries to accommodate these changes, resulting in significant updates to 511 files.&lt;/p&gt;
&lt;p&gt;This event is perfect for developers, DBAs, and anyone interested in databases. Sveta, an expert in MySQL and Percona Toolkit, is also an accomplished author and a speaker at international conferences on development and databases. During the stream, she will discuss the challenges she faced while renewing legacy code, including supporting SSL and handling the deprecation of certain tools.&lt;/p&gt;
&lt;p&gt;We invite you to join the discussion and share your experiences, questions, and insights. Engage directly with Sveta and other participants to gain a deeper understanding of the Percona Toolkit and its latest enhancements.&lt;/p&gt;
&lt;h4 id="discussion-topics"&gt;Discussion Topics&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Introduction to Percona Toolkit&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;History and evolution of Percona Toolkit.&lt;/li&gt;
&lt;li&gt;Overview of the most popular tools and their uses.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Changes in MySQL&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;Overview of new and legacy syntax.&lt;/li&gt;
&lt;li&gt;Implications of dropped offensive replication statements.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Adapting Percona Toolkit&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;Challenges in renewing legacy code.&lt;/li&gt;
&lt;li&gt;Solutions implemented, including SSL support and deprecation of certain tools.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Practical Insights&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;Detailed explanation of the changes made to 511 files.&lt;/li&gt;
&lt;li&gt;Fine-tuning and migration strategies for Percona Toolkit users.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="why-attend"&gt;Why Attend?&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Insightful Content:&lt;/strong&gt; Gain valuable knowledge on the latest changes in MySQL and how they impact Percona Toolkit.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Expert Guidance:&lt;/strong&gt; Learn directly from Sveta Smirnova, an industry expert with extensive experience in database management.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Interactive Session:&lt;/strong&gt; Have the opportunity to ask questions live and engage directly with the speaker.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="how-to-join"&gt;How to Join&lt;/h4&gt;
&lt;p&gt;Tune in on March 27, 2025, at 13:30 GMT / 9:30 ET, and watch the live stream on &lt;a href="https://www.linkedin.com/events/removingoffensivelanguagefrompe7307408691371077632/theater/" target="_blank" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; and &lt;a href="https://www.youtube.com/live/JOEpIQL7cXM" target="_blank" rel="noopener noreferrer"&gt;YouTube&lt;/a&gt;. Don’t miss this chance to enhance your understanding of MySQL and Percona Toolkit while gaining practical insights from one of the best in the field.&lt;/p&gt;
&lt;p&gt;Mark your calendars, spread the word, and get ready for an informative session! We look forward to seeing you there!&lt;/p&gt;
&lt;p&gt;If you have any questions or need further information, feel free to reach out to us.&lt;/p&gt;
&lt;p&gt;📅 Add to Calendar&lt;br&gt;
🔗 &lt;a href="https://www.linkedin.com/events/removingoffensivelanguagefrompe7307408691371077632/theater/" target="_blank" rel="noopener noreferrer"&gt;Join the LinkedIn Stream&lt;/a&gt;&lt;br&gt;
🔗 &lt;a href="https://www.youtube.com/live/JOEpIQL7cXM" target="_blank" rel="noopener noreferrer"&gt;Join the YouTube Stream&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We can’t wait to see you at the event!&lt;/p&gt;</content:encoded>
      <author>Sveta Smirnova</author>
      <category>MySQL</category>
      <category>Toolkit</category>
      <category>Events</category>
      <media:thumbnail url="https://percona.community/events/streams/Live-Sveta-Edith-march-27_hu_8acd1ec53a021f.jpg"/>
      <media:content url="https://percona.community/events/streams/Live-Sveta-Edith-march-27_hu_b4d5e82775302e73.jpg" medium="image"/>
    </item>
    <item>
      <title>Percona Monitoring and Management 3 and rootless containers</title>
      <link>https://percona.community/blog/2025/02/19/percona-monitoring-and-management-3-and-rootless-containers/</link>
      <guid>https://percona.community/blog/2025/02/19/percona-monitoring-and-management-3-and-rootless-containers/</guid>
      <pubDate>Wed, 19 Feb 2025 00:00:00 UTC</pubDate>
      <description>In today’s landscape, where security breaches are a constant concern, reducing potential attack vectors is a top priority for any organization. Percona Monitoring and Management (PMM) has established itself as a reliable solution for database performance monitoring. With the release of PMM version 3, Percona has significantly strengthened its security posture, notably by introducing support for rootless container deployments. This advancement directly addresses a crucial security challenge and enhances the overall robustness and reliability of PMM.</description>
      <content:encoded>&lt;p&gt;In today’s landscape, where security breaches are a constant concern, reducing potential attack vectors is a top priority for any organization. Percona Monitoring and Management (PMM) has established itself as a reliable solution for database performance monitoring. With &lt;a href="https://docs.percona.com/percona-monitoring-and-management/3/release-notes/3.0.0.html" target="_blank" rel="noopener noreferrer"&gt;the release of PMM version 3&lt;/a&gt;, Percona has significantly strengthened its security posture, notably by introducing support for rootless container deployments. This advancement directly addresses a crucial security challenge and enhances the overall robustness and reliability of PMM.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2025/02/pmm3-homepage_hu_ab475622fd130cae.jpg 480w, https://percona.community/blog/2025/02/pmm3-homepage_hu_b786868d12aa39e8.jpg 768w, https://percona.community/blog/2025/02/pmm3-homepage_hu_256f4d15d640605c.jpg 1400w"
src="https://percona.community/blog/2025/02/pmm3-homepage.jpg" alt="Percona Monitoring and Management (PMM) 3.0.0" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;The inherent risks associated with root privileges are well-documented. While many applications, including those containerized, have historically relied on root access, this practice presents a substantial security vulnerability. In the event of a successful exploit, an attacker gains comprehensive control over the host system. This risk is further exacerbated in environments with outdated software or complex configurations. Essentially, while the root user offers extensive capabilities, it also represents a significant potential liability that should be carefully mitigated.&lt;/p&gt;
&lt;p&gt;In this blog post we will look at the exact differences between PMM versions 2 and 3 and how they behave.&lt;/p&gt;
&lt;h2 id="enforcing-pod-security-standards"&gt;Enforcing Pod Security Standards&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://kubernetes.io/docs/concepts/security/pod-security-standards/" target="_blank" rel="noopener noreferrer"&gt;The Pod Security Standards&lt;/a&gt; define three different policies to broadly cover the security spectrum. These policies are cumulative and range from highly-permissive to highly-restrictive.&lt;/p&gt;
&lt;p&gt;To enforce restrictions on a specific namespace we will create the following YAML manifest:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;apiVersion: v1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kind: Namespace
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;metadata:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; name: secure-namespace
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; labels:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; pod-security.kubernetes.io/enforce: restricted
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; pod-security.kubernetes.io/warn: restricted
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; pod-security.kubernetes.io/audit: restricted&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This YAML creates a namespace named secure-namespace. The pod-security.kubernetes.io/enforce: restricted label instructs Kubernetes to deny any pods in this namespace that violate the “restricted” PSS profile. The warn and audit labels are also very useful for monitoring and testing before fully enforcing the restricted policy.&lt;/p&gt;
&lt;h2 id="deploy-pmm"&gt;Deploy PMM&lt;/h2&gt;
&lt;p&gt;We will execute a series of deployments to demonstrate the difference between PMM2 and PMM3 behavior in insecure and secure environments. All files can be found in this github repository: &lt;a href="https://github.com/spron-in/blog-data/tree/master/pmm3-rootless" target="_blank" rel="noopener noreferrer"&gt;spron-in/blog-data/pmm3-rootless&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="regular-namespace"&gt;Regular namespace&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;PMM2&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-1"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;% kubectl apply -f 01.pmm2.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;statefulset.apps/pmm-server created
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;service/pmm-server created
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;% kubectl get pods
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NAME READY STATUS RESTARTS AGE
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pmm-server-0 1/1 Running 0 45s&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;I can connect to my PMM2 server with a Service that I created.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;PMM3&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-2" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-2"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;% kubectl apply -f 02.pmm3.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;statefulset.apps/pmm-server created
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;service/pmm-server created
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;% kubectl get pods
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NAME READY STATUS RESTARTS AGE
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pmm-server-0 1/1 Running 0 20s&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;I can connect to my PMM3 server with a Service that I created.&lt;/p&gt;
&lt;h3 id="secure-namespace"&gt;Secure namespace&lt;/h3&gt;
&lt;p&gt;Let’s try to deploy both versions of Percona Monitoring and Management servers in a secure namespace. For both we will see the following:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-3" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-3"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;% kubectl apply -f 01.pmm2.yaml -n secure-namespace
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Warning: would violate PodSecurity "restricted:latest": allowPrivilegeEscalation != false (container "pmm-server" must set securityContext.allowPrivilegeEscalation=false), unrestricted capabilities (container "pmm-server" must set securityContext.capabilities.drop=["ALL"]), runAsNonRoot != true (pod or container "pmm-server" must set securityContext.runAsNonRoot=true), seccompProfile (pod or container "pmm-server" must set securityContext.seccompProfile.type to "RuntimeDefault" or "Localhost")
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;statefulset.apps/pmm-server created
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;service/pmm-server created
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;% kubectl -n secure-namespace get pods
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;No resources found in secure-namespace namespace.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;There are no Pods created and if you describe the StatefulSet, you are going to see a similar error:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-4" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-4"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Warning FailedCreate 5s (x15 over 87s) statefulset-controller create Pod pmm-server-0 in StatefulSet pmm-server failed error: pods "pmm-server-0" is forbidden: violates PodSecurity "restricted:latest": allowPrivilegeEscalation != false (container "pmm-server" must set securityContext.allowPrivilegeEscalation=false), unrestricted capabilities (container "pmm-server" must set securityContext.capabilities.drop=["ALL"]), runAsNonRoot != true (pod or container "pmm-server" must set securityContext.runAsNonRoot=true), seccompProfile (pod or container "pmm-server" must set securityContext.seccompProfile.type to "RuntimeDefault" or "Localhost")&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The error will be the same for PMM2 and PMM3 manifests.&lt;/p&gt;
&lt;h3 id="secure-namespace-and-security-contexts"&gt;Secure namespace and security contexts&lt;/h3&gt;
&lt;p&gt;We are now going to apply Pod and Container Security Contexts to both manifests.&lt;/p&gt;
&lt;p&gt;Under spec.containers we add everything that Kubernetes suggested us:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-5" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-5"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - name: pmm-server
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; securityContext:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; allowPrivilegeEscalation: false
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; capabilities:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; drop:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - ALL
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; runAsNonRoot: true
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; seccompProfile:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; type: 'RuntimeDefault'&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;PMM2&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-6" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-6"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;% kubectl -n secure-namespace apply -f 03.pmm2-secure.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;statefulset.apps/pmm-server created
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;service/pmm-server created
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;% kubectl -n secure-namespace get pods
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NAME READY STATUS RESTARTS AGE
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pmm-server-0 0/1 Error 2 (15s ago) 28s&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Even though the PMM2 server Pod can be created now, it is failing to start. If you check the logs, you are going to see the following:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-7" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-7"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;% kubectl -n secure-namespace logs pmm-server-0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Error: Can't drop privilege as nonroot user
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;For help, use /usr/local/bin/supervisord -h&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;PMM3&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-8" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-8"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;% kubectl -n secure-namespace apply -f 04.pmm3-secure.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;statefulset.apps/pmm-server created
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;service/pmm-server created
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;% kubectl -n secure-namespace get pods
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NAME READY STATUS RESTARTS AGE
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pmm-server-0 1/1 Running 0 32s&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;PMM3 starts just fine.&lt;/p&gt;
&lt;h3 id="helm"&gt;Helm&lt;/h3&gt;
&lt;p&gt;The recommended approach to deploy PMM3 in Kubernetes is via Helm. You can find our helm charts in &lt;a href="https://github.com/percona/percona-helm-charts/tree/main/charts/pmm" target="_blank" rel="noopener noreferrer"&gt;percona/helm-charts&lt;/a&gt; github repository and more in &lt;a href="https://docs.percona.com/percona-monitoring-and-management/3/install-pmm/install-pmm-server/deployment-options/helm/index.html" target="_blank" rel="noopener noreferrer"&gt;our documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To deploy PMM3 in a namespace or environment with strict security (like OpenShift), you need to pass similar security context parameters. You can find how in &lt;a href="https://github.com/spron-in/blog-data/blob/master/pmm3-rootless/05.pmm3-helm.yaml" target="_blank" rel="noopener noreferrer"&gt;05.pmm3-helm.yaml&lt;/a&gt; values manifest.&lt;/p&gt;
&lt;p&gt;Then the deployment will look like this:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-9" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-9"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;helm repo update
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;helm install pmm3 percona/pmm -f 05.pmm3-helm.yaml --namespace secure-namespace&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;PMM 3’s rootless design excels where PMM 2 falters in secure Kubernetes environments. Enforcing Pod Security Standards, we saw PMM 3 deploy successfully, while PMM 2 failed, even with security contexts. This highlights PMM 3’s enhanced security, crucial for modern, hardened deployments. Using Helm simplifies secure PMM 3 deployments, ensuring robust database monitoring without compromising security.&lt;/p&gt;
&lt;p&gt;Try out &lt;a href="https://docs.percona.com/percona-monitoring-and-management/3/release-notes/3.0.0.html" target="_blank" rel="noopener noreferrer"&gt;Percona Monitoring and Management version 3&lt;/a&gt;, 100% open source database observability solution, and learn more about its enhancements.&lt;/p&gt;
&lt;p&gt;Tell us what you think in &lt;a href="https://forums.percona.com/c/percona-monitoring-and-management-pmm/pmm-3/84/l/new" target="_blank" rel="noopener noreferrer"&gt;our forum&lt;/a&gt; or let us know if you are looking for &lt;a href="https://www.percona.com/about/contact" target="_blank" rel="noopener noreferrer"&gt;commercial support&lt;/a&gt;.&lt;/p&gt;</content:encoded>
      <author>Sergey Pronin</author>
      <category>PMM</category>
      <category>HELM</category>
      <category>Docker</category>
      <media:thumbnail url="https://percona.community/blog/2025/02/pmm3-rootless_hu_74de63da6cea5681.jpg"/>
      <media:content url="https://percona.community/blog/2025/02/pmm3-rootless_hu_f897b8c176da0f3f.jpg" medium="image"/>
    </item>
    <item>
      <title>How to Use IAM Roles for Service Accounts (IRSA) with Percona Operator for MongoDB on AWS</title>
      <link>https://percona.community/blog/2025/02/17/how-to-use-iam-roles-for-service-accounts-irsa-with-percona-operator-for-mongodb-on-aws/</link>
      <guid>https://percona.community/blog/2025/02/17/how-to-use-iam-roles-for-service-accounts-irsa-with-percona-operator-for-mongodb-on-aws/</guid>
      <pubDate>Mon, 17 Feb 2025 00:00:00 UTC</pubDate>
      <description>Introduction Percona Operator for MongoDB is an open-source solution designed to streamline and automate database operations within Kubernetes. It allows users to effortlessly deploy and manage highly available, enterprise-grade MongoDB clusters. The operator simplifies both initial deployment and setup, as well as ongoing management tasks like backups, restores, scaling, and upgrades, ensuring seamless database lifecycle management.</description>
      <content:encoded>&lt;h1 id="introduction"&gt;Introduction&lt;/h1&gt;
&lt;p&gt;&lt;a href="https://docs.percona.com/percona-operator-for-mongodb/index.html" target="_blank" rel="noopener noreferrer"&gt;Percona Operator for MongoDB&lt;/a&gt; is an open-source solution designed to streamline and automate database operations within Kubernetes. It allows users to effortlessly deploy and manage highly available, enterprise-grade MongoDB clusters.  The operator simplifies both initial deployment and setup, as well as ongoing management tasks like backups, restores, scaling, and upgrades, ensuring seamless database lifecycle management.&lt;/p&gt;
&lt;p&gt;When running database workloads on Amazon EKS (Elastic Kubernetes Service), backup and restore processes often require access to AWS services like S3 for storage. A key challenge is ensuring these operations have secure, least-privileged access to AWS resources without relying on static credentials. Properly managing these permissions is crucial to maintaining data integrity, security, and compliance in automated backup and restore workflows.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html" target="_blank" rel="noopener noreferrer"&gt;IAM Roles for Service Accounts (IRSA)&lt;/a&gt; is the recommended approach to solve this problem. IRSA allows Kubernetes pods to securely assume IAM roles, eliminating the need for hardcoded credentials, long-lived AWS keys, or excessive permissions. Instead, it leverages OpenID Connect (OIDC) authentication, ensuring that only the right workloads get access to AWS services.&lt;br&gt;
By implementing IRSA, you enhance the security posture of your Kubernetes workloads while simplifying IAM management. In this article, we’ll walk through how IRSA works, why it’s beneficial, and how to configure it properly for the Percona Operator for MongoDB in EKS clusters.&lt;/p&gt;
&lt;h1 id="irsa-installation-and-configuration-for-percona-operator-for-mongodb"&gt;IRSA Installation and Configuration for Percona Operator for MongoDB&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;IRSA requires an OpenID Connect (OIDC) provider associated with your EKS cluster.&lt;br&gt;
So, you should &lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/enable-iam-roles-for-service-accounts.html#:~:text=To%20create%20a%20provider%2C%20choose,com%20and%20choose%20Add%20provider." target="_blank" rel="noopener noreferrer"&gt;create an OIDC provider for your EKS cluster&lt;/a&gt;. &lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Creating an OIDC provider for your EKS cluster involves several steps. This setup allows your EKS cluster to use IAM roles for service accounts, which makes it possible to grant fine-grained IAM permissions to pods.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;shell&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Check if OIDC is already set up:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws eks describe-cluster --name &lt;cluster_name&gt; --query &lt;span class="s2"&gt;"cluster.identity.oidc.issuer"&lt;/span&gt; --output text
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;https://oidc.eks.eu-west-3.amazonaws.com/id/7AA1C67941083331A80382E464EB2F1F
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# If it is not already set up, create an OIDC provider:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;eksctl utils associate-iam-oidc-provider --region &lt;region&gt; --cluster &lt;cluster-name&gt; --approve&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Here oidc-id is 7AA1C67941083331A80382E464EB2F1F. We will use it under role creation.&lt;/p&gt;
&lt;ol start="2"&gt;
&lt;li&gt;Create an IAM Policy to access s3 buckets.  Substitute &lt;s3_bucket&gt; with your correct bucket name:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;shell&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-1"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Define the required permissions in an IAM policy JSON file: &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat s3-bucket-policy.json
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;"Version"&lt;/span&gt;: &lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;"Statement"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;"Effect"&lt;/span&gt;: &lt;span class="s2"&gt;"Allow"&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;"Action"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;"s3:*"&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;]&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;"Resource"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;"arn:aws:s3:::&lt;s3_bucket&gt;"&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;"arn:aws:s3:::&lt;s3_bucket&gt;/*"&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Create the IAM policy:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam create-policy --policy-name &lt;policy name&gt; --policy-document file://s3-bucket-policy.json&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ol start="3"&gt;
&lt;li&gt;Create an IAM Role and Attach the Policy:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;shell&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-2" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-2"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Role example. Replace &lt;account-id&gt; with account id and &lt;oidc-id&gt; with cluster’s OIDC ID&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat role-trust-policy.json
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;"Version"&lt;/span&gt;: &lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;"Statement"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;"Effect"&lt;/span&gt;: &lt;span class="s2"&gt;"Allow"&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;"Principal"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;"Federated"&lt;/span&gt;: &lt;span class="s2"&gt;"arn:aws:iam::&lt;account-id&gt;:oidc-provider/oidc.eks.&lt;region&gt;.amazonaws.com/id/&lt;oidc-id&gt;"&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;}&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;"Action"&lt;/span&gt;: &lt;span class="s2"&gt;"sts:AssumeRoleWithWebIdentity"&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;"Condition"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;"StringEquals"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;"oidc.eks.&lt;region&gt;.amazonaws.com/id/&lt;oidc-id&gt;:aud"&lt;/span&gt;: &lt;span class="s2"&gt;"sts.amazonaws.com"&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Create role:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam create-role --role-name &lt;role_name&gt; --assume-role-policy-document file://role-trust-policy.json --description &lt;span class="s2"&gt;"Allow access to s3 bucket"&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ol start="4"&gt;
&lt;li&gt;Attach the policy to the role.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;shell&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-3" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-3"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Please update &lt;role-name&gt;, &lt;account-id&gt; and &lt;policy-name&gt; with the corresponding values.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam attach-role-policy --role-name &lt;role-name&gt; --policy-arn arn:aws:iam::&lt;account-id&gt;:policy/&lt;policy-name&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ol start="5"&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://docs.percona.com/percona-operator-for-mongodb/eks.html#install-the-operator-and-deploy-your-mongodb-cluster" target="_blank" rel="noopener noreferrer"&gt;Install the operator and deploy Percona Server for MongoDB&lt;/a&gt; in your EKS cluster (skip this step if you already have the operator and the database cluster installed).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;To ensure proper functionality, we need to annotate both the operator service account (default: percona-server-mongodb-operator) and the cluster service account (default: default).&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;🔴 Warning: The cluster and operator  won’t restart automatically; therefore, a manual restart is necessary to apply the changes.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;shell&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-4" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-4"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Get service accounts:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ kubectl get sa -n &lt;namespace&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NAME SECRETS AGE
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;default &lt;span class="m"&gt;0&lt;/span&gt; 25m
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;percona-server-mongodb-operator &lt;span class="m"&gt;0&lt;/span&gt; 25m
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Get role_arn:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam get-role --role-name &lt;role-name&gt; --query &lt;span class="s2"&gt;"Role.Arn"&lt;/span&gt; --output text
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Annotate service account. Please update role_arn with appropriate value.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl annotate serviceaccount default &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt; eks.amazonaws.com/role-arn&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;role_arn&gt;"&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl annotate serviceaccount percona-server-mongodb-operator &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt; eks.amazonaws.com/role-arn&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;role_arn&gt;"&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ol start="7"&gt;
&lt;li&gt;To verify that the settings have been applied, inspect service accounts and the environment variables in both the operator and replica set (RS/Config) pods. The variable AWS_ROLE_ARN should be properly set.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;shell&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-5" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-5"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Check annotation in service account&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ kubectl get sa -n &lt;namespace&gt; percona-server-mongodb-operator -o yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ kubectl get sa -n &lt;namespace&gt; default -o yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Check the variable inside container&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; -ti &lt;percona-server-mongodb-operator-container&gt; -n &lt;operator_namespace&gt; bash
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;bash-5.1$ printenv &lt;span class="p"&gt;|&lt;/span&gt; grep &lt;span class="s1"&gt;'AWS_ROLE_ARN'&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;AWS_ROLE_ARN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;arn:aws:iam::1111111111111:role/some-name-psmdb-access-s3-bucket
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; -ti &lt;rs0-0_pod&gt; -n &lt;namespace&gt; bash
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;mongodb@some-name-rs0-0 db&lt;span class="o"&gt;]&lt;/span&gt;$ printenv &lt;span class="p"&gt;|&lt;/span&gt; grep &lt;span class="s1"&gt;'AWS_ROLE_ARN'&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;AWS_ROLE_ARN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;arn:aws:iam::1111111111111:role/some-name-psmdb-access-s3-bucket&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ol start="8"&gt;
&lt;li&gt;Configure the backup/restore settings as usual, but do not provide s3.credentialsSecret for the storage in deploy/cr.yaml. For detailed instructions  please refer to &lt;a href="https://docs.percona.com/percona-operator-for-mongodb/backups-storage.html" target="_blank" rel="noopener noreferrer"&gt;Configure storage for backups&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;shell&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-6" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-6"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# backup section in cr.yaml example &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; storages:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; aws-s3:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; type: s3
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; s3:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; region: &lt;region&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; bucket: &lt;bucket&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h1 id="conclusion"&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;Using IAM Roles for Service Accounts (IRSA) in an Amazon EKS cluster is a best practice when running &lt;a href="https://docs.percona.com/percona-operators/" target="_blank" rel="noopener noreferrer"&gt;database operators&lt;/a&gt; in Kubernetes. By integrating IRSA, database operators—such as the&lt;a href="https://docs.percona.com/percona-operator-for-mongodb/index.html" target="_blank" rel="noopener noreferrer"&gt; Percona Server for MongoDB Operator&lt;/a&gt;—can securely access AWS services like S3 for backups without relying on static credentials.&lt;/p&gt;
&lt;p&gt;IRSA enhances security by enforcing the principle of least privilege, ensuring that database operators in EKS have access only to the specific AWS resources they require. This approach reduces the risk of unauthorized access while also improving manageability by eliminating the need to store and rotate AWS credentials within Kubernetes secrets. By adopting IRSA in &lt;a href="https://docs.percona.com/percona-operator-for-mongodb/index.html" target="_blank" rel="noopener noreferrer"&gt;Percona Server for MongoDB Operator&lt;/a&gt; , organizations can create a more secure, scalable, and automated environment for managing MongoDB databases.&lt;/p&gt;</content:encoded>
      <author>Natalia Marukovich</author>
      <category>Kubernetes</category>
      <category>MongoDB</category>
      <media:thumbnail url="https://percona.community/blog/2025/02/mongo-aws-iam_hu_784c39e43abdfe63.jpg"/>
      <media:content url="https://percona.community/blog/2025/02/mongo-aws-iam_hu_2d794beb55bbadb2.jpg" medium="image"/>
    </item>
    <item>
      <title>Percona Operator for MongoDB 1.19: Remote Backups, Auto-Generated Passwords, and More!</title>
      <link>https://percona.community/blog/2025/01/31/percona-operator-for-mongodb-1.19-remote-backups-auto-generated-passwords-and-more/</link>
      <guid>https://percona.community/blog/2025/01/31/percona-operator-for-mongodb-1.19-remote-backups-auto-generated-passwords-and-more/</guid>
      <pubDate>Fri, 31 Jan 2025 00:00:00 UTC</pubDate>
      <description>The latest release of the Percona Operator for MongoDB, version 1.19, is here. It brings a suite of enhancements designed to streamline your MongoDB deployments on Kubernetes. This release introduces a technical preview of remote file server backups, simplifies user management with auto-generated passwords, supports Percona Server for MongoDB 8.0, and includes numerous other improvements and bug fixes. Let’s dive into the details of what 1.19 has to offer.</description>
      <content:encoded>&lt;p&gt;The latest release of the &lt;a href="https://docs.percona.com/percona-operator-for-mongodb/index.html" target="_blank" rel="noopener noreferrer"&gt;Percona Operator for MongoDB&lt;/a&gt;, &lt;a href="https://docs.percona.com/percona-operator-for-mongodb/RN/Kubernetes-Operator-for-PSMONGODB-RN1.19.0.html" target="_blank" rel="noopener noreferrer"&gt;version 1.19&lt;/a&gt;, is here. It brings a suite of enhancements designed to streamline your MongoDB deployments on Kubernetes. This release introduces a technical preview of remote file server backups, simplifies user management with auto-generated passwords, supports Percona Server for MongoDB 8.0, and includes numerous other improvements and bug fixes. Let’s dive into the details of what 1.19 has to offer.&lt;/p&gt;
&lt;h2 id="remote-backups-with-network-file-system-technical-preview"&gt;Remote Backups with Network File System (Technical Preview)&lt;/h2&gt;
&lt;p&gt;Backing up your MongoDB data is crucial, and Percona Operator for MongoDB 1.19 introduces a powerful new option for backup storage: the filesystem type. This feature, currently in technical preview, allows you to leverage a remote file server, mounted locally as a sidecar volume, for your backups. This is particularly useful in environments with network restrictions that prevent the use of S3-compatible storage or for organizations using non-standard storage solutions that support the Network File System (NFS) protocol.&lt;/p&gt;
&lt;h3 id="setting-up-remote-backups"&gt;Setting Up Remote Backups&lt;/h3&gt;
&lt;p&gt;To use this new capability, you’ll need to add your remote storage as a sidecar volume within the replsets section of your Custom Resource (and configsvrReplSet for sharded clusters). Here’s how:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;replsets:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; sidecarVolumes:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - name: backup-nfs-vol
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; nfs:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; server: "nfs-service.storage.svc.cluster.local"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; path: "/psmdb-my-cluster-name-rs0"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Then, configure the mount point and sidecar volume name in the &lt;code&gt;backup.volumeMounts&lt;/code&gt; section:&lt;/p&gt;
&lt;p&gt;YAML:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-1"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;backup:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; volumeMounts:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - mountPath: /mnt/nfs/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; name: backup-nfs-vol
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Finally, set up a filesystem type storage in the backup.storages section, pointing it to the mount point:&lt;/p&gt;
&lt;p&gt;YAML:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-2" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-2"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;backup:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; enabled: true
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; storages:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; backup-nfs:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; type: filesystem
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; filesystem:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; path: /mnt/nfs/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;See more in our &lt;a href="https://docs.percona.com/percona-operator-for-mongodb/backups-storage.html#remote-file-server" target="_blank" rel="noopener noreferrer"&gt;documentation about this storage type&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="simplified-user-management-with-auto-generated-passwords"&gt;Simplified User Management with Auto-Generated Passwords&lt;/h2&gt;
&lt;p&gt;Managing user credentials just got easier. Percona Operator for MongoDB 1.19 enhances declarative management of custom MongoDB users by adding the ability to generate passwords automatically. Now, when defining a new user in your deploy/cr.yaml file, you can omit the reference to an existing Secret containing the password, and the Operator will handle the generation for you:&lt;/p&gt;
&lt;p&gt;YAML:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-3" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-3"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;users:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - name: my-user
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; db: admin
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; roles:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - name: clusterAdmin
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; db: admin
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - name: userAdminAnyDatabase
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; db: admin&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The Operator will create a Secret to store the generated password securely. It is important to note that the Secret will be created after the cluster is in the Ready state.&lt;/p&gt;
&lt;p&gt;Get the user credentials:
Find the Secret resource named &lt;cluster-name&gt;-custom-user-secret
Get the user password with this one-liner:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-4" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-4"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl get secret my-cluster-name-custom-user-secret -o jsonpath='{.data.my-user}' | base64 -d&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;You can find more details on this automatically created Secret in our &lt;a href="https://docs.percona.com/percona-operator-for-mongodb/users.html#custom-mongodb-roles" target="_blank" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="percona-server-for-mongodb-80-support"&gt;Percona Server for MongoDB 8.0 Support&lt;/h2&gt;
&lt;p&gt;Staying up-to-date with the latest MongoDB versions is essential for performance and security. Percona Operator for MongoDB 1.19 now officially supports Percona Server for MongoDB 8.0, in addition to 6.0 and 7.0. This means you can leverage the latest features and improvements from MongoDB 8.0, combined with the enterprise-grade enhancements and open-source commitment of Percona Server for MongoDB.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2025/01/operator-mongodb-8.png" alt="Percona Server for MongoDB 8.0 Support" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Check out &lt;a href="https://www.percona.com/blog/percona-server-for-mongodb-8-0-most-performant-ever/" target="_blank" rel="noopener noreferrer"&gt;this blog post&lt;/a&gt; to learn more about the features in MongoDB 8.0.&lt;/p&gt;
&lt;h2 id="streamlined-aws-s3-access-with-iam-roles-for-service-accounts-irsa"&gt;Streamlined AWS S3 Access with IAM Roles for Service Accounts (IRSA)&lt;/h2&gt;
&lt;p&gt;Percona Operator for MongoDB 1.19 adds support for &lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html" target="_blank" rel="noopener noreferrer"&gt;IAM Roles for Service Accounts (IRSA)&lt;/a&gt;, simplifying secure access to AWS S3 for backups on Amazon EKS. IRSA lets you grant granular S3 permissions to specific Pods via their associated Kubernetes service accounts. This approach ensures that only the Pods that require S3 access receive it, adhering to the principle of least privilege. Furthermore, each Pod can only access credentials linked to its service account, providing strong credential isolation. For enhanced security, all S3 access is tracked through AWS CloudTrail, enabling comprehensive auditability. All of this happens without the need to manually manage and distribute AWS credentials.&lt;/p&gt;
&lt;p&gt;Configuration Steps&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Create an IAM Role: Define an IAM role with S3 access permissions. See &lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html" target="_blank" rel="noopener noreferrer"&gt;AWS documentation&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Identify Service Accounts: The Operator uses percona-server-mongodb-operator and your cluster uses default (customizable in deploy/cr.yaml).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Annotate Service Accounts: Link the IAM role to both service accounts:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-5" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-5"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ kubectl -n &lt;cluster namespace&gt; annotate serviceaccount default eks.amazonaws.com/role-arn: &lt;YOUR_IAM_ROLE_ARN&gt; --overwrite
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ kubectl -n &lt;operator namespace&gt; annotate serviceaccount percona-server-mongodb-operator eks.amazonaws.com/role-arn: &lt;YOUR_IAM_ROLE_ARN&gt; --overwrite&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Configure S3 Storage: Set up S3 storage in deploy/cr.yaml without s3.credentialsSecret. The Operator will use IRSA.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Important: IRSA credentials take precedence over IAM instance profiles, and S3 credentials in a Secret override both.&lt;/p&gt;
&lt;p&gt;IRSA streamlines S3 access, enhancing security and manageability for your MongoDB backups on EKS. Learn more in our &lt;a href="https://docs.percona.com/percona-operator-for-mongodb/backups-storage.html#automating-access-to-amazon-s3-based-on-iam-roles" target="_blank" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Percona Operator for MongoDB 1.19 delivers a significant step forward in simplifying and automating the management of your MongoDB clusters on Kubernetes. With features like remote backups, auto-generated passwords, and support for Percona Server for MongoDB 8.0, this release empowers you to deploy, manage, and scale your databases with greater ease and efficiency.&lt;/p&gt;
&lt;p&gt;We encourage you to explore the &lt;a href="https://docs.percona.com/percona-operator-for-mongodb/RN/Kubernetes-Operator-for-PSMONGODB-RN1.19.0.html" target="_blank" rel="noopener noreferrer"&gt;full release notes&lt;/a&gt; and try out the new features. As always, your feedback is invaluable to us. Please share your thoughts and contribute to the project on our &lt;a href="https://github.com/percona/percona-server-mongodb-operator" target="_blank" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt; or our &lt;a href="https://forums.percona.com/c/mongodb/percona-kubernetes-operator-for-mongodb/29" target="_blank" rel="noopener noreferrer"&gt;Community Forum&lt;/a&gt;.&lt;/p&gt;</content:encoded>
      <author>Sergey Pronin</author>
      <category>Kubernetes</category>
      <category>MongoDB</category>
      <category>Percona</category>
      <category>Opensource</category>
      <media:thumbnail url="https://percona.community/blog/2025/01/operator-1-19_hu_6722f842e532b42a.jpg"/>
      <media:content url="https://percona.community/blog/2025/01/operator-1-19_hu_61ed34aa6c8532c6.jpg" medium="image"/>
    </item>
    <item>
      <title>Percona Monitoring and Management 3.0.0-GA</title>
      <link>https://percona.community/blog/2025/01/29/percona-monitoring-management-3-ga/</link>
      <guid>https://percona.community/blog/2025/01/29/percona-monitoring-management-3-ga/</guid>
      <pubDate>Wed, 29 Jan 2025 00:00:00 UTC</pubDate>
      <description>We’re excited to announce the release of Percona Monitoring and Management (PMM) 3.0.0 GA.</description>
      <content:encoded>&lt;p&gt;We’re excited to announce the release of &lt;strong&gt;Percona Monitoring and Management (PMM) 3.0.0 GA&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The Percona Monitoring and Management (PMM) 3.0.0 release delivers major security and stability enhancements. Notable security improvements include rootless deployments and encryption of sensitive data, along with improved API authentication using Grafana service accounts. Deployment options have expanded with official ARM support and the ability to use Podman for rootless deployments, providing flexibility and better security. Additionally, the introduction of containerized architecture has increased stability, and a streamlined upgrade process ensures reliability and ease of maintenance.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2025/01/PMM-3.0.0_hu_bab4bf52b037997b.png 480w, https://percona.community/blog/2025/01/PMM-3.0.0_hu_aad2d5b4f9ec2c44.png 768w, https://percona.community/blog/2025/01/PMM-3.0.0_hu_a72c59d901d4239b.png 1400w"
src="https://percona.community/blog/2025/01/PMM-3.0.0.png" alt="Percona Monitoring and Management (PMM) 3.0.0" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;User experience has been significantly improved with more flexible monitoring configurations and UI-based upgrades for Podman installations. This release also includes new features such as monitoring for MongoDB 8.0 and integration with Watchtower for automated container updates. These enhancements aim to provide users with a more secure, stable, and user-friendly monitoring and management experience.&lt;/p&gt;
&lt;h2 id="release-notes"&gt;Release notes&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;To see the full list of changes, check out the &lt;a href="https://docs.percona.com/percona-monitoring-and-management/3/release-notes/3.0.0.html" target="_blank" rel="noopener noreferrer"&gt;3.0.0 GA Release Notes&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Percona Monitoring and Management (PMM) 3.0.0 Release Notes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Security Enhancements&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Implementation of rootless deployments to enhance security.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Encryption of sensitive data to ensure information confidentiality.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Improved API authentication with Grafana service accounts, increasing access security.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Deployment Options&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Official PMM Client ARM support, allowing the use of PMM on ARM architecture devices.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Rootless deployments using Podman, providing flexibility and security.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Support for deployments using Helm, Docker, Virtual Appliance, and Amazon AWS for various use cases.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Stability Improvements&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Increased stability through containerized architecture, providing isolation and manageability.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Streamlined upgrade process, reducing the risk of failures during updates and enhancing reliability.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;User Experience&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Flexible monitoring configurations, allowing users to tailor the system to their needs.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;UI-based upgrades for Podman installations, making the update process more convenient and intuitive.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;New Features&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Monitoring for MongoDB 8.0, ensuring support for the latest database versions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Integration with Watchtower for automated container updates, simplifying management and keeping the system up-to-date.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We invite you to install and try the new PMM 3.0&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Quickstart guide&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.percona.com/percona-monitoring-and-management/3/quickstart.html" target="_blank" rel="noopener noreferrer"&gt;Get started with PMM&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Multiple installation options&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.percona.com/percona-monitoring-and-management/3/install-pmm/index.html" target="_blank" rel="noopener noreferrer"&gt;About PMM installation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;Contact us on the &lt;a href="https://forums.percona.com/c/percona-monitoring-and-management-pmm/pmm-3/84" target="_blank" rel="noopener noreferrer"&gt;Percona Community Forums&lt;/a&gt;.&lt;/p&gt;</content:encoded>
      <author>Ondrej Patocka</author>
      <category>PMM</category>
      <category>General Availability</category>
      <category>Monitoring</category>
      <category>Percona</category>
      <category>Databases</category>
      <media:thumbnail url="https://percona.community/blog/2025/01/pmm-blog-post-cover_hu_157785b07ee52466.jpg"/>
      <media:content url="https://percona.community/blog/2025/01/pmm-blog-post-cover_hu_dd1f0c6bd73fc043.jpg" medium="image"/>
    </item>
    <item>
      <title>MySQL 8.4 Support in Percona Toolkit 3.7.0</title>
      <link>https://percona.community/blog/2025/01/06/mysql-8.4-support-in-percona-toolkit-3.7.0/</link>
      <guid>https://percona.community/blog/2025/01/06/mysql-8.4-support-in-percona-toolkit-3.7.0/</guid>
      <pubDate>Mon, 06 Jan 2025 00:00:00 UTC</pubDate>
      <description>Percona Toolkit 3.7.0 has been released on Dec 23, 2024. The main feature of this release is MySQL 8.4 support.</description>
      <content:encoded>&lt;p&gt;&lt;em&gt;Percona Toolkit 3.7.0 has been released on &lt;strong&gt;Dec 23, 2024&lt;/strong&gt;. The main feature of this release is MySQL 8.4 support.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;In this blog, I will explain what has been changed. A full list of improvements and bug fixes can be found in the &lt;em&gt;&lt;a href="https://docs.percona.com/percona-toolkit/release_notes.html" target="_blank" rel="noopener noreferrer"&gt;&lt;em&gt;release notes&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;TLDR;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Replication statements in 8.4 are fully supported by the Percona Toolkit&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pt-slave-delay&lt;/code&gt; has been deprecated.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pt-slave-find&lt;/code&gt; has been renamed to &lt;code&gt;pt-replica-find&lt;/code&gt;. The old name has been deprecated but exists in the repository as an alias of the &lt;code&gt;pt-replica-find&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pt-slave-restart&lt;/code&gt; has been renamed to &lt;code&gt;pt-replica-restart&lt;/code&gt;. Old name has been deprecated but exists in the repository as an alias of the &lt;code&gt;pt-replica-restart&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Basic SSL support has been added to the tools where it was not working before (see &lt;a href="https://perconadev.atlassian.net/browse/PT-191" target="_blank" rel="noopener noreferrer"&gt;https://perconadev.atlassian.net/browse/PT-191&lt;/a&gt; ), and Percona Toolkit now supports &lt;code&gt;caching_sha2_password&lt;/code&gt; and &lt;code&gt;sha256_password&lt;/code&gt;authentication plugins. Full implementation of &lt;a href="https://perconadev.atlassian.net/browse/PT-191" target="_blank" rel="noopener noreferrer"&gt;https://perconadev.atlassian.net/browse/PT-191&lt;/a&gt; is planned for the next version.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="replication-statements"&gt;Replication Statements&lt;/h2&gt;
&lt;p&gt;MySQL 8.4 removed earlier deprecated offensive language, such as &lt;code&gt;SLAVE&lt;/code&gt; or &lt;code&gt;MASTER&lt;/code&gt;. This made tools written for earlier versions not compatible with the new version. Percona Toolkit was also affected, and I had to rewrite it.&lt;/p&gt;
&lt;p&gt;However, Percona Toolkit should be able to run not only with MySQL 8.4 but also with older versions. So, the change was not a simple grep and replace of offensive words. It is not even possible for version MySQL 8.0 because new syntax was first introduced in 8.0.23 for the &lt;code&gt;CHANGE REPLICATION SOURCE&lt;/code&gt; and &lt;code&gt;START/STOP REPLICA&lt;/code&gt; commands. Earlier versions weren’t aware of this change.&lt;/p&gt;
&lt;p&gt;Another challenge was the fact that I could replace all occurrences of the word &lt;code&gt;SLAVE&lt;/code&gt; with &lt;code&gt;REPLICA&lt;/code&gt;. Still, I could not do the same for the &lt;code&gt;MASTER&lt;/code&gt; and &lt;code&gt;SOURCE&lt;/code&gt; pairs because replication source-related commands are mapped differently:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Legacy syntax&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Syntax without offensive words&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;CHANGE MASTER&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;CHANGE REPLICATION SOURCE&lt;/code&gt; (since 8.0.23)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SHOW MASTER STATUS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SHOW BINARY LOG STATUS&lt;/code&gt; (since 8.4.0)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;RESET MASTER&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;RESET BINARY LOGS[ AND GTIDS]&lt;/code&gt; ( since 8.4.0)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;MASTER&lt;/code&gt;  in other commands&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SOURCE&lt;/code&gt; (partially since 8.0.23, fully since 8.4)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;So, I added selectors that use the correct command depending on the MySQL server version.&lt;/p&gt;
&lt;p&gt;I intentionally implemented new syntax for version 8.4 only, so I do not have to check every single minor version of 8.0. I also did not implement new syntax for MariaDB. This may happen in the future.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;However, all messages displayed to the user use the new syntax. If you rely on old syntax somewhere in your scripts, adjust them.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Internally, most of the functions were renamed to use the new syntax, but the important module &lt;code&gt;lib/MasterSlave.pm&lt;/code&gt; kept its name.&lt;/p&gt;
&lt;h2 id="deprecated-and-outdated-tools"&gt;Deprecated and Outdated Tools&lt;/h2&gt;
&lt;p&gt;As a result of this change, &lt;code&gt;pt-slave-delay&lt;/code&gt; has been deprecated. The tool stays in the repository and works as before when connected to MySQL 8.0 or an earlier version. However, it refuses to work with MySQL 8.4. The tool will be removed in one of the future versions.&lt;/p&gt;
&lt;p&gt;Tools &lt;code&gt;pt-slave-find&lt;/code&gt; and &lt;code&gt;pt-slave-restart&lt;/code&gt; were renamed to &lt;code&gt;pt-replica-find&lt;/code&gt; and &lt;code&gt;pt-replica-restart&lt;/code&gt;. Aliases with old names still exist, so you have time to change your scripts. However, expect that these aliases will be removed in one of the future versions as well.&lt;/p&gt;
&lt;p&gt;Tool &lt;code&gt;pt-variable-advisor&lt;/code&gt; has been updated to reflect current default values.&lt;/p&gt;
&lt;h2 id="basic-ssl-support"&gt;Basic SSL Support&lt;/h2&gt;
&lt;p&gt;Percona Toolkit did not have consistent SSL support: some of the tools were able to connect using SSL, and others did not. This was reported at &lt;a href="https://perconadev.atlassian.net/browse/PT-191" target="_blank" rel="noopener noreferrer"&gt;https://perconadev.atlassian.net/browse/PT-191&lt;/a&gt;. In this version, I added option “&lt;code&gt;s&lt;/code&gt;” for &lt;code&gt;DSN&lt;/code&gt; that instructs &lt;code&gt;DBD::mysql&lt;/code&gt; to open a secure connection with the database. As a result, Percona Toolkit now supports &lt;code&gt;caching_sha2_password&lt;/code&gt; and &lt;code&gt;sha256_password&lt;/code&gt; authentication plugins. But other SSL options are still missed. Full SSL support will be added in the next version.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Percona Toolkit fully supports MySQL 8.4. If you use &lt;code&gt;pt-slave-find&lt;/code&gt; and &lt;code&gt;pt-slave-restart&lt;/code&gt;, consider calling them by their new names &lt;code&gt;pt-replica-find&lt;/code&gt; and &lt;code&gt;pt-replica-restart&lt;/code&gt;. Tool &lt;code&gt;pt-slave-delay&lt;/code&gt; has been deprecated and will be removed in future versions. Use built-in feature &lt;a href="https://dev.mysql.com/doc/refman/8.4/en/replication-delayed.html" target="_blank" rel="noopener noreferrer"&gt;delayed replication&lt;/a&gt; instead.&lt;/p&gt;</content:encoded>
      <author>Sveta Smirnova</author>
      <category>Toolkit</category>
      <category>MySQL</category>
      <category>Percona</category>
      <category>Opensource</category>
      <media:thumbnail url="https://percona.community/blog/2025/01/toolkit-370_hu_5b639c8b155c6c50.jpg"/>
      <media:content url="https://percona.community/blog/2025/01/toolkit-370_hu_a2b76fa1e2f67fb9.jpg" medium="image"/>
    </item>
    <item>
      <title>Percona Monitoring and Management 3.0.0-Beta - Tech Preview</title>
      <link>https://percona.community/blog/2024/12/02/percona-monitoring-management-technical-preview/</link>
      <guid>https://percona.community/blog/2024/12/02/percona-monitoring-management-technical-preview/</guid>
      <pubDate>Mon, 02 Dec 2024 00:00:00 UTC</pubDate>
      <description>Percona Monitoring and Management 3.0.0 Beta - Tech Preview We’re excited to announce the Tech Preview (Beta) release of Percona Monitoring and Management (PMM) 3.0.0-Beta.</description>
      <content:encoded>&lt;h2 id="percona-monitoring-and-management-300-beta---tech-preview"&gt;Percona Monitoring and Management 3.0.0 Beta - Tech Preview&lt;/h2&gt;
&lt;p&gt;We’re excited to announce the Tech Preview (Beta) release of &lt;strong&gt;Percona Monitoring and Management (PMM) 3.0.0-Beta&lt;/strong&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This release is intended for testing environments only, as it’s not yet production-ready. The GA (General Availability) release will be available through standard channels in the upcoming months.&lt;/p&gt;&lt;/blockquote&gt;
&lt;h2 id="release-notes"&gt;Release notes&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;To see the full list of changes, check out the &lt;a href="https://pmm-doc-3.onrender.com/release-notes/3.0.0_Beta.html" target="_blank" rel="noopener noreferrer"&gt;3.0.0-Beta - Tech Preview Release Notes&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="installation-options"&gt;Installation options&lt;/h2&gt;
&lt;h3 id="pmm-server"&gt;PMM Server&lt;/h3&gt;
&lt;h4 id="docker"&gt;Docker&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://hubgw.docker.com/r/perconalab/pmm-server/tags?name=3.0.0-beta" target="_blank" rel="noopener noreferrer"&gt;Server&lt;/a&gt;: &lt;code&gt;docker pull perconalab/pmm-server:3.0.0-beta&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pmm-doc-3.onrender.com/install-pmm/install-pmm-server/baremetal/docker/easy-install.html" target="_blank" rel="noopener noreferrer"&gt;Docker installation guide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="vm"&gt;VM&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://percona-vm.s3.amazonaws.com/PMM3-Server-2024-11-26-1307.ova" target="_blank" rel="noopener noreferrer"&gt;Download OVA file&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pmm-doc-3.onrender.com/install-pmm/install-pmm-server/baremetal/virtual/index.html" target="_blank" rel="noopener noreferrer"&gt;VM Installation guide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="pmm-client"&gt;PMM Client&lt;/h3&gt;
&lt;h4 id="docker-images"&gt;Docker images&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://hubgw.docker.com/r/perconalab/pmm-client/tags?name=3.0.0-beta" target="_blank" rel="noopener noreferrer"&gt;AMD 64 + ARM 64&lt;/a&gt;: &lt;code&gt;docker pull perconalab/pmm-client:3.0.0-beta&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="binary-packages"&gt;Binary packages&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://downloads.percona.com/downloads/TESTING/pmm-client-3.0.0beta/pmm-client-3.0.0beta.AMD64.tar.gz" target="_blank" rel="noopener noreferrer"&gt;Download AMD 64 tarball&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://downloads.percona.com/downloads/TESTING/pmm-client-3.0.0beta/pmm-client-3.0.0beta.ARM64.tar.gz" target="_blank" rel="noopener noreferrer"&gt;Download ARM 64 tarball&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="package-manager-installation"&gt;Package Manager installation&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;Enable testing repository via Percona-release: &lt;code&gt;percona-release enable pmm3-client testing&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Install relevant pmm-client package using your system’s package manager&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;p&gt;Contact us on the &lt;a href="https://forums.percona.com/c/percona-monitoring-and-management-pmm" target="_blank" rel="noopener noreferrer"&gt;Percona Community Forums&lt;/a&gt;.&lt;/p&gt;</content:encoded>
      <author>Ondrej Patocka</author>
      <category>PMM</category>
      <category>Technical Preview</category>
      <category>Monitoring</category>
      <category>Percona</category>
      <category>Databases</category>
      <media:thumbnail url="https://percona.community/images/pmm/pmm-blog-post-cover_hu_d535f2202891bf3f.jpg"/>
      <media:content url="https://percona.community/images/pmm/pmm-blog-post-cover_hu_ab7fc16f44593397.jpg" medium="image"/>
    </item>
    <item>
      <title>Percona Monitoring and Management 2.43.0 Preview Release</title>
      <link>https://percona.community/blog/2024/09/12/preview-release/</link>
      <guid>https://percona.community/blog/2024/09/12/preview-release/</guid>
      <pubDate>Thu, 12 Sep 2024 00:00:00 UTC</pubDate>
      <description>Percona Monitoring and Management 2.43.0 Tech Preview Release Hello everyone! Percona Monitoring and Management (PMM) 2.43.0 is now available as a Tech Preview Release.</description>
      <content:encoded>&lt;h2 id="percona-monitoring-and-management-2430-tech-preview-release"&gt;Percona Monitoring and Management 2.43.0 Tech Preview Release&lt;/h2&gt;
&lt;p&gt;Hello everyone! Percona Monitoring and Management (PMM) 2.43.0 is now available as a Tech Preview Release.&lt;/p&gt;
&lt;p&gt;We encourage you to try this PMM preview release in &lt;strong&gt;testing environments only&lt;/strong&gt;, as these packages and images are not fully production-ready. The final version is expected to be released through the standard channels in the coming week.&lt;/p&gt;
&lt;p&gt;To see the full list of changes, check out the &lt;a href="https://pmm-doc-pr-1271.onrender.com/release-notes/2.43.0.html" target="_blank" rel="noopener noreferrer"&gt;PMM 2.43.0 Tech Preview Release Notes&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="pmm-server-docker-installation"&gt;PMM server Docker installation&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://docs.percona.com/percona-monitoring-and-management/setting-up/server/docker.html" target="_blank" rel="noopener noreferrer"&gt;Run PMM Server with Docker instructions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;docker tag:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;perconalab/pmm-server:2.43.0-rc&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="pmm-client-package-installation"&gt;PMM client package installation&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://s3.us-east-2.amazonaws.com/pmm-build-cache/PR-BUILDS/pmm2-client/pmm2-client-latest-29.tar.gz" target="_blank" rel="noopener noreferrer"&gt;Download AMD64&lt;/a&gt; or &lt;a href="https://s3.us-east-2.amazonaws.com/pmm-build-cache/PR-BUILDS/pmm2-client-arm/pmm2-client-latest-49.tar.gz" target="_blank" rel="noopener noreferrer"&gt;Download ARM64&lt;/a&gt; pmm2-client tarball for 2.43.0.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;To install pmm2-client package, enable testing repository via Percona-release:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;percona-release enable percona testing&lt;/code&gt;&lt;/p&gt;
&lt;ol start="3"&gt;
&lt;li&gt;Install pmm2-client package for your OS via Package Manager.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="ova"&gt;OVA&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://docs.percona.com/percona-monitoring-and-management/setting-up/server/virtual-appliance.html" target="_blank" rel="noopener noreferrer"&gt;Run PMM Server as a VM instructions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://percona-vm.s3.amazonaws.com/PMM2-Server-2.43.0.ova" target="_blank" rel="noopener noreferrer"&gt;PMM2-Server-2.43.0.ova file&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="ami"&gt;AMI&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://docs.percona.com/percona-monitoring-and-management/setting-up/server/aws.html" target="_blank" rel="noopener noreferrer"&gt;Run PMM Server hosted at AWS Marketplace instructions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ami-0db618c7da6e202f4&lt;/code&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Contact us on the [Percona Community Forums](&lt;a href="https://forums.percona.com/]" target="_blank" rel="noopener noreferrer"&gt;https://forums.percona.com/]&lt;/a&gt;.&lt;/p&gt;</content:encoded>
      <author>Ondrej Patocka</author>
      <category>PMM</category>
      <category>Release</category>
      <media:thumbnail url="https://percona.community/superhero_hu_252fc2b480c0a197.jpg"/>
      <media:content url="https://percona.community/superhero_hu_17979f11d5d3562e.jpg" medium="image"/>
    </item>
    <item>
      <title>Timeline for Database on Kubernetes</title>
      <link>https://percona.community/blog/2024/07/16/timeline-for-database-on-kubernetes/</link>
      <guid>https://percona.community/blog/2024/07/16/timeline-for-database-on-kubernetes/</guid>
      <pubDate>Tue, 16 Jul 2024 00:00:00 UTC</pubDate>
      <description>The Evolution Since its inception in June 2014, Kubernetes has dramatically transformed container orchestration, revolutionizing the management and scaling of applications. To mark its tenth anniversary, the Data on Kubernetes Community (DoKC) released an infographic showcasing key milestones and community contributions to the evolution of operators for managing stateful applications. This project was made possible by the collaboration of DoKC members Edith Puclla, Sergey Pronin, Robert Hodges, Gabriele Bartolini, Chris Malarky, Mark Kember, Paul Au, and Luciano Stabel.</description>
      <content:encoded>&lt;h2 id="the-evolution"&gt;The Evolution&lt;/h2&gt;
&lt;p&gt;Since its inception in June 2014, &lt;strong&gt;Kubernetes&lt;/strong&gt; has dramatically transformed container orchestration, revolutionizing the management and scaling of applications. To mark its tenth anniversary, the &lt;a href="https://dok.community/" target="_blank" rel="noopener noreferrer"&gt;Data on Kubernetes Community (DoKC)&lt;/a&gt; released an infographic showcasing key milestones and community contributions to the evolution of operators for managing stateful applications. This project was made possible by the collaboration of DoKC members &lt;strong&gt;Edith Puclla, Sergey Pronin, Robert Hodges, Gabriele Bartolini, Chris Malarky, Mark Kember, Paul Au, and Luciano Stabel&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Explore the infographic to see how Kubernetes has shaped the future of database management on Kubernetes.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2024/07/databases-kubernetes-timeline.png" alt="Databases Kubernetes Timeline" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h2 id="adoption-and-impact"&gt;Adoption and Impact&lt;/h2&gt;
&lt;p&gt;The &lt;a href="https://www.cncf.io/" target="_blank" rel="noopener noreferrer"&gt;CNCF&lt;/a&gt; says that 84% of organizations are using or considering Kubernetes, with 70% running stateful applications on it in production. The number of users and containers has grown, showing that more people are contributing, adopting cloud-native technologies, and finding new ways to use Kubernetes to manage stateful applications.&lt;/p&gt;
&lt;h2 id="looking-ahead"&gt;Looking Ahead&lt;/h2&gt;
&lt;p&gt;As we celebrate ten years of Kubernetes, the way databases are integrated keeps improving, thanks to community efforts and new technology. &lt;strong&gt;Percona Everest is an excellent example of this progress&lt;/strong&gt;. It’s more than just a tool for databases; it represents the future of running databases on Kubernetes. It’s open-source and makes running any database on cloud-based Kubernetes clusters easy. If you want to try it, visit our &lt;a href="https://github.com/percona/everest" target="_blank" rel="noopener noreferrer"&gt;Percona Everest GitHub Repository&lt;/a&gt; and give us a star if you like it. For feedback or comments, join the &lt;a href="https://forums.percona.com/c/percona-everest/81" target="_blank" rel="noopener noreferrer"&gt;Percona Forum&lt;/a&gt; for Percona Everest discussion.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2024/07/percona-everest.png" alt="Percona Everest" /&gt;&lt;/figure&gt;&lt;/p&gt;</content:encoded>
      <author>Edith Puclla</author>
      <category>CNCF</category>
      <category>Percona Everest</category>
      <category>Kubernetes</category>
      <category>DoK</category>
      <category>Databases</category>
      <media:thumbnail url="https://percona.community/blog/2024/07/databases-kubernetes-timeline_hu_567dc635c8d5b739.jpg"/>
      <media:content url="https://percona.community/blog/2024/07/databases-kubernetes-timeline_hu_1372998829c52fee.jpg" medium="image"/>
    </item>
    <item>
      <title>How to Provision a MongoDB Cluster in Kubernetes with Percona Everest Summary</title>
      <link>https://percona.community/blog/2024/05/02/how-to-provision-a-mongodb-cluster-in-kubernetes-with-percona-everest-summary/</link>
      <guid>https://percona.community/blog/2024/05/02/how-to-provision-a-mongodb-cluster-in-kubernetes-with-percona-everest-summary/</guid>
      <pubDate>Thu, 02 May 2024 00:00:00 UTC</pubDate>
      <description>Kubernetes continues evolving, and the complexity of deploying and managing databases within the ecosystem is a topic of considerable discussion and importance these days. This article summarizes a detailed discussion between Piotr Szczepaniak and Diogo Recharte, who offer insights and live demonstrations to simplify database operations on Kubernetes with a new technology for cloud-native applications: Percona Everest. If you want to watch the full video, check out How to Provision a MongoDB Cluster in Kubernetes Webinar.</description>
      <content:encoded>&lt;p&gt;&lt;strong&gt;Kubernetes&lt;/strong&gt; continues evolving, and the complexity of deploying and managing databases within the ecosystem is a topic of considerable discussion and importance these days. This article summarizes a detailed discussion between &lt;a href="https://www.linkedin.com/in/petersgd/" target="_blank" rel="noopener noreferrer"&gt;Piotr Szczepaniak&lt;/a&gt; and &lt;a href="https://www.linkedin.com/in/diogo-recharte/" target="_blank" rel="noopener noreferrer"&gt;Diogo Recharte&lt;/a&gt;, who offer insights and live demonstrations to simplify database operations on Kubernetes with a new technology for cloud-native applications: Percona Everest. If you want to watch the full video, check out &lt;a href="https://www.youtube.com/live/ITeM7Pdp4oc?si=XAeL_4myDdhyq38h" target="_blank" rel="noopener noreferrer"&gt;How to Provision a MongoDB Cluster in Kubernetes Webinar&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2024/05/peterdiogo.png" alt="Percona Everest Webinar" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Peter mentions that Initially, people were doubtful about using virtual machines for databases, just like they were skeptical about Kubernetes. However, the topic brings together many people who run databases on containers to share their use cases and new discussions at events like Data on &lt;a href="https://www.youtube.com/playlist?list=PLHgdNuGxrJt1eqQeSHJ4J-RydHO6-LTeW" target="_blank" rel="noopener noreferrer"&gt;Kubernetes Day at Kubecon&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The introduction of &lt;strong&gt;StatefulSets&lt;/strong&gt; and &lt;strong&gt;Persistent Volumes&lt;/strong&gt; has altered the perception of Kubernetes from being purely ephemeral to being capable of handling persistent data. This change is important for database applications that require data retention over time.&lt;/p&gt;
&lt;p&gt;The Kubernetes ecosystem is rapidly expanding. This growth is thanks to its open-source nature and the continuous addition of new functionalities, such as support for specialized hardware like GPUs, which are crucial for AI and machine learning applications.&lt;/p&gt;
&lt;p&gt;Peter also mentioned that its complexity is the main barrier to Kubernetes adoption for databases. Organizations often need help with the layer added by Kubernetes on top of database management. Also, failure in initial attempts to integrate Kubernetes can discourage organizations from further attempts, primarily due to a lack of internal expertise.&lt;/p&gt;
&lt;h4 id="benefits-of-database-as-a-service-dbaas"&gt;Benefits of Database as a Service (DBaaS)&lt;/h4&gt;
&lt;p&gt;DBaaS significantly reduces the time required for database provisioning, which is particularly useful in organizations needing rapid deployment. Public and private DBaaS solutions offer scalability, which is crucial for handling varying workloads and organizational growth without compromising performance.&lt;/p&gt;
&lt;h4 id="private-vs-public-dbaas"&gt;Private vs. Public DBaaS&lt;/h4&gt;
&lt;p&gt;Private DBaaS offers more extensive customization options and control over databases, which is essential for companies with specific needs that public solutions cannot meet.&lt;/p&gt;
&lt;p&gt;Data security and compliance with regulations are more manageable in a private DBaaS because it operate within the company’s internal infrastructure.&lt;/p&gt;
&lt;h4 id="demo-to-deploying-mongodb-on-kubernetes"&gt;Demo  to Deploying MongoDB on Kubernetes&lt;/h4&gt;
&lt;p&gt;Diogo presented a demo of deploying a MongoDB database using Percona’s Everest platform on Kubernetes, where he showed how to handle daily operations and disaster recovery scenarios efficiently. Watch the &lt;a href="https://youtu.be/ITeM7Pdp4oc?t=1039" target="_blank" rel="noopener noreferrer"&gt;Percona Everest Demo on YouTube&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2024/05/percona-everest-mongodb.png" alt="Percona Everest Draw" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;The session explained how Kubernetes operators and custom resources help manage databases more easily. They do this by simplifying complex processes and automating regular tasks.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2024/05/everest-gui_hu_b50d53946abc8f4e.png 480w, https://percona.community/blog/2024/05/everest-gui_hu_84f30b9b15bb341f.png 768w, https://percona.community/blog/2024/05/everest-gui_hu_7b6b85bd53e63366.png 1400w"
src="https://percona.community/blog/2024/05/everest-gui.png" alt="Percona Everest GUI" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Some questions that users asked in this presentation are:&lt;/p&gt;
&lt;h3 id="how-do-we-handle-the-pv-when-the-pods-go-down"&gt;How do we handle the PV when the Pods go down?&lt;/h3&gt;
&lt;p&gt;The PV will remain in place; this is a standard functionality of a stateful set. After the Pod goes down, the replacement Pod will attach to the PVC, which is standard behavior for a stateful set.&lt;/p&gt;
&lt;h3 id="what-happens-if-the-node-in-kubernetes-goes-down"&gt;What happens if the node in Kubernetes goes down?&lt;/h3&gt;
&lt;p&gt;It depends on the storage layer that you have configured in your cluster. If the storage class you are using is tied to that node, then placing it on a new node will provision a new one, and some reconciliation will occur within the database itself.&lt;/p&gt;
&lt;h3 id="what-is-the-current-state-of-percona-everest"&gt;What is the current state of Percona Everest?&lt;/h3&gt;
&lt;p&gt;Percona Everest is currently in a Beta stage, and Percona aims to release a GA version. The project is fully open source, and anyone can join our project on GitHub. We appreciate feedback from the community.&lt;/p&gt;
&lt;p&gt;Do you want to send us feedback or contribute in this cool project? We are completely open-source, you can visit &lt;a href="https://github.com/percona/everest" target="_blank" rel="noopener noreferrer"&gt;Percona Everest on GitHub&lt;/a&gt;.&lt;/p&gt;</content:encoded>
      <author>Edith Puclla</author>
      <category>Percona Everest</category>
      <category>MongoDB</category>
      <category>Kubernetes</category>
      <category>Databases</category>
      <media:thumbnail url="https://percona.community/blog/2024/05/percona-everest-mongodb_hu_6b827eddfe206ace.jpg"/>
      <media:content url="https://percona.community/blog/2024/05/percona-everest-mongodb_hu_4dc3ff5621cad4a0.jpg" medium="image"/>
    </item>
    <item>
      <title>Using ProxySQL Query Mirroring to test query performance on a new cluster</title>
      <link>https://percona.community/blog/2024/05/01/using-proxysql-query-mirroring-to-test-query-peromance-on-a-new-cluster/</link>
      <guid>https://percona.community/blog/2024/05/01/using-proxysql-query-mirroring-to-test-query-peromance-on-a-new-cluster/</guid>
      <pubDate>Wed, 01 May 2024 00:00:00 UTC</pubDate>
      <description>ProxySQL is an SQL aware proxy, which gives DBA’s fine grained control over clients’ access to the MySQL cluster. A key part of our DBA team’s process in testing and preparing for major MySQL version upgrades is comparing query plans using ProxySQL query mirroring. This feature allows us to mirror queries to another cluster / host, by configuring query rules. What makes mirroring particularly useful is the ability to selectively mirror queries based on the query digest, or client user. Results from the queries that are mirrored are not returned to the client, and are sent to /dev/null.</description>
      <content:encoded>&lt;p&gt;ProxySQL is an SQL aware proxy, which gives DBA’s fine grained control over clients’ access to the MySQL cluster. A key part of our DBA team’s process in testing and preparing for major MySQL version upgrades is comparing query plans using &lt;a href="https://proxysql.com/documentation/mirroring/" target="_blank" rel="noopener noreferrer"&gt;ProxySQL query mirroring&lt;/a&gt;. This feature allows us to mirror queries to another cluster / host, by configuring query rules. What makes mirroring particularly useful is the ability to selectively mirror queries based on the query digest, or client user. Results from the queries that are mirrored are not returned to the client, and are sent to /dev/null.&lt;/p&gt;
&lt;p&gt;Before configuring ProxySQL for Query Mirroring, ensure that the clients that you want to mirror the queries for, are able to connect to both the current, and the new cluster. You should also ensure that the ProxySQL monitor can connect to the new cluster, otherwise ProxySQL will mark the new hosts as offline, and the queries will not be mirrored there.&lt;/p&gt;
&lt;h2 id="to-set-up-query-mirroring-in-proxysql"&gt;To set up query mirroring in ProxySQL:&lt;/h2&gt;
&lt;p&gt;In order to set up query mirroring, you need to add the new hosts into the &lt;code&gt;mysql_server&lt;/code&gt; table in ProxySQL. This is how the current &lt;code&gt;mysql_servers&lt;/code&gt; table looks, before we add the new host that we want to mirror the queries to:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;MySQL&gt; SELECT hostgroup_id, hostname FROM mysql_servers;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+--------------+--------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| hostgroup_id | hostname |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+--------------+--------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| 10 | 10.12.0.123 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| 20 | 10.12.0.123 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| 20 | 10.16.0.456 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| 20 | 10.16.0.789 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+--------------+--------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;4 rows in set (0.01 sec)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;It is important to choose a &lt;code&gt;hostgroup_id&lt;/code&gt; that is not yet in use. You can double check the currently configured host groups in the mysql hostgroups table, as you do not want to inadvertently add the mirror hosts into the production traffic!&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-1"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;MySQL&gt; select * from mysql_replication_hostgroups;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+------------------+------------------+------------+----------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| writer_hostgroup | reader_hostgroup | check_type | comment |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+------------------+------------------+------------+----------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| 10 | 20 | read_only | Async Cluster |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+------------------+------------------+------------+----------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;1 row in set (0.00 sec)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Please note, in our example, we are using async replication, so we check the &lt;code&gt;mysql_replication_hostgroups&lt;/code&gt; table, but the hostgroups table you need to check, depends on the cluster architecture you are using:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;async replica clusters check the &lt;code&gt;mysql_replications_hostgroups&lt;/code&gt; table.&lt;/li&gt;
&lt;li&gt;galera clusters check the &lt;code&gt;mysql_galera_hostgroups&lt;/code&gt; table&lt;/li&gt;
&lt;li&gt;group replication check the &lt;code&gt;mysql_group_replication_hostgroups&lt;/code&gt; table.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We are using hostgroup 10 for the writer hostgroup, and hostgroup 20 for the reader. For this example, we will choose 100 for the mirror &lt;code&gt;hostgroup_id&lt;/code&gt;. Once you have decided on an unused hostgroup ID, add the new clusters’ nodes to the &lt;code&gt;mysql_servers&lt;/code&gt; table in ProxySQL.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-2" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-2"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;MySQL&gt; INSERT INTO mysql_servers(host, hostgroup, comment) VALUES ("10.12.0.987", 100, "mirror_cluster");
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;LOAD MYSQL SERVERS TO RUN;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;SAVE MYSQL SERVERS TO DISK;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;mysql_servers&lt;/code&gt; table will now include the new host:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-3" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-3"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;MySQL&gt; SELECT hostgroup_id, hostname FROM mysql_servers;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+--------------+--------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| hostgroup_id | hostname |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+--------------+--------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| 10 | 10.12.0.123 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| 20 | 10.12.0.123 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| 20 | 10.16.0.456 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| 20 | 10.16.0.789 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| 100 | 10.12.0.987 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+--------------+--------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;4 rows in set (0.01 sec)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;In order to enable query mirroring, you need to update the &lt;code&gt;mirror_hostgroup&lt;/code&gt; column in the &lt;code&gt;mysql_query_rules&lt;/code&gt; table. When mirroring is not enabled, the value of the &lt;code&gt;mirror_hostgroup&lt;/code&gt; column is &lt;code&gt;NULL&lt;/code&gt;.
Our query rules before enabling query mirroring are defined as:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-4" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-4"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;MySQL&gt; select rule_id, username, match_digest, destination_hostgroup, mirror_hostgroup from mysql_query_rules;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+---------+------------------------+---------------------+-----------------------+------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| rule_id | username | match_digest | destination_hostgroup | mirror_hostgroup |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+---------+------------------------+---------------------+-----------------------+------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| 1 | myApplicationUser | ^SELECT.*FOR UPDATE | 10 | NULL |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| 2 | myApplicationUser | ^SELECT | 20 | NULL |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+---------+------------------------+---------------------+-----------------------+------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2 rows in set (0.00 sec)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;To enable mirroring, we just need to update the &lt;code&gt;mirror_hostgroup&lt;/code&gt;. For this example, we will mirror all the &lt;code&gt;SELECT&lt;/code&gt; queries made by &lt;code&gt;myApplicationUser&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-5" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-5"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;UPDATE mysql_query_rules SET mirror_hostgroup = 100 where rule_id=2;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;LOAD mysql query rules TO RUN;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;SAVE mysql query rules TO DISK;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The rules should now be updated:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-6" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-6"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;MySQL&gt; select rule_id, username, match_digest, destination_hostgroup, mirror_hostgroup from mysql_query_rules;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+---------+-----------------------+---------------------+-----------------------+------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| rule_id | username | match_digest | destination_hostgroup | mirror_hostgroup |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+---------+-----------------------+---------------------+-----------------------+------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| 1 | myApplicationUser | ^SELECT.*FOR UPDATE | 10 | NULL |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| 2 | myApplicationUser | ^SELECT | 20 | 100 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+---------+-----------------------+---------------------+-----------------------+------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2 rows in set (0.00 sec)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The incoming queries that match the query rule, (in our example above, this is all queries as matching the regular expression ‘^SELECT’, for myApplicationUser, excluding queries matching ‘^SELECT.*FOR UPDATE’), will now be mirrored to the new cluster. You can verify this by checking the MySQL processlist on the new cluster.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;stats_mysql_query_digest&lt;/code&gt; table on ProxySQL holds statistics for the queries that are being processed by ProxySQL. To use the &lt;code&gt;stats_mysql_query_digest&lt;/code&gt; table, the global variables &lt;code&gt;mysql-commands_stats&lt;/code&gt; and &lt;code&gt;mysql-query_digests&lt;/code&gt; must be set to true, which is the default.&lt;/p&gt;
&lt;p&gt;Comparing query performance between two clusters&lt;/p&gt;
&lt;p&gt;Query the &lt;code&gt;stats_mysql_query_digest&lt;/code&gt; table to compare the performance per query between the current and the new cluster:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-7" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-7"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;MySQL&gt; select
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; (b.count_star+a.count_star)/2 as count,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; cast(round(((b.sum_time + 0.0)/(b.count_star + 0.0))/((a.sum_time + 0.0)/(a.count_star + 0.0)),2)*100 as int) as percent,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; cast(round(((b.sum_time + 0.0)/(b.count_star + 0.0))/((a.sum_time + 0.0)/(a.count_star + 0.0)),2)*100 as int)*(b.count_star+a.count_star)/2 as load ,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; substr(a.digest_text,1,150)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;from
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; stats_mysql_query_digest a
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;inner join
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; stats_mysql_query_digest b on
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; a.digest = b.digest
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;where
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; a.hostgroup = 10
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; and b.hostgroup = 100
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;order by
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; percent ASC;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;In this example, the current production cluster has hostgroup 10, and the new mirror cluster was assigned hostgroup 100. The queries with a percentage above 100 are the queries that perform slower on the new cluster, and may be worth investigating, while the queries with a percentage below 100 are more performant on the new cluster. To investigate queries, you can compare the EXPLAIN plan of the query on the current and the new cluster. We use PMM Query Analytics to compare query analytics and the explain plan of the queries on the two separate clusters.&lt;/p&gt;
&lt;p&gt;It is worth noting, that you should allow enough time for the MySQL buffer pool to get filled, before checking the &lt;code&gt;stats_mysql_query_digest&lt;/code&gt; table. Otherwise, the query times on the new cluster can be skewed, as the active dataset may not yet be in memory (whereas on the current cluster it might be). Also, keep in mind that if you are mirroring only a subset of queries, the load on the new cluster will be different to the current cluster, and could affect the query performance on the new cluster, so that they appear significantly faster. Checking the execution plan of the query to see whether it has changed, is therefore more important than looking at overall load.&lt;/p&gt;
&lt;p&gt;To conclude, using query mirroring to test queries on a new system, before making the migration, allows you to compare latency and query plans per normalised query, and proactively detect any necessary alterations before switching live traffic to the new cluster.&lt;/p&gt;</content:encoded>
      <author>Isobel Smith</author>
      <category>ProxySQL</category>
      <category>Upgrades</category>
      <media:thumbnail url="https://percona.community/blog/2024/04/proxysql-query-mirroring_hu_ad2dbd1d1ccccd65.jpg"/>
      <media:content url="https://percona.community/blog/2024/04/proxysql-query-mirroring_hu_b4ee1838b6b620a9.jpg" medium="image"/>
    </item>
    <item>
      <title>Creating a Standby Cluster With the Percona Operator for PostgreSQL</title>
      <link>https://percona.community/blog/2024/03/27/creating-a-standby-cluster-with-the-percona-operator-for-postgresql/</link>
      <guid>https://percona.community/blog/2024/03/27/creating-a-standby-cluster-with-the-percona-operator-for-postgresql/</guid>
      <pubDate>Wed, 27 Mar 2024 00:00:00 UTC</pubDate>
      <description>In this video, Nickolay Ihalainen, a Senior Scaling Specialist at Percona Global Services, explains how to set up replication with standby clusters for Kubernetes databases using Percona’s open-source tools, including the Percona Operator for PostgreSQL</description>
      <content:encoded>&lt;p&gt;In this video, &lt;a href="https://www.linkedin.com/in/nickolay-ihalainen-b8a35838/?originalSubdomain=ru" target="_blank" rel="noopener noreferrer"&gt;Nickolay Ihalainen&lt;/a&gt;, a Senior Scaling Specialist at Percona Global Services, explains how to set up replication with standby clusters for Kubernetes databases using Percona’s open-source tools, including the &lt;a href="https://www.percona.com/postgresql" target="_blank" rel="noopener noreferrer"&gt;Percona Operator for PostgreSQL&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A &lt;strong&gt;Standby Cluster&lt;/strong&gt; is a backup version of your main database. It’s there to keep your data safe and make sure your database can keep running even if something goes wrong with the main one.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2024/03/standby.png" alt="Percona Demo for StandBy Cluster" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;For this demo, we use &lt;strong&gt;Percona Operators for PostgreSQL&lt;/strong&gt; to create the clusters, which facilitates high availability setups and database management by automating deployment, scaling, and management tasks within Kubernetes environments.&lt;/p&gt;
&lt;p&gt;Nickolay created a primary node and the configuration of replication to standby clusters for PostgreSQL, ensuring data redundancy and availability. This primary node has two standby databases in the same primary node.&lt;/p&gt;
&lt;p&gt;Then, we have the &lt;strong&gt;object storage (S3)&lt;/strong&gt; for backups, highlighting the importance of having offsite backups in different geographical locations to safeguard against data loss. This is where the primary node will access to make a data replication.&lt;/p&gt;
&lt;p&gt;This demo also includes using &lt;strong&gt;Patroni&lt;/strong&gt; to manage this process, enabling replication and failover between primary and standby servers, and &lt;strong&gt;PgBouncer&lt;/strong&gt;, a tool that manages how applications are aligned to communicate with a PostgreSQL database.&lt;/p&gt;
&lt;p&gt;Watch our complete hands on in this YouTube video:&lt;/p&gt;
&lt;br /&gt;
&lt;iframe width="560" height="315" src="https://www.youtube.com/embed/nqeGvvZ5G5Y?si=n3ho7xHJiT6F8u9v" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen&gt;&lt;/iframe&gt;
&lt;p&gt;You can find more instructions on how to &lt;a href="https://docs.percona.com/percona-operator-for-postgresql/2.0/standby.html" target="_blank" rel="noopener noreferrer"&gt;deploy a standby cluster for Disaster Recovery&lt;/a&gt;, and also you can &lt;a href="https://www.percona.com/blog/creating-a-standby-cluster-with-the-percona-distribution-for-postgresql-operator/" target="_blank" rel="noopener noreferrer"&gt;Create a Standby Cluster With the Percona Operator for PostgreSQL&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Is you have questions o feedback, write to us in our &lt;a href="https://forums.percona.com/" target="_blank" rel="noopener noreferrer"&gt;Percona Comunity Forum&lt;/a&gt;&lt;/p&gt;</content:encoded>
      <author>Zsolt Parragi</author>
      <author>Edith Puclla</author>
      <category>PostgreSQL</category>
      <category>Backups</category>
      <category>Percona</category>
      <category>pg_zsolt</category>
      <media:thumbnail url="https://percona.community/blog/2024/03/standby_hu_bb4bc2d9eb612df1.jpg"/>
      <media:content url="https://percona.community/blog/2024/03/standby_hu_2e050ddc08ff64b3.jpg" medium="image"/>
    </item>
    <item>
      <title>Setting Up Your Environment for Kubernetes Operators Using Docker, kubectl, and k3d</title>
      <link>https://percona.community/blog/2024/03/04/setting-up-your-environment-for-kubernetes-operators-using-docker-kubectl-and-k3d/</link>
      <guid>https://percona.community/blog/2024/03/04/setting-up-your-environment-for-kubernetes-operators-using-docker-kubectl-and-k3d/</guid>
      <pubDate>Mon, 04 Mar 2024 00:00:00 UTC</pubDate>
      <description>If you are just starting out in the world of Kubernetes operators, like me, preparing the environment for their installation should be something we do with not much difficulty. This blog will quickly guide you in setting the minimal environment.</description>
      <content:encoded>&lt;p&gt;If you are just starting out in the world of Kubernetes operators, like me, preparing the environment for their installation should be something we do with not much difficulty. This blog will quickly guide you in setting the minimal environment.&lt;/p&gt;
&lt;p&gt;Kubernetes operators are invaluable for automating complex database operations, tasks that Kubernetes does not handle directly. Operators make it easy for us – they take care of essential tasks like &lt;strong&gt;backups&lt;/strong&gt; and &lt;strong&gt;restores&lt;/strong&gt;, which are crucial in database management.&lt;/p&gt;
&lt;p&gt;If you want an introduction to Kubernetes Operators, I cover it in this 5-minute blog post, &lt;a href="https://www.percona.com/blog/exploring-the-kubernetes-application-lifecycle-with-percona/" target="_blank" rel="noopener noreferrer"&gt;Exploring the Kubernetes Application Lifecycle With Percona&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Now that we know why Kubernetes Operators are essential let’s prepare our environment to install some of them. We are going to base this installation on Linux for now.
Prerequisites:
For this, we will need a basic understanding of Kubernetes concepts and some Linux command line skills.
We also need &lt;a href="https://docs.docker.com/engine/install/ubuntu/" target="_blank" rel="noopener noreferrer"&gt;Docker Engine&lt;/a&gt; to be able to use K3d at all for containerization. To test, make sure this command runs appropriately:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker run hello-world&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="installing-kubectl"&gt;Installing kubectl&lt;/h2&gt;
&lt;p&gt;To manage and deploy applications on Kubernetes, we will need &lt;strong&gt;kubectl&lt;/strong&gt; tool, which is included in most Kubernetes distributions. If it’s not installed, let’s do it following the &lt;a href="https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/" target="_blank" rel="noopener noreferrer"&gt;official installation instructions&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;To install the &lt;strong&gt;kubectl&lt;/strong&gt; binary with curl on Linux, we need to download the latest release of kubectl using the command:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-1"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -LO &lt;span class="s2"&gt;"https://dl.k8s.io/release/&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;curl -L -s https://dl.k8s.io/release/stable.txt&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;/bin/linux/amd64/kubectl"&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The previous binary installs kubectl in /usr/local/bin/kubectl. We need root ownership and specific permissions for secure execution.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-2" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-2"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo install -o root -g root -m &lt;span class="m"&gt;0755&lt;/span&gt; kubectl /usr/local/bin/kubectl&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;To test the installation, we use the following:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-3" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-3"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl version --client&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Or&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-4" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-4"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl version --client --output&lt;span class="o"&gt;=&lt;/span&gt;yaml&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;If you receive a response like this, it indicates that you are ready to use &lt;code&gt;kubectl&lt;/code&gt;.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-5" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-5"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Client Version: v1.29.2
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Kustomize Version: v5.0.4-0.20230601165947-6ce0bf390ce3&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="installing-k3d"&gt;Installing K3d&lt;/h2&gt;
&lt;p&gt;k3d is a lightweight tool that simplifies running k3s (Rancher Lab’s minimal Kubernetes distribution in Docker), enabling easy creation of single and multi-node k3s clusters for local development.&lt;/p&gt;
&lt;p&gt;Install the current latest release of k3d with curl:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-6" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-6"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -s https://raw.githubusercontent.com/k3d-io/k3d/main/install.sh &lt;span class="p"&gt;|&lt;/span&gt; bash&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;To test the installation, you can use the following:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-7" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-7"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;k3d --help&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;If you see a message similar to this, you are ready to create your k3d Kubernetes clusters.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-8" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-8"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;https://k3d.io/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;k3d is a wrapper CLI that helps you to easily create k3s clusters inside docker.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Nodes of a k3d cluster are docker containers running a k3s image.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;All Nodes of a k3d cluster are part of the same docker network.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Usage:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;k3d &lt;span class="o"&gt;[&lt;/span&gt;flags&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;k3d &lt;span class="o"&gt;[&lt;/span&gt;command&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Available Commands:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cluster Manage cluster&lt;span class="o"&gt;(&lt;/span&gt;s&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;completion Generate completion scripts &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;bash, zsh, fish, powershell &lt;span class="p"&gt;|&lt;/span&gt; psh&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;config Work with config file&lt;span class="o"&gt;(&lt;/span&gt;s&lt;span class="o"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="starting-the-kubernetes-cluster"&gt;Starting the Kubernetes cluster&lt;/h2&gt;
&lt;p&gt;Let’s use K3d and create a Kubernetes cluster with three nodes. Using the flag -a, you can specify the number of nodes you want to add to the k3d cluster.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-9" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-9"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;k3d cluster create database-cluster -a &lt;span class="m"&gt;3&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Now, list details for our k3d cluster.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-10" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-10"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;k3d cluster list database-cluster
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NAME SERVERS AGENTS LOADBALANCER
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;database-cluster 1/1 3/3 true&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Now, our environment is ready to begin installing our Percona Kubernetes Operators.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this tutorial, we chose k3d over Minikube due to its efficiency and speed in setting up Kubernetes clusters with multiple nodes, which are essential for effectively testing Kubernetes operators in a local environment. Although it’s possible to perform tests on a single node with both systems, k3d makes it easier to simulate a more realistic distributed environment, allowing us to utilize our resources more efficiently.&lt;/p&gt;
&lt;p&gt;Take a look at our GitHub repository for our Percona Kubernetes Operators:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/percona/percona-server-mysql-operator" target="_blank" rel="noopener noreferrer"&gt;Percona Operator for MySQL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/percona/percona-server-mongodb-operator" target="_blank" rel="noopener noreferrer"&gt;Percona Operator for MongoDB&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/percona/percona-postgresql-operator" target="_blank" rel="noopener noreferrer"&gt;Percona Operator for PostgreSQL&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;They are fully Open Source. And if you are looking for a version with a graphical interface, we have &lt;a href="https://docs.percona.com/everest/index.html" target="_blank" rel="noopener noreferrer"&gt;Percona Everest&lt;/a&gt;, our cloud-native database platform: docs.percona.com/everest&lt;/p&gt;
&lt;p&gt;What’s Next? Let’s install our Kubernetes Operators!&lt;/p&gt;</content:encoded>
      <author>Edith Puclla</author>
      <category>edith_puclla</category>
      <category>kubernetes</category>
      <category>operators</category>
      <category>k3d</category>
      <category>docker</category>
      <media:thumbnail url="https://percona.community/blog/2024/03/intro_hu_f38b7c56cf487f0.jpg"/>
      <media:content url="https://percona.community/blog/2024/03/intro_hu_6fa6a90910cc0565.jpg" medium="image"/>
    </item>
    <item>
      <title>Unexpected Stalled Upgrade to MySQL 8.0</title>
      <link>https://percona.community/blog/2024/01/26/unexpected-stalled-upgrade-to-mysql-8-0/</link>
      <guid>https://percona.community/blog/2024/01/26/unexpected-stalled-upgrade-to-mysql-8-0/</guid>
      <pubDate>Fri, 26 Jan 2024 00:00:00 UTC</pubDate>
      <description>A multi-tenant database is a database that serves multiple clients, or tenants, who share the same database schema but have separate data sets. One way to achieve data isolation for each client is to create a separate MySQL database for each tenant.</description>
      <content:encoded>&lt;p&gt;A multi-tenant database is a database that serves multiple clients, or tenants, who share the same database schema but have separate data sets. One way to achieve data isolation for each client is to create a separate MySQL database for each tenant.&lt;/p&gt;
&lt;p&gt;Some advantages of this approach are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It allows for easy backup and restore of individual tenant data.&lt;/li&gt;
&lt;li&gt;It simplifies the database administration and maintenance tasks, as each database can be managed independently.&lt;/li&gt;
&lt;li&gt;Scaling is easily achieved by adding more database servers and distributing tenant databases across them.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This approach requires a large number of tables on each server. Combined with the default value of &lt;code&gt;innodb_file_per_table=ON&lt;/code&gt;, this results in a large number of files that affects &lt;a href="https://percona.community/blog/2019/07/23/impact-of-innodb_file_per_table-option-on-crash-recovery-time" target="_blank" rel="noopener noreferrer"&gt;crash recovery time&lt;/a&gt; or &lt;a href="https://www.percona.com/blog/using-percona-xtrabackup-mysql-instance-large-number-tables" target="_blank" rel="noopener noreferrer"&gt;Percona XtraBackup&lt;/a&gt; execution.&lt;/p&gt;
&lt;p&gt;This blog post describes how to take care of a large number of files when upgrading to MySQL 8.0 in-place.&lt;/p&gt;
&lt;h3 id="version-selection"&gt;Version Selection&lt;/h3&gt;
&lt;p&gt;A steady stream of MySQL 8.0 minor releases provides improvements and refactoring of new MySQL 8.0 features. However, some of these releases introduce incompatibilities that require corresponding changes on the application side. Limiting scope of the application-side changes, we chose MySQL 8.0.25 version. This was our first step towards the major version 8.0.&lt;/p&gt;
&lt;h2 id="upgrade-in-place"&gt;Upgrade In-Place&lt;/h2&gt;
&lt;p&gt;A new MySQL 8.0 option is the upgrade in-place procedure. According to the &lt;a href="https://docs.percona.com/percona-server/8.0/upgrading-guide.html" target="_blank" rel="noopener noreferrer"&gt;upgrading guide&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;An in-place upgrade is performed by using existing data on the server and involves the following actions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Stopping the MySQL 5.7 server&lt;/li&gt;
&lt;li&gt;Replacing the old binaries with MySQL 8.0 binaries&lt;/li&gt;
&lt;li&gt;Starting the MySQL 8.0 server with the same data files.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;While an in-place upgrade may not be suitable for all environments, especially those environments with many variables to consider, the upgrade should work in most cases.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;As an exception, in the case of an environment with a large number of tables, the upgrade in-place may get &lt;a href="https://forums.mysql.com/read.php?35,697581" target="_blank" rel="noopener noreferrer"&gt;stalled for weeks&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Below we describe how to debug and resolve such issue.&lt;/p&gt;
&lt;h3 id="encountering-the-issue"&gt;Encountering the Issue&lt;/h3&gt;
&lt;p&gt;In our test environment, we encountered a similar issue. Despite steady CPU usage, the in-place upgrade looks stalled. We monitored the upgrade progress by counting files modified in the last 24 hours. Monitoring revealed low modification rates, like&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;find /var/lib/mysql -name "*.ibd" -mtime -1 | wc -l
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;14887&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;that were decreasing. Although the InnoDB files continued to be modified, the decreasing modification rate was too low to be practical.&lt;/p&gt;
&lt;h3 id="investigating-the-issue"&gt;Investigating the Issue&lt;/h3&gt;
&lt;p&gt;To debug this problem we used the Linux &lt;a href="https://percona.community/blog/2020/02/05/finding-mysql-scaling-problems-using-perf" target="_blank" rel="noopener noreferrer"&gt;&lt;code&gt;perf&lt;/code&gt;&lt;/a&gt; tool. While the &lt;code&gt;mysqld&lt;/code&gt; process was running during upgrade:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;we collected &lt;code&gt;perf&lt;/code&gt; data&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-1"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;perf record -F 10 -o mysqld.perf -p $(pidof mysqld) -- sleep 20;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[ perf record: Woken up 1 times to write data ]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[ perf record: Captured and wrote 0.256 MB mysqld.perf (1016 samples) ]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;and produced the &lt;code&gt;perf&lt;/code&gt; report&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-2" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-2"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;perf report --input mysqld.perf --stdio
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# To display the perf.data header info, please use --header/--header-only options.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;#
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;#
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# Total Lost Samples: 0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;#
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# Samples: 1K of event 'cpu-clock'
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# Event count (approx.): 101600000000
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;#
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# Overhead Command Shared Object Symbol
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# ........ ....... .................. ................................
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;#
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 34.55% mysqld libc-2.17.so [.] __sched_yield
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 14.86% mysqld [kernel.kallsyms] [k] __raw_spin_unlock_irq
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 11.32% mysqld [kernel.kallsyms] [k] system_call_after_swapgs
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 11.32% mysqld mysqld [.] Fil_shard::reserve_open_slot
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;To find out why &lt;code&gt;mysqld&lt;/code&gt; process stuck in the &lt;code&gt;Fil_shard::reserve_open_slot&lt;/code&gt; call, we checked the &lt;a href="https://github.com/percona/percona-server/blob/Percona-Server-8.0.25-15/storage/innobase/fil/fil0fil.cc#L2125" target="_blank" rel="noopener noreferrer"&gt;Percona Server source code&lt;/a&gt; that shows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the function code&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-3" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-3"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/** Wait for an empty slot to reserve for opening a file.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;@return true on success. */
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;bool Fil_shard::reserve_open_slot(size_t shard_id) {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; size_t expected = EMPTY_OPEN_SLOT;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; return s_open_slot.compare_exchange_weak(expected, shard_id);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;and the corresponding comments&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-4" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-4"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;The data structure (Fil_shard) that keeps track of the tablespace ID to
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;fil_space_t* mapping are hashed on the tablespace ID. The tablespace name to
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;fil_space_t* mapping is stored in the same shard. A shard tracks the flushing
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;and open state of a file. When we run out open file handles, we use a ticketing
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;system to serialize the file open, see Fil_shard::reserve_open_slot() and
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Fil_shard::release_open_slot().&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Apparently, the stalled upgrade process hit the open files limit, given the large number of files in our environment.&lt;/p&gt;
&lt;h3 id="resolving-the-issue"&gt;Resolving the Issue&lt;/h3&gt;
&lt;p&gt;To prevent the &lt;code&gt;mysqld&lt;/code&gt; upgrade process from running out of open file handles, we followed &lt;a href="https://www.percona.com/blog/using-percona-xtrabackup-mysql-instance-large-number-tables" target="_blank" rel="noopener noreferrer"&gt;Percona guidance&lt;/a&gt; for setting open files limit&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Counted files as&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-5" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-5"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;find /var/lib/mysql/ -name "*.ibd" | wc -l
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;324780&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;and added another 1000 to this number for other miscellaneous open file needs.&lt;/p&gt;
&lt;ol start="2"&gt;
&lt;li&gt;Increased the &lt;code&gt;innodb_open_files&lt;/code&gt; limit in two places:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;added a corresponding line to configuration file &lt;code&gt;/etc/my.cnf&lt;/code&gt; like&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-6" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-6"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;innodb_open_files = 325780&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;added a corresponding line to the &lt;code&gt;systemd&lt;/code&gt; configuration file such as &lt;code&gt;/etc/systemd/system/mysqld.service.d/override.conf&lt;/code&gt; like&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-7" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-7"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[Service]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;LimitNOFILE = 325780&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;With these adjustments our upgrade completed processing of a terabyte of data in just a few hours. To provide more visibility into the upgrade process we also increased the default level of error log verbosity by adding another line to the &lt;code&gt;/etc/my.cnf&lt;/code&gt; file:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-8" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-8"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;log_error_verbosity = 3&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Increased verbosity enabled progress monitoring in the mysql error log during upgrade, like:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-9" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-9"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2023-10-28T00:27:09.331924Z 0 [System] [MY-010116] [Server] /usr/sbin/mysqld (mysqld 8.0.25-15) starting as process 16034
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2023-10-28T00:27:09.353871Z 1 [System] [MY-011012] [Server] Starting upgrade of data directory.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2023-10-28T00:27:09.353986Z 1 [System] [MY-013576] [InnoDB] InnoDB initialization has started.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2023-10-28T00:27:19.412572Z 1 [Note] [MY-012206] [InnoDB] Found 324780 '.ibd' and 0 undo files
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2023-10-28T00:27:19.412757Z 1 [Note] [MY-012207] [InnoDB] Using 17 threads to scan 324780 tablespace files
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2023-10-28T00:27:28.764032Z 0 [Note] [MY-012200] [InnoDB] Thread# 0 - Checked 15615/20298 files
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2023-10-28T00:27:31.718051Z 0 [Note] [MY-012201] [InnoDB] Checked 20298 files
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2023-10-28T00:27:31.718440Z 1 [Note] [MY-012208] [InnoDB] Completed space ID check of 324780 files.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2023-10-28T00:27:48.821432Z 1 [Note] [MY-012922] [InnoDB] Waiting for purge to start
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2023-10-28T00:27:48.878058Z 1 [System] [MY-013577] [InnoDB] InnoDB initialization has ended.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2023-10-28T00:27:48.885203Z 1 [Note] [MY-011088] [Server] Data dictionary initializing version '80023'.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2023-10-28T00:27:49.187508Z 1 [Note] [MY-010337] [Server] Created Data Dictionary for upgrade
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2023-10-28T01:57:55.312683Z 2 [System] [MY-011003] [Server] Finished populating Data Dictionary tables with data.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2023-10-28T01:59:15.187709Z 5 [System] [MY-013381] [Server] Server upgrade from '50700' to '80025' started.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2023-10-28T03:01:09.880932Z 5 [System] [MY-013381] [Server] Server upgrade from '50700' to '80025' completed.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2023-10-28T03:01:13.905459Z 0 [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Version: '8.0.25-15' socket: '/var/lib/mysql/mysql.sock' port: 3306 Percona Server (GPL), Release 15, Revision a558ec2.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="discussion"&gt;Discussion&lt;/h3&gt;
&lt;p&gt;While we were contemplating if this is a feature or a bug, MySQL release 8.0.28 refactored the related &lt;a href="https://dev.mysql.com/doc/refman/8.0/en/innodb-parameters.html#sysvar_innodb_open_files" target="_blank" rel="noopener noreferrer"&gt;&lt;code&gt;innodb_open_files&lt;/code&gt;&lt;/a&gt; code. Further details are provided in the corresponding open source commit &lt;a href="https://github.com/percona/percona-server/commit/b184bd30f94df30a8bf178fc327590c5865d33bc" target="_blank" rel="noopener noreferrer"&gt;WL#14591 InnoDB: Make system variable &lt;code&gt;innodb_open_files&lt;/code&gt; dynamic&lt;/a&gt;:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-10" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-10"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- The `innodb_open_files` system variable can now be set with a dynamic SQL procedure `innodb_set_open_files_limit(N)`. If the new value is too low, an error is returned to client with the minimum value presented. If the value is out of bounds or of incorrect type, it will be reported as error also.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- `Fil_system::set_open_files_limit` was added to allow changes to the global opened files limit. The `Fil_system::m_max_n_open` is atomic now and extracted to a separate class `fil::detail::Open_files_limit`, instantiated as `Fil_system::m_open_files_limit`.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- `Fil_shard::reserve_open_slot`, Fil_shard::release_open_slot and static Fil_shard::s_open_slot were removed. Now we have CAS-based system of assuring the opened files will not exceed the limit set.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Thus, the new MySQL 8.0.28 feature – dynamic &lt;code&gt;innodb_open_files&lt;/code&gt; variable – eliminated the need for open files limit adjustments in preparation for MySQL 8.0 upgrade.&lt;/p&gt;
&lt;h2 id="conclusions"&gt;Conclusions&lt;/h2&gt;
&lt;p&gt;Lessons learned:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Prepare for MySQL 8.0 upgrade in-place by taking a backup of the data directory.&lt;/li&gt;
&lt;li&gt;Take advantage of the Percona Server open source code.&lt;/li&gt;
&lt;li&gt;Follow guidance and advice posted in Percona blogs.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;The content in this blog is provided in good faith by members of the open source community. Percona has not edited or tested the technical content. Views expressed are the authors’ own. When using the advice from this or any other online resource test ideas before applying them to your production systems, and always secure a working back up.&lt;/em&gt;&lt;/p&gt;</content:encoded>
      <author>Alexandre Vaniachine</author>
      <category>Intermediate Level</category>
      <category>MySQL</category>
      <category>Percona Server for MySQL</category>
      <category>upgrade</category>
      <media:thumbnail url="https://percona.community/blog/2024/01/unexpected-stalled-upgrade-to-mysql-8-0_hu_bbbfb5f7838bc57d.jpg"/>
      <media:content url="https://percona.community/blog/2024/01/unexpected-stalled-upgrade-to-mysql-8-0_hu_b802951e238a2edd.jpg" medium="image"/>
    </item>
    <item>
      <title>Our Top Picks from the Kubernetes 1.29 Release</title>
      <link>https://percona.community/blog/2024/01/12/our-top-picks-from-the-kubernetes-release/</link>
      <guid>https://percona.community/blog/2024/01/12/our-top-picks-from-the-kubernetes-release/</guid>
      <pubDate>Fri, 12 Jan 2024 00:00:00 UTC</pubDate>
      <description>The latest Kubernetes version, 1.29, was released on December 13th 2023. Inspired by the Mandala and symbolizing universal perfection, it concludes the 2023 release calendar. This version comes with various exciting improvements, many of which will be helpful for users who run databases on Kubernetes.</description>
      <content:encoded>&lt;p&gt;The latest &lt;strong&gt;Kubernetes&lt;/strong&gt; version, &lt;strong&gt;1.29&lt;/strong&gt;, was released on December 13th 2023. Inspired by the Mandala and symbolizing universal perfection, it concludes the 2023 release calendar. This version comes with various exciting improvements, many of which will be helpful for users who run databases on Kubernetes.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2024/01/k8s-mandala-medium.png" alt="Mandala" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Figure 1&lt;/strong&gt; - Mandala created in Excalidraw, not perfectly symmetrical.&lt;/p&gt;
&lt;p&gt;Here, we highlight this latest release’s four key features and improvements. Let’s take a look at them together.&lt;/p&gt;
&lt;h2 id="in-place-update-of-pod-resources"&gt;In-Place Update of Pod Resources&lt;/h2&gt;
&lt;p&gt;This alpha feature allows users to change requests and limits for containers without restarting. It simplifies scaling by a lot and opens new opportunities for auto scaling tools like HPA, VP, and Kubernetes Event-driven Autoscaling (KEDA). It removes the barriers of scaling the applications that were not easy to restart.&lt;/p&gt;
&lt;p&gt;When resource resizing is not possible in-place, there are clear strategies for users and controllers (like StatefulSets, JobController, etc.) to handle the situation effectively.&lt;/p&gt;
&lt;p&gt;It was first introduced in 1.27 but moved back to alpha as it requires additional architectural changes. It also has &lt;a href="https://github.com/kubernetes/kubernetes/pull/119665" target="_blank" rel="noopener noreferrer"&gt;performance improvements&lt;/a&gt; and comes with &lt;a href="https://github.com/kubernetes/kubernetes/pull/112599" target="_blank" rel="noopener noreferrer"&gt;Windows containers support&lt;/a&gt;.
Read more about this in its Kubernetes Enhancement Proposals (&lt;a href="https://github.com/kubernetes/enhancements/tree/master/keps/sig-node/1287-in-place-update-pod-resources" target="_blank" rel="noopener noreferrer"&gt;KEP&lt;/a&gt;) and the &lt;a href="https://github.com/kubernetes/enhancements/issues/1287" target="_blank" rel="noopener noreferrer"&gt;issue #1287&lt;/a&gt; created to add this feature.&lt;/p&gt;
&lt;h2 id="kubernetes-volumeattributesclass-modifyvolume"&gt;Kubernetes VolumeAttributesClass ModifyVolume&lt;/h2&gt;
&lt;p&gt;The Kubernetes v1.29 release introduces an alpha feature enabling modification of volume attributes, like IOPS and throughput, by altering the volumeAttributesClassName in a PersistentVolumeClaim (PVC). This simplifies volume management by allowing direct updates within Kubernetes, avoiding the need for external provider API management. Previously, users had to create a new StorageClass resource and migrate to a new PVC; now, changes can be made directly in the existing PVC.&lt;/p&gt;
&lt;p&gt;Discover further details in the &lt;a href="https://github.com/kubernetes/enhancements/pull/3780" target="_blank" rel="noopener noreferrer"&gt;KEP&lt;/a&gt; and issue &lt;a href="https://github.com/kubernetes/enhancements/issues/3751" target="_blank" rel="noopener noreferrer"&gt;#1287&lt;/a&gt;, which was established for the inclusion of this feature.&lt;/p&gt;
&lt;h2 id="readwriteoncepod-persistentvolume-access-mode"&gt;ReadWriteOncePod PersistentVolume Access Mode&lt;/h2&gt;
&lt;p&gt;Kubernetes offers access modes for Persistent Volumes (PVs) and Persistent Volume Claims (PVCs), including ReadWriteOnce, ReadOnlyMany, and ReadWriteMany. In particular, ReadWriteOnce restricts volume access to a single node, enabling multiple pods on that node to read from and write to the same volume concurrently. This setup ensures exclusive volume access on a per-node basis while allowing shared volume usage within the node. However, this introduces a potential issue, especially for applications that require exclusive access by a single pod.
In this release, the ReadWriteOncePod access mode for PersistentVolumeClaims has become stable. Now that it is stable, a PVC can be configured to be mounted by a single Pod exclusively.&lt;/p&gt;
&lt;p&gt;Here are the Kubernetes Enhancement Proposal (&lt;a href="https://github.com/kubernetes/enhancements/tree/master/keps/sig-storage/2485-read-write-once-pod-pv-access-mode" target="_blank" rel="noopener noreferrer"&gt;KEP&lt;/a&gt;) and issue &lt;a href="https://github.com/kubernetes/enhancements/issues/2485" target="_blank" rel="noopener noreferrer"&gt;#2485&lt;/a&gt; that led to the development of this feature.&lt;/p&gt;
&lt;h2 id="make-kubernetes-aware-of-the-loadbalancer-behavior"&gt;Make Kubernetes aware of the LoadBalancer behavior&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;kube-proxy’s&lt;/strong&gt; handling of LoadBalancer Service External IPs is set to change. Traditional methods, such as IPVS and iptables, bind these IPs to nodes, optimizing traffic but causing issues with certain cloud providers and bypassing key Load Balancer features.&lt;/p&gt;
&lt;p&gt;There are numerous problems with existing behavior:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Some cloud providers (Scaleway, Tencent Cloud, …) are using the LB’s external IP (or a private IP) as source IP when sending packets to the cluster. This is a problem in the ipvs mode of kube-proxy since the IP is bounded to an interface, and healthchecks from the LB is never coming back.&lt;/li&gt;
&lt;li&gt;Some cloud providers (DigitalOcean, Scaleway, …) have features at the LB level (TLS termination, PROXY protocol, …). Bypassing the LB means missing these features when the packet arrives at the service (leading to protocol errors).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The solution would be to add a new field in the loadBalancer field of a Service’s status, like ipMode. This new field will be used by kube-proxy in order to not bind the Load Balancer’s External IP to the node (in both IPVS and iptables mode). The value VIP would be the default one (if not set, for instance), keeping the current behavior. The value Proxy would be used to disable the shortcut. This change allows more flexible handling of External IPs, maintaining current behavior as the default and offering an alternative to avoid these issues.&lt;/p&gt;
&lt;p&gt;Read more about this in its Kubernetes Enhancement Proposals (&lt;a href="https://github.com/kubernetes/enhancements/tree/b103a6b0992439f996be4314caf3bf7b75652366/keps/sig-network/1860-kube-proxy-IP-node-binding#kep-1860-make-kubernetes-aware-of-the-loadbalancer-behaviour" target="_blank" rel="noopener noreferrer"&gt;KEP&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;If you are interested in learning about databases on Kubernetes, you can start by &lt;a href="https://www.percona.com/blog/run-mysql-in-kubernetes-solutions-pros-and-cons/" target="_blank" rel="noopener noreferrer"&gt;running MySQL in Kubernetes&lt;/a&gt;. Explore the solutions, and weigh the pros and cons.
Also, discover our &lt;a href="https://www.percona.com/blog/cloud-native-predictions-for-2024/" target="_blank" rel="noopener noreferrer"&gt;predictions for Cloud Native&lt;/a&gt; technologies for this year.&lt;/p&gt;</content:encoded>
      <author>Sergey Pronin</author>
      <author>Edith Puclla</author>
      <category>edith_puclla</category>
      <category>sergey_pronin</category>
      <category>kubernetes</category>
      <category>release</category>
      <media:thumbnail url="https://percona.community/blog/2024/01/k8s-mandala-medium_hu_ccf52cc202bf7b2b.jpg"/>
      <media:content url="https://percona.community/blog/2024/01/k8s-mandala-medium_hu_18b7d20759a07139.jpg" medium="image"/>
    </item>
    <item>
      <title>Data on Kubernetes Community initiatives: Automated storage scaling</title>
      <link>https://percona.community/blog/2024/01/10/data-on-kubernetes-community-initiatives/</link>
      <guid>https://percona.community/blog/2024/01/10/data-on-kubernetes-community-initiatives/</guid>
      <pubDate>Wed, 10 Jan 2024 00:00:00 UTC</pubDate>
      <description>In the world of Kubernetes, where everything evolves quickly. Automated storage scaling stands out as a critical challenge. Members of the Data on Kubernetes Community have proposed a solution to address this issue for Kubernetes operators.</description>
      <content:encoded>&lt;p&gt;In the world of Kubernetes, where everything evolves quickly. Automated storage scaling stands out as a critical challenge. Members of the &lt;a href="https://dok.community/" target="_blank" rel="noopener noreferrer"&gt;Data on Kubernetes Community&lt;/a&gt; have proposed a solution to address this issue for Kubernetes operators.&lt;/p&gt;
&lt;p&gt;If, like me, this is your first time hearing about Automated storage scaling, this will help you understand it better:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Storage scaling in Kubernetes Operators&lt;/strong&gt; refers to the ability of an application running on Kubernetes to adjust its storage capacity automatically based on demand. In other words, it is about ensuring that an application has the right amount of storage available at any given time, optimizing for performance, cost, and operational efficiency, and doing this as automatically as possible.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2024/01/dok-initiatives_hu_4bcb895cefa55e4d.png 480w, https://percona.community/blog/2024/01/dok-initiatives_hu_7f5c00b0f4b03204.png 768w, https://percona.community/blog/2024/01/dok-initiatives_hu_3ea9e18a22740b26.png 1400w"
src="https://percona.community/blog/2024/01/dok-initiatives.png" alt="DoKC Initiatives" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;As databases grow increasingly integral, the absence of unified solutions for storage scaling is becoming more evident. Let’s explore some existing solutions and their limitations:&lt;/p&gt;
&lt;h2 id="pvc-autoresizer"&gt;pvc-autoresizer&lt;/h2&gt;
&lt;p&gt;This project detects and scales &lt;strong&gt;PersistentVolumeClaims&lt;/strong&gt; (PVCs) when the free amount of storage is below the threshold. &lt;a href="https://github.com/topolvm/pvc-autoresizer" target="_blank" rel="noopener noreferrer"&gt;pvc-autoresizer&lt;/a&gt; It is and active open source project on GitHub.&lt;/p&gt;
&lt;p&gt;There are certain downsides:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Works with PVCs only. It does not work with StatefulSet and does not have integration with Kubernetes Operator.&lt;/li&gt;
&lt;li&gt;It requires Prometheus stack to be deployed.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Percona wrote a &lt;a href="https://www.percona.com/blog/storage-autoscaling-with-percona-operator-for-mongodb/" target="_blank" rel="noopener noreferrer"&gt;blog post&lt;/a&gt; about pvc-autoresizer to automate storage scaling for MongoDB clusters on Kubernetes.&lt;/p&gt;
&lt;h2 id="ebs-params-controller"&gt;EBS params controller&lt;/h2&gt;
&lt;p&gt;This controller provides a way to control IOPS and throughput parameters for EBS volumes provisioned by EBS CSI Driver with annotations on corresponding PersistentVolumeClaim objects in Kubernetes. It also sets some annotations on PVCs backed by EBS CSI Driver representing current parameters and last modification status and timestamps.&lt;/p&gt;
&lt;p&gt;Find more about &lt;a href="https://github.com/Altinity/ebs-params-controller" target="_blank" rel="noopener noreferrer"&gt;EBS params controller on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="kubernetes-volume-autoscaler"&gt;Kubernetes Volume Autoscaler&lt;/h2&gt;
&lt;p&gt;This automatically increases the size of a Persistent Volume Claim (PVC) in Kubernetes when it is nearing full (either on space OR inode usage). It is a similar solution to pvc-autoresizer. Check out more about &lt;a href="https://github.com/DevOps-Nirvana/Kubernetes-Volume-Autoscaler" target="_blank" rel="noopener noreferrer"&gt;Kubernetes Volume Autoscaler&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="kubernetes-event-driven-autoscalingkeda"&gt;Kubernetes Event-driven Autoscaling(KEDA)&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://keda.sh/" target="_blank" rel="noopener noreferrer"&gt;KEDA&lt;/a&gt; performs horizontal scaling for various resources in k8s, including custom resources. The metric tracking component is already figured out, but unfortunately, it does not work with vertical scaling or storage scaling yet. We opened &lt;a href="https://github.com/kedacore/keda/issues/5232" target="_blank" rel="noopener noreferrer"&gt;an issue in GitHub&lt;/a&gt; to start the discussion.&lt;/p&gt;
&lt;p&gt;As you can see, there are some limitations to performing Automated storage scaling, and to address this gap, the &lt;strong&gt;Data on Kubernetes community&lt;/strong&gt; wants to develop a solution that solves practical problems and contributes to the open source community.&lt;/p&gt;
&lt;p&gt;We’re tackling the significant challenge of unexpected disk usage alerts and potential system shutdowns due to insufficient volume space, a common issue in Kubernetes-based databases.&lt;/p&gt;
&lt;h2 id="possible-solutions"&gt;Possible Solutions&lt;/h2&gt;
&lt;p&gt;The following possible solutions were proposed:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Operators must be capable of changing the storage size when Custom Resource is changed.&lt;/li&gt;
&lt;li&gt;Operators must create resources following certain standards, like applying annotations with indications of which fields should be changed&lt;/li&gt;
&lt;li&gt;3rd party component (Scaler) will take care of monitoring the storage consumption and changing the field in the CR of the DB&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Our goal as a community is to develop a fully automated solution to prevent these inconveniences and failures.&lt;/p&gt;
&lt;h2 id="final-thoughts"&gt;Final Thoughts&lt;/h2&gt;
&lt;p&gt;Once a new solution is validated and proven functional, it will benefit many communities, enabling them to integrate it with their operators. Additionally, it will present an excellent opportunity for Percona to incorporate it into our Operators, enhancing efficiency and facilitating automated storage scaling.&lt;/p&gt;
&lt;p&gt;We invite those interested, especially in this particular project, to join us. This is an opportunity to be at the forefront of shaping the automated scaling solutions in Kubernetes. You can join the &lt;a href="https://join.slack.com/t/dokcommunity/shared_invite/zt-2a0ahuhsh-MdZ4OpF4nr_s4kyOwTurVw" target="_blank" rel="noopener noreferrer"&gt;Data on Kubernetes community&lt;/a&gt; on Slack, specifically on the #SIG-Operator.&lt;/p&gt;
&lt;p&gt;Are you interested in understanding Storage Autoscaling in databases? Explore our detailed example of &lt;a href="https://www.percona.com/blog/storage-autoscaling-with-percona-operator-for-mongodb/" target="_blank" rel="noopener noreferrer"&gt;Storage Autoscaling using the Percona Operator for MongoDB&lt;/a&gt;. For questions or discussions, feel free to join our experts on the &lt;a href="https://forums.percona.com/" target="_blank" rel="noopener noreferrer"&gt;Percona Community Forum&lt;/a&gt;&lt;/p&gt;</content:encoded>
      <author>Sergey Pronin</author>
      <author>Edith Puclla</author>
      <category>edith_puclla</category>
      <category>sergey_pronin</category>
      <category>kubernetes</category>
      <category>dok</category>
      <category>storage</category>
      <category>operators</category>
      <media:thumbnail url="https://percona.community/blog/2024/01/dok-initiatives_hu_9ee5c4ee06283257.jpg"/>
      <media:content url="https://percona.community/blog/2024/01/dok-initiatives_hu_5d481efe00c9cbde.jpg" medium="image"/>
    </item>
    <item>
      <title>Volunteering as a Program Committee Member for Data on Kubernetes Day Europe 2024</title>
      <link>https://percona.community/blog/2024/01/10/volunteering-program-committee-data-kubernetes-europe/</link>
      <guid>https://percona.community/blog/2024/01/10/volunteering-program-committee-data-kubernetes-europe/</guid>
      <pubDate>Wed, 10 Jan 2024 00:00:00 UTC</pubDate>
      <description>The Data on Kubernetes Day Europe 2024 Program Committee is a group of professionals and experts responsible for organizing the Data on Kubernetes Day Europe 2024 content for the upcoming co-located events at Kubecon in Paris on 19 March.</description>
      <content:encoded>&lt;p&gt;The Data on &lt;strong&gt;Kubernetes Day Europe 2024 Program Committee&lt;/strong&gt; is a group of professionals and experts responsible for organizing the &lt;strong&gt;Data on Kubernetes Day Europe 2024&lt;/strong&gt; content for the upcoming co-located events at &lt;a href="https://events.linuxfoundation.org/kubecon-cloudnativecon-europe/" target="_blank" rel="noopener noreferrer"&gt;Kubecon in Paris&lt;/a&gt; on 19 March.&lt;/p&gt;
&lt;p&gt;As Data on Kubernetes community members, &lt;a href="https://www.linkedin.com/in/sergeypronin/" target="_blank" rel="noopener noreferrer"&gt;Sergey Pronin&lt;/a&gt; (Group Product Manager at @Percona) and I (Tech Evangelist) volunteered to evaluate proposal topics submitted for the event through the Sessionize platform. Not only us but also many other members of the Data on Kubernetes community participated as volunteers.&lt;/p&gt;
&lt;p&gt;Community members who participate in this &lt;strong&gt;Program Committee&lt;/strong&gt; evaluate proposals for talks, workshops, and other sessions submitted by potential speakers. This involves identifying each submission’s relevance, quality, and originality and being completely transparent and honest when reviewing a set of talks for the Data On Kubernetes Community co-located event.&lt;/p&gt;
&lt;p&gt;Being a program committee means adhering to guidelines and following the Linux Foundation’s code of conduct.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Be professional and courteous.&lt;/li&gt;
&lt;li&gt;Even express feedback constructively, not destructively.&lt;/li&gt;
&lt;li&gt;Be considerate when choosing communication channels&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After all program committee members completed their evaluations, the Data on Kubernetes Day Co-located Events Europe 2024 &lt;a href="https://colocatedeventseu2024.sched.com/overview/type/Data+on+Kubernetes+Day?iframe=no" target="_blank" rel="noopener noreferrer"&gt;schedule&lt;/a&gt; was announced.&lt;/p&gt;
&lt;p&gt;Look at this promising agenda:&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2024/02/dok2.png" alt="DoKC agenda" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;We feel great to be a part of these efforts and to contribute to something significant by making it a reality at an in-person event. Thanks to the &lt;strong&gt;Linux Foundation&lt;/strong&gt; for recognizing our efforts as Program Committee Members and for considering &lt;a href="https://www.percona.com/" target="_blank" rel="noopener noreferrer"&gt;Percona&lt;/a&gt;, an active member of the DoK community.&lt;/p&gt;
&lt;p&gt;In recognition of this support, we earned a badge from The Linux Foundation.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2024/02/dok3.png" alt="DoKC badge" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;If you want to know more initiatives &lt;strong&gt;Percona&lt;/strong&gt; have in the DoK community, read &lt;a href="https://percona.community/blog/2024/01/10/data-on-kubernetes-community-initiatives/" target="_blank" rel="noopener noreferrer"&gt;Data on Kubernetes Community initiatives: Automated storage scaling&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you have any questions, remember to visit our &lt;a href="https://forums.percona.com/" target="_blank" rel="noopener noreferrer"&gt;Percona Community Forum&lt;/a&gt;.&lt;/p&gt;</content:encoded>
      <author>Edith Puclla</author>
      <category>edith_puclla</category>
      <category>kubernetes</category>
      <category>dok</category>
      <category>kubecon</category>
      <category>europe</category>
      <media:thumbnail url="https://percona.community/blog/2024/02/dok3_hu_aaf69425b29d2d1a.jpg"/>
      <media:content url="https://percona.community/blog/2024/02/dok3_hu_d26ec19e4b6de0df.jpg" medium="image"/>
    </item>
    <item>
      <title>Percona Monitoring and Management 2.41 preview release</title>
      <link>https://percona.community/blog/2023/12/06/preview-release/</link>
      <guid>https://percona.community/blog/2023/12/06/preview-release/</guid>
      <pubDate>Wed, 06 Dec 2023 00:00:00 UTC</pubDate>
      <description>Percona Monitoring and Management 2.41 preview release Hello folks! Percona Monitoring and Management (PMM) 2.41 is now available as a preview release.</description>
      <content:encoded>&lt;h2 id="percona-monitoring-and-management-241-preview-release"&gt;Percona Monitoring and Management 2.41 preview release&lt;/h2&gt;
&lt;p&gt;Hello folks! Percona Monitoring and Management (PMM) 2.41 is now available as a preview release.&lt;/p&gt;
&lt;p&gt;We encourage you to try this PMM preview release in &lt;strong&gt;testing environments only&lt;/strong&gt;, as these packages and images are not fully production-ready. The final version is expected to be released through the standard channels in the coming week.&lt;/p&gt;
&lt;p&gt;To see the full list of changes, check out the &lt;a href="https://pmm-release-branch-pr-1182.onrender.com/release-notes/2.41.0.html" target="_blank" rel="noopener noreferrer"&gt;PMM 2.41 Release Notes&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="pmm-server-docker-installation"&gt;PMM server Docker installation&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://docs.percona.com/percona-monitoring-and-management/setting-up/server/docker.html" target="_blank" rel="noopener noreferrer"&gt;Run PMM Server with Docker instructions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;docker tag:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;perconalab/pmm-server:2.41.0-rc&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="pmm-client-package-installation"&gt;PMM client package installation&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://s3.us-east-2.amazonaws.com/pmm-build-cache/PR-BUILDS/pmm2-client/pmm2-client-latest-5997.tar.gz" target="_blank" rel="noopener noreferrer"&gt;Download&lt;/a&gt; the latest pmm2-client release candidate tarball for 2.41.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;To install pmm2-client package, enable testing repository via Percona-release:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;percona-release enable percona testing&lt;/code&gt;&lt;/p&gt;
&lt;ol start="3"&gt;
&lt;li&gt;Install pmm2-client package for your OS via Package Manager.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="ova"&gt;OVA&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://docs.percona.com/percona-moitoring-and-management/setting-up/server/virtual-appliance.html" target="_blank" rel="noopener noreferrer"&gt;Run PMM Server as a VM instructions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://percona-vm.s3.amazonaws.com/PMM2-Server-2.41.0.ova" target="_blank" rel="noopener noreferrer"&gt;PMM2-Server-2.41.0.ova file&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="ami"&gt;AMI&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://docs.percona.com/percona-monitoring-and-management/setting-up/server/aws.html" target="_blank" rel="noopener noreferrer"&gt;Run PMM Server hosted at AWS Marketplace instructions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ami-0a04085f4c721e913&lt;/code&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Contact us on the [Percona Community Forums](&lt;a href="https://forums.percona.com/]" target="_blank" rel="noopener noreferrer"&gt;https://forums.percona.com/]&lt;/a&gt;.&lt;/p&gt;</content:encoded>
      <author>Ondrej Patocka</author>
      <category>PMM</category>
      <category>Release</category>
      <media:thumbnail url="https://percona.community/superhero_hu_252fc2b480c0a197.jpg"/>
      <media:content url="https://percona.community/superhero_hu_17979f11d5d3562e.jpg" medium="image"/>
    </item>
    <item>
      <title>The Importance of Anti-Affinity in Kubernetes</title>
      <link>https://percona.community/blog/2023/11/30/anti-affinity-in-kubernetes/</link>
      <guid>https://percona.community/blog/2023/11/30/anti-affinity-in-kubernetes/</guid>
      <pubDate>Thu, 30 Nov 2023 00:00:00 UTC</pubDate>
      <description>Last week, I embarked on the task of deploying our Percona Operator for MongoDB in Kubernetes. After completing the deployment process, I noticed that the status of the Custom Resource Definition for Percona Server for MongoDB was still displaying as ‘initializing’ and two of our Pods remained in a Pending state.</description>
      <content:encoded>&lt;p&gt;Last week, I embarked on the task of deploying our &lt;a href="https://docs.percona.com/percona-operator-for-mongodb/index.html" target="_blank" rel="noopener noreferrer"&gt;Percona Operator for MongoDB&lt;/a&gt; in Kubernetes. After completing the deployment process, I noticed that the status of the Custom Resource Definition for Percona Server for MongoDB was still displaying as ‘initializing’ and two of our Pods remained in a &lt;strong&gt;Pending&lt;/strong&gt; state.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;edithpuclla@Ediths-MBP % kubectl get perconaservermongodbs.psmdb.percona.com -n mongodb
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NAME ENDPOINT STATUS AGE
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;my-db-psmdb-db my-db-psmdb-db-mongos.mongodb.svc.cluster.local initializing 4m58s&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-1"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;edithpuclla@Ediths-MBP % kubectl get pods -n mongodb
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NAME READY STATUS RESTARTS AGE
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;my-db-psmdb-db-cfg-0 2/2 Running &lt;span class="m"&gt;0&lt;/span&gt; 109m
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;my-db-psmdb-db-cfg-1 2/2 Running &lt;span class="m"&gt;0&lt;/span&gt; 108m
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;my-db-psmdb-db-cfg-2 0/2 Pending &lt;span class="m"&gt;0&lt;/span&gt; 107m
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;my-db-psmdb-db-mongos-0 1/1 Running &lt;span class="m"&gt;0&lt;/span&gt; 106m
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;my-db-psmdb-db-mongos-1 1/1 Running &lt;span class="m"&gt;0&lt;/span&gt; 106m
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;my-db-psmdb-db-rs0-0 2/2 Running &lt;span class="m"&gt;0&lt;/span&gt; 109m
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;my-db-psmdb-db-rs0-1 2/2 Running &lt;span class="m"&gt;0&lt;/span&gt; 108m
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;my-db-psmdb-db-rs0-2 0/2 Pending &lt;span class="m"&gt;0&lt;/span&gt; 107m
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;my-op-psmdb-operator-77b75bbc7c-qd9ls 1/1 Running &lt;span class="m"&gt;0&lt;/span&gt; 118m&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Upon further inspection of the pod in &lt;strong&gt;pending&lt;/strong&gt; status, I discovered a clear indicator of the error:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-2" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-2"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl describe pod my-db-psmdb-db-cfg-2 -n mongodb
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Events:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Type Reason Age From Message
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ---- ------ ---- ---- -------
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Normal NotTriggerScaleUp 3m53s &lt;span class="o"&gt;(&lt;/span&gt;x62 over 13m&lt;span class="o"&gt;)&lt;/span&gt; cluster-autoscaler pod didn&lt;span class="s1"&gt;'t trigger scale-up:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; Warning FailedScheduling 3m27s (x4 over 13m) default-scheduler 0/2 nodes are available: 2 node(s) didn'&lt;/span&gt;t match pod anti-affinity rules. preemption: 0/2 nodes are available: &lt;span class="m"&gt;2&lt;/span&gt; No preemption victims found &lt;span class="k"&gt;for&lt;/span&gt; incoming pod..&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;I took a closer look at the YAML configuration of our CRD in the &lt;strong&gt;Replsets&lt;/strong&gt; section, particularly drawn to the &lt;strong&gt;Affinity&lt;/strong&gt; subsection.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-3" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-3"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl describe perconaservermongodbs.psmdb.percona.com my-db-psmdb-db -n mongodb&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Here’s what I discovered:&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2023/11/affinity-01.png" alt="Affinity" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Affinity&lt;/strong&gt; and &lt;strong&gt;Anti-Affinity&lt;/strong&gt; are key parts of the scheduling process in Kubernetes, and both focus on ensuring that Pods are correctly assigned to Nodes in the cluster. You can configure a Pod to run on a specific node or group of nodes. There are several ways to achieve this, &lt;a href="https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector" target="_blank" rel="noopener noreferrer"&gt;nodeSelector&lt;/a&gt; is the simplest way to constrain Pods to nodes with specific labels. Affinity and anti-affinity expand the types of constraints you can define and give you more flexibility.&lt;/p&gt;
&lt;p&gt;Let’s explore what it means to specify anti-affinity rules for the ReplicaSets.&lt;/p&gt;
&lt;p&gt;The key &lt;strong&gt;kubernetes.io/hostname&lt;/strong&gt; is a well-known label in Kubernetes that is automatically assigned to each node in the cluster. It usually holds the value of the node’s hostname.
When used as a topology key in anti-affinity rules, it implies that the rule should consider the hostname of the nodes. In simpler terms, it’s telling Kubernetes to not to schedule the pods of this ReplicaSet on the same physical or virtual host (node).&lt;/p&gt;
&lt;p&gt;If we review our cluster, it has two nodes for installing the Percona Operator for MongoDB.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-4" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-4"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;edithpuclla@Ediths-MBP ~ % kubectl get nodes
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NAME STATUS ROLES AGE VERSION
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gke-mongo-operator-test-default-pool-7c118de9-b9vc Ready &lt;none&gt; 68m v1.27.4-gke.900
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gke-mongo-operator-test-default-pool-7c118de9-ts16 Ready &lt;none&gt; 68m v1.27.4-gke.900&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;In the context of databases like MongoDB, High availability is often achieved through replication, ensuring that the database can continue to operate even if one or more nodes fail. Within a MongoDB Replica Set, there are multiple copies of the data, and these copies are hosted on different Replica Set members. The default HA MongoDB topology is a 3-member Replica Set. &lt;strong&gt;Percona Operator for MongoDB&lt;/strong&gt; deploys MongoDB in the same topology by default. With anti-affinity set to kubernetes.io/hostname, that means at least 3 Kubernetes worker nodes are needed to deploy MongoDB.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2023/11/affinity-02_hu_9f71c4f3e029f3f6.png 480w, https://percona.community/blog/2023/11/affinity-02_hu_f22f9a32d98909e3.png 768w, https://percona.community/blog/2023/11/affinity-02_hu_5830a796c8ada964.png 1400w"
src="https://percona.community/blog/2023/11/affinity-02.png" alt="Affinity" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;We created the minimum three nodes that the &lt;strong&gt;Percona Operator for MongoDB&lt;/strong&gt; needs. We see that we don’t have the error with Antiaffinity in the Pods because each Pod was located appropriately in different nodes. Now our operator and our database were deployed correctly.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-5" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-5"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;edithpuclla@Ediths-MBP ~ % kubectl get nodes
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NAME STATUS ROLES AGE VERSION
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gke-mongo-operator-test-default-pool-e4e024a8-1dj3 Ready &lt;none&gt; 76s v1.27.4-gke.900
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gke-mongo-operator-test-default-pool-e4e024a8-d6j2 Ready &lt;none&gt; 74s v1.27.4-gke.900
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gke-mongo-operator-test-default-pool-e4e024a8-jkkr Ready &lt;none&gt; 76s v1.27.4-gke.900&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;If we list all the resources in our namespace, we can see that all pods are running properly and all the resources have been created.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-6" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-6"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;edithpuclla@Ediths-MBP ~ % kubectl get all -n mongodb
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NAME READY STATUS RESTARTS AGE
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pod/my-db-psmdb-db-cfg-0 2/2 Running &lt;span class="m"&gt;0&lt;/span&gt; 4m40s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pod/my-db-psmdb-db-cfg-1 2/2 Running &lt;span class="m"&gt;0&lt;/span&gt; 4m2s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pod/my-db-psmdb-db-cfg-2 2/2 Running &lt;span class="m"&gt;0&lt;/span&gt; 3m20s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pod/my-db-psmdb-db-mongos-0 1/1 Running &lt;span class="m"&gt;0&lt;/span&gt; 2m56s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pod/my-db-psmdb-db-mongos-1 1/1 Running &lt;span class="m"&gt;0&lt;/span&gt; 2m39s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pod/my-db-psmdb-db-rs0-0 2/2 Running &lt;span class="m"&gt;0&lt;/span&gt; 4m39s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pod/my-db-psmdb-db-rs0-1 2/2 Running &lt;span class="m"&gt;0&lt;/span&gt; 3m59s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pod/my-db-psmdb-db-rs0-2 2/2 Running &lt;span class="m"&gt;0&lt;/span&gt; 3m28s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pod/my-op-psmdb-operator-77b75bbc7c-q2rqh 1/1 Running &lt;span class="m"&gt;0&lt;/span&gt; 6m47s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NAME TYPE CLUSTER-IP EXTERNAL-IP PORT&lt;span class="o"&gt;(&lt;/span&gt;S&lt;span class="o"&gt;)&lt;/span&gt; AGE
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;service/my-db-psmdb-db-cfg ClusterIP None &lt;none&gt; 27017/TCP 4m40s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;service/my-db-psmdb-db-mongos ClusterIP 10.72.17.115 &lt;none&gt; 27017/TCP 2m56s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;service/my-db-psmdb-db-rs0 ClusterIP None &lt;none&gt; 27017/TCP 4m39s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NAME READY UP-TO-DATE AVAILABLE AGE
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;deployment.apps/my-op-psmdb-operator 1/1 &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; 6m47s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NAME DESIRED CURRENT READY AGE
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;replicaset.apps/my-op-psmdb-operator-77b75bbc7c &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; 6m47s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NAME READY AGE
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;statefulset.apps/my-db-psmdb-db-cfg 3/3 4m41s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;statefulset.apps/my-db-psmdb-db-mongos 2/2 2m58s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;statefulset.apps/my-db-psmdb-db-rs0 3/3 4m40s&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;In conclusion, affinity and anti-affinity in Kubernetes are tools for strategically placing pods in a cluster to optimize factors such as performance, availability, and compliance, which are critical for the smooth and efficient operation of containerized applications, also setting up anti-affinity rules like &lt;a href="https://docs.percona.com/percona-operator-for-mongodb/constraints.html#affinity-and-anti-affinity" target="_blank" rel="noopener noreferrer"&gt;failure-domain.beta.kubernetes.io/zone&lt;/a&gt; in Kubernetes is a key strategy for keeping clusters running, especially in production environments. This approach spreads pods across different availability zones, which means if one zone has an issue, the others can keep the system running. It’s a smart way to ensure your cluster can handle unexpected outages, making it a popular choice for those who need their Kubernetes setups to be reliable and available at all times.&lt;/p&gt;
&lt;p&gt;Learn more about our &lt;a href="https://docs.percona.com/percona-operator-for-mongodb/index.html" target="_blank" rel="noopener noreferrer"&gt;Percona Operator for MongoDB&lt;/a&gt;, and if you have questions or comments, you can write to us on our &lt;a href="https://forums.percona.com/" target="_blank" rel="noopener noreferrer"&gt;Percona Community Forum&lt;/a&gt;.&lt;/p&gt;</content:encoded>
      <author>Edith Puclla</author>
      <category>Kubernetes</category>
      <category>Mongodb</category>
      <media:thumbnail url="https://percona.community/blog/2023/11/affinity-intro_hu_329445018cc2184f.jpg"/>
      <media:content url="https://percona.community/blog/2023/11/affinity-intro_hu_57483ac446857898.jpg" medium="image"/>
    </item>
    <item>
      <title>Data On Kubernetes</title>
      <link>https://percona.community/blog/2023/11/10/data-on-kubernetes/</link>
      <guid>https://percona.community/blog/2023/11/10/data-on-kubernetes/</guid>
      <pubDate>Fri, 10 Nov 2023 00:00:00 UTC</pubDate>
      <description>If you’ve attended one of the Kubecon talks or related events, you’ve likely encountered the phrase Data on Kubernetes. To understand what this means, let’s explore some fundamental concepts related to Kubernetes, workload, stateless, and stateful applications.</description>
      <content:encoded>&lt;p&gt;If you’ve attended one of the Kubecon talks or related events, you’ve likely encountered the phrase &lt;strong&gt;Data on Kubernetes&lt;/strong&gt;.
To understand what this means, let’s explore some fundamental concepts related to &lt;strong&gt;Kubernetes&lt;/strong&gt;, &lt;strong&gt;workload&lt;/strong&gt;, &lt;strong&gt;stateless&lt;/strong&gt;, and &lt;strong&gt;stateful&lt;/strong&gt; applications.&lt;/p&gt;
&lt;h2 id="kubernetes-workload-stateless-and-stateful-applications"&gt;Kubernetes, workload, stateless and stateful applications&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://kubernetes.io/" target="_blank" rel="noopener noreferrer"&gt;Kubernetes&lt;/a&gt; is a &lt;strong&gt;container orchestration&lt;/strong&gt; tool that has already become an industry standard. When we talk about “container orchestration”, we are referring to the automated management and coordination of containers using Kubernetes.&lt;/p&gt;
&lt;p&gt;Now, let’s explore what a workload is in the context of Kubernetes. A workload represents an application running on Kubernetes. An application may consist of a single component or multiple components working together. These components are packaged into containers operating within a group of &lt;a href="https://kubernetes.io/docs/concepts/workloads/pods/" target="_blank" rel="noopener noreferrer"&gt;Pods&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;There are two types of workloads, depending on the nature of the application: Stateless and Stateful.&lt;/p&gt;
&lt;p&gt;In a stateless application, the client session data is not stored on the server. This is because the application doesn’t need to retain past interactions to function. However, in a stateful application, storing client session data is essential as it is necessary for subsequent interactions within the application.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2023/11/steteless-and-stateful_hu_d4dca7f1ecb66dcd.png 480w, https://percona.community/blog/2023/11/steteless-and-stateful_hu_60e3c79bfb338538.png 768w, https://percona.community/blog/2023/11/steteless-and-stateful_hu_bf0a78cdbbceecff.png 1400w"
src="https://percona.community/blog/2023/11/steteless-and-stateful.png" alt="steteless-and-stateful" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Now, we are already familiar with Kubernetes, workloads, stateless and stateful applications, and we also understand that Pods are responsible for managing these types of workloads.&lt;/p&gt;
&lt;h2 id="built-in-workload-resources-in-kubernetes"&gt;Built-in Workload Resources in Kubernetes&lt;/h2&gt;
&lt;p&gt;In a Kubernetes cluster, we can have thousands of Pods, and we don’t need to directly manage them individually. Instead, we utilize &lt;a href="https://kubernetes.io/docs/concepts/workloads/" target="_blank" rel="noopener noreferrer"&gt;workload resources&lt;/a&gt; to manage a group of Pods and choose what workload resource depends on the type of workload we are dealing with, Stateless or Stateful.&lt;/p&gt;
&lt;p&gt;For example, if we have stateless applications, we can use the &lt;a href="https://kubernetes.io/docs/concepts/workloads/controllers/deployment/" target="_blank" rel="noopener noreferrer"&gt;Deployment&lt;/a&gt; and &lt;a href="https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/" target="_blank" rel="noopener noreferrer"&gt;ReplicaSet&lt;/a&gt; resources, which are well-suited for this type of workflow. On the other hand, the &lt;a href="https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/" target="_blank" rel="noopener noreferrer"&gt;StatefulSet&lt;/a&gt; resource allows us to run Pods that need to maintain state.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Data on Kubernetes&lt;/em&gt; refers to the management and storage of data within the Kubernetes ecosystem. Kubernetes provides a robust framework for handling data, making it a versatile platform for both &lt;em&gt;stateless and stateful&lt;/em&gt; applications while ensuring data durability, availability, and security.&lt;/p&gt;
&lt;h2 id="the-challenge"&gt;The challenge&lt;/h2&gt;
&lt;p&gt;Kubernetes was initially designed to run stateless applications. However, the number of stateful applications running on Kubernetes has increased significantly. There are many challenges when it comes to running applications with state in Kubernetes, such as data management strategies, volume persistence, and others. According to the &lt;a href="https://dok.community/wp-content/uploads/2021/10/DoK_Report_2021.pdf" target="_blank" rel="noopener noreferrer"&gt;2021 Data on Kubernetes report&lt;/a&gt; of more than 500 executives and technology leaders, 90% believe it is ready for stateful workloads, and a large majority (70%) are running them in production, with databases topping the list. This gives rise to initiatives aimed at standardizing the requirements for managing stateful applications on Kubernetes.&lt;/p&gt;
&lt;p&gt;This is how &lt;a href="https://community.cncf.io/data-on-kubernetes/" target="_blank" rel="noopener noreferrer"&gt;Data on the Kubernetes Community&lt;/a&gt; emerges. The Data on Kubernetes (DoKc) community was established in spring 2020. It is an openly governed group of curious and experienced practitioners, drawing inspiration from the Cloud Native Computing Foundation (CNCF) and the Apache Software Foundation. They aim to help create and improve techniques for using Kubernetes with data.&lt;/p&gt;
&lt;p&gt;There are several organizations that are part of the Data on Kubernetes community, and Percona is part of it as well. &lt;a href="https://www.percona.com/" target="_blank" rel="noopener noreferrer"&gt;Percona&lt;/a&gt; is adding efforts in DoKC Operator SIG(Special Interest Groups), where we discuss gaps in information around K8s operators for the industry-at-large &amp; co-creates projects to fill the gap. Watch the &lt;a href="https://www.youtube.com/watch?v=TmDdkBPW_hI" target="_blank" rel="noopener noreferrer"&gt;Kubernetes Database Operator Landscape&lt;/a&gt; panel discussion to learn more about the community efforts in Data on Kubernetes.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2023/11/dok.png" alt="dok" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Data on Kubernetes is a crucial concept in the Kubernetes ecosystem. Kubernetes was initially designed for the stateless application, now faces the challenge of managing stateful workloads, and is more notable in databases. The Data on Kubernetes (DoKc) community has emerged to address these challenges and standardize the management of stateful applications, drawing inspiration from industry standards like CNCF and Apache Software Foundation.&lt;/p&gt;
&lt;p&gt;If you want to be part of them, you are welcome to join &lt;a href="https://community.cncf.io/data-on-kubernetes/" target="_blank" rel="noopener noreferrer"&gt;DoKC&lt;/a&gt;. Also, check this outstanding &lt;a href="https://www.youtube.com/watch?v=TmDdkBPW_hI" target="_blank" rel="noopener noreferrer"&gt;Kubernetes Database Operators Landscape&lt;/a&gt;, where members of DoKC talk about operations for data workloads on Kubernetes.&lt;/p&gt;</content:encoded>
      <author>Edith Puclla</author>
      <category>Kubernetes</category>
      <category>DoK</category>
      <category>Databases</category>
      <media:thumbnail url="https://percona.community/blog/2023/11/steteless-and-stateful_hu_521986dedeb9a949.jpg"/>
      <media:content url="https://percona.community/blog/2023/11/steteless-and-stateful_hu_f4c812c7cccc0443.jpg" medium="image"/>
    </item>
    <item>
      <title>Exploring Kubernetes Operators</title>
      <link>https://percona.community/blog/2023/11/03/kubernetes-operators/</link>
      <guid>https://percona.community/blog/2023/11/03/kubernetes-operators/</guid>
      <pubDate>Fri, 03 Nov 2023 00:00:00 UTC</pubDate>
      <description>The concept of Kubernetes Operators was introduced around 2016 by the CoreOS Linuxdevelopment team. They were in search of a solution to improve automated container management within Kubernetes, primarily with the goal of incorporating operational expertise directly into the software.</description>
      <content:encoded>&lt;p&gt;The concept of &lt;strong&gt;Kubernetes Operators&lt;/strong&gt; was introduced around 2016 by the &lt;a href="https://en.wikipedia.org/wiki/Container_Linux" target="_blank" rel="noopener noreferrer"&gt;CoreOS Linux&lt;/a&gt;development team. They were in search of a solution to improve automated container management within Kubernetes, primarily with the goal of incorporating operational expertise directly into the software.&lt;/p&gt;
&lt;p&gt;According to the &lt;a href="https://www.cncf.io/blog/2022/06/15/kubernetes-operators-what-are-they-some-examples/#:~:text=K8s%20Operators%20are%20controllers%20for,Custom%20Resource%20Definitions%20%28CRD%29." target="_blank" rel="noopener noreferrer"&gt;Cloud Native Computing Foundation&lt;/a&gt;, &lt;strong&gt;“Operators are software extensions that use custom resources to manage applications and their components”.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Kubernetes is designed for automation, offering essential automation features. It can automatically deploy and manage workloads. The definition provided by CNCF regarding operators, as mentioned above, highlights the flexibility we have to customize the automation capabilities made possible by Kubernetes Operators using custom resources.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2023/11/k8s-01_hu_e56aaa8dbc6d4a1.png 480w, https://percona.community/blog/2023/11/k8s-01_hu_bb3ea29d96e519d2.png 768w, https://percona.community/blog/2023/11/k8s-01_hu_fa5fccab6c97cf60.png 1400w"
src="https://percona.community/blog/2023/11/k8s-01.png" alt="kubernetes-operators" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;In Kubernetes, certain applications require manual attention as Kubernetes can not autonomously manage them. This is especially the case with databases. This is where Operators come into play.
Databases are complex entities that also have complex database operations and features that Kubernetes itself may not inherently understand. While deploying a database in Kubernetes manually isn’t a problem, the true strength of operators shines during &lt;a href="https://thenewstack.io/cloud-native-day-2-operations-why-this-begins-on-day-0/" target="_blank" rel="noopener noreferrer"&gt;Day 2 operations&lt;/a&gt;, which include tasks such as backups, failover, and scaling. Operators automate these manual tasks for applications within Kubernetes.&lt;/p&gt;
&lt;p&gt;The main challenge that arises when implementing &lt;strong&gt;containerized databases&lt;/strong&gt; is the problem of &lt;strong&gt;data persistence&lt;/strong&gt;. This is the challenge for containers in general, and it is more critical in the context of databases despite ongoing advances in container maturity. Kubernetes operators are designed to address this gap. While it is possible to use Kubernetes resources like Persistent Volume Claims (PVCs) without operators, operators simplify the process by providing a higher level of abstraction and automation.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2023/11/k8s-02.png" alt="kubernetes-operators" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;It is possible to create new operators using the &lt;strong&gt;Kubernetes operator pattern&lt;/strong&gt; concept. This allows you to extend cluster behavior without modifying the Kubernetes code by linking controllers to one or more custom resources. These Operators use and extend the Kubernetes API, a key component within the Kubernetes architecture, with the essential concepts for users to interact with the Kubernetes cluster. They create &lt;a href="https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/#:~:text=A%20custom%20resource%20is%20an,resources%2C%20making%20Kubernetes%20more%20modular." target="_blank" rel="noopener noreferrer"&gt;custom resources&lt;/a&gt; to add new functionality according to the needs of an application to be flexible and scalable. This is how we automate workloads using Kubernetes Operators.&lt;/p&gt;
&lt;p&gt;One of the primary benefits of operators is the &lt;strong&gt;automation&lt;/strong&gt; of repetitive tasks that are often managed by human operators, eliminating errors in application lifecycle management.&lt;/p&gt;
&lt;h3 id="conclusion"&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;In this article, we explored an overview of what Kubernetes Operators are; we saw why they are necessary and the benefits of using them. I hope you have gained a general understanding of why Kubernetes Operators are valuable.&lt;/p&gt;
&lt;p&gt;If you want to know more about Kubernetes operators designed specifically for databases, you can visit the &lt;a href="https://www.percona.com/software/percona-kubernetes-operators" target="_blank" rel="noopener noreferrer"&gt;Percona website&lt;/a&gt;, where you will find Kubernetes operators created by Percona for &lt;strong&gt;MongoDB&lt;/strong&gt;, &lt;strong&gt;PostgreSQL&lt;/strong&gt;, and &lt;strong&gt;MySQL&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Are you considering creating your own operator? Start by using the &lt;strong&gt;Operator-SDK&lt;/strong&gt;. Additionally, you can watch &lt;a href="https://www.linkedin.com/in/sergeypronin/" target="_blank" rel="noopener noreferrer"&gt;Sergey Pronin’s&lt;/a&gt; (Group Product Manager At Percona) talk at the DoK Community about Migrating MongoDB to Kubernetes, where he discusses the reasons why Percona created an Operator for MongoDB.&lt;/p&gt;</content:encoded>
      <author>Edith Puclla</author>
      <category>CNCF</category>
      <category>Kubernetes</category>
      <category>Operators</category>
      <category>Databases</category>
      <media:thumbnail url="https://percona.community/blog/2023/11/k8s-01_hu_ed80426dd6e0a7aa.jpg"/>
      <media:content url="https://percona.community/blog/2023/11/k8s-01_hu_88a1c819ea89bc3f.jpg" medium="image"/>
    </item>
    <item>
      <title>Kubernetes Community Days UK: Keynote Cilium and eBPF</title>
      <link>https://percona.community/blog/2023/10/24/kcduk-cilium-ebpf/</link>
      <guid>https://percona.community/blog/2023/10/24/kcduk-cilium-ebpf/</guid>
      <pubDate>Tue, 24 Oct 2023 00:00:00 UTC</pubDate>
      <description>This week, at Kubernetes Community Days UK in London. Liz Rice, Chief Open Source Officer at Isovalent, delivered a keynote on Cilium, eBPF, and the new feature of Cilium: Mutual Authentication.</description>
      <content:encoded>&lt;p&gt;This week, at &lt;a href="https://community.cncf.io/events/details/cncf-kcd-uk-presents-kubernetes-community-days-uk-2023/" target="_blank" rel="noopener noreferrer"&gt;Kubernetes Community Days UK&lt;/a&gt; in London. &lt;strong&gt;Liz Rice&lt;/strong&gt;, Chief Open Source Officer at Isovalent, delivered a keynote on &lt;strong&gt;Cilium, eBPF&lt;/strong&gt;, and the new feature of &lt;strong&gt;Cilium: Mutual Authentication&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2023/10/kcduk-01_hu_bd6faf10c7fc4fca.jpg 480w, https://percona.community/blog/2023/10/kcduk-01_hu_aa53236b59c4188b.jpg 768w, https://percona.community/blog/2023/10/kcduk-01_hu_13ae809b73043ef5.jpg 1400w"
src="https://percona.community/blog/2023/10/kcduk-01.jpg" alt="lizrice-keynote-01" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Figure 1&lt;/strong&gt;. Liz Rice Keynote KCD UK, London. Tuesday 17, 2023&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://cilium.io/" target="_blank" rel="noopener noreferrer"&gt;Cilium&lt;/a&gt; is an &lt;strong&gt;eBPF-powered open source&lt;/strong&gt;, cloud native solution for delivering, securing, and observing network connectivity between workloads.&lt;/p&gt;
&lt;p&gt;eBPF is a technology that allows us to create modules to modify the behavior of the Linux kernel, but why would we want to change the Linux kernel?&lt;/p&gt;
&lt;p&gt;Some use cases for observability, security, and networking require tracking and monitoring our application, but we don’t want to constantly modify our application with these changes. It’s better to add a program that can observe the behavior of our application from the kernel.&lt;/p&gt;
&lt;p&gt;But changing the Linux kernel can be, well, hard.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2023/10/kcduk-02.png" alt="addfea-to-the-kernel" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Figure 2&lt;/strong&gt;. Adding features to the kernel (cartoon by Vadim Shchekoldin, Isovalent)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;However, eBPF enables you to modify the kernel’s behavior without directly altering the kernel itself. It might sound unconventional, but eBPF makes this possible through the creation of programs for the Linux kernel. The Linux kernel accepts eBPF programs that can be loaded and unloaded as needed.
&lt;figure&gt;&lt;img src="https://percona.community/blog/2023/10/kcduk-03.png" alt="addingfeatures-to-the-kernel-with-ebpf" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Figure 3. Adding kernel features with eBPF (cartoon by Vadim Shchekoldin, Isovalent)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;To ensure that these eBPF programs written by us are secure, there is a mechanism in place that allows these programs to be verified safe for execution. This can be seen in &lt;a href="https://ebpf.io/what-is-ebpf/#ebpf-safety" target="_blank" rel="noopener noreferrer"&gt;eBPF verification and security&lt;/a&gt;. You don’t have to restart the kernel to deploy or remove eBPF applications, which makes eBPF one of the technology tools of the moment.&lt;/p&gt;
&lt;p&gt;Liz also announced that Cilium recently graduated from CNCF. This means Cilium is considered stable and has been successfully used in production environments.
&lt;figure&gt;&lt;img src="https://percona.community/blog/2023/10/kcduk-04.png" alt="cncf-project-maturity-levels" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Figure 4&lt;/strong&gt;. &lt;a href="https://www.cncf.io/project-metrics/" target="_blank" rel="noopener noreferrer"&gt;CNCF Project Maturity Levels&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;After understanding what eBPF is, let’s move on to the actual topic of Liz’s keynote. She spoke about &lt;strong&gt;Mutual Authentication with Cilium&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Mutual Authentication with Cilium was the last significant feature missing from Cilium Service Mesh. It’s a somewhat more complex topic related to mTLS (Mutual transport layer security).&lt;/p&gt;
&lt;p&gt;mTLS is a mechanism that ensures the authenticity, integrity, and confidentiality of data exchanged between two entities in the network.&lt;/p&gt;
&lt;p&gt;In &lt;a href="https://isovalent.com/blog/post/cilium-release-114/" target="_blank" rel="noopener noreferrer"&gt;Cilium 1.14&lt;/a&gt;, one of the most significant releases, Cilium introduces support for a feature that many developers have requested: mutual authentication. This feature simplifies the process of achieving mutual authentication between two workloads. It now only requires adding two lines of code to the YAML in the Cilium Network Policy to authenticate communication between two workloads.&lt;/p&gt;
&lt;p&gt;Slightly more complex, isn’t it? Let’s explore Mutual Authentication with Cilium in a second blog post very soon. We’ll also examine how this is related to Kubernetes and why it matters when running databases on Kubernetes.&lt;/p&gt;
&lt;p&gt;Check what the other &lt;a href="https://www.cncf.io/projects/" target="_blank" rel="noopener noreferrer"&gt;Graduated and Incubating Projects are at CNCF&lt;/a&gt;, and don´t forget to subscribe to our &lt;a href="https://percona.community/blog/" target="_blank" rel="noopener noreferrer"&gt;Percona Community Blog&lt;/a&gt; to read more about Open Source, CNCF Projects, and Database.&lt;/p&gt;</content:encoded>
      <author>Edith Puclla</author>
      <category>Events</category>
      <category>Kubernetes</category>
      <media:thumbnail url="https://percona.community/blog/2023/10/kcduk-01_hu_1fbc1ab2e4b72516.jpg"/>
      <media:content url="https://percona.community/blog/2023/10/kcduk-01_hu_92c2c0c5c7a1073a.jpg" medium="image"/>
    </item>
    <item>
      <title>Percona Monitoring and Management 2.40 preview release</title>
      <link>https://percona.community/blog/2023/10/03/preview-release/</link>
      <guid>https://percona.community/blog/2023/10/03/preview-release/</guid>
      <pubDate>Tue, 03 Oct 2023 00:00:00 UTC</pubDate>
      <description>Percona Monitoring and Management 2.40 preview release Hello folks! Percona Monitoring and Management (PMM) 2.40 is now available as a preview release.</description>
      <content:encoded>&lt;h2 id="percona-monitoring-and-management-240-preview-release"&gt;Percona Monitoring and Management 2.40 preview release&lt;/h2&gt;
&lt;p&gt;Hello folks! Percona Monitoring and Management (PMM) 2.40 is now available as a preview release.&lt;/p&gt;
&lt;p&gt;We encourage you to try this PMM preview release in &lt;strong&gt;testing environments only&lt;/strong&gt;, as these packages and images are not fully production-ready. The final version is expected to be released through the standard channels in the coming week.&lt;/p&gt;
&lt;p&gt;To see the full list of changes, check out the &lt;a href="https://pmm-doc-pr-1139.onrender.com/release-notes/2.40.0.html" target="_blank" rel="noopener noreferrer"&gt;PMM 2.40 Release Notes&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="pmm-server-docker-installation"&gt;PMM server Docker installation&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://docs.percona.com/percona-monitoring-and-management/setting-up/server/docker.html" target="_blank" rel="noopener noreferrer"&gt;Run PMM Server with Docker instructions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;docker tag:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;perconalab/pmm-server:2.40.0-rc&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="pmm-client-package-installation"&gt;PMM client package installation&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://s3.us-east-2.amazonaws.com/pmm-build-cache/PR-BUILDS/pmm2-client/pmm2-client-latest-5830.tar.gz" target="_blank" rel="noopener noreferrer"&gt;Download&lt;/a&gt; the latest pmm2-client release candidate tarball for 2.40.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;To install pmm2-client package, enable testing repository via Percona-release:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;percona-release enable percona testing&lt;/code&gt;&lt;/p&gt;
&lt;ol start="3"&gt;
&lt;li&gt;Install pmm2-client package for your OS via Package Manager.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="ova"&gt;OVA&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://docs.percona.com/percona-moitoring-and-management/setting-up/server/virtual-appliance.html" target="_blank" rel="noopener noreferrer"&gt;Run PMM Server as a VM instructions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://percona-vm.s3.amazonaws.com/PMM2-Server-2.40.0.ova" target="_blank" rel="noopener noreferrer"&gt;PMM2-Server-2.40.0.ova file&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="ami"&gt;AMI&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://docs.percona.com/percona-monitoring-and-management/setting-up/server/aws.html" target="_blank" rel="noopener noreferrer"&gt;Run PMM Server hosted at AWS Marketplace instructions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ami-09895e9b605f14cbc&lt;/code&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Contact us on the [Percona Community Forums](&lt;a href="https://forums.percona.com/]" target="_blank" rel="noopener noreferrer"&gt;https://forums.percona.com/]&lt;/a&gt;.&lt;/p&gt;</content:encoded>
      <author>Taras Kozub</author>
      <category>PMM</category>
      <category>Releases</category>
      <media:thumbnail url="https://percona.community/superhero_hu_252fc2b480c0a197.jpg"/>
      <media:content url="https://percona.community/superhero_hu_17979f11d5d3562e.jpg" medium="image"/>
    </item>
    <item>
      <title>Dolphie, your real-time MySQL monitoring assistant</title>
      <link>https://percona.community/blog/2023/08/22/dolphie-your-real-time-mysql-monitoring-assistant/</link>
      <guid>https://percona.community/blog/2023/08/22/dolphie-your-real-time-mysql-monitoring-assistant/</guid>
      <pubDate>Tue, 22 Aug 2023 00:00:00 UTC</pubDate>
      <description>For as long as I can remember, Innotop has been the go-to terminal tool for real-time MySQL monitoring. It is an invaluable addition to any DBA’s toolkit, but unfortunately, it’s not really actively maintained these days, except for addressing critical issues, and it hasn’t kept pace with the evolving capabilities of modern terminals. With no viable alternatives except for InnotopGo, which is also no longer actively maintained and limited to MySQL 8 (while many still use 5.7), I decided to build my own in Python.</description>
      <content:encoded>&lt;p&gt;For as long as I can remember, &lt;a href="https://github.com/innotop/innotop" target="_blank" rel="noopener noreferrer"&gt;Innotop&lt;/a&gt; has been the go-to terminal tool for real-time MySQL monitoring. It is an invaluable addition to any DBA’s toolkit, but unfortunately, it’s not really actively maintained these days, except for addressing critical issues, and it hasn’t kept pace with the evolving capabilities of modern terminals. With no viable alternatives except for &lt;a href="https://github.com/lefred/innotopgo" target="_blank" rel="noopener noreferrer"&gt;InnotopGo&lt;/a&gt;, which is also no longer actively maintained and limited to MySQL 8 (while many still use 5.7), I decided to build my own in Python.&lt;/p&gt;
&lt;center&gt;I call it, Dolphie&lt;/center&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2023/08/dolphie-150.png" alt="image" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Initially, I relied on Python’s Rich package for the user interface. However, I recently stumbled upon &lt;a href="https://textual.textualize.io" target="_blank" rel="noopener noreferrer"&gt;Textual&lt;/a&gt; a few months ago, and it piqued my interest. It’s a framework that extends the capabilities of Rich, opening up a world of possibilities in the terminal. After experimenting with it for a few days, it inspired me to redevelop Dolphie with it, and I’ve been thoroughly pleased with the results. It has allowed me to showcase many of the features that will be displayed in this blog post!&lt;/p&gt;
&lt;h3 id="getting-started"&gt;Getting started&lt;/h3&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2023/08/dolphie_dashboard_processlist_hu_24be22e07edc4bf4.png 480w, https://percona.community/blog/2023/08/dolphie_dashboard_processlist_hu_df05cb1e26fb3c6b.png 768w, https://percona.community/blog/2023/08/dolphie_dashboard_processlist_hu_92b0f1475efd055e.png 1400w"
src="https://percona.community/blog/2023/08/dolphie_dashboard_processlist.png" alt="image" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;When you first start Dolphie, you’ll be greeted with a dashboard displaying various important MySQL metrics, along with a sparkline below it to measure the QPS (Queries per second) + process list. There are multiple ways to manipulate the process list, such as changing how it sorts, filtering by user/host/query text/database/time, killing threads, and much more.&lt;/p&gt;
&lt;p&gt;There are currently four panels that can be toggled interchangeably for display:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dashboard&lt;/li&gt;
&lt;li&gt;Process list&lt;/li&gt;
&lt;li&gt;Replication/Replicas&lt;/li&gt;
&lt;li&gt;Graph Metrics&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A big perk of transitioning to Textual is the integration of graphs. It’s as if I’ve incorporated a mini-PMM (Percona Monitoring and Management) right into Dolphie! The switches you see can be toggled on and off to display or hide their corresponding metrics on the graph.&lt;/p&gt;
&lt;h4 id="buffer-pool-requests-graph--replication-panel"&gt;Buffer Pool Requests Graph + Replication Panel&lt;/h4&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2023/08/dolphie_buffer_pool_hu_fdce19cbdc265c45.png 480w, https://percona.community/blog/2023/08/dolphie_buffer_pool_hu_988946439dee2f04.png 768w, https://percona.community/blog/2023/08/dolphie_buffer_pool_hu_62e296398fe406a0.png 1400w"
src="https://percona.community/blog/2023/08/dolphie_buffer_pool.png" alt="image" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h4 id="checkpoint-graph"&gt;Checkpoint Graph&lt;/h4&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2023/08/dolphie_checkpoint_hu_5033305ee10d6583.png 480w, https://percona.community/blog/2023/08/dolphie_checkpoint_hu_74a6e4c86ec95af9.png 768w, https://percona.community/blog/2023/08/dolphie_checkpoint_hu_5a698e4c73d34dcb.png 1400w"
src="https://percona.community/blog/2023/08/dolphie_checkpoint.png" alt="image" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h4 id="redo-logs-graph"&gt;Redo Logs Graph&lt;/h4&gt;
&lt;p&gt;How are your redo logs performing? Dolphie shows you how much data is being written per second, the active count of redo logs (MySQL 8 only), and how much data is being written to it per hour (inspired by &lt;a href="https://www.percona.com/blog/how-to-calculate-a-good-innodb-log-file-size" target="_blank" rel="noopener noreferrer"&gt;this&lt;/a&gt; blog post)
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2023/08/dolphie_redo_log_hu_9910b81fe35285ca.png 480w, https://percona.community/blog/2023/08/dolphie_redo_log_hu_6b9afd6973d0a0db.png 768w, https://percona.community/blog/2023/08/dolphie_redo_log_hu_72f024a19a7ff856.png 1400w"
src="https://percona.community/blog/2023/08/dolphie_redo_log.png" alt="image" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h4 id="dml-graph"&gt;DML Graph&lt;/h4&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2023/08/dolphie_dml_hu_75d0ff8eec2097c8.png 480w, https://percona.community/blog/2023/08/dolphie_dml_hu_994150f7053e54e3.png 768w, https://percona.community/blog/2023/08/dolphie_dml_hu_e93fcf1a3f10c47b.png 1400w"
src="https://percona.community/blog/2023/08/dolphie_dml.png" alt="image" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h4 id="thread-data"&gt;Thread data&lt;/h4&gt;
&lt;p&gt;Dolphie lets you display a thread’s information with an explanation of its query along + transaction history
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2023/08/dolphie_thread_details_hu_8f8c1fb75755d18c.png 480w, https://percona.community/blog/2023/08/dolphie_thread_details_hu_b496012bf78e57c4.png 768w, https://percona.community/blog/2023/08/dolphie_thread_details_hu_63f9f4bd3b0b4058.png 1400w"
src="https://percona.community/blog/2023/08/dolphie_thread_details.png" alt="image" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h4 id="kill-threads"&gt;Kill threads&lt;/h4&gt;
&lt;p&gt;Dolphie lets you terminate threads using a selected option. Notice how it autocompletes the input for you. This is a feature across the board. It will autocomplete any input that it can
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2023/08/dolphie_kill_threads_by_parameters_hu_c4f31ce433898534.png 480w, https://percona.community/blog/2023/08/dolphie_kill_threads_by_parameters_hu_964130d68a4a7dfb.png 768w, https://percona.community/blog/2023/08/dolphie_kill_threads_by_parameters_hu_96107756d31feeb6.png 1400w"
src="https://percona.community/blog/2023/08/dolphie_kill_threads_by_parameters.png" alt="image" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h4 id="quick-switch-host"&gt;Quick switch host&lt;/h4&gt;
&lt;p&gt;After using Dolphie extensively myself, I realized the need to simplify host switching. I found myself restarting it frequently just to change the host. This feature saves all the hosts you’ve connected to, allowing for autocomplete when you want to switch
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2023/08/dolphie_quick_host_switch_hu_5d3c6a08487285f0.png 480w, https://percona.community/blog/2023/08/dolphie_quick_host_switch_hu_169ea628728d9861.png 768w, https://percona.community/blog/2023/08/dolphie_quick_host_switch_hu_da537a303647e77c.png 1400w"
src="https://percona.community/blog/2023/08/dolphie_quick_host_switch.png" alt="image" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h4 id="error-log"&gt;Error log&lt;/h4&gt;
&lt;p&gt;In MySQL 8, I was delighted to see that the error log was in performance_schema. Of course, I had to support it! It has switches to toggle on/off event types and search functionality
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2023/08/dolphie_error_log_hu_29ea1ccb044dab49.png 480w, https://percona.community/blog/2023/08/dolphie_error_log_hu_5a3b5f1623d4935c.png 768w, https://percona.community/blog/2023/08/dolphie_error_log_hu_5cc6d6bdaa55ba72.png 1400w"
src="https://percona.community/blog/2023/08/dolphie_error_log.png" alt="image" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h4 id="errant-transactions"&gt;Errant transactions&lt;/h4&gt;
&lt;p&gt;The Replicas panel will let you know if your replicas have any errant transactions and what they are
&lt;figure&gt;&lt;img src="https://percona.community/blog/2023/08/dolphie_errant_transaction.png" alt="image" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;These are just some of the features that Dolphie has. There are many more that I haven’t covered, which you can discover for yourself and try out!&lt;/p&gt;
&lt;p&gt;If you’d like to try Dolphie, it’s just a pip away:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pip install dolphie&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;I’m open to feedback and suggestions so don’t be a stranger :) If you’d like to contribute to the project, I’d be delighted to have you!&lt;/p&gt;
&lt;p&gt;You can find Dolphie on its &lt;a href="https://github.com/charles-001/dolphie" target="_blank" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;</content:encoded>
      <author>Charles Thompson</author>
      <category>Dev</category>
      <category>MySQL</category>
      <category>Monitoring</category>
      <category>Python</category>
      <media:thumbnail url="https://percona.community/blog/2023/08/dolphie_header_hu_c50d81109e2ceaa2.jpeg"/>
      <media:content url="https://percona.community/blog/2023/08/dolphie_header_hu_1bafd2a4bddf608e.jpeg" medium="image"/>
    </item>
    <item>
      <title>Percona Monitoring and Management 2.38 preview release</title>
      <link>https://percona.community/blog/2023/06/30/preview-release/</link>
      <guid>https://percona.community/blog/2023/06/30/preview-release/</guid>
      <pubDate>Fri, 30 Jun 2023 00:00:00 UTC</pubDate>
      <description>Percona Monitoring and Management 2.38 preview release Hello folks! Percona Monitoring and Management (PMM) 2.38 is now available as a preview release.</description>
      <content:encoded>&lt;h2 id="percona-monitoring-and-management-238-preview-release"&gt;Percona Monitoring and Management 2.38 preview release&lt;/h2&gt;
&lt;p&gt;Hello folks! Percona Monitoring and Management (PMM) 2.38 is now available as a preview release.&lt;/p&gt;
&lt;p&gt;We encourage you to try this PMM preview release in &lt;strong&gt;testing environments only&lt;/strong&gt;, as these packages and images are not fully production-ready. The final version is expected to be released through the standard channels in the coming week.&lt;/p&gt;
&lt;p&gt;To see the full list of changes, check out the &lt;a href="https://pmm-doc-pr-1081.onrender.com/release-notes/2.38.0.html" target="_blank" rel="noopener noreferrer"&gt;PMM 2.38 Release Notes&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="pmm-server-docker-installation"&gt;PMM server Docker installation&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://docs.percona.com/percona-monitoring-and-management/setting-up/server/docker.html" target="_blank" rel="noopener noreferrer"&gt;Run PMM Server with Docker instructions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;docker tag:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;perconalab/pmm-server:2.38.0-rc&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; To use the DBaaS functionality during the PMM preview release, add the following environment variable when starting PMM server:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;PERCONA_TEST_DBAAS_PMM_CLIENT=perconalab/pmm-client:2.38.0-rc&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="pmm-client-package-installation"&gt;PMM client package installation&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://s3.us-east-2.amazonaws.com/pmm-build-cache/PR-BUILDS/el9/pmm2-client/pmm2-client-latest-5607.tar.gz" target="_blank" rel="noopener noreferrer"&gt;Download&lt;/a&gt; the latest pmm2-client release candidate tarball for 2.38.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;To install pmm2-client package, enable testing repository via Percona-release:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;percona-release enable percona testing&lt;/code&gt;&lt;/p&gt;
&lt;ol start="3"&gt;
&lt;li&gt;Install pmm2-client package for your OS via Package Manager.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="ova"&gt;OVA&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://docs.percona.com/percona-moitoring-and-management/setting-up/server/virtual-appliance.html" target="_blank" rel="noopener noreferrer"&gt;Run PMM Server as a VM instructions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://percona-vm.s3.amazonaws.com/PMM2-Server-2.38.0.ova" target="_blank" rel="noopener noreferrer"&gt;PMM2-Server-2.38.0.ova file&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="ami"&gt;AMI&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://docs.percona.com/percona-monitoring-and-management/setting-up/server/aws.html" target="_blank" rel="noopener noreferrer"&gt;Run PMM Server hosted at AWS Marketplace instructions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ami-09895e9b605f14cbc&lt;/code&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Contact us on the [Percona Community Forums](&lt;a href="https://forums.percona.com/]" target="_blank" rel="noopener noreferrer"&gt;https://forums.percona.com/]&lt;/a&gt;.&lt;/p&gt;</content:encoded>
      <author>Taras Kozub</author>
      <category>PMM</category>
      <category>Release</category>
      <media:thumbnail url="https://percona.community/superhero_hu_252fc2b480c0a197.jpg"/>
      <media:content url="https://percona.community/superhero_hu_17979f11d5d3562e.jpg" medium="image"/>
    </item>
    <item>
      <title>Data on Kubernetes Meetup May 23</title>
      <link>https://percona.community/blog/2023/06/01/percona-and-data-on-kubernetes-meetup/</link>
      <guid>https://percona.community/blog/2023/06/01/percona-and-data-on-kubernetes-meetup/</guid>
      <pubDate>Thu, 01 Jun 2023 00:00:00 UTC</pubDate>
      <description>Percona has started to participate in Data on Kubernetes (DoK) meetings about Kubernetes Operators. These meetings are an initiative of DoK meetups that spotlight DoK case studies. In this blog post series, I will summarize the topics covered in each meeting.</description>
      <content:encoded>&lt;p&gt;&lt;strong&gt;Percona&lt;/strong&gt; has started to participate in &lt;strong&gt;Data on Kubernetes&lt;/strong&gt; (DoK) meetings about &lt;strong&gt;Kubernetes Operators&lt;/strong&gt;.
These meetings are an initiative of DoK meetups that spotlight DoK case studies. In this blog post series, I will summarize the topics covered in each meeting.&lt;/p&gt;
&lt;p&gt;On May 23, very interesting topics were discussed on the agenda. Let’s begin to summarize it.&lt;/p&gt;
&lt;p&gt;We start with a new project proposal, which is called: &lt;a href="https://docs.google.com/document/d/1CJeFtNpDSyaPoPWvimwMFt5s1g2Zj2Ppg_DJX7nVurk/edit#" target="_blank" rel="noopener noreferrer"&gt;Distributed Systems Operator Interface (DSOI)&lt;/a&gt;. It is proposed by &lt;strong&gt;Adheip Singh&lt;/strong&gt; from DataInfra, &lt;strong&gt;Nitish Tiwari&lt;/strong&gt; from Parseable, and &lt;strong&gt;Itamar Marom&lt;/strong&gt; from AppsFlyer.&lt;/p&gt;
&lt;p&gt;This project is a set of best practices for building Kubernetes operators for distributed systems. The spec defines standard practices that can help define custom resources (CR). It consists of Kubernetes-native &lt;strong&gt;CRDs&lt;/strong&gt; and specs and is not bound to any specific application. There are already two operators built using this set of practices:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/parseablehq/operator" target="_blank" rel="noopener noreferrer"&gt;Parseable Kubernetes Operator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/datainfrahq/pinot-operator" target="_blank" rel="noopener noreferrer"&gt;Control Plane For Apache Pinot&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you want to contribute, send proposals, join &lt;a href="https://launchpass.com/datainfra-workspace" target="_blank" rel="noopener noreferrer"&gt;datainfra-workspace&lt;/a&gt; or raise bugs in the GitHub repository of &lt;a href="https://github.com/datainfrahq/dsoi-spec/issues" target="_blank" rel="noopener noreferrer"&gt;DSOI&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2023/06/dok-datainfra_hu_7b0c7765b89587f3.jpeg 480w, https://percona.community/blog/2023/06/dok-datainfra_hu_341b3d3b21b105f5.jpeg 768w, https://percona.community/blog/2023/06/dok-datainfra_hu_107d85156bd1ca95.jpeg 1400w"
src="https://percona.community/blog/2023/06/dok-datainfra.jpeg" alt="Panel Discussion" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;As the second item on the agenda, we have an update about the &lt;a href="https://docs.google.com/document/d/1tbm44jC1qf6kAf9qje5V-UhaXG-AlGud9nhMaoPN6mU/edit#heading=h.fjdgqyupbu03" target="_blank" rel="noopener noreferrer"&gt;DoK Operator SIG Project Proposal - Security &amp; Hardening Guide&lt;/a&gt;. This project is proposed by &lt;strong&gt;Robert Hodges&lt;/strong&gt;, Altinity Inc.&lt;/p&gt;
&lt;p&gt;This project is a guide to establishing a baseline for secure data management on Kubernetes by fortifying the database operators. The guide aims to identify the typical attack surfaces that exist for databases running on Kubernetes. &lt;strong&gt;It will establish a collection of best practices for enhancing their security through the utilization of operators&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Robert mentioned that he connected to TAG Security, which in turn led to a link to BadRobot, which is a scanner that checks operators for excessive privileges. Also, Robert presented to DoK Bay Area last week to introduce the problem of operator security.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2023/06/dok-security-hardering_hu_3f51e5babc38029f.jpeg 480w, https://percona.community/blog/2023/06/dok-security-hardering_hu_2a38fc6f49ac0f71.jpeg 768w, https://percona.community/blog/2023/06/dok-security-hardering_hu_95fe32da725a235a.jpeg 1400w"
src="https://percona.community/blog/2023/06/dok-security-hardering.jpeg" alt="Panel Discussion" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;For the Operator security &amp; hardening guide, we can raise issues on &lt;a href="https://github.com/dokc/sig-operator" target="_blank" rel="noopener noreferrer"&gt;sig-operator&lt;/a&gt;. They are currently seeking volunteers and contributors for their project; Find &lt;a href="https://github.com/dokc/sig-operator/tree/main/operator-security-hardening" target="_blank" rel="noopener noreferrer"&gt;operator-security-hardening&lt;/a&gt; project on GitHub, or feel free to write Robert Hodges &lt;strong&gt;&lt;a href="mailto:rhodges@altinity.com"&gt;rhodges@altinity.com&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Finally, we have an update of the Operator Feature Matrix (OFM)&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;Operator Feature Matrix (OFM)&lt;/strong&gt; is a project from the Data on Kubernetes Community to create a standardized and vendor-neutral feature matrix for various Kubernetes operators that manage stateful workloads. This project is proposed by &lt;strong&gt;Alvaro Hernandez&lt;/strong&gt;, and it is definitely a good project to contribute if you are looking to improve the end-user experience with the use of workloads in Kubernetes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CloudNativePG&lt;/strong&gt; project sent feedback to improve OFM. CloudNativePG is the Kubernetes operator that covers the full lifecycle of a highly available PostgreSQL database cluster. Planning to create a website for end-user adoption&lt;/p&gt;
&lt;p&gt;There are other (non-Postgres) technologies, like Apache Druid, jumping on OFM. This is a work in progress.&lt;/p&gt;
&lt;p&gt;The end of June is being considered for a 1.0 freeze, before which it is required to get as much feedback as possible.
If you are interested, feedback can be as simple as opening an issue to discuss something; or sending a PR requesting improvements (or both). Feel free to do it on &lt;a href="https://github.com/dokc/operator-feature-matrix" target="_blank" rel="noopener noreferrer"&gt;OFM GitHub Repo&lt;/a&gt;.&lt;/p&gt;</content:encoded>
      <author>Edith Puclla</author>
      <category>DoK</category>
      <category>Opensource</category>
      <category>CNCF</category>
      <category>Kubernetes</category>
      <category>Operators</category>
      <media:thumbnail url="https://percona.community/blog/2023/06/dok-intro_hu_551fc8233fc2d418.jpg"/>
      <media:content url="https://percona.community/blog/2023/06/dok-intro_hu_9e64bcec089fa010.jpg" medium="image"/>
    </item>
    <item>
      <title>​What experts said at Kubecon about Data on Kubernetes</title>
      <link>https://percona.community/blog/2023/05/31/what-experts-said-at-kubecon-about-data-on-kubernetes/</link>
      <guid>https://percona.community/blog/2023/05/31/what-experts-said-at-kubecon-about-data-on-kubernetes/</guid>
      <pubDate>Wed, 31 May 2023 00:00:00 UTC</pubDate>
      <description>Melissa Logan, managing director of Data on Kubernetes (DoK), led one of the best panels I’ve been to at a conference at Kubecon EU in Amsterdam about challenges with and the state of the art of running databases on Kubernetes.</description>
      <content:encoded>&lt;p&gt;&lt;strong&gt;Melissa Logan&lt;/strong&gt;, managing director of &lt;strong&gt;Data on Kubernetes&lt;/strong&gt; (DoK), led one of the &lt;a href="https://www.youtube.com/watch?v=TmDdkBPW_hI&amp;t=313s" target="_blank" rel="noopener noreferrer"&gt;best panels I’ve been to at a conference at Kubecon EU&lt;/a&gt; in Amsterdam about challenges with and the state of the art of running databases on Kubernetes.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2023/05/01-pd-intro.jpeg" alt="Panel Discussion" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;This panel united the &lt;strong&gt;Data on Kubernetes Community Operator SIG&lt;/strong&gt; and &lt;strong&gt;Kubernetes Storage SIG&lt;/strong&gt; to discuss key features of Kubernetes database operators. &lt;strong&gt;Xing Yang&lt;/strong&gt; from VMware, &lt;strong&gt;Sergey Pronin&lt;/strong&gt; from Percona, and &lt;strong&gt;Álvaro Hernández&lt;/strong&gt; from OnGres came together to discuss what works, what doesn’t, and where the industry is going. They also presented a feature matrix to help end users compare many database Operators.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2023/05/02-pd-panel-discution.jpeg" alt="Panel Discussion" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;If you are new to the topic of Kubernetes Operators, I wrote a blog post about &lt;a href="https://percona.community/blog/2022/10/13/learning-kubernetes-operators-with-percona-operator-for-mongodb/" target="_blank" rel="noopener noreferrer"&gt;Kubernetes Operators in a nutshell&lt;/a&gt;, you can read the first part of this article.&lt;/p&gt;
&lt;p&gt;Let’s start by summarizing the challenges the panelists mentioned when running &lt;strong&gt;stateful&lt;/strong&gt; applications on &lt;strong&gt;Kubernetes&lt;/strong&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Some Operators have certain limitations, and there are security concerns. Database users always think about data encryption: is the data safe? What happens if the node goes down? What happens if we lose the storage?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The Operator model is very extensible and flexible, which is great, but on the other hand, there are so many Operators, and it becomes a challenge to choose the right one for our use cases.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;People who are developing Operators also find challenges because every database has its native way of doing backups, but if you want to support more than one type of database, then it’s more challenging to find a generic way.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="does-the-framework-capture-what-is-needed-for-data-workloads-well"&gt;Does the framework capture what is needed for data workloads well?&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;There is a capability model for Operators that classify them into five levels. There is room for improvement in this model. It can be improved to build test compatibility and more objective measures of these capability levels if you look at level five, the top one for data workloads.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2023/05/03-pd-capability-models.jpeg" alt="Panel Discussion" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Security is the number one criterion that people use to evaluate Operators. How are they addressing security in Kubernetes Operators?&lt;/li&gt;
&lt;li&gt;Users want to ensure that the Operator does not get a lot of privileges or does not interfere with other tenants in the Kubernetes cluster.&lt;/li&gt;
&lt;li&gt;Now users are looking for more sophisticated ways with their existing security key-value storage. They can be sure they are safe.&lt;/li&gt;
&lt;li&gt;The framework should provide ransomware protection, so when you back up your databases, you also want to have one immutable copy to provide your protection and recover from that.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="now-lets-talk-about-solutions"&gt;Now Let’s talk about solutions&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;DoK&lt;/strong&gt; started an &lt;strong&gt;Operator Special Interest Group&lt;/strong&gt; (SIG), and community members have been meeting to discuss how as a group and as an industry, to collaborate to come up with solutions for some of the challenges end users face. The Operator SIG works with the Storage Technical Advisory Group (TAG), Storage SIG, and Security SIG.&lt;/p&gt;
&lt;p&gt;According to data on Kubernetes’s (DoK) &lt;a href="https://dok.community/wp-content/uploads/2022/10/DoK_Report_2022.pdf" target="_blank" rel="noopener noreferrer"&gt;first report&lt;/a&gt;, 70% of responses are running workloads in production. More data workloads are running on Kubernetes, so it is essential to know what works well. Sharing knowledge and leveraging that expertise is vital at this stage.&lt;/p&gt;
&lt;p&gt;There are things that SIG Operators detail in a &lt;a href="https://docs.google.com/document/d/1Uyk5qQ4KhpI-YnLdG72V66dO9Hxv_kqTK_CrMHS9EFc/edit#heading=h.nxcx7r52ocev" target="_blank" rel="noopener noreferrer"&gt;document&lt;/a&gt;, like common patterns and features used when running databases on Kubernetes, best practices, the criteria for running a good operator, why observability is so important in the cloud-native environment and security.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;Operator Feature Matrix&lt;/strong&gt; is a big initiative to help end users find operators based on different criteria to choose what they need. It is a project to compare different Operators. They are starting with database Operators, and one project is already defined: &lt;a href="https://github.com/dokc/operator-feature-matrix/tree/main/postgres" target="_blank" rel="noopener noreferrer"&gt;Postgres Operator Feature Matrix&lt;/a&gt;. Feel free to contribute to &lt;a href="https://github.com/dokc/operator-feature-matrix" target="_blank" rel="noopener noreferrer"&gt;OFM&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;New to Kubernetes Operators and databases? Check out &lt;a href="https://www.percona.com/software/percona-kubernetes-operators" target="_blank" rel="noopener noreferrer"&gt;Percona’s Operators&lt;/a&gt; for MySQL, PostgreSQL, and MongoDB.&lt;/p&gt;</content:encoded>
      <author>Edith Puclla</author>
      <category>Kubeconeu</category>
      <category>Opensource</category>
      <category>CNCF</category>
      <category>Kubernetes</category>
      <category>DoK</category>
      <category>Operators</category>
      <media:thumbnail url="https://percona.community/blog/2023/05/01-pd-intro_hu_19ef74926ec419b2.jpeg"/>
      <media:content url="https://percona.community/blog/2023/05/01-pd-intro_hu_c928a8c7630a9410.jpeg" medium="image"/>
    </item>
    <item>
      <title>Easy Way to Start Contributing to Open Source With PMM Documentation</title>
      <link>https://percona.community/blog/2023/05/18/easy-way-to-start-contributing-to-open-source-with-pmm-documentation/</link>
      <guid>https://percona.community/blog/2023/05/18/easy-way-to-start-contributing-to-open-source-with-pmm-documentation/</guid>
      <pubDate>Thu, 18 May 2023 00:00:00 UTC</pubDate>
      <description>If you are a user of Percona Monitoring and Management and noticed any typo or inaccurate information in its documentation, you can easily correct it yourself in the repository following detailed instructions in README.md. But if you are not experienced in open source contributions, you may still feel uneasy about following those steps. This post is for you! We will walk through the main steps with pictures and explanations.</description>
      <content:encoded>&lt;p&gt;If you are a user of Percona Monitoring and Management and noticed any typo or inaccurate information in its &lt;a href="https://docs.percona.com/percona-monitoring-and-management/index.html" target="_blank" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;, you can easily correct it yourself in the &lt;a href="https://github.com/percona/pmm-doc" target="_blank" rel="noopener noreferrer"&gt;repository&lt;/a&gt; following detailed instructions in &lt;a href="https://github.com/percona/pmm-doc#readme" target="_blank" rel="noopener noreferrer"&gt;README.md&lt;/a&gt;. But if you are not experienced in open source contributions, you may still feel uneasy about following those steps. This post is for you! We will walk through the main steps with pictures and explanations.&lt;/p&gt;
&lt;h2 id="create-a-fork"&gt;Create a Fork&lt;/h2&gt;
&lt;p&gt;First, you need to create a fork from the main repository to your account. In the top-right corner of the page, click &lt;strong&gt;Fork - Create a new fork&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2023/05/contribution2_hu_94d1252e7873a71a.jpg 480w, https://percona.community/blog/2023/05/contribution2_hu_77c7ef72837f51a7.jpg 768w, https://percona.community/blog/2023/05/contribution2_hu_3031673fbd200a2b.jpg 1400w"
src="https://percona.community/blog/2023/05/contribution2.jpg" alt="Contribution" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h2 id="build-documentation-with-docker"&gt;Build Documentation With Docker&lt;/h2&gt;
&lt;p&gt;The easiest way is to build documentation with Docker. If you don’t have it installed, download it from the Docker official website and follow the instructions. The process of installation is quick, and it is no more difficult than the installation of any other app.&lt;/p&gt;
&lt;p&gt;Open your fork on GitHub and clone that repository to your local environment.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;git clone git@github.com:{user-name}/pmm-doc.git&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2023/05/contribution1_hu_c45b801f2d40d62c.jpg 480w, https://percona.community/blog/2023/05/contribution1_hu_f71352ebd639c2cb.jpg 768w, https://percona.community/blog/2023/05/contribution1_hu_f589238117718bb0.jpg 1400w"
src="https://percona.community/blog/2023/05/contribution1.jpg" alt="Contribution" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Change directory to &lt;strong&gt;pmm-doc&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;cd pmm-doc&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;To check how our edits will look like, we need to build documentation for live previewing. Run:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;docker run --rm -v $(pwd):/docs -p 8000:8000 perconalab/pmm-doc-md mkdocs serve --dev-addr=0.0.0.0:8000&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Wait until you see &lt;code&gt;INFO - Start detecting changes&lt;/code&gt;. When the documentation is ready to work with, it will be available at &lt;a href="http://0.0.0.0:8000/" target="_blank" rel="noopener noreferrer"&gt;http://0.0.0.0:8000&lt;/a&gt; in your browser, and it will reflect all changes that you make locally.&lt;/p&gt;
&lt;h2 id="make-changes"&gt;Make Changes&lt;/h2&gt;
&lt;p&gt;In a new Terminal tab, create a new branch and make your changes. Save them, create a commit, and push it to your fork.&lt;/p&gt;
&lt;p&gt;Create a pull request to the main repository. You will also need to sign the CLA, so we could merge your changes.&lt;/p&gt;
&lt;p&gt;You did it! Congratulations! Now wait for the feedback from the Percona team. If there is no problem with your PR, it will be merged into the main repository.&lt;/p&gt;
&lt;h2 id="next-steps"&gt;Next Steps&lt;/h2&gt;
&lt;p&gt;To make further changes, you need to keep your repository up-to-date with the upstream one. There are several ways to do it. You can find the information &lt;a href="https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork" target="_blank" rel="noopener noreferrer"&gt;here&lt;/a&gt;. The simplest way is to do it using the GitHub interface. Just click on &lt;strong&gt;Sync fork&lt;/strong&gt; and then &lt;strong&gt;Update branch&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2023/05/contribution3_hu_56b6b21ef294a916.jpg 480w, https://percona.community/blog/2023/05/contribution3_hu_190d31d23ea9722e.jpg 768w, https://percona.community/blog/2023/05/contribution3_hu_e84d49da02568d17.jpg 1400w"
src="https://percona.community/blog/2023/05/contribution3.jpg" alt="Contribution" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;After that, you will be able to update your local repository with &lt;code&gt;git pull&lt;/code&gt; command.&lt;/p&gt;
&lt;p&gt;If you face any problems with contributions to Percona repositories, don’t hesitate to contact us at &lt;a href="mailto:community-team@percona.com"&gt;community-team@percona.com&lt;/a&gt; or ask your question on the &lt;a href="https://forums.percona.com/" target="_blank" rel="noopener noreferrer"&gt;Percona Forum&lt;/a&gt;.&lt;/p&gt;</content:encoded>
      <category>Opensource</category>
      <category>Documentation</category>
      <media:thumbnail url="https://percona.community/blog/2023/05/PMM-Doc-Contribute_hu_405740408eff0264.jpg"/>
      <media:content url="https://percona.community/blog/2023/05/PMM-Doc-Contribute_hu_7c2bbccc235458aa.jpg" medium="image"/>
    </item>
    <item>
      <title>​My Experience at Kubecon Europe in Amsterdam</title>
      <link>https://percona.community/blog/2023/05/11/experience-at-kubecon-europe-in-amsterdam/</link>
      <guid>https://percona.community/blog/2023/05/11/experience-at-kubecon-europe-in-amsterdam/</guid>
      <pubDate>Thu, 11 May 2023 00:00:00 UTC</pubDate>
      <description>Kubecon is the most significant event focused on the Kubernetes ecosystem. It takes place once a year in North America, Europe, and Asia. It is a perfect opportunity to learn from experts, meet friends, grow your network, and attend talks at a varied technical level and meetings focused on CNCF communities. This time I attended Kubecon in Amsterdam. The theme for this version of Kubecon was: community-in-bloom because we are still healing from COVID, and people are getting back to feeling comfortable participating in events.</description>
      <content:encoded>&lt;p&gt;&lt;strong&gt;Kubecon&lt;/strong&gt; is the most significant event focused on the &lt;strong&gt;Kubernetes&lt;/strong&gt; ecosystem. It takes place once a year in North America, Europe, and Asia. It is a perfect opportunity to learn from experts, meet friends, grow your network, and attend talks at a varied technical level and meetings focused on CNCF communities.
This time I attended Kubecon in Amsterdam. The theme for this version of Kubecon was: &lt;strong&gt;community-in-bloom&lt;/strong&gt; because we are still healing from COVID, and people are getting back to feeling comfortable participating in events.&lt;/p&gt;
&lt;p&gt;It is not my first time attending &lt;strong&gt;Kubecon&lt;/strong&gt;; this is my fourth time! What was different this time was that &lt;a href="https://www.percona.com/" target="_blank" rel="noopener noreferrer"&gt;Percona&lt;/a&gt;, the company I work for, sponsored Kubecon. This means we also had a booth at the event to share what we do at Percona.&lt;/p&gt;
&lt;p&gt;Yessss!! Percona had a booth in Kubecon, Amsterdam.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2023/05/01-percona-kubecon_hu_c1ca5fc462feb3ca.jpg 480w, https://percona.community/blog/2023/05/01-percona-kubecon_hu_84ba9093843a0bf7.jpg 768w, https://percona.community/blog/2023/05/01-percona-kubecon_hu_3fd2fbf0a8ed07bb.jpg 1400w"
src="https://percona.community/blog/2023/05/01-percona-kubecon.jpg" alt="Percona At Kubecon" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Percona is a 100% &lt;strong&gt;remote&lt;/strong&gt; company, and &lt;strong&gt;Kubecon&lt;/strong&gt; was the opportunity to meet part of the team I work with daily.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2023/05/02-percona-team_hu_6a1b9d4a83eb6b5f.JPG 480w, https://percona.community/blog/2023/05/02-percona-team_hu_9001b6a047c40d27.JPG 768w, https://percona.community/blog/2023/05/02-percona-team_hu_145c32af2f2c18a4.JPG 1400w"
src="https://percona.community/blog/2023/05/02-percona-team.JPG" alt="Percona Team" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;We started by meeting with friends in one of the most popular places in &lt;strong&gt;Amsterdam&lt;/strong&gt;. I met people from different tech communities and &lt;strong&gt;CNCF ambassadors&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2023/05/03-kubecon-happyhour_hu_afb248e4c85d7a87.jpeg 480w, https://percona.community/blog/2023/05/03-kubecon-happyhour_hu_cce5ceb33f1eab7e.jpeg 768w, https://percona.community/blog/2023/05/03-kubecon-happyhour_hu_640e67a17e3019b3.jpeg 1400w"
src="https://percona.community/blog/2023/05/03-kubecon-happyhour.jpeg" alt="Kubecon Happy Hour" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;If you are in Amsterdam and don’t ride a bicycle, it is an incomplete experience&lt;/em&gt;. We rode a bike to the convention center and collected the event badge.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2023/05/04-bicicle_hu_cf11f52540367ec6.jpg 480w, https://percona.community/blog/2023/05/04-bicicle_hu_86d206f37bc97a7d.jpg 768w, https://percona.community/blog/2023/05/04-bicicle_hu_951c1fa69f4379d8.jpg 1400w"
src="https://percona.community/blog/2023/05/04-bicicle.jpg" alt="Amsterdam Bicycle" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;After that, there were three intense days, many activities, meetings, and sessions.&lt;/p&gt;
&lt;h2 id="community"&gt;Community&lt;/h2&gt;
&lt;p&gt;I met with several members of the &lt;strong&gt;Docker&lt;/strong&gt; and &lt;strong&gt;CNCF&lt;/strong&gt; communities. This is the meeting of the Docker captains and various members of the Docker team. Such an amazing experience to know them in person.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2023/05/05-docker-community.jpeg" alt="Docker Captains" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;And this is the group of photos that all the CNCF ambassadors had at Kubecon. There are 155 CNCF ambassadors around the world and contributors and advocates of the CNCF ecosystem.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2023/05/06-cncf-ambassadors_hu_7700f94bcf2d2c3.JPG 480w, https://percona.community/blog/2023/05/06-cncf-ambassadors_hu_b09ae86575012c0d.JPG 768w, https://percona.community/blog/2023/05/06-cncf-ambassadors_hu_1c7a7e407b0aeb33.JPG 1400w"
src="https://percona.community/blog/2023/05/06-cncf-ambassadors.JPG" alt="CNCF ambassadors breakfast" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h2 id="lightning-talks"&gt;Lightning Talks&lt;/h2&gt;
&lt;p&gt;I attended a large part of the lightning sessions, which were very inspiring. Each speaker has less than 5 minutes to explain a specific topic.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Kevin Patrick&lt;/strong&gt; talked about the &lt;a href="https://www.youtube.com/watch?v=eAoC1ordaXQ" target="_blank" rel="noopener noreferrer"&gt;Armada as a Sandbox project in the CNCF&lt;/a&gt;, in which the principal goal is enabling batch processing across multiple Kubernetes clusters. Kevin made an introduction to Armada and showed the integration with &lt;a href="https://airflow.apache.org/" target="_blank" rel="noopener noreferrer"&gt;Apache Airflow&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The next talk was about &lt;a href="https://www.youtube.com/watch?v=BDA7atvmnV4" target="_blank" rel="noopener noreferrer"&gt;The CNCF Board Game Rules&lt;/a&gt;, where &lt;strong&gt;Peter O’Neill&lt;/strong&gt; made an abstract about the world of the CNCF and imagined it as a role-playing game (RPG) board game. It was pretty nice for Peter to show us the adventure of CNCF with games.&lt;/p&gt;
&lt;p&gt;This was one of my favorite lightning talks: [A Beginners Guide to Conference Speaking] (&lt;a href="https://www.youtube.com/watch?v=jCz9QPrJ6Eo%29with" target="_blank" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=jCz9QPrJ6Eo)with&lt;/a&gt; &lt;strong&gt;Paula Kennedy&lt;/strong&gt;. She showed a friendly way to prepare proposals for CFPs and advice that will help us through the process.&lt;/p&gt;
&lt;p&gt;Another good lightning session was about the &lt;a href="https://www.youtube.com/watch?v=Wn0S6CTXGS4" target="_blank" rel="noopener noreferrer"&gt;Power-Aware Scheduling in Kubernetes&lt;/a&gt; with &lt;strong&gt;Yuan Chen&lt;/strong&gt; from Apple. In this talk, Yan gave an overview of a new scheduler feature to support power-aware scheduling in Kubernetes and how it can help safely increase server hardware and data center infrastructure size and improve resource utilization and workload reliability for Kubernetes clusters.&lt;/p&gt;
&lt;p&gt;Another of my favorites was &lt;a href="https://www.youtube.com/watch?v=Kp6GQjZixPE" target="_blank" rel="noopener noreferrer"&gt;Talking to Kubernetes with Rust&lt;/a&gt; with &lt;strong&gt;James Laverack&lt;/strong&gt;, where he showed how to interact with Kubernetes in Rust.&lt;/p&gt;
&lt;h2 id="kubernetes-operators-panel-discussion"&gt;Kubernetes Operators Panel Discussion&lt;/h2&gt;
&lt;p&gt;I also attended a &lt;strong&gt;Panel Discussion about Kubernetes Operators&lt;/strong&gt;.
In this panel discussion, &lt;strong&gt;Xing Yang&lt;/strong&gt;, &lt;strong&gt;Melissa Logan&lt;/strong&gt;, &lt;strong&gt;Sergey Pronin&lt;/strong&gt;, and &lt;strong&gt;Alvaro Hernandez&lt;/strong&gt; talked about the challenges that final users have when running data workloads in Kubernetes Operators. They also shared about the need to fulfill the process of data workloads.
Check out this fantastic &lt;a href="https://www.youtube.com/watch?v=TmDdkBPW_hI&amp;list=PLj6h78yzYM2PyrvCoOii4rAopBswfz1p7&amp;index=184" target="_blank" rel="noopener noreferrer"&gt;talk&lt;/a&gt; and learn more about &lt;strong&gt;Kubernetes Operators&lt;/strong&gt;.
A very curious and interesting fact is that most of the assistants use data workload with Kubernetes Operators&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2023/05/07-kuberentes-operators_hu_71012bd382d2162e.JPG 480w, https://percona.community/blog/2023/05/07-kuberentes-operators_hu_416aefb6a1340926.JPG 768w, https://percona.community/blog/2023/05/07-kuberentes-operators_hu_cae55e1fb1827ff2.JPG 1400w"
src="https://percona.community/blog/2023/05/07-kuberentes-operators.JPG" alt="Kubernetes Operator Panel Discussion" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h2 id="ebpf"&gt;eBPF&lt;/h2&gt;
&lt;p&gt;The last talk I attended was an &lt;strong&gt;eBPF&lt;/strong&gt; talk with &lt;strong&gt;Liz Rice&lt;/strong&gt; (Chief Open Source Officer, Savant)
In this talk, Liz shows a demo about how Cilium and its ClusterMesh feature can take care of many aspects of connectivity across multiple clusters in a cloud-agnostic way. Check this &lt;a href="https://www.youtube.com/watch?v=fJiuqRY5Oi4&amp;t=22s" target="_blank" rel="noopener noreferrer"&gt;talk in CNCF YouTube Channel&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2023/05/08-ebpf_hu_f32e6846c31f46c8.jpg 480w, https://percona.community/blog/2023/05/08-ebpf_hu_7ba6da22255833a.jpg 768w, https://percona.community/blog/2023/05/08-ebpf_hu_fa07e96002c796a4.jpg 1400w"
src="https://percona.community/blog/2023/05/08-ebpf.jpg" alt="Kubecon eBPF" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h2 id="clossign-kubecon-amsterdam"&gt;Clossign Kubecon Amsterdam&lt;/h2&gt;
&lt;p&gt;Finally, in Percona, we closed the event with a raffle to take home an Atari’; the expectations were relatively high and very fun, and many Percona lovers came to participate in the raffle.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2023/05/09-raffle_hu_6ebda76d1a389918.jpg 480w, https://percona.community/blog/2023/05/09-raffle_hu_e02825ea1325de47.jpg 768w, https://percona.community/blog/2023/05/09-raffle_hu_ac3f6b8018f60f59.jpg 1400w"
src="https://percona.community/blog/2023/05/09-raffle.jpg" alt="Percona Raffle" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;You can check in which &lt;a href="https://www.percona.com/events" target="_blank" rel="noopener noreferrer"&gt;events&lt;/a&gt; Percona is going to be in the next months&lt;/p&gt;</content:encoded>
      <author>Edith Puclla</author>
      <category>Events</category>
      <category>Opensource</category>
      <category>CNCF</category>
      <category>Kubernetes</category>
      <media:thumbnail url="https://percona.community/blog/2023/05/00-kubeconeu-intro_hu_70f7290cee15e82a.jpg"/>
      <media:content url="https://percona.community/blog/2023/05/00-kubeconeu-intro_hu_1dc5373850d16e87.jpg" medium="image"/>
    </item>
    <item>
      <title>Percona Monitoring and Management 2.37 preview release</title>
      <link>https://percona.community/blog/2023/04/20/preview-release/</link>
      <guid>https://percona.community/blog/2023/04/20/preview-release/</guid>
      <pubDate>Thu, 20 Apr 2023 00:00:00 UTC</pubDate>
      <description>Percona Monitoring and Management 2.37 preview release Hello folks! Percona Monitoring and Management (PMM) 2.37 is now available as a preview release.</description>
      <content:encoded>&lt;h2 id="percona-monitoring-and-management-237-preview-release"&gt;Percona Monitoring and Management 2.37 preview release&lt;/h2&gt;
&lt;p&gt;Hello folks! Percona Monitoring and Management (PMM) 2.37 is now available as a preview release.&lt;/p&gt;
&lt;p&gt;We encourage you to try this PMM preview release in &lt;strong&gt;testing environments only&lt;/strong&gt;, as these packages and images are not fully production-ready. The final version is expected to be released through the standard channels in the coming week.&lt;/p&gt;
&lt;p&gt;You can find the Release Notes &lt;a href="https://pmm-2-37-0-pr-1043.onrender.com/release-notes/2.37.0.html" target="_blank" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="percona-monitoring-and-management-server-docker-installation"&gt;Percona Monitoring and Management server docker installation&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://docs.percona.com/percona-monitoring-and-management/setting-up/server/docker.html" target="_blank" rel="noopener noreferrer"&gt;Instructions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;docker tag:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;perconalab/pmm-server:2.37.0-rc&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; In order to use the DBaaS functionality during the Percona Monitoring and Management preview release, you should add the following environment variable when starting PMM server:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;PERCONA_TEST_DBAAS_PMM_CLIENT=perconalab/pmm-client:2.37.0-rc&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="percona-monitoring-and-management-client-package-installation"&gt;Percona Monitoring and Management client package installation&lt;/h3&gt;
&lt;p&gt;Download the latest pmm2-client release candidate tarball for 2.37 by this &lt;a href="https://s3.us-east-2.amazonaws.com/pmm-build-cache/PR-BUILDS/pmm2-client/pmm2-client-latest-5256.tar.gz" target="_blank" rel="noopener noreferrer"&gt;link&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you want to install pmm2-client package, please enable testing repository via Percona-release:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;percona-release enable percona testing&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;install pmm2-client package for your OS via package manager.&lt;/p&gt;
&lt;h3 id="ova"&gt;OVA&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://docs.percona.com/percona-monitoring-and-management/setting-up/server/virtual-appliance.html" target="_blank" rel="noopener noreferrer"&gt;Instructions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://percona-vm.s3.amazonaws.com/PMM2-Server-2.37.0.ova" target="_blank" rel="noopener noreferrer"&gt;PMM2-Server-2.37.0.ova&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="ami"&gt;AMI&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://docs.percona.com/percona-monitoring-and-management/setting-up/server/aws.html" target="_blank" rel="noopener noreferrer"&gt;Instructions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ami-013c92f3d0c727b8f&lt;/code&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Contact us in &lt;a href="https://forums.percona.com/" target="_blank" rel="noopener noreferrer"&gt;https://forums.percona.com/&lt;/a&gt;.&lt;/p&gt;</content:encoded>
      <author>Taras Kozub</author>
      <category>PMM</category>
      <category>Release</category>
      <media:thumbnail url="https://percona.community/superhero_hu_252fc2b480c0a197.jpg"/>
      <media:content url="https://percona.community/superhero_hu_17979f11d5d3562e.jpg" medium="image"/>
    </item>
    <item>
      <title>​​Using the JSON data type with MySQL 8 - Part II</title>
      <link>https://percona.community/blog/2023/04/11/using-the-json-data-type-with-mysql-8-ii/</link>
      <guid>https://percona.community/blog/2023/04/11/using-the-json-data-type-with-mysql-8-ii/</guid>
      <pubDate>Tue, 11 Apr 2023 00:00:00 UTC</pubDate>
      <description>If you read - Using the JSON data type with MySQL 8 - Part I, you will see that inserting data into MySQL of JSON type is a very common and effective practice. Now we’ll see how to do it with a Python project, using SQLAlchemy and Docker Compose, which further automates this example. You can run this example using a single command: docker-compose up</description>
      <content:encoded>&lt;p&gt;If you read - &lt;a href="https://percona.community/blog/2023/03/13/using-the-json-data-type-with-mysql-8/" target="_blank" rel="noopener noreferrer"&gt;Using the JSON data type with MySQL 8 - Part I&lt;/a&gt;, you will see that inserting data into &lt;strong&gt;MySQL&lt;/strong&gt; of &lt;strong&gt;JSON&lt;/strong&gt; type is a very common and effective practice. Now we’ll see how to do it with a &lt;strong&gt;Python&lt;/strong&gt; project, using &lt;strong&gt;SQLAlchemy&lt;/strong&gt; and &lt;strong&gt;Docker Compose&lt;/strong&gt;, which further automates this example. You can run this example using a single command: &lt;strong&gt;docker-compose up&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Before getting down to work, we will review some important concepts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Percona Server for MySQL&lt;/strong&gt; is an open source, drop-in replacement for MySQL Community that provides better performance, more scalability, and enhanced security features.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SQLAlchemy&lt;/strong&gt; is a library that allows us to communicate between Python programs and databases.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Docker Compose&lt;/strong&gt; is a tool for defining and running multi-container Docker applications.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let’s start with the structure of this project:&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2023/04/01-mjii-folders.jpg" alt="Project folder structure" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;We have a folder called &lt;strong&gt;app&lt;/strong&gt; which contains the &lt;strong&gt;db.py&lt;/strong&gt; file, and this is where we create the &lt;strong&gt;library&lt;/strong&gt; database and establish the connection with this database.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;db_user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; os.environ&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'DB_USER'&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;db_password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; os.environ&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'DB_PASSWORD'&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;engine&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; create_engine&lt;span class="o"&gt;(&lt;/span&gt;f&lt;span class="s2"&gt;"mysql+pymysql://{db_user}:{db_password}@db:3306/library"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;In this file, we also create the class transactions. This will create the fields for the &lt;strong&gt;library&lt;/strong&gt; databases with &lt;strong&gt;SQLAlchemy&lt;/strong&gt;; we define the attributes, and they will be the database fields.
We have four attributes: book_id, tittle, publishes, and labels. The last one (labels) of JSON data type.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-1"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;class transactions&lt;span class="o"&gt;(&lt;/span&gt;base&lt;span class="o"&gt;)&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;__tablename__&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'book'&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;book_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; Column&lt;span class="o"&gt;(&lt;/span&gt;Integer, &lt;span class="nv"&gt;primary_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;True&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; Column&lt;span class="o"&gt;(&lt;/span&gt;String&lt;span class="o"&gt;(&lt;/span&gt;50&lt;span class="o"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;publisher&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; Column&lt;span class="o"&gt;(&lt;/span&gt;String&lt;span class="o"&gt;(&lt;/span&gt;50&lt;span class="o"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;labels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; Column&lt;span class="o"&gt;(&lt;/span&gt;JSON&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; def __init__&lt;span class="o"&gt;(&lt;/span&gt;self, book_id, title, publisher, labels&lt;span class="o"&gt;)&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; self.book_id &lt;span class="o"&gt;=&lt;/span&gt; book_id
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; self.title &lt;span class="o"&gt;=&lt;/span&gt; title
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; self.publisher &lt;span class="o"&gt;=&lt;/span&gt; publisher
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; self.labels &lt;span class="o"&gt;=&lt;/span&gt; labels
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;base.metadata.create_all&lt;span class="o"&gt;(&lt;/span&gt;engine&lt;span class="o"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Now let’s review the Python script called &lt;strong&gt;insert.py&lt;/strong&gt;, where we use the transactions class to insert data into the database.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-2" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-2"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;import db
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;from sqlalchemy.orm import sessionmaker
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;Session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; sessionmaker&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;bind&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;db.engine&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; Session&lt;span class="o"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;tr1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; db.transactions&lt;span class="o"&gt;(&lt;/span&gt;1,&lt;span class="s1"&gt;'Green House'&lt;/span&gt;, &lt;span class="s1"&gt;'Joe Monter'&lt;/span&gt;, &lt;span class="s1"&gt;'{"about" : {"gender": "action", "cool": true, "notes": "labeled"}}'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;session.add&lt;span class="o"&gt;(&lt;/span&gt;tr1&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;session.commit&lt;span class="o"&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Now let’s explore the &lt;strong&gt;docker-compose.yaml&lt;/strong&gt; file, we have two services, the db and the api&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-3" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-3"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;version: &lt;span class="s2"&gt;"3.8"&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;services:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; api:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; build: .
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; container_name: api
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; depends_on:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; db:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; condition: service_healthy
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; db:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; image: percona/percona-server:8.0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; container_name: db
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; restart: always
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; environment:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; MYSQL_USER: root
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; MYSQL_ROOT_PASSWORD: root
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; MYSQL_DATABASE: library
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; healthcheck:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; test: &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"CMD"&lt;/span&gt;, &lt;span class="s2"&gt;"mysqladmin"&lt;/span&gt;, &lt;span class="s2"&gt;"ping"&lt;/span&gt;, &lt;span class="s2"&gt;"-h"&lt;/span&gt;, &lt;span class="s2"&gt;"localhost"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; timeout: 20s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; retries: &lt;span class="m"&gt;10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; volumes:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - my-db:/var/lib/mysql
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ports:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - &lt;span class="s2"&gt;"3306:3306"&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; expose:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - &lt;span class="s2"&gt;"3306"&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Names for volume&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;volumes:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; my-db:&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The &lt;strong&gt;db&lt;/strong&gt; service uses the &lt;strong&gt;Percona Server for MySQL&lt;/strong&gt; image (percona/percona-server:8.0) for the database and has a healthcheck that allows you to confirm when the database is started and ready to receive requests.
The &lt;strong&gt;api&lt;/strong&gt; service depends on the &lt;strong&gt;db&lt;/strong&gt; service to start. The api service will build a Dockerfile, it does a build of the Python applications (of db.py and insert.py), so in this way, we can insert data into the database when it is ready.&lt;/p&gt;
&lt;p&gt;It’s time to see the example in action; let’s locate it inside the &lt;strong&gt;json-mysql&lt;/strong&gt; project and run &lt;strong&gt;docker-compose ps -d&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Once this is done, we can connect to the database and query the table without needing to go inside the container with the following command:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-4" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-4"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; -i db mysql -uroot -proot &lt;span class="o"&gt;&lt;&lt;&lt;&lt;/span&gt; &lt;span class="s2"&gt;"use library;show tables;select \* from book;describe book;"&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;We can check the data types of our fields and the inserted data. You will also see the JSON data type “labels” data type.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-5" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-5"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;book_id title publisher labels
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;1 Green House Joe Monter &lt;span class="s2"&gt;"{\\"&lt;/span&gt;about&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;" : {\\"&lt;/span&gt;gender&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;": \\"&lt;/span&gt;action&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;", \\"&lt;/span&gt;cool&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;": true, \\"&lt;/span&gt;notes&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;": \\"&lt;/span&gt;labeled&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;"}}"&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2 El camino Daniil Zotl &lt;span class="s2"&gt;"{\\"&lt;/span&gt;about&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;" : {\\"&lt;/span&gt;gender&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;": \\"&lt;/span&gt;documental&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;", \\"&lt;/span&gt;cool&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;": true, \\"&lt;/span&gt;notes&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;": \\"&lt;/span&gt;labeled&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;"}}"&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;3 London Bridge Mario Mesa &lt;span class="s2"&gt;"{\\"&lt;/span&gt;about&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;" : {\\"&lt;/span&gt;gender&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;": \\"&lt;/span&gt;drama&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;", \\"&lt;/span&gt;cool&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;": true, \\"&lt;/span&gt;notes&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;": \\"&lt;/span&gt;labeled&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;"}}"&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-6" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-6"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Field Type Null Key Default Extra
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;book_id int NO PRI NULL auto_increment
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;title varchar&lt;span class="o"&gt;(&lt;/span&gt;50&lt;span class="o"&gt;)&lt;/span&gt; YES NULL
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;publisher varchar&lt;span class="o"&gt;(&lt;/span&gt;50&lt;span class="o"&gt;)&lt;/span&gt; YES NULL
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;labels json YES NULL&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Use “docker compose ps” to see your services running. In this case, we have the “db” service running, which is for the database, and we have “api” with the state “exited,” which means that the scripts to create the database and insert the data into the database “library” was created.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-7" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-7"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NAME COMMAND SERVICE STATUS PORTS
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;api &lt;span class="s2"&gt;"/bin/sh -c 'bash -C…"&lt;/span&gt; api exited &lt;span class="o"&gt;(&lt;/span&gt;0&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;db &lt;span class="s2"&gt;"/docker-entrypoint.…"&lt;/span&gt; db running &lt;span class="o"&gt;(&lt;/span&gt;healthy&lt;span class="o"&gt;)&lt;/span&gt; 0.0.0.0:3306-&gt;3306/tcp, 33060/tcp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;It was an example of inserting JSON data into MySQL using SQLAlchemy in Python and docker-compose for deployment.&lt;/p&gt;
&lt;p&gt;You can find the project on &lt;a href="//github.com/edithturn/json-mysql.git"&gt;GitHub&lt;/a&gt;. If there is any other way to make it better happy to hear it so I can improve this project.&lt;/p&gt;
&lt;p&gt;You can explore more about &lt;a href="https://www.percona.com/software/mysql-database/percona-server" target="_blank" rel="noopener noreferrer"&gt;Percona Server for MySQL&lt;/a&gt;, and if you want to see how this project start check &lt;a href="https://percona.community/blog/2023/03/13/using-the-json-data-type-with-mysql-8/" target="_blank" rel="noopener noreferrer"&gt;Using the JSON data type with MySQL 8 - Part I&lt;/a&gt;&lt;/p&gt;</content:encoded>
      <author>Edith Puclla</author>
      <category>JSON</category>
      <category>MySQL</category>
      <category>Databases</category>
      <category>Open Source</category>
      <media:thumbnail url="https://percona.community/blog/2023/04/00-mjii-intro_hu_cb63b3892f2127a0.jpg"/>
      <media:content url="https://percona.community/blog/2023/04/00-mjii-intro_hu_9e1506643b3b38f0.jpg" medium="image"/>
    </item>
    <item>
      <title>How to prevent unauthorized users from connecting to ProxySQL</title>
      <link>https://percona.community/blog/2023/03/30/how-to-prevent-unauthorized-users-from-connecting-to-proxysql/</link>
      <guid>https://percona.community/blog/2023/03/30/how-to-prevent-unauthorized-users-from-connecting-to-proxysql/</guid>
      <pubDate>Thu, 30 Mar 2023 00:00:00 UTC</pubDate>
      <description>ProxySQL is a great load balancer which however suffers from some shortcomings concerning the management of MySQL users. ProxySQL provides a firewall which, in my case, is not complete enough to properly manage users and secure their access. Indeed, this firewall does not accept subnets and keeps unauthorized connections in ProxySQL. We cannot then be sure of not suffering a DDOS attack on our ProxySQL instance. In this article, I will explain how I managed to overcome this problem.</description>
      <content:encoded>&lt;p&gt;ProxySQL is a great load balancer which however suffers from some shortcomings concerning the management of MySQL users. ProxySQL provides a firewall which, in my case, is not complete enough to properly manage users and secure their access. Indeed, this firewall does not accept subnets and keeps unauthorized connections in ProxySQL. We cannot then be sure of not suffering a DDOS attack on our ProxySQL instance. In this article, I will explain how I managed to overcome this problem.&lt;/p&gt;
&lt;h2 id="reminder-of-the-principle-of-connection-through-proxysql"&gt;Reminder of the principle of connection through ProxySQL&lt;/h2&gt;
&lt;p&gt;To understand what follows, you have to bear in mind how ProxySQL connects to MySQL. The user connects to Proxysql which then establishes the connection to MySQL. For this, ProxySQL maintains MySQL users in its internal database. The names of MySQL users, their passwords as well as the MySQL destination server are entered in the mysql_users table. At each connection request to a MySQL server, ProxySQL checks the presence of the user in the mysql_users table to connect itself to MySQL with this same user.&lt;/p&gt;
&lt;p&gt;Something is missing, isn’t it?&lt;/p&gt;
&lt;p&gt;Yes, the host associated with each MySQL user is missing!&lt;/p&gt;
&lt;p&gt;In MySQL, users are configured to only be able to connect from ProxySQL. In ProxySQL we don’t have this information. By default, all users can therefore connect to ProxySQL from any IP address and ProxySQL will open connections to MySQL for them. As I specified in the introduction, ProxySQL provides a Firewall to overcome this problem, but this one is not really satisfactory.&lt;/p&gt;
&lt;h2 id="prevent-connection-to-proxysql-with-an-unauthorized-user"&gt;Prevent connection to ProxySQL with an unauthorized user&lt;/h2&gt;
&lt;p&gt;In this part, our ProxySQL instance will allow user &lt;em&gt;bob&lt;/em&gt; to connect to the MySQL (&lt;em&gt;mysql_server&lt;/em&gt;) instance. &lt;em&gt;Bob&lt;/em&gt; is allowed to connect from &lt;em&gt;IP_1&lt;/em&gt; but cannot from &lt;em&gt;IP_2&lt;/em&gt;. The ProxySQL instance is running on &lt;em&gt;IP_PROXYSQL&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;In MySQL, user &lt;em&gt;bob&lt;/em&gt; was created like this:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'bob'&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="s1"&gt;'IP_PROXYSQL'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;IDENTIFIED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'PASSWORD'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;In ProxySQL, let’s create &lt;em&gt;bob&lt;/em&gt; like this:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-1"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INTO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mysql_users&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;default_hostgroup&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;VALUES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'bob'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'PASSWORD'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="k"&gt;LOAD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MYSQL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;USERS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RUNTIME&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="n"&gt;SAVE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MYSQL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;USERS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DISK&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;and declare the MySQL server like this:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-2" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-2"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INTO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mysql_servers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hostgroup_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;hostname&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;VALUES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'mysql_server'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="k"&gt;LOAD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MYSQL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SERVERS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RUNTIME&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="n"&gt;SAVE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MYSQL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SERVERS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DISK&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;As you may have noticed, I didn’t declare the same hostgroup when creating the user and the server. Hostgroup 0 does not correspond to any MySQL server. By default, our user bob will therefore be able to connect to ProxySQL but his queries will not be redirected to any MySQL server. Let’s move on to host management. I will declare each authorized host in the mysql_query_rules table. In ProxySQL, this table is used, among other things, to assign different parameters to a connection. You see what I mean? Let’s declare our rule!&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-3" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-3"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INTO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mysql_query_rules&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rule_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;active&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;client_addr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;destination_hostgroup&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;VALUES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'bob'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'IP_1'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="k"&gt;LOAD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MYSQL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QUERY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RULES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RUNTIME&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="n"&gt;SAVE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MYSQL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QUERY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RULES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DISK&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;I have just declared a rule indicating that all requests coming from user bob connected from &lt;em&gt;IP_1&lt;/em&gt; must be played on host 1. And icing on the cake, &lt;em&gt;IP_1&lt;/em&gt; can be a subnet (&lt;em&gt;IP_1%&lt;/em&gt;), which would not have could not be possible with the firewall. From now on, bob will be able to perform queries from IP_1 and get results from MySQL. If bob plays a request from IP_2, he will not be able to obtain a result since the hostgroup queried will be 0 which does not correspond to any MySQL server. However, this is not satisfactory. Nothing prevents bob from creating a very large number of connections from &lt;em&gt;IP_2&lt;/em&gt;. It won’t reach any MySQL servers but may be able to crash my ProxySQL instance. It’s time to deal with those unauthorized connections!&lt;/p&gt;
&lt;p&gt;ProxySQL provides a scheduler which will be very useful here. This scheduler will allow us to play a bash script every x ms. I created this script in the ProxySQL datadir:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;kill_connections.sh&lt;/em&gt;&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-4" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-4"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;PROXYSQL_USERNAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;PROXYSQL_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;2&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;PROXYSQL_HOSTNAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"127.0.0.1"&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;PROXYSQL_PORT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"6032"&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mysql -u&lt;span class="nv"&gt;$PROXYSQL_USERNAME&lt;/span&gt; -p&lt;span class="nv"&gt;$PROXYSQL_PASSWORD&lt;/span&gt; -h&lt;span class="nv"&gt;$PROXYSQL_HOSTNAME&lt;/span&gt; -P&lt;span class="nv"&gt;$PROXYSQL_PORT&lt;/span&gt; -e &lt;span class="s2"&gt;"SELECT SessionID,user,cli_host FROM stats_mysql_processlist WHERE hostgroup = 0"&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="nb"&gt;read&lt;/span&gt; SessionID user cli_host&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$SessionID&lt;/span&gt; !&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"SessionID"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;enabled_account&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;mysql -u&lt;span class="nv"&gt;$PROXYSQL_USERNAME&lt;/span&gt; -p&lt;span class="nv"&gt;$PROXYSQL_PASSWORD&lt;/span&gt; -h&lt;span class="nv"&gt;$PROXYSQL_HOSTNAME&lt;/span&gt; -P&lt;span class="nv"&gt;$PROXYSQL_PORT&lt;/span&gt; -se&lt;span class="s2"&gt;"SELECT count(*) FROM mysql_query_rules WHERE username = '&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="s2"&gt;' and '&lt;/span&gt;&lt;span class="nv"&gt;$cli_host&lt;/span&gt;&lt;span class="s2"&gt;' LIKE client_addr;"&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$enabled_account&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; -eq &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; mysql -u&lt;span class="nv"&gt;$PROXYSQL_USERNAME&lt;/span&gt; -p&lt;span class="nv"&gt;$PROXYSQL_PASSWORD&lt;/span&gt; -h&lt;span class="nv"&gt;$PROXYSQL_HOSTNAME&lt;/span&gt; -P&lt;span class="nv"&gt;$PROXYSQL_PORT&lt;/span&gt; -e &lt;span class="s2"&gt;"KILL CONNECTION &lt;/span&gt;&lt;span class="nv"&gt;$SessionID&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;done&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This script lists all the connections opened in ProxySQL on hostgroup 0. It then checks whether the connected user/host pair is authorized using the mysql_query_rules table. If not, the connection is killed. Let’s activate the scheduler in ProxySQL:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-5" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-5"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INTO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;scheduler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;arg2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;interval_ms&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;VALUES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'kill_connections.sh'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'proxysql_admin_user'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'proxysql_admin_password'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="k"&gt;LOAD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SCHEDULER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RUNTIME&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="n"&gt;SAVE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SCHEDULER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DISK&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Now, any connection opened in ProxySQL but not authorized will be automatically killed!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;WARNING:&lt;/em&gt;&lt;/strong&gt; unfortunately, the ProxySQL scheduler does not work like the MySQL scheduler. It is necessary to open the connection from a .sh file and therefore to indicate the ProxySQL administration credentials. These identifiers will then be visible by monitoring the list of server processes. To avoid this problem, I advise you to indicate the identifiers directly in the .sh file and to protect this file correctly on your server.&lt;/p&gt;&lt;/blockquote&gt;
&lt;h2 id="additional-information"&gt;Additional Information&lt;/h2&gt;
&lt;p&gt;When I deploy ProxySQL, I always create a rule with a very high rule_id to block unauthorized connections; this is an additional barrier in case I forget something:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-6" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-6"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INTO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mysql_query_rules&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rule_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;active&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;error_msg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;destination_hostgroup&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;VALUES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;999999999&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'ProxySQL : Access denied'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="k"&gt;LOAD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MYSQL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QUERY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RULES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RUNTIME&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="n"&gt;SAVE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MYSQL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QUERY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RULES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DISK&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This rule redirects unauthorized connections to hostgroup 0 (if ever a user was declared in mysql_users with a hostgroup leading to a MySQL server) and displays an error message for each request.
I create all my rules to manage hosts with a rule_id &gt; or = 10000. This allows me to have 9999 empty slots if I ever want to create other priority rules in mysql_query_rules.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-7" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-7"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INTO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mysql_query_rules&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rule_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;active&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;client_addr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;VALUES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;IFNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;MAX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rule_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mysql_query_rules&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rule_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;MAX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rule_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mysql_query_rules&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rule_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;9999&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'USERNAME'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'HOST'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="k"&gt;LOAD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MYSQL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QUERY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RULES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RUNTIME&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="n"&gt;SAVE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MYSQL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QUERY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RULES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DISK&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Don’t hesitate to ask me questions, I’ll be happy to answer them.&lt;/p&gt;</content:encoded>
      <author>Valentin TRAËN</author>
      <category>Databases</category>
      <category>MySQL</category>
      <category>ProxySQL</category>
      <category>LoadBalancer</category>
      <media:thumbnail url="https://percona.community/blog/2023/03/proxysql_user_management_cover_hu_56dc53c3bd9592d8.jpg"/>
      <media:content url="https://percona.community/blog/2023/03/proxysql_user_management_cover_hu_4a261bdecc8d22a5.jpg" medium="image"/>
    </item>
    <item>
      <title>Percona Monitoring and Management 2.36 preview release</title>
      <link>https://percona.community/blog/2023/03/20/preview-release/</link>
      <guid>https://percona.community/blog/2023/03/20/preview-release/</guid>
      <pubDate>Mon, 20 Mar 2023 00:00:00 UTC</pubDate>
      <description>Percona Monitoring and Management 2.36 preview release Hello folks! Percona Monitoring and Management (PMM) 2.36 is now available as a preview release.</description>
      <content:encoded>&lt;h2 id="percona-monitoring-and-management-236-preview-release"&gt;Percona Monitoring and Management 2.36 preview release&lt;/h2&gt;
&lt;p&gt;Hello folks! Percona Monitoring and Management (PMM) 2.36 is now available as a preview release.&lt;/p&gt;
&lt;p&gt;We encourage you to try this PMM preview release in &lt;strong&gt;testing environments only&lt;/strong&gt;, as these packages and images are not fully production-ready. The final version is expected to be released through the standard channels in the coming week.&lt;/p&gt;
&lt;p&gt;You can find the Release Notes &lt;a href="https://two-36-0-pr-1011.onrender.com/release-notes/2.36.0.html" target="_blank" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="percona-monitoring-and-management-server-docker-installation"&gt;Percona Monitoring and Management server docker installation&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://docs.percona.com/percona-monitoring-and-management/setting-up/server/docker.html" target="_blank" rel="noopener noreferrer"&gt;Instructions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;docker tag:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;perconalab/pmm-server:2.36.0-rc&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; In order to use the DBaaS functionality during the Percona Monitoring and Management preview release, you should add the following environment variablewhen starting PMM server:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;PERCONA_TEST_DBAAS_PMM_CLIENT=perconalab/pmm-client:2.36.0-rc&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="percona-monitoring-and-management-client-package-installation"&gt;Percona Monitoring and Management client package installation&lt;/h3&gt;
&lt;p&gt;Download the latest pmm2-client release candidate tarball for 2.36 by this &lt;a href="https://s3.us-east-2.amazonaws.com/pmm-build-cache/PR-BUILDS/pmm2-client/pmm2-client-latest-5090.tar.gz" target="_blank" rel="noopener noreferrer"&gt;link&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you want to install pmm2-client package, please enable testing repository via Percona-release:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;percona-release enable percona testing&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;install pmm2-client package for your OS via package manager.&lt;/p&gt;
&lt;h3 id="ova"&gt;OVA&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://docs.percona.com/percona-monitoring-and-management/setting-up/server/virtual-appliance.html" target="_blank" rel="noopener noreferrer"&gt;Instructions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://percona-vm.s3.amazonaws.com/PMM2-Server-2.36.0.ova" target="_blank" rel="noopener noreferrer"&gt;PMM2-Server-2.36.0.ova&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="ami"&gt;AMI&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://docs.percona.com/percona-monitoring-and-management/setting-up/server/aws.html" target="_blank" rel="noopener noreferrer"&gt;Instructions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ami-0ce04c507ec1187b1&lt;/code&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Contact us in &lt;a href="https://forums.percona.com/" target="_blank" rel="noopener noreferrer"&gt;https://forums.percona.com/&lt;/a&gt;.&lt;/p&gt;</content:encoded>
      <author>Taras Kozub</author>
      <category>PMM</category>
      <category>Release</category>
      <media:thumbnail url="https://percona.community/superhero_hu_252fc2b480c0a197.jpg"/>
      <media:content url="https://percona.community/superhero_hu_17979f11d5d3562e.jpg" medium="image"/>
    </item>
    <item>
      <title>Some Notable Bugfixes in MySQL 8.0.32</title>
      <link>https://percona.community/blog/2023/03/15/some-notable-bugfixes-in-mysql-8.0.32/</link>
      <guid>https://percona.community/blog/2023/03/15/some-notable-bugfixes-in-mysql-8.0.32/</guid>
      <pubDate>Wed, 15 Mar 2023 00:00:00 UTC</pubDate>
      <description>MySQL 8.0.32 came out recently and had some important bugfixes contributed by Perconians. Here is a brief overview of the work done.</description>
      <content:encoded>&lt;p&gt;MySQL 8.0.32 came out recently and had some important bugfixes contributed by Perconians. Here is a brief overview of the work done.&lt;/p&gt;
&lt;h2 id="inconsistent-data-and-gtids-with-mysqldump"&gt;Inconsistent data and GTIDs with mysqldump&lt;/h2&gt;
&lt;p&gt;Marcelo Altmann (Senior Software Engineer) fixed the bug when data and GTIDs backed up by mysqldump were inconsistent. It happened when the options –single-transaction and –set-gtid-purged=ON were both used because GTIDs on the server could have already increased between the start of the transaction by mysqldump and the fetching of GTID_EXECUTED. Marcelo developed a patch, and it was partially included in the release. Now, in MySQL 8.0.32, a FLUSH TABLES WITH READ LOCK is performed before fetching GTID_EXECUTED, to ensure its value is consistent with the snapshot taken by mysqldump. However, Percona Server for MySQL includes the entire patch, which does not require FLUSH TABLE WITH READ LOCK to work.&lt;/p&gt;
&lt;p&gt;Marcelo also corrected the issue when the MySQL server &lt;a href="https://perconadev.atlassian.net/browse/PS-8303" target="_blank" rel="noopener noreferrer"&gt;exits on ALTER TABLE created an assertion failure: dict0mem.h:2498:pos &lt; n_def&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="fixing-garbled-utf-characters"&gt;Fixing garbled UTF characters&lt;/h2&gt;
&lt;p&gt;Kamil Holubicki (Senior Software Engineer) proposed a patch to fix garbled UTF characters in SHOW ENGINE INNODB STATUS. It happened because the string was truncated, and UTF characters (which are multibyte) were cut in the middle which caused garbage at the end of the string.&lt;/p&gt;
&lt;h2 id="duplicate-table-space-objects-in-56-to-80-upgrade"&gt;Duplicate table space objects in 5.6 to 8.0 upgrade&lt;/h2&gt;
&lt;p&gt;Rahul Malik (Software Engineer) investigated and fixed an issue when an 8.0 upgrade from MySQL 5.6 crashed with Assertion failure. It happened due to a duplicate table space object. All SYS_* tables are loaded, and then their table IDs are changed. Some SYS tables like SYS_ZIP_DICT, VIRTUAL can have ids &gt; 1024 (say, 1028).&lt;/p&gt;
&lt;p&gt;Changing table_ids of SYS_FIELDS from 4 to 1028 will conflict with the table_ids of those existing SYS_ZIP_DICT/VIRTUAL which haven’t been shifted by 1024 yet and are currently loaded with 1028. Hence, we need to change the IDs of that SYS tables in reverse order to fix it. So in the example above, SYS_FIELD is the first shift to 1028+1024, and then SYS_FIELD changes to 1028 to avoid conflicts.&lt;/p&gt;
&lt;h2 id="why-open-source-databases-matter"&gt;Why open source databases matter&lt;/h2&gt;
&lt;p&gt;Great work by Marcelo, Kamil, Rahul, and everybody else who contributed to the MySQL 8.0.32 release.&lt;/p&gt;
&lt;p&gt;This is why open source databases are so important. We can all help improve MySQL, and those improvements benefit all users of MySQL.&lt;/p&gt;
&lt;p&gt;Percona is proud to be part of the MySQL community, and we hope you’ll join us in improving MySQL and its surrounding software. Check out our &lt;a href="https://percona.community/contribute/" target="_blank" rel="noopener noreferrer"&gt;contributing page&lt;/a&gt; to find ways to contribute!&lt;/p&gt;</content:encoded>
      <author>Aleksandra Abramova</author>
      <category>MySQL</category>
      <category>Databases</category>
      <category>Open Source</category>
      <category>Release</category>
      <media:thumbnail url="https://percona.community/blog/2023/03/mysql-bugfixes_hu_3963a5ecfa010f5.jpg"/>
      <media:content url="https://percona.community/blog/2023/03/mysql-bugfixes_hu_1fd86d064829157f.jpg" medium="image"/>
    </item>
    <item>
      <title>Using the JSON data type with MySQL 8</title>
      <link>https://percona.community/blog/2023/03/13/using-the-json-data-type-with-mysql-8/</link>
      <guid>https://percona.community/blog/2023/03/13/using-the-json-data-type-with-mysql-8/</guid>
      <pubDate>Mon, 13 Mar 2023 00:00:00 UTC</pubDate>
      <description>If you are a mobile app, frontend, backend, or game developer, you use data types such as string, numeric, or DateTime. You also know that since the advent of non-relational databases (NoSQL) such as MongoDB, which, by not being tied to a traditional SQL schema, do reading and writing on databases much faster. But MySQL showed that storing the JSON (JavaScript Object Notation) data type could also improve the speed of reading and writing relational databases.</description>
      <content:encoded>&lt;p&gt;If you are a mobile app, frontend, backend, or game developer, you use data types such as string, numeric, or DateTime. You also know that since the advent of non-relational databases (NoSQL) such as &lt;strong&gt;MongoDB&lt;/strong&gt;, which, by not being tied to a traditional &lt;strong&gt;SQL schema&lt;/strong&gt;, do reading and writing on databases much faster. But &lt;strong&gt;MySQL&lt;/strong&gt; showed that storing the JSON (JavaScript Object Notation) data type could also improve the speed of reading and writing relational databases.&lt;/p&gt;
&lt;p&gt;This post will explore the JSON Data type in &lt;a href="https://www.percona.com/software/mysql-database/percona-server" target="_blank" rel="noopener noreferrer"&gt;Percona Server for MySQL&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;One of the key features of &lt;strong&gt;Percona Server&lt;/strong&gt; is support for &lt;strong&gt;JSON&lt;/strong&gt; data type, which allows for the storage of JSON documents within MySQL. It allows for more flexible and efficient storage of semi-structured data (​​which is more human-readable ) within a relational database.&lt;/p&gt;
&lt;p&gt;We will install &lt;strong&gt;Percona Server for MySQL&lt;/strong&gt; in a Docker container to make basic operations for inserting, modifying, and removing JSON data types.&lt;/p&gt;
&lt;p&gt;To start, we will bring version 8.0 of Percona Server for MySQL; the name of this image in Docker Hub is percona-server. You will need Docker; if you don’t have it installed, follow the official &lt;a href="https://docs.docker.com/engine/install/" target="_blank" rel="noopener noreferrer"&gt;Docker documentation&lt;/a&gt;.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker pull percona/percona-server:8.0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;We will run the container for &lt;strong&gt;Percona Server for MySQL&lt;/strong&gt;, call our container percona-server and pass in an environment variable called &lt;strong&gt;MYSQL_ROOT_PASSWORD&lt;/strong&gt;; This variable specifies a password that is set for the MySQL root account.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-1"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker run -d &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt; --name percona-server &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt; -e &lt;span class="nv"&gt;MYSQL_ROOT_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;root &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt; percona/percona-server:8.0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;After confirming that our container is running with “docker ps,” we can enter our Percona Server for MySQL container to start executing commands.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-2" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-2"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; -it percona-server /bin/bash&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The Percona Server for MySQL database is already running, and we will proceed to connect to it:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-3" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-3"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mysql -uroot -p&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Use &lt;strong&gt;root&lt;/strong&gt; as a password.&lt;/p&gt;
&lt;p&gt;Create the database called &lt;strong&gt;cinema&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-4" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-4"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;CREATE DATABASE library&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;USE library&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Create a table called &lt;strong&gt;books&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-5" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-5"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;CREATE TABLE books &lt;span class="o"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; book_id BIGINT PRIMARY KEY AUTO_INCREMENT,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; title VARCHAR&lt;span class="o"&gt;(&lt;/span&gt;100&lt;span class="o"&gt;)&lt;/span&gt; UNIQUE NOT NULL,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; publisher VARCHAR&lt;span class="o"&gt;(&lt;/span&gt;100&lt;span class="o"&gt;)&lt;/span&gt; NOT NULL,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; labels JSON NOT NULL
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;ENGINE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; InnoDB&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="insert-json-type-into-books-table"&gt;Insert JSON type into books table&lt;/h2&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-6" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-6"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;INSERT INTO books&lt;span class="o"&gt;(&lt;/span&gt;title,publisher, labels&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;VALUES&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Green House'&lt;/span&gt;, &lt;span class="s1"&gt;'Joe Monter'&lt;/span&gt;, &lt;span class="s1"&gt;'{"about" : {"gender": "action", "cool": true, "notes": "labeled"}}'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;INSERT INTO books&lt;span class="o"&gt;(&lt;/span&gt;title,publisher, labels&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;VALUES&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'El camino'&lt;/span&gt;, &lt;span class="s1"&gt;'Daniil Zotl'&lt;/span&gt;, &lt;span class="s1"&gt;'{"about" : {"gender": "documental", "cool": true, "notes": "labeled"}}'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-7" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-7"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;select&lt;/span&gt; * from books&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;As you can see, JSON is a more flexible data type than what you might be used to when working with data in &lt;strong&gt;MySQL&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id="select-with-json_extract"&gt;Select with JSON_EXTRACT&lt;/h2&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-8" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-8"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;SELECT title, JSON_EXTRACT&lt;span class="o"&gt;(&lt;/span&gt;labels, &lt;span class="s1"&gt;'$.about.notes'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; AS Notes FROM books&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;A shortcut of JSON_EXTRACT is “-&gt;”
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;SELECT title, labels-&gt;&lt;span class="s1"&gt;'$.about.notes'&lt;/span&gt; AS Notes FROM books&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The short operator -&gt; provides the same functionality as JSON_EXTRACT&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-9" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-9"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;SELECT titulo, etiquetas-&gt;&lt;span class="s1"&gt;'$.acerca.genero'&lt;/span&gt; AS Genero FROM books&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="updating-json-type-records"&gt;Updating JSON type records&lt;/h2&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-10" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-10"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;UPDATE books SET &lt;span class="nv"&gt;labels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; JSON_REPLACE&lt;span class="o"&gt;(&lt;/span&gt;labels, &lt;span class="s1"&gt;'$.about.gender'&lt;/span&gt;, &lt;span class="s1"&gt;'romance'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; WHERE &lt;span class="nv"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'the roses'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;UPDATE books SET &lt;span class="nv"&gt;labels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; JSON_REPLACE&lt;span class="o"&gt;(&lt;/span&gt;labels, &lt;span class="s1"&gt;'$.about.notes'&lt;/span&gt;, &lt;span class="s1"&gt;'not labeled'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; WHERE &lt;span class="nv"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'the roses'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-11" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-11"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;select&lt;/span&gt; * from books&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="deleting-a-json-record"&gt;Deleting a JSON record&lt;/h2&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-12" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-12"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;DELETE FROM books WHERE &lt;span class="nv"&gt;book_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; AND JSON_EXTRACT&lt;span class="o"&gt;(&lt;/span&gt;labels, &lt;span class="s1"&gt;'$.about.gender'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"documental"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="deleting-a-value-inside-a-json-structure"&gt;Deleting a value inside a JSON structure&lt;/h2&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-13" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-13"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;UPDATE books SET &lt;span class="nv"&gt;labels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; JSON_REMOVE&lt;span class="o"&gt;(&lt;/span&gt;labels, &lt;span class="s1"&gt;'$.about.notes'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; WHERE &lt;span class="nv"&gt;book_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 2&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;You can use these fundamental operations to manage JSON data types in Percona Server MySQL. This allows for more flexible and efficient data modeling and querying for applications that work with JSON data. How will that work in an application? Keep an eye out, I’ll be following this up with a blog about an application using JSON data in MySQL very soon.&lt;/p&gt;
&lt;p&gt;Get more about Percona Server for MySQL documentation in our &lt;a href="https://www.percona.com/software/mysql-database/percona-server" target="_blank" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt;. And if you want to know why JSON is the preferred format for many developers and why it’s so popular, check out &lt;a href="https://www.percona.com/blog/json-and-relational-databases-part-one" target="_blank" rel="noopener noreferrer"&gt;David Stokes’ blog: JSON and Relational Databases – Part One&lt;/a&gt;&lt;/p&gt;</content:encoded>
      <author>Edith Puclla</author>
      <category>JSON</category>
      <category>MySQL</category>
      <category>Databases</category>
      <category>Open Source</category>
      <media:thumbnail url="https://percona.community/blog/2023/03/13-cover-change_hu_828a39cdc2af9b2a.jpg"/>
      <media:content url="https://percona.community/blog/2023/03/13-cover-change_hu_ad37fbc7e77a97a0.jpg" medium="image"/>
    </item>
    <item>
      <title>Backups for MySQL With mysqldump</title>
      <link>https://percona.community/blog/2023/03/10/backups-for-mysql-with-mysqldump/</link>
      <guid>https://percona.community/blog/2023/03/10/backups-for-mysql-with-mysqldump/</guid>
      <pubDate>Fri, 10 Mar 2023 00:00:00 UTC</pubDate>
      <description>Basic Usage mysqldump is a client utility that can be used for doing logical backups. It will generate the necessary SQL statements to reproduce the original database.</description>
      <content:encoded>&lt;h2 id="basic-usage"&gt;Basic Usage&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://dev.mysql.com/doc/refman/8.0/en/mysqldump.html" target="_blank" rel="noopener noreferrer"&gt;mysqldump&lt;/a&gt; is a client utility that can be used for doing logical backups. It will generate the necessary SQL statements to reproduce the original database.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2023/03/backup.jpg" alt="Backup" /&gt;&lt;figcaption&gt;Backup by Nick Youngson CC BY-SA 3.0 Pix4free&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;The following statements are some common uses of mysqldump:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;mysqldump -u username -p database_name [table_name] &gt; dump.sql&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mysqldump -u username -p --databases db1_name db2_name &gt; dump.sql&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mysqldump -u username -p --all-databases &gt; dump.sql&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The first example is for backing up a single database. If you need to back up some specific tables instead of the whole database, write their names, space-separated.&lt;/p&gt;
&lt;p&gt;With the &lt;code&gt;--databases&lt;/code&gt; option, you can back up two or more databases, their names must be space separated.&lt;/p&gt;
&lt;p&gt;To back up all the databases in your MySQL server, just append the &lt;code&gt;--all-databases&lt;/code&gt; option.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;dump.sql&lt;/code&gt; file doesn’t contain the create database SQL statement. If you need it, add it with the &lt;code&gt;-B&lt;/code&gt; option. This is unnecessary if you’re running &lt;code&gt;mysqldump&lt;/code&gt; with the &lt;code&gt;--databases&lt;/code&gt; and &lt;code&gt;--all-databases&lt;/code&gt; options.&lt;/p&gt;
&lt;p&gt;Ignoring tables when backing up a database is also possible with the &lt;code&gt;--ignore-tables&lt;/code&gt; option.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ mysqldump -u username -p database_name --ignore-tables=database_name.table1 &gt; database_name.sql&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;If you need to ignore more than one database, just use the option as many times as needed.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-1"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ mysqldump -u root -p database_name --ignore-table=database_name.table1 --ignore-table=database_name.table2 &gt; database_name.sql&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="schema-backup"&gt;Schema Backup&lt;/h2&gt;
&lt;p&gt;In case you need to backup only the schema of your database with no data, run mysqldump with the &lt;code&gt;--no-data&lt;/code&gt; option:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-2" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-2"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ mysqldump -u username -p database_name --no-data &gt; dump.sql&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;You can also backup the schema while running &lt;code&gt;mysqldump&lt;/code&gt; with the &lt;code&gt;--databases&lt;/code&gt; and &lt;code&gt;--all-databases&lt;/code&gt; options.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-3" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-3"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ mysqldump -u username -p --all-databases --no-data &gt; dump.sql&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-4" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-4"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ mysqldump -u username -p --databases db1_name db2_name --no-data &gt; dump.sql&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="data-restore"&gt;Data Restore&lt;/h2&gt;
&lt;p&gt;To restore the databases in your &lt;code&gt;dump.sql&lt;/code&gt; file, run the following command:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-5" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-5"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ mysqldump -u root -p &lt; dump.sql&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;If you need to restore a single database from the complete backup, you can do it by running any of the following statements:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-6" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-6"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ mysqldump -u root -p -o database_name &lt; dump.sql&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-7" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-7"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ mysqldump -u root -p --one-database database_name &lt; dump.sql&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;In both cases, the database must exist in your MySQL server, as it only will restore the schema and the data.&lt;/p&gt;
&lt;h2 id="conditional-backup"&gt;Conditional Backup&lt;/h2&gt;
&lt;p&gt;If you need to create a backup that contains data that matches a condition, you can use a &lt;code&gt;WHERE&lt;/code&gt; clause with mysqldump.&lt;/p&gt;
&lt;p&gt;You can use a single where condition:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-8" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-8"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ mysqldump database_name table_name --where="id &gt; 500" &gt; dump.sql&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Or multiple conditions:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-9" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-9"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ mysqldump database_name users --where="id &gt; 500 and disabled = 0" &gt; dump.sql&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;As explained &lt;a href="https://mysqldump.guru/how-to-use-a-where-clause-with-mysqldump.html" target="_blank" rel="noopener noreferrer"&gt;here&lt;/a&gt; in the &lt;a href="https://mysqldump.guru/" target="_blank" rel="noopener noreferrer"&gt;mysqldump.guru&lt;/a&gt; website.&lt;/p&gt;
&lt;p&gt;For example, in a database with the following schema, built from the &lt;a href="https://movienet.github.io/" target="_blank" rel="noopener noreferrer"&gt;Movienet&lt;/a&gt; dataset:&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2023/03/movienet_model.png" alt="Movienet Database" /&gt;&lt;figcaption&gt;Movienet Database&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;If you want to back up the movies produced in a specific country, like Mexico, a way to do it is by running mysqldump with a &lt;code&gt;WHERE&lt;/code&gt; clause.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-10" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-10"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ mysqldump -u root -p movienet movies --where=”country = 22” &gt; dump.sql&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;code&gt;22&lt;/code&gt; is the &lt;code&gt;country_id&lt;/code&gt; of Mexico in this particular database, created using &lt;a href="https://github.com/mattdark/json-mysql-importer" target="_blank" rel="noopener noreferrer"&gt;this Python script&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You can also get those values by executing the following SQL statement:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-11" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-11"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;select movies.movie_id, movies.title, countries.name as country from movies inner join countries on movies.country = countrie
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;s.country_id and movies.country = '22';&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-12" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-12"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+-----------+-----------------------------------------------------------+---------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| movie_id | title | country |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+-----------+-----------------------------------------------------------+---------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| tt0047501 | Sitting Bull (1954) | Mexico |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| tt0049046 | Canasta de cuentos mexicanos (1956) | Mexico |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| tt0076336 | Hell Without Limits (1978) | Mexico |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| tt0082048 | El barrendero (1982) | Mexico |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| tt0082080 | Blanca Nieves y sus 7 amantes (1980) | Mexico |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| tt0083057 | El sexo de los pobres (1983) | Mexico |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| tt0110185 | El jardín del Edén (1994) | Mexico |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| tt0116043 | De jazmín en flor (1996) | Mexico |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| tt0121322 | El giro, el pinto, y el Colorado (1979) | Mexico |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| tt0133354 | Algunas nubes (1995) | Mexico |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| tt0207055 | La risa en vacaciones 4 (TV Movie 1994) | Mexico |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| tt0208889 | To and Fro (2000) | Mexico |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| tt0211878 | La usurpadora (TV Series 1998– ) | Mexico |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| tt0220306 | El amarrador 3 (1995) | Mexico |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| tt0229008 | El vampiro teporocho (1989) | Mexico |&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="skipping-databases"&gt;Skipping Databases&lt;/h2&gt;
&lt;p&gt;There’s no option for &lt;code&gt;mysqldump&lt;/code&gt; to skip databases when generating the backup, but here’s a solution that could work for you:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-13" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-13"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;DATABASES_TO_EXCLUDE="db1 db2 db3"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;EXCLUSION_LIST="'information_schema','mysql'"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;for DB in `echo "${DATABASES_TO_EXCLUDE}"`
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;do
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; EXCLUSION_LIST="${EXCLUSION_LIST},'${DB}'"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;done
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;SQLSTMT="SELECT schema_name FROM information_schema.schemata"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;SQLSTMT="${SQLSTMT} WHERE schema_name NOT IN (${EXCLUSION_LIST})"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;MYSQLDUMP_DATABASES="--databases"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;for DB in `mysql -u username -p -ANe"${SQLSTMT}"`
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;do
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; MYSQLDUMP_DATABASES="${MYSQLDUMP_DATABASES} ${DB}"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;done
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;MYSQLDUMP_OPTIONS="--routines --triggers"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mysqldump -u username -p ${MYSQLDUMP_OPTIONS} ${MYSQLDUMP_DATABASES} &gt; MySQLDatabases.sql&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The above BASH script will generate the backup of your MySQL server excluding the &lt;code&gt;information_schema&lt;/code&gt; and &lt;code&gt;mysql&lt;/code&gt; databases, listed in the &lt;code&gt;EXCLUSION_LIST&lt;/code&gt; variable, as well as the databases of your choice in the &lt;code&gt;DATABASES_TO_EXCLUDE&lt;/code&gt; variable.&lt;/p&gt;
&lt;p&gt;Don’t forget to add the databases you want to exclude to the &lt;code&gt;DATABASES_TO_EXCLUDE&lt;/code&gt; variable, replace the &lt;code&gt;username&lt;/code&gt;, in both &lt;code&gt;mysql&lt;/code&gt; and &lt;code&gt;mysqldump&lt;/code&gt; commands, and add the required options to the &lt;code&gt;MYSQLDUMP_OPTIONS&lt;/code&gt; variable.&lt;/p&gt;
&lt;h2 id="security-considerations"&gt;Security Considerations&lt;/h2&gt;
&lt;p&gt;Some of the common questions in &lt;a href="https://forums.percona.com" target="_blank" rel="noopener noreferrer"&gt;our forum&lt;/a&gt; are about how to do a partial restoration from a complete backup. For example, when you back up a database with &lt;code&gt;mysqldump&lt;/code&gt;, you will get the statements for creating the schema of the database and inserting the data from your backup.&lt;/p&gt;
&lt;p&gt;If you only need the schema, you can run mysqldump with the –no-data option. But if you need to restore the schema of a specific database from a complete backup, I found an interesting solution:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-14" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-14"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat dump.sql | grep -v ^INSERT | mysql -u username -p&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The above command will restore the schema of your database, skipping the SQL statements for inserting the data. It works well when you backup a single database, but there’s no reason to use it as you can get the schema with the &lt;code&gt;--no-data&lt;/code&gt; option, instead of removing the inserts.&lt;/p&gt;
&lt;p&gt;What happens if you try to run this command with a backup that includes all the databases in your server? You must be careful as this will try to overwrite the system schema in the &lt;code&gt;mysql&lt;/code&gt; database which is dangerous. This database store authentication details and overriding the data will make you lose access to your server.&lt;/p&gt;
&lt;p&gt;If you don’t need to backup the &lt;code&gt;mysql&lt;/code&gt; database, run &lt;code&gt;mysqldump&lt;/code&gt; with the &lt;code&gt;--databases&lt;/code&gt; option to specify which databases you require or use the script shared in the &lt;a href="#skipping-databases"&gt;Skipping Databases&lt;/a&gt; section.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Through this blog post you learned how to use mysqldump for backing up the databases in your MySQL server as well as some recommendations while using this tool. For advanced usage of mysqldump you can check &lt;a href="https://www.percona.com/blog/the-mysqlpump-utility/" target="_blank" rel="noopener noreferrer"&gt;this article&lt;/a&gt; in our blog.&lt;/p&gt;</content:encoded>
      <author>Mario García</author>
      <category>MySQL</category>
      <category>Backup</category>
      <media:thumbnail url="https://percona.community/blog/2023/03/backup_hu_aac33fbd4cc33f69.jpg"/>
      <media:content url="https://percona.community/blog/2023/03/backup_hu_8f2cb2ce79c4a147.jpg" medium="image"/>
    </item>
    <item>
      <title>Monitor your databases with Open Source tools like PMM</title>
      <link>https://percona.community/blog/2023/03/06/monitor-your-databases-with-open-source-tools-like-pmm/</link>
      <guid>https://percona.community/blog/2023/03/06/monitor-your-databases-with-open-source-tools-like-pmm/</guid>
      <pubDate>Mon, 06 Mar 2023 00:00:00 UTC</pubDate>
      <description>In this post, we will cover the value of database monitoring and how we can use Open Source tools like PMM Percona Monitoring and Management to monitor and manage databases effectively.</description>
      <content:encoded>&lt;p&gt;In this post, we will cover the value of database monitoring and how we can use Open Source tools like &lt;strong&gt;PMM&lt;/strong&gt; &lt;a href="https://www.percona.com/software/database-tools/percona-monitoring-and-management" target="_blank" rel="noopener noreferrer"&gt;Percona Monitoring and Management&lt;/a&gt; to monitor and manage databases effectively.&lt;/p&gt;
&lt;h2 id="why-should-i-care-about-database-monitoring"&gt;Why should I care about database monitoring?&lt;/h2&gt;
&lt;p&gt;Once you have passed the installation and configuration of your databases and it is well underway, you have to start monitoring it, and not only the database but the elements related to it.&lt;/p&gt;
&lt;p&gt;Questions like these will begin to arise:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Is my database performing well?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Are query response times consistently slow?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Is my database available and accepting connections?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Connections to the database close to the maximum limit&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Is my system stable?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How about CPU, memory, and disk?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Am I experiencing avoidable downtime?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hardware failures, network outages.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;Am I experiencing data loss?
&lt;ul&gt;
&lt;li&gt;Disk crashes&lt;/li&gt;
&lt;li&gt;Human errors&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Am I minimizing performance issues that can impact my business?&lt;/li&gt;
&lt;li&gt;Can I quickly identify and resolve issues before they become more significant problems?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To answer these questions, you will need to find tools that let you keep your database monitored, and you can opt for free tools for monitoring. &lt;strong&gt;PMM&lt;/strong&gt; is one of them, which is entirely open source.&lt;/p&gt;
&lt;h2 id="percona-monitoring-and-management-pmm"&gt;Percona Monitoring and Management (PMM)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;PMM&lt;/strong&gt; is an open source database observability, monitoring, and management tool for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;MySQL&lt;/li&gt;
&lt;li&gt;MariaDB&lt;/li&gt;
&lt;li&gt;PostgreSQL&lt;/li&gt;
&lt;li&gt;MongoDB&lt;/li&gt;
&lt;li&gt;And others&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It can also help to improve the performance of your databases, simplify their management and strengthen their security.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;PMM&lt;/strong&gt; is built on top of open source software&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Grafana&lt;/li&gt;
&lt;li&gt;VictoriaMetrics/Prometheus&lt;/li&gt;
&lt;li&gt;ClickHouse&lt;/li&gt;
&lt;li&gt;PostgreSQL&lt;/li&gt;
&lt;li&gt;Docker&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="pmm-interface"&gt;PMM Interface&lt;/h2&gt;
&lt;p&gt;There are three levels of depth:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dashboards&lt;/li&gt;
&lt;li&gt;Graphs&lt;/li&gt;
&lt;li&gt;Metrics&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2023/03/01-interface.jpg" alt="Interface" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h2 id="metrics--database-monitoring"&gt;Metrics &amp; Database Monitoring&lt;/h2&gt;
&lt;p&gt;Important database metrics you should monitor:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It will depend on your specific database and use case&lt;/li&gt;
&lt;li&gt;Monitor the metrics that are relevant to your database and your business&lt;/li&gt;
&lt;li&gt;You should have alerts and monitoring processes to ensure you are aware of any problems as they occur or before&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Some important metrics that could indicate potential database issues:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Query performance&lt;/li&gt;
&lt;li&gt;High CPU utilization&lt;/li&gt;
&lt;li&gt;High Memory usage&lt;/li&gt;
&lt;li&gt;High Disk I/O&lt;/li&gt;
&lt;li&gt;User Connection&lt;/li&gt;
&lt;li&gt;Data growth&lt;/li&gt;
&lt;li&gt;Others&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let’s analyze each of them, and they will also answer your questions at the beginning.&lt;/p&gt;
&lt;h3 id="long-query-response-times"&gt;Long Query Response Times&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;PMM&lt;/strong&gt; helps you monitor the performance of individual queries and identify slow-performing queries that need to be optimized.
We can use &lt;a href="https://docs.percona.com/percona-monitoring-and-management/get-started/query-analytics.html" target="_blank" rel="noopener noreferrer"&gt;Query Analytics in PMM&lt;/a&gt; to visualize all the queries running in our database; we can inspect each of them and see which is the one sending more queries per second and much longer it takes to execute it. Also, &lt;strong&gt;PMM&lt;/strong&gt; will show you suggestions to fix or improve queries.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2023/03/02-long-query-response_hu_62a852a5133eca47.jpg 480w, https://percona.community/blog/2023/03/02-long-query-response_hu_c591c54cbe30a2db.jpg 768w, https://percona.community/blog/2023/03/02-long-query-response_hu_3267cec7f34660ea.jpg 1400w"
src="https://percona.community/blog/2023/03/02-long-query-response.jpg" alt="Long query Response" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h3 id="high-cpu-utilization"&gt;High CPU Utilization&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;PMM&lt;/strong&gt; helps you monitor the number of &lt;a href="https://docs.percona.com/percona-monitoring-and-management/details/dashboards/dashboard-cpu-utilization-details.html" target="_blank" rel="noopener noreferrer"&gt;CPU resources&lt;/a&gt; the database uses and identify performance bottlenecks.&lt;/p&gt;
&lt;p&gt;In the section on CPU utilization, you will see how much of your CPU is being used in a period of time. This is very useful when you need to increase your resources.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2023/03/03-high-cpu-utilization_hu_864290ce529632af.jpg 480w, https://percona.community/blog/2023/03/03-high-cpu-utilization_hu_db70c270db2c3c4b.jpg 768w, https://percona.community/blog/2023/03/03-high-cpu-utilization_hu_a3a8d6ea22fbef2e.jpg 1400w"
src="https://percona.community/blog/2023/03/03-high-cpu-utilization.jpg" alt="High Cpu Utilization" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h3 id="high-memory-usage"&gt;High Memory usage&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;PMM&lt;/strong&gt; helps you &lt;a href="https://docs.percona.com/percona-monitoring-and-management/details/dashboards/dashboard-memory-details.html" target="_blank" rel="noopener noreferrer"&gt;monitor the amount of memory&lt;/a&gt; being used by the database and determine if you need to add more memory or optimize your database configuration.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2023/03/04-high-memory-usage_hu_26bf5764a8cc862e.jpg 480w, https://percona.community/blog/2023/03/04-high-memory-usage_hu_44c022f77a424a53.jpg 768w, https://percona.community/blog/2023/03/04-high-memory-usage_hu_906f31d272252b92.jpg 1400w"
src="https://percona.community/blog/2023/03/04-high-memory-usage.jpg" alt="High Memory Usage" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h3 id="disk-io"&gt;Disk I/O&lt;/h3&gt;
&lt;p&gt;PMM helps you monitor the number of &lt;a href="https://docs.percona.com/percona-monitoring-and-management/details/dashboards/dashboard-disk-details.html" target="_blank" rel="noopener noreferrer"&gt;disk I/O operations&lt;/a&gt; performed by the database and identify any potential performance bottlenecks. See here the panel of Disk IO Latency!&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2023/03/05-disk-io_hu_4a27991163e403f1.jpg 480w, https://percona.community/blog/2023/03/05-disk-io_hu_7be04ca93c7a3e22.jpg 768w, https://percona.community/blog/2023/03/05-disk-io_hu_6ed179d2eea2cc2a.jpg 1400w"
src="https://percona.community/blog/2023/03/05-disk-io.jpg" alt="Disk Io" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h3 id="user-connections"&gt;User connections&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;PMM&lt;/strong&gt; helps you monitor the number of &lt;a href="https://docs.percona.com/percona-monitoring-and-management/details/dashboards/dashboard-mysql-user-details.html" target="_blank" rel="noopener noreferrer"&gt;active database connections&lt;/a&gt; and determine if your user connection is sized appropriately. If you limit the number of users that should connect to your database, this panel will show you when you are reaching that limit so that you can increase the number.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2023/03/06-user-conexion_hu_fbde4c457f6e6d56.jpg 480w, https://percona.community/blog/2023/03/06-user-conexion_hu_7077b7be7ebefd15.jpg 768w, https://percona.community/blog/2023/03/06-user-conexion_hu_2f45dabbef25cf92.jpg 1400w"
src="https://percona.community/blog/2023/03/06-user-conexion.jpg" alt="User Conexion" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h3 id="data-growth"&gt;Data growth&lt;/h3&gt;
&lt;p&gt;PMM helps you monitor &lt;a href="https://docs.percona.com/percona-monitoring-and-management/details/dashboards/dashboard-mysql-table-details.html" target="_blank" rel="noopener noreferrer"&gt;your database growth&lt;/a&gt; over time and plan for capacity and performance needs. This dashboard helps to see the time period in which your database is growing and to be able to learn about performance issues or issues as they occur.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2023/03/07-data-grown_hu_5c5fc49e74281736.jpg 480w, https://percona.community/blog/2023/03/07-data-grown_hu_6e0ef3cc7be596ed.jpg 768w, https://percona.community/blog/2023/03/07-data-grown_hu_e8ddf2f3e2ca5739.jpg 1400w"
src="https://percona.community/blog/2023/03/07-data-grown.jpg" alt="Data Grown" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h3 id="summary"&gt;Summary&lt;/h3&gt;
&lt;p&gt;We see the importance of monitoring databases and how to explore PMM for some essential metrics to detect issues and prevent them on time.&lt;/p&gt;
&lt;p&gt;Want to try PMM? We have a &lt;a href="https://pmmdemo.percona.com/graph/" target="_blank" rel="noopener noreferrer"&gt;test environment to try PMM&lt;/a&gt; without having to install it first. Feel free to play with it and see how PMM works. If you like it, you can &lt;a href="https://www.percona.com/software/pmm/quickstart" target="_blank" rel="noopener noreferrer"&gt;install PMM quickly and start using it in your own environment&lt;/a&gt;.&lt;/p&gt;</content:encoded>
      <author>Edith Puclla</author>
      <category>Monitor</category>
      <category>PMM</category>
      <category>Databases</category>
      <category>Open Source</category>
      <media:thumbnail url="https://percona.community/blog/2023/03/00-moni-cover_hu_bac40403f6d5c7ee.jpg"/>
      <media:content url="https://percona.community/blog/2023/03/00-moni-cover_hu_723ac9c5f153c5a1.jpg" medium="image"/>
    </item>
    <item>
      <title>Exploring Databases on Containers with Percona Server for MySQL</title>
      <link>https://percona.community/blog/2023/02/23/exploring-databases-on-containers-with-mysql/</link>
      <guid>https://percona.community/blog/2023/02/23/exploring-databases-on-containers-with-mysql/</guid>
      <pubDate>Thu, 23 Feb 2023 00:00:00 UTC</pubDate>
      <description>In this blog, we will explore databases on containers. We will use Docker as a container engine tool and Percona Server for MySQL as a database administration tool. Both are open source tools.</description>
      <content:encoded>&lt;p&gt;In this blog, we will explore databases on containers. We will use Docker as a container engine tool and &lt;a href="https://www.percona.com/software/mysql-database/percona-server" target="_blank" rel="noopener noreferrer"&gt;Percona Server for MySQL&lt;/a&gt; as a database administration tool. Both are open source tools.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;MySQL&lt;/strong&gt; is a relational database management system that stores data on disk. Percona Server for &lt;strong&gt;MySQL&lt;/strong&gt; is a fork of MYSQL, providing much more advanced features. To run it correctly, we need to know volumes because we want to “persist” the data, the most important thing in databases.&lt;/p&gt;
&lt;h2 id="running-a-single-percona-server-for-mysql-container"&gt;Running a single Percona Server for MySQL container&lt;/h2&gt;
&lt;p&gt;First, let’s create a container without volumes:&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2023/02/1-volume_hu_7c2971b9d8f8b858.png 480w, https://percona.community/blog/2023/02/1-volume_hu_c18f7cb63cd443b3.png 768w, https://percona.community/blog/2023/02/1-volume_hu_f342c14e99bb50bd.png 1400w"
src="https://percona.community/blog/2023/02/1-volume.png" alt="1-no-volume" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Figure 1: From Percona Server for MySQL image to a running container in Docker&lt;/p&gt;
&lt;p&gt;The following command will create a container called percona-server-1, where we can create databases and add some data.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker run -d --name percona-server-1 -e &lt;span class="nv"&gt;MYSQL_ROOT_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;root percona/percona-server:8.0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Listing the image and the container:
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2023/02/2-ls_hu_de414575bf8202f4.png 480w, https://percona.community/blog/2023/02/2-ls_hu_75b0710387e86d0.png 768w, https://percona.community/blog/2023/02/2-ls_hu_bf400be65ca46ef9.png 1400w"
src="https://percona.community/blog/2023/02/2-ls.png" alt="2-ls" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;After the container is created:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We have our base image, which is &lt;strong&gt;percona/percona-server:8.0&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;The base image in Docker is read-only. We can’t modify it. It allows you to spin up multiple containers from the same image with the same immutable base.&lt;/li&gt;
&lt;li&gt;We can add data to our image. This new layer is readable and writable.
If we create our database and populate it:&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Accessing the detached container:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-1"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; -it percona-server-1 /bin/bash&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Connecting to the database&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-2" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-2"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mysql -uroot -proot&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Create a Database “cinema” and use it&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-3" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-3"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;CREATE DATABASE cinema&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;USE cinema&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Create table movies in Database “cinema”&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-4" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-4"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;CREATE TABLE movies &lt;span class="o"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;book_id BIGINT PRIMARY KEY AUTO_INCREMENT,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;title VARCHAR&lt;span class="o"&gt;(&lt;/span&gt;100&lt;span class="o"&gt;)&lt;/span&gt; UNIQUE NOT NULL,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;publisher VARCHAR&lt;span class="o"&gt;(&lt;/span&gt;100&lt;span class="o"&gt;)&lt;/span&gt; NOT NULL,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;labels JSON NOT NULL
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;ENGINE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; InnoDB&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Insert data into Database “cinema”&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-5" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-5"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INTO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;movies&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;publisher&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="k"&gt;VALUES&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="n"&gt;Green&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;House&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="n"&gt;Joe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Monter&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;’{“&lt;/span&gt;&lt;span class="n"&gt;about&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;{“&lt;/span&gt;&lt;span class="n"&gt;gender&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="n"&gt;cool&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="n"&gt;notes&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="n"&gt;labeled&lt;/span&gt;&lt;span class="err"&gt;”}}’&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Checking table&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-6" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-6"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;select&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;movies&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;If you delete this container, everything will be deleted, too, your databases and your data because containers are temporary.
&lt;figure&gt;&lt;img src="https://percona.community/blog/2023/02/3-image-no-volume.png" alt="3-image-no-volume" /&gt;&lt;/figure&gt;
Figure 2: View of the layers that are generated when we create the container. Source: Severalnines AB&lt;/p&gt;
&lt;h2 id="running-multiple-mysql-containers"&gt;Running Multiple MySQL Containers&lt;/h2&gt;
&lt;p&gt;Now let’s see how the layers of two different containers work together.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-7" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-7"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker run -d --name percona-server-1 -e &lt;span class="nv"&gt;MYSQL_ROOT_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;root percona/percona-server:8.0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-8" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-8"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker run -d --name percona-server-2 -e &lt;span class="nv"&gt;MYSQL_ROOT_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;root percona/percona-server:8.0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Multiple containers can share the same base image, which is read-only. Each container can have its data state for reading and writing (Which is built on the top of the base image), but this state will be lost if we don’t create persistent volumes that can ve saved after the container is shut down.
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2023/02/4-image-multiple-sql_hu_5b5689c245419b36.png 480w, https://percona.community/blog/2023/02/4-image-multiple-sql_hu_1c2329af4b746da4.png 768w, https://percona.community/blog/2023/02/4-image-multiple-sql_hu_254369876d9745e7.png 1400w"
src="https://percona.community/blog/2023/02/4-image-multiple-sql.png" alt="4-image-multiple-sql.png" /&gt;&lt;/figure&gt;
Figure 3: View the layers generated when we create two different containers. Source: Severalnines AB&lt;/p&gt;
&lt;p&gt;As we said before, “Volumes open the door for stateful applications to run efficiently in Docker.”&lt;/p&gt;
&lt;h2 id="running-containers-with-persistent-volumes"&gt;Running containers with Persistent Volumes&lt;/h2&gt;
&lt;p&gt;Now we will create a container with a persistent volume in Docker.
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2023/02/5-no-volume_hu_ad7a1b2379229cf9.png 480w, https://percona.community/blog/2023/02/5-no-volume_hu_101c56ebf8822b3a.png 768w, https://percona.community/blog/2023/02/5-no-volume_hu_bb2f91ebe61513c1.png 1400w"
src="https://percona.community/blog/2023/02/5-no-volume.png" alt="5-image-volume" /&gt;&lt;/figure&gt;
Figure 4: From Percona Server for MySQL image to a running container in Docker with volumes&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;percona-server&lt;/strong&gt; is the base of the image. On top of that, we have all the changes we will make in the database. When we create the volume, we link a directory in the container with a directory on your local machine or in the machine where you want to persist the data.
When you delete the container, you can attach another container to this volume to have the same data on a different container.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-9" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-9"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker run -d --name percona-server -e &lt;span class="nv"&gt;MYSQL_ROOT_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;root -v local-datadir:/var/lib/mysql percona/percona-server:8.0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2023/02/6-image-volume_hu_3cdcfe2f40298fae.png 480w, https://percona.community/blog/2023/02/6-image-volume_hu_931ff76363437249.png 768w, https://percona.community/blog/2023/02/6-image-volume_hu_5505923f1bc291ac.png 1400w"
src="https://percona.community/blog/2023/02/6-image-volume.png" alt="6-image-volume" /&gt;&lt;/figure&gt;
Figure 4: View of the layers that are generated when we create the container with volume.&lt;/p&gt;
&lt;h2 id="backing-up-and-restroring-databases"&gt;Backing up and restroring databases&lt;/h2&gt;
&lt;p&gt;There are two kinds of backups in databases, logical and physical backups.
We can use mysqldump to make logical backups and Percona XtraBackup, for physical backups. If we want to restore, we can use mysqldump and Percona XtraBackup, which offer much more advanced features.&lt;/p&gt;
&lt;h2 id="back-up"&gt;Back up&lt;/h2&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-10" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-10"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; -it percona-server-backup mysqldump -uroot --password&lt;span class="o"&gt;=&lt;/span&gt;root --single-transaction &gt; /path/in/physical/host/dump.sql&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="restore"&gt;Restore&lt;/h2&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-11" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-11"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; -it percona-server-restore mysql -u root --password&lt;span class="o"&gt;=&lt;/span&gt;root &lt; /path/in/physical/host/dump.sql&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Now let’s share some tips to run databases on containers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Constantly monitor your database and host system&lt;/li&gt;
&lt;li&gt;Store data in a persistent volume outside the container&lt;/li&gt;
&lt;li&gt;Limit resource utilization, e.g., Memory, CPU&lt;/li&gt;
&lt;li&gt;Regularly back up the database and store the backup in a secure and separate location.&lt;/li&gt;
&lt;li&gt;Have a plan for database migrations and disaster recovery.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We explored how databases work on containers. Volumes are the important thing to persist the data.&lt;/p&gt;
&lt;p&gt;What is next? Watch this fantastic talk by Peter Zaitsev &lt;a href="https://www.youtube.com/watch?v=b_COgWA1lvk&amp;t=145s" target="_blank" rel="noopener noreferrer"&gt;Open Source Databases on Kubernetes&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Thanks for reading this! You can install Percona Server for MySQL from our &lt;a href="https://hub.docker.com/r/percona/percona-server/tags??utm_source=percona-community&amp;utm_medium=blog&amp;utm_campaign=edith" target="_blank" rel="noopener noreferrer"&gt;Docker Repository&lt;/a&gt; and if you have doubts write us in our &lt;a href="https://forums.percona.com/?utm_source=percona-community&amp;utm_medium=blog&amp;utm_campaign=edith" target="_blank" rel="noopener noreferrer"&gt;Percona community forum&lt;/a&gt;.&lt;/p&gt;</content:encoded>
      <author>Edith Puclla</author>
      <category>Docker</category>
      <category>MySQL</category>
      <category>Volume</category>
      <media:thumbnail url="https://percona.community/blog/2023/02/0-cover_hu_595fd28de0de994b.jpg"/>
      <media:content url="https://percona.community/blog/2023/02/0-cover_hu_ac452a760a367ffb.jpg" medium="image"/>
    </item>
    <item>
      <title>Percona Monitoring and Management 2.35 preview release</title>
      <link>https://percona.community/blog/2023/02/14/preview-release/</link>
      <guid>https://percona.community/blog/2023/02/14/preview-release/</guid>
      <pubDate>Tue, 14 Feb 2023 00:00:00 UTC</pubDate>
      <description>Percona Monitoring and Management 2.35 preview release Hello folks! Percona Monitoring and Management (PMM) 2.35 is now available as a preview release.</description>
      <content:encoded>&lt;h2 id="percona-monitoring-and-management-235-preview-release"&gt;Percona Monitoring and Management 2.35 preview release&lt;/h2&gt;
&lt;p&gt;Hello folks! Percona Monitoring and Management (PMM) 2.35 is now available as a preview release.&lt;/p&gt;
&lt;p&gt;We encourage you to try this PMM preview release in &lt;strong&gt;testing environments only&lt;/strong&gt;, as these packages and images are not fully production-ready. The final version is expected to be released through the standard channels in the coming week.&lt;/p&gt;
&lt;p&gt;You can find the Release Notes &lt;a href="https://two-34-0-pr-977.onrender.com/release-notes/2.35.0.html" target="_blank" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="percona-monitoring-and-management-server-docker-installation"&gt;Percona Monitoring and Management server docker installation&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://docs.percona.com/percona-monitoring-and-management/setting-up/server/docker.html" target="_blank" rel="noopener noreferrer"&gt;Instructions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;docker tag:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;perconalab/pmm-server:2.35.0-rc&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; In order to use the DBaaS functionality during the Percona Monitoring and Management preview release, you should add the following environment variablewhen starting PMM server:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;PERCONA_TEST_DBAAS_PMM_CLIENT=perconalab/pmm-client:2.35.0-rc&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="percona-monitoring-and-management-client-package-installation"&gt;Percona Monitoring and Management client package installation&lt;/h3&gt;
&lt;p&gt;Download the latest pmm2-client release candidate tarball for 2.35 by this &lt;a href="https://s3.us-east-2.amazonaws.com/pmm-build-cache/PR-BUILDS/pmm2-client/pmm2-client-latest-4898.tar.gz" target="_blank" rel="noopener noreferrer"&gt;link&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you want to install pmm2-client package, please enable testing repository via Percona-release:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;percona-release enable percona testing&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;install pmm2-client package for your OS via package manager.&lt;/p&gt;
&lt;h3 id="ova"&gt;OVA&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://docs.percona.com/percona-monitoring-and-management/setting-up/server/virtual-appliance.html" target="_blank" rel="noopener noreferrer"&gt;Instructions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://percona-vm.s3.amazonaws.com/PMM2-Server-2.35.0.ova" target="_blank" rel="noopener noreferrer"&gt;PMM2-Server-2.35.0.ova&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="ami"&gt;AMI&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://docs.percona.com/percona-monitoring-and-management/setting-up/server/aws.html" target="_blank" rel="noopener noreferrer"&gt;Instructions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ami-09d19be2cfb10a60c&lt;/code&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Contact us in &lt;a href="https://forums.percona.com/" target="_blank" rel="noopener noreferrer"&gt;https://forums.percona.com/&lt;/a&gt;.&lt;/p&gt;</content:encoded>
      <author>Taras Kozub</author>
      <category>PMM</category>
      <category>Releases</category>
      <media:thumbnail url="https://percona.community/superhero_hu_252fc2b480c0a197.jpg"/>
      <media:content url="https://percona.community/superhero_hu_17979f11d5d3562e.jpg" medium="image"/>
    </item>
    <item>
      <title>Binding your application to the database in the Kubernetes cluster</title>
      <link>https://percona.community/blog/2023/01/24/k8s-app-db-binding/</link>
      <guid>https://percona.community/blog/2023/01/24/k8s-app-db-binding/</guid>
      <pubDate>Tue, 24 Jan 2023 00:00:00 UTC</pubDate>
      <description>dbaas-operator is Yet Another DBaaS Kubernetes Operator (need to suggest yadbko as a name) that tries to simplify and unify Database Cluster deployments by building a higher abstraction layer on top of Percona Kubernetes Operators.</description>
      <content:encoded>&lt;p&gt;&lt;a href="https://github.com/percona/dbaas-operator" target="_blank" rel="noopener noreferrer"&gt;dbaas-operator&lt;/a&gt; is Yet Another DBaaS Kubernetes Operator (need to suggest yadbko as a name) that tries to simplify and unify Database Cluster deployments by building a higher abstraction layer on top of &lt;a href="https://www.percona.com/software/percona-kubernetes-operators" target="_blank" rel="noopener noreferrer"&gt;Percona Kubernetes Operators&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So it becomes much easier to deploy the DB cluster with &lt;code&gt;dbaas-operator&lt;/code&gt; and &lt;a href="https://docs.percona.com/percona-monitoring-and-management/get-started/dbaas.html" target="_blank" rel="noopener noreferrer"&gt;PMM DBaaS&lt;/a&gt; on top of it.&lt;/p&gt;
&lt;p&gt;But another part of the picture is applications and their workloads to connect to the deployed DB Clusters.&lt;/p&gt;
&lt;h2 id="services-and-applications"&gt;Services and Applications&lt;/h2&gt;
&lt;p&gt;On Kubernetes, application deployment could be done in many ways, either manually or as part of automatic deployments.&lt;/p&gt;
&lt;p&gt;PMM DBaaS offers both - UI to create DB Clusters and get credentials and API to automate those actions.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;dbaas-operator&lt;/code&gt; adds Kubernetes native API to that batch as well.&lt;/p&gt;
&lt;p&gt;But both require additional automation to join the application and the database in one deployment and provide a service to the end user.&lt;/p&gt;
&lt;p&gt;And that operation is a challenging task, as every application could expect credentials in some specific format: secrets with hardcoded structures, environment variables with custom names, mount point secrets in particular locations, etc.&lt;/p&gt;
&lt;p&gt;Database services add their complexity to that picture by exposing their connections and secrets in a format that is convenient or makes sense for them.&lt;/p&gt;
&lt;p&gt;Usually, some Continues Delivery system or deployment package (helm, etc.) ensures all components’ correct deployment sequence and health. So many custom pipelines and packages exist to connect a specific application to a database service.&lt;/p&gt;
&lt;p&gt;But for simplicity and scalability, it would be nice to have some standard for connection or software that automates such a connection.&lt;/p&gt;
&lt;h2 id="service-binding"&gt;Service Binding&lt;/h2&gt;
&lt;p&gt;Connecting services is a known pattern: Service Discovery (broker, registry, repository) for the &lt;a href="https://en.wikipedia.org/wiki/Service-oriented_architecture" target="_blank" rel="noopener noreferrer"&gt;Service-Oriented Architecture&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://servicebinding.io/" target="_blank" rel="noopener noreferrer"&gt;servicebinding.io&lt;/a&gt; is another pattern to bind applications and workloads to the services (REST APIs, databases, event buses, etc.). This specification aims to create a Kubernetes-wide specification for communicating service secrets to workloads in a consistent way.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://redhat-developer.github.io/service-binding-operator/userguide/intro.html" target="_blank" rel="noopener noreferrer"&gt;Service Binding Operator&lt;/a&gt; glues services and Kubernetes workflows together. It does so for the services and applications that support ServiceBinding specifications and those that don’t.&lt;/p&gt;
&lt;p&gt;Out of the box Service Binding Operator supports &lt;a href="https://docs.percona.com/percona-operator-for-mysql/pxc/index.html" target="_blank" rel="noopener noreferrer"&gt;Percona Operator for MySQL based on Percona XtraDB Cluster&lt;/a&gt; (PXC), so we will deploy Database Cluster with &lt;code&gt;dbaas-operator&lt;/code&gt; and connect it to the simple Java application. We will use Spring PetClinic application that supports &lt;a href="https://github.com/spring-cloud/spring-cloud-bindings" target="_blank" rel="noopener noreferrer"&gt;Spring Cloud Bindings&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="create-an-environment"&gt;Create an environment&lt;/h2&gt;
&lt;p&gt;We need to have Kubernetes cluster, &lt;a href="https://olm.operatorframework.io/" target="_blank" rel="noopener noreferrer"&gt;Operator Lifecycle Manager&lt;/a&gt; (OLM) to install operators, and all required operators installed. In this blog, I would use minikube and assume that &lt;code&gt;operator-sdk&lt;/code&gt; is installed on the system&lt;/p&gt;
&lt;p&gt;Here is a &lt;a href="https://github.com/denisok/k8s-connect-app-to-db/blob/main/assets/bin/service_binding.sh" target="_blank" rel="noopener noreferrer"&gt;link to the script&lt;/a&gt; that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;setups multi-node Kubernetes cluster&lt;/li&gt;
&lt;li&gt;installs OLM&lt;/li&gt;
&lt;li&gt;installs needed operators with the help of OLM&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As a result we get cluster with all needed operators:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sh&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ kubectl get sub -A
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NAMESPACE NAME PACKAGE SOURCE CHANNEL
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;default dbaas-operator dbaas-operator dbaas-catalog stable-v0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;default percona-server-mongodb-operator percona-server-mongodb-operator dbaas-catalog stable-v1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;default percona-xtradb-cluster-operator percona-xtradb-cluster-operator dbaas-catalog stable-v1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;operators my-service-binding-operator service-binding-operator operatorhubio-catalog stable&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="create-database-cluster"&gt;Create Database Cluster&lt;/h2&gt;
&lt;p&gt;We will use &lt;code&gt;dbaas-operator&lt;/code&gt; to demonstrate how easy it is to create DB Cluster with it:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sh&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-1"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ cat &lt;span class="s"&gt;&lt;&lt;EOF | kubectl apply -f -
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;apiVersion: dbaas.percona.com/v1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;kind: DatabaseCluster
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;metadata:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; name: test-pxc-cluster
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;spec:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; databaseType: pxc
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; databaseImage: percona/percona-xtradb-cluster:8.0.27-18.1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; databaseConfig: |
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; [mysqld]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; wsrep_provider_options="debug=1;gcache.size=1G"
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; wsrep_debug=1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; wsrep_trx_fragment_unit='bytes'
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; wsrep_trx_fragment_size=3670016
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; secretsName: pxc-sample-secrets
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; clusterSize: 1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; loadBalancer:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; type: haproxy
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; exposeType: ClusterIP
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; size: 1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; image: percona/percona-xtradb-cluster-operator:1.11.0-haproxy
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; dbInstance:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; cpu: "1"
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; memory: 1G
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; diskSize: 15G
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ kubectl get db
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NAME SIZE READY STATUS ENDPOINT AGE
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;test-pxc-cluster &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; ready test-pxc-cluster-haproxy.default 5m&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="create-spring-petclinic-app-and-bind-it-to-the-database"&gt;Create Spring PetClinic app and bind it to the database&lt;/h2&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sh&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-2" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-2"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ kubectl apply -f https://raw.githubusercontent.com/redhat-developer/service-binding-operator/master/samples/apps/spring-petclinic/petclinic-mysql-deployment.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;deployment.apps/spring-petclinic created
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;service/spring-petclinic created
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ kubectl get pods
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NAME READY STATUS RESTARTS AGE
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;spring-petclinic-f7f587c5c-rvq2v 0/1 CrashLoopBackOff &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;17s ago&lt;span class="o"&gt;)&lt;/span&gt; 67s&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;As we didn’t create a binding yet, the application can’t connect to the database and thus fails.&lt;/p&gt;
&lt;p&gt;Let us bind application to the database and verify it is working:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sh&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-3" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-3"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ cat &lt;span class="s"&gt;&lt;&lt;EOF | kubectl apply -f -
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;apiVersion: binding.operators.coreos.com/v1alpha1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;kind: ServiceBinding
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;metadata:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; name: spring-petclinic
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; namespace: default
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;spec:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; services:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; - group: pxc.percona.com
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; version: v1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; kind: PerconaXtraDBCluster
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; name: test-pxc-cluster
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; application:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; name: spring-petclinic
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; group: apps
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; version: v1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; resource: deployments
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ kubectl get servicebindings
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NAME READY REASON AGE
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;spring-petclinic True ApplicationsBound 4m47s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ kubectl get deployments
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NAME READY UP-TO-DATE AVAILABLE AGE
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;spring-petclinic 1/1 &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; 17m
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ minikube service spring-petclinic --url
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;http://192.168.39.215:31181&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;What we have done above:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Created &lt;code&gt;kind: ServiceBinding&lt;/code&gt;, which takes PXC secrets and maps them to the application as mount points.&lt;/li&gt;
&lt;li&gt;As PetClinic supports ServiceBinding spec with Spring framework, it understands those mount points and connects to the database.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Here is what mount point by ServiceBinding specification that Spring Cloud Bindings library parsed and connected to the database:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sh&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-4" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-4"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; deployment/spring-petclinic -- ls -la /bindings/spring-petclinic/..2023_01_20_21_33_47.4121788695
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;total &lt;span class="m"&gt;56&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;drwxr-xr-x &lt;span class="m"&gt;2&lt;/span&gt; root root &lt;span class="m"&gt;320&lt;/span&gt; Jan &lt;span class="m"&gt;20&lt;/span&gt; 21:33 .
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;drwxrwxrwt &lt;span class="m"&gt;3&lt;/span&gt; root root &lt;span class="m"&gt;360&lt;/span&gt; Jan &lt;span class="m"&gt;20&lt;/span&gt; 21:33 ..
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-rw-r--r-- &lt;span class="m"&gt;1&lt;/span&gt; root root &lt;span class="m"&gt;18&lt;/span&gt; Jan &lt;span class="m"&gt;20&lt;/span&gt; 21:33 clustercheck
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-rw-r--r-- &lt;span class="m"&gt;1&lt;/span&gt; root root &lt;span class="m"&gt;5&lt;/span&gt; Jan &lt;span class="m"&gt;20&lt;/span&gt; 21:33 database
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-rw-r--r-- &lt;span class="m"&gt;1&lt;/span&gt; root root &lt;span class="m"&gt;32&lt;/span&gt; Jan &lt;span class="m"&gt;20&lt;/span&gt; 21:33 host
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-rw-r--r-- &lt;span class="m"&gt;1&lt;/span&gt; root root &lt;span class="m"&gt;17&lt;/span&gt; Jan &lt;span class="m"&gt;20&lt;/span&gt; 21:33 monitor
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-rw-r--r-- &lt;span class="m"&gt;1&lt;/span&gt; root root &lt;span class="m"&gt;17&lt;/span&gt; Jan &lt;span class="m"&gt;20&lt;/span&gt; 21:33 operator
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-rw-r--r-- &lt;span class="m"&gt;1&lt;/span&gt; root root &lt;span class="m"&gt;18&lt;/span&gt; Jan &lt;span class="m"&gt;20&lt;/span&gt; 21:33 password
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-rw-r--r-- &lt;span class="m"&gt;1&lt;/span&gt; root root &lt;span class="m"&gt;4&lt;/span&gt; Jan &lt;span class="m"&gt;20&lt;/span&gt; 21:33 port
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-rw-r--r-- &lt;span class="m"&gt;1&lt;/span&gt; root root &lt;span class="m"&gt;7&lt;/span&gt; Jan &lt;span class="m"&gt;20&lt;/span&gt; 21:33 provider
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-rw-r--r-- &lt;span class="m"&gt;1&lt;/span&gt; root root &lt;span class="m"&gt;17&lt;/span&gt; Jan &lt;span class="m"&gt;20&lt;/span&gt; 21:33 proxyadmin
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-rw-r--r-- &lt;span class="m"&gt;1&lt;/span&gt; root root &lt;span class="m"&gt;18&lt;/span&gt; Jan &lt;span class="m"&gt;20&lt;/span&gt; 21:33 replication
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-rw-r--r-- &lt;span class="m"&gt;1&lt;/span&gt; root root &lt;span class="m"&gt;18&lt;/span&gt; Jan &lt;span class="m"&gt;20&lt;/span&gt; 21:33 root
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-rw-r--r-- &lt;span class="m"&gt;1&lt;/span&gt; root root &lt;span class="m"&gt;5&lt;/span&gt; Jan &lt;span class="m"&gt;20&lt;/span&gt; 21:33 &lt;span class="nb"&gt;type&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-rw-r--r-- &lt;span class="m"&gt;1&lt;/span&gt; root root &lt;span class="m"&gt;4&lt;/span&gt; Jan &lt;span class="m"&gt;20&lt;/span&gt; 21:33 username
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-rw-r--r-- &lt;span class="m"&gt;1&lt;/span&gt; root root &lt;span class="m"&gt;17&lt;/span&gt; Jan &lt;span class="m"&gt;20&lt;/span&gt; 21:33 xtrabackup
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; deployment/spring-petclinic -- cat /bindings/spring-petclinic/..2023_01_20_21_33_47.4121788695/database
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mysql
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; deployment/spring-petclinic -- cat /bindings/spring-petclinic/..2023_01_20_21_33_47.4121788695/host
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;test-pxc-cluster-haproxy.default&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Check the url that was exposed by minikube:&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2023/02/petclinic_hu_141342c1c5d61197.png 480w, https://percona.community/blog/2023/02/petclinic_hu_bba157abaa156f1e.png 768w, https://percona.community/blog/2023/02/petclinic_hu_e045fca286d3aa54.png 1400w"
src="https://percona.community/blog/2023/02/petclinic.png" alt="Pet Clinic" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h2 id="summary"&gt;Summary&lt;/h2&gt;
&lt;p&gt;There are many ways to deploy applications and services and connect them.&lt;/p&gt;
&lt;p&gt;I am trying to collect some of them under my &lt;a href="https://github.com/denisok/k8s-connect-app-to-db" target="_blank" rel="noopener noreferrer"&gt;personal repo&lt;/a&gt; to understand the problem deeper. Please suggest other ways by commenting under this blog or in repo.&lt;/p&gt;
&lt;p&gt;ServiceBinding specification is a standardized way that scales easily and allows you to connect Kubernetes workloads to the database services.&lt;/p&gt;
&lt;p&gt;I will propose to &lt;code&gt;dbaas-operator&lt;/code&gt; to implement that specification so that it could expose different Database engines (mysql, mongo, pg) in a standard way.&lt;/p&gt;</content:encoded>
      <author>Denys Kondratenko</author>
      <category>Labs</category>
      <category>Kubernetes</category>
      <category>Operators</category>
      <category>Databases</category>
      <category>PMM</category>
      <category>DBaaS</category>
      <category>Minikube</category>
      <media:thumbnail url="https://percona.community/blog/2023/02/petclinic_hu_1a8d4824c10dfb88.jpg"/>
      <media:content url="https://percona.community/blog/2023/02/petclinic_hu_a952755f21de9430.jpg" medium="image"/>
    </item>
    <item>
      <title>Percona Monitoring and Management 2.34 preview release</title>
      <link>https://percona.community/blog/2023/01/17/preview-release/</link>
      <guid>https://percona.community/blog/2023/01/17/preview-release/</guid>
      <pubDate>Tue, 17 Jan 2023 00:00:00 UTC</pubDate>
      <description>Percona Monitoring and Management 2.34 preview release Hello folks! Percona Monitoring and Management (PMM) 2.34 is now available as a preview release.</description>
      <content:encoded>&lt;h2 id="percona-monitoring-and-management-234-preview-release"&gt;Percona Monitoring and Management 2.34 preview release&lt;/h2&gt;
&lt;p&gt;Hello folks! Percona Monitoring and Management (PMM) 2.34 is now available as a preview release.&lt;/p&gt;
&lt;p&gt;We encourage you to try this PMM preview release in &lt;strong&gt;testing environments only&lt;/strong&gt;, as these packages and images are not fully production-ready. The final version is expected to be released through the standard channels in the coming week.&lt;/p&gt;
&lt;p&gt;You can find the Release Notes &lt;a href="https://two-34-0-pr-954.onrender.com/release-notes/2.34.0.html" target="_blank" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="percona-monitoring-and-management-server-docker-installation"&gt;Percona Monitoring and Management server docker installation&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://docs.percona.com/percona-monitoring-and-management/setting-up/server/docker.html" target="_blank" rel="noopener noreferrer"&gt;Instructions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;docker tag:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;perconalab/pmm-server:2.34.0-rc&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; In order to use the DBaaS functionality during the Percona Monitoring and Management preview release, you should add the following environment variablewhen starting PMM server:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;PERCONA_TEST_DBAAS_PMM_CLIENT=perconalab/pmm-client:2.34.0-rc&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="percona-monitoring-and-management-client-package-installation"&gt;Percona Monitoring and Management client package installation&lt;/h3&gt;
&lt;p&gt;Download the latest pmm2-client release candidate tarball for 2.34 by this &lt;a href="https://s3.us-east-2.amazonaws.com/pmm-build-cache/PR-BUILDS/pmm2-client/pmm2-client-latest-4747.tar.gz" target="_blank" rel="noopener noreferrer"&gt;link&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you want to install pmm2-client package, please enable testing repository via Percona-release:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;percona-release enable percona testing&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;install pmm2-client package for your OS via package manager.&lt;/p&gt;
&lt;h3 id="ova"&gt;OVA&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://docs.percona.com/percona-monitoring-and-management/setting-up/server/virtual-appliance.html" target="_blank" rel="noopener noreferrer"&gt;Instructions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://percona-vm.s3.amazonaws.com/PMM2-Server-2.34.0.ova" target="_blank" rel="noopener noreferrer"&gt;PMM2-Server-2.34.0.ova&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="ami"&gt;AMI&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://docs.percona.com/percona-monitoring-and-management/setting-up/server/aws.html" target="_blank" rel="noopener noreferrer"&gt;Instructions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ami-08c09a75c3dd22956&lt;/code&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Contact us in &lt;a href="https://forums.percona.com/" target="_blank" rel="noopener noreferrer"&gt;https://forums.percona.com/&lt;/a&gt;.&lt;/p&gt;</content:encoded>
      <author>Taras Kozub</author>
      <category>PMM</category>
      <category>Releases</category>
      <media:thumbnail url="https://percona.community/superhero_hu_252fc2b480c0a197.jpg"/>
      <media:content url="https://percona.community/superhero_hu_17979f11d5d3562e.jpg" medium="image"/>
    </item>
    <item>
      <title>Setting Up PMM For Monitoring Your Databases on Windows</title>
      <link>https://percona.community/blog/2023/01/16/setting-up-pmm-for-monitoring-your-databases-on-windows/</link>
      <guid>https://percona.community/blog/2023/01/16/setting-up-pmm-for-monitoring-your-databases-on-windows/</guid>
      <pubDate>Mon, 16 Jan 2023 00:00:00 UTC</pubDate>
      <description>Before deploying Percona Monitoring and Management (PMM) in production, you might want to test it or set up a development instance locally. Since many developers and DBAs have Windows desktops, I wanted to demonstrate how to set up PMM on Windows for an easy test environment. In this post, I’ll walk you through setting up PMM with Docker and WSL.</description>
      <content:encoded>&lt;p&gt;Before deploying Percona Monitoring and Management (PMM) in production, you might want to test it or set up a development instance locally. Since many developers and DBAs have Windows desktops, I wanted to demonstrate how to set up PMM on Windows for an easy test environment. In this post, I’ll walk you through setting up PMM with Docker and WSL.&lt;/p&gt;
&lt;p&gt;If you’re a Linux user, check the blog post I wrote on &lt;a href="https://percona.community/blog/2022/08/05/setting-up-pmm-for-monitoring-mysql-on-a-local-environment/" target="_blank" rel="noopener noreferrer"&gt;Setting up PMM for monitoring MySQL in a local environment&lt;/a&gt;. There you can find instructions for installing Percona Monitoring and Management (PMM) on Linux and how to set it up for monitoring a MySQL instance. Otherwise, continue reading to get PMM up and running on Windows.&lt;/p&gt;
&lt;h2 id="getting-started-with-pmm-on-windows"&gt;Getting Started With PMM on Windows&lt;/h2&gt;
&lt;p&gt;If you’re a Windows user and want to try PMM, the recommended way for installing both the server and client would be to use the official Docker images and follow these guides:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.percona.com/percona-monitoring-and-management/setting-up/server/docker.html" target="_blank" rel="noopener noreferrer"&gt;Server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.percona.com/percona-monitoring-and-management/setting-up/client/index.html#docker" target="_blank" rel="noopener noreferrer"&gt;Client&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Before running the commands in those guides, you should install Docker Desktop and Windows Subsystem for Linux (WSL). These instructions should work for users who are on current versions of Windows 10 and Windows 11. For installing WSL, follow the &lt;a href="https://learn.microsoft.com/en-us/windows/wsl/install" target="_blank" rel="noopener noreferrer"&gt;instructions&lt;/a&gt; on the Microsoft Learn website. Then, get the &lt;a href="https://docs.docker.com/get-docker/" target="_blank" rel="noopener noreferrer"&gt;Docker Desktop&lt;/a&gt; installer. Now you’re ready to install and configure PMM.&lt;/p&gt;
&lt;h2 id="pmm-server"&gt;PMM Server&lt;/h2&gt;
&lt;p&gt;As stated in the &lt;a href="https://docs.percona.com/percona-monitoring-and-management/setting-up/server/docker.html" target="_blank" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;, you can store data from your PMM in:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Docker volume (Preferred method)&lt;/li&gt;
&lt;li&gt;Data container&lt;/li&gt;
&lt;li&gt;Host directory&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The preferred method is also recommended for Windows. Open PowerShell and execute the instructions in the &lt;a href="https://docs.percona.com/percona-monitoring-and-management/setting-up/server/docker.html#run-docker-with-volume" target="_blank" rel="noopener noreferrer"&gt;Run Docker with volume&lt;/a&gt; section. I’ve reproduced the steps here to save you time:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Get the Docker image:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ docker pull percona/pmm-server:2&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ol start="2"&gt;
&lt;li&gt;Create a volume:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-1"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ docker volume create pmm-data&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ol start="3"&gt;
&lt;li&gt;Run the image:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-2" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-2"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ docker run --detach --restart always \
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;--publish 443:443 \
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-v pmm-data:/srv \
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;--name pmm-server \
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;percona/pmm-server:2&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ol start="4"&gt;
&lt;li&gt;Change the password for the default &lt;code&gt;admin&lt;/code&gt; user:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-3" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-3"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ docker &lt;span class="nb"&gt;exec&lt;/span&gt; -t pmm-server change-admin-password &lt;new_password&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Once PMM Server is installed, open the browser and visit https://localhost. You will see the PMM login screen.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2023/01/pmm-login-screen_hu_56ea1277e5f7c4b7.png 480w, https://percona.community/blog/2023/01/pmm-login-screen_hu_75ec84a085ea39ca.png 768w, https://percona.community/blog/2023/01/pmm-login-screen_hu_b889a7e009f52ded.png 1400w"
src="https://percona.community/blog/2023/01/pmm-login-screen.png" alt="PMM Login Screen" /&gt;&lt;figcaption&gt;PMM Login Screen&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Now that the server is up and running, you need to get its IP address before connecting the client to the server. To get the IP address, you need the name or container ID. You can get it by running:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-4" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-4"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ docker ps&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;docker ps&lt;/code&gt; command will give you a list of the containers running on your system, as follows:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-5" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-5"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;fd988ad761aa percona/pmm-server:2 "/opt/entrypoint.sh" 2 months ago Up 11 minutes (healthy) 80/tcp, 0.0.0.0:443-&gt;443/tcp pmm-server&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Take note of the container ID or name of the PMM Server container. Then, execute this command:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-6" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-6"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' your_container&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Replacing &lt;code&gt;your_container&lt;/code&gt; with the container ID or name copied previously.&lt;/p&gt;
&lt;h2 id="pmm-client"&gt;PMM Client&lt;/h2&gt;
&lt;p&gt;Go to the &lt;a href="https://docs.percona.com/percona-monitoring-and-management/setting-up/client/index.html#docker" target="_blank" rel="noopener noreferrer"&gt;Set Up PMM Client&lt;/a&gt; section in the documentation and follow the first two steps. All of these commands are executed from PowerShell.&lt;/p&gt;
&lt;p&gt;In Step 3, you need to specify the IP address of the PMM Server by setting up the &lt;code&gt;PMM_SERVER&lt;/code&gt; environment variable:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-7" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-7"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ &lt;span class="nv"&gt;$env&lt;/span&gt;:PMM_SERVER&lt;span class="o"&gt;=&lt;/span&gt;’X.X.X.X:443’&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Replacing &lt;code&gt;X.X.X.X&lt;/code&gt; with the server’s IP address. Then, initialize the container:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-8" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-8"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ docker run \
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;--rm \
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;--name pmm-client \
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-e PMM_AGENT_SERVER_ADDRESS=$env:PMM_SERVER \
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-e PMM_AGENT_SERVER_USERNAME=admin \
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-e PMM_AGENT_SERVER_PASSWORD=admin \
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-e PMM_AGENT_SERVER_INSECURE_TLS=1 \
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-e PMM_AGENT_SETUP=1 \
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-e PMM_AGENT_CONFIG_FILE=config/pmm-agent.yaml \
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;--volumes-from pmm-client-data \
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;percona/pmm-client:2&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;code&gt;PMM_AGENT_SERVER_PASSWORD&lt;/code&gt; default value is &lt;code&gt;admin&lt;/code&gt;. Replace this value with the password assigned when the server was configured.&lt;/p&gt;
&lt;h2 id="configure-your-database"&gt;Configure Your Database&lt;/h2&gt;
&lt;p&gt;Now that the client is connected to the server, you must configure PMM for monitoring your database. Follow the instructions below.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;MySQL
&lt;ul&gt;
&lt;li&gt;&lt;a href="#mysql-installation"&gt;Installation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#mysql-configuration"&gt;Configuration&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;PostgreSQL
&lt;ul&gt;
&lt;li&gt;&lt;a href="#postgresql-installation"&gt;Installation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#postgresql-configuration"&gt;Configuration&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;MongoDB
&lt;ul&gt;
&lt;li&gt;&lt;a href="#mongodb-installation"&gt;Installation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#mongodb-configuration"&gt;Configuration&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once PMM is configured, the Home Dashboard will show the databases that are being monitored. For more information and advanced configuration, check the &lt;a href="https://docs.percona.com/percona-monitoring-and-management/index.html" target="_blank" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2023/01/pmm-home-dashboard_hu_39234b2ff6de287c.png 480w, https://percona.community/blog/2023/01/pmm-home-dashboard_hu_8f62f17f42acb0a9.png 768w, https://percona.community/blog/2023/01/pmm-home-dashboard_hu_7e88b1c2319e1589.png 1400w"
src="https://percona.community/blog/2023/01/pmm-home-dashboard.png" alt="PMM Home Dashboard" /&gt;&lt;figcaption&gt;PMM Home Dashboard&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h3 id="mysql-installation"&gt;MySQL Installation&lt;/h3&gt;
&lt;p&gt;If you already have a MySQL instance running, skip the installation process and continue with the &lt;a href="#mysql-configuration"&gt;configuration&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;On Windows, you can install Percona Server for MySQL on Ubuntu running under WSL, but it’s better to use the official &lt;a href="https://hub.docker.com/r/percona/percona-server/" target="_blank" rel="noopener noreferrer"&gt;Docker image&lt;/a&gt;, as the MySQL server would be running on the same network as PMM.&lt;/p&gt;
&lt;p&gt;For installing MySQL using Docker, follow the instructions in the &lt;a href="https://docs.percona.com/percona-server/8.0/installation/docker.html" target="_blank" rel="noopener noreferrer"&gt;Percona Server for MySQL&lt;/a&gt; documentation.&lt;/p&gt;
&lt;p&gt;You need to start the container with the latest version of Percona Server for MySQL 8.0:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-9" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-9"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ docker run -d \
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --name ps \
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -e MYSQL_ROOT_PASSWORD=root \
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; percona/percona-server:8.0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Where &lt;code&gt;ps&lt;/code&gt; is the name of the container, and the default password for the &lt;code&gt;root&lt;/code&gt; user is &lt;code&gt;root&lt;/code&gt;. You can change these values according to your needs.&lt;/p&gt;
&lt;h3 id="mysql-configuration"&gt;MySQL Configuration&lt;/h3&gt;
&lt;p&gt;Once Percona Server for MySQL is running, you need to get its IP address by running:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-10" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-10"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ docker ps&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-11" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-11"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;1fb4ddb35e48 percona/pmm-client:2 &lt;span class="s2"&gt;"/usr/local/percona/…"&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; minutes ago Up &lt;span class="m"&gt;2&lt;/span&gt; minutes pmm-client&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Copy the container ID or name of the Percona Server for MySQL container. Then, execute this command:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-12" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-12"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ docker inspect -f &lt;span class="s1"&gt;'{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}'&lt;/span&gt; your_container&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Replacing &lt;code&gt;your_container&lt;/code&gt; with the value you copied previously.&lt;/p&gt;
&lt;p&gt;The IP address of the PMM Client container is also needed.&lt;/p&gt;
&lt;p&gt;For configuring PMM for monitoring MySQL, we need to create a PMM user. First, log into MySQL:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-13" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-13"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ docker run -it --rm percona mysql -h MYSQL_SERVER -uroot -p&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Where &lt;code&gt;MYSQL_SERVER&lt;/code&gt; is the IP address of the Percona Server for MySQL container&lt;/p&gt;
&lt;p&gt;Then, execute the following SQL statements&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-14" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-14"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'pmm'&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="s1"&gt;'localhost'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;IDENTIFIED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'pass'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MAX_USER_CONNECTIONS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-15" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-15"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GRANT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PROCESS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SUPER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;REPLICATION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CLIENT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RELOAD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BACKUP_ADMIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'pmm'&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="s1"&gt;'localhost'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Replacing &lt;code&gt;pass&lt;/code&gt; with your desired password, and &lt;code&gt;localhost&lt;/code&gt; with the IP address of the PMM Client container.&lt;/p&gt;
&lt;p&gt;And finally, register the MySQL server for monitoring:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-16" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-16"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ docker &lt;span class="nb"&gt;exec&lt;/span&gt; pmm-client pmm-admin add mysql --username&lt;span class="o"&gt;=&lt;/span&gt;pmm --password&lt;span class="o"&gt;=&lt;/span&gt;pass --host MYSQL_SERVER --query-source&lt;span class="o"&gt;=&lt;/span&gt;perfschema&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Where &lt;code&gt;MYSQL_SERVER&lt;/code&gt; is the IP address of the Percona Server for MySQL container. Replace this value with the IP address and replace &lt;code&gt;pass&lt;/code&gt; with the password of your &lt;code&gt;pmm&lt;/code&gt; user.&lt;/p&gt;
&lt;h3 id="postgresql-installation"&gt;PostgreSQL Installation&lt;/h3&gt;
&lt;p&gt;If you already have a PostgreSQL instance running, skip the installation process and continue with the &lt;a href="#postgresql-configuration"&gt;configuration&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;On Windows, you can install PostgreSQL using the Windows installer or install it on Ubuntu running under WSL, but it’s better to install it using the official image provided by the PostgreSQL project.&lt;/p&gt;
&lt;p&gt;You need to start the container with the latest version of PostgreSQL:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-17" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-17"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ docker run --name postgres -e &lt;span class="nv"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;password -d postgres&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Where &lt;code&gt;password&lt;/code&gt; is the password for the default &lt;code&gt;postgres&lt;/code&gt; user. Replace this value according to your needs.&lt;/p&gt;
&lt;h3 id="postgresql-configuration"&gt;PostgreSQL Configuration&lt;/h3&gt;
&lt;p&gt;Once PostgreSQL is running, you need to get its IP address by running:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-18" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-18"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ docker ps&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-19" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-19"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;0460c671db12 postgres &lt;span class="s2"&gt;"docker-entrypoint.s…"&lt;/span&gt; &lt;span class="m"&gt;6&lt;/span&gt; days ago Up &lt;span class="m"&gt;48&lt;/span&gt; seconds 5432/tcp postgres&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Copy the container ID or name of the PostgreSQL container. Then, execute this command:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-20" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-20"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ docker inspect -f &lt;span class="s1"&gt;'{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}'&lt;/span&gt; your_container&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Replacing &lt;code&gt;your_container&lt;/code&gt; with the value you copied previously.&lt;/p&gt;
&lt;p&gt;The IP address of the PMM Client container is also needed.&lt;/p&gt;
&lt;p&gt;For configuring PMM for monitoring PostgreSQL, we need to create a PMM user. First, log into PostgreSQL:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-21" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-21"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ docker &lt;span class="nb"&gt;exec&lt;/span&gt; -it postgres psql --user postgres&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Then, execute the following SQL statement:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-22" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-22"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pmm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SUPERUSER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ENCRYPTED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PASSWORD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'&lt;password&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Replacing &lt;code&gt;&lt;password&gt;&lt;/code&gt; with your desired password.&lt;/p&gt;
&lt;p&gt;And finally, register the PostgreSQL server for monitoring:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-23" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-23"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ docker &lt;span class="nb"&gt;exec&lt;/span&gt; pmm-client pmm-admin add postgresql --username&lt;span class="o"&gt;=&lt;/span&gt;pmm --password&lt;span class="o"&gt;=&lt;/span&gt;pass --host POSTGRESQL_SERVER --query-source&lt;span class="o"&gt;=&lt;/span&gt;perfschema&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Where &lt;code&gt;POSTGRESQL_SERVER&lt;/code&gt; is the IP address of the PostgreSQL container. Replace this value with the IP address and replace &lt;code&gt;pass&lt;/code&gt; with the password of your &lt;code&gt;pmm&lt;/code&gt; user.&lt;/p&gt;
&lt;h3 id="mongodb-installation"&gt;MongoDB Installation&lt;/h3&gt;
&lt;p&gt;If you already have a MongoDB instance running, skip the installation process and continue with the &lt;a href="#mongodb-configuration"&gt;configuration&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;On Windows, you can install Percona Server for MongoDB on Ubuntu running under WSL, but it’s better to use the official &lt;a href="https://hub.docker.com/r/percona/percona-server/" target="_blank" rel="noopener noreferrer"&gt;Docker image&lt;/a&gt;, as the MongoDB server would be running on the same network as PMM.&lt;/p&gt;
&lt;p&gt;For installing MongoDB using Docker, follow the instructions in the &lt;a href="https://docs.percona.com/percona-server-for-mongodb/6.0/install/docker.html" target="_blank" rel="noopener noreferrer"&gt;Percona Server for MongoDB&lt;/a&gt; documentation.&lt;/p&gt;
&lt;p&gt;You need to start the container with the latest version of Percona Server for MongoDB 6.0:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-24" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-24"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ docker run --name psmdb -d percona/percona-server-mongodb:6.0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="mongodb-configuration"&gt;MongoDB Configuration&lt;/h3&gt;
&lt;p&gt;Once Percona Server for MongoDB is running, you need to get its IP address by running.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-25" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-25"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ docker ps&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-26" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-26"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2c3d291535b3 percona/percona-server-mongodb:6.0 &lt;span class="s2"&gt;"/entrypoint.sh mong…"&lt;/span&gt; &lt;span class="m"&gt;6&lt;/span&gt; days ago Up &lt;span class="m"&gt;27&lt;/span&gt; minutes 27017/tcp psmdb&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Copy the container ID or name of the Percona Server for MongoDB container. Then, execute this command:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-27" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-27"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ docker inspect -f &lt;span class="s1"&gt;'{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}'&lt;/span&gt; your_container&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Replacing &lt;code&gt;your_container&lt;/code&gt; with the value you copied previously.&lt;/p&gt;
&lt;p&gt;The IP address of the PMM Client container is also needed.&lt;/p&gt;
&lt;p&gt;For configuring PMM for monitoring MongoDB, we need to create a PMM user. First, connect to the &lt;code&gt;admin&lt;/code&gt; database in MongoDB using the MongoDB Shell (mongosh):&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-28" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-28"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ docker run -it --link psmdb --rm percona/percona-server-mongodb:6.0 mongosh mongodb://MONGODB_SERVER:27017/admin&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Where &lt;code&gt;MONGODB_SERVER&lt;/code&gt; is the IP address of your MongoDB server.&lt;/p&gt;
&lt;p&gt;Then, create the user for PMM, executing the following instructions:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-29" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-29"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;db.createRole({
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "role":"explainRole",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "privileges":[
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "resource":{
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "db":"",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "collection":""
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "actions":[
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "collStats",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "dbHash",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "dbStats",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "find",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "listIndexes",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "listCollections"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ],
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "roles":[]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;})&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-30" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-30"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;db.getSiblingDB("admin").createUser({
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "user":"pmm",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "pwd":"&lt;password&gt;",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "roles":[
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "role":"explainRole",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "db":"admin"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "role":"clusterMonitor",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "db":"admin"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "role":"read",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "db":"local"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;})&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Replacing &lt;code&gt;&lt;password&gt;&lt;/code&gt; with the password you want to assign to the &lt;code&gt;pmm&lt;/code&gt; user.&lt;/p&gt;
&lt;p&gt;And finally, register the MongoDB server for monitoring:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-31" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-31"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ docker &lt;span class="nb"&gt;exec&lt;/span&gt; pmm-client pmm-admin add mongodb --username&lt;span class="o"&gt;=&lt;/span&gt;pmm --password&lt;span class="o"&gt;=&lt;/span&gt;pass --host MONGODB_SERVER&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Where &lt;code&gt;MONGODB_SERVER&lt;/code&gt; is the IP address of the MongoDB container. Replace this value with the IP address and replace &lt;code&gt;pass&lt;/code&gt; with the password of your &lt;code&gt;pmm&lt;/code&gt; user.&lt;/p&gt;</content:encoded>
      <author>Mario García</author>
      <category>PMM</category>
      <category>MySQL</category>
      <category>PostgreSQL</category>
      <category>MongoDB</category>
      <category>Monitoring</category>
      <media:thumbnail url="https://percona.community/blog/2023/01/pmm-login-screen_hu_782bdd089cea0085.jpg"/>
      <media:content url="https://percona.community/blog/2023/01/pmm-login-screen_hu_ca2504a4a3694f9d.jpg" medium="image"/>
    </item>
    <item>
      <title>Automating Percona's XtraBackup</title>
      <link>https://percona.community/blog/2023/01/04/automating-perconas-xtrabackup/</link>
      <guid>https://percona.community/blog/2023/01/04/automating-perconas-xtrabackup/</guid>
      <pubDate>Wed, 04 Jan 2023 00:00:00 UTC</pubDate>
      <description>Percona’s XtraBackup is a beautiful tool that allows for the backup and restoration of MySQL databases.</description>
      <content:encoded>&lt;p&gt;&lt;a href="https://www.percona.com/software/mysql-database/percona-xtrabackup" target="_blank" rel="noopener noreferrer"&gt;Percona’s XtraBackup&lt;/a&gt; is a beautiful tool that allows for the backup and restoration of MySQL databases.&lt;/p&gt;
&lt;p&gt;From the documentation:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The Percona XtraBackup tools provide a method of performing a hot backup of your MySQL data while the system is running. Percona XtraBackup is a free, online, open source, complete database backups solution for all versions of Percona Server for MySQL and MySQL®. Percona XtraBackup performs online non-blocking, tightly compressed, highly secure full backups on transactional systems so that applications remain fully available during planned maintenance windows.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;It is great but it quickly becomes difficult to wield when using it multiple times per day across multiple environments. &lt;a href="https://github.com/phildoesdev/xtrabackupautomator" target="_blank" rel="noopener noreferrer"&gt;XtraBackup Automator&lt;/a&gt; attempts to make this easier by providing the ability to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Schedule when we should create backups
&lt;ul&gt;
&lt;li&gt;Times of day, when to make a base backup vs incremental&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Archive old backups
&lt;ul&gt;
&lt;li&gt;Decide what to do with the base backup and its increments when we are ready to create a new base&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Maintain x days of archives
&lt;ul&gt;
&lt;li&gt;Define how many archived backup groups should we keep before removing them from the file system&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href="https://github.com/phildoesdev/xtrabackupautomator" target="_blank" rel="noopener noreferrer"&gt;XtraBackup Automator&lt;/a&gt; automates away the management of MySQL backups.&lt;/p&gt;
&lt;h2 id="considerations-before-installing"&gt;Considerations Before Installing&lt;/h2&gt;
&lt;p&gt;I strongly recommend testing this on some sort of preproduction environment first. The thing I’ve seen most likely to cause trouble is the archival process. By default, this tool uses the gztar ’tarball’ as its compression method, which can be resource intensive if you are working on a large database backup. For instance, one of our servers (a Google Cloud Platform virtual machine with 8 vCPU, 32gb RAM, 1000GB SSD persistent disk, running Debian 10) with a ~140GB base backup currently jumps in CPU usage by ~13% for 4 hours, with a handful of 5%-15% jumps in RAM usage, while creating this archive. Another downside of this compression method is that it can take 10-20 minutes to unzip, depending on settings. The benefit of the tarball is that we are able to take these large backups from 140GB to &lt; 10GB and this is worth all that other trouble for us as we want to have two weeks of daily backups. If these down sides are not acceptable, I recommend playing with the archive type as described in the config. I have not personally tested any other methods.&lt;/p&gt;
&lt;p&gt;I am assuming that you have administrative access to the server this will run on as installing systemd services and timers requires root access. I see no reason why Cron Jobs could not be used to run this program, but I have never tested that and all documentation references systemd and its tools.&lt;/p&gt;
&lt;h2 id="info--requirements"&gt;Info &amp; Requirements&lt;/h2&gt;
&lt;h4 id="developed-on"&gt;Developed On&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;OS:&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Debian GNU/Linux 10 (buster)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Python Version:&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Python 3.10.4&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Python Packages&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Name:&lt;/strong&gt; &lt;a href="https://pexpect.readthedocs.io/en/stable/" target="_blank" rel="noopener noreferrer"&gt;pexpect&lt;/a&gt;, &lt;strong&gt;Version:&lt;/strong&gt; 4.8.0&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Percona XtraBackup Version:&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.percona.com/software/mysql-database/percona-xtrabackup" target="_blank" rel="noopener noreferrer"&gt;XtraBackup&lt;/a&gt; version 8.0.28-21 based on MySQL server 8.0.28 Linux (x86_64)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MySQL&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;MySql Ver 8.0.28 for Linux on x86_64 (MySQL Community Server - GPL)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="required-python-libraries"&gt;Required Python Libraries&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://pexpect.readthedocs.io/en/stable/" target="_blank" rel="noopener noreferrer"&gt;pexpect&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="required-files"&gt;Required Files&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/phildoesdev/xtrabackupautomator/blob/main/src/xtrabackupautomator.py" target="_blank" rel="noopener noreferrer"&gt;xtrabackupautomator.py&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/phildoesdev/xtrabackupautomator/blob/main/xtrabackupautomator.service" target="_blank" rel="noopener noreferrer"&gt;xtrabackupautomator.service&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/phildoesdev/xtrabackupautomator/blob/main/xtrabackupautomator.timer" target="_blank" rel="noopener noreferrer"&gt;xtrabackupautomator.timer&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="installing"&gt;Installing&lt;/h2&gt;
&lt;p&gt;Below is a general explanation of how to install and start running this program. I would suggest running the program manually via command line a couple times, in a preproduction environment, to verify things are working as you expect.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Download The Files&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Download the &lt;a href="#required-files"&gt;Required Files&lt;/a&gt; from &lt;a href="https://github.com/phildoesdev/xtrabackupautomator" target="_blank" rel="noopener noreferrer"&gt;https://github.com/phildoesdev/xtrabackupautomator&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Review Your Config Settings&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Review the &lt;a href="#configuration"&gt;Configuration&lt;/a&gt; section of this readme and alter these settings to your liking.&lt;br&gt;
Any altered folder paths may affect the create folder instructions below. At minimum you must include database login information, but alter as necessary. I suggest reading through all the config options to see what might be interesting to tweak.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Edit your systemd service and timer&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;If you change the location that the script should run from you must alter the file path in the xtrabackupautomator.service file. I will not explain much else here as there is a lot that might go into these settings. I have given some default settings that hopefully make sense.&lt;/p&gt;
&lt;p&gt;I have also included several links that describe what is possible in the &lt;a href="#sources--links"&gt;Sources &amp; Links&lt;/a&gt; section. If there are specific questions in the future I will address them here.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2023/01/automate_xtrabackup_service_timer_example.jpg" alt="ServiceTimerExample" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Install the required dependencies&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ python3 -m pip install pexpect&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Create the directory for our code to live in&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-1"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ sudo mkdir /lib/xtrabackupautomator
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ sudo chmod &lt;span class="m"&gt;700&lt;/span&gt; /lib/xtrabackupautomator&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Create the directories for our backups to save to&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-2" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-2"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ sudo mkdir -p /data/backups/mysql
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ sudo mkdir -p /data/backups/archive
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ sudo mkdir -p /data/backups/archive/archive_restore
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ sudo chmod &lt;span class="m"&gt;760&lt;/span&gt; /data/backups/mysql
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ sudo chmod &lt;span class="m"&gt;700&lt;/span&gt; /data/backups/archive
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ sudo chmod &lt;span class="m"&gt;700&lt;/span&gt; /data/backups/archive/archive_restore
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ sudo chown -R root:root /data/backups/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Move your downloaded files&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-3" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-3"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ sudo mv xtrabackupautomator.py /lib/xtrabackupautomator/.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ sudo mv xtrabackupautomator.service /etc/systemd/system/.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ sudo mv xtrabackupautomator.timer /etc/systemd/system/.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Enable your service and timer&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-4" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-4"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ sudo systemctl daemon-reload
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ sudo systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; xtrabackupautomator.timer
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ sudo systemctl start xtrabackupautomator.timer
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ sudo systemctl status xtrabackupautomator.timer&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Congrats, you are now installed!&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;You have now installed XtraBackup Automator, it will begin running automatically according to your xtrabackupautomator.timer file. If you wish to run it manually, you can run the python file, or use my preferred method, the &lt;code&gt;systemd start&lt;/code&gt; command to start it and &lt;code&gt;journalctl&lt;/code&gt; to view its output:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-5" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-5"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ systemctl start xtrabackupautomator.service
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ journalctl -f -n &lt;span class="m"&gt;100&lt;/span&gt; -u xtrabackupautomator&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Unzipping and Restoring your Backup&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I have included a link in the &lt;a href="#sources--links"&gt;Sources &amp; Links&lt;/a&gt; section on &lt;a href="https://linuxize.com/post/how-to-extract-unzip-tar-gz-file/" target="_blank" rel="noopener noreferrer"&gt;unzipping tar gz files&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I strongly suggest reading the &lt;a href="https://docs.percona.com/percona-xtrabackup/8.0/backup_scenarios/incremental_backup.html" target="_blank" rel="noopener noreferrer"&gt;official Percona documentation&lt;/a&gt; on restoring backups.&lt;/p&gt;
&lt;p&gt;For a point of a reference, I will describe my generic unzip and restore process. I am using the directory &lt;code&gt;/data/backups/archive/archive_restore/&lt;/code&gt; as a place to unzip and restore from.&lt;/p&gt;
&lt;p&gt;Executing any of the below commands can obviously be very dangerous as we must stop mysql, wipe the current data, and restore with our prepared backup. &lt;a href="https://docs.percona.com/percona-xtrabackup/8.0/backup_scenarios/incremental_backup.html" target="_blank" rel="noopener noreferrer"&gt;Read the documentation&lt;/a&gt; and come up with your own plan! The code below is only meant as a reference and may change greatly with time and environments. Always test your plans in a preprod environment!!&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2023/01/automate_xtrabackup_archive_pic.png" alt="Archives" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-6" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-6"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Always verify our version of Percona's XtraBackup and MySQL match before performing a backup... these differences can make restores fail or behave oddly.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ sudo mysql --version
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ sudo xtrabackup --version
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Clean our restore folder, just to be safe&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ rm -r /data/backups/archive/archive_restore/*
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Unzip our archived backup to an empty folder. Always verify we have enough disk space to unzip before unzipping&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ sudo tar -xvf database_backup_12_23_2022__06_25_10.tar.gz -C /data/backups/archive/archive_restore/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Sanity check, verify we are looking at the backup we think we are (This command checks the base folder, check the latest incremental folder we may have)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ &lt;span class="nb"&gt;cd&lt;/span&gt; /data/backups/archive/archive_restore/data/backups/mysql/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ sudo cat base/xtrabackup_info &lt;span class="p"&gt;|&lt;/span&gt; grep &lt;span class="s1"&gt;'tool_version\|server_version\|start_time\|end_time\|partial\|incremental'&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Prepare the base&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ sudo xtrabackup --prepare --apply-log-only --no-server-version-check --target-dir&lt;span class="o"&gt;=&lt;/span&gt;/data/backups/archive/archive_restore/data/backups/mysql/base
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Prepare each incremental folder. This must be done for each incremental folder we wish to back up to.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ sudo xtrabackup --prepare --apply-log-only --no-server-version-check --target-dir&lt;span class="o"&gt;=&lt;/span&gt;/data/backups/archive/archive_restore/data/backups/mysql/base --incremental-dir&lt;span class="o"&gt;=&lt;/span&gt;/data/backups/archive/archive_restore/data/backups/mysql/inc_0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Repeat as necssary....&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Stop SQL and our backup script as we do not want it running mid restore&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ sudo systemctl stop mysql
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ sudo systemctl stop xtrabackupautomator.timer
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Wipe bad/corrupted sql data from current instance&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ sudo rm -rv /var/lib/mysql/*
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Verify our mysql data is wiped&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ sudo ls /var/lib/mysql
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# I use this method to restore my base backup, there are other options but they did not work correctly in my environment&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ sudo xtrabackup --copy-back --target-dir&lt;span class="o"&gt;=&lt;/span&gt;/data/backups/archive/archive_restore/data/backups/mysql/base
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Verify the contents are the size we expect as a sanity check and apply the correct ownership to the files&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ du -hs /var/lib/mysql/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ sudo chown -R mysql:mysql /var/lib/mysql
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Restart mysql and xtrabackupautomator. Verify MySQL's status&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ sudo systemctl start mysql
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ sudo systemctl xtrabackupautomator.timer
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ sudo systemctl status mysql&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="configuration"&gt;Configuration&lt;/h2&gt;
&lt;p&gt;In an attempt to make this a one file, easy to install piece of software, I included the configuration struct in the xtrabackupautomator.py file, in the &lt;code&gt;__init__&lt;/code&gt; method of the XtraBackupAutomator class, on line ~60 (as of this writing). I will describe that struct, its default values, and other relevant information below. Most of this information can also be found in comments throughout, or in the getter methods for each variable.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-7" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-7"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;== db ==
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -un
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; [DEFAULT_VALUE: ""]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; XtraBackup user you set up during your initial configuration of Percona's XtraBackup
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -pw
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; [DEFAULT_VALUE: ""]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; This user's password
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -host
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; [DEFAULT_VALUE: "localhost"]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; The IP of your database
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -port
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; [DEFAULT_VALUE: 3306]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; The port to access database
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;== folder_names ==
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -base_dir
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; [DEFAULT_VALUE: "/data/backups/"]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; The root directory for all backup related things. Holds current backup and any archived backups.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; This is the default location and is reflected in the setup as we request you create this folder.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; If you change this directory in the config this change must be reflected in the setup.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -datadir
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; [DEFAULT_VALUE: "mysql/"]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Folder that current backups will be saved to. This would be the folder that holds the base backup and any
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; incremental backups before they are archived
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; If you change this directory in the config this change must be reflected in the setup.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; *** XtraBackupAutomator WILL ARCHIVE AND DELETE ANYTHING IN HERE. THIS SHOULD BE AN EMPTY FOLDER, NOT UTILIZED BY ANYTHING ELSE.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -archivedir
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; [DEFAULT_VALUE: "archive/"]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Folder that a group of backups will be archived to.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; If you change this directory in the config this change must be reflected in the setup.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; *** XtraBackupAutomator COULD POTENTIALLY DELETE ANY NON-DIRECTORY IN HERE.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;== file_names ==
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -basefolder_name
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; [DEFAULT_VALUE: "base"]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Foldername for the base backup
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -incrementalfolder_perfix
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; [DEFAULT_VALUE: "inc_"]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Folder name prefix for incremental backups.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Suffixed with the current number of incremental backups minus one
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; e.g., 'inc_0'
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -archive_name_prefix
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; [DEFAULT_VALUE: "database_backup_"]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Prefix for the archive files.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Suffixed by the datetime of the archive
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; e.g., 'database_backup_11_28_2022__06_25_03.tar.gz'
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;== archive_settings ==
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -allow_archive
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; [DEFAULT_VALUE: True]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; An override to enable/disable all archive settings.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Currently, disabling this will cause the program to do a base backup and then incremental backups forever.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -archive_zip_format
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; [DEFAULT_VALUE: "gztar"]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; The default archive file type. I like tarballs because they zip our large database into a manageable file.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; However, tarballs can take a long time to create and require a fair amount of resources if your DB is large.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; This setting will depend on your system and the size of your DB. I recommend playing around with this.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Other zip options: [Shutil Man Page](https://docs.python.org/3/library/shutil.html#shutil.make_archive)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -archived_bu_count
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; [DEFAULT_VALUE: 7]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Keep x archived backups, once this threshold is reached the oldest archive will be deleted.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Archiving daily, this is a week of archives.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -enforce_max_num_bu_before_archive
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; [DEFAULT_VALUE: True]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; One of two ways to 'force archive' of backups.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; This counts the # of incremental backup folders and initiates the archives once that number is reached.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; A sample use case is that in your systemd timer file is scheduled to do 5 backups throughout the day, so setting this to
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; true and max_num_bu_before_archive_count set to 4 (because we do not count the base) would give you a 'daily archive'
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -max_num_bu_before_archive_count
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; [DEFAULT_VALUE: 4]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; The max number of incremental backups to do before we archive (does not count the base).
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Set to 0 to archive after each base
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -enforce_archive_at_time
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; [DEFAULT_VALUE: False]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; One of two ways to 'force archive' of backups.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; This will archive what ever base or incremental folders exist if a backup is happening within the
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; archive_at_utc_24_hour hour. This is intended to make it easier to schedule when your archive and base backup occur.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; These can be resource intensive and so it is nice to do at off hours.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; *If this program is scheduled to run more than once during the 'archive_at_utc_24_hour' hour each run will cause an archive.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -archive_at_utc_24_hour
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; [DEFAULT_VALUE: 6]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; If a backup happens within this hour we will archive w/e was previously there and create a new base.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Matching this with a time setup in your xtrabackupautomator.timer allows you to choose when your backups will
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; occur.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; No explicit consideration for daylight savings time.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Defaults to the hour of 1:00am EST, 6:00am UTC.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;== general_settings ==
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -backup_command_timeout_seconds
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; [DEFAULT_VALUE: 30]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Give us 'backup_command_timeout_seconds' seconds for the command to respond.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; This is not the same as saying 'a backup can only take this long'.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -max_time_between_backups_seconds
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; [DEFAULT_VALUE: 60*60*24]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Max number of seconds between this backup and the last.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; If the last backup is older than this we will archive and create a new base.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; This is in an attempt to prevent an incremental backup that might span days or weeks due to this service being
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; turned off or some such.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Defaults (arbitrarily) to 24 hours
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -additional_bu_command_params
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; [DEFAULT_VALUE: ["no-server-version-check"]]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Any additional parameters that you wish to pass along to your backup commands.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; We loop this list, put a '--' before each element and append it to the end of our backup commands.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; This gets applied to the base and incremental backup commands.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; These are params that I have found useful.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;== log_settings ==
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -is_enabled
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; [DEFAULT_VALUE: True]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Enables/Disables all logging type settings. This was useful in testing, so I kept it around.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -log_child_process_to_screen
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; [DEFAULT_VALUE: True]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; If this is set to true the child process's output will be dumped to screen but not actually logged anywhere
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -is_log_to_file
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; [DEFAULT_VALUE: True]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; If set to True we will try to log to the 'default_log_file' in the 'default_log_path' directory
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -default_log_path
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; [DEFAULT_VALUE: "/var/log/"]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; The path that we will try to place our log file ('default_log_file')
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -default_log_file
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; [DEFAULT_VALUE: "xtrabackupautomator.log"]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; The file name we will try to log to&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="sources--links"&gt;Sources &amp; Links&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Official Percona XtraBackup Documentation
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.percona.com/percona-xtrabackup/8.0/index.html" target="_blank" rel="noopener noreferrer"&gt;https://docs.percona.com/percona-xtrabackup/8.0/index.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Systemctl Overveiw
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://fedoramagazine.org/what-is-an-init-system/" target="_blank" rel="noopener noreferrer"&gt;https://fedoramagazine.org/what-is-an-init-system/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.digitalocean.com/community/tutorials/how-to-use-systemctl-to-manage-systemd-services-and-units" target="_blank" rel="noopener noreferrer"&gt;https://www.digitalocean.com/community/tutorials/how-to-use-systemctl-to-manage-systemd-services-and-units&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/codex/setup-a-python-script-as-a-service-through-systemctl-systemd-f0cc55a42267" target="_blank" rel="noopener noreferrer"&gt;https://medium.com/codex/setup-a-python-script-as-a-service-through-systemctl-systemd-f0cc55a42267&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Systemctl Timers Overview
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://linuxconfig.org/how-to-schedule-tasks-with-systemd-timers-in-linux" target="_blank" rel="noopener noreferrer"&gt;https://linuxconfig.org/how-to-schedule-tasks-with-systemd-timers-in-linux&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://opensource.com/article/20/7/systemd-timers" target="_blank" rel="noopener noreferrer"&gt;https://opensource.com/article/20/7/systemd-timers&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Systemctl Services Details
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.freedesktop.org/software/systemd/man/systemd.service.html" target="_blank" rel="noopener noreferrer"&gt;https://www.freedesktop.org/software/systemd/man/systemd.service.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Systemctl Timers Details
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.freedesktop.org/software/systemd/man/systemd.timer.html" target="_blank" rel="noopener noreferrer"&gt;https://www.freedesktop.org/software/systemd/man/systemd.timer.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;OnCalendar Expected Formats
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.freedesktop.org/software/systemd/man/systemd.time.html#" target="_blank" rel="noopener noreferrer"&gt;https://www.freedesktop.org/software/systemd/man/systemd.time.html#&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Archive Zip Options
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.python.org/3/library/shutil.html#shutil.make_archive" target="_blank" rel="noopener noreferrer"&gt;https://docs.python.org/3/library/shutil.html#shutil.make_archive&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;How to Extract (Unzip) Tar Gz File
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://linuxize.com/post/how-to-extract-unzip-tar-gz-file/" target="_blank" rel="noopener noreferrer"&gt;https://linuxize.com/post/how-to-extract-unzip-tar-gz-file/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Restoring Xtrabackup Incremental Backups
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.percona.com/percona-xtrabackup/8.0/backup_scenarios/incremental_backup.html" target="_blank" rel="noopener noreferrer"&gt;https://docs.percona.com/percona-xtrabackup/8.0/backup_scenarios/incremental_backup.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</content:encoded>
      <author>Phil Plachta</author>
      <category>XtraBackup</category>
      <category>DevOps</category>
      <media:thumbnail url="https://percona.community/blog/2023/01/automate_xtrabackup_hu_7a589919ed67f9a0.jpg"/>
      <media:content url="https://percona.community/blog/2023/01/automate_xtrabackup_hu_4800e348e5210562.jpg" medium="image"/>
    </item>
    <item>
      <title>Testing Kubernetes with KUTTL</title>
      <link>https://percona.community/blog/2022/12/16/testing-kubernetes-with-kuttl/</link>
      <guid>https://percona.community/blog/2022/12/16/testing-kubernetes-with-kuttl/</guid>
      <pubDate>Fri, 16 Dec 2022 00:00:00 UTC</pubDate>
      <description>Automated testing is the only way to be sure that your code works. Enabling automated testing can be hard and we say a lot of tools to write automated tests in the industry since the beginning. Some veterans in the industry may remember Selenium, Cucumber frameworks that help automate testing in the browser. However, testing in Kubernetes can be hard.</description>
      <content:encoded>&lt;p&gt;Automated testing is the only way to be sure that your code works. Enabling automated testing can be hard and we say a lot of tools to write automated tests in the industry since the beginning. Some veterans in the industry may remember Selenium, Cucumber frameworks that help automate testing in the browser. However, testing in Kubernetes can be hard.&lt;/p&gt;
&lt;p&gt;In Percona we deal with Kubernetes and have different operators to automate the management of databases. It requires testing. A lot of testing. We have different frameworks to help us with it&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Codecept.js to write UI tests for PMM. Also, we use a playwright for some cases.&lt;/li&gt;
&lt;li&gt;We have tools to help us with API testing as well as automating some routines by running bash commands during the test step.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;However, those frameworks are not applicable to test Kubernetes workloads as well as Kubernetes operators. I’ve been working in the PMM integrations team for six months and saw different approaches to automate testing for PMM/DBaaS. We have a Go test library with wrappers around kubectl and codecept.js for end-to-end tests for the User Interface.&lt;/p&gt;
&lt;h2 id="what-challenges-do-we-have"&gt;What challenges do we have?&lt;/h2&gt;
&lt;p&gt;Well, to be sure that a database cluster creation works we need to automate the following steps&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Installation of operators to Kubernetes cluster&lt;/li&gt;
&lt;li&gt;Test integration with version service to respect compatibility matrix.&lt;/li&gt;
&lt;li&gt;Create a database cluster and wait once it’ll be available&lt;/li&gt;
&lt;li&gt;Do some assertions against Kubernetes as well as UI.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The main pain point here is that we need to wait up to 10-15 minutes for each step and we can’t have different test cases to cover as many cases as we can. Yet we can achieve some performance benefits by paralleling workloads, still, it requires learning Javascript and testing framework to work with it. We had some architectural changes recently and moved from our custom gRPC API to create and manage database clusters to an operator that runs on top of other operators and converts K8s’ Custom Resource from generic format to operator specific. We had a couple of options for this new project and after research, we chose kuttl as a framework for integration/e2e testing.&lt;/p&gt;
&lt;h2 id="what-is-kuttl-anyway-and-why-should-i-care"&gt;What is KUTTL anyway and why should I care?&lt;/h2&gt;
&lt;p&gt;KUTTL is the KUbernetes Test TooL. It’s written in Go and provides a declarative way to test Kubernetes operators using Kubernetes primitives. It’s easy to start kuttling. Let’s take a deeper look. I’ll use &lt;a href="https://github.com/percona/dbaas-operator" target="_blank" rel="noopener noreferrer"&gt;dbaas-operator&lt;/a&gt; as an example. DBaaS-operator is an operator that has a simple and generic Custom Resource Definition available to create Percona Server MongoDB or Percona XtraDB Cluster instances in kubernetes. It uses underlying operators as a dependencies. We have the following structure&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;e2e-tests
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── kind.yml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── kuttl-eks.yml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── kuttl.yml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;└── tests
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; └── pxc
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ├── 00-assert.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ├── 00-deploy-operators.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ├── 01-assert.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ├── 01-deploy-pxc.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ├── 02-assert.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ├── 02-upgrade-pxc.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ├── 03-assert.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ├── 03-restart-pxc.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ├── 04-delete-cluster.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ├── 05-assert.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ├── 05-create-cluster.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ├── 06-assert.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ├── 06-scale-up-pxc.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ├── 07-assert.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ├── 07-scale-down-pxc.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; └── 08-delete-cluster.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2 directories, 19 files&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Let’s discuss these YAML files more&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;kind.yml contains settings to run &lt;a href="https://kind.sigs.k8s.io/" target="_blank" rel="noopener noreferrer"&gt;Kind&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;kuttl.yml has all required settings for Kuttl framework and kuttl-eks.yml has some EKS specific configurations&lt;/li&gt;
&lt;li&gt;tests folder has test steps and assertions&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="kind-and-kuttl-settings"&gt;Kind and KUTTL settings&lt;/h2&gt;
&lt;p&gt;Let’s discuss Kind and kuttl settings and I’ll start with KUTTL first&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;yaml&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-1"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;apiVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;kuttl.dev/v1beta1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;TestSuite&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;kindConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;e2e-tests/kind.yml &lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# Path to Kind config that will be used to create Kind clusters&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;crdDir&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;config/crd/bases &lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# Path to a directory that contains CRD files. Kuttl will apply them before running tests&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;artifactsDir&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;/tmp/ &lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# Path to a directory to store artifacts such as logs and other information&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;testDirs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;- &lt;span class="l"&gt;e2e-tests/tests &lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# Path to directories that have test steps&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Kind config is quite easy&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;yaml&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-2" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-2"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Cluster&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;apiVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;kind.x-k8s.io/v1alpha4&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;- &lt;span class="nt"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;control-plane&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;- &lt;span class="nt"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;worker&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;- &lt;span class="nt"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;worker&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;- &lt;span class="nt"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;worker&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;containerdConfigPatches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;- &lt;span class="p"&gt;|-&lt;/span&gt;&lt;span class="sd"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; [plugins."io.containerd.grpc.v1.cri".registry.mirrors."localhost:5000"]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; endpoint = ["http://kind-registry:5000"]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The aforementioned config will use local registry and will create 3 k8s worker nodes controlled by control plane&lt;/p&gt;
&lt;h2 id="writing-tests"&gt;Writing tests&lt;/h2&gt;
&lt;p&gt;At the first glance, kuttling can be easy because it uses Kubernetes primitives as a test step and assertion but I had a couple of problems to test my operator. Let’s take a look at a couple of examples. Since dbaas-operator depends on PXC operator we need to prepare our environment for testing. Let’s write first test that installs PXC operator and ensures that it was installed.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-3" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-3"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat e2e-tests/tests/pxc/00-deploy-pxc-operator.yml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;apiVersion: kuttl.dev/v1beta1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kind: TestStep
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;timeout: 10 # Timeout for the test step
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;commands:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - command: kubectl apply -f https://raw.githubusercontent.com/percona/percona-xtradb-cluster-operator/v${PXC_OPERATOR_VERSION}/deploy/bundle.yaml -n "${NAMESPACE}"&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;KUTTL test steps easily extensible with &lt;a href="https://kuttl.dev/docs/testing/reference.html#commands" target="_blank" rel="noopener noreferrer"&gt;commands&lt;/a&gt;. One can run even scripts as a prerequisite for a test case. PXC operator installs CRDs and creates a deployment and here’s an example of assertion.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-4" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-4"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat e2e-tests/tests/pxc/00-assert.yml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;apiVersion: kuttl.dev/v1beta1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kind: TestAssert
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;timeout: 120 # Timeout waiting for the state
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;---
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;apiVersion: apiextensions.k8s.io/v1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kind: CustomResourceDefinition
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;metadata:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; name: perconaxtradbclusters.pxc.percona.com
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;spec:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; group: pxc.percona.com
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; names:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; kind: PerconaXtraDBCluster
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; listKind: PerconaXtraDBClusterList
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; plural: perconaxtradbclusters
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; shortNames:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - pxc
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - pxcs
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; singular: perconaxtradbcluster
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; scope: Namespaced
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;---
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;apiVersion: apiextensions.k8s.io/v1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kind: CustomResourceDefinition
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;metadata:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; name: databaseclusters.dbaas.percona.com
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;spec:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; group: dbaas.percona.com
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; names:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; kind: DatabaseCluster
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; listKind: DatabaseClusterList
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; plural: databaseclusters
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; shortNames:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - db
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; singular: databasecluster
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; scope: Namespaced
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;---
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;apiVersion: apps/v1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kind: Deployment
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;metadata:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; name: percona-xtradb-cluster-operator
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;status:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; availableReplicas: 1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; observedGeneration: 1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; readyReplicas: 1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; replicas: 1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; updatedReplicas: 1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Our first test is ready and one needs to run &lt;code&gt;kubectl kuttl test --config ./e2e-tests/kuttl.yml&lt;/code&gt; to run kuttl.&lt;/p&gt;
&lt;h2 id="more-advanced-tests"&gt;More advanced tests&lt;/h2&gt;
&lt;p&gt;We need to run our operator first to be able to work with resources and test it. KUTTL recomends configure it via &lt;code&gt;TestSuite&lt;/code&gt; by the following example&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;yaml&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-5" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-5"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;apiVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;kuttl.dev/v1beta1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;TestSuite&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nn"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;commands&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;./bin/manager&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nn"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;However, since dbaas-operator depends on underlying operators it needs to work correctly even if they are not present in a Kubernetes cluster. It has the following logic in the controller&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-6" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-6"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;// SetupWithManager sets up the controller with the Manager.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;func (r *DatabaseReconciler) SetupWithManager(mgr ctrl.Manager) error {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; fmt.Println(os.Getenv("WATCH_NAMESPACE"))
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; unstructuredResource := &amp;unstructured.Unstructured{}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; unstructuredResource.SetGroupVersionKind(schema.GroupVersionKind{
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Group: "apiextensions.k8s.io",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Kind: "CustomResourceDefinition",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Version: "v1",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; controller := ctrl.NewControllerManagedBy(mgr).
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; For(&amp;dbaasv1.DatabaseCluster{})
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; err := r.Get(context.Background(), types.NamespacedName{Name: pxcCRDName}, unstructuredResource)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; if err == nil {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; if err := r.addPXCToScheme(r.Scheme); err == nil {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; controller.Owns(&amp;pxcv1.PerconaXtraDBCluster{})
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; err = r.Get(context.Background(), types.NamespacedName{Name: psmdbCRDName}, unstructuredResource)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; if err == nil {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; if err := r.addPSMDBToScheme(r.Scheme); err == nil {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; controller.Owns(&amp;psmdbv1.PerconaServerMongoDB{})
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; return controller.Complete(r)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;controller.Owns&lt;/code&gt; sets up a controller to watch specified resources and once they were changed it’ll run a reconciliation loop to sync changes. Also, it checks that operator is present in the cluster by checking that deployment and CRDs are available. It means that to make the operator work correctly in tests we need to choose from the following options&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Restart operator once upsteam operator was installed by sending &lt;code&gt;HUP&lt;/code&gt; signal&lt;/li&gt;
&lt;li&gt;Run operator only after underlying operator is present in a cluster&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Hence, I moved command as the next step before creating a cluster. You can see it below&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-7" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-7"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat e2e-tests/tests/pxc/01-deploy-pxc.yml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;apiVersion: kuttl.dev/v1beta1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kind: TestStep
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;timeout: 10
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;commands:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - script: WATCH_NAMESPACE=$NAMESPACE ../../../bin/manager
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; background: true
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;---
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;apiVersion: dbaas.percona.com/v1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kind: DatabaseCluster
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;metadata:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; name: test-cluster
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;spec:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; databaseType: pxc
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; databaseImage: percona/percona-xtradb-cluster:8.0.23-14.1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; databaseConfig: |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; [mysqld]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; wsrep_provider_options="debug=1;gcache.size=1G"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; secretsName: pxc-sample-secrets
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; clusterSize: 1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; loadBalancer:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; type: haproxy
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; exposeType: ClusterIP
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; size: 1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; image: percona/percona-xtradb-cluster-operator:1.11.0-haproxy
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; dbInstance:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; cpu: "1"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; memory: 1G
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; diskSize: 15G&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Note: &lt;code&gt;command&lt;/code&gt; supports only simple commands and does not fully support env variables. It supports only $NAMESPACE, $PATH and $HOME. However, &lt;code&gt;script&lt;/code&gt; solves the problem of setting &lt;code&gt;WATCH_NAMESPACE&lt;/code&gt; environment variable.&lt;/p&gt;
&lt;p&gt;In nutshell, the test step above does two things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Runs the operator&lt;/li&gt;
&lt;li&gt;Creates a database cluster&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The assertion checks that kubernetes cluster has the &lt;code&gt;DatabaseCluster&lt;/code&gt; object with &lt;code&gt;ready&lt;/code&gt; status as well as PXC cluster with the same status.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;yaml&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-8" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-8"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;apiVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;kuttl.dev/v1beta1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;TestAssert&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;600&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nn"&gt;---&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;apiVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;dbaas.percona.com/v1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;DatabaseCluster&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;test-cluster&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;databaseType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;pxc&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;databaseImage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;percona/percona-xtradb-cluster:8.0.23-14.1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;databaseConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="sd"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; [mysqld]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; wsrep_provider_options="debug=1;gcache.size=1G"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;secretsName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;pxc-sample-secrets&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;clusterSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;loadBalancer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;haproxy&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;exposeType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;ClusterIP&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;percona/percona-xtradb-cluster-operator:1.11.0-haproxy&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;dbInstance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;cpu&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;1G&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;diskSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;15G&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nn"&gt;---&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;apiVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;pxc.percona.com/v1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;PerconaXtraDBCluster&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;test-cluster&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;allowUnsafeConfigurations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;crVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1.11.0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;haproxy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;percona/percona-xtradb-cluster-operator:1.11.0-haproxy&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;serviceType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;ClusterIP&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;pxc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="sd"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; [mysqld]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; wsrep_provider_options="debug=1;gcache.size=1G"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;expose&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;{}&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;percona/percona-xtradb-cluster:8.0.23-14.1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;livenessProbes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;{}&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;readinessProbes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;{}&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;resources&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;cpu&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;1G&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;serviceType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;ClusterIP&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;sidecarResources&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;{}&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;volumeSpec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;persistentVolumeClaim&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;resources&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;15G&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;secretsName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;pxc-sample-secrets&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;updateStrategy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;SmartUpdate&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;upgradeOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;8.0&lt;/span&gt;-&lt;span class="l"&gt;recommended&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;*&lt;span class="w"&gt; &lt;/span&gt;*&lt;span class="w"&gt; &lt;/span&gt;*&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ready&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;ready&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="caveats-and-notes"&gt;Caveats and notes&lt;/h2&gt;
&lt;p&gt;I had problems running tests in Kind. They were flaky because PXC operator can’t expose metrics and had problems with liveness probe. I haven’t figured out how to fix it but as a workaround I use minikube to run tests&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-9" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-9"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; minikube start --nodes=4 --cpus=2 --memory=4g --apiserver-names host.docker.internal --kubernetes-version=v1.23.6
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; minikube kubectl -- config view --flatten --minify &gt; ~/.kube/test-minikube
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; KUBECONFIG=~/.kube/test-minikube kubectl kuttl test --config ./e2e-tests/kuttl.yml&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="further-steps"&gt;Further steps&lt;/h2&gt;
&lt;p&gt;There’s always room for improvement and I have these steps in mind&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Use docker images and OLM bundles as a way to run the operator for tests. This will be the best way to simulate a production like environment.&lt;/li&gt;
&lt;li&gt;Add more advanced tests for database clusters such as running queries, try loading data as well as capacity testing. It’s easily achivable with kuttl&lt;/li&gt;
&lt;/ol&gt;</content:encoded>
      <author>Andrew Minkin</author>
      <category>PMM</category>
      <category>DBaaS</category>
      <category>KUTTL</category>
      <category>testing</category>
      <media:thumbnail url="https://percona.community/blog/2022/12/K8S-KUTTL_hu_89a8b6eb1df21ae3.jpg"/>
      <media:content url="https://percona.community/blog/2022/12/K8S-KUTTL_hu_848f0ae66b9be622.jpg" medium="image"/>
    </item>
    <item>
      <title>Percona Monitoring and Management 2.33 preview release</title>
      <link>https://percona.community/blog/2022/12/08/preview-release/</link>
      <guid>https://percona.community/blog/2022/12/08/preview-release/</guid>
      <pubDate>Thu, 08 Dec 2022 00:00:00 UTC</pubDate>
      <description>Percona Monitoring and Management 2.33 preview release Hello folks! Percona Monitoring and Management (PMM) 2.33 is now available as a preview release.</description>
      <content:encoded>&lt;h2 id="percona-monitoring-and-management-233-preview-release"&gt;Percona Monitoring and Management 2.33 preview release&lt;/h2&gt;
&lt;p&gt;Hello folks! Percona Monitoring and Management (PMM) 2.33 is now available as a preview release.&lt;/p&gt;
&lt;p&gt;We encourage you to try this PMM preview release in &lt;strong&gt;testing environments only&lt;/strong&gt;, as these packages and images are not fully production-ready. The final version is expected to be released through the standard channels in the coming week.&lt;/p&gt;
&lt;p&gt;Release notes can be found in &lt;a href="https://pmm-2-33-0.onrender.com/release-notes/2.33.0.html" target="_blank" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="percona-monitoring-and-management-server-docker"&gt;Percona Monitoring and Management server docker&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://docs.percona.com/percona-monitoring-and-management/setting-up/server/docker.html" target="_blank" rel="noopener noreferrer"&gt;Instructions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;docker tag:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;perconalab/pmm-server:2.33.0-rc&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; In order to use the DBaaS functionality during the Percona Monitoring and Management preview release, you should add the following environment variablewhen starting PMM server:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;PERCONA_TEST_DBAAS_PMM_CLIENT=perconalab/pmm-client:2.33.0-rc&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="percona-monitoring-and-management-client-package-installation"&gt;Percona Monitoring and Management client package installation&lt;/h3&gt;
&lt;p&gt;Download the latest pmm2-client release candidate tarball for 2.33 by this &lt;a href="https://s3.us-east-2.amazonaws.com/pmm-build-cache/PR-BUILDS/pmm2-client/pmm2-client-latest-4615.tar.gz" target="_blank" rel="noopener noreferrer"&gt;link&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you want to install pmm2-client package, please enable testing repository via Percona-release:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;percona-release enable percona testing&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;install pmm2-client package for your OS via package manager.&lt;/p&gt;
&lt;h3 id="ova"&gt;OVA&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://docs.percona.com/percona-monitoring-and-management/setting-up/server/virtual-appliance.html" target="_blank" rel="noopener noreferrer"&gt;Instructions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://percona-vm.s3.amazonaws.com/PMM2-Server-2.33.0.ova" target="_blank" rel="noopener noreferrer"&gt;PMM2-Server-2.33.0.ova&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="ami"&gt;AMI&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://docs.percona.com/percona-monitoring-and-management/setting-up/server/aws.html" target="_blank" rel="noopener noreferrer"&gt;Instructions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ami-005acacf35adcfa57&lt;/code&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Contact us at &lt;a href="mailto:community-team@percona.com"&gt;community-team@percona.com&lt;/a&gt; .&lt;/p&gt;</content:encoded>
      <author>Taras Kozub</author>
      <category>PMM</category>
      <media:thumbnail url="https://percona.community/superhero_hu_252fc2b480c0a197.jpg"/>
      <media:content url="https://percona.community/superhero_hu_17979f11d5d3562e.jpg" medium="image"/>
    </item>
    <item>
      <title>Percona Monitoring and Management 2.32 preview release</title>
      <link>https://percona.community/blog/2022/11/04/preview-release/</link>
      <guid>https://percona.community/blog/2022/11/04/preview-release/</guid>
      <pubDate>Fri, 04 Nov 2022 00:00:00 UTC</pubDate>
      <description>Percona Monitoring and Management 2.32 preview release Hello folks! Percona Monitoring and Management (PMM) 2.32 is now available as a preview release.</description>
      <content:encoded>&lt;h2 id="percona-monitoring-and-management-232-preview-release"&gt;Percona Monitoring and Management 2.32 preview release&lt;/h2&gt;
&lt;p&gt;Hello folks! Percona Monitoring and Management (PMM) 2.32 is now available as a preview release.&lt;/p&gt;
&lt;p&gt;We encourage you to try this PMM preview release in &lt;strong&gt;testing environments only&lt;/strong&gt;, as these packages and images are not fully production-ready. The final version is expected to be released through the standard channels in the coming week.&lt;/p&gt;
&lt;p&gt;Release notes can be found in &lt;a href="https://pmm-doc-2-32-pr-904.onrender.com/release-notes/2.32.0.html" target="_blank" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="percona-monitoring-and-management-server-docker"&gt;Percona Monitoring and Management server docker&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://docs.percona.com/percona-monitoring-and-management/setting-up/server/docker.html" target="_blank" rel="noopener noreferrer"&gt;Instructions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;docker tag:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;perconalab/pmm-server:2.32.0-rc&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; In order to use the DBaaS functionality during the Percona Monitoring and Management preview release, you should add the following environment variablewhen starting PMM server:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;PERCONA_TEST_DBAAS_PMM_CLIENT=perconalab/pmm-client:2.32.0-rc&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="percona-monitoring-and-management-client-package-installation"&gt;Percona Monitoring and Management client package installation&lt;/h3&gt;
&lt;p&gt;Download the latest pmm2-client release candidate tarball for 2.32 by this &lt;a href="https://s3.us-east-2.amazonaws.com/pmm-build-cache/PR-BUILDS/pmm2-client/pmm2-client-latest-4500.tar.gz" target="_blank" rel="noopener noreferrer"&gt;link&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you want to install pmm2-client package, please enable testing repository via Percona-release:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;percona-release enable percona testing&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;install pmm2-client package for your OS via package manager.&lt;/p&gt;
&lt;h3 id="ova"&gt;OVA&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://docs.percona.com/percona-monitoring-and-management/setting-up/server/virtual-appliance.html" target="_blank" rel="noopener noreferrer"&gt;Instructions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://percona-vm.s3.amazonaws.com/PMM2-Server-2.32.0.ova" target="_blank" rel="noopener noreferrer"&gt;PMM2-Server-2.32.0.ova&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="ami"&gt;AMI&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://docs.percona.com/percona-monitoring-and-management/setting-up/server/aws.html" target="_blank" rel="noopener noreferrer"&gt;Instructions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ami-02cfe7580e77fb5fa&lt;/code&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Contact us at &lt;a href="mailto:community-team@percona.com"&gt;community-team@percona.com&lt;/a&gt; .&lt;/p&gt;</content:encoded>
      <author>Taras Kozub</author>
      <category>PMM</category>
      <media:thumbnail url="https://percona.community/superhero_hu_252fc2b480c0a197.jpg"/>
      <media:content url="https://percona.community/superhero_hu_17979f11d5d3562e.jpg" medium="image"/>
    </item>
    <item>
      <title>MySQL: Tracing a single query with PERFORMANCE_SCHEMA</title>
      <link>https://percona.community/blog/2022/10/18/mysql-tracing-a-single-query-with-performance_schema/</link>
      <guid>https://percona.community/blog/2022/10/18/mysql-tracing-a-single-query-with-performance_schema/</guid>
      <pubDate>Tue, 18 Oct 2022 00:00:00 UTC</pubDate>
      <description>My task is to collect performance data about a single query, using PERFORMANCE_SCHEMA (P_S for short) in MySQL, to ship it elsewhere for integration with other data.</description>
      <content:encoded>&lt;p&gt;My task is to collect performance data about a single query, using &lt;code&gt;PERFORMANCE_SCHEMA&lt;/code&gt; (P_S for short) in MySQL, to ship it elsewhere for integration with other data.&lt;/p&gt;
&lt;p&gt;In a grander scheme of things, I will need to define what performance data from a query I am actually interested in.
I will also need to find a way to attribute the query (as seen on the server) to a point in the codebase of the client, which is not always easy when an ORM or other SQL generator is being used.
And finally I will need to find a way to view the query execution in the context of the client code execution, because the data access is only a part of the system performance.&lt;/p&gt;
&lt;p&gt;But this is about query execution in the server, and the instrumentation available to me in MySQL 8, at least to get things started.
So we take the tour of performance schema, and then run one example query (a simple join) and see what we can find out about this query.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;First published on &lt;a href="https://blog.koehntopp.info/2021/09/15/mysql-tracing-a-single-query-with-performanceschema.html" target="_blank" rel="noopener noreferrer"&gt;https://blog.koehntopp.info/&lt;/a&gt; and syndicated here with permission of the &lt;a href="https://percona.community/contributors/koehntopp/"&gt;author&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;h1 id="performance-schema-the-10000-m-view"&gt;Performance Schema, the 10.000 m view&lt;/h1&gt;
&lt;p&gt;&lt;a href="https://dev.mysql.com/doc/refman/8.0/en/performance-schema.html" target="_blank" rel="noopener noreferrer"&gt;The Manual&lt;/a&gt; has a major chapter that covers P_S in details.
The original idea of P_S is to have a bunch of preallocated memory areas without locks, presented to the database itself as tables.&lt;/p&gt;
&lt;p&gt;P_S is unusual in the way that P_S “tables” are never locked while you work with them.
That means the values in a “table” can change while you read them.
That is important - if you for example calculate percentages, they may not add up to 100%.
If you &lt;code&gt;ORDER BY&lt;/code&gt;, the sort may or may not be stable.&lt;/p&gt;
&lt;p&gt;These are good properties: P_S will not freeze the server, and you won’t kill the server by working with P_S tables.&lt;/p&gt;
&lt;p&gt;It is a good idea to make a copy of P_S tables while you work with them, by turning off subquery merging with &lt;code&gt;select /*+ NO_MERGE(t) */ &lt;/code&gt;, and then materializing P_S tables in subqueries.&lt;/p&gt;
&lt;p&gt;Originally, P_S also had no secondary indexes, so joining P_S tables against other P_S tables did not work efficiently.
That was probably a good idea, because joining against a table that is changing while you execute the join is probably generating random results anyway.
But because it is so common, and because MySQL itself does this now internally in &lt;code&gt;sys.*&lt;/code&gt;, secondary indexes to join efficiently now exist.
That does not make the joins more correct, but at least you get the result faster.&lt;/p&gt;
&lt;p&gt;I wrote about all this &lt;a href="https://blog.koehntopp.info/2020/12/01/not-joining-on-performance-schema.html" target="_blank" rel="noopener noreferrer"&gt;in an earlier article&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="instruments-objects-actors-threads-and-consumers"&gt;Instruments, Objects, Actors, Threads and Consumers&lt;/h2&gt;
&lt;p&gt;The data P_S collects is centered around three major things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Time consumed. In database servers, that is mostly wait time - waiting on I/O or locks.&lt;/li&gt;
&lt;li&gt;Data transferred. In database servers, that is mostly pages read or written. In a way, this related to I/O wait.&lt;/li&gt;
&lt;li&gt;Memory used. In database servers, that is buffers allocated - how large, and how often, and peak usage.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;P_S collects this in the form of “events” (and takes care to note that P_S events are not binlog events or other any events).
The collection points are in the database server code, which is instrumented, so the collectors are &lt;em&gt;instruments&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The thing that the server code works on may be of a certain kind, for example a table or another &lt;em&gt;object&lt;/em&gt; in the server, but have a variable identity (that would be different tables, with different names).
Instruments can be filtered by using object names.&lt;/p&gt;
&lt;p&gt;The activity done in the server is done on behalf of a database user, in the form of &lt;em&gt;user@host&lt;/em&gt; or, new in MySQL 8, using roles.
The entity on which behalf the server is working on is called the &lt;em&gt;actor&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The activity done in the server is also done in the context of a &lt;em&gt;thread&lt;/em&gt;, some of which are background threads, while the majority in a busy server are usually connection threads.&lt;/p&gt;
&lt;p&gt;And finally, the data collected is put into the in-memory tables of P_S.
These come in various groups, and are called &lt;em&gt;consumers&lt;/em&gt;.&lt;/p&gt;
&lt;img src="https://blog.koehntopp.info/uploads/2021/09/performance_schema_filtering.png" /&gt;
&lt;p&gt;&lt;em&gt;Data is collected from objects using instruments. Instruments can be turned on and off. Their collected data is then filtered by Objects, Actors and Threads, and finally dropped into consumers. Many consumers are aggregates, some collect information specific to one query execution.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;For each of these things there is a &lt;code&gt;setup_...&lt;/code&gt; table that controls how event data is collected by the instrumentation, filtered and the consumed in result tables.
In parallel, object identities are collected in &lt;code&gt;..._instances&lt;/code&gt; tables, which are needed to resolve object identities.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8025&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;&lt;span class="n"&gt;msandbox&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;performance_schema&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;show&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tables&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;like&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"setup_%"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;----------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Tables_in_performance_schema&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;setup_&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;----------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;setup_actors&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;setup_consumers&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;setup_instruments&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;setup_objects&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;setup_threads&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;----------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;rows&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8025&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;&lt;span class="n"&gt;msandbox&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;performance_schema&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;show&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tables&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;like&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"%_instances"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;--------------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Tables_in_performance_schema&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;_instances&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;--------------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cond_instances&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;file_instances&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mutex_instances&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;prepared_statements_instances&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rwlock_instances&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;socket_instances&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;--------------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;rows&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8025&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;&lt;span class="n"&gt;msandbox&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;performance_schema&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;select&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;socket_instances&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;----------------------------------------+-----------------------+-----------+-----------+-----------+-------+--------+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT_NAME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OBJECT_INSTANCE_BEGIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;THREAD_ID&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SOCKET_ID&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;IP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PORT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;STATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;----------------------------------------+-----------------------+-----------+-----------+-----------+-------+--------+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;mysqlx&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tcpip_socket&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;106328376&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;44&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;18025&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ACTIVE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;mysqlx&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;unix_socket&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;106328688&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;44&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ACTIVE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;server_tcpip_socket&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;106329000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;26&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;127&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8025&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ACTIVE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;server_unix_socket&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;106329312&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;28&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ACTIVE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;client_connection&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;106330560&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;41&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ACTIVE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;----------------------------------------+-----------------------+-----------+-----------+-----------+-------+--------+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;rows&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="current-history-and-history-long-tables-vs-summaries"&gt;Current, History and History Long Tables vs. Summaries&lt;/h2&gt;
&lt;p&gt;P_S collects data in a lot of summary table, which should not interest us that much here.
Our task is to look at the performance data of a single, individual query to better understand what happened when it ran.&lt;/p&gt;
&lt;p&gt;These unaggregated tables are &lt;code&gt;events_transactions&lt;/code&gt;, &lt;code&gt;events_statements&lt;/code&gt;, &lt;code&gt;events_stages&lt;/code&gt; and &lt;code&gt;events_waits&lt;/code&gt;.
For each of them, we have &lt;code&gt;_current&lt;/code&gt;, &lt;code&gt;_history&lt;/code&gt; or &lt;code&gt;_history_long&lt;/code&gt; tables.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;_current&lt;/code&gt; tables contain one entry for the currently running thread.
The &lt;code&gt;_history&lt;/code&gt; tables contain a configurable number of entries for each thread, for example 10 per thread.
And the &lt;code&gt;_history_long&lt;/code&gt; tables contain a configurable number of entries, shared across all threads, for example 10.000 in total.
As the server continues to execute statements and produce events, old entries are discarded and new entries are added, automatically.
Additionally, each query execution is aggregated along several dimensions in summary tables.
Summary tables state these dimension(s) using &lt;code&gt;by_&lt;dimensionname&gt;&lt;/code&gt;, for example &lt;code&gt;_by_user_by_eventname&lt;/code&gt; or similar.&lt;/p&gt;
&lt;p&gt;In current MySQL, P_S is enabled by default.
But not all instruments and consumers are enabled, because some instrumentation slows query execution down, and some consumers can use a lot of memory.
To be fast and safe, all memory is statically allocated at config change so the memory resource usage of P_S is constant and no allocations are made during execution.&lt;/p&gt;
&lt;p&gt;We can enable all instrumentation completely with this SQL:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-1"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8025&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;&lt;span class="n"&gt;msandbox&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;performance_schema&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;performance_schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setup_instruments&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ENABLED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'YES'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TIMED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'YES'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;494&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;rows&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;affected&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="k"&gt;Rows&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;matched&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1216&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Changed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;494&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Warnings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8025&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;&lt;span class="n"&gt;msandbox&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;performance_schema&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;performance_schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setup_consumers&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ENABLED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'YES'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;rows&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;affected&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="k"&gt;Rows&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;matched&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Changed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Warnings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;When we look at one of these tables, for example &lt;code&gt;events_statements_current&lt;/code&gt;, we see a structure like this:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-2" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-2"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8025&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;&lt;span class="n"&gt;msandbox&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;performance_schema&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;show&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;create&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;table&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;events_statements_current&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="k"&gt;G&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;***************************&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;row&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;***************************&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;Table&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;events_statements_current&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="k"&gt;Create&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;Table&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="n"&gt;events_statements_current&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="n"&gt;THREAD_ID&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;bigint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="n"&gt;EVENT_ID&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;bigint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="n"&gt;END_EVENT_ID&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;bigint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DEFAULT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="n"&gt;EVENT_NAME&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="k"&gt;SOURCE&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DEFAULT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="n"&gt;TIMER_START&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;bigint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DEFAULT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="n"&gt;TIMER_END&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;bigint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DEFAULT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="n"&gt;TIMER_WAIT&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;bigint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DEFAULT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="n"&gt;NESTING_EVENT_ID&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;bigint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DEFAULT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="n"&gt;NESTING_EVENT_TYPE&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;enum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'TRANSACTION'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'STATEMENT'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'STAGE'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'WAIT'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DEFAULT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="n"&gt;NESTING_EVENT_LEVEL&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DEFAULT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="n"&gt;STATEMENT_ID&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;bigint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DEFAULT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PRIMARY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="n"&gt;THREAD_ID&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="n"&gt;EVENT_ID&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ENGINE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;PERFORMANCE_SCHEMA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DEFAULT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CHARSET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;utf8mb4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;COLLATE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;utf8mb4_0900_ai_ci&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;row&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;That is, events are tagged with a &lt;code&gt;THREAD_ID&lt;/code&gt; (which is not a CONNECTION_ID() as seen in processlist), an &lt;code&gt;EVENT_ID/END_EVENT_ID&lt;/code&gt; bracket, various source and timer values and for further dissection, a &lt;code&gt;NESTING_EVENT_ID&lt;/code&gt; and &lt;code&gt;_TYPE&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We can translate processlist ids into thread ids using the &lt;code&gt;P_S.THREADS&lt;/code&gt; table, and then use this to limit our view on the &lt;code&gt;events_statements_current&lt;/code&gt; table:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-3" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-3"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8025&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;&lt;span class="n"&gt;msandbox&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;performance_schema&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;select&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;threads&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;where&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;processlist_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;connection_id&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;-----------+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;-----------+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;-----------+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;row&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8025&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;&lt;span class="n"&gt;msandbox&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;performance_schema&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;select&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format_time&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timer_wait&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sql_text&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;events_statements_current&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;where&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="k"&gt;G&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;***************************&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;row&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;***************************&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;88463&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;statement&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;select&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;init_net_server_extension&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;94&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format_time&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timer_wait&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;341&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;04&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;us&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sql_text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;select&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format_time&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timer_wait&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sql_text&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;events_statements_current&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;where&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;row&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;So running this query took 341 Microseconds, or 0.341 ms.
And sources are named after their location in the server sourcecode, &lt;a href="https://github.com/mysql/mysql-server/blob/8.0/sql/conn_handler/init_net_server_extension.cc#L94-L96" target="_blank" rel="noopener noreferrer"&gt;filename and line number&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Events exist in a hierarchy: wait events nest within stage events, which nest within statement events, which nest within transaction events.
Some nested events refer to their own type, for example, statement events can point to other statement events they are nested in.
Other events refer to their enclosing context in the hierarchy.
Nesting Event ID, Type and Level make this clear.&lt;/p&gt;
&lt;h2 id="instrument-names"&gt;Instrument names&lt;/h2&gt;
&lt;p&gt;The manual explains &lt;a href="https://dev.mysql.com/doc/refman/8.0/en/performance-schema-instrument-naming.html" target="_blank" rel="noopener noreferrer"&gt;Instrument Names&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;They have path-like names that group instruments hierarchically, for example &lt;code&gt;wait/io/file/innodb/innodb_data_file&lt;/code&gt;.
This is a &lt;code&gt;wait&lt;/code&gt; event, &lt;code&gt;io&lt;/code&gt; related, specifically &lt;code&gt;file&lt;/code&gt; I/O, more specific &lt;code&gt;innodb&lt;/code&gt; and even more specific &lt;code&gt;innodb_data_file&lt;/code&gt;.
Looking at other fields in the &lt;code&gt;events_waits_history&lt;/code&gt; table, we would see the file name as part of the &lt;code&gt;OBJECT_SCHEMA.OBJECT_NAME&lt;/code&gt; designator for this event.
That means, we can see how long we waited for I/O coming from this specific file or going to the file.&lt;/p&gt;
&lt;p&gt;Further up in the nesting we would see, at the statement level, the actual &lt;code&gt;SQL_TEXT&lt;/code&gt;, and also the number of rows scanned.
That means we can get a rough estimate why this particular statement instance was slow - for example, the plan was good, the number of rows was low, but we see a lot of actual file IO waits, so probably the buffer pool was cold.&lt;/p&gt;
&lt;p&gt;The manual page above discusses the instrument names at length, and it is important to get an overview of what exists and what is measured.
Specifically, for statement level entries the instruments vary during query execution and become more detailed, as they reflect the progress in understanding of the server about the nature of the statement as it is executed.&lt;/p&gt;
&lt;h1 id="an-example-run"&gt;An example run&lt;/h1&gt;
&lt;p&gt;In a freshly restarted idle server, we log in to a shell and &lt;code&gt;use world&lt;/code&gt; for the world sample database.
This is a tiny database, but because the server has been just restarted, nothing of it is cached.
We run a simple query:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-4" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-4"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8025&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;&lt;span class="n"&gt;msandbox&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;world&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;select&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;co&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;continent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;co&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;country&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;co&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;population&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;copop&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ci&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;capital&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ci&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;population&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cipop&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;country&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;co&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;join&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ci&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;co&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;capital&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ci&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;where&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;continent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'Europe'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;-----------+-------------------------------+-----------+------------------------------------+---------+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;continent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;country&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;copop&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;capital&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cipop&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;-----------+-------------------------------+-----------+------------------------------------+---------+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Europe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Albania&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3401200&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Tirana&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;270000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Europe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Yugoslavia&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10640000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Beograd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1204000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;-----------+-------------------------------+-----------+------------------------------------+---------+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;&lt;span class="mi"&gt;46&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;rows&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Now let’s check what we can find out, using a second session:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-5" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-5"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8025&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;&lt;span class="n"&gt;msandbox&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;performance_schema&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;select&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;threads&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;where&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;processlist_db&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'world'&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="k"&gt;G&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;***************************&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;row&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;***************************&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;THREAD_ID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NAME&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;thread&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;one_connection&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TYPE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FOREGROUND&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PROCESSLIST_ID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PROCESSLIST_USER&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;msandbox&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PROCESSLIST_HOST&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PROCESSLIST_DB&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;world&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="n"&gt;PROCESSLIST_COMMAND&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PROCESSLIST_TIME&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PROCESSLIST_STATE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PROCESSLIST_INFO&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PARENT_THREAD_ID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ROLE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;INSTRUMENTED&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;YES&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;HISTORY&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;YES&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CONNECTION_TYPE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Socket&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;THREAD_OS_ID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;346752&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RESOURCE_GROUP&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;USR_default&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;row&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;In our case we are only interested in the fact that our &lt;code&gt;thread/sql/one_connection&lt;/code&gt; in the processlist is shown as connection &lt;code&gt;9&lt;/code&gt;, but internally has a thread_id of &lt;code&gt;48&lt;/code&gt;.
The Linux Operating System PID is &lt;code&gt;346752&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We can use this to check &lt;code&gt;events_transactions_wait&lt;/code&gt;, and find&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-6" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-6"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8025&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;&lt;span class="n"&gt;msandbox&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;performance_schema&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;select&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format_time&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timer_wait&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;timer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nesting_event_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nesting_event_type&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;events_transactions_history&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;where&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;-----------+----------+-----------+-----------------+-----------+------------------+--------------------+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;state&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;source&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;timer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nesting_event_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nesting_event_type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;-----------+----------+-----------+-----------------+-----------+------------------+--------------------+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;179&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;COMMITTED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1328&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;496&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;05&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;us&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;85&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;STATEMENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;COMMITTED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1328&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;559&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;99&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;us&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;278&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;STATEMENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5606&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;COMMITTED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1328&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;03&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ms&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5574&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;STATEMENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;-----------+----------+-----------+-----------------+-----------+------------------+--------------------+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;rows&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Why are there three statement events? We can check:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-7" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-7"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8025&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;&lt;span class="n"&gt;msandbox&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;performance_schema&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;select&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sql_text&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;events_statements_history&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;where&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;85&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;278&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5574&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;-----------+----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sql_text&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;-----------+----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;85&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;show&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;databases&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;278&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;show&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tables&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5574&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;select&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;co&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;continent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;co&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;country&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;co&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;population&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;copop&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ci&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;capital&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ci&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;population&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cipop&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;country&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;co&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;join&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ci&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;co&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;capital&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ci&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;where&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;continent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'Europe'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;-----------+----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;rows&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The mysql command line client is running from the sandbox with &lt;code&gt;/home/kris/opt/mysql/8.0.25/bin/mysql --defaults-file=/home/kris/sandboxes/msb_8_0_25/my.sandbox.cnf world&lt;/code&gt;.
Autocompletion for names is not disabled.
So on client startup, the client invisibly runs &lt;code&gt;show databases&lt;/code&gt; to learn the names of all databases for autocompletion.
It then enters the &lt;code&gt;world&lt;/code&gt; database as requested and runs &lt;code&gt;show tables&lt;/code&gt; to learn the names of all tables in the &lt;code&gt;world&lt;/code&gt; database.&lt;/p&gt;
&lt;p&gt;Only then we come to the prompt and can paste our query.&lt;/p&gt;
&lt;p&gt;We are only interested in &lt;code&gt;thread_id = 48 AND event_id = 5574&lt;/code&gt;, our query.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-8" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-8"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8025&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;&lt;span class="n"&gt;msandbox&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;performance_schema&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;select&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;events_statements_history&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;where&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5574&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="k"&gt;G&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;***************************&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;row&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;***************************&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;THREAD_ID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT_ID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5574&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;END_EVENT_ID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6624&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT_NAME&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;statement&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;select&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SOURCE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;init_net_server_extension&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;94&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TIMER_START&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;61628458852000&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TIMER_END&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;61631769329000&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TIMER_WAIT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3310477000&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LOCK_TIME&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;224000000&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SQL_TEXT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;select&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;co&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;continent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;co&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;country&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;co&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;population&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;copop&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ci&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;capital&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ci&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;population&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cipop&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;country&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;co&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;join&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ci&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;co&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;capital&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ci&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;where&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;continent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'Europe'&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DIGEST&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;409&lt;/span&gt;&lt;span class="n"&gt;c336982f0d3d45c4b29da77fe83aed12c6043e8ce9771c11ec82ff347e647&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DIGEST_TEXT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="n"&gt;co&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="n"&gt;continent&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="n"&gt;co&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="n"&gt;country&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="n"&gt;co&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="n"&gt;population&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="n"&gt;copop&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="n"&gt;ci&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="n"&gt;capital&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="n"&gt;ci&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="n"&gt;population&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="n"&gt;cipop&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="n"&gt;country&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="n"&gt;co&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="n"&gt;ci&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="n"&gt;co&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="n"&gt;capital&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="n"&gt;ci&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="n"&gt;continent&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CURRENT_SCHEMA&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;world&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OBJECT_TYPE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OBJECT_SCHEMA&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OBJECT_NAME&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OBJECT_INSTANCE_BEGIN&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MYSQL_ERRNO&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;RETURNED_SQLSTATE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;MESSAGE_TEXT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ERRORS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;WARNINGS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ROWS_AFFECTED&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ROWS_SENT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;46&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ROWS_EXAMINED&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;92&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="n"&gt;CREATED_TMP_DISK_TABLES&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CREATED_TMP_TABLES&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SELECT_FULL_JOIN&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SELECT_FULL_RANGE_JOIN&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SELECT_RANGE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SELECT_RANGE_CHECK&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SELECT_SCAN&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SORT_MERGE_PASSES&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SORT_RANGE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SORT_ROWS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SORT_SCAN&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NO_INDEX_USED&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NO_GOOD_INDEX_USED&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NESTING_EVENT_ID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NESTING_EVENT_TYPE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NESTING_EVENT_LEVEL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;STATEMENT_ID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;125&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;row&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The statement is &lt;code&gt;statement/sql/select&lt;/code&gt;.
It took 3310477000 picoseconds (3.31ms) to run.
The &lt;code&gt;sql_text&lt;/code&gt; is the full text of the statement (up to a cutoff point, in order to manage memory consumption).
The parsed statement is called &lt;code&gt;digest_text&lt;/code&gt; - identifiers are quoted, whitespace is normalized, actual constants are replaced with placeholders, and (not shown here) variable length &lt;code&gt;WHERE ... IN (...)&lt;/code&gt; clauses are shortened with ellipses.
This normalized digest is then hashed and produces an identifier for this group of identically formed statements, the &lt;code&gt;digest&lt;/code&gt;.
We learn about the number of rows looked at, &lt;code&gt;92&lt;/code&gt; and sent, &lt;code&gt;46&lt;/code&gt;.
No special flags indicating specific execution modes were set.&lt;/p&gt;
&lt;p&gt;We can use the &lt;code&gt;event_id&lt;/code&gt; to look even deeper:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-9" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-9"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8025&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;&lt;span class="n"&gt;msandbox&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;performance_schema&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;select&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format_time&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timer_wait&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;timer&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;events_stages_history&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;where&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nesting_event_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5574&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;order&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;by&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;-----------+----------+--------------------------------------+----------------------+-----------+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;source&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;timer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;-----------+----------+--------------------------------------+----------------------+-----------+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5610&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;optimizing&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sql_optimizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;270&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;88&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;us&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5611&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;statistics&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sql_optimizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;534&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;703&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;58&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;us&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5710&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;preparing&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sql_optimizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;618&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;31&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;93&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;us&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5712&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;executing&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sql_union&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1126&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;26&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ms&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6593&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sql_select&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;586&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;86&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;us&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6594&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sql_parse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;4542&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;93&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;us&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6596&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;waiting&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;handler&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;commit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1594&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;05&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;us&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6600&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;closing&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tables&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sql_parse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;4593&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;02&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;us&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6621&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;freeing&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sql_parse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;5042&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;29&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;us&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6623&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;cleaning&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;up&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sql_parse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;2252&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;us&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;-----------+----------+--------------------------------------+----------------------+-----------+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;rows&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;These are the various execution stages of our statement - we select by &lt;code&gt;thread_id&lt;/code&gt; and with the &lt;code&gt;event_id&lt;/code&gt; of the statement, &lt;code&gt;5574&lt;/code&gt; as a &lt;code&gt;nesting_id&lt;/code&gt;, ordered by &lt;code&gt;event_id&lt;/code&gt;.
Time was consumed by the &lt;code&gt;stage/sql/statistics&lt;/code&gt; phase, looking up table stats for a good execution plan, and then by the actual query execution in &lt;code&gt;stage/sql/executing&lt;/code&gt;.
The former took 0.7ms (703.58us), the latter 2.26ms.&lt;/p&gt;
&lt;p&gt;We are interested in what took so long, specifically, so we look into waits for event_ids 5611 and 5712 - finding nothing, and also nothing particularly time-consuming:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-10" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-10"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8025&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;&lt;span class="n"&gt;msandbox&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;performance_schema&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;select&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format_time&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timer_wait&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;timer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nesting_event_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nesting_event_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;operation&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;events_waits_history&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;where&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;order&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;by&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;-----------+----------+------------------------------------------+-----------+--------------------+------------------+-----------+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;timer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nesting_event_type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nesting_event_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;operation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;-----------+----------+------------------------------------------+-----------+--------------------+------------------+-----------+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6614&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;synch&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;innodb&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;trx_mutex&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;56&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;26&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;STAGE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6600&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;lock&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6615&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;synch&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;innodb&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;trx_mutex&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;STAGE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6600&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;lock&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6616&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;synch&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;innodb&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;trx_mutex&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;STAGE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6600&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;lock&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6617&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;synch&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;innodb&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;trx_mutex&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;46&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;88&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;STAGE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6600&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;lock&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6618&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;synch&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;innodb&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;trx_mutex&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;43&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;36&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;STAGE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6600&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;lock&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6619&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;synch&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;innodb&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;trx_mutex&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;45&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;STAGE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6600&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;lock&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6620&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;synch&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;LOCK_table_cache&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;66&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;STAGE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6600&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;lock&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6622&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;client_connection&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;91&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;us&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;STAGE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6621&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6624&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;synch&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;THD&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;LOCK_thd_query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;124&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;STAGE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6623&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;lock&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6626&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;client_connection&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;WAIT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6625&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;recv&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;-----------+----------+------------------------------------------+-----------+--------------------+------------------+-----------+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;rows&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;We can see I/O in a global summary, and the timings make sense in the context of the experiment:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-11" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-11"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8025&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;&lt;span class="n"&gt;msandbox&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;performance_schema&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;select&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;object_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;object_schema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;object_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;count_star&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format_time&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_timer_read&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="k"&gt;read&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format_time&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_timer_write&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="k"&gt;write&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format_time&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_timer_fetch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="k"&gt;fetch&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;table_io_waits_summary_by_table&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;where&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;object_schema&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'world'&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="k"&gt;G&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;***************************&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;row&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;***************************&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;object_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="n"&gt;object_schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;world&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;object_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;count_star&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;46&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;read&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;569&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;us&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;write&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ps&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;569&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;us&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;***************************&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;row&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;***************************&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;object_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="n"&gt;object_schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;world&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;object_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;country&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;count_star&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;47&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;read&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;703&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;us&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;write&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ps&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;703&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;us&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;But why are the I/O times not visible to us?
That’s a bit unclear.
My theory was that the reads happen asynchronously by some background thread.
But a quick query shows no time spend on reader threads.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-12" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-12"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8025&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;&lt;span class="n"&gt;msandbox&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;performance_schema&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;select&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;threads&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;join&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;events_waits_summary_by_thread_by_event_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;where&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;max_timer_wait&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;event_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'wait/io/file/innodb/innodb_data_file'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;-----------+---------------------------------------------+------------+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;-----------+---------------------------------------------+------------+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;thread&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BACKGROUND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;thread&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;innodb&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;io_write_thread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BACKGROUND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;thread&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;innodb&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;io_write_thread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BACKGROUND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;thread&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;innodb&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;io_write_thread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BACKGROUND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;thread&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;innodb&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;io_write_thread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BACKGROUND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;thread&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;innodb&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;page_flush_coordinator_thread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BACKGROUND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;33&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;thread&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;innodb&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;clone_gtid_thread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BACKGROUND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;47&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;thread&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;one_connection&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FOREGROUND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;thread&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;one_connection&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FOREGROUND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;-----------+---------------------------------------------+------------+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;rows&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;We seem to be unable to attribute time spent loading data from disk to a specific thread, and we seem to be unable to account for the runtime of certain stages by looking at waits.
That’s unexpected.&lt;/p&gt;
&lt;h1 id="memory-only-as-summary"&gt;Memory only as summary&lt;/h1&gt;
&lt;p&gt;Diverse &lt;code&gt;memory_%&lt;/code&gt; tables exist to track memory usage in the server.
All of these tables are summary tables, there are no memory events tables that could trace memory usage per query.
That might be okay.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-13" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-13"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8025&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;&lt;span class="n"&gt;msandbox&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;performance_schema&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;show&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tables&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;like&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'%memory%'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;-----------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Tables_in_performance_schema&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;-----------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;memory_summary_by_account_by_event_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;memory_summary_by_host_by_event_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;memory_summary_by_thread_by_event_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;memory_summary_by_user_by_event_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;memory_summary_global_by_event_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;-----------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;rows&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;We can do interesting things with stuff such as &lt;code&gt;memory_summary_by_thread_by_event_name&lt;/code&gt;, at least on our mostly idle server.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;sql&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-14" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-14"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8025&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;&lt;span class="n"&gt;msandbox&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;performance_schema&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;select&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;count_alloc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sum_number_of_bytes_alloc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;high_number_of_bytes_used&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;memory_summary_by_thread_by_event_name&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;where&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;HIGH_NUMBER_OF_BYTES_USED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;order&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;by&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;HIGH_NUMBER_OF_BYTES_USED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;desc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;limit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;-----------+-------------------------------+-------------+---------------------------+---------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;count_alloc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sum_number_of_bytes_alloc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;high_number_of_bytes_used&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;-----------+-------------------------------+-------------+---------------------------+---------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;THD&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;main_mem_root&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1181008&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;613544&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;innodb&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;226&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1059368&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;250032&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;dd&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;205&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;47432&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;44648&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;innodb&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;ha_innodb&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;26&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;35784&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;35784&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;innodb&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;fil0fil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;65600&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;32800&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;-----------+-------------------------------+-------------+---------------------------+---------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;rows&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h1 id="no-explain"&gt;No EXPLAIN&lt;/h1&gt;
&lt;p&gt;Another thing that would be useful to collect from P_S is the actual execution plan of a query.
But while we can explain a lot of statements by running &lt;code&gt;EXPLAIN &lt;stmt&gt;&lt;/code&gt;, and while we can &lt;code&gt;EXPLAIN FOR CONNECT ...&lt;/code&gt;, the former is not the recorded execution plan, and the latter only works while the query is running.
It’s the actual execution plan while the query executes, but it is not recorded.&lt;/p&gt;
&lt;h1 id="summary"&gt;Summary&lt;/h1&gt;
&lt;p&gt;A lot of information about query execution can be gathered from P_S.
The query execution can be broken down in statements, stages and waits.
Specifically, statements collect a lot of interesting quality flags.
Stages can collect percentages of completion for long-running queries and give a general feel about where in the query execution time is spent.
Waits should be able to attribute time to individual operations in the database server, but specifically for file I/O this seems to be more complicated, and I have not been able to solve it.&lt;/p&gt;
&lt;p&gt;We can see waits for I/O summary tables, and we can see a lot of other statistical information in other summary tables.
We can also use additional tables not covered here for debugging (for example &lt;code&gt;DATA_LOCKS&lt;/code&gt; for locking behavior).&lt;/p&gt;
&lt;p&gt;Memory instrumentation is interesting, but at this stage it is unclear to me if it is sufficient.&lt;/p&gt;
&lt;p&gt;It seems to be really hard to record execution plans together with statements.&lt;/p&gt;
&lt;p&gt;More experimentation with more complicated queries is necessary to see if it is possible to see things like sorting, temp files and similar operations, and attribute time to these operations.&lt;/p&gt;
&lt;p&gt;The number of queries on P_S necessary to extract information about a single query is staggering, a 10:1 ratio.
At least filters exist and are on by default, so that I do not have to hear my monitoring noise in my monitoring.
That is good.&lt;/p&gt;
&lt;p&gt;I could really use a single large JSON blob containing the entire package with performance data for a query, at once - one query to trace one query.
That is, the information from transaction, statement, stages, waits, the execution plan and the memory consumption for a given transaction or statement, in one go.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;First published on &lt;a href="https://blog.koehntopp.info/2021/09/15/mysql-tracing-a-single-query-with-performanceschema.html" target="_blank" rel="noopener noreferrer"&gt;https://blog.koehntopp.info/&lt;/a&gt; and syndicated here with permission of the &lt;a href="https://percona.community/contributors/koehntopp/"&gt;author&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;</content:encoded>
      <author>Kristian Köhntopp</author>
      <category>MySQL</category>
      <media:thumbnail url="https://percona.community/blog/2022/10/mysql-tracing-a-single-query_hu_b2d226be793a1ee7.jpg"/>
      <media:content url="https://percona.community/blog/2022/10/mysql-tracing-a-single-query_hu_bd5f0967e8de6c92.jpg" medium="image"/>
    </item>
    <item>
      <title>Learning Kubernetes Operators with Percona Operator for MongoDB</title>
      <link>https://percona.community/blog/2022/10/13/learning-kubernetes-operators-with-percona-operator-for-mongodb/</link>
      <guid>https://percona.community/blog/2022/10/13/learning-kubernetes-operators-with-percona-operator-for-mongodb/</guid>
      <pubDate>Thu, 13 Oct 2022 00:00:00 UTC</pubDate>
      <description>One of the topics that have resonated a lot for me since the first KubeCon I attended in 2018 is Kubernetes Operators.</description>
      <content:encoded>&lt;p&gt;One of the topics that have resonated a lot for me since the first KubeCon I attended in 2018 is &lt;strong&gt;Kubernetes Operators&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The concept of Operators was introduced much earlier in 2016 by the CoreOS Linux development team. They were looking for a way to improve automated container management in Kubernetes.&lt;/p&gt;
&lt;h2 id="what-do-we-mean-by-a-kubernetes-operator"&gt;What do we mean by a Kubernetes Operator?&lt;/h2&gt;
&lt;p&gt;We use the &lt;a href="https://www.cncf.io/blog/2022/06/15/kubernetes-operators-what-are-they-some-examples/#:~:text=K8s%20Operators%20are%20controllers%20for,Custom%20Resource%20Definitions%20%28CRD%29." target="_blank" rel="noopener noreferrer"&gt;definition of CNCF&lt;/a&gt;. The Kubernetes project defines &lt;strong&gt;“Operator”&lt;/strong&gt; simply: &lt;strong&gt;“Operators are software extensions that use custom resources to manage applications and their components“&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;This means that among the applications that can be run on Kubernetes, there are applications that still require manual operations to manage them and complete the Kubernetes deployment cycle because Kubernetes itself can’t manage all these manual operations. It is what the Operators take care of, to automate those manual processes of the applications deployed in Kubernetes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How can this be possible?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The Operators use/extend the &lt;strong&gt;Kubernetes API&lt;/strong&gt; (this API has the basics needed for a user to interact with the Kubernetes cluster) and create &lt;a href="https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/#:~:text=A%20custom%20resource%20is%20an,resources%2C%20making%20Kubernetes%20more%20modular." target="_blank" rel="noopener noreferrer"&gt;custom resources&lt;/a&gt; to add new functionality according to the needs of an application to be flexible and scalable.&lt;/p&gt;
&lt;p&gt;Once the creation of the &lt;strong&gt;custom resource&lt;/strong&gt; is finished, it creates objects that can be managed using kubectl, as other default Kubernetes resources are managed, such as Deployments, Pods, etc.&lt;/p&gt;
&lt;p&gt;Here we see the difference between the workflows with and without operators.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;With Operators&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2022/13/with-operators_hu_25016fe3b8ee1355.png 480w, https://percona.community/blog/2022/13/with-operators_hu_e7bb015fe7e101a6.png 768w, https://percona.community/blog/2022/13/with-operators_hu_858a6341bc137533.png 1400w"
src="https://percona.community/blog/2022/13/with-operators.png" alt="With Operators" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Without Operators&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2022/13/without-operators_hu_5377d9c9d2b94577.png 480w, https://percona.community/blog/2022/13/without-operators_hu_f7bbc57613f173b6.png 768w, https://percona.community/blog/2022/13/without-operators_hu_3c994909e3b25a95.png 1400w"
src="https://percona.community/blog/2022/13/without-operators.png" alt="Without Operators" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;The above illustration is based on a presentation by &lt;a href="https://youtu.be/i9V4oCa5f9I?t=403" target="_blank" rel="noopener noreferrer"&gt;Sai Vennam&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It is time for an example!
We will see how Percona Operator for MongoDB works.&lt;/p&gt;
&lt;p&gt;Percona Operator for MongoDB contains everything we need to quickly and consistently deploy and scale &lt;a href="https://www.percona.com/software/mongodb/percona-server-for-mongodb" target="_blank" rel="noopener noreferrer"&gt;Percona Server for MongoDB instances&lt;/a&gt; into a Kubernetes cluster on-premises or in the cloud.&lt;/p&gt;
&lt;p&gt;You can find Percona Operator for MongoDB officially in:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://artifacthub.io/packages/olm/community-operators/percona-server-mongodb-operator" target="_blank" rel="noopener noreferrer"&gt;Artifact Hub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://operatorhub.io/operator/percona-server-mongodb-operator" target="_blank" rel="noopener noreferrer"&gt;Operator Hub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Why does Percona Server for MongoDB (a database) need a Kubernetes Operator?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Kubernetes has been designed for stateless applications. Kubernetes in many cases doesn’t require operators for stateless applications because Kubernetes doesn’t need more automation logic. But stateful applications like databases do need operators because they cannot automate the entire process natively.&lt;/p&gt;
&lt;p&gt;One of the main benefits of operators is the automation of repetitive tasks that are often handled by human operators, eliminating errors in application lifecycle management.&lt;/p&gt;
&lt;h2 id="installing-mongodb-percona-operator-using-gke"&gt;Installing MongoDB Percona Operator using GKE&lt;/h2&gt;
&lt;p&gt;This guide shows you how to deploy &lt;strong&gt;Percona Operator for MongoDB&lt;/strong&gt; on &lt;strong&gt;Google Kubernetes Engine (GKE)&lt;/strong&gt;. We use GKE which takes less time to set up Kubernetes in Google Cloud just for the purpose of this demo. This demonstration assumes you have some experience with the platform. For more information on the GKE, see &lt;a href="https://cloud.google.com/kubernetes-engine/docs/deploy-app-cluster." target="_blank" rel="noopener noreferrer"&gt;Kubernetes Engine Quickstart&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;As prerequisites, we need &lt;a href="https://docs.percona.com/percona-operator-for-mongodb/gke.html#prerequisites" target="_blank" rel="noopener noreferrer"&gt;Google Cloud shell and Kubectl&lt;/a&gt;. You can find the installation guides for AWS and AZURE in the &lt;a href="https://docs.percona.com/percona-operator-for-mongodb/#advanced-installation-guides" target="_blank" rel="noopener noreferrer"&gt;Percona documentation&lt;/a&gt;. Let´s start!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Creating a GKE cluster with three nodes.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gcloud container clusters create my-cluster-name --project percona-product --zone us-central1-a --cluster-version 1.23 --machine-type n1-standard-4 --num-nodes&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2022/13/1-operators-gcloud_hu_de723b372159705f.png 480w, https://percona.community/blog/2022/13/1-operators-gcloud_hu_ea395a17e92310cb.png 768w, https://percona.community/blog/2022/13/1-operators-gcloud_hu_861f73d47bb21ff9.png 1400w"
src="https://percona.community/blog/2022/13/1-operators-gcloud.png" alt="Overview" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Now you should configure the command-line access to your newly created cluster to make kubectl able to use it.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-1"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gcloud container clusters get-credentials my-cluster-name --zone us-central1-a --project percona-product&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2022/13/2-operators-get-credentials_hu_8097b375aa73fbcf.png 480w, https://percona.community/blog/2022/13/2-operators-get-credentials_hu_e5b63776963c800b.png 768w, https://percona.community/blog/2022/13/2-operators-get-credentials_hu_e169e84be299341e.png 1400w"
src="https://percona.community/blog/2022/13/2-operators-get-credentials.png" alt="Overview" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Finally, use your &lt;a href="https://cloud.google.com/iam" target="_blank" rel="noopener noreferrer"&gt;Cloud Identity and Access Management [Cloud IAM]&lt;/a&gt; to control access to the cluster. The following command will give you the ability to create Roles and RoleBindings:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-2" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-2"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl create clusterrolebinding cluster-admin-binding --clusterrole cluster-admin --user &lt;span class="k"&gt;$(&lt;/span&gt;gcloud config get-value core/account&lt;span class="k"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2022/13/3-kubectl-create-cluisterrolebinding_hu_f39b8053e9ddaeca.png 480w, https://percona.community/blog/2022/13/3-kubectl-create-cluisterrolebinding_hu_f39683c329e3ef82.png 768w, https://percona.community/blog/2022/13/3-kubectl-create-cluisterrolebinding_hu_eee4cd83e1a80d7.png 1400w"
src="https://percona.community/blog/2022/13/3-kubectl-create-cluisterrolebinding.png" alt="Overview" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h3 id="install-the-operator-and-deploy-your-mongodb-cluster"&gt;Install the Operator and deploy your MongoDB cluster&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Create a new namespace called &lt;strong&gt;percona-demo-namespace&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-3" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-3"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl create namespace percona-demo-namespace&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2022/13/4-kubectl-create-namespace.png" alt="Overview" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Set the context for the namespace&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-4" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-4"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl config set-context &lt;span class="k"&gt;$(&lt;/span&gt;kubectl config current-context&lt;span class="k"&gt;)&lt;/span&gt; --namespace&lt;span class="o"&gt;=&lt;/span&gt;percona-demo-namespace&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2022/13/5-kubectl-config-set-contex_hu_1080c21e94cf84db.png 480w, https://percona.community/blog/2022/13/5-kubectl-config-set-contex_hu_4ea4341c3e043911.png 768w, https://percona.community/blog/2022/13/5-kubectl-config-set-contex_hu_deef002f9d32086f.png 1400w"
src="https://percona.community/blog/2022/13/5-kubectl-config-set-contex.png" alt="Overview" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Deploy the Operator&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-5" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-5"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl apply -f https://raw.githubusercontent.com/percona/percona-server-mongodb-operator/v1.13.0/deploy/bundle.yaml&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2022/13/6-kubectl-apply-f-bundle_hu_b7cfd39a938c998.png 480w, https://percona.community/blog/2022/13/6-kubectl-apply-f-bundle_hu_51373f5156f5b8fb.png 768w, https://percona.community/blog/2022/13/6-kubectl-apply-f-bundle_hu_80edbe4bcf31daa8.png 1400w"
src="https://percona.community/blog/2022/13/6-kubectl-apply-f-bundle.png" alt="Overview" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The operator has been started, and you can deploy your MongoDB cluster:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-6" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-6"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl apply -f https://raw.githubusercontent.com/percona/percona-server-mongodb-operator/v1.13.0/deploy/cr.yaml&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2022/13/7-kubectl-apply-f-cr_hu_e15f0b4f5f83c92b.png 480w, https://percona.community/blog/2022/13/7-kubectl-apply-f-cr_hu_beee7a6c3f1bcc2f.png 768w, https://percona.community/blog/2022/13/7-kubectl-apply-f-cr_hu_b93531c29e27188.png 1400w"
src="https://percona.community/blog/2022/13/7-kubectl-apply-f-cr.png" alt="Overview" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When the process is over, your cluster will obtain the ready status. Check with:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-7" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-7"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; kubectl get psmdb.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2022/13/8-kubectl-get-psmdb_hu_ab0b66e14d3e0dce.png 480w, https://percona.community/blog/2022/13/8-kubectl-get-psmdb_hu_3b90fcee2f23f22e.png 768w, https://percona.community/blog/2022/13/8-kubectl-get-psmdb_hu_d1b125d7248e7401.png 1400w"
src="https://percona.community/blog/2022/13/8-kubectl-get-psmdb.png" alt="Overview" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; “psmdb” stands for &lt;a href="https://www.percona.com/software/mongodb/percona-server-for-mongodb" target="_blank" rel="noopener noreferrer"&gt;Percona Server for MongoDB&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="verifying-the-cluster-operation"&gt;Verifying the cluster operation&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;You will need the login and password for the admin user to access the cluster. Use kubectl get secrets command to see the list of Secrets objects&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-8" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-8"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl get secret my-cluster-name-secrets -o yaml&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2022/13/9-kubectl-get-secret.png" alt="Overview" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Bring it back to a human-readable form to &lt;strong&gt;MONGODB_DATABASE_ADMIN_PASSWORD&lt;/strong&gt; and &lt;strong&gt;MONGODB_DATABASE_ADMIN_USER&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2022/13/10-decode_hu_da6ebad61ea4ad21.png 480w, https://percona.community/blog/2022/13/10-decode_hu_29ea244e25562ac0.png 768w, https://percona.community/blog/2022/13/10-decode_hu_769410ebe71992c5.png 1400w"
src="https://percona.community/blog/2022/13/10-decode.png" alt="Overview" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We check the details of the Services, before testing the connection to the cluster&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2022/13/11-get-services_hu_e92af432fa97bcfe.png 480w, https://percona.community/blog/2022/13/11-get-services_hu_42b31a5d2454eb28.png 768w, https://percona.community/blog/2022/13/11-get-services_hu_6c04eb35762d6405.png 1400w"
src="https://percona.community/blog/2022/13/11-get-services.png" alt="Overview" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Run a Docker container with a MongoDB client and connect its console output to your terminal. The following command will do this, naming the new Pod percona-client:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-9" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-9"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl run -i --rm --tty percona-client --image&lt;span class="o"&gt;=&lt;/span&gt;percona/percona-server-mongodb:4.4.16-16 --restart&lt;span class="o"&gt;=&lt;/span&gt;Never -- bash -il&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2022/13/12-run-docker-container_hu_356e62773d644d48.png 480w, https://percona.community/blog/2022/13/12-run-docker-container_hu_bff79e73a0bb2abe.png 768w, https://percona.community/blog/2022/13/12-run-docker-container_hu_4a6102786c9b3333.png 1400w"
src="https://percona.community/blog/2022/13/12-run-docker-container.png" alt="Overview" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Now run mongo tool in the percona-client command shell using the login (which is normally clusterAdmin)&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-10" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-10"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mongo &lt;span class="s2"&gt;"mongodb://clusterAdmin:Dgqjc1HElUvvGnH9@my-cluster-name-mongos.percona-demo-namespace.svc.cluster.local/admin?ssl=false"&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2022/13/13-mongo_hu_63f0d96c6ef06538.png 480w, https://percona.community/blog/2022/13/13-mongo_hu_7d8ef4e37f86ba6e.png 768w, https://percona.community/blog/2022/13/13-mongo_hu_758cba1cf4d7227c.png 1400w"
src="https://percona.community/blog/2022/13/13-mongo.png" alt="Overview" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Woolaaa!&lt;/strong&gt; We have deployed MongoDB in Kubernetes using Operator, It works! &lt;strong&gt;:)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Now that you have the MongoDB cluster, you have full control to configure and manage MongoDB deployment from a single Kubernetes control plane, which means that you can manage MongoDB instances in the same way you manage default objects in Kubernetes like Deployments, Pods, or Services. For advanced configuration, topics see our guide &lt;a href="https://docs.percona.com/percona-operator-for-mongodb/users.html" target="_blank" rel="noopener noreferrer"&gt;Percona Operator for MongoDB&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="conclusion"&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;Kubernetes Operators extend the Kubernetes API to automate processes that cannot be achieved natively with Kubernetes. This is the case for stateful applications like MongoDB.
Percona develops &lt;a href="https://github.com/percona/percona-server-mongodb-operator" target="_blank" rel="noopener noreferrer"&gt;Percona Operator for MongoDB&lt;/a&gt; that contains everything you need to quickly and consistently deploy and scale Percona Server for MongoDB instances into a Kubernetes cluster on-premises or in the cloud. You can try it on different cloud providers and &lt;a href="https://docs.percona.com/percona-operator-for-mongodb/#advanced-installation-guides" target="_blank" rel="noopener noreferrer"&gt;tutorials&lt;/a&gt; for more advanced configurations.&lt;/p&gt;
&lt;p&gt;You can find &lt;strong&gt;Percona Operator for MongoDB&lt;/strong&gt; in Hacktoberfest! If you’re looking to improve your Kubernetes skills, this is a &lt;a href="https://www.percona.com/blog/contribute-to-open-source-with-percona-and-hacktoberfest/" target="_blank" rel="noopener noreferrer"&gt;great project to start contributing&lt;/a&gt; to.&lt;/p&gt;
&lt;p&gt;We also have a &lt;strong&gt;&lt;a href="https://github.com/percona/roadmap/projects/1" target="_blank" rel="noopener noreferrer"&gt;public roadmap&lt;/a&gt;&lt;/strong&gt; of Percona Kubernetes Operators. If you have any feedback or want to draw our attention to a particular feature, feel free to be part of it and vote for issues! :)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Resources:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=HZ9yaS-ZS48&amp;t=2809s" target="_blank" rel="noopener noreferrer"&gt;Installation of MongoDB via Kubernetes Operator by Sergey Pronin - MongoDB Kubernetes operator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.percona.com/percona-operator-for-mongodb/gke.html" target="_blank" rel="noopener noreferrer"&gt;Install Percona Server for MongoDB on Google Kubernetes Engine (GKE)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/percona/percona-server-mongodb-operator" target="_blank" rel="noopener noreferrer"&gt;Percona Server Mongodb Operator GitHub Repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.cncf.io/blog/2022/06/15/kubernetes-operators-what-are-they-some-examples/#:~:text=K8s%20Operators%20are%20controllers%20for,Custom%20Resource%20Definitions%20%28CRD%29." target="_blank" rel="noopener noreferrer"&gt;Kubernetes Operators: what are they? Some examples CNCF.IO&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=i9V4oCa5f9I" target="_blank" rel="noopener noreferrer"&gt;Kubernetes Operators Explained by Sai Vennam&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://iximiuz.com/en/series/working-with-kubernetes-api/" target="_blank" rel="noopener noreferrer"&gt;Working with Kubernetes API Ivan Velichko&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded>
      <author>Edith Puclla</author>
      <category>kubernetes</category>
      <category>operators</category>
      <category>databases</category>
      <category>mongodb</category>
      <category>docker</category>
      <media:thumbnail url="https://percona.community/blog/2022/13/with-operators_hu_bdd003d62e36fb66.jpg"/>
      <media:content url="https://percona.community/blog/2022/13/with-operators_hu_59b4693fcad8842d.jpg" medium="image"/>
    </item>
    <item>
      <title>Percona Monitoring and Management 2.31 preview release</title>
      <link>https://percona.community/blog/2022/09/19/preview-release/</link>
      <guid>https://percona.community/blog/2022/09/19/preview-release/</guid>
      <pubDate>Mon, 19 Sep 2022 00:00:00 UTC</pubDate>
      <description>Percona Monitoring and Management 2.31 preview release Hello folks! Percona Monitoring and Management (PMM) 2.31 is now available as a preview release.</description>
      <content:encoded>&lt;h2 id="percona-monitoring-and-management-231-preview-release"&gt;Percona Monitoring and Management 2.31 preview release&lt;/h2&gt;
&lt;p&gt;Hello folks! Percona Monitoring and Management (PMM) 2.31 is now available as a preview release.&lt;/p&gt;
&lt;p&gt;We encourage you to try this PMM preview release in &lt;strong&gt;testing environments only&lt;/strong&gt;, as these packages and images are not fully production-ready. The final version is expected to be released through the standard channels in the coming week.&lt;/p&gt;
&lt;p&gt;Release notes can be found in &lt;a href="https://pmm-v2-31-0-pr-868.onrender.com/release-notes/2.31.0.html" target="_blank" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="known-issue"&gt;Known issue&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://perconadev.atlassian.net/browse/PMM-10735" target="_blank" rel="noopener noreferrer"&gt;PMM-10735&lt;/a&gt;: OVF stopped working in a few minutes.&lt;/p&gt;
&lt;h3 id="percona-monitoring-and-management-server-docker"&gt;Percona Monitoring and Management server docker&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://docs.percona.com/percona-monitoring-and-management/setting-up/server/docker.html" target="_blank" rel="noopener noreferrer"&gt;Instructions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;docker tag:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;perconalab/pmm-server:2.31.0-rc&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; In order to use the DBaaS functionality during the Percona Monitoring and Management preview release, you should add the following environment variablewhen starting PMM server:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;PERCONA_TEST_DBAAS_PMM_CLIENT=perconalab/pmm-client:2.31.0-rc&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="percona-monitoring-and-management-client-package-installation"&gt;Percona Monitoring and Management client package installation&lt;/h3&gt;
&lt;p&gt;Download the latest pmm2-client release candidate tarball for 2.31 by this &lt;a href="https://s3.us-east-2.amazonaws.com/pmm-build-cache/PR-BUILDS/pmm2-client/pmm2-client-latest-4348.tar.gz" target="_blank" rel="noopener noreferrer"&gt;link&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you want to install pmm2-client package, please enable testing repository via Percona-release:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;percona-release enable percona testing&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;install pmm2-client package for your OS via package manager.&lt;/p&gt;
&lt;hr&gt;</content:encoded>
      <author>Taras Kozub</author>
      <category>PMM</category>
      <media:thumbnail url="https://percona.community/superhero_hu_252fc2b480c0a197.jpg"/>
      <media:content url="https://percona.community/superhero_hu_17979f11d5d3562e.jpg" medium="image"/>
    </item>
    <item>
      <title>Creating a Kubernetes cluster on Amazon EKS with eksctl</title>
      <link>https://percona.community/blog/2022/09/13/creating-a-kubernetes-cluster-on-amazon-eks-with-eksctl/</link>
      <guid>https://percona.community/blog/2022/09/13/creating-a-kubernetes-cluster-on-amazon-eks-with-eksctl/</guid>
      <pubDate>Tue, 13 Sep 2022 00:00:00 UTC</pubDate>
      <description>Amazon Elastic Kubernetes Service (Amazon EKS) is a managed Kubernetes service that makes it easy for you to run Kubernetes on AWS and on-premises. Kubernetes is an open-source system for automating deployment, scaling, and management of containerized applications. Amazon EKS is certified Kubernetes-conformant, so existing applications that run on upstream Kubernetes are compatible with Amazon EKS.</description>
      <content:encoded>&lt;p&gt;&lt;a href="https://aws.amazon.com/eks/" target="_blank" rel="noopener noreferrer"&gt;Amazon Elastic Kubernetes Service&lt;/a&gt; (Amazon EKS) is a managed Kubernetes service that makes it easy for you to run Kubernetes on AWS and on-premises. &lt;a href="https://kubernetes.io/" target="_blank" rel="noopener noreferrer"&gt;Kubernetes&lt;/a&gt; is an open-source system for automating deployment, scaling, and management of containerized applications. Amazon EKS is certified Kubernetes-conformant, so existing applications that run on upstream Kubernetes are compatible with Amazon EKS.&lt;/p&gt;
&lt;p&gt;Getting started guides available in the AWS documentation explain two different procedures for creating an EKS cluster. One using eksctl, a simple command line utility for creating and managing Kubernetes clusters on Amazon EKS, and the other one using the AWS Management Console and AWS CLI.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/getting-started-eksctl.html" target="_blank" rel="noopener noreferrer"&gt;Getting started with Amazon EKS - eksctl&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/getting-started-console.html" target="_blank" rel="noopener noreferrer"&gt;Getting started with Amazon EKS – AWS Management Console and AWS CLI&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Through this article, you will learn how to use eksctl for creating a Kubernetes cluster on Amazon EKS.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://eksctl.io" target="_blank" rel="noopener noreferrer"&gt;eksctl&lt;/a&gt; is a simple CLI tool for creating and managing clusters on EKS - Amazon’s managed Kubernetes service for EC2. It is written in Go, uses CloudFormation, and was created by &lt;a href="https://www.weave.works/" target="_blank" rel="noopener noreferrer"&gt;Weaveworks&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For using eksctl, you must:.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Install &lt;a href="https://kubernetes.io/docs/reference/kubectl/" target="_blank" rel="noopener noreferrer"&gt;kubectl&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Install &lt;a href="https://github.com/kubernetes-sigs/aws-iam-authenticator" target="_blank" rel="noopener noreferrer"&gt;AWS IAM Authenticator for Kubernetes&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Install &lt;a href="https://aws.amazon.com/cli/" target="_blank" rel="noopener noreferrer"&gt;AWS CLI&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Create a user with &lt;a href="https://eksctl.io/usage/minimum-iam-policies/" target="_blank" rel="noopener noreferrer"&gt;minimal IAM policies&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After running eksctl, you will get a cluster with default configuration:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Exciting auto-generated name&lt;/li&gt;
&lt;li&gt;Two m5.large worker nodes&lt;/li&gt;
&lt;li&gt;Use the official AWS EKS AMI&lt;/li&gt;
&lt;li&gt;Default us-west-2 region&lt;/li&gt;
&lt;li&gt;A dedicated VPC&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="creating-iam-user"&gt;Creating IAM user&lt;/h2&gt;
&lt;p&gt;Go to &lt;a href="https://console.aws.amazon.com/iamv2" target="_blank" rel="noopener noreferrer"&gt;console.aws.amazon.com/iamv2&lt;/a&gt;, create a user group, named EKS, and attach the policies described in the &lt;a href="https://eksctl.io/usage/minimum-iam-policies/" target="_blank" rel="noopener noreferrer"&gt;minimal IAM policies&lt;/a&gt; section from the eksctl documentation.&lt;/p&gt;
&lt;p&gt;These policies already exist, and you must attach them as they are.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AmazonEC2FullAccess (AWS managed)&lt;/li&gt;
&lt;li&gt;AWSCloudFormationFullAccess (AWS managed)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In addition to previous policies, you must create:&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;&lt;b&gt;EksAllAccess&lt;/b&gt; (click to expand)&lt;/summary&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "Version": "2012-10-17",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "Statement": [
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "Effect": "Allow",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "Action": "eks:*",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "Resource": "*"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "Action": [
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "ssm:GetParameter",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "ssm:GetParameters"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ],
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "Resource": [
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "arn:aws:ssm:*:&lt;account_id&gt;:parameter/aws/*",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "arn:aws:ssm:*::parameter/aws/*"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ],
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "Effect": "Allow"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "Action": [
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "kms:CreateGrant",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "kms:DescribeKey"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ],
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "Resource": "*",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "Effect": "Allow"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "Action": [
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "logs:PutRetentionPolicy"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ],
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "Resource": "*",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "Effect": "Allow"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/details&gt;
&lt;details&gt;
&lt;summary&gt;&lt;b&gt;IAMLimitedAccess&lt;/b&gt; (click to expand)&lt;/summary&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-1"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "Version": "2012-10-17",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "Statement": [
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "Effect": "Allow",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "Action": [
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "iam:CreateInstanceProfile",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "iam:DeleteInstanceProfile",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "iam:GetInstanceProfile",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "iam:RemoveRoleFromInstanceProfile",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "iam:GetRole",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "iam:CreateRole",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "iam:DeleteRole",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "iam:AttachRolePolicy",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "iam:PutRolePolicy",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "iam:ListInstanceProfiles",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "iam:AddRoleToInstanceProfile",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "iam:ListInstanceProfilesForRole",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "iam:PassRole",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "iam:DetachRolePolicy",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "iam:DeleteRolePolicy",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "iam:GetRolePolicy",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "iam:GetOpenIDConnectProvider",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "iam:CreateOpenIDConnectProvider",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "iam:DeleteOpenIDConnectProvider",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "iam:TagOpenIDConnectProvider",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "iam:ListAttachedRolePolicies",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "iam:TagRole",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "iam:GetPolicy",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "iam:CreatePolicy",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "iam:DeletePolicy",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "iam:ListPolicyVersions"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ],
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "Resource": [
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "arn:aws:iam::&lt;account_id&gt;:instance-profile/eksctl-*",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "arn:aws:iam::&lt;account_id&gt;:role/eksctl-*",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "arn:aws:iam::&lt;account_id&gt;:policy/eksctl-*",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "arn:aws:iam::&lt;account_id&gt;:oidc-provider/*",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "arn:aws:iam::&lt;account_id&gt;:role/aws-service-role/eks-nodegroup.amazonaws.com/AWSServiceRoleForAmazonEKSNodegroup",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "arn:aws:iam::&lt;account_id&gt;:role/eksctl-managed-*"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "Effect": "Allow",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "Action": [
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "iam:GetRole"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ],
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "Resource": [
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "arn:aws:iam::&lt;account_id&gt;:role/*"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "Effect": "Allow",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "Action": [
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "iam:CreateServiceLinkedRole"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ],
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "Resource": "*",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "Condition": {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "StringEquals": {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "iam:AWSServiceName": [
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "eks.amazonaws.com",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "eks-nodegroup.amazonaws.com",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; "eks-fargate.amazonaws.com"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/details&gt;
&lt;p&gt;Replace &lt;code&gt;&lt;account_id&gt;&lt;/code&gt;, in both policies, with your AWS account ID, you can find it in the upper right corner, in the navigation bar. For other ways of getting your account ID, go to &lt;a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/console_account-alias.html" target="_blank" rel="noopener noreferrer"&gt;Your AWS account ID and its alias&lt;/a&gt; in the docs.&lt;/p&gt;
&lt;p&gt;Add a new user, named eksctl, to the group previously created.&lt;/p&gt;
&lt;p&gt;Don’t forget to download or copy your credentials, Access Key ID and Secret Access Key, as you will need them for setting up authentication.&lt;/p&gt;
&lt;h2 id="installing-aws-cli"&gt;Installing AWS CLI&lt;/h2&gt;
&lt;p&gt;On Linux, download the installer:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-2" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-2"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Unzip the installer:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-3" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-3"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ unzip awscliv2.zip&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;And run the installer:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-4" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-4"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ sudo ./aws/install&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;For instructions on how to install AWS CLI on other operating systems, go to &lt;a href="https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html" target="_blank" rel="noopener noreferrer"&gt;Installing or updating the latest version of the AWS CLI&lt;/a&gt; in the documentation.&lt;/p&gt;
&lt;p&gt;After installing AWS CLI, run the following command for setting up authentication locally:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-5" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-5"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ aws configure --profile eksctl&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;It will ask you for your AWS credentials and default region.&lt;/p&gt;
&lt;h2 id="installing-aws-iam-authenticator"&gt;Installing AWS IAM Authenticator&lt;/h2&gt;
&lt;p&gt;On Linux, run the following command:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-6" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-6"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ curl -o aws-iam-authenticator https://s3.us-west-2.amazonaws.com/amazon-eks/1.21.2/2021-07-05/bin/linux/amd64/aws-iam-authenticator&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Apply execute permissions to the binary:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-7" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-7"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ chmod +x ./aws-iam-authenticator&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Create a folder in your &lt;code&gt;$HOME&lt;/code&gt; directory and add it to the &lt;code&gt;$PATH&lt;/code&gt; variable:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-8" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-8"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ mkdir -p $HOME/bin &amp;&amp; cp ./aws-iam-authenticator $HOME/bin/aws-iam-authenticator &amp;&amp; export PATH=$PATH:$HOME/bin&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Add &lt;code&gt;$HOME/bin&lt;/code&gt; to your &lt;code&gt;.bashrc&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-9" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-9"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ echo 'export PATH=$PATH:$HOME/bin' &gt;&gt; ~/.bashrc&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;For Mac and Windows, check &lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/install-aws-iam-authenticator.html" target="_blank" rel="noopener noreferrer"&gt;Installing aws-iam-authenticator&lt;/a&gt; in the documentation.&lt;/p&gt;
&lt;h2 id="installing-kubectl"&gt;Installing kubectl&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;NOTE:&lt;/em&gt;&lt;/strong&gt; From the documentation - You must use a &lt;code&gt;kubectl&lt;/code&gt; version that is within one minor version difference of your Amazon EKS cluster control plane. For example, a &lt;code&gt;1.22&lt;/code&gt; &lt;code&gt;kubectl&lt;/code&gt; client works with Kubernetes &lt;code&gt;1.21&lt;/code&gt;, &lt;code&gt;1.22&lt;/code&gt;, and &lt;code&gt;1.23&lt;/code&gt; clusters.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;As of today, the latest version of Kubernetes used by eksctl is 1.21. Run the following command for installing the corresponding version of kubectl:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-10" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-10"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ curl -o kubectl https://s3.us-west-2.amazonaws.com/amazon-eks/1.21.2/2021-07-05/bin/linux/amd64/kubectl&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Apply execute permissions to the binary:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-11" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-11"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ chmod +x ./kubectl&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Copy the binary to &lt;code&gt;$HOME/bin&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-12" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-12"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ cp ./kubectl $HOME/bin/kubectl&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;If you’re using another version of Kubernetes, check &lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/install-kubectl.html" target="_blank" rel="noopener noreferrer"&gt;Installing or updating kubectl&lt;/a&gt; in the documentation, where you can also find instructions for other operating systems.&lt;/p&gt;
&lt;h2 id="installing-eksctl-and-creating-a-kubernetes-cluster"&gt;Installing eksctl and creating a Kubernetes cluster&lt;/h2&gt;
&lt;p&gt;Download the binary and copy it to &lt;code&gt;/usr/local/bin&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-13" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-13"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ curl --silent --location "https://github.com/weaveworks/eksctl/releases/latest/download/eksctl_$(uname -s)_amd64.tar.gz" | tar xz -C /tmp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-14" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-14"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ sudo mv /tmp/eksctl /usr/local/bin&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;On Mac and Windows, you can install eksctl following the instructions in the GitHub &lt;a href="https://github.com/weaveworks/eksctl" target="_blank" rel="noopener noreferrer"&gt;repository&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Once installed, create a cluster with default configuration, and authenticate to AWS using IAM user created previously.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-15" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-15"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ eksctl create cluster --profile eksctl&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;NOTE:&lt;/em&gt;&lt;/strong&gt; From the documentation - That command will create an EKS cluster in your default region (as specified by your AWS CLI configuration) with one managed nodegroup containing two m5.large nodes.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;For a cluster with custom configuration, create a config file, named &lt;code&gt;cluster.yaml&lt;/code&gt;, with the following content:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;yaml&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-16" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-16"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;apiVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;eksctl.io/v1alpha5&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;ClusterConfig&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;basic-cluster&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;eu-north-1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;nodeGroups&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;ng-1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;instanceType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;m5.large&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;desiredCapacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;volumeSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;80&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ssh&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;allow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# will use ~/.ssh/id_rsa.pub as the default ssh key&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;ng-2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;instanceType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;m5.xlarge&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;desiredCapacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;volumeSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ssh&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;publicKeyPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;~/.ssh/ec2_id_rsa.pub&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Run eksctl to create the cluster as follows:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-17" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-17"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ eksctl create cluster -f cluster.yaml --profile eksctl&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;While running, eksctl will create the cluster and all the necessary resources.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2022/9/eksctl_running_hu_c15eff3eca8ba295.png 480w, https://percona.community/blog/2022/9/eksctl_running_hu_8bb0aeea46f4047d.png 768w, https://percona.community/blog/2022/9/eksctl_running_hu_bf12dad224322e69.png 1400w"
src="https://percona.community/blog/2022/9/eksctl_running.png" alt="eksctl running" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;It will take a few minutes to complete. After the command is executed, you can go to &lt;a href="https://us-east-1.console.aws.amazon.com/eks/home?region=us-east-1#/clusters" target="_blank" rel="noopener noreferrer"&gt;us-east-1.console.aws.amazon.com/eks/home?region=us-east-1#/clusters&lt;/a&gt; to see the cluster.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2022/9/eks_cluster_hu_ff679d01ae9bc6d3.png 480w, https://percona.community/blog/2022/9/eks_cluster_hu_4ab0e18f253db1d7.png 768w, https://percona.community/blog/2022/9/eks_cluster_hu_b29bc1f177b5650d.png 1400w"
src="https://percona.community/blog/2022/9/eks_cluster.png" alt="EKS Cluster" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Don’t forget to replace &lt;code&gt;us-east-1&lt;/code&gt; in the URL, if your default region is different.&lt;/p&gt;
&lt;p&gt;Cluster credentials can be found in &lt;code&gt;~/.kube/config&lt;/code&gt;. Try &lt;code&gt;kubectl get nodes&lt;/code&gt; to verify that this file is valid, as suggested by eksctl.&lt;/p&gt;
&lt;p&gt;If, for any reason, you need to delete your cluster, just run:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-18" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-18"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ eksctl delete cluster --name=ferocious-painting-1660755039 --profile eksctl&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Replacing &lt;code&gt;name&lt;/code&gt; with corresponding value.&lt;/p&gt;
&lt;p&gt;You’ve created your first Kubernetes cluster using eksctl. Check the documentation for more information on how to &lt;a href="https://eksctl.io/usage/creating-and-managing-clusters/" target="_blank" rel="noopener noreferrer"&gt;create and manage clusters&lt;/a&gt;.&lt;/p&gt;</content:encoded>
      <author>Mario García</author>
      <category>Linux</category>
      <category>Kubernetes</category>
      <category>AWS</category>
      <category>Amazon EKS</category>
      <media:thumbnail url="https://percona.community/blog/2022/9/eksctl_running_hu_b6470d877e89d74e.jpg"/>
      <media:content url="https://percona.community/blog/2022/9/eksctl_running_hu_44229ef62aeab1fe.jpg" medium="image"/>
    </item>
    <item>
      <title>Running PMM with Docker on Ubuntu 20.04</title>
      <link>https://percona.community/blog/2022/08/05/installing-pmm-with-docker-on-ubuntu-20/</link>
      <guid>https://percona.community/blog/2022/08/05/installing-pmm-with-docker-on-ubuntu-20/</guid>
      <pubDate>Fri, 05 Aug 2022 00:00:00 UTC</pubDate>
      <description>I started at Percona a few weeks ago and was looking for a quick way to learn about PMM (Percona Monitoring and Management), which is one of my favorite technologies within Percona to monitor the health of our database infrastructure, explore new patterns in the database behavior, manage and improve the performance of our databases, all with customizable dashboards and real-time alerts using Grafana and VictoriaMetrics.</description>
      <content:encoded>&lt;p&gt;I started at Percona a few weeks ago and was looking for a quick way to learn about PMM (Percona Monitoring and Management), which is one of my favorite technologies within Percona to monitor the health of our database infrastructure, explore new patterns in the database behavior, manage and improve the performance of our databases, all with customizable dashboards and real-time alerts using &lt;a href="https://grafana.com/" target="_blank" rel="noopener noreferrer"&gt;Grafana&lt;/a&gt; and &lt;a href="https://victoriametrics.com/" target="_blank" rel="noopener noreferrer"&gt;VictoriaMetrics&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The best of all is that PMM is Open Source, you can check the &lt;a href="https://github.com/percona/pmm" target="_blank" rel="noopener noreferrer"&gt;PMM repository&lt;/a&gt; in case you want to contribute.&lt;/p&gt;
&lt;p&gt;There are many flavors for PMM installation, here I will describe the steps to install PMM on Ubuntu 20.04, using Docker for PMM Server on an Amazon EC2 instance.&lt;/p&gt;
&lt;p&gt;This image summarizes our goal.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2022/8/pmm-ubuntu-overview_hu_130c66d5b3f9665a.png 480w, https://percona.community/blog/2022/8/pmm-ubuntu-overview_hu_7a58c512dd9cc0f9.png 768w, https://percona.community/blog/2022/8/pmm-ubuntu-overview_hu_82edbc1ac276728a.png 1400w"
src="https://percona.community/blog/2022/8/pmm-ubuntu-overview.png" alt="Overview" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h2 id="requirements"&gt;Requirements&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;An Amazon EC2 instance with Ubuntu 20.04
&lt;ul&gt;
&lt;li&gt;This instance is configured with a Security Group with TCP port 443 open.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Docker
&lt;ul&gt;
&lt;li&gt;You can install Docker by following this &lt;a href="https://docs.docker.com/engine/install/ubuntu/" target="_blank" rel="noopener noreferrer"&gt;guide&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Manage Docker as a non-root user: &lt;strong&gt;&lt;em&gt;sudo usermod -aG docker $USER&lt;/em&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;MySQL
&lt;ul&gt;
&lt;li&gt;I am using Percona Server for MySQL from &lt;a href="https://docs.percona.com/percona-server/8.0/installation/apt_repo.html" target="_blank" rel="noopener noreferrer"&gt;Percona apt repository&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="installing-pmm-server-with-docker"&gt;Installing PMM Server with Docker&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Download PMM server Docker image&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker pull percona/pmm-server:2&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ol start="2"&gt;
&lt;li&gt;Create the data volume container&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-1"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker create --volume /srv --name pmm-data percona/pmm-server:2 /bin/true&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ol start="3"&gt;
&lt;li&gt;Run PMM server container&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-2" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-2"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker run --detach --restart always --publish 443:443 --volumes-from pmm-data --name pmm-server percona/pmm-server:2&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ol start="4"&gt;
&lt;li&gt;Verify the creation of the container.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-3" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-3"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker ps&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2022/8/pmm-ubuntu-docker-ps_hu_778334322893c109.png 480w, https://percona.community/blog/2022/8/pmm-ubuntu-docker-ps_hu_ea22912ba5ddf4b4.png 768w, https://percona.community/blog/2022/8/pmm-ubuntu-docker-ps_hu_73f8a686032ac833.png 1400w"
src="https://percona.community/blog/2022/8/pmm-ubuntu-docker-ps.png" alt="docker ps" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Start a web browser and in the address bar enter the IP address of the &lt;strong&gt;PMM server&lt;/strong&gt; host: https://&lt;PUBLIC_IP&gt;:443/. For example, https://172.31.53.46. If you are running on your local machine use https://localhost:443/.
Woohoo! We have a PMM Server running and we can see our dashboard!&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2022/8/pmm-ubuntu-pmm-dashboard_hu_f3e2a7e99a4fad50.png 480w, https://percona.community/blog/2022/8/pmm-ubuntu-pmm-dashboard_hu_5a53ccebcba11bba.png 768w, https://percona.community/blog/2022/8/pmm-ubuntu-pmm-dashboard_hu_db72bae5247480bf.png 1400w"
src="https://percona.community/blog/2022/8/pmm-ubuntu-pmm-dashboard.png" alt="pmm-ubuntu-pmm-dashboard" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Some browsers may not trust the self-signed SSL certificate when you first open the URL. If this is the case, Chrome users may want to type &lt;strong&gt;thisisunsafe&lt;/strong&gt; to bypass the warning.&lt;/p&gt;
&lt;p&gt;The user and password are &lt;strong&gt;“admin”&lt;/strong&gt; and &lt;strong&gt;“admin”&lt;/strong&gt;, It will ask you to change the password after login in for the first time, for this demo I will use &lt;strong&gt;admin2020&lt;/strong&gt; as a password. We will use these credentials to register the node in PMM Server later.&lt;/p&gt;
&lt;p&gt;Until now we have only PMM Server. To monitor a database, we need a PMM client.&lt;/p&gt;
&lt;h2 id="installing-pmm-client"&gt;Installing PMM client&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;PMM Client&lt;/strong&gt; is a collection of agents and exporters that run on the host being monitored. Let´s install it using the repository package.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Download Percona Repo Package&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-4" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-4"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;wget https://repo.percona.com/apt/percona-release_latest.&lt;span class="k"&gt;$(&lt;/span&gt;lsb_release -sc&lt;span class="k"&gt;)&lt;/span&gt;_all.deb&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ol start="2"&gt;
&lt;li&gt;Install Percona Repo Package&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-5" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-5"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt install ./percona-release_latest.&lt;span class="k"&gt;$(&lt;/span&gt;lsb_release -sc&lt;span class="k"&gt;)&lt;/span&gt;_all.deb&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ol start="3"&gt;
&lt;li&gt;Update apt cache&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-6" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-6"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt update&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ol start="4"&gt;
&lt;li&gt;Install Percona Monitoring and Management Client&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-7" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-7"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt install pmm2-client&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ol start="5"&gt;
&lt;li&gt;Checking the installation. We will use pmm-admin in the next steps.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-8" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-8"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo pmm-admin -v&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2022/8/pmm-ubuntu-pmm-admin-v.png" alt="pmm-ubuntu-pmm-dashboard" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h2 id="creating-a-user-for-monitoring"&gt;Creating a user for monitoring&lt;/h2&gt;
&lt;p&gt;Let’s create a user in MySQL.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Login in MySQL for use the command-line: &lt;strong&gt;&lt;em&gt;mysql -uroot -p&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a “pmm” user with “welcOme1!” As a password&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-9" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-9"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;CREATE USER &lt;span class="s1"&gt;'pmm'&lt;/span&gt;@&lt;span class="s1"&gt;'localhost'&lt;/span&gt; IDENTIFIED BY &lt;span class="s1"&gt;'welcOme1!'&lt;/span&gt; WITH MAX_USER_CONNECTIONS 10&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ol start="3"&gt;
&lt;li&gt;Give “pmm” user with specific permission to monitor the database&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-10" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-10"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;GRANT SELECT, PROCESS, REPLICATION CLIENT, RELOAD, BACKUP_ADMIN ON *.* TO &lt;span class="s1"&gt;'pmm'&lt;/span&gt;@&lt;span class="s1"&gt;'localhost'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Checking if the user was created correctly with the respective permissions, use&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-11" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-11"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; show grants &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="s1"&gt;'pmm'&lt;/span&gt;@&lt;span class="s1"&gt;'localhost'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2022/8/pmm-ubuntu-show-grants_hu_eaaf118b3b5e1001.png 480w, https://percona.community/blog/2022/8/pmm-ubuntu-show-grants_hu_6e04aa1898999067.png 768w, https://percona.community/blog/2022/8/pmm-ubuntu-show-grants_hu_e2b21b7188491d1b.png 1400w"
src="https://percona.community/blog/2022/8/pmm-ubuntu-show-grants.png" alt="pmm-ubuntu-show-grants" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h2 id="connect-client-to-server"&gt;Connect Client to Server&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Register Percona Monitoring and Management client with server, use the default admin/admin username and password.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-12" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-12"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo pmm-admin config --server-insecure-tls --server-url&lt;span class="o"&gt;=&lt;/span&gt;https://admin:admin2020@172.17.0.1:443&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; I am using &lt;strong&gt;172.17.0.1&lt;/strong&gt; because this is the private IP where the PMM Server is running. You can get this IP by entering the docker container and typing &lt;strong&gt;“hostname -I”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2022/8/pmm-ubuntu-hostname-i.png" alt="pmm-ubuntu-hostname-i" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;After registering your client with the server you will see this information:&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2022/8/pmm-ubuntu-pmm-admin-config_hu_2c92046682bc7a77.png 480w, https://percona.community/blog/2022/8/pmm-ubuntu-pmm-admin-config_hu_671dd038024060eb.png 768w, https://percona.community/blog/2022/8/pmm-ubuntu-pmm-admin-config_hu_a94187a076dfb2be.png 1400w"
src="https://percona.community/blog/2022/8/pmm-ubuntu-pmm-admin-config.png" alt="pmm-ubuntu-pmm-admin-config" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;ol start="2"&gt;
&lt;li&gt;Check if the node was registered&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-13" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-13"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pmm-admin inventory list nodes&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;A new node should appear in the list which is &lt;strong&gt;pmm-server&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2022/8/pmm-ubuntu-pmm-admin-inventory_hu_58d197706bc000c5.png 480w, https://percona.community/blog/2022/8/pmm-ubuntu-pmm-admin-inventory_hu_beb71ec4c1d61705.png 768w, https://percona.community/blog/2022/8/pmm-ubuntu-pmm-admin-inventory_hu_5a81dc5f4682635d.png 1400w"
src="https://percona.community/blog/2022/8/pmm-ubuntu-pmm-admin-inventory.png" alt="pmm-ubuntu-hostname-i" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h2 id="adding-a-mysql-database-to-monitoring"&gt;Adding a MySQL Database to monitoring&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Use pmm-admin to register the database with the user we created in MySQL&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-14" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-14"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo pmm-admin add mysql --username&lt;span class="o"&gt;=&lt;/span&gt;pmm --password&lt;span class="o"&gt;=&lt;/span&gt;welcOme1! --query-source&lt;span class="o"&gt;=&lt;/span&gt;perfschema&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2022/8/pmm-ubuntu-pmm-admin-add-sql_hu_aa3fe358f469ad93.png 480w, https://percona.community/blog/2022/8/pmm-ubuntu-pmm-admin-add-sql_hu_4888b439ca1fd46a.png 768w, https://percona.community/blog/2022/8/pmm-ubuntu-pmm-admin-add-sql_hu_762478fafd9b7c38.png 1400w"
src="https://percona.community/blog/2022/8/pmm-ubuntu-pmm-admin-add-sql.png" alt="pmm-ubuntu-pmm-admin-add-sql" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;ol start="2"&gt;
&lt;li&gt;In the dashboard, we will see that our node and database are registered and ready to be monitored by PMM.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2022/8/pmm-ubuntu-last-dashboard_hu_7f077b03e0f2bfa4.png 480w, https://percona.community/blog/2022/8/pmm-ubuntu-last-dashboard_hu_bddc5b9da8193857.png 768w, https://percona.community/blog/2022/8/pmm-ubuntu-last-dashboard_hu_20a42dc5d29c7d3b.png 1400w"
src="https://percona.community/blog/2022/8/pmm-ubuntu-last-dashboard.png" alt="pmm-ubuntu-last-dashboard" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;That’s it! :) We learned how to monitor our databases for free with Percona Monitoring Database (PMM). Additionally, you can go to the next level by registering a PMM instance with &lt;a href="https://docs.percona.com/percona-platform/" target="_blank" rel="noopener noreferrer"&gt;Percona Platform&lt;/a&gt; and receive more information.&lt;/p&gt;
&lt;p&gt;I hope you’ve enjoyed this tutorial, and if you need help following it, feel free to contact the &lt;a href="https://percona.community/blog/2022/02/10/how-to-publish-blog-post/#assistance-and-support" target="_blank" rel="noopener noreferrer"&gt;Percona team support&lt;/a&gt;. We will be happy to help.&lt;/p&gt;</content:encoded>
      <author>Edith Puclla</author>
      <category>PMM</category>
      <category>DevOps</category>
      <category>MySQL</category>
      <category>Docker</category>
      <media:thumbnail url="https://percona.community/blog/2022/8/pmm-ubuntu-overview_hu_5ad125c14b3da007.jpg"/>
      <media:content url="https://percona.community/blog/2022/8/pmm-ubuntu-overview_hu_6bd40fe72fd83535.jpg" medium="image"/>
    </item>
    <item>
      <title>Percona Monitoring and Management 2.29.0 Preview Release</title>
      <link>https://percona.community/blog/2022/07/12/preview-release/</link>
      <guid>https://percona.community/blog/2022/07/12/preview-release/</guid>
      <pubDate>Tue, 12 Jul 2022 00:00:00 UTC</pubDate>
      <description>Percona Monitoring and Management 2.29.0 Preview Release Hello folks! Percona Monitoring and Management (PMM) 2.29.0 is now available as a Preview Release.</description>
      <content:encoded>&lt;h2 id="percona-monitoring-and-management-2290-preview-release"&gt;Percona Monitoring and Management 2.29.0 Preview Release&lt;/h2&gt;
&lt;p&gt;Hello folks! Percona Monitoring and Management (PMM) 2.29.0 is now available as a Preview Release.&lt;/p&gt;
&lt;p&gt;We encourage you to try this PMM Preview Release in &lt;strong&gt;testing environments only&lt;/strong&gt;, as these packages and images are not fully production-ready. The final version is expected to be released through the standard channels in the coming week.&lt;/p&gt;
&lt;p&gt;Release Notes can be found in &lt;a href="https://pmm-doc-release-pr-811.onrender.com/release-notes/2.29.0.html" target="_blank" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="known-issues"&gt;Known issues&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://perconadev.atlassian.net/browse/PMM-10312" target="_blank" rel="noopener noreferrer"&gt;PMM-10312&lt;/a&gt;: Metrics are not displayed on Experimental Overview and Summary dashboards&lt;/p&gt;
&lt;h3 id="percona-monitoring-and-management-server-docker"&gt;Percona Monitoring and Management server docker&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://docs.percona.com/percona-monitoring-and-management/setting-up/server/docker.html" target="_blank" rel="noopener noreferrer"&gt;Instructions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;docker tag:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;perconalab/pmm-server:2.29.0-rc&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="percona-monitoring-and-management-client-package-installation"&gt;Percona Monitoring and Management client package installation&lt;/h3&gt;
&lt;p&gt;Download the latest pmm2-client Release Candidate tarball for 2.29.0 by this &lt;a href="https://s3.us-east-2.amazonaws.com/pmm-build-cache/PR-BUILDS/pmm2-client/pmm2-client-latest-4028.tar.gz" target="_blank" rel="noopener noreferrer"&gt;link&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you want to install pmm2-client package, please enable testing repository via Percona-release:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;percona-release enable percona testing&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;install pmm2-client package for your OS via package manager.&lt;/p&gt;
&lt;h3 id="ova"&gt;OVA&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://docs.percona.com/percona-monitoring-and-management/setting-up/server/virtual-appliance.html" target="_blank" rel="noopener noreferrer"&gt;Instructions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://percona-vm.s3.amazonaws.com/PMM2-Server-2.29.0.ova" target="_blank" rel="noopener noreferrer"&gt;PMM2-Server-2.29.0.ova&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="ami"&gt;AMI&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://docs.percona.com/percona-monitoring-and-management/setting-up/server/aws.html" target="_blank" rel="noopener noreferrer"&gt;Instructions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ami-0e68224439dd6f200&lt;/code&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Contact us at &lt;a href="mailto:community-team@percona.com"&gt;community-team@percona.com&lt;/a&gt; .&lt;/p&gt;</content:encoded>
      <author>Taras Kozub</author>
      <category>PMM</category>
      <media:thumbnail url="https://percona.community/superhero_hu_252fc2b480c0a197.jpg"/>
      <media:content url="https://percona.community/superhero_hu_17979f11d5d3562e.jpg" medium="image"/>
    </item>
    <item>
      <title>Percona Monitoring and Management 2.28.0 Preview Release</title>
      <link>https://percona.community/blog/2022/05/05/preview-release/</link>
      <guid>https://percona.community/blog/2022/05/05/preview-release/</guid>
      <pubDate>Thu, 05 May 2022 00:00:00 UTC</pubDate>
      <description>Percona Monitoring and Management 2.28.0 Preview Release Hello folks! Percona Monitoring and Management (PMM) 2.28.0 is now available as a Preview Release.</description>
      <content:encoded>&lt;h2 id="percona-monitoring-and-management-2280-preview-release"&gt;Percona Monitoring and Management 2.28.0 Preview Release&lt;/h2&gt;
&lt;p&gt;Hello folks! Percona Monitoring and Management (PMM) 2.28.0 is now available as a Preview Release.&lt;/p&gt;
&lt;p&gt;We encourage you to try this PMM Preview Release in &lt;strong&gt;testing environments only&lt;/strong&gt;, as these packages and images are not fully production-ready. The final version is expected to be released through the standard channels in the coming week.&lt;/p&gt;
&lt;p&gt;Release Notes can be found in &lt;a href="https://pmm-doc-release-pr-781.onrender.com/release-notes/2.28.0.html" target="_blank" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="percona-monitoring-and-management-server-docker"&gt;Percona Monitoring and Management server docker&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://docs.percona.com/percona-monitoring-and-management/setting-up/server/docker.html" target="_blank" rel="noopener noreferrer"&gt;Instructions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;docker tag:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;perconalab/pmm-server:2.28.0-rc&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="percona-monitoring-and-management-client-package-installation"&gt;Percona Monitoring and Management client package installation&lt;/h3&gt;
&lt;p&gt;Download the latest pmm2-client Release Candidate tarball for 2.28.0 by this &lt;a href="https://s3.us-east-2.amazonaws.com/pmm-build-cache/PR-BUILDS/pmm2-client/pmm2-client-latest-3776.tar.gz" target="_blank" rel="noopener noreferrer"&gt;link&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you want to install pmm2-client package, please enable testing repository via Percona-release:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;percona-release enable percona testing&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;install pmm2-client package for your OS via package manager.&lt;/p&gt;
&lt;h3 id="ova"&gt;OVA&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://docs.percona.com/percona-monitoring-and-management/setting-up/server/virtual-appliance.html" target="_blank" rel="noopener noreferrer"&gt;Instructions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Artifact: &lt;a href="http://percona-vm.s3.amazonaws.com/PMM2-Server-2.28.0.ova" target="_blank" rel="noopener noreferrer"&gt;PMM2-Server-2.28.0.ova&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="ami"&gt;AMI&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://docs.percona.com/percona-monitoring-and-management/setting-up/server/aws.html" target="_blank" rel="noopener noreferrer"&gt;Instructions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Artifact: &lt;code&gt;ami-09ce0dc58b2f81889&lt;/code&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Contact us at &lt;a href="mailto:community-team@percona.com"&gt;community-team@percona.com&lt;/a&gt; .&lt;/p&gt;</content:encoded>
      <author>Taras Kozub</author>
      <category>PMM</category>
      <media:thumbnail url="https://percona.community/superhero_hu_252fc2b480c0a197.jpg"/>
      <media:content url="https://percona.community/superhero_hu_17979f11d5d3562e.jpg" medium="image"/>
    </item>
    <item>
      <title>The MySQL Workshop Book Review</title>
      <link>https://percona.community/blog/2022/05/03/the-mysql-workshop-book-review/</link>
      <guid>https://percona.community/blog/2022/05/03/the-mysql-workshop-book-review/</guid>
      <pubDate>Tue, 03 May 2022 00:00:00 UTC</pubDate>
      <description>Good books on MySQL for beginners are rare and excellent ones are even rarer. I often get requests from novices starting with MySQL or intermediates looking to level up on recommendations on books targeted at their level. The MySQL Workshop (Amazon link) by Thomas Pettit and Scott Cosentino is a must buy for those two groups, or those of us who would like a handy reference.</description>
      <content:encoded>&lt;p&gt;Good books on MySQL for beginners are rare and excellent ones are even rarer. I often get requests from novices starting with MySQL or intermediates looking to level up on recommendations on books targeted at their level. The MySQL Workshop (&lt;a href="https://www.amazon.com/MySQL-Workshop-Interactive-Approach-Learning-ebook/dp/B084T32T3B/" target="_blank" rel="noopener noreferrer"&gt;Amazon link&lt;/a&gt;) by Thomas Pettit and Scott Cosentino is a must buy for those two groups, or those of us who would like a handy reference.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2022/5/TheMySQLWorkshopBook.jpg" alt="The MySQL Workshop Book Review" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;This is a great book and I recommend getting a copy regardless of your MySQL expertise.&lt;/p&gt;
&lt;h2 id="the-basics"&gt;The Basics&lt;/h2&gt;
&lt;p&gt;At seven hundred pages, this book has a wide scope that starts with background concepts like data normalization, proceeds into creating databases, SQL, and administration. And there are sections on programming with Node.js, working with Microsoft applications, loading data, DBA tasks, and logical backups. There are exercises at the end of the chapters with solutions at the end of the book.&lt;/p&gt;
&lt;p&gt;Writing such a book is a tremendous task and the authors need to be applauded as they have produced a great book.&lt;/p&gt;
&lt;h2 id="the-nitty-gritty"&gt;The Nitty-Gritty&lt;/h2&gt;
&lt;p&gt;MySQL is a complex product and introducing concepts with a fresh approach is hard to do but this book does it consistently. Complex topics like creating functions are explained thoroughly without being bogged down in minute details.&lt;/p&gt;
&lt;p&gt;Does it cover everything? Nope, and no book under a few thousand pages will ever do that (while keeping pace with product development). There are minor omissions like constraint checks which a still fairly new but I would like to point you to the section on triggers that is the clearest explanation on the subject I have found.&lt;/p&gt;
&lt;p&gt;The writing style is concise, the formatting easy on the eyes, and I am sure the book will be very popular.&lt;/p&gt;</content:encoded>
      <author>David Stokes</author>
      <category>blog</category>
      <category>books</category>
      <category>MySQL</category>
      <media:thumbnail url="https://percona.community/blog/2022/5/TheMySQLWorkshop_hu_9d42aaa4854afa5a.jpg"/>
      <media:content url="https://percona.community/blog/2022/5/TheMySQLWorkshop_hu_ddc11a064cd4a3d2.jpg" medium="image"/>
    </item>
    <item>
      <title>Liquibase Data is Git for Databases</title>
      <link>https://percona.community/blog/2022/04/25/liquibase-data-is-git-for-databases/</link>
      <guid>https://percona.community/blog/2022/04/25/liquibase-data-is-git-for-databases/</guid>
      <pubDate>Mon, 25 Apr 2022 00:00:00 UTC</pubDate>
      <description>Author’s Note: Robert will be demoing Liquibase Data at Percona Live 2022 on Wednesday, May 18 at 11:50am. Add this presentation to your schedule.</description>
      <content:encoded>&lt;p&gt;&lt;em&gt;Author’s Note: Robert will be demoing Liquibase Data at Percona Live 2022 on Wednesday, May 18 at 11:50am. &lt;a href="https://sched.co/10JOM" target="_blank" rel="noopener noreferrer"&gt;Add this presentation to your schedule.&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Git is an amazing tool for collaboration — developers can work together to build better software faster. However, the usual Git workflow neglects the database. With &lt;a href="https://github.com/liquibase/liquibase-data" target="_blank" rel="noopener noreferrer"&gt;Liquibase Data&lt;/a&gt; we’re bringing git to the database so you can easily version containerized databases, share changes with team members, store versions in remote locations, and tag versions.&lt;/p&gt;
&lt;h2 id="the-vanilla-git-workflow"&gt;The Vanilla Git Workflow&lt;/h2&gt;
&lt;p&gt;The standard Git workflow is simple. A developer can &lt;code&gt;git init&lt;/code&gt; to create a local repository. Next, after making changes, &lt;code&gt;git commit&lt;/code&gt; creates a local version. Then, the developer pushes to a remote branch using &lt;code&gt;git push&lt;/code&gt;. Finally, another developer can &lt;code&gt;git pull&lt;/code&gt; to see the new code updates.&lt;/p&gt;
&lt;h2 id="liquibase-data-workflow"&gt;Liquibase Data Workflow&lt;/h2&gt;
&lt;p&gt;We created the same Git workflow in Liquibase Data. Using the &lt;a href="https://github.com/liquibase/liquibase-data" target="_blank" rel="noopener noreferrer"&gt;Liquibase Data extension&lt;/a&gt;, Liquibase users can initialize a new database in a Docker container using &lt;code&gt;liquibase data run&lt;/code&gt;. Which databases? ALL of them. All it requires is a database Docker image that has a volume mount for the data. Liquibase takes it from there. If you already run your development databases via Docker, you will find that Liquibase Data parallels the &lt;code&gt;docker run&lt;/code&gt; command.&lt;/p&gt;
&lt;p&gt;Here’s what you’ll be able to do:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Clone from remote repositories&lt;/li&gt;
&lt;li&gt;Make changes to the database&lt;/li&gt;
&lt;li&gt;Commit and push your changes to share with team members&lt;/li&gt;
&lt;li&gt;Tag commits&lt;/li&gt;
&lt;li&gt;Easily view the difference between two database commits to identify changes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Our team thinks this will be useful for test data management and supporting developer database workflows.&lt;/p&gt;
&lt;p&gt;Just like you commit after changing your code, you can do the same with Liquibase Data. After you add data to your database or change the schema, run &lt;code&gt;liquibase data commit&lt;/code&gt;. Commands such as &lt;code&gt;push&lt;/code&gt;, &lt;code&gt;remote&lt;/code&gt;, and &lt;code&gt;log&lt;/code&gt; are also available.&lt;/p&gt;
&lt;h2 id="easily-compare-databases"&gt;Easily Compare Databases&lt;/h2&gt;
&lt;p&gt;Determining what has changed in your database schema can be very difficult. Liquibase Data makes it simple to find schema differences between commits using the &lt;code&gt;diff&lt;/code&gt; command. With Liquibase Data, the required database starts automatically for you to create the diff.&lt;/p&gt;
&lt;h2 id="watch-liquibase-data-demos"&gt;Watch Liquibase Data Demos&lt;/h2&gt;
&lt;p&gt;Robert Reeves, CTO of Liquibase, &lt;a href="https://www.youtube.com/watch?v=k4m2UCqddHo" target="_blank" rel="noopener noreferrer"&gt;demonstrates how to quickly provision a developer instance of MongoDB&lt;/a&gt;, make changes to MongoDB, and then commit the change. You’ll see how easy it is to roll your changes backward and forward.&lt;/p&gt;
&lt;p&gt;Check out our other Liquibase Data demos for &lt;a href="https://www.youtube.com/watch?v=AByPvVoWIXM" target="_blank" rel="noopener noreferrer"&gt;Oracle&lt;/a&gt; and &lt;a href="https://www.youtube.com/watch?v=gLub_7Fcnh4" target="_blank" rel="noopener noreferrer"&gt;SQL Server&lt;/a&gt;! Liquibase Data works with ANY database in a Docker Container.&lt;/p&gt;
&lt;p&gt;Try Liquibase Data
We think Liquibase Data will be helpful for developers sharing databases among team members. Just imagine — you’ll be able to share datasets you’re working on early in the process and share a separate one later in the process. The distribution of valid test data amongst Dev and QA will speed testing cycles and help find bugs sooner.&lt;/p&gt;
&lt;p&gt;Of course, we want to hear from you! Tell us what you would like to see in Liquibase Data and share with us how you are using it. Our &lt;a href="https://github.com/liquibase/liquibase-data/tree/main/beta" target="_blank" rel="noopener noreferrer"&gt;Open Beta program&lt;/a&gt; is a great way to experience the benefits and give us input to make it work even better. We have a tutorial that will walk you through, step by step, how to use Liquibase Data. Along the way, you will have an opportunity to provide your thoughts.&lt;/p&gt;
&lt;p&gt;Finally, all of us at Liquibase thank you for your support over the past 15 years of open source greatness. We could not have done it with you. And, the best is yet to come!&lt;/p&gt;</content:encoded>
      <author>Robert Reeves</author>
      <category>blog</category>
      <category>PerconaLive</category>
      <category>PerconaLive2022</category>
      <category>DevOps</category>
      <media:thumbnail url="https://percona.community/blog/2022/4/liquibase-data-gitflow-580x296_hu_43885590fb372c6c.jpg"/>
      <media:content url="https://percona.community/blog/2022/4/liquibase-data-gitflow-580x296_hu_4e632644633ce561.jpg" medium="image"/>
    </item>
    <item>
      <title>A Quick Guide To Austin For Percona Live 2022 Attendees</title>
      <link>https://percona.community/blog/2022/04/11/percona-live-austin-guide/</link>
      <guid>https://percona.community/blog/2022/04/11/percona-live-austin-guide/</guid>
      <pubDate>Mon, 11 Apr 2022 00:00:00 UTC</pubDate>
      <description>Percona Live returns again to Austin May 16th through the 18th will find the city vibrant, charming, and weird. The semi-official motto for the city is ‘Keep Austin Weird’ and during your visit you will indeed see many of the residents working hard to do just that. Not in a bad way. Austin is at the intersection of so many cultural, artistic, and lifestyle modes that there are a fair amount of many different things happening at the same time to ensure that any dull moments you have will have to be an active choice on your part.</description>
      <content:encoded>&lt;p&gt;&lt;a href="https://www.percona.com/live/conferences" target="_blank" rel="noopener noreferrer"&gt;Percona Live&lt;/a&gt; returns again to Austin May 16th through the 18th will find the city vibrant, charming, and weird. The semi-official motto for the city is ‘Keep Austin Weird’ and during your visit you will indeed see many of the residents working hard to do just that. Not in a bad way. Austin is at the intersection of so many cultural, artistic, and lifestyle modes that there are a fair amount of many different things happening at the same time to ensure that any dull moments you have will have to be an active choice on your part.&lt;/p&gt;
&lt;p&gt;The following is a quick guide for those new to Austin or looking for activities for the days before or after the show&lt;/p&gt;
&lt;h2 id="what-to-wear"&gt;What To Wear?&lt;/h2&gt;
&lt;p&gt;Austin in May averages 86F/30C (which is better than the August 96F/35C) so shorts, t-shirts, and comfortable shoes are a must. Bring sunscreen and water if you plan to spend time outdoors.&lt;/p&gt;
&lt;h2 id="what-to-eat"&gt;What to Eat?&lt;/h2&gt;
&lt;p&gt;The two main choices are barbeque and Tex-Mex. But you will find any type of cuisine you desire either in the restaurants or the food trucks (mostly on South Congress Street but found throughout the city). You may see many celebrities but remember in Austin that Matthew McConaughey is just another professor at the University of Texas and that Elon Musk builds pickup trucks.&lt;/p&gt;
&lt;h2 id="bbq"&gt;BBQ?&lt;/h2&gt;
&lt;p&gt;Barbecue is almost considered a religion in Texas and you will find many recommendations on where to go (see &lt;a href="https://austin.eater.com/maps/best-barbecue-austin-restaurants" target="_blank" rel="noopener noreferrer"&gt;https://austin.eater.com/maps/best-barbecue-austin-restaurants&lt;/a&gt;) but everyone has their favorite. Major competitions are run each year to determine who is the best. My personal favorite is the Salt Lick has two locations that are sadly out of Austin proper and they are known for moderating the heat of their barbeque pits by using pecans which adds a unique flavor. And they do have a location at the airport too; the food is good but the ambience is lacking with all the flight announcements.&lt;/p&gt;
&lt;p&gt;But the other places are pretty good too. Stubb’s, Franklin, Black’s are all excellent. If you do see a line at another place where salivating people are somewhat impatiently waiting to order, then join the queue. And it is okay to salivate too.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Big hint:&lt;/strong&gt; If you are not used to Texas Sweet Tea start with half sweetened and half unsweetened until your gums and your dentist have time to adjust.&lt;/p&gt;
&lt;h2 id="tex-mex"&gt;Tex-Mex&lt;/h2&gt;
&lt;p&gt;This style of food is a tasty combination of Chihuahuan Mexican food and frontier based ingredients with lots of cheese and chili. What started as simple staple foods for settlers on the frontier made from the available commodities has evolved into a tasty treat.&lt;br&gt;
Chuy’s original restaurant is a top pick and features theme rooms. Sadly we have already missed the birthday of Elvis Presley where all who dress like the King or his wife Priscilla dine free in their Elvis room. For the less decor oriented try Matt’s El Rancho.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Big tip:&lt;/strong&gt; You will generally get big portions, especially if you order fajitas or margaritas.&lt;/p&gt;
&lt;p&gt;For breakfast, go to Snooze AM for the pineapple upside pancakes or an omelet.&lt;/p&gt;
&lt;h2 id="museums"&gt;Museums&lt;/h2&gt;
&lt;p&gt;The Bob Bullock Museum is at the state capital building and is the state’s official history museum. The Museum of the Weird is just as the name implies and, while not official, provides a look into the odder parts of Austin. Not too far away is the Alamo in San Antonio (nearby the Alamo is the Buckhorn Saloon which actually has two floors of oddities that are weirder than the Museum of the Weird). The Museum of the Pacific War in Fredericksburg is a must for history fans. The Contemporary Austin is great for art fans while the Texas Toy museum will appeal to your inner child.&lt;/p&gt;
&lt;h2 id="outdoors-activity"&gt;Outdoors Activity&lt;/h2&gt;
&lt;p&gt;Swim in spring fed Barton Springs, ride the bike trails, and hike your feet off before you rent a paddleboard to tour Lake Austin. Lots of things for the physically active with appealing hikes and you may actually run into an Armadillo.&lt;/p&gt;
&lt;p&gt;You can rent inner tubes to float the nearby Guadalupe or Comal Rivers. Rent another inner tube for your cooler of drinks. Or visit the Schlitterbahn water park. All three are a short drive away and worth an extra day on your trip for time to spend with family or friends.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Big hint:&lt;/strong&gt; Stay hydrated as the heat is deceiving.&lt;/p&gt;
&lt;h2 id="other-activities"&gt;Other Activities&lt;/h2&gt;
&lt;p&gt;Gruene (pronounced ‘green’) Hall is the oldest dancehall in Texas and is the place where many top stars got their starts. Currently there are no acts scheduled during the time of Percona Live (well, I expect they will be at Percona Live learning about databases!) but fans of ZZ Top, George Strait, Willy Nelson, or Greg Allman will relish the history of the place before heading to the Grist Mill for a meal. The dance hall itself has not changed much since being built in 1878 and they will open the side flaps when the dancers need fresh air.&lt;/p&gt;
&lt;p&gt;Sixth Street is the live music capital of Texas and you will find any genre there. This is where Stevie Ray Vaughn rose to fame and where Willie Nelson rebuilt his career after leaving Nashville.Ear plugs recommended but optional.&lt;/p&gt;
&lt;p&gt;Yes, the bats do fly out from under the Congress Street bridge at sunset which is amazing when millions of them fly out. The last physical Percona Live they were shy and only a few appeared. I assume that they were intimidated by having so many DBAs nearby.&lt;/p&gt;
&lt;p&gt;Austin is an awesome town and not just for Percona Live itself. I have only touched the proverbial iceberg tip on things to see and do there. If you have questions, find me at Percona Live or email me at &lt;a href="mailto:david.stokes@percona.com"&gt;david.stokes@percona.com&lt;/a&gt; and hopefully we can try one of the local craft brews together.&lt;/p&gt;</content:encoded>
      <author>David Stokes</author>
      <category>blog</category>
      <category>PerconaLive</category>
      <category>PerconaLive2022</category>
      <category>Conference</category>
      <media:thumbnail url="https://percona.community/blog/2022/4/Guide-PL-2022_hu_e1bd6c54bf4e82b.jpg"/>
      <media:content url="https://percona.community/blog/2022/4/Guide-PL-2022_hu_d41ab1d8990e6564.jpg" medium="image"/>
    </item>
    <item>
      <title>Percona Monitoring and Management 2.27.0 Preview Release</title>
      <link>https://percona.community/blog/2022/04/08/preview-release/</link>
      <guid>https://percona.community/blog/2022/04/08/preview-release/</guid>
      <pubDate>Fri, 08 Apr 2022 00:00:00 UTC</pubDate>
      <description>Percona Monitoring and Management 2.27.0 Preview Release Percona Monitoring and Management 2.27.0 is now available as a Preview Release.</description>
      <content:encoded>&lt;h2 id="percona-monitoring-and-management-2270-preview-release"&gt;Percona Monitoring and Management 2.27.0 Preview Release&lt;/h2&gt;
&lt;p&gt;Percona Monitoring and Management 2.27.0 is now available as a Preview Release.&lt;/p&gt;
&lt;p&gt;PMM team really appreciates your feedback!&lt;/p&gt;
&lt;p&gt;We encourage you to try this PMM Preview Release in &lt;strong&gt;testing environments only&lt;/strong&gt;, as these packages and images are not fully production-ready. The final version is expected to be released through the standard channels in the coming week.&lt;/p&gt;
&lt;p&gt;Known issues:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://perconadev.atlassian.net/browse/PMM-9797" target="_blank" rel="noopener noreferrer"&gt;PMM-9797&lt;/a&gt; - Wrong Plot on Stat Panels for DB Conns and Disk Reads at Home Dashboard&lt;/li&gt;
&lt;li&gt;&lt;a href="https://perconadev.atlassian.net/browse/PMM-9820" target="_blank" rel="noopener noreferrer"&gt;PMM-9820&lt;/a&gt; - QAN page disappeared after upgrade via UI&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Release Notes can be found &lt;a href="https://pmm-doc-release-pr-726.onrender.com/release-notes/2.27.0.html" target="_blank" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="pmm-server-docker"&gt;PMM server docker&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://www.percona.com/doc/percona-monitoring-and-management/2.x/setting-up/server/docker.html" target="_blank" rel="noopener noreferrer"&gt;Instructions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;docker tag:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;perconalab/pmm-server:2.27.0-rc&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="pmm-client-package-installation"&gt;PMM client package installation&lt;/h3&gt;
&lt;p&gt;Download the latest pmm2-client Release Candidate tarball for 2.27.0 by this &lt;a href="https://s3.us-east-2.amazonaws.com/pmm-build-cache/PR-BUILDS/pmm2-client/pmm2-client-latest-3622.tar.gz" target="_blank" rel="noopener noreferrer"&gt;link&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you want to install pmm2-client package, please enable testing repository via Percona-release:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;percona-release enable percona testing&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;install pmm2-client package for your OS via package manager.&lt;/p&gt;
&lt;h3 id="ova"&gt;OVA&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://www.percona.com/doc/percona-monitoring-and-management/2.x/setting-up/server/virtual-appliance.html" target="_blank" rel="noopener noreferrer"&gt;Instructions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Artifact: &lt;a href="http://percona-vm.s3.amazonaws.com/PMM2-Server-2.27.0.ova" target="_blank" rel="noopener noreferrer"&gt;PMM2-Server-2.27.0.ova&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="ami"&gt;AMI&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://www.percona.com/doc/percona-monitoring-and-management/2.x/setting-up/server/aws.html" target="_blank" rel="noopener noreferrer"&gt;Instructions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Artifact: &lt;code&gt;ami-05592e370cca655b9&lt;/code&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Please also check out our Engineering Monthly Meetings &lt;a href="https://percona.community/contribute/engineeringmeetings/" target="_blank" rel="noopener noreferrer"&gt;https://percona.community/contribute/engineeringmeetings/&lt;/a&gt; and join us on our journey in OpenSource! Contact us in &lt;a href="https://forums.percona.com/" target="_blank" rel="noopener noreferrer"&gt;https://forums.percona.com/&lt;/a&gt;.&lt;/p&gt;</content:encoded>
      <author>Taras Kozub</author>
      <category>PMM</category>
      <media:thumbnail url="https://percona.community/superhero_hu_252fc2b480c0a197.jpg"/>
      <media:content url="https://percona.community/superhero_hu_17979f11d5d3562e.jpg" medium="image"/>
    </item>
    <item>
      <title>5 Steps to Improve Performance of Default MySQL Installation</title>
      <link>https://percona.community/blog/2022/01/27/5-steps-to-improve-performance-of-default-mysql-installation/</link>
      <guid>https://percona.community/blog/2022/01/27/5-steps-to-improve-performance-of-default-mysql-installation/</guid>
      <pubDate>Thu, 27 Jan 2022 00:00:00 UTC</pubDate>
      <description>Let’s say you have a fresh MySQL installation. Are there any possible steps to improve performance right away? Yes, there are!</description>
      <content:encoded>&lt;p&gt;Let’s say you have a fresh MySQL installation. Are there any possible steps to improve performance right away? Yes, there are!&lt;/p&gt;
&lt;p&gt;Recently, Marcos Albe (Principal Support Engineer, Percona) did an &lt;a href="https://percona.community/events/percona-meetups/2022-01-14-percona-meetup-for-mysql-january-2022/" target="_blank" rel="noopener noreferrer"&gt;online tuning&lt;/a&gt; on the MySQL Meetup hosted by Matt Yonkovit (Head of Open Source Strategy, Percona). Here are some steps you can consider to make your fresh MySQL installation to run better right from the start.&lt;/p&gt;
&lt;p&gt;So, we have a very basic default MySQL installation with some workload. It is connected to PMM, the slow query log is turned on. But it is largely unconfigured. Here is what actions Marcos considered to take to set up a new system to make sure that it’s actually set up from the beginning to reasonable defaults. Do some reactive configuration - go through the workload, observe bottlenecks and then configure to avoid bottlenecks&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1. Rate Limit for Slow Queries&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Go to MySQL Summary Dashboard In PMM, find your instance and set a rate limit instead of setting low query time to zero. Once we get to the 3000-4000 queries per second, these might start impacting performance in a way that is going to show in the latency papers. The thing is that while it is important to collect as many query details as possible, you don’t want to collect too many because it can impact performance and have the opposite effect of what you’re trying to do.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 2. Spikes&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Go down and turn the metrics off and on from data series from each of the graphs to be able to see the spikes on each magnitude. It allows you to find bad query patterns, under-dimensional or over-dimensional things.&lt;/p&gt;
&lt;p&gt;Think of it as workload being the light, MySQL being the prism and the metrics being the reflection of the light.&lt;/p&gt;
&lt;p&gt;Doing this, you can suggest different changes, like trying a slightly larger buffer size or increasing the thread cache. And as you go through the metrics, look at the values in the configuration, at the workload, and the actual work to find out if your hypotheses is correct.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2022/1/move_hu_a7820a12e73872ca.png 480w, https://percona.community/blog/2022/1/move_hu_396b32e948dbc00e.png 768w, https://percona.community/blog/2022/1/move_hu_bba934b29a032821.png 1400w"
src="https://percona.community/blog/2022/1/move.png" alt="Spikes" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 3. Buffer Pool Size&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Increase the buffer pool size. It is probably the most used and most recommended setting.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 4. Redo Log Size&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Increase the redo log size and restart the instance. Make the redo log file as large as reasonably possible. What is reasonable? Reasonable is an amount of time that will allow you to write at that rate for the duration of your big workload. The purpose is to allow more pages during the heavy write periods. The only thing you could fear here is the recovery time. You should do some testing to see if the recovery times are acceptable, just like you do for backups. And then if the time of recovery is unacceptable, you should consider having a HA setup, semi-synchronous or virtually synchronous setup, where you can failover to the next instance when this one crashes. Also, you could get faster drives, or you could try to convince your developers to write less&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 5. InnoDB IO Capacity&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Set InnoDB IO capacity to 200 unless you have proof you need more. Otherwise, you’re just forcing the flushing to happen too early. The thing is that you want to keep dirty pages. Dirty pages are the performance optimization. Imagine that you update the views counter for a popular video 100 times per second. If you have a very high capacity, you will probably write that road 50 times per second to disk. If you have a smaller capacity, you will probably write it once every few seconds. And then you’re actually only doing one write for hundreds of updates because all the rest were in memory and on the redo log.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2022/1/innodb_hu_55d3fb89c55056ca.png 480w, https://percona.community/blog/2022/1/innodb_hu_bcff448b89085994.png 768w, https://percona.community/blog/2022/1/innodb_hu_763774e0526e18b1.png 1400w"
src="https://percona.community/blog/2022/1/innodb.png" alt="InnoDB" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you want to watch the video of the meetup and see how Marcos tuned the installation, it is always available on the &lt;a href="https://percona.community/events/percona-meetups/2022-01-14-percona-meetup-for-mysql-january-2022/" target="_blank" rel="noopener noreferrer"&gt;Community Website&lt;/a&gt;.
The meetups for MySQL, PostgreSQL, PMM, and MongoDB are regularly live-streamed. Stay tuned to &lt;a href="https://percona.community/events/percona-meetups/" target="_blank" rel="noopener noreferrer"&gt;announcements&lt;/a&gt; and feel free to join!&lt;/p&gt;</content:encoded>
      <category>MySQL</category>
      <category>tuning</category>
      <media:thumbnail url="https://percona.community/blog/2018/10/export-data-to-JSON-from-MySQL_hu_42c14ff7c0d70c61.jpg"/>
      <media:content url="https://percona.community/blog/2018/10/export-data-to-JSON-from-MySQL_hu_db9c8048c3d6f089.jpg" medium="image"/>
    </item>
    <item>
      <title>PMM 2.26.0 Preview Release</title>
      <link>https://percona.community/blog/2022/01/27/preview-release-2-26/</link>
      <guid>https://percona.community/blog/2022/01/27/preview-release-2-26/</guid>
      <pubDate>Thu, 27 Jan 2022 00:00:00 UTC</pubDate>
      <description>PMM 2.26.0 Preview Release Percona Monitoring and Management 2.26.0 is now available as a Preview Release.</description>
      <content:encoded>&lt;h2 id="pmm-2260-preview-release"&gt;PMM 2.26.0 Preview Release&lt;/h2&gt;
&lt;p&gt;Percona Monitoring and Management 2.26.0 is now available as a Preview Release.&lt;/p&gt;
&lt;p&gt;PMM team really appreciates your feedback!&lt;/p&gt;
&lt;p&gt;We encourage you to try this PMM Preview Release in &lt;strong&gt;testing environments&lt;/strong&gt; only, as these packages and images are not fully production-ready. The final version is expected to be released through the standard channels in the coming week.&lt;/p&gt;
&lt;p&gt;Release Notes can be found &lt;a href="https://github.com/percona/pmm-doc/blob/bfc10bc70028af54e5f45a412010c3b301685750/docs/release-notes/2.26.0.md" target="_blank" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="pmm-server-docker"&gt;PMM server docker&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://www.percona.com/doc/percona-monitoring-and-management/2.x/setting-up/server/docker.html" target="_blank" rel="noopener noreferrer"&gt;Instructions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;docker tag: &lt;a href="https://hub.docker.com/layers/perconalab/pmm-server/2.26.0-rc/" target="_blank" rel="noopener noreferrer"&gt;perconalab/pmm-server:2.26.0-rc&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="pmm-client-package-installation"&gt;PMM client package installation&lt;/h3&gt;
&lt;p&gt;Download the latest pmm2-client Release Candidate tarball for 2.26.0 from this &lt;a href="https://s3.us-east-2.amazonaws.com/pmm-build-cache/PR-BUILDS/pmm2-client/pmm2-client-latest-3413.tar.gz" target="_blank" rel="noopener noreferrer"&gt;link&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you want to install pmm2-client package, please enable testing repository via Percona-release:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;percona-release enable original testing&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;install pmm2-client package for your OS via package manager.&lt;/p&gt;
&lt;h3 id="ova"&gt;OVA&lt;/h3&gt;
&lt;p&gt;Artifact: &lt;a href="http://percona-vm.s3-website-us-east-1.amazonaws.com/PMM2-Server-2022-01-27-1524.ova" target="_blank" rel="noopener noreferrer"&gt;PMM2-Server-2022-01-27-1524.ova&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.percona.com/doc/percona-monitoring-and-management/2.x/setting-up/server/virtual-appliance.html" target="_blank" rel="noopener noreferrer"&gt;Instructions&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Please also check out our Engineering Monthly Meetings &lt;a href="https://percona.community/contribute/engineeringmeetings/" target="_blank" rel="noopener noreferrer"&gt;https://percona.community/contribute/engineeringmeetings/&lt;/a&gt; and join us on our journey in OpenSource! Contact us at &lt;a href="mailto:community-team@percona.com"&gt;community-team@percona.com&lt;/a&gt; .&lt;/p&gt;</content:encoded>
      <author>Rasika Chivate</author>
      <category>PMM</category>
      <media:thumbnail url="https://percona.community/blog/2022/1/preview_226_hu_a4515b2b4583e574.jpg"/>
      <media:content url="https://percona.community/blog/2022/1/preview_226_hu_48fb868323cf9c7d.jpg" medium="image"/>
    </item>
    <item>
      <title>2.25.0 Preview Release</title>
      <link>https://percona.community/blog/2021/12/03/preview-release/</link>
      <guid>https://percona.community/blog/2021/12/03/preview-release/</guid>
      <pubDate>Fri, 03 Dec 2021 00:00:00 UTC</pubDate>
      <description>2.25.0 Preview Release Percona Monitoring and Management 2.25.0 is now available as a Preview Release.</description>
      <content:encoded>&lt;h2 id="2250-preview-release"&gt;2.25.0 Preview Release&lt;/h2&gt;
&lt;p&gt;Percona Monitoring and Management 2.25.0 is now available as a Preview Release.&lt;/p&gt;
&lt;p&gt;PMM team really appreciates your feedback!&lt;/p&gt;
&lt;p&gt;We encourage you to try this PMM Preview Release in &lt;strong&gt;testing environments&lt;/strong&gt; only, as these packages and images are not fully production-ready. The final version is expected to be released through the standard channels in the coming week.&lt;/p&gt;
&lt;p&gt;Release Notes can be found &lt;a href="https://docs.percona.com/percona-monitoring-and-management/release-notes/2.25.0.html" target="_blank" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="pmm-server-docker"&gt;PMM server docker&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://www.percona.com/doc/percona-monitoring-and-management/2.x/setting-up/server/docker.html" target="_blank" rel="noopener noreferrer"&gt;Instructions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;docker tag: perconalab/pmm-server:2.25.0-rc&lt;/p&gt;
&lt;h3 id="pmm-client-package-installation"&gt;PMM client package installation&lt;/h3&gt;
&lt;p&gt;Download the latest pmm2-client Release Candidate tarball for 2.25.0 from this &lt;a href="https://s3.us-east-2.amazonaws.com/pmm-build-cache/PR-BUILDS/pmm2-client/pmm2-client-latest-3300.tar.gz" target="_blank" rel="noopener noreferrer"&gt;link&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you want to install pmm2-client package, please enable testing repository via Percona-release:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;percona-release enable original testing&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;install pmm2-client package for your OS via package manager.&lt;/p&gt;
&lt;h3 id="ova"&gt;OVA&lt;/h3&gt;
&lt;p&gt;Artifact: &lt;a href="http://percona-vm.s3-website-us-east-1.amazonaws.com/PMM2-Server-2021-12-03-1855.ova" target="_blank" rel="noopener noreferrer"&gt;PMM2-Server-2021-12-03-1855.ova&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.percona.com/doc/percona-monitoring-and-management/2.x/setting-up/server/virtual-appliance.html" target="_blank" rel="noopener noreferrer"&gt;Instructions&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="ami"&gt;AMI&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://www.percona.com/doc/percona-monitoring-and-management/2.x/setting-up/server/aws.html" target="_blank" rel="noopener noreferrer"&gt;https://www.percona.com/doc/percona-monitoring-and-management/2.x/setting-up/server/aws.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Artifact id: &lt;code&gt;ami-04ba67eb15e6e089e&lt;/code&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Please also check out our Engineering Monthly Meetings &lt;a href="https://percona.community/contribute/engineeringmeetings/" target="_blank" rel="noopener noreferrer"&gt;https://percona.community/contribute/engineeringmeetings/&lt;/a&gt; and join us on our journey in OpenSource! Contact us at &lt;a href="mailto:community-team@percona.com"&gt;community-team@percona.com&lt;/a&gt; .&lt;/p&gt;</content:encoded>
      <author>Taras Kozub</author>
      <category>PMM</category>
      <media:thumbnail url="https://percona.community/blog/2021/12/preview_225_hu_b57661f11988d885.jpg"/>
      <media:content url="https://percona.community/blog/2021/12/preview_225_hu_7501f4a76d1ef9da.jpg" medium="image"/>
    </item>
    <item>
      <title>2.24.0 Preview Release</title>
      <link>https://percona.community/blog/2021/11/11/preview-release/</link>
      <guid>https://percona.community/blog/2021/11/11/preview-release/</guid>
      <pubDate>Thu, 11 Nov 2021 00:00:00 UTC</pubDate>
      <description>2.24.0 Preview Release Percona Monitoring and Management 2.24.0 is now available as a Preview Release.</description>
      <content:encoded>&lt;h2 id="2240-preview-release"&gt;2.24.0 Preview Release&lt;/h2&gt;
&lt;p&gt;Percona Monitoring and Management 2.24.0 is now available as a Preview Release.&lt;/p&gt;
&lt;p&gt;PMM team really appreciates your feedback!&lt;/p&gt;
&lt;p&gt;We encourage you to try this PMM Preview Release in &lt;strong&gt;testing environments&lt;/strong&gt; only, as these packages and images are not fully production-ready. The final version is expected to be released through the standard channels in the coming week.&lt;/p&gt;
&lt;p&gt;Release Notes can be found &lt;a href="https://deploy-preview-622--pmm-doc.netlify.app/release-notes/2.24.0.html" target="_blank" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="pmm-server-docker"&gt;PMM server docker&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://www.percona.com/doc/percona-monitoring-and-management/2.x/setting-up/server/docker.html" target="_blank" rel="noopener noreferrer"&gt;Instructions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;docker tag: &lt;a href="https://hub.docker.com/layers/perconalab/pmm-server/2.24.0-rc/images/sha256-e59fbdf2ffe7e30a3eb3cc83c438130bcecd8ca6ea02ef04c8a121fbb81a948a?context=explore" target="_blank" rel="noopener noreferrer"&gt;perconalab/pmm-server:2.24.0-rc&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="pmm-client-package-installation"&gt;PMM client package installation&lt;/h3&gt;
&lt;p&gt;Download the latest pmm2-client Release Candidate tarball for 2.24.0 from this &lt;a href="https://s3.us-east-2.amazonaws.com/pmm-build-cache/PR-BUILDS/pmm2-client/pmm2-client-latest-3216.tar.gz" target="_blank" rel="noopener noreferrer"&gt;link&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you want to install pmm2-client package, please enable testing repository via Percona-release:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;percona-release enable original testing&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;install pmm2-client package for your OS via package manager.&lt;/p&gt;
&lt;h3 id="ova"&gt;OVA&lt;/h3&gt;
&lt;p&gt;Artifact: &lt;a href="http://percona-vm.s3-website-us-east-1.amazonaws.com/PMM2-Server-2021-11-10-1310.ova" target="_blank" rel="noopener noreferrer"&gt;PMM2-Server-2021-11-10-1310.ova&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.percona.com/doc/percona-monitoring-and-management/2.x/setting-up/server/virtual-appliance.html" target="_blank" rel="noopener noreferrer"&gt;Instructions&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="ami"&gt;AMI&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://www.percona.com/doc/percona-monitoring-and-management/2.x/setting-up/server/aws.html" target="_blank" rel="noopener noreferrer"&gt;https://www.percona.com/doc/percona-monitoring-and-management/2.x/setting-up/server/aws.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Artifact id: &lt;code&gt;ami-03db8ae0f3ef49618&lt;/code&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Please also check out our Engineering Monthly Meetings &lt;a href="https://percona.community/contribute/engineeringmeetings/" target="_blank" rel="noopener noreferrer"&gt;https://percona.community/contribute/engineeringmeetings/&lt;/a&gt; and join us on our journey in OpenSource! Contact us Contact us at &lt;a href="mailto:community-team@percona.com"&gt;community-team@percona.com&lt;/a&gt; .&lt;/p&gt;</content:encoded>
      <author>Taras Kozub</author>
      <category>PMM</category>
      <media:thumbnail url="https://percona.community/blog/2021/11/preview_224_hu_7fcb27e8f8ae902d.jpg"/>
      <media:content url="https://percona.community/blog/2021/11/preview_224_hu_32b78b028248d4eb.jpg" medium="image"/>
    </item>
    <item>
      <title>The Errant GTID</title>
      <link>https://percona.community/blog/2021/11/08/the-errant-gtid-pt1/</link>
      <guid>https://percona.community/blog/2021/11/08/the-errant-gtid-pt1/</guid>
      <pubDate>Mon, 08 Nov 2021 00:00:00 UTC</pubDate>
      <description>Part 1 What is a GTID? Oracle/MySQL define a GTID as "A global transaction identifier (GTID) is a unique identifier created and associated with each transaction committed on the server of origin (the source). This identifier is unique not only to the server on which it originated, but is unique across all servers in a given replication topology." An errant transaction can make promotion of a replica to primary very difficult.</description>
      <content:encoded>&lt;h1 id="part-1"&gt;Part 1&lt;/h1&gt;
&lt;p&gt;What is a GTID? Oracle/MySQL define a GTID as "A global transaction identifier (GTID) is a unique identifier created and associated with each transaction committed on the server of origin (the source). This identifier is unique not only to the server on which it originated, but is unique across all servers in a given replication topology."
&lt;p&gt;An errant transaction can make
promotion of a replica to primary very difficult.&lt;/p&gt;
&lt;p&gt;An errant transaction is BAD. Why is it bad? The errant transaction could still be in the replicas binlog so when it becomes the new primary these event will get sent to other replicas causing data corruption or breaking replication.&lt;/p&gt;
&lt;h4 id="its-easy-to-prevent-errant-transaction"&gt;Its easy to prevent errant transaction.&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;read_only = ON&lt;/code&gt; in the replicas my.cnf&lt;/li&gt;
&lt;li&gt;Disable binlogs when you need to perform work on a replica. &lt;code&gt;set session sql_log_bin = 'off';&lt;/code&gt; before your work on replica. &lt;code&gt;set session sql_log_bin = 'on';&lt;/code&gt; when your work is complete.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="find-and-correct-errant-transaction"&gt;Find and correct errant transaction&lt;/h4&gt;
&lt;p&gt;How do you correct an errant transaction? Compare the &lt;code&gt;gtid_executed&lt;/code&gt; on the primary and replica. Identify the errant transaction on the replica and then apply that transaction to the primary.&lt;/p&gt;
&lt;p&gt;I will show you one method in the steps below.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;On the replica run &lt;code&gt;show variables like 'gtid_executed'&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You will receive output similar to this:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mysql_replica&gt; show variables like 'gtid_executed'\G
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;*************************** 1. row ***************************
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Variable_name: gtid_executed
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Value: 858d4d54-3fe1-11ec-a7e8-080027ae8b99:1,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;a6b3751e-3fd3-11ec-a4f5-080027ae8b99:1-2
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;1 row in set (0.00 sec)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Make note of the gtid_executed value. You will need this to check if you have an errant transaction.&lt;/p&gt;
&lt;ol start="2"&gt;
&lt;li&gt;On the primary run &lt;code&gt;show variables like 'gtid_executed'&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You will receive output similar to this:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-1"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mysql_primary&gt; show variables like 'gtid_executed'\G
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;*************************** 1. row ***************************
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Variable_name: gtid_executed
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Value: 858d4d54-3fe1-11ec-a7e8-080027ae8b99:1,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;a6b3751e-3fd3-11ec-a4f5-080027ae8b99:1-2
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;1 row in set (0.00 sec)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Make note of the gtid_executed value. You will need this to check if you have an errant transaction.&lt;/p&gt;
&lt;ol start="3"&gt;
&lt;li&gt;We need to determine if the replica has any errant transaction’s. We will use the function: ‘gtid_subset’ to compare the executed GTID set from &lt;strong&gt;replica&lt;/strong&gt; and &lt;strong&gt;primary&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-2" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-2"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mysql_replica&gt; select gtid_subset('858d4d54-3fe1-11ec-a7e8-080027ae8b99:1,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; '&gt; a6b3751e-3fd3-11ec-a4f5-080027ae8b99:1-2','858d4d54-3fe1-11ec-a7e8-080027ae8b99:1,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; '&gt; a6b3751e-3fd3-11ec-a4f5-080027ae8b99:1-2') as subset;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+--------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| subset |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+--------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| 1 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+--------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;1 row in set (0.00 sec)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Subset = 1 tells us we have &lt;strong&gt;no&lt;/strong&gt; errant transactions.&lt;/p&gt;
&lt;p&gt;Now we need to introduce an errant transaction in to the replica. Let’s do something simple by creating a new database.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-3" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-3"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mysql_replica&gt; create database community;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Query OK, 1 row affected (0.01 sec)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Lets repeat step 1 from above.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-4" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-4"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mysql_replica&gt; show variables like 'gtid_executed'\G
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;*************************** 1. row ***************************
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Variable_name: gtid_executed
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Value: 858d4d54-3fe1-11ec-a7e8-080027ae8b99:1-2,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;a6b3751e-3fd3-11ec-a4f5-080027ae8b99:1-2
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;1 row in set (0.00 sec)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;We will repeat step 3 using the &lt;strong&gt;new gtid_executed&lt;/strong&gt; from the replica and the &lt;strong&gt;original gtid_executed&lt;/strong&gt; from the primary.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-5" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-5"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mysql_replica&gt; select gtid_subset('858d4d54-3fe1-11ec-a7e8-080027ae8b99:1-2,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; '&gt; a6b3751e-3fd3-11ec-a4f5-080027ae8b99:1-2','858d4d54-3fe1-11ec-a7e8-080027ae8b99:1,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; '&gt; a6b3751e-3fd3-11ec-a4f5-080027ae8b99:1-2') as subset;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+--------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| subset |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+--------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| 0 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+--------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;1 row in set (0.00 sec)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Subset = 0 tells us that this replica has errant transactions.&lt;/p&gt;
&lt;p&gt;Now we need to determine the errant transaction. We will need to subtract the &lt;code&gt;replica executed GTID&lt;/code&gt; from the &lt;code&gt;primary executed GTID&lt;/code&gt;. To do this we will use the &lt;code&gt;gtid_subtract&lt;/code&gt; function.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-6" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-6"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;`mysql_replica&gt; select gtid_subtract('858d4d54-3fe1-11ec-a7e8-080027ae8b99:1-2,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; '&gt; a6b3751e-3fd3-11ec-a4f5-080027ae8b99:1-2','858d4d54-3fe1-11ec-a7e8-080027ae8b99:1,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; '&gt; a6b3751e-3fd3-11ec-a4f5-080027ae8b99:1-2') as errant;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+----------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| errant |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+----------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| 858d4d54-3fe1-11ec-a7e8-080027ae8b99:2 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+----------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;1 row in set (0.00 sec)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Now we have our errant transaction from the replica &lt;code&gt;858d4d54-3fe1-11ec-a7e8-080027ae8b99:2&lt;/code&gt;&lt;/p&gt;
&lt;h4 id="repair-the-issue"&gt;Repair the issue&lt;/h4&gt;
&lt;p&gt;Now let’s move to the &lt;strong&gt;primary&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Once on the &lt;strong&gt;primary&lt;/strong&gt; we want to insert a pseudo transaction to resolve the errant transaction from the replica.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-7" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-7"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mysql_primary&gt; set gtid_next='858d4d54-3fe1-11ec-a7e8-080027ae8b99:2';
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Query OK, 0 rows affected (0.00 sec)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mysql_primary&gt; begin;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Query OK, 0 rows affected (0.00 sec)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;`mysql_primary&gt; commit;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Query OK, 0 rows affected (0.00 sec)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;`mysql_primary&gt; set gtid_next='automatic';
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Query OK, 0 rows affected (0.00 sec)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;We can compare the GTID executed again from the replica and primary.&lt;/p&gt;
&lt;h4 id="primary"&gt;Primary:&lt;/h4&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-8" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-8"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mysql_primary&gt; show variables like 'gtid_executed'\G
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;*************************** 1. row ***************************
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Variable_name: gtid_executed
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Value: 858d4d54-3fe1-11ec-a7e8-080027ae8b99:1-2,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;a6b3751e-3fd3-11ec-a4f5-080027ae8b99:1-2
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;1 row in set (0.00 sec)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h4 id="replica"&gt;Replica:&lt;/h4&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-9" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-9"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mysql_replica&gt; show variables like 'gtid_executed'\G
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;*************************** 1. row ***************************
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Variable_name: gtid_executed
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Value: 858d4d54-3fe1-11ec-a7e8-080027ae8b99:1-2,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;a6b3751e-3fd3-11ec-a4f5-080027ae8b99:1-2
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;1 row in set (0.00 sec)`&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Note that both values match. We have repaired the errant transaction from the replica to the primary.&lt;/p&gt;
&lt;p&gt;Now we need to take care of the replica that had the errant transaction. We need to flush and purge the binary logs. Use the commands below to find the current binary file, and then flush and purge. &lt;strong&gt;Remember to be on the replica&lt;/strong&gt;.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-10" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-10"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;show binary logs;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;FLUSH LOGS;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;PURGE BINARY LOGS TO 'binlog.00000x';&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Thats it. You have fixed the errant transaction. This was a rather simple example of an errant GTID. I will be doing part 2 that will look at more complexed examples.
&lt;/p&gt;
&lt;h3 id="referance-information"&gt;Referance Information&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.mysql.com/doc/refman/8.0/en/set-sql-log-bin.html" target="_blank" rel="noopener noreferrer"&gt;Set SQL Log Bin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.mysql.com/doc/refman/8.0/en/gtid-functions.html" target="_blank" rel="noopener noreferrer"&gt;GTID Functions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded>
      <author>Wayne Leutwyler</author>
      <category>Percona</category>
      <category>MySQL</category>
      <category>Recovery</category>
      <category>Replication</category>
      <category>GTID</category>
      <media:thumbnail url="https://percona.community/blog/2021/11/errant-gtid-1_hu_ee112b4f2df8b1e3.jpg"/>
      <media:content url="https://percona.community/blog/2021/11/errant-gtid-1_hu_34baad6223fe5844.jpg" medium="image"/>
    </item>
    <item>
      <title>2.23.0 Preview Release(Updated!)</title>
      <link>https://percona.community/blog/2021/10/15/preview-release/</link>
      <guid>https://percona.community/blog/2021/10/15/preview-release/</guid>
      <pubDate>Fri, 15 Oct 2021 00:00:00 UTC</pubDate>
      <description>Update Percona Monitoring and Management 2.23.0 is now available as a Public Release!</description>
      <content:encoded>&lt;h2 id="update"&gt;Update&lt;/h2&gt;
&lt;p&gt;Percona Monitoring and Management 2.23.0 is now available as a Public Release!&lt;/p&gt;
&lt;p&gt;Release notes for Percona Monitoring and Management 2.23.0 Public Release can be found &lt;a href="https://per.co.na/pmm/2.23.0" target="_blank" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="2230-preview-release"&gt;2.23.0 Preview Release&lt;/h2&gt;
&lt;p&gt;Percona Monitoring and Management 2.23.0 is released today as a Preview Release.&lt;/p&gt;
&lt;p&gt;PMM team really appreciates your feedback!&lt;/p&gt;
&lt;p&gt;We encourage you to try this PMM Internal Release in &lt;strong&gt;testing environments&lt;/strong&gt; only, as these packages and images are not fully production-ready. The final version is expected to be released through the standard channels in the coming week.&lt;/p&gt;
&lt;p&gt;Known issue:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://perconadev.atlassian.net/browse/PMM-8983" target="_blank" rel="noopener noreferrer"&gt;PMM-8983&lt;/a&gt; - DBaaS: PXC cluster is displayed as active after suspend&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Release notes:
Release Notes Preview found &lt;a href="https://deploy-preview-610--pmm-doc.netlify.app/release-notes/2.23.0.html" target="_blank" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="pmm-server-docker"&gt;PMM server docker&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://www.percona.com/doc/percona-monitoring-and-management/2.x/setting-up/server/docker.html" target="_blank" rel="noopener noreferrer"&gt;Instructions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;docker tag: &lt;a href="https://hub.docker.com/layers/percona/pmm-server/2.23.0/images/sha256-ff0bb20cba0dbfcc8929dbbba0558bb01acc933ec593717727707dce083441b4?context=explore" target="_blank" rel="noopener noreferrer"&gt;percona/pmm-server:2.23.0&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="pmm-client-package-installation"&gt;PMM client package installation&lt;/h3&gt;
&lt;p&gt;Download the latest pmm2-client Release Candidate tarball for 2.23.0 from this &lt;a href="https://s3.us-east-2.amazonaws.com/pmm-build-cache/PR-BUILDS/pmm2-client/pmm2-client-latest-3126.tar.gz" target="_blank" rel="noopener noreferrer"&gt;link&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you want to install pmm2-client package, please enable testing repository via Percona-release:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;percona-release enable original testing&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;install pmm2-client package for your OS via package manager.&lt;/p&gt;
&lt;h3 id="ova"&gt;OVA&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://www.percona.com/doc/percona-monitoring-and-management/2.x/setting-up/server/virtual-appliance.html" target="_blank" rel="noopener noreferrer"&gt;Instructions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Artifact: &lt;a href="http://percona-vm.s3-website-us-east-1.amazonaws.com/PMM2-Server-2021-10-14-2120.ova" target="_blank" rel="noopener noreferrer"&gt;PMM2-Server-2021-10-14-2120.ova&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="ami"&gt;AMI&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://www.percona.com/doc/percona-monitoring-and-management/2.x/setting-up/server/aws.html" target="_blank" rel="noopener noreferrer"&gt;https://www.percona.com/doc/percona-monitoring-and-management/2.x/setting-up/server/aws.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Artifact id: &lt;code&gt;ami-047173e7a14c3f287&lt;/code&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Please also check out our Engineering Monthly Meetings &lt;a href="https://percona.community/contribute/engineeringmeetings/" target="_blank" rel="noopener noreferrer"&gt;https://percona.community/contribute/engineeringmeetings/&lt;/a&gt; and join us on our journey in OpenSource! Contact us at &lt;a href="mailto:community-team@percona.com"&gt;community-team@percona.com&lt;/a&gt; .&lt;/p&gt;</content:encoded>
      <author>Taras Kozub</author>
      <category>PMM</category>
      <media:thumbnail url="https://percona.community/blog/2021/10/super_hero_sloth_hu_8a1e547f9c5b81d0.jpg"/>
      <media:content url="https://percona.community/blog/2021/10/super_hero_sloth_hu_c66f52f5f7da3ea3.jpg" medium="image"/>
    </item>
    <item>
      <title>2.22.0 Preview Release</title>
      <link>https://percona.community/blog/2021/09/16/preview-release/</link>
      <guid>https://percona.community/blog/2021/09/16/preview-release/</guid>
      <pubDate>Thu, 16 Sep 2021 00:00:00 UTC</pubDate>
      <description>2.20.0 Preview Release Percona Monitoring and Management 2.22.0 is released today as a Preview Release.</description>
      <content:encoded>&lt;h2 id="2200-preview-release"&gt;2.20.0 Preview Release&lt;/h2&gt;
&lt;p&gt;Percona Monitoring and Management 2.22.0 is released today as a Preview Release.&lt;/p&gt;
&lt;p&gt;PMM team really appreciates your feedback!&lt;/p&gt;
&lt;p&gt;We encourage you to try this PMM Preview Release in &lt;strong&gt;testing environments&lt;/strong&gt; only, as these packages and images are not fully production-ready. The final version is expected to be released through the standard channels in the coming week.&lt;/p&gt;
&lt;p&gt;Known issue:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://perconadev.atlassian.net/browse/PMM-8829" target="_blank" rel="noopener noreferrer"&gt;PMM-8829&lt;/a&gt; - “Missing Listen Port” error for external exporters after restart&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Release notes:
Release Notes Preview found &lt;a href="https://deploy-preview-588--pmm-doc.netlify.app/release-notes/2.22.0.html" target="_blank" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="pmm-server-docker"&gt;PMM server docker&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://www.percona.com/doc/percona-monitoring-and-management/2.x/setting-up/server/docker.html" target="_blank" rel="noopener noreferrer"&gt;Instructions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;docker tag: &lt;code&gt;perconalab/pmm-server:2.22.0-rc&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://hub.docker.com/layers/perconalab/pmm-server/2.22.0-rc/" target="_blank" rel="noopener noreferrer"&gt;https://hub.docker.com/layers/perconalab/pmm-server/2.22.0-rc/&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="pmm-client-package-installation"&gt;PMM client package installation&lt;/h3&gt;
&lt;p&gt;Download the latest pmm2-client Release Candidate tarball for 2.22.0 from this &lt;a href="https://s3.us-east-2.amazonaws.com/pmm-build-cache/PR-BUILDS/pmm2-client/pmm2-client-PR-2003-7917413.tar.gz" target="_blank" rel="noopener noreferrer"&gt;link&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you want to install pmm2-client package, please enable testing repository via Percona-release:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;percona-release enable original testing&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;install pmm2-client package for your OS via package manager.&lt;/p&gt;
&lt;h3 id="ova"&gt;OVA&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://www.percona.com/doc/percona-monitoring-and-management/2.x/setting-up/server/virtual-appliance.html" target="_blank" rel="noopener noreferrer"&gt;Instructions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Artifact: &lt;a href="http://percona-vm.s3-website-us-east-1.amazonaws.com/PMM2-Server-2021-09-14-1514.ova" target="_blank" rel="noopener noreferrer"&gt;PMM2-Server-2021-09-14-1514.ova&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="ami"&gt;AMI&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://www.percona.com/doc/percona-monitoring-and-management/2.x/setting-up/server/aws.html" target="_blank" rel="noopener noreferrer"&gt;https://www.percona.com/doc/percona-monitoring-and-management/2.x/setting-up/server/aws.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Artifact id: &lt;code&gt;ami-0a6b861c9225afbd8&lt;/code&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Please also check out our Engineering Monthly Meetings &lt;a href="https://percona.community/contribute/engineeringmeetings/" target="_blank" rel="noopener noreferrer"&gt;https://percona.community/contribute/engineeringmeetings/&lt;/a&gt; and join us on our journey in OpenSource! Contact us at &lt;a href="mailto:community-team@percona.com"&gt;community-team@percona.com&lt;/a&gt; .&lt;/p&gt;</content:encoded>
      <author>Denys Kondratenko</author>
      <category>PMM</category>
      <media:thumbnail url="https://percona.community/superhero_hu_252fc2b480c0a197.jpg"/>
      <media:content url="https://percona.community/superhero_hu_17979f11d5d3562e.jpg" medium="image"/>
    </item>
    <item>
      <title>The lost art of Database Server Initialization.</title>
      <link>https://percona.community/blog/2021/09/06/lost-art-of-database-server-initialization/</link>
      <guid>https://percona.community/blog/2021/09/06/lost-art-of-database-server-initialization/</guid>
      <pubDate>Mon, 06 Sep 2021 00:00:00 UTC</pubDate>
      <description>With all the DBaaS, IaaS and PaaS environments, sometimes I think the Art of MySQL initialization is becoming a lost art. Many times we just delete the MySQL Server and order a new one.</description>
      <content:encoded>&lt;p&gt;With all the DBaaS, IaaS and PaaS environments, sometimes I think the Art of MySQL initialization is becoming a lost art. Many times we just delete the MySQL Server and order a new one.&lt;/p&gt;
&lt;p&gt;Just recently I was talking with a colleague, and this subject came up. We both thought about it and decided we have become spoiled by automation. We were both rusty on this process. This gave me the idea for this post.
&lt;figure&gt;&lt;img src="https://percona.community/blog/2021/09/lostart-01.png" alt="lostart-10" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;You might be thinking why initialize MySQL again? Let’s say that you wanted MySQL Server 8.0 not to use mixed case. Yet when the database was initialized the default setting of &lt;code&gt;lower_case_table_names = 0&lt;/code&gt; was used. With 8.0 you can’t make the change &lt;code&gt;lower_case_table_names = 1&lt;/code&gt; in the my.cnf and restart MySQL. It won’t work, leaving you with two option. One Initialize MySQL a second time, or order a new environment.&lt;/p&gt;
&lt;p&gt;Let’s look at the steps we would need to change the MySQL server to support only lower case.&lt;/p&gt;
&lt;p&gt;You may want to take a backup before you begin these steps if you have already loaded data that you wish to keep.&lt;/p&gt;
&lt;h2 id="the-steps"&gt;The Steps&lt;/h2&gt;
&lt;p&gt;The steps below assume you are working with a default MySQL
server installation. Modify as needed for a custom installation. One word of caution. Please dont user root to run the bellow commands. Use &lt;code&gt;sudo mysql&lt;/code&gt; this will add an extra layer of safety by not being root.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Stop the MySQL Server. &lt;code&gt;$ systemctl stop mysqld&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You will need to delete everything out of your current data directory.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ rm -fR /var/lib/mysql*&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Edit your my.cnf file and add: &lt;code&gt;lower_case_table_names=1&lt;/code&gt;&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-1"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ vi /etc/my.cnf&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2021/09/lostart-02.png" alt="lostart-10" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Now initialize mysql.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-2" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-2"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ /usr/sbin/mysqld --initialize --user=mysql&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Get the temporary root password from the &lt;code&gt;mysqld.log&lt;/code&gt;&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-3" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-3"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ cat /var/log/mysqld.log | grep password&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2021/09/lostart-03_hu_5141778ed22a6fd5.png 480w, https://percona.community/blog/2021/09/lostart-03_hu_1c375d4cb25f1391.png 768w, https://percona.community/blog/2021/09/lostart-03_hu_649f1469cd09bbe4.png 1400w"
src="https://percona.community/blog/2021/09/lostart-03.png" alt="lostart-10" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;If you dont find the temporary password for the root user, review the steps above making sure you did not miss something.&lt;/p&gt;
&lt;ol start="6"&gt;
&lt;li&gt;Start MySQL.
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-4" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-4"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ systemctl start mysqld&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;Verify MySQL is running.
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-5" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-5"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ cat /var/log/mysqld.log&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2021/09/lostart-04.png" alt="lostart-10" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Now you should be able to log into MySQL using the password received got from step 5.&lt;/p&gt;
&lt;p&gt;There could be many more reasons to re-initliatize a MySQL Database. This is just one example.
Automation is great. Just remember to pull out your command line tools now and then, so they dont get to rusty.&lt;/p&gt;</content:encoded>
      <author>Wayne Leutwyler</author>
      <category>Percona</category>
      <category>MySQL</category>
      <category>Recovery</category>
      <category>Installation</category>
      <media:thumbnail url="https://percona.community/blog/2021/09/lostart-01_hu_62162eb2becac880.jpg"/>
      <media:content url="https://percona.community/blog/2021/09/lostart-01_hu_6c77c8b753b5f4a8.jpg" medium="image"/>
    </item>
    <item>
      <title>Lets be inSync!</title>
      <link>https://percona.community/blog/2021/07/22/lets-be-insync/</link>
      <guid>https://percona.community/blog/2021/07/22/lets-be-insync/</guid>
      <pubDate>Thu, 22 Jul 2021 00:00:00 UTC</pubDate>
      <description>Percona Toolkit + pt-table-checksum + pt-table-sync = Faster Replica Recovery Asynchronous replication with MySQL is a tried and true technology. Add the use of GTID’s and you have a very stable solution.</description>
      <content:encoded>&lt;h2 id="percona-toolkit--pt-table-checksum--pt-table-sync--faster-replica-recovery"&gt;Percona Toolkit + pt-table-checksum + pt-table-sync = Faster Replica Recovery&lt;/h2&gt;
&lt;p&gt;Asynchronous replication with MySQL is a tried and true technology. Add the use of GTID’s and you have a very
stable solution.&lt;/p&gt;
&lt;p&gt;The fundamental issue with async replication is that writes sent to the Replica are not guaranteed to be written. I have only seen a handful of times when writes did not get applied to the replica. Most of the time this happens is due to network packet drops or a replica crashes before new data is committed.&lt;/p&gt;
&lt;p&gt;I can remember long nights of restoring backups of the primary to the replica’s. Not a painful process but time consuming.&lt;/p&gt;
&lt;p&gt;Please take a few moments to review the full &lt;a href="https://www.percona.com/software/database-tools/percona-toolkit" target="_blank" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; of both tools before trying this example on live data: &lt;strong&gt;pt-table-checksum, pt-table-sync&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;With pt-table-check and pt-table-sync provided by Percona Toolkit we can recover a replica without needed to do a restore. Keep in mind this approach might not work for all situations. We will go over one example below. We will also use dbdeployer to help us setup a testing sandbox.&lt;/p&gt;
&lt;p&gt;Let’s start off by setting up a VM to play with. For this I will be using Virtualbox and Ubuntu 20.04LTS.&lt;/p&gt;
&lt;h3 id="prepare-ubuntu-2004lts"&gt;Prepare Ubuntu 20.04LTS&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;sudo apt install gnupg2 curl libaio-dev libncurses-dev mysql-client-core-8.0&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;wget https://repo.percona.com/apt/percona-release_latest.$(lsb_release -sc)_all.deb&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sudo dpkg -i percona-release_latest.$(lsb_release -sc)_all.deb&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sudo percona-release enable tools release&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sudo apt update&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sudo apt install percona-toolkit sysbench&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="install-dbdeployer"&gt;Install dbdeployer&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;mkdir $HOME/bin ; cd $HOME/bin ; source $HOME/.profile&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;curl -s https://raw.githubusercontent.com/datacharmer/dbdeployer/master/scripts/dbdeployer-install.sh | bash&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2021/07/lbis-2.png" alt="lbis-2" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;ol start="3"&gt;
&lt;li&gt;&lt;code&gt;ln -s dbdeployer-1.60.0.linux dbdeployer&lt;/code&gt; (symlink for less typing)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dbdeployer init&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2021/07/lbis-3.png" alt="lbis-3" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;ol start="5"&gt;
&lt;li&gt;Download Percona Server: &lt;code&gt;wget https://downloads.percona.com/downloads/Percona-Server-LATEST/Percona-Server-8.0.25-15/binary/tarball/Percona-Server-8.0.25-15-Linux.x86_64.glibc2.17-minimal.tar.gz&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2021/07/lbis-4.png" alt="lbis-4" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;ol start="6"&gt;
&lt;li&gt;Prepare Percona Server: &lt;code&gt;dbdeployer --prefix=ps unpack Percona-Server-8.0.23-14-Linux.x86_64.glibc2.17-minimal.tar.gz&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2021/07/lbis-6.png" alt="lbis-6" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;ol start="7"&gt;
&lt;li&gt;Deploy your cluster:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; dbdeployer deploy replication ps8.0.23 \
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --gtid \
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --custom-role-name=R_POWERFUL \
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --custom-role-privileges='ALL PRIVILEGES' \
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --custom-role-target='*.*' \
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --custom-role-extra='WITH GRANT OPTION' \
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --default-role=R_POWERFUL \
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --bind-address=0.0.0.0 \
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --remote-access='%' \
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --native-auth-plugin \
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --db-user=sbtest \
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --db-password=sbtest!&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Lets verify our Cluster: &lt;code&gt;dbdeployer sandboxes --full-info&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2021/07/lbis-7.png" alt="lbis-7" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Change directories into you cluster directory: &lt;code&gt;_$HOME/sandboxes/rsandboxps8.0.23_&lt;/code&gt; and run the &lt;code&gt;./check_slaves&lt;/code&gt; script.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2021/07/lbis-9.png" alt="lbis-9" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;This will display information about your new cluster. Take time to make yourself familiar with the scripts in this directory.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; we will stay in the &lt;code&gt;_$HOME/sandboxes/rsandboxps8.0.23_&lt;/code&gt; for remainder of this post. * Please note that the location of your cluster might be different. *&lt;/p&gt;
&lt;h3 id="preparing-data-for-testing"&gt;Preparing Data for testing&lt;/h3&gt;
&lt;p&gt;Let’s move on and add some data to play with. While in your sandboxes/cluster directory run this command:&lt;/p&gt;
&lt;p&gt;Connect you to the master: &lt;code&gt;mysql --socket=/tmp/mysql_sandbox21325.sock --port=21325 -u sbtest -p&lt;/code&gt;&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-1"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;create database synctest;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;use synctest;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;create table names (id int not null auto_increment primary key, fname varchar(50), lname varchar(50));
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;insert into names (fname,lname) values ('Moe','Howard');
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;insert into names (fname,lname) values ('Larry','Howard');
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;insert into names (fname,lname) values ('Curly','Howard');
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;insert into names (fname,lname) values ('Shemp','Howard');
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;insert into names (fname,lname) values ('Joe','Howard');
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;insert into names (fname,lname) values ('James','Bond');
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;insert into names (fname,lname) values ('Doctor','No');
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;insert into names (fname,lname) values ('Gold','Finger');
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;insert into names (fname,lname) values ('Money','Penny');
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;insert into names (fname,lname) values ('Number','One');
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;insert into names (fname,lname) values ('Number','Two');
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;insert into names (fname,lname) values (‘Micky','Mouse');&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Make sure you do a quick &lt;code&gt;select * from percona.synctest&lt;/code&gt;;&lt;/p&gt;
&lt;p&gt;You should see 12 rows of data. If you don’t double check your inserts.&lt;/p&gt;
&lt;p&gt;Let’s connect to mysql and create a percona database and add the dsns table.
We will need this database and table to hold our checksums and DSNS data.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-2" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-2"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;create database percona;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;use percona;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;CREATE TABLE `dsns` (
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; `id` int(11) NOT NULL AUTO_INCREMENT,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; `parent_id` int(11) DEFAULT NULL,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; `dsn` varchar(255) NOT NULL,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; PRIMARY KEY (`id`)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;insert into dsns (id,parent_id,dsn) values (1,1,"h=percona-lab,u=sbtest,p=sbtest!,P=21325");
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;insert into dsns (id,parent_id,dsn) values (2,2,"h=percona-lab,u=sbtest,p=sbtest!,P=21326");&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Remember to populate this data based on your cluster&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Quit out of your master sandbox.&lt;/p&gt;
&lt;p&gt;Now we are ready to move on to the pt-table-checksum tool.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pt-table-checksum --user=sbtest --socket=/tmp/mysql_sandbox21324.sock --port=21234 --ask-pass --no-check-binlog-format&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2021/07/lbis-15.png" alt="lbis-15" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Notice we had errors: (I cropped out the rest of the output since it does not show a good run of pt-table-checksum.)
pt-table-checksum could not find the slaves. Lets run the command a second time, but this time lets tell it the the –recursion-method:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pt-table-checksum --user=sbtest --socket=/tmp/mysql_sandbox21324.sock --port=21234 --ask-pass --no-check-binlog-format --recursion-method=dsn=D=percona,t=dsns&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Success!!!&lt;/strong&gt; This time pt-table-checksum was able to find the replicas.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2021/07/lbis-16.png" alt="lbis-16" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note: there a couple mysql tables that are different between the master and replicas. This is normal.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="now-lets-remove-data-from-both-replicas"&gt;Now lets remove data from both replicas.&lt;/h2&gt;
&lt;p&gt;Connect to the 1st replica:
&lt;code&gt;mysql --socket=/tmp/mysql_sandbox21325.sock --port=21325 -u sbtest -p&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Change into the synctest database. Do a select on the synctest.names table and you should see 12 rows of data. Remove one row of data.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-3" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-3"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;delete from names where id = 7;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;quit out of slave1.&lt;/p&gt;
&lt;p&gt;Connect to the 2nd replica.
&lt;code&gt;mysql --socket=/tmp/mysql_sandbox21326.sock --port=21326 -u sbtest -p&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Change into the synctest database. Do a select on the names table and you should see 12 rows of data. Remove one row of data.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-4" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-4"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;delete from names where id = 8;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;quit out of slave2.&lt;/p&gt;
&lt;p&gt;Now we know that our cluster is out of sync, but let’s use the tool to verify. This time on checksum we will ignore mysql and sys databases.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pt-table-checksum --user=sbtest --socket=/tmp/mysql_sandbox21324.sock --port=21234 --ask-pass --no-check-binlog-format —recursion-method=dsn=D=percona,t=dsns -- ignore-databases=mysql,sys&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2021/07/lbis-10.png" alt="lbis-10" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note: that pt-table-checksum is shows a DIFFS of 1 and DIFF_ROWS of 1. This reflects that we have 1 row of data missing from one our both of the slaves.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Go back to slave2 and remove another row of data. Run Checksum again.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-5" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-5"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;delete from names where id = 9;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2021/07/lbis-11.png" alt="lbis-11" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;This time we are seeing DIFF_ROWS of 2. This would now reflect that we have 2 rows missing on at least of one the slaves. Let’s fix this mess we created. Before we do that let’s look at the data on both slaves. As we can see they are not in-sync with the master.&lt;/p&gt;
&lt;center&gt; &lt;b&gt;Slave1&lt;/b&gt; &lt;/center&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2021/07/lbis-13.png" alt="lbis-13" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;center&gt; &lt;b&gt;Slave2&lt;/b&gt; &lt;/center&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2021/07/lbis-12.png" alt="lbis-12" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="now-lets-sync-the-slaves-to-the-master"&gt;Now let’s sync the slaves to the master.&lt;/h2&gt;
&lt;p&gt;Replication Safety is very important. Please take a moment to read the replication safety section of the pt-table-sync tool.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pt-table-sync --execute h=percona-lab,P=21324,u=sbtest,p=sbtest! h=percona-lab,P=21325,u=sbtest,p=sbtest! h=percona-lab,P=21326,u=sbtest,p=sbtest! --no-check-slave --ignore-databases=mysql,sys&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;This will run in a couple seconds. When done lets checksum the cluster again.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Your cluster is now repaired.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2021/07/lbis-14.png" alt="lbis-14" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;This is just an example of what the two tools can do, they may not meet your every need.&lt;/p&gt;
&lt;p&gt;If you look to use this to repair a production databases, &lt;strong&gt;please make sure have have good backups on hand to fall back on&lt;/strong&gt; if needed.&lt;/p&gt;
&lt;h2 id="whats-next"&gt;Whats next?&lt;/h2&gt;
&lt;p&gt;I really only scratched the surface of these tools, dbdeployer, percona-toolkit.&lt;/p&gt;
&lt;p&gt;For more information on both tools please check out the the links below:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://www.dbdeployer.com/" target="_blank" rel="noopener noreferrer"&gt;dbdeployer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.percona.com/software/database-tools/percona-toolkit" target="_blank" rel="noopener noreferrer"&gt;Percona-Toolkit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.percona.com/doc/percona-toolkit/LATEST/pt-table-checksum.html" target="_blank" rel="noopener noreferrer"&gt;pt-table-checksum&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.percona.com/doc/percona-toolkit/LATEST/pt-table-sync.html" target="_blank" rel="noopener noreferrer"&gt;pt-table-sync&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;</content:encoded>
      <author>Wayne Leutwyler</author>
      <category>Toolkit</category>
      <category>MySQL</category>
      <media:thumbnail url="https://percona.community/blog/2021/07/lbis-1_hu_e04ff82b3f8b1772.jpg"/>
      <media:content url="https://percona.community/blog/2021/07/lbis-1_hu_1c6e417900bfd5fb.jpg" medium="image"/>
    </item>
    <item>
      <title>Exporters Roadmap</title>
      <link>https://percona.community/blog/2021/06/11/exporters-roadmap/</link>
      <guid>https://percona.community/blog/2021/06/11/exporters-roadmap/</guid>
      <pubDate>Fri, 11 Jun 2021 00:00:00 UTC</pubDate>
      <description>Exporters Roadmap Goals Prometheus exports as a part of PMM are a big and valuable component.</description>
      <content:encoded>&lt;h2 id="exporters-roadmap"&gt;Exporters Roadmap&lt;/h2&gt;
&lt;h3 id="goals"&gt;Goals&lt;/h3&gt;
&lt;p&gt;Prometheus exports as a part of PMM are a big and valuable component.&lt;/p&gt;
&lt;p&gt;According to the goal to involve open source contributors to contribute to PMM and Percona to contribute to open source. As the main focus, it was decided to start from the exporter.&lt;/p&gt;
&lt;p&gt;For now PMM use the next exporters:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://github.com/percona/node_exporter" target="_blank" rel="noopener noreferrer"&gt;https://github.com/percona/node_exporter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/percona/mysqld_exporter" target="_blank" rel="noopener noreferrer"&gt;https://github.com/percona/mysqld_exporter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/percona/mongodb_exporter" target="_blank" rel="noopener noreferrer"&gt;https://github.com/percona/mongodb_exporter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/percona/postgres_exporter" target="_blank" rel="noopener noreferrer"&gt;https://github.com/percona/postgres_exporter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Percona-Lab/clickhouse_exporter" target="_blank" rel="noopener noreferrer"&gt;https://github.com/Percona-Lab/clickhouse_exporter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/percona/proxysql_exporter" target="_blank" rel="noopener noreferrer"&gt;https://github.com/percona/proxysql_exporter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/percona/rds_exporter" target="_blank" rel="noopener noreferrer"&gt;https://github.com/percona/rds_exporter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/percona/azure_metrics_exporter" target="_blank" rel="noopener noreferrer"&gt;https://github.com/percona/azure_metrics_exporter&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="groups"&gt;Groups&lt;/h3&gt;
&lt;p&gt;We can split them into three groups.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The first group&lt;/strong&gt; is exporters that are created by Percona or Percona contribution in its fork is so big - that it cannot be pushed back upstream.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://github.com/percona/mongodb_exporter" target="_blank" rel="noopener noreferrer"&gt;https://github.com/percona/mongodb_exporter&lt;/a&gt; - built by Percona from scratch.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/percona/proxysql_exporter" target="_blank" rel="noopener noreferrer"&gt;https://github.com/percona/proxysql_exporter&lt;/a&gt; - built by Percona from scratch.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/percona/rds_exporter" target="_blank" rel="noopener noreferrer"&gt;https://github.com/percona/rds_exporter&lt;/a&gt; - too far from upstream - Percona made a big contribution to fit it for PMM needs.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For those three exporters we are going to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;encourage contribution from the community;&lt;/li&gt;
&lt;li&gt;create an easy setup dev environment to speed up development and testing;&lt;/li&gt;
&lt;li&gt;consider user’s issues and request - and try to solve this with “community priority” level;&lt;/li&gt;
&lt;li&gt;create regular releases with needed binaries for community consumption.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;The second group&lt;/strong&gt; is exporters that are not that far away from upstream and Percona would like to contribute back as much as possible.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://github.com/percona/node_exporter" target="_blank" rel="noopener noreferrer"&gt;https://github.com/percona/node_exporter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/percona/mysqld_exporter" target="_blank" rel="noopener noreferrer"&gt;https://github.com/percona/mysqld_exporter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/percona/postgres_exporter" target="_blank" rel="noopener noreferrer"&gt;https://github.com/percona/postgres_exporter&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For this group, we will try to push all fixes made by Percona to Upstream and are going to take part in development and bug fixing as open-source contributors - trying to bring value for the community as well as for PMM.&lt;/p&gt;
&lt;p&gt;And &lt;strong&gt;the third group&lt;/strong&gt; are exporters that currently fit PMM needs and Percona did not contribute a lot in its forks.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://github.com/Percona-Lab/clickhouse_exporter" target="_blank" rel="noopener noreferrer"&gt;https://github.com/Percona-Lab/clickhouse_exporter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/percona/azure_metrics_exporter" target="_blank" rel="noopener noreferrer"&gt;https://github.com/percona/azure_metrics_exporter&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For those exporters, we are going to start using upstream and make changes if needed in other PMM components. Downstream repos would only be used as forks synced with upstream only for the PMM build support.&lt;/p&gt;
&lt;h3 id="action-plan"&gt;Action plan&lt;/h3&gt;
&lt;p&gt;Here is some short term plan of tasks to implement a part of the plan above:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Remove fork of clickhouse_exporter and remove it as component from PMM - looks like the easiest task. The new version of the ClickHouse server exposes metrics in Prometheus format, so we can collect them without any exporters. (we can use build-in metrics exporter &lt;a href="https://clickhouse.tech/docs/en/operations/server-configuration-parameters/settings/#server_configuration_parameters-prometheus" target="_blank" rel="noopener noreferrer"&gt;https://clickhouse.tech/docs/en/operations/server-configuration-parameters/settings/#server_configuration_parameters-prometheus&lt;/a&gt; starting from &lt;a href="https://clickhouse.tech/docs/en/whats-new/changelog/2020/#clickhouse-release-v20-1-2-4-2020-01-22" target="_blank" rel="noopener noreferrer"&gt;https://clickhouse.tech/docs/en/whats-new/changelog/2020/#clickhouse-release-v20-1-2-4-2020-01-22&lt;/a&gt;)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Discard our changes in azure_metrics_exporter and keep the fork in sync with upstream. We use common formulas in Grafana to visualize metrics from different exporters. Current azure_exporter has slightly different a few metric names - we can achieve the same by renaming using Prometheus recording rules &lt;a href="https://prometheus.io/docs/prometheus/latest/configuration/recording_rules" target="_blank" rel="noopener noreferrer"&gt;https://prometheus.io/docs/prometheus/latest/configuration/recording_rules&lt;/a&gt; . This discard needs to keep the fork up to date with upstream.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Node exporter looks like the best candidate to contribute back to the community &lt;a href="https://github.com/prometheus/node_exporter/compare/master...percona:main" target="_blank" rel="noopener noreferrer"&gt;https://github.com/prometheus/node_exporter/compare/master...percona:main&lt;/a&gt;. This exporter’s source code did not go far away - so we can leverage what we can accept from upstream and create minimal PR to upstream with features we only required.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;MySQL exporter can be the heaviest task to push back to upstream - we did a lot of change. So the tactic could be split difference into logical parts and try to push back it step by step &lt;a href="https://github.com/percona/mysqld_exporter/pull/61/files" target="_blank" rel="noopener noreferrer"&gt;https://github.com/percona/mysqld_exporter/pull/61/files&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;PostgreSQL exporter is also quite far from upstream plus it requires a few fundamental improvements like a handle DB connection, etc. For this exporter, we also need split difference on logical parts and contribute it with small PR back to upstream &lt;a href="https://github.com/percona/postgres_exporter/pull/28/files" target="_blank" rel="noopener noreferrer"&gt;https://github.com/percona/postgres_exporter/pull/28/files&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Maintain mongodb_exporter, add needed packaging, docker container and update helm chart.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Proxy exporter looks good for now, but we need to take into consideration that ProxySQL start exports metrics natively &lt;a href="https://proxysql.com/documentation/prometheus-exporter" target="_blank" rel="noopener noreferrer"&gt;https://proxysql.com/documentation/prometheus-exporter&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;And RDS exporter goes to be separated from upstream - now it contains a big part of code that serve mostly PMM needs.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For all the above we would try to use the GitHub Project board &lt;a href="https://github.com/orgs/percona/projects/2" target="_blank" rel="noopener noreferrer"&gt;https://github.com/orgs/percona/projects/2&lt;/a&gt; to track progress in different repositories for all mentioned tasks above.&lt;/p&gt;
&lt;p&gt;We would sync with the community during Engineering Monthly Meeting &lt;a href="https://percona.community/contribute/engineeringmeetings/" target="_blank" rel="noopener noreferrer"&gt;https://percona.community/contribute/engineeringmeetings/&lt;/a&gt; as well as by participating in Upstream meetings.&lt;/p&gt;
&lt;p&gt;Come and join us on our journey in OpenSource! Contact us at &lt;a href="mailto:community-team@percona.com"&gt;community-team@percona.com&lt;/a&gt; .&lt;/p&gt;</content:encoded>
      <author>Andrii Skomorokhov</author>
      <category>Exporter</category>
      <category>Prometheus</category>
      <category>PMM</category>
      <category>Monitoring</category>
      <media:thumbnail url="https://percona.community/blog/2021/06/pmm-exporters_hu_d93268051f105860.jpg"/>
      <media:content url="https://percona.community/blog/2021/06/pmm-exporters_hu_5dd9a213d87f4edc.jpg" medium="image"/>
    </item>
    <item>
      <title>Mayastor: Lightning Fast Storage for Kubernetes</title>
      <link>https://percona.community/blog/2020/10/23/mayastor-lightning-fast-storage-for-kubernetes/</link>
      <guid>https://percona.community/blog/2020/10/23/mayastor-lightning-fast-storage-for-kubernetes/</guid>
      <pubDate>Fri, 23 Oct 2020 14:03:08 UTC</pubDate>
      <description>At MayaData we like new tech. Tech that makes our databases perform better. Tech like lockless ring buffers, NVMe-oF, and Kubernetes. In this blog post we’re going to see those technologies at work to give us awesome block storage performance with flexibility and simple operations.</description>
      <content:encoded>&lt;p&gt;At MayaData we like new tech. Tech that makes our databases perform better. Tech like &lt;a href="https://www.kernel.org/doc/Documentation/trace/ring-buffer-design.txt" target="_blank" rel="noopener noreferrer"&gt;lockless ring buffers&lt;/a&gt;, &lt;a href="https://en.wikipedia.org/wiki/NVM_Express" target="_blank" rel="noopener noreferrer"&gt;NVMe-oF&lt;/a&gt;, and &lt;a href="https://kubernetes.io/" target="_blank" rel="noopener noreferrer"&gt;Kubernetes&lt;/a&gt;. In this blog post we’re going to see those technologies at work to give us awesome block storage performance with flexibility and simple operations.&lt;/p&gt;
&lt;h2 id="mayastor--spdk--nvme--fast-databases"&gt;Mayastor + SPDK + NVMe = fast databases&lt;/h2&gt;
&lt;p&gt;Mayastor is new tech, it’s fast, and it’s based on &lt;a href="https://spdk.io/" target="_blank" rel="noopener noreferrer"&gt;SPDK&lt;/a&gt;. Why is SPDK exciting? It’s a new generation in storage software, designed for super high speed low latency &lt;a href="https://en.wikipedia.org/wiki/NVM_Express" target="_blank" rel="noopener noreferrer"&gt;NVMe&lt;/a&gt; devices. I’ll save you the scrolling and just tell you I believe Mayastor was able to max out the practical throughput of the nvme device I used for my benchmark, allowing for multiple high performance (20kqps+) database instances on a single node. Perfect for a database farm in Kubernetes&lt;/p&gt;
&lt;h2 id="why-test-with-a-relational-db"&gt;Why Test With a Relational DB?&lt;/h2&gt;
&lt;p&gt;Open source relational databases are a staple component for app developers. People use them all the time for all kinds of software projects. It’s easy to build relationships between different groups of data, the syntax is well known, and they’ve been around for as long as modern computing.  When a dev wants a relational database to hack on, odds are good that it’s going to be &lt;a href="https://www.postgresql.org/" target="_blank" rel="noopener noreferrer"&gt;Postgres&lt;/a&gt; or &lt;a href="https://www.mysql.com/" target="_blank" rel="noopener noreferrer"&gt;MySQL&lt;/a&gt;. They’re Free. They’re open source. They’ve both been quite stable for a long time, and they both run in Kubernetes just great. The good folks at Percona make containerized, production ready versions of these databases, and we’re going to use their &lt;a href="https://www.percona.com/software/mysql-database" target="_blank" rel="noopener noreferrer"&gt;Percona Distribution for MySQL&lt;/a&gt; for the following tests.&lt;/p&gt;
&lt;h2 id="kubernetes-and-the-learning-curve"&gt;Kubernetes and the Learning Curve&lt;/h2&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2020/10/image1.png" alt="Mayastor 1" /&gt;&lt;/figure&gt;
So what is the difficulty with running relational databases, or databases in general, inside of Kubernetes?  Given all the features of Kubernetes for managing highly available application deployments: Automation with control, Common declarative configuration interface, and build-in observability, one would think Databases are the application to deploy to it. The main difficulty is storage. Until now.&lt;/p&gt;
&lt;h2 id="dbs-are-often-io-bound"&gt;DBs are Often IO Bound&lt;/h2&gt;
&lt;p&gt;The trick is, databases are notoriously disk intensive and latency sensitive. The reason this has an impact on your Kubernetes deployments is that storage support in stock settings and untuned K8s clusters is rudimentary at best. That’s created a number of projects that are out to provide for storage in K8s projects, including, of course, the popular OpenEBS project.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;yaml&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nn"&gt;---&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;apiVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;apps/v1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Deployment&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;percona-mysql&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;app&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;percona-mysql&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;replicas&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;matchLabels&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;app&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;percona-mysql&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;percona-mysql&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;app&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;percona-mysql&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;nodeSelector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;app&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;db&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;securityContext&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;fsGroup&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1001&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;containers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;resources&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;limits&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;cpu&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"20"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;8Gi&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;percona-mysql&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;percona&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s2"&gt;"--ignore-db-dir"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s2"&gt;"lost+found"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;MYSQL_ROOT_PASSWORD&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;foobarbaz&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;containerPort&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;3306&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;percona-mysql&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;volumeMounts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;mountPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;/var/lib/mysql&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;percona-mysql&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;percona-mysql&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;persistentVolumeClaim&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;claimName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;vol2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;In this post I’m going to investigate the newest of the storage engines that comprise the data plane for OpenEBS. As a challenge, I’d like to be able to achieve 20,000 queries per second out of a MySQL database using this storage engine for block storage underneath.&lt;/p&gt;
&lt;p&gt;Now, getting to 20kqps could be easy with the right dataset. But I want to achieve this with data that’s significantly larger than available RAM. In that scenario, 20kqps is pretty fast (as you can see below by the disk traffic and cpu load it generates).&lt;/p&gt;
&lt;p&gt;There are a number of great options available for deploying MySQL in Kubernetes, but for this test we really just want a good, high performance database to start with. I won’t really need fancy DBaaS functionality, an operator to take care of backups, or anything of the sort. We’ll start from scratch with Percona’s MySQL container, and build a little deployment manifest for it. Now, maybe you’re thinking: “don’t you mean a stateful set?” But no, we’re going to use a deployment for this. Simple and easy to configure alongside of Container Attached Storage.&lt;/p&gt;
&lt;p&gt;The deployment pictured references an external volume, vol2. Now we could create a PV for this on the local system, but then if our MySQL instance gets scheduled on a different machine, the storage won’t be present.  &lt;/p&gt;
&lt;h2 id="enter-mayastor"&gt;Enter Mayastor&lt;/h2&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;span class="code-block__lang"&gt;yaml&lt;/span&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-1"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nn"&gt;---&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;PersistentVolumeClaim&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;apiVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;v1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;vol2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;storageClassName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;mayastor-nvmf-fast&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;accessModes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;ReadWriteOnce&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;resources&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;20Gi&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Mayastor is the latest storage engine for OpenEBS and MayaData’s Kubera offering. Mayastor represents the state-of-the-art in feature-rich storage for Linux systems. Mayastor creates virtual volumes that are backed by fast NVMe disks, and exports those volumes over the super-fast NVMf protocol. It’s a fresh implementation of the Container Attached Storage model. By &lt;a href="https://www.cncf.io/blog/2018/04/19/container-attached-storage-a-primer/" target="_blank" rel="noopener noreferrer"&gt;CAS&lt;/a&gt;, I mean it’s purpose built for the multi-tenant distributed world of the cloud. CAS means each workload gets its own storage system, with knobs for tuning and everything. The beauty of the CAS architecture is that it decouples your apps from their storage. You can attach to a disk locally or via NVMf or iSCSI.&lt;/p&gt;
&lt;p&gt;Mayastor is CAS and it is purpose built to support cloud native workloads at speed with very little overhead. At MayaData we wrote it in Rust; we worked with Intel to implement new breakthrough technology called SPDK; made it easy to use with Kubernetes and possible to use with anything; and open-sourced it because, well, it improves the state of the art of storage in k8s and community always wins (eventually).&lt;/p&gt;
&lt;p&gt;If you’d like to set up Mayastor on a new or existing cluster, have a look at: &lt;a href="https://mayastor.gitbook.io/introduction/" target="_blank" rel="noopener noreferrer"&gt;https://mayastor.gitbook.io/introduction/&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="the-speed-hypothesis"&gt;The Speed Hypothesis&lt;/h2&gt;
&lt;p&gt;The first thing I want to do is get an idea of how many queries per second (QPS) at which the DB maxes out. My suspicion at the outset is that the limiter for QPS is typically storage latency. We can deploy our Mayastor pool and storage class manifests in a small test cluster just to make sure they’re working as expected, and then tune our test to drive the DB as hard as we can. Performance characteristics of databases are very much tied to the specifics of the workload and table structure. So the first challenge here is to sort out what kind of workload is going to exercise the disk effectively.&lt;/p&gt;
&lt;p&gt;Sysbench is a great tool for exercising various aspects of Linux systems, and it includes some database tests we can use to get some baselines. &lt;a href="https://github.com/akopytov/sysbench" target="_blank" rel="noopener noreferrer"&gt;https://github.com/akopytov/sysbench&lt;/a&gt; is where you can find it. We can put it in a container and point that mysql OLTP test right at our database service.&lt;/p&gt;
&lt;p&gt;After a little bit of experimentation with sysbench options to set different values for the table size, number of tables, etc., I arrived at very stable results on a small cluster in AWS using m5ad.xlarge nodes. I’ve settled on 10 threads and 10 tables, with 10M rows in each table. With no additional tuning on MySQL, sysbench settles into about 4300 queries per second with an average latency at 46ms. Pretty good for a small cloud setup.&lt;/p&gt;
&lt;p&gt;With that as a baseline, let’s see how much we can get out of it on a larger system. Intel makes high core-count cpus and very fast Optane NVMe devices, and they’ve generously allowed us to use their benchmarking labs for a little while for some database testing. Without going into too much hardware geekery, we have three 96 core boxes running at 2.2Ghz with more RAM than I need and 100Gb networking to string them together. Each box has a small Optane NVMe device, and this single little drive is capable of at least 400k iops and 1.7GB/s through an ext4 filesystem. That’s fast. The published specs for this device are a little bit higher (about 500k iops and 2GB/s) but we’ll take this to be peak perf for our purposes.&lt;/p&gt;
&lt;h2 id="results-of-the-first-test"&gt;Results of the First Test&lt;/h2&gt;
&lt;p&gt;For the first test, just to characterize the setup, I threw 80 or so cores at the database, and ran sysbench against it with a whole lot of threads. Like 300.&lt;/p&gt;
&lt;p&gt;I started with a smaller table size just to save a little time on the load phase.  It took a few iterations to get the test to run - adjustments to &lt;code&gt;max_connections&lt;/code&gt;. The smaller table size means it might fit into memory, but it’ll test our test framework quickly.  Sure enough, running our OLTP test gets us close to 100k queries per second. But, there’s no real disk activity. We need more data in order to test the underlying disks.&lt;/p&gt;
&lt;p&gt;I cranked up the table size to 20,000,000 rows per table, tuned Mayastor to use three of the cores on each box, and started tuning the test to get max queries per second out of it. Three tables seem to be enough to overflow the 8G of RAM we have allocated to the container. Now when I check the disk stats on the node, there’s plenty of storage traffic. Still less than a gigabyte per second though. The system settles down into a comfortably speedy 30kqps or thereabouts, with disk throughput right around 700MB/s and a latency right around 50ms per query. Curiously the database is using about 8 cores. Clearly we don’t need to allocate all 80.&lt;/p&gt;
&lt;p&gt;We’ve seen more than 700MB/s out of the storage already from our synthetic tests. That’s pretty far off of the peak measured perf of 1.7GB/s.&lt;/p&gt;
&lt;h2 id="i-wonder-if-we-can-get-another-mysql-on-here"&gt;I wonder if we can get another MySQL on here…&lt;/h2&gt;
&lt;p&gt;Sure enough, this system is fast enough to host two high performance relational database instances on the same nvme drive, with cpu to spare.  If only I had another one of those NVMe drives in this box….&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2020/10/image3_hu_87e0210307088601.png 480w, https://percona.community/blog/2020/10/image3_hu_8de5514575f4b675.png 768w, https://percona.community/blog/2020/10/image3_hu_4fca178fb10e261.png 1400w"
src="https://percona.community/blog/2020/10/image3.png" alt="A screenshot showing Mayastor in action" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;That’s about 1.1GB/s, with 52k IOPs. Not bad. We might even be able to fit a third in if we’re willing to sacrifice a little bit of speed across all the instances.&lt;/p&gt;
&lt;p&gt;There’s more work to be done to characterize database workloads like this one. There’s also an opportunity to investigate why the database scales up to 20-30k IOPs but leaves some storage and system resources available.&lt;/p&gt;
&lt;p&gt;Perhaps most importantly - Maystor provides a complete abstraction for kubernetes volumes, and allows for replicating to multiple nodes, snapshotting volumes, encrypting traffic, and generally everything you’ve come to expect from enterprise storage.  Mayastor is showing the promise here of LocalPV like performance - at least maxing out the capabilities of our DB as configured - while also providing the ease of use and ability to add resilience.&lt;/p&gt;
&lt;p&gt;Lastly, if you are interested in Percona and OpenEBS, there are a lot of blogs from the OpenEBS community and a recent one by the CTO of Percona on the use of OpenEBS LocalPV as their preferred LocalPV solution here: &lt;a href="https://www.percona.com/blog/2020/10/01/deploying-percona-kubernetes-operators-with-openebs-local-storage/" target="_blank" rel="noopener noreferrer"&gt;https://www.percona.com/blog/2020/10/01/deploying-percona-kubernetes-operators-with-openebs-local-storage/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The &lt;a href="https://forums.percona.com/categories/percona-distribution-for-mysql" target="_blank" rel="noopener noreferrer"&gt;Percona Community Forum&lt;/a&gt;, &lt;a href="https://openebs.io/community/" target="_blank" rel="noopener noreferrer"&gt;OpenEBS&lt;/a&gt;, and &lt;a href="https://dok.community/" target="_blank" rel="noopener noreferrer"&gt;Data on Kubernetes&lt;/a&gt;communities are increasingly overlapping and I hope and expect this write up will result in yet more collaboration. Come check out Check out &lt;a href="https://mayastor.gitbook.io/introduction/" target="_blank" rel="noopener noreferrer"&gt;Mayastor&lt;/a&gt; on your own and let us know how Mayastor works for your use case in the comments below!&lt;/p&gt;
&lt;p&gt;Brian Matheson has spent twenty years doing things like supporting developers, tuning networks, and writing tools. A serial entrepreneur with an intense customer focus, Brian has helped a number of startups in a technical capacity. You can read more of Brian’s blog posts at &lt;a href="https://blog.mayadata.io/author/brian-matheson" target="_blank" rel="noopener noreferrer"&gt;https://blog.mayadata.io/author/brian-matheson&lt;/a&gt;.&lt;/p&gt;</content:encoded>
      <author>Brian Matheson</author>
      <category>Kubernetes</category>
      <category>Kubernetes</category>
      <category>MayaData</category>
      <category>Mayastor</category>
      <category>MySQL</category>
      <category>MySQL</category>
      <category>mysql-and-variants</category>
      <category>Open Source Databases</category>
      <category>Tools</category>
      <media:thumbnail url="https://percona.community/blog/2020/10/image1_hu_73722df26ba683eb.jpg"/>
      <media:content url="https://percona.community/blog/2020/10/image1_hu_ef94108f054a471a.jpg" medium="image"/>
    </item>
    <item>
      <title>MySQL 8.0 Document Store, Discovery of a New World – Percona Live ONLINE Talk Preview</title>
      <link>https://percona.community/blog/2020/10/19/mysql-8-0-document-store-discovery-of-a-new-world-percona-live-online-talk-preview/</link>
      <guid>https://percona.community/blog/2020/10/19/mysql-8-0-document-store-discovery-of-a-new-world-percona-live-online-talk-preview/</guid>
      <pubDate>Mon, 19 Oct 2020 14:01:12 UTC</pubDate>
      <description>Percona Live Online Agenda Slot: Wed 21 Oct • New York 5:00 a.m. • London 10:00 a.m. • New Delhi 2:30 p.m. • Singapore 5:00 p.m.</description>
      <content:encoded>&lt;p&gt;&lt;em&gt;&lt;a href="https://www.percona.com/live/agenda" target="_blank" rel="noopener noreferrer"&gt;Percona Live Online Agenda&lt;/a&gt; Slot: Wed 21 Oct • New York 5:00 a.m. • London 10:00 a.m. • New Delhi 2:30 p.m. • Singapore 5:00 p.m.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id="abstract"&gt;Abstract&lt;/h3&gt;
&lt;p&gt;MySQL Document Store enables us to work with SQL relational tables and schema-less JSON collections. So instead of having a mixed bag of databases, you can just rely on MySQL, where the JSON documents can be stored in collections and managed with CRUD operations. All you need to do is install the X plugin. In this session, you will learn what a document store is, how to install and use it, and all the reasons for considering it. We will also see several specific features helping developers and illustrate how the usual MySQL DBA can manage this new world.&lt;/p&gt;
&lt;h3 id="why-is-your-talk-exciting"&gt;Why is your talk exciting?&lt;/h3&gt;
&lt;p&gt;This talk is very exciting because it’s focus on new capabilities that is available only in MySQL and that many people are not aware of it. Every time I talk about that topic, the audience is really surprised and enthusiast about MySQL Document Store. It’s not common to have a JSON document store will all the capabilities of MySQL, fully transactional but at the same time using CRUD operations where you can mix your relational data and your schemaless document in the same query.&lt;/p&gt;
&lt;h3 id="who-would-benefit-the-most-from-your-talk"&gt;Who would benefit the most from your talk?&lt;/h3&gt;
&lt;p&gt;This particular talk is more focused on developers but I tried to also include content for DBAs. However it’s not a talk oriented on operators like I usually do during Percona Live shows.&lt;/p&gt;
&lt;h3 id="what-other-talks-are-you-most-looking-forward-to"&gt;What other talks are you most looking forward to?&lt;/h3&gt;
&lt;p&gt;I’m looking forward to hear again from René and ProxySQL, a project that I really appreciate. And also I’m curious to see which recommendation Øystein will provide for MySQL analytics queries.&lt;/p&gt;
&lt;h3 id="is-there-any-other-question-you-would-like-to-answer"&gt;Is there any other question you would like to answer?&lt;/h3&gt;
&lt;p&gt;I will also have the honor to present the State of the Dolphin during the show, don’t miss it if you want to learn about MySQL 8.0 and our Community. Of course I won’t deliver a full list of features as it would take almost the full conference time ;)&lt;/p&gt;</content:encoded>
      <author>Frédéric Descamps</author>
      <category>frederic.descamps</category>
      <category>MySQL</category>
      <category>PLO-2020-10</category>
      <media:thumbnail url="https://percona.community/blog/2020/10/DB-PLO-Blog-Image-2020-10-05_hu_ee2e8da0448380e1.jpg"/>
      <media:content url="https://percona.community/blog/2020/10/DB-PLO-Blog-Image-2020-10-05_hu_e5cd6fdb7763e3c5.jpg" medium="image"/>
    </item>
    <item>
      <title>The State of ProxySQL, 2020 Edition – Percona Live ONLINE Talk Preview</title>
      <link>https://percona.community/blog/2020/10/16/the-state-of-proxysql-2020-edition-percona-live-online-talk-preview/</link>
      <guid>https://percona.community/blog/2020/10/16/the-state-of-proxysql-2020-edition-percona-live-online-talk-preview/</guid>
      <pubDate>Fri, 16 Oct 2020 20:08:01 UTC</pubDate>
      <description>Percona Live Online Agenda Slot: Wed 21 Oct • New York 7:30 a.m. • London 12:30 p.m. • New Delhi 5:00 p.m. • Singapore 7:30 p.m.</description>
      <content:encoded>&lt;p&gt;&lt;em&gt;&lt;a href="https://www.percona.com/live/agenda" target="_blank" rel="noopener noreferrer"&gt;Percona Live Online Agenda&lt;/a&gt; Slot: Wed 21 Oct • New York 7:30 a.m. • London 12:30 p.m. • New Delhi 5:00 p.m. • Singapore 7:30 p.m.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id="abstract"&gt;Abstract&lt;/h3&gt;
&lt;p&gt;ProxySQL is a high performance, high available, protocol aware proxy for MySQL. 2.0 has been GA for some time now, and there have been a lot of changes that come in point releases as well, such that you can benefit from them. Listen to René, the founder of ProxySQL, take you through some of the new features in 2.0, and how you can effectively utilize them. Some topics that are covered include: - LDAP authentication - SSL for client connections - AWS Aurora usage - Native clustering support for Percona XtraDB Cluster (PXC) / Galera Cluster / group replication - Kubernetes deployments This is the talk to take you from intermediate ProxySQL user to expert in the 2.0 feature set. There will also be talk about the roadmap for what is coming next.&lt;/p&gt;
&lt;h3 id="why-is-your-talk-exciting"&gt;Why is your talk exciting?&lt;/h3&gt;
&lt;p&gt;This talk is exciting because it will bring to the community all the latest features in ProxySQL, and short term plans for even more exciting features.&lt;/p&gt;
&lt;h3 id="who-would-benefit-the-most-from-your-talk"&gt;Who would benefit the most from your talk?&lt;/h3&gt;
&lt;p&gt;Devs, DBAs, sysadmins: all users interested in optimizing and manging traffic against MySQL backends can benefit from this talk, no matter their level of experience.&lt;/p&gt;
&lt;h3 id="what-other-presentations-are-you-most-looking-forward-to"&gt;What other presentations are you most looking forward to?&lt;/h3&gt;
&lt;p&gt;All the talks on the Percona Live agenda are exciting, but the two talks that rank very high in my list are “&lt;a href="https://sched.co/eouq" target="_blank" rel="noopener noreferrer"&gt;Why Public Database as a Service is Prime for Open Source Disruption&lt;/a&gt;” by Peter Zaitsev, and “&lt;a href="https://sched.co/ePpr" target="_blank" rel="noopener noreferrer"&gt;Sharding: DIY or Out of the Box Solution?&lt;/a&gt;” by Art van Scheppingen.&lt;/p&gt;</content:encoded>
      <author>René Cannaò</author>
      <category>rene.cannao</category>
      <category>MySQL</category>
      <category>PLO-2020-10</category>
      <category>Tools</category>
      <media:thumbnail url="https://percona.community/blog/2020/10/DB-PLO-Blog-Image-2020-10-05_hu_ee2e8da0448380e1.jpg"/>
      <media:content url="https://percona.community/blog/2020/10/DB-PLO-Blog-Image-2020-10-05_hu_e5cd6fdb7763e3c5.jpg" medium="image"/>
    </item>
    <item>
      <title>Engineering Data Reliably Using SLO Theory – Percona Live ONLINE Talk Preview</title>
      <link>https://percona.community/blog/2020/10/15/engineering-data-reliably-using-slo-theory-percona-live-online-talk-preview/</link>
      <guid>https://percona.community/blog/2020/10/15/engineering-data-reliably-using-slo-theory-percona-live-online-talk-preview/</guid>
      <pubDate>Thu, 15 Oct 2020 02:43:47 UTC</pubDate>
      <description>Percona Live Online Agenda Slot: Tue 20 Oct • New York 12:30 p.m. • London 5:30 p.m. • New Delhi 10:00 p.m. • Singapore 12:30 a.m. (next day)</description>
      <content:encoded>&lt;p&gt;&lt;em&gt;&lt;a href="https://www.percona.com/live/agenda" target="_blank" rel="noopener noreferrer"&gt;Percona Live Online Agenda&lt;/a&gt; Slot: Tue 20 Oct • New York 12:30 p.m. • London 5:30 p.m. • New Delhi 10:00 p.m. • Singapore 12:30 a.m. (next day)&lt;/em&gt;&lt;/p&gt;
&lt;h3 id="abstract"&gt;Abstract&lt;/h3&gt;
&lt;p&gt;Not so long ago, operations specialists worked much like today’s data engineers do: with specialized skills, they were the people who kept sites running, who responded to emergencies, and who—unfortunately—spent much of their time dealing with incidents and other “fires.” When the DevOps revolution came, this began to change. Better tools, better practices, and better culture shaped how Ops folks worked. A subset of that DevOps culture soon emerged: Site Reliability Engineers. These were people whose focus was not just on the day-to-day deployment of applications, but running platforms, products, and services with very high performance, very large scale, and with very high demand for reliability. Data Engineering was left out of this revolution.&lt;/p&gt;
&lt;p&gt;But it is not too late! By taking concepts from SRE culture, in particular, the theory of Service Level Objectives, we look at how teams operating and developing data platforms and data products can be built more reliably through the use of quantitative measures and product thinking. This talk will discuss concrete examples of the benefits of this approach for data teams and how organizations can benefit from this mindset.&lt;/p&gt;
&lt;h3 id="why-is-your-talk-exciting"&gt;Why is your talk exciting?&lt;/h3&gt;
&lt;p&gt;I see a lot of the same pains over and over in the data engineering world: data engineers spending too much time firefighting or dealing with ad hoc requests to innovate, data scientists pained by long lead times for pipeline engineering, and poor data quality eroding trust and leading organizations to make “gut” decisions instead of data-driven ones. This doesn’t have to be our world. The reality that many data engineers face today is similar to the one ops folks faced years ago, before Site Reliability Engineering (SRE) practices began to solidify. However, most of the learnings in the SRE space, particularly Service Level Objective (SLO) theory, don’t translate directly to the data space unless we adapt them to our unique reality. But if we can build solid, data-driven best practices, we can achieve so much—less firefighting, more creation; less guesswork, more trust.&lt;/p&gt;
&lt;h3 id="who-would-benefit-the-most-from-your-talk"&gt;Who would benefit the most from your talk?&lt;/h3&gt;
&lt;p&gt;Certainly, data engineers will benefit. But also managers, executives, and product owners will all benefit from learning how we can deliberately craft data engineering practices to optimize for reliability. Data should be a business driver, but too often I see it as a cost center. We need to change that calculus.&lt;/p&gt;
&lt;h3 id="what-other-talks-are-you-most-looking-forward-to"&gt;What other talks are you most looking forward to?&lt;/h3&gt;
&lt;p&gt;I’m excited to see &lt;a href="https://sched.co/eouw" target="_blank" rel="noopener noreferrer"&gt;Karen Ambrose’s talk&lt;/a&gt;. I think that building technology to address rapidly-evolving crises is an enormous challenge, and frankly, I think that maybe a lot of organizations have been too complacent and risk averse to manage rapid pivots. I’m really curious to hear the story about how people came together to change the status quo in an effort to literally save the world.&lt;/p&gt;
&lt;h3 id="is-there-any-other-question-you-would-like-to-answer"&gt;Is there any other question you would like to answer?&lt;/h3&gt;
&lt;p&gt;There’s a Millennial Prize Problem or two still unsolved, and I’d love to answer one of those.&lt;/p&gt;</content:encoded>
      <author>Emily Gorcenski</author>
      <category>emily.gorcenski</category>
      <category>DevOps</category>
      <category>PLO-2020-10</category>
      <media:thumbnail url="https://percona.community/blog/2020/10/DB-PLO-Blog-Image-2020-10-05_hu_ee2e8da0448380e1.jpg"/>
      <media:content url="https://percona.community/blog/2020/10/DB-PLO-Blog-Image-2020-10-05_hu_e5cd6fdb7763e3c5.jpg" medium="image"/>
    </item>
    <item>
      <title>DBdeployer, the Community Edition – Percona Live ONLINE Talk Preview</title>
      <link>https://percona.community/blog/2020/10/14/dbdeployer-the-community-edition-percona-live-online-talk-preview/</link>
      <guid>https://percona.community/blog/2020/10/14/dbdeployer-the-community-edition-percona-live-online-talk-preview/</guid>
      <pubDate>Wed, 14 Oct 2020 18:44:09 UTC</pubDate>
      <description>Percona Live Online Agenda Slot: Wed 21 Oct • New York 3:30 a.m. • London 8:30 a.m. • New Delhi 1:00 p.m. • Singapore 3:30 p.m.</description>
      <content:encoded>&lt;p&gt;&lt;em&gt;&lt;a href="https://www.percona.com/live/agenda" target="_blank" rel="noopener noreferrer"&gt;Percona Live Online Agenda&lt;/a&gt; Slot: Wed 21 Oct • New York 3:30 a.m. • London 8:30 a.m. • New Delhi 1:00 p.m. • Singapore 3:30 p.m.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id="abstract"&gt;Abstract&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://github.com/datacharmer/dbdeployer" target="_blank" rel="noopener noreferrer"&gt;DBdeployer&lt;/a&gt;, an open source tool that allows easy deployment of many MySQL/Percona servers in the same host, has passed two years of development. Its latest additions have aimed at improving ease of use for both beginners and experts. This talk will show how to start with dbdeployer with an empty box, and quickly populate it with recent and less recent server versions, all at the command line.&lt;/p&gt;
&lt;h3 id="why-is-your-talk-exciting"&gt;Why is your talk exciting?&lt;/h3&gt;
&lt;p&gt;This talk is a celebration of collaboration in the community. I will present recent features that were requested, or suggested, by the community. I will also show how those suggestions came to fruition, to encourage more of the same from attendees.&lt;/p&gt;
&lt;h3 id="who-would-benefit-the-most-from-your-talk"&gt;Who would benefit the most from your talk?&lt;/h3&gt;
&lt;p&gt;Any current or future user of dbdeployer. They will see the process of refining the usability of the tool through interaction with the community.&lt;/p&gt;
&lt;h3 id="is-there-any-other-question-you-would-like-to-answer"&gt;Is there any other question you would like to answer?&lt;/h3&gt;
&lt;p&gt;There is a recurring question that I get from people who are about to use dbdeployer but haven’t gotten to know it well: “is it cloud friendly?” It pains me to answer that it isn’t, not because of a deficiency of the tool, but because it was designed to stay out of the cloud. Using dbdeployer, the cloud is your laptop, or the tiny Linux server in your workroom. The main purpose of dbdeployer is to enable developers, support engineers, QA engineers, database administrators, to have on demand deployments of MySQL always, even when there is no connection with the cloud or when you want something faster than the cloud.&lt;/p&gt;
&lt;h3 id="what-other-talks-are-you-most-looking-forward-to"&gt;What other talks are you most looking forward to?&lt;/h3&gt;
&lt;p&gt;Most of the talks and keynote are promising. I look forward in particular to watch “&lt;a href="https://sched.co/ePp6" target="_blank" rel="noopener noreferrer"&gt;Vitess Online Schema Migration Automation&lt;/a&gt;” by Shlomi Noach and “&lt;a href="https://sched.co/ePpc" target="_blank" rel="noopener noreferrer"&gt;MySQL 8.0 Document Store - Discovery of a New World&lt;/a&gt;” by Frédéric Descamps.&lt;/p&gt;</content:encoded>
      <author>Giuseppe Maxia</author>
      <category>Events</category>
      <category>MySQL</category>
      <category>PLO-2020-10</category>
      <media:thumbnail url="https://percona.community/blog/2020/10/DB-PLO-Blog-Image-2020-10-05_hu_ee2e8da0448380e1.jpg"/>
      <media:content url="https://percona.community/blog/2020/10/DB-PLO-Blog-Image-2020-10-05_hu_e5cd6fdb7763e3c5.jpg" medium="image"/>
    </item>
    <item>
      <title>Sharding: DIY or Out of the Box Solution? – Percona Live ONLINE Talk Preview</title>
      <link>https://percona.community/blog/2020/10/13/sharding-diy-or-out-of-the-box-solution-percona-live-online-talk-preview/</link>
      <guid>https://percona.community/blog/2020/10/13/sharding-diy-or-out-of-the-box-solution-percona-live-online-talk-preview/</guid>
      <pubDate>Tue, 13 Oct 2020 03:04:37 UTC</pubDate>
      <description>Percona Live Online Agenda Slot: Wed 21 Oct • New York 7:00 a.m. • London 12:00 noon • New Delhi 4:30 p.m. • Singapore 7:00 p.m.</description>
      <content:encoded>&lt;p&gt;&lt;em&gt;&lt;a href="https://www.percona.com/live/agenda" target="_blank" rel="noopener noreferrer"&gt;Percona Live Online Agenda&lt;/a&gt; Slot: Wed 21 Oct • New York 7:00 a.m. • London 12:00 noon • New Delhi 4:30 p.m. • Singapore 7:00 p.m.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id="why-is-your-talk-exciting"&gt;Why is your talk exciting?&lt;/h3&gt;
&lt;p&gt;I’m not sure if my talk is exciting, but I’m quite positive the subject is! Vitess has been gaining a lot of traction over the past few years and I must admit that I’ve been keen to get hands-on experience with it for years. As we, MessageBird, encounter rapid growth standard (read) scaling wasn’t applicable anymore and we were in need for a solution. Late 2019 we implemented our (quick) DIY sharding solution based upon existing components. A few months later we encountered the next scaling issue and we found our own built solution wasn’t suitable in this case. That’s when we considered investing our time instead in a Vitess proof of concept (community edition) and this talk will compare the two paths chosen and show some of the choices and compromises you have to make.&lt;/p&gt;
&lt;h3 id="who-would-benefit-the-most-from-your-talk"&gt;Who would benefit the most from your talk?&lt;/h3&gt;
&lt;p&gt;People who need to shard their (write) workloads and are considering using Vitess for this purpose. Our intention is to do a fair comparison between the two to help others make a well prepared decision.&lt;/p&gt;
&lt;h3 id="what-other-presentations-are-you-most-looking-forward-to"&gt;What other presentations are you most looking forward to?&lt;/h3&gt;
&lt;p&gt;The agenda is full of presentations I’m looking forward to. However as my current world is dominated by productionalising Vitess, I will be looking forward to &lt;a href="https://perconaliveonline2020.sched.com/event/ePp6/vitess-online-schema-migration-automation" target="_blank" rel="noopener noreferrer"&gt;Shlomi Noach’s talk&lt;/a&gt; about online schema migrations automation in Vitess.&lt;/p&gt;</content:encoded>
      <author>Art van Scheppingen</author>
      <category>art.vanscheppingen</category>
      <category>MySQL</category>
      <category>PLO-2020-10</category>
      <media:thumbnail url="https://percona.community/blog/2020/10/DB-PLO-Blog-Image-2020-10-05_hu_ee2e8da0448380e1.jpg"/>
      <media:content url="https://percona.community/blog/2020/10/DB-PLO-Blog-Image-2020-10-05_hu_e5cd6fdb7763e3c5.jpg" medium="image"/>
    </item>
    <item>
      <title>What If We Could Use Machine Learning Models as Tables – Percona Live ONLINE Talk Preview</title>
      <link>https://percona.community/blog/2020/10/12/what-if-we-could-use-machine-learning-models-as-tables-percona-live-online-talk-preview/</link>
      <guid>https://percona.community/blog/2020/10/12/what-if-we-could-use-machine-learning-models-as-tables-percona-live-online-talk-preview/</guid>
      <pubDate>Mon, 12 Oct 2020 17:56:51 UTC</pubDate>
      <description>Percona Live Online Agenda Slot: Tue 20 Oct • New York 1:30 p.m. • London 6:30 p.m. • New Delhi 11:00 p.m. • Singapore 1:30 a.m. (next day)</description>
      <content:encoded>&lt;p&gt;&lt;em&gt;&lt;a href="https://www.percona.com/live/agenda" target="_blank" rel="noopener noreferrer"&gt;Percona Live Online Agenda&lt;/a&gt; Slot: Tue 20 Oct • New York 1:30 p.m. • London 6:30 p.m. • New Delhi 11:00 p.m. • Singapore 1:30 a.m. (next day)&lt;/em&gt;&lt;/p&gt;
&lt;h3 id="abstract"&gt;Abstract&lt;/h3&gt;
&lt;p&gt;In most machine learning tasks, one has to first organize data in some form and then turn it into information about the problem that needs to be solved. One could say that the requirement to train many machine learning algorithms is information, not just data. Given that most of the world’s structured and semi-structured data (information) lives in databases, it makes sense to bring ML capabilities straight to the databases themselves. In this talk we want to present to the Percona community what we have learned in the effort of enabling existing databases like MariaDB and Postgres with frictionless ML powers.&lt;/p&gt;
&lt;h3 id="why-is-your-talk-exciting"&gt;Why is your talk exciting?&lt;/h3&gt;
&lt;p&gt;ML straight in databases is exciting because it enables hundreds of thousands of people that already know SQL to solve problems using machine learning without any extra skills.&lt;/p&gt;
&lt;h3 id="who-would-benefit-the-most-from-your-talk"&gt;Who would benefit the most from your talk?&lt;/h3&gt;
&lt;p&gt;Anyone knows how to query a SQL database.&lt;/p&gt;
&lt;h3 id="is-there-any-other-question-you-would-like-to-answer"&gt;Is there any other question you would like to answer?&lt;/h3&gt;
&lt;p&gt;What databases can we do machine learning in now, and which ones are coming?&lt;/p&gt;
&lt;h3 id="what-other-talks-are-you-most-looking-forward-to"&gt;What other talks are you most looking forward to?&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://perconaliveonline2020.sched.com/#" target="_blank" rel="noopener noreferrer"&gt;The Cloud is Inevitable&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://perconaliveonline2020.sched.com/#" target="_blank" rel="noopener noreferrer"&gt;Serverless Databases: The Good, the Bad, and the Ugly &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://perconaliveonline2020.sched.com/#" target="_blank" rel="noopener noreferrer"&gt;The State of MongoDB, Its Open Source Community, and Where Percona Is Going With It&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded>
      <author>Jorge Torres</author>
      <category>jorge.torres</category>
      <category>MariaDB</category>
      <category>PLO-2020-10</category>
      <category>PostgreSQL</category>
      <media:thumbnail url="https://percona.community/blog/2020/10/DB-PLO-Blog-Image-2020-10-05_hu_ee2e8da0448380e1.jpg"/>
      <media:content url="https://percona.community/blog/2020/10/DB-PLO-Blog-Image-2020-10-05_hu_e5cd6fdb7763e3c5.jpg" medium="image"/>
    </item>
    <item>
      <title>Vitess Online Schema Migration Automation – Percona Live ONLINE Talk Preview</title>
      <link>https://percona.community/blog/2020/10/09/vitess-online-schema-migration-automation-percona-live-online-talk-preview/</link>
      <guid>https://percona.community/blog/2020/10/09/vitess-online-schema-migration-automation-percona-live-online-talk-preview/</guid>
      <pubDate>Fri, 09 Oct 2020 17:28:19 UTC</pubDate>
      <description>Percona Live Online Agenda Slot: Wed 21 Oct • New York 2:30 a.m. • London 7:30 a.m. • New Delhi 12:00 noon • Singapore 2:30 p.m.</description>
      <content:encoded>&lt;p&gt;&lt;em&gt;&lt;a href="https://www.percona.com/live/agenda" target="_blank" rel="noopener noreferrer"&gt;Percona Live Online Agenda&lt;/a&gt; Slot: Wed 21 Oct • New York 2:30 a.m. • London 7:30 a.m. • New Delhi 12:00 noon • Singapore 2:30 p.m.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id="abstract"&gt;Abstract&lt;/h3&gt;
&lt;p&gt;For many, running an online schema migration operation is still a manual job: from building the correct command, through identifying where the migration should run and which servers are to be affected, to auditing progress and completing the migration. Sharded environment poses an additional burden, as any logical migration must be applied multiple times, once for each shard.&lt;/p&gt;
&lt;p&gt;What if you could just issue an ALTER TABLE … statement, and have all that complexity automated away? Vitess, an open source sharding framework for MySQL, is in a unique position to do just that. This session shows how Vitess’s proxy/agent/topology architecture, together with gh-ost, are used to hide schema change complexity, and carefully schedule and apply schema migrations.&lt;/p&gt;
&lt;h3 id="why-is-your-talk-exciting"&gt;Why is your talk exciting?&lt;/h3&gt;
&lt;p&gt;My work unifies multiple open source solutions (gh-ost, freno, and others) in a single, managed place. Vitess becomes an infrastructure solution, which can automate away the complexities of schema migrations: running, tracking, handling errors, cleaning up. It offers a completely automated cycle for most users, yet still gives them the controls.&lt;/p&gt;
&lt;p&gt;Whether with gh-ost or pt-online-schema-change, vitess is able to abstract away the migration process such that the user will normally just run and forget. Having worked as an operational engineer, and having developed schema migration automation in my past experience, I’m just excited to think about the users who will save hours of manual labor a week with this new offering.&lt;/p&gt;
&lt;h3 id="who-would-benefit-the-most-from-your-talk"&gt;Who would benefit the most from your talk?&lt;/h3&gt;
&lt;p&gt;Operational DBAs and engineers who perform manual schema migrations, or are looking to automate their database infrastructure.&lt;/p&gt;
&lt;h3 id="what-other-talks-are-you-most-looking-forward-to"&gt;What other talks are you most looking forward to?&lt;/h3&gt;
&lt;p&gt;I’m in particular curious to hear about what’s new in distributed databases and geo replication. Otherwise, as always, I’m keen to hear about open source tools in the MySQL ecosystem.&lt;/p&gt;
&lt;h3 id="is-there-any-other-question-you-would-like-to-answer"&gt;Is there any other question you would like to answer?&lt;/h3&gt;
&lt;p&gt;Q: Is this work public? A: Yes, it is. This work is expected to be released as an experimental feature as part of Vitess 8.0, end of October 2020. It is public, free and open source.&lt;/p&gt;</content:encoded>
      <author>Shlomi Noach</author>
      <category>shlomi.noach</category>
      <category>MySQL</category>
      <category>PLO-2020-10</category>
      <media:thumbnail url="https://percona.community/blog/2020/10/DB-PLO-Blog-Image-2020-10-05_hu_ee2e8da0448380e1.jpg"/>
      <media:content url="https://percona.community/blog/2020/10/DB-PLO-Blog-Image-2020-10-05_hu_e5cd6fdb7763e3c5.jpg" medium="image"/>
    </item>
    <item>
      <title>Analytical Queries in MySQL – Percona Live ONLINE Talk Preview</title>
      <link>https://percona.community/blog/2020/10/09/analytical-queries-in-mysql-percona-live-online-talk-preview/</link>
      <guid>https://percona.community/blog/2020/10/09/analytical-queries-in-mysql-percona-live-online-talk-preview/</guid>
      <pubDate>Fri, 09 Oct 2020 17:05:14 UTC</pubDate>
      <description>Percona Live Online Agenda Slot: Tue 20 Oct • New York 6:00 p.m. • London 11:00 p.m. • New Delhi 3:30 a.m. • Singapore 6:00 a.m.</description>
      <content:encoded>&lt;p&gt;&lt;em&gt;&lt;a href="https://www.percona.com/live/agenda" target="_blank" rel="noopener noreferrer"&gt;Percona Live Online Agenda&lt;/a&gt; Slot: Tue 20 Oct • New York 6:00 p.m. • London 11:00 p.m. • New Delhi 3:30 a.m. • Singapore 6:00 a.m.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id="abstract"&gt;Abstract&lt;/h3&gt;
&lt;p&gt;MySQL’s sweet spot is known to be online transaction processing (OLTP), and it can support a very high load of short transactions. Many users will also want to run analytical queries (OLAP) on their MySQL data. Often they achieve this by exporting their data to another database system that is tailored for analytical queries. However, this introduces overhead and delay that can be avoided by running your analytical queries directly in your MySQL database.&lt;/p&gt;
&lt;p&gt;This presentation will discuss how you can tune your complex analytical queries to achieve better performance with MySQL. We will look at some of the queries from the well-known TPC-H/DBT-3 benchmark, and show how we can improve the performance of these queries through query rewrites, optimizer hints, and improved configuration settings.&lt;/p&gt;
&lt;p&gt;We will also compare the performance of these queries to other database systems like MariaDB and PostgreSQL, and discuss how MySQL could be improved to better support these queries. While this presentation will mainly focus on MySQL, we will also compare with MariaDB and Postgres and discuss what causes the difference in performance between the systems.&lt;/p&gt;
&lt;h3 id="why-is-your-talk-exciting"&gt;Why is your talk exciting?&lt;/h3&gt;
&lt;p&gt;This talk is exciting because we will show several ways you can improve the performance of complex queries in MySQL. We will also compare the performance of MySQL to other database systems, and discuss what MySQL could learn from those systems.&lt;/p&gt;
&lt;h3 id="who-would-benefit-the-most-from-your-talk"&gt;Who would benefit the most from your talk?&lt;/h3&gt;
&lt;p&gt;Developers who use MySQL will learn how to write more efficient queries, and DBAs will learn how to tune their systems for better performance of complex queries. People that are interested in implementation aspects of database systems, should find the discussion of what.can be learned from other database systems interesting.&lt;/p&gt;
&lt;h3 id="what-other-presentations-are-you-most-looking-forward-to"&gt;What other presentations are you most looking forward to?&lt;/h3&gt;
&lt;p&gt;I look forward to the other presentations on analytical queries: “&lt;a href="https://sched.co/ePo2" target="_blank" rel="noopener noreferrer"&gt;SQL Row Store vs Data Warehouse: Which Is Right for Your Application?&lt;/a&gt;” by Robert Hodges, and “&lt;a href="https://sched.co/ePr2" target="_blank" rel="noopener noreferrer"&gt;Building Data Lake with MariaDB ColumnStore&lt;/a&gt;” by Sasha Vaniachine. (However, I will probably not get up at 5:30am to watch the latter live :-)).&lt;/p&gt;
&lt;p&gt;I also look forward to the presentations on “&lt;a href="https://sched.co/eN9q" target="_blank" rel="noopener noreferrer"&gt;How Can Databases Capitalize on Computational Storage?&lt;/a&gt;” by Tong Zhang and JB Baker, and “&lt;a href="https://sched.co/ePo7" target="_blank" rel="noopener noreferrer"&gt;How to Protect the SQL Engine From Running Out of Memory&lt;/a&gt;” by Huaiyu Xu and Song Gao.&lt;/p&gt;</content:encoded>
      <author>Øystein Grøvlen</author>
      <category>oystein.grovlen</category>
      <category>Events</category>
      <category>MariaDB</category>
      <category>MySQL</category>
      <category>PLO-2020-10</category>
      <category>PostgreSQL</category>
      <media:thumbnail url="https://percona.community/blog/2020/10/DB-PLO-Blog-Image-2020-10-05_hu_ee2e8da0448380e1.jpg"/>
      <media:content url="https://percona.community/blog/2020/10/DB-PLO-Blog-Image-2020-10-05_hu_e5cd6fdb7763e3c5.jpg" medium="image"/>
    </item>
    <item>
      <title>Serverless Databases: The Good, the Bad, and the Ugly – Percona Live ONLINE Talk Preview</title>
      <link>https://percona.community/blog/2020/10/08/serverless-databases-the-good-the-bad-and-the-ugly-percona-live-online-talk-preview/</link>
      <guid>https://percona.community/blog/2020/10/08/serverless-databases-the-good-the-bad-and-the-ugly-percona-live-online-talk-preview/</guid>
      <pubDate>Thu, 08 Oct 2020 20:58:38 UTC</pubDate>
      <description>Percona Live Online Agenda Slot: Wed 21 Oct • New York 4:30 a.m. • London 9:30 a.m • New Delhi 2:00 p.m. • Singapore 4:30 p.m.</description>
      <content:encoded>&lt;p&gt;&lt;em&gt;&lt;a href="https://www.percona.com/live/agenda" target="_blank" rel="noopener noreferrer"&gt;Percona Live Online Agenda&lt;/a&gt; Slot: Wed 21 Oct • New York 4:30 a.m. • London 9:30 a.m • New Delhi 2:00 p.m. • Singapore 4:30 p.m.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="abstract"&gt;Abstract&lt;/h2&gt;
&lt;p&gt;Starting with AWS, the major cloud providers offer different options to run a MySQL or a MySQL-compatible database on the cloud. A new approach is to rely on so-called serverless (relational) databases like Aurora Serverless that offer both traditional TCP connections and HTTP API access. Can serverless really be the future? Can data API really replace a MySQL connector? What are the major limitations of a serverless database cluster and do they really protect from inefficient use of database resources?&lt;/p&gt;
&lt;h2 id="why-is-your-talk-exciting"&gt;Why is your talk exciting?&lt;/h2&gt;
&lt;p&gt;The database is the most challenging layer to optimize resources in the cloud and achieve elasticity. Serverless relational databases can help in that but introduce as well new limitations and challenges, including cloud vendor lock-in. We will discuss the good, the bad and the ugly of running a MySQL database serverless.&lt;/p&gt;
&lt;h2 id="who-would-benefit-the-most-from-your-talk"&gt;Who would benefit the most from your talk?&lt;/h2&gt;
&lt;p&gt;DevOps and cloud architects, almost all the lazy ones. The ones who would like to hide the complexity of managing a relational database on the cloud and optimise price-performances on their deployments with the click of a button.&lt;/p&gt;
&lt;h2 id="what-other-presentations-are-you-most-looking-forward-to"&gt;What other presentations are you most looking forward to?&lt;/h2&gt;
&lt;p&gt;Many exciting topics in the agenda but I am really looking forward to “&lt;a href="https://sched.co/eN9q" target="_blank" rel="noopener noreferrer"&gt;How Can Databases Capitalize on Computational Storage?&lt;/a&gt;” and “&lt;a href="https://sched.co/ePnR" target="_blank" rel="noopener noreferrer"&gt;MySQL Ecosystem on ARM&lt;/a&gt;” among many others. For the keynotes, I am very interested in “&lt;a href="https://sched.co/eov2" target="_blank" rel="noopener noreferrer"&gt;The Cloud is Inevitable&lt;/a&gt;” and I am looking forward to Peter’s one as well ("&lt;a href="https://perconaliveonline2020.sched.com/#" target="_blank" rel="noopener noreferrer"&gt;Why Public Database as a Service is Prime for Open Source Disruption").&lt;/a&gt;&lt;/p&gt;</content:encoded>
      <author>Renato Losio</author>
      <category>renato-losio</category>
      <category>AWS</category>
      <category>Events</category>
      <category>MySQL</category>
      <category>PLO-2020-10</category>
      <media:thumbnail url="https://percona.community/blog/2020/10/DB-PLO-Blog-Image-2020-10-05_hu_ee2e8da0448380e1.jpg"/>
      <media:content url="https://percona.community/blog/2020/10/DB-PLO-Blog-Image-2020-10-05_hu_e5cd6fdb7763e3c5.jpg" medium="image"/>
    </item>
    <item>
      <title>MySQL Ecosystem on ARM – Percona Live ONLINE Talk Preview</title>
      <link>https://percona.community/blog/2020/10/07/mysql-ecosystem-on-arm-percona-live-online-talk-preview/</link>
      <guid>https://percona.community/blog/2020/10/07/mysql-ecosystem-on-arm-percona-live-online-talk-preview/</guid>
      <pubDate>Wed, 07 Oct 2020 02:28:58 UTC</pubDate>
      <description>Percona Live Online Agenda Slot: Tue 20 Oct • New York 8:00 p.m. • London 1:00 a.m (next day) • New Delhi 5:30 a.m. • Singapore 8:00 a.m.</description>
      <content:encoded>&lt;p&gt;&lt;em&gt;&lt;a href="https://www.percona.com/live/agenda" target="_blank" rel="noopener noreferrer"&gt;Percona Live Online Agenda&lt;/a&gt; Slot: Tue 20 Oct • New York 8:00 p.m. • London 1:00 a.m (next day) • New Delhi 5:30 a.m. • Singapore 8:00 a.m.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id="abstract"&gt;Abstract?&lt;/h3&gt;
&lt;p&gt;The ARM ecosystem is quickly evolving as a cost-effective alternative to run High-Performance Computing (HPC) software. It continues to grow with some major cloud players hosting ARM-based cloud servers. MySQL too joined the ecosystem with 8.x. MariaDB already has made its presence. But besides the mainline server, a lot of tools are yet to get ported to ARM.&lt;/p&gt;
&lt;p&gt;In this talk, we will explore what all aspects of the MySQL ecosystem are part of ARM, work in progress, optimization being done for ARM, challenges involved, Is it safe to run MySQL (or its variant) on ARM?, community and industry support, performance aspect (especially with x86_64), etc.&lt;/p&gt;
&lt;h3 id="why-is-your-talk-exciting"&gt;Why is your talk exciting?&lt;/h3&gt;
&lt;p&gt;MySQL recently added support for ARM (starting 8.x). ARM on the other hand is gaining popularity as a cost-effective solution for running High-Performance Computing Software with multiple cloud providers (Huawei, Amazon, Oracle cloud) providing ARM instances. The community is excited to learn how the MySQL ecosystem is evolving on ARM and what kind of advantage users could get by running it on ARM.&lt;/p&gt;
&lt;h3 id="who-would-benefit-the-most-from-your-talk"&gt;Who would benefit the most from your talk?&lt;/h3&gt;
&lt;p&gt;Talk is mainly meant for end-user/DBA/dev-ops all those who need to decide how to optimally deploy MySQL and still ensure maximum throughput. The talk will explore the pros and cons of running MySQL on ARM and supporting ecosystems that should give audiences fair ideas if it is time for them to consider the said route.&lt;/p&gt;
&lt;h3 id="what-other-presentations-are-you-most-looking-forward-to"&gt;What other presentations are you most looking forward to?&lt;/h3&gt;
&lt;p&gt;Percona Live, as always, has a lined up number of good and new talks. Personally, I am interested in checking MySQL deployment that scales geographically. Users are not only moving to the cloud but also considering if the said setup could now be globalized through geo-distribution keeping a tight check on cost especially with the situation of the current pandemic that has forced all businesses to re-look at their spending. Managing Database @ Scale, Best Practices in Design, and Implementing MySQL Geographic Distributed HA solutions are some of my short-lists to attend.&lt;/p&gt;
&lt;h3 id="is-there-any-other-question-you-would-like-to-answer"&gt;Is there any other question you would like to answer?&lt;/h3&gt;
&lt;p&gt;I think there are a plethora of options available for users in the DB ecosystem space and the ecosystem is evolving at a pretty good pace. My only message to the users is to keep all options open and be flexible because you never know which options may work wonders for you. With an open-source ecosystem, try/experiment with new things is the key.&lt;/p&gt;</content:encoded>
      <author>Krunal Bauskar</author>
      <category>krunal.bauskar</category>
      <category>Events</category>
      <category>MariaDB</category>
      <category>MySQL</category>
      <category>PLO-2020-10</category>
      <media:thumbnail url="https://percona.community/blog/2020/10/DB-PLO-Blog-Image-2020-10-05_hu_ee2e8da0448380e1.jpg"/>
      <media:content url="https://percona.community/blog/2020/10/DB-PLO-Blog-Image-2020-10-05_hu_e5cd6fdb7763e3c5.jpg" medium="image"/>
    </item>
    <item>
      <title>NoSQL Endgame – Percona Live ONLINE Talk Preview</title>
      <link>https://percona.community/blog/2020/10/05/nosql-endgame-percona-live-online-talk-preview/</link>
      <guid>https://percona.community/blog/2020/10/05/nosql-endgame-percona-live-online-talk-preview/</guid>
      <pubDate>Mon, 05 Oct 2020 01:08:04 UTC</pubDate>
      <description>Percona Live Online Agenda Slot: Tue 20 Oct • New York 3:00 p.m. • London 8:00 p.m. • New Delhi 12:30 a.m. (next day) • Singapore 3:00 a.m.</description>
      <content:encoded>&lt;p&gt;&lt;em&gt;&lt;a href="https://www.percona.com/live/agenda" target="_blank" rel="noopener noreferrer"&gt;Percona Live Online Agenda&lt;/a&gt; Slot: Tue 20 Oct • New York 3:00 p.m. • London 8:00 p.m. • New Delhi 12:30 a.m. (next day) • Singapore 3:00 a.m.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id="abstract"&gt;Abstract&lt;/h3&gt;
&lt;p&gt;The amount of data collected by applications nowadays is growing at a scary pace. Many of them need to handle billions of users generating and consuming data at an incredible speed. Maybe you are wondering how to create an application like this? What is required? What works best for your project?&lt;/p&gt;
&lt;p&gt;In this session we’ll compare popular Java and JVM persistence frameworks for NoSQL databases: Spring Data, Micronaut Data, Hibernate OGM, Jakarta NoSQL, and GORM. How do they compare, what are the strengths, weaknesses, differences, and similarities? We’ll show each of them with a selection of different NoSQL database systems (Key-Value, Document, Column, Graph).&lt;/p&gt;
&lt;h3 id="why-is-your-talk-exciting"&gt;Why is your talk exciting?&lt;/h3&gt;
&lt;p&gt;The data load on applications has increased exponentially in recent years. We know the JVM (Java Virtual Machine) can cope with heavy loads very well yet we often come across the big dilemma: there are tons of persistence frameworks out there but which one performs best for my case? It would normally take ages to evaluate and choose the best fit for your use case. We’ve done those comparisons for you.&lt;/p&gt;
&lt;h3 id="who-would-benefit-the-most-from-your-talk"&gt;Who would benefit the most from your talk?&lt;/h3&gt;
&lt;p&gt;Those who make technical roadmap decisions such as software architects, engineering managers, and developers involved in new technology decisions.&lt;/p&gt;
&lt;h3 id="what-other-talks-are-you-most-looking-forward-to"&gt;What other talks are you most looking forward to?&lt;/h3&gt;
&lt;p&gt;The conference agenda is simply amazing. It’s difficult to choose which sessions to attend, but we’re pretty sure we’ll attend “&lt;a href="https://sched.co/ePlw" target="_blank" rel="noopener noreferrer"&gt;The 411 PMM&lt;/a&gt;” by Brandon Fleisher and Steve Hoffman, and also “&lt;a href="https://sched.co/eN9q" target="_blank" rel="noopener noreferrer"&gt;How Can Databases Capitalize on Computational Storage&lt;/a&gt;” by Tong Zhang and JB Baker.&lt;/p&gt;</content:encoded>
      <author>Thodoris Bais</author>
      <author>Werner Keil</author>
      <category>thodoris.bais</category>
      <category>werner.keil</category>
      <category>Entry Level</category>
      <category>Events</category>
      <category>Open Source Databases</category>
      <category>PLO-2020-10</category>
      <media:thumbnail url="https://percona.community/blog/2020/10/DB-PLO-Blog-Image-2020-10-05_hu_ee2e8da0448380e1.jpg"/>
      <media:content url="https://percona.community/blog/2020/10/DB-PLO-Blog-Image-2020-10-05_hu_e5cd6fdb7763e3c5.jpg" medium="image"/>
    </item>
    <item>
      <title>Kunlun Distributed DB Cluster Intro – Percona Live ONLINE Talk Preview</title>
      <link>https://percona.community/blog/2020/10/02/kunlun-distributed-db-cluster-intro-percona-live-online-talk-preview/</link>
      <guid>https://percona.community/blog/2020/10/02/kunlun-distributed-db-cluster-intro-percona-live-online-talk-preview/</guid>
      <pubDate>Fri, 02 Oct 2020 22:25:34 UTC</pubDate>
      <description>Percona Live Online Agenda Slot: Tue 20 Oct • New York 9:30 p.m. • London 02:30 a.m. (next day) • New Delhi 7:00 a.m. • Singapore 09:30 a.m.</description>
      <content:encoded>&lt;p&gt;&lt;em&gt;&lt;a href="https://www.percona.com/live/agenda" target="_blank" rel="noopener noreferrer"&gt;Percona Live Online&lt;/a&gt; Agenda Slot: Tue 20 Oct • New York 9:30 p.m. • London 02:30 a.m. (next day) • New Delhi 7:00 a.m. • Singapore 09:30 a.m.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id="abstract"&gt;Abstract&lt;/h3&gt;
&lt;p&gt;Kunlun Distributed Database Cluster is a distributed DBMS that aims to combine the best of both MySQL and PostgreSQL for a highly performant, highly available, highly scalable and fault-tolerant, easy to use and manage database system that requires minimal human maintenance.  It enables users to define table sharding rules so that it automatically distributes tables properly to available storage shards; implements the two-phase commit protocol to do distributed transaction commit; uses MySQL group replication for high availability in storage shards; fixes a series of MySQL XA bugs to make distributed transactions highly reliable, among many other enhancements.&lt;/p&gt;
&lt;h3 id="why-is-your-talk-exciting"&gt;Why is your talk exciting?&lt;/h3&gt;
&lt;p&gt;Audience will get to know Kunlun — a brand new distributed database cluster built from two most popular open source database systems — MySQL and PostgreSQL, and how Kunlun can make developers and DBAs’ life much easier. They will also know why it’s troublesome and error prone to use MySQL group replication as is and how Kunlun make it totally easy by hiding all the complexity.&lt;/p&gt;
&lt;h3 id="who-would-benefit-the-most-from-your-talk"&gt;Who would benefit the most from your talk?&lt;/h3&gt;
&lt;p&gt;Application developers and DBAs who use MySQL and/or PostgreSQL clusters, especially those having to deal with multi terabytes of relational data that no single db instance can manage.&lt;/p&gt;
&lt;h3 id="what-other-presentations-are-you-most-looking-forward-to"&gt;What other presentations are you most looking forward to?&lt;/h3&gt;
&lt;p&gt;Those about alternative ways to deal with ever growing and multi terabytes of relational data which far exceeds the capacity of a single db instance.&lt;/p&gt;</content:encoded>
      <author>David Zhao</author>
      <category>david.zhao</category>
      <category>Events</category>
      <category>MySQL</category>
      <category>Open Source Databases</category>
      <category>PLO-2020-10</category>
      <category>PostgreSQL</category>
      <media:thumbnail url="https://percona.community/blog/2020/10/DB-PLO-Blog-Image-2020-10-05_hu_ee2e8da0448380e1.jpg"/>
      <media:content url="https://percona.community/blog/2020/10/DB-PLO-Blog-Image-2020-10-05_hu_e5cd6fdb7763e3c5.jpg" medium="image"/>
    </item>
    <item>
      <title>MariaDB 10.5 New Features for Troubleshooting – Percona Live ONLINE Talk Preview</title>
      <link>https://percona.community/blog/2020/10/01/mariadb-10-5-new-features-for-troubleshooting-percona-live-online-talk-preview/</link>
      <guid>https://percona.community/blog/2020/10/01/mariadb-10-5-new-features-for-troubleshooting-percona-live-online-talk-preview/</guid>
      <pubDate>Thu, 01 Oct 2020 23:42:03 UTC</pubDate>
      <description>Percona Live Online Agenda Slot: Wed 21 Aug • New York 12:00 midnight • London 05:00 a.m. • New Delhi 9:30 a.m. • Singapore 12:00 noon</description>
      <content:encoded>&lt;p&gt;&lt;em&gt;&lt;a href="https://www.percona.com/live/agenda" target="_blank" rel="noopener noreferrer"&gt;Percona Live Online&lt;/a&gt; Agenda Slot: Wed 21 Aug • New York 12:00 midnight • London 05:00 a.m. • New Delhi 9:30 a.m. • Singapore 12:00 noon&lt;/em&gt;&lt;/p&gt;
&lt;h3 id="abstract"&gt;Abstract&lt;/h3&gt;
&lt;p&gt;I want to help DBAs and Support engineers find out what’s really going on when some problem strikes.  My goal is to show new ways to diagnose problems now available in MariaDB 10.5.   See &lt;a href="https://perconaliveonline2020.sched.com/event/ePoK/mariadb-105-new-features-for-troubleshooting" target="_blank" rel="noopener noreferrer"&gt;the full abstract&lt;/a&gt; for more.&lt;/p&gt;
&lt;h3 id="why-is-your-talk-exciting"&gt;Why Is Your Talk Exciting?&lt;/h3&gt;
&lt;p&gt;It provides a lot of details and practical examples of how MariaDB 10.5 new features for troubleshooting may help DBAs and developers in understanding the production load and tuning MariaDB server for it. The process of documenting these new features is not completed yet, so you may not be able to easily find the information presented elsewhere.&lt;/p&gt;
&lt;h3 id="who-would-benefit-from-your-talk"&gt;Who Would Benefit From Your Talk?&lt;/h3&gt;
&lt;p&gt;DBAs and consultants who use or plan to use MariaDB server 10.5 in production.&lt;/p&gt;
&lt;h3 id="what-is-the-most-useful-new-feature-in-mariadb-105"&gt;What Is the Most Useful New Feature in MariaDB 10.5?&lt;/h3&gt;
&lt;p&gt;For me it’s memory instrumentation. There are alternative ways to find memory leaks or trace memory allocations in detail, but they either have notable performance impacts or are hard to implement in production. This feature potentially can bring DBAs many insights and help to resolve nasty problems. I’ve missed it for years.&lt;/p&gt;
&lt;h3 id="what-other-talks-are-you-most-looking-forward-to"&gt;What Other Talks Are You Most Looking Forward To?&lt;/h3&gt;
&lt;p&gt;For me these presentations look really interesting:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://perconaliveonline2020.sched.com/event/ePnR/mysql-ecosystem-on-arm?iframe=yes&amp;w=100%25&amp;sidebar=no&amp;bg=no" target="_blank" rel="noopener noreferrer"&gt;MySQL Ecosystem on ARM By Krunal Bauskar &amp; Mike Grayson&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;I think ARM is a future for servers and historically I was always interested in MySQL implementations on non-x86 hardware.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://perconaliveonline2020.sched.com/event/ePp6/vitess-online-schema-migration-automation?iframe=yes&amp;w=100%25&amp;sidebar=no&amp;bg=no" target="_blank" rel="noopener noreferrer"&gt;Vitess Online Schema Migration Automation By Shlomi Noach &amp; Evgeniy Patlan&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;Whatever Shlomi speaks about, it’s always interesting and useful!&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;See the full conference agenda &lt;a href="https://www.percona.com/live/agenda" target="_blank" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;</content:encoded>
      <author>Valeriy Kravchuk</author>
      <category>valeriy.kravchuk</category>
      <category>Events</category>
      <category>MariaDB</category>
      <category>perconalive</category>
      <category>PLO-2020-10</category>
      <media:thumbnail url="https://percona.community/blog/2020/10/DB-PLO-Blog-Image-2020-10-05_hu_ee2e8da0448380e1.jpg"/>
      <media:content url="https://percona.community/blog/2020/10/DB-PLO-Blog-Image-2020-10-05_hu_e5cd6fdb7763e3c5.jpg" medium="image"/>
    </item>
    <item>
      <title>Two weeks to MariaDB Server Fest</title>
      <link>https://percona.community/blog/2020/09/04/two-weeks-to-mariadb-server-fest/</link>
      <guid>https://percona.community/blog/2020/09/04/two-weeks-to-mariadb-server-fest/</guid>
      <pubDate>Fri, 04 Sep 2020 09:34:53 UTC</pubDate>
      <description>There is still time to register for the MariaDB Server Fest 2020!</description>
      <content:encoded>&lt;p&gt;There is still time to &lt;a href="https://mariadb.org/fest-registration/" target="_blank" rel="noopener noreferrer"&gt;register&lt;/a&gt; for the MariaDB Server Fest 2020!&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2020/09/mariadb_fest_video.jpeg" alt="MariaDB Fest 2020" /&gt;&lt;/figure&gt; MariaDB Fest 2020[/caption]&lt;/p&gt;
&lt;p&gt;Our Fest is the opportunity to have live interactions with the key players on MariaDB Server: the developers of MariaDB Server, the service providers, the experts, the system integrators, and – perhaps most importantly – your fellow users!&lt;/p&gt;
&lt;p&gt;Interactivity happens all the time, with the presenters being cloned and available for answering questions throughout the presentation. This is because the presentations (including voice, a talking head, and the slide decks) are pre-recorded, freeing up the presenter’s attention to be fully devoted to the audience. Multithreading!&lt;/p&gt;
&lt;p&gt;Sessions are listed in full on the &lt;a href="https://mariadb.org/fest2020-sessions" target="_blank" rel="noopener noreferrer"&gt;web&lt;/a&gt;, with the exact timing for the three virtual locations still being fine-tuned. Turn in to listen to 30 presenters from eg. Supermetrics, MariaDB Corporation, Percona, Microsoft, Galera, Tencent, Bilibili and MariaDB Foundation.&lt;/p&gt;
&lt;p&gt;Timing is during your day-time, and spread out across three days, five hours a day, so you can still get most of your normal job done.&lt;/p&gt;
&lt;p&gt;On Monday-Wednesday 14-16 Sep 2020 we have the Paris conference, on Tuesday-Thursday 15-17 Sep 2020 we have the New York conference, and on Friday-Sunday 18-20 Sep 2020 the Beijing conference. Exact agendas vary slightly between the locations, to cater to the sleeping patterns of the presenters from other time zones.&lt;/p&gt;
&lt;p&gt;Talk to you in less than two weeks!&lt;/p&gt;
&lt;p&gt;Links:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Registration: &lt;a href="https://mariadb.org/fest-registration/" target="_blank" rel="noopener noreferrer"&gt;https://mariadb.org/fest-registration/&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Session list: &lt;a href="https://mariadb.org/fest2020-sessions/" target="_blank" rel="noopener noreferrer"&gt;https://mariadb.org/fest2020-sessions/&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;</content:encoded>
      <author>Kaj Arnö</author>
      <category>kaj.arno</category>
      <category>Events</category>
      <category>MariaDB</category>
      <category>MariaDB</category>
      <category>MySQL</category>
      <category>MySQL</category>
      <category>mysql-and-variants</category>
      <category>Open Source Databases</category>
      <media:thumbnail url="https://percona.community/blog/2020/09/mariadb_fest_video_hu_c1795516dda166aa.jpeg"/>
      <media:content url="https://percona.community/blog/2020/09/mariadb_fest_video_hu_49e15c79741cdaae.jpeg" medium="image"/>
    </item>
    <item>
      <title>MariaDB Server Fest: Call for Papers</title>
      <link>https://percona.community/blog/2020/06/26/mariadb-server-fest-call-for-papers/</link>
      <guid>https://percona.community/blog/2020/06/26/mariadb-server-fest-call-for-papers/</guid>
      <pubDate>Fri, 26 Jun 2020 21:42:28 UTC</pubDate>
      <description>In the week of 14-20 September 2020, MariaDB Foundation will host the MariaDB Server Fest Online Conference. We welcome the Percona Community not just to participate, but also to submit papers for the event. We already have Peter Zaitsev joining as keynoter; we hope for more to come.</description>
      <content:encoded>&lt;p&gt;In the week of 14-20 September 2020, MariaDB Foundation will host the MariaDB Server Fest Online Conference. We welcome the Percona Community not just to participate, but also to submit papers for the event. We already have Peter Zaitsev joining as keynoter; we hope for more to come.&lt;/p&gt;
&lt;p&gt;Our target audience are the users of MariaDB Server – current and future ones. We are looking for use cases, practices, tools and insights from our user base as well as from application developers, service providers and other experts.&lt;/p&gt;
&lt;p&gt;When planning and phrasing your CfP submission at &lt;a href="https://mariadb.org/fest2020cfp/" target="_blank" rel="noopener noreferrer"&gt;https://mariadb.org/fest2020cfp/&lt;/a&gt;, think about what makes MariaDB Server unique, and what insights you can give the demanding audience.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Our audience is interested in your insights about new cool features of the latest releases, but also in underused MariaDB functionality that has been there for a while.&lt;/li&gt;
&lt;li&gt;Functionality such as system versioned tables, JSON functionality, and security features is interesting, and the same goes for usage patterns and best practices.&lt;/li&gt;
&lt;li&gt;Share your knowledge of PL/SQL, SEQUENCEs and other Oracle compatibility features, but also in experiences from overall migration strategies.&lt;/li&gt;
&lt;li&gt;Our audience is interested in comparing HA, Galera and general replication functionality to that of other similar databases, but would likely want to avoid overly confrontational flame wars on, say, Global Transaction ID.&lt;/li&gt;
&lt;li&gt;Developers and DBAs are used to seeing MariaDB positioned in contrast to MySQL (level of compatibility; differences in feature set), but may also find it insightful with comparisons to PostgreSQL, MongoDB and Oracle.&lt;/li&gt;
&lt;li&gt;Developers, sysadmins and devops are focused on technology and functionality, but is also very mindful of the implications of release schedules, security fix processes, and engaging the community in submitting code contributions.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For more about our conference, see our announcement at &lt;a href="https://mariadb.org/fest/" target="_blank" rel="noopener noreferrer"&gt;https://mariadb.org/fest/&lt;/a&gt; and &lt;a href="https://mariadb.org/fest2020cfp/" target="_blank" rel="noopener noreferrer"&gt;https://mariadb.org/fest2020cfp/&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Finally: thank you to Tom Basil of Percona, who opened up the opportunity for us to write this guest blog on the Percona Community Blog!&lt;/p&gt;
&lt;p&gt;We hope for many interesting submissions – and, later on, attendees – from the Percona Community. Footnote: The Call for Papers is open for one more week, until the end of June.&lt;/p&gt;</content:encoded>
      <author>Kaj Arnö</author>
      <category>kaj.arno</category>
      <category>Events</category>
      <category>MariaDB</category>
      <category>MySQL</category>
      <category>mysql-and-variants</category>
      <media:thumbnail url="https://percona.community/blog/2020/06/MDBS_Fest_logowhite_bg_hu_bcf01eb058e3a10.jpg"/>
      <media:content url="https://percona.community/blog/2020/06/MDBS_Fest_logowhite_bg_hu_980005dd80e7e01.jpg" medium="image"/>
    </item>
    <item>
      <title>Cassandra Where and How by John Schulz</title>
      <link>https://percona.community/blog/2020/06/24/cassandra-where-and-how-by-john-schulz/</link>
      <guid>https://percona.community/blog/2020/06/24/cassandra-where-and-how-by-john-schulz/</guid>
      <pubDate>Wed, 24 Jun 2020 12:20:22 UTC</pubDate>
      <description>If Percona Live ONLINE had graded its talks by skill level this year, John Schulz’s talk would have been essential viewing in the Beginners track. (You can watch all the event’s presentations now on Percona’s YouTube channel.) This talk was a good overview and meant for anyone who had heard of the Apache Cassandra distributed database but wasn’t sure whether it would be suitable for their project or not.</description>
      <content:encoded>&lt;p&gt;If Percona Live ONLINE had graded its talks by skill level this year, John Schulz’s talk would have been essential viewing in the Beginners track. (You can watch all the event’s presentations now on &lt;a href="https://www.youtube.com/user/PerconaMySQL/videos" target="_blank" rel="noopener noreferrer"&gt;Percona’s YouTube channel.&lt;/a&gt;) This talk was a good overview and meant for anyone who had heard of the Apache Cassandra distributed database but wasn’t sure whether it would be suitable for their project or not.&lt;/p&gt;
&lt;p&gt;Database-veteran, John Schulz has been tinkering with Cassandra for about a decade and to help anyone get started he gave a whistle-stop tour of the Cassandra ecosystem. He introduced Apache Cassandra by laying out some important characteristics of the database. These include the way Cassandra is designed to handle high-traffic volumes, especially writes, and is designed from the ground-up for high availability. John briefly talked about the ‘democratized nature’ of the database; how all its nodes are designed to be equal. However, while Cassandra is designed to scale linearly, he stressed that this ability comes with some serious caveats: “You have to understand the way it was designed,” John cautioned an audience of over 500 attendees. “You have to understand how you need to model data with it, otherwise its linear scaling will go out the window.”&lt;/p&gt;
&lt;h2 id="not-relational"&gt;Not relational&lt;/h2&gt;
&lt;p&gt;Cassandra has many strengths, but it’s not suitable for every use case. For instance, John said he would discourage using Cassandra for analytics as “it’s not a massive parallel processing engine.”&lt;/p&gt;
&lt;p&gt;He also highlighted the fact that Cassandra uses an SQL-like language called the &lt;a href="https://en.wikipedia.org/wiki/Apache_Cassandra#Cassandra_Query_Language" target="_blank" rel="noopener noreferrer"&gt;Cassandra Query Language (CQL)&lt;/a&gt;, which despite its similarities is definitely not SQL. Similarly, while you can add &lt;a href="https://spark.apache.org/sql/" target="_blank" rel="noopener noreferrer"&gt;Spark SQL&lt;/a&gt; to Cassandra and perform &lt;a href="https://en.wikipedia.org/wiki/Join_%28SQL%29" target="_blank" rel="noopener noreferrer"&gt;JOINs&lt;/a&gt;, Cassandra is not a relational database and shouldn’t be used as one. He also warned against implementing &lt;a href="https://en.wikipedia.org/wiki/Record_locking" target="_blank" rel="noopener noreferrer"&gt;locks&lt;/a&gt; in Cassandra. Apparently, he’s seen many customers do this only to regret it later. In fact, he suggested that if using a lock is essential for your application, then perhaps you shouldn’t be looking at Cassandra.&lt;/p&gt;
&lt;p&gt;After cautioning his virtual attendees, John shared some of the circumstances and use cases where Cassandra does excel. As a general principle, Cassandra works best in environments where the database writes exceed the reads by a large margin and where the sheer amount of traffic would normally overwhelm a traditional relational database.&lt;/p&gt;
&lt;p&gt;By way of example, John said that Cassandra works well for tracking ad hit rates. The database is also popularly used in the IoT industry for capturing raw data from devices, such as fitness trackers and vehicles. Also, many phone companies in North America are using Cassandra for customer service and a number of companies use it to provide metrics collection as a service.&lt;/p&gt;
&lt;h2 id="first-steps"&gt;First steps&lt;/h2&gt;
&lt;p&gt;Before getting started with Cassandra, John strongly recommended setting aside some time to design your database: “Badly designed data models, produce badly performing databases.”&lt;/p&gt;
&lt;p&gt;He suggested a couple of resources that would help with that including an &lt;a href="https://cassandra.apache.org/doc/latest/data_modeling/" target="_blank" rel="noopener noreferrer"&gt;overview of the topic from the Apache Cassandra project itself&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Next, he shared some of the questions you need to ask yourself before using Cassandra. For instance, what’s your main purpose for using Cassandra? The answer to that question will have a bearing on how you want to run Cassandra. That’s because the database offers plenty of options that range from a traditional data center environment to various cloud solutions. You can run Cassandra on your laptop, which is a good environment for tinkering with it. For a production environment though you can deploy Cassandra on physical servers, or inside VMs, or wrapped in containers.&lt;/p&gt;
&lt;p&gt;The next piece of the puzzle is to decide on a Cassandra flavour or distribution. John rounded up some of the most popular including Apache Cassandra, DataStax Enterprise, Scylla Open Source and Enterprise, Yugabyte, CosmosDB, Amazon Keyspaces, and Elassandra. He spent some time explaining them all and the key differences between them, but besides Apache Cassandra and DataStax Enterprise, he classified all other solutions as Cassandra API upstarts that look and behave like Cassandra, but aren’t exactly Cassandra under the covers. He was particularly excited about Elassandra, the mashup of Elasticsearch and Cassandra and pointed out that the former’s global index helps negate the limitations of Cassandra’s secondary indexes that are local-only by default.&lt;/p&gt;
&lt;h2 id="at-your-service"&gt;At your service&lt;/h2&gt;
&lt;p&gt;You can run Cassandra on various platforms, though John recommended using one of the Database-as-a-Service (DBaaS) providers as he felt it made very little sense to do it any other way. He briefly talked about some of the most popular services including InstaClustr, DataStax Astra, Amazon KeySpaces, Scylla Cloud, IBM Compose for Scylla, YugaByte Cloud, and CosmosDB.&lt;/p&gt;
&lt;p&gt;The main advantage of these services, John felt, was that they get you a Cassandra cluster instantly. Furthermore, they also come with lots of useful features such as automatic backups, automatic repairs, as well as monitoring. However, if you don’t want to deploy Cassandra on your own hardware, John supplied a list of things you’ll want to think about.&lt;/p&gt;
&lt;p&gt;He suggested using an automation tool, such as Chef, Puppet, Ansible, to build your clusters. He also recommended using a log aggregator and monitoring the cluster in real-time. He cautioned anyone looking to deploy Cassandra to never run an installation with a single node. John says that while you can do this, you won’t be able to observe all of the interactions that go on between the nodes, which will eventually affect the real-world performance and behaviour of your application. However, John recommended running a cluster of at least n nodes where n equals your replication factor. This is a talk in its own right, but, in essence, he suggested a replication factor of at least three.&lt;/p&gt;
&lt;p&gt;In the final section of his talk he covered the two mechanisms for deploying Cassandra: inside a Docker container and with the &lt;a href="https://github.com/riptano/ccm" target="_blank" rel="noopener noreferrer"&gt;Cassandra Cluster Manager (CCM)&lt;/a&gt;. Written in Python, John says CCM makes starting a Cassandra cluster on your laptop or desktop, or even a Raspberry Pi, just as easy as using a Database-as-a-Service option on the cloud. He ended by detailing the procedure for both mechanisms using which you can spin up a Cassandra cluster in a matter of minutes. You can watch the whole of &lt;a href="https://www.percona.com/resources/videos/cassandra-where-and-how-john-schulz-percona-live-online-2020" target="_blank" rel="noopener noreferrer"&gt;John Schulz’s Apache Cassandra talk&lt;/a&gt; through the link.&lt;/p&gt;</content:encoded>
      <author>Mayank Sharma</author>
      <category>Mayank Sharma</category>
      <category>Cassandra</category>
      <category>DBaaS</category>
      <category>DevOps</category>
      <category>Docker</category>
      <category>Events</category>
      <category>Open Source Databases</category>
      <category>Percona Live</category>
      <category>Tools</category>
      <media:thumbnail url="https://percona.community/blog/2020/06/PLO-Card-Cassandra_hu_7c6defe97179165d.jpg"/>
      <media:content url="https://percona.community/blog/2020/06/PLO-Card-Cassandra_hu_eb3f6bd7bb1747b9.jpg" medium="image"/>
    </item>
    <item>
      <title>Percona Live ONLINE Opening Keynote: State of Open Source Databases by Peter Zaitsev</title>
      <link>https://percona.community/blog/2020/06/15/percona-live-online-opening-keynote-state-of-open-source-databases-by-peter-zaitsev/</link>
      <guid>https://percona.community/blog/2020/06/15/percona-live-online-opening-keynote-state-of-open-source-databases-by-peter-zaitsev/</guid>
      <pubDate>Mon, 15 Jun 2020 15:44:28 UTC</pubDate>
      <description>Peter Zaitsev is CEO and co-founder of Percona. He opened Percona Live ONLINE with a keynote which took a look at the historical foundations of open source software and how they have shaped the field today.</description>
      <content:encoded>&lt;p&gt;Peter Zaitsev is CEO and co-founder of Percona. He opened &lt;a href="https://www.percona.com/live/conferences" target="_blank" rel="noopener noreferrer"&gt;Percona Live ONLINE&lt;/a&gt; with a keynote which took a look at the historical foundations of open source software and how they have shaped the field today.&lt;/p&gt;
&lt;h2 id="the-history-of-open-source-software"&gt;The history of open source software&lt;/h2&gt;
&lt;p&gt;In the early days of computing, software and hardware were bundled together. While the term open source wasn’t coined, software was open by default. According to Peter:  “One of the big reasons for that was copyrights on software was not a thing, because the software was not really a thing before that. Laws tend to move slower and only kind of catch up with technological development.”&lt;/p&gt;
&lt;p&gt;The source code for software was shipped with early hardware. Early adopters - typically from universities - would modify the code to fix bugs and add needed functionality, akin to the advanced open source users of today. The changes back then were openly shared under academic principles.&lt;/p&gt;
&lt;h2 id="enter-antitrust-in-the-1970s"&gt;Enter antitrust in the 1970s&lt;/h2&gt;
&lt;p&gt;In the late 1960s and the early 1970s, computing was growing into a significant industry, where IBM was controlling the vast majority of the mainframe market. This resulted in an antitrust lawsuit against IBM in the US, who as a response unbundled software from hardware.&lt;/p&gt;
&lt;p&gt;The Copyright Act was moved by Congress to make software copyrightable and created a separate software industry distinct from hardware. Software becomes the major class of intellectual property.&lt;/p&gt;
&lt;h2 id="the-1980s-and-1990s-the-era-of-romantic-open-source-and-free-software"&gt;The 1980s and 1990s: The Era of Romantic Open source (and free) software&lt;/h2&gt;
&lt;p&gt;After the development of copyright for software, new projects started that rejected applying copyright and restrictive licenses to their development. Peter asserted: “I would call that an era of romantic open source software. Right? Because a lot of software was started by hobbyists or as according to Linus Torvald ‘just for fun.’”&lt;/p&gt;
&lt;h2 id="the-2000s-a-dramatic-decade-for-oss"&gt;The 2000s: A dramatic decade for OSS&lt;/h2&gt;
&lt;p&gt;The 2000s was a dramatic decade for open source software, part in response to the .com crash. “A lot of companies needed ways to build their solutions very efficiently and Linux, Apache MySQL, a lot of other open source options allowed them to do just that,” said Peter.&lt;/p&gt;
&lt;p&gt;Prior to 2000, big OSS companies were limited to Red Hat which went through an IPO in the late 1990s. Enter the 2000s and Sun acquired MySQL for $1 billion, which was hugely significant to the OSS market. It was during this period that Steve Ballmer famously asserted, “Linux is a cancer that attaches itself in an intellectual property sense to everything it touches.”&lt;/p&gt;
&lt;p&gt;In the 2000s, many businesses started to recognize the value of open source software, and with an increasing number of large enterprises starting to adopt the open-source first mentality. This included adoption by governments “to help them avoid reliance on companies from other countries,” according to Peter.&lt;/p&gt;
&lt;p&gt;The use of open source software had a range of benefits for both companies and for developers as individuals. For enterprise customers, moving to open source resulted in lower direct costs both short term and long term. As for developers, using open source became the preference for many of them, as it was easier to experiment and get familiar with tools. Over time, it became easier to find developers that were proficient in open source technologies compared to proprietary software. This led to better productivity and faster innovation. Customers were also able to avoid the historical barrier of vendor lock-in.&lt;/p&gt;
&lt;p&gt;The decade then led to a new generation of open source companies being created. However, the fact that many of these were venture capital funded lead to the need for fast, high returns on those investments. Thus, many of these companies found they had the need to build a monopoly based on the pervasive message as to the advantages of open source while also increasing “stickiness” for their own businesses.&lt;/p&gt;
&lt;h2 id="romantic-vs-business-values-lead-to-not-quite-open-source"&gt;Romantic vs business values lead to ’not quite open source’&lt;/h2&gt;
&lt;p&gt;For Peter, the time of new open source companies is a new challenge. “If you really look at those approaches to business values, many are in conflict with the early stage of romantic open-source software, and the values and ideas about sharing and letting other people innovate on your software, because hey, that actually can create competition for you,” he explained.&lt;/p&gt;
&lt;p&gt;A lot of business models were evolving from open source to ’not quite open-source’. Some of those models would be open source eventually, such as shared source licenses and open-source compatible software, which is used by a lot of cloud vendors. Peter noted that vendors would spruik this by saying, “You can move from open source to our open-source compatible software. You probably would have a very hard time moving back, but we don’t talk about that.”&lt;/p&gt;
&lt;p&gt;On the positive side, the availability of funding meant there were a lot of investments and a high pace of innovation in the software around the open source community. On the negative side, the market became more complicated with the challenge to differentiate between open source software and ‘not quite open’ software that didn’t provide the same value of truly open source software.&lt;/p&gt;
&lt;h2 id="the-2010s-the-rise-of-the-cloud-unique-challenges-and-opportunities-for-oss"&gt;The 2010s: The rise of the cloud: unique challenges and opportunities for OSS&lt;/h2&gt;
&lt;p&gt;While AWS was started in the previous decade, the 2010s were critical for open source databases - specifically, around the cloud and open source. Peter asserted, “Cloud really hijacked the GPL license. Before the Software as a Service deployment model, software vendors who did not want others to build commercial software on their solutions could just use the GPL. Not anymore. Now, AWS probably makes more money on MySQL than Oracle does. And they can just use the GPL software and don’t have to pay Oracle anything.”&lt;/p&gt;
&lt;p&gt;Unlike the 1970s, cloud services are now bundling hardware usage costs with software. This meant open source software could no longer benefit from a zero price effect.&lt;/p&gt;
&lt;p&gt;This was important psychology, as Peter noted: “Previously I would have to buy a server separately. And then I have a choice, either I could go and pay thousands of dollars to license Oracle to run on that server, or I could go ahead and download Postgres and use it for free.  That is not the case anymore. It just becomes a case of a difference in the price which may not be very well understood.”&lt;/p&gt;
&lt;h2 id="market-acceptance-of-not-fully-open-source-software-models"&gt;Market acceptance of Not fully open source software models&lt;/h2&gt;
&lt;p&gt;Peter asserted that acceptance of not fully Open Source Software models is on the rise. “It’s very important for us as an open source database community to really educate folks in the market about the difference of an open source software offering and one which is marketed using an open source term but not providing the true values of open source software.”&lt;/p&gt;
&lt;h2 id="2020s-great-momentum-for-commercial-open-source"&gt;2020s: Great Momentum for Commercial Open Source&lt;/h2&gt;
&lt;p&gt;It’s a fantastic time for Commercial Open Source, with many companies getting billion dollar valuations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;RedHat - $24B (acquired by IBM)&lt;/li&gt;
&lt;li&gt;MongoDB - $11.2B (current valuation)&lt;/li&gt;
&lt;li&gt;GitHub - $7.5B (acquired by Microsoft)&lt;/li&gt;
&lt;li&gt;Databricks - $6.2B (current valuation)&lt;/li&gt;
&lt;li&gt;Elastic - $5.8B (current valuation)&lt;/li&gt;
&lt;li&gt;Hashicorp - $5B (current valuation)&lt;/li&gt;
&lt;li&gt;Confluent - $4.5B (current valuation)&lt;/li&gt;
&lt;li&gt;Cloudera - $2.5B  (current valuation)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Peter commented, “Because of the success of MongoDB, Elastic and some other open source companies, we see a lot of investment and a lot of innovation in the Open Source Database space.” This includes new technologies like Planet-Scale, InfluxDB, yugabyteDB, and others. It’s not limited to relational databases, it includes multimodal cloud, graph databases, and time series focused.&lt;/p&gt;
&lt;h2 id="covid-19-pandemic"&gt;COVID-19 Pandemic&lt;/h2&gt;
&lt;p&gt;The pandemic has led to an acceleration of digital transformation including service delivery online and digital education. This requires lower costs and/or cost-cutting due to the predicted economic slowdown. This can be another reason for open source success, as companies have to innovate and keep their costs down. These two desires will encourage companies to both consider open source, and to keep a close key on the cost for running those systems whether this is on existing hardware or in the cloud.&lt;/p&gt;
&lt;h2 id="dbaas"&gt;DBaaS&lt;/h2&gt;
&lt;p&gt;Today database as a service (DBaaS) is a preferred way to consume open source database software. According to Peter, “This allows the development team to use multiple database technologies more easily, matching them to application needs because they don’t really need to install and maintain them.”&lt;/p&gt;
&lt;p&gt;However, Peter did point to one problem around DBaaS that can affect the success of implementation for companies and for developer teams. For many use cases, DBaaS is commonly marketed by cloud vendors as ‘fully managed.’ “Because of that, we don’t have to get any DBAs or other database experts on the team. However this ‘fully managed’ approach still needs to be configured for security, somebody still needs to advise us on the schema, help us to design the queries, etc,” explained Peter.&lt;/p&gt;
&lt;p&gt;The rise of DBaaS has meant that developers can choose and use databases directly without the supervision of database professionals. This can cause various bad outcomes ranging from security leaks to very inefficient delivery of database services over time. For developers that assume their DBaaS provider will deliver more insights or advice, this can lead to wasted time and budget.&lt;/p&gt;
&lt;h2 id="dbaas-and-multiverse"&gt;DBaaS and Multiverse&lt;/h2&gt;
&lt;p&gt;Peter then provided an overview of the future as he sees it: “From an open source prism, you can think of the cloud as a commodity with many compatible implementations. Or think about highly differentiated clouds, where you have proprietary solutions available from a single vendor. The latter can be a huge vendor lock-in.  However, many are trying to avoid lock-in.”&lt;/p&gt;
&lt;p&gt;Thus, he said, we are increasingly seeing multiple database technologies: multiple environments, hybrid cloud, multi-cloud, Many proprietary solutions are available around cloud and hybrid environments, like Google Anthos, VMware and AWS Outposts.  Simultaneously Kubernetes also has emerged as the leading open source API for hybrid and public clouds.&lt;/p&gt;
&lt;p&gt;Kubernetes is ubiquitous. There are proprietary solutions to simplify Kubernetes management, and the Kubernetes interface is supported by Multi and Hybrid Cloud Platforms. The is relevant to open source databases and Peter believes we should be focusing on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Adapting Cloud Native deployments in Multi and Hybrid Cloud&lt;/li&gt;
&lt;li&gt;Kubernetes as the API of choice for Open Source database deployments&lt;/li&gt;
&lt;li&gt;Making things simple and comparable to integrated DBaaS Solutions&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;An important question to ask is: “If I am choosing DBaaS as my software consumption model, how do I get the most value from what Open Source Software provides?”&lt;/p&gt;
&lt;p&gt;According to Peter, Percona is embracing the cloud-native and multi-cloud approach through Kubernetes. Percona has released &lt;a href="https://www.percona.com/doc/kubernetes-operator-for-pxc/index.html" target="_blank" rel="noopener noreferrer"&gt;Kubernetes Operator for  XtraDB Cluster&lt;/a&gt; and &lt;a href="https://www.percona.com/doc/kubernetes-operator-for-psmongodb/index.html" target="_blank" rel="noopener noreferrer"&gt; Kubernetes Operator for Percona Server for MongoDB&lt;/a&gt;. “We are also working through &lt;a href="https://www.percona.com/software/database-tools/percona-monitoring-and-management" target="_blank" rel="noopener noreferrer"&gt;Percona Monitor and Management&lt;/a&gt; to really help you to reduce the friction and run the open source database successfully in those cloud environments and on-premises,” he said.&lt;/p&gt;
&lt;p&gt;Peter also advised attendees to take the time to fill out the &lt;a href="https://www.percona.com/blog/2020/03/31/share-your-database-market-insight-by-completing-perconas-annual-survey/" target="_blank" rel="noopener noreferrer"&gt;Open Source Data Management Survey&lt;/a&gt;. Peter closed the keynote with: “Finally, I want to say Happy 25th Birthday to MySQL. Great job, MySQL team!”&lt;/p&gt;
&lt;p&gt;You can also watch Peter’s &lt;a href="https://www.percona.com/resources/videos/state-open-source-database-plo2020" target="_blank" rel="noopener noreferrer"&gt;keynote&lt;/a&gt;.&lt;/p&gt;</content:encoded>
      <author>Cate Lawrence</author>
      <category>AWS</category>
      <category>DBaaS</category>
      <category>Kubernetes</category>
      <category>Kubernetes</category>
      <category>MariaDB</category>
      <category>MongoDB</category>
      <category>MongoDB</category>
      <category>MySQL</category>
      <category>MySQL</category>
      <category>mysql-and-variants</category>
      <category>Open Source Databases</category>
      <category>opensource</category>
      <category>Percona</category>
      <category>PostgreSQL</category>
      <category>Tools</category>
      <media:thumbnail url="https://percona.community/blog/2020/06/SC-3-Matt-Percona_hu_1395b6e2186771a6.jpg"/>
      <media:content url="https://percona.community/blog/2020/06/SC-3-Matt-Percona_hu_c0e4c47b55fa22a9.jpg" medium="image"/>
    </item>
    <item>
      <title>Matt Yonkovit: It's a crazy world, and these trends are disrupting and breaking your database infrastructure</title>
      <link>https://percona.community/blog/2020/06/12/matt-yonkovit-its-a-crazy-world-and-these-trends-are-disrupting-and-breaking-your-database-infrastructure/</link>
      <guid>https://percona.community/blog/2020/06/12/matt-yonkovit-its-a-crazy-world-and-these-trends-are-disrupting-and-breaking-your-database-infrastructure/</guid>
      <pubDate>Fri, 12 Jun 2020 15:30:28 UTC</pubDate>
      <description>Matt Yonkovit, Chief Experience Officer at Percona, presented a session at this year’s Percona Live ONLINE, sharing initial insights from the Open Source Data Management Survey 2020. The survey provides a critical insight first-hand into how enterprises of all sizes are using, developing, and troubleshooting open source database software. The full data will be released later this year with a detailed analysis.</description>
      <content:encoded>&lt;p&gt;Matt Yonkovit, Chief Experience Officer at Percona, presented a session at this year’s Percona Live ONLINE, sharing initial insights from the &lt;a href="https://www.percona.com/open-source-data-management-software-survey" target="_blank" rel="noopener noreferrer"&gt;Open Source Data Management Survey 2020.&lt;/a&gt; The survey provides a critical insight first-hand into how enterprises of all sizes are using, developing, and troubleshooting open source database software. The full data will be released later this year with a detailed analysis.&lt;/p&gt;
&lt;h2 id="he-who-controls-the-application-controls-the-stack"&gt;He who controls the application controls the stack&lt;/h2&gt;
&lt;p&gt;Matt started with discussing the challenge that developers face: “Those building it are not the ones managing it. And those who are building it are the ones deciding what to put in it.”&lt;/p&gt;
&lt;p&gt;Last year a survey asked Who gets to choose the database technology at companies? Most people choosing database technology are outside the database or the infrastructure side. More architects (32%) and developers (26%) are choosing the tech than management (17%) or DBAs (23%).&lt;/p&gt;
&lt;p&gt;However, the challenge is that the DBAs are inheriting technology from the development stack, and all of a sudden they have to support it. Matt said he likes to call this, “The technology inheritance problem: So now you’ve got a team of people who are not necessarily skilled at managing those technologies all of a sudden being responsible for new technologies.”&lt;/p&gt;
&lt;h2 id="the-multiverse-of-technology"&gt;The multiverse of technology&lt;/h2&gt;
&lt;p&gt;Enter the multiverse of technology: multi-database, multi-cloud, multi-location, multi-skilled. Matt explained this as follows:&lt;/p&gt;
&lt;p&gt;“Instead of saying we’re going to run on AWS and we’re going to consolidate on a single database or a set of databases, you’re running on multiple databases, you’re running in multiple locations, you’re running multi skilled people, because you’re no longer, you know, an expert Oracle DBA on its own. You’re a DBA of everything. And it’s leading to these multi-database environments.”&lt;/p&gt;
&lt;h2 id="the-database-footprint-is-growing"&gt;The database footprint is growing&lt;/h2&gt;
&lt;p&gt;In last year’s survey, more than 92% of companies were running more than one database, and 89% have more than one open source database in place. This year the number of companies that reported having between 100 and 1000 database instances in place grew by 40%. Those reporting over 1000 database instances grew by more than 50%. Matt noted:&lt;/p&gt;
&lt;p&gt;“Now we’ve got environments that have thousands of databases that have to be managed and supported, and that means that the care and feeding of each database is very difficult.”&lt;/p&gt;
&lt;p&gt;This is partly attributable to new technologies like machine learning and an insatiable need for more data to make better decisions. The footprints of databases continue to grow. Only 3.5% shrunk, whereas 14% stayed the same. And the vast majority, 80% saw growth, and almost 39% saw larger massive growth in the size of their environment.&lt;/p&gt;
&lt;h2 id="enter-the-multiverse"&gt;Enter the multiverse&lt;/h2&gt;
&lt;p&gt;The deluge of data and more databases leads to a multi-cloud space. In 2019, 30% reported that they were running a multi-cloud environment. In 2020 it’s 39%. Matt noted this by saying, “Some of the cloud providers are now taking notice. They’re investing in tools to let you run their platform across other competitors’ platforms. The growth also exists, albeit slower in the hybrid space: In 2019, 41% were hybrid, and in 2020 it’s 44%.&lt;/p&gt;
&lt;p&gt;So we’re seeing more databases, more data, more providers, more locations, more hybrid installations. And so, what are the consequences? “It means for a lot of us who have to work on these systems, we have less expertise in any one of them, because we don’t have the time to not only enhance our skills but to enhance the systems that we’re supporting and ensure that they’re properly managed and set up. We’ve less time per application, and we just have less time available,” continued Matt.&lt;/p&gt;
&lt;p&gt;This means more mistakes are happening, more automated cascading issues, more outages, more security issues, more complexity, more cost, and more help is needed.&lt;/p&gt;
&lt;h2 id="how-does-the-industry-respond"&gt;How does the industry respond?&lt;/h2&gt;
&lt;p&gt;Matt asserted: “There’s a pervasive debate between, ‘Do we need to automate? Or how much do we need to automate? How much do we not need people? How much do we need to focus on, the automation of things, and the AI versus bringing in experts?’ We are looking at DBaaS versus the need for DBAs, and we still need experts and people who know what they are doing.”&lt;/p&gt;
&lt;p&gt;“We need to ensure that we still have the tools and the skill set to address these problems as they occur correctly. Otherwise, we just make more problems.”&lt;/p&gt;
&lt;h2 id="dbaas"&gt;DBaaS&lt;/h2&gt;
&lt;p&gt;According to Matt: “Database as a service (DBaaS) is probably one of the best inventions that have happened in the last ten years to databases.” It enables developers to move quicker; it overcomes all kinds of skill gaps. However, it doesn’t eliminate the need for understanding and the tools to help. It helps, but it does not eliminate the need for DBAs and expertise.&lt;/p&gt;
&lt;h2 id="what-keeps-you-up-at-night"&gt;What keeps you up at night?&lt;/h2&gt;
&lt;p&gt;According to the respondents of this year’s survey, particular challenges keep developers up at night:&lt;/p&gt;
&lt;p&gt;The biggest is downtime (31%) followed by fixing some unforeseen issues (17%), security issues 15%). Bad performance and query issues are insomnia inducing for 13%, while staffing issues/a lack of resources challenge 9% of respondents.&lt;/p&gt;
&lt;h2 id="problems-happen-everywhere"&gt;Problems happen everywhere&lt;/h2&gt;
&lt;p&gt;The survey further found that problems happen everywhere, whether you’re in the cloud or not:&lt;/p&gt;
&lt;p&gt;62% in the cloud had performance issues, 54% non-cloud. Overworked staff increase by 10% when DBaaS is factored in, from 19% to 29%. According to Matt: “My speculation is when we move to a database service, we move those resources to do other things. And when database problems occur, they’ve got 17 other jobs to work on.”&lt;/p&gt;
&lt;h2 id="configuration-errors-a-significant-cause-of-data-breaches"&gt;Configuration errors a significant cause of data breaches&lt;/h2&gt;
&lt;p&gt;Outages and slowdowns persist in being a headline-grabbing problem. &lt;a href="https://www.cisomag.com/db8151dd-an-untraceable-data-breach-22-mn-emails-compromised/" target="_blank" rel="noopener noreferrer"&gt;News this week&lt;/a&gt; reported the hacking of an open Elasticsearch database containing around 22 million of email records. &lt;a href="https://enterprise.verizon.com/resources/reports/dbir/" target="_blank" rel="noopener noreferrer"&gt;Research&lt;/a&gt; by Verizon reveals that the fastest growing data breach cause is configuration errors.&lt;/p&gt;
&lt;h2 id="how-many-people-choose-to-scale-their-database-via-credit-card"&gt;How many people choose to scale their database via credit card?&lt;/h2&gt;
&lt;p&gt;From a spend perspective, survey respondents were asked: are you spending at plan, below plan, or above plan? About 24% were above plan. 33% of those using DBaaS and Cloud were above plan.&lt;/p&gt;
&lt;p&gt;Upon being asked, how often have you had to upgrade your database instances to something bigger the results are significant:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;0 times - 11%&lt;/li&gt;
&lt;li&gt;1-3 times 40.4%&lt;/li&gt;
&lt;li&gt;4-9 times 28.6%&lt;/li&gt;
&lt;li&gt;10+ times 19.5%&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Matt stated that he believes the following situation is more common than it should be: “Most of these can be avoided by fixing performance problems. If we don’t look for those performance issues, then we’re going to fix them by paying more. And that’s what a lot of people end up doing.”&lt;/p&gt;
&lt;h2 id="unexpected-costs"&gt;Unexpected costs&lt;/h2&gt;
&lt;p&gt;Several survey respondents have experienced unexpected costs, which have increased as the software complexity increases:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Non-public cloud users - 8% reported unexpected costs.&lt;/li&gt;
&lt;li&gt;Public cloud users - 10% reported unexpected costs&lt;/li&gt;
&lt;li&gt;Public cloud DBaaS - 19% said that their costs were unexpectedly higher&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;“We need better automation, and we need smarter tools, we need better education, better security, better performance, we need to make us all more efficient and be able to solve these problems that come up. It’s very, very important,” commented Matt.&lt;/p&gt;
&lt;h2 id="percona-monitoring-and-management"&gt;Percona Monitoring and Management&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.percona.com/software/database-tools/percona-monitoring-and-management" target="_blank" rel="noopener noreferrer"&gt;Percona Monitoring and Management&lt;/a&gt; is the company’s free and open source tool to simplify this with a single interface to reduce complexity. Matt shared this as background: “We want a simplified management system, where we can take that complexity and give you the ability to reduce the complexity with it.”&lt;/p&gt;
&lt;h2 id="matts-selfish-security-goal-and-a-simple-solution"&gt;Matt’s selfish security goal and a simple solution&lt;/h2&gt;
&lt;p&gt;When discussing databases and security, Matt provided a very personal goal for improving the current situation. He lamented, “I don’t need more credit monitoring in response to database breaching, I am good until the year 2082!”&lt;/p&gt;
&lt;p&gt;Matt has a simple solution: “I can solve more than 50% of the data breaches that exist now. And I can do it in one line of code: Set your password! db.changeUserPassword (username, password). It is the Change Password command for MongoDB. Mongo and Elastic are currently the two most breached databases. Most of those breaches are because nobody set a password!”&lt;/p&gt;
&lt;p&gt;Percona Monitoring and Management 2.6 includes the first version of Percona’s security threat tool:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;This provides checks for basic security problems and the most common issues, like missing passwords or not being at the latest version&lt;/li&gt;
&lt;li&gt;More checks will be added over the next several months&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="the-first-release-of-percona-distribution-for-mongodb"&gt;The first Release of &lt;a href="https://www.percona.com/software/mongodb" target="_blank" rel="noopener noreferrer"&gt;Percona Distribution for MongoDB:&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;On the first Distribution that Percona has released for MongoDB, Matt shared: “We take all the best of the open-source components and bundle it into one there. And we’re also now offering &lt;a href="https://www.percona.com/services/managed-services/percona-managed-database-services" target="_blank" rel="noopener noreferrer"&gt;managed services for MongoDB&lt;/a&gt;.”&lt;/p&gt;
&lt;p&gt;Percona also has a Distribution for PostgreSQL currently, with a Distribution for MySQL coming up. Matt also mentioned the world’s highest, most trusted high availability solution for MySQL in &lt;a href="https://www.percona.com/software/mysql-database/percona-xtradb-cluster" target="_blank" rel="noopener noreferrer"&gt;PerconaXtraDB Cluster&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Matt described Percona’s approach as looking to remove the problems for companies running multiple databases: “We take out all of those features and fixes and bundle it on top of MySQL Community to make it truly an enterprise-ready system.”&lt;/p&gt;
&lt;h2 id="helping-you-to-scale-and-simplify"&gt;Helping you to scale and simplify:&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.percona.com/software/mysql-database/percona-xtradb-cluster" target="_blank" rel="noopener noreferrer"&gt;XtraDB Cluster 8&lt;/a&gt; is faster and more scalable. There are new Kubernetes operators with easier management.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.percona.com/software/postgresql-distribution" target="_blank" rel="noopener noreferrer"&gt;Percona Distribution for PostgreSQL&lt;/a&gt; has launched with more performance enhancements to come.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="percona-and-linode-partnership"&gt;Percona and Linode Partnership&lt;/h2&gt;
&lt;p&gt;At the end of the session Matt went through how Percona is partnering with Linode to help bring Linode’s customers an enhanced DBaaS. The community benefits from better operations, better tools, and enhancements that will show up in our distributions.&lt;/p&gt;
&lt;p&gt;Blair Lyon, VP of Marketing at Linode joined the session to share how he sees this developing:&lt;/p&gt;
&lt;p&gt;“Since 2003, Linode has been helping our clients accelerate innovation by making cloud computing simple, affordable, and accessible for all. We’re leading a growing category of alternative cloud providers with nearly a million worldwide customers and 11 global data centers. And the key to being a true alternative to the big guys is providing the best of breed enterprise solutions and DBaaS is no exception.”&lt;/p&gt;
&lt;p&gt;Finally, Matt encouraged all attendees to the Percona Live event to provide their insight as part of 2020’s Open Source Data Management research report. If you have not filled out the &lt;a href="https://www.percona.com/blog/2020/03/31/share-your-database-market-insight-by-completing-perconas-annual-survey/" target="_blank" rel="noopener noreferrer"&gt;Open Source Data Management Survey&lt;/a&gt; then you can do so. Watch Matt’s &lt;a href="https://www.percona.com/resources/videos/trends-are-disrupting-and-breaking-your-db-infrastructure-matt-yonkovit-percona" target="_blank" rel="noopener noreferrer"&gt;keynote&lt;/a&gt;.&lt;/p&gt;</content:encoded>
      <author>Cate Lawrence</author>
      <category>Cloud</category>
      <category>DBA Tools</category>
      <category>DBaaS</category>
      <category>Kubernetes</category>
      <category>Kubernetes</category>
      <category>MongoDB</category>
      <category>MongoDB</category>
      <category>MySQL</category>
      <category>MySQL</category>
      <category>mysql-and-variants</category>
      <category>Open Source Databases</category>
      <category>Percona Monitoring and Management</category>
      <category>PMM</category>
      <category>Postgres</category>
      <category>PostgreSQL</category>
      <category>Tools</category>
      <media:thumbnail url="https://percona.community/blog/2020/06/PLO-Card-Matt_hu_b48ba47ad5468a2d.jpg"/>
      <media:content url="https://percona.community/blog/2020/06/PLO-Card-Matt_hu_b4dc25bdfce8547c.jpg" medium="image"/>
    </item>
    <item>
      <title>Percona Live ONLINE: MySQL on Google Cloud: War and Peace! by Akshay Suryawanshi &amp; Jeremy Cole</title>
      <link>https://percona.community/blog/2020/06/02/percona-live-online-mysql-on-google-cloud-war-and-peace-by-akshay-suryawanshi-jeremy-cole/</link>
      <guid>https://percona.community/blog/2020/06/02/percona-live-online-mysql-on-google-cloud-war-and-peace-by-akshay-suryawanshi-jeremy-cole/</guid>
      <pubDate>Tue, 02 Jun 2020 16:12:51 UTC</pubDate>
      <description>This session at Percona Live ONLINE was presented by Akshay Suryawanshi, Senior Production Engineer at Shopify, and Jeremy Cole, Senior Staff Production Engineer - Datastores at Shopify. Shopify is an online and on-premise commerce platform, founded in 2006.</description>
      <content:encoded>&lt;p&gt;This session at &lt;a href="https://www.percona.com/live/conferences" target="_blank" rel="noopener noreferrer"&gt;Percona Live ONLINE&lt;/a&gt; was presented by Akshay Suryawanshi, Senior Production Engineer at Shopify, and Jeremy Cole, Senior Staff Production Engineer - Datastores at Shopify. Shopify is an online and on-premise commerce platform, founded in 2006.&lt;/p&gt;
&lt;p&gt;Shopify is used by more than a million merchants, and hundreds of billions of dollars of sales have happened on the platform since its inception. The company is a large user of MySQL, and the Black Friday and Cyber Monday weekends are their peak dates during the year, handling hundreds of billions of queries with MySQL. This year’s presentation was an opportunity to talk about the company’s challenges and progress over the last twelve months.&lt;/p&gt;
&lt;h2 id="key-google-cloud-concepts-from-the-presentation"&gt;Key Google Cloud concepts from the presentation&lt;/h2&gt;
&lt;p&gt;As part of the presentation, it’s important to understand the naming conventions that exist around Google Cloud:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Regions - a geographic region where cloud operates (these could include a building or adjoining buildings)&lt;/li&gt;
&lt;li&gt;Zones - a subdivision inside particular regions. Typically there are three within each region, but it varies a bit by region.&lt;/li&gt;
&lt;li&gt;GCE - Google Compute Engine platform, the system provides virtual machines to run as servers (most of Shopify’s microscale infrastructure is on GCP and runs in VMs).&lt;/li&gt;
&lt;li&gt;Virtual machine instance - A GC virtual machine scheduled in a particular zone&lt;/li&gt;
&lt;li&gt;Persistent disk - A network-attached log-structured block storage zone&lt;/li&gt;
&lt;li&gt;GKE - Google’s Kubernetes Engine, a managed Kubernetes solution that is managed on top of Google Cloud Platform (GPC) and managed within Google Cloud.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="peacetime-stories"&gt;Peacetime stories&lt;/h2&gt;
&lt;p&gt;Akshay spoke about Persistent disks, which are Network-Attached, distributed log-structure, block storage: “This is the place where you basically say most of your data is, especially when you’re running MySQL data or any sort of databases.” Except for their performance, (which is usually affected by some degree of latency for network-attached storage) they provide incredible features, especially fast snapshotting of volumes.&lt;/p&gt;
&lt;p&gt;“We have utilized the snapshotting behavior to revamp our Backup and Restore infrastructure and brought down our recovery time to less than one hour for even a multi-terabyte disk. This is so incredibly fast that we actually restore each and every snapshot that we preserve or retain as a backup every single day. It’s happening in both regions where we run most of our MySQL fleet,” detailed Akshay.&lt;/p&gt;
&lt;h2 id="configurable-vms"&gt;Configurable VMs&lt;/h2&gt;
&lt;p&gt;Virtual machines (VMs) expose an extensive API which is useful to do things programmatically with: “The API is very helpful. It is well documented, and we are using it in a bunch of places,” continued Akshay.&lt;/p&gt;
&lt;p&gt;Scaling VMs up and down are seamless operations (of course, most of them require a restart) and manageable. Provisioning new VMs in an appropriate region is very easy, according to Akshay: “Again because of the extensive API, which has provided something required to build resiliency against its own failures. So we spread our VMs across multiple zones. That helps us tremendously when a particular zone goes down. All of this has allowed us to build self-healing tooling to automatically replace failed VMs easily.”&lt;/p&gt;
&lt;h2 id="gcp-is-truly-multi-regional"&gt;GCP is truly multi-regional&lt;/h2&gt;
&lt;p&gt;Google Cloud’s multi-region availability means failover from one region to another is easy and Shopify can move all its traffic from one region to another in just a few minutes, multiple times in a day. They can also expand to a distant geographical region without a lot of work, yet maintain the same stability.&lt;/p&gt;
&lt;p&gt;Akshay noted: “Isolating PII data has been a big win for Shopify in the past year when we launched a certain product where PII data needed to be preserved in a particular region, and GCP provides excellent support for that.”&lt;/p&gt;
&lt;h2 id="google-kubernetes-engine"&gt;Google Kubernetes Engine&lt;/h2&gt;
&lt;p&gt;Kubernetes is an open-source project for container orchestration and Google Kubernetes Engine (GKE) is a feature-rich tool for using and running Kubernetes. According to Akshay: “Most of our future work is happening towards containers writing MySQL and running and scheduling them inside companies. The automatic storage and file system expansion are helpful in solving database problems.”&lt;/p&gt;
&lt;p&gt;Zone aware cluster node scheduling helps schedule the Kubernetes pods so that they are fault-tolerant towards zone failures.&lt;/p&gt;
&lt;p&gt;The GCP networking is simple to set up. Inter-regional latencies are pretty low, and Shopify can perform region failovers for databases quickly in the event of a disaster. “We can do a whole region, evac within a few minutes. This is because we can keep our databases in both regions up to date due to these low latencies,” explained Akshay.&lt;/p&gt;
&lt;p&gt;Virtual private clouds (VPCs) are a great way to segment the workloads. Isolating the networking connection at VPC level has helped this achievement.&lt;/p&gt;
&lt;h2 id="war-some-of-the-things-that-can-go-wrong"&gt;War: Some of the things that can go wrong&lt;/h2&gt;
&lt;p&gt;Jeremy detailed some of the specific challenges that Shopify had faced over the last year, including stock outs which are when a resource requested (such as a VM or a disk) is not available at that time.&lt;/p&gt;
&lt;p&gt;Jeremy noted: “What that looks like is that you attempt to allocate it using some API, and it just takes a very long time to show up. In one particular instance, in one region, we had consistent PD and VM stockouts regularly occurring for several weeks.”&lt;/p&gt;
&lt;p&gt;It meant that the company had to adapt for when resources were not available at a moment’s notice, and to consider where time-critical components had to be resourced for availability.&lt;/p&gt;
&lt;h2 id="trouble-in-persistent-disk-land"&gt;Trouble in persistent disk land&lt;/h2&gt;
&lt;p&gt;According to Jeremy: “One of the bigger problems that we’ve had in general is a persistent disk (PD).” An example was a recent outage caused by a change in persistent disks backend, which caused a regression “anywhere from minor latency impacts to full stalls for several seconds of the underlying PD volume, which of course, pretends to be a disk. So that means the disk is fully stalled for several seconds.”&lt;/p&gt;
&lt;p&gt;It took several weeks to diagnose and pin the blame of the stalls on PD properly. Jeremy noted, “The fun part of the story is that the mitigation for this particular problem involves attaching a substantial PD volume to every one of our VMs to work around a problem that was happening in PD. In order to do that, since we had so many VMs in aggregate, we had to allocate petabytes of persistent disk, and leave them attached for a few months.”&lt;/p&gt;
&lt;p&gt;Crucial to solving the problem was working closely with their vendor partner. As Jeremy explained, “Sometimes you have to get pretty creative to make things work right now and get yourself back in action.&lt;/p&gt;
&lt;h2 id="troop-replacements"&gt;Troop replacements&lt;/h2&gt;
&lt;p&gt;Live migration (LM) was referred to in the previous year’s Shopify presentation at Percona Live, and the problem still persists according to Jeremy. “We continuously have machines being live migrated and their VMs being moved around between different physical machines.”&lt;/p&gt;
&lt;p&gt;The frequency of LM problems occurring and the number of times it causes this problem is directly related to the frequency of Linux kernel or Intel CDEs. “We’re still getting hostError instance failures where migrations fail and this kills the host,” explained Jeremy.&lt;/p&gt;
&lt;p&gt;Some live migrations are still breaking in NTP time sync. “And we are still periodically getting multiple migrations per VM for the same maintenance - up to 11 within a day or so.”&lt;/p&gt;
&lt;h2 id="a-regional-ally-surrenders"&gt;A regional ally surrenders&lt;/h2&gt;
&lt;p&gt;In the last year, there was a regional outage: “Google had made a change to their traffic routing in one region, causing basically an overload of their networking stack. And we went down pretty hard because of that. There was nothing really that we could do about it,” said Jeremy. This was despite being deployed across multiple zones and multiple regions.&lt;/p&gt;
&lt;p&gt;Jeremy concluded the talk with a simple statement: Running MySQL in the cloud is not magic. “There are some unique challenges to Google Cloud, unique challenges to running MySQL in cloud infrastructure and unique challenges with the cloud itself. Sometimes running databases in the cloud can feel like you are constantly at war.”&lt;/p&gt;
&lt;p&gt;Preparing in advance as much as possible around how you manage your database in the cloud can help, particularly when you run at the kind of scale that Shopify does. However there will always be unexpected events and incidents. Working with your cloud partner and support providers can help here too.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;You can &lt;a href="https://www.percona.com/resources/videos/mysql-google-cloud-war-and-peace-akshay-suryawanshi-jeremy-cole-percona-live-online" target="_blank" rel="noopener noreferrer"&gt;watch a video of the recording&lt;/a&gt; which includes a Q&amp;A at the end of the presentation.&lt;/em&gt;&lt;/p&gt;</content:encoded>
      <author>Cate Lawrence</author>
      <category>DevOps</category>
      <category>Google</category>
      <category>Kubernetes</category>
      <category>Kubernetes</category>
      <category>MySQL</category>
      <category>MySQL</category>
      <category>mysql-and-variants</category>
      <category>Open Source Databases</category>
      <category>Shopify</category>
      <media:thumbnail url="https://percona.community/blog/2020/06/SC-3-Matt-Percona_hu_1395b6e2186771a6.jpg"/>
      <media:content url="https://percona.community/blog/2020/06/SC-3-Matt-Percona_hu_c0e4c47b55fa22a9.jpg" medium="image"/>
    </item>
    <item>
      <title>Percona Live ONLINE Talk: Enhancing MySQL security at LinkedIn by Karthik Appigatla</title>
      <link>https://percona.community/blog/2020/06/01/percona-live-online-talk-enhancing-mysql-security-at-linkedin-by-karthik-appigatla/</link>
      <guid>https://percona.community/blog/2020/06/01/percona-live-online-talk-enhancing-mysql-security-at-linkedin-by-karthik-appigatla/</guid>
      <pubDate>Mon, 01 Jun 2020 08:01:24 UTC</pubDate>
      <description>MySQL, arguably the most popular relational database, is used pretty extensively at the popular professional social network LinkedIn. At Percona Live ONLINE 2020, the company’s flagship event held online for the first time due to the Covid-19 pandemic, Karthik Appigatla from LinkedIN’s database SRE team discussed the company’s approach to securing their database deployment without introducing operational hiccups or adversely affecting performance.</description>
      <content:encoded>&lt;p&gt;MySQL, arguably the most popular relational database, is used pretty extensively at the popular professional social network LinkedIn. At Percona Live ONLINE 2020, the company’s flagship event held online for the first time due to the Covid-19 pandemic, Karthik Appigatla from LinkedIN’s database SRE team discussed the company’s approach to securing their database deployment without introducing operational hiccups or adversely affecting performance.&lt;/p&gt;
&lt;p&gt;Instead of just performing admin duties, Karthik’s team builds automated tools to scale their infrastructure, and he talked about some of these tailored tools in his presentation. The database SREs on his team also work with the developers at LinkedIn and help them streamline their applications to make best use of the database.&lt;/p&gt;
&lt;p&gt;Talking about LinkedIn’s reliance on MySQL, Karthik said that not only do all their infrastructural tools rely on MySQL, many of the internal applications use MySQL as their backend datastore, and so do a few of the website facing applications as well.&lt;/p&gt;
&lt;h2 id="database-proliferation"&gt;Database proliferation&lt;/h2&gt;
&lt;p&gt;The magnitude of the MySQL deployment at LinkedIn is pretty impressive. Thanks to the sheer number of microservices, each of which gets its own database, Karthik’s team looks after more than 2300 databases. These are powered by different versions of the MySQL server, namely v5.6, v5.7 and v8.0, all of which are hosted atop RHEL 7 installations.&lt;/p&gt;
&lt;p&gt;As he ran through the layout of the MySQL deployments at LinkedIn, Karthik mentioned that they have a multi-tenant architecture where multiple databases are hosted on a single MySQL server instance.&lt;/p&gt;
&lt;p&gt;MySQL is consumed as-a-service at LinkedIn and all the administrative tasks like backups, bootstrapping clusters, monitoring, and such are handled by automated systems built by Karthik’s team. He said that the level of automation is so high in fact that application owners can actually provision a database for their applications with just a few mouse clicks.&lt;/p&gt;
&lt;h2 id="shared-responsibility"&gt;Shared responsibility&lt;/h2&gt;
&lt;p&gt;Given their scale of deployment, the developers at LinkedIn give special credence to the security of their databases. Karthik believes “security is a shared responsibility between the database SRE team and the application owners.”&lt;/p&gt;
&lt;p&gt;He illustrated how the databases are provisioned, from a security point of view and gave several security insights in his presentation based on his experience. For one, his team doesn’t take the easy approach of isolating databases by running multiple mysqld processes. This approach doesn’t scale well since the overhead on the server increases linearly as the number of databases it hosts increases.&lt;/p&gt;
&lt;p&gt;His description of how the various applications access different databases on the different servers was also pretty insightful for anyone looking to deploy databases at scale. One of the peculiar issues he described is that various components inside individual applications usually need to access different databases simultaneously. His team handled this by employing multiple user accounts with varying privileges.&lt;/p&gt;
&lt;h2 id="access-control"&gt;Access control&lt;/h2&gt;
&lt;p&gt;He dwelled on this some more and spent some time explaining the different access management controls they’ve built into the system to facilitate access. One of the interesting security measures he talked about is how they limit the number of hosts that can access a database by adopting an IP-based grants system, which is slightly cumbersome to implement but a lot more secure.&lt;/p&gt;
&lt;p&gt;Also interesting is their approach to granting SSH access to the database servers to the SREs. Instead of the default public-key authentication, his team uses a certificate-based authentication scheme, and Karthik presented a high-level overview of this arrangement.&lt;/p&gt;
&lt;p&gt;Auditing and monitoring are also important aspects of security. At LinkedIn, the logins are audited by the &lt;a href="https://www.percona.com/doc/percona-server/LATEST/management/audit_log_plugin.html%E2%80%9D" target="_blank" rel="noopener noreferrer"&gt;Percona Audit Log plugin&lt;/a&gt;, while the queries go through LinkedIN’s home-brewed Query Analyser agent. Karthik ran through the architecture of their Query Analyser agent, which LinkedIn plans to release under an open source license soon.&lt;/p&gt;
&lt;p&gt;Perhaps one of the biggest takeaways from the presentation was Karthik’s insight into the operational challenges that crop up due to their rather stringent security requirements, particularly their IP-based grants system. While the solutions he discussed were specific to LinkedIn, his presentation was peppered with tips and tricks that you can easily adapt for your deployments.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.percona.com/resources/videos/enhancing-mysql-security-linkedin-karthik-appigatla-percona-live-online-2020" target="_blank" rel="noopener noreferrer"&gt;Click here to watch&lt;/a&gt; Karthik’s presentation at Percona Live ONLINE 2020.&lt;/p&gt;</content:encoded>
      <author>Mayank Sharma</author>
      <category>Mayank Sharma</category>
      <category>MySQL</category>
      <category>mysql-and-variants</category>
      <category>Open Source Databases</category>
      <category>security</category>
      <category>SRE</category>
      <category>Tools</category>
      <media:thumbnail url="https://percona.community/blog/2020/06/SC-3-Matt-Percona_hu_1395b6e2186771a6.jpg"/>
      <media:content url="https://percona.community/blog/2020/06/SC-3-Matt-Percona_hu_c0e4c47b55fa22a9.jpg" medium="image"/>
    </item>
    <item>
      <title>Join ProxySQL Tech Talks with Percona on June 4th, 2020!</title>
      <link>https://percona.community/blog/2020/05/29/join-proxysql-tech-talks-with-percona-on-june-4th-2020/</link>
      <guid>https://percona.community/blog/2020/05/29/join-proxysql-tech-talks-with-percona-on-june-4th-2020/</guid>
      <pubDate>Fri, 29 May 2020 09:16:07 UTC</pubDate>
      <description>Long months of the pandemic lockdown have brought to life many great online events enabling the MySQL community to get together and stay informed about the very recent developments and innovations available to MySQL users. It isn’t over yet! Next Thursday, June 4th, Percona &amp; ProxySQL are co-hosting the ProxySQL Tech Talks with Percona virtual meetup covering ProxySQL, MySQL and Percona XtraDB Cluster.</description>
      <content:encoded>&lt;p&gt;Long months of the pandemic lockdown have brought to life many great online events enabling the MySQL community to get together and stay informed about the very recent developments and innovations available to MySQL users. It isn’t over yet! Next &lt;strong&gt;Thursday, June 4th&lt;/strong&gt;, Percona &amp; ProxySQL are co-hosting the &lt;a href="https://bit.ly/2THdDqv" target="_blank" rel="noopener noreferrer"&gt;&lt;strong&gt;ProxySQL Tech Talks with Percona&lt;/strong&gt;&lt;/a&gt; virtual meetup covering ProxySQL, MySQL and Percona XtraDB Cluster.&lt;/p&gt;
&lt;p&gt;The attendees are invited to participate in the &lt;a href="https://bit.ly/2THdDqv" target="_blank" rel="noopener noreferrer"&gt;two-hour deep-dive event&lt;/a&gt; with plenty of time for questions and answers (we will have two 40-minute sessions + 20 minutes allocated for Q&amp;A). Get prepared, come with your burning questions and true war stories - we’ll have our speakers answer and comment on them! And here come the speakers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;René Cannaò&lt;/strong&gt;, ProxySQL author and CEO of ProxySQL Inc.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Vinicius M. Grippa&lt;/strong&gt;, Senior Support Engineer at Percona.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;René and Vinicius will give presentations covering the evolution of ProxySQL and ProxySQL’s native support for PXC 5.7 respectively:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ProxySQL, the journey from a MySQL proxy to being the de-facto multi-functional tool that scales MySQL&lt;/strong&gt; by René Cannaò starts at &lt;strong&gt;7 PM CEST&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ProxySQL 2.0 native support for Percona XtraDB Cluster (PXC) 5.7&lt;/strong&gt; by Vinicius Grippa starts at &lt;strong&gt;8 PM CEST&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The detailed abstracts, full agenda, and speaker bios are available on &lt;a href="https://bit.ly/2THdDqv" target="_blank" rel="noopener noreferrer"&gt;the event’s registration page&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The list of technologies &amp; tools covered at this event will include&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ProxySQL&lt;/li&gt;
&lt;li&gt;MySQL&lt;/li&gt;
&lt;li&gt;Percona XtraDB Cluster (PXC)&lt;/li&gt;
&lt;li&gt;Kubernetes (K8s)&lt;/li&gt;
&lt;li&gt; Percona Monitoring &amp; Management (PMM)&lt;/li&gt;
&lt;li&gt;AWS Aurora&lt;/li&gt;
&lt;li&gt;LDAP&lt;/li&gt;
&lt;li&gt;Galera Cluster&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Our virtual room has already started to fill up, please register now to &lt;a href="https://bit.ly/2THdDqv" target="_blank" rel="noopener noreferrer"&gt;join us at ProxySQL Tech Talks with Percona&lt;/a&gt; next Thursday at 7 PM CST! Hope to see many of you there!&lt;/p&gt;</content:encoded>
      <author>Stacy Rostova</author>
      <category>stacy</category>
      <category>Containers</category>
      <category>database</category>
      <category>DBA Tools</category>
      <category>Kubernetes</category>
      <category>MySQL</category>
      <category>MySQL</category>
      <category>mysql-and-variants</category>
      <category>Open Source Databases</category>
      <category>Percona XtraDB Cluster</category>
      <category>ProxySQL</category>
      <category>PXC</category>
      <category>tools</category>
      <category>Tools</category>
      <media:thumbnail url="https://percona.community/blog/2020/05/2160x1080-cover-Proxy-Percona-3_hu_b621f13821783f82.jpg"/>
      <media:content url="https://percona.community/blog/2020/05/2160x1080-cover-Proxy-Percona-3_hu_4dde3d5c75fdbccc.jpg" medium="image"/>
    </item>
    <item>
      <title>Anti-Cheating Tool for Massive Multiplayer Games Using Amazon Aurora and Amazon ML Services – Percona Live ONLINE Talk Preview</title>
      <link>https://percona.community/blog/2020/05/13/anti-cheating-tool-for-massive-multiplayer-games-using-amazon-aurora-and-amazon-ml-services-percona-live-online-talk-preview/</link>
      <guid>https://percona.community/blog/2020/05/13/anti-cheating-tool-for-massive-multiplayer-games-using-amazon-aurora-and-amazon-ml-services-percona-live-online-talk-preview/</guid>
      <pubDate>Wed, 13 May 2020 16:06:06 UTC</pubDate>
      <description>Percona Live Online Agenda Slot: Tue 19 May • New York 4 p.m. • London 9 p.m. • New Delhi 1:30 a.m. (Wed) Level: Intermediate</description>
      <content:encoded>&lt;p&gt;&lt;em&gt;&lt;a href="https://www.percona.com/live/conferences" target="_blank" rel="noopener noreferrer"&gt;Percona Live Online&lt;/a&gt; Agenda Slot: Tue 19 May • New York 4 p.m. • London 9 p.m. • New Delhi 1:30 a.m. (Wed)&lt;/em&gt; &lt;em&gt;Level:  Intermediate&lt;/em&gt;&lt;/p&gt;
&lt;h3 id="abstract"&gt;Abstract&lt;/h3&gt;
&lt;p&gt;Multiplayer video games are among the most lucrative online services. The overall games industry worldwide generated an estimated $174B in 2019, according to IDC. With this popularity, cheating becomes a common trend. Cheating in multiplayer games negatively impacts the game experience for players who play by the rules, and it becomes a revenue issue for game developers and publishers. According to Irdeto, 60% of online games were negatively impacted by cheaters, and 77% of players said they would stop playing a multiplayer game if they think opponents are cheating.&lt;/p&gt;
&lt;p&gt;Current methods for detecting and addressing cheating become difficult and expensive to operate as cheaters respond to the evolution of anti-cheating techniques. This session will show an effective method for game developers to continuously and dynamically improve their cheat-detection mechanisms. It uses Amazon Aurora and Amazon SageMaker for cheating detection, but can be adapted to other databases with similar capabilities. We’ll utilize the recently-launched Aurora machine learning functionality, which allows game developers to add ML-based predictions using the familiar SQL programming language without building custom integrations or learning separate tools. We’ll show which ML algorithms are useful for cheat detection and how an anti-cheat developer can write a single SQL query that handles the inputs and outputs for the algorithm.&lt;/p&gt;
&lt;h3 id="why-is-your-talk-exciting"&gt;Why is your talk exciting?&lt;/h3&gt;
&lt;p&gt;Machine learning is everywhere these days, or at least that’s how it feels when you work at Amazon. Some types of ML get a lot of attention, like self-driving cars, or services that take a JPEG and tell you if it’s a dog or a cat. But if you think about it, a vast amount of the world’s information is plain old tabular data in traditional relational databases. What about running ML on that data? Who knows what amazing insights and secrets are lurking inside?&lt;/p&gt;
&lt;p&gt;We’ll look at a cool video game example where we’re looking for cheaters, e.g. people who write bots to play on their behalf. We’ll show which ML models can detect these cheats and how to more easily run the analysis from your application, using tools that we’ve built. You should be able to run it on other databases if they have similar ML capabilities.&lt;/p&gt;
&lt;h3 id="who-would-benefit-the-most-from-your-talk"&gt;Who would benefit the most from your talk?&lt;/h3&gt;
&lt;p&gt;Application developers and database administrators who don’t know a whole lot about machine learning but would like to start.&lt;/p&gt;
&lt;h3 id="what-other-presentations-are-you-most-looking-forward-to"&gt;What other presentations are you most looking forward to?&lt;/h3&gt;
&lt;p&gt;We’re curious what a complete online event will be like.  We’re looking forward to see how it compares to the traditional kind of conference.&lt;/p&gt;</content:encoded>
      <author>Yoav Eilat</author>
      <author>Yahav Biran</author>
      <category>yoav.eilat</category>
      <category>yahav.biran</category>
      <category>AWS</category>
      <category>Events</category>
      <media:thumbnail url="https://percona.community/blog/2020/05/Social-PL-Online-2020-1_hu_5f15f9d3f957c60b.jpg"/>
      <media:content url="https://percona.community/blog/2020/05/Social-PL-Online-2020-1_hu_6e248db3cecf756e.jpg" medium="image"/>
    </item>
    <item>
      <title>State of the Dolphin – Percona Live ONLINE Talk Preview</title>
      <link>https://percona.community/blog/2020/05/12/state-of-the-dolphin-percona-live-online-talk-preview/</link>
      <guid>https://percona.community/blog/2020/05/12/state-of-the-dolphin-percona-live-online-talk-preview/</guid>
      <pubDate>Tue, 12 May 2020 16:30:04 UTC</pubDate>
      <description>Percona Live Online Agenda Slot: Tue 19 May • New York 11:00 a.m. • London 4:00 p.m. • New Delhi 8:30 p.m.</description>
      <content:encoded>&lt;p&gt;&lt;em&gt;&lt;a href="https://www.percona.com/live/conferences" target="_blank" rel="noopener noreferrer"&gt;Percona Live Online&lt;/a&gt; Agenda Slot: Tue 19 May • New York 11:00 a.m. • London 4:00 p.m. • New Delhi 8:30 p.m.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id="abstract"&gt;Abstract&lt;/h3&gt;
&lt;p&gt;I will talk about the latest improvements in MySQL 8.0.20 and the MySQL Engineering Team’s steady progress with MySQL 8.0. These include solutions like Document Store, InnoDB Cluster, and InnoDB ReplicaSet where MySQL Router and MySQL Shell are playing an important role. All of these Oracle solutions are completely open source.&lt;/p&gt;
&lt;h3 id="why-is-your-talk-exciting"&gt;Why is your talk exciting?&lt;/h3&gt;
&lt;p&gt;This talk is exciting because we will be looking at all the latest features in MySQL 8.0 Sadly my time will be probably too short to detail them all and cover the open source code contributions we’ve received from users.&lt;/p&gt;
&lt;h3 id="who-would-benefit-the-most-from-your-talk"&gt;Who would benefit the most from your talk?&lt;/h3&gt;
&lt;p&gt;All MySQL users would benefit, whether newbies or veterans. You would be surprised how many people still have wrong assumptions about MySQL! So this talk is really for anyone seeking a fuller experience with MySQL, whether DBAs, developers, or others.&lt;/p&gt;
&lt;h3 id="what-other-presentations-are-you-most-looking-forward-to"&gt;What other presentations are you most looking forward to?&lt;/h3&gt;
&lt;p&gt;I’m always very happy to learn new things about Vitess from Morgan Tocker and ProxySQL from René Cannaò.&lt;/p&gt;</content:encoded>
      <author>Frédéric Descamps</author>
      <category>frederic.descamps</category>
      <category>Events</category>
      <category>MySQL</category>
      <media:thumbnail url="https://percona.community/blog/2020/05/Social-PL-Online-2020-1_hu_5f15f9d3f957c60b.jpg"/>
      <media:content url="https://percona.community/blog/2020/05/Social-PL-Online-2020-1_hu_6e248db3cecf756e.jpg" medium="image"/>
    </item>
    <item>
      <title>Kubernetes, The Swiss Army Knife For Your ProxySQL Deployments – Percona Live ONLINE Talk Preview</title>
      <link>https://percona.community/blog/2020/05/08/kubernetes-the-swiss-army-knife-for-your-proxysql-deployments-percona-live-online-talk-preview/</link>
      <guid>https://percona.community/blog/2020/05/08/kubernetes-the-swiss-army-knife-for-your-proxysql-deployments-percona-live-online-talk-preview/</guid>
      <pubDate>Fri, 08 May 2020 02:02:48 UTC</pubDate>
      <description>Percona Live Online Agenda Slot: Tue 19 May • New York 10:00 p.m. • London 3:00 a.m. (Wed) • New Delhi 7:30 a.m. (Wed)</description>
      <content:encoded>&lt;p&gt;&lt;em&gt;Percona Live Online Agenda Slot: Tue 19 May • New York 10:00 p.m. • London 3:00 a.m. (Wed) • New Delhi 7:30 a.m. (Wed)&lt;/em&gt;&lt;/p&gt;
&lt;h3 id="abstract"&gt;Abstract&lt;/h3&gt;
&lt;p&gt;ProxySQL is a high performance proxy from design to implementation. It speaks the MySQL protocol, and can go beyond load balancing. This talk covers various deployment options for ProxySQL in a Kubernetes environment.&lt;/p&gt;
&lt;p&gt;Typically ProxySQL is deployed in one of three ways depending on the scale and needs of your environment:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Directly on each application server&lt;/li&gt;
&lt;li&gt;On a separate server (or layer)&lt;/li&gt;
&lt;li&gt;Cascaded, i.e. on each application server as well as a separate server (or layer)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This talk will cover how to successfully implement each of these ProxySQL deployment methods in Kubernetes using a highly scalable and robust approach.&lt;/p&gt;
&lt;h3 id="why-is-your-talk-exciting"&gt;Why is your talk exciting?&lt;/h3&gt;
&lt;p&gt;This was originally meant to be a tutorial, but it is now a talk, so it is not 3 hours cut into one, but tailored to whet your appetites for what is possible with ProxySQL on Kubernetes, which is an important topic in the community. I will share practical examples of deployment methods that have been implemented successfully in collaboration with large scale users.&lt;/p&gt;
&lt;h3 id="who-would-benefit-the-most-from-your-talk"&gt;Who would benefit the most from your talk?&lt;/h3&gt;
&lt;p&gt;You should have an intermediate understanding of MySQL and how replication and proxying would work as well as at least a basic understanding of Kubernetes.&lt;/p&gt;
&lt;h3 id="what-other-presentations-are-you-most-looking-forward-to"&gt;What other presentations are you most looking forward to?&lt;/h3&gt;
&lt;p&gt;All the talks on the &lt;a href="https://www.percona.com/live/percona-live-online-full-agenda" target="_blank" rel="noopener noreferrer"&gt;Percona Live agenda&lt;/a&gt; are exciting, but if I had to pick one talk, it would be “Mostly Mistaken and Ignored Parameters While Optimizing a PostgreSQL Database” by Avi Vallarapu.&lt;/p&gt;</content:encoded>
      <author>Raghavendra Prabhu</author>
      <category>rene.cannao</category>
      <category>Events</category>
      <category>Kubernetes</category>
      <category>Tools</category>
      <media:thumbnail url="https://percona.community/blog/2020/05/Social-PL-Online-2020-1_hu_5f15f9d3f957c60b.jpg"/>
      <media:content url="https://percona.community/blog/2020/05/Social-PL-Online-2020-1_hu_6e248db3cecf756e.jpg" medium="image"/>
    </item>
    <item>
      <title>MariaDB 10.4 and the Competition – Percona Live ONLINE Talk Preview</title>
      <link>https://percona.community/blog/2020/05/07/mariadb-10-4-and-the-competition-percona-live-online-talk-preview/</link>
      <guid>https://percona.community/blog/2020/05/07/mariadb-10-4-and-the-competition-percona-live-online-talk-preview/</guid>
      <pubDate>Thu, 07 May 2020 23:10:23 UTC</pubDate>
      <description>Percona Live Online Agenda Slot: Tue 19 May • New York 12:30 p.m. • London 5:30 p.m. • New Delhi 10:00 p.m.</description>
      <content:encoded>&lt;p&gt;&lt;a href="https://www.percona.com/live/conferences" target="_blank" rel="noopener noreferrer"&gt;Percona Live Online&lt;/a&gt; Agenda Slot: Tue 19 May • New York 12:30 p.m. • London 5:30 p.m. • New Delhi 10:00 p.m.&lt;/p&gt;
&lt;h3 id="abstract"&gt;Abstract&lt;/h3&gt;
&lt;p&gt;There are many good databases out there. Picking the right database for your project is never easy. There are technical criteria, business criteria, perhaps even ethical criteria. In this keynote, MariaDB Foundation CEO Kaj Arno will present his - obviously completely impartial - view of the process. Should you pick a database in the cloud or on premise? Should you pick an Open Source database or a closed-source one? And if you pick relational open source databases, how should you choose between MariaDB, MySQL and PostgresSQL? Expect the recommendation to not always be “go with MariaDB 10.4”. However, do expect to get a view of how the MariaDB Foundation sees its role, in relation to MariaDB Server, to MariaDB Corporation, to its other members (Microsoft, IBM, Service Now, Alibaba, Tencent, Booking.com, et al.), and above all, to the community of database developers and users.&lt;/p&gt;
&lt;h3 id="why-is-your-talk-exciting"&gt;Why is your talk exciting?&lt;/h3&gt;
&lt;p&gt;Can you expect a partial person to come with a neutral comparison between competitors? No. But it can still be logical and insightful. Can you expect such a comparison to be exciting? Yes. And it can be entertaining, too. Why? Because I am starting from the basic reasoning of “Cui bono”: Who benefits? From what? What is the likely reasoning by the actors in the database industry? And what is their actual behavior?&lt;/p&gt;
&lt;h3 id="who-would-benefit-the-most-from-your-talk"&gt;Who would benefit the most from your talk?&lt;/h3&gt;
&lt;p&gt;Developers, DBAs, sysadmins. Anyone who needs to decide how to make data persistent in their apps. Where should data be stored? How should one even think about the choice process? Technology issues, business issues, the lot.&lt;/p&gt;
&lt;h3 id="what-other-presentations-are-you-most-looking-forward-to"&gt;What other presentations are you most looking forward to?&lt;/h3&gt;
&lt;p&gt;On &lt;a href="https://www.percona.com/live/percona-live-online-full-agenda" target="_blank" rel="noopener noreferrer"&gt;the full agenda&lt;/a&gt;, all the keynoters are great! The last few PeterZ presentations I’ve seen have been wonderful combinations of deep technical expertise and logical business reasoning. Matt Asay is always insightful. And there is a lot to be learned from Bruce Momjian and Frédéric Descamps.&lt;/p&gt;
&lt;p&gt;I’m also looking forward to MySQL on Google Cloud, by Leo Tolstoy and my former colleague Jeremy Cole. And speaking of former colleagues, Colin’s MariaDB Server talk is clearly going to be an exciting one, a different angle to what I will touch upon in my keynote.&lt;/p&gt;
&lt;p&gt;Last and by no means least: I already attended an earlier version of Valerii Kravchuk’s super-cool tracing and performance debugging presentation, but it was so good that I will want to look at it again.&lt;/p&gt;</content:encoded>
      <author>Kaj Arnö</author>
      <category>kaj.arno</category>
      <category>Events</category>
      <category>MariaDB</category>
      <category>MySQL</category>
      <category>PostgreSQL</category>
      <media:thumbnail url="https://percona.community/blog/2020/05/Social-PL-Online-2020-1_hu_5f15f9d3f957c60b.jpg"/>
      <media:content url="https://percona.community/blog/2020/05/Social-PL-Online-2020-1_hu_6e248db3cecf756e.jpg" medium="image"/>
    </item>
    <item>
      <title>Orchestrating Cassandra with Kubernetes Operator and Yelp PaaSTA - Percona Live ONLINE Talk Preview</title>
      <link>https://percona.community/blog/2020/05/06/orchestrating-cassandra-with-kubernetes-operator-and-yelp-paasta-percona-live-online-talk-preview/</link>
      <guid>https://percona.community/blog/2020/05/06/orchestrating-cassandra-with-kubernetes-operator-and-yelp-paasta-percona-live-online-talk-preview/</guid>
      <pubDate>Wed, 06 May 2020 19:42:03 UTC</pubDate>
      <description>Percona Live Online Agenda Slot: Tue 19 May • New York 3:00 p.m. • London 8:00 p.m. • New Delhi 12:30 a.m. (Wed) Level: Intermediate</description>
      <content:encoded>&lt;p&gt;&lt;em&gt;&lt;a href="https://www.percona.com/live/conferences" target="_blank" rel="noopener noreferrer"&gt;Percona Live Online&lt;/a&gt; Agenda Slot: Tue 19 May • New York 3:00 p.m. • London 8:00 p.m. • New Delhi 12:30 a.m. (Wed)&lt;/em&gt; &lt;em&gt;Level: Intermediate&lt;/em&gt;&lt;/p&gt;
&lt;h3 id="abstract"&gt;Abstract&lt;/h3&gt;
&lt;p&gt;At Yelp, Cassandra, our NoSQL database of choice, has been deployed on AWS compute (EC2) and AutoScaling Groups (ASG), backed by Block Storage (EBS). This deployment model has been quite robust over the years while presenting its own set of challenges. To make our Cassandra deployment more resilient and reduce the engineering toil associated with our constantly growing infrastructure, we are abstracting Cassandra deployments further away from EC2 with Kubernetes and orchestrating with our Cassandra Operator. We are also leveraging Yelp’s PaaSTA for consistent abstractions and features such as fleet autoscaling with Clusterman, and Spot fleets, features that will be quite useful for an efficient datastore deployment.&lt;/p&gt;
&lt;p&gt;In this talk, we delve into the architecture of our Cassandra operator and the multi-region multi-AZ clusters it manages, and strategies we have in place for safe rollouts and zero-downtime migration. We will also discuss the challenges that we have faced en route and the design tradeoffs done. Last but not least, our plans for the future will also be shared.&lt;/p&gt;
&lt;h3 id="why-is-your-talk-exciting"&gt;Why is your talk exciting?&lt;/h3&gt;
&lt;p&gt;The talk not only delves into the architecture of Yelp’s Cassandra deployment on Kubernetes, and the operator but also the various challenges that we encountered and our approaches to them.  We also talk about how we have integrated this operator with our own PaaS (Platform-as-a-Service) called PaaSTA, and leveraged capabilities such as Spot fleets and Clusterman for significant savings in cloud costs.&lt;/p&gt;
&lt;h3 id="who-would-benefit-the-most-from-your-talk"&gt;Who would benefit the most from your talk?&lt;/h3&gt;
&lt;p&gt;Attendees interested in stateful deployments - databases, streaming pipelines - on Kubernetes and orchestration systems in general, should find this talk interesting. Also, anyone using existing Kubernetes operators or planning on writing an operator should benefit from this talk.&lt;/p&gt;
&lt;h3 id="what-other-presentations-are-you-most-looking-forward-to"&gt;What other presentations are you most looking forward to?&lt;/h3&gt;
&lt;p&gt;Among talks on &lt;a href="https://www.percona.com/live/percona-live-online-full-agenda" target="_blank" rel="noopener noreferrer"&gt;the full agenda,&lt;/a&gt; I am looking forward to the State of Open Source Databases from Peter Zaitsev to get a snapshot of the current trends and technologies in the database world. Lefred’s talk on the State of the Dolphin should be similarly helpful in keeping up with the state of MySQL which is a rapidly growing project. Finally, given our current focus on databases and Kubernetes, I am also looking forward to Comparison of Kubernetes Operators for MySQL and A Step by Step Guide to Using Databases on Containers talks from Percona and AWS respectively.&lt;/p&gt;</content:encoded>
      <author>Raghavendra Prabhu</author>
      <category>raghu.prabhu</category>
      <category>Events</category>
      <category>Kubernetes</category>
      <media:thumbnail url="https://percona.community/blog/2020/05/Social-PL-Online-2020-1_hu_5f15f9d3f957c60b.jpg"/>
      <media:content url="https://percona.community/blog/2020/05/Social-PL-Online-2020-1_hu_6e248db3cecf756e.jpg" medium="image"/>
    </item>
    <item>
      <title>Dynamic Tracing for Finding and Solving MariaDB (and MySQL) Performance Problems on Linux - Percona Live ONLINE Talk Preview</title>
      <link>https://percona.community/blog/2020/05/05/dynamic-tracing-for-finding-and-solving-mariadb-and-mysql-performance-problems-on-linux-percona-live-online-talk-preview/</link>
      <guid>https://percona.community/blog/2020/05/05/dynamic-tracing-for-finding-and-solving-mariadb-and-mysql-performance-problems-on-linux-percona-live-online-talk-preview/</guid>
      <pubDate>Tue, 05 May 2020 21:13:57 UTC</pubDate>
      <description>Percona Live Online Agenda Slot (CORRECTED): Wed 20 May • New York 6:00 a.m. • London 11:00 a.m. • New Delhi 3:30 p.m. Level: Advanced</description>
      <content:encoded>&lt;p&gt;&lt;em&gt;&lt;a href="https://www.percona.com/live/conferences" target="_blank" rel="noopener noreferrer"&gt;Percona Live Online&lt;/a&gt; Agenda Slot (CORRECTED): Wed 20 May • New York 6:00 a.m. • London 11:00 a.m. • New Delhi 3:30 p.m.&lt;/em&gt; &lt;em&gt;Level: Advanced&lt;/em&gt;&lt;/p&gt;
&lt;h3 id="abstract"&gt;Abstract&lt;/h3&gt;
&lt;p&gt;While troubleshooting MariaDB server performance problems it is important to find out where the time is spent in the mysqld process, on-CPU and off-CPU. The process of investigation should have as small influence as possible on the server we try to troubleshoot.  Performance_schema introduced in MySQL 5.5 (and inherited from MySQL 5.6 by MariaDB) is supposed to provide detailed enough instrumentation for most cases. But it comes with a cost, requires careful sizing of performance counters, and the process of instrumenting the code is not yet complete even for MySQL 8, to say nothing about MariaDB with its 3rd party storage engines, plugins and libraries like Galera.&lt;/p&gt;
&lt;p&gt;This is when perf profiler and, on recent Linux kernels (4.9+) eBPF and bpftrace tools come handy.  Specifically, perf profiler and ftrace interface can be easily used while studying MariaDB performance problems. Basic usage steps are presented and several typical real life use cases (including adding dynamic probes to almost any line of MariaDB code) are discussed.  On Linux 4.9+ eBPF is probably the most powerful and least intrusive way to study performance problems. Basic usage of , bcc tools and bpftrace, as well as main bpftrace features and commands are demonstrated.  One of the ways to present and study stack samples collected by perf or bpftrace, Flame Graphs, is also presented with examples coming from my experince as a support engineer.&lt;/p&gt;
&lt;h3 id="why-is-your-talk-exciting"&gt;Why is your talk exciting?&lt;/h3&gt;
&lt;p&gt;It summarizes the experience from my recent years of practical non-trivial performance problems solving for MariaDB and MySQL systems in production. It turned out that application level instrumentation of database servers in MySQL ecosystem is not detailed and dynamic enough for some complex cases. We do not see Performance Schema instrumentation as every other line of MySQL code, yet, and even less so it applied to 3rd party plugins and technologies, like Galera.&lt;/p&gt;
&lt;p&gt;We can not expect developers to promptly add instrumentation where we need it and release custom binaries for every specific case, even in such a dynamic company like MariaDB Corporation, where we in services work closely with Engineering every day. That is why I personally got so excited when I found out that Linux starting for kernels 2.6.x (RHEL6) provides tools and approaches to add instrumentation almost anywhere, from kernel code to applications, dynamically, at run time, without any change needed in kernel or application code (something I’ve seen in action with DTrace on Solaris and OS X since 2008 or so).&lt;/p&gt;
&lt;p&gt;I started with perf profiler as a way to find out why some threads hanged for minutes when Performance Schema had not provided the answer, back in 2016, and this is when I first hit Brendan Gregg’s site (&lt;a href="http://www.brendangregg.com/" target="_blank" rel="noopener noreferrer"&gt;http://www.brendangregg.com/)&lt;/a&gt;). Since that first real success with perf I follow him and dynamic tracing topic closely, and try to apply new tools added in the meantime while working on complex performance issues in MariaDB Support. I’ve shared my experience both in public and internally in MariaDB Corporation, and got several key MariaDB developers excited and happy about the details they can get from perf and dynamic tracing in general, comparing to any other approach. I’d like to convert more engineers to this faith with my presentation.&lt;/p&gt;
&lt;p&gt;I know about companies like Facebook having the entire teams working on custom dynamic tracing tools, and other MySQL Community members sharing their positive experience recently. Linux kernel developers work hard on making dynamic tracing even more safe, non-intrusive and easy to use. So, dynamic tracing (finally) becomes a hot topic that every database expert should follow!&lt;/p&gt;
&lt;h3 id="who-would-benefit-the-most-from-your-talk"&gt;Who would benefit the most from your talk?&lt;/h3&gt;
&lt;p&gt;I think experienced DBAs, as well as everyone working in professional services who cares about performance tuning on Linux would benefit a lot. But Linux sysadmins and application developers may get entirely new, different perspective on how to deal with performance problems when their application level instrumentation does not help to pinpoint the root cause. I consider dynamic tracing and profiling on modern Linux systems (starting from kernels 2.6.x, and especially 4.9+ with eBPF fully functional) a practice worth to be mastered by any IT professional these days.&lt;/p&gt;
&lt;h3 id="what-other-presentations-are-you-most-looking-forward-to"&gt;What other presentations are you most looking forward to?&lt;/h3&gt;
&lt;p&gt;I am really interested in “Diagnosing Memory Utilization, Leaks and Stalls in Production” by Marcos Albe. I expect they my dear friend, former colleague and manager in Percona Support is exploring the same way of approaching performance problems (with Linux dynamic tracing tools) that I do. He probably started exploring this way earlier than me (my first attempts to use perf profiler while working on support issues date back only to 2016). He is also of the smartest people I ever worked with, and is working for a company that deals with complex performance problems on all kinds of forks of open source databases, not only MySQL, in all kinds of environments including containers. So I’ll surely benefit from his views and experience shared in this presentation. I hope to study more about eBPF-based dynamic tracing of memory allocations, cache and registers usage, memory flame graphs and similar tools applied in production to MySQL and other DBMSes.&lt;/p&gt;
&lt;p&gt;I am also looking forward to “Profiling MySQL and MariaDB Hash Join Implementations” by Jim Tommaney. MySQL Optimizer and query optimization in general are my area of interests since 2005 and I’d really want to find more details about the way hash joins are finally implemented, and comparison to various BKA-based optimizations we have for that in MariaDB. MySQL 8.0.x is a moving target now, with every minor release introducing new features, and I do not have enough time to keep my knowledge current on this topic. That’s why i expect both a useful review and summary, and details about changes introduced by recent MySQL 8.0.20 in this area.&lt;/p&gt;
&lt;p&gt;Overall &lt;a href="https://www.percona.com/live/percona-live-online-full-agenda" target="_blank" rel="noopener noreferrer"&gt;the conference agenda&lt;/a&gt; looks really great, and i am considering taking a full day (if not two) off to spend most of these 24 hours online listening to talks.&lt;/p&gt;</content:encoded>
      <author>Valeriy Kravchuk</author>
      <category>valeriy.kravchuk</category>
      <category>Events</category>
      <category>MariaDB</category>
      <category>MySQL</category>
      <media:thumbnail url="https://percona.community/blog/2020/05/Social-PL-Online-2020-1_hu_5f15f9d3f957c60b.jpg"/>
      <media:content url="https://percona.community/blog/2020/05/Social-PL-Online-2020-1_hu_6e248db3cecf756e.jpg" medium="image"/>
    </item>
    <item>
      <title>Expert MariaDB: Utilize MariaDB Server Effectively - Percona Live ONLINE Talk Preview</title>
      <link>https://percona.community/blog/2020/05/04/expert-mariadb-utilize-mariadb-server-effectively-percona-live-online-talk-preview/</link>
      <guid>https://percona.community/blog/2020/05/04/expert-mariadb-utilize-mariadb-server-effectively-percona-live-online-talk-preview/</guid>
      <pubDate>Mon, 04 May 2020 20:30:20 UTC</pubDate>
      <description>Percona Live Online Agenda Slot: Tue 19 May • New York 11:00 p.m. • London 4:00 a.m. (Wed) • New Delhi 8:30 a.m. (Wed) Level: Intermediate</description>
      <content:encoded>&lt;p&gt;&lt;em&gt;&lt;a href="https://www.percona.com/live/conferences" target="_blank" rel="noopener noreferrer"&gt;Percona Live Online&lt;/a&gt; Agenda Slot:  Tue 19 May • New York&lt;/em&gt; &lt;em&gt;11:00 p.m. • London 4:00 a.m. (Wed) • New Delhi 8:30 a.m. (Wed)&lt;/em&gt; &lt;em&gt;Level: Intermediate&lt;/em&gt;&lt;/p&gt;
&lt;h3 id="abstract"&gt;Abstract&lt;/h3&gt;
&lt;p&gt;MariaDB Server 10.4 has been out for some time now (June 2019) and it has many new features, some of which MySQL does not have. Feature-wise, it is important to know what MariaDB Server 10.4 has (e.g. system tables in the Aria storage engine, ability to reload SSL certificates without a restart and more!) and what it lacks compared to MySQL 8.0 (group replication, the X Protocol, etc.)  Attendees will become more knowledgeable about how to better manage, observe, and secure their MariaDB Servers.&lt;/p&gt;
&lt;h3 id="why-is-your-talk-exciting"&gt;Why is Your Talk Exciting?&lt;/h3&gt;
&lt;p&gt;I am going to talk about MariaDB Server from a user perspective and why you might consider using this fork of MySQL for your production use cases. After all, it has progressed differently from MySQL and has features that are similar, sometimes implemented differently, yet it also has new features that MySQL may not get to, e.g. Oracle compatibility.&lt;/p&gt;
&lt;p&gt;It is also likely that we can talk a little about MariaDB Server 10.5 which should be just around the corner, as it is currently in beta. There are plenty of improvements around JSON, more information reported in the threadpool, a new Amazon S3 storage engine, plenty of InnoDB improvements, Galera 4 inconsistency voting, and more.&lt;/p&gt;
&lt;h3 id="who-would-benefit-the-most-from-your-talk"&gt;Who Would Benefit the Most From Your Talk?&lt;/h3&gt;
&lt;p&gt;Are you MariaDB curious? You would enjoy this talk as it is will only cover features not already present in MySQL. After all, it doesn’t matter how things are implemented — this is totally from a user perspective, so if you’re already used to MySQL, find out what *else* you will get from MariaDB Server.&lt;/p&gt;
&lt;h3 id="what-other-presentations-are-you-most-looking-forward-to"&gt;What Other Presentations Are You Most Looking Forward To?&lt;/h3&gt;
&lt;p&gt;I’m interested in the ProxySQL talks, though &lt;a href="https://www.percona.com/live/percona-live-online-full-agenda" target="_blank" rel="noopener noreferrer"&gt;the entire agenda&lt;/a&gt; is great.&lt;/p&gt;</content:encoded>
      <author>Colin Charles</author>
      <category>Colin.Charles</category>
      <category>Events</category>
      <category>MariaDB</category>
      <media:thumbnail url="https://percona.community/blog/2020/05/Social-PL-Online-2020-1_hu_5f15f9d3f957c60b.jpg"/>
      <media:content url="https://percona.community/blog/2020/05/Social-PL-Online-2020-1_hu_6e248db3cecf756e.jpg" medium="image"/>
    </item>
    <item>
      <title>Our Offer to Online Meetups and Community Leaders</title>
      <link>https://percona.community/blog/2020/04/07/our-offer-to-online-meetups-and-community-leaders/</link>
      <guid>https://percona.community/blog/2020/04/07/our-offer-to-online-meetups-and-community-leaders/</guid>
      <pubDate>Tue, 07 Apr 2020 10:52:51 UTC</pubDate>
      <description> Percona’s Community team organizes our speakers at in-person events around the world, such as Percona Live, Percona University, and events sponsored by other organizations. However, like everyone else around the world, all our plans are on hold due to the Coronavirus pandemic.</description>
      <content:encoded>&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2020/04/online-meetups-percona-linkedin.jpg" alt="Offer of Percona Speakers for events" /&gt;&lt;/figure&gt;Percona’s Community team organizes our speakers at in-person events around the world, such as Percona Live, Percona University, and events sponsored by other organizations. However, like everyone else around the world, all our plans are on hold due to the Coronavirus pandemic.&lt;/p&gt;
&lt;p&gt;Perhaps you, like many others, are organizing online events, such as &lt;a href="https://help.meetup.com/hc/en-us/articles/360040609112" target="_blank" rel="noopener noreferrer"&gt;virtual meetups on Meetup.com&lt;/a&gt;. We can help you by making Percona’s team of experienced and well-known speakers available for your event. We have experts on key open-source database topics, including Kubernetes, monitoring, high availability, and more.&lt;/p&gt;
&lt;p&gt;Many of our speakers have spoken at major tech conferences before. These include experts like &lt;a href="https://www.linkedin.com/in/peterzaitsev/" target="_blank" rel="noopener noreferrer"&gt;Peter Zaitsev&lt;/a&gt;, &lt;a href="https://www.linkedin.com/in/askdba/" target="_blank" rel="noopener noreferrer"&gt;Alkin Tezuysal&lt;/a&gt;, &lt;a href="https://www.linkedin.com/in/ibrarahmed74/" target="_blank" rel="noopener noreferrer"&gt;Ibrar Ahmed&lt;/a&gt;, &lt;a href="https://www.linkedin.com/in/tylerduzan/" target="_blank" rel="noopener noreferrer"&gt;Tyler Duzan&lt;/a&gt;, and &lt;a href="https://www.linkedin.com/in/svetsmirnova/" target="_blank" rel="noopener noreferrer"&gt;Sveta Smirnova&lt;/a&gt;, with availability across many timezones. Further, if you invite a Percona speaker to present virtually, Percona will help promote your events on our blog and social networks.&lt;/p&gt;
&lt;p&gt;To get started, just email &lt;a href="mailto:community-team@percona.com"&gt;community-team@percona.com&lt;/a&gt; anytime.&lt;/p&gt;
&lt;h2 id="percona-live-amsterdam-2019"&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2020/04/ple-1.jpg" alt="Percona Live Amsterdam 2019" /&gt;&lt;/figure&gt;
Percona Live Amsterdam 2019&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Desk Photo by: &lt;a href="https://burst.shopify.com/@sarahpflugphoto" target="_blank" rel="noopener noreferrer"&gt;Sarah Pflug&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;</content:encoded>
      <author>Daniil Bazhenov</author>
      <category>daniil.bazhenov</category>
      <category>Events</category>
      <category>Information</category>
      <category>online meetups</category>
      <category>percona speakers</category>
      <media:thumbnail url="https://percona.community/blog/2020/04/online-meetups-percona-linkedin_hu_6db2be1eb222853b.jpg"/>
      <media:content url="https://percona.community/blog/2020/04/online-meetups-percona-linkedin_hu_8e18047ade9254f6.jpg" medium="image"/>
    </item>
    <item>
      <title>Finding MySQL Scaling Problems Using perf</title>
      <link>https://percona.community/blog/2020/02/05/finding-mysql-scaling-problems-using-perf/</link>
      <guid>https://percona.community/blog/2020/02/05/finding-mysql-scaling-problems-using-perf/</guid>
      <pubDate>Wed, 05 Feb 2020 16:18:14 UTC</pubDate>
      <description>The thing I wish I’d learned while still a DBA is how to use perf. Conversely after moving to a developer role, getting access to real external client workloads to get a perf recording directly is rare. To bridge this gap, I hope to encourage a bit of perf usage to help DBAs report bugs/feature requests in more detail to MySQL developers, who can then serve your needs better.</description>
      <content:encoded>&lt;p&gt;The thing I wish I’d learned while still a DBA is how to use &lt;a href="https://perf.wiki.kernel.org/index.php/Main_Page" target="_blank" rel="noopener noreferrer"&gt;perf&lt;/a&gt;. Conversely after moving to a developer role, getting access to real external client workloads to get a perf recording directly is rare. To bridge this gap, I hope to encourage a bit of perf usage to help DBAs report bugs/feature requests in more detail to MySQL developers, who can then serve your needs better.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2020/01/ricardo-gomez-angel-87vUJY3ntyI-unsplash.jpg" alt=" " /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;A recent client request showed how useful perf is in exposing the areas of MySQL that are otherwise well tuned, but can still be in need of coding improvements that increase throughput. The client had a &lt;a href="https://sourceforge.net/projects/tpccruner/" target="_blank" rel="noopener noreferrer"&gt;TPCCRunner&lt;/a&gt; (variant) workload that they wanted to run on a &lt;a href="https://www.ibm.com/it-infrastructure/power/power9" target="_blank" rel="noopener noreferrer"&gt;Power 9&lt;/a&gt; CPU, in &lt;a href="https://dev.mysql.com/doc/refman/5.7/en/innodb-transaction-isolation-levels.html#isolevel_read-committed" target="_blank" rel="noopener noreferrer"&gt;READ-COMMITTED&lt;/a&gt; mode, and they received less performance than they hoped. Being a 2 socket, 20 cpus/socket 4 threads per core, and 256G RAM total it has enough resources.&lt;/p&gt;
&lt;p&gt;With such abundance of resources, the perf profile exposed code bottlenecks not normally seen.&lt;/p&gt;
&lt;p&gt;The principles driving MySQL development for a considerable time have been to a) maintain correctness, and b) deliver performance, usually meaning the CPU should be the bottleneck. The whole reason for large innodb buffer pools, innodb MVCC / LSN, group commit, table caches, thread caches, indexes, query planner etc, is to ensure that all hot data is in memory, ready to be processed optimally in the most efficient way by the CPU.&lt;/p&gt;
&lt;p&gt;Based on this principle, without a requirement to sync to persistent storage for durability, a SQL read mostly load should be able to add scale linearly up to the CPU capacity. Ideally after the CPU capacity has been reached the throughput should stay at the capacity limit and not degrade. Practical overheads of thread measurement mean this is never perfectly achieved. However, it is the goal.&lt;/p&gt;
&lt;h2 id="steps-to-using-perf"&gt;Steps to using perf&lt;/h2&gt;
&lt;p&gt;To install and use perf, use the following steps:&lt;/p&gt;
&lt;h4 id="1-install-perf"&gt;1. Install perf&lt;/h4&gt;
&lt;p&gt;This is a standard package and is closely tied to the Linux kernel version. The package name varies per distro:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ubuntu: &lt;a href="https://packages.ubuntu.com/bionic/linux-tools-common" target="_blank" rel="noopener noreferrer"&gt;linux-tools-common&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Debian: &lt;a href="https://packages.debian.org/buster/linux-base" target="_blank" rel="noopener noreferrer"&gt;linux-base&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;RHEL / Centos / Fedora: perf&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Distributions normally set the &lt;a href="http://man7.org/linux/man-pages/man8/sysctl.8.html" target="_blank" rel="noopener noreferrer"&gt;sysctl&lt;/a&gt; &lt;a href="https://www.kernel.org/doc/html/latest/admin-guide/sysctl/kernel.html#perf-event-paranoid" target="_blank" rel="noopener noreferrer"&gt;&lt;em&gt;kernel.perf_event_paranoid&lt;/em&gt;&lt;/a&gt; to a level which is hard to use (or &lt;a href="https://www.kernel.org/doc/html/latest/admin-guide/perf-security.html" target="_blank" rel="noopener noreferrer"&gt;exploit&lt;/a&gt;) and this may need to be adjusted to obtain our recording. Large perf recordings due to hardware threads can require file descriptors and memory, and their limits may need to be increased with care (see &lt;a href="https://www.kernel.org/doc/html/latest/admin-guide/perf-security.html#perf-events-perf-resource-control" target="_blank" rel="noopener noreferrer"&gt;kernel manual&lt;/a&gt;).&lt;/p&gt;
&lt;h4 id="2-install-debug-symbols-aka-debug-info-for-mysql"&gt;2. Install debug symbols (a.k.a. debug info) for MySQL&lt;/h4&gt;
&lt;p&gt;Debug symbols mapping memory addresses to real server code can assist greatly in understanding the recorded results. The debug info needs to map to the exact build of MySQL (both version number and its origin).&lt;/p&gt;
&lt;p&gt;Distros provide debug information in separate package repositories (distribution instructions: &lt;a href="https://wiki.ubuntu.com/Debug%20Symbol%20Packages" target="_blank" rel="noopener noreferrer"&gt;Ubuntu&lt;/a&gt;, &lt;a href="https://wiki.debian.org/AutomaticDebugPackages" target="_blank" rel="noopener noreferrer"&gt;Debian&lt;/a&gt;, &lt;a href="https://access.redhat.com/solutions/9907" target="_blank" rel="noopener noreferrer"&gt;RHEL&lt;/a&gt;, &lt;a href="https://fedoraproject.org/wiki/StackTraces#What_are_debuginfo_rpms.2C_and_how_do_I_get_them.3F" target="_blank" rel="noopener noreferrer"&gt;Fedora&lt;/a&gt;) and MySQL, &lt;a href="https://mariadb.com/kb/en/library/how-to-produce-a-full-stack-trace-for-mysqld/#installing-debug-info-packages-on-linux" target="_blank" rel="noopener noreferrer"&gt;MariaDB&lt;/a&gt; and Percona provide debug info packages in their repositories without additional configuration.&lt;/p&gt;
&lt;p&gt;If compiling from source, the default cmake option -DCMAKE_BUILD_TYPE=RelWithDebugInfo  has debug info as the name suggests.&lt;/p&gt;
&lt;h4 id="3-ensure-that-your-table-structures-and-queries-are-sane"&gt;3. Ensure that your table structures and queries are sane.&lt;/h4&gt;
&lt;p&gt;MySQL works well when the database table structures, indexes, and queries are in a &lt;code&gt;natural&lt;/code&gt; simple form. Asking MySQL developers to make poor table structures/queries to achieve greater performance will attract a low priority as making these changes can add to the overhead of simple queries.&lt;/p&gt;
&lt;h4 id="4-ensure-that-you-have-tuned-the-database-for-the-workload"&gt;4. Ensure that you have tuned the database for the workload.&lt;/h4&gt;
&lt;p&gt;MySQL has a lot of system variables, and using the performance schema and status variables assists in creating an optimally tuned MySQL instance before beginning perf measurements.&lt;/p&gt;
&lt;h4 id="5-ensure-that-the-active-data-is-off-disk"&gt;5. Ensure that the active data is off disk&lt;/h4&gt;
&lt;p&gt;To ensure you measurement is at its maximum, having the hot part of the data loaded into memory enables perf to focus on recording CPU related areas under stress, not just waiting to load from disk.&lt;/p&gt;
&lt;p&gt;For example, the TPCCRunner example described earlier took about an hour before it reached a point where it achieved its maximum transaction throughput. TPCRunner displays this, but generally watch for a leveling out of the queries per second over several minutes.&lt;/p&gt;
&lt;p&gt;When starting/stopping mysqld for testing, &lt;a href="https://dev.mysql.com/doc/refman/5.7/en/innodb-parameters.html#sysvar_innodb_buffer_pool_dump_at_shutdown" target="_blank" rel="noopener noreferrer"&gt;innodb_buffer_pool_dump_at_shutdown&lt;/a&gt;=1 / innodb_buffer_pool_dump_at_start=1 / innodb_buffer_pool_dump_pct=100 will help restore the innodb buffer pool significantly quicker.&lt;/p&gt;
&lt;h4 id="6-know-what-workload-is-being-measured"&gt;6. Know what workload is being measured&lt;/h4&gt;
&lt;p&gt;A batch job may not have the same throughput requirements. It also may impact the concurrent workload that you are perf recording by creating longer history length, innodb buffer pool pressure etc.&lt;/p&gt;
&lt;p&gt;The application that generates the workload should be on a different server, different VM or in some way constrained in CPU to avoid resource contention with mysqld. Check the client side to ensure that it isn’t overloaded (CPU, network) as this could be indirectly constraining the server side workload.&lt;/p&gt;
&lt;h2 id="measuring"&gt;Measuring&lt;/h2&gt;
&lt;p&gt;With a hot workload running let’s start some measurement.&lt;/p&gt;
&lt;p&gt;Perf uses hardware (PMU) to assist its recording work, but there are limits to hardware support so there’s a point where it will affect your workload, so start slow. Perf works by looking at a frequency distribution of where the mysqld process is spending its time. To examine a function that is taking 0.1% of the time means that 1000 samples will likely show it once. As such a few thousand samples is sufficient. The number of samples is the multiplication of &lt;a href="http://man7.org/linux/man-pages/man1/perf-record.1.html" target="_blank" rel="noopener noreferrer"&gt;perf record’s&lt;/a&gt; &lt;em&gt;-F / –freq&lt;/em&gt; – which may by default be several thousand / second – the recording duration, and the number of CPUs.&lt;/p&gt;
&lt;p&gt;If your SQL queries are all running in much less than a second and occurring frequently, then a high frequency recording for a short duration is sufficient. If some query occurs less often, with a high CPU usage spike, a helper program &lt;a href="https://github.com/Netflix/flamescope" target="_blank" rel="noopener noreferrer"&gt;FlameScope&lt;/a&gt; will be able to narrow down a perf recording to a usable sample interval.&lt;/p&gt;
&lt;p&gt;Analysis involves looking through a number of sets of data. Below I show a pattern of using _name _as a shell variable, and a large one line command to conduct a number of recordings in sequence. In my case, I cycled through _RC _ (read-committed) vs _RR _(repeatable read), different compile options &lt;em&gt;-O0&lt;/em&gt; , kernel versions, final stages of _warmup _(compared to test run) and even local changes to mysqld (thread_local_ut_rnd_ulint_counter ). Keeping track of these alongside the same measurement of the test run output helps to correlate results more easily.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;name=5.7.28-thread_local_ut_rnd_ulint_counterO0-RC_warmup2 ;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pid=$(pidof mysqld);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;perf record -F 10 -o mysql-${name}.perf -p $pid  -- sleep 20;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;perf record -g -F 10 -o mysql-${name}.g.perf -p $pid  -- sleep 5;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;perf stat -B -e cache-references,cache-misses,cycles,instructions,branches,faults,migrations -p $pid sleep 20
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2&gt;&amp;1 | tee perf-stats-${name}.txt&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;With the above command, the recording is constrained the recording to mysqld (&lt;em&gt;-p $pid&lt;/em&gt;), at &lt;em&gt;-F 10&lt;/em&gt; samples/per second for (&lt;em&gt;sleep&lt;/em&gt;) &lt;em&gt;20&lt;/em&gt; seconds. A longer recording without the stack trace (-g) is taken as reference point to see if the shorter recording with &lt;em&gt;-g&lt;/em&gt; stack trace is a fair sample. 10 hz x 20 seconds may not seem like many samples, however this occurred on each of the 160 threads. A record with &lt;em&gt;-g&lt;/em&gt; is needed as a perf profile that shows all time in the kernel or pthread mutex (lock) code, but it doesn’t mean much without knowing which lock it is and where it was accessed from.&lt;/p&gt;
&lt;p&gt;Perf record with &lt;em&gt;-g&lt;/em&gt; call-graph (also known as stack chain or backtrace) adds to the size of the recording and the overhead of measurements. To ensure that there isn’t too much perf data (resulting in workload stalls), get the right frequency and duration before enabling &lt;em&gt;-g&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Perf stats were measured to identify (cpu) cache efficiency, instructions/cycle efficiency, instructions throughput (watch out for frequency scaling), faults (connecting real memory to the virtual address - should be low after warmup), and migrations between numa nodes.&lt;/p&gt;
&lt;p&gt;During measurement look at &lt;em&gt;htop&lt;/em&gt;/&lt;em&gt;top&lt;/em&gt; to ensure that the CPUs are indeed loaded. Also check the client side isn’t flooded with connection errors that could impact the validity of the recorded results.&lt;/p&gt;
&lt;h2 id="analysis"&gt;Analysis&lt;/h2&gt;
&lt;h3 id="viewing-a-perf-recording"&gt;Viewing a perf recording&lt;/h3&gt;
&lt;p&gt;&lt;a href="http://man7.org/linux/man-pages/man1/perf-report.1.html" target="_blank" rel="noopener noreferrer"&gt;perf report&lt;/a&gt; is used to textually view a perf recording. It is during the report stage that the debug info is read, since the linux kernel image resolves symbols. Run the report under &lt;code&gt;nice -n 19 perf report&lt;/code&gt; to ensure it has the lowest CPU priority if you are at all concerned about production impacts. It’s quite possible to do this on a different server provided the same kernel and MySQL packages are installed. &lt;code&gt;perf report --input mysql-5.7.28-event_run2_warmup_run1.perf --stdio&lt;/code&gt;&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-1"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# Total Lost Samples: 0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;#
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# Samples: 91K of event 'cycles:ppp'
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# Event count (approx.): 1261395960159641
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;#
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# Overhead Command Shared Object Symbol
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# ........ ....... ................... ...............................................................................
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;#
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 5.84% mysqld mysqld [.] rec_get_offsets_func
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 3.62% mysqld mysqld [.] MYSQLparse
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 2.70% mysqld mysqld [.] page_cur_search_with_match
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 2.70% mysqld mysqld [.] buf_page_get_gen
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 2.22% mysqld mysqld [.] cmp_dtuple_rec_with_match_low
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 1.93% mysqld mysqld [.] buf_page_hash_get_low
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 1.49% mysqld mysqld [.] btr_cur_search_to_nth_level
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 1.35% mysqld [kernel.kallsyms] [k] do_syscall_64
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 1.14% mysqld mysqld [.] row_search_mvcc
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 0.93% mysqld mysqld [.] alloc_root
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 0.92% mysqld mysqld [.] lex_one_token
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 0.67% mysqld libc-2.27.so [.] malloc
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 0.64% mysqld libc-2.27.so [.] _int_malloc
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 0.61% mysqld libpthread-2.27.so [.] __pthread_getspecific
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 0.59% mysqld mysqld [.] pfs_rw_lock_s_lock_func
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 0.59% mysqld mysqld [.] dispatch_command
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 0.50% mysqld mysqld [.] check_stack_overrun
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 0.50% mysqld [tg3] [k] tg3_poll_work&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This shows a %CPU time measured when the CPU instruction pointer was at a particular time, grouped by the function name. To find out why malloc or the kernel do_syscall_64 appears so often the stack recording is needed.&lt;/p&gt;
&lt;h3 id="viewing-a-perf-recording-with-a-stack"&gt;Viewing a perf recording with a stack&lt;/h3&gt;
&lt;p&gt;When the &lt;em&gt;perf record&lt;/em&gt; used &lt;em&gt;-g&lt;/em&gt;, then &lt;em&gt;-g&lt;/em&gt; can be used in perf report to show the breakdown. By default it groups the functions, including the functions it calls, as below.
&lt;code&gt;perf report -i mysql-5.7.28-event_run2_warmup_run1.g.perf&lt;/code&gt;&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-2" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-2"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Samples: 85K of event 'cycles:ppp', Event count (approx.): 261413311777846
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Children Self Command Shared Object Symbol
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+ 80.08% 0.00% mysqld libpthread-2.27.so [.] start_thread
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+ 80.08% 0.00% mysqld mysqld [.] pfs_spawn_thread
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+ 80.05% 0.07% mysqld mysqld [.] handle_connection
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+ 79.75% 0.14% mysqld mysqld [.] do_command
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+ 77.98% 0.70% mysqld mysqld [.] dispatch_command
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+ 75.32% 0.18% mysqld mysqld [.] mysql_parse
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+ 62.63% 0.38% mysqld mysqld [.] mysql_execute_command
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+ 58.65% 0.13% mysqld mysqld [.] execute_sqlcom_select
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+ 55.63% 0.05% mysqld mysqld [.] handle_query
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+ 25.31% 0.41% mysqld mysqld [.] st_select_lex::optimize
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+ 24.67% 0.12% mysqld mysqld [.] JOIN::exec
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+ 24.45% 0.59% mysqld mysqld [.] JOIN::optimize
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+ 22.62% 0.29% mysqld mysqld [.] sub_select
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+ 20.15% 1.56% mysqld mysqld [.] btr_cur_search_to_nth_level&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;In MySQL, as expected, most significant CPU load is in the threads. Most of the time this is a user connection, under the &lt;em&gt;handle_connection&lt;/em&gt; function, which parses and executes the SQL. In different situations you might see innodb background threads, or replication threads: understanding which thread is causing the load is important at a top level. Then, to continue analysis, use the perf report &lt;em&gt;–no-children&lt;/em&gt; option. This will show approximately the same as the non_-g_ recording, however it will provide the mechanism of being able to hit Enter on a function to show all the call stacks that go to that particular function.
&lt;code&gt;perf report -g --no-children --input mysql-5.7.28-event_run2_warmup_run1.g.perf&lt;/code&gt;&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-3" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-3"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Overhead Command Shared Object Symbol ◆
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- 6.24% mysqld mysqld [.] rec_get_offsets_func ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; start_thread ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; pfs_spawn_thread ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; handle_connection ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; do_command ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; dispatch_command ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; mysql_parse ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; mysql_execute_command ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; execute_sqlcom_select ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - handle_query ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - 4.57% JOIN::exec ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - sub_select ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; + 3.77% evaluate_join_record ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; + 0.60% join_read_always_key ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; + 1.67% st_select_lex::optimize&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This shows a common call stack into &lt;em&gt;handle_query&lt;/em&gt;, where the &lt;em&gt;JOIN::exec&lt;/em&gt; and &lt;em&gt;st_select_lex::optimize&lt;/em&gt; is the diverging point. If the &lt;em&gt;evaluate_join_record&lt;/em&gt; and other sub-functions were to be expanded, the bottom level of the call graph would show &lt;em&gt;rec_get_offsets_func.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id="disassembly-annotation"&gt;Disassembly (annotation)&lt;/h3&gt;
&lt;p&gt;In the ncurses interfaces. Selecting ‘a’ (annotate) on a particular function calls out to the &lt;a href="https://linux.die.net/man/1/objdump" target="_blank" rel="noopener noreferrer"&gt;objdump&lt;/a&gt; (binutils) disassembler to show where in this function the highest frequency occurred and maps this to a commented C++ code above it.&lt;/p&gt;
&lt;p&gt;As compilers have significant understanding of the architecture, and given that the C/C++ language provides significant freedom in generating code, it’s sometimes quite difficult to parse from assembly back to the C/C++ source. In complex operations, C++ variables don’t have an easy translation to CPU registers. Inlined functions are also particularly hard as each inlining can further be optimized to a unique assembly depending on its location. To understand the assembly, I recommend focusing on the loads, stores, maths/conditions with constants and branches to see which register maps to which part of the MySQL server code in the context of the surrounding code.&lt;/p&gt;
&lt;p&gt;E.g annotation on &lt;em&gt;rec_get_offsets_func&lt;/em&gt;:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-4" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-4"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ dict_table_is_comp():
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ #if DICT_TF_COMPACT != 1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ #error "DICT_TF_COMPACT must be 1"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ #endif
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ return(table-&gt;flags &amp; DICT_TF_COMPACT);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 0.44 │ mov 0x20(%rsi),%rsi
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 39.30 │ movzbl -0x3(%rdi),%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ _Z20rec_get_offsets_funcPKhPK12dict_index_tPmmPP16mem_block_info_t():
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ ut_ad(rec);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ ut_ad(index);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ ut_ad(heap);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ if (dict_table_is_comp(index-&gt;table)) {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 0.44 │ testb $0x1,0x34(%rsi)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 0.15 │ ↓ je e611d8 &lt;rec_get_offsets_func(unsigned char const*, dict_index_t const*, 128
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ switch (UNIV_EXPECT(rec_get_status(rec),&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Here we see that &lt;em&gt;dict_table_is_comp&lt;/em&gt; is an expanded inline function at the top of &lt;em&gt;rec_get_offsets&lt;/em&gt;, the &lt;em&gt;movzlb .. %eax.&lt;/em&gt; The dominate CPU use in the function however isn’t part of this. The &lt;em&gt;testb 0x1 (DICT_TF_COMPACT) … %rsi&lt;/em&gt; is the testing of the flag with &lt;em&gt;je&lt;/em&gt; afterwards to return from the function.&lt;/p&gt;
&lt;h2 id="example---mutex-contention"&gt;Example - mutex contention&lt;/h2&gt;
&lt;p&gt;Compared to the performance profile on x86 above under ‘Viewing a perf recording’, this is what the performance profile looked like on POWER. perf report –input mysql-5.7.28-read_mostly_EVENT_RC-run2.perf –stdio&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-5" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-5"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# Total Lost Samples: 0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;#
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# Samples: 414K of event 'cycles:ppp'
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# Event count (approx.): 3884039315643070
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;#
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# Overhead Command Shared Object Symbol
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# ........ ....... ................... ...............................................................................
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 13.05% mysqld mysqld [.] MVCC::view_open
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 10.99% mysqld mysqld [.] PolicyMutex&lt;TTASEventMutex&lt;GenericPolicy&gt; &gt;::enter
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 4.11% mysqld mysqld [.] rec_get_offsets_func
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 3.78% mysqld mysqld [.] buf_page_get_gen
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 2.34% mysqld mysqld [.] MYSQLparse
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 2.27% mysqld mysqld [.] cmp_dtuple_rec_with_match_low
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 2.15% mysqld mysqld [.] btr_cur_search_to_nth_level
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 2.05% mysqld mysqld [.] page_cur_search_with_match
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 1.99% mysqld mysqld [.] ut_delay
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 1.83% mysqld mysqld [.] mtr_t::release_block_at_savepoint
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 1.35% mysqld mysqld [.] rw_lock_s_lock_func
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 0.96% mysqld mysqld [.] buf_page_hash_get_low
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 0.88% mysqld mysqld [.] row_search_mvcc
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 0.84% mysqld mysqld [.] lex_one_token
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 0.80% mysqld mysqld [.] pfs_rw_lock_s_unlock_func
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 0.80% mysqld mysqld [.] mtr_t::commit
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 0.62% mysqld mysqld [.] pfs_rw_lock_s_lock_func
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 0.59% mysqld [kernel.kallsyms] [k] power_pmu_enable
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 0.59% mysqld [kernel.kallsyms] [k] _raw_spin_lock
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 0.55% mysqld libpthread-2.28.so [.] __pthread_mutex_lock
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 0.54% mysqld mysqld [.] alloc_root
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 0.43% mysqld mysqld [.] PolicyMutex&lt;TTASEventMutex&lt;GenericPolicy&gt; &gt;::exit&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;What stands out clearly is the top two entries that didn’t appear on x86. Looking closer at &lt;em&gt;MVCC::view_open&lt;/em&gt;:
&lt;code&gt;perf report -g --no-children --input mysql-5.7.28-read_mostly_EVENT_RC-run2.g.perf&lt;/code&gt;&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-6" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-6"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- 13.47% mysqld mysqld [.] MVCC::view_open ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; __clone ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 0x8b10 ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; pfs_spawn_thread ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; handle_connection ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; do_command ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; dispatch_command ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; mysql_parse ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; mysql_execute_command ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; execute_sqlcom_select ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - handle_query ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - 11.22% JOIN::exec ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - sub_select ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - 10.99% join_read_always_key ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; handler::ha_index_read_map ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ha_innobase::index_read ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - row_search_mvcc ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - 10.99% trx_assign_read_view ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; MVCC::view_open&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Annotation of MVCC::view_open&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-7" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-7"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ _ZNK14TTASEventMutexI13GenericPolicyE7is_freeEjjRj(): ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ bool is_free( ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 0.02 │a08: ↓ bne cr4,10db7a30 &lt;MVCC::view_open(ReadView*&amp;, a90 ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ ↓ b 10db7ad0 &lt;MVCC::view_open(ReadView*&amp;, trx_t*)+0xb30&gt; ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ ut_rnd_gen_ulint(): ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ ut_rnd_ulint_counter = UT_RND1 * ut_rnd_ulint_counter + UT_RND2; ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │a10: addis r7,r2,2 ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 0.02 │ addi r7,r7,26904 ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 81.15 │ ld r8,0(r7) ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 0.02 │ mulld r8,r27,r8 ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 0.02 │ addis r8,r8,1828 ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 0.02 │ addi r8,r8,-14435 ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ ut_rnd_gen_next_ulint(): ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ rnd = UT_RND2 * rnd + UT_SUM_RND3; ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 0.02 │ mulld r9,r8,r19 ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ ut_rnd_gen_ulint(): ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ ut_rnd_ulint_counter = UT_RND1 * ut_rnd_ulint_counter + UT_RND2; ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 0.04 │ std r8,0(r7)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Due to the inline of code, within &lt;a href="https://github.com/mysql/mysql-server/blob/mysql-5.7.28/storage/innobase/read/read0read.cc#L554..L611" target="_blank" rel="noopener noreferrer"&gt;MVCC::view_open&lt;/a&gt; one of the mutexs got expanded out and the random number is used to spinlock wait for the lock again. &lt;a href="https://github.com/mysql/mysql-server/blob/mysql-5.7.28/storage/innobase/include/ib0mutex.h#L707..L717" target="_blank" rel="noopener noreferrer"&gt;PolicyMutex&lt;TTASEventMutex&lt;GenericPolicy&gt; &gt;::enter&lt;/a&gt; expanded to exactly the same code.&lt;/p&gt;
&lt;p&gt;We see here that the load (&lt;em&gt;ld&lt;/em&gt;) into &lt;em&gt;r8&lt;/em&gt;, is the slowest part of this. In mysql-5.7.28, &lt;a href="https://github.com/mysql/mysql-server/blob/mysql-5.7.28/storage/innobase/ut/ut0rnd.cc#L48" target="_blank" rel="noopener noreferrer"&gt;ut_rnd_ulint_counter&lt;/a&gt; is an ordinary global variable, meaning its shared between threads. The simple line of code &lt;em&gt;ut_rnd_ulint_counter = UT_RND1 * ut_rnd_ulint_counter + UT_RND2&lt;/em&gt;,  shows the result stored back in the same variable. To understand why this didn’t scale, we need to understand cache lines.&lt;/p&gt;
&lt;p&gt;note: &lt;em&gt;MVCC::view_open&lt;/em&gt; did show up in the x86 profile, at 0.23% and had the lock release as the highest cpu point. For x86 &lt;em&gt;PolicyMutex&lt;TTASEventMutex&lt;GenericPolicy&gt; &gt;::enter&lt;/em&gt; was at 0.32%.&lt;/p&gt;
&lt;h3 id="cache-lines"&gt;Cache Lines&lt;/h3&gt;
&lt;p&gt;All modern CPUs that are likely to support MySQL will have some from of &lt;a href="https://en.wikipedia.org/wiki/Cache_hierarchy" target="_blank" rel="noopener noreferrer"&gt;cache hierarchy&lt;/a&gt;. The principles are that a largely accessed memory location, like &lt;em&gt;ut_rnd_ulint_counter&lt;/em&gt;, can be copied into cache and at some point the CPU will push it back to memory. To ensure behavior is consistent, cache lines represent a MMU (memory management unit) concept of a memory allocation to a particular CPU. Cache lines can be read only, or exclusive, and a protocol between CPU cores exists to ensure that exclusive access is to one CPU only. When one CPU modifies a memory location it gains an exclusive cache line, and the cached value in other CPU caches are flushed. At which cache level this flushing occurs at, and to what extent are caches shared between CPUs, is quite architecture specific. However, citing rough &lt;a href="http://brenocon.com/dean_perf.html" target="_blank" rel="noopener noreferrer"&gt;metrics&lt;/a&gt;, cache access is orders of magnitude faster than RAM.&lt;/p&gt;
&lt;p&gt;In the perf recording above, storing back of &lt;em&gt;ut_rnd_ulint_counter&lt;/em&gt; clears the cache for the other CPUs, and this is why the load instruction is slow. MySQL did have this fixed in &lt;a href="https://github.com/mysql/mysql-server/commit/dedc8b3d567fbb92ce912f1559fe6a08b2857045" target="_blank" rel="noopener noreferrer"&gt;5.7.14&lt;/a&gt; but reverted this fix in &lt;a href="https://github.com/mysql/mysql-server/commit/dedc8b3d567fbb92ce912f1559fe6a08b2857045" target="_blank" rel="noopener noreferrer"&gt;5.7.20&lt;/a&gt; (assuming some performance degradation in thread local storage). In MySQL &lt;a href="https://github.com/mysql/mysql-server/commit/ea4913b403db72f26565520f68686b385872e7d2#diff-5f582f65ca6be1efafb5e278e4bffc44R35" target="_blank" rel="noopener noreferrer"&gt;8.0+&lt;/a&gt;, &lt;em&gt;ut_rnd_ulint_counter&lt;/em&gt; is a C++11 &lt;a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2659.htm" target="_blank" rel="noopener noreferrer"&gt;thread_local&lt;/a&gt; variable which has a faster implementation. &lt;a href="https://github.com/MariaDB/server/commit/ce04790" target="_blank" rel="noopener noreferrer"&gt;MariaDB-10.3.5&lt;/a&gt; avoided this by removing the random delay in InnoDB mutexes. Thread local variables reduce contention because each thread has its independent memory location. Because this is only a random number seed, there’s no need for synchronization of results.&lt;/p&gt;
&lt;h3 id="cache-collisions"&gt;Cache collisions&lt;/h3&gt;
&lt;p&gt;The impacts of &lt;em&gt;ut_rnd_ulint_counter&lt;/em&gt; however aren’t limited to itself. Cache lines reserve blocks of memory according to the cache line size of the architecture (x86 - 64 bytes, arm64 and POWER - 128 bytes, s390 - 256 bytes). High in the CPU profile is the &lt;em&gt;btr_cur_search_to_nth_level&lt;/em&gt; function. This is part of innodb’s scanning of an index and it would be easy to discount its high CPU usage. Looking at the disassembly however shows:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-8" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-8"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 0.01 │ ld r8,3464(r31)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ cursor-&gt;low_match = low_match;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 0.05 │ std r10,96(r25)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ cursor-&gt;up_bytes = up_bytes;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 0.00 │ ld r10,3456(r31)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ if (btr_search_enabled &amp;&amp; !index-&gt;disable_ahi) {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 24.08 │ lbz r9,0(r9)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ cursor-&gt;low_bytes = low_bytes;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 0.01 │ std r7,104(r25)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ cursor-&gt;up_match = up_match;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 0.00 │ std r8,80(r25)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ cursor-&gt;up_bytes = up_bytes;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 0.01 │ std r10,88(r25)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ if (UNIV_LIKELY(btr_search_enabled) &amp;&amp; !index-&gt;disable_ahi) {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 0.00 │ cmpwi cr7,r9,0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 0.00 │ ld r9,48(r29)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 0.01 │ ↓ beq cr7,10eb88a8 &lt;btr_cur_search_to_nth_level(dict_index_t*, 2348&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The &lt;em&gt;lbz&lt;/em&gt; is a load byte instruction referring to &lt;em&gt;btr_search_enabled&lt;/em&gt;. &lt;em&gt;btr_search_enabled&lt;/em&gt; and is the MySQL server variable associated with the SQL global &lt;a href="https://dev.mysql.com/doc/refman/5.7/en/innodb-parameters.html#sysvar_innodb_adaptive_hash_index" target="_blank" rel="noopener noreferrer"&gt;innodb_adaptive_hash_index&lt;/a&gt; . As a global system variable, this isn’t changed frequently, probably only once at startup. As such it should be able to rest comfortably in the cache of all CPUs in a read only cache line.&lt;/p&gt;
&lt;p&gt;To find out why the relative address is examined in the mysql executable:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-9" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-9"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ readelf -a bin/mysqld | grep btr_search_enabled
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 8522: 0000000011aa1b40 1 OBJECT GLOBAL DEFAULT 24 btr_search_enabled
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 17719: 0000000011aa1b40 1 OBJECT GLOBAL DEFAULT 24 btr_search_enabled&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Taking the last two characters off the hexadecimal address &lt;em&gt;0000000011aa1b40&lt;/em&gt; and the other variables in the same 256 (0x100) byte address range can be examined.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-10" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-10"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ readelf -a bin/mysqld | grep 0000000011aa1b
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 1312: 0000000011aa1be0 296 OBJECT GLOBAL DEFAULT 24 fts_default_stopword
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 8522: 0000000011aa1b40 1 OBJECT GLOBAL DEFAULT 24 btr_search_enabled
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 9580: 0000000011aa1b98 16 OBJECT GLOBAL DEFAULT 24 fil_addr_null
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 11434: 0000000011aa1b60 8 OBJECT GLOBAL DEFAULT 24 zip_failure_threshold_pct
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 12665: 0000000011aa1b70 40 OBJECT GLOBAL DEFAULT 24 dot_ext
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 13042: 0000000011aa1b30 8 OBJECT GLOBAL DEFAULT 24 ut_rnd_ulint_counter
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 13810: 0000000011aa1b48 8 OBJECT GLOBAL DEFAULT 24 srv_checksum_algorithm
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 18831: 0000000011aa1bb0 48 OBJECT GLOBAL DEFAULT 24 fts_common_tables
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 27713: 0000000011aa1b38 8 OBJECT GLOBAL DEFAULT 24 btr_ahi_parts
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 33183: 0000000011aa1b50 8 OBJECT GLOBAL DEFAULT 24 zip_pad_max
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 2386: 0000000011aa1b58 7 OBJECT LOCAL DEFAULT 24 _ZL9dict_ibfk
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 5961: 0000000011aa1b68 8 OBJECT LOCAL DEFAULT 24 _ZL8eval_rnd
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 10509: 0000000011aa1be0 296 OBJECT GLOBAL DEFAULT 24 fts_default_stopword
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 17719: 0000000011aa1b40 1 OBJECT GLOBAL DEFAULT 24 btr_search_enabled
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 18777: 0000000011aa1b98 16 OBJECT GLOBAL DEFAULT 24 fil_addr_null
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 20631: 0000000011aa1b60 8 OBJECT GLOBAL DEFAULT 24 zip_failure_threshold_pct
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 21862: 0000000011aa1b70 40 OBJECT GLOBAL DEFAULT 24 dot_ext
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 22239: 0000000011aa1b30 8 OBJECT GLOBAL DEFAULT 24 ut_rnd_ulint_counter
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 23007: 0000000011aa1b48 8 OBJECT GLOBAL DEFAULT 24 srv_checksum_algorithm
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 28028: 0000000011aa1bb0 48 OBJECT GLOBAL DEFAULT 24 fts_common_tables
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 36910: 0000000011aa1b38 8 OBJECT GLOBAL DEFAULT 24 btr_ahi_parts
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 42380: 0000000011aa1b50 8 OBJECT GLOBAL DEFAULT 24 zip_pad_max&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The &lt;em&gt;ut_rnd_ulint_counter&lt;/em&gt; is stored 16 bytes away from the &lt;em&gt;btr_search_enabled&lt;/em&gt;. Because of this, every invalidation of &lt;em&gt;ut_rnd_ulint_counter&lt;/em&gt; cache line results in a cache invalidation of &lt;em&gt;btr_search_enabled&lt;/em&gt; on POWER, and every other variable in the &lt;em&gt;0000000011aa1b00 to 0000000011aa1b40&lt;/em&gt; address range for x86_64 (or to &lt;em&gt;0000000011aa1b80&lt;/em&gt; for POWER and ARM64, or to &lt;em&gt;0000000011aa1c00&lt;/em&gt; for s390). There are no rules governing the layout of these variables so it was only luck that caused x86_64 to not be affected here.&lt;/p&gt;
&lt;p&gt;While the contended management of &lt;em&gt;ut_rnd_ulint_counter&lt;/em&gt; remains an unsolved problem on MySQL-5.7, putting all the global variables into the same memory block as a way to keep them out of the same cache as other potentially frequently changed variables is a way to prevent unintended contention. Global variables are an ideal candidate for this as they are changed infrequently and are usually hot in code paths. By pulling all the global variables in the same location, this maximized the cache by using less cache lines that remain in a read only mode.&lt;/p&gt;
&lt;p&gt;To achieve this co-location, MySQL uses the Linux kernel mechanism of using &lt;a href="https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html#index-section-variable-attribute" target="_blank" rel="noopener noreferrer"&gt;section attributes on variables&lt;/a&gt; and a linker script to bind their location. This was is described in MySQL &lt;a href="https://bugs.mysql.com/bug.php?id=97777" target="_blank" rel="noopener noreferrer"&gt;bug 97777&lt;/a&gt; and the MariaDB task &lt;a href="https://jira.mariadb.org/browse/MDEV-21145" target="_blank" rel="noopener noreferrer"&gt;MDEV-21145&lt;/a&gt;. The segmenting of the system global variables using this mechanism resulted in a 5.29% increase in the transactions per minute of the TPCCRunner benchmark (using MUTEXTYPE=sys).&lt;/p&gt;
&lt;h2 id="mutex-implementations"&gt;Mutex Implementations&lt;/h2&gt;
&lt;p&gt;Having discovered what I thought to be a smoking gun with the &lt;em&gt;ut_rnd_ulint_counter&lt;/em&gt; contention being the source of throughput problems for the benchmark, the &lt;em&gt;thread_local&lt;/em&gt; implementation of MySQL-8.0 was back-ported to MySQL-5.7.28. Disappointingly it was discovered that the throughput was approximately the same. From a perf profile perspective, the CPU usage was no longer in the inlined &lt;em&gt;ut_rnd_gen_ulint&lt;/em&gt; function, it was in the &lt;a href="https://github.com/mysql/mysql-server/blob/mysql-5.7.28/storage/innobase/sync/sync0arr.cc#L451..L488" target="_blank" rel="noopener noreferrer"&gt;sync_array_wait_event&lt;/a&gt; and &lt;a href="https://github.com/mysql/mysql-server/blob/mysql-5.7.28/storage/innobase/sync/sync0arr.cc#L333..L400" target="_blank" rel="noopener noreferrer"&gt;sync_array_reserve_cell&lt;/a&gt; functions.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-11" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-11"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Samples: 394K of event 'cycles:ppp', Event count (approx.): 2348024370370315
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;  Overhead Command Shared Object Symbol ◆
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- 45.48% mysqld [kernel.vmlinux] [k] _raw_spin_lock ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; __clone ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - 0x8b10 ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - 45.48% pfs_spawn_thread ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; handle_connection ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - do_command ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - 45.44% dispatch_command ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - 45.38% mysql_parse ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - 45.38% mysql_execute_command ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - 44.75% execute_sqlcom_select ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - handle_query ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - 38.28% JOIN::exec ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - 25.34% sub_select ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - 24.85% join_read_always_key ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; handler::ha_index_read_map ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - ha_innobase::index_read ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - 24.85% row_search_mvcc ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - 24.85% trx_assign_read_view ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - MVCC::view_open ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - 12.00% sync_array_wait_event ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - 5.44% os_event::wait_low ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - 2.21% os_event::wait_low ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; __pthread_mutex_unlock ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; system_call ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; sys_futex ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; + do_futex ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; + 2.04% __pthread_mutex_lock ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; + 0.94% pthread_cond_wait ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; + 2.34% __pthread_mutex_lock ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; + 2.28% sync_array_free_cell ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; + 1.60% sync_array_wait_event ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; + 10.69% sync_array_reserve_cell ▒
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; + 1.32% os_event_set&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;These functions are largely wrappers around a pthread locking implementation. From the version history these were imported from MySQL-5.0 with minor modification in 2013 compared to the pthread implementation that receives significant maintenance from the glibc community represented by major CPU architecture manufacturers.&lt;/p&gt;
&lt;p&gt;Thankfully, MySQL has a compile option &lt;em&gt;-DMUTEXTYPE=sys&lt;/em&gt; that results in &lt;a href="https://github.com/mysql/mysql-server/blob/mysql-5.7.28/storage/innobase/include/ib0mutex.h#L110..L123" target="_blank" rel="noopener noreferrer"&gt;pthreads being used directly&lt;/a&gt; and that increased x86 performance marginally, but much more significantly on POWER (understandable as since the sync_array elements have multiple instances on the same cache line size of 128 bytes compared to x86_64 which is 64 bytes). I’ll soon get to benchmarking these changes in more detail and generate some bug report to get this default changed in distro packages at least.&lt;/p&gt;
&lt;h2 id="encode---another-example"&gt;Encode - Another example&lt;/h2&gt;
&lt;p&gt;Even while carrying out this investigation a &lt;a href="https://jira.mariadb.org/browse/MDEV-21285" target="_blank" rel="noopener noreferrer"&gt;MariaDB zulip chat&lt;/a&gt; exposed a benchmark of &lt;a href="https://mariadb.com/kb/en/library/encode/" target="_blank" rel="noopener noreferrer"&gt;ENCODE&lt;/a&gt; (notably deprecated in MySQL-5.7) having scaling problems. Using the exact techniques here it was quick to generate and extracted a perf profile (&lt;a href="https://jira.mariadb.org/browse/MDEV-21285" target="_blank" rel="noopener noreferrer"&gt;MDEV-21285&lt;/a&gt;) and stack that showed every initial guess at the source of the problem – including mine – was incorrect. With the perf profile, however, the nature of the problem is quite clear – unlike the solution. That requires more thought.&lt;/p&gt;
&lt;h2 id="reportshow-your-perf-recordings"&gt;Report/Show your perf recordings&lt;/h2&gt;
&lt;p&gt;Alongside its low overhead during recording, the useful aspect of perf from a DBA perspective is that perf stack traces show only the MySQL code being executed, and the frequency of its execution. There is no exposed database data, SQL queries, or table names in the output. However, the &lt;a href="https://www.kernel.org/doc/html/latest/admin-guide/perf-security.html#overview" target="_blank" rel="noopener noreferrer"&gt;Perf Events and tool security (item 4)&lt;/a&gt; indicates that registers can be captured in a perf recording so be careful about sharing raw perf data.&lt;/p&gt;
&lt;p&gt;Once the raw perf data is processed by &lt;em&gt;perf report&lt;/em&gt;, with correct debug info and kernel, there are no addresses and only mysqld and kernel function names in its output. The most that is being exposing by sharing a perf report is the frequency of use of the MySQL code that was obtained externally. This should be enough to convince strict and competent managers and security people to sharing the perf recordings.&lt;/p&gt;
&lt;p&gt;With some realistic expectations (code can’t execute in 0 time, all of the database can’t be in CPU cache) you should now be able to show the parts of MySQL that are limiting your queries.&lt;/p&gt;
&lt;h3 id="resulting-bug-reports"&gt;Resulting bug reports&lt;/h3&gt;
&lt;p&gt;MySQL:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://bugs.mysql.com/bug.php?id=97777" target="_blank" rel="noopener noreferrer"&gt;bug 97777&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bugs.mysql.com/bug.php?id=97822" target="_blank" rel="noopener noreferrer"&gt;bug 97822&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;MariaDB:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://jira.mariadb.org/browse/MDEV-21145" target="_blank" rel="noopener noreferrer"&gt;MDEV-21145 &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://jira.mariadb.org/browse/MDEV-21452" target="_blank" rel="noopener noreferrer"&gt;MDEV-21452&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://jira.mariadb.org/browse/MDEV-21212" target="_blank" rel="noopener noreferrer"&gt;MDEV-21212&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;–&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Disclaimer: The postings on this site are the authors own and don’t necessarily represent IBM’s positions, strategies or opinions.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The content in this blog is provided in good faith by members of the open source community. Percona has not edited or tested the technical content. Views expressed are the authors’ own. When using the advice from this or any other online resource test ideas before applying them to your production systems, and always secure a working back up.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href="https://unsplash.com/@ripato?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" target="_blank" rel="noopener noreferrer"&gt;Ricardo Gomez Angel&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/perforations?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" target="_blank" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;</content:encoded>
      <author>Daniel Black</author>
      <category>cacheline</category>
      <category>MariaDB</category>
      <category>MySQL</category>
      <category>perf</category>
      <category>performance</category>
      <category>POWER</category>
      <media:thumbnail url="https://percona.community/blog/2020/01/ricardo-gomez-angel-87vUJY3ntyI-unsplash_hu_78060d87e7ddad26.jpg"/>
      <media:content url="https://percona.community/blog/2020/01/ricardo-gomez-angel-87vUJY3ntyI-unsplash_hu_17197b9de458aa08.jpg" medium="image"/>
    </item>
    <item>
      <title>How To Contribute to PMM Documentation</title>
      <link>https://percona.community/blog/2020/01/28/how-to-contribute-to-pmm-documentation/</link>
      <guid>https://percona.community/blog/2020/01/28/how-to-contribute-to-pmm-documentation/</guid>
      <pubDate>Tue, 28 Jan 2020 16:43:38 UTC</pubDate>
      <description>We’d love to see more contributions towards the development and improvement of Percona Monitoring and Management (PMM), one of Percona’s most valued projects. Like all of Percona’s software, PMM is free and open-source. An area where we’d dearly love to see some community provided enhancement is in its documentation. In future blog posts, we’ll provide some insight on how to contribute to our software but… the beauty of documentation is that it’s straightforward to maintain, and you don’t even have to be a programmer to be able to provide valuable corrections and enhancements. So it’s a great place to start. In this post, we set out how you might be able to contribute to this to make PMM even better than it is already!</description>
      <content:encoded>&lt;p&gt;We’d love to see more contributions towards the development and improvement of &lt;a href="https://www.percona.com/software/database-tools/percona-monitoring-and-management" target="_blank" rel="noopener noreferrer"&gt;Percona Monitoring and Management (PMM),&lt;/a&gt; one of Percona’s most valued projects. Like all of Percona’s software, PMM is free and open-source. An area where we’d dearly love to see some community provided enhancement is in its documentation. In future blog posts, we’ll provide some insight on how to contribute to our software but… the beauty of documentation is that it’s straightforward to maintain, and you don’t even have to be a programmer to be able to provide valuable corrections and enhancements. So it’s a great place to start. In this post, we set out how you might be able to contribute to this to make PMM even better than it is already!&lt;/p&gt;
&lt;h2 id="some-context"&gt;Some context&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.percona.com/doc/percona-monitoring-and-management/2.x/index.html" target="_blank" rel="noopener noreferrer"&gt;PMM documentation&lt;/a&gt; is available from the Percona website, and it is an essential part of PMM; all the tasks and functions of the developer need to be documented. There are a couple of things that might inspire you to contribute to enhancing the PMM documentation:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It’s something you can do without feeling you need stellar programming skills&lt;/li&gt;
&lt;li&gt;It is useful for a large number of users.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;By the way, if you aren’t sure where to start, there are currently more than 50 PMM documentation improvement tasks listed in &lt;a href="https://perconadev.atlassian.net/browse/PMM-5333?jql=project%20%3D%20PMM%20AND%20resolution%20%3D%20Unresolved%20AND%20component%20%3D%20Documentation" target="_blank" rel="noopener noreferrer"&gt;JIRA,&lt;/a&gt; Percona’s fault recording system. Once you have checked out a few of those and become familiar with the documentation structure and style, you’ll probably be able to find more issues to report… or think of your own improvements.&lt;/p&gt;
&lt;p&gt;Even enhancements that help only a few users are very welcome.&lt;/p&gt;
&lt;h2 id="a-simple-example"&gt;A simple example&lt;/h2&gt;
&lt;p&gt;This article provides a simple example which changes only a few lines of documentation, but these steps are all you need to be able to  contribute all manner of documentation improvements. Here, I focus just on the process and tools that are used to create the documentation. You’ll find more background information in the &lt;a href="https://www.percona.com/community/contributions/pmm" target="_blank" rel="noopener noreferrer"&gt;PMM Contributions Overview&lt;/a&gt;.
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2020/01/PMM-Contribute-1_hu_1c1b623882062453.png 480w, https://percona.community/blog/2020/01/PMM-Contribute-1_hu_4df0ffc42a97dc10.png 768w, https://percona.community/blog/2020/01/PMM-Contribute-1_hu_2e97ee929d5662eb.png 1400w"
src="https://percona.community/blog/2020/01/PMM-Contribute-1.png" alt=" " /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h2 id="my-work-plan"&gt;My work plan…&lt;/h2&gt;
&lt;h3 id="or-a-summary"&gt;…or a summary&lt;/h3&gt;
&lt;p&gt;Having decided I was going to be a contributor, too, I created a simple outline of what I needed to do. Here it is:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Find an existing task or create a new one. PMM is an excellent product, but it has known &lt;a href="https://perconadev.atlassian.net/issues/?jql=project+%3D+PMM+AND+component+%3D+Documentation" target="_blank" rel="noopener noreferrer"&gt;documentation issues.&lt;/a&gt; that I can help with&lt;/li&gt;
&lt;li&gt;Find the repository and install the PMM documentation on my computer so I can work out how to make changes&lt;/li&gt;
&lt;li&gt;Make the changes and test them.&lt;/li&gt;
&lt;li&gt;Send the changes to the PMM repository.&lt;/li&gt;
&lt;li&gt;Go through a review and verification process so that my changes can be published.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In the process of exploring this, I’ve written and published a manual for you, which is available in the primary documentation repository at &lt;a href="https://github.com/percona/pmm-doc" target="_blank" rel="noopener noreferrer"&gt;https://github.com/percona/pmm-doc.&lt;/a&gt; This was my small contribution, and you are welcome to help improve that too!&lt;/p&gt;
&lt;p&gt;If you’re ready to jump in, though, let’s take a look step-by-step at what’s involved.&lt;/p&gt;
&lt;h3 id="1-find-an-existing-task-or-create-a-new-one"&gt;1. Find an existing task or create a new one&lt;/h3&gt;
&lt;p&gt;Percona has identified over &lt;a href="https://perconadev.atlassian.net/issues/?jql=project%20%3D%20PMM%20AND%20resolution%20%3D%20Unresolved%20AND%20component%20%3D%20Documentation" target="_blank" rel="noopener noreferrer"&gt;50 specific documentation needs for PMM&lt;/a&gt; as shown in &lt;a href="https://perconadev.atlassian.net/projects/PMM/issues/PMM-5075?filter=allopenissues" target="_blank" rel="noopener noreferrer"&gt;Percona’s JIRA repository of all PMM development tasks&lt;/a&gt;. Create an account and log in to JIRA, then you can choose a current task, or create a new report to start contributing to PMM.&lt;/p&gt;
&lt;p&gt;In fact, for the sake of this example, while I liked the look of quite a few of the existing tasks I wanted to take the first step quickly. So I identified an improvement for the main documentation page and created a new record in JIRA. Here it is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://perconadev.atlassian.net/browse/PMM-5012" target="_blank" rel="noopener noreferrer"&gt;https://perconadev.atlassian.net/browse/PMM-5012&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;It’s really important that you use JIRA as the starting point for any changes&lt;/strong&gt;. This is the only way for the PMM team to find out what your intentions are and to advise you of the best approach. Through JIRA, too, you can discuss the task before you start work. If you want to work on an existing report, then I recommend that you contact the author of the task through comments in JIRA.
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2020/01/PMM-Contribute-2_hu_10d09c79448f3e8b.png 480w, https://percona.community/blog/2020/01/PMM-Contribute-2_hu_981f35364b7097dd.png 768w, https://percona.community/blog/2020/01/PMM-Contribute-2_hu_cac33e2989c14f49.png 1400w"
src="https://percona.community/blog/2020/01/PMM-Contribute-2.png" alt=" " /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h3 id="2-repository-and-installation"&gt;2. Repository and installation&lt;/h3&gt;
&lt;p&gt;All PMM documentation is written using the &lt;a href="https://www.sphinx-doc.org/" target="_blank" rel="noopener noreferrer"&gt;Sphinx engine markup language&lt;/a&gt;.  We store the documentation as *.rst files inside GitHub’s &lt;a href="https://github.com/percona/pmm-doc" target="_blank" rel="noopener noreferrer"&gt;PMM documentation repository&lt;/a&gt;. Sphinx allows easy publishing of various output formats such as HTML, LaTeX (for PDF), ePub, Texinfo, etc. You’ll need a GitHub account. A simple overview:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The text is written using a unique markup language as .rst files. The syntax is very similar to markdown but with its own rules. All the rules are available on the &lt;a href="http://www.sphinx-doc.org/en/master/" target="_blank" rel="noopener noreferrer"&gt;official website&lt;/a&gt; or can be found implemented in existing documentation.&lt;/li&gt;
&lt;li&gt;Source files are stored in the GitHub repository. Each version of PMM has its branch in the repository.&lt;/li&gt;
&lt;li&gt;The Sphinx engine collects the source code into an HTML documentation. This works very quickly.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In fact, you don’t even need to install Sphinx-doc, you can write or edit documentation without it just using a standard editor.
&lt;figure&gt;&lt;img src="https://percona.community/blog/2020/01/PMM-Contribute-3.png" alt=" " /&gt;&lt;/figure&gt; The PMM project team uses several separate repositories. See this &lt;a href="https://github.com/percona/pmm/tree/PMM-2.0" target="_blank" rel="noopener noreferrer"&gt;list of all PMM repositories in Github&lt;/a&gt;. One of them is the &lt;a href="https://github.com/percona/pmm-doc" target="_blank" rel="noopener noreferrer"&gt;PMM documentation repository&lt;/a&gt;. You’ll find a link to the documentation repository from the main PMM repository at &lt;a href="https://github.com/percona/pmm/tree/PMM-2.0" target="_blank" rel="noopener noreferrer"&gt;https://github.com/percona/pmm/tree/PMM-2.0&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;To begin, &lt;a href="https://help.github.com/en/github/getting-started-with-github/fork-a-repo" target="_blank" rel="noopener noreferrer"&gt;fork the PMM repository&lt;/a&gt; under your GitHub account. You can then edit this personal fork safely, without interfering with the main repository. Later on, Percona can pull your changes into its main repository.&lt;/p&gt;
&lt;h4 id="local-installation-of-the-documentation"&gt;Local installation of the documentation&lt;/h4&gt;
&lt;p&gt;Install the documentation locally on your computer. Here’s the process:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Clone the fork repository to your environment.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.sphinx-doc.org/en/master/usage/installation.html" target="_blank" rel="noopener noreferrer"&gt;Install Sphinx-doc&lt;/a&gt; according to the instructions in the repository&lt;/li&gt;
&lt;li&gt;Build the documentation. Use the instruction from &lt;a href="https://github.com/percona/pmm-doc#install" target="_blank" rel="noopener noreferrer"&gt;pmm-doc repository&lt;/a&gt; (see p.3 in Install section)&lt;/li&gt;
&lt;li&gt;Check the result in your browser.  You may need the Apache webserver on your computer. For example, you can use a Docker image with Apache (&lt;a href="https://hub.docker.com/_/httpd" target="_blank" rel="noopener noreferrer"&gt;link&lt;/a&gt;). However, documentation may open in your browser without this.&lt;/li&gt;
&lt;li&gt;Edit some changes and rebuild.&lt;/li&gt;
&lt;li&gt;Check the changes in your browser.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;… and so on. It’s essential not only to install but also to check what you can change. If you’d like more instructions, please leave a message in the comments to this post or contact me &lt;a href="mailto:community-team@percona.com"&gt;by email&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="3-making-changes-and-testing-them"&gt;3. Making changes and testing them&lt;/h3&gt;
&lt;p&gt;Now you can make changes. Two important points:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;If you aren’t sure how make changes correctly, take a look at how others do it. There are already plenty of changes in the documentation; and you should be able to see them.&lt;/li&gt;
&lt;li&gt;It’s essential to make changes properly, otherwise your hard work will be wasted.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We have already selected or created a task in JIRA, and we will need its ID. The JIRA task ID is used as an identifier for the JIRA and GitHub bundle.&lt;/p&gt;
&lt;p&gt;We need to create a new git branch. When creating a branch, correctly name it using the formula: JIRA_ID_SHORTTITLE. For example, my GitHub user is dbazhenov, and the changes I’m making are related to the JIRA task PMM-5012, so here’s the command:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git checkout -b PMM-5012_dbazhenov_introduction&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;So… you found the right page and made some changes. If you created a new page, there are examples in the existing documentation. In this case, you need to create a new page file and include it in the toctree level below. If you need help with that, please just ask.&lt;/p&gt;
&lt;p&gt;Now save your changes to git and be sure to call the commit correctly. What do I mean by that? Well, be sure to use the task ID and describe in detail the change you’ve made. Here’s my example:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-1"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git add .
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git commit -m "PMM-5012 PostgreSQL and ProxySQL have been added to the home page"&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Now, build the documentation and check the result in your browser. If you get warnings during the build, this is mostly likely to be due to using different versions of Sphinx and nothing to worry about.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2020/01/PMM-Contribute-7-warn.png" alt=" " /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;When you see the documentation, don’t worry that it’s not CSS or JavaScript, only pure HTML. In due course, it will be built into the current percona.com website and will inherit its styling from there.&lt;/p&gt;
&lt;h3 id="4-saving-the-result-and-contributing"&gt;4. Saving the result and contributing&lt;/h3&gt;
&lt;p&gt;This is where you send your work to the PMM team. First, you have to send your branch to your own fork. That’s straightforward:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-2" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-2"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; git push origin PMM-5012_dbazhenov&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Now, open your repository and check the results. In particular, make sure that your branch holds only the changed files. It’s possible that additional files have been uploaded. To check the result, create &lt;a href="https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests" target="_blank" rel="noopener noreferrer"&gt;a pull request&lt;/a&gt; in the master branch of your repository. This will give you a list of the changes that you’ve made.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2020/01/PMM-Contribute-5_hu_c8205f9871ed0107.png 480w, https://percona.community/blog/2020/01/PMM-Contribute-5_hu_6214fa658463ed88.png 768w, https://percona.community/blog/2020/01/PMM-Contribute-5_hu_bf49d9cb7dc9b968.png 1400w"
src="https://percona.community/blog/2020/01/PMM-Contribute-5.png" alt=" " /&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2020/01/PMM-Contribute-4.png" alt=" " /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Once you’ve checked that the pull request has only the intended changes, you can make a second pull request, but this time it’s to the Percona repository.&lt;/p&gt;
&lt;p&gt;Here’s my pull request: &lt;a href="https://github.com/percona/pmm-doc/pull/45" target="_blank" rel="noopener noreferrer"&gt;https://github.com/percona/pmm-doc/pull/45&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2020/01/PMM-Contribute-6_hu_a24e26e2ae910c77.png 480w, https://percona.community/blog/2020/01/PMM-Contribute-6_hu_129d0bcaabd8198c.png 768w, https://percona.community/blog/2020/01/PMM-Contribute-6_hu_bae6a0276ffc5110.png 1400w"
src="https://percona.community/blog/2020/01/PMM-Contribute-6.png" alt=" " /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h3 id="5-passing-a-review"&gt;5. Passing a review&lt;/h3&gt;
&lt;p&gt;All submissions are thoroughly reviewed before being released. This guarantees the quality and safety of PMM. Even if it’s “just” documentation, it has a very important role to play in the user experience.&lt;/p&gt;
&lt;p&gt;You will also need to confirm the Contributor License Agreement.&lt;/p&gt;
&lt;p&gt;Once I’d submitted my changes, I waited a little while, and then the Percona team checked my work and sent it back to me for improvement. I made the necessary changes and – this is an important point – I sent them to the &lt;strong&gt;same pull request&lt;/strong&gt;.
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2020/01/PMM-Contribute-8-lic_hu_889bfe8a10809cdd.png 480w, https://percona.community/blog/2020/01/PMM-Contribute-8-lic_hu_e8d54b73856ac009.png 768w, https://percona.community/blog/2020/01/PMM-Contribute-8-lic_hu_564bd6e3f781cf5f.png 1400w"
src="https://percona.community/blog/2020/01/PMM-Contribute-8-lic.png" alt=" " /&gt;&lt;/figure&gt;
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2020/01/PMM-Contribute-9_hu_cf73d2ff4193d390.png 480w, https://percona.community/blog/2020/01/PMM-Contribute-9_hu_e6f3ad12818c865a.png 768w, https://percona.community/blog/2020/01/PMM-Contribute-9_hu_257f945253406da2.png 1400w"
src="https://percona.community/blog/2020/01/PMM-Contribute-9.png" alt=" " /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h4 id="release"&gt;Release&lt;/h4&gt;
&lt;p&gt;There’s nothing for you to do here, the Percona team have to create releases of software and documentation.&lt;/p&gt;
&lt;p&gt;After a few days, Percona published my changes to the PMM documentation site.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.percona.com/doc/percona-monitoring-and-management/2.x/index.html" target="_blank" rel="noopener noreferrer"&gt;https://www.percona.com/doc/percona-monitoring-and-management/2.x/index.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;That’s how I ended up on the list of pmm-doc contributors.
&lt;figure&gt;&lt;img src="https://percona.community/blog/2020/01/PMM-Contribute-10.png" alt=" " /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Contributing to documentation is a great way to start your journey as an open source contributor, especially if you are not too familiar with git and GitHub. If you’d like to start contributing to open source, then I recommend you try contributing to the PMM documentation. Instructions here: &lt;a href="https://github.com/percona/pmm-doc" target="_blank" rel="noopener noreferrer"&gt;https://github.com/percona/pmm-doc&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;All the same, I realize that documentation is not for everyone, even as a means of introduction. So here are some ideas and options for contributing to PMM in other ways: &lt;a href="https://www.percona.com/community/contributions/pmm" target="_blank" rel="noopener noreferrer"&gt;https://www.percona.com/community/contributions/pmm&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;As already reported, I more than happy to help you out. Just sent me an email to &lt;a href="mailto:community-team@percona.com"&gt;community-team@percona.com&lt;/a&gt; and add “PMM Community” to your subject line so that my colleagues know that the email’s for me. Good luck!&lt;/p&gt;</content:encoded>
      <author>Daniil Bazhenov</author>
      <category>daniil.bazhenov</category>
      <category>contributing</category>
      <category>contributions</category>
      <category>contributors</category>
      <category>documentation</category>
      <category>Open Source Databases</category>
      <category>Percona Monitoring and Management</category>
      <category>Tools</category>
      <media:thumbnail url="https://percona.community/blog/2020/01/PMM-Contribute-10_hu_7cafffa62fa0b179.jpg"/>
      <media:content url="https://percona.community/blog/2020/01/PMM-Contribute-10_hu_e8c3686c85efc412.jpg" medium="image"/>
    </item>
    <item>
      <title>Percona Server for MySQL 8.0 – New Data Masking Feature</title>
      <link>https://percona.community/blog/2019/12/13/percona-server-for-mysql-8-0-new-data-masking-feature/</link>
      <guid>https://percona.community/blog/2019/12/13/percona-server-for-mysql-8-0-new-data-masking-feature/</guid>
      <pubDate>Fri, 13 Dec 2019 10:43:14 UTC</pubDate>
      <description>Database administrators are responsible for maintaining the privacy and integrity of data. When the data contains confidential information, your company has a legal obligation to ensure that privacy is maintained. Even so, being able to access the information contained in that dataset, for example for testing or reporting purposes, has great value so what to do? MySQL Enterprise Edition offers data masking and de-identification, so I decided to contribute similar functionality to Percona Server for MySQL. In this post, I provide some background context and information on how to use these new functions in practice.</description>
      <content:encoded>&lt;p&gt;Database administrators are responsible for maintaining the privacy and integrity of data. When the data contains confidential information, your company has a legal obligation to ensure that privacy is maintained. Even so, being able to access the information contained in that dataset, for example for testing or reporting purposes, has great value so what to do? &lt;a href="https://dev.mysql.com/doc/refman/8.0/en/data-masking.html" target="_blank" rel="noopener noreferrer"&gt;MySQL Enterprise Edition&lt;/a&gt; offers data masking and de-identification, so I decided to contribute similar functionality to &lt;a href="https://www.percona.com/doc/percona-server/LATEST/security/data-masking.html" target="_blank" rel="noopener noreferrer"&gt;Percona Server for MySQL&lt;/a&gt;. In this post, I provide some background context and information on how to use these new functions in practice.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2019/12/data-masking-Percona-Server-for-MySQL.jpg" alt="Data Masking in Percona Server for MySQL 8.0.17" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h2 id="some-context"&gt;Some context&lt;/h2&gt;
&lt;p&gt;One of the most important assets of any company is data. Having good data allows engineers to build better systems and user experiences.&lt;/p&gt;
&lt;p&gt;Even through our most trivial activities, we continuously generate and share great volumes of data. I’m walking down the street and if I take a look at my phone it’s quite straightforward to get recommendations for a place to have lunch. The platform knows that it’s almost lunch time and that I have visited this nearby restaurant, or a similar one, a few times in the past. Sounds cool, right?&lt;/p&gt;
&lt;p&gt;But this process could be more manual than we might think at first. Even if the system has implemented things like AI or Machine Learning, a human will have validated the results; they might have taken a peek to ensure that everything is fine; or perhaps they are developing some new cool feature that must be tested… And this means that someone, somewhere has the ability to access my data. Or your data.&lt;/p&gt;
&lt;p&gt;Now, that is not so great, is it?&lt;/p&gt;
&lt;p&gt;In the last decade or so, governments around the world have taken this challenge quite seriously. They have enforced a series of rules to guarantee that the data is not only safely stored, but also safely used. I’m sure you will have heard terms like PCI, GDPR or HIPAA. They contain mandatory guidelines for how our data can be used, for primary or secondary purposes, and if it can be used at all.&lt;/p&gt;
&lt;h2 id="data-masking-and-de-identification"&gt;Data masking and de-identification&lt;/h2&gt;
&lt;p&gt;One of the most basic safeguarding rules is that if the data is to be used for secondary purposes – such as for data analytics – it has to be de-identified in a way that it would make impossible identify the original individual.&lt;/p&gt;
&lt;p&gt;Let’s say that the company ACME is storing employee data.&lt;/p&gt;
&lt;p&gt;We will use the &lt;a href="https://github.com/datacharmer/test_db" target="_blank" rel="noopener noreferrer"&gt;example database of employees&lt;/a&gt; that’s freely available.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Employee number
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;First name
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Last name
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Birth date
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Gender
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Hire date
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Gross salary
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Salary from date
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Salary to date&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;We can clearly see that all those fields can be classified as private information. Some of these directly identify the original individual, like employee number or first + last name. Others could be used for indirect identification: I could ask my co-workers their birthday and guess the owner of that data using birth date.&lt;/p&gt;
&lt;p&gt;So, here is where de-identification and data-masking come into play. But what are the differences?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;De-identification&lt;/strong&gt; transforms the original data into something different that could look more or less real. For example, I could de-identify birth date and get a different date.&lt;/p&gt;
&lt;p&gt;However, this method would make that information unusable if I want to see the relationship between salary and employee’s age.&lt;/p&gt;
&lt;p&gt;On the other hand, &lt;strong&gt;data-masking&lt;/strong&gt; transforms the original data leaving some part untouched. I could mask birth date replacing the month and day for January first. That way, the year would be retained and that would allow us to identify that salary–employee’s age relationship.&lt;/p&gt;
&lt;p&gt;Of course, if the dataset I’m working with is not big enough, certain methods of data-masking would be inappropriate as I could still deduce who the data belonged to.&lt;/p&gt;
&lt;h2 id="mysql-data-masking"&gt;MySQL data masking&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Oracle’s MySQL Enterprise Edition&lt;/strong&gt; offers a &lt;a href="https://dev.mysql.com/doc/refman/8.0/en/data-masking.html" target="_blank" rel="noopener noreferrer"&gt;de-identification and data-masking solution for MySQL&lt;/a&gt;, using a flexible set of functions that cover most of our needs.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Percona Server for MySQL 8.0.17&lt;/strong&gt; introduces that functionality as &lt;a href="https://www.percona.com/doc/percona-server/LATEST/security/data-masking.html" target="_blank" rel="noopener noreferrer"&gt;an open source plugin&lt;/a&gt;, and is compatible with Oracle’s implementation. You no longer need to code slow and complicated stored procedures to achieve data masking, and you can migrate the processes that were written for the MySQL Enterprise Edition to Percona Server for MySQL. Go grab a cup of coffee and contribute something cool to the community with all that time you have got back. ☺&lt;/p&gt;
&lt;h2 id="in-the-lab"&gt;In the lab&lt;/h2&gt;
&lt;p&gt;Put on your thinking cap and let’s see how it works.&lt;/p&gt;
&lt;p&gt;First we need an instance of Percona MySQL Server 8.0.17 or newer. I think containers are the most flexible way to test new stuff so I will be using that, but you could use a virtual server or just a traditional setup. Let’s download the latest version of Percona MySQL Server in a ready to run container:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-1"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker pull percona:8.0.17-1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Eventually that command should work but sadly, Percona hadn’t built this version of the docker image when this article was written. Doing it yourself is quite simple, though, and by the time you read this it will likely be already there.&lt;/p&gt;
&lt;p&gt;Once in place, Running an instance of Percona MySQL Server has never been so easy:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-2" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-2"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker run --name ps -e MYSQL_ROOT_PASSWORD=secret -d percona:8.0.17-8&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;We’ll logon to the new container:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-3" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-3"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker exec -ti ps mysql -u root -p&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Now is the time to download the test database employees from &lt;a href="https://github.com/datacharmer/test_db" target="_blank" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; and load it into our Percona Server. You can follow the official instructions in the project page.&lt;/p&gt;
&lt;p&gt;Next step is to enable the data de-identification and masking feature. Installing the data masking module in Percona MySQL Server is easier than in Oracle.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-4" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-4"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mysql&gt; INSTALL PLUGIN data_masking SONAME 'data_masking.so';
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Query OK, 0 rows affected (0.06 sec)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This automatically defines a set of global functions in our MySQL instance, so we don’t need to do anything else.&lt;/p&gt;
&lt;h3 id="a-new-concept-dictionaries"&gt;A new concept: Dictionaries&lt;/h3&gt;
&lt;p&gt;Sometimes we will like to generate new data selecting values from a predefined collection. For example we could want to have first name  values that are really first names and not a random alphanumeric. This will make our masked data looks real, and it’s perfect for creating demo or QA environments.&lt;/p&gt;
&lt;p&gt;For this task we have &lt;strong&gt;dictionaries&lt;/strong&gt;. They are nothing more than text files containing a value per line that are loaded into MySQL memory. You need to be aware that the contents of the file are fully loaded into memory and that the dictionary only exists while MySQL is running. So keep this in mind before loading any huge file or after restarting the instance.&lt;/p&gt;
&lt;p&gt;For our lab we will load two dictionaries holding first and last names. You can use these files or create different ones: &lt;a href="https://raw.githubusercontent.com/philipperemy/name-dataset/master/names_dataset/first_names.all.txt" target="_blank" rel="noopener noreferrer"&gt;first names&lt;/a&gt; and &lt;a href="https://raw.githubusercontent.com/philipperemy/name-dataset/master/names_dataset/last_names.all.txt" target="_blank" rel="noopener noreferrer"&gt;last names&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Store the files in a folder of your database server (or container) readable by the mysqld  process.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-5" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-5"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;wget https://raw.githubusercontent.com/philipperemy/name-dataset/master/names_dataset/first_names.all.txt
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker cp first_names.all.txt ps:/tmp/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;wget https://raw.githubusercontent.com/philipperemy/name-dataset/master/names_dataset/last_names.all.txt
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker cp last_names.all.txt ps:/tmp/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Once the files are in our server we can map them as MySQL dictionaries.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-6" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-6"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mysql&gt; select gen_dictionary_load('/tmp/first_names.all.txt', 'first_names');
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+----------------------------------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| gen_dictionary_load('/tmp/first_names.all.txt', 'first_names') |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+----------------------------------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| Dictionary load success                                        |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+----------------------------------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;1 row in set (0.04 sec)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mysql&gt; select gen_dictionary_load('/tmp/last_names.all.txt', 'last_names');
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+--------------------------------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| gen_dictionary_load('/tmp/last_names.all.txt', 'last_names') |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+--------------------------------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| Dictionary load success                                      |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+--------------------------------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;1 row in set (0.03 sec)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="masking-some-data"&gt;Masking some data&lt;/h3&gt;
&lt;p&gt;Now let’s take another look at our employees table&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-7" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-7"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mysql&gt; show columns from employees;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+------------+---------------+------+-----+---------+-------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| Field      | Type   | Null | Key | Default | Extra |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+------------+---------------+------+-----+---------+-------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| emp_no     | int(11)   | NO | PRI | NULL    | |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| birth_date | date          | NO | | NULL   | |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| first_name | varchar(14)   | NO | | NULL   | |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| last_name  | varchar(16)   | NO | | NULL   | |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| gender     | enum('M','F') | NO   | | NULL   | |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| hire_date  | date   | NO | | NULL    | |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+------------+---------------+------+-----+---------+-------+&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Ok, it’s very likely we will want to de-identify everything in this table. You can apply different methods to achieve your security requirements, but I will create a view with the following transformations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;emp_no&lt;/strong&gt;: get a random value from 900.000.000 to 999.999.999&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;birth_date&lt;/strong&gt;: set it to January 1st of the original year&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;first_name&lt;/strong&gt;: set a random first name from a list of names that we have in a text file&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;last_name&lt;/strong&gt;: set a random last name from a list of names that we have in a text file&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;gender&lt;/strong&gt;: no transformation&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;hire_date&lt;/strong&gt;: set it to January 1st of the original year&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-8" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-8"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;CREATE VIEW deidentified_employees
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;AS
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;SELECT
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;  gen_range(900000000, 999999999) as emp_no,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;  makedate(year(birth_date), 1) as birth_date,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;  gen_dictionary('first_names') as first_name,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;  gen_dictionary('last_names') as last_name,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;  gender,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;  makedate(year(hire_date), 1) as hire_date
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;FROM employees;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Let’s check how the data looks in our de-identified view.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-9" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-9"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mysql&gt; SELECT * FROM employees LIMIT 10;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+--------+------------+------------+-----------+--------+------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| emp_no | birth_date | first_name | last_name | gender | hire_date  |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+--------+------------+------------+-----------+--------+------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;|  10001 | 1953-09-02 | Georgi     | Facello | M | 1986-06-26 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;|  10002 | 1964-06-02 | Bezalel    | Simmel | F | 1985-11-21 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;|  10003 | 1959-12-03 | Parto      | Bamford | M | 1986-08-28 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;|  10004 | 1954-05-01 | Chirstian  | Koblick | M | 1986-12-01 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;|  10005 | 1955-01-21 | Kyoichi    | Maliniak | M | 1989-09-12 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;|  10006 | 1953-04-20 | Anneke     | Preusig | F | 1989-06-02 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;|  10007 | 1957-05-23 | Tzvetan    | Zielinski | F | 1989-02-10 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;|  10008 | 1958-02-19 | Saniya     | Kalloufi | M | 1994-09-15 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;|  10009 | 1952-04-19 | Sumant     | Peac | F | 1985-02-18 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;|  10010 | 1963-06-01 | Duangkaew  | Piveteau | F | 1989-08-24 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+--------+------------+------------+-----------+--------+------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;10 rows in set (0.00 sec)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mysql&gt; SELECT * FROM deidentified_employees LIMIT 10;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+-----------+------------+------------+---------------+--------+------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| emp_no    | birth_date | first_name | last_name     | gender | hire_date |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+-----------+------------+------------+---------------+--------+------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| 930277580 | 1953-01-01 | skaidrīte  | molash | M | 1986-01-01 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| 999241458 | 1964-01-01 | grasen     | cessna | F | 1985-01-01 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| 951699030 | 1959-01-01 | imelda     | josephpauline | M | 1986-01-01 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| 985905688 | 1954-01-01 | dunc       | burkhardt | M | 1986-01-01 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| 923987335 | 1955-01-01 | karel      | wanamaker | M | 1989-01-01 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| 917751275 | 1953-01-01 | mikrut     | allee | F | 1989-01-01 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| 992344830 | 1957-01-01 | troyvon    | muma | F | 1989-01-01 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| 980277046 | 1958-01-01 | aliziah    | tiwnkal | M | 1994-01-01 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| 964622691 | 1952-01-01 | dominiq    | legnon | F | 1985-01-01 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| 948247243 | 1963-01-01 | sedale     | tunby | F | 1989-01-01 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+-----------+------------+------------+---------------+--------+------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;10 rows in set (0.01 sec)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The data looks quite different, but remains good enough to apply some analytics and get meaningful results. Let’s de-identify the table salaries  this time.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-10" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-10"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mysql&gt; show columns from salaries;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+-----------+---------+------+-----+---------+-------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| Field     | Type | Null | Key | Default | Extra |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+-----------+---------+------+-----+---------+-------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| emp_no    | int(11) | NO   | PRI | NULL |       |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| salary    | int(11) | NO   | | NULL |       |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| from_date | date    | NO | PRI | NULL |       |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| to_date   | date | NO   | | NULL |       |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+-----------+---------+------+-----+---------+-------+&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;We could use something like this:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-11" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-11"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;CREATE VIEW deidentified_salaries
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;AS
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;SELECT
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gen_range(900000000, 999999999) as emp_no,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gen_range(40000, 80000) as salary,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mask_inner(date_format(from_date, '%Y-%m-%d'), 4, 0) as from_date,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mask_outer(date_format(to_date, '%Y-%m-%d'), 4, 2, '0') as to_date
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;FROM salaries;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;We are using again the function gen_range . For the dates this time we are using the very flexible functions mask_inner  and mask_outer  that replace some characters in the original string. Let’s see how the data looks now.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In a real life exercise we would like to have the same values for emp_no across all the tables to keep referential integrity. This is where I think the original MySQL data-masking plugin falls short, as we don’t have deterministic functions using the original value as seed.&lt;/p&gt;&lt;/blockquote&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-12" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-12"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mysql&gt; SELECT * FROM salaries LIMIT 10;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+--------+--------+------------+------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| emp_no | salary | from_date  | to_date |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+--------+--------+------------+------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;|  10001 |  60117 | 1986-06-26 | 1987-06-26 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;|  10001 |  62102 | 1987-06-26 | 1988-06-25 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;|  10001 |  66074 | 1988-06-25 | 1989-06-25 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;|  10001 |  66596 | 1989-06-25 | 1990-06-25 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;|  10001 |  66961 | 1990-06-25 | 1991-06-25 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;|  10001 |  71046 | 1991-06-25 | 1992-06-24 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;|  10001 |  74333 | 1992-06-24 | 1993-06-24 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;|  10001 |  75286 | 1993-06-24 | 1994-06-24 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;|  10001 |  75994 | 1994-06-24 | 1995-06-24 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;|  10001 |  76884 | 1995-06-24 | 1996-06-23 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+--------+--------+------------+------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;10 rows in set (0.00 sec)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mysql&gt; SELECT * FROM deidentified_salaries LIMIT 10;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+-----------+--------+------------+------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| emp_no    | salary | from_date  | to_date |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+-----------+--------+------------+------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| 929824695 | 61543  | 1986XXXXXX | 0000-06-00 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| 954275265 | 63138  | 1987XXXXXX | 0000-06-00 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| 948145700 | 53448  | 1988XXXXXX | 0000-06-00 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| 937927997 | 54704  | 1989XXXXXX | 0000-06-00 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| 978459605 | 78179  | 1990XXXXXX | 0000-06-00 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| 993464164 | 75526  | 1991XXXXXX | 0000-06-00 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| 946692434 | 51788  | 1992XXXXXX | 0000-06-00 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| 979870243 | 54807  | 1993XXXXXX | 0000-06-00 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| 958708118 | 70647  | 1994XXXXXX | 0000-06-00 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| 945701146 | 76056  | 1995XXXXXX | 0000-06-00 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+-----------+--------+------------+------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;10 rows in set (0.00 sec)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="clean-up"&gt;Clean-up&lt;/h3&gt;
&lt;p&gt;Remember that when you’re done, you can free up memory by removing the dictionaries. Restarting the instance will also remove the dictionaries.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-13" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-13"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mysql&gt; SELECT gen_dictionary_drop('first_names');
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| gen_dictionary_drop('first_names') |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| Dictionary removed                 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;1 row in set (0.01 sec)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mysql&gt; SELECT gen_dictionary_drop('last_names');
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| gen_dictionary_drop('last_names') |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| Dictionary removed                 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;1 row in set (0.01 sec)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;If you use the MySQL data-masking plugin to define different levels of access to the data, remember that you will need to load the dictionaries each time the instance is restarted. With this usage, for example, you could control the data that someone in support has access to, very much like a bargain-basement virtual private database solution. (I’m not proposing this for production systems!)&lt;/p&gt;
&lt;h2 id="other-de-identification-and-masking-functions"&gt;Other de-identification and masking functions&lt;/h2&gt;
&lt;p&gt;Percona Server for MySQL Data-Masking includes more functions that the ones we’ve seen here. We have specialized functions for Primary Account Numbers (PAN), Social Security Numbers (SSN), phone numbers, e-Mail addresses… And also generic functions that will allow us to de-identify types without a specialized method. Being an open source plugin it should be quite easy to implement any additional methods and contribute it to the broader community.&lt;/p&gt;
&lt;h2 id="next-steps"&gt;Next Steps&lt;/h2&gt;
&lt;p&gt;Using these functions we can de-identify and mask any existing dataset. But if you are populating a lower level environment using production data you would want to store the transformed data only. To achieve this you could choose between various options.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Small volumes of data&lt;/strong&gt;: use “de-identified” views to export the data and load into a new database using mysqldump or mysqlpump.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Medium volumes of data&lt;/strong&gt;: Clone the original database and de-identify locally the data using updates.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Large volumes of data option one&lt;/strong&gt;: using replication, create a master -&gt; slave chain with STATEMENT binlog format and define triggers de-identifying the data on the slave. Your master can be a slave to the master (using log_slave_updates), so you don’t need to run your primary master in STATEMENT mode.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Large volumes of data option two&lt;/strong&gt;: using multiplexing in &lt;a href="https://www.proxysql.com/" target="_blank" rel="noopener noreferrer"&gt;ProxySQL&lt;/a&gt;, configure ProxySQL to send writes to a clone server where you have defined triggers to de-identify the data.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="future-developments"&gt;Future developments&lt;/h2&gt;
&lt;p&gt;While de-identifying complex schemas we could find that, for example, the name of a person is stored in multiple tables (de-normalized tables). In this case, these functions would generate different names and the resulting data will look broken. You can solve this using a variant of the dictionary functions that will obtain the value based on the original value and passed as parameter:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-14" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-14"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gen_dictionary_deterministic('Francisco', 'first_names')&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This not-yet-available function would always return the same value using that dictionary file, but in such a way that the de-identification cannot be reversed. Oracle doesn’t currently support this, so we will expand Percona Data-Masking plugin to introduce this as a unique feature. However, that will be in another contribution, so stay tuned for more exciting changes to Percona Server for MySQL Data Masking.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;–&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Image: Photo by &lt;a href="https://unsplash.com/@finan?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" target="_blank" rel="noopener noreferrer"&gt;Finan Akbar&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/mask?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" target="_blank" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The content in this blog is provided in good faith by members of the open source community. Percona has not edited or tested the technical content (although in this case, of course, we have tested the data masking feature incorporated into Percona Server for MySQL 8.0/17, just not the examples in this blog). Views expressed are the authors’ own. When using the advice from this or any other online resource test ideas before applying them to your production systems, and always secure a working back up.&lt;/p&gt;</content:encoded>
      <author>Francisco Miguel Biete Banon</author>
      <category>data obfuscation</category>
      <category>data privacy</category>
      <category>identity protection</category>
      <category>Intermediate Level</category>
      <category>MySQL</category>
      <category>Percona Server for MySQL</category>
      <media:thumbnail url="https://percona.community/blog/2019/12/data-masking-Percona-Server-for-MySQL_hu_579bb5525b9e0b33.jpg"/>
      <media:content url="https://percona.community/blog/2019/12/data-masking-Percona-Server-for-MySQL_hu_3d1019fef5fce818.jpg" medium="image"/>
    </item>
    <item>
      <title>Minimalist Tooling for MySQL/MariaDB DBAs</title>
      <link>https://percona.community/blog/2019/08/14/minimalist-tooling-for-mysql-mariadb-dbas/</link>
      <guid>https://percona.community/blog/2019/08/14/minimalist-tooling-for-mysql-mariadb-dbas/</guid>
      <pubDate>Wed, 14 Aug 2019 14:21:10 UTC</pubDate>
      <description>In my roles as a DBA at various companies, I generally found the tooling to be quite lacking. Everything from metrics collection, alerting, backup management; they were either missing, incomplete or implemented poorly. DBA-Tools was born from a desire to build backup tools that supported my needs in smaller/non-cloud environments. As BASH is easily the most common shell available out there on systems running MySQL® or MariaDB®, it was an easy choice.</description>
      <content:encoded>&lt;p&gt;In my roles as a DBA at various companies, I generally found the tooling to be quite lacking. Everything from metrics collection, alerting, backup management; they were either missing, incomplete or implemented poorly. &lt;a href="http://gitlab.com/gwinans/dba-tools" target="_blank" rel="noopener noreferrer"&gt;DBA-Tools&lt;/a&gt; was born from a desire to build backup tools that supported my needs in smaller/non-cloud environments. As BASH is easily the most common shell available out there on systems running MySQL® or MariaDB®, it was an easy choice.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2019/08/dba-tools-minimalist-mysql-tooling.jpg" alt=" " /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h2 id="how-dba-tools-came-to-be"&gt;How DBA-Tools came to be&lt;/h2&gt;
&lt;p&gt;While rebuilding my home-lab two years ago, I decided I wanted some simple tools for my database environment. Being a fan of NOT re-inventing the wheel, I thought I would peruse GitHub and Gitlab to see what others have put together. Nothing I saw looked quite like what I wanted. They all hit one or more of the checkboxes I wanted, but never all of them.&lt;/p&gt;
&lt;p&gt;My checklist when searching for tools included the following features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Extendable&lt;/li&gt;
&lt;li&gt;Configurable&lt;/li&gt;
&lt;li&gt;User Friendly&lt;/li&gt;
&lt;li&gt;Easy-to-Read&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The majority of scripts I found were contained within a single file and not easy to extend. They were universally easy-to-use. My subjective requirement for code quality simply was not met. When I considered what kits were already available to me against the goal I had in mind, I came to the only reasonable conclusion I could muster:&lt;/p&gt;
&lt;p&gt;I would build my own tools!&lt;/p&gt;
&lt;h2 id="a-trip-down-release-lane-and-publicity"&gt;A trip down release lane and publicity&lt;/h2&gt;
&lt;p&gt;DBA-Tools was designed to be simple, extendible and configurable. I wanted my kit to have very few external dependencies. BASH was the shell I chose for implementation and I grew my vision from there. At the most fundamental level, I enjoy simplicity. I consider procedural programming to be just that – simple. This, thus far, remains my guiding philosophy with these tools.&lt;/p&gt;
&lt;p&gt;My first public release was on July 7th, 2019. The scripts only did single full backups and most of the secondary scripts only worked with MariaDB. I posted about it in one of the MySQL Slack groups. The tools were written for my lab use and, while I hoped others would find my offering useful, the lack of noticeable response did not bother me.&lt;/p&gt;
&lt;p&gt;The second release, 22 days later, marked full incremental support and ensured all the secondary scripts supported MySQL and MariaDB. I decided to call this one 2.0.0 and posted it again. I received my first “support” email that day, which spurred me to create better documentation.&lt;/p&gt;
&lt;p&gt;Later, I found out that Peter Zaitsev posted about the tools I wrote on his Twitter and LinkedIn pages on August 11th 2019. I can’t say thank you enough – I didn’t expect these tools to be used much beyond a small niche of home-lab engineers that might stumble across them.&lt;/p&gt;
&lt;h2 id="whats-next"&gt;What’s next?&lt;/h2&gt;
&lt;p&gt;As of this writing, I’m working on adding extensible, easy-to-use alerting facilities to these tools. I’m always ready to accept PRs and help from anyone that would like to add their own features.&lt;/p&gt;
&lt;p&gt;Now, I just need to get significantly better with git.&lt;/p&gt;
&lt;p&gt;In any case, check them out at &lt;a href="http://gitlab.com/gwinans/dba-tools" target="_blank" rel="noopener noreferrer"&gt;http://gitlab.com/gwinans/dba-tools&lt;/a&gt; or read the Wiki at &lt;a href="https://gitlab.com/gwinans/dba-tools/wikis/home" target="_blank" rel="noopener noreferrer"&gt;https://gitlab.com/gwinans/dba-tools/wikis/home&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;–
&lt;em&gt;Photo by &lt;a href="https://unsplash.com/@iurte?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" target="_blank" rel="noopener noreferrer"&gt;Iker Urteaga&lt;/a&gt; on &lt;a href="https://unsplash.com/search/photos/tools?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" target="_blank" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The content in this blog is provided in good faith by members of the open source community. Percona has not edited or tested the technical content. Views expressed are the authors’ own. When using the advice from this or any other online resource test ideas before applying them to your production systems, and always secure a working back up.&lt;/em&gt;&lt;/p&gt;</content:encoded>
      <author>Geoff Winans</author>
      <category>DBA Tools</category>
      <category>MariaDB</category>
      <category>MySQL</category>
      <category>Tools</category>
      <media:thumbnail url="https://percona.community/blog/2019/08/dba-tools-minimalist-mysql-tooling_hu_c1630e839fb0625.jpg"/>
      <media:content url="https://percona.community/blog/2019/08/dba-tools-minimalist-mysql-tooling_hu_615ce1dd4f0852a4.jpg" medium="image"/>
    </item>
    <item>
      <title>MySQL 5.6/Maria 10.1 : How we got from 30k qps to 101k qps.....</title>
      <link>https://percona.community/blog/2019/08/07/mysql-how-we-got-from-30k-qps-to-101k-qps/</link>
      <guid>https://percona.community/blog/2019/08/07/mysql-how-we-got-from-30k-qps-to-101k-qps/</guid>
      <pubDate>Wed, 07 Aug 2019 07:52:45 UTC</pubDate>
      <description>Late one evening, I was staring at one of our large MySQL installations and noticed the database was hovering around 7-10 run queue length (48 cores, ~500 gigs memory, fusionIO cards). I had been scratching my head on how to get more throughput from the database. This blog records the changes I made to tune performance in order to achieve a 300% better throughput in MySQL. I tested my theories on MySQL 5.6/Maria 10.1. While with 5.7 DBAs would turn to performance_schema for the supporting metrics, I hope that you find the process interesting nevertheless.</description>
      <content:encoded>&lt;p&gt;Late one evening, I was staring at one of our large MySQL installations and noticed the database was hovering around 7-10 run queue length (48 cores, ~500 gigs memory, fusionIO cards). I had been scratching my head on how to get more throughput from the database. This blog records the changes I made to tune performance in order to achieve a 300% better throughput in MySQL. I tested my theories on MySQL 5.6/Maria 10.1. While with 5.7 DBAs would turn to &lt;em&gt;performance_schema&lt;/em&gt; for the supporting metrics, I hope that you find the process interesting nevertheless.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2019/08/tuning-mysql-for-throughput.jpg" alt=" " /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h2 id="view-from-an-oracle-rdbms-dba"&gt;View from an Oracle RDBMS DBA…&lt;/h2&gt;
&lt;p&gt;For context, I came to MySQL from a background as an Oracle RDBMS DBA, and this informs my expectations. For this exercise, unlike with Oracle RDBMS, I had no access to view &lt;em&gt;wait events&lt;/em&gt; so that I could see where my database was struggling. At least, no access in MySQL 5.6/Maria 10.1 without taking a performance hit by using &lt;em&gt;performance_schema&lt;/em&gt;, which was less efficient in these earlier versions.&lt;/p&gt;
&lt;p&gt;In fact, overall, I find that MySQL has far fewer bells and whistles than Oracle at the database level. I constantly whine to my team mates how MySQL provides less knobs compared to Oracle. Even for just creating an index. Without counting, I can confidently say there are over 50 permutations combinations I could use. For example initrans, pctfree, pct, reverse, function, w/o gathering statistics… Admittedly some may be obsolete and discarded in recent versions, but you get my point. :)&lt;/p&gt;
&lt;p&gt;Oracle allows the DBA’s to tune blocks in an index or a table, their physical characteristics….all the way to pinning tables in buffer, tuning specific latches used for buffer cache so one can get rid of cache buffer chains waits with help of a hidden parameter  :)&lt;/p&gt;
&lt;p&gt;Anyway, I digress. Back to the challenges of MySQL!&lt;/p&gt;
&lt;h2 id="tuning-mysql-a-process"&gt;Tuning MySQL… a process&lt;/h2&gt;
&lt;p&gt;Given the version of MySQL that provided this challenge, one of the few tools you have access to is the output from &lt;code&gt;show engine innodb status&lt;/code&gt;. While that has a wealth of information, I haven’t yet found a single source of good documentation for each of the metrics shown in the report. I repeatedly saw these &lt;em&gt;waits&lt;/em&gt; in the SEMAPHOREs section:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;buf0buf.c
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;row0rel.cc
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;btr0btr.c&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Very naturally I started with reference books available on MySQL’s website, traversing through countless blogs, and sniffing through the code. Only after I had looked at multiple sources did I begin to get a gist of the metrics available in the status report. My research over the next few nights led me to a few different parameters. These ultimately helped me to find the answers I needed.&lt;/p&gt;
&lt;h2 id="making-the-changes-that-mattered"&gt;Making the changes that mattered&lt;/h2&gt;
&lt;p&gt;Here is a quick snippet that I changed from the default – or lower – values set by a previous DBA.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-1"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;innodb_buffer_pool_instances=32
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;table_open_cache_instances=12
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;table_open_cache=8000
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;table_definition_cache=12000
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;innodb_change_buffer_size=5&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Some other parameters that I changed are shown next. Although these are very scenario specific, they all helped in tuning one or other of the performance problems I was encountering:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-2" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-2"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;innodb_purge_batch_size=5000 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;optimizer_search_depth=0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;innodb_log_file_size=32g
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;innodb_log_buffer_size=1G&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Plus, I set innodb_adaptive_hash_index_parts to 32. &lt;em&gt;Note:&lt;/em&gt; this parameter may be called &lt;code&gt;innodb_adaptive_hash_partitions&lt;/code&gt; in some db versions.&lt;/p&gt;
&lt;p&gt;I will try and explain them to the best of my knowledge and understanding.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;innodb_buffer_pool_instances&lt;/code&gt; had to be increased to allow a greater number of latches to access the buffer pool. Ideally we want to keep this parameter either equal to or a little lower than the number of cores. In this case we set this at half of the number of cores. We have other boxes in the farm with fewer cores and prefer to keep to standard configs and not have snowflakes!&lt;/p&gt;
&lt;p&gt;&lt;code&gt;table_open_cache_instance&lt;/code&gt; also provided similar performance improvement for all queries accessing table metadata. If you are a heavy user of adaptive hash indexes, splitting innodb_adaptive_hash_parts/innodb_adaptive_hash_partitions (depending on your db version) to a higher number of partitions helps a lot with concurrency. It allows you to split hash indexes into  different partitions and to remove contention with hot tables access.&lt;/p&gt;
&lt;p&gt;We reduced &lt;code&gt;innodb_change_buffer_size&lt;/code&gt; to 5% from its default 25% because change buffer was never used more than 400mb. With the default value the change buffer had ~90gb allocated.&lt;/p&gt;
&lt;p&gt;This provided for a lot more data and indices to fit into the buffer pool.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Overall this set of parameters tuning worked for us and for our workload. We saw a great performance benefit from these changes. It was the first time we ever surpassed 100k qps without changing the code or hardware. Please make sure to understand what each parameter does, and to test your workload against them.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;—&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;a href="https://unsplash.com/search/photos/raspberry?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" target="_blank" rel="noopener noreferrer"&gt;Photo by &lt;/a&gt;&lt;a href="https://unsplash.com/@joaosilas?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" target="_blank" rel="noopener noreferrer"&gt;João Silas&lt;/a&gt;&lt;a href="https://unsplash.com/search/photos/raspberry?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" target="_blank" rel="noopener noreferrer"&gt; on &lt;/a&gt;&lt;a href="https://unsplash.com/search/photos/mystery?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" target="_blank" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The content in this blog is provided in good faith by members of the open source community. Percona has not edited or tested the technical content. Views expressed are the authors’ own. When using the advice from this or any other online resource test ideas before applying them to your production systems, and always secure a working back up.&lt;/em&gt;&lt;/p&gt;</content:encoded>
      <author>Gurnish Anand</author>
      <category>MariaDB</category>
      <category>MySQL</category>
      <category>performance</category>
      <media:thumbnail url="https://percona.community/blog/2019/08/tuning-mysql-for-throughput_hu_771cfd6c2edbf6b8.jpg"/>
      <media:content url="https://percona.community/blog/2019/08/tuning-mysql-for-throughput_hu_222ac1377e0a2344.jpg" medium="image"/>
    </item>
    <item>
      <title>How to Build a Percona Server "Stack" on a Raspberry Pi 3+</title>
      <link>https://percona.community/blog/2019/08/01/how-to-build-a-percona-server-stack-on-a-raspberry-pi-3/</link>
      <guid>https://percona.community/blog/2019/08/01/how-to-build-a-percona-server-stack-on-a-raspberry-pi-3/</guid>
      <pubDate>Thu, 01 Aug 2019 12:50:36 UTC</pubDate>
      <description>The blog post How to Compile Percona Server for MySQL 5.7 in Raspberry Pi 3 by Walter Garcia, inspired me to create an updated install of Percona Server for the Raspberry Pi 3+.</description>
      <content:encoded>&lt;p&gt;The blog post &lt;a href="https://www.percona.com/blog/2018/08/22/how-to-compile-percona-server-for-mysql-5-7-in-raspberry-pi-3/" target="_blank" rel="noopener noreferrer"&gt;&lt;em&gt;How to Compile Percona Server for MySQL 5.7 in Raspberry Pi 3&lt;/em&gt;&lt;/a&gt; by Walter Garcia, inspired me to create an updated install of Percona Server for the &lt;a href="https://www.raspberrypi.org/products/" target="_blank" rel="noopener noreferrer"&gt;Raspberry Pi 3+&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2019/07/Percona-installation-on-Raspberry-Pi-3.jpg" alt="Percona installation on Raspberry Pi 3+" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;This how-to post covers installing from source and being able to use &lt;a href="https://www.percona.com/software/mysql-database" target="_blank" rel="noopener noreferrer"&gt;Percona Server for MySQL&lt;/a&gt; in any of your maker projects. I have included everything you need to have a complete Percona Server, ready to store data collection for your weather station, your GPS data, or any other project you can think of that would require data collection in a database.&lt;/p&gt;
&lt;p&gt;My years of hands-on support of Percona Server enable me to customize the install a bit. I wanted to build a full Percona “Stack” including XtraBackup, and Percona Toolkit.&lt;/p&gt;
&lt;h2 id="hardware-and-software"&gt;Hardware and Software&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Tested on a Raspberry PI 3B and 3B+&lt;/li&gt;
&lt;li&gt;OS is Raspbian Buster. You can download it here: &lt;a href="https://www.raspberrypi.org/downloads/raspbian/" target="_blank" rel="noopener noreferrer"&gt;https://www.raspberrypi.org/downloads/raspbian/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;I choose the option: Raspbian Buster with Desktop.&lt;/li&gt;
&lt;li&gt;64GB SD Card, not required, but would not suggest less than 32GB. For best performance use and SD card that is between 90 - 100MB per sec.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-step-by-step-guide"&gt;The Step-by-Step Guide&lt;/h2&gt;
&lt;p&gt;Let’s get on and build!&lt;/p&gt;
&lt;h3 id="1-prep-your-raspberry-pi"&gt;1. Prep Your Raspberry PI&lt;/h3&gt;
&lt;p&gt;You will notice I use sudo rather often, even during the make and cmake. I found that running as the default pi user for the install gave me issues. Using sudo for root based commands is the best practice that I always try to follow.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt-get update
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt-get upgrade
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt-get install screen cmake debhelper autotools-dev libaio-dev
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;automake libtool bison bzr libgcrypt20-dev flex autoconf libtool libncurses5-dev
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mariadb-client-10.0 libboost-dev libreadline-dev libcurl4-openssl-dev libtirpc-dev&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Create a swapfile. Very much needed for these two compiles.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-1"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo dd if=/dev/zero of=/swapfile2GB bs=1M count=2048
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo mkswap /swapfile2GB
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo swapon /swapfile2GB
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo chmod 0600 /swapfile2GB&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="2-build-percona-server-for-mysql"&gt;2. Build Percona Server for MySQL&lt;/h3&gt;
&lt;p&gt;This will take about 3.5 to 4 hours to run. Download percona-server 5.7.26 source tar ball&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-2" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-2"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;wget https://www.percona.com/downloads/Percona-Server-5.7/Percona-Server-5.7.26-29/source/tarball/percona-server-5.7.26-29.tar.gz&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Extract to /home/pi&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-3" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-3"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cd percona-server-5.7.26-29
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo cmake -DDOWNLOAD_BOOST=ON -DWITH_BOOST=$HOME/boost .
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo make -j3
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo make install&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="3-build-percona-xtrabackup"&gt;3. Build Percona XtraBackup&lt;/h3&gt;
&lt;p&gt;This will take about 3 hours.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-4" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-4"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt-get install libcurl4-gnutls-dev libev-dev libev4&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Note: installing the package libcurl4-gnutls-dev  will remove the package libcurl4-openssl-dev . I had compile failures for XtraBackup when libcurl4-openssl-dev  was installed. Download XtraBackup 2.4.14&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-5" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-5"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;wget https://www.percona.com/downloads/Percona-XtraBackup-2.4/Percona-XtraBackup-2.4.14/source/tarball/percona-xtrabackup-2.4.14.tar.gz&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Extract to /home/pi&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-6" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-6"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cd percona-xtrabackup-2.4.14
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo cmake -DWITH_BOOST=$HOME/boost -DBUILD_CONFIG=xtrabackup_release -DWITH_MAN_PAGES=OFF
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo make -j3
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo make install&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="4-build-percona-toolkit"&gt;4. Build Percona Toolkit&lt;/h3&gt;
&lt;p&gt;Done in a few minutes.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-7" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-7"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;wget https://www.percona.com/downloads/percona-toolkit/3.0.13/source/tarball/percona-toolkit-3.0.13.tar.gz&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;extract to /home/pi&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-8" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-8"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cd percona-toolkit-3.0.13
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;perl Makefile.PL
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;make
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;make test
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo make install&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="5-create-the-mysqsl-user"&gt;5. Create the mysqsl user&lt;/h3&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-9" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-9"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo useradd mysql -d /var/lib/mysql&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Create directories for mysql to use.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-10" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-10"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo mkdir -p /var/lib/mysql/data
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo mkdir /var/lib/mysql/binlog
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo mkdir /var/lib/mysql/tmp
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo mkdir /var/log/mysql&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Change ownership of directories to mysql user.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-11" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-11"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo chown -R mysql:mysql /var/lib/mysql
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo chown mysql:mysql /var/log/mysql
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo chown -R mysql:mysql /usr/local/mysql&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="6-prep-mycnf"&gt;6. Prep my.cnf&lt;/h3&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-12" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-12"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo rm -fR /etc/mysql&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;I like to remove any leftover mysql directories or files in /etc before I create my file in the next step.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-13" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-13"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo vi /etc/my.cnf&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Add these lines, below, to your new my.cnf file.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-14" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-14"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[mysqld]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;port = 3306
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;socket = /var/lib/mysql/mysql.sock
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pid-file = /var/lib/mysql/mysqld.pid
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;basedir = /usr/local/mysql
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;datadir = /var/lib/mysql/data
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;general_log_file = /var/log/mysql/mysql-general.log
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;log-error = /var/log/mysql/mysqld.log
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;slow_query_log_file = /var/log/mysql/log/slow_query.log
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;slow_query_log = 0 # Slow query log off
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;lc-messages-dir = /usr/local/mysql/share
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;plugin_dir = /usr/local/mysql/lib/mysql/plugin
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;skip-external-locking
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;log-bin = /var/lib/mysql/binlog/mysql-bin
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sync_binlog = 1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;expire_logs_days = 5
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;server-id = 1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;binlog_format = mixed
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;innodb_data_home_dir = /var/lib/mysql/data
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;innodb_log_group_home_dir = /var/lib/mysql/data
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;innodb_log_files_in_group = 2
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;innodb_buffer_pool_size = 128M
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;innodb_log_file_size = 16M
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;innodb_log_buffer_size = 8M
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;innodb_flush_log_at_trx_commit = 1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;innodb_lock_wait_timeout = 50
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;innodb_flush_method = O_DIRECT
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;innodb_file_per_table = 1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;innodb_buffer_pool_instances = 1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Save the my.cnf file.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-15" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-15"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo chown mysql:mysql /etc/my.cnf&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="7-initialize-the-database-files"&gt;7. Initialize the database files&lt;/h3&gt;
&lt;p&gt;At this point, you can initialize the database files&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-16" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-16"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo /usr/local/mysql/bin/mysqld --initialize-insecure --user=mysql --basedir=/usr/local/mysql --datadir=/var/lib/mysql/data&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="8-start-percona-server"&gt;8. Start Percona Server&lt;/h3&gt;
&lt;p&gt;This is the exciting part coming up. We are going to start Percona Server&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-17" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-17"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo /usr/local/mysql/bin/mysqld_safe --defaults-file=/etc/my.cnf --user=mysql &amp;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;If everything went well you should see the following lines in your /var/log/mysql/mysqld.log .```
2019-06-24T19:56:52.071765Z 0 [Note] Server hostname (bind-address): ‘*’; port: 3306
2019-06-24T19:56:52.072251Z 0 [Note] IPv6 is available.
2019-06-24T19:56:52.072385Z 0 [Note]   - ‘::’ resolves to ‘::’;
2019-06-24T19:56:52.072770Z 0 [Note] Server socket created on IP: ‘::’.
2019-06-24T19:56:52.132587Z 0 [Note] InnoDB: Buffer pool(s) load completed at 190624 15:56:52
2019-06-24T19:56:52.136886Z 0 [Note] Failed to start slave threads for channel ’’
2019-06-24T19:56:52.178087Z 0 [Note] Event Scheduler: Loaded 0 events
2019-06-24T19:56:52.179153Z 0 [Note] /usr/local/mysql/bin/mysqld: ready for connections.
Version: ‘5.7.26-29-log’  socket: ‘/var/lib/mysql/mysql.sock’  port: 3306 Source distribution&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-18" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-18"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;### 9. Test login to Percona Server&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;mysql -u root –socket=/var/lib/mysql/mysql.sock&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-19" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-19"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;If you plan on keeping this as an active Percona Server I **strongly advise** you to remove the root user and create your own privileged user.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;First, stop Percona Server&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;/usr/local/mysql/bin/mysqladmin -u root –socket=/var/lib/mysql/mysql.sock shutdown&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-20" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-20"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Create the mysqld.server and enable it.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;sudo vi /etc/systemd/system/mysqld.service
[Unit]
Description=Percona Server Version 5.7.x
After=syslog.target
After=network.target
[Install]
WantedBy=multi-user.target
[Service]
User=mysql
Group=mysql
ExecStart=/usr/local/mysql/bin/mysqld –defaults-file=/etc/my.cnf
TimeoutSec=300
WorkingDirectory=/usr/local/mysql/bin
#Restart=on-failure
#RestartPreventExitStatus=1
PrivateTmp=true
sudo systemctl enable mysqld.service&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-21" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-21"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Now if everything was done correctly you should be able to reboot your Pi and Percona Server will auto start on OS Boot.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;This is it, you now have an entire Percona Server for MySQL up and running, with XtraBackup for your daily backups and Percona Toolkit to assist you with daily and complicated tasks. If you try this out, I'd love to hear about the uses you make of your Percona Server on a Raspberry Pi.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;_—_
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;_Image based on Photo by [Hector Bermudez](https://unsplash.com/@hectorbermudez?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText) on [Unsplash](https://unsplash.com/search/photos/raspberry?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText)_
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;_The content in this blog is provided in good faith by members of the open source community. The content is not edited or tested by Percona, and views expressed are the authors’ own. When using the advice from this or any other online resource test ideas before applying them to your production systems, and always secure a working back up._&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</content:encoded>
      <author>Wayne Leutwyler</author>
      <category>MySQL</category>
      <category>Percona Server for MySQL</category>
      <category>Raspberry Pi</category>
      <category>Toolkit</category>
      <media:thumbnail url="https://percona.community/blog/2019/07/Percona-installation-on-Raspberry-Pi-3_hu_bac5ba8285ff105a.jpg"/>
      <media:content url="https://percona.community/blog/2019/07/Percona-installation-on-Raspberry-Pi-3_hu_c834587c85969757.jpg" medium="image"/>
    </item>
    <item>
      <title>MySQL Optimizer: Naughty Aberrations on Queries Combining WHERE, ORDER BY and LIMIT</title>
      <link>https://percona.community/blog/2019/07/29/mysql-optimizer-naughty-aberrations-on-queries-combining-where-order-by-and-limit/</link>
      <guid>https://percona.community/blog/2019/07/29/mysql-optimizer-naughty-aberrations-on-queries-combining-where-order-by-and-limit/</guid>
      <pubDate>Mon, 29 Jul 2019 11:50:51 UTC</pubDate>
      <description>Sometimes, the MySQL Optimizer chooses a wrong plan, and a query that should execute in less than 0.1 second ends-up running for 12 minutes!This is not a new problem: bugs about this can be traced back to 2014, and a blog post on this subject was published in 2015.But even if this is old news, because this problem recently came yet again to my attention, and because this is still not fixed in MySQL 5.7 and 8.0, this is a subject worth writing about.</description>
      <content:encoded>&lt;p&gt;Sometimes, the MySQL Optimizer chooses a wrong plan, and a query that should execute in less than 0.1 second ends-up running for 12 minutes!This is not a new problem: bugs about this can be traced back to 2014, and a blog post on this subject was published in 2015.But even if this is old news, because this problem recently came yet again to my attention, and because this is still not fixed in MySQL 5.7 and 8.0, this is a subject worth writing about.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2019/07/mysql-optimizer-choose-wrong-path.jpg" alt=" " /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h2 id="the-mysql-optimizer"&gt;The MySQL Optimizer&lt;/h2&gt;
&lt;p&gt;Before looking at the problematic query, we have to say a few words about the optimizer.The &lt;a href="https://dev.mysql.com/doc/internals/en/optimizer.html" target="_blank" rel="noopener noreferrer"&gt;Query Optimizer&lt;/a&gt; is the part of query execution that chooses the query plan.A &lt;a href="https://dev.mysql.com/doc/refman/5.7/en/execution-plan-information.html" target="_blank" rel="noopener noreferrer"&gt;Query Execution Plan&lt;/a&gt; is the way MySQL chooses to execute a specific query.It includes index choices, join types, table query order, temporary table usage, sorting type … You can get the execution plan for a specific query using the &lt;a href="https://dev.mysql.com/doc/refman/5.7/en/explain.html" target="_blank" rel="noopener noreferrer"&gt;EXPLAIN command&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="a-case-in-question"&gt;A Case in Question&lt;/h2&gt;
&lt;p&gt;Now that we know what are the Query Optimizer and a Query Execution Plan, I can introduce you to the table we are querying. The SHOW CREATE TABLE for our table is below.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mysql&gt; SHOW CREATE TABLE _test_jfg_201907G
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;*************************** 1. row ***************************
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Table: _test_jfg_201907
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Create Table: CREATE TABLE `_test_jfg_201907` (
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;`str1` varchar(150) DEFAULT NULL,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;`id1` int(10) unsigned NOT NULL,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;`id2` bigint(20) unsigned DEFAULT NULL,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;`str2` varchar(255) DEFAULT NULL,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[...many more id and str fields...]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;`create_datetime` datetime NOT NULL,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;`update_datetime` datetime DEFAULT NULL,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;PRIMARY KEY (`id`),
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;KEY `key1` (`id1`,`id2`)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;) ENGINE=InnoDB AUTO_INCREMENT=_a_big_number_ DEFAULT CHARSET=utf8
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;1 row in set (0.00 sec)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;And this is not a small table (it is not very big either though…):&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-1"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# ls -lh _test_jfg_201907.ibd
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-rw-r----- 1 mysql mysql 11G Jul 23 13:21 _test_jfg_201907.ibd&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Now we are ready for the problematic query (I ran PAGER cat &gt; /dev/null before to skip printing the result):&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-2" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-2"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mysql&gt; SELECT * FROM _test_jfg_201907
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;WHERE id1 = @v AND id2 IS NOT NULL
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ORDER BY id DESC LIMIT 20;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;20 rows in set (27.22 sec)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Hum, this query takes a long time (27.22 sec) considering that the table has an index on id1 and id2. Let’s check the query execution plan:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-3" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-3"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mysql&gt; EXPLAIN SELECT * FROM _test_jfg_201907
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;WHERE id1 = @v AND id2 IS NOT NULL
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ORDER BY id DESC LIMIT 20G
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;*************************** 1. row ***************************
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;id: 1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;select_type: SIMPLE
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;table: _test_jfg_201907
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;partitions: NULL
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;type: index
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;possible_keys: key1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;key: PRIMARY
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;key_len: 4
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ref: NULL
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rows: 13000
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;filtered: 0.15
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Extra: Using where
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;1 row in set, 1 warning (0.00 sec)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;What ? The query is not using the index key1, but is scanning the whole table (key: PRIMARY in above EXPLAIN) ! How can this be ? The short explanation is that the optimizer thinks — or should I say hopes — that scanning the whole table (which is already sorted by the id field) will find the limited rows quick enough, and that this will avoid a sort operation. So by trying to avoid a sort, the optimizer ends-up losing time scanning the table.&lt;/p&gt;
&lt;h2 id="some-solutions"&gt;Some Solutions&lt;/h2&gt;
&lt;p&gt;How can we solve this ? The first solution is to hint MySQL to use key1 as shown below. Now the query is almost instant, but this is not my favourite solution because if we drop the index, or if we change its name, the query will fail.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-4" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-4"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mysql&gt; SELECT * FROM _test_jfg_201907 USE INDEX (key1)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;WHERE id1 = @v AND id2 IS NOT NULL
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ORDER BY id DESC LIMIT 20;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;20 rows in set (0.00 sec)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;A more elegant, but still very hack-ish, solution is to prevent the optimizer from using an index for the ORDER BY. This can be achieved with the modified ORDER BY clause below (thanks to &lt;a href="http://code.openark.org/blog/" target="_blank" rel="noopener noreferrer"&gt;Shlomi Noach&lt;/a&gt; for suggesting this solution on a MySQL Community Chat). This is the solution I prefer so far, even if it is still somewhat a hack.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-5" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-5"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mysql&gt; SELECT * FROM _test_jfg_201907
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;WHERE id1 = @v AND id2 IS NOT NULL
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ORDER BY (id+0) DESC LIMIT 20;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;20 rows in set (0.00 sec)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;A third solution is to use the &lt;a href="https://explainextended.com/2009/10/23/mysql-order-by-limit-performance-late-row-lookups/" target="_blank" rel="noopener noreferrer"&gt;Late Row Lookups&lt;/a&gt; trick. Even if the post about this trick is 10 years old, it is still useful — thanks to my colleague Michal Skrzypecki for bringing it to my attention. This trick basically forces the optimizer to choose the good plan because the query is modified with the intention of making the plan explicit. This is an elegant hack, but as it makes the query more complicated to understand, I prefer not to use it.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-6" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-6"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mysql&gt; SELECT y.* FROM (
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;SELECT id FROM _test_jfg_201907
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;WHERE id1 = @v AND id2 IS NOT NULL
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ORDER BY id DESC LIMIT 20) x
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;JOIN _test_jfg_201907 y ON x.id = y.id
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ORDER by y.id DESC;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;20 rows in set (0.00 sec)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="the-ideal-solution"&gt;The ideal solution…&lt;/h2&gt;
&lt;p&gt;Well, the best solution would be to fix the bugs below. I claim Bug#74602 is not fixed even if it is marked as such in the bug system, but I will not make too much noise about this as Bug#78612 also raises attention on this problem:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://bugs.mysql.com/bug.php?id=74602" target="_blank" rel="noopener noreferrer"&gt;Bug#74602: Optimizer prefers wrong index because of low_limit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bugs.mysql.com/bug.php?id=78612" target="_blank" rel="noopener noreferrer"&gt;Bug#78612: Optimizer chooses wrong index for ORDER BY&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://perconadev.atlassian.net/browse/PS-1653" target="_blank" rel="noopener noreferrer"&gt;PS-1653: Optimizer chooses wrong index for ORDER BY DESC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://perconadev.atlassian.net/browse/PS-4935" target="_blank" rel="noopener noreferrer"&gt;PS-4935: Optimizer choosing full table scan (instead of index range scan) on query order by primary key with limit.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;PS-4935 is a duplicate of PS-1653 that I opened a few months ago. In that report, I mention a query that is taking 12 minutes because of a bad choice by the optimizer (when using the good plan, the query is taking less than 0.1 second).&lt;/p&gt;
&lt;p&gt;One last thing before ending this post: I wrote above that I would give a longer explanation about the reason for this bad choice by the optimizer. Well, this longer explanation has already been written by Domas Mituzas in 2015, so I am referring you to his &lt;a href="https://dom.as/2015/07/30/on-order-by-optimization/" target="_blank" rel="noopener noreferrer"&gt;on ORDER BY optimization&lt;/a&gt; post for more details.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;–&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Photo by &lt;a href="https://unsplash.com/@jamie452?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" target="_blank" rel="noopener noreferrer"&gt;Jamie Street&lt;/a&gt; on &lt;a href="https://unsplash.com/search/photos/wrong?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" target="_blank" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The content in this blog is provided in good faith by members of the open source community. The content is not edited or tested by Percona, and views expressed are the authors’ own. When using the advice from this or any other online resource test ideas before applying them to your production systems, and always secure a working back up.&lt;/em&gt;&lt;/p&gt;
&lt;div class="comments"&gt;
&lt;h2 id="6-comments"&gt;6 Comments&lt;/h2&gt;
&lt;div class="comment"&gt;
&lt;div class="info"&gt;
&lt;a href="http://oysteing.blogspot.com/"&gt;Øystein Grøvlen&lt;/a&gt;
&lt;span&gt;July 29, 2019 at 9:43 am&lt;/span&gt;
&lt;/div&gt;
Hi JF,
&lt;p&gt;I think this behavior may be expected if there is a correlation between the columns. For example, that id2 is more likely to be NULL for high (recent?) values of id. The MySQL optimizer does not have any statistics on how columns are correlated. Hence, it is not be able to effectively determine how many rows it needs to read to find the first 20 rows that satisfies the WHERE clause.&lt;/p&gt;
&lt;p&gt;Bug#74602 describes a scenario where column values were not correlated. This particular problem was fixed in 5.7.
Bug#78612 seems to be caused by the use of a prefix index, which does not seem to be relevant here.&lt;/p&gt;
&lt;p&gt;However, there are probably other bug reports that describes the problem you are facing. In order to address this problem, I think MySQL needs to add statistics on correlation between columns.&lt;/p&gt;
&lt;p&gt;Unfortunately, as Domas decribes, the optimizer trace does not contain any information on the cost calculations made when it decides to switch to an index that provides sorting. Hence, it is not straight-forward to verify why this choice was made.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="comment"&gt;
&lt;div class="info"&gt;
&lt;a href="https://jfg-mysql.blogspot.com/"&gt;Jean-François Gagné&lt;/a&gt;
&lt;span&gt;July 29, 2019 at 9:59 am&lt;/span&gt;
&lt;/div&gt;
Hi Øystein, thanks for the details about Bug#74602 and Bug#78612.
&lt;blockquote&gt;
&lt;p&gt;In order to address this problem, I think MySQL needs to add statistics on correlation between columns.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;This might be a solution, but I am sure there are others. Tracking correlations might be very complicated. A more simple solution might be to identify plans that are “probabilistic” (like the worse case I show in this post) and to not let queries using those plans run for too long before trying an alternative plan. Also, in the case of plans that might have a very worse case (like the one in this post), maybe running both queries in parallel and killing the other when one completes might be another way to avoid this problem.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="comment"&gt;
&lt;div class="info"&gt;
&lt;a href="http://oysteing.blogspot.com/"&gt;Øystein Grøvlen&lt;/a&gt;
&lt;span&gt;July 30, 2019 at 5:13 am&lt;/span&gt;
&lt;/div&gt;
Hi,
&lt;p&gt;I think it is an interesting idea to let the optimizer have a fallback plan, in case its original estimates is off. The challenge is how to detect in time that the estimates are off. Maybe it would be easier to just switch to the more safe plan if the execution takes longer than the estimate for the safe plan. (Unfortunately, it is not straight-forward to translate query cost to execution time in MySQL.) Another aspect is diagnostics. It must be a way for the user to determine which plan was actually used.&lt;/p&gt;
&lt;p&gt;Maybe, the optimizer could be a bit more cautious, and choose a safe plan over a more risky, but potentially quicker plan. In your case, there will be a pretty accurate estimate for the number of rows that need to be read when using the secondary index, while how many rows needs to be read using the primary index depends on how the interesting rows are distributed.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="comment"&gt;
&lt;div class="info"&gt;
&lt;a href=""&gt;Jeremy&lt;/a&gt;
&lt;span&gt;July 31, 2019 at 4:08 pm&lt;/span&gt;
&lt;/div&gt;
While in an ideal world I would like to see this fixed my solution is turn towards the application. It is easier to grow application servers than database servers. After all with solutions like Nginx and such one can easily have a farm of whatever application servers (PHP, Python, Java) and just keep adding more.
&lt;p&gt;I generally keep queries super simple and let the application server(s) do the heavy lifting. For example sort. I almost never ask the database server(s) to sort in my own applications. That is wasting DB cycles on something the application layer can do quite easily and faster. So I am like just dump the raw data DB to app.&lt;/p&gt;
&lt;p&gt;Thus keeping in mind: “The fastest query is the query you do NOT run”. I prefer to dump as much heavy lifting onto the application and let the database layer handle as little as possible. As stated I would rather spin up another app server than a DB server.&lt;/p&gt;
&lt;p&gt;Of course I understand in some limited cases this isn’t always possible. Still in the vast majority of deployments there is an application layer. Also one could turn toward solutions like ProxySQL to cache bad queries although that doesn’t address the bug.&lt;/p&gt;
&lt;p&gt;Finally, as stated, I would like to see this bug fixed. However I still wouldn’t ask the DB to sort in most cases.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="comment"&gt;
&lt;div class="info"&gt;
&lt;a href=""&gt;s&lt;/a&gt;
&lt;span&gt;August 3, 2019 at 4:27 am&lt;/span&gt;
&lt;/div&gt;
also see &lt;a href="https://bugs.mysql.com/bug.php?id=95543"&gt;https://bugs.mysql.com/bug.php?id=95543&lt;/a&gt; (optimizer prefers index for order by rather than filtering – (70x slower))
&lt;/div&gt;
&lt;div class="comment"&gt;
&lt;div class="info"&gt;
&lt;a href="https://jfg-mysql.blogspot.com/"&gt;Jean-François Gagné&lt;/a&gt;
&lt;span&gt;July 28, 2021 at 5:48 pm&lt;/span&gt;
&lt;/div&gt;
Another blog post on the same subject (with a patch that was merged in 5.7 and 8.0):
&lt;a href="https://blog.jcole.us/2019/09/30/reconsidering-access-paths-for-index-ordering-a-dangerous-optimization-and-a-fix/"&gt;https://blog.jcole.us/2019/09/30/reconsidering-access-paths-for-index-ordering-a-dangerous-optimization-and-a-fix/&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;</content:encoded>
      <author>Jean-François Gagné</author>
      <category>bugs</category>
      <category>MySQL</category>
      <category>optimizer</category>
      <category>performance</category>
      <media:thumbnail url="https://percona.community/blog/2019/07/mysql-optimizer-choose-wrong-path_hu_e5b755342fc0fd9a.jpg"/>
      <media:content url="https://percona.community/blog/2019/07/mysql-optimizer-choose-wrong-path_hu_75a34687f5d0d9cd.jpg" medium="image"/>
    </item>
    <item>
      <title>Impact of innodb_file_per_table Option On Crash Recovery Time</title>
      <link>https://percona.community/blog/2019/07/23/impact-of-innodb_file_per_table-option-on-crash-recovery-time/</link>
      <guid>https://percona.community/blog/2019/07/23/impact-of-innodb_file_per_table-option-on-crash-recovery-time/</guid>
      <pubDate>Tue, 23 Jul 2019 13:34:14 UTC</pubDate>
      <description>Starting at version MySQL5.6+ by default innodb_file_per_table is enabled and all data is stored in separate tablespaces. It provides some advantages.</description>
      <content:encoded>&lt;p&gt;Starting at version MySQL5.6+ by default innodb_file_per_table is enabled and all data is stored in separate tablespaces. It provides some &lt;a href="https://dev.mysql.com/doc/refman/5.7/en/innodb-multiple-tablespaces.html" target="_blank" rel="noopener noreferrer"&gt;advantages&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2019/07/logo-mysql-170x115.png" alt="MySQL Logo" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;I will highlight some of them:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You can reclaim disk space when truncating or dropping a table stored in a file-per-table tablespace. Truncating or dropping tables stored in the shared &lt;a href="https://dev.mysql.com/doc/refman/5.7/en/glossary.html#glos_system_tablespace" title="system tablespace" target="_blank" rel="noopener noreferrer"&gt;system tablespace&lt;/a&gt; creates free space internally in the system tablespace data files (&lt;a href="https://dev.mysql.com/doc/refman/5.7/en/glossary.html#glos_ibdata_file" title="ibdata file" target="_blank" rel="noopener noreferrer"&gt;ibdata files&lt;/a&gt;) which can only be used for new InnoDB data.&lt;/li&gt;
&lt;li&gt;You can store specific tables on separate storage devices, for I/O optimization, space management, or backup purposes.&lt;/li&gt;
&lt;li&gt;You can monitor table size at a file system level without accessing MySQL.&lt;/li&gt;
&lt;li&gt;Backups taken with &lt;a href="https://www.percona.com/software/mysql-database/percona-xtrabackup" target="_blank" rel="noopener noreferrer"&gt;Percona XtraBackup&lt;/a&gt; takes less space (compared with the physical backup of ibdata files)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="problem"&gt;Problem&lt;/h3&gt;
&lt;p&gt;There are disadvantages &lt;a href="https://dev.mysql.com/doc/refman/5.7/en/innodb-multiple-tablespaces.html" target="_blank" rel="noopener noreferrer"&gt;described&lt;/a&gt; on MySQL man page but I found another one that is not mentioned: if you have a huge number of tables, the crash recovery process may take a lot of time. During crash recovery the MySQL daemon scans .ibd files:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2019-07-16 21:00:04 6766 [Note] InnoDB: Starting crash recovery.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2019-07-16 21:00:04 6766 [Note] InnoDB: Reading tablespace information from the .ibd files...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# Started at Jul 16 23:46:52:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Version: '5.6.39-83.1-log' socket: ......&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;During startup time I checked MySQL behavior and found that MySQL opens files one by one. In my test case it was 1400000+ tables and it took 02:46:48 just to scan ibd files.&lt;/p&gt;
&lt;p&gt;To prevent such a long downtime we decided to move all the tables to shared tablespaces.&lt;/p&gt;
&lt;h3 id="solution--moving-tables-to-shared-tablespaces"&gt;Solution – moving tables to shared tablespaces&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Make sure that you have enough space on disk.&lt;/li&gt;
&lt;li&gt;Modify my.cnf and add the files.&lt;/li&gt;
&lt;li&gt;Restart MySQL and wait until it creates the data files.&lt;/li&gt;
&lt;li&gt;Move your InnoDB tables to shared tablespaces.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You can use this script:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-1"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# Get table list that stored in own tablespace (SPACE&gt;0)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mysql -NB information_schema -e "select NAME from INNODB_SYS_TABLES WHERE name not like 'SYS_%' AND name not like 'mysql/%' AND SPACE &gt; 0" | split -l 30000 - tables;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# Generate SQL script
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;for file in `ls tables*`;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;do
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;perl -e '$curdb=""; while(&lt;STDIN&gt;) {chomp; ($db,$table) = split(///); if ($curdb ne $db ) { print "USE $db;n"; $curdb=$db; } print "ALTER TABLE $table engine=innodb;n"; }' &lt; $file &gt; $file.SQL;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;done
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# Apply files $file.SQL ( you can use parallel execution ) :
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat&lt;&lt;EOF&gt;convert.sh
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;file=$1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mysql &lt; ${file}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;EOF
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# Do not forget to fix my.cnf
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mysql -e "set global innodb_file_per_table = 0"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;chmod +x convert.sh
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# run 10 parallel threads
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ls tables*.SQL | xargs -n1 -P10 ./convert.sh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;What the script does:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Retrieves all tables that are occupying their own tablespace&lt;/li&gt;
&lt;li&gt;Generates SQL code in this pattern USE DB_X; ALTER TABLE TBL_Y engine=innodb;&lt;/li&gt;
&lt;li&gt;Applies the SQL scripts in parallel.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;After changing file_per_table to 0 and moving the InnoDB tables:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-2" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-2"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2019-07-17 22:16:47 976 [Note] InnoDB: Reading tablespace information from the .ibd files...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2019-07-17 22:25:45 976 [Note] mysqld: ready for connections.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="conclusion"&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;Using the default value of innodb_file_per_table (ON) is not always a good choice. In my test case: 4000+ databases, 1400000+ tables. I reduced recovery time from 02:46:48 to 00:08:58 seconds. That’s 18 times less! Remember, there is no “golden my.cnf config”, and each case is special. Optimize MySQL configuration according to your needs.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;–&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The content in this blog is provided in good faith by members of the open source community. The content is not edited or tested by Percona, and views expressed are the authors’ own. When using the advice from this or any other online resource, please &lt;strong&gt;test&lt;/strong&gt; ideas before applying them to your production systems, and **always **secure a working back up.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Cartoon source &lt;a href="https://imgur.com/" target="_blank" rel="noopener noreferrer"&gt;https://imgur.com/&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;</content:encoded>
      <author>Timur Solodovnikov</author>
      <category>MySQL</category>
      <category>MySQL</category>
      <category>MySQL Crash Recovery</category>
      <category>Open Source Databases</category>
      <media:thumbnail url="https://percona.community/blog/2019/07/logo-mysql-170x115_hu_be9204a60de7f14a.jpg"/>
      <media:content url="https://percona.community/blog/2019/07/logo-mysql-170x115_hu_1f5d5e082bdcb177.jpg" medium="image"/>
    </item>
    <item>
      <title>Tame Kubernetes with These Open-Source Tools</title>
      <link>https://percona.community/blog/2019/07/08/tame-kubernetes-with-open-source-tools/</link>
      <guid>https://percona.community/blog/2019/07/08/tame-kubernetes-with-open-source-tools/</guid>
      <pubDate>Mon, 08 Jul 2019 13:03:15 UTC</pubDate>
      <description>Kubernetes’ popularity as the most-preferred open-source container-orchestration system has skyrocketed in the recent past. The overall container market is expected to cross USD 2.7 billion by 2020 with a CAGR of 40 percent. Three orchestrators spearhead this upward trend, namely Kubernetes, Mesos, and Docker Swarm. However, referring to the graph below, Kubernetes clearly leads the pack.</description>
      <content:encoded>&lt;p&gt;&lt;a href="https://kubernetes.io/" target="_blank" rel="noopener noreferrer"&gt;Kubernetes&lt;/a&gt;’ popularity as the most-preferred open-source container-orchestration system has skyrocketed in the recent past. The &lt;a href="https://enterprisersproject.com/article/2017/11/kubernetes-numbers-10-compelling-stats" target="_blank" rel="noopener noreferrer"&gt;overall container market&lt;/a&gt; is expected to cross USD 2.7 billion by 2020 with a CAGR of 40 percent. Three orchestrators spearhead this upward trend, namely Kubernetes, &lt;a href="http://mesos.apache.org/" target="_blank" rel="noopener noreferrer"&gt;Mesos&lt;/a&gt;, and &lt;a href="https://docs.docker.com/engine/swarm/" target="_blank" rel="noopener noreferrer"&gt;Docker Swarm&lt;/a&gt;. However, referring to the graph below, Kubernetes clearly leads the pack.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2019/07/kubernetes-growth.jpg" alt=" " /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;source: &lt;a href="https://medium.com/@rdodev/saved-you-an-analyst-read-on-kubernetes-growth-2018-edition-810367876981" target="_blank" rel="noopener noreferrer"&gt;https://medium.com/@rdodev/saved-you-an-analyst-read-on-kubernetes-growth-2018-edition-810367876981 &lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The automation and infrastructural capabilities of Kubernetes are transforming the DevOps space,  thereby enhancing the value of the business through software. With Kubernetes you can deploy, scale, and &lt;a href="https://www.percona.com/live/19/sites/default/files/digital_rack_aws.pdf" target="_blank" rel="noopener noreferrer"&gt;manage cloud-native databases&lt;/a&gt; and applications from anywhere. No wonder, data scientists and &lt;a href="https://www.manipalprolearn.com/data-science/post-graduate-certificate-program-in-data-science-and-machine-learning-manipal-academy-higher-education" target="_blank" rel="noopener noreferrer"&gt;machine learning engineers&lt;/a&gt; love Kubernetes and apply it to improve their productivity. As Kubernetes continues to evolve and grow in complexity, we need to be ready with solutions that simplify Kubernetes, thereby enhancing your development work. Here is a comprehensive list of Kubernetes tools that can help you tame this orchestrator, many of them open source. I have divided them into five functional categories.&lt;/p&gt;
&lt;h2 id="1-tools-for-automating-cluster-deployments"&gt;1. Tools for Automating Cluster Deployments&lt;/h2&gt;
&lt;p&gt;Automated Kubernetes cluster services are a hot topic today because they eliminate much of the deployment and management hassles. An ideal application should consume declarative manifests, bootstrap fully-functioning clusters, and ensure that the K8 clusters are highly available.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/kubernetes-sigs/kubespray" target="_blank" rel="noopener noreferrer"&gt;&lt;strong&gt;KubeSpray&lt;/strong&gt;&lt;/a&gt; is a great choice for individuals who know Ansible. You can deploy this Ansible-driven cluster deployment tool on AWS, GCE, Azure, OpenStack, Baremetal, and Oracle Cloud Infrastructure.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://conjure-up.io/" target="_blank" rel="noopener noreferrer"&gt;&lt;strong&gt;Conjure-Up&lt;/strong&gt;&lt;/a&gt; can deploy the Canonical distribution of Kubernetes across several cloud providers using simple commands. The tool has native AWS integration, yet supports other cloud providers like GCE, Azure, Joyent, and OpenStack.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/kubernetes/kops" target="_blank" rel="noopener noreferrer"&gt;Kops&lt;/a&gt;&lt;/strong&gt; or &lt;strong&gt;Kubernetes Operations&lt;/strong&gt; can automate the provisioning of K8 clusters in Amazon Web Services (officially supported) and GCE (beta support). The tool allows you to take full control of the cluster lifecycle, from infrastructure provisioning to cluster deletion.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kubernetes-incubator/kube-aws" target="_blank" rel="noopener noreferrer"&gt;&lt;strong&gt;Kube-AWS&lt;/strong&gt;&lt;/a&gt; is a command-line tool that creates/updates/destroys fully-functional clusters using Amazon Web Services, namely CloudFormation, Auto Scaling, Spot Fleet, and KMS among others.&lt;/li&gt;
&lt;li&gt;You might also like to check out the &lt;a href="https://www.percona.com/software/percona-kubernetes-operators" target="_blank" rel="noopener noreferrer"&gt;&lt;strong&gt;Percona Kubernetes operators&lt;/strong&gt;&lt;/a&gt; for Percona XtraDB Cluster and Percona Server for MongoDB.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="2-cluster-monitoring-tools"&gt;2. Cluster Monitoring Tools&lt;/h2&gt;
&lt;p&gt;Monitoring Kubernetes clusters is critical in a microservice architecture. The following graph shows the top cluster monitoring tools available today.
&lt;figure&gt;&lt;img src="https://percona.community/blog/2019/07/tools-services-to-monitor-kubernetes-clusters.jpg" alt=" " /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Source: &lt;a href="https://thenewstack.io/5-tools-monitoring-kubernetes-scale-production/" target="_blank" rel="noopener noreferrer"&gt;https://thenewstack.io/5-tools-monitoring-kubernetes-scale-production/&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Here are our recommendations.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://prometheus.io/" target="_blank" rel="noopener noreferrer"&gt;&lt;strong&gt;Prometheus&lt;/strong&gt;&lt;/a&gt; is an open-source Cloud Native Computing Foundation (CNCF) tool that offers enhanced querying, visualization, and alerting features.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/google/cadvisor" target="_blank" rel="noopener noreferrer"&gt;&lt;strong&gt;CAdvisor&lt;/strong&gt;&lt;/a&gt; or &lt;strong&gt;Container Advisor&lt;/strong&gt; comes embedded into the kubelet, the primary node agent that runs on each node in the cluster. The tool focuses on container-level performance and provides an understanding of the resource usage and performance characteristics of the running containers.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.datadoghq.com/" target="_blank" rel="noopener noreferrer"&gt;&lt;strong&gt;Datadog&lt;/strong&gt;&lt;/a&gt; is a good monitoring tool for those who prefer working with a fully-managed SaaS solution. It has a simple user interface to monitor containers. Further, it hosts metrics, such as the CPU and RAM. Its open source projects can be accessed in &lt;a href="https://github.com/DataDog" target="_blank" rel="noopener noreferrer"&gt;github&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/kubernetes-retired/heapster" target="_blank" rel="noopener noreferrer"&gt;Heapster&lt;/a&gt;&lt;/strong&gt; was a native supporter of Kubernetes and is installed as a pod inside Kubernetes. Thus, it can effectively gather data from the containers and pods inside the cluster. Unfortunately developers have retired the project, but you can still access the open source code.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="3-security-tools"&gt;3. Security Tools&lt;/h2&gt;
&lt;p&gt;Since Kubernetes effectively automates the provisioning and configuration of containers and provides IP-based security to each pod in the cluster, it has become the de facto container orchestrator. However, Kubernetes cannot offer advanced security monitoring and compliance enforcement, making it important for you to rely on the below-mentioned tools to secure your container stack and in turn &lt;a href="https://www.manipalprolearn.com/blog/decoding-devops-security-three-best-practices" target="_blank" rel="noopener noreferrer"&gt;bolster DevOps security&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/aporeto-inc" target="_blank" rel="noopener noreferrer"&gt;&lt;strong&gt;Aporeto&lt;/strong&gt;&lt;/a&gt; offers runtime protection to containers, microservices, and cloud and legacy applications, thereby securing Kubernetes workloads. It provides a cloud-network firewall system to secure apps running in distributed environments.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://www.twistlock.com/" target="_blank" rel="noopener noreferrer"&gt;Twistlock&lt;/a&gt;&lt;/strong&gt; is designed to monitor applications deployed on Kubernetes for vulnerability, compliance issues, whitelisting, firewalling, and offer runtime protection to containers. In fact, it had compliance controls for enforcing HIPAA and PCI regulations on the K8 containers. The latest version adds forensic analysis that can reduce runtime overhead.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://neuvector.com/" target="_blank" rel="noopener noreferrer"&gt;&lt;strong&gt;NeuVector&lt;/strong&gt;&lt;/a&gt; was designed to safeguard the entire K8 cluster. The container security product can protect applications at all stages of deployment.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sysdig.com/products/secure/" target="_blank" rel="noopener noreferrer"&gt;&lt;strong&gt;Sysdig Secure&lt;/strong&gt;&lt;/a&gt; offers a set of tools for monitoring container runtime environments. Sysdig designed this tool for deep integrations with container orchestration tools and to run along with other tools, such as Sysdig Monitor.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="4-development-tools"&gt;4. Development Tools&lt;/h2&gt;
&lt;p&gt;Kubernetes applications consist of multiple services, each running in its own container. Developing and debugging them on a remote Kubernetes cluster can be a cumbersome undertaking. Here are a few development tools that can ease the process of developing and debugging the services locally.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://www.telepresence.io/" target="_blank" rel="noopener noreferrer"&gt;Telepresence&lt;/a&gt;&lt;/strong&gt; is a development tool that allows you to use custom tools, namely debugger and IDE to simplify the developing and &lt;a href="https://kubernetes.io/docs/tasks/debug-application-cluster/local-debugging/" target="_blank" rel="noopener noreferrer"&gt;local debugging process&lt;/a&gt;. It provides full access to ConfigMap and other services running on the remote cluster.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://keel.sh/" target="_blank" rel="noopener noreferrer"&gt;Keel&lt;/a&gt;&lt;/strong&gt; automates Kubernetes deployment updates as soon as the new version is available in the repository. It is stateless and robust and deploys Kubernetes services through labels, annotations, and charts.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kubernetes/helm" target="_blank" rel="noopener noreferrer"&gt;&lt;strong&gt;Helm&lt;/strong&gt;&lt;/a&gt; is an application package manager for Kubernetes that allows the description of the application structure using helm-charts and simple commands.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/logzio/apollo/wiki/Getting-Started-with-Apollo" target="_blank" rel="noopener noreferrer"&gt;&lt;strong&gt;Apollo&lt;/strong&gt;&lt;/a&gt; is an open-source application that helps operators create and deploy their services to Kubernetes. It also allows the user to view logs and revert deployments at any time.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="5-kubernetes-based-serverless-frameworks"&gt;5. Kubernetes-Based Serverless Frameworks&lt;/h2&gt;
&lt;p&gt;Due to Kubernetes’ ability to orchestrate containers across clusters of hosts, serverless FaaS frameworks rely on Kubernetes for orchestration and management. Here are a few Kubernetes-based serverless frameworks that can help build a serverless environment.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://kubeless.io/" target="_blank" rel="noopener noreferrer"&gt;Kubeless&lt;/a&gt;&lt;/strong&gt; is a Kubernetes-native open-source serverless framework that allows developers to deploy bits of code without worrying about the underlying infrastructure. It uses Kubernetes resources to offer auto-scaling, API routing, monitoring, and troubleshooting&lt;/li&gt;
&lt;li&gt;&lt;a href="https://platform9.com/fission/" target="_blank" rel="noopener noreferrer"&gt;&lt;strong&gt;Fission&lt;/strong&gt;&lt;/a&gt; is an open-source serverless framework released by Platform9, a software company that manages hybrid cloud infrastructure with Kubernetes cloud solutions. The framework helps developers manage their applications without bothering about the plumbing related to containers.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/knative" target="_blank" rel="noopener noreferrer"&gt;&lt;strong&gt;KNative&lt;/strong&gt;&lt;/a&gt; is a platform used by operators to build serverless solutions on top of Kubernetes. It isn’t an outright serverless solution. KNative acts as a layer between Kubernetes and the serverless framework, enabling developers to run the application anywhere that Kubernetes runs.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="time-for-action"&gt;Time for Action&lt;/h2&gt;
&lt;p&gt;Open-source container-orchestration systems like Kubernetes have helped users overcome several challenges in the DevOps space. However, as Kubernetes continues to evolve, your development, monitoring, and security strategies need to change. Use the Kubernetes tools and frameworks shared in this post to simplify cluster orchestration and deployment, making it easy to deploy this popular orchestrator.&lt;/p&gt;
&lt;p&gt;–&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The content in this blog is provided in good faith by members of the open source community. The content is not edited or tested by Percona, and views expressed are the authors’ own. When using the advice from this or any other online resource, please &lt;strong&gt;test&lt;/strong&gt; ideas before applying them to your production systems, and **always **secure a working back up.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Featured image photograph &lt;a href="https://pixabay.com/photos/boat-wheel-ship-sea-nautical-2387790/" target="_blank" rel="noopener noreferrer"&gt;AnnaD on Pixabay&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;</content:encoded>
      <author>Gaurav Belani</author>
      <category>DevOps</category>
      <category>Kubernetes</category>
      <category>Tools</category>
      <media:thumbnail url="https://percona.community/blog/2019/07/kubernetes-management-tools_hu_130ec8379081eda6.jpg"/>
      <media:content url="https://percona.community/blog/2019/07/kubernetes-management-tools_hu_e815360ef9f99cd8.jpg" medium="image"/>
    </item>
    <item>
      <title>Percona Live Presents: The First Ever TiDB Track</title>
      <link>https://percona.community/blog/2019/05/06/percona-live-presents-first-ever-tidb-track/</link>
      <guid>https://percona.community/blog/2019/05/06/percona-live-presents-first-ever-tidb-track/</guid>
      <pubDate>Mon, 06 May 2019 20:45:41 UTC</pubDate>
      <description>The PingCAP team has always been a strong supporter of Percona and the wider open source database community. As the people who work day in and day out on TiDB, an open source NewSQL database with MySQL compatibility, open source database is what gets us in the morning, and there’s no better place to share that passion than Percona Live.</description>
      <content:encoded>&lt;p&gt;The PingCAP team has always been a strong supporter of Percona and the wider open source database community. As the people who work day in and day out on &lt;a href="https://github.com/pingcap/tidb" target="_blank" rel="noopener noreferrer"&gt;TiDB&lt;/a&gt;, an open source NewSQL database with MySQL compatibility, open source database is what gets us in the morning, and there’s no better place to share that passion than Percona Live.&lt;/p&gt;
&lt;p&gt;At this year’s &lt;a href="https://www.percona.com/live/19/" target="_blank" rel="noopener noreferrer"&gt;Percona Live Open Source Database Conference&lt;/a&gt; in Austin, Texas, we are particularly excited to bring you a full track of talks and demo on the latest development in TiDB during Day 1 of the conference.&lt;/p&gt;
&lt;h2 id="who-would-benefit-from-the-tidb-track"&gt;Who would benefit from the TiDB track&lt;/h2&gt;
&lt;p&gt;The TiDB track is designed to share with developers, DBAs, and practitioners in general technical know-hows, reproducible benchmarks (no benchmark-eting), and best practices on how TiDB can solve their problems. There are 7 talks total by folks from PingCAP and Intel that cover the full gamut of how you can test, migrate, and use TiDB in the cloud to solve technical problems and deliver business value. Here’s a run down of the talk topics:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.percona.com/live/19/sessions/tidb-30-whats-new-and-whats-next" target="_blank" rel="noopener noreferrer"&gt;How to benchmark TiDB 3.0, the newest version&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.percona.com/live/19/sessions/using-chaos-engineering-to-build-a-reliable-tidb" target="_blank" rel="noopener noreferrer"&gt;Using chaos engineering to ensure system reliability&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.percona.com/live/19/sessions/leveraging-optane-to-tackle-your-io-challenges-with-tidb" target="_blank" rel="noopener noreferrer"&gt;Leveraging Intel Optane to tackle IO challenges&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.percona.com/live/19/sessions/deep-dive-into-tidb-sql-layer" target="_blank" rel="noopener noreferrer"&gt;A deep look at TiDB’s SQL processing layer, optimized for a distributed system&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.percona.com/live/19/sessions/making-htap-real-with-tiflash-a-tidb-native-columnar-extension" target="_blank" rel="noopener noreferrer"&gt;Introducing a new columnar storage engine (TiFlash) that makes hybrid OLTP/OLAP a reality&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.percona.com/live/19/sessions/making-an-aas-out-of-tidb-building-dbaas-on-a-kubernetes-operator" target="_blank" rel="noopener noreferrer"&gt;Building TiDB as a managed service (aka DBaaS) on a Kubernetes Operator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.percona.com/live/19/sessions/from-mysql-to-tidb-and-back-again" target="_blank" rel="noopener noreferrer"&gt;Migration best practices in and out of TiDB from MySQL and MariaDB&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Phew! That’s a lot. I hope you are excited to join us for this track. As Peter Zaitsev and Morgan Tocker (one of the TiDB track speakers) noted in a recent &lt;a href="https://www.percona.com/resources/webinars/how-horizontally-scale-mysql-tidb-while-avoiding-sharding-issues" target="_blank" rel="noopener noreferrer"&gt;Percona webinar&lt;/a&gt;, there’s a lot TiDB can do to help scale MySQL while avoiding common manual sharding issues. This track will peel the onion to show you all the fun stuff under the hood.&lt;/p&gt;
&lt;h2 id="whose-presentations-do-you-look-forward-to"&gt;Whose presentations do you look forward to?&lt;/h2&gt;
&lt;p&gt;Besides the TiDB track, there are many other presentations we are excited about. In particular, I look forward to attending Stacy Yuan and Yashada Jadhav of PayPal’s talk on &lt;a href="https://www.percona.com/live/19/sessions/mysql-security-and-standardization-at-paypal" target="_blank" rel="noopener noreferrer"&gt;MySQL Security and Standardization&lt;/a&gt;, and Vinicius Grippa of Percona’s presentation on &lt;a href="https://www.percona.com/live/19/sessions/enhancing-mysql-security" target="_blank" rel="noopener noreferrer"&gt;enhancing MySQL Security&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;See you soon in Austin!&lt;/p&gt;</content:encoded>
      <author>PingCAP</author>
      <category>Kubernetes</category>
      <category>MySQL</category>
      <category>Open Source Databases</category>
      <category>Percona Live 2019</category>
      <media:thumbnail url="https://percona.community/blog/2019/05/state-of-databases-2019_hu_22a71a457a8ad3d7.jpg"/>
      <media:content url="https://percona.community/blog/2019/05/state-of-databases-2019_hu_a4b61c990581d86.jpg" medium="image"/>
    </item>
    <item>
      <title>Percona Live Presents: The MySQL Query Optimizer Explained Through Optimizer Trace</title>
      <link>https://percona.community/blog/2019/04/24/mysql-query-optimizer-explained-optimizer-trace/</link>
      <guid>https://percona.community/blog/2019/04/24/mysql-query-optimizer-explained-optimizer-trace/</guid>
      <pubDate>Wed, 24 Apr 2019 16:16:09 UTC</pubDate>
      <description>During my presentation at Percona Live 2019 I will show how using Optimizer Trace can give insight into the inner workings of the MySQL Query Optimizer. Through the presentation, the audience will both be introduced to optimizer trace, learn more about the decisions the query optimizer makes, and learn about the query execution strategies the query optimizer has at its disposal. I’ll be covering the main phases of the MySQL optimizer and its optimization strategies, including query transformations, data access strategies, the range optimizer, the join optimizer, and subquery optimization.</description>
      <content:encoded>&lt;p&gt;During my presentation at &lt;a href="https://www.percona.com/live/19/sessions/the-mysql-query-optimizer-explained-through-optimizer-trace" target="_blank" rel="noopener noreferrer"&gt;Percona Live 2019&lt;/a&gt; I will show how using Optimizer Trace can give insight into the inner workings of the MySQL Query Optimizer. Through the presentation, the audience will both be introduced to optimizer trace, learn more about the decisions the query optimizer makes, and learn about the query execution strategies the query optimizer has at its disposal. I’ll be covering the main phases of the MySQL optimizer and its optimization strategies, including query transformations, data access strategies, the range optimizer, the join optimizer, and subquery optimization.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2019/04/oysteing3.jpg" alt="Øystein Grøvlen" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h2 id="whod-benefit-most-from-the-presentation"&gt;Who’d benefit most from the presentation?&lt;/h2&gt;
&lt;p&gt;DBAs, developers, support engineers and other people who are concerned about MySQL query performance will benefit from this presentation. Knowing the optimizer trace will enable them to understand why the query optimizer selected a particular query plan. This will be very helpful in order to understand how tune their queries for better performance.&lt;/p&gt;
&lt;h2 id="whose-presentations-are-you-most-looking-forward-to"&gt;Whose presentations are you most looking forward to?&lt;/h2&gt;
&lt;p&gt;I’m definitely looking forward to &lt;a href="https://www.percona.com/live/19/sessions/a-proactive-approach-to-monitoring-slow-queries" target="_blank" rel="noopener noreferrer"&gt;A Proactive Approach to Monitoring Slow Queries&lt;/a&gt; by Shashank Sahni of &lt;a href="https://www.thousandeyes.com/" target="_blank" rel="noopener noreferrer"&gt;ThousandEyes Inc&lt;/a&gt;. It is always interesting to learn how users of MySQL monitor their systems to detect and improve slow queries.&lt;/p&gt;</content:encoded>
      <author>Øystein Grøvlen</author>
      <category>Events</category>
      <category>MySQL</category>
      <category>Percona Live 2019</category>
      <media:thumbnail url="https://percona.community/blog/2019/04/oysteing3_hu_6fbb8ac78c811860.jpg"/>
      <media:content url="https://percona.community/blog/2019/04/oysteing3_hu_f3e25d50fc98dc57.jpg" medium="image"/>
    </item>
    <item>
      <title>Percona Live Presents: Vitess – Running Sharded MySQL on Kubernetes</title>
      <link>https://percona.community/blog/2019/04/18/percona-live-presents-vitess-running-sharded-mysql-kubernetes/</link>
      <guid>https://percona.community/blog/2019/04/18/percona-live-presents-vitess-running-sharded-mysql-kubernetes/</guid>
      <pubDate>Thu, 18 Apr 2019 17:19:49 UTC</pubDate>
      <description>The topic I’m presenting addresses a growing and unfulfilled need: the ability to run stateful workloads in Kubernetes. Running stateless applications is now considered a solved problem. However, it’s currently not practical to put databases like MySQL in containers, give them to Kubernetes, and expect it to manage their life cycles.</description>
      <content:encoded>&lt;p&gt;The topic I’m presenting addresses a growing and unfulfilled need: the ability to run stateful workloads in Kubernetes. Running stateless applications is now considered a solved problem. However, it’s currently not practical to put databases like MySQL in containers, give them to Kubernetes, and expect it to manage their life cycles.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2019/04/sugu_sougoumarane.jpg" alt="Sugu Sougoumarane" /&gt;&lt;/figure&gt;
Sugu Sougoumarane, CTO of Planetscale and creator of &lt;a href="https://vitess.io/" target="_blank" rel="noopener noreferrer"&gt;Vitess&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Vitess addresses this need by providing all the necessary orchestration and safety, and it has multiple years of mileage to show for it. Storage is the last piece of the puzzle that needs to be solved in Kubernetes, and it’s exciting to see people look towards Vitess to fill this gap.&lt;/p&gt;
&lt;h2 id="whod-benefit-most-from-the-presentation"&gt;Who’d benefit most from the presentation?&lt;/h2&gt;
&lt;p&gt;Anybody that’s looking to move to Kubernetes and is wondering about what to do about their data is the perfect audience. Needless to say, vitess also addresses problems of scalability. So, those who are looking to scale mysql will also benefit from our talk.&lt;/p&gt;
&lt;h2 id="whose-presentations-are-you-most-looking-forward-to"&gt;Whose presentations are you most looking forward to?&lt;/h2&gt;
&lt;p&gt;I’m looking forward to &lt;em&gt;&lt;a href="https://www.percona.com/live/19/sessions/an-open-source-cloud-native-database-cndb" target="_blank" rel="noopener noreferrer"&gt;An Open-Source, Cloud Native Database (CNDB)&lt;/a&gt;&lt;/em&gt; by David Cohen, of Intel, and others. They are doing something unique by bridging the gap from legacy systems and cloud-based architectures that are coming up today, and using all open source technology.&lt;/p&gt;
&lt;p&gt;I’ll be presenting my talk &lt;em&gt;&lt;a href="https://www.percona.com/live/19/sessions/vitess-running-sharded-mysql-on-kubernetes" target="_blank" rel="noopener noreferrer"&gt;Vitess: Running Sharded MySQL on Kubernetes&lt;/a&gt;&lt;/em&gt; at Percona Live 2019 on Wednesday, May 29 alongside Dan Kozlowski, also of &lt;a href="https://planetscale.com/" target="_blank" rel="noopener noreferrer"&gt;PlanetScale&lt;/a&gt;. If you’d like to &lt;a href="https://www.percona.com/live/19/register" target="_blank" rel="noopener noreferrer"&gt;register for the conference&lt;/a&gt;, use the code SEEMESPEAK for a 20% discount on your ticket.&lt;/p&gt;
&lt;p&gt;Percona Live 2019 takes place in Austin Texas from May 28 – May 30, &lt;a href="https://www.percona.com/live/19/" target="_blank" rel="noopener noreferrer"&gt;view the full programme here&lt;/a&gt;.&lt;/p&gt;</content:encoded>
      <author>Sugu Sougoumarane</author>
      <category>Events</category>
      <category>MySQL</category>
      <category>Percona Live 2019</category>
      <media:thumbnail url="https://percona.community/blog/2019/04/sugu_sougoumarane_hu_20c445e194a57b97.jpg"/>
      <media:content url="https://percona.community/blog/2019/04/sugu_sougoumarane_hu_2634aeccf4aaf5bc.jpg" medium="image"/>
    </item>
    <item>
      <title>Some Notes on MariaDB system-versioned Tables</title>
      <link>https://percona.community/blog/2018/12/14/notes-mariadb-system-versioned-tables/</link>
      <guid>https://percona.community/blog/2018/12/14/notes-mariadb-system-versioned-tables/</guid>
      <pubDate>Fri, 14 Dec 2018 14:53:29 UTC</pubDate>
      <description>As mentioned in a previous post, I gave a talk at Percona Live Europe 2018 about system-versioned tables. This is a new MariaDB 10.3 feature, which consists of preserving old versions of a table rows. Each version has two timestamps that indicate the start (INSERT,UPDATE) of the validity of that version, and its end (DELETE, UPDATE). As a result, the user is able to query these tables as they appear at a point in the past, or how data evolved in a certain time range. An alternative name for this feature is temporal table, and I will use it in the rest of this text.</description>
      <content:encoded>&lt;p&gt;As mentioned in a &lt;a href="https://www.percona.com/community-blog/2018/10/17/percona-live-europe-presents-mariadb-system-versioned-tables/" target="_blank" rel="noopener noreferrer"&gt;previous post&lt;/a&gt;, I gave a talk at &lt;a href="https://www.percona.com/live/e18/sessions/mariadb-system-versioned-tables" target="_blank" rel="noopener noreferrer"&gt;Percona Live Europe 2018&lt;/a&gt; about system-versioned tables. This is a new MariaDB 10.3 feature, which consists of preserving old versions of a table rows. Each version has two timestamps that indicate the start (INSERT,UPDATE) of the validity of that version, and its end (DELETE, UPDATE). As a result, the user is able to query these tables as they appear at a point in the past, or how data evolved in a certain time range. An alternative name for this feature is &lt;em&gt;temporal table&lt;/em&gt;, and I will use it in the rest of this text.
&lt;figure&gt;&lt;img src="https://percona.community/blog/2018/12/mariadb-system-versioned-tables.jpg" alt="mariadb system-versioned tables" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;In this post, I want to talk a bit about temporal tables best practices. Some of the information that I will provide is not present in &lt;a href="https://mariadb.com/kb/en/library/system-versioned-tables/" target="_blank" rel="noopener noreferrer"&gt;the documentation&lt;/a&gt;; while they are based on my experience and tests, there could be errors. My suggestions for good practices are also based on my experience and opinions, and I don’t consider them as universal truths. If you have different opinions, I hope that you will share them in the comments or as a separate blog post.&lt;/p&gt;
&lt;h2 id="create-temporal-columns"&gt;Create temporal columns&lt;/h2&gt;
&lt;p&gt;It is possible – but optional – to create the columns that contain the timestamps of rows. Since there is no special term for them, I call them &lt;em&gt;temporal columns&lt;/em&gt;. MariaDB allows us to give them any name we like, so I like to use the names valid_from and valid_to, which seem to be some sort of de facto standard in data warehousing. Whichever names you decide to use, I advise you to use them for all your temporal columns and for nothing else, so that the meaning will be clear.
Temporal columns are &lt;em&gt;generated columns&lt;/em&gt;, meaning that their values are generated by MariaDB and cannot be modified by the user. They are also &lt;em&gt;invisible columns&lt;/em&gt;, which means that they can only be read by mentioning them explicitly. In other words, the following query will not return those columns:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;SELECT * FROM temporal_table;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Also, that query will only show current versions of the rows. In this way, if we make a table temporal, existing applications and queries will continue to work as before.&lt;/p&gt;
&lt;p&gt;But we can still read old versions and obtain timestamp with a query like this:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-1"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;SELECT *, valid_from, valid_to
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;    FROM temporal_table **FOR SYSTEM_TIME ALL**
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;    WHERE valid_from &lt; NOW() - INTERVAL 1 MONTH;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;If we don’t create these columns, we will not be able to read the timestamps of current and old row versions. We will still be able to read data from a point in time or from a time range by using some special syntax. However, I believe that using the consolidated WHERE syntax is easier and more expressive than using some syntax sugar.&lt;/p&gt;
&lt;h2 id="primary-keys"&gt;Primary keys&lt;/h2&gt;
&lt;p&gt;For performance reasons, InnoDB tables should always have a primary key, and normally it shouldn’t be updated. Temporal tables provide another reason to follow this golden rule – even on storage engines that are not organised by primary key, like MyISAM.&lt;/p&gt;
&lt;p&gt;The reason is easy to demonstrate with an example:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-2" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-2"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;SELECT id, valid_from, valid_to FROM t FOR SYSTEM_TIME ALL WHERE id IN (500, 501);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+-----+----------------------------+----------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| id | valid_from | valid_to |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+-----+----------------------------+----------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| 500 | 2018-12-09 12:22:45.000001 | 2018-12-09 12:23:03.000001 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| 501 | 2018-12-09 12:23:03.000001 | 2038-01-19 03:14:07.999999 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+-----+----------------------------+----------------------------+&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;What do these results mean? Maybe row 500 has been deleted and row 501 has been added. Or maybe row 500 has been modified, and its id became 501. The timestamps suggest that the latter hypothesis is more likely, but there is no way to know that for sure.&lt;/p&gt;
&lt;p&gt;That is why, in my opinion, we need to be able to assume that UPDATEs never touch primary key values.&lt;/p&gt;
&lt;h2 id="indexes"&gt;Indexes&lt;/h2&gt;
&lt;p&gt;Currently, the documentation says nothing about how temporal columns are indexed. However, my conclusion is that the valid_to column is appended to UNIQUE indexes and the primary key. My opinion is based on the results of some EXPLAIN commands, like the following:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-3" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-3"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;EXPLAIN SELECT email, valid_to FROM customer ORDER BY email G
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;*************************** 1. row ***************************
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; id: 1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; select_type: SIMPLE
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; table: customer
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; type: index
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;possible_keys: NULL
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; key: unq_email
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; key_len: 59
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ref: NULL
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; rows: 4
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Extra: Using where; Using index&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This means that the query only reads from a UNIQUE index, and not from table data – therefore, the index contains the email column. It is also able to use the index for sorting, which confirms that email is the first column (as expected). In this way, UNIQUE indexes don’t prevent the same value from appearing multiple times, but it will always be shown at different points in time.&lt;/p&gt;
&lt;p&gt;It can be a good idea to include valid_to or valid_from in some regular indexes, to optimize queries that use such columns for filtering results.&lt;/p&gt;
&lt;h2 id="transaction-safe-temporal-tables"&gt;Transaction-safe temporal tables&lt;/h2&gt;
&lt;p&gt;Temporal columns contain timestamps that indicate when a row was INSERTed, UPDATEd, or DELETEd. So, when autocommit is not enabled, temporal columns don’t match the COMMIT time. For most use cases, this behaviour is desirable or at least acceptable. But there are cases when we want to only see committed data, to avoid data inconsistencies that were never seen by applications.&lt;/p&gt;
&lt;p&gt;To do so, we can create a history-precise temporal table. This only works with InnoDB – not with RocksDB or TokuDB, even if they support transactions. A history-precise temporal table doesn’t contain timestamps; instead, it contains the id’s of transactions that created and deleted each row version. If you know PostgreSQL, you are probably familiar with the xmin and xmax columns – it’s basically the same idea, except that in postgres at some point autovacuum will make old row versions disappear. Because of the similarity, for transaction-precise temporal tables, I like to call the temporal columns xmin and xmax.&lt;/p&gt;
&lt;p&gt;From this short description, the astute reader may already see a couple of problems with this approach:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Temporal tables are based on transaction id’s &lt;strong&gt;or&lt;/strong&gt; on timestamps, not both. There is no way to run a transaction-precise query to extract data that were present one hour ago. But think about it: even if it was possible, it would be at least problematic, because transactions are meant to be concurrent.&lt;/li&gt;
&lt;li&gt;Transaction id’s are written in the binary log, but such information is typically only accessible by DBAs. An analyst (someone who’s typically interested in temporal tables) has no access to transaction id’s.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A partial workaround would be to query tables with columns like created_at and modified_at. We can run queries like this:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-4" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-4"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;SELECT created_at, xmin
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; FROM some_table
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; WHERE created_at &gt;= '2018-05-05 16:00:00'
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ORDER BY created_at
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; LIMIT 1;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This will return the timestamp of the first row created since ‘2018-05-05 16:00:00’, as well as the id of the transaction which inserted it.&lt;/p&gt;
&lt;p&gt;While this approach could give us the information we need with a reasonable extra work, it’s possible that we don’t have such columns, or that rows are not inserted often enough in tables that have them.&lt;/p&gt;
&lt;p&gt;In this case, we can occasionally write in a table the current timestamp and the current transaction id. This should allow us to associate a transaction to the timestamp we are interested in. We cannot write all transaction id’s for performance reasons, so we can use two different approaches:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Write the transaction id and the timestamp periodically, for example each minute. This will not create performance problems. On the other hand, we are arbitrarily deciding the granularity of our “log”. This could be acceptable or not.&lt;/li&gt;
&lt;li&gt;Write this information when certain events happen. For example when a product is purchased, or when a user changes their password. This will give us a very precise way to see the data as they appeared during critical events, but will not allow us to investigate with the same precision other types of events.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="partitioning"&gt;Partitioning&lt;/h2&gt;
&lt;p&gt;If we look at older implementations of temporary tables, in the world of proprietary databases (Db2, SQL Server, Oracle), they generally store historical data in a separate physical table or partition, sometimes called a history table. In MariaDB this doesn’t happen automatically or by default, leaving the choice to the user. However, it seems to me a good idea in the general case to create one or more partitions to store historical rows. The main reason is that, rarely, a query has to read both historical and current data, and reading only one partition is an interesting optimization.&lt;/p&gt;
&lt;h2 id="excluding-columns-from-versioning"&gt;Excluding columns from versioning&lt;/h2&gt;
&lt;p&gt;MariaDB allows us to exclude some columns from versioning. This means that if we update the values of those columns, we update the current row version in place rather than creating a new one. This is probably useful if a column is frequently updated and we don’t care about these changes. However, if we update more columns with one statement, and only a subset of them is excluded from versioning, a new row version is still created. All in all, the partial exclusion of some rows could be more confusing than useful in several cases.&lt;/p&gt;
&lt;h2 id="replication"&gt;Replication&lt;/h2&gt;
&lt;p&gt;10.3 is a stable version, but it is still recent. Some of us adopt a new major version after some years, and we can even have reasons to stick with an old version. Furthermore, of course, many of us use MySQL, and MariaDB is not a drop-in replacement.&lt;/p&gt;
&lt;p&gt;But we can still enjoy temporal tables by adding a MariaDB 10.3 slave. I attached such a slave to older MariaDB versions, and to MySQL 5.6. In all tests, the feature behaved as expected.&lt;/p&gt;
&lt;p&gt;Initially, I was worried about replication lags. I assumed that, if replication lags, the slave applies the changes with a delay, and the timestamps in the tables are delayed accordingly. I am glad to say that I was wrong: the timestamps in temporal tables seem to match the ones in the binary log, so replication lags don’t affect their correctness.&lt;/p&gt;
&lt;p&gt;This is true both with row-based replication and with statement-based replication.&lt;/p&gt;
&lt;p&gt;A small caveat about temporal tables is that the version timestamps are only precise at second level. The fractional part should be ignored. You may have noticed this in the example at the beginning of this post.&lt;/p&gt;
&lt;h2 id="backups"&gt;Backups&lt;/h2&gt;
&lt;p&gt;For backups you will need to use &lt;a href="https://mariadb.com/kb/en/library/mariabackup-overview/" target="_blank" rel="noopener noreferrer"&gt;mariabackup&lt;/a&gt; instead of xtrabackup.&lt;/p&gt;
&lt;p&gt;mysqldump can be used, not necessarily from a MariaDB distribution. However, it treats temporal tables as regular tables. It does not backup historical data. This is necessary because of a design choice: we cannot insert rows with timestamps in the past. This makes temporal tables much more reliable. Also, temporal tables are likely to be (or become) quite big, so a dump is probably not the best way to backup them.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;–&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Photo by &lt;a href="https://unsplash.com/photos/WeYamle9fDM?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" target="_blank" rel="noopener noreferrer"&gt;Ashim D’Silva&lt;/a&gt; on &lt;a href="https://unsplash.com/search/photos/canyon?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" target="_blank" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;</content:encoded>
      <author>Federico Razzoli</author>
      <category>MariaDB</category>
      <category>MySQL</category>
      <category>system-versioned tables</category>
      <media:thumbnail url="https://percona.community/blog/2018/12/mariadb-system-versioned-tables_hu_67f40cbc67439966.jpg"/>
      <media:content url="https://percona.community/blog/2018/12/mariadb-system-versioned-tables_hu_d2a41d9d1c19f4c6.jpg" medium="image"/>
    </item>
    <item>
      <title>MySQL Setup at Hostinger Explained</title>
      <link>https://percona.community/blog/2018/12/11/mysql-setup-hostinger-explained/</link>
      <guid>https://percona.community/blog/2018/12/11/mysql-setup-hostinger-explained/</guid>
      <pubDate>Tue, 11 Dec 2018 15:27:45 UTC</pubDate>
      <description>Ever wondered how hosting companies manage their MySQL database architecture? At Hostinger, we have various MySQL setups starting from the standalone replica-less instances to Percona XtraDB Cluster (later just PXC), ProxySQL routing-based and even absolutely custom and unique solutions which I’m going to describe in this blog post.</description>
      <content:encoded>&lt;p&gt;Ever wondered how hosting companies manage their MySQL database architecture? At &lt;a href="https://www.hostinger.com/" target="_blank" rel="noopener noreferrer"&gt;Hostinger,&lt;/a&gt; we have various MySQL setups starting from the standalone replica-less instances to &lt;a href="https://www.percona.com/software/mysql-database/percona-xtradb-cluster" target="_blank" rel="noopener noreferrer"&gt;Percona XtraDB Cluster&lt;/a&gt; (later just PXC), &lt;a href="http://www.proxysql.com/" target="_blank" rel="noopener noreferrer"&gt;ProxySQL&lt;/a&gt; routing-based and even absolutely custom and unique solutions which I’m going to describe in this blog post.&lt;/p&gt;
&lt;p&gt;We do not have elephant-sized databases for internal services like API, billing, and clients. Thus almost every decision ends up with high availability as a top priority instead of scalability.&lt;/p&gt;
&lt;p&gt;Still, scaling vertically is good enough for our case, as the database size does not exceed 500GB. One and the top requirements is the ability to access the master node, as we have fairly equal-distanced workloads for reading and writing.&lt;/p&gt;
&lt;p&gt;Our current setup for storing all the data about the clients, servers and so forth is using PXC formed of three nodes without any geo-replication. All nodes are running in the same datacenter.&lt;/p&gt;
&lt;p&gt;We have plans to migrate this cluster to geo-replicated cluster across three locations: the United States, Netherlands, and Singapore. This would allow us to warrant high availability if one of the locations became unreachable.&lt;/p&gt;
&lt;p&gt;Since PXC uses fully synchronous replication, there will be higher latencies for writes. But the reads will be much quicker because of the local replica in every location.&lt;/p&gt;
&lt;p&gt;We did some research on &lt;a href="https://dev.mysql.com/doc/refman/8.0/en/group-replication.html" target="_blank" rel="noopener noreferrer"&gt;MySQL Group Replication&lt;/a&gt;, but it requires instances to be closer to each other and is more sensitive to latencies.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Group Replication is designed to be deployed in a cluster environment where server instances are very close to each other, and is impacted by both network latency as well as network bandwidth.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;PXC was used previously, thus we to know how to deal with it in critical circumstances and make it more highly available.&lt;/p&gt;
&lt;p&gt;In &lt;a href="https://www.000webhost.com/" target="_blank" rel="noopener noreferrer"&gt;000webhost.com&lt;/a&gt; project and hAPI (Hostinger API) we use our aforementioned unique solution which selects the master node using Layer3 protocol.&lt;/p&gt;
&lt;p&gt;One of our best friends is BGP and BGP protocol, which is aged enough to buy its own beer, hence we use it a lot. This implementation also uses BGP as the underlying protocol and helps to point to the real master node. To run BGP protocol we use the ExaBGP service and announce VIP address as anycast from both master nodes.&lt;/p&gt;
&lt;p&gt;You should be asking: but how are you sure MySQL queries go to the one and the same instance instead of hitting both? We use &lt;a href="https://zookeeper.apache.org/doc/current/zookeeperOver.html" target="_blank" rel="noopener noreferrer"&gt;Zookeeper’s ephemeral nodes&lt;/a&gt; to acquire the lock as mutually exclusive.&lt;/p&gt;
&lt;p&gt;Zookeeper acts like a circuit breaker between BGP speakers and the MySQL clients. If the lock is acquired we announce the VIP from the master node and applications send the queries toward this path. If the lock is released, another node can take it over and announce the VIP, so the application will send the queries without any efforts.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2018/12/mysql-setup-hostinger.jpg" alt="mysql setup at hostinger" /&gt;&lt;/figure&gt;
&lt;em&gt;MySQL Setup at Hostinger&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The second question comes: what conditions should be met to stop announcing VIP? This can be implemented differently depending on use case, but we release the lock if MySQL process is down using systemd’s &lt;code&gt;Requires&lt;/code&gt; in the unit file of ExaBGP:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Besides, with or without specifying After=, this unit will be stopped if one of the other units is explicitly stopped.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;With &lt;a href="https://www.freedesktop.org/wiki/Software/systemd/" target="_blank" rel="noopener noreferrer"&gt;systemd&lt;/a&gt; we can create a nice dependency tree which ensures all of them are met. Stopping, killing, or even rebooting the MySQL will make systemd stop the ExaBGP process and withdraw the VIP announcement. The final result is a new master selected.&lt;/p&gt;
&lt;p&gt;We battle tested those master failovers during our &lt;a href="https://www.hostinger.com/blog/new-network-infrastructure" target="_blank" rel="noopener noreferrer"&gt;Gaming days&lt;/a&gt; and nothing critical was noticed &lt;em&gt;yet&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;If you think good architecture is expensive, try bad architecture 😉&lt;/p&gt;
&lt;p&gt;– &lt;em&gt;This post was originally published at &lt;a href="https://www.hostinger.com/blog/mysql-setup-at-hostinger-explained/" target="_blank" rel="noopener noreferrer"&gt;https://www.hostinger.com/blog/mysql-setup-at-hostinger-explained/&lt;/a&gt; in June 2018. The content in this blog is provided in good faith by members of the open source community. The content is not edited or tested by Percona, and views expressed are the authors’ own. When using the advice from this or any other online resource &lt;strong&gt;test&lt;/strong&gt; ideas before applying them to your production systems, and **always **secure a working back up.&lt;/em&gt;&lt;/p&gt;</content:encoded>
      <author>Donatas Abraitis</author>
      <category>hosting</category>
      <category>MySQL</category>
      <category>ProxySQL</category>
      <category>Tools</category>
      <category>Zookeeper Cluster</category>
      <media:thumbnail url="https://percona.community/blog/2018/12/mysql-setup-hostinger_hu_acb7bb452c7e7b06.jpg"/>
      <media:content url="https://percona.community/blog/2018/12/mysql-setup-hostinger_hu_d028d027cd277e4d.jpg" medium="image"/>
    </item>
    <item>
      <title>Export to JSON from MySQL All Ready for MongoDB</title>
      <link>https://percona.community/blog/2018/10/16/export-to-json-from-mysql-all-ready-for-mongodb/</link>
      <guid>https://percona.community/blog/2018/10/16/export-to-json-from-mysql-all-ready-for-mongodb/</guid>
      <pubDate>Tue, 16 Oct 2018 15:18:36 UTC</pubDate>
      <description>This post walks through how to export data from MySQL® into JSON format, ready to ingest into MongoDB®. Starting from MySQL 5.7+, there is native support for JSON. MySQL provides functions that actually create JSON values, so I will be using these functions in this article to export to JSON from MySQL:</description>
      <content:encoded>&lt;p&gt;This post walks through how to export data from &lt;a href="https://dev.mysql.com/" target="_blank" rel="noopener noreferrer"&gt;MySQL&lt;/a&gt;® into JSON format, ready to ingest into &lt;a href="https://www.mongodb.com/" target="_blank" rel="noopener noreferrer"&gt;MongoDB&lt;/a&gt;®. Starting from MySQL 5.7+, there is native support for JSON. MySQL provides functions that actually create JSON values, so I will be using these functions in this article to export to JSON from MySQL:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;JSON_OBJECT&lt;/li&gt;
&lt;li&gt;JSON_ARRAY&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These functions make it easy to convert MySQL data to JSON e.g.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mysql&gt; SELECT json_object('employee_id', emp_no, 'first_name', first_name ) AS 'JSON' FROM employees LIMIT 2;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+------------------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| JSON |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+------------------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| {"first_name": "Aamer", "employee_id": 444117} |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| {"first_name": "Aamer", "employee_id": 409151} |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+------------------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2 rows in set (0.00 sec)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;In this article, I will be using the employees sample database available from here: &lt;a href="https://dev.mysql.com/doc/employee/en/employees-installation.html" target="_blank" rel="noopener noreferrer"&gt;https://dev.mysql.com/doc/employee/en/employees-installation.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You can find the employees schema on &lt;a href="https://dev.mysql.com/doc/employee/en/images/employees-schema.png" target="_blank" rel="noopener noreferrer"&gt;dev.mysql.com&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;When mapping relations with collections, generally there is no one to one mapping, you would want to merge data from some MySQL tables into a single collection.&lt;/p&gt;
&lt;h2 id="export-data-to-json-format"&gt;Export data to JSON format&lt;/h2&gt;
&lt;p&gt;To export data, I have constructed the following SQL (the data is combined from 3 different tables: employees, salaries, and departments):&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-1"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;SELECT json_pretty(json_object(
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;'emp_no', emp.emp_no,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;'first_name', emp.first_name,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;'last_name', emp.last_name,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;'hire_date',
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;json_object("$date", DATE_FORMAT(emp.hire_date,'%Y-%m-%dT%TZ')),
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;'Department', JSON_ARRAY(json_object('dept_id', dept.dept_no, 'dept_name', dept.dept_name)),
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;'Salary', s.salary)) AS 'json'
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;FROM employees emp
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;INNER JOIN salaries s ON s.emp_no=emp.emp_no
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;INNER JOIN current_dept_emp c on c.emp_no = emp.emp_no
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;INNER JOIN departments dept on dept.dept_no = c.dept_no
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;LIMIT 1;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Output:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;*************************** 1. row ***************************
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;json: {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;"Salary": 60117,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;"emp_no": 10001,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;"hire_date": "1986-06-26",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;"last_name": "Facello",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;"Department": [
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;"dept_id": "d005",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;"dept_name": "Development"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;"first_name": "Georgi"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;You can see from this that json_object did not convert ‘hire_date’ column value to be compatible with MongoDB.  We have to convert date into ISODate format:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-2" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-2"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mysql&gt; select json_object('hire_date', hire_date) AS "Original Date", json_object('hire_date', DATE_FORMAT(hire_date,'%Y-%m-%dT%TZ')) AS "ISODate" from employees limit 1;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+-----------------------------+---------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| Original Date | ISODate |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+-----------------------------+---------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| {"hire_date": "1985-01-01"} | {"hire_date": "1985-01-01T00:00:00Z"} |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+-----------------------------+---------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;1 row in set (0.00 sec)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Next, we dump the output to a file (the above query is slightly modified) e.g.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-3" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-3"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;SELECT json_object(
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;'emp_no', emp.emp_no,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;'first_name', emp.first_name,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;'last_name', emp.last_name,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;'hire_date', json_object("$date", DATE_FORMAT(emp.hire_date,'%Y-%m-%dT%TZ')),
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;'Department', JSON_ARRAY(json_object('dept_id', dept.dept_no, 'dept_name', dept.dept_name)),
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;'Salary', s.salary) as 'json'
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;INTO OUTFILE 'C:/ProgramData/MySQL/MySQL Server 8.0/Uploads/employees.json' ## IMPORTANT you may want to adjust outfile path here
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;FROM employees emp
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;INNER JOIN salaries s ON s.emp_no=emp.emp_no
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;INNER JOIN current_dept_emp c on c.emp_no = emp.emp_no
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;INNER JOIN departments dept on dept.dept_no = c.dept_no&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="importing-data"&gt;Importing data&lt;/h2&gt;
&lt;p&gt;To load the file employees.json  into MongoDB, I use the &lt;a href="https://docs.mongodb.com/manual/reference/program/mongoimport/" target="_blank" rel="noopener noreferrer"&gt;mongoimport&lt;/a&gt; utility.  It’s a multi-threaded tool that can load large files efficiently.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-4" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-4"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# mongoimport --db test --collection employees --drop &lt; employees.json
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2018-10-05T12:32:30.401+0100 connected to: localhost
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2018-10-05T12:32:30.401+0100 dropping: test.employees
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2018-10-05T12:32:33.400+0100 test.employees 34.0MB
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2018-10-05T12:32:36.401+0100 test.employees 67.3MB
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2018-10-05T12:32:39.399+0100 test.employees 100MB
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2018-10-05T12:32:42.400+0100 test.employees 134MB
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2018-10-05T12:32:45.401+0100 test.employees 168MB
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2018-10-05T12:32:48.402+0100 test.employees 202MB
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2018-10-05T12:32:51.402+0100 test.employees 235MB
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2018-10-05T12:32:54.400+0100 test.employees 269MB
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2018-10-05T12:32:57.400+0100 test.employees 303MB
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2018-10-05T12:33:00.403+0100 test.employees 335MB
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2018-10-05T12:33:03.404+0100 test.employees 368MB
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2018-10-05T12:33:06.399+0100 test.employees 397MB
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2018-10-05T12:33:09.400+0100 test.employees 430MB
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2018-10-05T12:33:12.400+0100 test.employees 465MB
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2018-10-05T12:33:15.403+0100 test.employees 499MB
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2018-10-05T12:33:18.401+0100 test.employees 530MB
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2018-10-05T12:33:18.589+0100 test.employees 533MB
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2018-10-05T12:33:18.589+0100 imported 2844047 documents&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="validate"&gt;Validate&lt;/h2&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-5" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-5"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&gt; db.employees.find({}).pretty()
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;"_id" : ObjectId("5bb740cfd73e26bf45435181"),
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;"Salary" : 60117,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;"emp_no" : 10001,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;"hire_date" : ISODate("1986-06-26T00:00:00Z"),
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;"last_name" : "Facello",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;"Department" : [
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;"dept_id" : "d005",
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;"dept_name" : "Development"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;"first_name" : "Georgi"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;We have successfully migrated some data from MySQL to MongoDB!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The content in this blog is provided in good faith by members of the open source community. The content is not edited or tested by Percona, and views expressed are the authors’ own. When using the advice from this or any other online resource &lt;strong&gt;test&lt;/strong&gt; ideas before applying them to your production systems, and **always **secure a working back up.&lt;/em&gt;&lt;/p&gt;</content:encoded>
      <author>Aftab Khan</author>
      <category>Entry Level</category>
      <category>export data</category>
      <category>MongoDB</category>
      <category>MySQL</category>
      <category>tools</category>
      <category>Tools</category>
      <media:thumbnail url="https://percona.community/blog/2018/10/export-data-to-JSON-from-MySQL_hu_42c14ff7c0d70c61.jpg"/>
      <media:content url="https://percona.community/blog/2018/10/export-data-to-JSON-from-MySQL_hu_db9c8048c3d6f089.jpg" medium="image"/>
    </item>
    <item>
      <title>Percona Live Europe Tutorial: Query Optimization and TLS at Large Scale</title>
      <link>https://percona.community/blog/2018/10/15/percona-live-europe-tutorial-query-optimization-workshop-tls-large-scale-session/</link>
      <guid>https://percona.community/blog/2018/10/15/percona-live-europe-tutorial-query-optimization-workshop-tls-large-scale-session/</guid>
      <pubDate>Mon, 15 Oct 2018 14:05:06 UTC</pubDate>
      <description> For Percona Live Europe this year, I got accepted a workshop on query optimization and a 50-minute talk covering TLS for MySQL at Large Scale, talking about our experiences at the Wikimedia Foundation.</description>
      <content:encoded>&lt;p&gt;&lt;a href="https://www.percona.com/live/e18/sessions/tls-for-mysql-at-large-scale" target="_blank" rel="noopener noreferrer"&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2018/10/MySQL-at-scale.jpg" alt="MySQL has many ways to provide scalability, but can it provide it while at the same time guarantee perfect privacy? Learn it at my tutorial!" /&gt;&lt;/figure&gt;&lt;/a&gt; For Percona Live Europe this year, &lt;a href="https://www.percona.com/live/e18/speaker/jaime-crespo" target="_blank" rel="noopener noreferrer"&gt;I got accepted&lt;/a&gt; a workshop on query optimization and a 50-minute talk covering TLS for MySQL at Large Scale, talking about our experiences at the &lt;a href="https://wikimediafoundation.org/" target="_blank" rel="noopener noreferrer"&gt;Wikimedia Foundation&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="workshop"&gt;Workshop&lt;/h3&gt;
&lt;p&gt;The 3-hour workshop on Monday, titled &lt;a href="https://www.percona.com/live/e18/sessions/query-optimization-with-mysql-80-and-mariadb-103-the-basics" target="_blank" rel="noopener noreferrer"&gt;&lt;em&gt;&lt;strong&gt;Query Optimization with MySQL 8.0 and MariaDB 10.3: The Basics&lt;/strong&gt;&lt;/em&gt;&lt;/a&gt; is a beginners’ tutorial–though dense in content. It’s for people who are more familiar with database storage systems other than InnoDB for MySQL, MariaDB or Percona Server. Or who, already familiar with them, are suffering performance and scaling issues with their SQL queries. If you get confused with the output of basic commands like EXPLAIN and SHOW STATUS and want to learn some SQL-level optimizations, such as creating the right indexes or altering the schema to get the most out of the performance of your database server, then you want to attend this tutorial before going into more advanced topics. Even veteran DBAs and developers may learn one or two new tricks, only available on the latest server versions!&lt;/p&gt;
&lt;p&gt;Something that people may enjoy is that, during the tutorial, every attendee will be able to throw queries to a real-time copy of the Wikipedia database servers—or setup their own offline Wikipedia copy in their laptop. They’ll get practice by themselves what is being explained—so it will be fully hands-on. I like my sessions to be interactive, so all attendees should get ready to answer questions and think through the proposed problems by themselves!&lt;/p&gt;
&lt;h3 id="fifty-minutes-talk"&gt;Fifty minutes talk&lt;/h3&gt;
&lt;p&gt;My 50 minute talk &lt;a href="https://www.percona.com/live/e18/sessions/tls-for-mysql-at-large-scale" target="_blank" rel="noopener noreferrer"&gt;&lt;em&gt;&lt;strong&gt;TLS for MySQL at Large Scale&lt;/strong&gt;&lt;/em&gt;&lt;/a&gt; will be a bit more advanced, although maybe more attractive to users of other database technologies. On Tuesday, I will tell the tale of the mistakes and lessons learned while deploying encryption (TLS/SSL) for the replication, administration, and client connections of our databases. At the Wikimedia Foundation we take very seriously the privacy of our users—Wikipedia readers, project contributors, data reusers and every members of our community—and while none of our databases are publicly reachable, our aim is to encrypt every single connection between servers, even within our datacenters.&lt;/p&gt;
&lt;p&gt;However, when people talk about security topics, most of the time they are trying to show off the good parts of their set up, while hiding the ugly parts. Or maybe they are too theoretical to actually learn something. My focus will not be on the security principles everybody should follow, but on the pure operational problems, and the solutions we needed to deploy, as well what we would have done differently if we had known, while deploying TLS on our 200+ MariaDB server pool.&lt;/p&gt;
&lt;h3 id="looking-forward"&gt;Looking forward…&lt;/h3&gt;
&lt;p&gt;For me, as an attendee, I always look forward to the &lt;a href="https://www.percona.com/live/e18/speaker/ren-canna" target="_blank" rel="noopener noreferrer"&gt;ProxySQL sessions&lt;/a&gt;, as it is something we are currently deploying in our production. Also, I want to know more about the maturity and roadmap of the newest &lt;a href="https://www.percona.com/live/e18/sessions/mysql-80-performance-scalability-benchmarks" target="_blank" rel="noopener noreferrer"&gt;MySQL&lt;/a&gt; and &lt;a href="https://www.percona.com/live/e18/sessions/whats-new-in-and-around-mariadb-server-103" target="_blank" rel="noopener noreferrer"&gt;MariaDB&lt;/a&gt; releases, as they keep adding new interesting features we need, as well as cluster technologies such as Galera and &lt;a href="https://www.percona.com/live/e18/sessions/the-latest-mysql-replication-features" target="_blank" rel="noopener noreferrer"&gt;InnoDB Cluster&lt;/a&gt;. I like, too, to talk with people developing and using other technologies outside of my stack, and you never know when they will fill in a need we have (&lt;a href="https://www.percona.com/live/e18/sessions/clickhouse-at-messagebird-analysing-billions-of-events-in-real-time" target="_blank" rel="noopener noreferrer"&gt;analytics&lt;/a&gt;, &lt;a href="https://www.percona.com/live/e18/sessions/myrocks-production-case-studies-at-facebook" target="_blank" rel="noopener noreferrer"&gt;compression&lt;/a&gt;, &lt;a href="https://www.percona.com/live/e18/sessions/sharedrocks-a-scalable-master-slave-replication-with-rocksdb-and-shared-file-storage" target="_blank" rel="noopener noreferrer"&gt;NoSQL&lt;/a&gt;, etc.).&lt;/p&gt;
&lt;p&gt;But above all, the thing I enjoy the most is the networking—being able to talk with professionals that suffer the same problems that I do is something I normally cannot do, and that I enjoy doing a lot during Percona Live. [caption id=“attachment_390” align=“alignright” width=“808”]&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2018/10/jaime_crespo_2018.jpeg" alt="Jaime Crespo" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Jaime Crespo in a Percona Live T-Shirt - why not come to this year’s event and start YOUR collection.&lt;/em&gt; [/caption]&lt;/p&gt;</content:encoded>
      <author>Jaime Crespo</author>
      <category>Events</category>
      <category>MariaDB</category>
      <category>MySQL</category>
      <category>Open Source Databases</category>
      <category>Percona Live Europe 2018</category>
      <media:thumbnail url="https://percona.community/blog/2018/10/MySQL-at-scale_hu_3c5128ac9f54aa12.jpg"/>
      <media:content url="https://percona.community/blog/2018/10/MySQL-at-scale_hu_ec646f6415dc7148.jpg" medium="image"/>
    </item>
    <item>
      <title>Deploying MySQL on Kubernetes with a Percona-based Operator</title>
      <link>https://percona.community/blog/2018/10/11/deploying-mysql-on-kubernetes-with-a-percona-based-operator/</link>
      <guid>https://percona.community/blog/2018/10/11/deploying-mysql-on-kubernetes-with-a-percona-based-operator/</guid>
      <pubDate>Thu, 11 Oct 2018 17:03:04 UTC</pubDate>
      <description>In the context of providing managed WordPress hosting services, at Presslabs we operate with lots of small to medium-sized databases, in a DB-per-service model, as we call it. The workloads are mostly reads, so we need to efficiently scale that. The MySQL® asynchronous replication model fits the bill very well, allowing us to scale horizontally from one server—with the obvious availability pitfalls—to tens of nodes. The next release of the stack is going to be open-sourced.</description>
      <content:encoded>&lt;p&gt;In the context of providing managed WordPress hosting services, at &lt;a href="https://www.presslabs.com/" target="_blank" rel="noopener noreferrer"&gt;Presslabs&lt;/a&gt; we operate with lots of small to medium-sized databases, in a DB-per-service model, as we call it. The workloads are mostly reads, so we need to efficiently scale that. The MySQL® asynchronous replication model fits the bill very well, allowing us to scale horizontally from one server—with the obvious availability pitfalls—to tens of nodes. The next release of the stack is going to be open-sourced.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2018/10/kubernetes-mysql-operator.png" alt="Kubernetes MySQL Operator" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;As we were already using &lt;a href="https://kubernetes.io/" target="_blank" rel="noopener noreferrer"&gt;Kubernetes&lt;/a&gt;, we were looking for an operator that could automate our DB deployments and auto-scaling. Those available were doing synchronous replication using MySQL group replication or Galera-based replication. Therefore, we decided to write our own operator.&lt;/p&gt;
&lt;h2 id="solution-architecture"&gt;Solution architecture&lt;/h2&gt;
&lt;p&gt;The &lt;a href="https://www.presslabs.com/code/mysqloperator/" target="_blank" rel="noopener noreferrer"&gt;MySQL operator&lt;/a&gt;, released under Apache 2.0 license, is based on Percona Server for MySQL for its operational improvements —like utility user and backup locks—and relies on the tried and tested &lt;a href="https://github.com/github/orchestrator" target="_blank" rel="noopener noreferrer"&gt;Orchestrator&lt;/a&gt; to do the automatic failovers. We’ve been using &lt;a href="https://www.percona.com/software/mysql-database/percona-server" target="_blank" rel="noopener noreferrer"&gt;Percona Server&lt;/a&gt; in production for about four years, with very good results, thus encouraging us to continue implementing it in the operator as well.&lt;/p&gt;
&lt;p&gt;The MySQL Operator-Orchestrator integration is highly important for topology, as well as for cluster healing and system failover. Orchestrator is a MySQL high availability and replication management tool that was coded and opened by &lt;a href="https://github.com/" target="_blank" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As we’re writing this, the operator is undergoing a full rewrite to implement the operator using the &lt;a href="https://github.com/kubernetes-sigs/kubebuilder" target="_blank" rel="noopener noreferrer"&gt;Kubebuilder&lt;/a&gt; framework, which is a pretty logical step to simplify and standardize the operator to make it more readable to contributors and users.&lt;/p&gt;
&lt;h2 id="aims-for-the-project"&gt;Aims for the project&lt;/h2&gt;
&lt;p&gt;We’ve built the MySQL operator with several considerations in mind, generated by the needs that no other operator could satisfy at the time we started working on it, last year.&lt;/p&gt;
&lt;p&gt;Here are some of them:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Easily deployable MySQL clusters in Kubernetes, following the cluster-per-service model&lt;/li&gt;
&lt;li&gt;DevOps-friendly, critical to basic operations such as monitoring, availability, scalability, and backup stories&lt;/li&gt;
&lt;li&gt;Out-of-the-box backups, scheduled or on-demand, and point-in-time recovery&lt;/li&gt;
&lt;li&gt;Support for cloning, both inside a cluster and across clusters&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It’s good to know that the MySQL operator is now in beta version, and can be tested in production workloads. However, you can take a spin and decide for yourself—we’re already successfully using it for a part of our production workloads at &lt;a href="https://www.presslabs.com/" target="_blank" rel="noopener noreferrer"&gt;Presslabs&lt;/a&gt;, for our customer dashboard services.&lt;/p&gt;
&lt;p&gt;Going further to some more practical info, we’ve successfully installed and tested the operator on AWS, Google Cloud Platform, and Microsoft Azure and covered the step by step process in three tutorials here.&lt;/p&gt;
&lt;h2 id="set-up-and-configuration"&gt;Set up and configuration&lt;/h2&gt;
&lt;p&gt;It’s fairly simple to use the operator. Prerequisites would be the ubiquitous &lt;a href="https://helm.sh/" target="_blank" rel="noopener noreferrer"&gt;Helm&lt;/a&gt; and &lt;a href="https://kubernetes.io/docs/reference/kubectl/overview/" target="_blank" rel="noopener noreferrer"&gt;Kubectl&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The first step is to install the controller. Two commands should be run, to make use of the Helm chart bundled in the operator:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ helm repo add presslabs https://presslabs.github.io/charts
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ helm install presslabs/mysql-operator --name mysql-operator&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;These commands will deploy the controller together with an Orchestrator cluster. The configuration parameters of the Helm chart for the operator and its default values are as follows:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Default value&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;replicaCount&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;replicas for controller&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;image&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;controller container image&lt;/td&gt;
&lt;td&gt;&lt;code&gt;quay.io/presslabs/mysql-operator:v0.1.5&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;imagePullPolicy&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;controller image pull policy&lt;/td&gt;
&lt;td&gt;&lt;code&gt;IfNotPresent&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;helperImage&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;mysql helper image&lt;/td&gt;
&lt;td&gt;&lt;code&gt;quay.io/presslabs/mysql-helper:v0.1.5&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;installCRDs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;whether or not to install CRDS&lt;/td&gt;
&lt;td&gt;&lt;code&gt;true&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;resources&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;controller pod resources&lt;/td&gt;
&lt;td&gt;{}&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nodeSelector&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;controller pod nodeSelector&lt;/td&gt;
&lt;td&gt;{}&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tolerations&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;controller pod tolerations&lt;/td&gt;
&lt;td&gt;{}&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;affinity&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;controller pod affinity&lt;/td&gt;
&lt;td&gt;{}&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;extraArgs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;args that are passed to controller&lt;/td&gt;
&lt;td&gt;[]&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;rbac.create&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;whether or not to create rbac service account, role and roleBinding&lt;/td&gt;
&lt;td&gt;&lt;code&gt;true&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;rbac.serviceAccountName&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;If rbac.create is false then this service account is used&lt;/td&gt;
&lt;td&gt;&lt;code&gt;default&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;orchestrator.replicas&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Control Orchestrator replicas&lt;/td&gt;
&lt;td&gt;&lt;code&gt;3&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;orchestrator.image&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Orchestrator container image&lt;/td&gt;
&lt;td&gt;&lt;code&gt;quay.io/presslabs/orchestrator:latest&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Further Orchestrator values can be tuned by checking the &lt;a href="https://github.com/presslabs/docker-orchestrator/blob/master/charts/orchestrator/values.yaml" target="_blank" rel="noopener noreferrer"&gt;values.yaml&lt;/a&gt; config file.&lt;/p&gt;
&lt;h3 id="cluster-deployment"&gt;Cluster deployment&lt;/h3&gt;
&lt;p&gt;The next step is to deploy a cluster. For this, you need to create a Kubernetes secret that contains MySQL credentials (root password, database name, user name, user password), to initialize the cluster and a custom resource MySQL cluster as you can see below:&lt;/p&gt;
&lt;p&gt;An example of a secret (&lt;a href="https://github.com/presslabs/mysql-operator/blob/master/examples/example-cluster-secret.yaml" target="_blank" rel="noopener noreferrer"&gt;example-cluster-secret.yaml&lt;/a&gt;):&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-1"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;apiVersion: v1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kind: Secret
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;metadata:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; name: my-secret
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;type: Opaque
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;data:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ROOT_PASSWORD: # root password, base_64 encoded&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;An example of simple cluster (&lt;a href="https://github.com/presslabs/mysql-operator/blob/master/examples/example-cluster.yaml" target="_blank" rel="noopener noreferrer"&gt;example-cluster.yaml&lt;/a&gt;):&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-2" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-2"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;apiVersion: mysql.presslabs.org/v1alpha1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kind: MysqlCluster
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;metadata:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; name: my-cluster
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;spec:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; replicas: 2
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; secretName: my-secret&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The usual kubectl commands can be used to do various operations, such as a basic listing:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-3" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-3"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ kubectl get mysql&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;or detailed cluster information:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-4" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-4"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ kubectl describe mysql my-cluster&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="backups"&gt;Backups&lt;/h3&gt;
&lt;p&gt;A further step could be setting up the backups on an object storage service. To create a backup is as simple as creating a MySQL Backup resource that can be seen in this example (&lt;a href="https://github.com/presslabs/mysql-operator/blob/master/examples/example-backup.yaml" target="_blank" rel="noopener noreferrer"&gt;example-backup.yaml&lt;/a&gt;):&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-5" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-5"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;apiVersion: mysql.presslabs.org/v1alpha1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kind: MysqlBackup
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;metadata:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; name: my-cluster-backup
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;spec:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; clusterName: my-cluster
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; backupUri: gs://bucket_name/path/to/backup.xtrabackup.gz
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; backupSecretName: my-cluster-backup-secret&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;To provide credentials for a storage service, you have to create a secret and specify your credentials to your provider; we currently support AWS, GCS or HTTP as in this example (&lt;a href="https://github.com/presslabs/mysql-operator/blob/master/examples/example-backup-secret.yaml" target="_blank" rel="noopener noreferrer"&gt;example-backup-secret.yaml&lt;/a&gt;):&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-6" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-6"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;apiVersion: v1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kind: Secret
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;metadata:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; name: my-cluster-backup-secret
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;type: Opaque
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Data:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; # AWS
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; AWS_ACCESS_KEY_ID: #add here your key, base_64 encoded
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; AWS_SECRET_KEY: #and your secret, base_64 encoded
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; # or Google Cloud base_64 encoded
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; # GCS_SERVICE_ACCOUNT_JSON_KEY: #your key, base_64 encoded
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; # GCS_PROJECT_ID: #your ID, base_64 encoded&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Also, recurrent cluster backups and cluster initialization from a backup are some additional operations you can opt for. For more details head for our &lt;a href="https://www.presslabs.com/code/mysqloperator/mysql-operator-backups/" target="_blank" rel="noopener noreferrer"&gt;documentation page&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Further operations and new usage information are kept up-to-date on the project homepage.&lt;/p&gt;
&lt;p&gt;Our future plans include developing the MySQL operator and integrating it with &lt;a href="https://www.percona.com/software/database-tools/percona-monitoring-and-management" target="_blank" rel="noopener noreferrer"&gt;Percona Management &amp; Monitoring&lt;/a&gt; for better exposing the internals of the Kubernetes DB cluster.&lt;/p&gt;
&lt;h2 id="open-source-community"&gt;Open source community&lt;/h2&gt;
&lt;p&gt;Community contributions are highly appreciated; we should mention the pull requests from &lt;a href="https://platform9.com" target="_blank" rel="noopener noreferrer"&gt;Platform9&lt;/a&gt;, so far, but also the sharp questions on the channel we’ve opened on &lt;a href="https://gitter.im/PressLabs/mysql-operator" target="_blank" rel="noopener noreferrer"&gt;Gitter&lt;/a&gt;, for which we do the best to answer in detail, as well as issue reports from early users of the operator.&lt;/p&gt;
&lt;h3 id="come-and-talk-to-us-about-the-project"&gt;Come and talk to us about the project&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://www.percona.com/live/e18/registration-information" target="_blank" rel="noopener noreferrer"&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2018/10/ple18_logo.png" alt="ple18_logo" /&gt;&lt;/figure&gt;&lt;/a&gt;Along with my colleague Calin Don, I’ll be talking about this at &lt;a href="https://www.percona.com/live/e18/sessions/automating-mysql-deployments-on-kubernetes" target="_blank" rel="noopener noreferrer"&gt;Percona Live Europe&lt;/a&gt; in November. It would be great to have the chance to meet other enthusiasts and talk about what we’ve discovered so far!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The content in this blog is provided in good faith by members of the open source community. The content is not edited or tested by Percona, and views expressed are the authors’ own. When using the advice from this or any other online resource &lt;strong&gt;test&lt;/strong&gt; ideas before applying them to your production systems, and **always **secure a working back up.&lt;/em&gt;&lt;/p&gt;</content:encoded>
      <author>Flavius Mecea</author>
      <category>Advanced Level</category>
      <category>auto-scaling</category>
      <category>automated deployments</category>
      <category>Containers</category>
      <category>Deployment</category>
      <category>DevOps</category>
      <category>GitHub</category>
      <category>Kubernetes</category>
      <category>MySQL</category>
      <category>Orchestrator</category>
      <category>Percona Server for MySQL</category>
      <category>Scalability</category>
      <media:thumbnail url="https://percona.community/blog/2018/10/kubernetes-mysql-operator_hu_4287e9c6027468e1.jpg"/>
      <media:content url="https://percona.community/blog/2018/10/kubernetes-mysql-operator_hu_7790fd442eb84810.jpg" medium="image"/>
    </item>
    <item>
      <title>Minimize MySQL Deadlocks with 3 Steps</title>
      <link>https://percona.community/blog/2018/09/24/minimize-mysql-deadlocks-3-steps/</link>
      <guid>https://percona.community/blog/2018/09/24/minimize-mysql-deadlocks-3-steps/</guid>
      <pubDate>Mon, 24 Sep 2018 10:49:35 UTC</pubDate>
      <description>MySQL has locking capabilities, for example table and row level locking, and such locks are needed to control data integrity in multi-user concurrency. Deadlocks—where two or more transactions are waiting for one another to give up locks before the transactions can proceed successfully—are an unwanted situation. It is a classic problem for all databases including MySQL/PostgreSQL/Oracle etc. By default, MySQL detects the deadlock condition and to break the deadlock it rolls back one of the transactions.</description>
      <content:encoded>&lt;p&gt;MySQL has locking capabilities, for example table and row level locking, and such locks are needed to control data integrity in multi-user concurrency. Deadlocks—where two or more transactions are waiting for one another to give up locks before the transactions can proceed successfully—are an unwanted situation. It is a classic problem for all databases including MySQL/PostgreSQL/Oracle etc. By default, MySQL detects the deadlock condition and to break the deadlock it rolls back one of the transactions.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2018/09/application-deadlock-in-MySQL-transactions.jpg" alt="application deadlock in MySQL transactions" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;For a deadlock example, see &lt;a href="https://dev.mysql.com/doc/refman/8.0/en/innodb-deadlock-example.html" target="_blank" rel="noopener noreferrer"&gt;InnoDB deadlocks&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="some-misconceptions"&gt;Some misconceptions&lt;/h2&gt;
&lt;p&gt;There are some misconceptions about deadlocks:&lt;/p&gt;
&lt;p&gt;a) &lt;strong&gt;Transaction isolation levels are responsible for deadlocks&lt;/strong&gt;. The possibility of deadlocks is not affected by isolation level. Isolation level changes the behavior of read operations, but deadlock occurs due to write operations. However, isolation level sets fewer locks, hence it can help you to avoid certain lock types (e.g. gap locking).&lt;/p&gt;
&lt;p&gt;b) &lt;strong&gt;Small transactions are not affected by deadlocks.&lt;/strong&gt; Small transactions are less prone to deadlocks but it can still happen if transactions do not use the same order of operations.&lt;/p&gt;
&lt;p&gt;c) &lt;strong&gt;Deadlocks are dangerous.&lt;/strong&gt; I still hear from some customers who are using MyISAM tables that their reason for not switching to InnoDB is the deadlock problem. Deadlocks aren’t dangerous if you retry the transaction that failed due to deadlock and follow the steps given below in this article.&lt;/p&gt;
&lt;p&gt;I hope that this article will help clear such misconceptions.&lt;/p&gt;
&lt;p&gt;Back to the topic of this article. There are many possibilities that can cause deadlocks to occur and, for simplicity, I have grouped my recommendations into 3 steps.&lt;/p&gt;
&lt;h2 id="1-use-a-lock-avoiding-design-strategy"&gt;1. Use a lock-avoiding design strategy&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Break big transactions into smaller transactions: keeping transactions short make them less prone to collision.&lt;/li&gt;
&lt;li&gt;If you use INSERT INTO … SELECT to copy some or all rows from one table to another, consider using a lesser locking transaction isolation level (e.g. READ_COMMITTED) and set the binary log format to row/mixed for that transaction. Alternatively, design your application to put a single INSERT statement in a loop and copy row(s) into the table.&lt;/li&gt;
&lt;li&gt;If your application performs locking reads, for example SELECT … FOR UPDATE or SELECT .. FOR SHARE consider using the NOWAIT and SKIPPED LOCK options available in MySQL 8.0, see &lt;a href="https://dev.mysql.com/doc/refman/8.0/en/innodb-locking-reads.html#innodb-locking-reads-nowait-skip-locked" target="_blank" rel="noopener noreferrer"&gt;Locking Read Concurrency with NOWAIT and SKIP LOCKED&lt;/a&gt;. Alternatively, you may consider using a lesser locking transaction isolation level (described earlier)&lt;/li&gt;
&lt;li&gt;Multiple transactions updating data set in one or more tables, should use the same order of operation for their transactions. Avoid locking table A, B, C in one transaction and C,A,B in another.&lt;/li&gt;
&lt;li&gt;If you have the application retry when a transaction fails due to deadlock, you should ideally have the application take a brief pause before resubmitting its query/transaction. This gives the other transaction involved in the deadlock a chance to complete and release the locks that formed part of the deadlock cycle.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="2-optimize-queries"&gt;2. Optimize queries&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Well optimized queries examine fewer rows and as result set fewer locks.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="3-disable-deadlock-detection-for-systems-running-mysql-8"&gt;3. Disable deadlock detection (for systems running MySQL 8+)&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;If you’re running a high concurrency system, it maybe more efficient to disable deadlock detection and rely on the &lt;a href="https://dev.mysql.com/doc/refman/5.5/en/innodb-parameters.html#sysvar_innodb_lock_wait_timeout" target="_blank" rel="noopener noreferrer"&gt;innodb_lock_wait_timeout&lt;/a&gt; setting. However, keep this setting low. The default timeout setting is 50 seconds which is too long if you’re running without deadlock detection. Be careful when disabling deadlock detection as it may do more harm than good.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;The content in this blog is provided in good faith by members of the open source community. The content is not edited or tested by Percona, and views expressed are the authors’ own. When using the advice from this or any other online resource &lt;strong&gt;test&lt;/strong&gt; ideas before applying them to your production systems, and **always **secure a working back up.&lt;/em&gt;&lt;/p&gt;</content:encoded>
      <author>Aftab Khan</author>
      <category>Dev</category>
      <category>Deadlock</category>
      <category>Entry Level</category>
      <category>MySQL</category>
      <media:thumbnail url="https://percona.community/blog/2018/09/application-deadlock-in-MySQL-transactions_hu_ed9ef2c46ac511fb.jpg"/>
      <media:content url="https://percona.community/blog/2018/09/application-deadlock-in-MySQL-transactions_hu_bcc897efd2d2043a.jpg" medium="image"/>
    </item>
    <item>
      <title>Question about Semi-Synchronous Replication: the Answer with All the Details</title>
      <link>https://percona.community/blog/2018/08/23/question-about-semi-synchronous-replication-answer-with-all-the-details/</link>
      <guid>https://percona.community/blog/2018/08/23/question-about-semi-synchronous-replication-answer-with-all-the-details/</guid>
      <pubDate>Thu, 23 Aug 2018 12:49:59 UTC</pubDate>
      <description>I was recently asked a question by mail about MySQL Lossless Semi-Synchronous Replication. As I think the answer could benefit many people, I am answering it in a blog post. The answer brings us to the internals of transaction committing, of semi-synchronous replication, of MySQL (server) crash recovery, and of storage engine (InnoDB) crash recovery. I am also debunking some misconceptions that I have often seen and heard repeated by many. Let’s start by stating one of those misconceptions.</description>
      <content:encoded>&lt;p&gt;I was recently asked a question by mail about &lt;a href="https://dev.mysql.com/doc/refman/5.7/en/replication-semisync.html" target="_blank" rel="noopener noreferrer"&gt;MySQL Lossless Semi-Synchronous Replication&lt;/a&gt;. As I think the answer could benefit many people, I am answering it in a blog post. The answer brings us to the internals of transaction committing, of semi-synchronous replication, of MySQL (server) crash recovery, and of storage engine (InnoDB) crash recovery. I am also debunking some misconceptions that I have often seen and heard repeated by many. Let’s start by stating one of those misconceptions.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2018/08/semi-sync-replication-MySQL.jpg" alt="semi-sync replication MySQL" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;One of those misconceptions is the following (this is NOT true): semi-synchronous enabled slaves are always the most up-to-date slaves (again, this is &lt;strong&gt;NOT&lt;/strong&gt; true). If you hear it yourself, then please call people out on it to avoid this spreading more. Even if some slaves have semi-synchronous replication disabled (I will use semi-sync for short in the rest of this post), these could still be the most up-to-date slaves after a master crash. I guess this false idea is coming from the name of the feature, not much can be done about this anymore (naming is hard). The details are in the rest of this post.&lt;/p&gt;
&lt;p&gt;Back to the question I received by mail, it can be summarized as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In a deployment where a MySQL 5.7 master is crashed (kill -9 or echo c &gt; /proc/sysrq-trigger ), a slave is promoted as the new master;&lt;/li&gt;
&lt;li&gt;when the old master is brought back up, transactions that are not on the new master are observed on this old master;&lt;/li&gt;
&lt;li&gt;is this normal in a lossless semi-sync environment?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The answer to that question is yes: it is normal to have transactions on the recovered old master that are not on the new master. This is not a violation of the semi-sync promise. To understand this, we need to go in detail about semi-sync (MySQL 5.5 and 5.6) and lossless semi-sync (MySQL 5.7).&lt;/p&gt;
&lt;h2 id="semi-sync-and-lossless-semi-sync"&gt;Semi-Sync and Lossless Semi-Sync&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://dev.mysql.com/doc/refman/5.5/en/replication-semisync.html" target="_blank" rel="noopener noreferrer"&gt;Semi-sync replication&lt;/a&gt; was introduced in MySQL 5.5. Its promise is that every transaction where the client has received a COMMIT acknowledgment would be replicated to a slave. It had a caveat though: while a client is waiting for this COMMIT acknowledgment, other clients could see the data of the committing transaction. If the master crashes at this moment (without a slave having received the transaction), it is a violation of transaction isolation. This is also known as phantom read: data observed by a client has disappeared. This is not very satisfactory.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://dev.mysql.com/doc/refman/5.7/en/replication-semisync.html" target="_blank" rel="noopener noreferrer"&gt;Lossless semi-sync replication&lt;/a&gt; was introduced in MySQL 5.7 to solve this problem. With lossless semi-sync, we keep the promise of semi-sync (every transaction where clients have received a COMMIT acknowledgment is replicated), with the additional promise that there is no phantom reads. To understand how this works, we need to dive into the way MySQL commits transactions.&lt;/p&gt;
&lt;h2 id="the-way-mysql-commits-transactions"&gt;The Way MySQL Commits Transactions&lt;/h2&gt;
&lt;p&gt;When MySQL commits a transaction, it is going through the following steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;em&gt;Prepare&lt;/em&gt; the transaction in the storage engine (InnoDB),&lt;/li&gt;
&lt;li&gt;Write the transaction to the binary logs,&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Complete&lt;/em&gt; the transaction in the storage engine,&lt;/li&gt;
&lt;li&gt;Return an acknowledgment to the client.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The implementation of semi-sync or lossless semi-sync inserts themselves into the above process.&lt;/p&gt;
&lt;p&gt;Semi-sync in MySQL 5.5 and 5.6 happens between step #3 and #4. After “completing” the transaction in the storage engine, a semi-sync master waits for one slave to confirm the replication of the transaction. As this happens after the storage engine has “completed” the transaction, other clients can see this transaction. &lt;strong&gt;This is the cause of phantom reads.&lt;/strong&gt; Also — unrelated to phantom reads — if the master crashes at that moment and after bringing it back up, this transaction will be in the database as it has been fully “completed” in the storage engine.&lt;/p&gt;
&lt;p&gt;It is important to realize that for semi-sync (and lossless-semi-sync), transactions are written to the binary logs in the same way as in standard (non-semi-sync) replication. In other words, standard and semi-sync replication behave exactly the same way up to and including step #2. Also, once transactions are in the binary logs, they are visible to all slaves, not only to the semi-sync slaves. So a non-semi-sync slave could receive a transaction before the semi-sync slaves. This is why it is false to assume that the semi-sync slaves are the most up-to-date slaves after a master crash.&lt;/p&gt;
&lt;h4 id="it-is-false-to-assume-that-the-semi-sync-slaves-are-the-most-up-to-date-slaves-after-a-master-crash"&gt;It is false to assume that the semi-sync slaves are the most up-to-date slaves after a master crash.&lt;/h4&gt;
&lt;p&gt;In lossless semi-sync, waiting for transaction replication happens between steps #2 and #3. At this point, the transaction is not “completed” in the storage engine, so other clients do not see its data yet. But even if this transaction is not “completed”, a master crash at that moment and a subsequent restart would cause this transaction to be in the database. To understand why, we need to dive into MySQL and InnoDB crash recovery.&lt;/p&gt;
&lt;h2 id="mysql-and-innodb-crash-recovery"&gt;MySQL and InnoDB Crash Recovery&lt;/h2&gt;
&lt;p&gt;During InnoDB crash recovery, transactions that are not “completed” (have not reached step #3 of transaction committing) are rolled back. So a transaction that is not yet committed (has not reached step #1) or a transaction that is not yet written to the binary logs (has not reached step #2) will not be in the database after InnoDB crash recovery. However, if InnoDB rolled back a transaction that has reached the binary logs (step #2) but that is not “completed” (step #3), this would mean a transaction that could have reached a slave would disappear from the master. This would create data inconsistency in replication and would be bad.&lt;/p&gt;
&lt;h4 id="once-a-transaction-reaches-the-binary-logs-it-should-roll-forward"&gt;Once a transaction reaches the binary logs it should roll forward.&lt;/h4&gt;
&lt;p&gt;To avoid the data inconsistency described above, MySQL does its own crash recovery before storage engine crash recovery. This recovery consists of making sure that all the transactions in the binary logs are flagged as “completed”. So if a transaction is between step #2 and #3 at the time of the crash, it is flagged as “completed” in the storage engine during MySQL crash recovery and it is rolled forward during storage engine crash recovery. In the case where this transaction has not reached at least a slave at the moment of the crash, it will appear in the master after crash recovery. It is important to note that this could happen even without semi-sync.&lt;/p&gt;
&lt;h4 id="having-extra-transactions-on-a-recovered-master-can-happen-even-without-semi-sync"&gt;Having extra transactions on a recovered master can happen even without semi-sync.&lt;/h4&gt;
&lt;p&gt;The extra transactions that are visible on the recovered old master are because of the way MySQL and InnoDB carry out crash recovery. This is more likely to happen in a lossless semi-sync environment because of the delay introduced between steps #2 and #3 of the way MySQL commits transactions, but it could also happen without semi-sync if the timing is right.&lt;/p&gt;
&lt;h2 id="the-facebook-trick-to-avoid-extra-transactions"&gt;The Facebook Trick to Avoid Extra Transactions&lt;/h2&gt;
&lt;p&gt;There is an original trick to avoid having extra transactions on a recovered master. This trick was presented by Facebook during a talk at &lt;a href="https://www.percona.com/live/" target="_blank" rel="noopener noreferrer"&gt;Percona Live&lt;/a&gt; a few years ago (sorry, I cannot find any link to this, please post a comment below if you know of public content about this). The idea is to force MySQL to roll-back (instead of rolling forward) the transactions that are not yet “completed” in the storage engine. It must be noted that this should only be done on an old master that has been replaced by a slave. If it is done on a recovering master without failing over to a slave, a transaction that could have reached a slave would disappear from the master.&lt;/p&gt;
&lt;p&gt;To trick MySQL into rolling back the non “completed” transactions, Facebook truncates the binary logs before restarting the old master. This way, MySQL thinks that the crash happened before writing to the binary logs (step #2). So MySQL crash recovery will not flag the transactions as “complete” in the storage engine and these will be rolled back during storage engine crash recovery. This avoids the recovered old master having extra transactions. Obviously, because these transactions were once in the binary logs, they could have been replicated to slaves. So the Facebook trick avoids the old master being ahead of the new master, possibly at the cost of bringing the old master behind the new master.&lt;/p&gt;
&lt;p&gt;I know that Facebook then re-slaves the recovered old master to the new master, but I am not sure that this is possible with standard MySQL. The Facebook variant of MySQL includes additional features, and I think one of those is to put GTIDs in the InnoDB Redo logs. With this, and after the recovery of the old master, the GTID state of the database can be determined even if the binary logs are gone. In standard MySQL, I think that truncating the binary logs will result in losing the GTID state of the database, which will prevent re-slaving the old master to the new master. However, as InnoDB crash recovery prints the binary log position or the last committed transaction, I think re-slaving the old master to a &lt;a href="https://medium.com/booking-com-infrastructure/abstracting-binlog-servers-and-mysql-master-promotion-without-reconfiguring-all-slaves-44be1febc8a0" target="_blank" rel="noopener noreferrer"&gt;Binlog Server&lt;/a&gt; would be possible in a semi-sync environment.&lt;/p&gt;
&lt;p&gt;You can read more about semi-synchronous replication at Facebook below:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://yoshinorimatsunobu.blogspot.com/2014/04/semi-synchronous-replication-at-facebook.html" target="_blank" rel="noopener noreferrer"&gt;Semi-Synchronous Replication at Facebook&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.percona.com/live/data-performance-conference-2016/sessions/highs-and-lows-semi-synchronous-replication" target="_blank" rel="noopener noreferrer"&gt;The highs and lows of semi-synchronous replication&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="debunking-other-misconceptions"&gt;Debunking Other Misconceptions&lt;/h2&gt;
&lt;p&gt;Before closing this post, I would like to debunk other misconceptions that I often hear. Some people say that semi-sync (or lossless semi-sync) increases the availability of MySQL. In my humble opinion, &lt;strong&gt;this is false.&lt;/strong&gt; Semi-sync and lossless semi-sync actually lower availability, there is no increase here.&lt;/p&gt;
&lt;h4 id="lossless-semi-sync-is-not-a-high-availability-solution"&gt;Lossless semi-sync is not a high availability solution.&lt;/h4&gt;
&lt;p&gt;The statement that semi-sync and lossless semi-sync have lower availability than standard replication is justified by the introduction of new situations where transactions could be prevented from committing. As an example, if no semi-sync slaves are present, transactions will not be able to commit. The promise of lossless semi-sync is not about increasing availability, it is about preventing the loss of committed transactions in case of a crash. The cost of this promise is the added COMMIT latency and the new cases where COMMIT would be prevented from succeeding (thus reducing availability).&lt;/p&gt;
&lt;h4 id="group-replication-is-not-a-high-availability-solution"&gt;Group Replication is not a high availability solution.&lt;/h4&gt;
&lt;p&gt;For the same reasons, Group Replication (or Galera or Percona XtraDB Cluster) reduces availability. Group replication also brings the promise of preventing the loss of committed transactions at the cost of adding COMMIT latency. There is also another cost of Group Replication: failing COMMIT in some situations (I do not know of any situation in standard MySQL where COMMIT can fail, if you know of one, please post a comment below). An example of COMMIT failing is mentioned in my previous post on &lt;a href="http://jfg-mysql.blogspot.com/2018/01/more-write-set-in-mysql-5-7-group-replication-certification.html" target="_blank" rel="noopener noreferrer"&gt;Group Replication certification&lt;/a&gt;. This additional cost introduces another interesting promise, but as this is not a post on Group Replication, so I am not covering this here.&lt;/p&gt;
&lt;h4 id="group-replication-also-introduces-cases-where-commit-can-fail"&gt;Group Replication also introduces cases where COMMIT can fail.&lt;/h4&gt;
&lt;p&gt;This does not mean that lossless semi-sync and Group Replication cannot be used as a building block for a high availability solution, but by themselves and without other important components, they are not a high availability solution.&lt;/p&gt;
&lt;h2 id="thoughts-about-rpl_semi_sync_master_timeoutwait_no_slave"&gt;Thoughts about rpl_semi_sync_master_{timeout,wait_no_slave}&lt;/h2&gt;
&lt;p&gt;Above, I write that there are situations where a transaction will be prevented from committing. One of those situations is when there are no semi-sync slaves or when those slaves are not acknowledging transactions (for any good or bad reasons). There are two parameters to bypass this: &lt;a href="https://dev.mysql.com/doc/refman/5.7/en/replication-options-master.html#sysvar_rpl_semi_sync_master_wait_no_slave" target="_blank" rel="noopener noreferrer"&gt;rpl_semi_sync_master_wait_no_slave&lt;/a&gt; and &lt;a href="https://dev.mysql.com/doc/refman/5.7/en/replication-options-master.html#sysvar_rpl_semi_sync_master_timeout" target="_blank" rel="noopener noreferrer"&gt;rpl_semi_sync_master_timeout&lt;/a&gt;. Let’s talk about these a little.&lt;/p&gt;
&lt;p&gt;The rpl_semi_sync_master_wait_no_slave parameter allows MySQL to bypass the semi-sync wait when there are not enough semi-sync slaves (semi-sync in MySQL 5.7 can wait for more than one slave and this behavior is controlled by the &lt;a href="https://dev.mysql.com/doc/refman/5.7/en/replication-options-master.html#sysvar_rpl_semi_sync_master_wait_for_slave_count" target="_blank" rel="noopener noreferrer"&gt;rpl_semi_sync_master_wait_for_slave_count&lt;/a&gt; parameter). The default value for the “wait_no_slave” parameter is ON, which means it still waits even if there are not enough semi-sync slaves. This is a safe default as it enforces the promise of semi-sync (not acknowledging COMMIT before the transaction is replicated to slaves). Even if setting this parameter to OFF is voiding that promise, I like that it exists (details below). However, I would not run MySQL unattended with waiting disabled in a full semi-sync environment.&lt;/p&gt;
&lt;p&gt;The rpl_semi_sync_master_timeout parameter allows MySQL to short-circuit waiting for slaves after a timeout with acknowledging COMMIT to the client event is the transaction was not replicated. Its default is 10 seconds, which I think is wrong. After 10 seconds, there are probably thousands of transactions waiting for commit on the master and MySQL is already struggling. If we want to prevent MySQL from struggling, this parameter should be lower. However, if we want a zero-loss failover (and failover is taking more than 10 seconds), we should not commit transactions without replicating them to slaves, in which case this parameter should be higher. Higher or lower, which one should be used…&lt;/p&gt;
&lt;p&gt;Using a “low” value for rpl_semi_sync_master_timeout looks very strange to me in a full semi-sync environment. It looks like the DBA cannot choose between committing as often as possible (standard non-semi-sync replication) or only committing transactions that are replicated (semi-sync). There is no way to have the best of both worlds here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;either someone wants &lt;strong&gt;high success rate on commit&lt;/strong&gt;, which means that the DBA does not deploy semi-sync (and the cost of this is to lose committed transactions on failover),&lt;/li&gt;
&lt;li&gt;or someone wants &lt;strong&gt;high persistence on committed transactions&lt;/strong&gt;, in which case the DBA deploys semi-sync at the cost of lowering the probability of a successful commit (and increasing commit latency).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I see one situation where these parameters are useful: transitioning from a non-semi-sync environment to a full semi-sync environment. During this transition, we want to learn about the new restrictions of semi-sync without causing too much disruption in production, and these parameters come in handy here. But once in a full semi-sync deployment, where we fully want to avoid loosing committed transactions when a master crash, I would not consider it a good idea to let transactions commit without being replicated to slaves.&lt;/p&gt;
&lt;p&gt;As a last comment on this, there are thoughts that a full semi-sync enabled master should probably crash itself when it is blocked for too long in waiting for slave acknowledgment. This is an interesting idea as it is the only way that MySQL has to unblock clients. I am not sure if this is implemented in some variant of MySQL though (maybe the Facebook variant).&lt;/p&gt;
&lt;p&gt;I hope this post clarified semi-sync and lossless semi-sync replication. If you still have questions about this or on related subjects, feel free to post them in the comments below.&lt;/p&gt;</content:encoded>
      <author>Jean-François Gagné</author>
      <category>Galera</category>
      <category>InnoDB</category>
      <category>MariaDB</category>
      <category>MySQL</category>
      <category>Percona Server</category>
      <category>Percona XtraDB Cluster</category>
      <category>Replication</category>
      <media:thumbnail url="https://percona.community/blog/2018/08/semi-sync-replication-MySQL_hu_73ec11f75c462b8b.jpg"/>
      <media:content url="https://percona.community/blog/2018/08/semi-sync-replication-MySQL_hu_3e58863ae8ce0efe.jpg" medium="image"/>
    </item>
    <item>
      <title>Easy and Effective Way of Building External Dictionaries for ClickHouse with Pentaho Data Integration Tool</title>
      <link>https://percona.community/blog/2018/08/02/easy-effective-building-external-dictionaries-clickhouse-pentaho-data-integration-tool/</link>
      <guid>https://percona.community/blog/2018/08/02/easy-effective-building-external-dictionaries-clickhouse-pentaho-data-integration-tool/</guid>
      <pubDate>Thu, 02 Aug 2018 16:09:26 UTC</pubDate>
      <description>In this post, I provide an illustration of how to use Pentaho Data Integration (PDI) tool to set up external dictionaries in MySQL to support ClickHouse. Although I use MySQL in this example, you can use any PDI supported source.</description>
      <content:encoded>&lt;p&gt;In this post, I provide an illustration of how to use Pentaho Data Integration (PDI) tool to set up external dictionaries in MySQL to support ClickHouse. Although I use MySQL in this example, you can use any PDI supported source.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2018/08/pentaho-clickhouse.jpg" alt="pentaho pdt with clickhouse" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h2 id="clickhouse"&gt;ClickHouse&lt;/h2&gt;
&lt;p&gt;ClickHouse is an open-source column-oriented DBMS (columnar database management system) for online analytical processing. Source: &lt;a href="https://en.wikipedia.org/wiki/ClickHouse" target="_blank" rel="noopener noreferrer"&gt;wiki&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="pentaho-data-integration"&gt;Pentaho Data Integration&lt;/h2&gt;
&lt;p&gt;Information from the Pentaho &lt;a href="https://wiki.pentaho.com/display/EAI/Pentaho+Data+Integration+%28Kettle%29+Tutorial" target="_blank" rel="noopener noreferrer"&gt;wiki&lt;/a&gt;: Pentaho Data Integration (PDI, also called Kettle) is the component of Pentaho responsible for the Extract, Transform and Load (ETL) processes. Though ETL tools are most frequently used in data warehouses environments, PDI can also be used for other purposes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Migrating data between applications or databases&lt;/li&gt;
&lt;li&gt;Exporting data from databases to flat files&lt;/li&gt;
&lt;li&gt;Loading data massively into databases&lt;/li&gt;
&lt;li&gt;Data cleansing&lt;/li&gt;
&lt;li&gt;Integrating applications&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;PDI is easy to use. Every process is created with a graphical tool where you specify what to do without writing code to indicate how to do it; because of this, you could say that PDI is &lt;em&gt;metadata oriented&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id="external-dictionaries"&gt;External dictionaries&lt;/h2&gt;
&lt;p&gt;You can add your own dictionaries from various data sources. The data source for a dictionary can be a local text or executable file, an HTTP(s) resource, or another DBMS. For more information, see “&lt;a href="https://clickhouse.yandex/docs/en/dicts/external_dicts_dict_sources/#dicts-external_dicts_dict_sources" target="_blank" rel="noopener noreferrer"&gt;Sources for external dictionaries&lt;/a&gt;”. ClickHouse:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Fully or partially stores dictionaries in RAM.&lt;/li&gt;
&lt;li&gt;Periodically updates dictionaries and dynamically loads missing values. In other words, dictionaries can be loaded dynamically.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The configuration of external dictionaries is located in one or more files. The path to the configuration is specified in the &lt;a href="https://clickhouse.yandex/docs/en/operations/server_settings/settings/#server_settings-dictionaries_config" target="_blank" rel="noopener noreferrer"&gt;dictionaries_config&lt;/a&gt; parameter. Dictionaries can be loaded at server startup or at first use, depending on the &lt;a href="https://clickhouse.yandex/docs/en/operations/server_settings/settings/#server_settings-dictionaries_lazy_load" target="_blank" rel="noopener noreferrer"&gt;dictionaries_lazy_load&lt;/a&gt; setting. Source: &lt;a href="https://clickhouse.yandex/docs/en/query_language/dicts/" target="_blank" rel="noopener noreferrer"&gt;dictionaries&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="example-of-external-dictionary"&gt;Example of external dictionary&lt;/h3&gt;
&lt;p&gt;In two words, dictionary is a key(s)-value(s) mapping that could be used for storing some value(s) which will be retrieved using a key. It is a way to build a “star” schema, where &lt;em&gt;dictionaries are dimensions&lt;/em&gt;:
&lt;figure&gt;&lt;img src="https://percona.community/blog/2018/08/example-external-dictionary.jpg" alt="example external dictionary" /&gt;&lt;/figure&gt; Using dictionaries you can lookup data by key(customer_id in this example). Why do not use tables for simple JOIN? Here is what documentation says:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you need a JOIN for joining with dimension tables (these are relatively small tables that contain dimension properties, such as names for advertising campaigns), a JOIN might not be very convenient due to the bulky syntax and the fact that the right table is re-accessed for every query. For such cases, there is an “external dictionaries” feature that you should use instead of JOIN. For more information, see the section “External dictionaries”.&lt;/p&gt;&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;h5 id="main-point-of-this-blog-post"&gt;Main point of this blog post:&lt;/h5&gt;
&lt;blockquote&gt;
&lt;p&gt;Demonstrating filling a MySQL table using PDI tool and connecting this table to ClickHouse as an external dictionary. You can create a scheduled job for loading or updating this table.&lt;/p&gt;&lt;/blockquote&gt;&lt;/blockquote&gt;
&lt;p&gt;Filling dictionaries during the ETL process is a challenge. Of course you can write a script (or scripts) that will do all of this, but I’ve found a better way. Benefits:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Self-documented: you see what exactly PDI job does;&lt;/li&gt;
&lt;li&gt;Easy to modify(see example below)&lt;/li&gt;
&lt;li&gt;Built-in logging&lt;/li&gt;
&lt;li&gt;Very flexible&lt;/li&gt;
&lt;li&gt;If you use the &lt;a href="https://wiki.pentaho.com/display/COM/Community+Edition+Downloads" target="_blank" rel="noopener noreferrer"&gt;Community Edition&lt;/a&gt; you will not pay anything.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="pentaho-data-integration-part"&gt;Pentaho Data Integration part&lt;/h2&gt;
&lt;p&gt;You need a UI for running/developing ETL, but it’s not necessary to use the UI for running a transformation or job. Here’s an example of running it from a Linux shell(read PDI’s docs about jobs/transformation):&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;${PDI_FOLDER}/kitchen.sh -file=${PATH_TO_PDI_JOB_FILE}.kjb [-param:SOMEPARAM=SOMEVALUE]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;${PDI_FOLDER}/pan.sh -file=${PATH_TO_PDI_TRANSFORMATION_FILE}.ktr [-param:SOMEPARAM=SOMEVALUE]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Here is a PDI transformation. In this example I use three tables as a source of information, but you can create very complex logic:
&lt;figure&gt;
&lt;img sizes="100vw" srcset="https://percona.community/blog/2018/08/pdi-transformation_hu_e8066f1ac7a9a3fe.png 480w, https://percona.community/blog/2018/08/pdi-transformation_hu_fdb1807e374723c6.png 768w, https://percona.community/blog/2018/08/pdi-transformation_hu_4ce0782f6b6e0830.png 1400w"
src="https://percona.community/blog/2018/08/pdi-transformation.png" alt="PDI transformation" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h3 id="datasource1-definition-example"&gt;“Datasource1” definition example&lt;/h3&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2018/08/datasource-definition-example.png" alt="datasource definition example" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Dimension lookup/update is a step that updates the MySQL table (in this example, it could be any database supported by PDI output step). It will be the source for ClickHouse’s external dictionary:&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2018/08/dimension-lookup-update-id-1.png" alt="dimension lookup update id " /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Fields definition:&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2018/08/dimension-lookup-update-fields-2.png" alt="dimension fields definition" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Once you have done this, you hit the “SQL” button and it will generate the DDL code for D_CUSTOMER table. You can manage the algorithm of storing data in the step above: update or insert new record(with time_start/time_end fields). Also, if you use PDI for ETL, then you can generate a “technical key” for your dimension and store this key in ClickHouse, this is a different story… For this example, I will use “id” as a key in the ClickHouse dictionary.&lt;/p&gt;
&lt;p&gt;The last step is setting up external dictionary in ClickHouse’s server config.&lt;/p&gt;
&lt;h3 id="the-clickhouse-part"&gt;The ClickHouse part&lt;/h3&gt;
&lt;p&gt;External dictionary config, in this example you’ll see that I use MySQL:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-1"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;dictionaries&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;dictionary&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;name&gt;customers&lt;/name&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;source&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;!-- Source configuration --&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;mysql&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;port&gt;3306&lt;/port&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;user&gt;MySQL_User&lt;/user&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;password&gt;MySQL_Pass&lt;/password&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;replica&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;host&gt;MySQL_host&lt;/host&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;priority&gt;1&lt;/priority&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;/replica&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;db&gt;DB_NAME&lt;/db&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;table&gt;D_CUSTOMER&lt;/table&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;/mysql&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;/source&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;layout&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;!-- Memory layout configuration --&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;flat/&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;/layout&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;structure&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;id&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;name&gt;id&lt;/name&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;/id&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;attribute&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;name&gt;name&lt;/name&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;type&gt;String&lt;/type&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;null_value&gt;&lt;/null_value&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;/attribute&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;attribute&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;name&gt;address&lt;/name&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;type&gt;String&lt;/type&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;null_value&gt;&lt;/null_value&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;/attribute&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;!-- Will be uncommented later
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;attribute&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;name&gt;phone&lt;/name&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;type&gt;String&lt;/type&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;null_value&gt;&lt;/null_value&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;/attribute&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;/structure&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;lifetime&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;min&gt;3600&lt;/min&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;max&gt;86400&lt;/max&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;/lifetime&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;/dictionary&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;/dictionaries&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Creating the fact table in ClickHouse:&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2018/08/table-in-ClickHouse.png" alt="Create table in ClickHouse" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Some sample data:&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2018/08/sample-data.png" alt="Sample data" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Now we can fetch data aggregated against the customer name:&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2018/08/aggregated-data-with-customer-name.png" alt="aggregated data with customer name" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h3 id="dictionary-modification"&gt;Dictionary modification&lt;/h3&gt;
&lt;p&gt;Sometimes, it happens that you need to modify your dimensions. In my example I am going to add phone number to the “customers” dictionary. Not a problem at all. You update your datasource in PDI job:&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2018/08/dictionary-modification.png" alt="dictionary modification add new field " /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Open the “Dimension lookup/update” step and add the &lt;em&gt;phone&lt;/em&gt; field:&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2018/08/add-a-field.png" alt="Add a field " /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;And hit the SQL button.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2018/08/alter-data-statement.png" alt="alter table statement" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Also add the “phone” field in ClickHouse’s dictionary config:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-2" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-2"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;   &lt;attribute&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;       &lt;name&gt;phone&lt;/name&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;               &lt;type&gt;String&lt;/type&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;               &lt;null_value&gt;&lt;/null_value&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;   &lt;/attribute&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;ClickHouse will update a dictionary on the fly and we are ready to go—if not please check the logs. Now you can run the query without a modification of fact_table:
&lt;figure&gt;&lt;img src="https://percona.community/blog/2018/08/query-without-modifying-fact.png" alt="query without modifying fact" /&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Also, note that PDI job is an XML file that could be put under version source control tools, so it is easy to track or rollback if needed. Please do not hesitate to ask if you have questions!&lt;/p&gt;</content:encoded>
      <author>Timur Solodovnikov</author>
      <category>ClickHouse</category>
      <category>Data Warehouse</category>
      <category>MySQL</category>
      <category>Open Source Databases</category>
      <category>Tools</category>
      <media:thumbnail url="https://percona.community/blog/2018/08/pentaho-clickhouse_hu_7cfbcd393858d937.jpg"/>
      <media:content url="https://percona.community/blog/2018/08/pentaho-clickhouse_hu_8b2d3d847705586b.jpg" medium="image"/>
    </item>
    <item>
      <title>How to Automate Minor Version Upgrades for MySQL on RDS</title>
      <link>https://percona.community/blog/2018/07/10/automate-minor-version-upgrades-mysql-rds/</link>
      <guid>https://percona.community/blog/2018/07/10/automate-minor-version-upgrades-mysql-rds/</guid>
      <pubDate>Tue, 10 Jul 2018 12:19:11 UTC</pubDate>
      <description>Amazon RDS for MySQL offers the option to automate minor version upgrades using the minor version upgrade policy, a property that lets you decide if Amazon is allowed to perform the upgrades on your behalf. Usually the goal is not to upgrade automatically every RDS instance but to keep up to date automatically non-production deployments. This helps you address engine issues as soon as possible and improve the automation of the deployment process.</description>
      <content:encoded>&lt;p&gt;Amazon RDS for MySQL offers the option to automate &lt;a href="https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_UpgradeDBInstance.MySQL.html#USER_UpgradeDBInstance.MySQL.Minor" target="_blank" rel="noopener noreferrer"&gt;minor version upgrades&lt;/a&gt; using the &lt;em&gt;minor version upgrade policy&lt;/em&gt;, a property that lets you decide if Amazon is allowed to perform the upgrades on your behalf. Usually the goal is not to upgrade automatically every RDS instance but to keep up to date automatically non-production deployments. This helps you address engine issues as soon as possible and improve the automation of the deployment process.&lt;/p&gt;
&lt;p&gt;If your are using the AWS Command Line Interface (CLI) and you have an instance called &lt;em&gt;test-rds01&lt;/em&gt; it is as simple as changing&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[--auto-minor-version-upgrade | --no-auto-minor-version-upgrade]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-1"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws rds modify-db-instance --db-instance-identifier test-rds01 --apply-immediately
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;--auto-minor-version-upgrade true&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;And if you use the AWS Management Console, it is just a check box. All sorted? Unfortunately not. The main problem is that Amazon performs those upgrade only in rare circumstances.&lt;/p&gt;
&lt;p&gt;As for Amazon’s &lt;a href="https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_UpgradeDBInstance.MySQL.html#USER_UpgradeDBInstance.MySQL.Minor" target="_blank" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Minor version upgrades only occur automatically if a minor upgrade replaces an unsafe version, such as a minor upgrade that contains bug fixes for a previous version. In all other cases, you must modify the DB instance manually to perform a minor version upgrade.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;If the new version fixes any vulnerabilities that were present in the previous version, then the auto minor version upgrade will automatically take place during the next weekly maintenance window on your DB instance. In all other cases, you should manually perform the minor version upgrade. So in most scenarios, the automatic upgrade is unlikely to happen and using the auto-minor-version-upgrade  attribute is not the way to keep your MySQL running on RDS updated to the latest available minor version.&lt;/p&gt;
&lt;h4 id="how-to-improve-automation-of-minor-version-upgrades-amazon-rds-for-mysql"&gt;How to improve automation of minor version upgrades Amazon RDS for MySQL&lt;/h4&gt;
&lt;p&gt;Let’s say you want to reduce the time a newer minor version reaches your development environments or even your production ones. How can you achieve that on RDS? First of all you have to consider the delay it takes for a minor version to reach RDS that can be anything between a few weeks and a few months.  And you might even not notice that a new minor is available as it is not obvious how to be notified when it is.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What is the best way to be notified of new minor versions available on RDS MySQL?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In the past you could (even automatically) monitor the &lt;a href="https://aws.amazon.com/releasenotes/?tag=releasenotes%23keywords%23amazon-rds" target="_blank" rel="noopener noreferrer"&gt;release notes page&lt;/a&gt; but the page is not anymore used for RDS. Now you have to monitor the &lt;a href="https://aws.amazon.com/new/#database-services" target="_blank" rel="noopener noreferrer"&gt;database announcement page&lt;/a&gt;, something that you can hardly automate.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Any way to speed up the minor version upgrades?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You can use the AWS CLI invoking the &lt;em&gt;describe-db-engine-versions&lt;/em&gt; API or write a simple Lambda function to retrieve the latest available minor version and act accordingly: you can, for example, notify your team of DBAs using Amazon Simple Notification Service (SNS) or you can automatically upgrade the instance. Let’s first see how to achieve that using the command line:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-2" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-2"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws --profile sandbox rds describe-db-engine-versions --engine 'mysql' --engine-version '5.7'
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;--query "DBEngineVersions[-1].EngineVersion"&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;where the -1 in the array let you filter out the very latest version of the engine available on RDS. Today the result is “5.7.21” and a simple cron job will monitor and can trigger notification for changes. Note that the same approach can be used to retrieve the latest available minor version for engines running MySQL 5.5 and MySQL 5.6. And PostgreSQL engines too.&lt;/p&gt;
&lt;p&gt;If you want to automatically and immediately upgrade your instance, the logic can be easily done in a few lines in bash with a cron on a EC2. For example, the following function requires only the database instance identifier:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-3" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-3"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rds_minor_upgrade() {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; rds_endpoint=$1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; engine_version="5.7"
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; rds_current_minor=$(aws rds describe-db-instances
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --db-instance-identifier="$rds_endpoint" --query "DBInstances[].EngineVersion")
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; rds_latest_minor=$(aws rds describe-db-engine-versions -- engine 'mysql'
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --engine-version $eng_version --query "DBEngineVersions[-1].EngineVersion")
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; if [ "$rds_latest_minor" != "$rds_current_minor" ]; then
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; aws rds modify-db-instance --apply-immediately --engine-version
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; $rds_latest_minor --db-instance-identifier $rds_endpoint
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; fi
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Alternatively you can write the code as a scheduled Lambda function in your favourite language. For example, using the AWS node.js SDK you can &lt;a href="https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/RDS.html" target="_blank" rel="noopener noreferrer"&gt;manage RDS&lt;/a&gt; and implement the logic above using the &lt;em&gt;rds.describeDBEngineVersions&lt;/em&gt; and_rds.modifyDBInstance_ to achieve the same.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-4" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-4"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;(...)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rds.describeDBEngineVersions(params, function(err, data) {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;(...)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;(...)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;var params = {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;DBInstanceIdentifier: 'test-rds01',
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ApplyImmediately: true,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;EngineVersion: '&lt;new minor version&gt;',
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;(...)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rds.modifyDBInstance(params, function(err, data) {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;(...)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h4 id="speed-up-your-minor-upgrade"&gt;Speed up your minor upgrade!&lt;/h4&gt;
&lt;p&gt;To summarize, Amazon Web Services does not offer a real way to automatically upgrade a RDS instance to the latest available minor in the most common scenarios, but it is very easy to achieve that by taking advantage of the AWS CLI or the many SDKs.&lt;/p&gt;
&lt;p&gt;The goal is not to upgrade automatically every deployment. You would not normally use this for production deployments. However, being able to monitor the latest available minor version on RDS and apply the changes automatically for development and staging deployment can significantly reduce the time it takes to have MySQL up to date on RDS and make your upgrade process more automated.&lt;/p&gt;
&lt;p&gt;
&lt;figure&gt;&lt;img src="https://percona.community/blog/2018/07/upgrade-minor-versions-MySQL-Amazon-RDS.jpg" alt="upgrade minor versions MySQL Amazon RDS" /&gt;&lt;/figure&gt;&lt;/p&gt;</content:encoded>
      <author>Renato Losio</author>
      <category>Amazon RDS</category>
      <category>AWS</category>
      <category>DevOps</category>
      <category>MySQL</category>
      <category>RDS</category>
      <category>Upgrade</category>
      <media:thumbnail url="https://percona.community/blog/2018/07/upgrade-minor-versions-MySQL-Amazon-RDS_hu_a12a8e21cdc46c96.jpg"/>
      <media:content url="https://percona.community/blog/2018/07/upgrade-minor-versions-MySQL-Amazon-RDS_hu_4b895255f425a679.jpg" medium="image"/>
    </item>
    <item>
      <title>A Nice Feature in MariaDB 10.3: no InnoDB Buffer Pool in Core Dumps</title>
      <link>https://percona.community/blog/2018/06/28/nice-feature-in-mariadb-103-no-innodb-buffer-pool-in-coredumps/</link>
      <guid>https://percona.community/blog/2018/06/28/nice-feature-in-mariadb-103-no-innodb-buffer-pool-in-coredumps/</guid>
      <pubDate>Thu, 28 Jun 2018 12:28:58 UTC</pubDate>
      <description>MariaDB 10.3 is now generally available (10.3.7 was released GA on 2018-05-25). The article What’s New in MariaDB Server 10.3 by the MariaDB Corporation lists three key improvements in 10.3: temporal data processing, Oracle compatibility features, and purpose-built storage engines. Even if I am excited about MyRocks and curious on Spider, I am also very interested in less flashy but still very important changes that make running the database in production easier. This post describes such improvement: no InnoDB Buffer Pool in core dumps.</description>
      <content:encoded>&lt;p&gt;MariaDB 10.3 is now generally available (10.3.7 was released GA on 2018-05-25). The article &lt;a href="https://mariadb.com/resources/blog/whats-new-mariadb-server-103" target="_blank" rel="noopener noreferrer"&gt;What’s New in MariaDB Server 10.3&lt;/a&gt; by the MariaDB Corporation lists three key improvements in 10.3: temporal data processing, Oracle compatibility features, and purpose-built storage engines. Even if I am excited about &lt;a href="https://mariadb.com/kb/en/library/myrocks/" target="_blank" rel="noopener noreferrer"&gt;MyRocks&lt;/a&gt; and curious on &lt;a href="https://mariadb.com/kb/en/library/spider-storage-engine-overview/" target="_blank" rel="noopener noreferrer"&gt;Spider&lt;/a&gt;, I am also very interested in less flashy but still very important changes that make running the database in production easier. This post describes such improvement: &lt;strong&gt;no&lt;/strong&gt; &lt;a href="https://dev.mysql.com/doc/refman/5.7/en/innodb-buffer-pool.html" target="_blank" rel="noopener noreferrer"&gt;&lt;strong&gt;InnoDB Buffer Pool&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;in core dumps&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Hidden in the &lt;em&gt;Compression&lt;/em&gt; section of the page &lt;a href="https://mariadb.com/kb/en/library/changes-improvements-in-mariadb-103/" target="_blank" rel="noopener noreferrer"&gt;Changes &amp; Improvements in MariaDB 10.3&lt;/a&gt; from the &lt;a href="https://mariadb.com/kb/" target="_blank" rel="noopener noreferrer"&gt;Knowledge Base&lt;/a&gt;, we can read:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;On Linux, shrink the core dumps by omitting the InnoDB buffer pool&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;This is it, no more details, only a link to &lt;a href="https://jira.mariadb.org/browse/MDEV-10814" target="_blank" rel="noopener noreferrer"&gt;MDEV-10814 (Feature request: Optionally exclude large buffers from core dumps)&lt;/a&gt;. This Jira ticket was open in 2016-09-15 by a well-known MariaDB Support Engineer: Hartmut Holzgraefe. I know Booking.com was asking for this feature for a long time, this is even mentioned by Hartmut in a &lt;a href="https://github.com/MariaDB/server/pull/333#issuecomment-296206130" target="_blank" rel="noopener noreferrer"&gt;GitHub comment&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The ways this feature eases operations with MariaDB are well documented by Hartmut in the description of the Jira ticket:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;it needs less available disk space to store core dumps,&lt;/li&gt;
&lt;li&gt;it reduces the time required to write core dumps (and hence restart MySQL after a crash),&lt;/li&gt;
&lt;li&gt;it improves security by omitting substantial amount of user data from core dumps.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In addition to that, I would add that smaller core dumps are easier to share in tickets. I am often asked by support engineers to provide a core dump in relation to a crash, and my reply is “&lt;em&gt;How do you want me to give you with a 192 GB file ?&lt;/em&gt;” (or even bigger files as I saw MySQL/MariaDB being used on servers with 384 GB of RAM). This often leads to a “&lt;em&gt;Let me think about this and I will come back to you&lt;/em&gt;” answer. Avoiding the InnoDB Buffer Pool in core dumps makes this less of an issue for both DBAs and support providers.&lt;/p&gt;
&lt;p&gt;Before continuing the discussion on this improvement, I need to give more details about what a core dump is.&lt;/p&gt;
&lt;h4 id="what-is-a-core-dump-and-why-is-it-useful"&gt;&lt;strong&gt;What is a Core Dump and Why is it Useful ?&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;By looking at the &lt;a href="http://man7.org/linux/man-pages/man5/core.5.html" target="_blank" rel="noopener noreferrer"&gt;Linux manual page for core (and core dump file)&lt;/a&gt;, we can read:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[A core dump is] a disk file containing an image of the process’s memory at the time of termination. This image can be used in a debugger to inspect the state of the program at the time that it terminated.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;The &lt;a href="https://en.wikipedia.org/wiki/Core_dump" target="_blank" rel="noopener noreferrer"&gt;Wikipedia article for core dump&lt;/a&gt; also tells us that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the core dump includes key pieces of program state as processor registers, memory management details, and other processor and operating system flags and information,&lt;/li&gt;
&lt;li&gt;the name comes from &lt;a href="https://en.wikipedia.org/wiki/Magnetic_core_memory" target="_blank" rel="noopener noreferrer"&gt;magnetic core memory&lt;/a&gt;, the principal form of random access memory from the 1950s to the 1970s, and the name has remained even if magnetic core technology is obsolete.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So a core dump is a file that can be very useful to understand the context of a crash. The exact details of how to use a core dump have been already discussed in many places and is beyond the subject of this post. The interested reader can learn more by following those links:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.percona.com/blog/2011/08/26/getting-mysql-core-file-on-linux/" target="_blank" rel="noopener noreferrer"&gt;Getting MySQL Core file on Linux&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mariadb.com/kb/en/library/how-to-produce-a-full-stack-trace-for-mysqld/" target="_blank" rel="noopener noreferrer"&gt;How to Produce a Full Stack Trace for mysqld&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.percona.com/blog/2015/08/17/mysql-is-crashing-a-support-engineers-point-of-view/" target="_blank" rel="noopener noreferrer"&gt;MySQL is crashing: a support engineer’s point of view&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.dropbox.com/s/j4salsgphyrsnjw/Cheat%20Sheet.pdf" target="_blank" rel="noopener noreferrer"&gt;Database issue cheat sheet (including gdb commands for using core dumps)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.mysql.com/doc/refman/5.7/en/crashing.html" target="_blank" rel="noopener noreferrer"&gt;What to Do If MySQL Keeps Crashing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.mysql.com/doc/refman/5.7/en/using-gdb-on-mysqld.html" target="_blank" rel="noopener noreferrer"&gt;Debugging mysqld under gdb&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Update 2018-07-31&lt;/strong&gt;: more links about how to use core dumps:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://mysqlentomologist.blogspot.com/2017/08/how-to-find-values-of-session-variables.html" target="_blank" rel="noopener noreferrer"&gt;How to Find Values of Session Variables With gdb&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://mysqlentomologist.blogspot.com/2017/07/how-to-find-processlist-thread-id-in-gdb.html" target="_blank" rel="noopener noreferrer"&gt;How to Find Processlist Thread id in gdb&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://archive.fosdem.org/2015/schedule/event/mysql_gdb/attachments/slides/595/export/events/attachments/mysql_gdb/slides/595/FOSDEM2015_gdb_tips_and_tricks_for_MySQL_DBAs.pdf" target="_blank" rel="noopener noreferrer"&gt;gdb tips and tricks for MySQL DBAs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now that we know more about core dumps, we can get back to the discussion of the new feature.&lt;/p&gt;
&lt;h4 id="the-no-innodb-buffer-pool-in-core-dump-feature-from-mariadb-103"&gt;&lt;strong&gt;The&lt;/strong&gt; &lt;strong&gt;&lt;em&gt;no InnoDB Buffer Pool in Core Dump&lt;/em&gt;&lt;/strong&gt; &lt;strong&gt;Feature from MariaDB 10.3&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;As already pointed out above, there are very few details in the release notes about how this feature works. By digging in &lt;a href="https://jira.mariadb.org/browse/MDEV-10814" target="_blank" rel="noopener noreferrer"&gt;MDEV-10814&lt;/a&gt;, following pointers to pull requests (#&lt;a href="https://github.com/MariaDB/server/pull/333" target="_blank" rel="noopener noreferrer"&gt;333&lt;/a&gt;, #&lt;a href="https://github.com/MariaDB/server/pull/364" target="_blank" rel="noopener noreferrer"&gt;364&lt;/a&gt;, &lt;a href="https://github.com/MariaDB/server/pull/365" target="_blank" rel="noopener noreferrer"&gt;365&lt;/a&gt;, …), and reading the &lt;a href="https://github.com/MariaDB/server/pull/364/commits/b600f30786816e33c1706dd36cdabf21034dc781" target="_blank" rel="noopener noreferrer"&gt;commit message&lt;/a&gt;, I was able to gather this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An initial patch was written by Hartmut in 2015.&lt;/li&gt;
&lt;li&gt;It uses the MADV_DONTDUMP flag to the &lt;a href="http://man7.org/linux/man-pages/man2/madvise.2.html" target="_blank" rel="noopener noreferrer"&gt;madvise&lt;/a&gt; system call (available in Linux kernel 3.4 and higher).&lt;/li&gt;
&lt;li&gt;Hartmut’s patch was rebased by Daniel Black, a well-known MariaDB Community Contributor (pull request #&lt;a href="https://github.com/MariaDB/server/pull/333" target="_blank" rel="noopener noreferrer"&gt;333&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;The first work by Daniel had a configuration parameter to allow including/excluding the InnoDB Buffer Pool in/from core dumps, but after a &lt;a href="https://github.com/MariaDB/server/pull/333#issuecomment-295460913" target="_blank" rel="noopener noreferrer"&gt;discussion&lt;/a&gt; in pull request #333, it was decided that the RELEASE builds would not put the InnoDB Buffer Pool in core dumps and that &lt;a href="https://mariadb.com/kb/en/library/compiling-mariadb-for-debugging/" target="_blank" rel="noopener noreferrer"&gt;DEBUG builds&lt;/a&gt; would include it (more about this below).&lt;/li&gt;
&lt;li&gt;The function buf_madvise_do_dump is added but never invoked by the server; it is there to be called from a debugger to re-enable full core dumping if needed (from this &lt;a href="https://github.com/MariaDB/server/pull/364/commits/b600f30786816e33c1706dd36cdabf21034dc781" target="_blank" rel="noopener noreferrer"&gt;commit message&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;The &lt;a href="https://dev.mysql.com/doc/refman/5.7/en/innodb-redo-log-buffer.html" target="_blank" rel="noopener noreferrer"&gt;InnoDB Redo Log buffer&lt;/a&gt; is also excluded from core dumps (from this &lt;a href="https://github.com/MariaDB/server/pull/364#issuecomment-345655419" target="_blank" rel="noopener noreferrer"&gt;comment&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I have doubts about the absence of a configuration parameter for controlling the feature. Even if the InnoDB Buffer Pool (as written above, the feature also concerns the InnoDB Redo Log buffer, but I will only mention InnoDB Buffer Pool in the rest of this post for brevity) is not often required in core dumps, Marko Mäkelä, InnoDB Engineer at MariaDB.com, &lt;a href="https://github.com/MariaDB/server/pull/364#issuecomment-325307968" target="_blank" rel="noopener noreferrer"&gt;mentioned sometimes needing it&lt;/a&gt; to investigate deadlocks, corruption or race conditions. Moreover, I was recently asked, in a support ticket, to provide a core dump to understand a crash in MariaDB 10.2 (public bug report in &lt;a href="https://jira.mariadb.org/browse/MDEV-15608" target="_blank" rel="noopener noreferrer"&gt;MDEV-15608&lt;/a&gt;): it looks to me that the InnoDB Buffer Pool be useful here. Bottom line: having the InnoDB Buffer Pool (and Redo log buffer) in core dumps might not be regularly useful, but it is sometimes needed.&lt;/p&gt;
&lt;p&gt;To include the InnoDB Buffer Pool in core dumps, DBAs can install DEBUG binaries or they can use a debugger to call the buf_madvise_do_dump function (well thought Daniel for compensating the absence of a configuration parameter, but there are caveats described below). Both solutions are suboptimal in my humble opinion. For #2, there are risks and drawbacks of using a debugger on a live production database (when it works … see below for a war story). For #1 and unless I am mistaken, DEBUG binaries are not available from the &lt;a href="https://downloads.mariadb.org/" target="_blank" rel="noopener noreferrer"&gt;MariaDB download site&lt;/a&gt;. This means that they will have to be built by engineers of your favorite support provider, or that DBAs will have to &lt;a href="https://mariadb.com/kb/en/library/compiling-mariadb-for-debugging/" target="_blank" rel="noopener noreferrer"&gt;manually compile&lt;/a&gt; them: this is a lot of work to expect from either party. I also think that the usage of DEBUG binaries in production should be minimized, not encouraged (DEBUG binaries are for developers, not DBAs); so I feel we are heading in the wrong direction. Bottom line: I would not be surprised (&lt;a href="https://github.com/MariaDB/server/pull/333#issuecomment-295644884" target="_blank" rel="noopener noreferrer"&gt;and I am not alone&lt;/a&gt;) that a parameter might be added in a next release to ease investigations of InnoDB bugs.&lt;/p&gt;
&lt;p&gt;Out of curiosity, I checked the core dump sizes for some versions of MySQL and MariaDB with &lt;a href="https://github.com/datacharmer/dbdeployer" target="_blank" rel="noopener noreferrer"&gt;dbdeployer&lt;/a&gt; (if you have not tried it yet, you should probably spend time &lt;a href="https://www.percona.com/blog/2018/05/24/using-dbdeployer-to-manage-mysql-percona-server-and-mariadb-sandboxes/" target="_blank" rel="noopener noreferrer"&gt;learning how to use dbdeployer&lt;/a&gt;: it is very useful). Here are my naive first results with default configurations and freshly started mysqld:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;487 MB and 666 MB core dumps with MySQL 5.7.22 and 8.0.11 respectively,&lt;/li&gt;
&lt;li&gt;673 MB and 671 MB core dumps with MariaDB 10.2.15 and MariaDB 10.3.7 respectively.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I tried understanding where the inflation is coming from in MySQL 8.0.11 but I tripped on &lt;a href="https://bugs.mysql.com/bug.php?id=90561" target="_blank" rel="noopener noreferrer"&gt;Bug#90561&lt;/a&gt; which prevents my investigations. We will have to wait for 8.0.12 to know more…&lt;/p&gt;
&lt;p&gt;Back to the feature, I was surprised to see no shrinking between MariaDB 10.2 and 10.3. To make sure something was not wrong, I tried to have the InnoDB Buffer Pool in the core dump by calling the buf_madvise_do_dump function. I used the &lt;a href="https://archive.fosdem.org/2015/schedule/event/mysql_gdb/attachments/slides/595/export/events/attachments/mysql_gdb/slides/595/FOSDEM2015_gdb_tips_and_tricks_for_MySQL_DBAs.pdf" target="_blank" rel="noopener noreferrer"&gt;slides&lt;/a&gt; from the &lt;a href="https://archive.fosdem.org/2015/schedule/event/mysql_gdb/" target="_blank" rel="noopener noreferrer"&gt;gdb tips and tricks for MySQL DBAs&lt;/a&gt; talk by &lt;a href="https://mysqlentomologist.blogspot.com/" target="_blank" rel="noopener noreferrer"&gt;Valerii Kravchuk&lt;/a&gt; presented at FOSDEM 2015 (I hope a similar talk will be given soon at Percona Live as my gdb skills need a lot of improvements), but I got the following result:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-0"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ gdb -p $(pidof mysqld) -ex "call buf_madvise_do_dump()" -batch
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[...]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;No symbol "buf_madvise_do_dump" in current context.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;After investigations, I understood that the generic MariaDB Linux packages that I used with dbdeployer are compiled without the feature. A reason could be that there is no way to know that those packages will be used on a Linux 3.4+ kernel (without a recent enough kernel, the MADV_DONTDUMP argument does not exist for the madvise system call). To be able to test the feature, I would either have to build my own binaries or try packages for a specific distribution. I chose to avoid compilation but this was more tedious than I thought…&lt;/p&gt;
&lt;p&gt;By the way, maybe the buf_madvise_do_dump function should always be present in binaries and return a non-zero value when failing with a detailed message in the error logs. This would have spared me spending time understanding why it did not work in my case. I opened &lt;a href="https://jira.mariadb.org/browse/MDEV-16605" target="_blank" rel="noopener noreferrer"&gt;MDEV-16605: Always include buf_madvise_do_dump in binaries&lt;/a&gt; for that.&lt;/p&gt;
&lt;p&gt;Back to my tests and to see the feature in action, I started a &lt;a href="http://releases.ubuntu.com/16.04/" target="_blank" rel="noopener noreferrer"&gt;Ubuntu 16.04.4 LTS&lt;/a&gt; in AWS (it comes with a 4.4 kernel). But again, I could not call buf_madvise_do_dump. After more investigation, I understood that the Ubuntu and Debian packages are &lt;a href="https://sysadmin.compxtreme.ro/how-to-add-debug-symbols-for-mariadb-debianubuntu-packages/" target="_blank" rel="noopener noreferrer"&gt;not compiled with symbols&lt;/a&gt;, so calling buf_madvise_do_dump cannot be easily done on those (I later learned that there are &lt;em&gt;mariadb-server-10.3-dbgsym&lt;/em&gt; packages, but I did not test them). I ended-up falling back to Centos 7.5, which comes with a 3.10 kernel, and it worked ! Below are the core dump sizes with and without calling buf_madvise_do_dump:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;527 MB core dump on MariaDB 10.3.7 (without calling buf_madvise_do_dump),&lt;/li&gt;
&lt;li&gt;674 MB core dump on MariaDB 10.3.7 (with calling buf_madvise_do_dump).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I was surprised by bigger core dumps in MariaDB 10.3 than in MySQL 5.7, so I spent some time looking into that. It would have been much easier with the &lt;a href="https://dev.mysql.com/doc/mysql-perfschema-excerpt/5.7/en/memory-summary-tables.html" target="_blank" rel="noopener noreferrer"&gt;Memory Instrumentation&lt;/a&gt; from &lt;a href="https://dev.mysql.com/doc/refman/5.5/en/performance-schema.html" target="_blank" rel="noopener noreferrer"&gt;Performance Schema&lt;/a&gt;, but this is not yet available in MariaDB. There is a Jira ticket opened for that (&lt;a href="https://jira.mariadb.org/browse/MDEV-16431" target="_blank" rel="noopener noreferrer"&gt;MDEV-16431&lt;/a&gt;); if you are also interested in this feature, I suggest you vote for it.&lt;/p&gt;
&lt;p&gt;I guessed that the additional RAM used by MariaDB 10.3 (compared to MySQL 5.7) comes from the caches for the &lt;a href="https://mariadb.com/kb/en/library/myisam-storage-engine/" target="_blank" rel="noopener noreferrer"&gt;MyISAM&lt;/a&gt; and &lt;a href="https://mariadb.com/kb/en/library/aria-storage-engine/" target="_blank" rel="noopener noreferrer"&gt;Aria&lt;/a&gt; storage engines. Those caches, whose sizes are controlled by the &lt;a href="https://mariadb.com/kb/en/library/myisam-system-variables/#key_buffer_size" target="_blank" rel="noopener noreferrer"&gt;key_buffer_size&lt;/a&gt; and &lt;a href="https://mariadb.com/kb/en/library/aria-system-variables/#aria_pagecache_buffer_size" target="_blank" rel="noopener noreferrer"&gt;aria_pagecache_buffer_size&lt;/a&gt; parameters, are 128 MB by default in MariaDB 10.3 (more discussion about these sizes below). I tried shrinking both caches to 8 MB (&lt;a href="https://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_key_buffer_size" target="_blank" rel="noopener noreferrer"&gt;the default value in MySQL since at least 5.5&lt;/a&gt;), but I got another surprise:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;div class="code-block__header"&gt;&lt;button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"&gt;
&lt;span class="code-block__copy-default"&gt;Copy&lt;/span&gt;
&lt;span class="code-block__copy-success" aria-hidden="true"&gt;Copied!&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;div class="code-block__content" id="codeblock-1"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&gt; SET GLOBAL key_buffer_size = 8388608;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Query OK, 0 rows affected (0.001 sec)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&gt; SET GLOBAL aria_pagecache_buffer_size = 8388608;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ERROR 1238 (HY000): Variable 'aria_pagecache_buffer_size' is a read only variable&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The &lt;a href="https://mariadb.com/kb/en/library/aria-system-variables/#aria_pagecache_buffer_size" target="_blank" rel="noopener noreferrer"&gt;aria_pagecache_buffer_size&lt;/a&gt; parameter is not dynamic ! This is annoying as I like tuning parameters to be dynamic, so I opened &lt;a href="https://jira.mariadb.org/browse/MDEV-16606" target="_blank" rel="noopener noreferrer"&gt;MDEV-16606: Make aria_pagecache_buffer_size dynamic&lt;/a&gt; for that. I tested with only shrinking the MyISAM cache and by modifying the startup configuration for Aria. The results for the core dump sizes are the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;527 MB core dump for the default behavior,&lt;/li&gt;
&lt;li&gt;400 MB core dump by shrinking the MyISAM cache from 128 MB to 8 MB,&lt;/li&gt;
&lt;li&gt;268 MB core dump by also shrinking the Aria cache from 128 MB to 8 MB.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We are now at a core dump size smaller than MySQL 5.7.22: this is the result I was expecting.&lt;/p&gt;
&lt;p&gt;I did some more tests with a larger InnoDB Buffer Pool and with a larger InnoDB Redo Log buffer while keeping MyISAM and Aria cache sizes to 8 MB. Here are the results of the sizes of the compact core dump (default behavior) vs the full core dump (using gdb):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;340 MB vs 1.4 GB core dumps when growing the InnoDB Buffer Pool from 128 MB to 1 GB,&lt;/li&gt;
&lt;li&gt;357 MB vs 1.7 GB core dumps when also growing the InnoDB Redo Log buffer from 16 MB to 128 MB.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I think the results above show the usefulness of the no InnoDB Buffer Pool in core dump feature.&lt;/p&gt;
&lt;h4 id="potential-improvements-of-the-shrinking-core-dump-feature"&gt;&lt;strong&gt;Potential Improvements of the&lt;/strong&gt; &lt;strong&gt;&lt;em&gt;Shrinking&lt;/em&gt;&lt;/strong&gt; &lt;strong&gt;Core Dump Feature&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;The end goal of excluding the InnoDB Buffer Pool from core dumps is to make generating and working with those files easier. As already mentioned above, the space and time taken to save core dumps are the main obstacles, and sharing them is also an issue (including leaking a lot of user data).&lt;/p&gt;
&lt;p&gt;Ideally, I would like to always run MySQL/MariaDB with core dump enabled on crashes (I see one exception when using &lt;a href="https://www.percona.com/blog/2016/04/08/mysql-data-at-rest-encryption/" target="_blank" rel="noopener noreferrer"&gt;database-level encryption&lt;/a&gt; for not leaking data). I even think this should be the default behavior, but this is another discussion that I will not start here. My main motivation is that if/when MySQL crashes, I want all information needed to understand the crash (and eventually report a bug) without having to change parameters, restart the database, and generate the same crash again. Obviously, this configuration is unsuitable for servers with a lot of RAM and with a large InnoDB Buffer Pool. MariaDB 10.3 makes a big step forward by excluding the InnoDB Buffer Pool (and Redo Log buffer) from core dumps, but what else could be done to achieve the goal of always running MySQL with core dump enabled ?&lt;/p&gt;
&lt;p&gt;There is a &lt;a href="https://github.com/MariaDB/server/pull/366" target="_blank" rel="noopener noreferrer"&gt;pull request to exclude the query cache from core dumps&lt;/a&gt; (also by Daniel Black, thanks for this work). When MariaDB is run with a large &lt;a href="https://mariadb.com/kb/en/library/query-cache/" target="_blank" rel="noopener noreferrer"&gt;query cache&lt;/a&gt; (and I know this is unusual, but if you know of a valid real world use case, please add a comment below), excluding it from core dumps is good. But I am not sure this is a generally needed improvement:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://mysqlserverteam.com/mysql-8-0-retiring-support-for-the-query-cache/" target="_blank" rel="noopener noreferrer"&gt;MySQL 8.0 has retired the query cache&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;the &lt;a href="https://mariadb.com/kb/en/library/server-system-variables/#query_cache_type" target="_blank" rel="noopener noreferrer"&gt;query cache is disabled by default from MariaDB 10.1.7&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;and the default value for the &lt;a href="https://mariadb.com/kb/en/library/server-system-variables/#query_cache_size" target="_blank" rel="noopener noreferrer"&gt;query cache size was zero before MariaDB 10.1.7&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It looks like there is a consensus that the query cache is a very niche feature and otherwise should be disabled, so this work might not be the one that will profit most people. Still good to be done though.&lt;/p&gt;
&lt;p&gt;I would like similar work to be done on MyISAM, Aria, &lt;a href="https://mariadb.com/kb/en/library/tokudb/" target="_blank" rel="noopener noreferrer"&gt;TokuDB&lt;/a&gt; and MyRocks. As we saw above, there is an opportunity, for default deployments, to remove 256 MB from core dumps by excluding MyISAM and Aria caches. I think this work is particularly important for those two storage engines as they are loaded by default in MariaDB. By the way, and considering the relatively low usage of the MyISAM and Aria storage engine, maybe the default value for their caches should be lower: I opened &lt;a href="https://jira.mariadb.org/browse/MDEV-16607" target="_blank" rel="noopener noreferrer"&gt;MDEV-16607: Consider smaller defaults for MyISAM and Aria cache sizes&lt;/a&gt; for that.&lt;/p&gt;
&lt;p&gt;I cannot think of any other large memory buffers that I would like to exclude from core dumps. If you think about one, please add a comment below.&lt;/p&gt;
&lt;p&gt;Finally, I would like the shrinking core dump feature to also appear in Oracle MySQL and Percona Server, so I opened &lt;a href="http://bugs.mysql.com/bug.php?id=91455" target="_blank" rel="noopener noreferrer"&gt;Bug#91455: Implement core dump size reduction&lt;/a&gt; for that. For the anecdote, I was recently working on a Percona Server crash in production, and we were reluctant to enable core dumps because of the additional minutes of downtime needed to write the file to disk. In this case, the no InnoDB Buffer Pool in core dump would have been very useful !&lt;/p&gt;</content:encoded>
      <author>Jean-François Gagné</author>
      <category>core dump</category>
      <category>InnoDB</category>
      <category>InnoDB Buffer Pool</category>
      <category>MariaDB</category>
      <category>MySQL</category>
      <media:thumbnail url="https://percona.community/blog/2018/06/InnoDB-buffer-pool-size_hu_939b40b5bf42d00f.jpg"/>
      <media:content url="https://percona.community/blog/2018/06/InnoDB-buffer-pool-size_hu_84b541430fa9029.jpg" medium="image"/>
    </item>
  </channel>
</rss>
