暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

开源 SQL分析工具【SOAR】剖析与优化

炬南山 2020-02-19
2859

一、soar-web部署

1.1 简介

soar-web是一款基于小米【SOAR】(https://github.com/XiaoMi/soar) 的开源 SQL 分析与优化的 web 图形化工具,支持 SOAR 配置的添加、修改、复制,多配置切换,配置的导出、导入与导入功能。

soar-web的github地址:https://github.com/xiyangxixian/soar-web



1.2 安装部署

python环境:需要安装python3.x

依赖包有3个,使用pip安装或者离线包安装。

Flask

pymysql

pycryptodome

离线安装采用下载soar-web的压缩包

https://codeload.github.com/xiyangxixian/soar-web/zip/master

解压后启动方式为执行run.sh。


二、soar-web的主要功能架构说明


2.1Flask框架简要说明

Flask是一个用Python编写的Web应用程序框架。Armin Ronacher带领一个名为Pocco的国际Python爱好者团队开发了Flask。Flask基于WerkzeugWSGI工具包和Jinja2模板引擎。两者都是Pocco项目。

Flask也被称为“microframework” ,因为它使用简单的核心,用extension增加其他功能。Flask没有默认使用的数据库、窗体验证工具。

目录结构上按照惯例, 模板和静态文件存放在应用的Python 源代码树的子目录中,名称分别为 templates 和 static 。

一个最基本的flask应用如下:

(注:摘自https://www.w3cschool.cn/flask/flask_application.html

from flask import Flask

app = Flask(__name__)

@app.route('/')

def hello_world():

  return 'Hello World’

if __name__ == '__main__':

  app.run()

必须在项目中导入Flask模块。Flask类的一个对象是我们的WSGI应用程序。

Flask构造函数使用当前模块(__name __)的名称作为参数。

Flask类的route()函数是一个装饰器,它告诉应用程序哪个URL应该调用相关的函数。

app.route(rule, options)

·        rule 参数表示与该函数的URL绑定。

·        options 是要转发给基础Rule对象的参数列表。

在上面的示例中,'/ ' URL与hello_world()函数绑定。因此,当在浏览器中打开web服务器的主页时,将呈现该函数的输出。

最后,Flask类的run()方法在本地开发服务器上运行应用程序。

app.run(host, port, debug, options)

所有参数都是可选的

序号

参数与描述

1

host

要监听的主机名。 默认为127.0.0.1(localhost)。设置为“0.0.0.0”以使服务器在外部可用

2

port

默认值为5000

3

debug

默认为false。 如果设置为true,则提供调试信息

4

options

要转发到底层的Werkzeug服务器。

上面给出的Python脚本是从Python shell执行的。

Python Hello.py

Pythonshell中的消息通知您:

* Running on http://127.0.0.1:5000/(Press CTRL+C to quit)

在浏览器中打开上述URL(localhost:5000)。将显示“Hello World”消息。


2.2小米soar-web源码说明

其核心采用轻量级的web应用Flask框架编写,主要功能点《SQL评估》菜单涉及到的函数方法如下图所示。


前端web的SQL评估、美化、压缩、指纹、语法检查、SQL改写,在前端的URL为/soar-api ,转由后端soar-web.py的soar()方法实现。

其中decrypt()方法解密提交的post内容,采用AES对称加密算法对明文进行加密,然后把对称密钥使用RSA算法的公钥进行加密,传回给服务器,soar_args_check()为检查参数是否正确,检查通过之后,提交给soar_result()方法做SQL审核等操作。

加密方式为RSA非对称加密算法+AES对称加密的结合,生成公钥密钥的方法在初始化check_env()里面,代码如下:


其中check_env()方法中,介绍了如何创建密钥对。


RSA算法简介1977年,三位数学家 Rivest、Shamir 和 Adleman 设计了一种算法,可以实现非对称加密。算法用他们三个人的名字命名,叫做RSA算法。

采用公钥加密的明文,只有私钥可以解密(用于客户端向服务端传数据的场景),使用私钥加密的明文,也只能采用公钥解密(用于数字证书的场景),这就是非对称加密。

AES算法简介密码学中的高级加密标准(Advanced Encryption Standard,AES),又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。

至于为什么不直接使用RSA加密传送的data呢?因为非对称加密的公钥是对外公开的,如果服务器要回传data给客户端时,采用私钥加密data,那么其他用于公钥的人也能解密data,所以正常情况都是采用RSA非对称加密客户端生成的AES对称密钥,用这个AES对称密钥加密data,然后把RSA加密的密钥和密文传给服务器进行解密。

在python当中,可以直接安装Crypto模块,实现RSA和AES算法,解密的过程如下所示:

其中pkcs是公钥加密标准(Public Key Cryptography Standards, PKCS),此一标准的设计与发布皆由RSA信息安全公司所制定。源码用的标准是PKCS#1:定义RSA公开密钥算法加密和签名机制,主要用于组织PKCS#7中所描述的数字签名和数字信封。

因为加密的编码采用base64,所以解密这边对应的也是base64。

加密解密部分的源码介绍完,回到我们最初的SQL审核究竟是怎样实现的,直接使用soar的话,SQL审核命令格式为:

sh ./soar.linux-amd64 -config ./uuid.yaml-query 待评审SQL语句或SQL语句文件路径

soar_result()的功能就是将post的内容,校验合格之后,转换为可执行文件的命令行参数,提交给后台shell执行(通过python的subprocess模块),并将执行结果反馈给前端。

例如在页面提交的SQL语句为“select * from dual”,soar_result()就是将其转为./soar.linux-amd64-config ./uuid.yaml -query 'select * from dual',并通过subprocess.Popen在shell当中执行。

soar_result()源码如下:

其中soar_run_uuid生成临时文件的唯一路径,用于写入soar二进制程序的配置文件的参数、日志和黑名单,这些临时文件在soar_result()执行的最后删除掉。

req_parse2cmd_parse()将json参数转为一行可执行的命令行参数列表。

runcmd()为执行外部命令,该方法为:

这是通过python的subprocess这个模块来产生子进程,并连接到子进程的标准输入/输出/错误中去,还可以得到子进程的返回值。

subprocess.Popen参数如下:

本文用的参数说明

1.args参数:可以是一个字符串,可以是一个包含程序参数的列表。要执行的程序一般就是这个列表的第一项,或者是字符串本身。例如以下都可行:

subprocess.Popen(["cat","test.txt"])

subprocess.Popen("cattest.txt")

2.shell参数:如果把shell设置成True,指定的命令会在shell里解释执行,默认为False。

3.cwd参数:如果cwd不是None,则会把cwd做为子程序的当前目录。

4.stdinstdout和stderr,分别表示子程序的标准输入、标准输出和标准错误。可选的值有PIPE或者一个有效的文件描述符(其实是个正整数)或者一个文件对象,还有None。如果是PIPE,则表示需要创建一个新的管道,如果是None,不会做任何重定向工作,子进程的文件描述符会继承父进程的。另外,stderr的值还可以是STDOUT,表示子进程的标准错误也输出到标准输出。

5.universal_newlines参数:如果把universal_newlines 设置成True,则子进程的stdout和stderr被视为文本对象,并且不管是*nix的行结束符('/n'),还是老mac格式的行结束符('/r' ),还是windows 格式的行结束符('/r/n' )都将被视为 '/n' 。


2.3原版存在的小问题

原版对sql语句的长度是有限制的,因为是把sql语句直接提交在命令行参数里面。

所以在实际使用中,如果我们提交了超长的sql,那么就会报错,如下图所示。


原因是源码的调用命令行分析SQL语句的时候,是把SQL语句当作字符串处理,提交在命令行当中,例如:./soar.linux-amd64-config ./uuid.yaml -query 'select * from dual'

解决方法是在执行命令行的时候,把sql语句写入到临时文件的方式进行审核。改为./soar.linux-amd64-config ./uuid.yaml -query SQL文件的路径。

改造如下:

初始源代码组合命令的方法中,是把SQL语句直接当中字符串写在“query”参数后面:

cmd_args['query'] = args['query']##源代码这里直接跟着SQL语句字符串。

我们先增加save_tmp_sqltext()函数方法,把post过来的sql语句写入临时文件。源码如下:

说明一下用的方法:
codecs.open(filepath,method,encoding)
filepath--文件路径。
method--打开方式,r为读,w为写,rw为读写。
encoding--文件的编码,中文文件使用utf-8。

同时在soar_result()方法增加对SQL语句文件的处理,把获取到的SQL语句,调用save_tmp_sqltext()方法写入到临时文件当中,并把源码的query参数修改为SQL文件路径。

cmd_args['query'] = sqltext_tmp_file  ##改造query后面的SQL语句为 SQL文件路径

改造index.html关于post请求超时的处理,因为默认为30秒,当SQL语句比较长的时候,soar工具会花比较长的时间处理。


改造后的效果,SQL语句太长的报错已解决:

三、结论

soar web是一个采用轻量级web框架的应用,Flask类的route()函数处理前端URL对应到的后端方法,比较适合新手做二次开发。



本期作者 | 快递源新炬网络工程师,在运营商领域工作10余年,
拥有大数据、数据库AIOps、运维日志分析、Oracle运维等项目经验,
目前在积极推动数据库AIOps与DevOps结合的研究工作
文章转载自炬南山,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论