前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >kubernetes自定义资源对象高级功能

kubernetes自定义资源对象高级功能

作者头像
我的小碗汤
发布2019-05-28 19:17:53
1.1K0
发布2019-05-28 19:17:53
举报
文章被收录于专栏:我的小碗汤我的小碗汤

点击上方“我的小碗汤”,选择“置顶公众号”

精品文章,第一时间送达

kubernetes自定义资源对象再极大程度提高了API Server的可扩展性,让企业能够根据业务需求通过CRD编写controller或者operator来实现生产中各种特殊场景。随着k8s的版本升级,CRD的功能也越来越完善,下面对其中几点进行说明。

以下验证kubernetes版本为1.13.2,docker版本:18.09.5

Validation(验证)

在项目中用自定义资源对象时,如果创建自定义资源时某些字段不符合要求,会导致监听该资源对象的controller或者operator出现异常,解析结构体报错,所以Validation这个功能非常实用,在创建时就进行校验,减少后面的排错和异常处理的麻烦。

可以通过 OpenAPI v3 schema(https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#schemaObject)验证自定义对象是否符合标准 。此外,以下限制适用于 schema:

  • 字段default、nullable、discriminator、readOnly、writeOnly、xml、 deprecated 和 $ref 不能设置。
  • 该字段 uniqueItems 不能设置为 true。
  • 该字段 additionalProperties 不能设置为 false。

可以使用 kube-apiserver CustomResourceValidation 上的功能门(feature gate)禁用此功能:

代码语言:javascript
复制
--feature-gates=CustomResourceValidation=false

从以下特性门参数说明地址,可以看到Validation功能在k8s 1.8版本就已经有了,但是CustomResourceValidation特性门是默认false,1.9Beta之后版本默认为true

https://kubernetes.io/docs/reference/command-line-tools-reference/feature-gates/

以下示例将大概对该功能进行应用和说明,在以下示例中,CustomResourceDefinition 对自定义对象应用以下验证:

  • spec.replicas 为必填项,类型为integer,值为大于等于0小于50的偶数(2的倍数);
  • spec.repository 为必填项;
  • spec.version为必填项;
  • spec.pause为boolean类型;
  • spec.updateStrategy为object类型,该object中有type、pipeline、assignStrategies属性;
  • spec.updateStrategy.type为string类型,而且只能为"AssignReceive", "AutoReceive"两个枚举值;
  • spec.updateStrategy.pipeline为string类型,而且为正整数的字符串,符合正则表达式^([1-9][0-9]*){1,3}$;
  • spec.updateStrategy.assignStrategies为array类型,其元素为object类型(包含slots和fromReplicas属性);
  • spec.updateStrategy.assignStrategies.slots为1-16384的正整数;
  • spec.updateStrategy.assignStrategies.fromReplicas为字符串,符合正则表达式^[a-z0-9,]{3,}$,即至少匹配3位a-z或者0-9或者逗号的字符串;
  • spec.pod为array类型,其元素为object类型(包含configmap、monitorImage、initImage、middlewareImage字段);
  • spec.pod.configmap、spec.pod.monitorImage、spec.pod.initImage 、spec.pod.middlewareImage为string类型;且用required指定configmap、initImage、middlewareImage字段为必填项。

将以下内容保存到 redis-cluster-crd.yaml:

代码语言:javascript
复制
apiVersion: apiextensions.k8s.io/v1beta1kind: CustomResourceDefinitionmetadata:  name: redisclusters.redis.middleware.hc.cnspec:  group: redis.middleware.hc.cn  versions:    - name: v1alpha1      # Each version can be enabled/disabled by Served flag.      served: true      # One and only one version must be marked as the storage version.      storage: true  scope: Namespaced  names:    kind: RedisCluster    singular: rediscluster    listKind: RedisClusterList    plural: redisclusters    shortNames:    - rec    # 执行kubectl get all时会查到pod、service、该crd等属于all categories的资源对象    categories:    - all  validation:    # openAPIV3Schema 适用于验证自定义对象的 schema。    openAPIV3Schema:      properties:        spec:          required: ["replicas", "repository", "version"]          properties:            pause:              type: boolean            replicas:              type: integer              minimum: 0              maximum: 50              # 偶数              multipleOf: 2            updateStrategy:              type: object              properties:                type:                  type: string                  # 枚举                  enum: ["AssignReceive", "AutoReceive"]                pipeline:                  type: string                  pattern: '^([1-9][0-9]*){1,3}$'                assignStrategies:                  type: array                  items:                    type: object                    properties:                      slots:                        type: integer                        minimum: 1                        maximum: 16384                      fromReplicas:                        type: string                        # 至少匹配3位,a-z或者0-9或者,                        pattern: '^[a-z0-9,]{3,}$'            pod:              type: array              items:                type: object                required: ["configmap", "middlewareImage", "initImage"]                properties:                  configmap:                    type: string                  monitorImage:                    type: string                  initImage:                    type: string                  middlewareImage:                    type: string

创建它:

代码语言:javascript
复制
kubectl create -f redis-cluster-crd.yaml

默认不加validation时,在创建自定义资源对象时,不会校验,有些字段没有了(如spec.replicas)都可以正常被创建,为了减少排错的难度和operator、controller的麻烦的检验,所以在创建自定义资源定义时,就把validation加上。以上的检验应该覆盖到了常见的检验场景,其他场景可以自己摸索。具体还可以参考kubernetes源码,1.13.2版本kubernetes源码位于types.go第327行CustomResourceValidation结构体:

代码语言:javascript
复制
$GOPATH/src/k8s.io/kubernetes/staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/types.go

将以下YAML保存到redis-cluster-cr.yaml:

代码语言:javascript
复制
apiVersion: redis.middleware.hc.cn/v1alpha1kind: RedisClustermetadata:   name: example000-redis-cluster  namespace: kube-systemspec:  # 代表redis集群的个数  replicas: 3  # 代表是否进入维修状态  pause: true  repository: library/redis  # 镜像版本,便于后续多版本特化支持  version: 3.2.6  #redis集群升级策略  updateStrategy:    # 升级类型为AutoReceive(自动分配,不用AssignStrategies), AssignReceive(指定值分配,需要用AssignStrategies)    type: AssignReceive1    pipeline: "100a"    assignStrategies:       -         slots: 0        fromReplicas: nodeId1       -         # 从nodeId3,nodeId4一共分配1000个卡槽        slots: 1000         # 多个nodeId用逗号分隔        fromReplicas: nodeId3,nodeId4  # redis 实例配置详情  pod:    # 配置文件模板名  - configmap: example000-redis-cluster-config    # 监控镜像    monitorImage: redis-exporter:v1    # 初始化镜像    #initImage: redis-init:v1    # 中间件容器镜像    middlewareImage: redis-trib:3.2.6

并创建它:

代码语言:javascript
复制
kubectl create -f redis-cluster-cr.yaml

会发现报以下错误:

如果所有字段都符合校验逻辑,才可以创建对象。将以下 YAML 保存到 redis-cluster-cr.yaml:

代码语言:javascript
复制
apiVersion: redis.middleware.hc.cn/v1alpha1kind: RedisClustermetadata:   name: example000-redis-cluster  namespace: kube-systemspec:  # 代表redis集群的个数  replicas: 6  # 代表是否进入维修状态  pause: true  repository: library/redis  # 镜像版本,便于后续多版本特化支持  version: 3.2.6  #redis集群升级策略  updateStrategy:    # 升级类型为AutoReceive(自动分配,不用AssignStrategies), AssignReceive(指定值分配,需要用AssignStrategies)    type: AssignReceive    pipeline: "100"    assignStrategies:       -         slots: 1        fromReplicas: all       -         # 从nodeId3,nodeId4一共分配1000个卡槽        slots: 1000         # 多个nodeId用逗号分隔        fromReplicas: node1,node2  # redis 实例配置详情  pod:    # 配置文件模板名  - configmap: example000-redis-cluster-config    # 监控镜像    monitorImage: redis-exporter:v1    # 初始化镜像    initImage: redis-init:v1    # 中间件容器镜像    middlewareImage: redis-trib:3.2.6

并创建它,发现才可以创建:

代码语言:javascript
复制
kubectl apply -f redis-cluster-cr.yamlrediscluster.redis.middleware.hc.cn/example000-redis-cluster configured

Category(分类)


类别是自定义资源所属的分组资源的列表(例如 all)。您可以使用 kubectl get 列出属于该类别的资源。此功能可用于 v1.10 及以上k8s版本自定义资源。

以下示例添加 all CustomResourceDefinition 中的类别列表,并说明如何使用 kubectl get all 输出自定义资源 。

将以下 内容保存到 redis-cluster-crd.yaml中执行:

代码语言:javascript
复制
kubectl apply -f redis-cluster-crd.yaml
代码语言:javascript
复制
apiVersion: apiextensions.k8s.io/v1beta1kind: CustomResourceDefinitionmetadata:  name: redisclusters.redis.middleware.hc.cnspec:  group: redis.middleware.hc.cn  versions:    - name: v1alpha1      # Each version can be enabled/disabled by Served flag.      served: true      # One and only one version must be marked as the storage version.      storage: true  scope: Namespaced  names:    kind: RedisCluster    singular: rediscluster    listKind: RedisClusterList    plural: redisclusters    shortNames:    - rec    # 执行kubectl get all时会查到pod、service、该crd等属于all categories的资源对象    categories:    - all

将以下内容保存到redis-cluster-cr.yaml中执行

代码语言:javascript
复制
kubectl apply -f redis-cluster-cr.yaml
代码语言:javascript
复制
apiVersion: redis.middleware.hc.cn/v1alpha1kind: RedisClustermetadata:   name: example000-redis-cluster  namespace: kube-systemspec:  # 代表redis集群的个数  replicas: 6  # 代表是否进入维修状态  pause: true  repository: library/redis  # 镜像版本,便于后续多版本特化支持  version: 3.2.6  #redis集群升级策略  updateStrategy:    # 升级类型为AutoReceive(自动分配,不用AssignStrategies), AssignReceive(指定值分配,需要用AssignStrategies)    type: AssignReceive    pipeline: "100"    assignStrategies:       -         slots: 2000        fromReplicas: nodeId1       -         # 从nodeId3,nodeId4一共分配1000个卡槽        slots: 1000         # 多个nodeId用逗号分隔        fromReplicas: nodeId3,nodeId4  # redis 实例配置详情  pod:    # 配置文件模板名  - configmap: example000-redis-cluster-config    # 监控镜像    monitorImage: redis-exporter:v1    # 初始化镜像    initImage: redis-init:v1    # 中间件容器镜像    middlewareImage: redis-trib:3.2.6

执行以下命令查看:

代码语言:javascript
复制
kubectl get all -nkube-system 

时会查到pod、service、该crd等属于all categories的资源对象。(这个可能得等几分钟才能生效)

子资源


status子资源

启用状态子资源后,将公开自定义资源的子资源 /status。

  • 状态和规范节分别由自定义资源内的 .status 和 .spec JSONPath 表示。
  • PUT /status 对子资源的请求采用自定义资源对象,并忽略除状态节之外的任何更改。
  • PUT /status 对子资源的请求仅验证自定义资源的状态节。
  • PUT/ POST/ PATCH 请求自定义资源忽略更改状态节。
  • 对 spec 节的任何更改都会增加 .metadata.generation 的值。

在code-generator生成代码时会生成,如下方法:

代码语言:javascript
复制
// RedisClusterInterface has methods to work with RedisCluster resources.type RedisClusterInterface interface {  Create(*v1alpha1.RedisCluster) (*v1alpha1.RedisCluster, error)  Update(*v1alpha1.RedisCluster) (*v1alpha1.RedisCluster, error)  UpdateStatus(*v1alpha1.RedisCluster) (*v1alpha1.RedisCluster, error)    ......}

scale子资源

启用 scale 子资源后,将公开自定义资源的子资源 /scale。该 autoscaling/v1.Scale 对象作为有效负载发送 /scale。

要启用 scale 子资源,CustomResourceDefinition 中需要定义以下值。

  • SpecReplicasPath 在与之对应的自定义资源中定义 JSONPath Scale.Spec.Replicas。这是一个必需的值。.spec 只允许使用带点符号的 JSONPaths 。如果 SpecReplicasPath 自定义资源中没有值,则 /scale 子资源将在GET上返回错误。
  • StatusReplicasPath 在与之对应的自定义资源中定义 JSONPath Scale.Status.Replicas。这是一个必需的值。.stutus 只允许使用带点符号的 JSONPaths 。如果 StatusReplicasPath 自定义资源中没有值,则子资源 /scale 中的状态副本值将默认为 0。
  • LabelSelectorPath在与之对应的自定义资源中定义 JSONPath Scale.Status.Selector。这是一个可选值。必须将其设置为与 HPA 一起使用。.status 只允许使用带点符号的 JSONPaths 。如果 LabelSelectorPath 自定义资源中没有值,则子资源 /scale 中的状态选择器值将默认为空字符串。

在以下示例中,启用了status 和 scale 子资源。将以下内容保存到redis-cluster-crd.yaml并创建 kubectl apply -f redis-cluster-crd.yaml:

代码语言:javascript
复制
apiVersion: apiextensions.k8s.io/v1beta1kind: CustomResourceDefinitionmetadata:  name: redisclusters.redis.middleware.hc.cnspec:  group: redis.middleware.hc.cn  versions:    - name: v1alpha1      # Each version can be enabled/disabled by Served flag.      served: true      # One and only one version must be marked as the storage version.      storage: true  scope: Namespaced  names:    kind: RedisCluster    singular: rediscluster    listKind: RedisClusterList    plural: redisclusters    shortNames:    - rec    # 执行kubectl get all时会查到pod、service、该crd等属于all categories的资源对象    categories:    - all  subresources:    # status enables the status subresource.    status: {}    scale:      # specReplicasPath defines the JSONPath inside of a custom resource that corresponds to Scale.Spec.Replicas.      specReplicasPath: .spec.replicas      # statusReplicasPath defines the JSONPath inside of a custom resource that corresponds to Scale.Status.Replicas.      statusReplicasPath: .status.replicas      # labelSelectorPath defines the JSONPath inside of a custom resource that corresponds to Scale.Status.Selector.      labelSelectorPath: .status.labelSelector

创建 CustomResourceDefinition 对象后,您可以创建自定义对象。

如果您将以下 YAML 保存到 redis-cluster-cr.yaml:

代码语言:javascript
复制
apiVersion: redis.middleware.hc.cn/v1alpha1kind: RedisClustermetadata:   name: example000-redis-cluster  namespace: kube-systemspec:  # 代表redis集群的个数  replicas: 6  # 代表是否进入维修状态  pause: true  repository: library/redis  # 镜像版本,便于后续多版本特化支持  version: 3.2.6  #redis集群升级策略  updateStrategy:    # 升级类型为AutoReceive(自动分配,不用AssignStrategies), AssignReceive(指定值分配,需要用AssignStrategies)    type: AssignReceive    pipeline: "100"    assignStrategies:       -         slots: 2000        fromReplicas: nodeId1       -         # 从nodeId3,nodeId4一共分配1000个卡槽        slots: 1000         # 多个nodeId用逗号分隔        fromReplicas: nodeId3,nodeId4  # redis 实例配置详情  pod:    # 配置文件模板名  - configmap: example000-redis-cluster-config    # 监控镜像    monitorImage: redis-exporter:v1    # 初始化镜像    initImage: redis-init:v1    # 中间件容器镜像    middlewareImage: redis-trib:3.2.6

并创建它:

代码语言:javascript
复制
kubectl create -f redis-cluster-cr.yaml

然后在以下位置创建新的命名空间 RESTful API 端点:

代码语言:javascript
复制
/apis/redis.middleware.hc.cn/v1alpha1/namespaces/kube-system/redisclusters/example000-redis-cluster/status

代码语言:javascript
复制
/apis/redis.middleware.hc.cn/v1alpha1/namespaces/kube-system/redisclusters/example000-redis-cluster/scale

可以使用该 kubectl scale 命令缩放自定义资源。例如,以上创建的自定义资源的的 .spec.replicas 设置为 10:

代码语言:javascript
复制
# kubectl get rec --all-namespacesNAMESPACE     NAME                       DESIRED   PAUSE   AGEkube-system   example000-redis-cluster   6         true    10h
# kubectl scale --replicas=10 rec/example000-redis-cluster -nkube-systemrediscluster.redis.middleware.hc.cn/example000-redis-cluster scaled
# kubectl get rec --all-namespacesNAMESPACE     NAME                       DESIRED   PAUSE   AGEkube-system   example000-redis-cluster   10        true    10h
# kubectl get rec example000-redis-cluster -n kube-system -o jsonpath='{.spec.replicas}'10

打印其他列


从 Kubernetes 1.11 开始,kubectl 使用服务器端打印。服务器决定 kubectl get 命令显示哪些列。您可以使用 CustomResourceDefinition 自定义这些列。下面的示例将输出 Spec、Replicas 和 Age 列。

将 CustomResourceDefinition保存到 redis-cluster-crd.yaml。

代码语言:javascript
复制
apiVersion: apiextensions.k8s.io/v1beta1kind: CustomResourceDefinitionmetadata:  name: redisclusters.redis.middleware.hc.cnspec:  group: redis.middleware.hc.cn  versions:    - name: v1alpha1      # Each version can be enabled/disabled by Served flag.      served: true      # One and only one version must be marked as the storage version.      storage: true  scope: Namespaced  names:    kind: RedisCluster    singular: rediscluster    listKind: RedisClusterList    plural: redisclusters    shortNames:    - rec    # 执行kubectl get all时会查到pod、service、该crd等属于all categories的资源对象    categories:    - all  additionalPrinterColumns:  - name: DESIRED    type: integer    description: The number of statefulset managed by the this redisCluster    JSONPath: .spec.replicas    # boolean,date,integer,number,string  - name: PAUSE    type: boolean    description: Whether this redisCluster's grandson (pod) will not be managed by statefulset    JSONPath: .spec.pause

创建 CustomResourceDefinition:

代码语言:javascript
复制
kubectl create -f redis-cluster-crd.yaml

使用上面创建的 redis-cluster-cr.yaml 实例。查看打印:

代码语言:javascript
复制
kubectl get rec --all-namespaces

请注意 NAME、NAMESPACE, DESIRED、PAUSE 和 AGE 在输出列,并且都被转成了大写字母:

代码语言:javascript
复制
[root@master-192 redis-container]# kubectl get rec --all-namespacesNAMESPACE     NAME                       DESIRED   PAUSE   AGEkube-system   example000-redis-cluster   6         true    10h

NAME和NAMESPACE 列是隐含的,不需要在CustomResourceDefinition 中定义。

operator中应用该特性


在golang编写的operator代码中创建该结构体:

代码语言:javascript
复制
//创建CRDfunc CreateRedisClusterCRD(extensionCRClient *extensionsclient.Clientset) error {    //add CustomResourceValidation due to guarantee redis operator work normally    labelSelectorPath := ".status.labelSelector"    replicasMinimum := float64(0)    replicasMaximum := float64(50)    replicasMultipleOf := float64(2)    slotsMinimum := float64(1)    slotsMaximum := float64(16384)    assignStr := "AssignReceive"    autoStr := "AutoReceive"    assignJson, _ := json.Marshal(assignStr)    autoJson, _ := json.Marshal(autoStr)
/*
* 提示:该行代码过长,系统自动注释不进行高亮。一键复制会移除系统注释 
* crd := &v1beta1.CustomResourceDefinition{        ObjectMeta: metav1.ObjectMeta{            Name: "redisclusters." + v1alpha1.SchemeGroupVersion.Group,        },        Spec: v1beta1.CustomResourceDefinitionSpec{            Group:   v1alpha1.SchemeGroupVersion.Group,            Versions: []v1beta1.CustomResourceDefinitionVersion {                {                    // Served is a flag enabling/disabling this version from being served via REST APIs                    Served: true,                    Name: v1alpha1.SchemeGroupVersion.Version,                    // Storage flags the version as storage version. There must be exactly one flagged as storage version                    Storage: true,                },            },            Scope:   v1beta1.NamespaceScoped,            Names: v1beta1.CustomResourceDefinitionNames{                Kind:       "RedisCluster",                ListKind:   "RedisClusterList",                Plural:     "redisclusters",                Singular:   "rediscluster",                ShortNames: []string{"rec"},                Categories: []string{"all"},            },            Subresources: &v1beta1.CustomResourceSubresources {                Status: &v1beta1.CustomResourceSubresourceStatus {},                Scale: &v1beta1.CustomResourceSubresourceScale {                    SpecReplicasPath: ".spec.replicas",                    StatusReplicasPath: ".status.replicas",                    LabelSelectorPath: &labelSelectorPath,                },            },            AdditionalPrinterColumns: []v1beta1.CustomResourceColumnDefinition{                {                    Name: "DESIRED",                    Type: "integer",                    Description: "The number of statefulset managed by the this redisCluster",                    JSONPath: ".spec.replicas",                },                {                    Name: "PAUSE",                    Type: "boolean",                    Description: "Whether this redisCluster's grandson (pod) will not be managed by statefulset",                    JSONPath: ".spec.pause",                },                {                    Name: "AGE",                    Type: "date",                    JSONPath: ".metadata.creationTimestamp",                },            },            Validation: &v1beta1.CustomResourceValidation {                OpenAPIV3Schema: &v1beta1.JSONSchemaProps {                    Properties: map[string]v1beta1.JSONSchemaProps {                        "spec": {                            Required: []string{"replicas", "repository", "version"},                            Properties: map[string]v1beta1.JSONSchemaProps{                                "pause": {                                    Type: "boolean",                                },                                "replicas": {                                    Type:       "integer",                                    Minimum:    &replicasMinimum,                                    Maximum:    &replicasMaximum,                                    MultipleOf: &replicasMultipleOf,                                },                                "updateStrategy": {                                    Type: "object",                                    Properties: map[string]v1beta1.JSONSchemaProps{                                        "type": {                                            Type: "string",                                            Enum: []v1beta1.JSON {                                                {                                                    //这里必须是JSON格式的字符串                                                    Raw: assignJson,                                                },                                                {                                                    Raw: autoJson,                                                },                                            },                                        },                                        "pipeline": {                                            Type:    "string",                                            Pattern: `^([1-9][0-9]*){1,3}$`,                                        },                                        "assignStrategies": {                                            Type: "array",                                            Items: &v1beta1.JSONSchemaPropsOrArray{                                                Schema: &v1beta1.JSONSchemaProps{                                                    Type: "object",                                                    Properties: map[string]v1beta1.JSONSchemaProps{                                                        "slots": {                                                            Type:    "integer",                                                            Minimum: &slotsMinimum,                                                            Maximum: &slotsMaximum,                                                        },                                                        "fromReplicas": {                                                            Type:    "string",                                                            Pattern: `^[a-z0-9,]{3,}$`,                                                        },                                                    },                                                },                                            },                                        },                                    },                                },                            },                        },                        "pod": {                            Type: "array",                            Items: &v1beta1.JSONSchemaPropsOrArray {                                Schema: &v1beta1.JSONSchemaProps {                                    Type: "object",                                    Required: []string{"replicas", "repository", "version"},                                    Properties: map[string]v1beta1.JSONSchemaProps{                                        "configmap": {                                            Type: "string",                                        },                                        "monitorImage": {                                            Type: "string",                                        },                                        "initImage": {                                            Type: "string",                                        },                                        "middlewareImage": {                                            Type: "string",                                        },                                    },                                },                            },                        },                    },                },            },        },    }    _, err := extensionCRClient.ApiextensionsV1beta1().CustomResourceDefinitions().Create(crd)    return err}
*/

参考

官方Extend the Kubernetes API with CustomResourceDefinitions:

https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions/

feature-gates参数说明:

https://kubernetes.io/docs/reference/command-line-tools-reference/feature-gates/

CustomResourceDefinition中文文档:

https://kubernetes.feisky.xyz/cha-jian-kuo-zhan/api/customresourcedefinition

swagger和openAPI: 数据类型:

https://www.breakyizhan.com/swagger/2969.html

正则表达式:

https://www.cnblogs.com/afarmer/archive/2011/08/29/2158860.html

• end •


本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-05-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 进击云原生 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 Redis
腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档