高斯混合模型 GMM 的详细解释
因为KMeans的限制很多,比如: 它假设簇是球形的并且大小相同,这在大多数现实世界的场景中是无效的。并且它是硬聚类方法,这意味着每个数据点都分配给一个集群,这也是不现实的。在本文中,我们将根据上面的内容来介绍 KMeans 的一个替代方案之一,高斯混合模型。从概念上解释:高斯混合模型就是用高斯概率密度函数(正态分布曲线)精确地量化事物,它是一个将事物分解为若干的基于高斯概率密度函数(正态分布曲线)形成的模型。高斯混合模型 (GMM) 算法的工作原理正如前面提到的,可以将 GMM 称为 概率的KMeans,这是因为 KMeans 和 GMM 的起点和训练过程是相同的。 但是,KMeans 使用基于距离的方法,而 GMM 使用概率方法。 GMM 中有一个主要假设:数据集由多个高斯分布组成,换句话说,GMM 模型可以看作是由 K 个单高斯模型组合而成的模型,这 K 个子模型是混合模型的隐变量(Hidden variable)上述分布通常称为多模型分布。 每个峰代表我们数据集中不同的高斯分布或聚类。 我们肉眼可以看到这些分布,但是使用公式如何估计这些分布呢?在解释这个问题之前,我们先创建一些高斯分布。这里我们生成的是多元正态分布; 它是单变量正态分布的更高维扩展。让我们定义数据点的均值和协方差。 使用均值和协方差,我们可以生成如下分布。 # Set the mean and covariance
mean1= [0, 0]
mean2= [2, 0]
cov1= [[1, .7], [.7, 1]]
cov2= [[.5, .4], [.4, .5]]
# Generate data from the mean and covariance
data1=np.random.multivariate_normal(mean1, cov1, size=1000)
data2=np.random.multivariate_normal(mean2, cov2, size=1000)可视化一下生成的数据 plt.figure(figsize=(10,6))
plt.scatter(data1[:,0],data1[:,1])
plt.scatter(data2[:,0],data2[:,1])
sns.kdeplot(data1[:, 0], data1[:, 1], levels=20, linewidth=10, color='k', alpha=0.2)
sns.kdeplot(data2[:, 0], data2[:, 1], levels=20, linewidth=10, color='k', alpha=0.2)
plt.grid(False)
plt.show()我们上面所做的工作是:使用均值和协方差矩阵生成了随机高斯分布。 而 GMM 要做正好与这个相反,也就是找到一个分布的均值和协方差,那么怎么做呢?工作过程大致如下:为给定的数据集确定聚类的数量(这里我们可以使用领域知识或其他方法,例如 BIC/AIC)。 根据我们上面的参数,有 1000 个数据点,和两个簇2。初始化每个簇的均值、协方差和权重参数。 使用期望最大化算法执行以下操作:期望步骤(E-step):计算每个数据点属于每个分布的概率,然后使用参数的当前估计评估似然函数最大化步骤(M-step):更新之前的均值、协方差和权重参数,这样最大化E步骤中找到的预期似然重复这些步骤,直到模型收敛。以上是GMM 算法的非数学的通俗化的解释。GMM 数学原理有了上面的通俗解释,我们开始进入正题,上面的解释可以看到GMM 的核心在于上一节中描述的期望最大化 (EM) 算法。在解释之前,我们先演示一下 EM 算法在 GMM 中的应用。1、初始化均值、协方差和权重参数mean (μ): 随机初始化协方差 (Σ):随机初始化权重(混合系数)(π):每个类的分数是指特定数据点属于每个类的可能性。 一开始,这对所有簇都是平等的。 假设我们用三个分量拟合 GMM,那么每个组件的权重参数可能设置为 1/3,这样概率分布为 (1/3, 1/3, 1/3)。2、期望步骤(E-step)对于每个数据点,使用以下等式计算数据点属于簇 () 的概率。 这里的k是我分布(簇)数。上面的_是高斯分布c的混合系数(有时称为权重),它在上一阶段被初始化,(|,)描述了高斯分布的概率密度函数(PDF),均值为和 关于数据点 x 的协方差 Σ; 所以可以有如下表示。E-step 使用模型参数的当前估计值计算概率。 这些概率通常称为高斯分布的“responsibilities”。 它们由变量 r_ic 表示,其中 i 是数据点的索引,c 是高斯分布的索引。 responsibilities衡量第 c 个高斯分布对生成第 i 个数据点“负责”的程度。 这里使用条件概率,更具体地说是贝叶斯定理。一个简单的例子。 假设我们有 100 个数据点,需要将它们聚类成两组。 我们可以这样写 r_ic(i=20,c=1) 。 其中 i 代表数据点的索引,c 代表我们正在考虑的簇的索引。不要忘记在开始时,_ 会初始化为等值。 在我们的例子中,_1 = _2 = 1/2。E-step 的结果是混合模型中每个数据点和每个高斯分布的一组responsibilities。 这些responsibilities会在 M-step更新模型参数的估计。3、最大化步骤(M-step)算法使用高斯分布的responsibilities(在 E-step中计算的)来更新模型参数的估计值。M-step更新参数的估计如下:上面的公式 4 更新 πc(混合系数),公式 5 更新 μc,公式6 更新 Σc。更新后的的估计会在下一个 E-step 中用于计算数据点的新responsibilities。GMM 将将重复这个过程直到算法收敛,通常在模型参数从一次迭代到下一次迭代没有显着变化时就被认为收敛了。让我们将上面的过程整理成一个简单的流程图,这样可以更好的理解:数学原理完了,下面该开始使用 Python 从头开始实现 GMM了使用 Python 从头开始实现 GMM理解了数学原理,GMM的代码也不复杂,基本上上面的每一个公式使用1-2行就可以完成首先,创建一个实验数据集,我们将为一维数据集实现 GMM,因为这个比较简单 importnumpyasnp
n_samples=100
mu1, sigma1=-5, 1.2
mu2, sigma2=5, 1.8
mu3, sigma3=0, 1.6
x1=np.random.normal(loc=mu1, scale=np.sqrt(sigma1), size=n_samples)
x2=np.random.normal(loc=mu2, scale=np.sqrt(sigma2), size=n_samples)
x3=np.random.normal(loc=mu3, scale=np.sqrt(sigma3), size=n_samples)
X=np.concatenate((x1,x2,x3))下面是可视化的函数封装 fromscipy.statsimportnorm
defplot_pdf(mu,sigma,label,alpha=0.5,linestyle='k--',density=True):
"""
Plot 1-D data and its PDF curve.
"""
# Compute the mean and standard deviation of the data
# Plot the data
X=norm.rvs(mu, sigma, size=1000)
plt.hist(X, bins=50, density=density, alpha=alpha,label=label)
# Plot the PDF
x=np.linspace(X.min(), X.max(), 1000)
y=norm.pdf(x, mu, sigma)
plt.plot(x, y, linestyle)并绘制生成的数据如下。 这里没有绘制数据本身,而是绘制了每个样本的概率密度。 plot_pdf(mu1,sigma1,label=r"$\mu={} \ ; \ \sigma={}$".format(mu1,sigma1))
plot_pdf(mu2,sigma2,label=r"$\mu={} \ ; \ \sigma={}$".format(mu2,sigma2))
plot_pdf(mu3,sigma3,label=r"$\mu={} \ ; \ \sigma={}$".format(mu3,sigma3))
plt.legend()
plt.show()下面开始根据上面的公式实现代码:1、初始化 defrandom_init(n_compenents):
"""Initialize means, weights and variance randomly
and plot the initialization
"""
pi=np.ones((n_compenents)) /n_compenents
means=np.random.choice(X, n_compenents)
variances=np.random.random_sample(size=n_compenents)
plot_pdf(means[0],variances[0],'Random Init 01')
plot_pdf(means[1],variances[1],'Random Init 02')
plot_pdf(means[2],variances[2],'Random Init 03')
plt.legend()
plt.show()
returnmeans,variances,pi2、E step defstep_expectation(X,n_components,means,variances):
"""E Step
Parameters
----------
X : array-like, shape (n_samples,)
The data.
n_components : int
The number of clusters
means : array-like, shape (n_components,)
The means of each mixture component.
variances : array-like, shape (n_components,)
The variances of each mixture component.
Returns
-------
weights : array-like, shape (n_components,n_samples)
"""
weights=np.zeros((n_components,len(X)))
forjinrange(n_components):
weights[j,:] =norm(loc=means[j],scale=np.sqrt(variances[j])).pdf(X)
returnweights3、M step defstep_maximization(X,weights,means,variances,n_compenents,pi):
"""M Step
Parameters
----------
X : array-like, shape (n_samples,)
The data.
weights : array-like, shape (n_components,n_samples)
initilized weights array
means : array-like, shape (n_components,)
The means of each mixture component.
variances : array-like, shape (n_components,)
The variances of each mixture component.
n_components : int
The number of clusters
pi: array-like (n_components,)
mixture component weights
Returns
-------
means : array-like, shape (n_components,)
The means of each mixture component.
variances : array-like, shape (n_components,)
The variances of each mixture component.
"""
r= []
forjinrange(n_compenents):
r.append((weights[j] *pi[j]) / (np.sum([weights[i] *pi[i] foriinrange(n_compenents)], axis=0)))
#5th equation above
means[j] =np.sum(r[j] *X) / (np.sum(r[j]))
#6th equation above
variances[j] =np.sum(r[j] *np.square(X-means[j])) / (np.sum(r[j]))
#4th equation above
pi[j] =np.mean(r[j])
returnvariances,means,pi然后就是训练的循环 deftrain_gmm(data,n_compenents=3,n_steps=50, plot_intermediate_steps_flag=True):
""" Training step of the GMM model
Parameters
----------
data : array-like, shape (n_samples,)
The data.
n_components : int
The number of clusters
n_steps: int
number of iterations to run
"""
#intilize model parameters at the start
means,variances,pi=random_init(n_compenents)
forstepinrange(n_steps):
#perform E step
weights=step_expectation(data,n_compenents,means,variances)
#perform M step
variances,means,pi=step_maximization(X, weights, means, variances, n_compenents, pi)
plot_pdf(means,variances)这样就完成了,让我们看看 GMM 表现如何。在上图中红色虚线表示原始分布,而其他颜色表示学习分布。 第 30 次迭代后,可以看到的模型在这个生成的数据集上表现良好。这里只是为了解释GMM的概念进行的Python实现,在实际用例中请不要直接使用,请使用scikit-learn提供的GMM,因为它比我们这个手写的要快多了,具体的对象名是sklearn.mixture.GaussianMixture,它的常用参数如下:tol:定义模型的停止标准。 当下限平均增益低于 tol 参数时,EM 迭代将停止。init_params:用于初始化权重的方法总结本文对高斯混合模型进行全面的介绍,希望阅读完本文后你对 GMM 能够有一个详细的了解,GMM 的一个常见问题是它不能很好地扩展到大型数据集。如果你想自己尝试,本文的完整代码在这里:https://avoid.overfit.cn/post/c9ca4de6d42d4d67b80cc789e921c636作者:Ransaka Ravihara
云ClickHouse 如何支持客户降本增效?
摘要当降本增效成为企业运营和技术投入的核心诉求时,能否有效帮助企业客户实现资源降本同时提高业务收益成为产品能否获得市场和客户认可的重要衡量指标。阿里云 ClickHouse 从提高企业实时分析业务收益和降低数仓资源成本投入角度思考,通过大存储规格及云原生等产品形态,帮助客户降本增效。降本增效成为主流需求截至今年6月份,我国网民规模达10.51亿,互联网普及率 74.4%, 企业客户都面临增长停滞缓慢和成本高企的困境,因此企业应通过进一步挖掘现有的用户价值、提高技术含量、降低营销和经营成本,提升企业效益和持续增长能力, 一言以蔽之就是需要降本增效 ,从过去一年经营相关产品的统计口径来看,大约 70%以上存量客户都表现出突出的降本增效诉求。而在接下来的新一年,个人判断“降本增效“ ”仍将持续成为企业在新一年的主流诉求。 实时数仓降本增效逻辑实时数仓是支撑企业数字化运营支撑的核心产品,通过发挥自身“大数据实时分析能力”来支撑业务精细化运营。当前实时数仓的降本增效逻辑从以下两个方面来考虑:一方面从数据分析效率思考,数据分析效率决定了运营决策,策略制定及效果评估的效率。运营决策和执行的时效性越高,就越能在运营过程更快的匹配到目标客户,更实时的将运营策略应用到目标客户,从而达到更好的转化率,留存率等业务转化效果,达到业务“增效”的预期。因此实时数仓产品的分析性能是衡量一个数仓产品成功与否最重要参考指标之一, 分析性能和业务“增效”效果在很大程度上是正比例关系。另外一方面是从资源使用成本考虑。 实时数仓通常需要对大规模业务数据实时处理,因此就需要消耗大量的存储介质来存储数据,同时也要消耗对应的计算资源参与实时计算。所以如果能总体实现存储和计算成本资源的最小化就能起到帮助客户“降本”的效果。阿里云 ClickHouse 如何落地降本增效ClickHouse 是一款开源的 OLAP 场景的列式数据库技术,从全球最大的俄语搜索引擎公司 Yandex 内部孵化而来,在 Yandex 内部支撑了核心商业化广告投放相关业务的数据分析场景。 20 万亿行的数据规模下,90%的查询分析能够在 2 秒内返回。阿里云 ClickHouse 是阿里云基于开源技术提供的全托管实时分析型列式数据库服务。具有高性能、开箱即用、企业特性支持。广泛应用于流量分析、广告营销分析、行为分析、人群划分、客户画像、敏捷BI、数据集市、网络监控、分布式服务和链路监控等业务场景。 阿里云 ClickHouse 作为实时分析型数据库/实时数仓服务,基于实时数仓的降本增效逻辑,进行了一系列的产品改进和优化,来帮助客户实现低成本上云,达到降本增效效果。阿里云承袭开源 ClickHouse 优异性能数仓的分析性能决定了构建在其上业务系统的实时性,进而直接影响到用户业务“增效”结果。而 ClickHouse 凭借其“暴力”的查询性能获得了广大开发者和企业用户的青睐。DB-Engine 的流行度排名上,产品的关注度快速增长,在同类产品的流行排名上也处于领先位置。ClickBench 是当前业界通用的针对分析型数据库性能对比提供的基准性能测试方法之一,此基准测试展现了点击流和流量分析、web分析、机器生成的数据、结构化日志和事件数据场景下典型工作负载:,并且涵盖了 ad-hoc 及实时仪表场景下的典型查询。测试数据集来自世界上最大的网络分析平台之一的实际流量记录,数据本身已进行脱敏,同时保留所有重要的数据分布,且查询集是临时设置的,能够反映实际的工作负载。在 ClickBench 基准性能测试场景中,ClickHouse 长期处于基准测试排行榜的头部。详情点击 ClickBench 测试报告阿里云 ClickHouse 大存储规格持续降本大规模业务场景下,数仓的数据存储成本是企业用户在数仓资源投入的最大成本组成部分。在典型的大规模点击事件流类及用户行为日志数据分析或离线大数据在线加速分析场景,需要分析的数据规模从几十上百 TB 到 PB 级,存储资源成本的比例可达 ~70%以上 。大幅降低存储成本,就可以最大化的帮助用户实现资源降本。阿里云 ClickHouse 大存储规格最大化实现资源降本。大存储规格基于阿里云特定的机型进行部署,整体成本可以降低 80%左右。 规格类型计算资源存储资源单盘最大吞吐量 整体成本大存储规格20Core 88GB ~58TB HDD 本地盘140MB/S ~5088 元/月标准规格20Core 80GB ~58TB 高效云盘190 MB /S ~23800 元/月大存储规格使用本地磁盘替代云盘进行存储,本地盘没有云盘的副本冗余,因此成本可以大幅缩减。同时,大存储规格计算和存储在同一台物理机上,数据传输没有网络延迟,因此整体 IO 吞吐能力也有明显的提升。通过大存储规格可以最大化的降低存储资源成本,提供最具性价比的规格类型,满足用户“降本”的诉求。当然,大存储规格虽然提供了非常大的成本优势 ,但也不是适用于所有的业务使用场景。大存储规格在弹性和可靠性等方面有一定的取舍,需要根据自己的业务场景来选择,可以参考以下三个维度来考虑选型。弹性维度。大存储规格的存储和计算资源的配比是固定的,没有单节点的灵活的“弹性”能力。单台 Server 节点如果有超出配额的计算资源需求,或者更多存储资源需求时,无法通过调整单台的存算资源配比来满足,只能通过水平扩容的方式,增加服务节点来满足需求,同时也会带来新节点额外的耦合资源浪费。所以本地盘规格更加适合“资源规划型”业务,能够提前做好存储计算的比例测算和分配,没有非常强的资源弹性需求的业务场景。基础数据规模。大存储规格的初始存储资源规格较大,面向初始业务数据就具有大数据量存储,达到 50TB 以上的数据规模需求。 如果数据分析规模在 10TB 以内,且长期看数据增长和数据淘汰的比例相当,那么建议选择标准规格类型,避免成额外的存储资源浪费,降低初期的业务成本。如果初始的数据规模就比较大,就更加适合大存储规格。数据可靠性。大存储规格的存储介质选用本地盘,本地盘来自单台物理机,数据可靠性取决于物理机的可靠性,存在单点故障风险,因此数据可靠性会显著降低。如果业务对数据可靠性要求高,那么需要考虑默认使用标准规格云盘版本,或者使用云 ClickHouse 引擎层的双副本版本。 阿里云 ClickHouse 云原生版降本增效阿里云 ClickHouse 大存储规格解决了资源规划型业务场景资源降本的诉求。 那么对于业务资源有实时弹性诉求的场景,通过云原生版本支持客户降本增效。对于实时弹性有强诉求的业务主要主要表现在几个层面。 第一,业务对于资源的需求不可预期,资源变配的需求频率高。这种业务场景下,初始规划的资源配置,通常随着业务的发展,会出现资源浪费或者资源短缺,需要通过变更资源配置来调整资源使用量。并且在业务高峰突然到来时,需要能够快速的进行资源的扩容,因此对资源扩容的效率要求会更高。 第二,业务对于存储资源和计算资源需求比例不固定,每一层资源的需求都更加灵活。客户业务在同等数据规模下,业务对于时效性响应的要求不同,对于并发性支撑能力要求不同,对于计算资源的需求量就不同。比如大促活动期间,业务决策效率要求更高,就需要更多的计算资源来支持实时分析。并且在相同的计算资源需求下,如果业务的数据规模增长更快,对于存储资源的需求更高时,就需要实时的扩充存储资源,满足存储需求。 阿里云 ClickHouse 云原生版本通过以下几个产品能力来解决强实时弹性的业务诉求。存算分离。开源社区版本的 ClickHouse 是存算一体化的架构,每一个 Server 主机既要负责数据存储也要负责数据计算,当单节点的存储或计算资源达到单机的上限时,就需要进行水平扩容。而计算和存储耦合的水平扩容方式,面对单一的存储或计算资源扩容需求时,就会带来额外计算或存储资源的“扩容浪费”。云原生版本通过 share storage 架构,支持产品层面将计算资源和存储资源解耦,实现存算分离。用户可以按照需求购买计算资源,按需按量使用存储资源。存储和计算之间没有固定的配比,业务可以根据需求灵活的选择资源配置,最大化资源利用率,降低资源耦合浪费,实现“降本”。实时弹性。开源社区版本 ClickHouse 采用 share nothing 的架构, 存算耦合模式。每个 ClickHouse Server 或者 Shard 节点负责本身节点存储数据和分析。水平扩容时需要对原有节点的数据进行 reshard/rebalance ,保证扩容前后集群各个节点的负载均衡,而 rebalance 需要进行大量的数据迁移,且扩容效率随着数据规模的增长而衰减。在百 TB 数据规模下,全量扩容迁移需要天级别来完成,对业务的可用性造成严重的影响。阿里云 ClickHouse 云原生版本,通过存算分离的架构和独立的 Meta 层管理,将 shard 计算和 shard 数据存储的映射关系进行独立管理。计算水平扩容时,仅仅需要在独立 Meta 层进行映射关系数据的的修改,存储层 shard 数量和存储内容不变,不需要数据迁移或者少量计算层缓存数据迁移,就可以完成计算的扩容。整体扩容效率从小时/天级别缩短到秒/分钟级别。帮助客户实现“增效”的目的,满足业务高频实时弹性的需求。总结分析业务的分析时效性决定了业务效果,而分析引擎的分析性能决定了对分析业务时效性的支撑。阿里云 ClickHouse 基于开源社区内核提供了的高效实时分析能力,满足了客户“提效”的诉求。同时,通过大存储规格,从数仓使用成本层面,大大降低了成本投入,满足了资源规划型业务“数仓降本”的普遍诉求。而对于实时弹性具有强依赖的场景,通过云原生存算分离版本提高了扩容效率和资源使用率,同样可以帮助达到了“降本增效”的目的。未来,阿里云 ClickHouse 会进一步加强在云原生 Serverless 层面产品演进,支持多计算组共享存储架构,实现业务隔离,读写分离及用户隔离;支持自动进行计算层的负载判断,实现 AutoScaling ,进一步帮助客户降本增效。
开源项目的演进会遇到哪些“坑”?KubeVela 从创立到 CNCF 孵化的全程回顾
作者: 孙健波(天元)、曾庆国(悦达)2023 年 2 月,KubeVela经过全体 ToC 投票成功进入 CNCF Incubation,是云原生领域首个晋级孵化的面向应用的交付和管理平台。KubeVela 背后的核心理念是 2019 年阿里云和微软联合发布的开放应用模型(OAM),演变至今,KubeVela 通过其可编程可扩展的架构、良好的用户体验,以及大量的生态核心能力,帮助了钉钉、招商银行、理想汽车、移动云、百度等数百家企业构建其云原生应用平台,大大降低了云原生技术的使用门槛。KubeVela 本身也有别于“大厂开源”的惯性模式,它从第一天起就遵循“社区发起、开放治理、国际化运作”的原则,核心理念之一就是“始终以业界的最广泛和最真实场景作为项目演进的指南针”,所以发展路径中一直在倾听社区的声音,以最普遍、最共性的需求为最高优先级。因此,我们也有幸经历了一个项目从社区发起到用户群体壮大的全过程。从技术迭代、完善功能,到社区运营、开源治理,再到打磨产品、建立生态,我们克服了诸多困难,这或许是开源项目都会遇到的挑战。今天,我们将做一个完整的回顾,梳理项目演进过程中的那些“坑”,希望对整个开源生态的发展有所帮助。项目发起:明确目标和定位一个开源项目的发起,其最核心的是明确项目的目标和定位。OAM/KubeVela 诞生之初的 2018-2019 年,当时我们判断:随着云原生技术逐渐统一基础设施和工作负载层面的抽象,如何进一步简化和标准化应用交付与管理层面的操作和功能,会成为接下来一个非常自然的演化方向,也会成为市场的下一个焦点。这里面我们主要考虑了四个方面:受众:大多数开发者,也就是最终业务应用的开发者,他们日常关心的是应用开发和部署,而不是计算存储网络,这意味着应用层的大幅简化和标准化一定会成为强需求。定位和空间:Kubernetes 非常明确的要把它的抽象层次停留在基础设施层,这为应用层的进一步创新和工作提供了足够的空间和支撑。行业格局:在 Kubernetes 逐渐成为事实标准的背景下,大多数技术(比如 OpenShift)依然在做局限的封装,而原生的工具(如 helm、kustomize)又过于简单。这样既不满足云上用户碎片化、多样化的使用诉求,也无法打造用户友好的使用体验。技术储备:CRD Operator, Terraform 等 IaC 技术的逐步普及提供了一个快速交付可编程、模块化的应用管理抽象,而基于 Kubernetes,一个独立的应用管理和交付系统可以非常专注于该层本身,而无需关注基础设施层的问题。基于以上趋势的判断,阿里开始在 2019 年逐步布局应用交付与管理领域,提出了一系列先导性探索和实践,包括 Helm/Kustomzie 应用管理、多集群应用交付等。最终确定将“让软件交付在当今流行的混合、多云环境中变得更加简单、高效、可靠”作为我们的核心目标和愿景,将“一个与基础设施无关的、用户友好但又灵活可扩展的应用交付抽象”作为我们的核心交付物,这个应用交付抽象就是今天的 OAM spec,而随后出现的 KubeVela 则是这一层抽象的具体实现。图 1:KubeVela 是什么?明确的目标和定位不仅支撑了 KubeVela 开源团队以及大量社区贡献者可以在相对松散的模式下长期协作,还帮助团队从大量杂乱的需求中解放出来,专注在最核心的问题域中。比如 KubeVela 不会触及工作负载本身,用户可以选择集成 Kubernetes 原生的 Deployment,或者自己扩展 CRD Operator,又或者选择 OpenKruise 这样的工作负载管理工具。同时团队专注于项目的集成能力和扩展性,比如我们投入了足够的精力去做 Kubernetes API 的编排,任意的 Kubernetes 资源都可以在 KubeVela 体系中组合、拆分、查看状态、传递参数,这一特性使得 KubeVela 早期快速的打出了自己的市场定位,并且获得了像第四范式这样的早期用户。早期演进:明确要坚守的核心技术原则开源项目的早期通常是沿着最初设定的目标去补齐核心功能,在此之前我们可能需要回答一个问题:“为了让我们的开源项目与众不同,我们该遵循怎样的设计原则?” KubeVela 项目的第一个年头是核心技术功能初步形成的阶段,设计之初我们给项目定下的关键原则是:Kubernetes 原生。OAM 应用模型不局限于 Kubernetes 生态,但是我们选择将 KubeVela 控制平面通过 Kubernetes 的插件(CRD)模式实现。一方面它充分利用了 Kubernetes 声明式 API 面向终态的设计理念,为用户带去易用性和确定性,方便用户安装和使用;另一方面它也帮助我们利用 Kubernetes 的 API 生态,快速实现了诸如 Helm 交付、弹性扩缩容、服务网关、灰度发布等应用所需的核心能力,而 KubeVela 团队随后发布的 Terraform Controller 项目也证明了基于 Kubernetes 控制平面衔接云能力的可行性。可扩展。KubeVela 基于 OAM 模型提供用户友好的上层抽象,但这些抽象可以随时扩展以满足用户的各种需求。这给技术实现带来了很大的挑战,但这也是一个非常重要的创新,它避免了 KubeVela 项目成为一个只能解决“最小公分母”问题的“鸡肋”项目。可编程。在众多的可扩展性设计中,KubeVela 最终选择了 Infra as Code(IaC) 的可编程扩展方式。因为这种扩展方式不仅简单易用,还可以方便的模块化和插件化。这个选择不仅提供了扩展 KubeVela 的最佳方案,还为后来的插件市场等生态能力打下了基础。围绕着这些原则,项目选择基于 CUE 配置语言来作为动态编程能力的基石,KubeVela 1.0 及早期版本给出了一个非常灵活的 OAM 实现。但项目的演进也使得 KubeVela 及 OAM 模型与早期发布的版本形成了较为明显的差异,这里形成了一个不小的挑战,即“开源项目的兼容性如何保证”。图 2:KubeVela 可编程可扩展的模块化设计?持续迭代:保持开源项目的兼容性KubeVela 基本上就是在 OAM 社区的众多用户呼声下诞生的,那些早期参与贡献的工程师们,他们其实也同时是公司里面积极推进 OAM 落地的平台构建者,他们不仅提供了大量的建议和代码贡献,还通过自身的实际场景帮助社区做验证。我们知道一个新技术的推广,很重要的一点是在解决原有问题的同时,尽可能降低采纳的成本,也就是不引入新的问题。所以当 KubeVela 发布的第一个版本的时候,我们的早期采纳者他们更多的是在做一个自身 OAM 实践的升级,而不是使用一个全新的系统。同样地,在后续的项目迭代过程中,对兼容性的考量一直都放在首要的位置。当 KubeVela 项目的第一阶段功能实现完成,并被开源社区逐步采用的过程中。根据大量的用户反馈和调研,我们发现,除了基础的工作负载和运维需求之外,用户还会有诸如多集群高可用、资源共享、资源回收等应用管理策略的需求,而看似非常碎片化和复杂的各类应用交付场景,其背后确实存在一个非常本质的模型,那就是“工作流”。我们很快就开始同时演进 OAM 模型本身,并且在 KubeVela 实现了一个非常轻量级的工作流引擎。而“工作流”这个特性本身就又与 Kubernetes 和 GitOps 生态天然互补,KubeVela 的工作流步骤可以任意扩展,而声明式 API 面向终态的语义也可以很好的描述工作流的状态机,这使得 KubeVela 的工作流几乎可以满足任何交付场景的需要,所以这个创新后来也成为了 KubeVela 被大量采用的“杀手锏”。图 3:KubeVela 1.0 发布后始终保持功能以及模型层面的兼容性当然这也会为技术方案的长期演进带来很多包袱和困难,所以我们在随后也加入了项目功能的废弃机制,仅对少量不合理、且几乎没有用户的功能做废弃,并且在正式废弃前提前两个版本做通知。核心能力形成的过程中,我们观察到用户增长并不满足预期。通过运营分析,我们发现无论是 Github 还是官网,初次访问流量是比较大的,但实际转化数据不太理想。此时我们意识到项目的使用体验可能不尽如人意,而社区用户的使用和反馈是驱动我们项目持续增长的重要输入。用户转化:注重易用性和首次体验KubeVela 的理念是业界领先的,所以我们一直在做大量布道,许多用户被我们吸引过来。然而许多用户反馈说,看了 KubeVela 项目官网,看不懂这个项目是做什么的。此时我们意识到,项目的易用性出了问题。我们把自己从项目维护者的身份中走出来,开始作为用户审视这个项目,对于首次接触项目的新用户,我们问自己三个问题:第一个问题:我能一下子看明白项目解决的是什么问题吗?KubeVela 项目本身是有一定的理解门槛的,它建立在 OAM 应用模型之上,OAM 模型关注点分离的核心思路又把平台的用户分成了平台的构建者和最终用户,这给直接接触 KubeVela 的用户带来了不小的认知成本。在 1.0 到 1.5 这接近一年的时间中,我们每次发版都会根据用户的反馈持续重构我们官网的文档,以广大用户最能产生共鸣的关键词、场景进行类比,同时也一直在做减法,将项目的高级功能藏到相对较深的位置。另一方面,我们在产品实现上也持续明确目标用户群体,将 KubeVela 控制器核心定位给平台工程师,而开发的 VelaUX 子项目初始定位是业务开发者开箱即用,同时也为平台工程师构造企业平台提供参考和基础框架。通过明确定位的产品培养用户心智,进而将越来越多关键信息传播给社区用户,再通过用户社群持续影响更广泛的生态。第二个问题:我能一下子联想到我的场景是否能够用它吗,或者它能满足我的需求吗?用户的注意力是有限的,通过对官网的用户访问数据进行分析,我们发现新用户在网站的平均驻留时间不超过 3 分钟,如何在有限的时间里迅速抓住目标用户的兴趣,文档结构的设计非常重要。通过对社区用户的大量访谈,我们意识到大多数用户会带着需求关键词来寻觅项目,所以们不断调整官网侧边栏目录,把项目能够实现的核心功能以用户熟悉的关键词体现到导航目录中方便用户快速匹配。除了项目文档,另一个关键点是提炼用户案例,行业头部用户案例具备很强的带动作用。有一段时间理想汽车率先采纳了 KubeVela,没多久就看到了小鹏汽车的采纳,甚至在不久前,自动驾驶领域的巨头 Aurora 也在 Slack 上联系我们,计划全公司采纳 KubeVela,而招商银行的案例也带动了一大批金融行业的用户采纳 KubeVela。当然这些案例的积累是一个小火慢炖的过程,很难一蹴而就。这不仅需要项目的维护者对于社区用户有足够的耐心,也需要站在开源项目背后支撑项目发展的公司有足够的远见,我们非常感谢阿里云、招商银行、Napptive等公司的维护者们持续而坚定的投入。第三个问题:我想试一下项目的实际运行效果,我能在几分钟只能快速体验完整的 Demo 吗?这个问题其实涉及到了开源项目的一个关键特点,那就是开源项目必须能够用户自助,即用户要有能力自发的安装、使用、运维,以及在社群进行传播。如果一个开源项目是大多数用户自己玩不起来的,那注定难以成功。所以我们在每次发版时都会检查以下两项:大多数用户能否顺畅进行安装?对于国际化运作的 KubeVela 项目来说,我们需要帮助用户客服网络障碍,不管是访问文档还是下载安装都需要在国内外流畅进行;为了降低安装复杂度,我们甚至专门发起了一个叫 VelaD的项目,帮助用户从单机一键离线拉起包括 Kubernetes 在内的完整体验环境,大大降低了用户的上手门槛。除此之外,还有包括 ARM 架构镜像支持、版本升级一键完成等体验优化。第一个用例是否足够简单又充分说明项目特性?KubeVela 早期的第一个用例要么过于简单看不出功能特点,要么过于复杂没有多个集群都跑不起来。经过持续打磨,现在的第一个用例围绕着核心概念,体现了工作负载抽象、交付策略、多集群、工作流等核心能力,但对用户环境又无额外要求。图 4:VelaD 全离线一键安装包括 Kubernetes 集群在内的完整环境逐步成熟:产品化运作和社区用户随着项目的逐步成熟,社区会迎来一批又一批的用户,而开源项目成功的核心就是大量的用户采纳。 KubeVela 很幸运,一直有阿里巴巴内部大量的场景可以帮助打磨孵化,而我们也非常注重社区用户的需求。除了每周定期举办国内外社区会议,还会组织跟不同企业的点对点交流会,甚至帮助他们制定完整的平台架构。而这个过程的积累也是相互的,KubeVela 维护团队从各行各业的头部企业中了解了行业的现状和差异化痛点,得以从更广阔的视野做功能的设计。在社区用户的过程中,我们也总结了一些关键经验:如何给到开源用户安全感?对于基础设施类的开源项目,一旦采纳就会成为企业内部核心架构的一部分,相比于企业内部自建,采纳开源往往会缺乏一些安全感,开源项目本身如何给到企业安全感至关重要。首先是项目维护团队的多样化、长期稳定性以及高活跃,KubeVela 是 CNCF 托管的孵化项目,背后有阿里云、招商银行、Napptive 等多个公司在持续维护。同时要持续对代码质量保持较高的要求、注重安全问题和稳定性,KubeVela 有 40 多项持续集成测试条目,总体测试覆盖率超过 60%,核心场景的覆盖率在 90% 以上,基本上每个合并的代码都能保证兼容性,同时对代码贡献者本身的能力也有较高的要求。而团队对安全问题的上报和稳定性问题也始终保持高度敏感,一旦发现会第一时间发布修复版本。最后是提供确定性,有明确的里程碑、发版计划,并且坚定的执行。KubeVela 发布至今每隔 2-3 个月发布一次大版本,每隔 1-2 周发布一个小版本,社区一直保持极高的活跃度,至今已经发布了超过 150 个版本,每个版本都有清晰的变更文档。如何平衡社区用户的小众需求?社区用户在落地过程中由于场景的差异,必然会产生相对小众的需求。对于这一点,我们的策略是 Blocker Issue 优先,即如果由于一些功能设定和实现直接阻碍了场景落地,那么这类问题要第一时间解决。对于功能新增类的需求,则交由社区一同评估等待更多的反馈,确认是一个相对普遍的需求再加入到版本计划中。例如 KubeVela 早期有一些用户希望对接他们企业内部的统一认证平台,这可能并不是标准的协议模式,通过社区 Issue 的来会讨论,有贡献者指出采用了 Dex 作为企业单点登录的统一方式,不同企业自行对接 Dex 即可。这使得项目能够群策群力,着眼于长远发展。如何获得海外用户?基础设施领域的开源项目,要想获得真正意义上的成功,如何打开国际化市场是一个绕不开的话题。一方面,项目本身要始终着眼于领域的最前沿,保持技术的先进性,聆听国外用户的使用场景和习惯,对技术发展趋势做出敏锐的判断。另一方面,KubeVela 的核心团队均在国内,也克服了包括时差、语言、文化在内的诸多客观困难,一直坚持在北美相对合适的时间召开社区会议,持续在 KubeCon 等各类海外大会布道,文档、文章始终用中英文双语发布,同时积极活跃在 Slack、Issue 中答疑,满足国外用户希望点对点沟通交流的诉求。这不仅需要项目维护者有较强的综合实力,也需要对项目真正的热爱。团队也在积极培养海外贡献者,随着 KubeVela 生态的不断繁荣,Napptive、Guidewire 等企业合作伙伴也在陆续加入社区,共同承担项目维护的职责。图 5:OAM/KubeVela 风雨无阻的国外社区会议生态建设与社区运营最后我们要谈一谈社区生态,因为做好一个开源项目绝不仅仅是做一项前沿的技术,它更像是在目标领域打造一款好的产品。除了打磨产品功能,我们还需要通过对项目持续运营、对社区治理,得到更多开发者的认可,让他们参与进来贡献。要实现这样的目标,就需要让开发者对 KubeVela 形成共识、主动加入并参与协作。KubeVela 诞生于 OAM 社区,也是第一个将“以应用为中心”的设计理念落地的项目。因此早期,我们首先要让大家理解 OAM 模型的思想,大家才会有意愿开始了解 KubeVela 是什么。我们做了大量的布道,并联合 CNCF 发布业界首个“云原生技术公开课”,介绍 OAM“以应用为中心”的理念如何解决云原生时代应用开发问题,得到了越来越多开发者的共鸣。发展到 2021 年 5 月,阿里云联合信通院发布业内首个以 OAM 为核心的“云计算开放架构”标准,将 OAM “模型”化虚为实,也对 KubeVela 发展起到关键作用。为使社区保持持续的生命力,2021 年 7 月,KubeVela 正式加入 CNCF ,项目受众也扩大至全球。我们投入了很多精力做海外运营,比如联动 CNCF TAG App Delivery,以及 Argo、FluxCD、Prometheus、K3s 等生态伙伴举办社区会议、在主流的海外开发者社区建立团队账号,渐渐将影响力渗透到北美、日本、西班牙、英国等多个国家。为了让周边生态繁荣起来,以便能够让项目在更大的领域得到广泛的传播,为此我们专门建立了一个插件(Addon)体系,方便社区里的开发者可以将生态项目的集成,方便地制作成一个具备版本、统一仓库、可发现、可分发、一键安装的插件包。图 6:KubeVela 的插件生态KubeVela 的技术很先进,社区的贡献者众多,但水平也有差异,为了保证项目的质量,又不打击贡献者的积极性。对于每一个代码提交,我们都会及时响应、充分交流,给予贡献者足够的尊重和耐心。同时我们会积极的补充开发者文档,将开发者遇到的常见问题体系化整理。另一方面,我们也建立了完善的开发者晋级机制,从组织的 member,到 reviewer、approver 最后到 maintainer,都有明确的达成条件,让开发者像打怪升级一样有成就感。如今 KubeVela 贡献者已经遍布全球,所在的企业和组织超过70个。我们倡导的理念是,开源贡献的形式不只是代码,一次分享、一次解答,都是对项目的贡献。我们也在建立并逐步完善社区晋升模型和协作机制,让大家更规范、高效地参与社区。KubeVela 社区依然非常年轻,还有很多事情在逐步完善,很开心有这么多朋友同行,让这个队伍越来越壮大。也期待更多朋友来到 KubeVela 社区感受开源的魅力。
【老司机平台技术】构建应用级项目集成任务通用实验室
欢迎使用老司机平台,共同推进高效业务测试体验,地址:http://drivers.alibaba.net/背景老司机项目集成任务原计划为每一个项目老司机创建一个实验室,当项目环境部署时,会拉起这个实验室,然后触发老司机的项目集成任务。项目集成任务本身配置可触发的项目标,通过与实验室传递的项目标匹配以判断是否真正执行此集成任务。这里存在几个问题:如果每个项目都创建一个实验室,那么最终同一个应用上存在的实验室数量非常多,进一步导致每次项目环境部署时拉起多个实验室,需要请求老司机后,由老司机判断不执行任务再关闭实验室,不仅消耗实验室、老司机的机器成本,也非常耗时。除了上述的设计路线与成本问题外,我们在实施过程中又发现了一个真正的阻断性的问题,目前AONE已经不支持通过API等方式自动创建实验室(成本问题),实验室仅支持用户手工创建。所以上述方案肯定是无法实现的。回到原始的需求重新分析,我们核心的需求点是AONE项目环境触发实验室后,拉起对应的老司机项目集成任务。AONE流水线触发行为,可以通过为每个我们关注的应用手工创建一个实验室来解决,接下来拉起对应的项目集成任务,是完全可以由老司机后台路由的。这里的核心要点就是通过AONE实验室传递的项目标与集成任务指定的项目标进行匹配,只拉起真正需要的项目集成任务,而无需拉起其他任务。设计基本流程与匹配触发条件AONE实验室配置为项目环境触发后,应用的项目环境部署时会触发这个实验室,同时会将本次变更的信息,如变更id(crId)、项目标(aoneEnv)、实验室应用(tone_app_name)、代码分支(branch)、提交id(commit_id)等信息带到老司机的集成任务拉起接口中,由老司机对具体拉起的任务做决策路由。具体来说,我们使用三个字段,来做实验室与不特定项目集成任务的匹配。应用匹配:AONE实验室可配置一个被测应用和多个关联应用,老司机项目任务可以配置多个触发应用。基于上述方案描述,我们认为这类实验室是应用级的,仅应当服务于同一个应用,因此在AONE实验室配置中,我们仅考虑配置一个被测应用的情形。当aone实验室传入的被测应用在任务配置的应用列表之内时,认为匹配成功。环境标匹配:老司机项目任务可以配置多个环境标,当aone实验室传入的环境标在任务配置的环境标列表之内,认为匹配成功。变更crid匹配:老司机项目任务可以配置多个crid,aone实验室也可以传入多个crid。当aone实验室传入一个crid时,只要这个crid在任务配置的crid列表之内,认为匹配成功;当aone实验室传入多个crid时,需要这一组crid均在任务配置的crid列表之内,才认为匹配成功仅当应用匹配且环境标匹配,或应用匹配且变更crid匹配时,才会由实验室拉起项目集成任务。当有多个项目集成任务匹配时,我们仅拉起第一个项目集成任务,这是因为一个实验室只能映射到一个集成任务,关联这一个集成任务的执行状态与执行结果。需要注意的是,这里的匹配条件不再包含实验室关联主干任务时使用的taskId,因为一个应用会有多个变更,A变更需要关联到a项目任务中,B变更需要关联到b项目任务中,使用固定的taskId则会绑定到固定的项目任务中,是不符合预期的。基于此,设计使用这个字段作为通用实验室触发项目集成任务匹配的标识字段:当taskId填0时,则在对应的环境组(线上或线下)中按照上述匹配规则,找到可触发的项目集成任务。多个变更部署触发同一个项目集成任务按照上述规则,我们为项目集成任务配置多个应用或多个项目标签时,就可以由多个变更在部署项目环境时触发本集成任务。但是如果有多个变更同时调用同一个项目集成任务时,集成任务应当允许重入吗?这里我们可以先分析项目集成任务在同时接到多个拉起请求时,可以做的响应有哪些:允许自由重入:后请求的实验室,完全不感知前一次执行的影响,直接继续执行。这样的好处是各个项目都可以无感使用老司机的项目集成任务,但问题是两个项目AONE实验室拉起同一个项目集成任务是,就说明他们在共用同一个项目标,这样就会访问到同一台项目机器上。这样难免就会产生预期外的影响,影响测试件执行的正确性和有效性。排队等待:后请求的实验室,排队等待前边的请求完成后再执行。这样可以完全保障两个项目实验室串行执行,项目机器与集成任务不会同时被多个实验室请求占用。但问题是老司机目前没有给集成任务请求做排队的能力,需要对集成任务调度做完全的重构,技术成本较高。完全拒绝重入:后请求的实验室,直接返回执行失败。这个方案初看比较粗暴,但首先可以保障项目机器和集成任务不会被同时请求,其次如果结合AONE实验室的失败自动重跑的能力,那么则可以间接的实现排队等待方案的效果,且老司机侧的集成任务调度完全无需改动。综合上述分析,我们最终采用直接拒绝同一个项目集成任务被多个AONE实验室拉起,但同时也需要AONE实验室做出相应的重试配置。一个应用内的多个变更部署触发多个项目集成任务接前述规则,如果同一个应用内的多个变更分别使用不同的项目环境标,来拉起多个老司机项目集成任务,理论上应当是完全不受影响的。这种情况下,我们发现即使每个应用仅使用同一个AONE实验室,也是能满足的。举例来说,两个变更在部署后分别拉起AONE实验室,由于传入的项目标不一致,那么每次AONE实验室执行时,都会请求到不同的项目集成任务,这样就实现了一个AONE实验室,对多个项目集成任务的调用。触发规则总结综合上述分析,我们列出了各种变更情况与项目环境配置情况的组合下,对项目环境的触发结果。变更情况项目环境配置触发结果X应用+A变更+aaa项目标X应用+aaa项目标A变更可以触发X应用+A变更+aaa项目标
与
X应用+B变更+bbb项目标X应用+aaa项目标A变更可以触发,B变更环境标不满足,不能触发X应用+A变更+aaa项目标
与Y应用+B变更+aaa项目标X应用+aaa项目标A变更可以触发,B变更应用名不满足,不能触发X应用+A变更+aaa项目标
与Y应用+B变更+aaa项目标X&Y应用+aaa项目标AB变更均可触发,但不可重入
如:同时触发时,首个实验室可以正常执行,后续实验室直接返回失败附录:AONE实验室提供的部分参数基于AONE实验室开发插件时,我们可以通过实验室的各类参数感知触发实验室时的各种环境信息,如流水线信息、应用信息、触发者信息等。通过这些信息,插件或后端均可以对实际的触发执行进行过滤与判断。#类型参数名称说明1实验室属性tone_job_id实验室id,即每个实验室的唯一id
每个应用可以有多个实验室2实验室配置tone_app_name实验室配置的“被测应用/二方库”字段中填写的应用3tone_app_id“被测应用/二方库”的应用id4tone_related_app_names实验室配置中触发策略的“关联应用”字段中填写的应用5tone_related_app_ids“关联应用”的应用id6yml_path实验室配置的“配置文件”字段中的脚本地址7代码属性repo被测应用代码仓库地址8branch代码分支9commit_id提交id10流水线&变更属性emp_id触发人员工id工号(手工触发或流水线触发)AK-ADMIN(系统定时触发)11pipeline_id发布流水线id12pipeline_app_name发布流水线应用名称13envType触发执行的发布流水线的环境类型,枚举值daily(日常环境)project(项目环境)auto-test(测试流程触发,如跨应用,预发触发自动化环境等)prepub(预发环境)14crId变更id15运行时信息trigger_from触发来源,枚举值testone(手工触发或流水线触发)internal(系统定时触发)16trigger_mode触发模式,枚举值1(系统定时触发)5(触发应用非被测应用)6(触发应用为被测应用)17build_id一次执行的唯一id通过拼接tone_job_id和build_id,可以获取当次实验室执行的URL。如:https://test.aone.alibaba-inc.com/jobs/1954527?buildId=172785148其中tone_job_id为1954527
Azure OpenAI服务&chatgpt模型
一.什么是 Azure OpenAI 服务?Azure OpenAI 服务允许通过 REST API 访问 OpenAI 的强大语言模型,包括 GPT-3、Codex 和 Embeddings 模型系列。这些模型可以轻松适应特定的任务,包括但不限于内容生成、汇总、语义搜索和自然语言到代码的转换。 用户可以在 Azure OpenAI Studio 中通过 REST API、Python SDK 或基于 Web 的界面访问该服务。1.1 功能概述功能Azure OpenAI可用的模型GPT-3 基本系列
Codex 系列
Embeddings 系列微调Ada
Babbage
Curie
Cushman*
Davinci*
* 当前不可用。 **在美国东部区域,微调目前对新客户不可用。 请使用美国中南部区域进行位于美国的训练虚拟网络支持和专用链接支持是托管标识是,通过 Azure Active DirectoryUI 体验用于帐户和资源管理的 Azure 门户
用于模型探索和微调的 Azure OpenAI Service Studio区域可用性美国东部
美国中南部
西欧内容筛选使用自动化系统根据内容策略评估提示和完成情况。 将筛选高严重性内容。1.2 负责任的 AIMicrosoft 致力于遵照“以人为本”的原则推动 AI 的进步。 生成性模型(例如 Azure OpenAI 中提供的模型)提供显著的潜在优势,但如果不经过精心设计和采用全方位的缓解措施,此类模型有可能会生成错误甚至有害的内容。 Microsoft 已做出大量投资来帮助防范滥用和意外损害,其中包括要求申请人展示妥善定义的用例、融入 Microsoft 的负责任 AI 使用原则、生成内容筛选器以支持客户,并向已加入的新客户提供负责任 AI 实施指导。1.3 如何访问 Azure OpenAI?由于需要应对很高的需求、即将推出的产品改进以及履行 Microsoft 对负责任 AI 做出的承诺,我们目前会限制访问。 当前,我们正在与已经同 Microsoft 建立了合作关系的客户、用例风险较低的客户以及承诺融入缓解措施的客户合作。 除了申请初始访问权限外,所有使用 Azure OpenAI 的解决方案都需要经历用例审查,然后才能发布用于生产用途。一般而言,提交审批的方案的敏感程度越高,风险缓解措施就越重要。1.3 比较 Azure OpenAI 和 OpenAIAzure OpenAI 服务通过 OpenAI GPT-3、Codex 和 DALL-E 模型为客户提供高级语言 AI,并能够实现 Azure 的安全性和企业前景。 Azure OpenAI 与 OpenAI 共同开发 API,确保兼容性的同时能够实现二者之间的平稳过渡。使用 Azure OpenAI,客户可在运行与 OpenAI 相同的模型时获得 Microsoft Azure 的安全功能。 Azure OpenAI 提供专用网络、区域可用性和负责任 AI 内容筛选功能。1.4 关键概念1.4.1 提示和补全补全是 API 服务的核心组件。 此 API 提供对模型的文本输入、文本输出接口的访问。 用户只需提供一个包含英文文本命令的输入提示,模型就会生成文本补全。下面是一个简单的提示和补全的示例:提示:""" count to 5 in a for loop """补全:for i in range(1, 6): print(i)1.4.2 令牌(token)Azure OpenAI 通过将文本分解为标记来处理文本。 标记可以是单词,也可以是字符块。 例如,单词“hamburger”将分解为标记“ham”、“bur”和“ger”,而“pear”之类的常见短单词只是一个单个标记。 许多标记以空格开头,例如“ hello”和“ bye”。给定请求中处理的标记总数取决于输入、输出和请求参数的长度。 处理的标记数量也会影响模型的响应延迟和吞吐量。1.4.3 资源Azure OpenAI 是 Azure 上的一个新产品。 可以像在 Azure 订阅中使用任何其他可用于创建资源或服务实例的 Azure 产品一样开始使用 Azure OpenAI。 1.4.3 部署创建 Azure OpenAI 资源后,必须先部署模型,然后才能开始发出 API 调用和生成文本。 可以使用部署 API 来完成此操作。 这些 API 允许指定要使用的模型。1.4.4 上下文学习Azure OpenAI 使用的模型使用生成调用期间提供的自然语言指令和示例来识别请求的任务和所需的技能。 使用此方法时,提示的第一个部分包括自然语言指令和/或所需特定任务的示例。 然后,模型通过预测概率最高的下一段文本来完成任务。 这种技术称为“上下文”学习。 在此步骤中不会重新训练这些模型,而是根据你在提示中包含的上下文做出预测。上下文学习有三种主要方法:少样本学习、单样本学习和零样本学习。 这些方法根据提供给模型的任务特定数据量而异:少样本学习在这种情况下,用户在调用提示中包含几个示例来演示预期的答案格式和内容。 以下示例显示了几个提示,我们在其中提供了多个示例(模型将生成最后一个答案):Convert the questions to a command:
Q: Ask Constance if we need some bread.
A: send-msg `find constance` Do we need some bread?
Q: Send a message to Greg to figure out if things are ready for Wednesday.
A: send-msg `find greg` Is everything ready for Wednesday?
Q: Ask Ilya if we're still having our meeting this evening.
A: send-msg `find ilya` Are we still having a meeting this evening?
Q: Contact the ski store and figure out if I can get my skis fixed before I leave on Thursday.
A: send-msg `find ski store` Would it be possible to get my skis fixed before I leave on Thursday?
Q: Thank Nicolas for lunch.
A: send-msg `find nicolas` Thank you for lunch!
Q: Tell Constance that I won't be home before 19:30 tonight — unmovable meeting.
A: send-msg `find constance` I won't be home before 19:30 tonight. I have a meeting I can't move.
Q: Tell John that I need to book an appointment at 10:30.
A:示例数量通常为 0 到 100 个,具体取决于单个提示的最大输入长度可以容纳多少个示例。 最大输入长度可能因使用的特定模型而异。 少样本学习可以大大减少准确进行预测所需的任务特定数据量。 此方法的准确度通常不如微调的模型。单样本学习这种情况与少样本学习方法相同,不过只提供了一个示例。零样本学习在这种情况下,未向模型提供任何示例,而只提供了任务请求。1.4.5 模型该服务为用户提供对多种不同模型的访问。 每种模型提供不同的功能和价位。 GPT-3 基础模型按功能降序和速度升序顺序分别称为 Davinci、Curie、Babbage 和 Ada。Codex 系列模型是 GPT-3 的后代,并且已基于自然语言和代码进行训练,可为自然语言到代码用例提供支持。 在模型概念页上详细了解每个模型。二. Azure OpenAI 服务配额和限制2.1 配额和限制参考以下部分提供了适用于 Azure OpenAI 配额和限制的快速指南:限制名称限制值每个区域的 OpenAI 资源2每个模型每分钟的请求数*Davinci 模型(002 及更高版本):120
所有其他模型:300每个模型每分钟的标记数*Davinci 模型(002 及更高版本):40,000
所有其他模型:120,000最大微调模型部署*2能够将同一模型部署到多个部署不允许每个资源的训练作业总数100每个资源同时运行训练作业的最大数目1排队的最大训练作业数20每个资源的最大文件数50每个资源的所有文件的总大小1 GB最大训练作业时间(如果超过,作业将失败)120 小时最大训练作业大小(训练文件中的标记数)×(时期数)Ada:40-M 令牌
Babbage:40-M 令牌
Curie:40-M 令牌
Cushman:40-M 令牌
Davinci:10-M三. Azure OpenAI 服务模型3.1 模型系列通过 Azure OpenAI 可使用很多不同模型,这些模型按系列和功能分组。 模型系列通常按其预期任务关联模型。 下表介绍了 Azure OpenAI 中当前可用的模型系列。 目前并非所有模型都可在所有区域中使用。模型系列说明GPT-3可以理解和生成自然语言的模型系列。Codex可以理解和生成代码(包括将自然语言翻译为代码)的模型系列。嵌入一组可以理解和使用嵌入的模型。 嵌入是一种特殊的数据表示格式,可由机器学习模型和算法轻松使用。 嵌入是一段文本的语义含义的信息密集表示。 目前,我们提供了三个系列的嵌入模型以实现不同的功能:相似性、文本搜索和代码搜索。3.2 模型功能每个模型系列都有一系列模型,这些模型按功能进一步区分。 这些功能通常由名称标识,并且这些名称的字母顺序通常指示给定模型系列中该模型的相对功能和成本。例如,GPT-3 模型使用 Ada、Babbage、Curie 和 Davinci 等名称来指示相对功能和成本。 Davinci 比 Curie 功能更强大(且成本更高),而 Curie 又比 Babbage 功能更强大(且成本更高),依此类推。备注功能较低的模型(如 Ada)可执行的任何任务都可以由功能较高的模型(如 Curie 或 Davinci)执行。3.3 命名约定Azure OpenAI 的模型名称通常对应于以下标准命名约定:{capability}-{family}[-{input-type}]-{identifier}元素说明{capability}模型的功能。 例如,GPT-3 模型使用 text,而 Codex 模型使用 code。{family}模型的相关系列。 例如,GPT-3 模型包括 ada、babbage、curie 和 davinci。{input-type}(仅限嵌入模型)模型支持的嵌入的输入类型。 例如,文本搜索嵌入模型支持 doc 和 query。{identifier}模型的版本标识符。例如,我们最强大的 GPT-3 模型称为 text-davinci-003,而我们最强大的 Codex 模型称为 code-davinci-002。名为 ada、babbage、curie 和 davinci 的旧版 GPT-3 模型不遵循标准命名约定,它们主要用于微调(借助 Azure OpenAI 服务,你可以使用称为微调的过程根据个人数据集定制模型)3.4 查找可用的模型可以使用模型列表 API 获取 Azure OpenAI 资源可用于推理和微调的模型列表。3.5 查找适当的模型建议从模型系列中功能最强大的模型开始,以确认模型功能是否满足你的要求。 然后可以继续使用该模型,也可以迁移到功能和成本较低的模型,围绕此模型的功能进行优化。3.6 GPT-3 模型GPT-3 模型可以理解和生成自然语言。 该服务提供四个模型功能,每个都有不同级别的能力以及适用于不同任务的速度。 Davinci 是功能最强大的模型,而 Ada 是速度最快的模型。 模型排序(按功能从高到低的顺序):text-davinci-003text-curie-001text-babbage-001text-ada-001虽然 Davinci 能力最强,但其他模型提供了显着的速度优势。 我们的建议是让用户在试验时从 Davinci 开始,因为它能产生最佳结果并验证 Azure OpenAI 可以提供的价值。 原型正常工作后,就可以优化模型选择,为应用程序实现最佳延迟/性能平衡。3.6.1 Davinci(达芬奇)Davinci 是功能最强大的模型,可以执行其他模型能够执行的任何任务,并且所用的指令通常更少。 对于需要深入理解内容的应用程序(例如面向特定受众的摘要和创意内容的生成),Davinci 将产生最佳结果。 Davinci 提供的这些增加的功能需要更多计算资源,因此 Davinci 的成本更高,并且 Davinci 不如其他模型快。Davinci 擅长的另一个领域是理解文本的意图。 Davinci 擅长解决多种逻辑问题并解释字符动机。 Davinci 已经能够解决一些涉及因果关系的最具挑战性的 AI 问题。用途:复杂的意图、因果关系、受众摘要3.6.2 Curie(居里)Curie 功能强大,但速度很快。 虽然 Davinci 在分析复杂文本方面更强大,但 Curie 可以执行许多精细化的任务,例如情绪分类和摘要。 Curie 也善于回答问题和执行问答,适合用作常规服务聊天机器人。用途:语言翻译、复杂分类、文本情绪、摘要3.6.3 Babbage(巴贝奇)Babbage 可以执行简单的分类等简单任务。 在语义搜索方面,它的功能也很强大,可对文档与搜索查询的匹配程度进行排名。用途:中等分类、语义搜索分类3.6.4 Ada(艾达)Ada 通常是最快的模型,可以执行的任务有分析文本、地址更正和不需要太多细微差别的某些分类任务等等。 Ada 的性能通常可以通过提供更多上下文来改进。用途:分析文本、简单分类、地址更正、关键字3.7 Codex 模型Codex 模型是基模型 GPT-3 的子代,可以理解和生成代码。 它们的训练数据包含自然语言和来自 GitHub 的数十亿行公开代码。它们最擅长 Python,并且精通十几种语言,包括 C#、JavaScript、Go、Perl、PHP、Ruby、Swift、TypeScript、SQL 和 Shell。 Codex 模型排序(按功能从高到低的顺序):code-davinci-002code-cushman-001Davinci类似于 GPT-3,Davinci 是功能最强大的 Codex 模型,可以执行其他模型能够执行的任何任务,并且所用的指令通常更少。 对于需要深入了解内容的应用程序,Davinci 会生成最佳结果。 更强的功能需要更多计算资源,因此 Davinci 的成本更高,并且不如其他模型快。Cushman(库什曼)Cushman 功能强大,但速度很快。 虽然 Davinci 在分析复杂任务方面更强大,但 Cushman 是能够执行许多代码生成任务的模型。 Cushman 通常也比 Davinci 运行速度更快、成本更低。3.8 嵌入模型(搜索&算法&机器学习)3.8.1 嵌入模型系列嵌入是一种特殊的数据表示格式,可由机器学习模型和算法轻松使用。 嵌入是一段文本的语义含义的信息密集表示。 每个嵌入是浮点数的一个向量,向量空间中两个嵌入之间的距离与原始格式的两个输入之间的语义相似性相关。例如,如果两个文本相似,则它们的向量表示形式也应该相似。每个系列都包含某一功能范围的模型。 以下列表根据模型功能指示服务返回的数字向量长度:Ada:1024 个维度Babbage:2048 个维度Curie:4096 个维度Davinci:12288 个维度Davinci 功能最强,但比其他模型更慢更贵。 Ada 功能最弱,但速度更快且更成本更低。3.8.2 相似性嵌入此类模型擅长捕获两个或更多文本片段之间的语义相似性。用例模型聚类分析、回归、异常情况检测、可视化text-similarity-ada-001
text-similarity-babbage-001
text-similarity-curie-001
text-similarity-davinci-001
文本搜索嵌入此类模型有助于度量长文档是否与短搜索查询相关。 此系列支持两种输入类型:doc(用于嵌入要检索的文档)和 query(用于嵌入搜索查询)。用例模型搜索、上下文相关性、信息检索text-search-ada-doc-001
text-search-ada-query-001
text-search-babbage-doc-001
text-search-babbage-query-001
text-search-curie-doc-001
text-search-curie-query-001
text-search-davinci-doc-001
text-search-davinci-query-001
代码搜索嵌入与文本搜索嵌入模型类似,此系列支持两种输入类型:code(用于嵌入要检索的代码片段)和 text(用于嵌入自然语言搜索查询)。用例模型代码搜索和相关性code-search-ada-code-001
code-search-ada-text-001
code-search-babbage-code-001
code-search-babbage-text-001使用嵌入模型时,请注意其限制和风险。3.9 模型摘要表和区域可用性3.9.1 GPT-3 模型模型 ID支持补全支持嵌入基本模型区域微调区域ada是否空值美国东部2、美国中南部、欧洲西部text-ada-001是否美国东部2、美国中南部、欧洲西部空值babbage是否空值美国东部2、美国中南部、欧洲西部text-babbage-001是否美国东部2、美国中南部、欧洲西部空值curie是否空值美国东部2、美国中南部、欧洲西部text-curie-001是否美国东部2、美国中南部、欧洲西部空值davinci1是否空值美国东部2、美国中南部、欧洲西部text-davinci-001是否美国中南部、欧洲西部空值text-davinci-002是否美国东部、美国中南部、欧洲西部空值text-davinci-003是否美国东部空值text-davinci-fine-tune-0021是否空值美国东部、西欧1 仅能通过请求获取该模型。 目前,我们不接受使用该模型的新请求。
2 由于需求高,美国东部区域的新用户目前无法进行微调。 请使用美国中南部区域进行位于美国的训练。3.9.2 Codex 模型模型 ID支持补全支持嵌入基本模型区域微调区域code-cushman-0011是否美国中南部、欧洲西部美国东部2、美国中南部、欧洲西部code-davinci-002是否美国东部、西欧空值code-davinci-fine-tune-0021是否空值美国东部2、西欧1 仅能通过请求将该模型用于微调。 目前,我们不接受微调该模型的新请求。
2 由于需求高,美国东部区域的新用户目前无法进行微调。 请使用美国中南部区域进行位于美国的训练。3.9.3 嵌入模型模型 ID支持补全支持嵌入基本模型区域微调区域text-ada-embeddings-002否是美国东部、美国中南部、欧洲西部空值text-similarity-ada-001否是美国东部、美国中南部、欧洲西部空值text-similarity-babbage-001否是美国中南部、欧洲西部空值text-similarity-curie-001否是美国东部、美国中南部、欧洲西部空值text-similarity-davinci-001否是美国中南部、欧洲西部空值text-search-ada-doc-001否是美国中南部、欧洲西部空值text-search-ada-query-001、否是美国中南部、欧洲西部空值text-search-babbage-doc-001否是美国中南部、欧洲西部空值text-search-babbage-query-001否是美国中南部、欧洲西部空值text-search-curie-doc-001否是美国中南部、欧洲西部空值text-search-curie-query-001否是美国中南部、欧洲西部空值text-search-davinci-doc-001否是美国中南部、欧洲西部空值text-search-davinci-query-001否是美国中南部、欧洲西部空值code-search-ada-code-001否是美国中南部、欧洲西部空值code-search-ada-text-001否是美国中南部、欧洲西部空值code-search-babbage-code-001否是美国中南部、欧洲西部空值code-search-babbage-text-001否是美国中南部、欧洲西部空值四. 定价详细信息:4.1 Language models模型Per 1,000 tokens标准Text-Ada$0.0004Text-Babbage$0.0005Text-Curie$0.002Text-Davinci$0.02Code-Cushman$0.024Code-Davinci$0.10ChatGPT (gpt-3.5-turbo)$0.0024.2 Image models(图片生成模型)模型Per 100 images标准Dall-E$24.3 Fine-tuned models(微调的模型)模型Per 1,000 tokens标准Text-Ada$0.0004Text-Babbage$0.0005Text-Curie$0.002Text-Davinci$0.02Code-Cushman$0.024模型Training per compute hour标准Text-Ada$20Text-Babbage$22Text-Curie$24Text-Davinci$84Code-Cushman$26模型Hosting per hour标准Text-Ada$0.05Text-Babbage$0.08Text-Curie$0.24Text-Davinci$3Code-Cushman$0.544.4 Embedding models模型Per 1,000 tokens标准Ada$0.0004Babbage$0.005Curie$0.02Davinci$0.20备注本文内容来自微软官方,个人只是做了一些简单的整理和标注,顺便分享给有兴趣的同学。
软件工程高效学 | 实战案例:在线选修课程管理系统设计
01、实战案例——在线选修课程管理系统设计本文以“在线选修课程管理系统”案例为示例,利用Rational Rose进行面向对象设计实战。该系统的需求描述如下。教师选择本学期要教授的课程。教师选课结束后,教务管理人员进行协调和确认教师的课程,并创建本学期的课程目录表,向学生公布。学生填写课程选修表。学生按最终的课程表到财务处办理收费手续(Billing System)。教师可查询所教课程的学生花名册(Roster)。教务管理人员维护学生、教师和课程的信息。构建用例模型① “在线选修课程管理系统”中的执行者(Actors)。注册选修课程的学生。教授选修课程的教师。教务管理人员必须汇总选修课程情况,制作课程表。教务管理人员必须维护关于课程、教师和学生的所有信息。财务管理系统从本系统中取出收费信息。② “在线选修课程管理系统”中的用例(Use Case)。步骤1: 使用Rational Rose创建执行者(Actors)。首先右击浏览器窗口中的Use Case View包,弹出快捷菜单后,选择New→Actor项,并输入执行者的名字(如果输入错误,可用Rename命令更改);如果文档窗口不可见,选择菜单和工具栏中的View→Documentation菜单,然后在浏览器窗口中选中所需执行者,输入相应文档。创建结果如图1所示。■ 图1 执行者创建结果步骤2: 使用Rational Rose创建用例(Use Case)。首先右击浏览器窗口中的Use Case View包,弹出快捷菜单后,选择New→Use Case项并输入用例的名字;然后在浏览器窗口中选中所需用例;将光标置于文档框中,输入相应文档。创建结果如图2所示。■ 图2用例创建结果步骤3:使用Rational Rose创建主用例图(Main Use Case Diagram)。首先双击浏览器窗口的Use Case View包中的Main条目,打开主用例图;然后单击选中浏览器窗口中的“执行者”,将其拖到主用例图中;随后单击选中浏览器窗口中的“用例”,并将其拖到主用例图中;最后,在工具栏中选择“单向关联”(Unidirectional Association)图标,单击一个“执行者”,并拖到相应的用例上;或单击一个“用例”,并拖到相应的执行者上。创建结果如图3和图4所示。■ 图3主用例图创建结果(1)■ 图4 主用例图创建结果(2)构建活动图模型本部分主要介绍建立选修课程目录表的步骤。步骤1: 使用Rational Rose创建活动图(Activity Diagram)。首先右击浏览器窗口中的Use Case View包,弹出快捷菜单后选择New→Activity Diagram项,然后输入活动图的名字;双击浏览器窗口中的Activity Diagram选项,打开该图。创建结果如图5所示。步骤2: 使用Rational Rose创建活动(Activity)。首先在工具栏中选择Activity 图标,在活动图(Activity Diagram)中单击要放置“活动”(Activity)的位置,输入活动名字;然后在工具栏中选择State Transition图标,单击一个“活动”,并将其拖到相应的活动上。创建结果如图5所示。步骤3: 使用Rational Rose创建决策点(Decision Points)。首先,在工具栏中选择Decision图标,在活动图(Activity Diagram)中单击要放置决策点的位置,并输入决策的名字;其次,在工具栏中选择State Transition图标,单击一个“活动”,并将其拖到相应的决策点上;然后,在工具栏中选择State Transition图标,单击一个“决策点”选项,拖至拐角处单击左键,再将其拖到相应的活动上;随后,双击此条“转换线”,打开规格设定框,单击Detail 标签,在Guard Condition框中输入条件No,单击OK按钮,关闭规格设定框;最后,在此条转换线上单击左键,选中此条“转换线”,单击菜单和工具栏中的Format→Line Style→Rectilinear 选项,使其变得美观,调整过程如图4-21所示,调整完成后,创建结果如图6所示。■ 图6 创建决策点调整过程■ 图7 决策点创建结果步骤4:使用Rational Rose创建同步条(Synchronization Bar)。首先在工具栏中选择Horizontal Synchronization图标;然后在活动图(Activity Diagram) 中单击要放置同步条的位置;最后在工具栏中选择State Transition图标;创建结果如图8所示。■ 图8 同步条创建结果步骤5:使用Rational Rose创建泳道(Swim lanes)。首先在工具栏中选择Swim lanes图标,在活动图(Activity Diagram)中单击要放置泳道的位置;然后双击泳道,打开规格说明框,在Name框中输入泳道的名字,单击OK按钮,关闭规格设定框;最后对泳道的大小位置进行调整,将所需的活动和变换线拖至新泳道中。创建结果如图9所示。■ 图9 泳道创建结果步骤6: 使用Rational Rose创建起始活动和终止活动。首先在工具栏中选择“起始活动”或“终止活动”图标,在活动图(Activity Diagram)中单击要放置“起始活动”或“终止活动”的位置;然后在工具栏中选择State Transition图标,单击“起始活动”图标,拖到相应的活动上;最后单击一个“活动”图标,拖至“终止活动”图标上。创建结果如图10所示。■ 图10 创建起始活动和终止活动构建相关的包和类以及简单类图步骤1: 在Rational Rose的浏览器窗口中创建类(Class)。首先右击浏览器窗口中的Logical View,弹出快捷菜单后,选择New→Class项,输入类的名字;然后在所建类上单击右键,弹出快捷菜单,选择Open Specification项,单击General标签;最后在Stereotype框中选择entity类;单击OK按钮关闭规格说明框。规格说明框的设置过程如图11所示。■ 图11规格说明框设置过程表1列出了边界类、控制类、实体类各自的功能。■ 表1 边界类、控制类、实体类功能步骤2: 在Rational Rose的浏览器窗口中创建包(Packages)。首先右击浏览器窗口中的Logical View选项,弹出快捷菜单后,选择New→Package选项,输入包的名字;然后新建相关类并设置其相应的类别,其中设置边界类和控制类的过程如图12和图13所示;最后单击浏览器窗口中的“类”选项,将其拖至相应的包中。■ 图12 设置边界类过程示意图■ 图13 设置控制类过程示意图在Package项中,PeopleInfo包用来存放与人员有关的内容,Interfaces包用来存放与界面有关的内容,UniversityArtifacts包用来存放与学校工件有关的内容。步骤3: 在Rational Rose中创建主类图(Main Class Diagram)。首先双击浏览器窗口中Logical View中的Main类图,打开它;然后单击浏览器窗口中的包,将其拖到Main类图上;重复以上步骤后,创建结果如图14所示。 ■ 图14 主类图创建结果步骤4: 在Rational Rose中创建包中的主类图(Package Main Class Diagram)。首先双击Main 类图中的University Artifacts包,打开这个包,并创建这个包的主类图(Package Main Class Diagram);然后,单击浏览器窗口中的“类”图标,将其拖到类图上;重复以上步骤,最后创建结果如图15所示。■ 图15 包中的主类图创建结果(4) 构建用例实现图(Use Case Realization Diagram)。使用Rational Rose创建逻辑视图中的用例图(Use Case Diagram)。首先,右击浏览器窗口中的Logical View选项,弹出快捷菜单后,选择New→Use Case Diagram选项,输入用例图的名字“Realizations”;其次,右击浏览器窗口中的Logical View选项,弹出快捷菜单后,选择New→ Use Case选项,输入用例的名字;然后双击新建的“用例”选项,打开用例的规格设定框,单击Stereotype框,选择use-case realization选项,规格设定过程如图16所示。重复以上过程,用例的创建结果如图17所示。最后,打开实现用例图,将新建的“实现用例”拖入图中,创建结果如图18所示。■ 图16 用例规格设定过程■ 图17 用例创建结果■ 图18 用例实现图创建结果构建顺序图(Sequence Diagram)与协作图(Collaboration Diagram)步骤1: 使用Rational Rose创建顺序图(Sequence Diagram)。首先,右击Logical View中的Maintain course information实现用例,弹出快捷菜单后,选择New→Sequence Diagram选项,然后输入顺序图的名字“Create a course”;创建结果如图19所示。■ 图19 顺序图创建结果图步骤2:在顺序图中创建对象和分配类。首先,双击顺序图名称,打开顺序图,将浏览器窗口中Use Case View包中的执行者Registrar拖入图中;其次,选择工具栏中的Object图标,单击图中放置对象的位置,并输入相应的名字,重复以上步骤;然后,选择工具栏中的Object Message图标,从信息发出者拖至信息接收者,并输入信息的名字,重复以上步骤,创建对象完成后结果如图20示;最后,单击选中浏览器窗口中所需的类,将此类拖至顺序图相应的对象上,对象分配类后,结果如图21所示。■ 图20 创建对象结果■ 图21 对象分配类结果步骤3:将顺序图转换为协作图。首先,双击顺序图名称,打开顺序图;然后选择屏幕上方的菜单Browser→Create Collaboration Diagram选项,或者按F5键;最后调整图中的对象和信息,使其美观。创建结果如图22所示。■ 图22 顺序图转换为协作图创建结果构建状态图(Statechart Diagram)步骤1:使用Rational Rose创建状态图(Statechart Diagrams)。首先,右击浏览器窗口中的CourseOffering类,弹出快捷菜单后,选择New→Statechart Diagrams选项;然后,输入状态图的名字“CourseOffering States”,创建结果如图23所示。■ 图23 状态图创建结果步骤2: 使用Rational Rose创建状态(States)。首先,在工具栏中选择State图标,在状态图中单击要放置状态的位置;然后,输入状态的名字。创建结果如图24所示。■ 图24 状态创建结果步骤3: 使用Rational Rose创建状态转换(State Transitions)。首先,在工具栏中选择State Transitions图标,单击“起始状态”,并拖至下一个状态;然后,输入状态转换的名字。创建结果如图25所示。■ 图25 状态转换创建结果步骤4:使用Rational Rose创建起始、结束状态。首先,在工具栏中选择Start图标,在状态图中单击要放置起始状态的位置;然后,用状态转换线进行连接。起始状态创建结果如图26所示。图26 起始状态创建结果同样地,在工具栏中选择Stop图标,在状态图中单击要放置结束状态的位置,用状态转换线进行连接,结束状态的创建结果如图27所示。图27 结束状态创建结果步骤5: 使用Rational Rose增加状态转换的细节部分。首先,双击某条转换线,打开规格设定框,单击Detail标签;然后,在相应的框中输入action(/后的内容)、guard condition([ ]里的内容)以及发出的event(^后的内容);最后,单击OK 按钮,关闭规格设定框。创建结果如图28所示。■ 图28 状态转换规格设定结果步骤6: 使用Rational Rose增加状态的Actions部分。首先,双击某个状态,打开规格设定框,单击Actions标签;然后,右击Actions框中的任一位置,弹出快捷菜单后,选择Insert选项,将创建一个类型为Entry的action,规格设定过程如图29所示;■ 图29 状态的Actions设定过程双击这个action,弹出action的规格设定框后,在when框中设定相应的类型,在type框中设定action或者send event(用^表示),输入action的名字或event的信息;单击OK按钮,关闭Actions规格设定框。创建结果如图30所示。■ 图30 状态的Actions设定结果构建构件图(Component Diagram)步骤1: 使用Rational Rose创建Main构件图(Component Diagram)。首先,在浏览器窗口中的Component View中创建图中的各个构件包,双击浏览器窗口中的Component View中的Main 构件图;然后,将浏览器窗口中的Component View中的构件包拖入图中;最后创建包之间的依赖线。创建结果如图31所示。■ 图31 Main构件图创建结果步骤2: 创建University构件包中的构件。首先,双击Main构件图中的University包,打开图形;然后,在工具栏中选择Component图标;最后,单击图中某一位置,放置构件,输入构件名称。创建结果如图32所示。■ 图32 University构件包中的构件创建结果步骤3: 将类映射到构件上。首先,右击浏览器窗口中的CourseOffering构件,弹出快捷菜单后,选择Open Specification项,单击Realizes标签;然后,右击所需的类,弹出快捷菜单,选择Assign项;最后,单击OK按钮,关闭规格设定框。创建过程如图33所示。■ 图33 将类映射到构件上构建部署图(Deployment Diagram)使用Rational Rose创建部署图(Deployment Diagram)。首先,双击浏览窗口中的“部署图”(Deployment Diagram)选项,选择工具栏中的Processor图标,并单击图中某一位置,输入结点的名字;然后,选择工具栏中的Connection图标,单击某一结点,拖至另一结点;最后,选择工具栏中的Text 图标,在相应结点下写上文字。创建结果如图34所示。■ 图34 部署图创建结果
JVM学习.05 JVM常见的排障和调优
1、前言前面介绍了JVM相关的内存和线程相关的技术。对于JVM也算有了一个比较系统、完整的理论基础。理论总是作为指导实践的工具,但是从理论到实践,总会遇到一些虚拟机相关问题,故障。所以还需要学习一些常用的JVM排障工具,和一些常见的调优手段。2、故障排查常用工具2.1、命令行工具2.1.1、jpsJVM Process Status Tool(jps)虚拟机进程状态工具。顾名思义主要用来查看虚拟机进程,并显示虚拟机执行主类名称和这些进程的状态等。同Linux的PS指令类似。jps命令格式为:jps [option] [hostid]示例:参数:选项作用-q只输出LVMID(进程的本地虚拟机唯一ID),省略主类名称-m输出虚拟机进程启动时传递给main()的参数-l输出主类的全限定名,如果进程执行的式jar包,则输出jar的路径-v输出虚拟机进程启动的JVM参数2.1.2、jstatJVM Statistics Monitoring Tool(jstat),虚拟机统计信息监控工具。用于监视虚拟机各种运行状态信息。可以显示虚拟机进程的类加载、内存、垃圾收集、即时编译等运行时数据。jstat命令格式为:jstat [option vmid [interval [s|ms] [count] ] ]示例:S0,S1:代表Survivor0、Survivor1区E:表示Eden区O:表示老年代M:表示永久代(元空间)CCS:表示压缩类空间YGC:表示Young GCYGCT:表示Young GC Time,耗时FGC:表示Full GCFGCT:表示Full GC Time,耗时CGC:表示并发GC次数CGCT:表示并发GC耗时GCT:表示GCV Time,GC总耗时/** * -gcutil 查看gc情况 * 7864 为进程pid * 500 每间隔500ms执行一次 * 10 总共执行10次 * 所以下面的命令为:每间隔500ms,查询一次进程id为7864的gc情况,一共查询10次 */ jstat -gcutil 7864 500 10参数(参数选项比较多,列举一些常用的,其他的自行查找):选项作用-class监视类加载信息、卸载数量、总空间以及类加载的耗时-gc监视Java堆情况-gccause功能同-gcutil,但是会额外输出导致上一次gc产生的原因-gcutil功能同-gc相同,但输出主要关注的已使用空间占总空间的百分比-compiler输出即使编译过的方法,耗时等2.1.3、jmapMemory Map for Java(jmap),用于生成JVM某一时刻运行的堆快照,即heapdump或dump文件。除了转储外,还可以查看当前的堆和方法区的详细信息等。除了使用jmap,可以指定-XX:+HeapDumpOnOutOfMemoryError参数,可以让虚拟机出现内存溢出后自动生成dump文件。注意:请尽可能不要在生产环境中使用jmap -dump来转储整个内存的dump文件。因为在dump过程中,会暂停所有执行线程的业务逻辑。会直接暂停线上业务的响应。jmap命令格式为:jmap [option ] vmid示例:参数:选项作用-dump生成Java堆快照。格式为:jmap -dump:format=b,file=F://heap001.hprof {PID}jmap -dump:live,format=b,file=F://heap001.hprof {PID} // live说明只dump出存活的对象-heap监视Java堆情况。只在Linux平台下有效-histo显示队中对象统计信息,包括类,实力数量,合计容量-gcutil功能同-gc相同,但输出主要关注的已使用空间占总空间的百分比-F当虚拟机进程堆-dump选项无响应时,可使用这个选项强制生成dump快照。只在Linux平台下有效2.1.4、jhatJVM Heap Analysis Tool(jhat),虚拟机堆快照分析工具。一般与jmap搭配使用。用来分析jmap生成的对快照。内置了一个微型的http/web服务器,分析结果可以通过浏览器访问既定的端口进行查看。但是个人建议可以使用第三方工具进行分析,如常用的MAT,jProfile等。jhat命令格式为:jhat -port 8080 d://xxx.hprof接着访问http://localhost:8080即可。如果不指定-port 默认为7000。示例:2.1.5、jstackStack Trace for Java(jstack),堆栈跟踪工具。用于生成JVM当前时刻的线程快照,一般为threaddump或javacore文件。线程快照就是当前JVM内每一条线程正在执行的方法堆栈的集合,一般生成快照用于定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致长时间挂起等原因。jstack命令格式为:jstack [option] vmid示例:参数:选项作用-F当正常输出的请求不被响应时,强制输出线程堆栈-l出堆栈外,显示关于锁的附加信息-m如果调用到本地方法的话,可以显示c/c++的堆栈2.2、可视化工具2.2.1、jConsoleJava Monitoring and Management Console(jConsole),Java监视与管理控制台。是一个基于JMX的可视化监控,管理工具。其中一项我常用的功能是通过JMX的MBean堆系统进行信息收集和参数动态调整。如一次线上的最大可用线程过载,就是通过MBean中临时调整参数恢复业务的。2.2.2、jvisualvmAll-in-One Java Troubleshooting Tool(VisualVM),我认为是JDK自带的监控和故障处理能力最强大的程序之一。也是我们平时使用最经常的JVM排障工具。它不仅包含了常规的运行监控,故障处理外,还提供了比如性能分析等额外功能。另外jvisualvm还支持安装插件,可以通过插件平台扩展该工具的功能。jvisualvm除了可以监视本地进程外,还可以通过JMX远程连接。java启动程序的时候,可以通过启动参数配置JMX相关信息即可。在工具菜单栏选择插件,可以自由安装想要的插件:2.3、第三方工具2.3.1、jProfileJProfiler是一个商业授权的Java剖析工具,由EJ技术有限公司,针对的Java EE和Java SE应用程序开发的。它把CPU、执行绪和内存的剖析组合在一个强大的应用中。JProfiler可提供许多IDE整合和应用服务器整合用途。JProfiler的是一个独立的应用程序,但其提供Eclipse和IntelliJ等IDE的插件。它允许两个内存剖面评估内存使用情况和动态分配泄漏和CPU剖析,以评估线程冲突。----来自百度百科2.3.2、MATEclipse Memory Analyzer (MAT)是一个快速且功能丰富的Java堆分析器,可帮助您发现内存泄漏并减少内存消耗。----来自百度百科2.3.3、arthasarthas,阿里开源的Java实时性能监控和问题排查工具。强烈推荐。具体使用方式可以参照我另一篇博客《java线上项目排查,Arthas简单上手》。3、常用的调优策略3.1、 编码阶段的预防良好的编码习惯可以减少一些常见的问题,也能使程序的性能提高。以下例举常见的几个编码阶段问题:3.1.1、避免短命大对象如byte[]。JVM中,大对象需要大量连续的内存空间,如很长的字符串或者元素数量很庞大的数组。jvm在分配空间时,有时候需要提前进行GC,以获取足够的空间分配。可以通过-XX:PretenureSizeThreshold指定大于该值的对象直接分配在老年代。3.1.2、变量作用域尽可能控制变量的作用域范围,尽可能不要定义全局变量。3.1.3、String操作String操作,尽可能使用Stringbuffer或者Stringbuilder,尽量减少字符串的+拼接。3.1.4、锁操作注意锁的粒度和范围。尽可能精确缩小锁的粒度。能不用锁就不用锁,能锁区块就不要锁整个方法体,能用对象锁,就不要用类锁。3.2、部署阶段的预防3.2.1、选用合适的硬件和软件设施很多性能问题,大部分可以通过氪金的方式解决。如果通过氪金的方式解决,效率是最高的(当然要看实际情况)。这里指的选用合适版本并不是氪金,选用配置越高越好,主要指的是做好程序的规划,业务体量,以及良好的程序设计和部署用例。做好CPU密集型和IO密集型的业务处理,如果IO密集型的,就选用IOPS高的磁盘等等。3.2.2、压力测试程序编码完成后,做一些压力测试。一个好的程序不仅要满足功能需求,更需要满足非功能性需求。压力测试正式验证这些非功能性需求是否负责指标的一个有力手段。宁愿问题在测试阶段发生,也尽量避免在生产阶段发生。3.3、常用的JVM参数配置-Xms512M 设置Heap 空间最小值-Xmx512M 设置Heap 空间最大值-Xmn200M 设置Young区大小-Xss 256K 设置线程栈大小-XX:MaxGCPauseMillis=500 垃圾回收器最大的停顿时间-XX:+UseG1GC 指定G1垃圾回收器(具体使用哪个垃圾回收期可以视程序要求而定)-XX:NewRatio 新老生代的比值-XX:+HeapDumpOnOutOfMemoryError 启动堆内存溢出打印-XX:HeapDumpPath=heap.hprof 指定Heap快照打印位置-XX:MinHeapFreeRatio jvm heap 在使用率小于n时,heap进行收缩-XX:MaxHeapFreeRatio jvm heap 在使用率大于n时,heap进行扩张3.4、问题排查和分析3.4.1、CPU过载CPU过高,可以通过top命令排查各个进程的资源占用情况。结合-Hp参数找到CPU过多的线程。如果一台服务器部署应用过多,出现CPU争用情况,可以自主分配具体CPU核心,错开CPU核心使用。具体参照我另一篇博客《windows系统启动java程序限制cpu核心数》。3.4.2、线程死锁可以使用jstack或者jvisualvm或arthas分析当前锁的情况进行排查。3.4.3、OOM出现OOM,先要观察报错类型。java.lang.OutOfMemoryError: java heap spaceheap溢出.检查是否存在内存泄漏问题. 分析堆栈对象情况java.lang.OutOfMemoryError: Meta space可通过JVM类加载的情况进行排查.jstat或者实时监测工具排查..java.lang.OutOfMemoryError:GC over head limit exceeded系统处于高频的GC状态,而且回收的效果依然不佳的情况分析GC日志曲线集合堆栈分析排查.关于OOM问题,个人经验在启动参数中加入-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=heap.hprof 指定溢出时候的dump文件生成目录,一旦生产出现OOM问题,需要紧急恢复情况下,大多数会采用重启的方案(前提是单机应用,且业务需要紧急恢复的情况,而且重启能解决99%的问题,如果不行,那就重启2次)。一旦重启后,内存镜像丢失就不利于接下来的问题分析和定位。所以配置完参数后,出现oom问题,系统自动帮我们dump当下的内存文件,我们就可以放心大胆重启了。然后再逐步分析hprof文件。......应该还有很多,这就不一一例举了,目前仅能想到这么多。4、小结前面几篇分别介绍了JVM的一些结构体系。对于Java程序员来说,不管是项目中,还是面试,经常会遇到关于JVM相关的问题。同时通过对JVM的深入学习,能够更加从容应对JVM底层相关的一些问题以及解决措施。