레이블이 master인 게시물을 표시합니다. 모든 게시물 표시
레이블이 master인 게시물을 표시합니다. 모든 게시물 표시

2014년 11월 22일 토요일

Why TokuDB need to redo log sync on internal XA

TokuDB has option whether redo log flush(sync) after each transaction or not like InnoDB. The option name is tokudb_commit_sync. If you set tokudb_commit_sync=OFF, TokuDB will not sync redo log or doing that periodically based on tokudb_fsync_log_period option. 

Usually we use deferred redo log sync mode. Redo log sync mode need a lot of disk write IO. But there's a lot of service where data is not so important (1~5 seconds data loss is allowed). And semi-sync replication or gallera-cluster doesn't need redo log to be synced on every commit.

But current version of TokuDB (now 7.5.2), enabling binary log is very expensive (even tokudb_commit_sync is OFF). TokuDB's redo log commit mode will be changed ON(sync on every transaction commit) automatically when your server's binary log is activated.
TokuTek says it's because of internal XA(Two-phase commit) between Binary log and TokuDB storage engine. But I can't understand why redo log sync is need for internal XA (Actually binary log is not synced when TokuDB do XA, only TokuDB redo log)
But InnoDB doing async mode flush(sync) both redo log and binary log. Why only TokuDB need to sync or redo log ?

I don't know TokuDB's internal story. Anyway I changed TokuDB redo log will be flushed async even though binary log activated (of couse tokub_commit_sync=OFF).
No weird things happened on my simple crash scenario like server failure and MySQL server failure (Of course tokudb_commit_sync is OFF, so last few second's data is lost). And also replicated data too.
But we can't simply disable TokuDB XA feature. Because it makes binary log and TokuDB redo stored different order. So your slave can different data from master.

Binary log
  UPDATE account SET money=money*10 WHERE id=?;
  UPDATE account SET money=money+100 WHERE id=?;

Redo log
  UPDATE account SET money=money+100 WHERE id=?;
  UPDATE account SET money=money*10 WHERE id=?;

Actually I heard that recent version of TokuDB added parameter for disabling XA. What makes TokuDB so strictly need redo log sync on XA ?
So I asked about this on tokudb-dev google groups, But I have not heard the reason. Below is my question I wrote on tokudb-dev groups.

-------------------------------------------------
I have question about TokuDB internal two – phase commit of MySQL(+TokuDB).
According to TokuDB ft-index source code (https://github.com/Tokutek/ft-index/blob/master/ft/txn/txn.cc),

toku_txn_prepare_txn() and toku_txn_commit_txn() have a little bit different sync mode.

void toku_txn_prepare_txn (TOKUTXN txn, TOKU_XA_XID *xa_xid) {
….
txn->do_fsync = (txn->force_fsync_on_commit || txn->roll_info.num_rollentries>0);
….
}

// toku_txn_commit_txn() –> toku_txn_commit_with_lsn()
int toku_txn_commit_with_lsn(TOKUTXN txn, int nosync, LSN oplsn,
TXN_PROGRESS_POLL_FUNCTION poll, void *poll_extra)
{
….
txn->do_fsync = !txn->parent && (txn->force_fsync_on_commit || (!nosync && txn->roll_info.num_rollentries>0));
….
}

As you can see, toku_txn_commit_txn() take into account nosync parameter and nosync parameter is actually determined by tokudb_commit_sync system variables. So If user set “tokudb_commit_sync=OFF” then toku_txn_commit_txn() is not call fsync() for toku redo log.
But toku_txn_prepare_txn() is not take into account this system variable. So toku_txn_prepare_txn() always call fsync() for tokudb redo log even though user set “tokudb_commit_sync=OFF”.

Is there any reason that prepare() does always call fsync() for tokudb redo log (on tokudb_commit_sync=OFF configured TokuDB) ?


This is related with below thread and we already talked about this issue a few months ago.
-------------------------------------------------

And still we are waiting for the answer.

2014년 6월 22일 일요일

Memcached Replication (3)

This is the last article about Memcached Replication.If you missed previous two article, Read below article first for understanding.

  1. http://seonguck.blogspot.kr/2014/06/memcached-replication-1.html
  1. http://seonguck.blogspot.kr/2014/06/memcached-replication-2.html 



Install

Download KMC source first from GitHub.
https://github.com/kakao/mysql_5.6.14_kmc

To build KMC, you need to install basic library needed for MySQL 5.6.
Especially there's a lot of system which lack of libaio-devel and ncurses-devel and cmake.
And you need to install libmemcached library and development package.

libmemcached-1.0.4-1.el5.remi.x86_64.rpm
libmemcached-devel-1.0.4-1.el5.remi.x86_64.rpm

Now you can build KMC, you should run cmake with a few options.

# cd mysql-5.6.14_kmc
# mkdir Release
# cd Release
# cmake .. \
'-DBUILD_CONFIG=mysql_release' \
'-DCMAKE_INSTALL_PREFIX=/usr/local/mysql' \
'-DWITH_INNODB_MEMCACHED=ON' \
'-DENABLED_LOCAL_INFILE=OFF' \
'-DHAVE_QUERY_CACHE=OFF' \
'-DOPTIMIZER_TRACE=OFF' \
'-DENABLE_DEBUG_SYNC=OFF' \
'-DENABLED_PROFILING=OFF' \
'-DWITH_ARCHIVE_STORAGE_ENGINE=OFF' \
'-DWITH_EMBEDDED_SERVER=OFF' \
'-DENABLE_DTRACE=OFF'

Of course you don't need to all options, but you should put "DWITH_INNODB_MEMCACHED" for Memcached plugin of MySQL.
After cmake, just run make && make install. After installing you can find built MySQL executables in the directory you specified as INSTALL_PREFIX.
Before starting MySQL server, you should run $MYSQL_HOME/scripts/mysql_install_db script to create default dictionary schema as normal MySQL server.


Creating Memcached related schema.

After starting MySQL server, you should create Memcached related schema to activate Memcached plugin.
Initialization script is located in your MySQL home directory. Just run it.
Actually this procedure also need to original MySQL Memcached plugin not only for KMC. 

mysql> source $MYSQL_HOME/share/innodb_memcached_config.sql
mysql> use innodb_memcache
mysql> show tables

Check below three tables have created in innodb_memcache database.


  • cache_policies
  • config_options
  • containers


Now we need to initialize KMC basic schema.

mysql> USE innodb_memcache;
mysql> INSERT INTO `containers` VALUES ('default','kmc','kmc_template','k','v','f','c','e','PRIMARY');

mysql> CREATE DATABASE kmc;
mysql> USE kmc;

mysql> DROP TABLE IF EXISTS `kmc_template`;
mysql> CREATE TABLE `kmc_template` (
  `k` varchar(255) CHARACTER SET latin1 COLLATE latin1_bin NOT NULL DEFAULT '',
  `v` mediumblob,
  `f` int(11) NOT NULL DEFAULT '0',
  `c` bigint(20) unsigned NOT NULL DEFAULT '0',
  `e` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`k`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 STATS_PERSISTENT=0;

## Don't need this default row anymore, But I am not sure.
mysql> INSERT INTO `kmc_template` VALUES ('1','DO-NOT-REMOVE',0,0,0);

On this procedure, table name must start with "kmc_" prefix.


Configurations

Lastly change my.cnf configuration file for KMC. Below options are not only for KMC but also memcached performance.
We don't use KMC as InnoDB or MyISAM engine together. So I changed InnoDB options minimally.
This is not so strict options(except kmc_connect_string and binlog-format), so you can change it for your system standardizations.

## InnoDB ------------------------
...
innodb_data_file_path = ibdata1:64M:autoextend
...
innodb_log_file_size = 32M
innodb_log_files_in_group = 2
innodb_log_buffer_size = 16M

## Memcached --------------------
daemon_memcached_option = '-m 20480 -p 11211 -c 80000 -t 8 -s /tmp/memcached.sock'
innodb_api_enable_binlog = 1
innodb_api_trx_level=0 ## READ-UNCOMMITTED
innodb_api_bk_commit_interval=1
daemon_memcached_r_batch_size=1
daemon_memcached_w_batch_size=1
innodb_api_enable_mdl=OFF

## Replication:Binary log -----------
server-id  = 1
## Replication query is always idempotent
slave_exec_mode = IDEMPOTENT
## Memcached connection string :: with socket file
kmc_connect_string = '--SOCKET="/tmp/memcached.sock" --BINARY-PROTOCOL --NOREPLY --TCP-NODELAY --TCP-KEEPALIVE'
binlog-checksum = NONE
sync_binlog = 0
master_info_repository = FILE
relay_log_info_repository = FILE
sync_master_info    = 0
sync_relay_log      = 0
sync_relay_log_info = 0
slave_checkpoint_group = 100000
slave_checkpoint_period = 1000
max_binlog_size = 100M
expire_logs_days=1
expire_max_log_files = 15
binlog-format = ROW

daemon_memcached_option is Memcached plugin startup options and kmc_connect_string option is for SQL thread of slave MySQL server.
Now starting MySQL server and check the basic function on.
And you can check replication setup and the way to check replication status out is same as original MySQL server.


Testing Memcached and Replication

MySQL Memcached plugin support both binary and text mode protocol, so we can simply test memcached operation with telnet program.

[root@matt001 ~]# telnet localhost 11211
Trying 127.0.0.1...
Connected to localhost.localdomain (127.0.0.1).
Escape character is '^]'.

set matt 0 0 9
Seong Uck
STORED

get matt
VALUE matt 0 9
Seong Uck
END

delete matt
DELETED

get matt
END

quit
Connection closed by foreign host.

If you want to check whether socket file(/tmp/memcached.sock) is working correctly, you can use netcat utility. In this case you can't use telnet.

[root@matt001 ~]# nc -U /tmp/memcached.sock
set matt 0 0 9
SEONG UCK
STORED

get matt
VALUE matt 0 9
SEONG UCK
END

quit
[root@matt001 ~]#

If you want to check the replicated data, run GET operation on slave memcached after run SET on master memcached.
Of course you can inspect the binary log file through mysqlbinlog utility.



Memcached replication feature(Added feature) does't have unit test yet. So you should be carefull.

2014년 6월 21일 토요일

Memcached Replication (2)

Modifications

As written in the first article about Memcached Replication, need to change some of MySQL 5.6 source code.
Below diagram will explain how MySQL Memcached plugin works and what I modified.



(Blue line is original behavior of MySQL 5.6 Memcached plugin's Caching and Innodb-only mode, Bold brown line means my modifications)


And the number of the diagram means ...


  1. InnoDB API will transfer the input data to InnoDB engine(Table) as configured with innodb_api_bk_commit_interval, daemon_memcached_r_batch_size, daemon_memcached_w_batch_size system variables. And after that InnoDB API will write changes to binary log. But this is not happened on Cache-only mode. I modified MySQL code as memcached changes is also written to binary log but not apply that changes to InnoDB engine on Cache-only mode Memcached plugin. On original MySQL 5.6 Memcached plugin, dictionary table(innodb_memcache DB) and container table needs for Caching and Innodb-only cache mode not for Cache-only mode. But after modification dictionary table and container table is gotten to need for binary log writting. Of course we will not store memcached data to container table, but need it's template for binary log writting. 
  2. On slave side, SQL thread have to apply relay log gotten by IO thread to MySQL Memcached plugin NOT InnoDB tables. But on original MySQL replication, SQL thread directly access InnoDB API not Memcached. I need a way to access to Memcached plugin. I implemented it as SQL thread bring up another memcached client (using libmemcached client library). I can use Non-blocking mode mode with libmemcached client library for fast relay log applying. Actually in original MySQL 5.6, libmemcached.so shared library also exist on your $MYSQL_HOME/lib/plugin, So I renamed it as "libmemcachedserver.so" so that install libmemcached RPM separately on the same system.
  3. Repication SQL thread act as Memcached client have to run as fast as possible, so modified SQL thread's memcached client connect to Memcached socket file rather than 11211 TCP port. And worked as Non-blocking mode for fast replication. Actually SQL thread will apply relay log event as sync-mode on every 100th request so that slave can check replication apply error.




Another modifications


  • Originally, Memcached plugin never open both of TCP port and Unix domain socket at the same time, But I need both channel.
  • Copy Memcached plugin's status metric to MySQL server's status variables so that we can monitor memcached status with MySQL monitoring tool.InnoDB master thread will copy memcached status metrics to MySQL status variables every second.

mysql> show global status like '%kmc%';
+----------------------------------+--------------+
| Variable_name                    | Value        |
+----------------------------------+--------------+
| Innodb_kmc_connection_structures | 2004         |
| Innodb_kmc_curr_connections      | 2002         |
| Innodb_kmc_curr_items            | 70638969     |
| Innodb_kmc_pointer_size          | 64           |
| Innodb_kmc_threads               | 8            |
| Innodb_kmc_total_connections     | 5090         |
| Innodb_kmc_total_items           | 778120599    |
| Innodb_kmc_bytes                 | 18648687816  |
| Innodb_kmc_bytes_read            | 460650586044 |
| Innodb_kmc_bytes_written         | 497924594841 |
| Innodb_kmc_cmd_get               | 7781206118   |
| Innodb_kmc_cmd_set               | 778120599    |
| Innodb_kmc_evictions             | 498675673    |
| Innodb_kmc_get_hits              | 1043938514   |
| Innodb_kmc_get_misses            | 6737267604   |
| Innodb_kmc_limit_maxbytes        | 21474836480  |
+----------------------------------+--------------+


  • Fix related memory leak of MySQL 5.6.14 and expiration time bug of Memcached plugin.
  • Remove every file sync call for fast processing (if possible).
  • Add expire_max_log_files system variables so that we can control total binary logs' size by file count.(This features only use binary log file's suffix number, so if you use frequent "PURGE LOGS" or other commands which switch binary log file, expire_max_log_files system variables will not work as expected)
  • Add Binlog_purge_failed system status variable for monitoring binary log purge
    • 0 : Okay
    • 1 : Set when MySQL server attempt to remove ACTIVE state binary log.
    • 2 : SET when MySQL server attempt to remove USE state binary log.
  • Add kmc_connect_string system variable so that you can change how SQL thread connect to it's local memcached plugin. You can change it whenever you want because it is dynamic variable. But You have to "STOP/START SLAVE" for applying change.




Usable Memcached Operations

Unfortunately on KMC(Kakao MemCached), Some of memcached operations are not usable. It's because of Memcached replication characteristic (And have not tested it).

Usable operations

  • GET
  • SET
  • ADD
  • DELETE
  • REPLACE


Not implemented or Not tested

  • INCREMENT
  • DECREMENT
  • CAS


Performance

GET operations' performance is same as Original Memcached. But SET/ADD/DELETE operations need to written to disk (Binary log file). And there's a lot of complex processing are involed even though it's not sync mode. So SET/ADD/DELETE performance is dramatically lower than original memcached server.
But general purpose of Memcached server, SET/ADD/DELETE operations is not so many. Once data item is cached on Memcached, then GET operation is performed all the time.
If not (If there's a lot of SET/ADD/DELETE), that memcached server has no effect becuase cache ratio is low. And in this case Memcached server only add overhead (I think).

I also modified SQL thread work as parallel based on row, But MySQL 5.6 multi threaded replication make a lot of sync overhead(CPU overhead) among slave threads and coordinate thread.

MySQL Memcached plugin can process more SET/ADD/DELETE operations than normal MySQL's SQL statements, but you have to consider replication.
SQL thread of slave side is working as single thread, and this might be bottleneck.
On Intel X86 commodity server, I think 10k SET/ADD/DELETE operations are limit. it's the limit of replication (No replication delay status)
So I added expire_max_log_files system variable and Binlog_purge_failed system status variable. If you have enough memory, allocate some of memory for binary log directory using RamFS or RamDisk for SET/DELETE/ADD operation's performance. Added system variable and status variable will help RamFs usage management.





Some limitations


  • Container table name must start with "kmc_".
  • Can't use CAS, INCR and DECR operations.
  • KMC(Kakao MemCached) use two upper bytes of Memcached flags field for originated server_id. So this is not compatible with your memcached client.
  • KMC will convert your DELETE operation to SET operation with 1 second expire (because we can't use flags field on DELETE operation).




Download

https://github.com/kakao/mysql_5.6.14_kmc

Memcached Replication (1)

Purpose

A lot of applications have data which have to be stored persistently. And theses data is stored on RDBMS or NoSQL solutions.
Sometimes these applications need a lot of data search operations, but current RDBMS or NoSQL solutions can't serve this requirement.
RDMBS or NoSQL solutions do really complicated internal processing for applications' request, and they have to store data to disk slowest component of computer.
So we use memory cache solution like Redis or Memcached. But they also have weak points especially Memcached doesn't have repilcation features.
Redis, this cache solution also have some weak points, this is not why I am focusing Memcached in this article.
We use a lot of Memcached on our service already, and I have to make Memcached can replicate data to remote Memcached(like slave of mysql) without migrating to Redis.

Some people doesn't feel any needs for Memcached replication. 
But replication feature is necessary for multi-idc synchronization. And multi-idc synchronization is need for disaster recovery or IDC location aware services.
Redis has replication features, but Memcached server has not. Redis can serve complex data types but Memcached not. On the other hand, Memcached has it's own advantages.
(I don't want to metion about "Why Memcached is better than Redis, and Why Redis better than Memcached", What I want to say in this article is there's still a lot of people use Memcached server).
Some company made mysql server's binary log parser and relay it to Memcached server of multi IDC. Because usually cached data items are originated from database server.
And this way, solve a lot of complexity of application.

Also our company(Kakao corp) has same needs for DR or location aware services.
But above binary log parsing method need a few change of sql statement of applications. It's not fully transparent from application.


MySQL 5.6 Memcached plugin

MySQL 5.6 is released during I am looking for memcached replication method, First time I saw the MySQL Memcached plugin it seems that it doesn't have no usability.
But after a few days, Suddenly I thought we use MySQL Server's Memcached plugin as standalone memcached server and easily have memcached replication. Because Memcached data change will be written to mysql binary log through MySQL(InnoDB API). MySQL Memcached plugin has below three cache policy.


  • Innodb-only
  • Caching
  • Cache-only


First of all, Memcached plugin act as whole memory operation. So we could not use Inoodb-only and Caching policy because memcached data will be stored in innodb finally on this two policy. We have to use Cache-only policy. But unfortunately Memcached data is never written to binary log because memcached data is not stored in InnoDB on Cache-only policy.
And this is only the story for binary log writting. But on slave side SQL thread will relay binary log contents to InnoDB only, Not memcached plugin.

If I changed MySQL as writting data change to binary log on master and apply change to memcached plugin on slave, Memcached replication can be possible.
This is not so easy task, but it would be best way to implement it. We don't have to implement whole replication features on Memcached and MySQL replication features is really stable.