Saturday, August 11, 2007

Rate limiting for InnoDB

What is rate limiting in MySQL and why might you need it? For starters this is limited to the InnoDB engine. InnoDB had performance problems on SMP servers and uses rate limiting as a workaround. There is an excellent description of this at mysqlperformanceblog.com. InnoDB limits the number of threads that can execute concurrently by giving each thread a number of tickets and making threads sleep when they are out of tickets and too many other threads are active.

Unfortunately, the replication thread is not given special treatment. It gets no more tickets than other sessions. On a busy replica where the number of concurrent queries exceeds innodb_thread_concurrency, replication can get far behind as the replication thread spends too much time waiting for tickets. This is easy to fix. Change the code so that the replication thread gets many more tickets per allocation than other threads. The result of this change is much less replication delay on busy slaves.

This feature in InnoDB can also be used to rate limit accounts that are using too many resources on a busy server. The trick is to provide a mechanism to change the number of tickets that a session may get at the account level. When too much work is done by one account and there is no easy way to change applications that use the account, reducing the number of tickets given to sessions for that account is a good way to make that account use less of a server. This requires a mechanism for setting the the equivalent of innodb_concurrency_tickets per account. This can be done by adding new SQL syntax to the parser, adding a system variable that can be set with a comma-separated list of account and number of ticket pairs or by redefining the values of rarely used columns in the mysql.user table. Since I have never been fond of the max_questions and max_updates columns in mysql.user, I would use the value of the column, when not set to 0, to be the per-account value for innodb_concurrency_tickets.

4 comments:

  1. InnoDB merely needs to allow innodb_concurrency_tickets to be set per SESSION rather than just GLOBAL.
    The rest can then be implemented without further server modifications.

    ReplyDelete
  2. The primary use case for this is for a DBA to set the value for future logins from an account. alter session SET innodb_concurrency_tickets will only set the value for the current session.

    ReplyDelete
  3. Mark - if it could be set per session, you could do it for future logins from an account. You could use init_connect to have all users execute a stored procedure upon login (say, "session_init"), that could set innodb_concurrency_tickets for their session based upon who they are. (Just a way it could be done.)

    ReplyDelete
  4. All,

    Vasil has just recently done this change in 5.1:

    http://bugs.mysql.com/bug.php?id=25078

    "
    The SQL thread on a slave now is always allowed to enter InnoDB even
    if this would exceed the limit imposed by the
    innodb_thread_concurrency system variable. In cases of high load on
    the slave server (when innodb_thread_concurrency is reached), this
    change helps the slave stay more up to date with the master; in the
    previous behavior, the SQL thread was competing for resources with
    all client threads active on the slave server.
    "

    Regards,

    Heikki

    ReplyDelete

 
Creative Commons License
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.