1.ES核心源码(二):创建索引和主节点
2.redis cluster 计ç®slotå¨åªä¸ªèç¹
3.游戏引擎随笔 0x20:UE5 Nanite 源码解析之渲染篇:BVH 与 Cluster 的 Culling
4.Redis集群架构剖析(4):槽位迁移,重新分配
ES核心源码(二):创建索引和主节点
在ElasticSearch系统中,写请求的流程引发了一个关键问题:主节点(master node)在数据写入过程中是否扮演了关键角色?让我们深入源码探讨这个话题,解答疑问。
首先,ElasticSearch的云播app源码核心在于如何高效地管理和存储数据。其主节点的职责之一是在索引创建和管理过程中提供协调服务。当用户发起创建索引的请求时,流程从接收HTTP请求开始,具体在`org.elasticsearch.ty4.Netty4HttpRequestHandler`中进行。随后,请求经过`RestController`处理,这个组件负责将请求检验和分发至相应的服务。
在分发请求过程中,关键在于请求对象的结构——它分为Action和Request。Action描述了请求的类型,如新建、删除等操作。在新建索引的请求中,系统通过URI匹配发现需要使用`TransportCreateIndexAction`来处理。这个Action继承自`TransportMasterNodeAction`,意味着其设计目标就是与主节点进行交互。
`TransportMasterNodeAction`的执行逻辑在于,它通过`transportService.sendRequest`方法向主节点发起请求。如果当前节点是主节点,该操作会直接在内部执行;若非主节点,简单缴费源码则通过网络请求主节点完成。
关于主节点如何通知其他节点这一问题,答案在于请求的分发机制。当请求到达主节点后,如果当前节点是主节点,它会通过一系列内部操作生成新的集群状态信息,并通过`org.elasticsearch.action.admin.indices.create.TransportCreateIndexAction#masterOperation`执行索引创建的逻辑。这个过程中,关键步骤是通过`clusterService.submitStateUpdateTask`将索引创建任务包装为集群状态更新任务,然后通过`MasterService#runTasks`方法向集群中的其他节点分发集群状态信息。
集群状态的分发通过`ZenDiscovery`服务完成,具体实现为`publish`方法。这个流程确保了主节点在集群中的协调作用,使得创建索引的操作能够有效地在集群范围内进行。
关于主节点如何验证索引创建的合法性,答案是通过自创建索引并随后删除的方式完成。这样,主节点确保了新索引符合集群的规则和需求。
总结起来,创建索引的请求首先通过Bulk请求的形式执行,先发起对主节点的请求。主节点验证索引创建请求后,内部生成新的集群状态信息,执行索引创建任务。主分片所在的saas建站 源码节点根据集群状态信息创建对应的索引,从而完成了索引的创建过程。整个流程中,主节点扮演了协调和验证的关键角色,确保了索引创建的正确性和集群的一致性。
redis cluster 计ç®slotå¨åªä¸ªèç¹
å设clusteræ5个nodeï¼é£ä¹client请æ±clusterå ¶å®æ¯éæºè¯·æ±äºä¸ä¸ªèç¹ï¼å设请æ±äºnode1ï¼è¯·æ±çkeyç»è¿ CRC( key ) % ä¼è®¡ç®åºè¿ä¸ªkeyè½å¨åªä¸ä¸ªslotä¸ï¼ç¶åä¼è·åsoltånodeçå ³ç³»ï¼è¿ä¸ªå ³ç³»ä¿åå¨clusterNodeè¿ä¸ªæ°æ®ç»æä¸ï¼å¦æè¿ä¸ªslotå¨å½ånodeä¸ï¼å°±æ§è¡å½ä»¤ï¼å¦åå°±è¿åä¸ä¸ªmovedä¿¡æ¯ï¼ä¸»è¦å æ¬slotåç®æ nodeä¿¡æ¯ï¼åç±clientéååé请æ±å°ç®æ nodeãè¿éå¨soltè¿ç§»çæ¶åï¼æä¸ä¸ªaskéå®åã大æ¦å°±æ¯è¿ä¸ªææå§ï¼æä¹ä¸æ¯å¾æ¸ æ¥ï¼ä½ åèåèå§
ç½é¡µé¾æ¥
游戏引擎随笔 0x:UE5 Nanite 源码解析之渲染篇:BVH 与 Cluster 的 Culling
在UE5 Nanite的渲染深度中,一个关键组件是其独特的剔除策略,特别是通过高效的BVH(Bounded Volume Hierarchy)和Cluster Culling技术。Nanite的目标在于智能地控制GPU资源,避免不必要的三角形绘制,确保每一点计算都被最大化利用。
首先,Nanite的渲染流程中,异步数据传输和GPU初始化完成后,进入CullRasterize阶段,其中的PersistentCulling pass至关重要。它分为两个步骤: BVH Node Culling 和 Cluster Culling,每个阶段都利用多线程并行处理,实现了GPU性能的极致发挥。
在Node Culling中,每个线程处理8个节点,通过Packed Node数据结构,确保数据的一致性和同步性。每组个线程间通过MPMC Job Queue协同工作,保证了负载均衡,避免了GPU资源的nodequery面板源码浪费。GroupNodeMask和NodeReadyMask等优化策略,确保了节点处理的高效性和准确性。
核心部分是TGS GroupNodeData,它接收并处理来自候选节点的Packed Node,进行实例数据、动态数据和BVH节点数据的整合。通过Frustum Culling,仅保留可见的节点,非叶节点的计数更新和候选Cluster的生成,都在这个过程中完成。
叶节点的Cluster Culling更为精细,通过计算Screen Rect,判断是否适合渲染。当遇到硬件光栅化需求时,Nanite会利用上一帧的LocalToClip矩阵进行HZB遮挡剔除,确保每个Cluster的可见性和正确性。
在硬件光栅化中,VisibleClusterOffset的计算和Cluster的有序写入,体现了UE5团队对性能的精心调教。而软光栅化则采取相反的存储策略,确保了渲染的高效执行。
尽管Nanite在百万面模型处理上展现出惊人的0.5ms速度,但它并非无懈可击,如不支持Forward Rendering。然而,sslo指标源码随着UE5技术的不断迭代,Nanite的潜力和优化空间将继续扩展,推动着游戏开发的创新边界。
总之,UE5 Nanite的渲染篇是技术与艺术的完美融合,通过深度剖析其渲染流程,我们不仅能领略到高效剔除策略的魅力,更能感受到Unreal团队在性能优化上的匠心独运。深入源码,解锁游戏引擎的内在魔力,让我们一起期待Nanite在未来的更多可能。
Redis集群架构剖析(4):槽位迁移,重新分配
在前一篇Redis集群架构剖析中,我们了解到集群如何处理来自redis-cli的指令,但都是在cluster槽位不变的情况下。那么,为什么槽位会发生变化呢?集群可能进行节点增删,在第二篇中我们得知,只有当所有节点都分配到槽位时,Redis cluster才会处于online状态。在开始之前,先思考以下问题:
集群在重新分配过程中,无需下线,且源节点和目标节点均可继续处理命令请求。下面我们将探讨Redis是如何实现这一过程的。
重新分配的操作是将指定给某个节点(源节点)的槽位重新分配给另一个节点(目标节点),同时相关槽位所属的键值对也会从源节点移动到目标节点。
例如,原本由、和组成的集群,现在加入一个新的节点。此时,原本分配给的槽位~中的~槽位将重新分配给节点。重新分配的动作在CLUSTER MEET这个节点时完成。
Redis cluster的重新分配操作由Redis的集群管理软件redis-trib负责执行,Redis提供进行重新分配所需的命令,redis-trib则通过向源节点和目标节点发送指令来进行重新分配的操作。
下面是一个槽位重新分配的流程图,需要注意的是其中的第三和第四步,先迁移value再迁移key,这在后面会有作用。
如果这个slot存储了多个键值对,会重复执行步骤4中的第二个指令和步骤5。
在迁移过程中,可能存在redis-cli发送请求来请求数据的情况。此时,可以联想到上一篇文章,如果请求到不是本节点的槽位,节点会告诉redis-cli应该去哪个节点找到对应的槽位。这个思路是否可以借鉴?其实,在设计分布式系统时,这个问题还是非常重要的。要么直接禁止访问,要么设计一个机制,让迁移和请求同时存在。显然,Redis选择了后者。
当客户端向源节点发送一个与数据库键有关的命令,且命令要处理的数据库键恰好属于正在被迁移的槽时:
下面是节点收到请求后是否要发送ASK的流程图
这个ASK和MOVED一样,也是返回Redirected到某个节点,如果需要看到ASK错误,需要用单机redis请求。
在细究ASK的实现细节之前,我们先看看cluster是用什么数据结构来记录哪些槽位在源节点,哪些正在迁移到目标节点。
在重新分配的实现过程中,我们知道最开始有两个动作,分别是目标节点准备导入槽,源节点准备将槽导出。这涉及到两个指令,分别对应两个数据结构。
clusterState结构的importing_slots_from数组记录了当前节点正在从其他节点导入的槽:
如果importing_slots_from[i]不为NULL,而是指向一个clusterNode结构,那么表示正在从这个clusterNode节点导入槽i。
例如,如果加入集群,将上的重新分配给,会执行CLUSTER SETSLOT IMPORTING 的节点ID。那么的importing_slots_from就会变成下图所示,也就是重新分配实现过程的第一步,的importing_slots_from[]会指向节点。
clusterState结构的migrating_slots_to数组记录了当前节点正在迁移至其他节点的槽:
如果migrating_slots_to[i]不为NULL,而是指向一个clusterNode结构,那么表示正在导入到这个clusterNode节点。
例如,继续上面的importing,到了重新分配实现过程的第二步,给发送指令CLUSTER SETSLOT MIGRATING 的节点ID,那么的migrating_slots_to会变成下图所示:
在前面了解到如果请求的命令对应的键不在源节点上,在迁移的目标节点上,源节点就会返回一个ASK错误。接到ASK错误的客户端就会根据错误提供的IP地址和端口号,转向正在导入槽的目标节点,然后首先会向目标节点发送一个ASKING命令,之后才会重新发送原本想要执行的命令。下面是一个简单的转向后,请求ASKING的示意图。
ASKING命令唯一要做的就是打开发送该命令的客户端的REDIS_ASKING标识,以下是这个命令实现的伪代码:
回想一下,之前槽位不存在请求节点的时候,节点会向客户端返回一个MOVED错误。但是,如果节点的clusterState.importing_slots_from[i]显示节点正在导入槽i,并且发送命令的客户端带有REDIS_ASKING标识,那么节点将执行这个关于槽i的命令一次,以下是流程图:
当客户端接收到ASK错误并转向到正在导入槽的节点时,客户端会先向节点发送一个ASKING命令,然后才重新发送想要执行的命令。这是因为如果客户端不发送ASKING命令,而直接发送想要执行的命令,客户端发送的命令将被节点拒绝执行,并返回MOVED错误。
例如,在上面的例子中,我们向节点请求槽,因为是在导入槽,所以如果我们没有发送一个ASKING的命令,会返回一个MOVED的错误,并转到,因为槽还分配在上。如果在请求之前,发送了ASKING命令,那么就会执行这个命令。
注意:REDIS_ASKING标识是一次性标识,当节点执行了一个带有REDIS_ASKING标识的客户端发送的命令之后,客户端的REDIS_ASKING标识就移除了。
ASK错误和MOVED错误都会导致客户端转向,它们之间的区别如下:
通过这篇文档,我们了解到节点在槽转移时,集群是如何处理重新分配的,数据结构又是如何存储的。这是针对数据的一种异常情况。还有一个是针对节点的异常,例如部署的redis节点挂掉了,原本存的槽即使知道导向这个节点,但这个节点也没有回复的能力了。那么,我们该怎么做呢?是否需要备份这个数据?似乎就是我挂了,你顶我。针对这个异常行为,我们下节分析。