Hologres est un entrepôt de données en temps réel qui intègre le service de données et l'analytique. Il prend en charge des jeux de données contenant plusieurs dizaines de milliards d'enregistrements et fournit des services de requête ponctuelle clé-valeur avec une latence inférieure à 10 ms et plus d'un million de requêtes par seconde (QPS) via SQL.
Ce guide présente la conception des tables et les méthodes de requête adaptées aux charges de travail de requêtes ponctuelles haute performance.
Prérequis
Avant de commencer, assurez-vous de disposer des éléments suivants :
Une instance Hologres en cours d'exécution
Le point de terminaison VPC de votre instance (disponible dans la section Network Information de la page des détails de l'instance dans la console Hologres)
Votre ID AccessKey et votre secret AccessKey depuis la page AccessKey Management
Fonctionnement
Une requête ponctuelle recherche une seule ligne à l'aide de sa clé primaire. Hologres achemine chaque requête directement vers le shard propriétaire de la ligne, la récupère depuis le stockage orienté ligne et la renvoie, le tout sans balayage complet de la table.
Trois propriétés de table contrôlent ce processus :
Clé de clustering — trie les lignes au sein de chaque shard afin que la ligne cible soit trouvée en une seule opération de recherche.
Clé de distribution — détermine quel shard possède une clé donnée, permettant un acheminement direct.
Stockage orienté ligne — conserve toutes les colonnes d'une ligne physiquement adjacentes, de sorte qu'une seule lecture renvoie la ligne complète.
Lorsque la clé primaire, la clé de clustering et la clé de distribution pointent vers la même colonne, chaque requête ponctuelle atteint exactement un shard et lit exactement une ligne.
Concevoir la table
Créez la table en définissant orientation sur row, et attribuez à la fois clustering_key et distribution_key à la colonne clé. Par défaut, la clé primaire sert également de clé de distribution ; l'appel à distribution_key est donc redondant lorsque la clé primaire et la clé de distribution correspondent à la même colonne, mais le spécifier explicitement évite toute ambiguïté.
Pour les colonnes de type chaîne, utilisez TEXT plutôt que VARCHAR ou CHAR. Les types à longueur variable nécessitent des vérifications de longueur supplémentaires qui ajoutent de la latence à grande échelle.
-- Create a row-oriented table optimized for point queries.
-- The key column is the primary key, clustering key, and distribution key.
-- Queries on key= go directly to the matching shard and return in one seek.
BEGIN;
CREATE TABLE test_kv_table (
key TEXT PRIMARY KEY,
value TEXT
);
CALL set_table_property('test_kv_table', 'orientation', 'row');
CALL set_table_property('test_kv_table', 'clustering_key', 'key');
CALL set_table_property('test_kv_table', 'distribution_key', 'key');
COMMIT;
Importance de chaque propriété
| Propriété | Valeur par défaut si omise | Effet lorsqu'elle est correctement définie |
|---|---|---|
orientation = 'row' |
Stockage en colonnes | Lit la ligne complète en une seule entrée/sortie au lieu d'une entrée/sortie par colonne |
clustering_key |
Aucune | Trie les lignes au sein de chaque shard afin que la ligne cible soit trouvée en une seule opération de recherche |
distribution_key |
Clé primaire | Achemine la requête vers exactement un shard, en ignorant tous les autres |
L'omission de orientation = 'row' constitue l'erreur de performance la plus courante. Une table utilisant le stockage en colonnes nécessite une entrée/sortie par colonne pour chaque requête ponctuelle, ce qui peut ajouter des dizaines de millisecondes de latence sur les tables larges.
Interroger les données
Exécutez les tests de performance depuis le code de votre application en utilisant votre pilote JDBC ou HoloClient, et non depuis la console Hologres. Les requêtes effectuées via la console incluent une surcharge liée à l'interface utilisateur qui gonfle la latence mesurée et ne reflète pas les performances obtenues via un pilote.
Requêtes SQL
Pour des recherches rapides ou des tests ad hoc, utilisez directement SQL :
-- Single key
SELECT * FROM test_kv_table WHERE key = '1';
-- Multiple keys in one round trip
SELECT * FROM test_kv_table WHERE key IN ('1', '2', '3');
Java avec des instructions préparées
Utilisez une instruction préparée et réutilisez-la pour plusieurs requêtes. La réutilisation d'une instruction préparée permet à Hologres d'éviter la planification de la requête à chaque appel, ce qui élimine une source significative de latence à haut débit QPS.
Connectez-vous toujours via le point de terminaison VPC. Les points de terminaison publics ajoutent du temps d'aller-retour réseau et sont soumis à des limitations de débit.
// Query multiple keys using a reused prepared statement.
// The prepared statement is created once and reused for every query in the loop.
private static void testKV(Connection conn) throws Exception {
String sql = "SELECT * FROM test_kv_table WHERE key = ?";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
for (int i = 0; i < 100; ++i) {
stmt.setString(1, Integer.toString(i));
long begin = System.currentTimeMillis();
try (ResultSet rs = stmt.executeQuery()) {
long cost = System.currentTimeMillis() - begin;
while (rs.next()) {
System.out.println(
"data => " + rs.getObject(1) + " " + rs.getObject(2)
+ " latency => [" + cost + "]ms"
);
}
}
}
}
}
HoloClient (recommandé pour les charges de travail à haut QPS)
HoloClient est un SDK Java natif pour Hologres qui regroupe automatiquement les appels Get concurrents en une seule instruction SQL. Cette approche réduit les allers-retours réseau et constitue la méthode recommandée lorsque le QPS est la contrainte principale.
Ajoutez la dépendance via Maven :
<dependency>
<groupId>com.alibaba.hologres</groupId>
<artifactId>holo-client</artifactId>
<version>{1.2.16.5}</version>
</dependency>
Configurez et utilisez le client :
// The JDBC URL format is jdbc:postgresql://host:port/db.
// Use your VPC endpoint as the host.
HoloConfig config = new HoloConfig();
config.setJdbcUrl(url);
config.setUsername(username);
config.setPassword(password);
config.setReadThreadCount(10); // Maintain up to 10 concurrent JDBC connections
try (HoloClient client = new HoloClient(config)) {
TableSchema schema0 = client.getTableSchema("t0");
// Submit two Gets asynchronously. HoloClient batches them into one SQL call.
Get get = Get.newBuilder(schema0).setPrimaryKey("id", 0).build(); // WHERE id = 0
Get get1 = Get.newBuilder(schema0).setPrimaryKey("id", 1).build(); // WHERE id = 1
client.get(get).thenAcceptAsync(record -> { /* handle result */ });
client.get(get1).thenAcceptAsync(record -> { /* handle result */ });
} catch (HoloClientException e) {
// handle exception
}
Exemple Java complet
L'exemple complet suivant crée la table, insère 10 000 lignes et interroge 100 clés à l'aide d'une instruction préparée.
package test;
import org.postgresql.jdbc.PgConnection;
import java.sql.*;
public class TestPointQuery {
// Create a row-oriented table and populate it with test data.
private static void init(Connection conn) throws Exception {
try (Statement stmt = conn.createStatement()) {
stmt.execute("DROP TABLE IF EXISTS test_kv_table;");
stmt.execute("BEGIN;");
stmt.execute(
"CREATE TABLE IF NOT EXISTS test_kv_table(" +
" key TEXT PRIMARY KEY," +
" value TEXT" +
");"
);
stmt.execute("CALL set_table_property('test_kv_table', 'orientation', 'row');");
stmt.execute("CALL set_table_property('test_kv_table', 'shard_count', '20');");
stmt.execute("END;");
stmt.execute(
"INSERT INTO test_kv_table SELECT i, i FROM generate_series(1, 10000) i"
);
}
}
// Query 100 keys using a reused prepared statement.
private static void testKV(Connection conn) throws Exception {
String sql = "SELECT * FROM test_kv_table WHERE key = ?";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
for (int i = 0; i < 100; ++i) {
stmt.setString(1, Integer.toString(i));
long begin = System.currentTimeMillis();
try (ResultSet rs = stmt.executeQuery()) {
long cost = System.currentTimeMillis() - begin;
while (rs.next()) {
System.out.println(
"data => " + rs.getObject(1) + " " + rs.getObject(2)
+ " latency => [" + cost + "]ms"
);
}
}
}
}
}
public static void main(String[] args) throws Exception {
Class.forName("org.postgresql.Driver").newInstance();
// Replace these placeholders with your actual values.
String host = "<vpc-endpoint>"; // VPC endpoint from the Hologres console
String db = "<database-name>";
String user = "<access-key-id>"; // AccessKey ID
String password = "<access-key-secret>"; // AccessKey secret
String url = "jdbc:postgresql://" + host + "/" + db;
try (PgConnection conn = (PgConnection) DriverManager.getConnection(url, user, password)) {
System.out.println("Initializing test_kv_table...");
init(conn);
System.out.println("Running point query test...");
testKV(conn);
}
}
}
Remplacez les espaces réservés suivants :
| Espace réservé | Description | Où le trouver |
|---|---|---|
<vpc-endpoint> |
Point de terminaison VPC de votre instance Hologres | Section Network Information de la page des détails de l'instance dans la console Hologres |
<database-name> |
Nom de la base de données à laquelle se connecter | Configuration de votre instance Hologres |
<access-key-id> |
ID AccessKey de votre compte Alibaba Cloud | Page AccessKey Management |
<access-key-secret> |
Secret AccessKey de votre compte Alibaba Cloud | Page AccessKey Management |
Bonnes pratiques de connexion
| Pratique | Pourquoi c'est important |
|---|---|
| Utiliser le point de terminaison VPC | Les points de terminaison publics ajoutent de la latence réseau et sont soumis à des limitations de débit. Le point de terminaison VPC offre la latence la plus faible et le débit le plus élevé. |
| Réutiliser les instructions préparées | Hologres réutilise le plan de requête à chaque appel, éliminant ainsi la surcharge liée à la planification de la requête du chemin critique. |
| Utiliser un pool de connexions | Établir une nouvelle connexion pour chaque requête ajoute une surcharge mesurable. Les connexions persistantes éliminent ce coût. |
| Utiliser HoloClient pour un QPS élevé | HoloClient regroupe plusieurs requêtes Get en un seul appel SQL, réduisant les allers-retours et augmentant le débit pour un même niveau de concurrence. |