16 ms·
GitHub's online schema migration for MySQL
- pkulak 8y agoHoly crap, an alternative to Percona? Why does MySQL get two awesome tools and Postgres nothing?
- Scarbutt 8y agomysql is a bigger target market.
- timewarrior 8y agoWe recently started investing in Postgres because of support of JSON fields and nested indexes in those fields. Should we have chosen MySQL?
- deleted 8y ago[deleted]
- lathiat 8y agoMySQL has I think all of these features now in 8.0 off the top of my head. Having said that it was only just released to stable very recently and like all good things it may pay to wait for a few more edge cases to be flexed out. Ultimately I’d always suggest the tool you are most familiar with if it’s doing a good enough job.
- sethhochberg 8y agoThey both have their issues (though I think in most cases Postgres has saner defaults. Alternative distributions of MySQL like Percona Server can help improve the situation somewhat for MySQL). Doing anything meaningfully complex or mission-critical with either will always require care, attention, and understanding of how the database is doing its work. If you know MySQL internals particularly better, it may benefit you to focus your efforts there as modern MySQL is perfectly capable (decent online DDL support, decent native JSON support, etc). If your team aren't experts with either, I'd invest my effort in learning Postgres.
- timewarrior 8y agoI have extensive experience with MySQL. In fact I used to run a really big social network (70M+ users) based on MySQL db. Main reason we chose Postgres was that JSON fields have been around for a few years. We really like the Mongo feature-set, but aren't very happy with reliability. In every discussion about Mongo, people used to recommend Postgres instead.
- toomanybeersies 8y agoI'm currently working on a product that uses JSONb columns extensively. To be honest, I don't like it. I'm not sure if it's bad design, or if it's just bad to mix relational databases with JSON, but I'm constantly battling to do things that I would find trivial in SQL. I guess it really depends on your requirements though. I've found that JSONb is great for storing historical data and results, write-once sort of stuff. I've found it's not so good for storing objects that get modified, especially if a relation can change.
- codedokode 8y agoAlso you cannot store foreign keys in JSON.
- timewarrior 8y agoIf I want to use it as a write only table where I would like to get virtual indexes for values inside the JSONb column. Would you recommend using Postgres for this usecase?
- guiriduro 8y agoThis discussion might be useful re: indexing JSONb columns and a comparison of performance (a bit out of date, things have probably improved even further); http://bitnine.net/blog-postgresql/postgresql-internals-jsonb-type-and-its-indexes http://bitnine.net/blog-postgresql/postgresql-internals-json... The GIN index is an inverted index, if you're expecting to query against several keys; alternatively if you have a large keyspace and no need to query outside a small number of properties, you could create individual hash or btree indexes for each one. Postgres is good for this usecase, but as always, YMMV, consider alternatives/optimizations if your scale or write-volume dictate otherwise (e.g. sharding, Citusdb etc.)
- emilsedgh 8y agoProbably no. As someone else pointed out, the reason so many similar tools exist for this task on mysql and there's no such tool for postgres is not that postgres isn't as popular. The reason is that this problem is almost non-existent on postgres as many table alterations do not lock the table.
- idunno246 8y agoAll alters require a full read/write lock, it’s just that most return instantly. This can be a problem if you have long running transactions, as the alter blocks behind all open txns and all new queries block behind that. python for instance has a very strong opinion that you should be using transactions for everything, and is much more likely to have to deal with it than say ruby. But you’re right, my comment is mostly pedantic, that Postgres implements alters better so these tools aren’t needed.
- timewarrior 8y agoThis is great to know. I usually am able to manage without transactions. So alerts should be pretty fast.
- paulryanrogers 8y agoThere are some techniques for mitigating those, such as adding new columns as nullable without a default.
- idunno246 8y agoRight, adding a column with a default means the alter takes time while holding that lock and nothing can be read/written so is generally unsafe for big tables, but it doesn’t help if the alter can’t acquire the lock in the first place
- meritt 8y agofwiw, MySQL has supported JSON [1] and also allows nested indexes via functional/virtual indexes [2] since v5.7.8 (August 2015) 1. https://dev.mysql.com/doc/refman/5.7/en/json.html https://dev.mysql.com/doc/refman/5.7/en/json.html 2. https://dev.mysql.com/doc/refman/5.7/en/create-table-secondary-indexes.html#json-column-indirect-index https://dev.mysql.com/doc/refman/5.7/en/create-table-seconda...
- sethhochberg 8y agoThere are several other notable options - SoundCloud's LHM, Facebook's online schema change tool, etc. They all have their different quirks. (And as modern MySQL releases get better online DDL support, become less and less critical - though still useful for all of those edge cases where native lockless online DDLs can't work yet)
- josegonzalez 8y agoPostgres supports transactional DDL statements natively, and many alter table statements don't end up locking the table nearly as severely as some MySQL versions do.
- michaeldejong 8y agoActually both lock for many (crucial) schema operators, and often severely enough to block your application from reading from the table(s) under change. I've been researching this stuff for a while. Check out http://blog.minicom.nl/blog/2015/04/03/revisiting-profiling-ddl-statements-mysqls-return/ http://blog.minicom.nl/blog/2015/04/03/revisiting-profiling-... . It's slightly outdated, but still holds.
- fipar 8y agoThat is true, but I wanted to share another angle that may or may not affect PostgreSQL while it continues to affect MySQL even as it has crash-safe (though not transactional) DDL now: these schema changes are online for the master, but are not replication-aware and can have impact in replication delay on servers down the hierarchy. For this reason alone I think we'll continue to use schema-change tools on MySQL even if the server itself becomes better at those. In the specific case of gh-ost, another good point is that migrations can be completely paused, which in MySQL is not true of online DDL.
- michaeldejong 8y agoI felt the same way, so I've been working on QuantumDB for the last couple of years. Take a look at https://quantumdb.io https://quantumdb.io . QuantumDB doesn't use the binlog / WAL log like gh-ost does, but it does support foreign key constraints, and it allows you to perform several schema operations in one go without having to deal with the intermediates. It's still not ready for production, but feel free to try it out. Feedback is welcome!
- viraptor 8y agoI used it and it's really impressive. Works as described. The only issue with this is that you can't easily use it without understanding how it works. It's more of a system you have to own rather than a tool you can use, so you can't just point a new person at it and go "just run this".
- groodt 8y agoI agree. I've used it a lot too, but only after a few test runs against some snapshots to get familiar with the operational aspects of it.
- qaq 8y agoYou can jump through hoops or just use an RDBMS that supports transactional DDL.
- dtech 8y agoThat does not solve the problem. Transactional DDL still needs a full table lock for most operations, which on large tables can take minutes to hours. Then it's not really an online schema migration anymore.
- c2h5oh 8y agoDepends on a migration. Postgres can add / drop a column to a table with a billion rows in milliseconds as long as you don't provide a default value for the new column.
- anarazel 8y agoAnd in v11, even if there's a default column!
- viraptor 8y agoAlso, even if the lock is not used, when you're changing an indexed column, you need to rebuild that index. In most production environments you just can't say "we're going to serve all the traffic without this index for a few hours" - that would kill the service (or a part of it if you're lucky and can disable it)
- manigandham 8y ago...so don't make use of the new indexed column until it's ready, why is that an issue? It's no different than waiting for Ghost to finish copying a table for DDL.
- rimliu 8y agoI think this is answered in the second sentence.
- ceohockey60 8y agoVery cool! Curious, does this leverage this go-mysql library at all? https://github.com/siddontang/go-mysql https://github.com/siddontang/go-mysql
- tejasmanohar 8y agoYes, https://github.com/github/gh-ost/search?utf8=%E2%9C%93&q=go-mysql&type= https://github.com/github/gh-ost/search?utf8=%E2%9C%93&q=go-...
- magoon 8y agoI believe RDS uses this same technique for instance resize/replace.
- throwawaypls 8y agoBack when I worked for Shopify, I got a chance to work on something similar -- GhostFerry(https://github.com/shopify/ghostferry https://github.com/shopify/ghostferry), which allows for doing all sorts of migrations, that too between various databases. It was recently open-sourced. Do take a look.
- pwnna 8y agoHey! I'm the current maintainer of Ghostferry. Thank you for all your work! For the reader here: one thing to clarify here is that gh-ost performs schema migration via a data migration between two different tables and it does it via a very efficient way. Ghostferry on the other hand is general purpose data migration library that moves data between different databases, most likely different hosts. Frequently, both schema migration and data migrations are abbreviated as migrations and thus may cause some confusion. The domain of operation of Ghostferry do not necessarily overlap with gh-ost, as it would be very inefficient to use Ghostferry to implement gh-ost. That said it is a very interesting project on its own as it has a lot of potential use cases. I don't want to hijack the thread any further than I already have so if anyone has any further questions, you can contact information and docs in the repo.
- AdamJacobMuller 8y agoThis is a really amazing, very well designed and thought out, tool that solves a problem that should never exist.
- analogmemory 8y agoSo my understanding is that this is for migrating a db to a new one? Can someone explain like I was beginner why/how'd you would use this?
- jschmitz28 8y agoIn certain scenarios if you need to modify the schema for a table in MySQL it will lead to the entire table being locked, and for large tables this could lead to a noticeable outage for users if you need to run queries on that table. One case I had where we faced this problem was changing the primary key for a table from 32 bit to 64 bit ints since we were running out of space. We used Percona's online schema change tool for handling this, which wrapped the creation of a new 'ghost' table (which has the target schema you want), rate limited writes from original table to ghost table, triggered writes from original table to ghost table as new writes came in, and finally a table rename from the ghost table back to the original table name in order to perform the full migration with no data loss or outage. Sounds like this tool is doing something similar but avoiding the use of triggers for flexibility.
- analogmemory 8y agoAh ok! This sound like a great tool then. I have no need for it, but good one to star for a day when I might need it :)
- toomanybeersies 8y agoWe had to do something similar at my old job, but rather than migrating to a different schema, we were migrating our moderately sized DB (tens of gigabytes) from MySQL to Postgres. We dual wrote to both DBs while we copied the existing data to the new DB, then switched them over. I think we had less than 5 minutes of downtime all up.
- y4mi 8y agotens of GB is tiny though. most production systems are at least a few hundred gb, and the previously mentioned scaling problems from foreign keys and constraints are pretty nonexistent unless you're starting to push the boundaries of normal ACID DBs. i.e. a few TB of data with at least thousands of queries per second and lots of writes/updates
- perlgeek 8y agoWe evaluated gh-ost, but the killer for us is that it doesn't support any kind of foreign keys. I understand that at GitHub's scale, foreign keys might be more of a hassle than what they are worth, but for a smallish company that values data integrity over scale and uptime, this is not an acceptable choice.
- pwnna 8y agoThis is an unfortunate by product due to the way that gh-ost is implemented. It is simply not possible to run it with a FK constraint. The reason is that since it replays the binlogs on the ghost table while the ghost table is not fully populated, the FK constraint will cause some of statements to fail. The data move from the original to the ghost table cannot be completed.
- codedokode 8y agoCannot it add FK constraints after the ghost table is fully populated?
- perlgeek 8y agoThe problem is that adding FK constraints is another schema change, which causes MySQL to copy the whole table, and lock the table during this time -- which is precisely what gh-ost tries to avoid. Worse, foreign keys from other tables to the one that is being changed would need to be updated as well, blocking those tables in turn.
- zmoazeni 8y ago> which causes MySQL to copy the whole table This is wrong on a couple levels. First it doesn't copy the whole table: https://dev.mysql.com/doc/refman/5.6/en/innodb-create-index-overview.html https://dev.mysql.com/doc/refman/5.6/en/innodb-create-index-... However, it can take a while if MySQL is evaluating the consistency. But you can disable that with `SET FOREIGN_KEY_CHECKS = 0` which turns it into a metadata change (nearly instantaneous). You still will need to check for violations, but you can do that in a more friendly-to-load manner, and of course will need to deal with any violations manually. But that strategy is a good middle ground to all-or-nothing FKs. Edit: Whoops, looks like I was wrong on the table-copy part. Per "Otherwise, only the COPY algorithm is supported." So it does copy the data when `FOREIGN_KEY_CHECKS=1` (the default)
- Existenceblinks 8y agoThat's really old and still good strategy. [off-topic] I've heard this first time from a novel (1964). Flynn.io uses the same kind of strategy; transaction log && async replication (https://flynn.io/docs/databases https://flynn.io/docs/databases) A little sad nanobox.io which one of my app running on has an inferior strategy; temporarily offline at the last sync moment (https://docs.nanobox.io/data-management/data-migrations-scaling/ https://docs.nanobox.io/data-management/data-migrations-scal...)
- MichaelGlass 8y agoAt NoRedInk, We've been using gh-ost for a few years now, and it's been a pleasure. - The ability to control a running migration is crucial. We have pretty predictable load, and we generally run long-running migrations during off-peak hours. If a migration runs longer than we were expecting and might run into peak hours, we can pause the migration and have the migration not impact users. - hooks make it trivial to integrate with other tools. Right now it reports to slack, but if we used it more, we'd likely hook it up to real monitoring infrastructure. - there's a lot of default behavior that we want. I'd recommend regular users wrap their best practices in another script and not call gh-ost directly. It's nice to not worry about good defaults for e.g. throttling, or worrying about whether ghost is hooked up to some kind of external monitoring.
- killbrad 8y agoI'm probably really ignorant asking this, but how do you "pause" schema migrations period. And even if you did, how do you ensure a consistent experience for your users if your db is broken? Some sort of application logic to deal with inconsistencies? That seems really expensive (from a development work perspective).
- radicality 8y agoNot OP but I’m familiar with the topic and run similar tooling on large clusters. By pause he probably means prevent it from starting on more databases and let whatever is inflight finish. For the second point, correct, your application needs to handle both schemas during transition. When that’s done, you can rip out the unneeded logic from your application.
- xenomachina 8y ago> your application needs to handle both schemas during transition. How is this typically done? Have a version number in the db? Have the app examine the schema with every transaction? Have the app assume old/new schema optimistically, and if that fails rollback and try with alt schema? Something else?
- 8y ago
- z3t4 8y agoI was investigating using the binary log for another project a few years ago, but came to the conclusion that it's too hard to work with ... I don't remember any details though, maybe someone can fill me in ?
- kd22 8y agoCan someone shed some light on how this tool compares to something like Flyway?
- bpicolo 8y agoIt's an alternative to e.g. pt-online-schema-change [0]. The problem is that, for very large mysql tables / clusters, running DDL against the tables live will lock up reads/writes against the table for ages. These tools allow you to run those changes without taking downtime. https://www.percona.com/doc/percona-toolkit/LATEST/pt-online-schema-change.html https://www.percona.com/doc/percona-toolkit/LATEST/pt-online...
- thathoo 8y agoSquare also its online schema migration tool that is open source here: https://github.com/square/shift https://github.com/square/shift Its pretty cool. Check it out as well.
- sciurus 8y agoThat's not a schema migration tool per-se. It's a web interface for managing running a schema migration tool (in their case the venerable pt-osc, but there is an open issue for supporting gh-ost too).
- zmoazeni 8y agoWe use gh-ost at Harvest[1] and it's a dream in comparison to manually migrating on a replica and switching master/slave roles [2]. Also the linked post[3] in the readme hit us very close to home. We originally tried some of our migrations with pt-online-schema-change, which was great in theory but caused a lot of locking contention during the actual process. I see many people hammering on the lack of foreign key support which is interesting to me. At some point, a database system grows to where relying on MySQL's Online DDL[4] "works" but not really with production load. I feel like a team knows when they need to bring in a tool like this. The dev in me understands how wonderful FKs are for consistency. But the db-guy in me that has had to deal with locking issues recognizes FKs as a tradeoff, not dogma. If you shy away from migrating your large or busy tables, or are scheduling frequent maintenance down times in order to migrate these tables, that's when gh-ost (and others) are appropriate to evaluate. So for us it's not an immediate red flag that gh-ost doesn't support FKs. We just have to work around that limitation[5] because the alternatives are much worse. For the record, we don't gh-ost all of our migrations. Only the ones that are deemed sufficiently large enough are gh-osted and those heuristics will change from team-to-team. But as a guy who has had to deal with our database issues AND as a developer who doesn't want to be chained by a database design decision from a decade ago, I love the flexibility gh-ost gives us as we continue to grow. [1] https://www.getharvest.com/ https://www.getharvest.com/ [2] https://dev.mysql.com/doc/refman/5.6/en/replication-features-differing-tables.html https://dev.mysql.com/doc/refman/5.6/en/replication-features... [3] https://dev.mysql.com/doc/refman/5.6/en/replication-features-differing-tables.html https://dev.mysql.com/doc/refman/5.6/en/replication-features... [4] https://dev.mysql.com/doc/refman/5.6/en/innodb-create-index-overview.html https://dev.mysql.com/doc/refman/5.6/en/innodb-create-index-... [5] https://github.com/github/gh-ost/issues/507#issuecomment-338725563 https://github.com/github/gh-ost/issues/507#issuecomment-338...