1. 程式人生 > >【Java】利用Gearman進行Mysql到Redis的複製

【Java】利用Gearman進行Mysql到Redis的複製

開始的架構圖已經有寫得非常漂亮的。我這裡就不重新再編輯了。java 版本實現job server和worker從第6點開始,紅色部分是我遇到的一些坑。。。

1, 環境

CentOS 64位, MySQL, Redis, Java

mysql安裝通過lnmp進行安裝。所以預設安裝路徑為/usr/local/mysql

2, Redis簡介

Redis是一個開源的K-V記憶體資料庫,它的key可以是string/set/hash/list/...,因為是基於記憶體的,所在訪問速度相當快。

Gearman是一個開源的Map/Reduce分散式計算框架,具有豐富的client sdk,而且它支援MySQL UDF。

Gearman工作圖

Gearman工作圖

Gearman呼叫流程

Gearman呼叫流程

Gearman叢集

從圖中可以看出貌似Gearman的叢集功能比較弱,Job Server之間沒啥關係好像。
Gearman叢集

4, MySQL - Redis配合使用方案

MySQL - Redis配合使用方案

首先我們以MySQL資料為主,將insert/update/delete交給MySQL,而select交給redis;
當有資料發生變化時,通過MySQL Trigger實時非同步呼叫Gearman的UDF提交一個job給Job Server,當job執行的時候會去更新redis;從而保證redis與MySQL中的資料是同步的。

5, 軟體安裝

安裝gearman

//安裝依賴
$ yum install -y boost-devel gperf libevent-devel libuuid-devel //下載gearman 2015-12-10來看都是最新版本 $ wget https://launchpad.net/gearmand/1.2/1.1.12/+download/gearmand-1.1.12.tar.gz $ tar zxvf gearmand-1.1.12.tar.gz //編譯安裝,指定mysqlclient的連結路徑
$ ./configure $ make $ make install //啟動gearmand服務端 (啟動之時,在/var/log/下建立gearmand.log日誌檔案。-l 指定日誌檔案 -d後臺執行 -L 0.0.0.0 繫結到IPV4)
$ /usr/local/sbin/gearmand -L 0.0.0.0 -l /var/log/gearmand.log -d
//檢視是否啟動成功[[email protected] mysql]# ps -ef | grep gearman root     31142     1  0 17:06 ?        00:00:00 /usr/local/sbin/gearmand -L 0.0.0.0 -l /znwx/logs/gearmand/gearmand.log -d root     31174 30507  0 17:40 pts/0    00:00:00 grep gearman//檢視是否安裝成功,檢視gearman版本 $ /usr/local/sbin/gearmand -V

5, MySQL UDF + Trigger同步資料到Gearman

安裝lib_mysqludf_json

lib_mysqludf_json可以把MySQL表的資料以json資料格式輸出

//下載lib_mysqludf_json(地址:https://github.com/mysqludf
$ cd lib_mysqludf_json
先刪除 lib_mysqludf_json.so
//編譯 mysql_config 這是mysql的配置檔案,可以 find /usr -name mysql_config 搜尋下在什麼位置
$ gcc $(/usr/local/mysql/bin/mysql_config  --cflags) -shared -fPIC -o lib_mysqludf_json.so lib_mysqludf_json.c
//拷貝lib_mysqludf_json.so到MySQL的plugin目錄
//可以登陸MySQL,輸入命令"show variables like '%plugin%'"檢視plugin位置
$ cp lib_mysqludf_json.so /usr/lib64/mysql/plugin/

//演示lib_mysqludf_json功能
$ mysql -uname -hhost -ppwd
//首先註冊UDF函式
mysql> CREATE FUNCTION json_object RETURNS STRING 
       SONAME "lib_mysqludf_json.so";
//json_array|json_members|json_values函式註冊方式與json_object一樣.
mysql> use test;
mysql> select * from user_list;
+------+----------+
| NAME | PASSWORD |
+------+----------+
| troy | pwd      |
+------+----------+
mysql> select json_object(name,password) as user from user_list;
+----------------------------------+
| user                             |
+----------------------------------+
| {"name":"troy","password":"pwd"} |
+----------------------------------+

安裝gearman-mysql-udf

//下載 2015年12月10日已知最新版本
$ wget https://launchpad.net/gearman-mysql-udf/trunk/0.6/+download/gearman-mysql-udf-0.6.tar.gz
$ tar zxvf gearman-mysql-udf-0.6.tar.gz
$ cd gearman-mysql-udf-0.6

//安裝libgearman-devel
$ yum install libgearman-devel

//編譯安裝

//可以登陸MySQL,輸入命令"show variables like '%plugin%'"檢視plugin位置, mysql_config的配置檔案,以及外掛庫所在路徑,編譯之後會在此路徑生成.so檔案

./configure --with-mysql=/usr/local/mysql/bin/mysql_config --libdir=/usr/local/mysql/lib/plugin/

$ make && make install //登入MySQL註冊UDF函式 mysql> CREATEFUNCTION gman_do_background RETURNS STRING SONAME "libgearman_mysql_udf.so"; mysql> CREATEFUNCTION gman_servers_set RETURNS STRING SONAME "libgearman_mysql_udf.so";//函式gman_do|gman_do_high|gman_do_low|gman_do_high_background|gman_do_low_background|gman_sum註冊方式類似,請參考gearman-mysql-udf-0.6/README//指定gearman job server地址 mysql> SELECT gman_servers_set('127.0.0.1:4730');

如果出現異常資訊:
ERROR 1126 (HY000): Can't open shared library 'libgearman_mysql_udf.so' (errno: 11 libgearman.so.8: cannot open shared object file: No such file or directory)
表示系統找不到 libgearman.so 檔案,一般so都在/usr/local/lib目錄下,修改配置檔案/etc/ld.so.conf,將/usr/local/lib目錄加入進去即可:

$ cat /etc/ld.so.conf
include ld.so.conf.d/*.conf
/usr/local/lib
$ /sbin/ldconfig -v | grep gearman*

MySQL Trigger呼叫Gearman UDF實現同步

DELIMITER $$
CREATE TRIGGER user_list_data_to_redis AFTER UPDATE ON user_list
  FOR EACH ROW BEGIN
    SET @ret=gman_do_background('MySQLToRedis', json_object(NEW.name as 'name', NEW.password as 'password')); 
  END$$
DELIMITER ;

6、這裡才是重點:java實現job server 和worker或者單worker,網上都是一些php的。可惡啊。。。。。

我上程式碼了:

/**
 * mysql 同步到 redis 的工具類。連線遠端gearman job server
 * 實現原理 
 * mysql_udf  >>>>>  gearman job server>>>> gearm worker(本類) >>>>> redis
 * @author 堼宸落宇 2015年12月10日
 *
 */
@Component
public class MysqlToRedisWorker implements GearmanFunction{
	private static final Logger log = LoggerFactory.getLogger(MysqlToRedisWorker.class);
	
	public static final String ECHO_FUNCTION_NAME = "MySQLToRedis";
	
	@Autowired
	private Config config;
    
	/**
	 * 連線其他jobserver用的。
	 */
	public void startWorker() {
		Gearman gearman = Gearman.createGearman();  //建立gearman物件,無論是client,worker都是由這個物件產生的
		log.info("MysqlToRedisWorkder connection:"+config.getEchoHost()+":"+config.getEchoPort()+",function:"+MysqlToRedisWorker.ECHO_FUNCTION_NAME);
		GearmanServer server = gearman.createGearmanServer(config.getEchoHost(), config.getEchoPort());  //建立gearman server,主要是server地址和埠

        GearmanWorker worker = gearman.createGearmanWorker();  //正題來了,建立work節點。
        worker.setReconnectPeriod(2, TimeUnit.SECONDS);  //設定超時重連時間
        worker.setMaximumConcurrency(5);  //最大併發數

        worker.addFunction(<span style="color:#cc0000;">ECHO_FUNCTION_NAME</span>, this);  //新增function方法
        worker.addServer(server);  //將work新增到server中
        log.info("MysqlToRedisWorkder is started!!!!");
	}
	
	@Override
	public byte[] work(String func, byte[] data, GearmanFunctionCallback callback)
			throws Exception {
		
		log.info("收到mysql的資料:::"+new String(data));
		System.out.println("@@@@@ " + new String(data));  //byte[] data是從client傳遞來的引數,我們將引數增加@@@@字串後,原封不動返回
        return data;
	}

說明以及問題:此類採用了gearman官網的java-gearman-service(地址:https://code.google.com/p/java-gearman-service/),目前release版本是0.6.6。java-gearman-servic.jar包中,即包括gearman server,還包括client和work客戶端API,此包在谷歌上。我這裡上傳了一份:http://download.csdn.net/detail/u012386696/9343319.

問題:config類為spring注入的配置檔案類,在worker.addFunction中,如果通過config類的屬性,並且屬性是從配置檔案來的就會有問題。不知道為啥,寫死就是OK的。此類連線遠端的gearman job server.

jar包需要新增到本地jar倉庫:

mvn install:install-file -Dfile=C:\software\java-gearman-service-0.6.6.jar -DgroupId=org.gearman.jgs -DartifactId=java-gearman-service -Dversion=0.6.6 -Dpackaging=jar

7、建立一個job server並註冊worker,本地服務。

/**
 * 建立一個job server 伺服器,並且註冊一個worker。
 * @author <span style="font-family: tahoma, helvetica, arial;">堼宸落宇</span><span style="font-family: tahoma, helvetica, arial;">  2015年12月10日</span>
 *
 */
@Component
public class MysqlToRedisJobServer {
	private static final Logger log = LoggerFactory.getLogger(MysqlToRedisJobServer.class);
	
	@Autowired
	MysqlToRedisWorker mysqlToRedisWorker;
	@Autowired
	Config config;
	
	public void startJobServer() throws Exception{
		 /*
         * Create a Gearman instance
         */
        Gearman gearman = Gearman.createGearman();

        try {

                /*
                 * Start a new job server. The resulting server will be running in
                 * the local address space.
                 * 
                 * Parameter 1: The port number to listen on
                 * 
                 * throws IOException
                 */
                GearmanServer server = gearman.startGearmanServer(config.getEchoPort());
                
                if (server!=null) {
					log.info("Start gearm jobServer with java !funcname:"+MysqlToRedisWorker.ECHO_FUNCTION_NAME+" port:"+config.getEchoPort());
				}
                
                /*
                 * Create a gearman worker. The worker poll jobs from the server and
                 * executes the corresponding GearmanFunction
                 */
                GearmanWorker worker = gearman.createGearmanWorker();

                /*
                 *  Tell the worker how to perform the echo function
                 */
                worker.addFunction(MysqlToRedisWorker.ECHO_FUNCTION_NAME, mysqlToRedisWorker);

                /*
                 *  Tell the worker that it may communicate with the given job server
                 */
                worker.addServer(server);

        } catch (IOException ioe) {

                /*
                 * If an exception occurs, make sure the gearman service is shutdown
                 */
                gearman.shutdown();

                // forward exception
                throw ioe;
        }
	}

說明以及問題:這裡建立一個job server,並設定監聽埠。。

到這裡就完成了java版本的mysql到redis的複製。可沒看到複製到redis中啊。worker類的work方法就是從mysql_udf中傳過來的,這裡就隨便怎麼玩了,不是麼。。。  備註  謹記 2天的成果

相關推薦

Java利用Gearman進行Mysql到Redis的複製

開始的架構圖已經有寫得非常漂亮的。我這裡就不重新再編輯了。java 版本實現job server和worker從第6點開始,紅色部分是我遇到的一些坑。。。 1, 環境 CentOS 64位, MySQL, Redis, Java mysql安裝通過lnmp進行安裝。

Matplotlib利用Python進行繪圖

官方文檔 ech subplot 表達式 str -m 多條 isp 字符串 【Matplotlib】   教程:https://morvanzhou.github.io/tutorials/data-manipulation/plt/   官方文檔:https://m

JAVA使用Mockito進行單元測試

1. @Mock與@InjectMocks的作用 @Mock:建立一個Mock @InjectMocks:建立一個例項(被測試類的例項,一般只用一次該註解) 在單元測試某個類的時候,需要標註@InjectMocks,該類的變數需要添加註解@Mock,當需要用到被測試類中

java利用第三方的IP地址屬地查詢

任務是根據IP地質查詢所述的省份,可以運用第三方的工具。 網上搜了一下,採用了網上的現成程式碼並進行了修改:返回的引數封裝成了DTO,包含所屬國家、地區、省份、城市、網際網路服務提供商。 放到同一個pakage裡,執行Test.java或參照Test.java呼叫即可。

JAVA利用反射呼叫不同方法,減少重複程式碼

今天在寫大作業的時候,遇到如下問題:整個方法裡只有資料獲取時的get方法不同,如何通過傳遞進來的不同的例項引數來使用不同的方法,而避免大段的程式碼copy,做到程式碼複用。於是今天粗略地瞭解了反射機制

Java利用自帶的file.mkdirs()建立資料夾與file.mkdirs()的注意事項

利用Java的自帶命令file.mkdirs();是可以直接在系統建立資料夾的。比如在d:\1資料夾下建立一個2的資料夾,則這樣寫:import java.io.*;  publicclass FileMkdirTest {      publicstaticvoid mai

Java利用String的compareTo比較兩個時期字串

在《【Java】比對兩個以字串形式表示的時期是否相差超過1天》(點選開啟連結)曾經介紹過,如果利用字串的擷取來比較兩個在資料庫中取出來,被特定格式化的日期。然而,這具有一定的侷限性,最大的缺點出在擷取字串太複雜太麻煩。 其實可以利用String的compareTo比較兩個表

Java對文件或文件夾進行重命名

更改 執行 board oid 文件名 file data- pla bsp 在Java中,對文件或文件夾進行重命名是很簡單的,因為Java的File類已經封裝好renameTo的方法。 修改文件或者文件夾的名字都使用這個方法。例如如下的程序: [java

javaspring項目中 對entity進行本類間的克隆

tor mini cti false display des private rac 重寫 方法1: 【使用spring自帶BeanUtils實現克隆】 【要求:需要被克隆的類實現Cloneable接口並且重寫clone()方法】 》例子: 》》實體: package

javamybatis在使用mybatis進行批量插入,批量更新等批量操作時,切割In集合List進行分批批量操作的java中的切割代碼

lse span ati 批量更新 次數 sublist 調用 size ==       紅字部分代表mybatis的批量操作調用方法:       int num = 0; int maxLength = 200; in

RS利用局部隱含空間模型進行Top-N推薦

針對 -s pac for chris com ext space 行為 【論文標題】Local Latent Space Models for Top- N Recommendation (KDD-2018 ) 【論文作者】—Evangelia Christak

JAVA在SpringBoot 專案中 利用maven 的generate外掛

使用maven 外掛 generate生成MyBatis相關檔案 在專案中增加 maven 依賴 - mybatis-spring-boot-starter - mysql-connector-java - mybatis-generator-maven-plugin 外掛 自

C++利用建構函式對類物件進行初始化

一、物件的初始化 每一個物件都應當在它建立之時就有就有確定的內容,否則就會失去物件的意義。 class Time { int hour = 0; int min = 0; int sec = 0; }; 這種是錯誤的,類並不是一個實體,並不佔儲存空間,顯然無處容納

react利用prop-types第三方庫對元件的props中的變數進行型別檢測

1.安裝:npm install prop-types --save 2.使用 import React, { Component } from 'react'; import PropTypes

java對被final修飾的變數進行賦值的幾種方法

對被final修飾的變數進行賦值的幾種方法 這是精華: 因為當類被載入進記憶體的時候,這個屬性並沒有給其分配記憶體空間,而只是定義了一個變數,只有當類被例項化的時候這個屬性才被分配記憶體空

ODPS利用阿里雲ODPS作業進行圓周率Pi的計算

原理: 1.畫一個正方形,邊長為1CM,在此正方形內繪製一個內接圓。 2.假如我們在此正方形內隨機點一個點,這個點落在圓內的概率是P 3.假如我們隨機足夠多的點,那麼我們的P就無限接近於Pi/4(=圓的面積/正方形的面積) 表設計: 1.隨機落點表(記錄隨機點的位置) 2

Java對MySQL資料庫進行操作java

資料庫幾乎是每一個應用型的程式都會用到,學會如何高效操作資料庫也是開發一個重點。今天我總結了具體的操作步驟以及注意點。Java訪問資料庫主要用的方法是JDBC,它是java語言中用來規範客戶端程式如何來訪問資料庫的應用程式介面,提供了諸如查詢和更新資料庫中資料的方法,接下來

Java對檔案或資料夾進行重新命名

                在Java中,對檔案或資料夾進行重新命名是很簡單的,因為Java的File類已經封裝好rename

iOS利用CocoaPods建立私有庫進行元件化開發

之前使用CocoaPods管理過第三方庫,前面也有翻譯文章介紹過CocoaPods的配置方法,隨著專案越來越大,很多公司會使用CocoaPods進行元件化開發,下面利用一個demo介紹一下。 什麼是庫 先說下什麼是庫,庫分為靜態庫和動態庫兩種: - 1

java陣列的複製System.arraycopy

預設提供的一種陣列複製的方法 System.arraycopy(src, srcPos, dest, destPos, length); src:源陣列 srcPos:源陣列開始位置 dest:目標陣列 destPos:目標陣列開始位置 length:複製的長度 這