Thực hiện phân tách đọc ghi MySQL bằng Amoeba

Thực hiện phân tách đọc ghi MySQL bằng Amoeba

1. Amoeba là gì?

Amoeba là một dự án tập trung vào việc phát triển proxy cho cơ sở dữ liệu phân tán. Nó nằm giữa client và các máy chủ cơ sở dữ liệu (DB Server), hoạt động trong suốt đối với client và cung cấp nhiều tính năng như cân bằng tải, khả dụng cao, lọc SQL, phân tách đọc ghi, định tuyến query tới cơ sở dữ liệu đích và có thể xử lý đồng thời nhiều yêu cầu từ các máy chủ khác nhau để hợp nhất kết quả.

Amoeba giải quyết:

  • Giảm độ phức tạp do việc chia nhỏ dữ liệu gây ra.
  • Cung cấp quy tắc chia nhỏ dữ liệu và giảm tác động của chúng lên ứng dụng.
  • Giảm số lượng kết nối giữa DB và client.
  • Phân tách đọc và ghi.

2. Tại sao nên sử dụng Amoeba?

Để thực hiện phân tách đọc ghi trên MySQL, hiện tại có một số phương pháp phổ biến sau:

  1. Qua chương trình: Có nhiều mã nguồn sẵn có trên mạng nhưng khá phức tạp. Việc thêm máy chủ phụ sẽ yêu cầu thay đổi mã nguồn trên nhiều máy chủ.
  2. Sử dụng MySQL-proxy: MySQL-proxy sử dụng script Lua để thực hiện phân tách đọc ghi. Tuy nhiên, việc phát triển script Lua chưa đáp ứng được nhu cầu và không có script hoàn hảo nào sẵn có. Hiệu suất của MySQL-proxy cũng bị đánh giá thấp.
  3. Phát triển giao diện riêng: Phương pháp này đòi hỏi kỹ năng cao, chi phí phát triển lớn và không phải công ty nhỏ nào cũng có thể gánh vác.
  4. Sử dụng Amoeba: Đây là một phần mềm nguồn mở của Alibaba, hỗ trợ cân bằng tải, khả dụng cao, lọc SQL, phân tách đọc ghi, định tuyến query tới cơ sở dữ liệu đích. Hơn nữa, việc cài đặt và cấu hình rất đơn giản.

3. Cài đặt Amoeba

1. Cài đặt JDK

Cài đặt JDK thông qua gói RPM.

2. Tải xuống và giải nén Amoeba

Tải phiên bản phù hợp từ SourceForge và giải nén.

3. Cấu hình file của Amoeba

dbServers.xml

<?xml version="1.0" encoding="utf-8"?>
<amoeba:dbServers xmlns:amoeba="http://amoeba.meidusa.com/">

    <dbServer name="baseConfig" abstract="true">
        <factoryConfig class="com.meidusa.amoeba.mysql.net.MysqlServerConnectionFactory">
            <property name="connectionManager">${defaultManager}</property>
            <property name="sendBufferSize">64</property>
            <property name="receiveBufferSize">128</property>
            <property name="port">3306</property>
            <property name="schema">testdb</property>
            <property name="user">admin</property>
            <property name="password">secret</property>
        </factoryConfig>

        <poolConfig class="com.meidusa.toolkit.common.poolable.PoolableObjectPool">
            <property name="maxActive">500</property>
            <property name="maxIdle">500</property>
            <property name="minIdle">1</property>
            <property name="minEvictableIdleTimeMillis">600000</property>
            <property name="timeBetweenEvictionRunsMillis">600000</property>
            <property name="testOnBorrow">true</property>
            <property name="testOnReturn">true</property>
            <property name="testWhileIdle">true</property>
        </poolConfig>
    </dbServer>

    <dbServer name="mainDb" parent="baseConfig">
        <factoryConfig>
            <property name="ipAddress">192.168.1.100</property>
        </factoryConfig>
    </dbServer>

    <dbServer name="replicaDb" parent="baseConfig">
        <factoryConfig>
            <property name="ipAddress">192.168.1.101</property>
        </factoryConfig>
    </dbServer>

    <dbServer name="replicaGroup" virtual="true">
        <poolConfig class="com.meidusa.amoeba.server.MultipleServerPool">
            <property name="loadbalance">1</property>
            <property name="poolNames">replicaDb</property>
        </poolConfig>
    </dbServer>
</amoeba:dbServers>

amoeba.xml

<?xml version="1.0" encoding="utf-8"?>
<amoeba:configuration xmlns:amoeba="http://amoeba.meidusa.com/">

    <proxy>
        <service name="MySQL Proxy" class="com.meidusa.amoeba.mysql.server.MySQLService">
            <property name="port">8066</property>
            <property name="connectionFactory">
                <bean class="com.meidusa.amoeba.mysql.net.MysqlClientConnectionFactory">
                    <property name="sendBufferSize">128</property>
                    <property name="receiveBufferSize">64</property>
                </bean>
            </property>
            <property name="authenticateProvider">
                <bean class="com.meidusa.amoeba.mysql.server.MysqlClientAuthenticator">
                    <property name="user">admin</property>
                    <property name="password">secret</property>
                    <property name="filter">
                        <bean class="com.meidusa.toolkit.net.authenticate.server.IPAccessController">
                            <property name="ipFile">${amoeba.home}/conf/access_list.conf</property>
                        </bean>
                    </property>
                </bean>
            </property>
        </service>

        <runtime class="com.meidusa.amoeba.mysql.context.MysqlRuntimeContext">
            <property name="executeThreadSize">128</property>
            <property name="statementCacheSize">500</property>
            <property name="serverCharset">utf8</property>
            <property name="queryTimeout">60</property>
        </runtime>
    </proxy>

    <connectionManagerList>
        <connectionManager name="defaultManager" class="com.meidusa.toolkit.net.MultiConnectionManagerWrapper">
            <property name="subManagerClassName">com.meidusa.toolkit.net.AuthingableConnectionManager</property>
        </connectionManager>
    </connectionManagerList>

    <dbServerLoader class="com.meidusa.amoeba.context.DBServerConfigFileLoader">
        <property name="configFile">${amoeba.home}/conf/dbServers.xml</property>
    </dbServerLoader>

    <queryRouter class="com.meidusa.amoeba.mysql.parser.MysqlQueryRouter">
        <property name="ruleLoader">
            <bean class="com.meidusa.amoeba.route.TableRuleFileLoader">
                <property name="ruleFile">${amoeba.home}/conf/rule.xml</property>
                <property name="functionFile">${amoeba.home}/conf/ruleFunctionMap.xml</property>
            </bean>
        </property>
        <property name="sqlFunctionFile">${amoeba.home}/conf/functionMap.xml</property>
        <property name="LRUMapSize">1500</property>
        <property name="defaultPool">mainDb</property>
        <property name="writePool">mainDb</property>
        <property name="readPool">replicaGroup</property>
        <property name="needParse">true</property>
    </queryRouter>
</amoeba:configuration>
4. Khởi động Amoeba

Chạy lệnh sau để khởi động:

/root/amoeba-mysql-3.0.5-RC/bin/launcher

4. Kiểm tra Amoeba

-- Thực hiện kiểm tra bằng các câu lệnh SQL
-- Đăng nhập MySQL trên máy chủ đã cài Amoeba
mysql -h192.168.1.102 -uadmin -psecret -P8066
-- Đăng nhập vào master, replica và Amoeba
use testdb;
select * from users;

-- Chèn dữ liệu qua Amoeba
insert into users values(2, 'John Doe');

-- Kiểm tra dữ liệu trên master và replica
select * from users;

-- Ngừng dịch vụ MySQL trên master và tiếp tục chèn dữ liệu. Dữ liệu sẽ không được chèn thành công nhưng vẫn có thể đọc.
-- Khởi động lại dịch vụ MySQL trên master và ngừng trên replica. Dữ liệu sẽ được chèn nhưng không thể đọc.

Thẻ: mysql Amoeba DatabaseProxy

Đăng vào ngày 5 tháng 6 lúc 02:01