本文是一篇小白科普文。
作为一名算法工程师,不仅需要实现模型,而且需要了解一些工程方面的知识,比如别人如何请求我的代码?如何监控程序运行状态?一些比较重要的信息在传输中通过怎样的方式进行加密?如何告诉请求我接口的人我的算法程序已经运行完毕?本篇主要介绍这些简单的工程问题。
一、别人如何请求我的代码(即:如何用python开发自己的接口)
先直接给个示例代码:
from flask import Flask, jsonify
from flask import abort
from flask import request
app = Flask(__name__)
app.config['JSON_AS_ASCII'] = False
def 我的算法模型_函数():
*****
return 我的算法模型_运行结果
# 接口部分
@app.route('/我随便定义的网址,比如Maria', methods=['POST'])
def 我定义的接口函数():
# 本地测试 读取参数
if request.json:
print("进来了")
df_data_json = request.json['我模型的参数1']
k_cluster = request.json['我模型的参数2']
df_feature_maxmin_json = request.json['我模型的参数3']
# 把传入的参数,代入“我的算法模型_函数”,得到“我的算法模型_运行结果”
我的算法模型_运行结果 = 我的算法模型_函数(df_data_json, k_cluster, df_feature_maxmin_json)
if len(我的算法模型_运行结果) > 1:
result = 1 # succeed
else:
result = -1
return jsonify({"result": result, "我的算法模型_运行结果": json.loads(我的算法模型_运行结果)})
if __name__ == '__main__':
app.run(host="本机IP地址如192.168.32.432", port=自己定义的端口号如6666, debug=True) # 本机测试
此时,其他人该如何请求我的接口呢?示例如下:
''' post数据, 请求接口 '''
# 先把模型需要的参数定义好
a = {"我模型的参数1": df_data_json, "我模型的参数2": k_cluster, "我模型的参数3": df_feature_maxmin_json}
r = requests.post("http://本机IP地址如192.168.32.432:自己定义的端口号如6666/我随便定义的网址,比如Maria", json=a) # 本机测试
# 查看返回的“我的算法模型_运行结果”
aaa = r.content
bbb = aaa.decode()
print("返回的开头数据:", bbb[0:1000])
print("============== finish ==============")
=============以上就是一个完整的python接口开发和请求的过程啦=========
以下是原理科普,可以参考以下教程:
python实现RESTful服务(基于flask)
数据蛙datafrog:用Python 的Flask实现 RESTful API(学习篇)
二、如何监控程序运行状态以及保持运行?(即:supervisor用法)
我们需要把我们的“我的算法模型”保持运行的状态,这样其他人才可能随时调用我们的接口,得到“我的算法模型_运行结果”,如何保持运行状态并监控呢?我们引用一个工具“supervisor”。配置方法如下:
1. ### 下载包
pip3 install supervisor
2. ### 生成配置文件,且放在/etc目录下
echo_supervisord_conf > /etc/supervisord.conf
3.### 为了不将所有新增配置信息全写在一个配置文件里,这里新建一个文件夹,每个程序设置一个配置文件,相互隔离
mkdir /etc/supervisord.d/
4. ### 修改配置文件
vim /etc/supervisord.conf
5.### 加入以下配置信息
"[include]
files = /etc/supervisord.d/*.conf"
### 在supervisord.conf中设置通过web可以查看管理的进程,加入以下代码(默认即有,取消注释即可)
"[inet_http_server]
port=定义的IP:定义的端口号 "
[supervisorctl] ; ### 在supervisord.conf中设置通过web可以查看管理的进程,加入以下代码(默认即有,取消注释即可)
serverurl=http://定义的IP:定义的端口号 ; #定义的IP:定义的端口号
[supervisord]
user=root ; supervisord ; setuid to this UNIX account at startup; recommended if root
6.启动supervisord
supervisorctl -c /etc/supervisord.conf
7. ### 以下即为配置文件中的内容
vim /etc/supervisord.d/supervisor_cluster.conf
[program:cluster]
command=python3 需运行的程序(带上程序放的位置_绝对路径).py ; 被监控的进程路径
;autostart=true ; 随着supervisord的启动而启动
autorestart=true ; 自动重启。。当然要选上了
8.重启
supervisorctl reload
### 或者
supervisorctl -c /etc/supervisord.conf
reload
start all
status
9. ## 查看报错日志
vim /tmp/supervisord.log
-------------------------
10. ### 其他的一些命令
update 更新新的配置到supervisord(不会重启原来已运行的程序)
reload,载入所有配置文件,并按新的配置启动、管理所有进程(会重启原来已运行的程序)
start xxx: 启动某个进程
restart xxx: 重启某个进程
stop xxx: 停止某一个进程(xxx),xxx为[program:theprogramname]里配置的值
stop groupworker: 重启所有属于名为groupworker这个分组的进程(start,restart同理)
stop all,停止全部进程,注:start、restart、stop都不会载入最新的配置文
reread,当一个服务由自动启动修改为手动启动时执行一下就ok
=============以上就是supervisor配置的过程啦=========
以下是原理科普,可以参考以下教程:
supervisor用法
三、一些比较重要的信息在传输中通过怎样的方式进行加密?(即:pyDes 加密解密)
对于传输的数据库的用户名、密码等,我们需要用加密的方式进行传输,可以采用DES加密解密的方式,示例如下:
def decode(cipher, DES_SECRET_KEY):
'''
# des模式 填充方式 CBC解密
:param cipher: 密文 需要解密的
:param DES_SECRET_KEY: # 秘钥 之后需要截取前8位作为真实的密钥
:return:
'''
# 偏移变量 这个固定不用改
IV_PARAMETER = 'AI_MP'
# 秘钥:截取前8位作为真实的密钥
DES_SECRET_KEY = DES_SECRET_KEY[0:8]
# 密钥字符串转字节码
s = bytes(cipher, 'utf-8')
# 初始化一个des对象,参数是秘钥,解密方式,偏移, 填充方式
des_obj = des(DES_SECRET_KEY, CBC, IV_PARAMETER, padmode=PAD_PKCS5)
# 解密
password = des_obj.decrypt(base64.b64decode(s))
# 打印真实数据
# print("真实数据:", password.decode())
return password.decode()
=============以上就是pyDes 加密解密的过程啦=========
以下是原理科普,可以参考以下教程:
pyDES实现DES加解密_我在浪里-CSDN博客_pydes
Python使用Crypto/pyDes,DES并Base64编码
四、如何告诉请求我接口的人我的算法程序已经运行完毕?(即:回调接口+rsa私钥加签)
rsa私钥加签(注意:rsajava是用的pkcs8编码,python是用的pkcs1编码,需要用openssl把pkcs8转成pkcs1):
def make_key():
"""
生成公钥和私钥
:return:
"""
pub_key, pri_key = rsa.newkeys(1024)
pub_pkcs = pub_key.save_pkcs1()
pri_pkcs = pri_key.save_pkcs1()
print('pub_pkcs:n' + pub_pkcs.decode())
print('pri_pkcs:n' + pri_pkcs.decode())
def sign(path: str, msg: str) -> str:
"""
对给定的字符串加签
:param path: 私钥文件路径
:param msg: 需要加签的字符串
:return: 加签后的字符串
"""
with open(path, 'r', encoding='utf-8') as f:
pri_pkcs = f.read()
print('私钥:n' + pri_pkcs)
pri_key = rsa.PrivateKey.load_pkcs1(pri_pkcs.encode())
result = rsa.sign(msg.encode(), pri_key, 'SHA-1')
sign_str = b64encode(result).decode()
return sign_str
def verify(path: str, sign_str: str, msg: str) -> bool:
"""
对给定的字符串和签名字符串验签
:param path: 公钥文件路径
:param sign_str: 加签的字符串
:param msg: 需要验签的字符串
:return: True:验证成功,False:验证失败
"""
with open(path, 'r', encoding='utf-8') as f:
pub_pkcs = f.read()
print('公钥:n' + pub_pkcs)
pub_key = rsa.PublicKey.load_pkcs1(pub_pkcs.encode())
result = rsa.verify(msg.encode(), b64decode(sign_str), pub_key)
if result == 'SHA-1':
return True
else:
return False
当对方(如java)来请求我们的python算法模型时,需要给定信号告诉对方,我的模型已经是否运行完毕,成功或失败及错误信息。
回调接口:
# 回调接口
try:
模型效果 = 运行我的算法主函数
# sign是使用rsa加密算法对jobExcuteInfo中的runId加签
# modelOutput:模型输出数据,推荐模型中是AUC的值
# jobExcuteInfo: 新的入参中包含有,直接取值
# completed: 模型是否执行成功,如果中途失败,值为false,在失败的地方直接调用这个接口;
# 否则值为true,在程序全部执行完成后再调用此接口
# sign: 加签信息,对jobExcuteInfo中的runId进行加签,根据私钥,使用rsa加签
param = {'modelOutput': 模型效果, 'jobExcuteInfo': 参数字典['jobExcuteInfo'],
'complete': True, 'errorMsg': '', 'sign': sign(absolute_path+'/config/rsa.pri.pkcs1.pem', 要加签的信息)}
except Exception as e:
param = {'modelOutput': 0.0, 'jobExcuteInfo': 参数字典['jobExcuteInfo'],
'complete': False, 'errorMsg': traceback.format_exc(), 'sign': sign(absolute_path+'/config/rsa.pri.pkcs1.pem', 要加签的信息)}
finally:
# 回调接口
call_back_url = 'http://对方给你的网址'
requests.post(call_back_url, json.dumps(param))
=============以上就是 回调接口+rsa私钥加签 的过程啦=========
以下是原理科普,可以参考以下教程:
RSA算法原理(一) - 阮一峰的网络日志
python RSA 密钥对的获取 数据加解密 加签验签
python RSA加密、解密、签名
对称加密:
描述: 加密解密使用同样的密钥。
特点: 速度快,安全性一般。
举例:DES、3DES、AES
使用场景:对大量数据进行加解密。
非对称加密:
描述:加解密使用不同的密钥。
特点:速度慢,安全性较高。
举例:RSA
使用场景:在对称加密前,使用非对称加密传输公共的密钥。
不可逆加密:
描述:只能加密,不能解密,加密过程不可逆。
特点:不可逆加密。
举例:md5
使用场景:使用md5(md5(password)),使用双重不可逆加密对用户密码加密,并存入数据库。在验证用户密码的时候,将待验证的数据进行双重加密后与数据库中的数据作比较即可。