2016-01-09 4 views
16

J'ai un client Java qui pousse les enregistrements (INSERT) en batch vers le cluster Cassandra. Les éléments du lot ont tous la même clé de ligne, de sorte qu'ils seront tous placés dans le même noeud. Aussi, je n'ai pas besoin que la transaction soit atomique, donc j'ai utilisé un batch non-ouvert.Quelle est la limite de lot à Cassandra?

Le nombre de commandes INSERT dans chaque lot dépend de différents facteurs, mais peut être compris entre 5 et 50000. Tout d'abord, je mets juste autant de commandes que j'avais dans un lot et je l'ai soumis. Cela a jeté com.datastax.driver.core.exceptions.InvalidQueryException: Batch too large. Ensuite, j'ai utilisé une limite de 1000 INSERT par lot, puis jusqu'à 300. J'ai remarqué que je ne fais que deviner au hasard sans savoir exactement d'où vient cette limite, ce qui peut causer des problèmes plus tard.

Ma question est, quelle est cette limite? Puis-je le modifier? Comment puis-je savoir combien d'éléments peuvent être placés dans un lot? Quand mon lot est "plein"?

Répondre

17

Je recommande de ne pas augmenter le plafond et de simplement diviser en plusieurs demandes. Tout mettre dans une requête unique géante aura un impact négatif sur le coordinateur de manière significative. Le fait d'avoir tout dans une partition peut améliorer le débit dans certains lots de taille en réduisant la latence, mais les lots ne sont jamais destinés à améliorer les performances. Donc, essayer d'optimiser pour obtenir un débit maximum en utilisant différentes tailles de lots dépendra largement de l'utilisation case/schema/nodes et nécessitera des tests spécifiques, car il y a généralement une falaise sur la taille où elle commence à se dégrader.

Il y a une option

# Fail any batch exceeding this value. 50kb (10x warn threshold) by default. 
batch_size_fail_threshold_in_kb: 50 

dans votre cassandra.yaml pour l'augmenter, mais assurez-vous de tester pour vous assurer que votre réellement aider et ne pas vous blesser êtes débit.

+0

C'est ce que je cherchais, merci. Savez-vous quelle est la meilleure façon de surveiller la taille du lot dans le client? –

+2

Dépend du pilote que vous utilisez, mais dans le pilote java, vous pouvez utiliser getValues ​​() sur chaque instruction de votre batch qui vous renvoie un tableau de ByteBuffers pour lequel vous pouvez utiliser la méthode remaining() pour obtenir la taille de les tampons individuellement et les résumer tous, mais en général je ne recommanderais pas de le faire. Vous ne devriez pas créer de super gros lots, juste assez grands pour sentir que vous êtes loin de cette limite. –

+0

Eh bien, il y a beaucoup de choses ici. C * prêche la conception par colonne au lieu de lignes et C * dit 2B colonnes par partition mais empiriquement nous savons que le point idéal est 100MB.donc même avec 100 Mo de partition et si la taille par défaut d'un lot est de 50 Ko c'est comme 100 Mo/50 Ko = 3125 demandes pour récupérer une partition de 100 Mo donc beaucoup trop de demandes. – user1870400

2

regardant le Cassandra se connecte, vous serez en mesure de repérer des choses comme:

erreur 19:54:13 Lot pour [résultats] est de taille 103.072KiB, dépassant le seuil spécifié de 50.000KiB par 53.072KiB. (Voir batch_size_fail_threshold_in_kb)

0

couru à travers un problème similaire en Java, voici un exemple fonctionnel de la façon de lots par lots:

import com.datastax.driver.core.BatchStatement; 
import com.datastax.driver.core.PreparedStatement; 
import com.datastax.driver.core.Session; 
import com.google.common.collect.Lists; 

import java.util.Collection; 
import java.util.stream.Collectors; 

public class CassandraBatchOfBatchesExample { 

    private final PreparedStatement statement; 
    private final Session session; 
    private final int batchSize; 

    public CassandraBatchOfBatchesExample(Session session, int batchSize) { 
     this.session = session; 
     this.batchSize = batchSize; 
     statement = session.prepare("INSERT_INTO some_table JSON ?"); 
    } 

    public void execute(Collection<String> jsons) { 
     Lists.partition(jsons 
       .stream() 
       .map(statement::bind) 
       .collect(Collectors.toList() 
      ), batchSize).stream() 
      .map(statements -> new BatchStatement().addAll(statements)) 
      .forEach(session::execute); 
    } 
} 

batchSize variable doit changer en fonction de la taille des dossiers individuels étant insérés.