引言
系统运行的表现通常会受到多种参数变量的影响.参数取值的两两组合,其可能的组合数是非常大的.如何比较好且快速地找到合适的参数呢?今天要讨论的就是使用优化技术来试图解决这样一种问题.由于 python 对计算和算法提供了很好支持,本文采用 python 来进行问题的描述和解决.
问题描述
在如下图所描述的服务模型中,分为交易层 - 创建需要处理的交易任务,服务层 - 异步处理交易任务.其中,交易层需要配置交易处理的并发数 dealconfig,用来控制创建交易任务的效率;服务层需要配置处理交易任务的并发数 serverconfig,用来控制处理交易任务的效率.
服务模型
所以我们需要找到一组 dealconfig,serverconfig 的配置,定义如下:
configs=['dealconfig','serverconfig']
使得系统运行是良好的,并且知道在这组配置下,打印系统预期的运行情况:
def printsolution(vec):
print configs[0],vec[0],dealcount(vec[0])
print configs[1],vec[1],servercount(vec[1])
其中 vec 代表配置项的一组可能的解,例如 [20,34],dealcount() 用于计算在当前交易并发配置时,交易创建的预期 tps(dealtps),servercount()用于计算在当前服务并发配置时,交易处理的 tps(servertps).接下来我们就要确定一下这两个函数.
确定配置项与 TPS 之间的关系函数
通过《 构建自动化性能测试系统的实践 》的方式,我们很容易构建在不同配置项下的压力测试,进而得到不同配置项下的 tps 数据:
例如:dealconfig 与 dealtps 数据:
交易配置与交易创建 tps 数据表
交易配置与交易创建 tps 数据走势图
从走势图,我们可以把数据分为 3 段:[0,70],[70,100],[100,150],来确定 dealcount() 函数.
对于 [0,70], 使用分段线性拟合得到 dealconfig 和 dealtps 的关系.
python 的线拟合代码如下:
import numpy as np
def get1function(x,y):
z = np.polyfit(x, y, 1)
print z
x 即为 [0,70],y 为 x 对应的值,z 即为一元方程的系数.
运行后,可得方程:y=200x
对于 x 在 [70,100],y=14000
对于 x 在 [100,150],y=-77x+21476
所以,我们可以得到 dealcount() 方法如下:
def dealcount(cno):
if cno <= 70 : return 200*cno
elif cno >70 and cno <= 100: return 14000
else : return -77*cno + 21476
对于 serverconfig 与 servertps 数据:
服务配置与交易处理 tps 数据表
采用分段线性拟合后,可以确定 servercount() 函数:
def servercount(cno):
if cno <=30 : return 4.9*cno - 1
elif cno >30 and cno <= 50:return -0.25*cno+148
elif cno >50 and cno <= 80: return -0.45*cno+46
else:return 10
这两个函数的参数:cno 应落在 [0,150].
成本函数
在使用优化算法时,需要比较那种配置项下的成本是低,用来确定出合适的配置.成本函数要求返回的值越大说明成本越高,该方案越差.在本例中,考虑的成本因素有:
1,dealertps 越大越好,且若是小于 10000,则成本相应升高
2,servertps 越大越好,且若是小于 100,则成本相应升高
3,dealertps 与 servertps 同样重要,分值提现应该在一个数量级上
基于这三点考虑,构造的成本函数如下:
def configcost(vec):
dcount = dealcount(vec[0])
scount = servercount(vec[1])
cost = -(dcount + scount*100)+(10000-dcount)+(100-scount)*100
return cost
优化算法
常见的优化算法:随机搜索,爬山法,模拟退火算法,遗传算法等[1] .优化算法至少需要传入参数值域,成本函数,输出一组解.这里以模拟退火算法做个例子,代码如下:
模拟退火的实现:
def annealingoptimize(domain,costf,T=10000.0,cool=0.95,step=1):
vec=[random.randint(domain[i][0],domain[i][1]) for i in range(len(domain))]
while T>0.1:
i=random.randint(0,len(domain)-1)
dir=random.randint(-step,step)
vecb=vec[:]
vecb[i]+=dir
if vecb[i]
elif vecb[i]>domain[i][1]:vecb[i]=domain[i][1]
ea=costf(vec)
eb=costf(vecb)
if (eb
vec=vecb
T=T*cool
return vec
其中 domain 表示值域,根据之前的测试数据,应在 [0,150],定义如下:
domain= [(0,150) for i in range(len(configs))]
costf 表示成本函数,即为 configcost()
运行
自此,我们先后确定了配置项与 tps 之间的关系函数,成本函数,优化算法.现在只需要将其运行起来即可:
s=annealingoptimize(domain,configcost)
print configcost(s)
printsolution(s)
得到:
-23150.0
dealconfig 39 7800
serverconfig 41 137.75
表示:成本值为 - 23150,dealconfig 为 39,dealtps 为 7800,serverconfig 为 41,serverconfig 为 137.75.
如果运行多次,会得到不同的解,这和成本函数是相关的,如下成本曲线图所示:
成本曲线
通常我们可能取到的是在一定范围内的成本最优的解,而不是整体最优解.
[1] 由于超出能力范围,没对算法做具体的说明,见谅.
欢迎批评指正,共同学习进步.
来源: http://www.jianshu.com/p/31faa928952a