通過MySQL的UDFs和Trigger操作Memcached
UDFs是User Defined Functions的縮寫,表示MySQL的使用者定義函式,應用程式可以利用這些函式從MySQL 5.0以上版本的資料庫中訪問Memcached寫入或者獲取的資料。此外,MySQL從5.1版本開始支援觸發器,從而可以在觸發器中使用UDFs直接更新Memcached的內容,這種方式降低了應用程式設計和編寫的複雜性。下面簡單介紹UDFs的安裝和使用。
UDFs安裝
安裝UDFs,需要依次安裝MySQL、libevent、memcached、libmemcached、memcached_functions_sql。
1. 安裝mysql-5.6.24.tar.gz
參照之前的博文《InnoDB memcached外掛部署》中MySQL安裝部分。
2. 安裝libevent-2.0.22-stable.tar.gz和安裝memcached-1.4.22.tar.gz
參照之前的博文《Memcached 1.4.22安裝和配置》。
3. 安裝libmemcached-0.34.tar.gz
memcached functions for mysql官網釋出的1.1版本是09年的,只相容libmemcached0.34版本。
mkdir -p /usr/local/libmemcached wget https://launchpad.net/libmemcached/1.0/0.34/+download/libmemcached-0.34.tar.gz tar zxvf libmemcached-0.34.tar.gz cd libmemcached-0.34 ./configure --prefix=/usr/local/libmemcached --with-memcached=/usr/local/bin/memcached make make install
4. 安裝memcached_functions_mysql
wget https://launchpad.net/memcached-udfs/trunk/1.1/+download/memcached_functions_mysql-1.1.tar.gz tar xvf memcached_functions_mysql-1.1.tar.gz cd memcached_functions_mysql-1.1 ./configure --prefix=/usr/local/memcache_mysql --with-mysql=/usr/local/mysql/bin/mysql_config --with-libmemcached=/usr/local/libmemcached make make install
5. 拷貝lib檔案到mysql的plugin下面
cp /usr/local/memcache_mysql/lib/libmemcached_functions* /usr/local/mysql/lib/plugin
6. 配置動態連結庫
echo "/usr/local/lib" >> /etc/ld.so.conf ldconfig
7. 新增memcache UDF 函式
mysql < ./sql/install_functions.sql
備註:
首次需要使用CREATE FUNCTION來初始化使用者定義函式。有兩種方法可以初始化所有MySQL提供的使用者定義函式:
第一種方法是在MySQL的SQL命令列中執行memcached_functions_mysql原始碼目錄下的sql/install_functions.sql。第二種方法是執行memcached_functions_mysql原始碼目錄下的utils/install.pl這個Perl指令碼,把memcache function作為UDFs加入MySQL。
8. 執行下面SQL命令,檢視安裝是否成功。
mysql> select name,dl from mysql.func; +------------------------------+---------------------------------+ | name | dl | +------------------------------+---------------------------------+ | memc_add | libmemcached_functions_mysql.so | | memc_add_by_key | libmemcached_functions_mysql.so | | memc_servers_set | libmemcached_functions_mysql.so | | memc_server_count | libmemcached_functions_mysql.so | | memc_set | libmemcached_functions_mysql.so | | memc_set_by_key | libmemcached_functions_mysql.so | | memc_cas | libmemcached_functions_mysql.so | | memc_cas_by_key | libmemcached_functions_mysql.so | | memc_get | libmemcached_functions_mysql.so | | memc_get_by_key | libmemcached_functions_mysql.so | | memc_get_cas | libmemcached_functions_mysql.so | | memc_get_cas_by_key | libmemcached_functions_mysql.so | | memc_delete | libmemcached_functions_mysql.so | | memc_delete_by_key | libmemcached_functions_mysql.so | | memc_append | libmemcached_functions_mysql.so | | memc_append_by_key | libmemcached_functions_mysql.so | | memc_prepend | libmemcached_functions_mysql.so | | memc_prepend_by_key | libmemcached_functions_mysql.so | | memc_increment | libmemcached_functions_mysql.so | | memc_decrement | libmemcached_functions_mysql.so | | memc_replace | libmemcached_functions_mysql.so | | memc_replace_by_key | libmemcached_functions_mysql.so | | memc_servers_behavior_set | libmemcached_functions_mysql.so | | memc_servers_behavior_get | libmemcached_functions_mysql.so | | memc_behavior_set | libmemcached_functions_mysql.so | | memc_behavior_get | libmemcached_functions_mysql.so | | memc_list_behaviors | libmemcached_functions_mysql.so | | memc_list_hash_types | libmemcached_functions_mysql.so | | memc_list_distribution_types | libmemcached_functions_mysql.so | | memc_udf_version | libmemcached_functions_mysql.so | | memc_libmemcached_version | libmemcached_functions_mysql.so | | memc_stats | libmemcached_functions_mysql.so | | memc_stat_get_keys | libmemcached_functions_mysql.so | | memc_stat_get_value | libmemcached_functions_mysql.so | +------------------------------+---------------------------------+ 34 rows in set (0.00 sec)
使用Trigger操作Memcached
1. 建立兩張表
新建兩張表:urls和results,更新urls表中的內容,使系統自動更新Memcached的內容。results用來記錄更新Memcached失敗的記錄。
SQL程式碼如下:
use test; drop table if exists urls; CREATE TABLE `urls` ( `id` int(10) NOT NULL, `url` varchar(255) NOT NULL DEFAULT ``, PRIMARY KEY (`id`) ); drop table if exists results; CREATE TABLE `results` ( `id` int(10) NOT NULL, `result` varchar(255) NOT NULL DEFAULT `error`, `time` timestamp NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`) );
2. 建立3個trigger
當向urls表中插入資料時,對Memcached執行set操作。trigger的程式碼如下:
DELIMITER // DROP TRIGGER IF EXISTS url_mem_insert; CREATE TRIGGER url_mem_insert BEFORE INSERT ON urls FOR EACH ROW BEGIN set @mm = memc_set(NEW.id, NEW.url); if @mm <> 0 then insert into results(id) values(NEW.id); end if; END // DELIMITER ;
當對urls表中的資料進行更新時,對Memcached執行replace操作。trigger程式碼如下:
DELIMITER // DROP TRIGGER IF EXISTS url_mem_update; CREATE TRIGGER url_mem_update BEFORE UPDATE ON urls FOR EACH ROW BEGIN set @mm = memc_replace(OLD.id,NEW.url); if @mm <> 0 then insert into results(id) values(OLD.id); end if; END // DELIMITER ;
當對urls表中的資料進行刪除操作時,對Memcached執行delete操作。trigger程式碼如下:
DELIMITER // DROP TRIGGER IF EXISTS url_mem_delete; CREATE TRIGGER url_mem_delete BEFORE DELETE ON urls FOR EACH ROW BEGIN set @mm = memc_delete(OLD.ID); if @mm <> 0 then insert into results(id) values(OLD.id); end if; END // DELIMITER ;
3. 設定Memcached相關引數
設定UDFs操作Memcaced伺服器的IP地址和埠。
mysql> SELECT memc_servers_set(`192.168.11.52:11211`); +-----------------------------------------+ | memc_servers_set(`192.168.11.52:11211`) | +-----------------------------------------+ | 0 | +-----------------------------------------+ 1 row in set (0.07 sec) mysql>select memc_server_count(); +---------------------+ | memc_server_count() | +---------------------+ | 1 | +---------------------+ 1 row in set (0.00 sec)
在MySQL命令列中列出可以修改Memcached引數的行為,執行的命令和輸出結果如下:
mysql>select memc_list_behaviors()G *************************** 1. row *************************** memc_list_behaviors(): MEMCACHED SERVER BEHAVIORS MEMCACHED_BEHAVIOR_SUPPORT_CAS MEMCACHED_BEHAVIOR_NO_BLOCK MEMCACHED_BEHAVIOR_TCP_NODELAY MEMCACHED_BEHAVIOR_HASH MEMCACHED_BEHAVIOR_CACHE_LOOKUPS MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE MEMCACHED_BEHAVIOR_BUFFER_REQUESTS MEMCACHED_BEHAVIOR_KETAMA MEMCACHED_BEHAVIOR_POLL_TIMEOUT MEMCACHED_BEHAVIOR_RETRY_TIMEOUT MEMCACHED_BEHAVIOR_DISTRIBUTION MEMCACHED_BEHAVIOR_BUFFER_REQUESTS MEMCACHED_BEHAVIOR_USER_DATA MEMCACHED_BEHAVIOR_SORT_HOSTS MEMCACHED_BEHAVIOR_VERIFY_KEY MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED MEMCACHED_BEHAVIOR_KETAMA_HASH MEMCACHED_BEHAVIOR_BINARY_PROTOCOL MEMCACHED_BEHAVIOR_SND_TIMEOUT MEMCACHED_BEHAVIOR_RCV_TIMEOUT MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK 1 row in set (0.00 sec)
設定MEMCACHED_BEHAVIOR_NO_BLOCK為開啟狀態,這樣在Memcached出現問題(不能連線)時,資料可以繼續插入MySQL中,但有報錯提示;如果不設定此值,那麼Memcached失敗時,資料需要等到Memcached失敗超時後才可以插入到表中。
通過下面的設定,可以避免這種情況的發生。
mysql>select memc_servers_behavior_set(`MEMCACHED_BEHAVIOR_NO_BLOCK`,`1`); +--------------------------------------------------------------+ | memc_servers_behavior_set(`MEMCACHED_BEHAVIOR_NO_BLOCK`,`1`) | +--------------------------------------------------------------+ | 0 | +--------------------------------------------------------------+ 1 row in set (0.00 sec) mysql>select memc_servers_behavior_set(`MEMCACHED_BEHAVIOR_TCP_NODELAY`,`1`); +-----------------------------------------------------------------+ | memc_servers_behavior_set(`MEMCACHED_BEHAVIOR_TCP_NODELAY`,`1`) | +-----------------------------------------------------------------+ | 0 | +-----------------------------------------------------------------+ 1 row in set (0.00 sec)
4. 對memcached_functions_mysql的簡單功能進行測試
1)向表urls中插入資料,然後檢視Memcached是否對資料執行set操作。
mysql>insert into urls (id,url) values (1, `http://www.test.com.cn`); Query OK, 1 row affected, 1 warning (0.00 sec) mysql> select memc_get(`1`); +------------------------+ | memc_get(`1`) | +------------------------+ | http://www.test.com | +------------------------+ 1 row in set (0.00 sec)
1>telnet 192.168.11.52 11211 Trying 192.168.11.52... Connected to 192.168.11.52 (192.168.11.52). Escape character is `^]`. get 1 VALUE 1 0 22 http://www.test.com.cn END
2)更新表urls裡面的資料,然後查詢Memcached中是否也進行了更新。
mysql>update test.urls set url=`http://blog.test.com.cn` where id=1; Query OK, 1 row affected, 1 warning (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> select memc_replace(`1`,`http://blog.test.com.cn`); +---------------------------------------------+ | memc_replace(`1`,`http://blog.test.com.cn`) | +---------------------------------------------+ | 0 | +---------------------------------------------+ 1 row in set (0.00 sec) mysql> select memc_get(`1`); +-------------------------+ | memc_get(`1`) | +-------------------------+ | http://blog.test.com.cn | +-------------------------+ 1 row in set (0.00 sec)
1>telnet 192.168.11.52 11211 Trying 192.168.11.52... Connected to 192.168.11.52(192.168.11.52). Escape character is `^]`. get 1 VALUE 1 0 23 http://blog.test.com.cn END
3)刪除表urls中的資料,然後檢視Memcached是否也將該資料刪除了。
mysql>delete from test.urls where id=1; Query OK, 1 row affected, 1 warning (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> select memc_get(`1`); +---------------+ | memc_get(`1`) | +---------------+ | NULL | +---------------+ 1 row in set (0.00 sec)
1>telnet 192.168.11.52 11211 Trying 192.168.11.52... Connected to 192.168.11.52 (192.168.11.52). Escape character is `^]`. get 1 END
5. 使用memcached_functions_mysql的經驗與技巧
memcached_functions_mysql使用起來比較簡單,但是由於環境的差別,在實踐過程中可能會遇到諸多的問題。下面總結了一些在使用memcached_functions_mysq過程中可能出現的問題和注意事項。
1) MySQL重啟問題
如果MySQL伺服器出現重啟,需要重新設定連線Memcached關係(SELECT memc_servers_set(`192.168.11.52:11211`))。
2) 程式BUG問題
memcached_functions_mysql的源程式有可能存在bug,並且會導致MySQL的失敗。針對這個問題,讀者要儘量選擇源程式的穩定版本。
3) 網路因素
網路因素是指MySQL和Memcached是否處在同一個IDC、它們之間的網路效能是否很好。網路效能越好,則速度越快。使用本機的Memcached可以適當減少網路開銷。
4) 插入的資料量
插入資料量的大小包含兩個方面:向MySQL插入每條記錄的大小,向Memcached中更新資料的大小。更新MySQL、Memcached的資料越大,更新的速度越慢。因此,要做好前期規劃。
5) 延時問題
如果MySQL所在的機器使用的資源比較大,會導致更新Memcached過於緩慢,即出現類似m/s的延時問題。
6) 容災問題
如果MySQL和Memcached中有當機情況出現時,需要考慮怎麼恢復,根據前一小節的測試可以這樣考慮:建一張錯誤表,如果在更新mc時出現問題,自動把更新錯誤的記錄插到這張表中,通過查詢這張表,可以知道哪些資料在什麼時間出現過更新錯誤。
如果memcached_functions_mysql應用於生產環境,需要考慮監控和出現問題時的恢復工作(寫好指令碼以完善這個工作)。
7) MySQL自身因素
如執行的MySQL語句的效率以及連線MySQL的client程式(php)的連線開銷等,這些問題都需要考慮。