Mi az az adatbázis magas rendelkezésre állása (HA)?

A digitális korban a modern üzleti rendszereknek rendkívül elérhetőnek, megbízhatónak és stabilnak kell lenniük. A modern üzleti rendszer sarokköveként az adatbázisoknak fel kell ölelniük a magas rendelkezésre állást.

A HA lehetővé teszi az adatbázisok számára, hogy szolgáltatásokat váltsanak az elsődleges és másodlagos adatbázisok között, és automatikusan kiválasszák a Master értéket, így kiválaszthatja a legjobb csomópontot főként, amikor az előző összeomlik.

MySQL magas rendelkezésre állás

Rengeteg „MySQL magas rendelkezésre állás” opció létezik, de mindegyiknek megvannak a maga előnyei és hátrányai. Az alábbiakban bemutatunk néhány általánosan elterjedt magas rendelkezésre állási lehetőséget:

  • Az Orchestrator egy MySQL HA- és replikációs topológia-kezelő eszköz, amely Go nyelven íródott. Előnye abban rejlik, hogy támogatja az elsődleges-másodlagos topológia kézi beállítását, az automatikus feladatátvételt, a fő csomópontok automatikus vagy kézi helyreállítását a webes vizuális konzolon keresztül. A programot azonban külön kell telepíteni, és a bonyolult konfigurációk miatt meredek tanulási görbéje is van.
  • Az „MHA” egy másik kiforrott megoldás. Elsődleges/másodlagos kapcsolási és feladatátvételi képességeket biztosít. Az a jó benne, hogy a legkevesebb adatvesztést tudja biztosítani a váltási folyamat során, miközben képes félszinkron és aszinkron replikációs keretrendszerekkel dolgozni. Az MHA indulása után azonban csak a Master figyelhető meg, és az MHA nem biztosítja a terheléselosztásiszolgáltatást az olvasott adatbázishoz.
  • Az MGR az elosztott Paxos protokollon alapuló csoportreplikációt valósít meg az adatok konzisztenciájának biztosítása érdekében. Ez a MySQL által biztosított hivatalos HA összetevő, és nincs szükség további telepítési programra. Ehelyett a felhasználóknak csak az MGR beépülő modult kell telepíteniük az egyes adatforrás-csomópontokra. Az eszköz nagy konzisztenciával, nagy hibatűréssel, nagy skálázhatósággal és nagy rugalmassággal rendelkezik.

Apache ShardingSphere magas rendelkezésre állás

Az Apache ShardingSphere architektúrája valójában elválasztja a tárolást a számítástechnikától. A tárolási csomópont az alapul szolgáló adatbázist képviseli, mint például a MySQL, PostgreSQL, openGauss stb., míg a számítási csomópont a ShardingSphere-JDBC vagy ShardingSphere-Proxy névre utal.

Ennek megfelelően a tárolási csomópontok és a számítási csomópontok „magas rendelkezésre állású megoldásai” eltérőek. Az állapot nélküli számítási csomópontok esetében, miközben érzékelniük kell a tárolócsomópontokban bekövetkezett változásokat, külön terheléselosztókat is be kell állítaniuk, és rendelkezniük kell a szolgáltatásfelderítési és kéréselosztási képességekkel. Az állapottartó tároló csomópontokat fel kell szerelni az adatszinkronizálás, a kapcsolatteszt, a főcsomópont kiválasztásának stb. lehetőségeivel.

Bár a ShardingSphere nem biztosít magas rendelkezésre állású adatbázist, segíthet a felhasználóknak az adatbázis-HA-megoldások integrálásában, mint például az elsődleges-másodlagos átkapcsolás, a hibafelderítés, a forgalomváltás irányítása stb. felfedezés és dinamikus észlelés.

Az elosztott forgatókönyvekben az elsődleges-másodlagos áramlásvezérlő funkcióval kombinálva a ShardingSphere jobb magas rendelkezésre állású olvasási/írási felosztási megoldásokat kínál. Könnyebb lesz a ShardingSphere-fürtök működtetése és kezelése, ha a DistSQL dinamikus magas rendelkezésre állási beállítási szabályait használjuk az elsődleges/másodlagos csomópontok információinak megszerzésére.

Legjobb gyakorlatok

Az Apache ShardingSphere beépülő modul-orientált architektúrát alkalmaz, így minden továbbfejlesztett képessége önállóan vagy együtt is használható. Magas rendelkezésre állású funkcióját gyakran használják az olvasási/írási felosztással együtt a lekérdezési kérések elosztására a szolga adatbázisok között a terheléselosztási algoritmus szerint, így biztosítva a rendszer HA-t, enyhítve az elsődleges adatbázisok nyomását, és javítva az üzleti rendszer átviteli sebességét.

Itt példának vesszük a HA+olvasási/írási felosztási konfigurációt ShardingSphere DistSQL RAL utasításokkal.

Egy dologra fel kell hívni a figyelmet, hogy a ShardingSphere HA megvalósítás az elosztott irányítási képességére támaszkodik. Ezért egyelőre csak fürt módban használható. Eközben a ShardingSphere 5.1.0 átdolgozza az olvasási/írási felosztási szabályokat. A részletekért tekintse meg a hivatalos dokumentációt az írás/olvasás felosztásáról.

Konfiguráció

schemaName: database_discovery_db
dataSources:
ds_0:
url: jdbc:mysql://127.0.0.1:1231/demo_primary_ds?serverTimezone=UTC&useSSL=false
username: root
password: 123456
connectionTimeoutMilliseconds: 3000
idleTimeoutMilliseconds: 60000
maxLifetimeMilliseconds: 1800000
maxPoolSize: 50
minPoolSize: 1
ds_1:
url: jdbc:mysql://127.0.0.1:1232/demo_primary_ds?serverTimezone=UTC&useSSL=false
username: root
password: 123456
connectionTimeoutMilliseconds: 3000
idleTimeoutMilliseconds: 60000
maxLifetimeMilliseconds: 1800000
maxPoolSize: 50
minPoolSize: 1
ds_2:
url: jdbc:mysql://127.0.0.1:1233/demo_primary_ds?serverTimezone=UTC&useSSL=false
username: root
password: 123456
connectionTimeoutMilliseconds: 3000
idleTimeoutMilliseconds: 50000
maxLifetimeMilliseconds: 1300000
maxPoolSize: 50
minPoolSize: 1
rules:
- !READWRITE_SPLITTING
dataSources:
replication_ds:
type: Dynamic
props:
auto-aware-data-source-name: mgr_replication_ds
- !DB_DISCOVERY
dataSources:
mgr_replication_ds:
dataSourceNames:
- ds_0
- ds_1
- ds_2
discoveryHeartbeatName: mgr-heartbeat
discoveryTypeName: mgr
discoveryHeartbeats:
mgr-heartbeat:
props:
keep-alive-cron: '0/5 * * * * ?'
discoveryTypes:
mgr:
type: MGR
props:
group-name: b13df29e-90b6-11e8-8d1b-525400fc3996

Követelmények

  • ShardingSphere-Proxy 5.1.0 (fürt mód + HA + dinamikus olvasási/írási felosztási szabály)
  • Zookeeper 3.7.0
  • MySQL MGR-fürt

SQL-szkript

CREATE TABLE `t_user` (
`id` int(8) NOT NULL,
`mobile` char(20) NOT NULL,
`idcard` varchar(18) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

Tekintse meg az elsődleges-másodlagos kapcsolatot

mysql> SHOW READWRITE_SPLITTING RULES;
+----------------+-----------------------------+------------------------+------------------------+--------------------+---------------------+
| name           | auto_aware_data_source_name | write_data_source_name | read_data_source_names | load_balancer_type | load_balancer_props |
+----------------+-----------------------------+------------------------+------------------------+--------------------+---------------------+
| replication_ds | mgr_replication_ds          | ds_0                   | ds_1,ds_2              | NULL               |                     |
+----------------+-----------------------------+------------------------+------------------------+--------------------+---------------------+
1 row in set (0.09 sec)

Tekintse meg a másodlagos adatbázis állapotát

mysql> SHOW READWRITE_SPLITTING READ RESOURCES;
+----------+---------+
| resource | status  |
+----------+---------+
| ds_1     | enabled |
| ds_2     | enabled |
+----------+---------+

A fenti eredményekből megtudhatjuk, hogy jelenleg az elsődleges adatbázis az ds_0, míg a másodlagos adatbázisok az ds_1 és ds_2.

Teszteljük INSERT:

mysql> INSERT INTO t_user(id, mobile, idcard) value (10000, '13718687777', '141121xxxxx');Query OK, 1 row affected (0.10 sec)

Tekintse meg a ShardingSphere-Proxy naplót, és ellenőrizze, hogy az útvonal csomópontja-e az elsődleges adatbázis ds_0.

[INFO ] 2022-02-28 15:28:21.495 [ShardingSphere-Command-2] ShardingSphere-SQL - Logic SQL: INSERT INTO t_user(id, mobile, idcard) value (10000, '13718687777', '141121xxxxx')
[INFO ] 2022-02-28 15:28:21.495 [ShardingSphere-Command-2] ShardingSphere-SQL - SQLStatement: MySQLInsertStatement(setAssignment=Optional.empty, onDuplicateKeyColumns=Optional.empty)
[INFO ] 2022-02-28 15:28:21.495 [ShardingSphere-Command-2] ShardingSphere-SQL - Actual SQL: ds_0 ::: INSERT INTO t_user(id, mobile, idcard) value (10000, '13718687777', '141121xxxxx')

Teszteljük SELECT (ismételjük meg kétszer):

mysql> SELECT id, mobile, idcard FROM t_user WHERE id = 10000;

Tekintse meg a ShardingSphere-Proxy naplót, és nézze meg, hogy az útvonal csomópontja ds_1 vagy ds_2.

[INFO ] 2022-02-28 15:34:07.912 [ShardingSphere-Command-4] ShardingSphere-SQL - Logic SQL: SELECT id, mobile, idcard FROM t_user WHERE id = 10000
[INFO ] 2022-02-28 15:34:07.913 [ShardingSphere-Command-4] ShardingSphere-SQL - SQLStatement: MySQLSelectStatement(table=Optional.empty, limit=Optional.empty, lock=Optional.empty, window=Optional.empty)
[INFO ] 2022-02-28 15:34:07.913 [ShardingSphere-Command-4] ShardingSphere-SQL - Actual SQL: ds_1 ::: SELECT id, mobile, idcard FROM t_user WHERE id = 10000
[INFO ] 2022-02-28 15:34:21.501 [ShardingSphere-Command-4] ShardingSphere-SQL - Logic SQL: SELECT id, mobile, idcard FROM t_user WHERE id = 10000
[INFO ] 2022-02-28 15:34:21.502 [ShardingSphere-Command-4] ShardingSphere-SQL - SQLStatement: MySQLSelectStatement(table=Optional.empty, limit=Optional.empty, lock=Optional.empty, window=Optional.empty)
[INFO ] 2022-02-28 15:34:21.502 [ShardingSphere-Command-4] ShardingSphere-SQL - Actual SQL: ds_2 ::: SELECT id, mobile, idcard FROM t_user WHERE id = 10000

Váltson az elsődleges adatbázisra

Zárja be a fő adatbázist ds_0:

Tekintse meg, hogy az elsődleges adatbázis megváltozott-e, és hogy a másodlagos adatbázis állapota helyes-e a DistSQL-ig.

mysql> SHOW READWRITE_SPLITTING RULES;
+----------------+-----------------------------+------------------------+------------------------+--------------------+---------------------+
| name           | auto_aware_data_source_name | write_data_source_name | read_data_source_names | load_balancer_type | load_balancer_props |
+----------------+-----------------------------+------------------------+------------------------+--------------------+---------------------+
| replication_ds | mgr_replication_ds          | ds_1                   | ds_2                   | NULL               |                     |
+----------------+-----------------------------+------------------------+------------------------+--------------------+---------------------+
1 row in set (0.01 sec)
mysql> SHOW READWRITE_SPLITTING READ RESOURCES;
+----------+----------+
| resource | status   |
+----------+----------+
| ds_2     | enabled  |
| ds_0     | disabled |
+----------+----------+
2 rows in set (0.01 sec)

Most pedig illesszünk be egy másik adatsort:

mysql> INSERT INTO t_user(id, mobile, idcard) value (10001, '13521207777', '110xxxxx');Query OK, 1 row affected (0.04 sec)

Tekintse meg a ShardingSphere-Proxy naplót, és ellenőrizze, hogy az útvonal csomópontja-e az elsődleges adatbázis ds_1.

[INFO ] 2022-02-28 15:40:26.784 [ShardingSphere-Command-6] ShardingSphere-SQL - Logic SQL: INSERT INTO t_user(id, mobile, idcard) value (10001, '13521207777', '110xxxxx')
[INFO ] 2022-02-28 15:40:26.784 [ShardingSphere-Command-6] ShardingSphere-SQL - SQLStatement: MySQLInsertStatement(setAssignment=Optional.empty, onDuplicateKeyColumns=Optional.empty)
[INFO ] 2022-02-28 15:40:26.784 [ShardingSphere-Command-6] ShardingSphere-SQL - Actual SQL: ds_1 ::: INSERT INTO t_user(id, mobile, idcard) value (10001, '13521207777', '110xxxxx')

Végül teszteljük a SELECT-t (ismételjük meg kétszer):

mysql> SELECT id, mobile, idcard FROM t_user WHERE id = 10001;

Tekintse meg a ShardingSphere-Proxy naplót, és nézze meg, hogy az útvonal csomópontja ds_2.

[INFO ] 2022-02-28 15:40:26.784 [ShardingSphere-Command-6] ShardingSphere-SQL - Logic SQL: INSERT INTO t_user(id, mobile, idcard) value (10001, '13521207777', '110xxxxx')
[INFO ] 2022-02-28 15:40:26.784 [ShardingSphere-Command-6] ShardingSphere-SQL - SQLStatement: MySQLInsertStatement(setAssignment=Optional.empty, onDuplicateKeyColumns=Optional.empty)
[INFO ] 2022-02-28 15:40:26.784 [ShardingSphere-Command-6] ShardingSphere-SQL - Actual SQL: ds_1 ::: INSERT INTO t_user(id, mobile, idcard) value (10001, '13521207777', '110xxxxx')

Engedje el a másodlagos adatbázisokat

Tekintse meg a legújabb elsődleges-másodlagos kapcsolatváltozásokat a DistSQL-ig. A ds_0 csomópont állapota az engedélyezett állapot szerint helyreáll, míg a ds_0 integrálva van a read_data_source_names-ba:

mysql> SHOW READWRITE_SPLITTING RULES;
+----------------+-----------------------------+------------------------+------------------------+--------------------+---------------------+
| name           | auto_aware_data_source_name | write_data_source_name | read_data_source_names | load_balancer_type | load_balancer_props |
+----------------+-----------------------------+------------------------+------------------------+--------------------+---------------------+
| replication_ds | mgr_replication_ds          | ds_1                   | ds_0,ds_2              | NULL               |                     |
+----------------+-----------------------------+------------------------+------------------------+--------------------+---------------------+
1 row in set (0.01 sec)
mysql> SHOW READWRITE_SPLITTING READ RESOURCES;
+----------+---------+
| resource | status  |
+----------+---------+
| ds_0     | enabled |
| ds_2     | enabled |
+----------+---------+
2 rows in set (0.00 sec)

A fent említett példa alapján most többet tud a ShardingSphere magas rendelkezésre állásáról és a dinamikus olvasási/írási felosztásról.

Ezután bemutatjuk a HA-tervek mögött meghúzódó elveket az alapul szolgáló adatbázissal, más néven tárolási csomópontokkal kapcsolatban.

Alapelvek

A ShardingSphere magas rendelkezésre állású megoldásai lehetővé teszik a felhasználók számára, hogy tovább szabják, és bővítményeket készítsenek. Jelenleg két HA tervet teljesítettünk: egy MySQL magas rendelkezésre állású MGR-re épülő megoldást, és az openGauss adatbázis magas rendelkezésre állású megoldását, amelyet néhány közösségi elkötelezettség támogat. A két megoldás elve alapvetően megegyezik.

Az alábbiakban bemutatjuk, miért és hogyan érheti el a ShardingSphere az adatbázis magas szintű rendelkezésre állását példaként a MySQL használatával.

Előfeltétel

A ShardingSphere a következő SQL utasítás végrehajtásával ellenőrzi, hogy az alapul szolgáló MySQL-fürtkörnyezet készen áll-e. A ShardingSphere nem indítható el, ha bármelyik teszt sikertelen.

  • Ellenőrizze, hogy az MGR telepítve van-e:
SELECT * FROM information_schema.PLUGINS WHERE PLUGIN_NAME='group_replication'
  • Tekintse meg az MGR csoport tagszámát:

Az alapul szolgáló MGR-fürtnek legalább három csomópontból kell állnia:

SELECT count(*) FROM performance_schema.replication_group_members
  • Ellenőrizze, hogy az MGR-fürt csoportneve összhangban van-e a konfigurációban szereplővel:

A csoportnév egy MGR-csoport jelölője, és az MGR-fürt minden csoportjának csak egy csoportneve van.

SELECT * FROM performance_schema.global_variables WHERE VARIABLE_NAME='group_replication_group_name'
  • Ellenőrizze, hogy az aktuális MGR van-e beállítva egyetlen elsődleges módként:

Jelenleg a ShardingSphere nem támogatja a kettős vagy több írásos forgatókönyveket. Csak az egyszeri írási módot támogatja:

SELECT * FROM performance_schema.global_variables WHERE VARIABLE_NAME='group_replication_single_primary_mode'
  • Az MGR-csoportfürt összes csomóponti gazdagépének, portjának és állapotának lekérdezésével ellenőrizze, hogy az általunk konfigurált adatforrás helyes-e:
SELECT MEMBER_HOST, MEMBER_PORT, MEMBER_STATE FROM performance_schema.replication_group_members

Dinamikus elsődleges adatbázis-felderítés

  • A ShardingSphere megkeresi az elsődleges adatbázis URL-címét a MySQL által biztosított lekérdezési főadatbázis SQL-parancsnak megfelelően.
private String findPrimaryDataSourceURL(final Map<String, DataSource> dataSourceMap) {
String result = "";
String sql = "SELECT MEMBER_HOST, MEMBER_PORT FROM performance_schema.replication_group_members WHERE MEMBER_ID = "
+ "(SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'group_replication_primary_member')";
for (DataSource each : dataSourceMap.values()) {
try (Connection connection = each.getConnection();
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(sql)) {
if (resultSet.next()) {
return String.format("%s:%s", resultSet.getString("MEMBER_HOST"), resultSet.getString("MEMBER_PORT"));
}
} catch (final SQLException ex) {
log.error("An exception occurred while find primary data source url", ex);
}
}
return result;
}
  • Hasonlítsa össze egyenként a fent talált elsődleges adatbázis URL-eket az általunk konfigurált dataSources URL-ekkel. Az egyeztetett adatforrás az elsődleges adatbázis, amely frissül az aktuális ShardingSphere memóriára, és állandósul a regisztrációs központban, amelyen keresztül a fürt más számítási csomópontjaihoz továbbítják.

Dinamikus másodlagos adatbázis-felderítés

A ShardingSpherezben kétféle másodlagos adatbázisállapot létezik: engedélyezés és letiltás. A másodlagos adatbázis állapota szinkronizálva lesz a ShardingSphere memóriával annak érdekében, hogy az olvasási forgalom megfelelően irányítható legyen.

  • Szerezze be az MGR csoport összes csomópontját:
SELECT MEMBER_HOST, MEMBER_PORT, MEMBER_STATE FROM performance_schema.replication_group_members
  • Másodlagos adatbázisok letiltása:
private void determineDisabledDataSource(final String schemaName, final Map<String, DataSource> activeDataSourceMap,
final List<String> memberDataSourceURLs, final Map<String, String> dataSourceURLs) {
for (Entry<String, DataSource> entry : activeDataSourceMap.entrySet()) {
boolean disable = true;
String url = null;
try (Connection connection = entry.getValue().getConnection()) {
url = connection.getMetaData().getURL();
for (String each : memberDataSourceURLs) {
if (null != url && url.contains(each)) {
disable = false;
break;
}
}
} catch (final SQLException ex) {
log.error("An exception occurred while find data source urls", ex);
}
if (disable) {
ShardingSphereEventBus.getInstance().post(new DataSourceDisabledEvent(schemaName, entry.getKey(), true));
} else if (!url.isEmpty()) {
dataSourceURLs.put(entry.getKey(), url);
}
}
}

Az, hogy a másodlagos adatbázis le van-e tiltva, az általunk konfigurált adatforráson és az MGR-csoport összes csomópontján alapul.

A ShardingSphere egyesével ellenőrizheti, hogy az általunk konfigurált adatforrás megfelelően be tudja-e szerezni a Connection értéket, és ellenőrizheti, hogy az adatforrás URL-je tartalmazza-e az MGR-csoport csomópontjait.

Ha a Connection nem érhető el, vagy az ellenőrzés sikertelen, a ShardingSphere letiltja az adatforrást egy eseményindítóval, és szinkronizálja azt a regisztrációs központtal.

  • Másodlagos adatbázisok engedélyezése:
private void determineDisabledDataSource(final String schemaName, final Map<String, DataSource> activeDataSourceMap,
final List<String> memberDataSourceURLs, final Map<String, String> dataSourceURLs) {
for (Entry<String, DataSource> entry : activeDataSourceMap.entrySet()) {
boolean disable = true;
String url = null;
try (Connection connection = entry.getValue().getConnection()) {
url = connection.getMetaData().getURL();
for (String each : memberDataSourceURLs) {
if (null != url && url.contains(each)) {
disable = false;
break;
}
}
} catch (final SQLException ex) {
log.error("An exception occurred while find data source urls", ex);
}
if (disable) {
ShardingSphereEventBus.getInstance().post(new DataSourceDisabledEvent(schemaName, entry.getKey(), true));
} else if (!url.isEmpty()) {
dataSourceURLs.put(entry.getKey(), url);
}
}
}

Miután az összeomlott másodlagos adatbázist helyreállították és hozzáadták az MGR-csoporthoz, a konfigurációnk ellenőrzi, hogy a helyreállított adatforrást használják-e. Ha igen, az eseményindító jelzi a ShardingSphere-nek, hogy az adatforrást engedélyezni kell.

Szívverés mechanizmusa

Az elsődleges-másodlagos állapotok valós idejű szinkronizálása érdekében a szívverés mechanizmusa bekerül a HA modulba.

Az ElasticJob ShardingSphere alprojekt integrálásával a fenti folyamatokat az ElasticJob ütemező keretrendszer Job formájában hajtja végre, amikor a HA modul inicializálva van, így valósul meg a funkciófejlesztés és a feladatütemezés szétválasztása.

Még ha a fejlesztőknek ki kell terjeszteniük a HA funkciót, nem kell törődniük azzal, hogy a munkákat hogyan alakítják ki és működtetik.

private void initHeartBeatJobs(final String schemaName, final Map<String, DataSource> dataSourceMap) {
Optional<ModeScheduleContext> modeScheduleContext = ModeScheduleContextFactory.getInstance().get();
if (modeScheduleContext.isPresent()) {
for (Entry<String, DatabaseDiscoveryDataSourceRule> entry : dataSourceRules.entrySet()) {
Map<String, DataSource> dataSources = dataSourceMap.entrySet().stream().filter(dataSource -> !entry.getValue().getDisabledDataSourceNames().contains(dataSource.getKey()))
.collect(Collectors.toMap(Entry::getKey, Entry::getValue));
CronJob job = new CronJob(entry.getValue().getDatabaseDiscoveryType().getType() + "-" + entry.getValue().getGroupName(),
each -> new HeartbeatJob(schemaName, dataSources, entry.getValue().getGroupName(), entry.getValue().getDatabaseDiscoveryType(), entry.getValue().getDisabledDataSourceNames())
.execute(null), entry.getValue().getHeartbeatProps().getProperty("keep-alive-cron"));
modeScheduleContext.get().startCronJob(job);
}
}
}

Következtetés

Eddig az Apache ShardingSphere HA funkciója alkalmazhatónak bizonyult a MySQL és az openGauss HA megoldásokhoz.

A jövőben több MySQL HA-terméket fog integrálni, és több adatbázis-HA-megoldást támogat.

Mint mindig, ha felkeltettük érdeklődését, örömmel csatlakozhat hozzánk, és hozzájárulhat az Apache ShardingSphere projekthez.

Apache ShardingSphere nyílt forráskódú projekthivatkozások:

"ShardingSphere Github"

"ShardingSphere Twitter"

"ShardingSphere Slack"

„Közreműködői irányelv”

Szerző

Zhao Jinchao

SphereEx Middleware mérnök és Apache ShardingSphere Committer

Jelenleg Zhao az Apache ShardingSphere High Availability szolgáltatásának fejlesztésére koncentrál.