系统联调测试与部署

系统联调测试与部署日萌社

人工智能AI:Keras PyTorch MXNet TensorFlow PaddlePaddle 深度学习实战(不定时更新)


智能对话系统:Unit对话API

在线聊天的总体架构与工具介绍:Flask web、Redis、Gunicorn服务组件、Supervisor服务监控器、Neo4j图数据库

linux 安装 neo4jlinux 安装 Redissupervisor 安装

neo4j图数据库:Cypher

neo4j图数据库:结构化数据流水线、非结构化数据流水线

命名实体审核任务:BERT中文预训练模型

命名实体审核任务:构建RNN模型

命名实体审核任务:模型训练

命名实体识别任务:BiLSTM+CRF part1

命名实体识别任务:BiLSTM+CRF part2

命名实体识别任务:BiLSTM+CRF part3

在线部分:werobot服务、主要逻辑服务、句子相关模型服务、BERT中文预训练模型+微调模型(目的:比较两句话text1和text2之间是否有关联)、模型在Flask部署

系统联调测试与部署

离线部分+在线部分:命名实体审核任务RNN模型、命名实体识别任务BiLSTM+CRF模型、BERT中文预训练+微调模型、werobot服务+flask


9.1 系统联调与测试


  • 学习目标:
    • 掌握如何启动系统在线部分的服务.
    • 掌握对运行服务分别进行测试的过程.

  • 系统架构图:

系统联调测试与部署

  • 系统在线部分的主要服务:
    • werobot服务
    • 主要逻辑服务
    • 句子相关模型服务
    • redis服务(会话管理)
    • neo4j服务(图数据查询)

  • 说明: 系统联调与测试是对系统在线部分服务的联调与测试, 不包含离线部分的内容.

  • 启动系统在线部分的服务:
    • 以挂起的方式启动werobot服务
    • 使用supervisor启动主要逻辑服务及其redis服务
    • 以挂起的方式启动子相关模型服务
    • 启动和查看neo4j服务(默认已启动)

  • 以挂起的方式启动werobot服务:
nohup python /data/wr.py &

  • 运行位置: /dara/目录下.

  • 通过端口查看挂起的服务进程:
# 通过yum安装lsof命令
sudo yum install lsof -y


# 查看80端口的进程
lsof -i:80

  • 使用supervisor启动主要逻辑服务及其redis服务
  • supervisor配置文件简要分析:
...

; 使用gunicorn启动基于Flask框架的主要逻辑服务 
[program:main_server]
command=gunicorn -w 1 -b 0.0.0.0:5000 app:app                    ; the program (relative uses PATH, can take args)
stopsignal=QUIT               ; signal used to kill process (default TERM)
stopasgroup=false             ; send stop signal to the UNIX process group (default false)
killasgroup=false             ; SIGKILL the UNIX process group (def false)
stdout_logfile=./log/main_server_out      ; stdout log path, NONE for none; default AUTO
stdout_logfile_maxbytes=1MB   ; max # logfile bytes b4 rotation (default 50MB)
stderr_logfile=./log/main_server_error        ; stderr log path, NONE for none; default AUTO
stderr_logfile_maxbytes=1MB   ; max # logfile bytes b4 rotation (default 50MB)

; 启动redis服务,作为会话管理数据库
[program:redis]
command=redis-server
  • 启动服务:
# 使用supervisord命令, 读取指定目录下的文件
supervisord -c /data/doctor_online/main_serve/supervisor.conf

  • 查看启动的服务状态
supervisorctl status all
  • 输出效果:
main_server                      RUNNING   pid 31609, uptime 0:32:20
redis                            RUNNING   pid 31613, uptime 0:32:18

  • 以挂起的方式启动句子相关模型服务:
  • 编写启动脚本start.sh
# 脚本中是使用gunicorn启动服务的命令
gunicorn -w 1 -b 0.0.0.0:5001 app:app
  • 以挂起的方式启动服务
nohup sh /data/doctor_online/bert_serve/start.sh &
  • 通过端口查看挂起的服务进程
# 通过yum安装lsof命令
sudo yum install lsof -y


# 查看5001端口的进程
lsof -i:5001

  • 启动和查看neo4j服务(图数据查询):
# neo4j服务在之前应该一直处在启动状态
neo4j start


# 查看服务启动状态:
neo4j status

  • 进行测试:
    • 第一步: 明确测试说明.
    • 第二步: 添加打印测试内容.
    • 第三步: 重新启动主要逻辑服务.
    • 第四步: 进行数据流测试并查看打印日志.

  • 第一步: 测试说明
    • 因为主要逻辑服务是所有在线服务的中心服务(该服务将接收或发送请求给其他服务), 因此我们的测试打印信息都在主要逻辑服务中进行.

  • 第二步: 添加打印测试内容
class Handler(object):
    """主要逻辑服务的处理类"""
    def __init__(self, uid, text, r, reply):
        """
        :param uid: 用户唯一标示uid
        :param text: 该用户本次输入的文本
        :param r: redis数据库的连接对象
        :param reply: 规则对话模版加载到内存的对象(字典)
        """
        self.uid = uid
        self.text = text
        self.r = r
        self.reply = reply

    def non_first_sentence(self, previous):
        """
        description: 非首句处理函数
        :param previous: 该用户当前句(输入文本)的上一句文本
        :return: 根据逻辑图返回非首句情况下的输出语句
        """
        # 尝试请求模型服务, 若失败则打印错误结果
        ###################################################
        # 能够打印该信息, 说明已经进入非首句处理函数.
        print("准备请求句子相关模型服务!")
        ###################################################
        try:
            data = {"text1": previous, "text2": self.text}
            result = requests.post(model_serve_url, data=data)
            if not result.text: return unit_chat(self.text)
            ###################################################
            # 能够打印该信息, 说明句子相关模型服务请求成功.
            print("句子相关模型服务请求成功, 返回结果为:", result.text)
            ###################################################
        except Exception as e:
            print("模型服务异常:", e)
            return unit_chat(self.text)

        ###################################################
        # 能够打印该信息, 说明开始准备请求neo4j查询服务.
        print("请求模型服务后, 准备请求neo4j查询服务!")
        ###################################################
        # 继续查询图数据库, 并获得结果
        s = query_neo4j(self.text)
        ###################################################
        # 能够打印该信息, 说明neo4j查询成功.
        print("neo4j查询服务请求成功, 返回结果:", s)
        ###################################################
        # 判断结果为空列表, 则直接使用UnitAPI返回
        if not s: return unit_chat(self.text)
        # 若结果不为空, 获取上一次已回复的疾病old_disease
        old_disease = self.r.hget(str(self.uid), "previous_d")
        if old_disease:
            # new_disease是本次需要存储的疾病, 是已经存储的疾病与本次查询到疾病的并集
            new_disease = list(set(s) | set(eval(old_disease)))
            # res是需要返回的疾病, 是本次查询到的疾病与已经存储的疾病的差集
            res = list(set(s) - set(eval(old_disease)))
        else:
            # 如果old_disease为空, 则它们相同都是本次查询结果s
            res = new_disease = list(set(s))

        # 存储new_disease覆盖之前的old_disease
        self.r.hset(str(self.uid), "previous_d", str(new_disease))
        # 设置过期时间
        self.r.expire(str(self.uid), ex_time)
        # 将列表转化为字符串, 添加到规则对话模版中返回
        res = ",".join(s)
        ###################################################
        # 能够打印该信息, 说明neo4j查询后有结果并将使用规则对话模版.
        print("使用规则对话模版进行返回对话的生成!")
        ###################################################
        print("###################################################")
        return self.reply["2"] %res

    def first_sentence(self):
        """首句处理函数"""
        # 直接查询图数据库, 并获得结果
        ###################################################
        # 能够打印该信息, 说明进入了首句处理函数并马上进行neo4j查询
        print("该用户近期首次发言, 不必请求模型服务, 准备请求neo4j查询服务!")
        ###################################################
        s = query_neo4j(self.text)
        ###################################################
        # 能够打印该信息, 说明已经完成neo4j查询.
        print("neo4j查询服务请求成功, 返回结果为:", s)
        ###################################################
        # 判断结果为空列表, 则直接使用UnitAPI返回
        if not s: return unit_chat(self.text)
        # 将s存储为"上一次返回的疾病"
        self.r.hset(str(self.uid), "previous_d", str(s))
        # 设置过期时间
        self.r.expire(str(self.uid), ex_time)
        # 将列表转化为字符串, 添加到规则对话模版中返回
        res = ",".join(s)
        ###################################################
        # 能够打印该信息, 说明neo4j查询后有结果并将使用规则对话模版.
        print("使用规则对话生成模版进行返回对话的生成!")
        ###################################################
        print("###################################################")
        return self.reply["2"] %res



# 设定主要逻辑服务的路由和请求方法
@app.route('/v1/main_serve/', methods=["POST"])
def main_serve():
    ###################################################
    # 能够打印该信息, 说明werobot服务发送请求成功.
    print("已经进入主要逻辑服务, werobot服务运行正常!")
    ###################################################
    # 接收来自werobot服务的字段
    uid = request.form['uid']
    text = request.form['text']
    # 从redis连接池中获得一个活跃连接
    r = redis.StrictRedis(connection_pool=pool)
    # 根据该uid获取他的上一句话(可能不存在)
    previous = r.hget(str(uid), "previous")
    # 将当前输入的文本设置成上一句
    r.hset(str(uid), "previous", text)
    ###################################################
    # 能够打印该信息, 说明redis能够正常读取和写入数据.
    print("已经完成初次会话管理, redis运行正常!")
    ###################################################
    # 读取规则对话模版内容到内存
    reply = json.load(open(reply_path, "r"))
    # 实例化主要逻辑处理对象
    handler = Handler(uid, text, r, reply)
    # 如果previous存在, 说明不是第一句话
    if previous:
        # 调用non_first_sentence方法
        return handler.non_first_sentence(previous)
    else:
        # 否则调用first_sentence()方法
        return handler.first_sentence()
  • 第三步: 重新启动主要逻辑服务
supervisorctl restart all
  • 第四步: 进行数据流测试并查看打印日志
    • 测试请求1: 用户关注公众号后首次发送一些症状描述.
    • 测试请求2: 首次发送后用户继续发送一些症状描述.

  • 测试请求1:
    • 用户关注公众号后首次发送一些症状描述.

  • 对应数据流:
    • werobot服务-->请求主要逻辑服务-->主要逻辑服务中请求redis服务-->请求neo4j查询服务-->使用规则对话模版/UnitAPI.

  • 对应操作:
    • 关注公众号(使用新用户), 发送"我最近有些腹痛".

  • 查看主要逻辑服务日志:
cat /data/doctor_online/main_serve/log/main_server_out

  • 日志打印结果:
## 打印如下结果说明测试成功!
已经进入主要逻辑服务, werobot服务运行正常!
已经完成初次会话管理, redis运行正常!
该用户近期首次发言, 不必请求模型服务, 准备请求neo4j查询服务!
neo4j查询服务请求成功, 返回结果为: ['癫痫', '小儿糖尿病', '肾上腺危象', '异位急性阑尾炎', '急性胆囊炎']
使用规则对话模版进行返回生成的对话!

  • 测试请求2:
    • 首次发送后用户继续发送一些症状描述.

  • 对应数据流:
    • werobot服务-->请求主要逻辑服务-->主要逻辑服务中请求redis服务-->请求句子相关模型服务-->请求neo4j查询服务-->使用规则对话模版/UnitAPI.

  • 对应操作:
    • 发送"我最近有些腹痛"后, 继续发送"并且左腹部有一些红点".
  • 日志打印结果:
## 打印如下结果说明测试成功!(使用UnitAPI返回结果)
已经进入主要逻辑服务, werobot服务运行正常!
已经完成初次会话管理, redis运行正常!
准备请求句子相关模型服务!
句子相关模型服务请求成功, 返回结果为: 1
请求模型服务后, 准备请求neo4j查询服务!
neo4j查询服务请求成功, 返回结果: []

  • 注意: 打印日志若不能即时出现, 重新启动主要逻辑服务即可.

  • 本章总结:

    • 学习了掌握如何启动系统在线部分的服务:
      • 以挂起的方式启动werobot服务
      • 使用supervisor启动主要逻辑服务及其redis服务
      • 以挂起的方式启动子相关模型服务
      • 启动和查看neo4j服务(默认已启动)

    • 学习了如何进行测试:
      • 第一步: 明确测试说明.
      • 第二步: 添加打印测试内容.
      • 第三步: 重新启动主要逻辑服务.
      • 第四步: 进行数据流测试并查看打印日志.

    • 第一步: 测试说明
      • 因为主要逻辑服务是所有在线服务的中心服务(该服务将接收或发送请求给其他服务), 因此我们的测试打印信息都在主要逻辑服务中进行.

    • 第二步: 添加打印测试内容

    • 第三步: 重新启动主要逻辑服务

    • 第四步: 进行数据流测试并查看打印日志
      • 测试请求1: 用户关注公众号后首次发送一些症状描述.
      • 测试请求2: 首次发送后用户继续发送一些症状描述.

  • 注意事项:
    • 这个安装手册只适用于操作系统: centos7.

  • 安装部署步骤:

  • 1: 拷贝必备文件.

  • 2: 安装Anaconda科学计算环境, 包括python2, pip, pandas, numpy, matplotplib等科学计算包.
# 将环境包安装在/root/目录下
cd /root
curl -O https://repo.anaconda.com/archive/Anaconda3-5.2.0-Linux-x86_64.sh
sh Anaconda3-2019.07-Linux-x86_64.sh 

# 配置~/.bashrc, 添加一行: export PATH=/root/anaconda/bin/:$PATH


  • 3: 安装项目需要的若干独立工具.
# 安装Flask
pip install Flask==1.1.1

# 安装Redis数据库
yum install redis -y

# 安装python中的redis驱动
pip install redis

# 安装gunicorn
pip install gunicorn==20.0.4

# 安装supervisor
yum install supervisor -y

# 安装lsof
yum install lsof -y


  • 4: 安装项目需要的重要工具Pytorch.
# 安装pytorch
pip install pytorch


  • 5: 安装图数据库neo4j.
# 第一步: 将neo4j安装信息载入到yum检索列表
cd /tmp
wget http://debian.neo4j.org/neotechnology.gpg.key
rpm --import neotechnology.gpg.key
cat <<EOF>  /etc/yum.repos.d/neo4j.repo
# 写入下面内容
[neo4j]
name=Neo4j RPM Repository
baseurl=http://yum.neo4j.org/stable
enabled=1
gpgcheck=1


# 第二步: 使用yum install命令安装
yum install neo4j-3.3.5


# 第三步: 使用自己的配置文件
cp /data/neo4j.conf /etc/neo4j/neo4j.conf


  • 6: 启动neo4j图数据库并查看状态.
# 启动neo4j命令
neo4j start

# 查看状态命令
neo4j status


  • 7: 使用脚本生成图谱.
# 执行已经写好的脚本代码, 将数据写入到neo4j数据库中
python /data/doctor_offline/neo4j_write.py


  • 8: 使用脚本训练模型.
# 在线部分只有一个模型bert-chinese
cd /data/doctor_online/bert_server/
python train.py


  • 9: 以挂起的方式启动werobot服务.
# 启动werobot服务, 使得用户可以通过微信接口和AI医生完成对话.
nohup python /data/wr.py &


  • 10: 使用supervisor启动主要逻辑服务及其redis服务.
# supervisor配置文件简要分析
# 文件路径位置/data/doctor_online/main_serve/supervisor.conf

; 使用gunicorn启动基于Flask框架的主要逻辑服务 
[program:main_server]
command=gunicorn -w 1 -b 0.0.0.0:5000 app:app                    ; the program (relative uses PATH, can take args)
stopsignal=QUIT               ; signal used to kill process (default TERM)
stopasgroup=false             ; send stop signal to the UNIX process group (default false)
killasgroup=false             ; SIGKILL the UNIX process group (def false)
stdout_logfile=./log/main_server_out      ; stdout log path, NONE for none; default AUTO
stdout_logfile_maxbytes=1MB   ; max # logfile bytes b4 rotation (default 50MB)
stderr_logfile=./log/main_server_error        ; stderr log path, NONE for none; default AUTO
stderr_logfile_maxbytes=1MB   ; max # logfile bytes b4 rotation (default 50MB)

; 启动redis服务,作为会话管理数据库
[program:redis]
command=redis-server


# 使用supervisord命令, 读取指定目录下的文件
supervisord -c /data/doctor_online/main_serve/supervisor.conf


# 查看启动的服务状态
supervisorctl status


  • 11: 以挂起的方式启动句子相关模型服务.
# 以挂起的方式启动服务, 代码已经预先编写好
# 脚本start.sh中的内容是 gunicorn -w 1 -b 0.0.0.0:5001 app:app

nohup sh /data/doctor_online/bert_serve/start.sh &


  • 12: 启动和查看neo4j服务(图数据查询):
# neo4j服务在之前应该一直处在启动状态
neo4j start


# 查看服务启动状态:
neo4j status


  • 13: 进行测试.
测试1: 关注公众号(新用户), 发送"我最近有些腹痛".

测试2: (老用户)发送"我最近有些腹痛"后, 继续发送"并且左腹部有一些红点".

上一篇:Mysql入门


下一篇:数据库的相关概念