Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provides built-in GraalVM Reachability Metadata for core features of ShardingSphere JDBC and adds nativeTest-related unit test subsets #29000

Merged
merged 3 commits into from
Nov 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .github/workflows/nightly-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ jobs:
ref: ${{ inputs.commit-id }}
- uses: graalvm/setup-graalvm@v1
with:
java-version: '17.0.8'
java-version: '17.0.9'
distribution: 'graalvm-community'
github-token: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/cache@v3
Expand All @@ -136,7 +136,6 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Push Docker Image
run: |
./mvnw -PgenerateStandardMetadata -DskipNativeTests -B -T1C clean test
./mvnw -am -pl distribution/proxy-native -Prelease.native,docker.buildx.push.native -B -T1C -DskipTests -Dproxy.image.repository=${{ env.PROXY_NATIVE }} -Dproxy.image.tag=${{ github.sha }} clean package

build-cache:
Expand Down
28 changes: 28 additions & 0 deletions .github/workflows/nightly-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,31 @@ jobs:
java-version: 8
- name: Run Tests with JDK 8
run: ./mvnw test -B -ntp -fae -T1C

ci-native-test:
if: github.repository == 'apache/shardingsphere'
name: NativeTest CI - GraalVM CE on ${{ matrix.os }}
needs: global-environment
runs-on: ${{ matrix.os }}
timeout-minutes: 90
strategy:
max-parallel: 20
fail-fast: false
matrix:
os: [ ubuntu-latest ]
steps:
- uses: actions/checkout@v3
- uses: graalvm/setup-graalvm@v1
with:
java-version: '17.0.9'
distribution: 'graalvm-community'
github-token: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/cache@v3
with:
path: ~/.m2/repository
key: ${{ needs.global-environment.outputs.GLOBAL_CACHE_PREFIX }}-maven-third-party-cache-${{ github.sha }}
restore-keys: |
${{ needs.global-environment.outputs.GLOBAL_CACHE_PREFIX }}-maven-third-party-cache-
${{ needs.global-environment.outputs.GLOBAL_CACHE_PREFIX }}-maven-third-party-
- name: Run nativeTest with GraalVM CE
run: ./mvnw -PnativeTestInShardingSphere -T1C -e clean test
17 changes: 0 additions & 17 deletions distribution/proxy-native/access-filter.json

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,263 @@
+++
title = "GraalVM Native Image"
weight = 8
chapter = true
+++

## 背景信息

ShardingSphere JDBC 已在 GraalVM Native Image 下完成可用性验证。

构建包含 `org.apache.shardingsphere:shardingsphere-jdbc-core:${shardingsphere.version}` 的 Maven 依赖的 GraalVM Native
Image,你需要借助于 GraalVM Native Build Tools。GraalVM Native Build Tools 提供了 Maven Plugin 和 Gradle Plugin 来简化 GraalVM
CE 的 `native-image` 工具的长篇大论的 shell 命令。

ShardingSphere JDBC 要求在如下或更高版本的 `GraalVM CE` 完成构建 GraalVM Native Image。使用者可通过 SDKMAN! 快速切换 JDK。这同理
适用于 `Oracle GraalVM`, `Liberica Native Image Kit` 和 `Mandrel` 等 `GraalVM CE` 的下游发行版。

- GraalVM CE 23.0.2 For JDK 17.0.9,对应于 SDKMAN! 的 `17.0.9-graalce`
- GraalVM CE 23.0.2 For JDK 21.0.1,对应于 SDKMAN! 的 `21.0.1-graalce`

### Maven 生态

使用者需要配置额外的 BuildArgs ,以阻止 GroovyShell 的相关类在构建 GraalVM Native Image 时报错。并主动使用 GraalVM Reachability
Metadata 中央仓库。如下配置可供参考,以配置项目额外的 Maven Profile,以 GraalVM Native Build Tools 的文档为准。

```xml
<project>
<dependencies>
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>shardingsphere-jdbc-core</artifactId>
<version>${shardingsphere.version}</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
<version>0.9.28</version>
<extensions>true</extensions>
<configuration>
<buildArgs>
<arg>--report-unsupported-elements-at-runtime</arg>
</buildArgs>
<metadataRepository>
<enabled>true</enabled>
</metadataRepository>
</configuration>
<executions>
<execution>
<id>build-native</id>
<goals>
<goal>compile-no-fork</goal>
</goals>
<phase>package</phase>
</execution>
<execution>
<id>test-native</id>
<goals>
<goal>test</goal>
</goals>
<phase>test</phase>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
```

### Gradle 生态

使用者需要配置额外的 BuildArgs ,以阻止 GroovyShell 的相关类在构建 GraalVM Native Image 时报错。并主动使用 GraalVM Reachability
Metadata 中央仓库。如下配置可供参考,以配置项目额外的 Gradle Task,以 GraalVM Native Build Tools 的文档为准。

```groovy
plugins {
id 'org.graalvm.buildtools.native' version '0.9.28'
}

dependencies {
implementation 'org.apache.shardingsphere:shardingsphere-jdbc-core:${shardingsphere.version}'
}

graalvmNative {
binaries {
main {
buildArgs.add('--report-unsupported-elements-at-runtime')
}
test {
buildArgs.add('--report-unsupported-elements-at-runtime')
}
}
metadataRepository {
enabled = true
}
}
```

### 对于 SBT 等不被 GraalVM Native Build Tools 支持的构建工具

此类需求需要在 https://github.com/graalvm/native-build-tools 打开额外的 issue 并提供对应构建工具的 Plugin 实现。


### 使用限制

1. 如下的算法类由于涉及到 https://github.com/oracle/graal/issues/5522 , 暂未可在 GraalVM Native Image 下使用。
- `org.apache.shardingsphere.sharding.algorithm.sharding.inline.InlineShardingAlgorithm`
- `org.apache.shardingsphere.sharding.algorithm.sharding.inline.ComplexInlineShardingAlgorithm`
- `org.apache.shardingsphere.sharding.algorithm.sharding.hint.HintInlineShardingAlgorithm`

对于常规案例,使用者可通过 CLASS_BASE 算法自行模拟 GroovyShell 的行为。例如对于如下配置。

```yaml
rules:
- !SHARDING
defaultDatabaseStrategy:
standard:
shardingColumn: user_id
shardingAlgorithmName: inline
shardingAlgorithms:
inline:
type: INLINE
props:
algorithm-expression: ds_${user_id % 2}
allow-range-query-with-inline-sharding: false
```

可首先定义 CLASS_BASE 的实现类。

```java
package org.example.test;

import org.apache.shardingsphere.sharding.api.sharding.standard.PreciseShardingValue;
import org.apache.shardingsphere.sharding.api.sharding.standard.RangeShardingValue;
import org.apache.shardingsphere.sharding.api.sharding.standard.StandardShardingAlgorithm;

import java.util.Collection;

public final class TestShardingAlgorithmFixture implements StandardShardingAlgorithm<Integer> {

@Override
public String doSharding(final Collection<String> availableTargetNames, final PreciseShardingValue<Integer> shardingValue) {
String resultDatabaseName = "ds_" + shardingValue.getValue() % 2;
for (String each : availableTargetNames) {
if (each.equals(resultDatabaseName)) {
return each;
}
}
return null;
}

@Override
public Collection<String> doSharding(final Collection<String> availableTargetNames, final RangeShardingValue<Integer> shardingValue) {
throw new RuntimeException("This algorithm class does not support range queries.");
}
}
```

修改相关 YAML 配置如下。

```yaml
rules:
- !SHARDING
defaultDatabaseStrategy:
standard:
shardingColumn: user_id
shardingAlgorithmName: inline
shardingAlgorithms:
inline:
type: CLASS_BASED
props:
strategy: STANDARD
algorithmClassName: org.example.test.TestShardingAlgorithmFixture
```

在 `src/main/resources/META-INF/native-image/exmaple-test-metadata/reflect-config.json` 加入如下内容即可在正常在 GraalVM Native
Image 下使用。

```json
[
{
"name":"org.example.test.TestShardingAlgorithmFixture",
"methods":[{"name":"<init>","parameterTypes":[] }]
}
]
```

2. 对于 `读写分离` 的功能,你需要使用 `行表达式` SPI 的其他实现,以在配置 `logic database name`,`writeDataSourceName` 和 `readDataSourceNames`
时绕开对 GroovyShell 的调用。一个可能的配置是使用 `LITERAL` 的 `行表达式` SPI 的实现。对于 `数据分片` 的功能的 `actualDataNodes` 同理。
```yaml
rules:
- !READWRITE_SPLITTING
dataSources:
<LITERAL>readwrite_ds:
writeDataSourceName: <LITERAL>ds_0
readDataSourceNames:
- <LITERAL>ds_1
- <LITERAL>ds_2
```

3. 使用者依然需要在 `src/main/resources/META-INF/native-image` 文件夹或 `src/test/resources/META-INF/native-image` 文件夹配置独立
文件的 GraalVM Reachability Metadata。使用者可通过 GraalVM Native Build Tools 的 GraalVM Tracing Agent 来快速采集 GraalVM
Reachability Metadata。

4. 尚未验证 DistSQL 的可用性。使用者需自行添加额外的 GraalVM Reachability Metadata。

## 贡献 GraalVM Reachability Metadata

ShardingSphere 对在 GraalVM Native Image 下的可用性的验证,是通过 GraalVM Native Build Tools 的 Maven Plugin 子项目来完成的。
通过在 JVM 下运行单元测试,为单元测试打上 `junit-platform-unique-ids*` 标签,此后构建为 GraalVM Native Image 进行 nativeTest 来测试
在 GraalVM Native Image 下的单元测试覆盖率。请贡献者不要使用 `io.kotest:kotest-runner-junit5-jvm:5.5.4` 等在 `test listener` mode 下
failed to discover tests 的测试库。

ShardingSphere 定义了 `shardingsphere-infra-nativetest` 的 Maven Module 用于为 native Test 提供小型的单元测试子集,
此单元测试子集避免了使用 Mockito 等 native Test 下无法使用的第三方库。

ShardingSphere 定义了 `nativeTestInShardingSphere` 的 Maven Profile 用于为 `shardingsphere-infra-nativetest` 模块执行 nativeTest 。

假设贡献者处于新的 Ubuntu 22.04.3 LTS 实例下,其可通过如下 bash 命令通过 SDKMAN! 管理 JDK 和工具链,
并为 `shardingsphere-infra-nativetest` 子模块执行 nativeTest。

```bash
sudo apt install unzip zip curl sed -y
curl -s "https://get.sdkman.io" | bash
source "$HOME/.sdkman/bin/sdkman-init.sh"
sdk install java 17.0.9-graalce
sdk use java 17.0.9-graalce
sudo apt-get install build-essential libz-dev zlib1g-dev -y

git clone [email protected]:apache/shardingsphere.git
cd ./shardingsphere/
./mvnw -PnativeTestInShardingSphere -T1C -e clean test
```

当贡献者发现缺少与 ShardingSphere 无关的第三方库的 GraalVM Reachability Metadata 时,应当在
https://github.com/oracle/graalvm-reachability-metadata 打开新的 issue, 并提交包含依赖的第三方库缺失的 GraalVM Reachability
Metadata 的 PR。ShardingSphere 在 `shardingsphere-infra-reachability-metadata` 子模块主动托管了部分第三方库的 GraalVM Reachability Metadata。

如果 nativeTest 执行失败, 应为单元测试生成初步的 GraalVM Reachability Metadata,并手动调整以修复 nativeTest。
如有需要,请使用 `org.junit.jupiter.api.condition.DisabledInNativeImage` 注解或 `org.graalvm.nativeimage.imagecode` 的
System Property 屏蔽部分单元测试在 GraalVM Native Image 下运行。

ShardingSphere 定义了 `generateMetadata` 的 Maven Profile 用于在 GraalVM JIT Compiler 下携带 GraalVM Tracing Agent 执行单元测试,并在特定目录下生成或合并
已有的 GraalVM Reachability Metadata 文件。可通过如下 bash 命令简单处理此流程。贡献者仍可能需要手动调整具体的 JSON 条目,并在适当的时候
调整 Maven Profile 和 GraalVM Tracing Agent 的 Filter 链。

以下命令仅为 `shardingsphere-infra-nativetest` 生成 Conditional 形态的 GraalVM Reachability Metadata 的一个举例。生成的 GraalVM
Reachability Metadata 位于 `shardingsphere-infra-reachability-metadata` 子模块下。

对于测试类和测试文件独立使用的 GraalVM Reachability Metadata,贡献者应该放置到
`${user.dir}/infra/nativetest/src/test/resources/META-INF/native-image/shardingsphere-infra-nativetest-test-metadata/`
文件夹下。`${}` 内为相关子模块对应的 POM 4.0 的常规系统变量,自行替换。

```bash
git clone [email protected]:apache/shardingsphere.git
cd ./shardingsphere/
./mvnw -PgenerateMetadata -DskipNativeTests -e -T1C clean test native:metadata-copy
```

请手动删除无任何具体条目的 JSON 文件。
Loading