|  | 
|  | 1 | +--- | 
|  | 2 | +type: docs | 
|  | 3 | +title: "ClickHouse" | 
|  | 4 | +linkTitle: "ClickHouse" | 
|  | 5 | +description: Detailed information on the ClickHouse state store component | 
|  | 6 | +aliases: | 
|  | 7 | +  - "/operations/components/setup-state-store/supported-state-stores/setup-clickhouse/" | 
|  | 8 | +--- | 
|  | 9 | + | 
|  | 10 | +## Component format | 
|  | 11 | + | 
|  | 12 | +To setup ClickHouse state store create a component of type `state.clickhouse`. See [this guide]({{< ref "howto-get-save-state.md#step-1-setup-a-state-store" >}}) on how to create and apply a state store configuration. | 
|  | 13 | + | 
|  | 14 | +```yaml | 
|  | 15 | +apiVersion: dapr.io/v1alpha1 | 
|  | 16 | +kind: Component | 
|  | 17 | +metadata: | 
|  | 18 | +  name: <NAME> | 
|  | 19 | +spec: | 
|  | 20 | +  type: state.clickhouse | 
|  | 21 | +  version: v1 | 
|  | 22 | +  metadata: | 
|  | 23 | +  - name: clickhouseURL | 
|  | 24 | +    value: <CONNECTION_URL> | 
|  | 25 | +  - name: databaseName | 
|  | 26 | +    value: <DATABASE_NAME> | 
|  | 27 | +  - name: tableName | 
|  | 28 | +    value: <TABLE_NAME> | 
|  | 29 | +  - name: username # Optional | 
|  | 30 | +    value: <USERNAME> | 
|  | 31 | +  - name: password # Optional | 
|  | 32 | +    value: <PASSWORD> | 
|  | 33 | +  # Uncomment this if you wish to use ClickHouse as a state store for actors (optional) | 
|  | 34 | +  #- name: actorStateStore | 
|  | 35 | +  #  value: "true" | 
|  | 36 | +``` | 
|  | 37 | + | 
|  | 38 | +{{% alert title="Warning" color="warning" %}} | 
|  | 39 | +The above example uses secrets as plain strings. It is recommended to use a secret store for the secrets as described [here]({{< ref component-secrets.md >}}). | 
|  | 40 | +{{% /alert %}} | 
|  | 41 | + | 
|  | 42 | +If you wish to use ClickHouse as an actor store, append the following to the yaml. | 
|  | 43 | + | 
|  | 44 | +```yaml | 
|  | 45 | +  - name: actorStateStore | 
|  | 46 | +    value: "true" | 
|  | 47 | +``` | 
|  | 48 | +
 | 
|  | 49 | +## Spec metadata fields | 
|  | 50 | +
 | 
|  | 51 | +| Field              | Required | Details | Example | | 
|  | 52 | +|--------------------|:--------:|---------|---------| | 
|  | 53 | +| clickhouseURL      | Y        | Connection URL for the ClickHouse server | `"clickhouse://localhost:9000"`, `"clickhouse://clickhouse-server:9000"` | | 
|  | 54 | +| databaseName       | Y        | Name of the database to use | `"dapr_state"`, `"my_database"` | | 
|  | 55 | +| tableName          | Y        | Name of the table to store state data | `"state_table"`, `"dapr_state_store"` | | 
|  | 56 | +| username           | N        | Username for ClickHouse authentication. Can be `secretKeyRef` to use a secret reference | `"default"`, `"my_user"` | | 
|  | 57 | +| password           | N        | Password for ClickHouse authentication. Can be `secretKeyRef` to use a secret reference | `"my_password"` | | 
|  | 58 | +| actorStateStore    | N        | Consider this state store for actors. Defaults to `"false"` | `"true"`, `"false"` | | 
|  | 59 | + | 
|  | 60 | +## Setup ClickHouse | 
|  | 61 | + | 
|  | 62 | +Dapr can use any ClickHouse instance: containerized, running on your local dev machine, or a managed cloud service. | 
|  | 63 | + | 
|  | 64 | +{{< tabs "Self-Hosted" "Kubernetes" "Cloud" >}} | 
|  | 65 | + | 
|  | 66 | +{{% codetab %}} | 
|  | 67 | + | 
|  | 68 | +1. Run an instance of ClickHouse. You can run a local instance of ClickHouse in Docker with the following command: | 
|  | 69 | + | 
|  | 70 | +   ```bash | 
|  | 71 | +   docker run -d --name clickhouse-server \ | 
|  | 72 | +     -p 8123:8123 -p 9000:9000 \ | 
|  | 73 | +     -e CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT=1 \ | 
|  | 74 | +     -e CLICKHOUSE_PASSWORD=my_password \ | 
|  | 75 | +     clickhouse/clickhouse-server | 
|  | 76 | +   ``` | 
|  | 77 | + | 
|  | 78 | +2. Create a database for state data (optional, as Dapr will create it automatically): | 
|  | 79 | + | 
|  | 80 | +   ```sql | 
|  | 81 | +   CREATE DATABASE IF NOT EXISTS dapr_state; | 
|  | 82 | +   ``` | 
|  | 83 | + | 
|  | 84 | +{{% /codetab %}} | 
|  | 85 | + | 
|  | 86 | +{{% codetab %}} | 
|  | 87 | + | 
|  | 88 | +You can use [Helm](https://helm.sh/) to quickly create a ClickHouse instance in your Kubernetes cluster. This approach requires [Installing Helm](https://github.com/helm/helm#install). | 
|  | 89 | + | 
|  | 90 | +1. Add the ClickHouse Helm repository: | 
|  | 91 | +   ```bash | 
|  | 92 | +   helm repo add clickhouse https://docs.altinity.com/clickhouse-operator/ | 
|  | 93 | +   helm repo update | 
|  | 94 | +   ``` | 
|  | 95 | + | 
|  | 96 | +2. Install ClickHouse into your cluster: | 
|  | 97 | +   ```bash | 
|  | 98 | +   helm install clickhouse clickhouse/clickhouse | 
|  | 99 | +   ``` | 
|  | 100 | + | 
|  | 101 | +3. Run `kubectl get pods` to see the ClickHouse containers now running in your cluster. | 
|  | 102 | + | 
|  | 103 | +4. Add the ClickHouse service endpoint as the `clickhouseURL` in your component configuration. For example: | 
|  | 104 | +   ```yaml | 
|  | 105 | +   metadata: | 
|  | 106 | +   - name: clickhouseURL | 
|  | 107 | +     value: "clickhouse://clickhouse:9000" | 
|  | 108 | +   ``` | 
|  | 109 | + | 
|  | 110 | +{{% /codetab %}} | 
|  | 111 | + | 
|  | 112 | +{{% codetab %}} | 
|  | 113 | + | 
|  | 114 | +ClickHouse is available as a managed service from various cloud providers: | 
|  | 115 | + | 
|  | 116 | +- [ClickHouse Cloud](https://clickhouse.com/cloud) | 
|  | 117 | +- [Altinity.Cloud](https://altinity.com/cloud-database/) | 
|  | 118 | +- [Yandex Managed Service for ClickHouse](https://cloud.yandex.com/services/managed-clickhouse) | 
|  | 119 | + | 
|  | 120 | +When using a managed service, ensure you have the correct connection URL, database name, and credentials configured in your component metadata. | 
|  | 121 | + | 
|  | 122 | +{{% /codetab %}} | 
|  | 123 | + | 
|  | 124 | +{{< /tabs >}} | 
|  | 125 | + | 
|  | 126 | +## Features | 
|  | 127 | + | 
|  | 128 | +The ClickHouse state store supports the following features: | 
|  | 129 | + | 
|  | 130 | +### ETags | 
|  | 131 | + | 
|  | 132 | +The ClickHouse state store supports [ETags]({{< ref state-management-overview.md >}}) for optimistic concurrency control. ETags are automatically generated and updated when state data is modified. | 
|  | 133 | + | 
|  | 134 | +### TTL (Time-To-Live) | 
|  | 135 | + | 
|  | 136 | +This state store supports [Time-To-Live (TTL)]({{< ref state-store-ttl.md >}}) for records stored with Dapr. When storing data using Dapr, you can set the `ttlInSeconds` metadata property to indicate after how many seconds the data should be considered "expired". | 
|  | 137 | + | 
|  | 138 | +Example of setting TTL: | 
|  | 139 | + | 
|  | 140 | +```json | 
|  | 141 | +{ | 
|  | 142 | +  "key": "my-key", | 
|  | 143 | +  "value": "my-value", | 
|  | 144 | +  "metadata": { | 
|  | 145 | +    "ttlInSeconds": "3600" | 
|  | 146 | +  } | 
|  | 147 | +} | 
|  | 148 | +``` | 
|  | 149 | + | 
|  | 150 | +Records with expired TTLs are automatically filtered out during read operations and are eligible for cleanup by ClickHouse's background processes. | 
|  | 151 | + | 
|  | 152 | +## Advanced | 
|  | 153 | + | 
|  | 154 | +### Table Schema | 
|  | 155 | + | 
|  | 156 | +The ClickHouse state store creates a table with the following schema: | 
|  | 157 | + | 
|  | 158 | +```sql | 
|  | 159 | +CREATE TABLE IF NOT EXISTS <database>.<table> ( | 
|  | 160 | +    key String, | 
|  | 161 | +    value String, | 
|  | 162 | +    etag String, | 
|  | 163 | +    expire DateTime64(3) NULL, | 
|  | 164 | +    PRIMARY KEY(key) | 
|  | 165 | +) ENGINE = ReplacingMergeTree() | 
|  | 166 | +ORDER BY key | 
|  | 167 | +``` | 
|  | 168 | + | 
|  | 169 | +The table uses ClickHouse's `ReplacingMergeTree` engine, which automatically deduplicates rows with the same primary key during background merges. | 
|  | 170 | + | 
|  | 171 | +### Connection URL Format | 
|  | 172 | + | 
|  | 173 | +The ClickHouse connection URL follows the standard format: | 
|  | 174 | + | 
|  | 175 | +``` | 
|  | 176 | +clickhouse://[username[:password]@]host[:port][/database][?param1=value1&...¶mN=valueN] | 
|  | 177 | +``` | 
|  | 178 | + | 
|  | 179 | +Examples: | 
|  | 180 | +- `clickhouse://localhost:9000` | 
|  | 181 | +- `clickhouse://user:password@clickhouse-server:9000/my_db` | 
|  | 182 | +- `clickhouse://localhost:9000?dial_timeout=10s&max_execution_time=60` | 
|  | 183 | + | 
|  | 184 | +### Performance Considerations | 
|  | 185 | + | 
|  | 186 | +- The ClickHouse state store is optimized for high-throughput scenarios | 
|  | 187 | +- For better performance with large datasets, consider partitioning your table by date or other relevant columns | 
|  | 188 | +- The `ReplacingMergeTree` engine provides eventual consistency for duplicate key handling | 
|  | 189 | +- Background merges in ClickHouse will automatically clean up old versions of updated records | 
|  | 190 | + | 
|  | 191 | +### Bulk Operations | 
|  | 192 | + | 
|  | 193 | +The ClickHouse state store supports bulk operations for improved performance: | 
|  | 194 | + | 
|  | 195 | +- `BulkGet`: Retrieve multiple keys in a single operation | 
|  | 196 | +- `BulkSet`: Store multiple key-value pairs in a single operation   | 
|  | 197 | +- `BulkDelete`: Delete multiple keys in a single operation | 
|  | 198 | + | 
|  | 199 | +## Related links | 
|  | 200 | + | 
|  | 201 | +- [Basic schema for a Dapr component]({{< ref component-schema >}}) | 
|  | 202 | +- Read [this guide]({{< ref "howto-get-save-state.md#step-2-save-and-retrieve-a-single-state" >}}) for instructions on configuring state store components | 
|  | 203 | +- [State management building block]({{< ref state-management >}}) | 
|  | 204 | +- [ClickHouse Official Documentation](https://clickhouse.com/docs)  | 
0 commit comments