diff --git a/content/develop/connect/clients/go.md b/content/develop/connect/clients/go.md index 875f9e9688..9e65e4dac8 100644 --- a/content/develop/connect/clients/go.md +++ b/content/develop/connect/clients/go.md @@ -15,30 +15,33 @@ title: Go guide weight: 5 --- -Install Redis and the Redis client, then connect your Go application to a Redis database. +[`go-redis`](https://github.com/redis/go-redis) is the [Go](https://go.dev/) client for Redis. +The sections below explain how to install `go-redis` and connect your application to a Redis database. -## go-redis +`go-redis` requires a running Redis or +[Redis Stack]({{< relref "/operate/oss_and_stack/install/install-stack/" >}}) server. +See [Getting started]({{< relref "/operate/oss_and_stack/install/" >}}) for Redis installation +instructions. -[go-redis](https://github.com/redis/go-redis) provides Go clients for various flavors of Redis and a type-safe API for each Redis command. +## Install -### Install - -`go-redis` supports last two Go versions and only works with Go modules. -So, first, you need to initialize a Go module: +`go-redis` supports the last two Go versions. You can only use it from within +a Go module, so you must initialize a Go module before you start, or add your code to +an existing module: ``` go mod init github.com/my/repo ``` -To install go-redis/v9: +Use the `go get` command to install `go-redis/v9`: ``` go get github.com/redis/go-redis/v9 ``` -### Connect +## Connect -To connect to a Redis server: +The following example shows the simplest way to connect to a Redis server: ```go import ( @@ -47,16 +50,17 @@ import ( "github.com/redis/go-redis/v9" ) -func main() { +func main() { client := redis.NewClient(&redis.Options{ Addr: "localhost:6379", - Password: "", // no password set - DB: 0, // use default DB + Password: "", // No password set + DB: 0, // Use default DB + Protocol: 2, // Connection protocol }) } ``` -Another way to connect is using a connection string. +You can also connect using a connection string: ```go opt, err := redis.ParseURL("redis://:@localhost:6379/") @@ -67,7 +71,8 @@ if err != nil { client := redis.NewClient(opt) ``` -Store and retrieve a simple string. +After connecting, you can test the connection by storing and retrieving +a simple [string]({{< relref "/develop/data-types/strings" >}}): ```go ctx := context.Background() @@ -84,24 +89,78 @@ if err != nil { fmt.Println("foo", val) ``` -Store and retrieve a map. +You can also easily store and retrieve a [hash]({{< relref "/develop/data-types/hashes" >}}): ```go -session := map[string]string{"name": "John", "surname": "Smith", "company": "Redis", "age": "29"} -for k, v := range session { - err := client.HSet(ctx, "user-session:123", k, v).Err() - if err != nil { - panic(err) - } +hashFields := []string{ + "model", "Deimos", + "brand", "Ergonom", + "type", "Enduro bikes", + "price", "4972", +} + +res1, err := rdb.HSet(ctx, "bike:1", hashFields).Result() + +if err != nil { + panic(err) +} + +fmt.Println(res1) // >>> 4 + +res2, err := rdb.HGet(ctx, "bike:1", "model").Result() + +if err != nil { + panic(err) +} + +fmt.Println(res2) // >>> Deimos + +res3, err := rdb.HGet(ctx, "bike:1", "price").Result() + +if err != nil { + panic(err) +} + +fmt.Println(res3) // >>> 4972 + +res4, err := rdb.HGetAll(ctx, "bike:1").Result() + +if err != nil { + panic(err) +} + +fmt.Println(res4) +// >>> map[brand:Ergonom model:Deimos price:4972 type:Enduro bikes] + ``` + + Use + [struct tags](https://stackoverflow.com/questions/10858787/what-are-the-uses-for-struct-tags-in-go) + of the form `redis:""` with the `Scan()` method to parse fields from + a hash directly into corresponding struct fields: + + ```go +type BikeInfo struct { + Model string `redis:"model"` + Brand string `redis:"brand"` + Type string `redis:"type"` + Price int `redis:"price"` +} + +var res4a BikeInfo +err = rdb.HGetAll(ctx, "bike:1").Scan(&res4a) + +if err != nil { + panic(err) } -userSession := client.HGetAll(ctx, "user-session:123").Val() -fmt.Println(userSession) +fmt.Printf("Model: %v, Brand: %v, Type: %v, Price: $%v\n", + res4a.Model, res4a.Brand, res4a.Type, res4a.Price) +// >>> Model: Deimos, Brand: Ergonom, Type: Enduro bikes, Price: $4972 ``` -#### Connect to a Redis cluster +### Connect to a Redis cluster -To connect to a Redis cluster, use `NewClusterClient`. +To connect to a Redis cluster, use `NewClusterClient()`. ```go client := redis.NewClusterClient(&redis.ClusterOptions{ @@ -113,11 +172,12 @@ client := redis.NewClusterClient(&redis.ClusterOptions{ }) ``` -#### Connect to your production Redis with TLS +### Connect to your production Redis with TLS -When you deploy your application, use TLS and follow the [Redis security]({{< relref "/operate/oss_and_stack/management/security/" >}}) guidelines. +When you deploy your application, use TLS and follow the +[Redis security]({{< relref "/operate/oss_and_stack/management/security/" >}}) guidelines. -Establish a secure connection with your Redis database using this snippet. +Establish a secure connection with your Redis database: ```go // Load client cert @@ -159,23 +219,283 @@ if err != nil { fmt.Println("foo", val) ``` +## Example: Index and search JSON documents -#### dial tcp: i/o timeout +Start by connecting to the Redis server: -You get a `dial tcp: i/o timeout` error when `go-redis` can't connect to the Redis Server, for example, when the server is down or the port is protected by a firewall. To check if Redis Server is listening on the port, run telnet command on the host where the `go-redis` client is running. +```go +import ( + "context" + "fmt" + + "github.com/redis/go-redis/v9" +) + +func main() { + ctx := context.Background() + + rdb := redis.NewClient(&redis.Options{ + Addr: "localhost:6379", + Password: "", + DB: 0, + Protocol: 2, + }) + + // ... +} +``` + +Add some `map` objects to store in JSON format in the database: ```go -telnet localhost 6379 -Trying 127.0.0.1... -telnet: Unable to connect to remote host: Connection refused +user1 := map[string]interface{}{ + "name": "Paul John", + "email": "paul.john@example.com", + "age": 42, + "city": "London", +} + +user2 := map[string]interface{}{ + "name": "Eden Zamir", + "email": "eden.zamir@example.com", + "age": 29, + "city": "Tel Aviv", +} + +user3 := map[string]interface{}{ + "name": "Paul Zamir", + "email": "paul.zamir@example.com", + "age": 35, + "city": "Tel Aviv", +} ``` -If you use Docker, Istio, or any other service mesh/sidecar, make sure the app starts after the container is fully available, for example, by configuring healthchecks with Docker and holdApplicationUntilProxyStarts with Istio. -For more information, see [Healthcheck](https://docs.docker.com/engine/reference/run/#healthcheck). +Use the code below to create a search index. The `FTCreateOptions` parameter enables +indexing only for JSON objects where the key has a `user:` prefix. +The +[schema]({{< relref "/develop/interact/search-and-query/indexing" >}}) +for the index has three fields for the user's name, age, and city. +The `FieldName` field of the `FieldSchema` struct specifies a +[JSON path]({{< relref "/develop/data-types/json/path" >}}) +that identifies which data field to index. Use the `As` struct field +to provide an alias for the JSON path expression. You can use +the alias in queries as a short and intuitive way to refer to the +expression, instead of typing it in full: -### Observability +```go +_, err := rdb.FTCreate( + ctx, + "idx:users", + // Options: + &redis.FTCreateOptions{ + OnJSON: true, + Prefix: []interface{}{"user:"}, + }, + // Index schema fields: + &redis.FieldSchema{ + FieldName: "$.name", + As: "name", + FieldType: redis.SearchFieldTypeText, + }, + &redis.FieldSchema{ + FieldName: "$.city", + As: "city", + FieldType: redis.SearchFieldTypeTag, + }, + &redis.FieldSchema{ + FieldName: "$.age", + As: "age", + FieldType: redis.SearchFieldTypeNumeric, + }, +).Result() -To monitor go-redis performance and trace the execution of Redis commands, you can install OpenTelemetry instrumentation: +if err != nil { + panic(err) +} +``` + +Add the three sets of user data to the database as +[JSON]({{< relref "/develop/data-types/json" >}}) objects. +If you use keys with the `user:` prefix then Redis will index the +objects automatically as you add them: + +```go +_, err = rdb.JSONSet(ctx, "user:1", "$", user1).Result() + +if err != nil { + panic(err) +} + +_, err = rdb.JSONSet(ctx, "user:2", "$", user2).Result() + +if err != nil { + panic(err) +} + +_, err = rdb.JSONSet(ctx, "user:3", "$", user3).Result() + +if err != nil { + panic(err) +} +``` + +You can now use the index to search the JSON objects. The +[query]({{< relref "/develop/interact/search-and-query/query" >}}) +below searches for objects that have the text "Paul" in any field +and have an `age` value in the range 30 to 40: + +```go +searchResult, err := rdb.FTSearch( + ctx, + "idx:users", + "Paul @age:[30 40]", +).Result() + +if err != nil { + panic(err) +} + +fmt.Println(searchResult) +// >>> {1 [{user:3 map[$:{"age":35,"city":"Tel Aviv"... +``` + +## Example: Index and search hash documents + +Start by connecting to the Redis server as before: + +```go +import ( + "context" + "fmt" + + "github.com/redis/go-redis/v9" +) + +func main() { + ctx := context.Background() + + rdb := redis.NewClient(&redis.Options{ + Addr: "localhost:6379", + Password: "", + DB: 0, + Protocol: 2, + }) + + // ... +} +``` + +In this example, the user objects will be stored as hashes in the database. Use a `string` +array in the form of name-value pairs to supply the data for the +hash fields: + +```go +user1 := []string{ + "name", "Paul John", + "email", "paul.john@example.com", + "age", "42", + "city", "London", +} + +user2 := []string{ + "name", "Eden Zamir", + "email", "eden.zamir@example.com", + "age", "29", + "city", "Tel Aviv", +} + +user3 := []string{ + "name", "Paul Zamir", + "email", "paul.zamir@example.com", + "age", "35", + "city", "Tel Aviv", +} +``` + +It is easier to create the index for hash objects than +for JSON objects. Use the `FTCreateOptions` parameter to enable +indexing only for hash objects, but specify the same `user:` prefix +as before. You don't need the `As:` field in the schema parameters +here because hash fields have simple identifiers. They have no +JSON path expression and don't require an alias: + +```go +_, err := rdb.FTCreate( + ctx, + "idx:users", + // Options: + &redis.FTCreateOptions{ + OnHash: true, + Prefix: []interface{}{"user:"}, + }, + // Index schema fields: + &redis.FieldSchema{ + FieldName: "name", + FieldType: redis.SearchFieldTypeText, + }, + &redis.FieldSchema{ + FieldName: "city", + FieldType: redis.SearchFieldTypeTag, + }, + &redis.FieldSchema{ + FieldName: "age", + FieldType: redis.SearchFieldTypeNumeric, + }, +).Result() + +if err != nil { + panic(err) +} +``` + +Add the user data arrays to the database as hash objects. Redis will +index the hashes automatically because their keys have the +`user:` prefix: + +```go +_, err = rdb.HSet(ctx, "user:1", user1).Result() + +if err != nil { + panic(err) +} + +_, err = rdb.HSet(ctx, "user:2", user2).Result() + +if err != nil { + panic(err) +} + +_, err = rdb.HSet(ctx, "user:2", user3).Result() + +if err != nil { + panic(err) +} +``` + +The hashes have a structure very much like the JSON objects +from the previous example, so you can search the database with the +same query as before: + +```go +searchResult, err := rdb.FTSearch( + ctx, + "idx:users", + "Paul @age:[30 40]", +).Result() + +if err != nil { + panic(err) +} + +fmt.Println(searchResult) +// >>> {1 [{user:2 map[age:35 city:Tel Aviv... +``` + +## Observability + +`go-redis` supports [OpenTelemetry](https://opentelemetry.io/) instrumentation. +to monitor performance and trace the execution of Redis commands. +For example, the following code instruments Redis commands to collect traces, logs, and metrics: ```go import ( @@ -196,11 +516,8 @@ if err := redisotel.InstrumentMetrics(rdb); err != nil { } ``` -The code above instruments Redis commands to collect traces, logs, and metrics. You can find the full example on [GitHub](https://github.com/redis/go-redis/blob/master/example/otel/README.md). - -OpenTelemetry is a vendor-agnostic observability framework that allows you to export data to Prometheus, Jaeger, Uptrace, and more. OpenTelemetry supports [distributed tracing](https://uptrace.dev/opentelemetry/distributed-tracing.html), metrics, and logs. - -You can also use OpenTelemetry for [monitoring Redis Server](https://uptrace.dev/blog/redis-monitoring.html) performance metrics, which works by periodically executing the Redis `INFO` command and turning results into [OpenTelemetry metrics](https://uptrace.dev/opentelemetry/metrics.html). +See the `go-redis` [GitHub repo](https://github.com/redis/go-redis/blob/master/example/otel/README.md). +for more OpenTelemetry examples. ### Learn more diff --git a/content/develop/get-started/vector-database.md b/content/develop/get-started/vector-database.md index 123b7e8760..cfd739a57c 100644 --- a/content/develop/get-started/vector-database.md +++ b/content/develop/get-started/vector-database.md @@ -76,7 +76,7 @@ Connect to Redis. By default, Redis returns binary responses. To decode them, yo {{< clients-example search_vss connect />}}
{{% alert title="Tip" color="warning" %}} -Instead of using a local Redis Stack server, you can copy and paste the connection details from the Redis Cloud database configuration page. Here is an example connection string of a Cloud database that is hosted in the AWS region `us-east-1` and listens on port 16379: `redis-16379.c283.us-east-1-4.ec2.cloud.redislabs.com:16379`. The connection string has the format `host:port`. You must also copy and paste the username and password of your Cloud database. The line of code for connecting with the default user changes then to `client = redis.Redis(host="redis-16379.c283.us-east-1-4.ec2.cloud.redislabs.com", port=16379, password="your_password_here" decode_responses=True)`. +Instead of using a local Redis Stack server, you can copy and paste the connection details from the Redis Cloud database configuration page. Here is an example connection string of a Cloud database that is hosted in the AWS region `us-east-1` and listens on port 16379: `redis-16379.c283.us-east-1-4.ec2.cloud.redislabs.com:16379`. The connection string has the format `host:port`. You must also copy and paste the username and password of your Cloud database. The line of code for connecting with the default user changes then to `client = redis.Redis(host="redis-16379.c283.us-east-1-4.ec2.cloud.redislabs.com", port=16379, password="your_password_here", decode_responses=True)`. {{% /alert %}} @@ -115,7 +115,7 @@ Now iterate over the `bikes` array to store the data as [JSON]({{< relref "/dev {{< clients-example search_vss load_data />}} -Once loaded, you can retrieve a specific attributes from one of the JSON documents in Redis using a [JSONPath](https://goessner.net/articles/JsonPath/) expression: +Once loaded, you can retrieve a specific attribute from one of the JSON documents in Redis using a [JSONPath](https://goessner.net/articles/JsonPath/) expression: {{< clients-example search_vss get />}} diff --git a/content/develop/interact/search-and-query/query/combined.md b/content/develop/interact/search-and-query/query/combined.md index e49c2b4a33..0a043b0253 100644 --- a/content/develop/interact/search-and-query/query/combined.md +++ b/content/develop/interact/search-and-query/query/combined.md @@ -54,15 +54,15 @@ FT.SEARCH index "@text_field:( value1 value2 ... )" The following example shows you a query that finds bicycles in new condition and in a price range from 500 USD to 1000 USD: -``` +{{< clients-example query_combined combined1 >}} FT.SEARCH idx:bicycle "@price:[500 1000] @condition:{new}" -``` +{{< /clients-example >}} You might also be interested in bicycles for kids. The query below shows you how to combine a full-text search with the criteria from the previous query: -``` +{{< clients-example query_combined combined2 >}} FT.SEARCH idx:bicycle "kids (@price:[500 1000] @condition:{used})" -``` +{{< /clients-example >}} ## OR @@ -89,21 +89,21 @@ FT.SEARCH index "@tag_field:{ value1 | value2 | ... }" The following query shows you how to find used bicycles that contain either the word 'kids' or 'small': -``` +{{< clients-example query_combined combined3 >}} FT.SEARCH idx:bicycle "(kids | small) @condition:{used}" -``` +{{< /clients-example >}} The previous query searches across all text fields. The following example shows you how to limit the search to the description field: -``` +{{< clients-example query_combined combined4 >}} FT.SEARCH idx:bicycle "@description:(kids | small) @condition:{used}" -``` +{{< /clients-example >}} If you want to extend the search to new bicycles, then the below example shows you how to do that: -``` +{{< clients-example query_combined combined5 >}} FT.SEARCH idx:bicycle "@description:(kids | small) @condition:{new | used}" -``` +{{< /clients-example >}} ## NOT @@ -115,9 +115,9 @@ FT.SEARCH index "-(expr)" If you want to exclude new bicycles from the search within the previous price range, you can use this query: -``` +{{< clients-example query_combined combined6 >}} FT.SEARCH idx:bicycle "@price:[500 1000] -@condition:{new}" -``` +{{< /clients-example >}} ## Numeric filter @@ -140,8 +140,8 @@ FT.SEARCH index "(filter_expr)=>[KNN num_neighbours @field $vector]" PARAMS 2 ve Here is an example: -``` +{{< clients-example query_combined combined7 >}} FT.SEARCH idx:bikes_vss "(@price:[500 1000] @condition:{new})=>[KNN 3 @vector $query_vector]" PARAMS 2 "query_vector" "Z\xf8\x15:\xf23\xa1\xbfZ\x1dI>\r\xca9..." DIALECT 2 -``` +{{< /clients-example >}} The [vector search article]({{< relref "/develop/interact/search-and-query/query/vector-search" >}}) provides further details about vector queries in general. diff --git a/content/operate/kubernetes/release-notes/6-4-2-releases/6-4-2-8-oct24.md b/content/operate/kubernetes/release-notes/6-4-2-releases/6-4-2-8-oct24.md new file mode 100644 index 0000000000..d6a4f251c2 --- /dev/null +++ b/content/operate/kubernetes/release-notes/6-4-2-releases/6-4-2-8-oct24.md @@ -0,0 +1,62 @@ +--- +alwaysopen: false +categories: +- docs +- operate +- kubernetes +description: The Redis Enterprise K8s 6.4.2-8 release supports Redis Enterprise Software 6.4.2. +linkTitle: 6.4.2-8 (Oct 2024) +title: Redis Enterprise for Kubernetes release notes 6.4.2-8 (Oct 2024) +weight: 53 +--- + +## Overview + +This is a maintenance release of Redis Enterprise for Kubernetes version 6.4.2-8 and includes an updated Redis Enterprise image. + +## New in this release + +### Feature enhancements + +* New Redis Enterprise software version 6.4.2-115 + +## Upgrade considerations + +Be aware the following changes included in this release affect the upgrade process. Please read carefully before upgrading to 6.4.2-8. + +* **Upgrade path to versions 7.2.4-2 or later** + + Upgrading from this versions 7.2.4-2 or 7.2.4-7 is not possible using the OpenShift Operator Lifecycle Manager (OLM). OLM users will need to skip to version 7.2.4-10 to upgrade from this release version. + +* **ValidatingWebhookConfiguration** + + This release uses a new `ValidatingWebhookConfiguration` resource to replace the `redb-admission` webhook resource. To use releases 6.4.2-4 or later, delete the old webhook resource and apply the new file. See [upgrade Redis cluster]({{< relref "/operate/kubernetes/upgrade/upgrade-redis-cluster#reapply-webhook" >}}) for instructions. + +* **OpenShift SCC** + + This release includes a new SCC (`redis-enterprise-scc-v2`) that you need to bind to your service account before upgrading. OpenShift clusters running version 6.2.12 or earlier upgrading to version 6.2.18 or later might get stuck if you skip this step. See [upgrade a Redis Enterprise cluster (REC)]({{< relref "/operate/kubernetes/upgrade/upgrade-redis-cluster#before-upgrading" >}}) for more info. + +## Compatibility + +See [6.4.2-8 (July 2023) release notes]({{< relref "/operate/kubernetes/release-notes/6-4-2-releases/6-4-2-8#compatibility" >}}). + +### Images + +* **Redis Enterprise**: `redislabs/redis:6.4.2-115` +* **Operator**: `redislabs/operator:6.4.2-8` +* **Services Rigger**: `redislabs/k8s-controller:6.4.2-8.` + +#### OpenShift images + +* **Redis Enterprise**: `registry.connect.redhat.com/redislabs/redis-enterprise:6.4.2-115.rhel8-openshift` + (or `redislabs/redis-enterprise:6.4.2-115.rhel7-openshift` if upgrading from RHEL 7) +* **Operator**: `registry.connect.redhat.com/redislabs/redis-enterprise-operator:6.4.2-8` +* **Services Rigger**: `registry.connect.redhat.com/redislabs/services-manager:6.4.2-8` + +#### OLM bundle + +* **Redis Enterprise operator bundle** : `v6.4.2-8.10` + +## Known limitations + +See [6.4.2-8 (July 2023) release notes]({{< relref "/operate/kubernetes/release-notes/6-4-2-releases/6-4-2-8#known-limitations" >}}). \ No newline at end of file diff --git a/content/operate/rc/security/database-security/_index.md b/content/operate/rc/security/database-security/_index.md index d6070d0144..1a20d93a6d 100644 --- a/content/operate/rc/security/database-security/_index.md +++ b/content/operate/rc/security/database-security/_index.md @@ -33,4 +33,4 @@ We strongly recommend enabling TLS for any application transmitting sensitive da ## Disk encryption -Redis Cloud provides encryption for all data stored on disk in Redis databases. See our [encrpytion at rest documentation]({{< relref "/operate/rc/security/encryption-at-rest.md" >}}) for specific details. +Redis Cloud provides encryption for all data stored on disk in Redis databases. See our [encryption at rest documentation]({{< relref "/operate/rc/security/encryption-at-rest.md" >}}) for specific details.