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

perf: benchmark and sample #769

Draft
wants to merge 1 commit into
base: postgresql-dialect
Choose a base branch
from
Draft
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
35 changes: 18 additions & 17 deletions benchmarks/ycsb/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
# BUILD
FROM maven:3.8.4-eclipse-temurin-17-alpine AS build
# Copy over build files to docker image.
COPY LICENSE ./
COPY CONTRIBUTING.md ./
COPY README.md ./
COPY NOTIFICATIONS.md ./
COPY logging.properties ./
COPY src src/
COPY pom.xml ./
COPY license-checks.xml ./
COPY java.header ./
# Download dependencies
RUN mvn dependency:go-offline

# Build from source.
RUN mvn package -Passembly -DskipTests

## Copy over build files to docker image.
#COPY LICENSE ./
#COPY CONTRIBUTING.md ./
#COPY README.md ./
#COPY NOTIFICATIONS.md ./
#COPY logging.properties ./
#COPY src src/
#COPY pom.xml ./
#COPY license-checks.xml ./
#COPY java.header ./
## Download dependencies
#RUN mvn dependency:go-offline
#
## Build from source.
#RUN mvn package -Passembly -DskipTests

COPY target/pgadapter target/pgadapter

# Docker image for the YCSB runner.
FROM gcr.io/google.com/cloudsdktool/google-cloud-cli:slim
Expand All @@ -27,7 +28,7 @@ RUN apt -y install python

COPY --from=build target/pgadapter /

ADD https://github.com/brianfrankcooper/YCSB/releases/download/0.17.0/ycsb-0.17.0.tar.gz /ycsb-0.17.0.tar.gz
COPY benchmarks/ycsb/ycsb-0.17.0.tar.gz ./
RUN tar xfvz ycsb-0.17.0.tar.gz
RUN mv ycsb-0.17.0 ycsb

Expand Down
11 changes: 7 additions & 4 deletions benchmarks/ycsb/create-and-run-ycsb-job.sh
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
#!/bin/bash
set -euo pipefail

PGADAPTER_YCSB_RUNNER=pgadapter-ycsb-runner
PGADAPTER_YCSB_JOB=pgadapter-ycsb-job
PGADAPTER_YCSB_RUNNER=pgadapter-channels-ycsb-runner
PGADAPTER_YCSB_JOB=pgadapter-channels-ycsb-job
PGADAPTER_YCSB_REGION=europe-north1
NUMBER_OF_TASKS=4

SPANNER_INSTANCE=pgadapter-ycsb-regional-test
SPANNER_DATABASE=pgadapter-ycsb-test
SPANNER_DATABASE=pgadapter-channels-ycsb-test

gcloud config set run/region $PGADAPTER_YCSB_REGION
gcloud config set builds/region $PGADAPTER_YCSB_REGION

mvn clean package -Passembly -DskipTests

gcloud auth configure-docker gcr.io --quiet
docker build --platform=linux/amd64 . -f benchmarks/ycsb/Dockerfile \
-t gcr.io/$(gcloud config get project --quiet)/$PGADAPTER_YCSB_RUNNER
Expand All @@ -20,7 +23,7 @@ gcloud beta run jobs delete $PGADAPTER_YCSB_JOB --quiet || true
sleep 3
gcloud beta run jobs create $PGADAPTER_YCSB_JOB \
--image gcr.io/$(gcloud config get project --quiet)/$PGADAPTER_YCSB_RUNNER \
--tasks 1 \
--tasks $NUMBER_OF_TASKS \
--set-env-vars SPANNER_INSTANCE=$SPANNER_INSTANCE \
--set-env-vars SPANNER_DATABASE=$SPANNER_DATABASE \
--max-retries 0 \
Expand Down
36 changes: 19 additions & 17 deletions benchmarks/ycsb/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ set -euox pipefail

echo "Starting Task #${CLOUD_RUN_TASK_INDEX}, Attempt #${CLOUD_RUN_TASK_ATTEMPT}..."
EXECUTED_AT=`date +"%Y-%m-%dT%T"`
EXECUTED_AT="${EXECUTED_AT} ${CLOUD_RUN_TASK_INDEX}"

DATABASES=$(gcloud spanner databases list --instance $SPANNER_INSTANCE --filter="name:${SPANNER_DATABASE}")
if [[ "$DATABASES" != *"$SPANNER_DATABASE"* ]]; then
gcloud spanner databases create $SPANNER_DATABASE --instance=$SPANNER_INSTANCE --database-dialect='POSTGRESQL'
fi

java -jar pgadapter.jar -p $(gcloud --quiet config get project) -i $SPANNER_INSTANCE -r="minSessions=1000;maxSessions=1000;numChannels=20" &
PARAMETERS="minSessions=400;maxSessions=400;numChannels=100"
java -jar pgadapter.jar -p $(gcloud --quiet config get project) -i $SPANNER_INSTANCE -r="${PARAMETERS}" &
sleep 6
export PGDATABASE=$SPANNER_DATABASE
psql -h localhost -c "CREATE TABLE IF NOT EXISTS usertable (
Expand Down Expand Up @@ -65,33 +67,33 @@ db.user=
db.passwd=
EOT

psql -h localhost -c "set spanner.autocommit_dml_mode='partitioned_non_atomic'; delete from usertable;"
#psql -h localhost -c "set spanner.autocommit_dml_mode='partitioned_non_atomic'; delete from usertable;"

# Load workloada
./bin/ycsb load jdbc -P workloads/workloada \
-threads 20 \
-p recordcount=100000 \
-p db.batchsize=200 \
-p jdbc.batchupdateapi=true \
-P tcp.properties \
-cp "jdbc-binding/lib/*" \
> ycsb.log
#./bin/ycsb load jdbc -P workloads/workloada \
# -threads 40 \
# -p recordcount=5000000 \
# -p db.batchsize=200 \
# -p jdbc.batchupdateapi=true \
# -P tcp.properties \
# -cp "jdbc-binding/lib/*" \
# > ycsb.log

# Run workloads a, b, c, f, and d.
for WORKLOAD in a b c f d
for WORKLOAD in a
do
for DEPLOYMENT in java_tcp java_uds
for DEPLOYMENT in java_uds
do
if [ $DEPLOYMENT == 'java_tcp' ]
then
CONN=tcp.properties
else
CONN=uds.properties
fi
for THREADS in 1 5 20 50 200
for THREADS in 100
do
OPERATION_COUNT=`expr $THREADS \* 100`
for BATCH_SIZE in 1 10 50 200
OPERATION_COUNT=`expr $THREADS \* 15000`
for BATCH_SIZE in 10
do
if [ $BATCH_SIZE == 1 ]
then
Expand Down Expand Up @@ -135,11 +137,11 @@ do
INSERT_P99=$(grep '\[INSERT\], 99thPercentileLatency(us), ' ycsb.log | sed 's/^.*, //' || echo null)

psql -h localhost \
-c "insert into run (executed_at, deployment, workload, threads, batch_size, operation_count, run_time, throughput,
-c "insert into run (description, executed_at, deployment, workload, threads, batch_size, operation_count, run_time, throughput,
read_min, read_max, read_avg, read_p50, read_p95, read_p99,
update_min, update_max, update_avg, update_p50, update_p95, update_p99,
insert_min, insert_max, insert_avg, insert_p50, insert_p95, insert_p99) values
('$EXECUTED_AT', '$DEPLOYMENT', '$WORKLOAD', $THREADS, $BATCH_SIZE, $OPERATION_COUNT, $OVERALL_RUNTIME, $OVERALL_THROUGHPUT,
('$PARAMETERS', '$EXECUTED_AT', '$DEPLOYMENT', '$WORKLOAD', $THREADS, $BATCH_SIZE, $OPERATION_COUNT, $OVERALL_RUNTIME, $OVERALL_THROUGHPUT,
$READ_MIN, $READ_MAX, $READ_AVG, $READ_P50, $READ_P95, $READ_P99,
$UPDATE_MIN, $UPDATE_MAX, $UPDATE_AVG, $UPDATE_P50, $UPDATE_P95, $UPDATE_P99,
$INSERT_MIN, $INSERT_MAX, $INSERT_AVG, $INSERT_P50, $INSERT_P95, $INSERT_P99)"
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
com.google.cloud.spanner.pgadapter.nodejs.NodeJSTest
</excludedTests>

<spanner.version>6.35.2</spanner.version>
<spanner.version>6.38.3-SNAPSHOT</spanner.version>
<junixsocket.version>2.6.2</junixsocket.version>
</properties>

Expand Down
100 changes: 100 additions & 0 deletions samples/ycsb/run-ycsb.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@

# Make sure you have psql, Java, wget and python installed on the system.

#sudo apt update && apt -y install postgresql-client
#sudo apt -y install default-jre
#sudo apt -y install wget
#sudo apt -y install python

# Change these variables to your database name and service account.
SPANNER_DATABASE="projects/my-project/instances/my-instance/databases/my-database"
CREDENTIALS=/path/to/service-account.json

echo "Downloading YCSB"
wget https://github.com/brianfrankcooper/YCSB/releases/download/0.17.0/ycsb-0.17.0.tar.gz

echo "Extracting YCSB"
tar xfvz ycsb-0.17.0.tar.gz
mv ycsb-0.17.0 ycsb

echo "Download the PostgreSQL JDBC driver and the additional libraries that are needed to use Unix Domain Sockets"
wget -P ycsb/jdbc-binding/lib/ https://repo1.maven.org/maven2/org/postgresql/postgresql/42.5.0/postgresql-42.5.0.jar
wget -P ycsb/jdbc-binding/lib/ https://repo1.maven.org/maven2/com/kohlschutter/junixsocket/junixsocket-common/2.6.2/junixsocket-common-2.6.2.jar
wget -P ycsb/jdbc-binding/lib/ https://repo1.maven.org/maven2/com/kohlschutter/junixsocket/junixsocket-native-common/2.6.2/junixsocket-native-common-2.6.2.jar

echo "Pull and start the PGAdapter Docker container"
docker pull gcr.io/cloud-spanner-pg-adapter/pgadapter
docker run \
--name pgadapter \
--rm \
-d -p 5432:5432 \
-v /tmp:/tmp \
-v $CREDENTIALS:/credentials.json:ro \
gcr.io/cloud-spanner-pg-adapter/pgadapter \
-c /credentials.json -x
sleep 6


echo "Create the 'usertable' table that is used by YCSB"
psql -h /tmp -d $SPANNER_DATABASE \
-c "CREATE TABLE IF NOT EXISTS usertable (
YCSB_KEY VARCHAR(255) PRIMARY KEY,
FIELD0 TEXT, FIELD1 TEXT,
FIELD2 TEXT, FIELD3 TEXT,
FIELD4 TEXT, FIELD5 TEXT,
FIELD6 TEXT, FIELD7 TEXT,
FIELD8 TEXT, FIELD9 TEXT
);"

cd ycsb

# This replaces '/' in the database name with '%2f' to make it URL safe.
# This is necessary when using a fully qualified database name in a JDBC connection URL.
URL_ENCODED_SPANNER_DATABASE=$(echo $SPANNER_DATABASE | sed -e 's/\//%2f/g')

# Create a properties file that can be used with YCSB.
# This tells YCSB which database it should connect to.
cat <<EOT >> uds.properties
db.driver=org.postgresql.Driver
db.url=jdbc:postgresql://localhost/$URL_ENCODED_SPANNER_DATABASE?socketFactory=org.newsclub.net.unix.AFUNIXSocketFactory\$FactoryArg&socketFactoryArg=/tmp/.s.PGSQL.5432
db.user=
db.passwd=
EOT

# Delete any data currently in the `usertable` table.
# Skip this if you want to reuse existing data.
psql -h /tmp -d $SPANNER_DATABASE \
-c "set spanner.autocommit_dml_mode='partitioned_non_atomic'; delete from usertable;"

# Load 'workload a' into `usertable`.
# Skip this if you want to reuse existing data.
# See also https://github.com/brianfrankcooper/YCSB/wiki/Running-a-Workload
echo "Load workload a"
echo ""
./bin/ycsb load jdbc -P workloads/workloada \
-threads 20 \
-p recordcount=10000 \
-p db.batchsize=200 \
-p jdbc.batchupdateapi=true \
-P uds.properties \
-cp "jdbc-binding/lib/*"

# Run 'workload a'.
# Repeat this step without any of the other steps to just repeatedly run a workload.
echo ""
echo "---------------"
echo "Run workload a"
echo ""
./bin/ycsb run jdbc -P workloads/workloada \
-threads 20 \
-p hdrhistogram.percentiles=50,95,99 \
-p operationcount=1000 \
-p recordcount=10000 \
-p db.batchsize=20 \
-p jdbc.batchupdateapi=true \
-P uds.properties \
-cp "jdbc-binding/lib/*"


# Stop PGAdapter.
docker stop pgadapter
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ private String appendPropertiesToUrl(String url, Properties info) {
return url;
}
StringBuilder result = new StringBuilder(url);
result.append(";numChannels=4");
for (Entry<Object, Object> entry : info.entrySet()) {
if (entry.getValue() != null && !"".equals(entry.getValue())) {
result.append(";").append(entry.getKey()).append("=").append(entry.getValue());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@
import java.time.ZoneOffset;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
Expand Down Expand Up @@ -337,16 +340,46 @@ private String getExpectedInitialApplicationName() {
}

@Test
public void testQuery() throws SQLException {
public void testQuery() throws SQLException, InterruptedException {
String sql = "SELECT 1";

try (Connection connection = DriverManager.getConnection(createUrl())) {
try (ResultSet resultSet = connection.createStatement().executeQuery(sql)) {
assertTrue(resultSet.next());
assertEquals(1L, resultSet.getLong(1));
assertFalse(resultSet.next());
}
}
int numThreads = 128;
ExecutorService service = Executors.newFixedThreadPool(128);
for (int i = 0; i < numThreads; i++) {
service.submit(
(Callable<Void>)
() -> {
try (Connection connection = DriverManager.getConnection(createUrl())) {
try (ResultSet resultSet = connection.createStatement().executeQuery(sql)) {
assertTrue(resultSet.next());
assertEquals(1L, resultSet.getLong(1));
assertFalse(resultSet.next());
}
}
return null;
});
}
service.shutdown();
service.awaitTermination(60L, TimeUnit.SECONDS);
System.out.println("Finished");
// 4 channels:
// 16 threads for Transport-Channel
// 4 grpc default executor
// 8 grpc default worker
// 5 grpc transport
//
// 8 channels:
// 16 threads for Transport-Channel
// 8 grpc default executor
// 8 grpc default worker
// 8 grpc transport
//
// 12 channels:
// 16 threads for Transport-Channel
// 5 grpc default executor
// 8 grpc default worker
// 8 grpc transport
//

// The statement is only sent once to the mock server. The DescribePortal message will trigger
// the execution of the query, and the result from that execution will be used for the Execute
Expand Down