主頁 >  其他 > 如何高效掌控K8s資源變化?K8s Informer實作機制淺析

如何高效掌控K8s資源變化?K8s Informer實作機制淺析

2021-09-15 06:29:47 其他

作者

王成,騰訊云研發工程師,Kubernetes contributor,從事資料庫產品容器化、資源管控等作業,關注 Kubernetes、Go、云原生領域,

概述

進入 K8s 的世界,會發現有很多的 Controller,它們都是為了完成某類資源(如 pod 是通過 DeploymentController, ReplicaSetController 進行管理)的調諧,目標是保持用戶期望的狀態,

K8s 中有幾十種型別的資源,如何能讓 K8s 內部以及外部用戶方便、高效的獲取某類資源的變化,就是本文 Informer 要實作的,本文將從 Reflector(反射器)、DeletaFIFO(增量佇列)、Indexer(索引器)、Controller(控制器)、SharedInformer(共享資源通知器)、processorListener(事件監聽處理器)、workqueue(事件處理作業佇列) 等方面進行決議,

本文及后續相關文章都基于 K8s v1.22

(K8s-informer)

從 Reflector 說起

Reflector 的主要職責是從 apiserver 拉取并持續監聽(ListAndWatch) 相關資源型別的增刪改(Add/Update/Delete)事件,存盤在由 DeltaFIFO 實作的本地快取(local Store) 中,

首先看一下 Reflector 結構體定義:

// staging/src/k8s.io/client-go/tools/cache/reflector.go
type Reflector struct {
	// 通過 file:line 唯一標識的 name
	name string

	// 下面三個為了確認型別
	expectedTypeName string
	expectedType     reflect.Type
	expectedGVK      *schema.GroupVersionKind

	// 存盤 interface: 具體由 DeltaFIFO 實作存盤
	store Store
	// 用來從 apiserver 拉取全量和增量資源
	listerWatcher ListerWatcher

	// 下面兩個用來做失敗重試
	backoffManager         wait.BackoffManager
	initConnBackoffManager wait.BackoffManager

	// informer 使用者重新同步的周期
	resyncPeriod time.Duration
	// 判斷是否滿足可以重新同步的條件
	ShouldResync func() bool
	
	clock clock.Clock
	
	// 是否要進行分頁 List
	paginatedResult bool
	
	// 最后同步的資源版本號,以此為依據,watch 只會監聽大于此值的資源
	lastSyncResourceVersion string
	// 最后同步的資源版本號是否可用
	isLastSyncResourceVersionUnavailable bool
	// 加把鎖控制版本號
	lastSyncResourceVersionMutex sync.RWMutex
	
	// 每頁大小
	WatchListPageSize int64
	// watch 失敗回呼 handler
	watchErrorHandler WatchErrorHandler
}

從結構體定義可以看到,通過指定目標資源型別進行 ListAndWatch,并可進行分頁相關設定,

第一次拉取全量資源(目標資源型別) 后通過 syncWith 函式全量替換(Replace) 到 DeltaFIFO queue/items 中,之后通過持續監聽 Watch(目標資源型別) 增量事件,并去重更新到 DeltaFIFO queue/items 中,等待被消費,

watch 目標型別通過 Go reflect 反射實作如下:

// staging/src/k8s.io/client-go/tools/cache/reflector.go
// watchHandler watches w and keeps *resourceVersion up to date.
func (r *Reflector) watchHandler(start time.Time, w watch.Interface, resourceVersion *string, errc chan error, stopCh <-chan struct{}) error {

	...
	if r.expectedType != nil {
		if e, a := r.expectedType, reflect.TypeOf(event.Object); e != a {
			utilruntime.HandleError(fmt.Errorf("%s: expected type %v, but watch event object had type %v", r.name, e, a))
			continue
		}
	}
	if r.expectedGVK != nil {
		if e, a := *r.expectedGVK, event.Object.GetObjectKind().GroupVersionKind(); e != a {
			utilruntime.HandleError(fmt.Errorf("%s: expected gvk %v, but watch event object had gvk %v", r.name, e, a))
			continue
		}
	}
	...
}

通過反射確認目標資源型別,所以命名為 Reflector 還是比較貼切的; List/Watch 的目標資源型別在 NewSharedIndexInformer.ListerWatcher 進行了確定,但 Watch 還會在 watchHandler 中再次比較一下目標型別;

認識 DeltaFIFO

還是先看下 DeltaFIFO 結構體定義:

// staging/src/k8s.io/client-go/tools/cache/delta_fifo.go
type DeltaFIFO struct {
	// 讀寫鎖、條件變數
	lock sync.RWMutex
	cond sync.Cond

	// kv 存盤:objKey1->Deltas[obj1-Added, obj1-Updated...]
	items map[string]Deltas

	// 只存盤所有 objKeys
	queue []string

	// 是否已經填充:通過 Replace() 介面將第一批物件放入佇列,或者第一次呼叫增、刪、改介面時標記為true
	populated bool
	// 通過 Replace() 介面將第一批物件放入佇列的數量
	initialPopulationCount int

	// keyFunc 用來從某個 obj 中獲取其對應的 objKey
	keyFunc KeyFunc

	// 已知物件,其實就是 Indexer
	knownObjects KeyListerGetter

	// 佇列是否已經關閉
	closed bool

	// 以 Replaced 型別發送(為了兼容老版本的 Sync)
	emitDeltaTypeReplaced bool
}

DeltaType 可分為以下型別:

// staging/src/k8s.io/client-go/tools/cache/delta_fifo.go
type DeltaType string

const (
	Added   DeltaType = "Added"
	Updated DeltaType = "Updated"
	Deleted DeltaType = "Deleted"
	Replaced DeltaType = "Replaced" // 第一次或重新同步
	Sync DeltaType = "Sync" // 老版本重新同步叫 Sync
)

通過上面的 Reflector 分析可以知道,DeltaFIFO 的職責是通過佇列加鎖處理(queueActionLocked)、去重(dedupDeltas)、存盤在由 DeltaFIFO 實作的本地快取(local Store) 中,包括 queue(僅存 objKeys) 和 items(存 objKeys 和對應的 Deltas 增量變化),并通過 Pop 不斷消費,通過 Process(item) 處理相關邏輯,

(K8s-DeltaFIFO)

索引 Indexer

上一步 ListAndWatch 到的資源已經存盤到 DeltaFIFO 中,接著呼叫 Pop 從佇列進行消費,實際使用中,Process 處理函式由 sharedIndexInformer.HandleDeltas 進行實作,HandleDeltas 函式根據上面不同的 DeltaType 分別進行 Add/Update/Delete,并同時創建、更新、洗掉對應的索引,

具體索引實作如下:

// staging/src/k8s.io/client-go/tools/cache/index.go
// map 索引型別 => 索引函式
type Indexers map[string]IndexFunc

// map 索引型別 => 索引值 map
type Indices map[string]Index

// 索引值 map: 由索引函式計算所得索引值(indexedValue) => [objKey1, objKey2...]
type Index map[string]sets.String

索引函式(IndexFunc):就是計算索引的函式,這樣允許擴展多種不同的索引計算函式,默認也是最常用的索引函式是:MetaNamespaceIndexFunc

索引值(indexedValue):有些地方叫 indexKey,表示由索引函式(IndexFunc) 計算出來的索引值(如 ns1),

物件鍵(objKey):物件 obj 的 唯一 key(如 ns1/pod1),與某個資源物件一一對應,

(K8s-indexer)

可以看到,Indexer 由 ThreadSafeStore 介面集成,最終由 threadSafeMap 實作,

索引函式 IndexFunc(如 MetaNamespaceIndexFunc)、KeyFunc(如 MetaNamespaceKeyFunc) 區別:前者表示如何計算索引,后者表示如何獲取物件鍵(objKey); 索引鍵(indexKey,有些地方是 indexedValue)、物件鍵(objKey) 區別:前者表示由索引函式(IndexFunc) 計算出來的索引鍵(如 ns1),后者則是 obj 的 唯一 key(如 ns1/pod1);

總管家 Controller

Controller 作為核心中樞,集成了上面的組件 Reflector、DeltaFIFO、Indexer、Store,成為連接下游消費者的橋梁,

Controller 由 controller 結構體進行具體實作:

在 K8s 中約定俗成:大寫定義的 interface 介面,由對應小寫定義的結構體進行實作,

// staging/src/k8s.io/client-go/tools/cache/controller.go
type controller struct {
	config         Config
	reflector      *Reflector // 上面已分析的組件
	reflectorMutex sync.RWMutex
	clock          clock.Clock
}

type Config struct {
	// 實際由 DeltaFIFO 實作
	Queue

	// 構造 Reflector 需要
	ListerWatcher

	// Pop 出來的 obj 處理函式
	Process ProcessFunc

	// 目標物件型別
	ObjectType runtime.Object

	// 全量重新同步周期
	FullResyncPeriod time.Duration

	// 是否進行重新同步的判斷函式
	ShouldResync ShouldResyncFunc

	// 如果為 true,Process() 函式回傳 err,則再次入隊 re-queue
	RetryOnError bool

	// Watch 回傳 err 的回呼函式
	WatchErrorHandler WatchErrorHandler

	// Watch 分頁大小
	WatchListPageSize int64
}

Controller 中以 goroutine 協程方式啟動 Run 方法,會啟動 Reflector 的 ListAndWatch(),用于從 apiserver 拉取全量和監聽增量資源,存盤到 DeltaFIFO,接著,啟動 processLoop 不斷從 DeltaFIFO Pop 進行消費,在 sharedIndexInformer 中 Pop 出來進行處理的函式是 HandleDeltas,一方面維護 Indexer 的 Add/Update/Delete,另一方面呼叫下游 sharedProcessor 進行 handler 處理,

啟動 SharedInformer

SharedInformer 介面由 SharedIndexInformer 進行集成,由 sharedIndexInformer(這里看到了吧,又是大寫定義的 interface 介面,由對應小寫定義的結構體進行實作) 進行實作,

看一下結構體定義:

// staging/src/k8s.io/client-go/tools/cache/shared_informer.go
type SharedIndexInformer interface {
	SharedInformer
	// AddIndexers add indexers to the informer before it starts.
	AddIndexers(indexers Indexers) error
	GetIndexer() Indexer
}

type sharedIndexInformer struct {
	indexer    Indexer
	controller Controller

	// 處理函式,將是重點
	processor *sharedProcessor

	// 檢測 cache 是否有變化,一把用作除錯,默認是關閉的
	cacheMutationDetector MutationDetector

	// 構造 Reflector 需要
	listerWatcher ListerWatcher

	// 目標型別,給 Reflector 判斷資源型別
	objectType runtime.Object

	// Reflector 進行重新同步周期
	resyncCheckPeriod time.Duration

	// 如果使用者沒有添加 Resync 時間,則使用這個默認的重新同步周期
	defaultEventHandlerResyncPeriod time.Duration
	clock                           clock.Clock

	// 兩個 bool 表達了三個狀態:controller 啟動前、已啟動、已停止
	started, stopped bool
	startedLock      sync.Mutex

	// 當 Pop 正在消費佇列,此時新增的 listener 需要加鎖,防止消費混亂
	blockDeltas sync.Mutex

	// Watch 回傳 err 的回呼函式
	watchErrorHandler WatchErrorHandler
}

type sharedProcessor struct {
	listenersStarted bool
	listenersLock    sync.RWMutex
	listeners        []*processorListener
	syncingListeners []*processorListener // 需要 sync 的 listeners
	clock            clock.Clock
	wg               wait.Group
}

從結構體定義可以看到,通過集成的 controller(上面已分析) 進行 Reflector ListAndWatch,并存盤到 DeltaFIFO,并啟動 Pop 消費佇列,在 sharedIndexInformer 中 Pop 出來進行處理的函式是 HandleDeltas,

所有的 listeners 通過 sharedIndexInformer.AddEventHandler 加入到 processorListener 陣列切片中,并通過判斷當前 controller 是否已啟動做不同處理如下:

// staging/src/k8s.io/client-go/tools/cache/shared_informer.go
func (s *sharedIndexInformer) AddEventHandlerWithResyncPeriod(handler ResourceEventHandler, resyncPeriod time.Duration) {
	...

	// 如果還沒有啟動,則直接 addListener 加入即可回傳
	if !s.started {
		s.processor.addListener(listener)
		return
	}

	// 加鎖控制
	s.blockDeltas.Lock()
	defer s.blockDeltas.Unlock()

	s.processor.addListener(listener)
	
	// 遍歷所有物件,發送到剛剛新加入的 listener
	for _, item := range s.indexer.List() {
		listener.add(addNotification{newObj: item})
	}
}

接著,在 HandleDeltas 中,根據 obj 的 Delta 型別(Added/Updated/Deleted/Replaced/Sync) 呼叫 sharedProcessor.distribute 給所有監聽 listeners 處理,

注冊 SharedInformerFactory

SharedInformerFactory 作為使用 SharedInformer 的工廠類,提供了高內聚低耦合的工廠類設計模式,其結構體定義如下:

// staging/src/k8s.io/client-go/informers/factory.go
type SharedInformerFactory interface {
	internalinterfaces.SharedInformerFactory // 重點內部介面
	ForResource(resource schema.GroupVersionResource) (GenericInformer, error)
	WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool

	Admissionregistration() admissionregistration.Interface
	Internal() apiserverinternal.Interface
	Apps() apps.Interface
	Autoscaling() autoscaling.Interface
	Batch() batch.Interface
	Certificates() certificates.Interface
	Coordination() coordination.Interface
	Core() core.Interface
	Discovery() discovery.Interface
	Events() events.Interface
	Extensions() extensions.Interface
	Flowcontrol() flowcontrol.Interface
	Networking() networking.Interface
	Node() node.Interface
	Policy() policy.Interface
	Rbac() rbac.Interface
	Scheduling() scheduling.Interface
	Storage() storage.Interface
}

// staging/src/k8s.io/client-go/informers/internalinterfaces/factory_interfaces.go
type SharedInformerFactory interface {
	Start(stopCh <-chan struct{}) // 啟動 SharedIndexInformer.Run
	InformerFor(obj runtime.Object, newFunc NewInformerFunc) cache.SharedIndexInformer // 目標型別初始化
}

以 PodInformer 為例,說明使用者如何構建自己的 Informer,PodInformer 定義如下:

// staging/src/k8s.io/client-go/informers/core/v1/pod.go
type PodInformer interface {
	Informer() cache.SharedIndexInformer
	Lister() v1.PodLister
}

由小寫的 podInformer 實作(又看到了吧,大寫介面小寫實作的 K8s 風格):

type podInformer struct {
	factory          internalinterfaces.SharedInformerFactory
	tweakListOptions internalinterfaces.TweakListOptionsFunc
	namespace        string
}

func (f *podInformer) defaultInformer(client kubernetes.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
	return NewFilteredPodInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
}

func (f *podInformer) Informer() cache.SharedIndexInformer {
	return f.factory.InformerFor(&corev1.Pod{}, f.defaultInformer)
}

func (f *podInformer) Lister() v1.PodLister {
	return v1.NewPodLister(f.Informer().GetIndexer())
}

由使用者傳入目標型別(&corev1.Pod{})、建構式(defaultInformer),呼叫 SharedInformerFactory.InformerFor 實作目標 Informer 的注冊,然后呼叫 SharedInformerFactory.Start 進行 Run,就啟動了上面分析的 SharedIndexedInformer -> Controller -> Reflector -> DeltaFIFO 流程,

通過使用者自己傳入目標型別、建構式進行 Informer 注冊,實作了 SharedInformerFactory 高內聚低耦合的設計模式,

回呼 processorListener

所有的 listerners 由 processorListener 實作,分為兩組:listeners, syncingListeners,分別遍歷所屬組全部 listeners,將資料投遞到 processorListener 進行處理,

因為各 listeners 設定的 resyncPeriod 可能不一致,所以將沒有設定(resyncPeriod = 0) 的歸為 listeners 組,將設定了 resyncPeriod 的歸到 syncingListeners 組; 如果某個 listener 在多個地方(sharedIndexInformer.resyncCheckPeriod, sharedIndexInformer.AddEventHandlerWithResyncPeriod)都設定了 resyncPeriod,則取最小值 minimumResyncPeriod;

// staging/src/k8s.io/client-go/tools/cache/shared_informer.go
func (p *sharedProcessor) distribute(obj interface{}, sync bool) {
	p.listenersLock.RLock()
	defer p.listenersLock.RUnlock()

	if sync {
		for _, listener := range p.syncingListeners {
			listener.add(obj)
		}
	} else {
		for _, listener := range p.listeners {
			listener.add(obj)
		}
	}
}

從代碼可以看到 processorListener 巧妙地使用了兩個 channel(addCh, nextCh) 和一個 pendingNotifications(由 slice 實作的滾動 Ring) 進行 buffer 緩沖,默認的 initialBufferSize = 1024,既做到了高效傳遞資料,又不阻塞上下游處理,值得學習,

(K8s-processorListener)

workqueue 忙起來

通過上一步 processorListener 回呼函式,交給內部 ResourceEventHandler 進行真正的增刪改(CUD) 處理,分別呼叫 OnAdd/OnUpdate/OnDelete 注冊函式進行處理,

為了快速處理而不阻塞 processorListener 回呼函式,一般使用 workqueue 進行異步化解耦合處理,其實作如下:

(K8s-workqueue)

從圖中可以看到,workqueue.RateLimitingInterface 集成了 DelayingInterface,DelayingInterface 集成了 Interface,最終由 rateLimitingType 進行實作,提供了 rateLimit 限速、delay 延時入隊(由優先級佇列通過小頂堆實作)、queue 佇列處理 三大核心能力,

另外,在代碼中可看到 K8s 實作了三種 RateLimiter:BucketRateLimiter, ItemExponentialFailureRateLimiter, ItemFastSlowRateLimiter,Controller 默認采用了前兩種如下:

// staging/src/k8s.io/client-go/util/workqueue/default_rate_limiters.go
func DefaultControllerRateLimiter() RateLimiter {
	return NewMaxOfRateLimiter(
		NewItemExponentialFailureRateLimiter(5*time.Millisecond, 1000*time.Second),
		// 10 qps, 100 bucket size.  This is only for retry speed and its only the overall factor (not per item)
		&BucketRateLimiter{Limiter: rate.NewLimiter(rate.Limit(10), 100)},
	)
}

這樣,在用戶側可以通過呼叫 workqueue 相關方法進行靈活的佇列處理,比如失敗多少次就不再重試,失敗了延時入隊的時間控制,佇列的限速控制(QPS)等,實作非阻塞異步化邏輯處理,

小結

本文通過分析 K8s 中 Reflector(反射器)、DeletaFIFO(增量佇列)、Indexer(索引器)、Controller(控制器)、SharedInformer(共享資源通知器)、processorListener(事件監聽處理器)、workqueue(事件處理作業佇列) 等組件,對 Informer 實作機制進行了決議,通過原始碼、圖文方式說明了相關流程處理,以期更好的理解 K8s Informer 運行流程,

可以看到,K8s 為了實作高效、非阻塞的核心流程,大量采用了 goroutine 協程、channel 通道、queue 佇列、index 索引、map 去重等方式;并通過良好的介面設計模式,給使用者開放了很多擴展能力;采用了統一的介面與實作的命名方式等,這些都值得深入學習與借鑒,

PS: 更多內容請關注
k8s-club GitHub地址:https://github.com/k8s-club/k8s-club

參考資料

[1] Kubernetes 官方檔案:【https://kubernetes.io/】

[2] Kubernetes 原始碼:【https://github.com/kubernetes/kubernetes】

[3] Kubernetes Architectural Roadmap:【https://github.com/kubernetes/community/blob/master/contributors/design-proposals/architecture/architectural-roadmap.md】

關于我們

更多關于云原生的案例和知識,可關注同名【騰訊云原生】公眾號~

福利:公眾號后臺回復【手冊】,可獲得《騰訊云原生路線圖手冊》&《騰訊云原生最佳實踐》~

【騰訊云原生】云說新品、云研新術、云游新活、云賞資訊,掃碼關注同名公眾號,及時獲取更多干貨!!

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/300165.html

標籤:其他

上一篇:閱讀《啊哈C語言!邏輯的挑戰(修訂版)》

下一篇:機器學習自學的四個重要階段,你在第幾個?

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more