运用AI搭建中间服务层(五)

其他文件的修改

ValuesControllers.cs 注意Post的参数从[FromBody]变成了[FromForm],以便接收上传的图片流数据

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using CognitiveMiddlewareService.CognitiveServices;
using CognitiveMiddlewareService.Processors;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;

namespace CognitiveMiddlewareService.Controllers
{
    [Route("api/[controller]")]
    public class ValuesController : Controller
    {
        private readonly IProcessService processor;

        public ValuesController(IProcessService ps)
        {
            this.processor = ps;
        }

        // GET api/values
        [HttpGet]
        public IEnumerable<string> Get()
        {
            return new string[] { "value1", "value2" };
        }

        // GET api/values/5
        [HttpGet("{id}")]
        public string Get(int id)
        {
            return "value";
        }

        // POST api/values
        [HttpPost]
        public async Task<string> Post([FromForm] IFormCollection formCollection)
        {
            try
            {
                IFormCollection form = await this.Request.ReadFormAsync();
                IFormFile file = form.Files.First();

                var bufferData = Helper.GetBuffer(file);
                var result = await this.processor.Process(bufferData);
                string jsonResult = JsonConvert.SerializeObject(result);
                // return json formatted data
                return jsonResult;
            }
            catch (Exception ex)
            {
                Debug.Write(ex.Message);
                return null;
            }
        }
    }
}

启动.cs

using CognitiveMiddlewareService.CognitiveServices;
using CognitiveMiddlewareService.MiddlewareService;
using CognitiveMiddlewareService.Processors;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

namespace CognitiveMiddleService
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
            services.AddScoped<IProcessService, ProcessService>();
            services.AddScoped<IVisionService, VisionService>();
            services.AddScoped<ILandmarkService, LandmarkService>();
            services.AddScoped<ICelebrityService, CelebrityService>();
            services.AddScoped<IEntitySearchService, EntitySearchService>();
            services.AddHttpClient();

        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseMvc();
        }
    }
}

除了第一行的services.AddMvc()以外,后面所有的行都是我们需要增加的依赖注入代码。

层次关系总结

总结一下,从调用关系上看,是这个次序:

控制器 -> ProcessService -> LandmarkService/CelebrityService -> VisionService/EntitySearchService

其中:

  • Controller是个Endpoint

  • ProcessService负责任务调度

  • LandmarkService/CelebrityService是个集成服务,封装了串行调用底层服务的逻辑

  • VisionService/EntitySearchService是基础服务,相当于最底层的原子操作

从数据结构上看,进化的顺序是这样的:

VisionResult/EntityResult -> CelebrityResult/LandmarkResult -> 聚合结果

其中:

  • VisionResult/EntityResult是最底层返回的原始结果,主要用于反序列化

  • CelebrityResult/LandmarkResult是集成了多个原始结果后的抽象结果,好处是隔离了原始结果中的一些噪音,解耦,只返回我们需要的字段

  • AggregatedResult是聚合在一起的结果,主要用于排序和生成返回JSON数据

完整的中间服务层系统堆栈

有的人会问了:有必要搞这么复杂吗?这几个调用在一个帮助函数里不就可以搞定了吗?

确实是这样,如果不考虑应用扩展什么的,那就用一个帮助函数搞定;如果想玩儿点大的,那么下面这张图就是一个完整系统的Stack图,这个系统通过组合调用多种微软认知服务/微软地图服务/微软实体服务等,能够提供给用户的智能设备丰富的视觉对象识别体验。

上图包含了以下层次:

  • 端点

    • 两个Endpoint,一个处理图片输入,另一个处理文本输入
  • 处理和分类器

    • 包含图像/文字的预处理/预分类
  • 任务分派器

    • 并行调用多种服务并协调同步关系
  • API 代理和识别器

    • 组合调用各种API,内置的识别器(比如正则表达式)
  • 蜜蜂属

    • 各种认知服务API
  • 处理器

    • 隔离层/聚合层/排序器的组合称呼
  • 自适应卡片生成器

    • 生成微软最新推出的Adaptive Card技术的数据,供跨平台客户端接收并渲染
  • 助理 元件

    • 其它辅助组件

对中间服务层的测试

基本概念与环境搭建

做好了一个中间层服务,不是说简单地向Azure上一部署就算完事儿了。任何一个商用的软件,都需要严格的测试,对于普通的手机/客户端软件的测试,相信很多人都知道,覆盖功能点,各种条件输入,等等等等。对于中间层服务,除了功能点外,性能方面的测试尤其重要。

如何进行测试呢?

ASP.NET Core Web API有一套测试工具,请看这个链接:https://docs.microsoft.com/en-us/aspnet/core/test/?view=aspnetcore-2.1,它讲述了一些列的方法,我们不再赘述,本文所要描述的是三种面向场景的测试方法:负载(较重的压力)测试,(较轻的压力)性能测试,(中等的压力)稳定性测试。不是以show code为主,而是以讲理念为主,懂得了理念,code容易写啦。

对于一个普通的App,我们用界面交互的方式进行测试。对于一个service,它的界面就相当于REST API,我们可以从客户端发起测试,自动化程度较高。

在Visual Studio 2017,有专门的Load Test工具可以帮助我们完成在客户端编写测试代码,调整各种测试参数,然后发起测试,具体的链接在这里。

在本文中,我们主要从概念上讲解一下针对含有认知服务的中间服务层的测试方法,因为认知服务本身如果访问量大的话,是要收取费用的!

小提示:各个认知服务的费用标准不同,请仔细阅读相关网页,以免在进行大量的测试时引起不必要的费用发生。

负载测试 Load Test

测试目的

模拟多个并发用户访问中间层服务,集中发生在一个持续的时间段内,以衡量服务质量。负载测试不断的发展下去,负载越来越大,就会变成极限测试,最终把机器跑瘫为止。

测试环境

注意!我们不是在测试认知服务的性能,是要测试自己的中间层服务的性能,所以如下图所示:

要把认知服务用一个模拟的mock up service来代替,这个mock up service可以自己简单地用 ASP.NET 搭建一个,接收请求后,不做任何逻辑处理,直接返回JSON字符串,但是中间需要模拟认知服务的处理时间,故意延迟2~3秒。

另外一个原因是,认知服务比较复杂,可能不能满足很高的QPS的要求,而用自己的模拟服务可以到达极高的QPS,这样就不会正在测试中产生瓶颈。

网络环境为局域网内部,亦即客户端、中间层、模拟服务都在局域网内部即可,这样可以避免网络延迟带来的干扰。

测试方法与结果

在本例中,我们测试了8轮,每轮都模拟不同的并发用户数持续运行一小时,最终结果如下:

并发用户1 位用户3 位用户5 位用户10 位用户25 位用户50 位用户75 位用户100 位用户
中央处理器0%<1%<1%1%2.5%6%12%17%21%
内存(MB)110116150158164176260301335
延迟02.612.612.612.622.632.642.672.7
总要求01,3774,1246,88513,66634,22167,976100,948132,894
请求失败。000000000
PP2型0.000.381.151.913.809.5118.8828.0436.92

从图表可以看出,CPU/Memory/QPS都是线性增长的,意味着是可以预测的。延迟(Latency)是平缓的,不会因为并发用户变多而变慢,很健康。

可靠性测试 Stability Test

测试目的

在一个足够长的时间内持续测试服务,以检查其可靠性。"足够长"一般定义为12小时、48小时、72小时等等。可以认为,被测对象只要跑够了预定的时长,就算是稳定性过关了。

测试环境

同理,我们要测试的是中间层服务,而不是认知服务。

测试环境与上面相同,也是使用模拟的认知服务,因为72小时的测试时间,会发送大量的请求,很可能超出了当月限额而收取费用。

网络环境仍然使用局域网。

测试方法与结果

模拟10个并发用户,持续向中间层服务发请求12小时,测试结果如下表:

采样点中央处理器记忆延迟请求总数失败PP2型
1:00:002.5%140 米2.63 秒13,73003.81
2:00:002.5%160 米2.61 秒13,74103.82
3:00:002.5%150 米2.62 秒13,72803.81
......
总计/平均值2.5%150 米2.62164,77203.81

从CPU/Memory/Latency/QPS上来看,在12个小时内,都保持得非常稳定,说明服务器不会因为长时间运行而变得不稳定。

性能测试 Performance Test

测试目的

测试端对端(e2e)的请求/响应时间。想得到具体的数值,所以不需要很大的负载压力。

测试环境

这次我们需要使用真实的认知服务,网络环境也使用真实的互联网环境。亦即需要把中间服务层部署到互联网上后进行测试,因为用模拟环境和局域网测试出来的数据不能代表实际的用户使用情况。

测试方法与结果

模拟1个用户,持续向中间服务层发送请求1小时。然后模拟3个并发用户,持续向中间服务层发送请求10分钟。这两种方法都不会对认知服务带来很大的压力。

在得到了一系列的数据以后,每组数据都会有响应时间,我们把它们按照从长(慢)到短(快)的顺序排列,得到下图(其中横坐标是用户数,纵坐标是响应时间):

一般来说,我们要考察几个点,P90/P95/P99,比如P90的含义是:有90%的用户的响应时间小于等于2449ms。这意味着如果有极个别用户响应时间在10秒以上时,是一种正常的情况;如果很多用户(比如>5%)都在10秒以上就不正常了,需要立刻检查服务器的运行状态。

最后得到的结果如下表,亦即性能指标:

百分比P90型P95型P99型平均
关键绩效指标<3000毫秒<3250<4000不适用
服务器端处理时间2449毫秒2652毫秒3571毫秒1675毫秒
测试客户端 e2e 延迟3160毫秒3368毫秒4369毫秒2317毫秒

服务器端处理时间: 服务器端接收到请求到发出响应,所经过的时长。

测试客户端 e2e 延迟: 客户端发出请求到接收到响应,所经过的时长。

习题与进阶学习

增加OCR服务以提供识别文字的功能

在集成服务层增加可以识别具有标准模式的文字的服务,比如电话号码、网络地址、邮件地址,这需要同时在基础服务层增加OCR底层服务,并在任务调度层增加一个并行任务。

部署到实际的Azure环境提供真实服务

在本地测试好服务器的基本功能后,部署到Azure上去,看看代码在实际环境中运行会有什么问题。因为我们不能实时地监控服务器,所以需要在服务层上增加log功能。

开发Android/iOS应用来提供影像/视觉感知

可以选择像Bob同学那样,先用第一种方式直接访问微软认知服务,然后一步步演进到中间层服务模式。建议使用VS2017 + Xamarin利器来实现跨平台应用。

图像基本分类

在任务调度层,增加一个本地的图像分类器,如同“todo”里的preprocess,能够把输入图片分类成“有人脸”、“有地标”、“有文字”等,然后再根据信心指数调用名人服务或地标服务,以减轻服务器的负担,节省费用。比如,当"有地标"的信心指数小于0.5时,就终止后面的调用。这需要训练一个图片分类器,导出模型,再用Tools for AI做本地推理代码。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/316236.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

大模型实战营Day3 基于 InternLM 和 LangChain 搭建你的知识库

LLM的局限性&#xff1a; 知识时效性&#xff0c;专业能力&#xff0c;定制化成本 两种大模型开发范式&#xff1a; RAG FineTune RAG: 检索问答生成 外挂知识库 成本低 FineTune&#xff1a; 更新成本高 GPU算力要求高 RAG开发框图&#xff1a; 用户输入 文本向量化 匹配相似…

20240114三角形边长周长和面积

代码 class Triangle(object):"""三角形类"""def __init__(self, a, b, c):"""初始化方法"""self.a aself.b bself.c cstaticmethoddef is_valid(a, b, c):"""判断三条边长能否构成三角形(静态…

【MySQL】:掌握SQL中DDL的数据库定义与操作

&#x1f3a5; 屿小夏 &#xff1a; 个人主页 &#x1f525;个人专栏 &#xff1a; MySQL从入门到进阶 &#x1f304; 莫道桑榆晚&#xff0c;为霞尚满天&#xff01; 文章目录 &#x1f4d1;前言一. SQL的分类二. DDL数据库操作2.1 查询所有数据库2.2 查询当前数据库2.3 创建数…

文件操作(一)

目录 一.什么是文件 1.程序文件和数据文件 2.文件名 3&#xff0c;文本文件和二进制文件 二.文件的打开和关闭 1.流和标准流 2.文件指针 3.文件的打开与关闭 三.结尾 一.什么是文件 在我们学习文件操作之前我们先了解一下什么是文件&#xff1f;以及文件为什么使用文件…

【面试合集】1.说说你对微信小程序的理解?优缺点?

面试官&#xff1a;说说你对微信小程序的理解&#xff1f;优缺点&#xff1f; 一、是什么 2017年&#xff0c;微信正式推出了小程序&#xff0c;允许外部开发者在微信内部运行自己的代码&#xff0c;开展业务 截至目前&#xff0c;小程序已经成为国内前端的一个重要业务&…

java求链表中倒数第k个结点

下面我用两种方法求解&#xff1a; 第一种方法&#xff1a;通常我们做这种题就是求出链表的长度length&#xff0c;然后呢length-k的值就是我们要从链表头部走几步就可以了&#xff0c;代码解释&#xff1a; public class Solution {public class ListNode {int val;ListNode…

分享一个使用python FastApi创建服务的简易模版,与使用http/python请求

这个博客分享一个fastapi的模版&#xff0c;并提供使用http/python访问的示例程序 文章目录 示例程序FastApi应用程序HTTP请求Python请求 示例程序 FastApi应用程序 下面是一个示例&#xff1a; 默认开启一个可以使用Get请求访问的URL&#xff1a;/example_connect这个请求有…

微信商家转账到零钱,既能单笔又能批量,支持多商户管理

大家好&#xff0c;我是小悟 微信商家转账到零钱的功能大家应该都熟悉吧&#xff0c;为了满足商家向用户微信零钱转账的需求&#xff0c;微信支付推出【商家转账到零钱】服务&#xff0c;方便商户可以一次向单个或多个用户的微信零钱转账。 商家转账到零钱为商户提供了简便、…

计算机毕业设计-----SSH计算机等级考试报名系统

项目介绍 该项目分为前后台&#xff0c;分为管理员与普通用户两种角色&#xff0c;前台为普通用户登录&#xff0c;后台为管理员登录&#xff1b; 管理员角色包含以下功能&#xff1a; 管理员登录,修改个人密码&#xff0c;院系信息管理&#xff0c;注册用户管理&#xff0c;留…

selenium模拟浏览器查询导出参考文献

通过使用Selenium和BeautifulSoup&#xff0c;在CNKI网站上&#xff0c;以"知识图谱"为关键词&#xff0c;通过自动化工具在搜索页面提取相关文章信息。点击清楚并全选进行文献导出&#xff0c;随后从导出页面和管理导出的页面提取参考文献。 浏览器及WebDriver下载…

【Maven】004-基于 IDEA 构建 Maven 工程

【Maven】004-基于 IDEA 构建 Maven 工程 文章目录 【Maven】004-基于 IDEA 构建 Maven 工程一、概述1、项目构建2、命令方式项目构建命令war 包打包插件和 jdk 版本不匹配 二、项目构建1、命令方式2、IDEA 可视化方式3、构建产物 一、概述 1、项目构建 项目构建是将软件开发…

第 3 章 Keepalived 双机热备

技能展示&#xff1a; 会构建双机热备系统 会构建 LVSHA 高可用群集 在这个高度信息化的 IT 时代&#xff0c;企业的生产系统、业务运营、销售和支持&#xff0c;以及日常管理等环节越来越依赖于计算机信息和服务&#xff0c;对高可用&#xff08;HA&#xff09;技术的应用需求…

力扣日记1.13-【二叉树篇】669. 修剪二叉搜索树

力扣日记&#xff1a;【二叉树篇】669. 修剪二叉搜索树 日期&#xff1a;2023.1.13 参考&#xff1a;代码随想录、力扣 669. 修剪二叉搜索树 题目描述 难度&#xff1a;中等 给你二叉搜索树的根节点 root &#xff0c;同时给定最小边界low 和最大边界 high。通过修剪二叉搜索树…

SSM框架整合:掌握Spring+Spring MVC+MyBatis的完美结合!

SSM整合 1.1 流程分析1.2 整合配置步骤1&#xff1a;创建Maven的web项目步骤2:添加依赖步骤3:创建项目包结构步骤4:创建SpringConfig配置类步骤5:创建JdbcConfig配置类步骤6:创建MybatisConfig配置类步骤7:创建jdbc.properties步骤8:创建SpringMVC配置类步骤9:创建Web项目入口配…

【python】——turtle动态画

&#x1f383;个人专栏&#xff1a; &#x1f42c; 算法设计与分析&#xff1a;算法设计与分析_IT闫的博客-CSDN博客 &#x1f433;Java基础&#xff1a;Java基础_IT闫的博客-CSDN博客 &#x1f40b;c语言&#xff1a;c语言_IT闫的博客-CSDN博客 &#x1f41f;MySQL&#xff1a…

Mac M2芯片pycharm配置conda python环境

Mac M2芯片pycharm配置conda python环境 详细步骤如下 1、pycharm界面右上方的小齿轮⚙️&#xff0c;进入Setting…状态 2、进入setting界面后&#xff0c;选择左边栏的Project-->python Interpreter,然后选择右边的Add Interpreter 3、进入Add Interpreter后&#xff0c…

类和对象---C++

类和对象目录 类和对象1.封装1.1 封装的意义1.2 struct和class区别1.3 成员属性设置为私有1.3.1 联系---判断圆和点的位置关系 2.对象的初始化和清理2.1 构造函数和析构函数2.2 构造函数的分类及调用2.2.1无参构造函数调用2.2.2有参构造函数调用2.2.2.1括号法2.2.2.2显式法2.2.…

PostMan、LoadRunner进行并发压测流程

需求 两个记账接口在同一时间大量处理同一账户账务时&#xff0c;锁表顺序不同导致死锁&#xff0c;在修改完代码后模拟生产记账流程进行测试&#xff0c;需要对两个接口进行并发测试。 在进行压测的时候&#xff0c;需要对流水号进行递增。 PostMan处理流程 1. 新建Collection…

jmap使用

jmap 是 Java 虚拟机 (JVM) 中的一个命令行工具&#xff0c;用于生成堆转储。这个工具对于诊断内存问题、分析内存占用情况等非常有用。 jmap 官方文档 bash: jmap: command not found 命令找不到 # jmap -dump <pid>jmap -dump 137886 安装一下java-devel yum -y in…

6.2 声音编辑工具GoldWave5简介(6)

3&#xff0e;选择【选项】|【控制器属性】命名或单击“控制器”面板上的“设置控制器属性”按钮&#xff0c;打开“控制器属性”对话框&#xff0c;将“音量”选项卡中的“麦克风”选项打上勾&#xff0c;使GoldWave只能录制来自麦克风的声音。如果要录制电脑内部的声音&#…