Shardingsphereのメタデータロードプロセス



概要
メタデータはデータを構成するデータです.データベース用語では、データベースを記述する任意のデータはメタデータです.列名、データベース名、ユーザ名、テーブル名等、データベースオブジェクトに関する情報を格納するデータカスタマイズライブラリテーブルはメタデータである.ShardingSphereコア機能は、データのシェアリング、暗号化、および復号化はすべて、データベースのメタデータに基づいています.
これは、メタデータがShardingSphereシステムのコアであり、すべてのデータストレージ関連のミドルウェアまたはコンポーネントのコアデータであることを示します.メタデータの注入によって、システム全体の神経中心を持つことと等価であり、データのシェアリング、データの暗号化、SQL書換えなどのような、ライブラリ、テーブル、および列上でパーソナライズされた操作を実行するためにメタデータと組み合わせることができます.
Shardingsphereメタデータローディングプロセスについては、まずShardingSphereのメタデータの種類と階層を明確にする必要があります.ShardingSphereのメタデータは主にShardingSphereMetaData , その中心はShardingSphereSchema , これはデータベースのメタデータであり、データソースメタデータの最上位オブジェクトでもあります.ShardingSphereにおけるデータベースメタデータの構造を以下のように示し、各層ごとに上位層データが下層データのアセンブリから来るので、以下のボトムアップ階層を使用して1つずつ解析する.


コラムメタデータとインデックスメタデータColumMetaData and IndexMetaData を構成する基本的な要素ですTableMetaData . 次に、2つのメタデータ型とローディングプロセスの構造を別々に解析します.ColumMetaData 以下の主な構造を持つ.
public final class ColumnMetaData {
    // 
    private final String name;
    // 
    private final int dataType;
    // 
    private final boolean primaryKey;
    // 
    private final boolean generated;
    //
    private final boolean caseSensitive;
}
ローディングプロセスは主にorg.apache.shardingsphere.infra.metadata.schema.builder.loader.ColumnMetaDataLoader#load メソッドと、その主なプロセスは、テーブル名の下にあるすべての列のメタデータを、データベースリンクを介してテーブル名に一致するメタデータを取得することです.コアコードは次のとおりです.
/**
 * Load column meta data list.
 *
 * @param connection connection
 * @param tableNamePattern table name pattern
 * @param databaseType database type
 * @return column meta data list
 * @throws SQLException SQL exception
 */
public static Collection<ColumnMetaData> load(final Connection 
connection, final String tableNamePattern, final DatabaseType 
databaseType) throws SQLException {
    Collection<ColumnMetaData> result = new LinkedList<>();
    Collection<String> primaryKeys = loadPrimaryKeys(connection, tableNamePattern);
    List<String> columnNames = new ArrayList<>();
    List<Integer> columnTypes = new ArrayList<>();
    List<String> columnTypeNames = new ArrayList<>();
    List<Boolean> isPrimaryKeys = new ArrayList<>();
    List<Boolean> isCaseSensitives = new ArrayList<>();
    try (ResultSet resultSet =
 connection.getMetaData().getColumns(connection.getCatalog(),
 connection.getSchema(), tableNamePattern, "%")) {
        while (resultSet.next()) {
            String tableName = resultSet.getString(TABLE_NAME);
            if (Objects.equals(tableNamePattern, tableName)) {
                String columnName =
 resultSet.getString(COLUMN_NAME);
                columnTypes.add(resultSet.getInt(DATA_TYPE));
                columnTypeNames.add(resultSet.getString(TYPE_NAME));
                isPrimaryKeys.add(primaryKeys.contains(columnName));
                columnNames.add(columnName);
            }
        }
    }
    try (Statement statement = connection.createStatement();
 ResultSet resultSet =
 statement.executeQuery(generateEmptyResultSQL(tableNamePattern,
 databaseType))) {
        for (int i = 0; i < columnNames.size(); i++) {

            isCaseSensitives.add(resultSet.getMetaData().isCaseSensitive(resultS
et.findColumn(columnNames.get(i))));
            result.add(new ColumnMetaData(columnNames.get(i), 
columnTypes.get(i), isPrimaryKeys.get(i),
                    resultSet.getMetaData().isAutoIncrement(i + 1), 
isCaseSensitives.get(i)));
        }
    }
    return result;
}
IndexMetaData テーブル内のインデックスの名前ですので、複雑な構造プロパティはありません.詳細に行く代わりに、我々はむしろロードプロセスに集中します.そのローディングプロセスは列のそれに似ています、そして、主要なプロセスはorg.apache.shardingsphere.infra.metadata.schema.builder.loader.IndexMetaDataLoader#load メソッド.基本的なプロセスはまた、コアを取得するデータベースリンクを介しててIndexMetaDataIndexInfo 関連データベースと表メタデータの構成、および実装コードは次のとおりです.
public static Collection<IndexMetaData> load(final Connection connection, final String table) throws SQLException {
    Collection<IndexMetaData> result = new HashSet<>();
    try (ResultSet resultSet = connection.getMetaData().getIndexInfo(
connection.getCatalog(), 
connection.getSchema(), table, false, false)) {
        while (resultSet.next()) {
            String indexName = resultSet.getString(INDEX_NAME);
            if (null != indexName) {
                result.add(new IndexMetaData(indexName));
            }
        }
    } catch (final SQLException ex) {
        if (ORACLE_VIEW_NOT_APPROPRIATE_VENDOR_CODE != 
ex.getErrorCode()) {
            throw ex;
        }
    }
    return result;
}

タブレット
このクラスはShardingSphereMetaData には以下の構造体がある:
public final class TableMetaData {
    // Table Name
    private final String name;
    // Column Metadata
    private final Map<String, ColumnMetaData> columns;
    // Index Metadata
    private final Map<String, IndexMetaData> indexes;
    // Omit other methods
}
上記の構造から見るとTableMetaData から組み立てられるColumnMetaData and IndexMetaData , だからロードプロセスTableMetaData 中間層として理解でき、特定の実装は依然ColumnMetaDataLoader and IndexMetaDataLoader データ読み込み用のテーブル名と関連リンクを取得するにはだから比較的単純なTableMetaData ロードプロセスは主にorg.apache.shardingsphere.infra.metadata.schema.builder.loader.TableMetaDataLoader#load そして、そのコアローディングプロセスは以下の通りです.
public static Optional<TableMetaData> load(final DataSource 
dataSource, final String tableNamePattern, final DatabaseType 
databaseType) throws SQLException {
    // Get the Link 
    try (MetaDataLoaderConnectionAdapter connectionAdapter = new
MetaDataLoaderConnectionAdapter(databaseType, 
dataSource.getConnection())) {
        // Format fuzzy matching field of the table name, according to database type
        String formattedTableNamePattern = 
databaseType.formatTableNamePattern(tableNamePattern);
        // Load ColumnMetaData and IndexMetaData to assemble TableMetaData
        return isTableExist(connectionAdapter,
formattedTableNamePattern)
                ? Optional.of(new TableMetaData(tableNamePattern, 
ColumnMetaDataLoader.load(
                        connectionAdapter,
formattedTableNamePattern, databaseType),
IndexMetaDataLoader.load(connectionAdapter,
formattedTableNamePattern)))
                : Optional.empty();
    }
}

スキーマ
つの下層の分析によると、この層がメタデータ露出の最も外側の層であり、最も外側の層がShardingSphereSchema 以下の主な構造を持つ.
/**
 * ShardingSphere schema.
 */
@Getter
public final class ShardingSphereSchema {

    private final Map<String, TableMetaData> tables;

    @SuppressWarnings("CollectionWithoutInitialCapacity")
    public ShardingSphereSchema() {
        tables = new ConcurrentHashMap<>();
    }

    public ShardingSphereSchema(final Map<String, TableMetaData> 
tables) {
        this.tables = new ConcurrentHashMap<>(tables.size(), 1);
        tables.forEach((key, value) ->
 this.tables.put(key.toLowerCase(), value));
    }
スキーマの概念に沿って、いくつかのテーブルが含まれます.の属性ShardingSphereSchema マップ構造、キーはtableName , 値は、tableName .
初期化は主にコンストラクタを通して行われます.再び、フォーカスはテーブルメタデータ読み込みにあります.
メタデータロード全体のコアエントリポイントはorg.apache.shardingsphere.infra.context.metadata.MetaDataContextsBuilder#build . ビルドでは、構成規則を使用して対応するメタデータをアセンブルして読み込みます.コアコードは次のとおりです.
/**
 * Build meta data contexts.
 * 
 * @exception SQLException SQL exception
 * @return meta data contexts
 */
public StandardMetaDataContexts build() throws SQLException {
    Map<String, ShardingSphereMetaData> metaDataMap = new HashMap<>
(schemaRuleConfigs.size(), 1);
    Map<String, ShardingSphereMetaData> actualMetaDataMap = new
 HashMap<>(schemaRuleConfigs.size(), 1);
    for (String each : schemaRuleConfigs.keySet()) {
        Map<String, DataSource> dataSourceMap = 
dataSources.get(each);
        Collection<RuleConfiguration> ruleConfigs = 
schemaRuleConfigs.get(each);
        DatabaseType databaseType =
DatabaseTypeRecognizer.getDatabaseType(dataSourceMap.values());
        // Obtain configuration rules
        Collection<ShardingSphereRule> rules =
ShardingSphereRulesBuilder.buildSchemaRules(each, ruleConfigs, 
databaseType, dataSourceMap);
        // Load actualTableMetaData andlogicTableMetaData
        Map<TableMetaData, TableMetaData> tableMetaDatas = 
SchemaBuilder.build(new SchemaBuilderMaterials(databaseType, 
dataSourceMap, rules, props));
        // Assemble rule metadata
        ShardingSphereRuleMetaData ruleMetaData = new
ShardingSphereRuleMetaData(ruleConfigs, rules);
        // Assemble data source metadata
        ShardingSphereResource resource =
buildResource(databaseType, dataSourceMap);
        // Assemble database metdadata
        ShardingSphereSchema actualSchema = new 
ShardingSphereSchema(tableMetaDatas.keySet().stream().filter(Objects
::nonNull).collect(Collectors.toMap(TableMetaData::getName, v -> 
v)));
        actualMetaDataMap.put(each, new ShardingSphereMetaData(each, 
resource, ruleMetaData, actualSchema));
        metaDataMap.put(each, new ShardingSphereMetaData(each, 
resource, ruleMetaData, buildSchema(tableMetaDatas)));
    }
    // 
    OptimizeContextFactory optimizeContextFactory = new 
OptimizeContextFactory(actualMetaDataMap);
    return new StandardMetaDataContexts(metaDataMap, 
buildGlobalSchemaMetaData(metaDataMap), executorEngine, props, 
optimizeContextFactory);
}

上記のコードでは、ビルドメソッドでは、データベースの種類、データベース接続プールなどの基本的なデータベースデータが、設定されたスキーマに基づいて読み込まれますShardingSphereResource が完了するのアセンブリShardingSphereRuleMetaData 構成規則、暗号化規則、認証規則等を組み立てる必要なデータベースメタデータShardingSphereSchema が読み込まれる.traceメタデータテーブルの読み込み方法を見つけるorg.apache.shardingsphere.infra.metadata.schema.builder.SchemaBuilder#build , その中でactualTableMetaData and logicTableMetaData が読み込まれる.
では、オペレーティングテーブルは何ですかlogicTable ? 簡単に言うt_order_1 , t_order_2 TRAN順序のノードと考えられるので、解析の概念ではt_order is logicTable , 中t_order_1 and t_order_2 is actualTable . これらの2つの概念が明確に定義されているので、ビルドメソッドを一緒に見ます.
1 ) ActualTableLetadata読み込みActualTableMetaData システムシェーディングの基本的なテーブルです.5.0ベータ版では、SQLを使用してメタデータを読み込むためにSQLデータベースを使用する方法を採用していますので、基本的なプロセスはSQLを最初にデータベースメタデータを問い合わせることです.データベースDirectローダが見つからない場合、JDBCドライバ接続が使用され、ShardingSphereRuleで構成されるテーブル名と組み合わせて、構成表のメタデータが読み込まれます.コアコードを以下に示します.
private static Map<String, TableMetaData> 
buildActualTableMetaDataMap(final SchemaBuilderMaterials materials) 
throws SQLException {
    Map<String, TableMetaData> result = new HashMap<>
(materials.getRules().size(), 1);
    // Database SQL Loading Metadata
    appendRemainTables(materials, result);
    for (ShardingSphereRule rule : materials.getRules()) {
        if (rule instanceof TableContainedRule) {
            for (String table : ((TableContainedRule) 
rule).getTables()) {
                if (!result.containsKey(table)) {
                    TableMetaDataBuilder.load(table, 
materials).map(optional -> result.put(table, optional));
                }
            }
        }
    }
    return result;
}
2 ) LogicTableLetadata読み込み
上記の概念から見るとlogicTable が実際の論理ノードであるactualTable 異なった規則(それは鋭利なノードまたは暗号化ノードまたは何か他の何でもよい)に基づきます.したがって、logicTableMetaData に基づいていますactualTableMetaData , ライブラリやテーブルルールやその他の関連ノードのような特定の設定規則と組み合わせます.特定のプロセスに関しては、まず設定ルールのテーブル名を取得し、actualTableMetaData は、ロードされて、関連ルールのメタデータを生成するTableMetaDataBuilder#decorate メソッド.コアコードの流れを以下に示します.
private static Map<String, TableMetaData> 
buildLogicTableMetaDataMap(final SchemaBuilderMaterials materials, 
final Map<String, TableMetaData> tables) throws SQLException {
    Map<String, TableMetaData> result = new HashMap<>
(materials.getRules().size(), 1);
    for (ShardingSphereRule rule : materials.getRules()) {
        if (rule instanceof TableContainedRule) {
            for (String table : ((TableContainedRule) 
rule).getTables()) {
                if (tables.containsKey(table)) {
                    TableMetaData metaData = 
TableMetaDataBuilder.decorate(table, tables.get(table), 
materials.getRules());
                    result.put(table, metaData);
                }
            }
        }
    }
    return result;
}
この時点で、コアメタデータがロードされ、各要求シナリオで使用するために、戻り値のマップにカプセル化されます.

メタデータロード最適化解析
メタデータは我々のシステムの重要なコアであるが、システム起動中のデータロードはシステム負荷を増加させ、システム起動効率を低下させる.したがって,負荷プロセスを最適化する必要がある.現在、次の2つの方法があります.

A .ネイティブのJDBCドライバ接続とSQLクエリの置換
5.0ベータ版の前に、使用されたアプローチはネイティブのJDBCドライバを通してロードすることでした.5.0ベータでは、SQLクエリを介してデータベースの方言を使用してメタデータ読み込みにマルチスレッドアプローチを徐々に採用しました.ロードデータの読み込み速度がさらに向上しました.詳細な方言ローダは、関連する実装で見つかりますorg.apache.shardingsphere.infra.metadata.schema.builder.spi.DialectTableMetaDataLoader .

メタデータロード時間を減らす
システムに共通のリソースのロードのために、我々は「複数の使用のための1回のロード」の概念に従います.もちろん、私たちはこの過程における空間と時間を考慮しなければなりません.その結果、我々は常に全体的なシステム効率を高めるためにメタデータの重複読み込みを削減する最適化されます.

Shardingsphereコミュニティ
Shardingsphere github :
https://github.com/apache/shardingsphere