构建 NodeJS 影院微服务并使用 docker 部署它(02/4)

news2024/11/24 17:05:19

一、说明

        构建一个微服务的电影网站,需要Docker、NodeJS、MongoDB,这样的案例您见过吗?如果对此有兴趣,您就继续往下看吧。

图片取自网络 — 封面由我制作

这是✌️“构建 NodeJS 影院微服务”系列的第二篇文章。

二、对第一部分的快速回顾

  • 我们讨论什么是微服务
  • 我们看到了微服务的优点和缺点
  • 我们定义了一个影院微服务架构。
  • 我们使用 RAML 设计我们的电影服务 API 规范。
  • 我们使用 NodeJS 和 ExpressJS 开发我们的电影服务 API
  • 我们对 API 进行了单元测试
  • 我们编写我们的 API 以使其成为服务,并将我们的电影服务运行到 Docker 容器中。
  • 我们对在 Docker 上运行的电影服务进行了集成测试

如果你还没有读过第一章,我会把链接放在下面,所以你可以看看👀。

构建一个 NodeJS 影院微服务并使用 docker 部署它 — 第 1 部分

这是“构建 NodeJS 影院微服务”系列的第一章,这个系列是关于构建 NodeJS...

在本文中,我们将继续构建我们的电影院微服务,这次我们将开发电影院目录服务,以完成下图。

我们将在本文中使用的是:

  • NodeJS 版本 7.2.0
  • MongoDB 3.4.1
  • Docker for Mac 1.13

跟进文章的先决条件:

  • 已完成上一章中的示例。

如果您还没有,我已经在以下 github 存储库上传了存储库,因此您可以在分支步骤 1 处获得最新的存储库链接。

三、微服务安全和  HTTP/2 

        在第一章中,我们做了一个简单的微服务来实现HTTP/1.1协议。HTTP/2 是 15 年来对 HTTP 协议的首次重大升级,经过高度优化,性能更好。HTTP/2是新的Web标准,最初是Google的SPDY协议。它已经被许多流行的网站使用,并被大多数主流浏览器支持。

HTTP/2 只有一些规则必须满足才能实现它。

  • 它仅适用于HTTPS协议(我们需要有效的SSL证书)。
  • 它是向后兼容的。如果运行应用程序的浏览器或设备不支持 HTTP/2,它将回退到 HTTP1.1。
  • 它具有开箱即用的巨大性能改进。
  • 它不需要您在客户端执行任何操作,只需在服务器端执行基本实现即可。
  • 一些新的有趣的功能将加快Web项目的加载时间,其方式甚至是HTTP1.1实现无法想象的。

四、为微服务启用网络架构的 HTTP/2

这意味着我们需要在客户端和服务器之间启用单个连接,然后在“网络”中利用 Y 轴分片等功能(更多地谈论系列中的缩放立方体)来保持 HTTP/2 对客户端的性能优势,同时实现微服务架构的所有操作和开发优势。

        那么我们为什么要实施新的HTTP / 2协议,这是因为作为优秀的开发人员,我们必须尽可能保护我们的应用程序,基础架构,通信,以防止恶意攻击,也因为作为优秀的开发人员,我们遵循我们认为对我们有益的最佳实践,就像这个。

        微服务的一些安全最佳实践如下所示:

安全性显然将在采用和部署微服务应用程序以供生产使用的决定中发挥重要作用。根据2016 Research发布的研究报告《451年软件定义的基础设施展望》,近45%的企业已经实施或计划在未来12个月内推出基于容器的应用程序。随着 DevOps 实践在企业中站稳脚跟,容器应用程序变得越来越普遍,安全管理员需要用保护应用程序的专业知识武装自己。— @Ranga 拉贾戈帕兰

  • 发现和监视服务间通信
  • 对应用程序和服务进行分段和隔离
  • 加密传输中的数据和静态数据

        我们要做的是加密我们的微服务通信以满足合规性要求并提高安全性,尤其是当流量通过公共网络时,这就是我们要实施HTTP / 2的原因之一,以获得更好的性能和安全性改进。

五、在微服务中实现 HTTP/2

        首先,让我们更新上一章的电影服务并实现HTTP / 2协议,但是在我们打算在config文件夹中创建一个ssl文件夹之后。

movies-service/config:/ $ mkdir ssl
movies-service/config:/ $ cd ssl

        现在,一旦进入 ssl 文件夹,让我们创建一个自签名 SSL 证书,以开始在我们的服务中实现 HTTP/2 协议。

# Let's generate the server pass key

ssl/: $ openssl genrsa -des3 -passout pass:x -out server.pass.key 2048 
# now generate the server key from the pass key

ssl/: $ openssl rsa -passin pass:x -in server.pass.key -out server.key
# we remove the pass key

ssl/: $ rm server.pass.key
# now let's create the .csr file
ssl/: $ openssl req -new -key server.key -out server.csr 
...
Country Name (2 letter code) [AU]:MX
State or Province Name (full name) [Some-State]:Michoacan 
... 
A challenge password []: 
...
# now let's create the .crt file
ssl/: $ openssl x509 -req -sha256 -days 365 -in server.csr -signkey server.key -out server.crt

        接下来我们需要使用以下命令安装 SPDY

cinema-catalog-service/: $ npm i -S spdy --silent

        首先让我们在文件夹中创建一个文件,使用以下代码,这里是我们加载密钥和证书文件的地方,这可能是我们可以使用的少数情况之一:index.jsssl/fs.readFileSync()

const fs = require('fs')
module.exports = {
  key: fs.readFileSync(`${__dirname}/server.key`),
  cert: fs.readFileSync(`${__dirname}/server.crt`)
}

然后我们需要修改几个文件,让我们先修改config.js

const dbSettings = { ... }
// The first modification is adding the ssl certificates to the 
// serverSettings
const serverSettings = {
  port: process.env.PORT || 3000,
  ssl: require('./ssl')
}
module.exports = Object.assign({}, { dbSettings, serverSettings })

接下来,让我们修改文件,如下所示:server.js

...
const spdy = require('spdy')
const api = require('../api/movies')
const start = (options) => {
...
 const app = express()
 app.use(morgan('dev'))
 app.use(helmet())
 app.use((err, req, res, next) => {
   reject(new Error('Something went wrong!, err:' + err))
   res.status(500).send('Something went wrong!')
 })
 api(app, options)
 // here is where we made the modifications, we create a spdy
 // server, then we pass the ssl certs, and the express app
 const server = spdy.createServer(options.ssl, app)
      .listen(options.port, () => resolve(server))
  })
}
module.exports = Object.assign({}, {start})

最后让我们修改主文件:index.js

'use strict'
const {EventEmitter} = require('events')
const server = require('./server/server')
const repository = require('./repository/repository')
const config = require('./config/')
const mediator = new EventEmitter()
...
mediator.on('db.ready', (db) => {
  let rep
  repository.connect(db)
    .then(repo => {
      console.log('Connected. Starting Server')
      rep = repo
      return server.start({
        port: config.serverSettings.port,
        // here we pass the ssl options to the server.js file
        ssl: config.serverSettings.ssl,
        repo
      })
    })
    .then(app => { ... })
})
...

现在我们需要使用以下命令重建我们的 docker 镜像:

$ docker build -t movies-service .

并使用以下参数运行我们的 docker 映像:movies-service

$ docker run --name movies-service -p 443:3000 -d movies-service

最后,我们使用Chrome浏览器对其进行了测试,我们可以证实我们的HTTP / 2协议完全有效。

Chrome 开发工具

我们还可以证实使用wireshark进行一些网络捕获,我们可以看到SSL确实有效。

线鲨帧捕获

5.1 将 JWT 实现到微服务

加密和保护微服务通信的另一种方法是使用该协议,但我们将在后面的系列🚉中看到此实现。json web token

5.2 构建微服务

好的,现在我们知道了如何实现 HTTP/2 协议,让我们继续构建电影目录服务。 我们将使用与电影服务相同的项目结构,因此 少说话🗣多编码 👨🏻 💻👩🏻 💻 .

在我们开始设计 API 之前,这次我们需要为我们的数据库设计我们的 Mongo 模式,因为我们将使用以下内容:

  • 地点(国家、州和城市)
  • 电影院(电影院、时间表、电影)

5.3  模型数据设计

        本文主要专注于创建微服务,因此我不会花费大量时间为我们的电影院数据库进行“模型数据设计”,而是将重点介绍这些领域和要点。

# posible collections for the cinemas db.
# For locations 
- countries
- states
- cities
# For cinemas
- cinemas
- cinemaRooms
- schedules

        因此,对于我们的位置,一个国家/地区具有许多州,而州具有一个国家/地区,因此第一种关系是一对多关系,但这也适用于,一个州有许多城市,一个城市具有一个州,因此让我们看看我们的关系示例如何。

国家 — 国家关系

        州/城市关系

        但是这种关系也是可能的,一个城市有很多电影院一个电影院属于一个城市,另一个关系我们可以看到就是一个电影院房间有很多档期,一个档期属于一个电影院房间,所以让我们看看这种关系是怎样的。

        如果电影院阵列或时间表阵列的增长受到限制,则上图中的这种引用可能很有用。假设一个电影室每天最多有 5 个时间表,所以在这里我们可以将时间表文档嵌入到电影院文档中。

嵌入式数据模型允许应用程序在同一数据库记录中存储相关信息。因此,应用程序可能需要发出较少的查询和更新来完成常见操作。— MongoDB Docs

因此,这是我们数据库模式设计的最终结果。

5.4 将数据导入我们的数据库

        我已经准备了一些数据示例,其中包含上面看到的模式设计,这些文件位于 github 存储库中,有 4 个 json 文件,因此您可以将其导入电影院数据库,但首先我们需要知道哪个数据库服务器是主要的,因此找出并执行以下命令:cinema-catalog-service/src/mock

# first we need to copy the files one by one or we can zip it and pass the zip file
$ docker cp countries.json mongoNodeContainer:/tmp
$ docker cp state.json mongoNodeContainer:/tmp
$ docker cp city.json mongoNodeContainer:/tmp
$ docker cp cinemas.json mongoNodeContainer:/tmp

执行上述命令后,让我们将其导入数据库,如下所示:

$ docker exec mongoNode{number} bash -c 'mongoimport --db cinemas --collection countries --file /tmp/countries.json --jsonArray -u $MONGO_USER_ADMIN -p $MONGO_PASS_ADMIN --authenticationDatabase "admin"'

$ docker exec mongoNode{number} bash -c 'mongoimport --db cinemas --collection states --file /tmp/states.json --jsonArray -u $MONGO_USER_ADMIN -p $MONGO_PASS_ADMIN --authenticationDatabase "admin"'

$ docker exec mongoNode{number} bash -c 'mongoimport --db cinemas --collection cities --file /tmp/cities.json --jsonArray -u $MONGO_USER_ADMIN -p $MONGO_PASS_ADMIN --authenticationDatabase "admin"'

$ docker exec mongoNode{number} bash -c 'mongoimport --db cinemas --collection cinemas --file /tmp/cinemas.json --jsonArray -u $MONGO_USER_ADMIN -p $MONGO_PASS_ADMIN --authenticationDatabase "admin"'

        现在我们已经准备好了数据库模式设计,数据也准备好了,可以查询了,所以我们现在可以为电影目录服务设计我们的 API,定义路由的一种方法是制作一些句子,如下所示:

  • 我们需要一个城市来展示可用的电影院。
  • 我们需要电影院来展示电影首映式。
  • 我们需要电影首映并显示时间表。
  • 我们需要时间表,以查看是否有可供预订的座位。

        让我们假设 Cinépolis IT 部门的其他团队正在执行其他 CRUD 操作,我们的任务是使“R”成为读取数据,让我们假设一些 Cinépolis 电影院运营人员已经为电影院制定了计划,因此我们的任务是检索这些计划。

        电影院目录服务所关注的只是电影院和时间表,仅此而已,上面我们看到我们进行了位置收集,但这是对另一个微服务的关注,但我们依赖于能够显示电影院和时间表的位置。

        现在我们已经定义了我们的需求,我们可以构建我们的 RAML 文件,如下所示:

#%RAML 1.0
title: Cinema Catalog Service
version: v1
baseUri: /
uses:
  object: types.raml
  stack: ../movies-service/api.raml

types:
  Cinemas: object.Cinema []
  Movies: stack.MoviePremieres
  Schedules: object.Schedule []

traits:
  FilterByLocation:
    queryParameters:
      city:
        type: string

resourceTypes:
  GET:
    get:
      responses:
        200:
          body:
            application/json:
              type: <<item>>


/cinemas:
  type:  { GET: {item : Cinemas } }
  get:
    is: [FilterByLocation]
  description: we already have the location defined to display the cinemas

  /cinemas/{cinema_id}:
    type:  { GET: {item : Movies } }
    description: we have selected the cinema to display the movie premieres

    /cinemas/{cinema_id}/{movie_id}:
      type:  { GET: {item : Schedules } }
      description: we have selceted a movie to display the schedules

        我们已经满足了上面 3 句话中的 4 句,第 4 句话用于在电影院预订,但我的朋友属于预订服务,他们负有这一责任,所以请继续关注“构建 NodeJs 电影院微服务 — 系列”。

现在我们可以继续为电影目录服务开发我们的 NodeJS API,其结构和配置与电影服务几乎相同,所以我将开始向您展示此 API。repository.js

// more code above

const getCinemasByCity = (cityId) => {
    return new Promise((resolve, reject) => {
      const cinemas = []
      const query = {city_id: cityId}
      const projection = {_id: 1, name: 1}
      // example of making a find query to mongoDB, 
      // passign a query and projection objects.
      const cursor = db.collection('cinemas').find(query, projection)
      const addCinema = (cinema) => {
        cinemas.push(cinema)
      }
      const sendCinemas = (err) => {
        if (err) {
          reject(new Error('An error occured fetching cinemas, err: ' + err))
        }
        resolve(cinemas)
      }
      cursor.forEach(addCinema, sendCinemas)
    })
  }

  const getCinemaById = (cinemaId) => {
    return new Promise((resolve, reject) => {
      const query = {_id: new ObjectID(cinemaId)}
      const projection = {_id: 1, name: 1, cinemaPremieres: 1}
      const response = (err, cinema) => {
        if (err) {
          reject(new Error('An error occuered retrieving a cinema, err: ' + err))
        }
        resolve(cinema)
      }
      // example of using findOne method from mongodb, 
      // we do this because we only need one record.
      db.collection('cinemas').findOne(query, projection, response)
    })
  }

  const getCinemaScheduleByMovie = (options) => {
    return new Promise((resolve, reject) => {
      const match = { $match: {
        'city_id': options.cityId,
        'cinemaRooms.schedules.movie_id': options.movieId
      }}
      const project = { $project: {
        'name': 1,
        'cinemaRooms.schedules.time': 1,
        'cinemaRooms.name': 1,
        'cinemaRooms.format': 1
      }}
      const unwind = [{ $unwind: '$cinemaRooms' }, { $unwind: '$cinemaRooms.schedules' }]
      const group = [{ $group: {
        _id: {
          name: '$name',
          room: '$cinemaRooms.name'
        },
        schedules: { $addToSet: '$cinemaRooms.schedules.time' }
      }}, { $group: {
        _id: '$_id.name',
        schedules: {
          $addToSet: {
            room: '$_id.room',
            schedules: '$schedules'
          }
        }
      }}]
      const sendSchedules = (err, result) => {
        if (err) {
          reject('An error has occured fetching schedules by movie, err: ' + err)
        }
        resolve(result)
      }
      // example of using a aggregation method from mongoDB
      // we difine our pipline above, we are using also ES6 spread operator
      db.collection('cinemas').aggregate([match, project, ...unwind, ...group], sendSchedules)
    })
  }


// more code below

要查看完整的文件,您可以在“github 存储库分支步骤-2”中检查它。repository.js

在这里,我们定义了 3 个函数:

  • getCinemasByCity:这个函数将获取城市中所有可用的电影院,我们通过city_id找到电影院,这个函数的结果帮助我们调用下一个电影院。
  • getCinemaById:此函数将通过cinema_id查询来检索可用的名称、id 和首映电影,该函数的结果将帮助我们最终获得时间表。
  • getCinemaScheduleByMovie: 此功能将为我们提供城市中所有电影院上可用的电影的所有时间表。

可能还有另一个功能,或者我们可以修改getCinemaById,以显示当前电影院的时间表,这对您来说可能是一个很好的挑战,如果您想练习,这不会那么困难,因为我已经为您提供了所有需要的信息。

下一个要检查的文件是我们的 API 文件 .cinemas-catalog.js

'use strict'
const status = require('http-status')

module.exports = (app, options) => {
  const {repo} = options

  app.get('/cinemas', (req, res, next) => {
    repo.getCinemasByCity(req.query.cityId)
      .then(cinemas => {
        res.status(status.OK).json(cinemas)
      })
      .catch(next)
  })

  app.get('/cinemas/:cinemaId', (req, res, next) => {
    repo.getCinemaById(req.params.cinemaId)
      .then(cinema => {
        res.status(status.OK).json(cinema)
      })
      .catch(next)
  })

  app.get('/cinemas/:cityId/:movieId', (req, res, next) => {
    const params = {
      cityId: req.params.cityId,
      movieId: req.params.movieId
    }
    repo.getCinemaScheduleByMovie(params)
      .then(schedules => {
        res.status(status.OK).json(schedules)
      })
      .catch(next)
  })
}

如您所见,这里我们实现端点,正如我们在 RAML 文件中定义的那样,并根据路由调用函数。repository.js

在我们的第一条路线中,我们用于获取值并查询我们的数据库以按城市获取电影院,而在其他路线中,我们用于获取值并能够查询。 😎req.query.cityIdcity_idreq.paramscinemaIdmovieIdschedules

最后我们可以看到用于测试的文件:cinema-catalog.spec.js

/* eslint-env mocha */
const request = require('supertest')
const server = require('../server/server')
process.env.NODE = 'test'

describe('Movies API', () => {
  let app = null
  const testCinemasCity = [{
    '_id': '588ac3a02d029a6d15d0b5c4',
    'name': 'Plaza Morelia'
  }, {
    '_id': '588ac3a02d029a6d15d0b5c5',
    'name': 'Las Americas'
  }]

  const testCinemaId = {
    '_id': '588ac3a02d029a6d15d0b5c4',
    'name': 'Plaza Morelia',
    'cinemaPremieres': [
      {
        'id': '1',
        'title': 'Assasins Creed',
        'runtime': 115,
        'plot': 'Lorem ipsum dolor sit amet',
        'poster': 'link to poster...'
      },
      {
        'id': '2',
        'title': 'Aliados',
        'runtime': 124,
        'plot': 'Lorem ipsum dolor sit amet',
        'poster': 'link to poster...'
      },
      {
        'id': '3',
        'title': 'xXx: Reactivado',
        'runtime': 107,
        'plot': 'Lorem ipsum dolor sit amet',
        'poster': 'link to poster...'
      }
    ]
  }

  const testSchedulesMovie = [{
    '_id': 'Plaza Morelia',
    'schedules': [{
      'room': 2.0,
      'schedules': [ '10:15' ]
    }, {
      'room': 1.0,
      'schedules': [ '6:55', '4:35', '10:15' ]
    }, {
      'room': 3.0,
      'schedules': [ '10:15' ]
    }]
  }, {
    '_id': 'Las Americas',
    'schedules': [ {
      'room': 2.0,
      'schedules': [ '3:25', '10:15' ]
    }, {
      'room': 1.0,
      'schedules': [ '12:15', '10:15' ]
    }]
  }]

  let testRepo = {
    getCinemasByCity (location) {
      console.log(location)
      return Promise.resolve(testCinemasCity)
    },
    getCinemaById (cinemaId) {
      console.log(cinemaId)
      return Promise.resolve(testCinemaId)
    },
    getCinemaScheduleByMovie (cinemaId, movieId) {
      console.log(cinemaId, movieId)
      return Promise.resolve(testSchedulesMovie)
    }
  }

  beforeEach(() => {
    return server.start({
      port: 3000,
      repo: testRepo
    }).then(serv => {
      app = serv
    })
  })

  afterEach(() => {
    app.close()
    app = null
  })

  it('can return cinemas by location', (done) => {
    const location = {
      city: '588ababf2d029a6d15d0b5bf'
    }
    request(app)
      .get(`/cinemas?cityId=${location.city}`)
      .expect((res) => {
        res.body.should.containEql(testCinemasCity[0])
        res.body.should.containEql(testCinemasCity[1])
      })
      .expect(200, done)
  })

  it('can get movie premiers by cinema', (done) => {
    request(app)
    .get('/cinemas/588ac3a02d029a6d15d0b5c4')
    .expect((res) => {
      res.body.should.containEql(testCinemaId)
    })
    .expect(200, done)
  })

  it('can get schedules by cinema and movie', (done) => {
    request(app)
      .get('/cinemas/588ababf2d029a6d15d0b5bf/1')
      .expect((res) => {
        res.body.should.containEql(testSchedulesMovie[0])
        res.body.should.containEql(testSchedulesMovie[1])
      })
      .expect(200, done)
  })
})

        最后,我们可以构建我们的 docker 镜像并在我们的容器中运行它,我们将从 movies 服务中使用相同的镜像,以使此过程更加自动化,让我们为此任务创建一个 bash 脚本,如下所示:cinema-catalog-servicedockerfilestart-service.sh

#!/usr/bin/env bash
eval `docker-machine env manager1`
docker build -t catalog-service .
docker run --name catalog-service -p 3000:3000 --env-file env -d catalog-service

        随着我们开始制作更多服务,我们需要小心我们服务可用的端口,所以这次,我将使用端口 3000,另外我将使用 a 开始使用我们的 NodeJS 服务中的配置,我们的 env 文件将如下所示:env fileprocess.env

DB=cinemas
DB_USER=cristian
DB_PASS=cristianPassword2017
DB_REPLS=rs1
DB_SERVERS='192.168.99.100:27017 192.168.99.101:27017 192.168.99.102:27017'
PORT=3000

        这被认为是在 devOps 领域之外的最佳实践。

        最后,我们需要像下面这样运行我们的小 bash 脚本:

# execute our script
$ bash < start-service.sh
# check running docker contianers
$ docker ps

我们需要这样的东西:

        码头工人状态

        我们可以在Chrome浏览器中测试我们的服务,并验证我们的HTTP / 2协议是否正常工作,以及我们的服务是否正常工作。

铬浏览器 — 测试

        为了好玩,我们可以使用 JMeter 进行压力测试,压力测试文件也位于 github 存储库的文件夹中。integration-test/

JMeter capture

stress test example

5.5 是时候回顾一下了

        已经实现的:

休息沟通

        我们已经完成了此图的微服务,您可能会说我们没有在我们的电影院目录服务中使用电影服务,是的,这是正确的,我们所做的只是来自我们服务的 GET 请求,并且在电影院目录服务中使用我们的电影服务是通过进行 POST 请求完成影院首映堆栈电影以便能够制定时间表,但由于我们的任务是从我们团队中的 CRUD 操作制作 R,这就是为什么我们没有看到这种交互,但稍后在该系列中,我们将在微服务之间进行更多的 CRUD 操作,请耐心等待,:D保持好奇心。

        因此,我们在本章🤔中了解了HTTP / 2协议,并看到了如何在微服务中实现它。我们还看到了如何设计 MongoDB 模式,我们没有深入,但我突出显示它是为了更好地了解电影院目录服务中发生的事情,然后我们使用 RAML 设计 API,我们开始构建我们的 API 服务,然后我们进行了相应的单元测试,最后我们编写所有内容以使我们的微服务完成。

        然后我们使用之前微服务中的相同 dockerfile,并编写一个脚本来自动化此过程,我们还介绍了如何使用和 env 文件并在 Docker 容器中使用它,准备好所有设置后,我向您展示了 JMeter 进行压力测试以补充集成测试的简短图片。environment variables

        我们已经在 NodeJS 中看到了很多开发,但我们可以做和学习的东西还有很多,这只是一个先睹为快的高峰。我希望这已经展示了一些有趣和有用的东西,你可以在你的工作流程中用于Docker和NodeJS

5.6 即将推出

        现在我们已经完成了第一个图表,我们将开发第二个图表,预订服务图......👀👨🏻‍💻👩🏻‍💻🎫

微服务图

六、在 Github 上完成代码

您可以在以下链接中查看文章的完整代码。

Crizstian/cinema-microservice

影院微服务 - 影院微服务示例

github.com

七、# 参考资料延伸阅读

为了更好地使用NodeJS,您可以查看此站点

  • 10年成为更好的节点开发人员的2017个技巧
  • NodeJS 教程系列 — Node Hero(几乎涵盖了所有节点主题)
  • 简单的HTTP / 2服务器与Node.js和Express.js
  • HTTP/2:好的、坏的和丑陋的

克里斯蒂安·拉米雷斯

 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

8.3.tensorRT高级(3)封装系列-tensor封装,索引计算,内存标记及自动复制

目录 前言1. Tensor封装总结 前言 杜老师推出的 tensorRT从零起步高性能部署 课程&#xff0c;之前有看过一遍&#xff0c;但是没有做笔记&#xff0c;很多东西也忘了。这次重新撸一遍&#xff0c;顺便记记笔记。 本次课程学习 tensorRT 高级-tensor封装&#xff0c;索引计算&a…

cuOSD(CUDA On-Screen Display Library)库的学习

目录 前言1. cuOSD1.1 Description1.2 Getting started1.3 For Python Interface1.4 Demo1.5 Performance Table 2. cuOSD案例2.1 环境配置2.2 simple案例2.3 segment案例2.4 segment2案例2.5 polyline案例2.6 comp案例2.7 perf案例 3. cuOSD浅析3.1 simple_draw函数 4. 补充知…

MacBook上有Face ID的梦想还没破灭,但是为什么迟迟不来呢

苹果公司详细介绍了Face ID与Touch ID相比的优势&#xff0c;尤其是在安全方面。因此&#xff0c;令人惊讶的是&#xff0c;该功能还没有进入MacBook&#xff0c;尤其是在显示方面。值得庆幸的是&#xff0c;一项新专利表明&#xff0c;在某个时候&#xff0c;这可能是一种可能…

《修图大杀器》PS beta 25.0最新版安装(无需魔法)和Draggan(拖拽式修图)安装

个人网站&#xff1a;https://tianfeng.space 文章目录 psbeta下载安装1.注册2.安装ps beta2.安装神经网络滤镜3.使用 Draggan下载安装 psbeta下载安装 链接&#xff1a;https://pan.baidu.com/s/1XbxSAFoXh0HDz6YbkrAzDg 提取码&#xff1a;e8pn 1.注册 https://account.a…

C++--深入类和对象(下)

续接上篇&#xff0c;接着来谈我们的类和对象的深入的知识&#xff0c;话不多说&#xff0c;我们即刻出发...... 目录 1.友元 1.1友元函数 输出流运算符的重载 1.2友元类 2.再谈构造函数 2.1构造函数体赋值和初始化列表 构造函数体赋值为何不能叫做初始化&#xff1f; …

一个模型解决所有类别的异常检测

文章目录 一、内容说明二、相关链接三、概述四、摘要1、现有方法存在的问题2、方案3、效果 五、作者的实验六、如何训练自己的数据1、数据准备2、修改配置文件3、代码优化修改4、模型训练与测试 七、结束 一、内容说明 在我接触的缺陷检测项目中&#xff0c;检测缺陷有两种方法…

TMS320C54X 的软件编程

1、DSP 编程工具与流程 DSP 的设计目标是进行数字信号处理&#xff0c;在硬件设计的基础上选择好一定的优化算法并 通过编程在 DSP 芯片上实现是 DSP 技术的核心内容。对 DSP 进行编程&#xff0c;目前最有效的语言 工具仍是 DSP 汇编语言&#xff0c;同时为方便用户用高级语言…

每日一题之数值的整数次方

数值的整数次方 描述&#xff1a; 实现函数 double Power(double base, int exponent)&#xff0c;求 base 的 exponent 次方。 注意&#xff1a; 1.保证base和exponent不同时为0。 2.不得使用库函数&#xff0c;同时不需要考虑大数问题 3.有特殊判题&#xff0c;不用考虑小数…

mysql+jdbc+servlet+java实现的学生在校疫情信息打卡系统

摘 要 I Abstract II 主 要 符 号 表 i 1 绪论 1 1.1 研究背景 1 1.2 研究目的与意义 2 1.3 国内外的研究情况 2 1.4 研究内容 2 2 系统的开发方法和关键技术 4 2.1 开发方法 4 2.1.1 结构化开发方法 4 2.1.2 面向对象方法 4 2.2 开发技术 4 2.2.1 小程序开发MINA框架 4 2.2.2 …

[Spring]事务相关

事务隔离级别 Spring 提供了以下五种事务隔离级别&#xff0c;用于控制多个事务之间的相互影响&#xff1a; DEFAULT&#xff08;默认隔离级别&#xff09;&#xff1a; 使用底层数据库的默认隔离级别。通常为数据库的默认隔离级别&#xff0c;如 MySQL 是 REPEATABLE READ&am…

逆向退货售后设计

一&#xff0c;项目背景 退货售后流程&#xff1a;涉及订单&#xff0c;票&#xff0c;款 二&#xff0c;方案一 三&#xff0c;方案二

残差网络实现

代码中涉及的图片实验数据下载地址&#xff1a;https://download.csdn.net/download/m0_37567738/88235543?spm1001.2014.3001.5501 代码&#xff1a; import torch import torch.nn as nn import torch.nn.functional as F #from utils import load_data,get_accur,train i…

只需5分钟,了解常见的四种限流算法

一、计数器算法 在指定周期内累加访问次数&#xff0c;当访问次数达到设定的阈值时&#xff0c;触发限流策略&#xff0c;当进入下一个时间周期时进行访问次数的清零。如图所示&#xff0c;我们要求3秒内的请求不要超过150次&#xff1a; 但是&#xff0c;貌似看似很“完美”的…

[mysql系列] mysql 数据库如何实现事务回滚

这里写自定义目录标题 一、事务回滚二、mysql InnoDB引擎如何实现回滚操作2.1 InnoDB引擎的 undo log2.2 具体实现2.2.1 insert 操作2.2.2 delete 操作2.2.3 update 操作 主要参考资料为&#xff1a;《Mysql 是怎样运行的》 一、事务回滚 根据原子性的定义&#xff0c;一个事务…

MySQL MVCC的详解之Read View

文章目录 概要一、基于UNDO LOG的版本链1.1、行记录结构1.2、了解UNDO LOG1.3、版本链 二、Read View2.1、判定机制 三、参考 概要 在上文中&#xff0c;我们提到了MVCC&#xff08;Multi-Version Concurrency Control)多版本并发控制&#xff0c;是通过undo log来实现的。那具…

MATLAB | 七夕节用MATLAB画个玫瑰花束叭

Hey又是一年七夕节要到了&#xff0c;每年一次直男审美MATLAB绘图大赛开始hiahiahia&#xff0c;真的这些代码越写越不知道咋写&#xff0c;又不想每年把之前的代码翻出来再发一遍&#xff0c;于是今年又对我之前写的老代码进行了点优化组合&#xff0c;整了个花球变花束&#…

计算机网络-物理层(三)-信道的极限容量

计算机网络-物理层(三)-信道的极限容量 当信号在信道中传输失真不严重时&#xff0c;在信道的输出端&#xff0c;这些信号可以被识别 当信号在信道中&#xff0c;传输失真严重时&#xff0c;在信道的输出端就难以识别 造成失真的因素 码元传输速率信号传输距离噪声干扰传输媒…

8.4.tensorRT高级(3)封装系列-infer推理封装,输入输出tensor的关联

目录 前言1. infer封装总结 前言 杜老师推出的 tensorRT从零起步高性能部署 课程&#xff0c;之前有看过一遍&#xff0c;但是没有做笔记&#xff0c;很多东西也忘了。这次重新撸一遍&#xff0c;顺便记记笔记。 本次课程学习 tensorRT 高级-infer推理封装&#xff0c;输入输出…

思维进化算法(MEA)优化BP神经网络

随着计算机科学的发展,人们借助适者生存这一进化规则,将计算机科学和生物进化结合起来,逐渐发展形成一类启发式随机搜索算法,这类算法被称为进化算法(Evolutionary Com-putation, EC)。最著名的进化算法有:遗传算法、进化策略、进化规划。与传统算法相比,进化算法的特点是群体搜…

嵌入式设备应用开发(boost库应用)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】 嵌入式开发过程中不可避免在很多情况下,需要使用到posix的api函数。一方面,这些api函数确实可以帮助我们解决一些问题;但是另外一方面,因为平台的差异,如果一段时间不做嵌入式…