Kubernetes 对象缓存和索引

informer机制之cache.indexer机制 阅读详情

Kubernetes 对象缓存和索引

Store 是 K-V 类型的内存对象缓存。

Indexer 在 Store 的基础上添加了对象索引,从而实现快速查找对象的功能。

IndexFunc 类型的函数可以为对象生成索引列表。

cache 实现了 Store 和 Indexer 接口,函数 NewIndexer() 和 NewStore() 返回 cache 类型的对象。

cache 使用比较广泛,如各种 Informer 和 DeltaFIFO 用它做对象缓存和索引。

对象缓存 Store

Store 是 KV 类型的对象缓存:

// 来源于 k8s.io/client-go/tools/cache/store.go
type Store interface {
	Add(obj interface{}) error
	Update(obj interface{}) error
	Delete(obj interface{}) error
	List() []interface{}
	ListKeys() []string
	Get(obj interface{}) (item interface{}, exists bool, err error)
	GetByKey(key string) (item interface{}, exists bool, err error)

    // 使用传入的对象列表替换 Store 中的对象
	Replace([]interface{}, string) error
	Resync() error
}

NewStore() 函数返回一个实现该接口的 struct cache 类型对象(见后文分析)。

Queue 接口是 Store 的超集,所以实现 Queue 接口的 FIFO 类型、DeltaFIFO 类型也实现了 Store接口。(详见: 2.queue-fifo-delta_fifo.md)

对象索引 Indexer

Indexer 是在 Store 的基础上,添加了索引功能,方便快速获取(一批)对象。

// 来源于 k8s.io/client-go/tools/cache/index.go
type Indexer interface {
	// Index 实现了 Store 的接口
	Store
	// 返回注册的、名为 indexName 的索引函数
	Index(indexName string, obj interface{}) ([]interface{}, error)
	IndexKeys(indexName, indexKey string) ([]string, error)
	ListIndexFuncValues(indexName string) []string
	ByIndex(indexName, indexKey string) ([]interface{}, error)
	GetIndexers() Indexers

	AddIndexers(newIndexers Indexers) error
}

NewIndexer() 函数返回一个实现该接口的 struct cache 类型对象(见后文分析)。

为对象生成索引值列表的 IndexFunc 和 IndexFunc 集合 Indexers

对象的索引是一个字符串列表,由 IndexFunc 类型的函数生成,所以索引值和对象是一对多关系。

// 来源于 k8s.io/client-go/tools/cache/index.go
type IndexFunc func(obj interface{}) ([]string, error)

client-go package 提供了名为 NamespaceIndex 的 IndexFunc 类型函数 MetaNamespaceIndexFunc,它提取对象的 Namespace 作为索引:

// 来源于 k8s.io/client-go/tools/cache/index.go
func MetaNamespaceIndexFunc(obj interface{}) ([]string, error) {
	meta, err := meta.Accessor(obj)
	if err != nil {
		return []string{""}, fmt.Errorf("object has no meta: %v", err)
	}
	return []string{meta.GetNamespace()}, nil
}

多个命名的 IndexFunc 类型函数用 Indexers 表示:

// 来源于 k8s.io/client-go/tools/cache/index.go
// map[索引函数名称]索引函数
type Indexers map[string]IndexFunc

Indexer 接口的 AddIndexers() 方法为对象添加索引函数,从而为对象生成不同类型的索引,满足各种查找需求。

类似于 IndexFunc 为对象生成索引值列表,KeyFunc 函数(见后文)为对象生成一个唯一的标识字符串,称为对象 Key。

索引缓存 Index 和 Indices

前面说过,索引值和对象是一对多映射关系:

  • Index:保存索引匹配的对象集合(用它的唯一表示 Key 表示);
  • Indices:保存某个索引函数生成的所有索引的对象集合;
// 来源于 k8s.io/client-go/tools/cache/index.go
// map[索引字符串]set{对象 Key 集合}
type Index map[string]sets.String

// 对象的索引。map[索引函数名称]Index
type Indices map[string]Index

后文分析 cache 类型时将用到 Index 和 Indices。

为对象生成唯一标识 Key 的 KeyFunc

// 来源于 k8s.io/client-go/tools/cache/store.go
type KeyFunc func(obj interface{}) (string, error)

client-go package 提供了两个 KeyFunc 类型函数 MetaNamespaceKeyFunc 和 DeletionHandlingMetaNamespaceKeyFunc (实际用的最多):

  • MetaNamespaceKeyFunc:提取对象的 <namespace>/<object-name> 或 <object-name> 作为 Key;
  • DeletionHandlingMetaNamespaceKeyFunc:先检查对象是不是 DeletedFinalStateUnknown 类型(见后文),如果是,直接返回该对象内的 Key 字段,否则调用 MetaNamespaceKeyFunc 函数生成 Key;
// 来源于 k8s.io/client-go/tools/cache/store.go
func MetaNamespaceKeyFunc(obj interface{}) (string, error) {
	// 如果对象是字符串,则直接使用它作为 Key
	if key, ok := obj.(ExplicitKey); ok {
		return string(key), nil
	}
	// 否则提取对象的 Meta 信息
	meta, err := meta.Accessor(obj)
	if err != nil {
		return "", fmt.Errorf("object has no meta: %v", err)
	}
	// 如果对象有 Namespace 则用  `<namespace>/<object-name>` 作为 key
	// 否则用 `<object-name>` 作为 key
	if len(meta.GetNamespace()) > 0 {
		return meta.GetNamespace() + "/" + meta.GetName(), nil
	}
	return meta.GetName(), nil
}

// 来源于 k8s.io/client-go/tools/cache/controller.go
func DeletionHandlingMetaNamespaceKeyFunc(obj interface{}) (string, error) {
	// DeletedFinalStateUnknown 封装了删除对象 Key 和对象自身的类型,由 DeltaFIFO.Replace() 方法产生
	if d, ok := obj.(DeletedFinalStateUnknown); ok {
		return d.Key, nil
	}
	return MetaNamespaceKeyFunc(obj)
}

与 MetaNamespaceKeyFunc() 功能相反的是 SplitMetaNamespaceKey() 函数,它将传入的 Key 分解,返回对象所在的命名空间和对象名称。

使用 KeyFunc 比较多的场景是创建 Store、Index 和 DeltaFIFO,如:

clientState := NewIndexer(DeletionHandlingMetaNamespaceKeyFunc, indexers)
fifo := NewDeltaFIFO(MetaNamespaceKeyFunc, clientState)

因为 DeltaFIFO 接收的是从 apiserver List/Watch 的 K8S 资源对象,所以可以用 MetaNamespaceKeyFunc 提取它的 NS 和 Name。

但是 NewIndexer() 返回的 clientState 一般是 Reflector 从 DeltaFIFO 弹出的 Deltas,它是一个 Delta 的列表,而 Delta.Object 可能是 K8S 资源对象,也可能是 DeletedFinalStateUnknown 类型对象。所以 NewIndexer() 使用能区分这两种类型的 DeletionHandlingMetaNamespaceKeyFunc KeyFunc。

可并发访问的索引缓存 ThreadSafeStore

ThreadSafeStore 通过锁机制,实现多 goroutine 可以并发访问的、带有索引功能(Indexer 接口)的对象缓存(Store 接口)。

ThreadSafeStore 本身没有实现 Indexer 和 Store 接口,但包含同名方法,后文会介绍,struct cache 类型内部使用 ThreadSafeStore 实现了 Indexer 和 Store 接口。

// 来源于 k8s.io/client-go/tools/cache/thread_safe_store.go
type ThreadSafeStore interface {
	// 下面这些方法和 Store 接口方法同名,差别在于多了唯一标识对象的 key 参数
	// 相比 Store 接口,缺少了 GetByKey() 方法
	Add(key string, obj interface{})
	Update(key string, obj interface{})
	Delete(key string)
	List() []interface{}
	ListKeys() []string
	Get(key string) (item interface{}, exists bool) 

	Replace(map[string]interface{}, string)
	Resync() error

	// 下面这些是 Indexer 定义的接口方法
	Index(indexName string, obj interface{}) ([]interface{}, error) 
	IndexKeys(indexName, indexKey string) ([]string, error)
	ListIndexFuncValues(name string) []string
	ByIndex(indexName, indexKey string) ([]interface{}, error)
	GetIndexers() Indexers
	AddIndexers(newIndexers Indexers) error
}

NewThreadSafeStore() 函数返回一个实现该接口的对象,类型是 threadSafeMap:

// 来源于 k8s.io/client-go/tools/cache/thread_safe_store.go
func NewThreadSafeStore(indexers Indexers, indices Indices) ThreadSafeStore {
	return &threadSafeMap{
		items:    map[string]interface{}{},
		indexers: indexers,
		indices:  indices,
	}
}

threadSafeMap 使用 map 缓存所有对象:

// 来源于 k8s.io/client-go/tools/cache/thread_safe_store.go
// threadSafeMap implements ThreadSafeStore
type threadSafeMap struct {
	lock  sync.RWMutex
	// 对象缓存。使用对象的 Key 作为 map key;
	items map[string]interface{}
	// 命名的索引函数集合。map[索引函数名称]索引函数
	indexers Indexers
	// 对象的索引缓存。map[索引函数名称][索引字符串]set{对象 Key 集合}
	indices Indices
}

Add/Update() 方法

// 来源于 k8s.io/client-go/tools/cache/thread_safe_store.go
func (c *threadSafeMap) Add(key string, obj interface{}) {
	c.lock.Lock()
	defer c.lock.Unlock()
	oldObject := c.items[key]
	c.items[key] = obj
	c.updateIndices(oldObject, obj, key)
}

func (c *threadSafeMap) Update(key string, obj interface{}) {
	c.lock.Lock()
	defer c.lock.Unlock()
	oldObject := c.items[key]
	c.items[key] = obj
	c.updateIndices(oldObject, obj, key)
}

当 Add()/Update() 一个对象时,先将它加到缓存,然后用 updateIndices() 方法更新索引。

updateIndices() 方法

updateIndices() 方法使用 c.indexers 中的索引函数,为对象创建多种类型索引值列表,然后将这些索引及对象的 Key 更新到索引缓存中(c.indices)。

// 来源于 k8s.io/client-go/tools/cache/thread_safe_store.go
func (c *threadSafeMap) updateIndices(oldObj interface{}, newObj interface{}, key string) {
	// 从索引中移除老的 obj
	if oldObj != nil {
		c.deleteFromIndices(oldObj, key)
	}
	// 遍历 c.indexers 中的索引函数,为对象生成不同类型的索引列表
	for name, indexFunc := range c.indexers {
		indexValues, err := indexFunc(newObj)
		if err != nil {
			panic(fmt.Errorf("unable to calculate an index entry for key %q on index %q: %v", key, name, err))
		}
		// 获取当前索引函数创建的索引
		index := c.indices[name]
		if index == nil {
			index = Index{}
			c.indices[name] = index
		}
		// 将所有索引值和对象 Key 更新到索引缓存 c.indices 中
		for _, indexValue := range indexValues {
			set := index[indexValue]
			if set == nil {
				set = sets.String{}
				index[indexValue] = set
			}
			set.Insert(key)
		}
	}
}

Delete() 方法

Delete() 方法先后从索引缓存和对象缓存中删除对象。deleteFromIndices() 方法遍历 c.indexers 中的索引函数,为对象计算索引值列表,然后再从索引缓存和对象缓存中删除该对象:

// 来源于 k8s.io/client-go/tools/cache/thread_safe_store.go
func (c *threadSafeMap) Delete(key string) {
	c.lock.Lock()
	defer c.lock.Unlock()
	if obj, exists := c.items[key]; exists {
		// 从索引缓存中删除对象
		c.deleteFromIndices(obj, key)
		// 从对象缓存中删除对象
		delete(c.items, key)
	}
}

注意:一个索引值可能匹配多个对象,所以不能直接删除索引缓存中索引值对应的对象集合。

Replace() 方法

Replace() 方法使用传入的对象列表替换内部缓存,然后重建索引:

func (c *threadSafeMap) Replace(items map[string]interface{}, resourceVersion string) {
	c.lock.Lock()
	defer c.lock.Unlock()
	c.items = items

	// rebuild any index
	c.indices = Indices{}
	for key, item := range c.items {
		c.updateIndices(nil, item, key)
	}
}

其它方法介绍

  1. Index(indexName string, obj interface{}) ([]interface{}, error)

    indexName 为索引函数名称(下同)。使用对应的索引函数为对象生成索引值列表,然后查询索引缓存,返回匹配这些索引值的对象列表(去重)。

  2. ByIndex(indexName, indexKey string) ([]interface{}, error)

    indexKey 为索引值,查询索引缓存,返回它匹配的对象列表;

  3. IndexKeys(indexName, indexKey string) ([]string, error)

    indexKey 为索引值,查询索引缓存,返回它匹配的对象 Key 列表;

  4. ListIndexFuncValues(indexName string) []string

    查询索引缓存,返回 indexName 对应的索引函数创建的所有索引包含的对象 Key 列表;

  5. GetIndexers() Indexers

    返回命名的索引函数集合 c.indexers

  6. AddIndexers(newIndexers Indexers) error

    将 newIndexers 中的命名函数添加到索引函数集合 c.indexers 中。

    必须在添加任何对象前调用该方法,否则会出错返回。

    newIndexers 中的命名函数不能与 c.indexers 中已有的函数重名,否则出错返回。

  7. Resync() error

    直接返回。因为 Add/Update/Delete/Replace 方法都会同时更新缓存和索引,两者时刻是同步的。

使用 ThreadSafeStore 实现 Store/Indexer 接口的 cache

在分析 ThreadSafeStore 接口时提到过,它的方法如 Add/Update/Delete/Get() 都需要传入对象的 Key。
而 cache 则封装了 ThreadSafeStore 和 KeyFunc,后者为添加到 ThreadSafeStore 的对象生成 Key:

// 来源于 k8s.io/client-go/tools/cache/store.go
type cache struct {
	// cacheStorage bears the burden of thread safety for the cache
	cacheStorage ThreadSafeStore
	// keyFunc is used to make the key for objects stored in and retrieved from items, and
	// should be deterministic.
	keyFunc KeyFunc
}

cache 实现了 Indexer 和 Store 接口,函数 NewIndexer() 和 NewStore() 均返回该类型的对象:

// 来源于 k8s.io/client-go/tools/cache/store.go
func NewIndexer(keyFunc KeyFunc, indexers Indexers) Indexer {
	return &cache{
		cacheStorage: NewThreadSafeStore(indexers, Indices{}),
		keyFunc:      keyFunc,
	}
}

// 来源于 k8s.io/client-go/tools/cache/store.go
func NewStore(keyFunc KeyFunc) Store {
	return &cache{
		cacheStorage: NewThreadSafeStore(Indexers{}, Indices{}),
		keyFunc:      keyFunc,
	}
}

使用 cache 的 DeltaFIFO 和 Informer

后文会介绍,DeltaFIFO 使用 NewStore() 或 NewIndexer() 返回的 cache 作为 knownObjects 对象缓存,而且传给这两个函数的 KeyFunc 一般是 DeletionHandlingMetaNamespaceKeyFunc:

  1. NewInformer 函数:

    // 来源于 k8s.io/client-go/tools/cache/controller.go
    func NewInformer(
    	lw ListerWatcher,
    	objType runtime.Object,
    	resyncPeriod time.Duration,
    	h ResourceEventHandler,
    ) (Store, Controller) {
    	// This will hold the client state, as we know it.
    	clientState := NewStore(DeletionHandlingMetaNamespaceKeyFunc)
    
    	return clientState, newInformer(lw, objType, resyncPeriod, h, clientState)
    }
    
  2. NewIndexerInformer 函数:

    // 来源于 k8s.io/client-go/tools/cache/controller.go
    func NewIndexerInformer(
    	lw ListerWatcher,
    	objType runtime.Object,
    	resyncPeriod time.Duration,
    	h ResourceEventHandler,
    	indexers Indexers,
    ) (Indexer, Controller) {
    	// This will hold the client state, as we know it.
    	clientState := NewIndexer(DeletionHandlingMetaNamespaceKeyFunc, indexers)
    
    	return clientState, newInformer(lw, objType, resyncPeriod, h, clientState)
    }
    
  3. NewSharedIndexInformer 函数:

    // 来源于 k8s.io/client-go/tools/cache/shared_informer.go
    func NewSharedIndexInformer(lw ListerWatcher, objType runtime.Object, defaultEventHandlerResyncPeriod time.Duration, indexers Indexers) SharedIndexInformer {
    	realClock := &clock.RealClock{}
    	sharedIndexInformer := &sharedIndexInformer{
    		processor:                       &sharedProcessor{clock: realClock},
    
    		indexer:                         NewIndexer(DeletionHandlingMetaNamespaceKeyFunc, indexers),
    		
    		listerWatcher:                   lw,
    		objectType:                      objType,
    		resyncCheckPeriod:               defaultEventHandlerResyncPeriod,
    		defaultEventHandlerResyncPeriod: defaultEventHandlerResyncPeriod,
    		cacheMutationDetector:           NewCacheMutationDetector(fmt.Sprintf("%T", objType)),
    		clock:                           realClock,
    	}
    	return sharedIndexInformer
    }
    
一图读懂k8s informer client-go informers实现了持续获取集群的所有资源对象、监听集群的资源对象变化功能,并在本地维护了全量资源对象的内存缓存,以减少对apiserver、对etcd的请求压力。Informers在启动的时候会首先在客户端调用List接口来获取全量的对象集合,然后通过Watch接口来获取增量的对象,然后更新本地缓存。 ...... 阅读详情

相关推荐

K8s集群内网环境下的Helm3私有仓库搭建实战(含避坑指南)

本文详细介绍了在Kubernetes内网环境中,如何从零开始搭建一个高可用的Helm3私有仓库。通过ChartMuseum与Nginx的架构组合,涵盖部署、HTTPS配置、安全认证及Chart推送等核心步骤,并提供了关键的避坑指南和优化建议,帮助运维团队在内网安全环境下实现高效的K8s应用部署与管理。

weixin_29252171的博客 323

K8s源码分析(25)-Store组件和Indexer组件

上一篇文章里,我们主要介绍了和对象存储相关的组件 ThreadSafeStore 接口以及它的实现结构体 threadSafeMap,本质上来说该接口是并发安全的资源对象存储数据结构。在本篇文章里我们主要来介绍Store和 Indexer ,它们同样也是资源对象存储组件。Store接口Store 是接口,图解和源码如下://k8s.io/client-go/tools/cache/store...

weixin_46073333的博客 472

金山办公运维开发笔试:脚本/数据库/缓存/排查/容器全解析

现代运维开发的核心,在于用自动化脚本与工程化思维解决复杂系统问题。从基础的Shell文本处理、Python脚本健壮性设计,到MySQL索引优化与Redis缓存穿透、击穿、雪崩的应对策略,再到网络故障排查、系统负载分析与容器化CI/CD链路,每一项都是保障服务稳定性的关键能力。这些技术不仅用于日常运维,更是互联网产品高可用架构的基石。理解原理、掌握排查思路、具备性能优化意识,才能应对真实业务场景中的挑战。本文围绕金山办公校招运维开发岗位的笔试第二部分,系统拆解高频题型、答题逻辑与备考重点,帮助求职者构建从脚本

weixin_34176694的博客 473

K8s源码分析(24)-ThreadSafeStore组件

上一篇文章里,我们主要介绍了和资源索引相关的一系列对象,其中包括了 indexer 对象,index 对象,以及 indices 对象等等。在本篇文章里我们主要来介绍和对象存储相关的组件 ThreadSafeStore 接口以及其实现。ThreadSafeStore接口ThreadSafeStore 是接口,图解和源码如下://k8s.io/client-go/tool...

weixin_46073333的博客 363

三菱JET伺服限位、原点信号通过PLC刷新设置方法

RWw及RWr软元件的初始设定值,可通过 [Pr. PA01.0 控制模式选择] 及 [Pr. PN22.0 默认映射模式选择] 的值进行切换。JET伺服参数用于CC-Link IE现场网络Basic。循环通信的请求报文与响应报文的收发数据被换读为伺服放大器的对象数据 (RWwn、RWrn)。接下来看映射字2D05具体的内容: 也就是2D05操作字的第九位、第十位、第十一位。响应报文的设定值可进行变更。变更初始设定值时,应变更PDO映射。不同的模式,对应不同的刷新映射内容。GXWORKS3程序。

qq_51166033的博客 8048

别再到处找包了!Keil5芯片支持包(Pack)最全管理指南:安装、更新、迁移与离线备份

本文详细解析了Keil5芯片支持包(Pack)的全生命周期管理,包括安装、更新、迁移与离线备份的工程化解决方案。针对STM32F10x等常见芯片,提供了高效获取Pack的策略、版本管理技巧及团队协作方案,帮助开发者解决常见的'Device Family Pack missing'等问题,提升嵌入式开发效率。

weixin_28729205的博客 539

k8s-Informer之Indexer的解析(4)

Indexer 中的数据始终要是与 ETCD 中数据一致的,当 client-go 需要数据时,可直接通过该本地缓存获取资源对象,不需要每次都从 APIServer中获取,这样就减轻了请求过多造成对 APIServer 、etcd的压力。该方法传入索引器名称 indexName 和索引键名称indexedValue,方法寻找该索引器下,索引键对应的对象键列表,然后根据对象键列表,到Indexer缓存(即threadSafeMap中的items属性)中获取出相应的对象列表。3、Indexer 索引功能。

渔夫.AI 671

从零构建:基于Docker与FRR的OSPF虚拟网络实验室

本文详细介绍了如何利用Docker与FRR构建OSPF虚拟网络实验室,从环境设计到高级网络拓扑配置,再到实验验证与排错。通过容器化技术实现高效资源利用和快速部署,特别适合网络协议教学、企业网络架构验证等场景。

plum99的博客 220

k8s之Informer Store、Indexer、ThreadStore详解

Indexer 和 Store 都是基于 ThreadSafeStore 来实现的。Store实例和Indexer实例初始化的区别,就是没有 Indexers,Store 算是阉割版的 Indexer。ThreadSafeStore 的操作时需要使用 key 来对对象进行操作的,而 cache 的作用便是使用 cache.keyFunc 来计算对象的 key。

fourierr的博客 858

脑肿瘤MRI图像分割实战:基于U-Net的深度学习完整指南

脑肿瘤是中枢神经系统最常见的疾病之一,全球每年有超过30万人被诊断为原发性脑肿瘤。在临床诊断和治疗过程中,磁共振成像(MRI)已成为评估脑肿瘤的标准影像学检查方法。然而,手动分割MRI图像中的肿瘤区域是一项耗时且依赖于专家经验的工作,不同医生之间可能存在显著差异。

YOLO 147

uniapp - 超详细的 H5 公众号网页微信登录示例代码,提供从 0-1 公众号配置及详细注释代码(站在新手小白的角度)第三方微信授权登录的实现!!

uniapp微信浏览器H5授权微信登录,UniApp开发H5接入微信登录的全过程,uniapp的H5页面使用微信登录,uniapp H5微信授权登录,H5之微信授权登陆 (uniapp网页版微信授权登录),uni-app开发H5第三方微信授权登录的实现,uniapp如何实现微信授权登录,公众号H5页面接入微信登录流程,uni-app - 最详细 H5 网页接入微信登录功能,提供公众号配置与详细注释示例代码(移动端网页实现点击登录按钮后 调用微信公众号授权登录功能 详细讲解接入流程与详细示例代码)官方最新超级

✅ 精选推荐文章 1万+

k8s 源码client-go 系列之 indexer

Indexer 是一个索引缓存,用于缓存 Reflector 从 Kube-apiserver List/Watch到的资源对象,可以理解是一个带索引查询的内存型存储。下面通过走读源码的形式来了解 Indexer 的原理,本篇基于 k8s.io/client-go v0.30.0 源码讲解。

chaoyueshijian的博客 634

永恒之蓝漏洞复现(ms17-010)

Metasploit Framework(MSF)是一款开源安全漏洞检测工具,附带数千个已知的软件漏洞,并保持持续更新。Metasploit可以用来信息收集、漏洞探测、漏洞利用等渗透测试的全流程,被安全社区冠以“可以黑掉整个宇宙”之名。刚开始的Metasploit是采用Perl语言编写的,但是再后来的新版中,改成了用Ruby语言编写的了。在kali中,自带了Metasploit工具。

渗透之路,攻防之间皆学问 2万+

Conda clean清除缓存释放磁盘空间

在数据科学和AI开发中,Conda缓存常导致磁盘空间迅速耗尽。`conda clean`能安全清理.tarballs、元数据等无用文件,避免手动删除引发的问题。结合Docker镜像优化与环境管理,可显著减小体积,提升CI/CD效率。合理使用该命令是保障系统整洁与可复现性的关键实践。

weixin_32661831的博客 485

锂电池的充电和放电曲线解读

锂电池充放电曲线是反映其性能的关键指标。充电曲线分为恒流和恒压两阶段:恒流阶段电压快速上升,恒压阶段电流逐渐降低;放电曲线则呈现平台期和快速衰减期特征。这些曲线受温度、充放电倍率及材料体系(如三元锂或磷酸铁锂)显著影响。通过分析曲线特征,可优化电池管理系统,实现精准的SOC估算、快充策略制定及故障诊断,从而在电池性能与安全性间取得平衡。不同应用场景(如新能源汽车或消费电子)对曲线形态有特定要求。

start_up_go的博客 5062

FPGA原型验证(七):如何选择、搭建原型验证平台?

本篇概要::讨论了在项目初期选择目标FPGA平台的重要性,包括自制板卡与购买现成板卡之间的决策。主要是为那些希望建立基于FPGA的原型平台的工程师和设计师提供了深入的技术细节和决策指导,无论是选择自制还是购买现成的解决方案。

叫好与叫座虽然不是对立面,但想在同一个作品中达到双重效果很难。 942

client-go之listers包源码分析

listers包源码分析listers包admissionregistration包 listers包 从cache.Indexer中获取原生k8s的对象/列表 admissionregistration包 以admissionregistration包做分析,其他的类似,不在分析 v1 expansion_generated.go 用于扩展resource client 接口// MutatingWebhookConfigurationListerExpansion 将自定义方法添加到Mutati

qq_36407557的博客 366

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

informer

文章目录Informer机制一、基础1.为什么需要informer?2.定义3.作用4.Informer工作流程图二、使用1.作为 client 使用示例2. 作为 controller 使用示例(如何编写一个CRD)1.创建CRD目录和文件2.生成 clientset、informer 和 lister3.编写自定义控制器编写main函数 Informer机制 0.参考 kubernetes 中 informer 的使用 k8s-controller-custom-resource 极客时间深入剖析ku

潜心无止境 2416

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

9月待学清单

开学啦,要好好准备秋招啦。总结一个待学清单,整理亟需学习的内容成体系。2.面向对象基本知识,封装继承多态、SOLID原则。1.24种代码的坏味道,重构方法(抽替组改移)4.缓存:本地缓存和分布式缓存的区别。6.打印堆栈解决:内存溢出和泄露。9.排序、栈、队列、回文的手撕题。7.索引失效的几种情况。8.SQL优化的方法。

qq_43604326的博客 110

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

软件测试中,如何通过吞吐量、吞吐率和负载优化系统性能?

本文深入解析软件测试中吞吐量、吞吐率与负载的核心概念及其动态关系,提供五大实战技巧优化系统性能,包括数据库优化、代码性能提升和架构扩展方案。通过负载均衡与过载保护机制,结合性能测试工具链配置,帮助开发者精准定位性能瓶颈并建立持续优化体系。

weixin_29291863的博客 176

sample-controller核心架构解析:从Reflector到Workqueue的完整流程

sample-controller是一个完整的Kubernetes自定义控制器示例项目,它展示了如何使用client-go库构建可靠的控制器。本文将深入解析其核心架构,从Reflector到Workqueue的完整数据流转流程,帮助开发者理解Kubernetes控制器的工作原理。 ## 控制器核心组件概览 sample-controller的架构基于client-go库构建,主要包含四大核心组

gitblog_00358的博客 439

【k8s源码篇之Informer篇1】理解 Informer 的缓存与索引数据结构的设计

可以看出 Store 接口主要定义 对缓存(Local Store)的操作// k8s.io/client-go/tools/cache/store.go // Store 接口定义了 对缓存的操作 (如删除、更新、获取等) type Store interface {

叮当猫的喵i 2364

【云原生】kubernetes常见组件安装,持续更新中...

通过helm来安装部署各种组件superset,mysql,redis,flink,spark。其中的参数都需要根据实际情况自行修改。 spark on k8s flink on k8s mysql on k8s

如切如磋,如琢如磨,臻于至善。 351

基于微服务架构自建Minecraft插件中心:mcphub部署与运维指南

在现代软件工程中,微服务架构通过将复杂应用拆分为一组小型、独立的服务,实现了系统的高内聚、低耦合与独立扩展能力。其核心原理在于每个服务围绕特定业务能力构建,通过轻量级通信机制(如HTTP/REST或gRPC)进行交互,并可以独立部署和伸缩。这种架构的技术价值在于提升了开发效率、系统弹性与容错性,尤其适合需要快速迭代和高可用性的平台型应用。典型的应用场景包括电商平台、内容管理系统以及各类中台服务。本文聚焦的mcphub项目,正是这一理念在游戏服务器管理领域的具体实践。它作为一个自托管的Minecraft插件仓

weixin_30414305的博客 676

langfuse-k8s:在 Kubernetes 上部署 Langfuse 的利器

langfuse-k8s:在 Kubernetes 上部署 Langfuse 的利器 langfuse-k8s 是一个社区维护的仓库,包含了在 Kubernetes 上部署 Langfuse 所需的资源。该项目以其高效的 Helm 图表和灵活的配置选项,为开发者提供了一个简洁而强大的解决方案。 项目介绍 langfuse-k8s 的核心功能在于帮助用户在 Kubernetes 环境中快速部署 La...

gitblog_00601的博客 1473
上一篇: kubernetes1.13.4部署traefik
下一篇: Kubernetes 事件队列
KingDragon_Baron
博客等级 码龄12年 55粉丝 73原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值