Postgresql源码(101)深入分析clog组提交(clog group updates)

news2024/11/17 15:33:02

1 背景知识

1.1 CLOG使用的全局变量XactLastRecEnd

XLogRecPtr	ProcLastRecPtr = InvalidXLogRecPtr;
XLogRecPtr	XactLastRecEnd = InvalidXLogRecPtr;
XLogRecPtr	XactLastCommitEnd = InvalidXLogRecPtr;

其中ProcLastRecPtr、XactLastRecEnd更新位置XLogInsertRecord:

XLogInsertRecord()
  ...
  ...
  /*
	 * Update our global variables
	 */
	ProcLastRecPtr = StartPos;
	XactLastRecEnd = EndPos;
  • XactLastRecEnd表示,当前事务所有xlog的最后一个位置。

    • 在顶层事务提交、回滚时更新。
    • 可以从XactLastRecEnd知道当前事务有没有生成xlog。
  • ProcLastRecPtr表示,当前事务插入的最后一个xlog的 起始位置。

1.2 CLOG中的group_lsn

Postgresql中的XLOG和CLOG是分开保存的,所以存在先写后写的问题。

  • 场景一:XLOG落盘,CLOG没落盘
    • 没问题,XLOG中有commit log,在redo中会重建clog。
  • 场景二:XLOG没落盘,CLOG落盘
    • 有问题:事务在clog中查询到已提交,但XLOG丢失redo无法恢复该事物,所以该事物应该是未提交状态,与CLOG矛盾——发生数据不一致。

在同步提交场景下:可以保证XLOG一定先与CLOG落盘。
在异步提交场景下:从下图中可以看到,没有XlogFlush的过程,所以可能发生上述场景二的问题。

所以在异步移交场景下,Postgresql做了另外一层保护,使用group_lsn来保证xlog先与clog落盘,

/* We store the latest async LSN for each group of transactions */
#define CLOG_XACTS_PER_LSN_GROUP	32	/* keep this a power of 2 */
#define CLOG_LSNS_PER_PAGE	(CLOG_XACTS_PER_PAGE / CLOG_XACTS_PER_LSN_GROUP)

每个逻辑组保存32个事务状态,每个页面有CLOG_LSNS_PER_PAGE个组。

在这里插入图片描述

1.3 全局唯一的PROC HDR结构

其中CLOG组提交会使用到的是clogGroupFirst,记录int类型,指向procs中,第一个等待组提交的那个proc(组提交leader)。

typedef struct PROC_HDR
{
	/* Array of PGPROC structures (not including dummies for prepared txns) */
	PGPROC	   *allProcs;

	/* Array mirroring PGPROC.xid for each PGPROC currently in the procarray */
	TransactionId *xids;

	/*
	 * Array mirroring PGPROC.subxidStatus for each PGPROC currently in the
	 * procarray.
	 */
	XidCacheStatus *subxidStates;
    ...
    ...
	/* First pgproc waiting for group XID clear */
	pg_atomic_uint32 procArrayGroupFirst;
	/* First pgproc waiting for group transaction status update */
	pg_atomic_uint32 clogGroupFirst;    <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
	...
	...
} PROC_HDR;

1.4 每个进程的PROC结构

  • clogGroupMember:布尔,当前proc是不是在使用组提交?
  • clogGroupNext:原子int,指向下一个组成员proc(allprocs数组中的位置)
  • clogGroupMemberXid:当前要提交的xid
  • clogGroupMemberXidStatus:当前要提交xid的状态
  • clogGroupMemberPage:当前要提交xid属于哪个page
  • clogGroupMemberLsn:当前要提交的xid的commit日志的lsn号(异步提交会有、同步提交没有)
struct PGPROC
{
	...
	...

	TransactionId xid;			/* id of top-level transaction currently being
								 * executed by this proc, if running and XID
								 * is assigned; else InvalidTransactionId.
								 * mirrored in ProcGlobal->xids[pgxactoff] */

	TransactionId xmin;			/* minimal running XID as it was when we were
								 * starting our xact, excluding LAZY VACUUM:
								 * vacuum must not remove tuples deleted by
								 * xid >= xmin ! */

	LocalTransactionId lxid;	/* local id of top-level transaction currently
								 * being executed by this proc, if running;
								 * else InvalidLocalTransactionId */
	int			pid;			/* Backend's process ID; 0 if prepared xact */

	int			pgxactoff;		/* offset into various ProcGlobal->arrays with
								 * data mirrored from this PGPROC */

	int			pgprocno;		/* Number of this PGPROC in
								 * ProcGlobal->allProcs array. This is set
								 * once by InitProcGlobal().
								 * ProcGlobal->allProcs[n].pgprocno == n */

	...
	...
	/* Support for group transaction status update. */
	bool                clogGroupMember;          /* true, if member of clog group */
	pg_atomic_uint32    clogGroupNext;            /* next clog group member */
	TransactionId       clogGroupMemberXid;       /* transaction id of clog group member */
	XidStatus           clogGroupMemberXidStatus; /* transaction status of clog
	                                               * group member */
	int                 clogGroupMemberPage;      /* clog page corresponding to
                                                   * transaction id of clog group member */
	XLogRecPtr          clogGroupMemberLsn;       /* WAL location of commit record for clog
	                                               * group member */
    ...
    ...
};

1.5 提交时CLOG写入流程

在这里插入图片描述

2 事务提交RecordTransactionCommit

RecordTransactionCommit

  1. 判断当前提交XID是否有效if (!markXidCommitted)
  2. 全局XactLastRecEnd判断当前事务是否有写入,wrote_xlog = (XactLastRecEnd != 0)
  3. 如果XID有效,写入一条commit的xlog,XactLogCommitRecord,注意全局wrote_xlog是在上面记录的,不受这里影响。
  4. 记录提交时间TransactionTreeSetCommitTsData
  5. 如果
    1. 事务写了xlog
    2. xid有效
    3. synchronous_commit不是off
  6. 如果上述三个条件满足:同步提交
    1. XLogFlush(XactLastRecEnd)
    2. TransactionIdCommitTree(xid, nchildren, children)
  7. 如果上述三个条件不满足:异步提交
    1. XLogSetAsyncXactLSN(XactLastRecEnd)
    2. TransactionIdAsyncCommitTree(xid, nchildren, children, XactLastRecEnd)

同步提交和异步提交的区别就是是否传入XactLastRecEnd,XactLastRecEnd记录了当前事务(包含最后一条commit)产生的所有xlog的最后一条的最后一个位点。注意这个是进程私有变量。

3 CLOG写入TransactionIdSetPageStatus

老版本PG的CLOG写入流程比较简单,可以总结为下面三步:

  1. 拿大锁:LWLockAcquire(CLogControlLock, LW_EXCLUSIVE)
  2. 写入:TransactionIdSetStatusBit; ClogCtl->shared->page_dirty[slotno] = true;
  3. 放锁:LWLockRelease(CLogControlLock)

新版本PG对CLogControlLock有了较大优化,主要是XactSLRULock锁优化(新版本XactSLRULock == 老版本CLogControlLock )(baaf272ac908ea27c09076e34f62c45fa7d1e448)

优化思路主要参考了procArray在高并发场景下使用单个进程来清理xid,避免ProcArrayLock的争抢。
(0e141c0fbb211bdd23783afa731e3eef95c9ad7a)

在这里插入图片描述

下面分析TransactionIdSetPageStatus的新流程

static void
TransactionIdSetPageStatus(TransactionId xid, int nsubxids,
						   TransactionId *subxids, XidStatus status,
						   XLogRecPtr lsn, int pageno,
						   bool all_xact_same_page)
{
	/* Can't use group update when PGPROC overflows. */
	StaticAssertDecl(THRESHOLD_SUBTRANS_CLOG_OPT <= PGPROC_MAX_CACHED_SUBXIDS,
					 "group clog threshold less than PGPROC cached subxids");

	/*
	 * When there is contention on XactSLRULock, we try to group multiple
	 * updates; a single leader process will perform transaction status
	 * updates for multiple backends so that the number of times XactSLRULock
	 * needs to be acquired is reduced.
	 *
	 * For this optimization to be safe, the XID and subxids in MyProc must be
	 * the same as the ones for which we're setting the status.  Check that
	 * this is the case.
	 *
	 * For this optimization to be efficient, we shouldn't have too many
	 * sub-XIDs and all of the XIDs for which we're adjusting clog should be
	 * on the same page.  Check those conditions, too.
	 */
	if (all_xact_same_page && xid == MyProc->xid &&
		nsubxids <= THRESHOLD_SUBTRANS_CLOG_OPT &&
		nsubxids == MyProc->subxidStatus.count &&
		(nsubxids == 0 ||
		 memcmp(subxids, MyProc->subxids.xids,
				nsubxids * sizeof(TransactionId)) == 0))

需要满足

  1. CLOG必须都在一个页面上。(有时提交xid需要一块提交多个subxid,所以可能分布在多个页面上)
  2. 为了性能考虑,子事务数要少于5个。
	{
		/*
		 * If we can immediately acquire XactSLRULock, we update the status of
		 * our own XID and release the lock.  If not, try use group XID
		 * update.  If that doesn't work out, fall back to waiting for the
		 * lock to perform an update for this transaction only.
		 */
		if (LWLockConditionalAcquire(XactSLRULock, LW_EXCLUSIVE))
		{
			/* Got the lock without waiting!  Do the update. */
			TransactionIdSetPageStatusInternal(xid, nsubxids, subxids, status,
											   lsn, pageno);
			LWLockRelease(XactSLRULock);
			return;
		}
		else if (TransactionGroupUpdateXidStatus(xid, status, lsn, pageno))
		{
			/* Group update mechanism has done the work. */
			return;
		}

		/* Fall through only if update isn't done yet. */
	}

	/* Group update not applicable, or couldn't accept this page number. */
	LWLockAcquire(XactSLRULock, LW_EXCLUSIVE);
	TransactionIdSetPageStatusInternal(xid, nsubxids, subxids, status,
									   lsn, pageno);
	LWLockRelease(XactSLRULock);
}

满足组提交条件后,所有拿不到锁的PROC都会进入TransactionGroupUpdateXidStatus。

由TransactionGroupUpdateXidStatus选一个最先进来的当leader,负责后续提交。

4 组提交TransactionGroupUpdateXidStatus

4.1 整体

static bool
TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
								XLogRecPtr lsn, int pageno)
{
	volatile PROC_HDR *procglobal = ProcGlobal;
	PGPROC	   *proc = MyProc;
	uint32		nextidx;
	uint32		wakeidx;

	/* We should definitely have an XID whose status needs to be updated. */
	Assert(TransactionIdIsValid(xid));

	/*
	 * Add ourselves to the list of processes needing a group XID status
	 * update.
	 */
	proc->clogGroupMember = true;
	proc->clogGroupMemberXid = xid;
	proc->clogGroupMemberXidStatus = status;
	proc->clogGroupMemberPage = pageno;
	proc->clogGroupMemberLsn = lsn;

	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);

	while (true)
	{
		// 不在同一个页面不交给leader去做。
		// 可能判断完了又不在页面了,但逻辑没问题,性能可能会差。
		if (nextidx != INVALID_PGPROCNO &&
			ProcGlobal->allProcs[nextidx].clogGroupMemberPage != proc->clogGroupMemberPage)
		{
			/*
			 * Ensure that this proc is not a member of any clog group that
			 * needs an XID status update.
			 */
			proc->clogGroupMember = false;
			pg_atomic_write_u32(&proc->clogGroupNext, INVALID_PGPROCNO);
			return false;
		}

		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);

		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
										   &nextidx,
										   (uint32) proc->pgprocno))
			break;
	}

	/*
	 * If the list was not empty, the leader will update the status of our
	 * XID. It is impossible to have followers without a leader because the
	 * first process that has added itself to the list will always have
	 * nextidx as INVALID_PGPROCNO.
	 */
	if (nextidx != INVALID_PGPROCNO)
	{
		int			extraWaits = 0;

		/* Sleep until the leader updates our XID status. */
		pgstat_report_wait_start(WAIT_EVENT_XACT_GROUP_UPDATE);
		for (;;)
		{
			/* acts as a read barrier */
			PGSemaphoreLock(proc->sem);
			if (!proc->clogGroupMember)
				break;
			extraWaits++;
		}
		pgstat_report_wait_end();

		Assert(pg_atomic_read_u32(&proc->clogGroupNext) == INVALID_PGPROCNO);

		/* Fix semaphore count for any absorbed wakeups */
		while (extraWaits-- > 0)
			PGSemaphoreUnlock(proc->sem);
		return true;
	}

	/* We are the leader.  Acquire the lock on behalf of everyone. */
	LWLockAcquire(XactSLRULock, LW_EXCLUSIVE);

	/*
	 * Now that we've got the lock, clear the list of processes waiting for
	 * group XID status update, saving a pointer to the head of the list.
	 * Trying to pop elements one at a time could lead to an ABA problem.
	 */
	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
									 INVALID_PGPROCNO);

	/* Remember head of list so we can perform wakeups after dropping lock. */
	wakeidx = nextidx;

	/* Walk the list and update the status of all XIDs. */
	while (nextidx != INVALID_PGPROCNO)
	{
		PGPROC	   *nextproc = &ProcGlobal->allProcs[nextidx];

		/*
		 * Transactions with more than THRESHOLD_SUBTRANS_CLOG_OPT sub-XIDs
		 * should not use group XID status update mechanism.
		 */
		Assert(nextproc->subxidStatus.count <= THRESHOLD_SUBTRANS_CLOG_OPT);

		TransactionIdSetPageStatusInternal(nextproc->clogGroupMemberXid,
										   nextproc->subxidStatus.count,
										   nextproc->subxids.xids,
										   nextproc->clogGroupMemberXidStatus,
										   nextproc->clogGroupMemberLsn,
										   nextproc->clogGroupMemberPage);

		/* Move to next proc in list. */
		nextidx = pg_atomic_read_u32(&nextproc->clogGroupNext);
	}

	/* We're done with the lock now. */
	LWLockRelease(XactSLRULock);

	/*
	 * Now that we've released the lock, go back and wake everybody up.  We
	 * don't do this under the lock so as to keep lock hold times to a
	 * minimum.
	 */
	while (wakeidx != INVALID_PGPROCNO)
	{
		PGPROC	   *wakeproc = &ProcGlobal->allProcs[wakeidx];

		wakeidx = pg_atomic_read_u32(&wakeproc->clogGroupNext);
		pg_atomic_write_u32(&wakeproc->clogGroupNext, INVALID_PGPROCNO);

		/* ensure all previous writes are visible before follower continues. */
		pg_write_barrier();

		wakeproc->clogGroupMember = false;

		if (wakeproc != MyProc)
			PGSemaphoreUnlock(wakeproc->sem);
	}

	return true;
}

4.2 选主逻辑与链表构造

使用pg_atomic_compare_exchange_u32函数构造链表:

    uint32		nextidx;

    nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
	while (true)
	{
		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
										   &nextidx,
										   (uint32) proc->pgprocno))
			break;
	}

pg_atomic_compare_exchange_u32逻辑:

  • nextidx一定会更新为procglobal->clogGroupFirst
  • procglobal->clogGroupFirst会视情况更新为proc->pgprocno(1、2参相等则更新)
  • 如果发生更新了,pg_atomic_compare_exchange_u32为真退出循环。

实例:

进程全局指针:procglobal->clogGroupFirstnextidx链表指针:proc->clogGroupNext
第一个进入的进程1997(☆)proc->pgprocno = 1997invalidinvalid
第二个进入的进程2001(△)proc->pgprocno = 200119971997
第三个进入的进程1998(▢)proc->pgprocno = 199820012001

在这里插入图片描述
总结:

  • nextidx都会通过全局clogGroupFirst指向链表头,记录clogGroupFirst的旧值。用于更新clogGroupNext,形成链表。
  • clogGroupFirst会更新为当前进程的procno。

4.3 非leader

nextidx有值说明他不在链表第一位,非leader。

  • 等leader唤醒:proc->sem。
  • 其他什么都不需要做。
	if (nextidx != INVALID_PGPROCNO)
	{
		int			extraWaits = 0;

		/* Sleep until the leader updates our XID status. */
		pgstat_report_wait_start(WAIT_EVENT_XACT_GROUP_UPDATE);
		for (;;)
		{
			/* acts as a read barrier */
			PGSemaphoreLock(proc->sem);
			if (!proc->clogGroupMember)
				break;
			extraWaits++;
		}
		pgstat_report_wait_end();

		Assert(pg_atomic_read_u32(&proc->clogGroupNext) == INVALID_PGPROCNO);

		/* Fix semaphore count for any absorbed wakeups */
		while (extraWaits-- > 0)
			PGSemaphoreUnlock(proc->sem);
		return true;
	}

4.4 leader

  1. 拿XactSLRULock干活(Leader只能有一个,拿锁是为了避免和其他场景竞争,比如非组提交的场景 或是ExtendCLOG)。
  2. 拿着锁后,下一个进来的进程有两种结果:
    • 第一种:clogGroupFirst还没清:继续挂链表
    • 第二种:clogGroupFirst清理了:成为新的leader
	LWLockAcquire(XactSLRULock, LW_EXCLUSIVE);

这里进来的新进程会继续挂链表

	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
									 INVALID_PGPROCNO);

这里进来的进程会成为新的leader,注意新的链表不会覆盖旧的,因为链表是由每个进程的proc->clogGroupNext构成的,新链表和旧链表的Proc不可能重复。

	/* Remember head of list so we can perform wakeups after dropping lock. */
	wakeidx = nextidx;

开始干活,从链表最后一个位置做。

	while (nextidx != INVALID_PGPROCNO)
	{
		PGPROC	   *nextproc = &ProcGlobal->allProcs[nextidx];

		/*
		 * Transactions with more than THRESHOLD_SUBTRANS_CLOG_OPT sub-XIDs
		 * should not use group XID status update mechanism.
		 */
		Assert(nextproc->subxidStatus.count <= THRESHOLD_SUBTRANS_CLOG_OPT);

		TransactionIdSetPageStatusInternal(nextproc->clogGroupMemberXid,
										   nextproc->subxidStatus.count,
										   nextproc->subxids.xids,
										   nextproc->clogGroupMemberXidStatus,
										   nextproc->clogGroupMemberLsn,
										   nextproc->clogGroupMemberPage);

		/* Move to next proc in list. */
		nextidx = pg_atomic_read_u32(&nextproc->clogGroupNext);
	}

	/* We're done with the lock now. */
	LWLockRelease(XactSLRULock);

都做完了,唤醒等待的进程。

	while (wakeidx != INVALID_PGPROCNO)
	{
		PGPROC	   *wakeproc = &ProcGlobal->allProcs[wakeidx];

		wakeidx = pg_atomic_read_u32(&wakeproc->clogGroupNext);
		pg_atomic_write_u32(&wakeproc->clogGroupNext, INVALID_PGPROCNO);

		/* ensure all previous writes are visible before follower continues. */
		pg_write_barrier();

		wakeproc->clogGroupMember = false;

		if (wakeproc != MyProc)
			PGSemaphoreUnlock(wakeproc->sem);
	}

	return true;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/375741.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何在logback.xml中自定义动态属性

原文地址&#xff1a;http://blog.jboost.cn/trick-logback-prop.html 当使用logback来记录Web应用的日志时&#xff0c;我们通过在logback.xml中配置appender来指定日志输出格式及输出文件路径&#xff0c;这在一台主机或一个文件系统上部署单个实例没有问题&#xff0c;但是…

K8S静态存储与动态存储工作流

静态存储 Kubernetes 同样将操作系统和 Docker 的 Volume 概念延续了下来&#xff0c;并且对其进一步细化。Kubernetes 将 Volume 分为持久化的 PersistentVolume 和非持久化的普通 Volume 两类。为了不与前面定义的 Volume 这个概念产生混淆&#xff0c;后面特指 Kubernetes …

Type and Value

Type and Value前言一、reflect.Type1.1 数据结构1.2 方法1.2.1 所有类型通用方法1.2.2 不同基础类型的专有方法二、reflect.Value总结参考资料前言 reflect.Type和reflect.Value是go 反射的两大基本类型&#xff0c;一个管变量的类型方面&#xff0c;一个管变量的值方面。 一…

PTA L1-058 6翻了(详解)

前言&#xff1a;内容包括&#xff1a;题目&#xff0c;代码实现&#xff0c;大致思路&#xff0c;代码解读 题目&#xff1a; “666”是一种网络用语&#xff0c;大概是表示某人很厉害、我们很佩服的意思。最近又衍生出另一个数字“9”&#xff0c;意思是“6翻了”&#xff0…

vue源码分析-动态组件

前面花了两节的内容介绍了组件&#xff0c;从组件的原理讲到组件的应用&#xff0c;包括异步组件和函数式组件的实现和使用场景。众所周知&#xff0c;组件是贯穿整个Vue设计理念的东西&#xff0c;并且也是指导我们开发的核心思想&#xff0c;所以接下来的几篇文章&#xff0c…

LLaMA-META发布单卡就能跑的大模型

2023年2月25日&#xff0c;Meta使用2048张A100 GPU&#xff0c;花费21天训练的Transformer大模型LLaMA开源了。 1.4T tokenstakes approximately 21 days 以下是觉得论文中重要的一些要点 1&#xff09;相对较小的模型也可以获得不错的性能 研究者发现在给定计算能力限制的情…

【YOLO系列】YOLOv4论文超详细解读1(翻译 +学习笔记)

前言 经过上一期的开篇介绍&#xff0c;我们知道YOLO之父Redmon在twitter正式宣布退出cv界&#xff0c;大家都以为YOLO系列就此终结的时候&#xff0c;天空一声巨响&#xff0c;YOLOv4闪亮登场&#xff01;v4作者是AlexeyAB大神&#xff0c;虽然换人了&#xff0c;但论文中给出…

【BN层的作用】论文阅读 | How Does Batch Normalization Help Optimization?

前言&#xff1a;15年Google提出Batch Normalization&#xff0c;成为深度学习最成功的设计之一&#xff0c;18年MIT团队将原论文中提出的BN层的作用进行了一一反驳&#xff0c;重新揭示BN层的意义 2015年Google团队论文&#xff1a;【here】 2018年MIT团队论文&#xff1a;【h…

谷粒学苑第六天

谷粒学苑第六天 https://hyy-0212.oss-cn-hangzhou.aliyuncs.com/%E5%A4%B4%E5%83%8F.jpg AccessKey看私密文件 后端&#xff1a; idea导入项目后文件颜色不对解决方法 解决&#xff1a;https://blog.csdn.net/m0_37735176/article/details/88916844 后端 私有转为公有&am…

C语言——字符串函数与内存函数

目录 前言 一. 函数介绍 1.1 strlen 1.2 strcpy 1.3 strcat 1.4 strcmp 1.5 strncpy 1.6 strncat 1.7 strncmp 1.8 strstr 1.9 strtok 1.10 strerror 1.11 字符分类函数 1.12 memcpy 1.13 memmove 1.14 memcmp 二. 函数的模拟实现 2.1 模拟实现strlen 2.2 模拟实现st…

阿里测试员晒薪资条,看完真的扎心了...

前几天&#xff0c;有位老粉私信我&#xff0c;说看到某95后学弟晒出阿里的工资单&#xff0c;他是真酸了…想狠补下技术&#xff0c;努力冲一把大厂。 为了帮到他&#xff0c;也为了大家能在最短的时间内做面试复习&#xff0c;我把软件测试面试系列都汇总在这一篇文章了。 …

Windows10 把两张图片合并成一张图片

Windows10把两张图片合并成一张图片 文章目录Windows10把两张图片合并成一张图片1. 背景2. "画图"实现多图拼接1. 背景 相比截图功能&#xff0c;在 Google 的 Chrome 浏览器上&#xff0c;整页截屏功能仍需要安装额外的插件才能完成&#xff0c;这一点 微软的 bing…

【K3s】第18篇 详解 Kubernetes 调度器工作原理

目录 1、概述 2、kube-scheduler 3、kube-scheduler 调度流程 4、支持两种方式配置调度器的过滤和打分行为 4.1 调度策略 4.2 调度策略 5、总结 1、概述 在 Kubernetes 中&#xff0c;调度 是指将Pod放置到合适的节点上&#xff0c;以便对应节点上kubelet能够运行这些 P…

ChatGPT来临,架构师何去何从?

你好&#xff0c;我是李运华。 最近科技圈大火的事件就是ChatGPT的全球火热流行。这款由OpenAI公司在2022年11月底推出的聊天机器人&#xff0c;创造了史上消费应用最快达成1亿用户的历史&#xff0c;在推出仅仅两个月后&#xff0c;月活跃用户估计已达1亿&#xff0c;成为历史…

dbever连接kerberos认证的hive

文章目录一、本地安装kerberos客户端二、本地kerberos客户端登录三、dbever连接hive一、本地安装kerberos客户端 下载地址&#xff1a;https://web.mit.edu/kerberos/dist/index.html 安装&#xff1a;下一步或者自定义安装即可 安装后会自动生成配置文件&#xff1a;C:\Pro…

强化学习RL 01: Reinforcement Learning 基础

目录 RL理解要点 1. RL数学基础 1.1 Random Variable 随机变量 1.2 概率密度函数 Probability Density Function(PDF) 1.3 期望 Expectation 1.4 随机抽样 Random Sampling 2. RL术语 Terminologies 2.1 agent、state 和 action 2.2 策略 policy π 2.3 奖励 reward …

利用GPT-3 Fine-tunes训练专属语言模型

利用GPT-3 Fine-tunes训练专属语言模型 文章目录什么是模型微调&#xff08;fine-tuning&#xff09;&#xff1f;为什么需要模型微调&#xff1f;微调 vs 重新训练微调 vs 提示设计训练专属模型数据准备清洗数据构建模型微调模型评估模型部署模型总结什么是模型微调&#xff0…

cesium: 绘制线段(008)

第008个 点击查看专栏目录 本示例的目的是介绍如何在vue+cesium中绘制线段,左键点击开始绘制,右键点击取消绘制 直接复制下面的 vue+cesium源代码,操作2分钟即可运行实现效果. 文章目录 示例效果配置方式示例源代码(共139行)相关API参考:专栏目标示例效果 配置方式 1)…

Win11的两个实用技巧系列清理磁盘碎片、设置系统还原点的方法

Win11如何清理磁盘碎片?Win11清理磁盘碎片的方法磁盘碎片过多&#xff0c;会影响电脑的运行速度&#xff0c;所以需要定期清理&#xff0c;这篇文章将以Win11为例&#xff0c;给大家分享的整理磁盘碎片方法相信很多用户都会发现&#xff0c;随着电脑使用时间的增加&#xff0c…

一文了解 requestAnimationFrame

requestAnimationFrame 的基本使用 requestAnimationFrame 是什么 window.requestAnimationFrame() 告诉浏览器——你希望执行一个动画&#xff0c;并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数&#xff0c;该回调函数会在浏…