0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Apache ShardingSphereによるシャーディング

Posted at

要約

  • Apache ShardingSphere-JDBCを使用し、SQL Serverのシャーディングを行う設定ファイルを紹介します
  • 本番運用を見据えて、シャーディング設定情報をZooKeeperやEtcdで管理する方法を紹介します

Apache ShardingSphereとは何か

Apache ShardingSphereはRDBのシャーディング(水平パーティショニング)を行うためのライブラリです。ShardingSphere-JDBCとShardingSphere-Proxyから構成されています。

ShardingSphere-JDBC

ShardingSphere-JDBCは、アプリケーションのJDBCドライバ層に組み込むライブラリで、既存のJDBC APIを拡張して水平パーティショニングやレプリケーションを透過的に実現します。依存ライブラリを追加するだけで、シャード間ルーティング、分散トランザクション、フェイルオーバーなどがサポートされ、Spring BootやMyBatisなどのフレームワークを意識せずに導入可能です。いくつかの制約はありますが、多数のRDBMSに対応しています。

ShardingSphere-Proxy

ShardingSphere-Proxyは、MySQL/PostgreSQLプロトコルをサポートする独立したミドルウェアで、アプリケーションとDBの間に配置することでシャーディング、読み書き分離、マスキングなどをプロキシレベルで透過的に提供します。複数言語やフレームワークから利用可能ですが、対応DBMSが限られている点に注意が必要です。

このほか、ShardingSphereの詳細は、公式サイトを参照してください

実施したこと

今回は、ShardingSphere-JDBCを使用して、簡単なシャーディングルールに基づきデータの格納、検索を行うSpringBootアプリを作成しました。

  • 簡単な注文テーブル(注文ID, 顧客ID, 詳細)を顧客IDでシャーディングする
  • データの格納先は、顧客ID(INT)の2で割った余りで決定する
  • DBはローカルにdockerで2インスタンス用意する

構成

  • JDK 21
  • Spring Boot 3.4.5
  • MyBatis Spring Boot Starter 3.0.4
  • Apache ShardingSphere-JDBC 5.5.2
  • SQL Server

ShardingSphere-JDBCの設定

シャーディングするデータソースとルールを定義します。

sharding-sphere.yaml
# ShardingSphere 設定ファイル

# データソース定義
# dockerで起動した2台のSQL Serverへの接続情報
dataSources:
  ds0:
    dataSourceClassName: com.zaxxer.hikari.HikariDataSource
    url: jdbc:sqlserver://localhost:14330;databaseName=db0;encrypt=false;trustServerCertificate=true;sendStringParametersAsUnicode=true
    username: sa
    password: xxxxxxxx
    driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver
  ds1:
    dataSourceClassName: com.zaxxer.hikari.HikariDataSource
    url: jdbc:sqlserver://localhost:14331;databaseName=db1;encrypt=false;trustServerCertificate=true;sendStringParametersAsUnicode=true
    username: sa
    password: xxxxxxxx
    driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver

# シャーディングルール定義
rules:
  - !SHARDING
    tables:
      # 注文テーブルのシャーディング設定
      t_order:
        actualDataNodes: ds${0..1}.t_order # ds0.t_order, ds1.t_order に展開される
        databaseStrategy:
          standard:
            shardingColumn: customer_id # 顧客IDでシャーディングする
            shardingAlgorithmName: db_mod_sharding_alg
    
    # シャーディングアルゴリズム定義
    shardingAlgorithms:
      db_mod_sharding_alg:
        type: INLINE
        props:
          # customer_id を 2 で割った余りで ds0 または ds1 に振り分ける INLINE 表現
          algorithm-expression: ds${customer_id % 2}

application.properties

ShardingSphere-JDBCを使用するよう、application.propertiesを設定します。

application.properties
# ShardingSphere Driver設定
spring.datasource.driver-class-name=org.apache.shardingsphere.driver.ShardingSphereDriver
# ShardingSphere 設定ファイルの指定
spring.datasource.url=jdbc:shardingsphere:classpath:sharding-sphere.yaml

依存関係の設定

ShardingSphere-JDBCへの依存関係をpom.xmlに追加します

pom.xml
<dependency>
	<groupId>org.apache.shardingsphere</groupId>
	<artifactId>shardingsphere-jdbc</artifactId>
	<version>5.5.2</version>
</dependency>

データベースの準備

dockerで2台のSQL Serverを起動します。

docker-compose-sqlserver.yaml
# 2台のSQL Serverを起動する
services:
  sqlserver-0:
    image: mcr.microsoft.com/mssql/server:latest
    container_name: sqlserver-0
    environment:
      ACCEPT_EULA: "Y"
      SA_PASSWORD: "xxxxxxxx"
    # Map host port 14330 to container port 1433
    ports:
      - "14330:1433"

  sqlserver-1:
    image: mcr.microsoft.com/mssql/server:latest
    container_name: sqlserver-1
    environment:
      ACCEPT_EULA: "Y"
      SA_PASSWORD: "xxxxxxxx"
    # Map host port 14331 to container port 1433
    ports:
      - "14331:1433" 

立ち上げた2つのSQL Serverインスタンスに同じDDLを使用してテーブルを作成しておきます。
sqlserver-0で以下を実行

    CREATE DATABASE db0;
    GO

    USE db0;
    GO

    CREATE TABLE t_order (
        order_id BIGINT PRIMARY KEY,
        customer_id INT NOT NULL, -- シャーディングキー
        order_details NVARCHAR(255)
        -- 他に必要なカラム
    );
    GO

sqlserver-1では、db1に同じテーブルを作成しておきます。

SpringBootアプリケーションの開発

通常のSpringBootアプリケーションの開発と同様です。
MyBatisもシャーディングを意識せずに使えます。

今回は /api/ordersに対する注文の登録と{orderId}を指定して注文を検索するAPIを実装しました。

動作確認

APIから注文を登録後、sqlcmd等で確認します。偶数の顧客IDからの注文が1台目のSQLServer(ds0)に、奇数顧客IDからの注文が2台目のSQLServer(ds1)に登録されていたら、成功です。

# 偶数顧客IDの確認
sqlcmd -S localhost,14330 -U sa -P xxxxxxxx -d db0 -Q "SELECT * FROM t_order;"
# 奇数顧客IDの確認
sqlcmd -S localhost,14331 -U sa -P xxxxxxxx -d db1 -Q "SELECT * FROM t_order;"

SpringBootアプリ内でのMyBatisからの検索はデータの登録先を意識することは不要です。

設定情報のクラスタ管理

ShardingSphere-JDBCでは、データストアやシャーディングルールなどをZooKeeperやEtcdを使用して分散管理するClusterモードを指定することができます。クライアント間でのルールの不整合等を防ぐことができ、本番運用では、Clusterモードの使用が推奨されています。

sharding-sphere-cluster.yaml
# モード設定 (Cluster Mode with ZooKeeper)
mode:
  type: Cluster
  repository:
    type: ZooKeeper
    props:
      namespace: shardingsphere
      server-lists: localhost:2181,localhost:2182,localhost:2183 # ZooKeeperを3台構成で起動
      connectionTimeoutMilliseconds: 5000 # e.g., 5 seconds connection timeout
      retryIntervalMilliseconds: 500
      maxRetries: 3
      timeToLiveSeconds: 60
      operationTimeoutMilliseconds: 5000 # e.g., 5 seconds operation timeout

ZooKeeperは以下のように構成しました

docker-compose-zookeeper.yaml
# ZooKeeper 3-node cluster for ShardingSphere Cluster Mode
version: '3.8'

services:
  zookeeper1:
    image: zookeeper:3.9
    container_name: zookeeper1
    hostname: zookeeper1
    ports:
      - "2181:2181" # Client port
    environment:
      ZOO_MY_ID: 1
      # server.<myid>=<hostname>:<peer port>:<leader election port>
      ZOO_SERVERS: server.1=zookeeper1:2888:3888 server.2=zookeeper2:2888:3888 server.3=zookeeper3:2888:3888
      ZOO_CFG_EXTRA: |
        metricsProvider.className=org.apache.zookeeper.metrics.prometheus.PrometheusMetricsProvider
        metricsProvider.httpPort=7000
        metricsProvider.exportJvmInfo=true
        clientPort=2181
        clientPortAddress=0.0.0.0
    volumes:
      - zk-data1:/data # ZooKeeper data directory
      - zk-datalog1:/datalog # ZooKeeper transaction log directory (optional, can improve performance)
    networks:
      - zookeeper-net

  zookeeper2:
    image: zookeeper:3.9
    container_name: zookeeper2
    hostname: zookeeper2
    ports:
      - "2182:2181" # Client port
    environment:
      ZOO_MY_ID: 2
      ZOO_SERVERS: server.1=zookeeper1:2888:3888 server.2=zookeeper2:2888:3888 server.3=zookeeper3:2888:3888
      ZOO_CFG_EXTRA: |
        metricsProvider.className=org.apache.zookeeper.metrics.prometheus.PrometheusMetricsProvider
        metricsProvider.httpPort=7000
        metricsProvider.exportJvmInfo=true
        clientPort=2181
        clientPortAddress=0.0.0.0
    volumes:
      - zk-data2:/data
      - zk-datalog2:/datalog
    networks:
      - zookeeper-net

  zookeeper3:
    image: zookeeper:3.9
    container_name: zookeeper3
    hostname: zookeeper3
    ports:
      - "2183:2181" # Client port
    environment:
      ZOO_MY_ID: 3
      ZOO_SERVERS: server.1=zookeeper1:2888:3888 server.2=zookeeper2:2888:3888 server.3=zookeeper3:2888:3888
      ZOO_CFG_EXTRA: |
        metricsProvider.className=org.apache.zookeeper.metrics.prometheus.PrometheusMetricsProvider
        metricsProvider.httpPort=7000
        metricsProvider.exportJvmInfo=true
        clientPort=2181
        clientPortAddress=0.0.0.0
    volumes:
      - zk-data3:/data
      - zk-datalog3:/datalog
    networks:
      - zookeeper-net

volumes:
  zk-data1:
    driver: local
  zk-datalog1:
    driver: local
  zk-data2:
    driver: local
  zk-datalog2:
    driver: local
  zk-data3:
    driver: local
  zk-datalog3:
    driver: local

networks:
  zookeeper-net:
    driver: bridge 

まとめ

ShardingSphere-JDBCを使用して、アプリケーションからは意識することなく、設定のみでシャーディングを実施することができました。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?