Open NicholasTao opened 2 years ago
Client收集节点组件部署、节点组件升级信息。上
Todo img sc交互、sc数据库
采用数据接口解耦数据(DataBase, Cps, Zookeeper...), 改善现有数据获取代码混乱的情况
通过升级前静态信息收集, 避免了升级中负责的状态变化、获取
1 概述 【关键内容】 新升级框架是全面替换旧升级框架,在保留对外提供升级服务(保留所有对外接口)的同时,新增了灵活可控操作,提升性能,简化SDK等优化。也为后续升级需求(N-X升级,多版本升级等)提供了扩展性,降低开发成本。 1.1 目的 本文档对升级框架的,数据模型(数据存储、数据接口),任务下发模型(instance级别细粒度),模块解耦等进行重新设计。明确主要数据结构和主要处理过程,作为今后的编码阶段的输入和编码人员、测试人员的指导。 1.2 范围 暂空缺 2 特性需求概述 基本特性: 与旧升级框架保持一致,云底座升级 新增特性: a) 灵活升级 a) 小工步独立回退升级:任意小工步升级失败后可以独立回退,并重试或添加规避代码后重试 b) 单工步调试:开发过程中可以单工步调试,且无需依赖前后工步。如单独调试升级配置转换 b) 并行升级 a) 工程一升级AB组件的同时,工程二可以并行升级无依赖的CD组件 c) 多版本升级 支持一个版本的组件升级到不同版本,如控制节点升级OS,计算节点不升级OS。控制节点升级到X版本Nova,计算节点升级到Y版本Nova d) N-X升级 支持N-X升级的升级框架支持 a) 提供管理面备区升级能力,管理组件随hostos在备区升级后重启生效;同时保留管理面重启单独组件升级方式 e) 并行化 编排、任务下发、任务上报接收、任务执行、查询进度都可以用独立进程执行,其中任务下发、任务上报接收、任务执行、查询进度各自可以用并发多进程 f) 大规模 可以支持10k节点升级,升级框架本身不再是性能瓶颈。提供相关性能分析接口,在开发过程中就能自动分析各升级组件和外部接口性能。 g) 可视化升级 升级前可以生成整个升级计划书,供用户和技术人员检视,并可以根据需要灵活修改。升级过程不再是盲盒 3 需求场景分析 3.1 特性需求来源与价值概述 【关键内容】 客户需求 不同的客户需要不同的灵活控制升级方案。 客户机群规模不断增大,需要支持更大规模更快速的升级框架 减少升级时的错误,出现错误要能自动规避或低成本回退再升级 内部优化 需要可读的升级策略 其余组件需要更简单的白盒的升级SDK 升级框架代码需要增加可读性和可维护性 升级框架需要低开发成本的功能可扩展性 描述该特性需求来源或背景,比如:XXX竞争对手分析、XXX客户需求、XXX内部优化等。描述该特性对用户带来什么具体价值,如果没有该特性,对客户或竞争力带来什么损失。 3.2 特性场景分析 【关键内容】 描述该特性的业务使用场景 内容包括: 1)场景触发条件及对象:什么角色/工具/接口等在什么具体情况下使用该特性,使用对象技能如何? 2)使用时间及频度 3)描述该特性主要有哪些场景、子场景及关键任务操作。 3.3 特性影响分析 当前研发版本保持对外接口不变。 未来可选的对外需求 cps\nova提供更高性能接口 各组件可选择使用更简单升级脚本 升级工具交互接口简化 描述该特性在整个系统中的位置及周边接口。其涉及的网元、部件或服务,及其依赖关系。描述该特性有哪些关键约束或特性冲突。 与其他需求及特性的交互分析: 平台差异性分析: 兼容性分析:
约束及限制:
3.4 业界实现方案分析 【关键内容】 该特性的在业界的实现机制,对比分析,优劣性对比 4 特性/功能实现原理 【关键内容】 设计需求来源于《系统需求分析说明书》,《架构设计说明书》,《系统设计说明书》 【参考信息】 可以参考《系统设计说明书》 4.1 总体方案
升级前通过编排器生成升级计划书(用结构语言详细描述了所有升级任务的顺序)。 升级时计划下发器会读取升级计划书,再按顺序分发给相应的计划执行器;计划执行器会按顺序调用对应的升级脚本。循环直到所有升级计划书内的任务完成。 a) 编排逻辑统一集中到升级前编排器中(使编排和执行不再耦合) b) 提取任务执行过程,开发与升级实际业务解耦的计划执行器(取代复杂不灵活的状态机) c) 框架采用统一数据平台,避免分散式的底层数据操作,提高数据使用效率 4.1.1 新旧框架比较
相同点: 新旧升级框架对外接口(自定义升级脚本,api)保持一致 升级流程保持一致(分发、检查、执行、生效、提交) 差异: a) 升级流程灵活性 旧框架: 升级流程是代码中固定的,包括大工步(分发、执行…)小工步(修改配置、开关…)。 新框架: 大小工步被包装成原子化脚本,可以单独执行,也可以调整顺序(通过调整升级任务书)。方便二次开发和测试。 b) 编排与执行 旧框架: 编排逻辑散步在各个业务逻辑中。编排逻辑黑盒且互相影响,不利于开发验证。 编排与执行逻辑写在一起造成耦合,无法单独测试开发 新框架: 编排逻辑统一提取到升级前。 编排与执行逻辑解耦。通过任务计划书解耦。 c) 任务执行处理 旧框架: 每个升级任务(分发、执行…)有单独的初始化、重试、回退、忽略、校验等逻辑。造成代码冗余,开发困难,容易出错。 新框架: 采用业务无关的任务执行器来统一处理初始化、重试、回退、忽略、校验等逻辑。增加开发效率,模块解耦。 d) 小工步 指操作开关、数据清理、数据迁移、配置转换等主流程以外的工步。 旧框架: 没有统一模块处理,小工步逻辑散布在主流程逻辑中。版本变更时容易引起错误。无法单独回退测试 新框架: 同样采用升级脚本来规范开发。使小工步可检视、可编排、可回退。 e) 数据接口 旧框架: 没有统一数据接口,升级和部署数据通过deepcopy互相传递。强耦合,可维护性差,易出错。 新框架: 采用统一数据接口,根据数据库范式精简数据,尽量使用静态数据。提升代码可靠性。
` HT = 8 WD = 8
class Game3(object): def init(self, px, py): self.px = px self.py = py
def main(self):
pass
class Board3(object): def init(self, b=None, p=None): if b is None: self.b = [2] * 9 self.p = 0 else: self.b = b self.p = p
# def nmove(self, m):
# if self.b[m] != 2:
# raise ValueError("already occupy: %s" % str(m))
# else:
# nb = [_ for _ in self.b]
# nb[m] = self.p
# return self.__class__(nb, 1 - self.p)
def move(self, m):
if self.b[m] != 2:
raise ValueError("already occupy: %s" % str(m))
else:
self.b[m] = self.p
self.p = 1 - self.p
def reverse(self, m):
if self.b[m] == 2:
raise ValueError("not occupy: %s" % str(m))
else:
self.b[m] = 2
self.p = 1 - self.p
def winner(self):
for x in [[0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 3, 6], [1, 4, 7], [2, 5, 8], [0, 4, 8], [2, 4, 6]]:
if self.b[x[0]] != 2 and self.b[x[0]] == self.b[x[1]] and self.b[x[0]] == self.b[x[2]]:
return self.b[x[0]]
if 2 not in self.b:
return 2
def hash(self):
h = self.b[0]
for x in self.b[1:]:
h = h * 3 + x
return h
def __repr__(self):
s = ""
for i in range(3):
for j in range(3):
if self.b[i * 3 + j] == 0:
s = s + "O "
elif self.b[i * 3 + j] == 1:
s = s + "X "
else:
# print("||", i, j, self.b[i*3+j], "||")
s = s + "_ "
s = s + "\n"
return s
# return "%s\n%s\n%s\n" % (self.b[:3], self.b[3:6], self.b[6:9])
def evaluation(b): if b.winner() is not None: if b.winner() == b.p: return 10 elif b.winner() == 1 - b.p: return -10 return 0
class GenMove(object): @staticmethod def gen_move(b): return [m for m in range(9) if b.b[m] == 2]
INF = 999999
class ABTree(object): board = Board3() count = 0 h2v = {}
def alphabeta(self, depth, beta):
self.count = self.count + 1
# print(33, self.board, self.board.winner())
if depth <= 0 or self.board.winner() is not None:
return evaluation(self.board)
alpha = -INF
for m in GenMove.gen_move(self.board):
self.board.move(m)
h = self.board.hash()
if h in self.h2v:
val = self.h2v[h]
else:
val = -self.alphabeta(depth - 1, -alpha)
if depth == 99:
print(333, self.board, val, 444)
self.h2v[h] = val
# val = -self.alphabeta(depth - 1, -alpha)
# print(self.board, val, alpha, beta)
self.board.reverse(m)
if val >= beta:
return val
if val > alpha:
alpha = val
return alpha
abt = ABTree()
abt.board.move(4) abt.board.move(0)
print(abt.board) ret = abt.alphabeta(99, INF) print(ret) print(abt.count)
`
去高电区 a. 循环所有电池 b. (电池范围R1内电量 + 中心电量) / 距离
开局直奔高分区, 点亮 根据平均每回合生成电池数
巡视高分区, 确定中点(地图)和半径()
顺路高分区
?. 攻防高分区 ?. 先攒电量, 最后发力 ?. 区域有优势, 后手 ?. 附近有人则先到一步等到期
背景
目标
新升级框架,满足未来5年内的
旧升级流程
现有问题
大规模性能
Client上报处理时间长
现状
以upg-server向Host1下发10个组件升级rpm命令为例,
问题分析
解决方案
升级相关数据提前(在升级前信息收集阶段)保存在upg-client端,upg-server仅需下发需要操作的template列表。节省了upg-server前处理计算量, 分布式到各节点计算;也方便通过命令行手动升级。
改为定期且仅上报变更参数:upg-client仅上报上一分钟有变更的task状态。对于已上报的成功\失败的task不再次上报
upg-server仅保存task状态,不进行任何其它操作。任务整体是否成功的判断,由另一线程(或进程)定期检查。
考虑到现网环境下upg-server较为稳定,必要的数据库zookeeper读写改为定时批量执行,平时已本地数据为主。异常情况下可由upg-client重新上报数据。
采用数据库范式设计数据库,减少冗余数据读写
Server查询时间长
现状
升级前端(HCCI\UPDATETOOL)在升级中会频繁调用查询接口。但一直以来大规模查询接口都比较慢,单次查询最多需要十分钟。
问题分析
解决方案
效果
升级框架前后需要兼容
问题现状
升级框架自升级时需要用到前一版本的升级框架,导致升级框架自升级困难。例如:
问题分析
升级框架当前是作为常驻服务部署的。如8.0.3新安装版本,尽管在很长一段时间内都不会有升级任务,upg-server, upg-client仍长期部署在环境中。8.0.3-8.1.0升级时,需要用8.0.3的升级框架对自身进行升级。这导致了:
解决方案
升级框架不再常驻在环境中,每次升级前,通过cps导入所需升级框架安装包,安装升级框架再开始升级。
效果
开发困难
升级粒度过大(重要)
底层数据结构不灵活,修改牵一发动全身。
问题现状
精细化升级需求,开发周期长,引入问题多
升级框架底层采用Service和Package作为基本单元处理
升级框架
依赖错误
牵一发而动全身,动静不分离
测试困难
无法单独调试错误点
现网定位时间长
代码可读性差
回退复杂
升级
背景介绍
旧升级流程
设计方案
总体设计
简略全局图和主要区别点
4+1视图
逻辑视图
简略模块划分
物理视图
新部署、未来分布式部署
运行视图
某个task流程的时序图
开发视图
重要,模块类关系
特性视图
主要特性
痛点解决
痛点解决图
逐点分析
模块详细设计
Task系统
模块图,以管理面升级为例
管理面升级Task流程
管理面升级前: 生成升级计划书
数据库中保存了所有task状态
upg-server API接收HCCI指令:
upg-server解析命令, 从升级计划书截取出当前:
upg-server task执行器下发升级命令给upg-client(host1-2), 以下发升级所有组件rpm命令为例(可以看见命令非常简单, 因为其余所需数据, 以保存在了client端)
upg-client执行接收到的命令, 安装相关rpm包
upg-client三个instance执行完成后,一次性上报结果
upg-server上报接收器收到upg-client的task执行结果后,定期将结果批量保存到数据库中 Plan B: upg-client直接写入数据库
upg-server task执行器定时监控数据库,当所有task执行完成后。继续下一步(下发启动第二批组件命令), 如果有失败(如上文keystone host1 fail)则中止执行。
如此循环直到所有task执行完成
缩小升级粒度至instance
数据整理
次要改动:升级框架重新部署,脚本易用性,统一数据接口,简化回退,简化upg-server数据处理,模块解耦
Server模块
Client模块