diff --git a/.gitignore b/.gitignore index 9a4aec200..1b01c4be9 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,7 @@ resources/ # Link checker bin/ tmp/ -.idea \ No newline at end of file +.idea + +# File generated when running npm install +package-lock.json \ No newline at end of file diff --git a/README.md b/README.md index cb78140b6..c7ff483ee 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,9 @@ This repo houses the assets used to build the website at https://vitess.io. ## Running the site locally -To run the website locally, you need to have the [Hugo](https://gohugo.io) static site generator installed (installation instructions [here](https://gohugo.io/getting-started/installing/)). Once Hugo is installed run the following: +To run the website locally, you need to have the [Hugo](https://gohugo.io) static site generator installed (installation instructions [here](https://gohugo.io/getting-started/installing/)). Installing the Hugo version in [netlify.toml](./netlify.toml) is recommended. + +Once Hugo is installed run the following: ```bash hugo server --buildDrafts --buildFuture diff --git a/assets/sass/docs.sass b/assets/sass/docs.sass index 489c6c56f..1c5f7c6c3 100644 --- a/assets/sass/docs.sass +++ b/assets/sass/docs.sass @@ -1,5 +1,4 @@ $docs-sidebar-logo-width: 30% -$docs-sidebar-margin: 1.75rem $docs-sidebar-header-margin-bottom: 2rem $tan: #f5993a @@ -12,156 +11,156 @@ html, body =h-center justify-content: center +// Bit of a hacky full-width container override for the docs page, +// since bulma.io doesn't appear to have a helper for this. +.navbar-container-docs + max-width: 100% + padding: 0 8px 0 24px + .docs-wrapper +flex flex-direction: row - height: 100vh + height: calc(100vh - #{$navbar-height}) align-items: stretch - .docs-navbar - position: sticky - top: 0 +.docs-navbar + position: sticky + top: 0 - .docs-sidebar - +flex - +h-center - background-color: $dark - flex: 0 0 15% - border-right: 1px solid lighten($dark, 10%) - overflow: scroll +.docs-sidebar + +flex + +h-center + background-color: $dark + flex: 0 0 15% + border-right: 1px solid lighten($dark, 10%) + overflow: auto - .docs-menu - width: 100% - margin: $docs-sidebar-margin +.docs-menu + width: 100% + margin: 24px 0 24px 0 - .docs-menu-header - margin-bottom: $docs-sidebar-header-margin-bottom +.docs-menu-header + margin-bottom: $docs-sidebar-header-margin-bottom - .docs-menu-logo - width: $docs-sidebar-logo-width - margin: 0 auto - display: block +.docs-menu-logo + margin: 0 auto + display: block - .docs-menu-bar - padding-bottom: 5rem +.docs-menu > .docs-navlist > li > a + font-size: 1.2rem - .docs-section - & + .docs-section - margin-top: .75rem +.docs-navlist ul > li + border-left: solid 1px rgba(255, 255, 255, 0.1) + margin-left: 16px - .docs-section-title - font-size: 1.2rem - color: $grey-lighter - line-height: 100% +.docs-navlist li + position: relative - &.is-active - color: $primary +.docs-navlist li a + color: $grey-lighter + display: block + font-size: 0.9rem + padding: 8px 24px 8px 16px - .docs-section-list - margin-left: .3rem - border-left: 1px solid $grey + &:hover + background: rgba(255, 255, 255, 0.05) - ul - margin-top: .75rem +.docs-navlist li.active > a + color: $tan - li - font-size: 1rem - margin-left: 1rem - line-height: 120% +.navlist-caret + height: 10px + margin-top: -5px + position: absolute + right: 16px + top: 22px + fill: rgba(255, 255, 255, 0.25) - a - color: $grey-lighter +li.expanded > a > .navlist-caret + transform: rotate(90deg) - & + li - margin-top: .8rem +.docs-article + flex: 1 1 auto + overflow: auto - &.is-active - a - color: $tan + .docs-content + margin: 2rem 2.5rem - .docs-article - flex: 1 1 auto - overflow: auto + +touch + margin: 1.5rem - .docs-content - margin: 2rem 2.5rem + padding-bottom: 5rem - +touch - margin: 1.5rem + .content + +desktop + width: 80% - padding-bottom: 5rem + p a, li a + font-weight: 700 - .content - +desktop - width: 80% + li .highlight, ol li + margin-bottom: 1rem - p a, li a - font-weight: 700 + h1 + font-size: 1.802rem + h2 + font-size: 1.602rem + h3 + font-size: 1.424rem + h4 + font-size: 1.266rem + h5 + font-size: 1.125rem + h2, h3, h4, h5, h6 + color: $vitess-orange - li .highlight, ol li - margin-bottom: 1rem + .docs-header + padding-bottom: 1rem + margin-bottom: 2rem - h1 - font-size: 1.802rem - h2 - font-size: 1.602rem - h3 - font-size: 1.424rem - h4 - font-size: 1.266rem - h5 - font-size: 1.125rem - h2, h3, h4, h5, h6 - color: $vitess-orange + .card-content + padding: 0 0 1.5rem 0 - .docs-header - padding-bottom: 1rem - margin-bottom: 2rem - border-bottom: 1px solid $grey-lighter +.docs-toc + flex: 0 0 15% + background-color: $white-bis + overflow: auto + border-left: 1px solid $grey-light - .card-content - padding: 0 0 1.5rem 0 + &-container + margin: 1rem - .docs-toc - flex: 0 0 15% - background-color: $white-bis - overflow: auto - border-left: 1px solid $grey-light + &-title + color: $dark + font-size: 1.25rem - &-container - margin: 1rem + &-menu + margin: 1.5rem 0 - &-title + a color: $dark - font-size: 1.25rem - - &-menu - margin: 1.5rem 0 - - a - color: $dark - &:hover - color: $primary + &:hover + color: $primary - #TableOfContents - ul - li - font-size: 1rem - line-height: 1.2rem + #TableOfContents + ul + li + font-size: 1rem + line-height: 1.2rem - & + li - margin-top: .75rem + & + li + margin-top: .75rem - ul - margin: .5rem 0 0 1rem + ul + margin: .5rem 0 0 1rem - li - font-size: 0.8rem + li + font-size: 0.8rem - & + li - margin-top: .75rem - line-height: 1.2rem + & + li + margin-top: .75rem + line-height: 1.2rem @@ -171,4 +170,3 @@ html, body margin-left: 30px; background-color: #f7f7f7; margin-bottom: 10px; - diff --git a/assets/sass/style.sass b/assets/sass/style.sass index b6c2310fc..9d0ee13a7 100644 --- a/assets/sass/style.sass +++ b/assets/sass/style.sass @@ -53,11 +53,12 @@ figure .has-extra-padding padding: 2.5rem -.docs-article ul li +.docs-article .content ul li margin-left: -.5rem list-style-type: square .is-blog-container + max-width: 100% margin: -12rem auto 0 auto .is-blog-card @@ -94,6 +95,8 @@ figure font-style: normal font-weight: 700 +.is-blog-container .media-content + max-width: 100% .toc-column @@ -147,8 +150,8 @@ figure justify-content: right .is-user-logo - max-height: 1.5rem - margin: 1.25rem + max-height: 1.7rem + margin: 1.1rem =logo($touch, $tablet) +touch @@ -163,7 +166,7 @@ figure +logo(40%, 30%) .is-cncf-logo - +logo(60%, 35%) + +logo(55%, 30%) .is-footer-logo +logo(30%, 10%) @@ -190,3 +193,45 @@ figure &.is-active position: fixed ++until($navbar-breakpoint) + #search-bar + display: block + + .algolia-autocomplete + // Fixes for the DocSearch widget to prevent clipping on mobile. + display: block !important + + .ds-dropdown-menu + max-width: 100vw !important + min-width: fit-content !important + ++from($navbar-breakpoint) + // On mobile (and by default), the search input is displayed at the top of the menu, + // whereas on desktop, it's displayed at the right side of the menu bar (i.e., flex-end) + .navbar-menu + flex-direction: row-reverse + + // Cuddle up the search input + social icons for the full-width navbar + .navbar-item-search + padding-left: 0 + +.header-link + color: $dark + opacity: 0.3 + + &:hover + opacity: 1 + +// When jumping to anchor links, we need to account for the height of the sticky navbar. +// Otherwise, the anchored header will be occluded by the navbar. +// See https://css-tricks.com/hash-tag-links-padding/ +$navbar-anchor-offset: calc(#{$navbar-height} + 16px) + +h1, h2, h3, h4, h5, h6 + &.anchored-header[id]:before + display: block + content: ' ' + margin-top: calc(-1 * #{$navbar-anchor-offset}) + height: $navbar-anchor-offset + visibility: hidden + pointer-events: none diff --git a/config.toml b/config.toml index 9ecf8a0b1..2570ab079 100644 --- a/config.toml +++ b/config.toml @@ -2,6 +2,7 @@ baseURL = "https://vitess.io" canonifyurls = true disableKinds = ["taxonomy", "taxonomyTerm"] googleAnalytics = "UA-163836834-1" +enableRobotsTXT = true # Syntax highlighting settings pygmentsCodeFences = true @@ -21,6 +22,11 @@ stackoverflow = "vitess" [params.blog] subtitle = "Updates and insights from the **Vitess** team." +[sitemap] +changefreq = "monthly" +filename = "sitemap.xml" +priority = 0.5 + # Language settings DefaultContentLanguage = "en" defaultContentLanguageInSubdir = true diff --git a/content/en/blog/2015-10-06-cloud-native-mysql-sharding-with-vitess-and-kubernetes.md b/content/en/blog/2015-10-06-cloud-native-mysql-sharding-with-vitess-and-kubernetes.md index 48f742a34..0d2325ec5 100644 --- a/content/en/blog/2015-10-06-cloud-native-mysql-sharding-with-vitess-and-kubernetes.md +++ b/content/en/blog/2015-10-06-cloud-native-mysql-sharding-with-vitess-and-kubernetes.md @@ -21,9 +21,9 @@ of [Vitess v2.0.0](https://github.com/youtube/vitess/releases). Some highlights * Java and Go clients use the new HTTP/2-based [gRPC](http://www.grpc.io/) framework. * Can now run on top of MySQL 5.6, in addition to MariaDB 10.0. * New administrative dashboard built on AngularJS. -* Built-in backup/restore](http://vitess.io/user-guide/backup-and-restore.html), designed to plug into blob stores like [Google Cloud Storage](https://cloud.google.com/storage/). -* GTID-based [reparenting](http://vitess.io/user-guide/reparenting.html) for reversible, routine failovers. -* Simpler [schema changes](http://vitess.io/user-guide/schema-management.html). +* [Built-in backup/restore](https://vitess.io/docs/user-guides/operating-vitess/backup-and-restore/) designed to plug into blob stores like [Google Cloud Storage](https://cloud.google.com/storage/). +* GTID-based [reparenting](https://vitess.io/docs/user-guides/configuration-advanced/reparenting/) for reversible, routine failovers. +* Simpler [schema changes](https://vitess.io/docs/reference/features/schema-management/). We've also been hard at work adding lots more [documentation](http://vitess.io/user-guide/introduction.html). In particular, the rest of this post will explore one of our new walkthroughs that demonstrates transparent [resharding](http://vitess.io/user-guide/sharding.html#resharding) of a live database - that is, changing the number of shards without any code changes or noticeable downtime for the application. @@ -38,30 +38,22 @@ values, which we call [keyspace IDs](http://vitess.io/overview/concepts.html#key **Transparent Resharding** -If you want to follow along with the new [resharding walkthrough](http://vitess.io/user-guide/sharding-kubernetes.html), you'll need to first bring up the cluster as described in the [unsharded guide](http://vitess.io/getting-started/). Both guides use the same [sample app](https://github.com/youtube/vitess/tree/master/examples/kubernetes/guestbook), which is a Guestbook that supports multiple, numbered pages. - - +If you want to follow along with the new [resharding walkthrough](http://vitess.io/user-guide/sharding-kubernetes.html), you'll need to first bring up the cluster as described in the [unsharded guide](http://vitess.io/getting-started/). In the [sample app code](https://github.com/youtube/vitess/blob/master/examples/kubernetes/guestbook/main.py), you'll see a `get\_keyspace\_id()` function that transforms a given page number to the set of all 8-byte sequences, establishing the mapping we need for consistent hashing. In the unsharded case, these values are stored but not used. When we introduce sharding, page numbers will be evenly distributed (on average) across all the shards we create, allowing the app to scale to support arbitrary amounts of pages. Before resharding, you'll see a single [custom shard](http://vitess.io/user-guide/sharding.html#custom-sharding) named "0" in the Vitess dashboard. This is what an unsharded [keyspace](http://vitess.io/overview/concepts.html#keyspace) looks like. - - As you begin the [resharding walkthrough](http://vitess.io/user-guide/sharding-kubernetes.html),you'll bring up two new shards for the same keyspace. During resharding, the new shards will run alongside the old one, but they'll remain idle (Vitess will not route any app traffic to them) until you're ready to migrate. In the dashboard, you'll see all three shards, but only shard "0" is currently active. - - Next, you'll run a few Vitess commands to [copy the schema and data](http://vitess.io/user-guide/sharding-kubernetes.html#copy-data-from-original-shard) from the original shard. The key to live migration is that once the initial snapshot copy is done, Vitess will automatically begin replicating fresh updates on the original shard to the new shards. We call this [filtered replication](http://vitess.io/user-guide/sharding.html#filtered-replication), since it distributes DMLs only to the shards to which they apply. Vitess also includes tools that compare the original and copied data sets, row-by-row, to [verify data integrity](http://vitess.io/user-guide/sharding-kubernetes.html#check-copied-data-integrity). Once you've verified the copy, and filtered replication has caught up to real-time updates, you can run the [migrate command](http://vitess.io/user-guide/sharding-kubernetes.html#switch-over-to-the-new-shards) which tells Vitess to atomically shift app traffic from the old shards to the new ones. It does this by disabling writes on the old masters, waiting for the new masters to receive the last events over filtered replication, and then enabling writes on the new masters. Since the process is automated, this typically only causes about a second of write unavailability. -Now you can[tear down the old shard](http://vitess.io/user-guide/sharding-kubernetes.html#remove-the-original-shard), +Now you can [tear down the old shard](http://vitess.io/user-guide/sharding-kubernetes.html#remove-the-original-shard), and verify that only the new ones show up in the dashboard. - - Note that we never had to tell the app that we were changing from one shard to two. The resharding process was completely transparent to the app, since Vitess automatically reroutes queries on-the-fly as the migration progresses. At YouTube, we've used Vitess to transparently reshard (both [horizontally and vertically](http://vitess.io/user-guide/sharding.html#supported-operations)) nearly all of our MySQL databases within the last year alone, and we have still more on the horizon as we continue to grow. See the full [walkthrough instructions](http://vitess.io/user-guide/sharding-kubernetes.html) if you want to try it out for yourself. @@ -73,14 +65,10 @@ The promise of sharding is that it allows you to scale write throughput linearly Below you can see preliminary results for scaling write throughput by adding more shards in Vitess running on [Google Container Engine](https://cloud.google.com/container-engine/). For this benchmark, we pointed YCSB at the [load balancer](http://kubernetes.io/v1.0/docs/user-guide/services.html#type-loadbalancer) for our Vitess cluster and told it to send a lot of INSERT statements. Vitess took care of routing statements to the various shards. -[](../images/2015-10-06-cloud-native-mysql-sharding-with-vitess-and-kubernetes-vitess%2B3.png) - The max throughput (QPS) for a given number of shards is the point at which round-trip write latency became degraded, which we define as >15ms on average or >50ms for the worst 1% of queries (99th percentile). We also ran YCSB's "read mostly" workload (95% reads, 5% writes) to show how Vitess can scale read traffic by adding replicas. The max throughput here is the point at which round-trip read latency became degraded, which we define as >5ms on average or >20ms for the worst 1% of queries. - - There's still a lot of room to improve the benchmarks (for example, by tuning the performance of MySQL itself). However, these preliminary results show that the returns don't diminish as you scale. And since you're scaling horizontally, you're not limited by the size of a single machine. **Conclusion** diff --git a/content/en/blog/2017-09-18-custom-sharding-with-vitess.md b/content/en/blog/2017-09-18-custom-sharding-with-vitess.md index 4dc67c2cb..7d77f60c2 100644 --- a/content/en/blog/2017-09-18-custom-sharding-with-vitess.md +++ b/content/en/blog/2017-09-18-custom-sharding-with-vitess.md @@ -119,7 +119,7 @@ The advantage of this approach is that it later allows us to change the vindex t The next obvious question is: why mod at all? What if we just used `ReverseBits(user_id)`? It turns out that this would also work. There was really no need to perform the mod in the first place. Once you’ve transitioned to using `ReverseBits`, you can shard at will from any number to any number. Over time, you can forget that you ever used mod-based sharding. -The sample code for the above Custom Vindex is [available here](https://gist.github.com/sougou/96e40aa54526447ae0b24d50ae8ea4a8). This Vindex is handy enough that we will look at adding it to the Vitess list of predefined vindexes. +This is now available as a predefined Vindex as [reverse_bits](https://github.com/vitessio/vitess/blob/master/go/vt/vtgate/vindexes/reverse_bits.go). Can you think of other ways to perform such migrations? Join us on our Slack channel to share your ideas. You can send an email to [vitess@googlegroups.com](mailto:vitess@googlegroups.com) to request an invite. diff --git a/content/en/blog/2020-04-29-announcing-vitess-6.md b/content/en/blog/2020-04-29-announcing-vitess-6.md index 04182e07b..27c4211c8 100644 --- a/content/en/blog/2020-04-29-announcing-vitess-6.md +++ b/content/en/blog/2020-04-29-announcing-vitess-6.md @@ -21,7 +21,7 @@ The Helm charts now default to using Kubernetes as the [Topology Service](https: This change also unlocked the adoption of Helm 3 and support for a wider range of Kubernetes versions, making installing Vitess much easier. ### General Availability of VReplication-based Workflows -While VReplication made its appearance in Vitess 4, it has now been promoted from experimental to general availability and the documentation now points to [MoveTables](https://vitess.io/docs/user-guides/move-tables/) and [Resharding](https://vitess.io/docs/user-guides/resharding/). +While VReplication made its appearance in Vitess 4, it has now been promoted from experimental to general availability and the documentation now points to [MoveTables](https://vitess.io/docs/user-guides/migration/move-tables/) and [Resharding](https://vitess.io/docs/user-guides/configuration-advanced/resharding/). These workflows require significantly fewer steps than their predecessors (Vertical Split Clone and Horizontal Sharding), of which we intend to deprecate at some point in the future. diff --git a/content/en/blog/2020-07-28-announcing-vitess-7.md b/content/en/blog/2020-07-28-announcing-vitess-7.md index 71630e7e8..f56735530 100644 --- a/content/en/blog/2020-07-28-announcing-vitess-7.md +++ b/content/en/blog/2020-07-28-announcing-vitess-7.md @@ -4,6 +4,7 @@ date: 2020-07-28 slug: '2020-07-28-announcing-vitess-7' tags: ['release'] title: 'Announcing Vitess 7' +description: 'We are pleased to announce the general availability of Vitess 7. Highlights include replica transactions, savepoint support, and per-session system variables.' --- On behalf of the Vitess maintainers team, I am pleased to announce the general availability of Vitess 7. diff --git a/content/en/blog/2020-10-27-announcing-vitess-8.md b/content/en/blog/2020-10-27-announcing-vitess-8.md new file mode 100644 index 000000000..d7259de52 --- /dev/null +++ b/content/en/blog/2020-10-27-announcing-vitess-8.md @@ -0,0 +1,60 @@ +--- +author: 'Alkin Tezuysal' +date: 2020-10-27 +slug: '2020-10-27-announcing-vitess-8' +tags: ['release'] +title: 'Announcing Vitess 8' +description: 'We are pleased to announce the general availability of Vitess 8. In this release, we have continued to make important improvements to the Vitess project with over 200 PRs in several areas.' +--- +On behalf of the Vitess maintainers team, I am pleased to announce the general availability of [Vitess 8](https://github.com/vitessio/vitess/releases/tag/v8.0.0). + +## Major Themes +In this release, we have continued to make important improvements to the Vitess project with over 200 PRs in several areas. Some of the major bug fixes and changes in behaviors are documented in the [Release Notes](https://github.com/vitessio/vitess/blob/master/doc/releasenotes/8_0_0_release_notes.md). Please read them carefully and report any issues via GitHub. We would like to highlight the following themes for this release. + +### Compatibility (MySQL, frameworks) + +Our ongoing work to make sure that Vitess accepts all queries that MySQL accepts. In particular, work has focused on SET and information_schema queries. Reserved connections are still not on by default, and you might need to enable it to see all queries and frameworks well supported. + +We are proud to announce that we have initial support for: +* PHP + * WordPress + * Mysqli +* JavaScript + * TypeORM + * Sequelize +* Python + * Django + * PyMySQL + * SQLAlchemy +* Ruby + * Rails/ActiveRecord +* Java + * JDBC + * Hibernate +* Rust + * MySQL + * mysql_async + * SQLx +* Tooling + * MySQL Workbench + * Mycli + +### Migration +Performance and error metrics and improved logging related to VReplication workflows have been added for more visibility into operational issues. Additional vtctld commands VExec and Workflow allow easier inspection and manipulation of VReplication streams. + +The VStream API was enhanced to provide more information for integration with change data capture platforms: the Debezium Vitess adapter uses this capability. + +We have incorporated several small feature enhancements and bug-fixes based on the increased traction that VReplication saw both among early adopters and large production setups. + +### Usability +Ease of usability and accessibility are very important for the Vitess community. Usability improvements were another highlight received from the community. + +### Innovation +We continue to add integration of popular open-source tools and utilities on top of the Vitess’s dynamic framework. There are a few of these in this release we would like to highlight. + +* VTorc : Integration of Orchestrator has continued and finally became part of Vitess. This proven open-source tool which has been the de-facto solution for MySQL failover mechanisms is now built into Vitess. Support is experimental in 8.0 and we will continue to harden it in future releases. +* [Online Schema Changes](https://vitess.io/docs/user-guides/schema-changes/): Understanding the ALTER TABLE problem and coming up with a solution using proven tools was our goal to achieve this release. We’re able to integrate both pt-online-schema-change and gh-ost to overcome major limitations for schema migrations. + +There is a shortlist of incompatible changes in this release. We encourage you to spend a moment reading the release notes. + +Please download [Vitess 8](https://github.com/vitessio/vitess/releases/tag/v8.0.0) and try it out! diff --git a/content/en/blog/2020-11-03-streaming-vitess-at-bolt.md b/content/en/blog/2020-11-03-streaming-vitess-at-bolt.md new file mode 100644 index 000000000..f0626fb60 --- /dev/null +++ b/content/en/blog/2020-11-03-streaming-vitess-at-bolt.md @@ -0,0 +1,137 @@ +--- +author: 'Kewei Shang' +date: 2020-11-03 +slug: '2020-11-03-streaming-vitess-at-bolt' +tags: ['Vitess','MySQL','Debezium','Kafka','CDC','Change Data Capture','Apache'] +title: 'Streaming Vitess at Bolt' +--- + + +Previously posted on [link](https://medium.com/bolt-labs/streaming-vitess-at-bolt-f8ea93211c3f) at Nov 3, 2020. + +Traditionally, MySQL has been used to power most of the backend services at Bolt. We've designed our schemas in a way that they're sharded into different MySQL clusters. Each MySQL cluster contains a subset of data and consists of one primary and multiple replication nodes. + +Once data is persisted to the database, we use the [Debezium MySQL Connector](https://debezium.io/documentation/reference/connectors/mysql.html) to [capture data change](https://www.confluent.io/blog/how-bolt-adopted-cdc-with-confluent-for-real-time-data-and-analytics/) events and send them to Kafka. This gives us an easy and reliable way to communicate changes between back-end microservices. + +### Vitess at Bolt +Bolt has grown considerably over the past few years, and so did the volume of data written to MySQL. Manual database sharding has become quite an expensive and long-lasting process prone to errors. So we started to evaluate more scalable databases, one of which is [Vitess](https://vitess.io/). Vitess is an open-source database clustering system that is based on MySQL and provides horizontal scalability for it. Originated and battle-tested at YouTube, it was later open-sourced and is used by companies like Slack, Github, JD.com to power their backend storage. It combines important MySQL features with the scalability of a NoSQL database. + +One of the most important features that Vitess provides is its built-in sharding. It allows the database to grow horizontally by adding new shards in a way that is transparent to back-end application logic. To your application, Vitess appears like a giant single database, but in fact data is partitioned into multiple physical shards behind the scenes. For any table, an arbitrary column can be chosen as the sharding key, and all inserts and updates will be seamlessly directed to a proper shard by Vitess itself. + +Figure 1 below illustrates how back-end services interact with Vitess. At a high level, services connect to stateless VTGate instances through a load balancer. Each VTGate has the Vitess cluster's topology cached in its memory and redirects queries to the correct shards and the correct VTTablet (and its underlying MySQL instance) within the shards. More on VTTablet is written below. + + + +Figure 1. Vitess architecture. Reference: https://www.planetscale.com/vitess + +Other useful features provided by Vitess are: +* Failover (a.k.a. Reparenting) is easy and transparent for clients. Clients only talk to a VTGate who takes care of failover and service discovery of the new primary transparently. +* It automatically rewrites "problematic" queries that could potentially cause database performance degradation. +* It has a caching mechanism that prevents duplicate queries to reach the underlying MySQL database simultaneously. Only one query will reach the database and its result will be cached and returned to answer duplicate queries. +* It has its connection pool and eliminates the high-memory overhead of MySQL connections. As a result, it can easily handle thousands of connections at the same time. +* Connection timeout and transaction timeout can be configured. +* It has minimal downtime when doing [resharding](https://vitess.io/docs/user-guides/configuration-advanced/resharding/) operations. +* Its VStream feature can be used by downstream CDC applications to read change events from Vitess. +### Streaming Vitess Options +The ability to capture data changes and publish them to Apache Kafka was one of the requirements for adopting Vitess at Bolt. There were several different options we've considered. +#### Option 1: Using Debezium MySQL Connector +Applications connect to Vitess VTGate to send queries. VTGate supports the MySQL protocol and has a SQL parser. You can use any MySQL client (e.g. JDBC) to connect to VTGate, which redirects your query to the correct shard and returns the result to your client. + +However, VTGate is not equal to a MySQL instance, it is rather a stateless proxy to various MySQL instances. For the MySQL connector to receive change events, the Debezium MySQL connector needs to connect to a real MySQL instance. To make it more obvious, VTGate also has some known [compatibility](https://vitess.io/docs/reference/compatibility/mysql-compatibility/) issues, which makes connecting to VTGate different from MySQL. + +Another option is to use the Debezium MySQL Connector to connect directly to the underlying MySQL instances of different shards. It has its advantages and disadvantages. + +One advantage is that for an unsharded keyspace (Vitess's terminology for a database), the MySQL Connector can continue to work correctly and we don't need to include additional logic or specific implementation. It should just work fine. + +One of the biggest disadvantages is that resharding operations would become more complex. For example, the GTID of the original MySQL instance would change when resharded, and the MySQL connector depends on the GTID to work correctly. We also believe that having the MySQL connector connected directly to each underlying MySQL instance defies the purpose of Vitess's operational simplicity as a new connector has to be added (or removed) each time resharding is done. Not to mention that such an operation would lead to data duplication inside Kafka brokers. +#### Option 2: Using JDBC Source Connector +We've also considered using the [JDBC Source Connector](https://docs.confluent.io/current/connect/kafka-connect-jdbc/source-connector/index.html). It allows sourcing data from any relational databases that support the JDBC driver into Kafka. Therefore, it is compatible with Vitess VTGate. It has its advantages and disadvantages as well. + +Advantages: +* It is compatible with VTGate. +* It handles Vitess resharding operation better. During resharding operation, reads are simply automatically redirected (by VTGate) to the target shards. It won't generate any duplicates or lose any data. + +Disadvantages: +* It is poll-based, meaning that the connector polls the database for new change events on a defined interval (typically every few seconds). This means that we would have a much higher latency, compared to the Debezium MySQL Connector. +* Its offsets are managed by either the table's incremental primary key or one of the table's timestamp columns. If we use the timestamp column for offset, we'd have to create a secondary-index of the timestamp column for each table. This adds more constraints on our backend services. If we use the incremental primary key, we would miss the change events for row-updates because the primary key is simply not updated. +* The topic name created by the JDBC connector doesn't include the table's schema name. Using the topic.prefix connector configuration would mean that we'll have one connector per schema. At Bolt, we have a large number of schemas, which means we would need to create a large number of JDBC Source Connectors. +* At Bolt, our downstream applications are already set up to use Debezium's data formats and topic naming conventions, we'd need to change our downstream application's decoding logic to the new data formats. +* Row deletes are not captured. +#### Option 3: Using VStream gRPC +VTGate exposes a gRPC service called VStream. It is a server-side streaming service. Any gRPC client can subscribe to the [VStream](https://vitess.io/docs/concepts/vstream/) service to get a continuous stream of change events from the underlying MySQL instances. The change events that VStream emits have similar information to the MySQL binary logs of the underlying MySQL instances. A single VStream can even subscribe to multiple shards for a given keyspace, making it quite a convenient API to build CDC tools. + +Behind the scene, as shown in Figure 2, VStream reads change events from multiple VTTablets - one [VTTablet](https://vitess.io/docs/reference/programs/vttablet/) per shard. Therefore, it doesn't send duplicates from multiple VTTablets for a given shard. Each VTTablet is a proxy to its MySQL instance. A typical topology would include one master VTTablet and its corresponding MySQL instance, and multiple replica VTTablets, each of which is the proxy of its own replica MySQL instance. A VTTablet gets change events from its underlying MySQL instance and sends the change events back to VTGate, which in turn sends the change events back to VStream's gRPC client. + +When subscribing to the VStream service, the client can specify a VGTID and [Tablet Type](https://vitess.io/docs/concepts/tablet/#tablet-types) (e.g. MASTER, REPLICA). The VGTID tells the position from which VStream starts to send change events. Essentially, VGTID includes a list of (keyspace, shard, shard GTID) tuples. The Tablet Type tells which MySQL instance (primary or replica) in each shard do we read change events from. + + + +Figure 2. VStream architecture. Reference: https://vitess.io/docs/concepts/vstream + +Some advantages of using VStream gRPC are: +* It is a simple way to receive change events from Vitess. It is also recommended in Vitess's documentation to use VStream to build CDC processes downstream. +* VTGate hides the complexity of connecting to various source MySQL instances. +* It has low latency since change events are streamed to the client as soon as they happen. +* The change events include not only inserts and updates, but also deletes. +* Probably one of the biggest advantages is that the change events contain the schema of each table. So you don't have to worry about fetching each table's schema in advance (by, for example, parsing DDLs or querying the table's definition). +* The change events have VGTID included, which the CDC process can store and use as the offset from where to restart the CDC process next time. +* Also importantly, VStream is designed to work well with Vitess operations such as Resharding and Moving Tables. + +There are also some disadvantages: +* Although it includes table schemas, some important information is still missing. For example, the Enum and Set column types don't provide all the allowed values yet. This should be fixed in the next major release (Vitess 9) though. +* Since VStream is a gRPC service, we cannot use the Debezium MySQL Connector out-of-the-box. However, it is quite straightforward to implement the gRPC client in other languages. + +All things considered, we've decided to use VStream gRPC to capture change events from Vitess and implement our Vitess Connector based on all the best practices of Debezium. +Vitess Connector Deep Dive and Open Source +After we've decided to implement our Vitess Connector, we started looking into the implementation details of various Debezium source connectors (MySQL, Postgres, SQLServer), to borrow some ideas. Almost all of them are implemented using a common Connector development framework. So it was clear we should develop the Vitess connector on top of it. We are very active users of the MySql Connector and we benefit from it being open-sourced, as it allows us to contribute to it things we were missing ourselves. So we decided we want to give back to the community and open-source the Vitess source connector code-base under the Debezium umbrella. Please feel free to learn more at Debezium Connector Vitess. We welcome and value any contributions. + +At a high level, as you can see below, connector instances are created in Kafka Connect workers. At the time of writing, you have two options to configure the connector to read from Vitess: + +#### Option 1 (recommended): +As shown in Figure 3, each connector captures change events from all shards in a specific keyspace. If the keyspace is not sharded, the connector can still capture change events from the only shard in the keyspace. When it's the first time that the connector starts, it reads from the current VGTID position of all shards in the keyspace. Because it subscribes to all shards, it continuously captures change events from all shards and sends them to Kafka. It automatically supports the Vitess Reshard operation, there is no data loss, nor duplication. + + + +Figure 3. Each connector subscribes to all shards of a specific keyspace + +#### Option 2: +As shown in Figure 4, each connector instance captures change events from a specific keyspace/shard pair. The connector instance gets the initial (the current) VGTID position of the keyspace/shard pair from VTCtld gRPC, which is another Vitess component. Each connector instance, independently, uses the VGTID it gets to subscribe to VStream gRPC and continuously capture change events from VStream and sends them to Kafka. To support the Vitess Reshard operation, you would need more manual operations. + + + +Figure 4. Each connector subscribes to one shard of a specific keyspace + +Internally, each connector task uses a gRPC thread to constantly receive change events from VStream and puts the events into an internal blocking queue. The connector task thread polls events out of the queue and sends them to Kafka, as can be seen in Figure 5. + + + +Figure 5. How each connector task works internally + +### Replication Challenges +While we were implementing the Vitess Connector and digging deeper into Vitess, we've also realized a few challenges. +Vitess Reshard +The Vitess connector supports the Vitess Reshard operation when the connector is configured to subscribe to all shards of a given keyspace. VStream sends a VGTID that contains the shard GTID for all shards. Vitess Resharding is transparent to users. Once it's completed, Vitess will send the VGTID of the new shards. Therefore, the connector will use the new VGTID after reshard. However, you need to make sure that the connector is up and running when the reshard operation takes place. Especially please check that the offset topic of the connector has the new VGTID before deleting the old shards. This is because in case the old shards are deleted, VStream will not be able to recognize the VGTID from the old shards. + +If you decide to subscribe to one shard per connector, the connector does not provide out-of-the-box support for Vitess resharding. One manual workaround to support resharding is creating one new connector per target shard. For example, one new connector for the commerce/-80 shard, and another new connector for the commerce/80- shard. Bear in mind that because they're new connectors, by default, new topics will be created, however, you could use the Debezium logical topic router to route the records to the same kafka topics. +#### Offset Management +VStream includes a VGTID event in its response. We save the VGTID as the offset in the Kafka offset topic, so when the connector restarts, we can start from the saved VGTID. However, in rare cases when a transaction includes a huge amount of rows, VStream batches the change events into multiple responses, and only the last response has the VGTID. In such cases, we don't have the VGTID for every change event we receive. We have a few options to solve this particular issue: + +* We can buffer all the change events in memory and wait for the last response that contains the VGTID to arrive. So all events will have the correct VGTID associated with them. A few disadvantages are that we'll have higher latency before events are sent to Kafka. Also, memory usage could potentially increase quite a lot due to buffering. Buffering also adds complexity to the logic. We also have no control over the number of events VStream sends to us. +* We can use the latest VGTID we have, which is the VGTID from the previous VStream response. If the connector fails and restarts when processing such a big transaction, it'll restart from the VGTID of the previous VStream response, thus reprocessing some events. Therefore, it has at-least-once event delivery semantics and it expects the downstream to be idempotent. Since most transactions are not big enough, most VStream responses will have VGTID in the response, so the chance of having duplicates is low. In the end, we chose this approach for its at-least-once delivery guarantee and its design simplicity. +#### Schema Management +VStream's response also includes a FIELD event. It's a special event that contains the schemas of the tables of which the rows are affected. For example, let's assume we have 2 tables, A and B. If we insert a few rows into table A, the FIELD event will only contain table A's schema. The VStream is smart enough to only include the FIELD event whenever necessary. For example, when a VStream client reconnects, or when a table's schema is changed. + +The older version of VStream includes only the column type (e.p. Integer, Varchar), no additional information such as whether the column is the primary key, whether the column has a default value, Decimal type's scale and precision, Enum type's allowed values, etc. + +The newer version (Vitess 8) of VStream starts to include more information on each column. This will help the connector to deserialize more accurately certain types and have a more precise schema in the change events sent to Kafka. +### Future Development Work +* We can use VStream's API to start streaming from the latest VGTID position, instead of getting the initial VGTID position from VTCtld gRPC. Doing so would eliminate the dependency from VTCtld. +* We don't support automatically extracting the primary keys from the change events yet. Currently, by default, all change events sent to Kafka have null as the key, unless the message.key.columns connector configuration is specified. Vitess recently added flags of each column in the VStream FIELD event, which allows us to implement this feature soon. +* Add support for initial snapshots to capture all existing data before streaming changes. +Summary +MySQL has been used to power most of our backend services at Bolt. Due to the considerable growth of the volume of data and operational complexity, Bolt started to evaluate Vitess for its scalability and its built-in features such as resharding. + +To capture data changes from Vitess, as what we've been doing with Debezium MySQL Connector, we've considered a few options. In the end, we have implemented our own Vitess Connector based on the common Debezium connector framework. While implementing the Vitess connector, we've encountered a few challenges. For example, support for the Vitess reshard operation, offset management, and schema management. We reasoned about ways to address the challenges and what we worked out as solutions. + +We've also received quite some interest from multiple communities in this project and we've decided to open-source [Vitess Connector](https://github.com/debezium/debezium-connector-vitess/) under the Debezium umbrella. Please feel free to learn more, and we welcome and value any contributions. + diff --git a/content/en/blog/2020-11-09-vitess-operator-for-kubernetes.md b/content/en/blog/2020-11-09-vitess-operator-for-kubernetes.md new file mode 100644 index 000000000..5bf6f318e --- /dev/null +++ b/content/en/blog/2020-11-09-vitess-operator-for-kubernetes.md @@ -0,0 +1,480 @@ +--- +author: 'Alkin Tezuysal' +date: 2020-11-09 +slug: '2020-11-09-vitess-operator-for-kubernetes' +tags: ['Vitess','MySQL','kubernetes','operator','cloud','GKE','sharding'] +title: 'Vitess Operator for Kubernetes' + +--- +### Introduction +In this blog, I would like to explore [Vitess Operator for Kubernetes](https://github.com/planetscale/vitess-operator). This post demonstrates the sample implementation of [Vitess](https://vitess.io/) in Kubernetes topology. I also explore common DBA tasks by demonstrating how they are handled in the Vitess ecosystem. Vitess, out of the box, comes with a lot of tools and utilities that one has to either incorporate or develop to manage MySQL topology. Let’s take a look at the capabilities of Vitess in these areas and demonstrate how they are performed under the operator realm. + +#### Prerequisites +* GKE Account +* Kubectl +* MySQL Client +* Install vtctlclient locally + * go get vitess.io/vitess/go/cmd/vtctlclient +* Download the Operator example files + * git clone git@github.com:vitessio/vitess.git +* cd vitess/examples/operator +* Run sample database implementation (Optional). + +#### Install the Vitess Operator +
+$ gcloud container clusters create vitess-k8s-operator --cluster-version 1.14 --zone us-east1-b --enable-autoscaling --min-nodes 8 --max-nodes 12
+Creating cluster vitess-k8s-operator in us-east1-b... Cluster is being health-checked (master is healthy)...done.
+Created [https://container.googleapis.com/v1/projects/planetscale-dev/zones/us-east1-b/clusters/vitess-k8s-operator].
+To inspect the contents of your cluster, go to:
+https://console.cloud.google.com/kubernetes/workload_/gcloud/us-east1-b/vitess-k8s-operator?project=planetscale-dev
+kubeconfig entry generated for vitess-k8s-operator.
+
+NAME LOCATION MASTER_VERSION MASTER_IP MACHINE_TYPE NODE_VERSION NUM_NODES STATUS
+vitess-k8s-operator us-east1-b 1.14.10-gke.50 35.237.26.125 n1-standard-1 1.14.10-gke.50 3 RUNNING
+
+```
+$ cd vitess/examples/operator
+$ kubectl apply -f operator.yaml
+customresourcedefinition.apiextensions.k8s.io/etcdlockservers.planetscale.com created
+customresourcedefinition.apiextensions.k8s.io/vitessbackups.planetscale.com created
+customresourcedefinition.apiextensions.k8s.io/vitessbackupstorages.planetscale.com created
+customresourcedefinition.apiextensions.k8s.io/vitesscells.planetscale.com created
+customresourcedefinition.apiextensions.k8s.io/vitessclusters.planetscale.com created
+customresourcedefinition.apiextensions.k8s.io/vitesskeyspaces.planetscale.com created
+customresourcedefinition.apiextensions.k8s.io/vitessshards.planetscale.com created
+serviceaccount/vitess-operator created
+role.rbac.authorization.k8s.io/vitess-operator created
+rolebinding.rbac.authorization.k8s.io/vitess-operator created
+priorityclass.scheduling.k8s.io/vitess created
+priorityclass.scheduling.k8s.io/vitess-operator-control-plane created
+deployment.apps/vitess-operator created
+
+$ kubectl get pods
+NAME READY STATUS RESTARTS AGE
+vitess-operator-8454d86687-hv9lg 1/1 Running 0 41s
+```
+Bring up an initial test cluster
+```
+$ kubectl apply -f 101_initial_cluster.yaml
+vitesscluster.planetscale.com/example created
+secret/example-cluster-config created
+
+$ kubectl get pods
+NAME READY STATUS RESTARTS AGE
+example-etcd-faf13de3-1 1/1 Running 0 54s
+example-etcd-faf13de3-2 1/1 Running 0 54s
+example-etcd-faf13de3-3 1/1 Running 0 53s
+example-vttablet-zone1-2469782763-bfadd780 3/3 Running 1 54s
+example-vttablet-zone1-2548885007-46a852d0 2/3 Running 1 54s
+example-zone1-vtctld-1d4dcad0-59d8498459-54p68 1/1 Running 1 54s
+example-zone1-vtgate-bc6cde92-6fcfbb6666-5bcjc 1/1 Running 1 53s
+vitess-operator-8454d86687-hv9lg 1/1 Running 0 2m28s
+```
+Setup Port-forward
+```
+$ ./pf.sh &
+[1] 34424
+askdba:operator askdba$ You may point your browser to http://localhost:15000, use the following aliases as shortcuts:
+alias vtctlclient="vtctlclient -server=localhost:15999 -logtostderr"
+alias mysql="mysql -h 127.0.0.1 -P 15306 -u user"
+Hit Ctrl-C to stop the port forwards
+Forwarding from 127.0.0.1:15306 -> 3306
+Forwarding from [::1]:15306 -> 3306
+Forwarding from 127.0.0.1:15000 -> 15000
+Forwarding from [::1]:15000 -> 15000
+Forwarding from 127.0.0.1:15999 -> 15999
+Forwarding from [::1]:15999 -> 15999
+```
+```
+$ vtctlclient ApplySchema -sql="$(cat create_commerce_schema.sql)" commerce
+$ vtctlclient ApplyVSchema -vschema="$(cat vschema_commerce_initial.json)" commerce
+Handling connection for 15999
+New VSchema object:
+{
+ "tables": {
+ "corder": {
+ },
+ "customer": {
+ },
+ "product": {
+ }
+ }
+}
+If this is not what you expected, check the input data (as JSON parsing will skip unexpected fields).
+```
+
+After this section it’s recommended to to continue with the sample [database](https://vitess.io/docs/get-started/local/) steps to have a running database in this cluster(optional).
+### Database Operations
+
+In this section as we’ve mentioned above, I’d like to show how to perform functional operations as follows:
+
+1. Backup & Recovery
+2. Failover to Replica
+3. Schema Change
+
+#### Backup Vitess Tablet
+
+At this stage, our cluster within Kubernetes is up, but backups won’t work until we configure a place to store them.
+First, we will check existing backups and as you can see there are none.
+```$ kubectl get vitessbackups
+No resources found in default namespace.
+```
+In order to perform backups, we need to set up a backup storage bucket in GCS.
+Fill in your own values for all the my-* names. The bucket name in particular must be globally unique across all GCS users.
+Select GCP project
+```
+$ gcloud config set project [project-name]
+Updated property [core/project].
+```
+Create a GCS bucket
+```
+$ gsutil mb -l us-central1 -b on gs://my-vitess-operator-backup-bucket
+Creating gs://my-vitess-operator-backup-bucket/...
+```
+Create a GCP service account
+```
+$ gcloud iam service-accounts create my-backup-service-account
+Created service account [my-backup-service-account].
+```
+Grant the service account access to the bucket gsutil iam ch
+```
+$ gsutil iam ch serviceAccount:my-backup-service-account@planetscale-dev.iam.gserviceaccount.com:objectViewer,objectCreator,objectAdmin \
+gs://my-vitess-operator-backup-bucket
+```
+Create and download a key for the service account
+```
+$ gcloud iam service-accounts keys create ~/gcs_key.json --iam-account my-backup-service-account@planetscale-dev.iam.gserviceaccount.com
+created key [ccd65b5a198298f9ca07ee6ab901a2492ea142c7] of type [json] as [/Users/askdba/gcs_key.json]
+for [my-backup-service-account@planetscale-dev.iam.gserviceaccount.com]
+```
+Upload the service account key as a k8s Secret
+```
+$ kubectl create secret generic gcs-auth --from-file=gcs_key.json="$HOME/gcs_key.json"
+secret/gcs-auth created
+```
+Delete the local copy
+```
+$ rm ~/gcs_key.json
+```
+Check Tablet(s) status
+```
+$ kubectl describe vt | grep 'Tablets'
+ Desired Tablets: 2
+ Ready Tablets: 2
+ Tablets: 2
+ Updated Tablets: 2
+ Desired Tablets: 6
+ Ready Tablets: 6
+ Tablets: 6
+ Updated Tablets: 6
+```
+Note: The numbers will be different if you ran the optional sample database steps.
+At this stage, our cluster still has no association with the GSC bucket. We need to apply the correct backup method (xtrabackup) and bucket definition to the cluster via YAML file.
+
+Add a backup section under spec in each VitessCluster YAML before applying it. Since this is an idempotent operation we can edit and re-apply 101_initial_cluster.yaml file.
+```
+yaml
+spec:
+ backup:
+ engine: xtrabackup
+ locations:
+ - gcs:
+ bucket: my-vitess-backup-bucket
+ authSecret:
+ name: gcs-auth
+ key: gcs_key.json
+```
+```
+$ kubectl apply -f 101_initial_cluster.yaml
+vitesscluster.planetscale.com/example configured
+secret/example-cluster-config configured
+$ kubectl get pods
+NAME READY STATUS RESTARTS AGE
+example-90089e05-vitessbackupstorage-subcontroller 1/1 Running 0 29s
+example-commerce-x-x-vtbackup-init-c6db73c9 0/1 CrashLoopBackOff 1 29s
+example-etcd-faf13de3-1 1/1 Running 0 7m51s
+example-etcd-faf13de3-2 1/1 Running 0 7m51s
+example-etcd-faf13de3-3 1/1 Running 0 7m51s
+example-vttablet-zone1-2469782763-bfadd780 3/3 Running 0 15s
+example-vttablet-zone1-2548885007-46a852d0 3/3 Running 2 7m51s
+example-zone1-vtctld-1d4dcad0-59d8498459-qg4rv 1/1 Running 3 7m51s
+example-zone1-vtgate-bc6cde92-6fcfbb6666-gz6mm 1/1 Running 3 7m50s
+vitess-operator-8454d86687-m225m 1/1 Running 0 8m5s
+```
+
+If we had configured backups in the VitessCluster before the initial deployment, the operator would initialize backup storage automatically. Since we initially started the cluster without backups configured, the automatic backup initialization will fail:
+```
+$ kubectl logs example-commerce-x-x-vtbackup-init-c6db73c9
+ERROR: logging before flag.Parse: E0928 12:08:20.897936 1 syslogger.go:122] can't connect to syslog
+E0928 12:08:21.075860 1 vtbackup.go:177] Can't take backup: refusing to upload initial backup of empty database: the shard commerce/-
+already has at least one tablet that may be serving (zone1-2469782763); you must take a backup from a live tablet instead
+```
+This means we need to take a backup manually to initialize backup storage:
+```
+$ vtctlclient -logtostderr BackupShard commerce/-
+…
+I0928 15:13:29.818114 80158 main.go:64] I0928 12:13:29.492382 backup.go:162] I0928 12:13:29.492048 xtrabackupengine.go:309] xtrabackup stderr: 200928 12:13:29 [00] Streaming
+
+
+
+
+
+ {{ .Title }}
diff --git a/layouts/partials/docs/landing-page.html b/layouts/partials/docs/landing-page.html index b3bf55a93..65f65ad48 100644 --- a/layouts/partials/docs/landing-page.html +++ b/layouts/partials/docs/landing-page.html @@ -1,10 +1,6 @@