client-go的Indexer三部曲之一:基本功能

欢迎访问我的GitHub

这里分类和汇总了欣宸的全部原创(含配套源码):github.com/zq2599/blog...

关于《client-go的Indexer三部曲》系列

  • 该系列是《client-go实战系列》的子系列文章,共三篇内容,分别从功能、性能、源码三个角度对client-go内部的Indexer组件进行说明,目标是与大家一同学习Indexer,并掌握如何在开发中通过Indexer实现灵活、高性能的查询检索操作
  • 再来回顾一下client-go的基本架构图,如下图所示,这次重点关注的是中间那根横向的虚线,可见在自定义的业务开发过程中,当我们需要得到某个资源对象的时候,是可以通过Indexer直接从本地缓存中获取的(Thread safe store)
  • 从用户角度来看,Indexer的作用就是可以帮助用户从本地获取资源对象,由于client-go的List & Watch机制,资源在kubernetes的所有变化都会及时同步到本地缓存中,这也就保证了本地缓存的数据是实时更新的

为什么要用Indexer获取资源?

  • 看到这里您可能会有疑问:从用户视角来看,client-go已经提供了API,可以远程访问api-server获取完整对象,那不就够用了吗?这里用Indexer获取本地对象有什么意义呢?

  • 理论上讲,从本地缓存获取数据属于进程内操作,如下图所示

  • 如果使用client-go提供的远程接口,就涉及到网络请求,理论上耗时更长

  • 从api-server视角来看还有另一层含义:走本地缓存后,来api-server查询的次数就少了,这也就降低了api-server的负载

  • 接下来就通过编码实战的方式,和大家一起了解Indexer的基本用法,另外为了印证本地缓存的性能优势,还会写一段远程访问api-server查询对象的代码,最后用性能工具同时对比两者,看看性能差距是否存在

  • 经过上述操作,相信咱们可以快速了解Indexer的实际用法,还能通过数据对其有更具体的认识,有了这些基础,在后面深入学习Indexer源码的时候,似乎可以轻松很多,每当您看到一段源码,对其设计原因和实际作用都有更多的认识,嗯,这也是欣宸一直推崇的学习方法:实战,不停的实战,拒绝凭空读代码

准备工作

  • 除了保证kubernetes环境正常,还要部署一些资源,以便稍后演示Indexer的功能
  • 先在kubernetes部署三种deployment,分别是:nginx、tomcat、mysql,完整的部署脚本可以在这里下载:github.com/zq2599/blog... ,共有下图这些文件
  • 由于涉及到本地存储,需要您根据自己电脑的情况修改deploy.sh的内容,如下图红色箭头所示,请修改成您自己电脑的有效路径
  • 执行deploy.sh即可完成部署,如果要清理掉所有部署的痕迹,执行deploy.sh即可
  • 部署成功后,在indexer-tutorials这个namespace下新增了五个pod,如下所示
shell 复制代码
kubectl get pods -n indexer-tutorials -o wide
NAME                                          READY   STATUS    RESTARTS   AGE    IP             NODE   NOMINATED NODE   READINESS GATES
mysql-556b999fd8-22hqh                        1/1     Running   0          8m4s   100.91.64.49   hedy   <none>           <none>
nginx-deployment-696cc4bc86-2rqcg             1/1     Running   0          8m1s   100.91.64.50   hedy   <none>           <none>
nginx-deployment-696cc4bc86-bkplx             1/1     Running   0          8m2s   100.91.64.46   hedy   <none>           <none>
nginx-deployment-696cc4bc86-m7wwh             1/1     Running   0          8m1s   100.91.64.47   hedy   <none>           <none>
tomcat-deployment-nautilus-7fcb47fcc4-vvdq6   1/1     Running   0          8m3s   100.91.64.48   hedy   <none>           <none>

准备一批业务需求

  • 本篇的目标是学会Indexer最基本的使用方式,因此先准备几个业务需求,然后用Indexer来实现这些需求,这样也算是有了具体的目标,可以更容易理解和掌握技术
  • 回顾刚才的部署脚本,如下图,nginx、tomcat、mysql都有两个自定义label:language和business-service-type
  • 下面的表格说明了nginx、tomcat、mysql这些pod的两个label的具体值
pod 语言类型(language) 服务类型(business-service-type)
nginx c web
tomcat c web
mysql java storage
  • 根据上述表格可见,nginx、tomcat、mysql这些pod,一共有两种分类方式:
  1. 按照语言类型分类,nginx和mysql都是c语言类,tomcat是java类
  2. 按照服务类型分类,nginx和tomcat都是web类,mysql是存储类
  • 请记住上述分类方式,接下来可以列出业务需求了
  1. 根据指定语言查询对应的pod的key,例如输入java,返回tomcat的pod的key
  2. 根据指定的pod的key查询pod对象,例如输入indexer-tutorials/nginx-deployment-87945df85-vzjgv,返回nginx的pod对象
  3. 查询指定语言的所有对象,例如输入java,返回tomcat的pod
  4. 根据某个对象的key,获取同语言类型的所有对象,例如输入indexer-tutorials/nginx-deployment-87945df85-vzjgv,返回的就是nginx和mysql的所有pod,因为它们的语言类型都是c
  5. 返回所有语言类型,这里应该是c和java
  6. 返回所有分类方式,这里应该是按服务类型和按语言类型两种
  • 接下来开始编码啦,用Indexer来实现上述六个需求

接口一览

  • 编码前先初步了解Indexer,直接看源码吧,毕竟稍后就要用到,结合刚刚准备好的kubernetes部署以及业务需求,这里对Indexer的接口做了详细的说明,请注意方法的注释
go 复制代码
type Indexer interface {
	// 存储相关的,不在本章讨论
	Store
	
	// indexName表示分类方式,obj表示用来查询的对象,
	// 例如indexName等于BY_LANGUAGE,obj等于nginx的pod对象,
	// 那么Index方法就会根据BY_LANGUAGE去获取pod对象的语言类型,即c语言,再返回所有c语言类型的对象
	// 简而言之就是:查找和obj同一个语言类型的所有对象
	Index(indexName string, obj interface{}) ([]interface{}, error)

	// indexName表示分类方式,indexedValue表示分类的值,
	// 例如indexName等于BY_LANGUAGE,indexedValue等于c,
	// 那么IndexKeys方法就会返回所有语言类型等于c的对象的key
	IndexKeys(indexName, indexedValue string) ([]string, error)
	
	// indexName表示分类方式,
	// 例如indexName等于BY_LANGUAGE,
	// ListIndexFuncValues返回的就是java和c
	ListIndexFuncValues(indexName string) []string
	
	// indexName表示分类方式,indexedValue表示分类的值,
	// 例如indexName等于BY_LANGUAGE,indexedValue等于c,
	// 那么ByIndex方法就会返回所有语言类型等于c的对象
	ByIndex(indexName, indexedValue string) ([]interface{}, error)
	
	// Indexers是个map,key是分类方式,
	// 本文中key有两个,分别是BY_LANGUAGE和BY_SERVICE,
	// value则是个方法,
	// key等于BY_LANGUAGE的时候,该方法的入参是个对象pod,返回值是这个pod的语言,
	// key等于BY_SERVICE的时候,该方法的入参是个对象pod,返回值是这个pod的服务类型,
	GetIndexers() Indexers
	// 添加Indexers
	AddIndexers(newIndexers Indexers) error
}

源码下载

名称 链接 备注
项目主页 github.com/zq2599/blog... 该项目在GitHub上的主页
git仓库地址(https) github.com/zq2599/blog... 该项目源码的仓库地址,https协议
git仓库地址(ssh) [email protected]:zq2599/blog_demos.git 该项目源码的仓库地址,ssh协议
  • 这个git项目中有多个文件夹,本篇的源码在tutorials/client-go-indexer-tutorials文件夹下,如下图红框所示:

项目简介

  • 接下来要开发的项目,使用常见的gin作为web框架,提供web接口来实现上述六个需求
  • 为了省事儿,这边会将编译好的二进制文件直接部署在kubernetes机器上,这样运行起来就能直接用上配置文件/root/.kube/config
  • 为了使用Indexer,需要做一些初始化操作,这里提前梳理出来,稍后只要对着这个流程图实现编码即可

编码,搭建框架

  • 新建名为client-go-indexer-tutorials的文件夹,构建一个新的module
shell 复制代码
go mod init client-go-indexer-tutorials
  • 下载gin
shell 复制代码
go get -u github.com/gin-gonic/gin
  • main.go的内容很简单:执行kubernetes初始化相关的方法,再设定好六个web接口的handler
go 复制代码
package main

import (
	"client-go-indexer-tutorials/basic"

	"github.com/gin-gonic/gin"
)

func main() {
	r := gin.Default()
	// kubernetes相关的初始化操作
	basic.DoInit()

	// 用于提供基本功能的路由组
	basicGroup := r.Group("/basic")

	// a. 查询指定语言的所有对象的key(演示2. IndexKeys方法)
	basicGroup.GET("get_obj_keys_by_language_name", basic.GetObjKeysByLanguageName)

	// b. 返回对象的key,返回对应的对象(演示Store.GetByKey方法)
	basicGroup.GET("get_obj_by_obj_key", basic.GetObjByObjKey)

	// c. 查询指定语言的所有对象(演示4. ByIndex方法)
	basicGroup.GET("get_obj_by_language_name", basic.GetObjByLanguageName)

	// d. 根据某个对象的key,获取同语言类型的所有对象(演示1. Index方法)
	basicGroup.GET("get_all_obj_by_one_name", basic.GetAllObjByOneName)

	// e. 返回所有语言类型(演示3. ListIndexFuncValues方法)
	basicGroup.GET("get_all_languange", basic.GetAllLanguange)

	// f. 返回所有分类方式,这里应该是按服务类型和按语言类型两种(演示5. GetIndexers方法)
	basicGroup.GET("get_all_class_type", basic.GetAllClassType)

	r.Run(":18080")
}

编码,业务功能

  • 完整的业务代码如下,已经添加了详细注释,另有几处要注意的地方,稍后会说明
go 复制代码
package basic

import (
	"errors"
	"flag"
	"fmt"
	"log"
	"path/filepath"
	"sync"

	"github.com/gin-gonic/gin"
	v1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/meta"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/fields"
	"k8s.io/apimachinery/pkg/util/runtime"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/tools/cache"
	"k8s.io/client-go/tools/clientcmd"
	"k8s.io/client-go/util/homedir"
)

const (
	NAMESPACE      = "indexer-tutorials"
	PARAM_LANGUAGE = "language"
	PARAM_OBJ_KEY  = "obj_key"

	LANGUAGE_C = "c"

	INDEXER_LANGUAGE              = "indexer_language"
	INDEXER_BUSINESS_SERVICE_TYPE = "indexer_business_service_type"

	LABEL_LANGUAGE              = "language"
	LABEL_BUSINESS_SERVICE_TYPE = "business-service-type"
)

var ClientSet *kubernetes.Clientset
var once sync.Once
var INDEXER cache.Indexer

// DoInit Indexer相关的初始化操作,这里确保只执行一次
func DoInit() {
	once.Do(initIndexer)
}

// initIndexer 这里是真正的初始化逻辑
func initIndexer() {
	log.Println("开始初始化Indexer")

	var kubeconfig *string

	// 试图取到当前账号的家目录
	if home := homedir.HomeDir(); home != "" {
		// 如果能取到,就把家目录下的.kube/config作为默认配置文件
		kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")
	} else {
		// 如果取不到,就没有默认配置文件,必须通过kubeconfig参数来指定
		kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file")
	}

	// 加载配置文件
	config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
	if err != nil {
		panic(err.Error())
	}

	// 用clientset类来执行后续的查询操作
	ClientSet, err = kubernetes.NewForConfig(config)
	if err != nil {
		panic(err.Error())
	}

	log.Println("kubernetes配置文件加载成功")

	// 确定从apiserver订阅的类型
	podListWatcher := cache.NewListWatchFromClient(ClientSet.CoreV1().RESTClient(), "pods", NAMESPACE, fields.Everything())

	// Indexers对象的类型是map,key是自定义字符串,value是个function,用于根据业务逻辑返回一个对象的字符串
	indexers := cache.Indexers{
		INDEXER_LANGUAGE: func(obj interface{}) ([]string, error) {
			var object metav1.Object
			object, err = meta.Accessor(obj)
			if err != nil {
				return []string{}, nil
			}

			labelValue := object.GetLabels()[LABEL_LANGUAGE]
			if labelValue == "" {
				return []string{}, nil
			}
			return []string{labelValue}, nil
		},
		INDEXER_BUSINESS_SERVICE_TYPE: func(obj interface{}) ([]string, error) {
			var object metav1.Object
			object, err = meta.Accessor(obj)
			if err != nil {
				return []string{}, nil
			}

			labelValue := object.GetLabels()[LABEL_BUSINESS_SERVICE_TYPE]
			if labelValue == "" {
				return []string{}, nil
			}
			return []string{labelValue}, nil
		},
	}

	var informer cache.Controller

	INDEXER, informer = cache.NewIndexerInformer(podListWatcher, &v1.Pod{}, 0, cache.ResourceEventHandlerFuncs{}, indexers)

	log.Println("Indexer初始化成功")

	stopCh := make(chan struct{})

	// informer的Run方法执行后,就开始接受apiserver推送的资源变更事件,并更新本地存储
	go informer.Run(stopCh)

	// 等待本地存储和apiserver完成同步
	if !cache.WaitForCacheSync(stopCh, informer.HasSynced) {
		err = errors.New("timed out waiting for caches to sync")
		runtime.HandleError(err)
		return
	}

	log.Println("pod加载完成")

}

// language 辅助方法,从请求参数中获取语言类型,默认返回c
func language(c *gin.Context) string {
	return c.DefaultQuery(PARAM_LANGUAGE, LANGUAGE_C)
}

// objKey 辅助方法,从请求参数中获取对象key
func objKey(c *gin.Context) string {
	return c.DefaultQuery(PARAM_OBJ_KEY, "")
}

// getObjKeysByLanguageName a. 查询指定语言的所有对象的key(演示2. IndexKeys方法)
func GetObjKeysByLanguageName(c *gin.Context) {
	language := language(c)

	v, err := INDEXER.IndexKeys(INDEXER_LANGUAGE, language)

	if err != nil {
		c.String(500, fmt.Sprintf("a. get pod failed, %v", err))
	} else if nil == v || len(v) < 1 {
		c.String(500, fmt.Sprintf("a. get empty pod, %v", err))
	} else {
		m := make(map[string][]string)
		m["language"] = v
		c.JSON(200, m)
	}
}

// GetObjByObjKey b. 根据对象的key返回(演示Store.Get方法)
func GetObjByObjKey(c *gin.Context) {
	rawObj, exists, err := INDEXER.GetByKey(objKey(c))

	if err != nil {
		c.String(500, fmt.Sprintf("b. get pod failed, %v", err))
	} else if !exists {
		c.String(500, fmt.Sprintf("b. get empty pod, %v", err))
	} else {
		if v, ok := rawObj.(*v1.Pod); ok {
			c.JSON(200, v)
		} else {
			c.String(500, "b. convert interface to pod failed")
		}
	}
}

// getObjByLanguageName c. 查询指定语言的所有对象(演示4. ByIndex方法)
func GetObjByLanguageName(c *gin.Context) {
	v, err := INDEXER.ByIndex(INDEXER_LANGUAGE, language(c))

	if err != nil {
		c.String(500, fmt.Sprintf("c. get pod failed, %v", err))
	} else if v == nil {
		c.String(500, fmt.Sprintf("c. get empty pod, %v", err))
	} else {
		m := make(map[string][]interface{})
		m["language"] = v
		c.JSON(200, m)
	}
}

// getAllObjByOneName d. 根据某个对象的key,获取同语言类型的所有对象(演示1. Index方法)
func GetAllObjByOneName(c *gin.Context) {
	// 注意,Index方法的第二个入参是对象,所以这里要先根据对象key查询到对象,然后再调用Index方法
	rawObj, exists, err := INDEXER.GetByKey(objKey(c))

	if err != nil {
		c.String(500, fmt.Sprintf("d1. get pod failed, %v", err))
	} else if !exists {
		c.String(500, fmt.Sprintf("d1. get empty pod, %v", err))
	} else {
		// 先得到pod对象,再根据pod对象查询同类型的所有对象
		if podObj, ok := rawObj.(*v1.Pod); ok {
			rawArray, err := INDEXER.Index(INDEXER_LANGUAGE, podObj)

			if err != nil {
				c.String(500, fmt.Sprintf("d2. get pod failed, %v", err))
			} else if len(rawArray) < 1 {
				c.String(500, fmt.Sprintf("d2. get empty pod, %v", err))
			} else {
				m := make(map[string][]interface{})
				m["language"] = rawArray
				c.JSON(200, m)
			}
		} else {
			c.String(500, "d1. convert interface to pod failed")
		}
	}
}

// getAllClassType e. 返回所有语言类型(演示3. ListIndexFuncValues方法)
func GetAllLanguange(c *gin.Context) {
	languages := INDEXER.ListIndexFuncValues(INDEXER_LANGUAGE)

	m := make(map[string][]string)
	m["language"] = languages

	c.JSON(200, m)
}

// getAllClassType f. 返回所有分类方式,这里应该是按服务类型和按语言类型两种(演示5. GetIndexers方法)
func GetAllClassType(c *gin.Context) {
	indexers := INDEXER.GetIndexers()
	// indexers是个map,其value是cache.IndexFunc类型,无法被序列化,所以这里只返回key
	names := make([]string, 0)
	for key, _ := range indexers {
		names = append(names, key)
	}
	c.JSON(200, names)
}
  • 上述代码有以下几处需要注意
  1. 注意区分Indexers和Indexer,两者不是同一个东西,Indexers是个map,Indexer提供了各种查询API,Indexer是本篇我们要重点关注的内容
  2. 对应Indexers,key是分类方式的名称,这个可以自己起名字,value是方法,用于自定义如何设定该对象在此分类下的的结果,举个例子,如果按照语言分类,那么key等于"indexer_language",value是个方法,该方法用于返回一个pod的label值,该label就是"language"
  3. Indexers中的func,让沉迷于Java的我想起了一段Java代码,就是自定义排序,也是自己写好具体的排序逻辑,至于如何使用这个逻辑就无需关心了,只要调用Arrays.sort就好,如下所示
java 复制代码
public class CustomSort {
    public static void main(String[] args) {
        String[] arr = {"banana", "apple", "orange", "pear"};
        
        // 使用自定义排序方法进行排序
        Arrays.sort(arr, new CustomComparator());
        
        // 输出排序后的数组
        for (String str : arr) {
            System.out.print(str + " ");
        }
    }
}

class CustomComparator implements Comparator<String> {
    @Override
    public int compare(String s1, String s2) {
        // 按照字符串长度进行排序
        return Integer.compare(s1.length(), s2.length());
    }
}

编码,运行脚本

  • 如果您使用的是vscode,可以把launch.json配置如下,以便使用运行和调试功能
json 复制代码
{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Launch Package",
            "type": "go",
            "request": "launch",
            "mode": "auto",
            "program": "${workspaceFolder}"
        }
    ]
}

编码,测试脚本

  • 写到这里,其实可以运行程序,然后用postman或者直接用浏览器来访问接口验证效果了,不过为了将操作也能归档,以便今后也能随时再次操作,我这里使用了vscode的REST Client插件,把所有web请求放在脚本中,借助插件来完成请求、获取响应,您若对REST Client没有兴趣可以跳过这段
  • 新建hello.http文件,内容如下
javascript 复制代码
### 变量,这是一个pod的对象key,和pod是一对一的关系
@obj_key=indexer-tutorials/nginx-deployment-87945df85-vzjgv

### 测试用例a. 查询指定语言的所有对象的key(演示2. IndexKeys方法)
GET http://192.168.50.76:18080/basic/get_obj_keys_by_language_name?language=c

### 测试用例b. 返回对象的key,返回对应的对象(演示Store.GetByKey方法)
GET http://192.168.50.76:18080/basic/get_obj_by_obj_key?obj_key={{obj_key}}

### 测试用例c. 查询指定语言的所有对象(演示4. ByIndex方法)
GET http://192.168.50.76:18080/basic/get_obj_by_language_name?language=c

### 测试用例d. 根据某个对象的key,获取同语言类型的所有对象(演示1. Index方法)
GET http://192.168.50.76:18080/basic/get_all_obj_by_one_name?obj_key={{obj_key}}

### 测试用例e. 返回所有语言类型(演示3. ListIndexFuncValues方法)
GET http://192.168.50.76:18080/basic/get_all_languange

### 测试用例f. 返回所有分类方式,这里应该是按服务类型和按语言类型两种(演示5. GetIndexers方法)
GET http://192.168.50.76:18080/basic/get_all_class_type

验证,查询指定语言的所有对象的key(演示2. IndexKeys方法)

  • 运行程序,可见如果和kubernetes同机部署,首次加载全量数据也不会消耗太长时间
  • 测试,第一个请求如下
shell 复制代码
http://192.168.50.76:18080/basic/get_obj_keys_by_language_name?language=c
  • 如果是REST Client,点击下图黄色箭头位置即可
  • 收到响应如下,可见编程语言是c的pod一共有四个,一个mysql,三个nginx的,它们的key都在JSON数组中返回,符合预期,
shell 复制代码
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Date: Wed, 14 Jun 2023 22:56:37 GMT
Content-Length: 219
Connection: close

{
  "language": [
    "indexer-tutorials/mysql-556b999fd8-22hqh",
    "indexer-tutorials/nginx-deployment-696cc4bc86-2rqcg",
    "indexer-tutorials/nginx-deployment-696cc4bc86-bkplx",
    "indexer-tutorials/nginx-deployment-696cc4bc86-m7wwh"
  ]
}
  • 现在拿到了对象的key,可见是namespace和pod name拼接而成,接下来试试用key得到对象,这是Store的基本功能

验证,查询指定语言的所有对象的key(演示Store.GetByKey方法)

  • 如果REST Client,可以用变量来保存对象key,这样便于维护,如下图
  • 根据对象key查询资源对象的path
shell 复制代码
http://192.168.50.76:18080/basic/get_obj_by_obj_key?obj_key=indexer-tutorials/nginx-deployment-696cc4bc86-2rqcg
  • 响应如下(篇幅所限只显示部分),可见是一个完整的pod信息
shell 复制代码
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Date: Wed, 14 Jun 2023 23:19:50 GMT
Connection: close
Transfer-Encoding: chunked

{
  "metadata": {
    "name": "nginx-deployment-696cc4bc86-2rqcg",
    "generateName": "nginx-deployment-696cc4bc86-",
    "namespace": "indexer-tutorials",
    "uid": "f079b9e3-2b0f-4090-8d0f-5bab4fa2eeda",
    "resourceVersion": "1341749",
    "creationTimestamp": "2023-06-12T23:04:58Z",
    "labels": {
      "app": "nginx-app",
      "business-service-type": "web",
      "language": "c",
      "pod-template-hash": "696cc4bc86",
      "type": "front-end"
    },
    ...

验证, 查询指定语言的所有对象(演示4. ByIndex方法)

  • 刚才咱们试过了get_obj_keys_by_language_name,可以根据语言查找对象的key,现在来试试根据语言查对象
shell 复制代码
http://192.168.50.76:18080/basic/get_obj_by_language_name?language=c
  • 响应(篇幅所限只显示部分)
shell 复制代码
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Date: Wed, 14 Jun 2023 23:25:00 GMT
Connection: close
Transfer-Encoding: chunked

{
  "language": [
    {
      "metadata": {
        "name": "mysql-556b999fd8-22hqh",
        "generateName": "mysql-556b999fd8-",
        "namespace": "indexer-tutorials",
        "uid": "ac7ca6a2-f463-450d-848a-f3a2ea6a02df",
        "resourceVersion": "1341711",
        "creationTimestamp": "2023-06-12T23:04:55Z",
        "labels": {
          "app": "mysql",
          "business-service-type": "storage",
          "language": "c",
          "pod-template-hash": "556b999fd8"
        },

验证,根据某个对象的key,获取同语言类型的所有对象(演示1. Index方法)

  • 用nginx对象的key,能查到同类型语言的所有对象
shell 复制代码
http://192.168.50.76:18080/basic/get_all_obj_by_one_name?obj_key=indexer-tutorials/nginx-deployment-696cc4bc86-2rqcg
  • 响应
shell 复制代码
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Date: Wed, 14 Jun 2023 23:30:11 GMT
Connection: close
Transfer-Encoding: chunked

{
  "language": [
    {
      "metadata": {
        "name": "nginx-deployment-696cc4bc86-bkplx",
        "generateName": "nginx-deployment-696cc4bc86-",
        "namespace": "indexer-tutorials",
        "uid": "eba92053-bc35-4ef5-835a-1c2f054891d5",
        "resourceVersion": "1341721",
        "creationTimestamp": "2023-06-12T23:04:57Z",
        "labels": {
          "app": "nginx-app",
          "business-service-type": "web",
          "language": "c",
          "pod-template-hash": "696cc4bc86",
          "type": "front-end"
        },
	...

验证,返回所有语言类型(演示3. ListIndexFuncValues方法)

  • 可以指定分类方式后,看到该方式分类后共有哪些值
shell 复制代码
http://192.168.50.76:18080/basic/get_all_languange
  • 可见共有两种
shell 复制代码
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Date: Wed, 14 Jun 2023 23:32:37 GMT
Content-Length: 25
Connection: close

{
  "language": [
    "java",
    "c"
  ]
}

验证,返回所有分类方式,这里应该是按服务类型和按语言类型两种(演示5. GetIndexers方法)

  • 由于具体的分类方式是函数,无法做序列化,因此返回的是分类方式对应的name
shell 复制代码
http://192.168.50.76:18080/basic/get_all_class_type
  • 响应
shell 复制代码
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Date: Wed, 14 Jun 2023 23:59:56 GMT
Content-Length: 52
Connection: close

[
  "indexer_language",
  "indexer_business_service_type"
]
  • 至此,Indexer的基本功能已经体验完成,对于如何使用Indexer相信您已经掌握了,接下来咱们会进入性能篇,来看看这个理论上的高性能在实际环境中有着怎样的表现

欢迎关注掘金:程序员欣宸

学习路上,你不孤单,欣宸原创一路相伴...

相关推荐
徐小黑ACG31 分钟前
GO语言 使用protobuf
开发语言·后端·golang·protobuf
战族狼魂3 小时前
CSGO 皮肤交易平台后端 (Spring Boot) 代码结构与示例
java·spring boot·后端
杉之5 小时前
常见前端GET请求以及对应的Spring后端接收接口写法
java·前端·后端·spring·vue
hycccccch5 小时前
Canal+RabbitMQ实现MySQL数据增量同步
java·数据库·后端·rabbitmq
GreenMountainEcho5 小时前
Kubernetes 入门篇之 Node 安装与部署
云原生·容器·kubernetes
bobz9656 小时前
k8s 怎么提供虚拟机更好
后端
bobz9656 小时前
nova compute 如何创建 ovs 端口
后端
用键盘当武器的秋刀鱼6 小时前
springBoot统一响应类型3.5.1版本
java·spring boot·后端
ghostwritten7 小时前
Rancher Backup
kubernetes·rancher
Asthenia04127 小时前
从迷宫到公式:为 NFA 构造正规式
后端