diff --git a/CHANGELOG.md b/CHANGELOG.md index 744d3b1c9dd..0973ab9705f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -157,6 +157,7 @@ Please make sure to review renamed metrics, and update your dashboards and alert * [FEATURE] TLS config options added to the Server. #2535 * [FEATURE] Experimental: Added support for `/api/v1/metadata` Prometheus-based endpoint. #2549 * [FEATURE] Add ability to limit concurrent queries to Cassandra with `-cassandra.query-concurrency` flag. #2562 +* [FEATURE] Add `-cassandra.table-options` flag to customize table options of Cassandra when creating the index or chunk table. #2575 * [ENHANCEMENT] Experimental TSDB: sample ingestion errors are now reported via existing `cortex_discarded_samples_total` metric. #2370 * [ENHANCEMENT] Failures on samples at distributors and ingesters return the first validation error as opposed to the last. #2383 * [ENHANCEMENT] Experimental TSDB: Added `cortex_querier_blocks_meta_synced`, which reflects current state of synced blocks over all tenants. #2392 diff --git a/docs/configuration/config-file-reference.md b/docs/configuration/config-file-reference.md index 5a32ebd3b28..7a523cab1a7 100644 --- a/docs/configuration/config-file-reference.md +++ b/docs/configuration/config-file-reference.md @@ -1738,6 +1738,14 @@ cassandra: # CLI flag: -cassandra.convict-hosts-on-failure [convict_hosts_on_failure: | default = true] + # Table options used to create index or chunk tables. This value is used as + # plain text in the table `WITH` like this, "CREATE TABLE + # (...) WITH ". For details, + # see https://cortexmetrics.io/docs/production/cassandra. (Default = "": use + # default table options of your Cassandra) + # CLI flag: -cassandra.table-options + [table_options: | default = ""] + boltdb: # Location of BoltDB index files. # CLI flag: -boltdb.dir diff --git a/docs/production/storage-cassandra.md b/docs/production/storage-cassandra.md index b19a365b1a4..2d8a6cd667b 100644 --- a/docs/production/storage-cassandra.md +++ b/docs/production/storage-cassandra.md @@ -118,6 +118,44 @@ docker run -d --name=cortex -v $(pwd)/single-process-config.yaml:/etc/single-pro ``` In case you prefer to run the master version, please follow this [documentation](../getting-started/getting-started-chunks.md) on how to build Cortex from source. +### Configure the index and chunk table options + +In order to create index and chunk tables on Cassandra, Cortex will use the default table options of your Cassandra. +If you want to configure the table options, use the `storage.cassandra.table_options` property or `cassandra.table-options` flag. +This configuration property is just `string` type and this value used as plain text on `WITH` option of table creation query. +It is recommended to enclose the value of `table_options` in double-quotes because you should enclose strings of table options in quotes on Cassandra. + +For example, suppose the name of index(or chunk) table is 'test_table'. +Details about column definitions of the table are omitted. +If no table options configured, then Cortex will generate the query to create a table without a `WITH` clause to use default table options: + +``` +CREATE TABLE IF NOT EXISTS cortex.test_table (...) +``` + +If table options configured with `table_options` as below: + +``` +storage: + cassandra: + addresses: 127.0.0.1 + keyspace: cortex + table_options: "gc_grace_seocnds = 86400 + AND comments = 'this is a test table' + AND COMPACT STORAGE + AND caching = { 'keys': 'ALL', 'rows_per_partition': 1024 }" +``` + +Then Cortex will generate the query to create a table with a `WITH` clause as below: + +``` +CREATE TABLE IF NOT EXISTS cortex.test_table (...) WITH gc_grace_seocnds = 86400 AND comments = 'this is a test table' AND COMPACT STORAGE AND caching = { 'keys': 'ALL', 'rows_per_partition': 1024 } +``` + +Available settings of the table options on Cassandra depend on Cassandra version or storage which is compatible. +For details about table options, see the official document of storage you are using. + +**WARNING**: Make sure there are no incorrect options and mistakes. Misconfigured table options may cause a failure in creating a table by Table Manager at runtime and seriously affect your Cortex. ## Configure Prometheus to send series to Cortex diff --git a/pkg/chunk/cassandra/storage_client.go b/pkg/chunk/cassandra/storage_client.go index d76410a788b..327938399ab 100644 --- a/pkg/chunk/cassandra/storage_client.go +++ b/pkg/chunk/cassandra/storage_client.go @@ -48,6 +48,7 @@ type Config struct { QueryConcurrency int `yaml:"query_concurrency"` NumConnections int `yaml:"num_connections"` ConvictHosts bool `yaml:"convict_hosts_on_failure"` + TableOptions string `yaml:"table_options"` } // RegisterFlags adds the flags required to config this to the given FlagSet @@ -75,6 +76,7 @@ func (cfg *Config) RegisterFlags(f *flag.FlagSet) { f.IntVar(&cfg.QueryConcurrency, "cassandra.query-concurrency", 0, "Limit number of concurrent queries to Cassandra. (Default is 0: no limit)") f.IntVar(&cfg.NumConnections, "cassandra.num-connections", 2, "Number of TCP connections per host.") f.BoolVar(&cfg.ConvictHosts, "cassandra.convict-hosts-on-failure", true, "Convict hosts of being down on failure.") + f.StringVar(&cfg.TableOptions, "cassandra.table-options", "", "Table options used to create index or chunk tables. This value is used as plain text in the table `WITH` like this, \"CREATE TABLE (...) WITH \". For details, see https://cortexmetrics.io/docs/production/cassandra. (Default = \"\": use default table options of your Cassandra)") } func (cfg *Config) Validate() error { diff --git a/pkg/chunk/cassandra/table_client.go b/pkg/chunk/cassandra/table_client.go index 0207a0964b0..ee242e354c7 100644 --- a/pkg/chunk/cassandra/table_client.go +++ b/pkg/chunk/cassandra/table_client.go @@ -40,13 +40,8 @@ func (c *tableClient) ListTables(ctx context.Context) ([]string, error) { } func (c *tableClient) CreateTable(ctx context.Context, desc chunk.TableDesc) error { - err := c.session.Query(fmt.Sprintf(` - CREATE TABLE IF NOT EXISTS %s ( - hash text, - range blob, - value blob, - PRIMARY KEY (hash, range) - )`, desc.Name)).WithContext(ctx).Exec() + query := c.getCreateTableQuery(&desc) + err := c.session.Query(query).WithContext(ctx).Exec() return errors.WithStack(err) } @@ -69,3 +64,17 @@ func (c *tableClient) UpdateTable(ctx context.Context, current, expected chunk.T func (c *tableClient) Stop() { c.session.Close() } + +func (c *tableClient) getCreateTableQuery(desc *chunk.TableDesc) (query string) { + query = fmt.Sprintf(` + CREATE TABLE IF NOT EXISTS %s ( + hash text, + range blob, + value blob, + PRIMARY KEY (hash, range) + )`, desc.Name) + if c.cfg.TableOptions != "" { + query = fmt.Sprintf("%s WITH %s", query, c.cfg.TableOptions) + } + return +} diff --git a/pkg/chunk/cassandra/table_client_test.go b/pkg/chunk/cassandra/table_client_test.go new file mode 100644 index 00000000000..ad885a51c0d --- /dev/null +++ b/pkg/chunk/cassandra/table_client_test.go @@ -0,0 +1,48 @@ +package cassandra + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestTableClient_getCreateTableQuery_default(t *testing.T) { + client := &tableClient{ + cfg: Config{}, + } + desc, _, _ := client.DescribeTable(context.Background(), "test_table") + query := client.getCreateTableQuery(&desc) + assert.Equal( + t, + ` + CREATE TABLE IF NOT EXISTS test_table ( + hash text, + range blob, + value blob, + PRIMARY KEY (hash, range) + )`, + query, + ) +} + +func TestTableClient_getCreateTableQuery_withOptions(t *testing.T) { + client := &tableClient{ + cfg: Config{ + TableOptions: "CLUSTERING ORDER BY (range DESC) AND compaction = { 'class' : 'LeveledCompactionStrategy' }", + }, + } + desc, _, _ := client.DescribeTable(context.Background(), "test_table") + query := client.getCreateTableQuery(&desc) + assert.Equal( + t, + ` + CREATE TABLE IF NOT EXISTS test_table ( + hash text, + range blob, + value blob, + PRIMARY KEY (hash, range) + ) WITH CLUSTERING ORDER BY (range DESC) AND compaction = { 'class' : 'LeveledCompactionStrategy' }`, + query, + ) +}