<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-5448983346854381269</id><updated>2012-02-16T00:48:37.245-08:00</updated><category term='mysql'/><title type='text'>Luís Soares</title><subtitle type='html'>Thoughts on Dependable Distributed Systems...</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://d2-systems.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5448983346854381269/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://d2-systems.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Luís Soares</name><uri>http://www.blogger.com/profile/15801959795245235917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>8</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-5448983346854381269.post-5108707105152195760</id><published>2011-10-05T12:28:00.001-07:00</published><updated>2011-10-05T17:05:40.393-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mysql'/><title type='text'>Global Transaction Identifiers Feature Preview</title><content type='html'>&lt;span style="font-weight: bold;"&gt;The Case for Global Transaction Identifiers&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;"Global Transaction Identifiers" is a feature that has been requested every now and then. And it is not so much about what it actually is, but rather about what it enables MySQL users to do. Having a logical identifier associated with each transaction instead of a physical one (filename + offset), provides more flexibility and removes the burden of complex math from userland scripts. We have put out there an early access release (based on 5.6 codebase) of our ongoing effort to implement the global transaction identifiers and we would like some early feedback. Keep in mind that this is NOT something to use in production as it is in very early development stages. That said...&lt;br /&gt;&lt;br /&gt;What exactly is a global transaction identifier?&lt;br /&gt;&lt;br /&gt;A global identifier is a tag that pin-points a set of changes resulting from the execution of a transaction.&lt;br /&gt;&lt;br /&gt;Why do we need global transaction identifiers?&lt;br /&gt;&lt;br /&gt;If every transaction has its own universally unique identifier, it becomes a lot easier to follow changes through a complex replication stream. It is easier for us, humans, to visualize and understand what is going on, consequently, the algorithms we write for dealing with binary logs and replication tend to be far less convoluted.&lt;br /&gt;&lt;br /&gt;In practice, what are the benefits of this all?&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Fail-over: automation of fail-over suddenly becomes a lot easier. Instead of working through the physical coordinates to decide which slave is most up to date, with respect to the master it is going to replace, one can just compare global transaction identifiers of the last applied transactions. Slave promotion gets easier. However, the major benefit comes when switching over the slaves to the new master. They can reference a global transaction identifier and not have to convert binary log filenames and offsets between different servers.&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;Session consistency and Hierarchical replication: Offloading the master, through some hierarchical replication scheme, often works very well, especially if tied together with an intelligent load-balancer. Sometimes the load balancer sends read queries to a slave down in the hierarchy chain and at the same time it has to be sure that session consistency is guaranteed (updates on the master must have already been applied on the slave being queried). Making sure that the update has flowed all the way down to the desired slave without global transaction identifiers is laborious (one needs to climb down the hierarchy and follow the changes on every level in the hierarchy). On the other hand, with global transaction identifiers, one can just wait for the transaction with the desired identifier to be applied on a given slave and then run the query.&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;Enabler for multi-master update everywhere replication: This is a complex problem to solve, but the fact that transactions can be uniquely identified and distinguished from one another lays the ground for establishing (at least partial) order between them. This property is often important in such replication setups (even for dealing with conflict detection).&lt;/li&gt;&lt;/ul&gt;I am sure that there are more benefits, and that there is a whole bunch of interesting things one can do on top of global transaction identifiers... But I'll leave it up to you to think and decide how that would be useful in your own setup.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Designing a Global Transaction Identifier&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The replication team has been working on several nice features that you must have noticed before (multi-threaded slave, row-based replication enhancements, ...). But now, we are adding global transaction identifiers to the list.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; font-style: italic;"&gt;Global Transaction Identifier&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The goal of this task is to augment MySQL binary log with Global Transaction Identifiers. Thus each transaction has an associated global identifier (GTID), which is essentially a pair:&lt;br /&gt;&lt;br /&gt;GTID = &amp;lt;SID, GNO&amp;gt;&lt;br /&gt;&lt;br /&gt;In practice a transaction is logged as a group of events in the binary log. Thus sometimes we refer to groups instead of transactions - I ended up use them intermixed in the text below. Actually, there are a few details about this, but to avoid risking excessive and unnecessary complexity in what I will describe below, I will just omit those.&lt;br /&gt;&lt;br /&gt;The following describes more clearly each part of an GTID.&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;SID =&amp;gt; currently it is a 128-bit number that identifies the server where the transaction/group of events was first committed. SID is normally the server UUID, but may be something different if a transaction is generated by something else other than than a regular MySQL Server. For example, for NDB, it identifies the Cluster.&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;GNO =&amp;gt; is a 64-bit sequence number: 1 for the first changes logged on SID, 2 for the second changes, and so on. No change can have GNO 0.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-weight: bold; font-style: italic;"&gt;Indexes and Relaying Transactions in the Replication Stream&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In a typical MySQL replication setup there is one master server and a set of slave servers retrieving the changes from that one master and replaying those changes locally, against their own databases. Thus, GTIDs are added to transaction on the originating server - the master. As such, the following major changes have to be done on the originating side:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Annotate existing binary log events with the GTID that they belong to... or create a new type of event that stores a GTID associated with a set of subsequent events in the replication stream.&lt;/li&gt;&lt;li&gt;Create an index to quickly find out which are the physical coordinates that map into the logical identifiers, ie, the GTID. This makes looking up for which binary log file and at which offset a transaction is in, given a certain GTID, very easy and quick. It is especially useful for a dump thread, when it starts, to quickly find the physical position from which it should start reading and sending events to the slave.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;      In practice, this index, that maps GTIDs to binary log positions, has the form of a set of files, each file containing a sequence of transaction specifications. Each transaction specification has, among other fields, the following ones:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;SID: The unique source identifier for this group of events/transaction.&lt;/li&gt;&lt;li&gt;GNO: the sequence number of the group of events/transaction.&lt;/li&gt;&lt;li&gt;LGID: This a local identifier like an auto-increment primary.&lt;/li&gt;&lt;li&gt;binlog file: name of binary log where this group is stored.&lt;/li&gt;&lt;li&gt;binlog pos: offset in binary log where this group starts.&lt;/li&gt;&lt;li&gt;binlog length: length of this group in binary log.&lt;/li&gt;&lt;li&gt;group end: true if this is the last set of events with GTID.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;When a transaction commits, the master generates a GTID and atomically writes it to the binary log along with the events of that transaction. After that the in-memory group index data structures are updated. However, this data is asynchronously flushed to the index file. This requires that on server restart the recovery routine is extended so that it also runs a procedure to make sure that the index is properly setup and consistent.&lt;span style="font-style: italic;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Slaves relay changes from the master. This means that transactions that are replayed by a slave thread will keep the original GTID. Furthermore, slaves also maintain indexes to keep track of their relay logs, and its content is also flushed asynchronously. As in the master, on slave restart, a recovery routine is run to make sure that the indexes are consistent.&lt;br /&gt;&lt;br /&gt;The current snapshot does not yet relay GTIDs through the replication protocol, so we do not get to see the identifiers flowing all the way to the slave. But we can inspect the master binary log and have a look at the identifiers...&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Early Access: Exercising the Labs Snapshot.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;We have uploaded a snapshot of our current work, to labs, which you can try out. It's buggy and it's incomplete, but it lays the ground to what we will be delivering in the future. So... how can we show off a bit of what we have done? Currently, we can issue a set of commands on the master and look into the resulting binary log to search for information regarding the new transaction identifiers. For instance, issuing the following commands on a server with binary log enabled:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;shell&amp;gt; SET AUTOCOMMIT=0;&lt;br /&gt;shell&amp;gt; CREATE TABLE t1 (a INT) Engine=InnoDB;&lt;br /&gt;shell&amp;gt; INSERT INTO t1 VALUES (1);&lt;br /&gt;shell&amp;gt; INSERT INTO t1 VALUES (2);&lt;br /&gt;shell&amp;gt; INSERT INTO t1 VALUES (3);&lt;br /&gt;shell&amp;gt; COMMIT;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Will get you an output very similar to the following one, when inspecting the binary log with the mysqlbinlog tool:&lt;br /&gt;&lt;pre&gt;$ mysqlbinlog -v var/mysqld.1/data/master-bin.000001&lt;br /&gt;&lt;br /&gt;(...)&lt;br /&gt;&lt;br /&gt;# at 114&lt;br /&gt;# Subgroup(#1, D5375118-EF7C-11E0-8C85-F0DEF11A08B7:1, END, COMMIT, binlog(no=0, pos=114, len=107, oals=0))&lt;br /&gt;SET UGID_NEXT='D5375118-EF7C-11E0-8C85-F0DEF11A08B7:1', UGID_END=1, UGID_COMMIT=1/*!*/;&lt;br /&gt;#111005 11:08:04 server id 1  end_log_pos 221     Query    thread_id=1    exec_time=0    error_code=0&lt;br /&gt;use test/*!*/;&lt;br /&gt;SET TIMESTAMP=1317838084/*!*/;&lt;br /&gt;SET @@session.pseudo_thread_id=1/*!*/;&lt;br /&gt;SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/;&lt;br /&gt;SET @@session.sql_mode=0/*!*/;&lt;br /&gt;SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;&lt;br /&gt;/*!\C utf8 *//*!*/;&lt;br /&gt;SET @@session.character_set_client=33,@@session.collation_connection=33,@@session.collation_server=8/*!*/;&lt;br /&gt;SET @@session.lc_time_names=0/*!*/;&lt;br /&gt;SET @@session.collation_database=DEFAULT/*!*/;&lt;br /&gt;CREATE TABLE t1 (a int) Engine=InnoDB&lt;br /&gt;/*!*/;&lt;br /&gt;# at 221&lt;br /&gt;# Subgroup(#2, D5375118-EF7C-11E0-8C85-F0DEF11A08B7:2, END, COMMIT, binlog(no=0, pos=221, len=387, oals=27))&lt;br /&gt;SET UGID_NEXT='D5375118-EF7C-11E0-8C85-F0DEF11A08B7:2', UGID_END=0, UGID_COMMIT=0/*!*/;&lt;br /&gt;#111005 11:08:10 server id 1  end_log_pos 296     Query    thread_id=1    exec_time=0    error_code=0&lt;br /&gt;SET TIMESTAMP=1317838090/*!*/;&lt;br /&gt;BEGIN&lt;br /&gt;/*!*/;&lt;br /&gt;# at 296&lt;br /&gt;#111005 11:08:10 server id 1  end_log_pos 391     Query    thread_id=1    exec_time=0    error_code=0&lt;br /&gt;SET TIMESTAMP=1317838090/*!*/;&lt;br /&gt;INSERT INTO t1 VALUES (1)&lt;br /&gt;/*!*/;&lt;br /&gt;# at 391&lt;br /&gt;#111005 11:08:13 server id 1  end_log_pos 486     Query    thread_id=1    exec_time=0    error_code=0&lt;br /&gt;SET TIMESTAMP=1317838093/*!*/;&lt;br /&gt;INSERT INTO t1 VALUES (2)&lt;br /&gt;/*!*/;&lt;br /&gt;# at 486&lt;br /&gt;# Subgroup(#2, D5375118-EF7C-11E0-8C85-F0DEF11A08B7:2, END, COMMIT, binlog(no=0, pos=221, len=387, oals=27))&lt;br /&gt;SET UGID_END=1, UGID_COMMIT=1/*!*/;&lt;br /&gt;#111005 11:08:16 server id 1  end_log_pos 581     Query    thread_id=1    exec_time=0    error_code=0&lt;br /&gt;SET TIMESTAMP=1317838096/*!*/;&lt;br /&gt;INSERT INTO t1 VALUES (3)&lt;br /&gt;/*!*/;&lt;br /&gt;# at 581&lt;br /&gt;#111005 11:08:18 server id 1  end_log_pos 608     Xid = 11&lt;br /&gt;COMMIT/*!*/;&lt;br /&gt;SET UGID_NEXT='AUTOMATIC'/*!*/;&lt;br /&gt;DELIMITER ;&lt;br /&gt;# End of log file&lt;br /&gt;ROLLBACK /* added by mysqlbinlog */;&lt;br /&gt;/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;In the output above one can find an additional line of metadata related to global transaction identifiers and a few new variables related to GTIDs. For now, lets just concentrate in finding the global transaction identifier. Looking at the line starting with "#Subgroup", one can find and '&amp;lt;UUID&amp;gt;:1' and '&amp;lt;UUID&amp;gt;:2'. These relate to the two transactional groups, the one that consists only of the DDL 'CREATE TABLE...' and the second group is the one that consists of the set of 'INSERT INTO...' statements that comprise the explicit transaction issued.&lt;br /&gt;&lt;br /&gt;Now... we can filter out one of the transactions just by issuing (lets skip the create table):&lt;br /&gt;&lt;pre&gt;$ mysqlbinlog -v --exclude-ugids=D5375118-EF7C-11E0-8C85-F0DEF11A08B7:1 var/mysqld.1/data/master-bin.000001&lt;br /&gt;(...)&lt;br /&gt;&lt;/pre&gt;Or we could even not print identifiers at all:&lt;br /&gt;&lt;pre&gt;$ mysqlbinlog -v --skip-ugids var/mysqld.1/data/master-bin.000001&lt;br /&gt;(...)&lt;br /&gt;&lt;/pre&gt;There are a couple of more switches implemented in the mysqlbinlog tool that are useful to handle contents on the binary log, based on the global transaction identifier. But I'll leave it up to you to check that out.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Summary&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This post provides some insights on the work the replication team is doing on designing and implementing global transaction ids. It gives a general overview of what the problem is and roughly what the solution is and how it is trying to solve a long standing requirement such as easier fail-over.&lt;br /&gt;&lt;br /&gt;The good news are that we are not just designing anymore, we are already implementing it and you can even get a &lt;a href="http://labs.mysql.com"&gt;recent snapshot of this feature branch&lt;/a&gt;. Go... download it, look at the code, build the branch (or download a binary one), play a little bit with it. In the current implementation, global transaction ids are not yet part of the replication protocol, but you can see them by inspecting the master binary log, using mysqlbinlog tool.&lt;br /&gt;&lt;br /&gt;Enjoy!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5448983346854381269-5108707105152195760?l=d2-systems.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://d2-systems.blogspot.com/feeds/5108707105152195760/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://d2-systems.blogspot.com/2011/10/global-transaction-identifiers-feature.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5448983346854381269/posts/default/5108707105152195760'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5448983346854381269/posts/default/5108707105152195760'/><link rel='alternate' type='text/html' href='http://d2-systems.blogspot.com/2011/10/global-transaction-identifiers-feature.html' title='Global Transaction Identifiers Feature Preview'/><author><name>Luís Soares</name><uri>http://www.blogger.com/profile/15801959795245235917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5448983346854381269.post-8730599415257052998</id><published>2011-10-04T15:25:00.000-07:00</published><updated>2011-10-04T15:32:45.624-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mysql'/><title type='text'>Multi-threaded slave: it's in!</title><content type='html'>I am very happy to share with you all that the much awaited feature request - multi-threaded slave (MTS) - has made it to the development tree targeting 5.6 release and is part of this latest 5.6 DMR release (&lt;a href="http://blogs.oracle.com/MySQL/entry/new_development_milestone_releases_certifications"&gt;5.6 DMR2&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;I would like to take a moment to thank those of you that took the time to evaluate and provide invaluable feedback. Some started as early as the very first snapshot that was put out in the open. Part of this feedback is directly responsible for many changes, as outlined in my previous posts about MTS. Since the last snapshot, we kept on taking your suggestions seriously and improved the implementation by deploying a few of them in time for this release. Again, thanks!&lt;br /&gt;&lt;br /&gt;What comes next for MTS? Well, it will continue to be debugged and get its overall quality improved.&lt;br /&gt;&lt;br /&gt;What comes next for MySQL replication? You already know that we are working on the &lt;a href="http://mysqlmusings.blogspot.com/2011/07/binlog-group-commit-experiments.html"&gt;binlog group commit&lt;/a&gt; (by the way, you can get a hold of the second labs snapshot for that one). But, wait, there's more! We are also spending time and effort to implement another much awaited feature: Global Transaction Ids. I think you'll enjoy that one very much (there is also a very early access labs snapshot that you can check out - I'll blog about the details later on...).&lt;br /&gt;&lt;br /&gt;Lots of interesting stuff going on. Stay tuned!&lt;br /&gt;&lt;br /&gt;In the meantime, you can download &lt;a href="http://dev.mysql.com/downloads/mysql/5.6.html"&gt;5.6 DMR2 &lt;/a&gt;and check out our &lt;a href="http://labs.mysql.com/"&gt;labs releases&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5448983346854381269-8730599415257052998?l=d2-systems.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://d2-systems.blogspot.com/feeds/8730599415257052998/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://d2-systems.blogspot.com/2011/10/multi-threaded-slave-its-in.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5448983346854381269/posts/default/8730599415257052998'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5448983346854381269/posts/default/8730599415257052998'/><link rel='alternate' type='text/html' href='http://d2-systems.blogspot.com/2011/10/multi-threaded-slave-its-in.html' title='Multi-threaded slave: it&apos;s in!'/><author><name>Luís Soares</name><uri>http://www.blogger.com/profile/15801959795245235917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5448983346854381269.post-5292884922352237011</id><published>2011-07-28T03:38:00.000-07:00</published><updated>2011-07-28T03:42:07.897-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mysql'/><title type='text'>Update on the Multi-threaded Slave</title><content type='html'>A few months have passed since we &lt;a href="http://d2-systems.blogspot.com/2011/04/mysql-56x-feature-preview-multi.html"&gt;announced our MySQL 5.6.2 DM based feature preview - Multi-threaded Slaves (MTS) - back in April&lt;/a&gt;. Since then, we have had some very good feedback from all around. You deserve a big thank you.&lt;br /&gt;&lt;br /&gt;We have now a new snapshot available on labs.mysql.com. This snapshot includes:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Bug fixes. A lot of them, both in the server core and in the replication layer, especially at the MTS layer.&lt;/li&gt;&lt;li&gt;Sound recovery procedure. The recovery procedure, which runs on slave threads (re)start, has been improved significantly.&lt;/li&gt;&lt;li&gt;STOP SLAVE consistently. We have made STOP SLAVE to stop at a consistent point with respect to the master execution history. There were quite a few requests to implement this behavior. That said, one can still stop the SQL thread immediately if one KILLs the SQL thread.&lt;/li&gt;&lt;li&gt;Enhanced SBR replication. In multi-threaded mode, in particular, support for temporary tables replication was added.&lt;/li&gt;&lt;li&gt;Usability improvements. There is now a simplified set of configuration options which will make DBAs life easier.&lt;/li&gt;&lt;li&gt;Improved codebase. Following an effort on codebase clean up and related refactorings, the multi-threaded slave code is now easier to maintain.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;Please, give the latest snapshot a spin and let us know how it goes!&lt;br /&gt;&lt;br /&gt;These are exciting times... Not only MTS is coming, some very cool replication features are also on their way, such as binary log group commit and an API for inspecting binary logs:&lt;br /&gt;&lt;br /&gt;    http://www.oracle.com/us/corporate/press/439460&lt;br /&gt;&lt;br /&gt;You can find these feature previews next to the MTS snapshot on labs.mysql.com as well.&lt;br /&gt;&lt;br /&gt;Enjoy!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5448983346854381269-5292884922352237011?l=d2-systems.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://d2-systems.blogspot.com/feeds/5292884922352237011/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://d2-systems.blogspot.com/2011/07/update-on-multi-threaded-slave.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5448983346854381269/posts/default/5292884922352237011'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5448983346854381269/posts/default/5292884922352237011'/><link rel='alternate' type='text/html' href='http://d2-systems.blogspot.com/2011/07/update-on-multi-threaded-slave.html' title='Update on the Multi-threaded Slave'/><author><name>Luís Soares</name><uri>http://www.blogger.com/profile/15801959795245235917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5448983346854381269.post-8660814253486783733</id><published>2011-04-13T11:49:00.000-07:00</published><updated>2011-04-13T11:59:22.801-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mysql'/><title type='text'>MySQL 5.6.2 DM: Binlog Informational Events</title><content type='html'>In some cases it would be really useful to have additional information in the binary log, mostly for debugging purposes. Starting with MySQL 5.6.2 DM release, the mysql replication event set was extended to include a new type of event that is basically used for transferring data around that does not actually changes state at the slaves. It can be safely ignored for the actual replication procedures, but it can be extremely relevant for conducting debugging…&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Row-based Replication&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;Quite frequently, one finds someone out there requesting that in row based replication, the original statement is written into the binary log, alongside with the row event(s) it generated.&lt;br /&gt;&lt;br /&gt;Starting with MySQL 5.6.2 DM, and by making use of the Informational Events facility, users can now do exactly that. While turning on the switch &lt;span style="font-style: italic; font-weight: bold;"&gt;--binlog-rows-query-log-events&lt;/span&gt; (or activating it through the correspondent session variable) the mysql replication layer is instructed to write the statement to the binary log as a special event. These events do not require any extra processing from the slave(s), well… maybe just to relay them, and only if the user wants them to be relayed...&lt;br /&gt;&lt;br /&gt;Lets have a look how it works! In the following example, the option to log statements is activated while logging in ROW, and then some rows are inserted into a table. This generates some row events entries in the binary log! As expected they show up when one issues the command 'SHOW BINLOG EVENTS'. In addition, the new event type Rows_query comes up in the output, showing the original query!&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;mysql&amp;gt; SET binlog_format=ROW;&lt;br /&gt;Query OK, 0 rows affected (0.00 sec)&lt;br /&gt;&lt;br /&gt;mysql&amp;gt; SET SESSION binlog_rows_query_log_events=ON;&lt;br /&gt;Query OK, 0 rows affected (0.00 sec)&lt;br /&gt;&lt;br /&gt;mysql&amp;gt; CREATE TABLE t1 (a INT);&lt;br /&gt;Query OK, 0 rows affected (0.07 sec)&lt;br /&gt;&lt;br /&gt;mysql&amp;gt; INSERT INTO t1 VALUES (1), (2), (3);&lt;br /&gt;Query OK, 3 rows affected (0.00 sec)&lt;br /&gt;Records: 3  Duplicates: 0  Warnings: 0&lt;br /&gt;&lt;br /&gt;mysql&amp;gt; SHOW BINLOG EVENTS;&lt;br /&gt;+-------------------+-----+-------------+-----------+-------------+-----------------------------------------------+&lt;br /&gt;| Log_name          | Pos | Event_type  | Server_id | End_log_pos | Info                                          |&lt;br /&gt;+-------------------+-----+-------------+-----------+-------------+-----------------------------------------------+&lt;br /&gt;| master-bin.000001 |   4 | Format_desc |         1 |         114 | Server ver: 5.6.3-m5-debug-log, Binlog ver: 4 |&lt;br /&gt;| master-bin.000001 | 114 | Query       |         1 |         200 | use `test`; CREATE TABLE t1 (a INT)           |&lt;br /&gt;| master-bin.000001 | 200 | Query       |         1 |         268 | BEGIN                                         |&lt;br /&gt;| master-bin.000001 | 268 | Rows_query  |         1 |         323 | # INSERT INTO t1 VALUES (1), (2), (3)         |&lt;br /&gt;| master-bin.000001 | 323 | Table_map   |         1 |         364 | table_id: 54 (test.t1)                        |&lt;br /&gt;| master-bin.000001 | 364 | Write_rows  |         1 |         408 | table_id: 54 flags: STMT_END_F                |&lt;br /&gt;| master-bin.000001 | 408 | Query       |         1 |         477 | COMMIT                                        |&lt;br /&gt;+-------------------+-----+-------------+-----------+-------------+-----------------------------------------------+&lt;br /&gt;7 rows in set (0.00 sec)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Actually, 'SHOW BINLOG EVENTS' is not the only way to display these events, one can also check them through the &lt;span style="font-weight: bold; font-style: italic;"&gt;mysqlbinlog&lt;/span&gt; tool. There is a catch however, mysqlbinlog will only output the special event if one sets the verbosity level to 2 (-vv) or more.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;shell&amp;gt; mysqlbinlog -vv data/master-bin.000001&lt;br /&gt;(...)&lt;br /&gt;# at 268&lt;br /&gt;#110401 14:24:29 server id 1  end_log_pos 323   Rows_query&lt;br /&gt;# INSERT INTO t1 VALUES (1), (2), (3)&lt;br /&gt;# at 323&lt;br /&gt;#110401 14:24:29 server id 1  end_log_pos 364   Table_map: `test`.`t1` mapped to number 54&lt;br /&gt;# at 364&lt;br /&gt;#110401 14:24:29 server id 1  end_log_pos 408   Write_rows: table id 54 flags: STMT_END_F&lt;br /&gt;(...)&lt;br /&gt;shell&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Summary&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;This blog post introduces the user to the new type of (informational) events that MySQL 5.6.2 DM provides. Furthermore, by making use of such type of events mysql replication can now log the original statements along with the rows it generated to the binary log. This is something that is asked every now and then, for a long time… So there you have it, you can find it in the MySQL 5.6.2 DM release.&lt;br /&gt;&lt;br /&gt;Enjoy!&lt;br /&gt;&lt;h3&gt;References&lt;/h3&gt;You can find detailed information about this feature in:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;http://forge.mysql.com/worklog/task.php?id=4033&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5448983346854381269-8660814253486783733?l=d2-systems.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://d2-systems.blogspot.com/feeds/8660814253486783733/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://d2-systems.blogspot.com/2011/04/mysql-562-dm-binlog-informational.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5448983346854381269/posts/default/8660814253486783733'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5448983346854381269/posts/default/8660814253486783733'/><link rel='alternate' type='text/html' href='http://d2-systems.blogspot.com/2011/04/mysql-562-dm-binlog-informational.html' title='MySQL 5.6.2 DM: Binlog Informational Events'/><author><name>Luís Soares</name><uri>http://www.blogger.com/profile/15801959795245235917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5448983346854381269.post-5391588538589497908</id><published>2011-04-13T11:22:00.000-07:00</published><updated>2011-04-13T11:46:23.240-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mysql'/><title type='text'>MySQL 5.6.2 DM: Optimized Row-based Replication Logging</title><content type='html'>Row based replication (RBR) is an amazing technology in MySQL replication. It has several advantages over statement based replication (SBR), where the lack of non-deterministic operations jumps to mind rather quickly. However, there is one drawback that drives some users away from it. RBR ships the changes over to the slave, instead of the operations as it happens in SBR. This means that RBR may exhibit a large binary log footprint for operations that make a rather big number of changes or operate over sizable rows. The problem boils down to the fact that for each row changed, one (sometimes even two) row image is inserted into the binary log, as part of a row event, and it contains all fields values (even those that are not part of the actual change). MySQL 5.6.2 DM release ships with a new feature that allows the user to tune logging in order to avoid this problem. Lets have a look at it!&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Row events, Before and After images &lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;In RBR, one row event contains changes to one or more rows in a given table. A row change, in its turn, may consist of one or two full row copies of the row that is being changed. These are generally known as row images. The first one, known as before image (BI), contains data as it was before the row was modified. The second one, known as after image (AI), is what the row looks like after the changes were done. Each image has different purpose: the BI is used for locating, in the storage engine, the row to be updated/deleted, while the AI, is used for replaying the actual changes. Needless to say, not both images are needed for every operation. Deletes only need the BI, inserts, on the other hand, just need the AI, while updates need both.&lt;br /&gt;&lt;br /&gt;This is pretty neat stuff already, however, there is room for improvements, in particular to address storage overuse. Logging can be optimized in such a way that writing full images into the binary log can be avoided, and instead, log only those parts that are meaningful for replication. Not only does this help with reducing storage space, but also enables less network bandwidth consumption - smaller events are transmitted to the slaves - as well as smaller mysql memory footprint - less buffer usage for handling row events. So… How can one tackle this ?&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Optimizing Before Image logging &lt;/h3&gt;&lt;br /&gt;The one and only usage for such image is to help finding the correct row to be updated or deleted at the slave's storage engine. Locating a row is done by considering one of the following search methods: search by primary key, by unique key, by an index scan or by doing a table scan - depending on what indexes are available on the slave's table. As such, assuming that the index structures are the same on master and slaves' tables, BIs can be logged based on the uniqueness of the index structures available. If there is a primary or unique key (with non-nullable columns), the fields that compose the key are enough to locate the row at the slave, thus BI can be composed of just those fields. On the other hand, if there is no unique key, all fields in the row need to be written into the binary log. Here is an example:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;MASTER&amp;gt; CREATE TABLE t1 (c1 INT PRIMARY KEY, c2 char(1), c3 TEXT);&lt;br /&gt;MASTER&amp;gt; INSERT INTO t1 VALUES (1, 'a', '1MB_text...');&lt;br /&gt;MASTER&amp;gt; DELETE FROM t1 WHERE c1=1;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Logging the full BI in this case, means that each row deleted has a correspondent before image stored in the binary log sizing up to (4 + 1 + 1024*1024) bytes ~ 1MB. Deleting 10 rows in the table, easily grows the binary log to 10 MB (assuming that c3 is always 1MB large). Now, if only the primary key is logged, then for the same 10 rows, only 40 bytes are needed for storing the BI. Lets see how that plays out for the scenario above by trying out this feature on a real mysql session:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;mysql&amp;gt; SET binlog_format=ROW;&lt;br /&gt;Query OK, 0 rows affected (0.00 sec)&lt;br /&gt;&lt;br /&gt;mysql&amp;gt; CREATE TABLE t1 (c1 INT PRIMARY KEY, c2 char(1), c3 LONGTEXT);&lt;br /&gt;Query OK, 0 rows affected (0.10 sec)&lt;br /&gt;&lt;br /&gt;mysql&amp;gt; SHOW MASTER STATUS;&lt;br /&gt;+-------------------+----------+--------------+------------------+&lt;br /&gt;| File              | Position | Binlog_Do_DB | Binlog_Ignore_DB |&lt;br /&gt;+-------------------+----------+--------------+------------------+&lt;br /&gt;| master-bin.000001 |      238 |              |                  |&lt;br /&gt;+-------------------+----------+--------------+------------------+&lt;br /&gt;1 row in set (0.00 sec)&lt;br /&gt;&lt;br /&gt;mysql&amp;gt; SET @text= repeat('a', 1048576);&lt;br /&gt;Query OK, 0 rows affected (0.02 sec)&lt;br /&gt;&lt;br /&gt;mysql&amp;gt; INSERT INTO t1 VALUES (1, 'a', @text);&lt;br /&gt;Query OK, 1 row affected (0.04 sec)&lt;br /&gt;&lt;br /&gt;mysql&amp;gt; SHOW MASTER STATUS;&lt;br /&gt;+-------------------+----------+--------------+------------------+&lt;br /&gt;| File              | Position | Binlog_Do_DB | Binlog_Ignore_DB |&lt;br /&gt;+-------------------+----------+--------------+------------------+&lt;br /&gt;| master-bin.000001 |  1049037 |              |                  |&lt;br /&gt;+-------------------+----------+--------------+------------------+&lt;br /&gt;1 row in set (0.00 sec)&lt;br /&gt;&lt;br /&gt;mysql&amp;gt; RESET MASTER;&lt;br /&gt;Query OK, 0 rows affected (0.30 sec)&lt;br /&gt;&lt;br /&gt;mysql&amp;gt; DELETE FROM t1 WHERE c1=1;&lt;br /&gt;Query OK, 1 row affected (0.01 sec)&lt;br /&gt;Rows matched: 1  Changed: 1  Warnings: 0&lt;br /&gt;&lt;br /&gt;mysql&amp;gt; SHOW MASTER STATUS;&lt;br /&gt;+-------------------+----------+--------------+------------------+&lt;br /&gt;| File              | Position | Binlog_Do_DB | Binlog_Ignore_DB |&lt;br /&gt;+-------------------+----------+--------------+------------------+&lt;br /&gt;| master-bin.000001 |  1048913 |              |                  |&lt;br /&gt;+-------------------+----------+--------------+------------------+&lt;br /&gt;1 row in set (0.00 sec)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;As one can see here, the DELETE operation resulted in a binary log entry that takes up to 1048913 bytes, although only the primary key would be needed to locate and delete the row at the slave. Now, if the server is set to log only minimal images, then it will instead log just a few bytes:&lt;br /&gt;&lt;pre&gt;mysql&amp;gt; INSERT INTO t1 VALUES (1, 'a', @text);&lt;br /&gt;Query OK, 1 row affected (0.04 sec)&lt;br /&gt;&lt;br /&gt;mysql&amp;gt; RESET MASTER;&lt;br /&gt;Query OK, 0 rows affected (0.37 sec)&lt;br /&gt;&lt;br /&gt;mysql&amp;gt; SET SESSION binlog_row_image='MINIMAL';&lt;br /&gt;Query OK, 0 rows affected (0.00 sec)&lt;br /&gt;&lt;br /&gt;mysql&amp;gt; SHOW MASTER STATUS;&lt;br /&gt;+-------------------+----------+--------------+------------------+&lt;br /&gt;| File              | Position | Binlog_Do_DB | Binlog_Ignore_DB |&lt;br /&gt;+-------------------+----------+--------------+------------------+&lt;br /&gt;| master-bin.000001 |      114 |              |                  |&lt;br /&gt;+-------------------+----------+--------------+------------------+&lt;br /&gt;1 row in set (0.00 sec)&lt;br /&gt;&lt;br /&gt;mysql&amp;gt; DELETE FROM t1 WHERE c1=1;&lt;br /&gt;Query OK, 1 row affected (0.00 sec)&lt;br /&gt;Rows matched: 1  Changed: 1  Warnings: 0&lt;br /&gt;&lt;br /&gt;mysql&amp;gt; SHOW MASTER STATUS;&lt;br /&gt;+-------------------+----------+--------------+------------------+&lt;br /&gt;| File              | Position | Binlog_Do_DB | Binlog_Ignore_DB |&lt;br /&gt;+-------------------+----------+--------------+------------------+&lt;br /&gt;| master-bin.000001 |      331 |              |                  |&lt;br /&gt;+-------------------+----------+--------------+------------------+&lt;br /&gt;1 row in set (0.00 sec)&lt;br /&gt;&lt;/pre&gt;Looking at the output from the last 'SHOW MASTER STATUS', one finds that indeed the binlog size for the delete operation decreased from 1048913 to 331, that is 1MB less than when using a full row.&lt;br /&gt;&lt;h3&gt;&lt;br /&gt;&lt;/h3&gt;&lt;h3&gt;Optimizing the After Image Logging&lt;/h3&gt;&lt;br /&gt;Assuming that the table definitions are pretty much the same on both master and slave(s), the server can avoid logging the entire AI and log only the columns that were actually changed/inserted, much like in SBR. Lets look at an example:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;MASTER&amp;gt; CREATE TABLE t1 (c1 INT PRIMARY KEY, c2 char(1), c3 CHAR(255) DEFAULT 'aaaaaaaaaaaaaaaaaaaa');&lt;br /&gt;MASTER&amp;gt; INSERT INTO t1(c1,c2) VALUES (1, 'a');&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;When the server is set to log full rows, the insert operation will generate an AI containing c1, c2 and c3 values. This means that an additional 20 bytes ('aaaaaaaaaaaaaaaaaaaa') will be logged pointlessly. On the other hand, if the server is set to log only minimal rows, the extra 20 bytes are avoided. Lets check what happens with a real sample:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;mysql&amp;gt; SET binlog_format=ROW;&lt;br /&gt;Query OK, 0 rows affected (0.00 sec)&lt;br /&gt;&lt;br /&gt;mysql&amp;gt; SET SESSION binlog_row_image='FULL';&lt;br /&gt;Query OK, 0 rows affected (0.00 sec)&lt;br /&gt;&lt;br /&gt;mysql&amp;gt; CREATE TABLE t1 (c1 INT PRIMARY KEY, c2 char(1), c3 VARCHAR(1024) DEFAULT 'aaaaaaaaaaaaaaaaaaaa');&lt;br /&gt;Query OK, 0 rows affected (0.10 sec)&lt;br /&gt;&lt;br /&gt;mysql&amp;gt; RESET MASTER;&lt;br /&gt;Query OK, 0 rows affected (0.37 sec)&lt;br /&gt;&lt;br /&gt;mysql&amp;gt; SHOW MASTER STATUS;&lt;br /&gt;+-------------------+----------+--------------+------------------+&lt;br /&gt;| File              | Position | Binlog_Do_DB | Binlog_Ignore_DB |&lt;br /&gt;+-------------------+----------+--------------+------------------+&lt;br /&gt;| master-bin.000001 |      114 |              |                  |&lt;br /&gt;+-------------------+----------+--------------+------------------+&lt;br /&gt;1 row in set (0.00 sec)&lt;br /&gt;&lt;br /&gt;mysql&amp;gt; INSERT INTO t1(c1,c2) VALUES (1, 'a');&lt;br /&gt;Query OK, 1 row affected (0.00 sec)&lt;br /&gt;&lt;br /&gt;mysql&amp;gt; SHOW MASTER STATUS;&lt;br /&gt;+-------------------+----------+--------------+------------------+&lt;br /&gt;| File              | Position | Binlog_Do_DB | Binlog_Ignore_DB |&lt;br /&gt;+-------------------+----------+--------------+------------------+&lt;br /&gt;| master-bin.000001 |      356 |              |                  |&lt;br /&gt;+-------------------+----------+--------------+------------------+&lt;br /&gt;1 row in set (0.00 sec)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;We can find that the event logged, corresponding to the INSERT operation, grows the binary log up to 356 bytes. Setting the server to log only minimal images we get the following:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;mysql&amp;gt; SET SESSION binlog_row_image='MINIMAL';&lt;br /&gt;Query OK, 0 rows affected (0.00 sec)&lt;br /&gt;&lt;br /&gt;mysql&amp;gt; DELETE FROM t1;&lt;br /&gt;Query OK, 1 row affected (0.00 sec)&lt;br /&gt;&lt;br /&gt;mysql&amp;gt; RESET MASTER;&lt;br /&gt;Query OK, 0 rows affected (0.34 sec)&lt;br /&gt;&lt;br /&gt;mysql&amp;gt; SHOW MASTER STATUS;&lt;br /&gt;+-------------------+----------+--------------+------------------+&lt;br /&gt;| File              | Position | Binlog_Do_DB | Binlog_Ignore_DB |&lt;br /&gt;+-------------------+----------+--------------+------------------+&lt;br /&gt;| master-bin.000001 |      114 |              |                  |&lt;br /&gt;+-------------------+----------+--------------+------------------+&lt;br /&gt;1 row in set (0.00 sec)&lt;br /&gt;&lt;br /&gt;mysql&amp;gt; INSERT INTO t1(c1,c2) VALUES (1, 'a');&lt;br /&gt;Query OK, 1 row affected (0.00 sec)&lt;br /&gt;&lt;br /&gt;mysql&amp;gt; SHOW MASTER STATUS;&lt;br /&gt;+-------------------+----------+--------------+------------------+&lt;br /&gt;| File              | Position | Binlog_Do_DB | Binlog_Ignore_DB |&lt;br /&gt;+-------------------+----------+--------------+------------------+&lt;br /&gt;| master-bin.000001 |      334 |              |                  |&lt;br /&gt;+-------------------+----------+--------------+------------------+&lt;br /&gt;1 row in set (0.00 sec)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Again, looking at the last SHOW MASTER STATUS command, one finds that the event entry, related to the INSERT operation, grows the binary log to 334 instead of 356 bytes, i.e., 22 bytes less (2 bytes for c3 metadata + 20 bytes for c3 content).&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;The case for UPDATE operations&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;Updates generate pairs of images for each row changed. One needs the BI to locate the row and the AI to actually update it. Thus, this operation benefits from both optimizations that were described previously for the INSERT and DELETE operations. The following picture depicts what columns each image contains in previous MySQL versions and compares against 5.6.2 with partial rows logging enabled (assuming same queries and table definition as in the example shown before). One can easily see that in the green shaded box (5.6.2 DM binary log with partial logging turned on) BI and AI contain far less columns (the dark green boxes with "C&lt;i&gt;n&lt;/i&gt;" on them):&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-0E-jgxATBsQ/TaXvRCaKiLI/AAAAAAAAA4g/KJlKbNpOHHk/s1600/both-images.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 158px;" src="http://2.bp.blogspot.com/-0E-jgxATBsQ/TaXvRCaKiLI/AAAAAAAAA4g/KJlKbNpOHHk/s320/both-images.png" alt="" id="BLOGGER_PHOTO_ID_5595141188061137074" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;BLOBs special case&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;Apart from full and minimal rows, there is also a special option to optimize just the logging of blob fields, if setting binlog_row_image to 'NOBLOB';&lt;br /&gt;&lt;br /&gt;In this case, replication will avoid logging blob fields whenever possible (BI: when they are not needed to locate the row, AI: when they are not modified). The other fields are still logged as if it the option binlog_row_image had been set to 'FULL'.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Summary&lt;/h3&gt;&lt;br /&gt;This post presents a new feature, available on MySQL 5.6.2 DM release, which enables more flexible logging of ROW events. It gives the user the freedom to choose whether the server should log full or partial rows, which is a major asset when either changing a large number of rows and/or changing sizable rows.&lt;br /&gt;&lt;br /&gt;There are some assumptions when using this feature, for instance:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The tables on both master and slave should have the same index structures, or at least the index set on the master should be a subset of slave's index set. If not, unexpected behavior may happen;&lt;/li&gt;&lt;li&gt;The table definition should be the same with respect to default values, otherwise on INSERTs there may be different content inserted on the master and the slave (just like in SBR);&lt;/li&gt;&lt;li&gt;When setting binlog_row_image to 'MINIMAL' or 'NOBLOB', the logged rows are incomplete, therefore, if the user requires that the binary log contains full rows, then he should not use these options.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;In general, if taking some care with indexes and default values and by knowing the workload the user can save a lot of storage space and network bandwidth by using these options to tweak RBR logging.&lt;br /&gt;&lt;br /&gt;Go and try it out. Have fun!&lt;br /&gt;&lt;h3&gt;References&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://forge.mysql.com/worklog/task.php?id=5092"&gt;http://forge.mysql.com/worklog/task.php?id=5092&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5448983346854381269-5391588538589497908?l=d2-systems.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://d2-systems.blogspot.com/feeds/5391588538589497908/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://d2-systems.blogspot.com/2011/04/mysql-562-dm-optimized-row-based.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5448983346854381269/posts/default/5391588538589497908'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5448983346854381269/posts/default/5391588538589497908'/><link rel='alternate' type='text/html' href='http://d2-systems.blogspot.com/2011/04/mysql-562-dm-optimized-row-based.html' title='MySQL 5.6.2 DM: Optimized Row-based Replication Logging'/><author><name>Luís Soares</name><uri>http://www.blogger.com/profile/15801959795245235917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-0E-jgxATBsQ/TaXvRCaKiLI/AAAAAAAAA4g/KJlKbNpOHHk/s72-c/both-images.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5448983346854381269.post-3638551529253078891</id><published>2011-04-11T20:13:00.000-07:00</published><updated>2011-04-12T04:32:35.234-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mysql'/><title type='text'>Feature Preview: The Multi-Threaded Slave</title><content type='html'>&lt;h3&gt;The Need for Multi-Threaded Slaves!&lt;/h3&gt;&lt;div style="text-align: justify;"&gt;The MySQL replication team has come up with a feature that looks very promising for improving slave scalability. Although there is some work that one can do on the master side, it is the work already done at the slave side that this blog post highlights...&lt;br /&gt;&lt;br /&gt;At its core, MySQL replication is single-threaded! In detail, the tiniest unit of work for replication is an event, and a group of events forms a transaction.  Events are pushed by the master to the slaves by a thread, known as "dump thread". At the slave, a reader ("IO thread") reads event-by-event and writes them to a local persistent queue, the "relay log". Then a single threaded applier, the "SQL thread", reads and applies events sequentially.&lt;br /&gt;&lt;br /&gt;Contrary to the master, which executes transactions concurrently, the slave serializes execution of each and every transaction, even if they were executed concurrently on the master and are guaranteed to be conflict free. In fact, should that be the case, then such transactions could be applied in parallel thus taking advantage of multi-core/cpu hardware. Furthermore, recent optimizations on the master side enabled much better scale-up, thence enforcing the need for more scalable slave execution as well.&lt;br /&gt;&lt;br /&gt;Today, Andrei Elkin has actually delivered a talk on this subject at Collaborate 11: &lt;a href="http://coll11.mapyourshow.com/3_0/sessions/sessiondetails.cfm?ScheduledSessionID=2909"&gt;Boosting MySQL Replication Performance Through the Multi-Threaded Slave&lt;/a&gt;. Roughly two hours earlier, a prototype - feature preview based on 5.6 codebase - was published in &lt;a href="http://labs.mysql.com/"&gt;MySQL Labs&lt;/a&gt; for you to go  and test it out. NOTE: &lt;span style="font-weight: bold;"&gt;the package is not intended for using in production. It IS a feature preview.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;h3 style="text-align: justify;"&gt;What is a Multi-Threaded Slave?&lt;br /&gt;&lt;/h3&gt;&lt;div style="text-align: justify;"&gt;While multi-threaded is a rather broad term, it is loosely used in the current context, targeting a specific technique of parallelization of transaction execution. In other words, multi-threaded slave refers to inter-transactional parallelization while applying transactions to the slave's databases. This makes replication more scalable, especially on multi-core architectures.&lt;br /&gt;&lt;br /&gt;The fact is that even the most common hardware today is multi-core and given that replication strives to exhibit good scalability always, the benefits from having a multi-core machine at the slave side must be exploited. Apparently, that is not completely the case yet, because every now and then we hear someone saying that the slave is not able to keep up with its master or that it is "lagging behind"! On such settings inter-transactional parallelization comes to the rescue, as it fits a big number of cases, is relatively easy to implement and is engine agnostic.&lt;br /&gt;&lt;br /&gt;Earlier today, the MySQL replication team has put up for download, on MySQL Labs, a prototype that fits one particular scenario: apply, in parallel, transactions that operate on different database sets. In fact, it turns out to be quite a commonplace. In detail, it is often the case that the application partitions its data logically per database, thus the workload pattern is such, that a set of unrelated and non-conflicting transactions are executed concurrently, and on different databases, at the master. The replication slave can take advantage of this fact and execute such transactions, concurrently as well, i.e., by applying them in parallel. In practice, and on such scenarios, a multi-threaded slave would read transactions from the relay log and assign them to different worker threads, depending on the database the transaction is working on. Transactions operating on the same database would then be guaranteed to be serialized. On the other hand, transactions executing on different databases would be concurrently executed and committed independently. This is depicted in the following diagram:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-b1ZN76Zpwg4/TaPFiM60I1I/AAAAAAAAA4E/KFEAv29rdKA/s1600/mts-arch.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 217px;" src="http://2.bp.blogspot.com/-b1ZN76Zpwg4/TaPFiM60I1I/AAAAAAAAA4E/KFEAv29rdKA/s320/mts-arch.png" alt="" id="BLOGGER_PHOTO_ID_5594532353498424146" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;In this figure we can find the usual stages that transactions go through during the apply procedure at the slave. It is not fundamentally different from what we have today on latest MySQL GA releases, except that now there is an additional "workers" stage. In a nutshell, the execution flow goes like this: IO thread receives events/transactions and queues them in the relay log; SQL coordinator thread reads them from the log file and queues the event on a specific worker queue. Selecting which queue to use is done by checking which database the event should be executed against (the best case scenario is the one that all events in a transaction change the same database, otherwise the scheduling may have some negative impact); Workers dequeue the events from their queues and execute them. If the event is a COMMIT operation, the worker then commits the transaction independently from other workers.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;h3 style="text-align: justify;"&gt;Some Special Cases&lt;/h3&gt;&lt;div style="text-align: justify;"&gt;There are some special cases that one needs to think of. What about cross-database transactions? What about slave positions ? What about stopping and restarting the slave ? What about crashing and recovering?&lt;br /&gt;&lt;br /&gt;I don't want to risk getting tangled into details, so lets not go into much detail and discuss them briefly:&lt;br /&gt;&lt;/div&gt;&lt;ul style="text-align: justify;"&gt;&lt;li&gt;For cross-database transactions, the slave waits until all preceding transactions that are working on the same database set are over. However, multiple databases in the same transaction can result in a partition itself that the slave can parallelize, e.g., if T1 changes "db1" and "db2" and T2 changes "db3" and "db4", then there is room for the slave to execute both transactions in parallel, despite the fact that both change more than one database;&lt;/li&gt;&lt;/ul&gt;&lt;ul style="text-align: justify;"&gt;&lt;li&gt;On a multi-threaded slave, there are several workers, each committing independently, therefore usual concept of "last executed position" is not very meaningful. Some concurrent transactions may commit in a different order than the one that is established in the binary log, thus execution gaps may exist throughout execution time. The slave needs to track such gaps, and for that purpose it keeps track of each worker position and stores them persistently on system tables ("mysql.slave_worker_info");&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul style="text-align: justify;"&gt;&lt;li&gt;Stopping and restarting the server is somewhat analogous to crashing and recovering it. On restart the slave checks each worker position, thus finding out which transactions need to be replayed since the last checkpoint (position in the log that has no execution gaps before it). This takes care of existing gaps,and the new workers can start executing from a base position.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;State of the Art&lt;/h3&gt;&lt;div style="text-align: justify;"&gt;For the following examples, a multi-threaded enabled slave server is required, replication is assumed to be setup, but the slave threads should not have been started. In addition, the slave should be configured to use the new system tables to store positions (not really necessary, but it turns the whole experience much more appealing). As such, one needs to start the slave MySQL server with the (additional) following options:&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;pre&gt;--relay-log-info-repository="TABLE" --master-info-repository="TABLE" --worker-info-repository="TABLE"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Now that the servers are started, lets begin by changing the number of workers that will be available for executing transactions and start the slave:&lt;br /&gt;&lt;/div&gt;&lt;pre&gt;mysql&amp;gt; STOP SLAVE;&lt;br /&gt;Query OK, 0 rows affected (0.00 sec)&lt;br /&gt;&lt;br /&gt;mysql&amp;gt; SET GLOBAL mts_slave_parallel_workers=2;&lt;br /&gt;Query OK, 0 rows affected (0.00 sec)&lt;br /&gt;&lt;br /&gt;mysql&amp;gt; SELECT @@mts_slave_parallel_workers;&lt;br /&gt;+------------------------------+&lt;br /&gt;| @@mts_slave_parallel_workers |&lt;br /&gt;+------------------------------+&lt;br /&gt;|                            2 |&lt;br /&gt;+------------------------------+&lt;br /&gt;1 row in set (0.00 sec)&lt;br /&gt;&lt;br /&gt;mysql&amp;gt; START SLAVE;&lt;br /&gt;Query OK, 0 rows affected (0.09 sec)&lt;br /&gt;&lt;br /&gt;mysql&amp;gt; SELECT USER,STATE FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER='system user';&lt;br /&gt;+-------------+------------------------------------------------------------------+&lt;br /&gt;| USER        | STATE                                                            |&lt;br /&gt;+-------------+------------------------------------------------------------------+&lt;br /&gt;| system user | Slave has read all relay log; waiting for the slave I/O thread t |&lt;br /&gt;| system user | Waiting for an event from sql thread                             |&lt;br /&gt;| system user | Waiting for an event from sql thread                             |&lt;br /&gt;| system user | Waiting for master to send event                                 |&lt;br /&gt;+-------------+------------------------------------------------------------------+&lt;br /&gt;4 rows in set (0.00 sec)&lt;br /&gt;&lt;br /&gt;mysql&amp;gt; SELECT * FROM mysql.slave_worker_info\G&lt;br /&gt;*************************** 1. row ***************************&lt;br /&gt;            Master_id: 2&lt;br /&gt;            Worker_id: 0&lt;br /&gt;       Relay_log_name:&lt;br /&gt;        Relay_log_pos: 0&lt;br /&gt;      Master_log_name:&lt;br /&gt;       Master_log_pos: 0&lt;br /&gt;Checkpoint_relay_log_name:&lt;br /&gt;Checkpoint_relay_log_pos: 0&lt;br /&gt;Checkpoint_master_log_name:&lt;br /&gt;Checkpoint_master_log_pos: 0&lt;br /&gt;     Checkpoint_seqno: 0&lt;br /&gt;Checkpoint_group_size: 64&lt;br /&gt;Checkpoint_group_bitmap:                                                            &lt;br /&gt;*************************** 2. row ***************************&lt;br /&gt;            Master_id: 2&lt;br /&gt;            Worker_id: 1&lt;br /&gt;       Relay_log_name:&lt;br /&gt;        Relay_log_pos: 0&lt;br /&gt;      Master_log_name:&lt;br /&gt;       Master_log_pos: 0&lt;br /&gt;Checkpoint_relay_log_name:&lt;br /&gt;Checkpoint_relay_log_pos: 0&lt;br /&gt;Checkpoint_master_log_name:&lt;br /&gt;Checkpoint_master_log_pos: 0&lt;br /&gt;     Checkpoint_seqno: 0&lt;br /&gt;Checkpoint_group_size: 64&lt;br /&gt;Checkpoint_group_bitmap:                                                            &lt;br /&gt;2 rows in set (0.00 sec)&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div style="text-align: justify;"&gt;In the instructions above, we have changed the number of workers and then we started the slave and showed the status of all "system user" processes entries. There is one SQL thread that acts as coordinator, and is waiting for the IO thread to queue more events into the relay log. Additionally, we can find two worker threads and an IO thread that are waiting for events. Finally, we also printed out the position entries for each worker by inspecting the "mysql.slave_worker_info" table.&lt;br /&gt;&lt;br /&gt;Next, lets issue a couple of statements that fit the multi-threaded use cases described previously. Thence, we need to create a couple of databases, some tables and issue some DML statements over those tables. On the master, we issue the following:&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;pre&gt;mysql&amp;gt; CREATE DATABASE db1;&lt;br /&gt;Query OK, 1 row affected (0.00 sec)&lt;br /&gt;&lt;br /&gt;mysql&amp;gt; CREATE DATABASE db2;&lt;br /&gt;Query OK, 1 row affected (0.00 sec)&lt;br /&gt;&lt;br /&gt;mysql&amp;gt; CREATE TABLE db2.t1 (a INT);&lt;br /&gt;Query OK, 0 rows affected (0.03 sec)&lt;br /&gt;&lt;br /&gt;mysql&amp;gt; CREATE TABLE db1.t1 (a INT);&lt;br /&gt;Query OK, 0 rows affected (0.04 sec)&lt;br /&gt;&lt;br /&gt;mysql&amp;gt; INSERT INTO db1.t1 VALUES (1), (2); INSERT INTO db2.t1 VALUES (3),(4);&lt;br /&gt;Query OK, 2 rows affected (0.00 sec)&lt;br /&gt;Records: 2  Duplicates: 0  Warnings: 0&lt;br /&gt;&lt;br /&gt;Query OK, 2 rows affected (0.00 sec)&lt;br /&gt;Records: 2  Duplicates: 0  Warnings: 0&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;At this point we have inserted into two tables that are on different databases. Since they are non-conflicting, the slave server will execute these two statements concurrently, one on each slave worker. Lets have a look at each worker positions:&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;pre&gt;mysql&amp;gt; SELECT * FROM mysql.slave_worker_info\G&lt;br /&gt;*************************** 1. row ***************************&lt;br /&gt;            Master_id: 2&lt;br /&gt;            Worker_id: 0&lt;br /&gt;       Relay_log_name: ./slave-relay-bin.000003&lt;br /&gt;        Relay_log_pos: 1081&lt;br /&gt;      Master_log_name: master-bin.000001&lt;br /&gt;       Master_log_pos: 927&lt;br /&gt;Checkpoint_relay_log_name: ./slave-relay-bin.000003&lt;br /&gt;Checkpoint_relay_log_pos: 626&lt;br /&gt;Checkpoint_master_log_name: master-bin.000001&lt;br /&gt;Checkpoint_master_log_pos: 472&lt;br /&gt;     Checkpoint_seqno: 1&lt;br /&gt;Checkpoint_group_size: 64&lt;br /&gt;Checkpoint_group_bitmap:                                                           &lt;br /&gt;*************************** 2. row ***************************&lt;br /&gt;            Master_id: 2&lt;br /&gt;            Worker_id: 1&lt;br /&gt;       Relay_log_name: ./slave-relay-bin.000003&lt;br /&gt;        Relay_log_pos: 854&lt;br /&gt;      Master_log_name: master-bin.000001&lt;br /&gt;       Master_log_pos: 700&lt;br /&gt;Checkpoint_relay_log_name: ./slave-relay-bin.000003&lt;br /&gt;Checkpoint_relay_log_pos: 626&lt;br /&gt;Checkpoint_master_log_name: master-bin.000001&lt;br /&gt;Checkpoint_master_log_pos: 472&lt;br /&gt;     Checkpoint_seqno: 0&lt;br /&gt;Checkpoint_group_size: 64&lt;br /&gt;Checkpoint_group_bitmap:                                                           &lt;br /&gt;2 rows in set (0.00 sec)&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;The table shows us that both workers were engaged during the apply activities. Worker #1 handled insert for one database, while worker #2 handled the other insert (on the other database).&lt;br /&gt;&lt;br /&gt;This is the very basics of multi-threaded slave, thence you should go and try/play with it yourself!&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;h3&gt;Tuning&lt;/h3&gt;&lt;div style="text-align: justify;"&gt;The multi-threaded slave can be tuned by changing some of its parameters. The following are just a few (those that are somewhat more relevant). Since this is still work in progress, it can be that they get renamed or even removed before the feature is actually released in a GA version. Anyway, if you're playing with the feature preview, the following might be helpful:&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;pre&gt;  --mts-slave-parallel-workers=#&lt;br /&gt;                Number of worker threads for executing events in parallel.&lt;br /&gt;&lt;br /&gt;--mts-pending-jobs-size-max=#&lt;br /&gt;                 Max size of Slave Worker queues holding yet not&lt;br /&gt;                 applied events.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;A quick and dirty list of parameters that the server can actually accept related to multi-threaded slave, can be obtained by running mysqld --help as in the following command:&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;pre&gt;shell&amp;gt; ./bin/mysqld --verbose --help | grep mts&lt;br /&gt;&lt;br /&gt;[... some error messages might show up here ...]&lt;br /&gt;&lt;br /&gt;--mts-checkpoint-group=#&lt;br /&gt;--mts-checkpoint-period=#&lt;br /&gt;--mts-coordinator-basic-nap=#&lt;br /&gt;--mts-exp-slave-local-timestamp&lt;br /&gt;--mts-partition-hash-soft-max=#&lt;br /&gt;                 Number of records in the mts partition hash below which&lt;br /&gt;--mts-pending-jobs-size-max=#&lt;br /&gt;--mts-slave-parallel-workers=#&lt;br /&gt;--mts-slave-worker-queue-len-max=#&lt;br /&gt;                 all queues are governed by mts_pending_jobs_size_max.&lt;br /&gt;--mts-worker-underrun-level=#&lt;br /&gt;mts-checkpoint-group                              512&lt;br /&gt;mts-checkpoint-period                             300&lt;br /&gt;mts-coordinator-basic-nap                         5&lt;br /&gt;mts-exp-slave-local-timestamp                     FALSE&lt;br /&gt;mts-partition-hash-soft-max                       16&lt;br /&gt;mts-pending-jobs-size-max                         16777216&lt;br /&gt;mts-slave-parallel-workers                        0&lt;br /&gt;mts-slave-worker-queue-len-max                    40000&lt;br /&gt;mts-worker-underrun-level                         0&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h3&gt;Summary&lt;/h3&gt;&lt;div style="text-align: justify;"&gt;This blog post presents the need for a Multi-threaded slave and stresses the fact that Oracle's MySQL replication team delivered a feature preview based on the MySQL 5.6 codebase. The user can download it from &lt;a href="http://labs.mysql.com/"&gt;MySQL Labs&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Apart from explaining the needs, it also details what its use cases are and explains briefly how it actually works internally.&lt;br /&gt;&lt;br /&gt;It finishes by presenting a few MySQL commands that one can use in the feature preview server to actually make use of several threads at the slave.&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5448983346854381269-3638551529253078891?l=d2-systems.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://d2-systems.blogspot.com/feeds/3638551529253078891/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://d2-systems.blogspot.com/2011/04/mysql-56x-feature-preview-multi.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5448983346854381269/posts/default/3638551529253078891'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5448983346854381269/posts/default/3638551529253078891'/><link rel='alternate' type='text/html' href='http://d2-systems.blogspot.com/2011/04/mysql-56x-feature-preview-multi.html' title='Feature Preview: The Multi-Threaded Slave'/><author><name>Luís Soares</name><uri>http://www.blogger.com/profile/15801959795245235917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-b1ZN76Zpwg4/TaPFiM60I1I/AAAAAAAAA4E/KFEAv29rdKA/s72-c/mts-arch.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5448983346854381269.post-7758462294655299267</id><published>2011-04-11T06:13:00.000-07:00</published><updated>2011-04-11T09:06:39.533-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mysql'/><title type='text'>Collaborate 11: Replication related talks!</title><content type='html'>Here are some interesting replication related talks that my team will deliver:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;"Boosting MySQL Replication Performance Through Multi-Threaded Slave", by Andrei Elkin (April 11th at 11:45AM).&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;"MySQL Replication", by Lars Thalmann (April 11th at 2:30 PM).&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;"Introduction to MySQL Replication", by Luis Soares (April 12th at 3:15 PM).&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;"Sharding Techniques for MySQL", by Mats Kindahl (April 13th at 8:00 AM).&lt;/li&gt;&lt;/ul&gt;Come and join us... Have a great week at Collaborate 11!&lt;br /&gt;&lt;br /&gt;Luís&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5448983346854381269-7758462294655299267?l=d2-systems.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://d2-systems.blogspot.com/feeds/7758462294655299267/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://d2-systems.blogspot.com/2011/04/collaborate-11-replication-related.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5448983346854381269/posts/default/7758462294655299267'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5448983346854381269/posts/default/7758462294655299267'/><link rel='alternate' type='text/html' href='http://d2-systems.blogspot.com/2011/04/collaborate-11-replication-related.html' title='Collaborate 11: Replication related talks!'/><author><name>Luís Soares</name><uri>http://www.blogger.com/profile/15801959795245235917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5448983346854381269.post-1545849211380644331</id><published>2011-04-08T14:53:00.000-07:00</published><updated>2011-04-08T15:44:43.430-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mysql'/><title type='text'>See you at Collaborate 11!</title><content type='html'>Hello everyone!&lt;br /&gt;&lt;br /&gt;During next week I'll be at Collaborate 11 conference in Orlando, Florida!&lt;br /&gt;&lt;br /&gt;Together with my colleagues and friends, I'll be talking about MySQL replication on a session named "&lt;a href="http://coll11.mapyourshow.com/3_0/sessions/sessiondetails.cfm?ScheduledSessionID=2792"&gt;INTRODUCTION TO MYSQL REPLICATION (Tutorial)&lt;/a&gt;". On April 13th (from 10:15 AM - 1:00 PM) I'll be on the Oracle demo pod.&lt;br /&gt;&lt;br /&gt;Hmm... This is also the first post on this blog, so "here be dragons".&lt;br /&gt;&lt;br /&gt;Enjoy!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5448983346854381269-1545849211380644331?l=d2-systems.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://d2-systems.blogspot.com/feeds/1545849211380644331/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://d2-systems.blogspot.com/2011/04/see-you-at-collaborate-11.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5448983346854381269/posts/default/1545849211380644331'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5448983346854381269/posts/default/1545849211380644331'/><link rel='alternate' type='text/html' href='http://d2-systems.blogspot.com/2011/04/see-you-at-collaborate-11.html' title='See you at Collaborate 11!'/><author><name>Luís Soares</name><uri>http://www.blogger.com/profile/15801959795245235917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
