Бессерверное практическое руководство по 4D Long Text

внешний интерфейс Serverless
Бессерверное практическое руководство по 4D Long Text

предисловие

Serverless = Faas (Function as a service) + Baas (Backend as a service)

Бессерверная технология позволяет нам больше сосредоточиться на развитии бизнеса.Бессерверная технология помогла нам решить некоторые распространенные проблемы на стороне сервера:

  • Serverless не нужно создавать серверную среду, распространять переменные среды и поддерживать согласованность среды каждой машины (механизм Serverless можно скопировать естественным образом).
  • Serverless не требует оценки трафика, заботы об использовании ресурсов, аварийного резервного копирования и расширения машин (Serverless может динамически расширяться в соответствии с трафиком и взимать плату в соответствии с реальными запросами).
  • Serverless не нужно заботиться об утечках памяти (бессерверная облачная функция будет уничтожена после завершения обслуживания)
  • Бессерверные службы имеют полные вспомогательные службы, такие как облачная база данных, облачное хранилище, облачная очередь сообщений, облачные аудио- и видеослужбы, облачные службы искусственного интеллекта и т. д. Использование этих облачных служб может значительно снизить нашу рабочую нагрузку.

Первые три пункта выше — это категория Faas, а четвертый пункт — это категория Baas.Проще говоря, Serverless можно понимать как систему, которая может загружать или редактировать функцию онлайн.Операционная среда этой функции предоставляется Чтобы сделать запрос, система автоматически запускает функцию для обслуживания, нам нужно только написать код функции, после отправки система будет автоматически расширяться и сжиматься в зависимости от трафика, и функция может вызывать различные существующие API-интерфейсы облачных сервисов для упрощения наших затрат на разработку и обслуживание.

Я прочитал много статей о Serverless, большинство из которых посвящено архитектуре и реализации самого serverless.В этой статье будет использован простой и понятный пример для иллюстрации реализации простой системы блогов в Tencent Cloud Serverless, во время которой только Будут задействованы Фаас и Баас Практическая часть.

Давайте начнем~

Краткое описание функций простой системы блогов

时序图

Как показано на диаграмме последовательности выше, простая система блогов, реализованная на этот раз, имеет только страницу списка блогов и страницу содержимого блога и не включает комментарии или входы в систему. сама функция, как разрабатывать локально и как связано с пользовательским доменным именем, как получить доступ к облаку MySQL, как организовать код в облачных функциях, таких как Router, Controller, Service, Model и View и т. д.

Давайте начнем с этих вопросов~

Инициализация и базовая настройка облачных функций

доступздесь, нажмите, чтобы использовать его немедленно, чтобы войти в облачную функцию:

腾讯云函数入口

Для того, чтобы вы не боялись, давайте сначала итоги, функции Tencent Cloud имеют бесплатную квоту в 1 миллион вызовов в месяц, что достаточно для личного обучения и использования.

Хорошо, продолжим~

После нажатия «Использовать сейчас» на приведенном выше рисунке мы можем увидеть обзорный интерфейс облачной функции:

腾讯云函数概览

Щелкните службу функции слева и в появившемся интерфейсе нажмите «Создать»:

新建云函数

Появится страница, показанная на снимке экрана ниже. Введите имя функции, выберите язык, и вы можете выбрать инициализацию из шаблона функции. Здесь в правом нижнем углу выбрано «Демонстрация продвижения операции SCF Национального дня». Ps, обратите внимание, что здесь есть много шаблонов, таких как доступ к базе данных, возврат на страницу, сжатие изображений, транскодирование видео, слияние файлов и многое другое, что снижает нашу стоимость входа.

选择模板

После выбора шаблона нажмите «Далее», появится этот интерфейс, установите переменные среды и сетевое окружение.

设置环境变量与网络环境

Нажмите «Готово», и наша облачная функция будет сгенерирована. Давайте посмотрим на эффект. Хотя это облачная функция, здесь больше одного файла. Он может быть организован в виде нескольких файлов:

云函数代码

При внимательном рассмотрении кода становится понятно, что сделать это очень просто: в соответствии со стандартом облачных функций предоставляется обработчик main_handler, который считывает шаблон html-страницы, анализирует html-шаблон + данные в html-строку с помощью функции рендеринга и, наконец, возвращается.

Итак, как мы можем получить доступ к этой облачной функции?

Ответ заключается в настройке метода триггера. Мы настраиваем метод триггера, который будет запускаться шлюзом API. Настройки следующие:

触发器配置

Некоторые понятия на диаграмме объясняются здесь:

  • Триггер синхронизации: обычно используется для некоторых задач синхронизации, таких как регулярная отправка электронных писем, запуск данных, отправка напоминаний и т. д.
  • COS — это облачное хранилище Tencent. Например, изображения и видео можно хранить в COS. Триггер COS означает, что эта функция активируется после загрузки файла в COS. В настоящее время эту функцию можно использовать для сжатия изображений, транскодирование видео и т.д.
  • Инициируется Ckafka, когда в очереди сообщений Ckafka появляются новые данные.
  • API-шлюз срабатывает, то есть когда есть запрос, срабатывает эта функция.

Здесь мы выбираем API Gateway для срабатывания, то есть когда есть запрос, эта функция срабатывает.

После сохранения мы можем увидеть путь доступа к облачной функции:

云函数访问路径

Вот ссылка для доступа в моем примере, вы можете ее испытать~

перейти по ссылке

Вышеизложенное является нашим начальным пониманием облачных функций.Далее мы углубимся и предложим вам создать простую систему блогов.

Tencent Serverless Toolkit for VS Code

В первую очередь нам нужна локальная среда разработки.Хотя опыт работы онлайн-редактора аналогичен опыту vscode, все-таки после нашей настройки редактирование локального кода лучше.Потом модифицируем код локально, как опубликовать облако функция Шерстяная ткань?

Взяв в качестве примера VSCode, нам нужно установить «Tencent Serverless Toolkit for VS Code», который можно найти и установить в плагине VSCode. Подробные инструкции по установке будут на домашней странице плагина, поэтому я не буду повторять их здесь.

Интерфейс плагина показан на рисунке:

scf vscode 插件

После установки слева появится дополнительная иконка облачной функции, с помощью которой вы сможете:

  • Потяните список облачных функций в облаке и активируйте облачную функцию для запуска в облаке.
  • Быстро создавайте проекты облачных функций локально.
  • Разрабатывайте, отлаживайте и тестируйте код облачных функций локально.
  • Используйте смоделированные события COS, CMQ, CKafka, API Gateway и т. д. для запуска функций.
  • Загрузите код функции в облако и обновите конфигурацию функции.

Обычно интерфейсный код необходимо упаковать и выполнить.npm install, npm run buildПодождите, облачная функция не предоставляет эту среду, мы можем опубликовать код через этот плагин после локальной упаковки.Конечно, мы также можем использовать инструмент непрерывной интеграции для запуска cli для публикации, это не будет обсуждаться.

Выбор и дизайн базы данных

Выбор базы данных

Вот выборTencent Cloud Mysql.Минимальная конфигурация базовой версии составляет всего 29 юаней в месяц~.Конечно, также можно создать свою собственную базу данных и выставить ее для обучения.Однако, если вы хотите использовать ее в течение длительного времени в более поздний период, для облегчения обслуживания и обеспечения стабильности данных рекомендуется выбирать云 MySQL, Cloud MySQL не требует от нас заботы об установке и потере данных из-за сбоя машины.Использование «из коробки» также является особенностью Baas.

Обратите внимание, что внутри выбрана сеть Default-VPC, Default-Subnet, которая должна соответствовать облачной функции, иначе облачная функция не сможет получить доступ к MySQL, как показано на рисунке:

腾讯云 MySQL 购买

После активации облачного MySQL вы можете увидеть IP-адрес и порт интрасети здесь, и облачные функции могут получить доступ к MySQL через этот IP-адрес и порт:

腾讯云 MySQL

Дизайн базы данных

Поскольку это простая система блогов, она не требует входа в систему и комментариев.На основе удовлетворения третьей парадигмы проектирования базы данных нам нужно спроектировать только одну таблицу, то есть саму таблицу блога:

имя поля Тип поля
id первичный ключ
title заглавие
content Содержание статьи
createdAt время создания
updatedAt Изменить время

Поскольку позже мы будем использовать инфраструктуру MySQL Node.js ORM Sequelize для работы с базой данных, создание таблиц базы данных выполняется автоматически, поэтому мы не будем объяснять это здесь~

Позже будет Sequelize, а также как подключиться и введение в работу с базой данных~

Пользовательское доменное имя облачной функции и сопоставление шлюза API

DNS

Как упоминалось ранее, после того, как облачная функция создала и настроила триггер API-шлюза, к нему можно получить доступ во внешней сети, но URL-адрес по умолчанию вообще нельзя запомнить, что не способствует распространению.Нам нужно собственное доменное имя. Как купить доменное имя здесь не будет раскрываться. , вы можете обратиться к этомуофициальная документацияСделайте покупку, самая дешевая всего 5 юаней в год ~

Вот введение в то, как привязать собственное доменное имя к облачной функции:

После покупки доменного имени нам необходимоСписок разрешений доменных именДобавьте разрешение доменного имени в:

添加域名解析

Как показано на рисунке ниже, добавление @ и www CNAME к нашему доменному имени облачной функции эквивалентно присвоению псевдонима доменному имени облачной функции. :

云函数解析细节

Обратите внимание, что в значении записи необходимо указать только доменное имя облачной функции, не нужно указывать путь и не нужно заполнять соглашение.

Сопоставление шлюза API

Недостаточно разрешить собственное доменное имя в доменное имя облачной функции, нам также нужно сопоставить путь, мы открываемСлужба шлюза API, щелкните имя нашей службы облачных функций, откройте имя пользовательского домена и нажмите «Создать»:

API 网关映射

После выполнения операции на скриншоте мы можем получить доступ к облачной функции во внешней сети с нашим собственным доменным именем~

Вот простой адрес блога, реализованный в этой статье:www.momentfly.com/

Проектирование маршрутизации в облачных функциях

Как мы упоминали ранее, реализованная простая система блогов имеет две страницы, и для соответствия двум страницам можно использовать две облачные функции, но эта реализация не является элегантной, поскольку код нельзя использовать повторно.Например, некоторые из страниц обработки мы написали, что Публичные методы должны быть реализованы в обеих функциях, а модули node_modules должны существовать в обеих облачных функциях, занимая место впустую.

Таким образом, мы должны организовать код двух страниц в функцию.Самое простое, что можно придумать, это написать простое суждение, если путь /, затем вернуться на страницу списка блогов, иначе, если путь /post, затем верните страницу содержимого блога. Но это все еще не элегантно. Чтобы получить путь, напишите кучу if else для маршрутизации, что не очень удобно, и если вы хотите расширить, вы должны увеличить суждение get, post и другие запросы, а также параметры на пути. Вам также придется написать функцию вручную, чтобы получить ее.

Можно ли организовать код так же просто, как в Express или koa? Ответ — да!

Если вы сравните AWS Lambda (Amazon Cloud Cloud Function), вы обнаружите, что Tencent Cloud Function и AWS Lambda имеют одинаковые параметры входа, мы можем передатьserverless-httpЭта библиотека реализует доступ к koa. Эта библиотека изначально была создана для AWS lambda, но ее можно беспрепятственно использовать в функциях Tencent Cloud.

Как упоминалось выше, код входа main_handler облачной функции выглядит следующим образом:

exports.main_handler = async (event, context, callback) => {

}

Вытягиваем код локально, устанавливаем koa, koa-router, serverless-http и организуем его следующим образом, чтобы koa можно было без проблем подключить:

const Koa = require("koa");
const serverless = require("serverless-http");
const app = new Koa();
const router = require('./router');

app
  .use(router.routes())
  .use(router.allowedMethods())

const handler = serverless(app);
exports.main_handler = async (event, context, callback) => {
  return await handler(
    { ...event, queryStringParameters: event.queryString },
    context
  );
}

И наш файл маршрутизатора — это обычный способ koa:

const Router = require('koa-router');
const { homeController } = require('../controllers/home')
const { postController } = require('../controllers/post')

const router = new Router();

router
    .get('/', homeController)
    .get('/post', postController)

module.exports = router;

Увидев это, студенты, знакомые с koa, освоили тему этой статьи и поняли, как реализовать Serverless.Но затем я полностью объясню логику, связанную с построением этой простой системы блогов.Заинтересованные студенты продолжают переходить к Давайте возьмем взгляд~

Организация кода в облачных функциях

В соответствии с организацией обычных приложений koa, чтобы прояснить обязанности, код обычно организован в маршрутизатор, контроллер, службу, модель, представление и т. д.serverless-httpПосле подключения koa наша организация облачных функций полностью соответствует традиционному приложению koa Давайте взглянем на полный каталог проекта:

/blog
├── controllers
|  ├── home
|  |  └── index.js
|  └── post
|     └── index.js
├── index.js
├── model
|  ├── db.js
|  └── index.js
├── package.json
├── router
|  └── index.js
├── services
|  ├── assets
|  |  └── index.js
|  ├── data
|  |  └── index.js
|  ├── home
|  |  └── render.js
|  ├── post
|  |  └── render.js
|  └── response
|     └── index.js
├── template.yaml
├── view
|  ├── github-markdown.css
|  ├── home
|  |  ├── home.css
|  |  └── home.html
|  └── post
|     ├── post.css
|     └── post.html
└── yarn.lock

Controller

Контроллер должен четко отражать процесс обработки запроса, а некоторые детали реализации должны быть инкапсулированы и размещены в Сервисе, что особенно важно в проектах со сложными процессами.

Контроллер для наших двух страниц очень прост:

controllers/home/index.js — страница со списком блогов

const render = require('../../services/home/render');
const { getBlogList } = require('../../services/data')
const { htmlResponse } = require('../../services/response')

exports.homeController = async (ctx) => {
    const blogList = await getBlogList() // 获取数据
    const html = render(blogList) // 数据 + 模板生成 html
    htmlResponse(ctx, html) // 返回 html 的流程
}

controllers/post/index.js — страница контента блога

const render = require('../../services/post/render');
const { getBlogById } = require('../../services/data')
const { htmlResponse } = require('../../services/response')

exports.postController = async (ctx) => {
    const { id } = ctx.query 
    const blog = await getBlogById(id)
    const html = render(blog)
    htmlResponse(ctx, html)
}

Как видите, у нашего контроллера всего три шага, а именно

  1. получить данные
  2. данные + шаблон для генерации html
  3. вернуть html

Мы объясним конкретную реализацию этих трех шагов в следующих Услугах.

Services

В простой системе блогов, описанной в этой статье, страница списка блогов очень похожа на страницу контента, поэтому код будет таким же.Здесь мы выбираем страницу списка блогов для Services:

Контроллеры прежде всего получают данные первыми, давайте взглянем на службу данных:

/services/data/index.js

const { Blog } = require('../../model')

exports.getBlogList = async () => {
    await Blog.sync({}); // 如果表不存在, 则自动创建, sequelize 的一个特性
    return await Blog.findAll();
}

exports.getBlogById = async (blogId) => {
    await Blog.sync({});
    return await Blog.findOne({
        where: {
            id: blogId,
        }
    })
}

Через определенную Модель, то есть Блог, выполнитьawait Blog.findAll(), await Blog.findOneВы можете получить список блогов и домашнюю страницу блога.

После того, как данные будут получены, в соответствии с процессом контроллера выше, мы выполним сращивание данных и шаблона html.Посмотрим на сервис рендеринга:

services/home/render.js

const template = require('art-template');
const marked = require('marked');
const hljs = require('highlight.js');
const { markdownCss, hightlightCss, resolveAssetsFromView } = require('../assets');
const homeHtml = resolveAssetsFromView('./home/home.html');
const homeCss = resolveAssetsFromView('./home/home.css');

module.exports = (blogList) => {
    marked.setOptions({
        highlight: function (code, lang) {
            return hljs.highlight(lang, code).value;
        }
    });

    let html = template.render(homeHtml, {
        blogList: blogList.map((blog) => {
            blog.content = marked(blog.content);
            return blog;
        }),
        markdownCss,
        hightlightCss,
        homeCss,
    })

    return html
}

используется здесьart-template, представляет собой высокопроизводительный механизм шаблонов.

Использование механизма шаблонов для обработки HTML-шаблонов и данных без реакции vue связано с тем, что простая система блогов слишком проста, нет необходимости использовать фреймворк.Более того, первоначальное намерение этой простой системы блогов сосредоточено на бессерверной практике с использованием react, vue или простые шаблоны Движок никак не влияет на бессерверную практику, если его заменить на react и в качестве ssr использовать vue, нужно открывать другую тему.

  • markedэто библиотека для преобразования строки уценки в строку html, например# helloПревратиться в<h1>hello</h1>

  • highlight.jsИспользуется для выделения кода в уценке

  • markdownCss, hightlightCss, homeCss,Это написанный файл css, строка содержимого файла читается fs

Ключевым предложением является рендеринг html-шаблона, данных (blogList, css) в html через арт-шаблон.

let html = template.render(homeHtml /* 模板 */, { /* 模板变量 */
    // 数据
    blogList: blogList.map((blog) => {
        blog.content = marked(blog.content); // markdown 的处理
        return blog;
    }),
    // 对模板来说, 以下这些也是数据, 只不过数据内容是 css 字符串罢了
    markdownCss,
    hightlightCss,
    homeCss,
});

Вышеупомянутые markdownCss, hightlightCss и homeCss обрабатываются через ассеты Давайте посмотрим на обработку ассетов:

/services/assets/index.js

const fs = require('fs');
const path = require('path');

const hightlightCss = fs.readFileSync(path.resolve(__dirname, '../../node_modules/highlight.js/styles/atom-one-light.css'), {
    encoding: 'utf-8',
})
const markdownCss = fs.readFileSync(path.resolve(__dirname, '../../view/github-markdown.css'), {
    encoding: 'utf-8',
})

const resolveAssetsFromView = (relativePath) => {
    // 辅助函数, 方便从 view 将文件读取为字符串
    const filePath = path.resolve(__dirname, '../../view', relativePath);
    console.log(`filePath: ${filePath}`);
    return fs.readFileSync(filePath, {
        encoding: 'utf-8',
    })
}

module.exports = {
    hightlightCss,
    markdownCss,
    resolveAssetsFromView
}

Через fs.readFileSync() файл читается в режиме utf-8 и выставляется вместе со вспомогательными функциями после чтения.

На последнем шаге контроллера, который заключается в возврате html, мы реализуем его через службу ответа:

/services/response/index.js

exports.htmlResponse = (ctx, html) => {
    ctx.set('Content-Type', 'text/html');
    ctx.body = html
    ctx.status = 200
}

Model

Служба данных выше может легко получать данные с помощью модели блога. Какова реализация модели блога? Давайте посмотрим:

/model/index.js

const { Sequelize, sequelize, Model } = require('./db');

class Blog extends Model { }

Blog.init({
    title: { // 定义 title 字段
        type: Sequelize.STRING, // 字符串类型
        allowNull: false // 不允许为空
    },
    content: {
        type: Sequelize.TEXT('medium'), // mysql 的 MEDIUMTEXT
        allowNull: false // 不允许为空
    }
}, {
    sequelize,
    modelName: 'blog'
});

module.exports = {
    Blog,
} 

Мы используем sequenceize, библиотеку ORM, чтобы упростить работу с MySQL, не требуя от нас написания операторов SQL вручную, а сама библиотека также помогает нам защититься от SQL-инъекций.

Blog.init инициализирует модель блога.Три поля id, createdAt и updatedAt не нужно объявлять, и sequenceize автоматически создаст их для нас.

Давайте посмотрим на реализацию db

/model/db.js

const Sequelize = require('sequelize');

const sequelize = new Sequelize('blog', 'root', process.env.password, {
    host: '172.16.0.15',
    dialect: 'mysql'
});

const Model = Sequelize.Model;

module.exports = {
    Sequelize,
    sequelize,
    Model,
}

blog — это имя базы данных, root — это учетная запись для входа, а пароль хранится в переменной среды.process.env.passwordПолучите, то есть переменные окружения, которые мы заполнили при создании облачной функции ранее.

View

Слой просмотра здесь просто шаблоны css и html, css обсуждать не будем, вот посмотрите на шаблон арт-шаблона:

/view/home/home.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>serverless blog demo</title>
    <style>
        {{markdownCss}}
        {{hightlightCss}}
        {{homeCss}}
    </style>
</head>
<body>
    <div class="blog-home">
        {{each blogList}}
        <div class="post" onclick="location.href='./post?id={{$value.id}}'">
            <h1>{{$value.title}}</h2>
            <div class="markdown-body">{{@ $value.content}}</div>
        </div>
        {{/each}}
    </div>
</body>
</html>

{{}}Существуют переменные шаблона, а к полям во втором параметре метода рендеринга выше можно получить доступ из{{}}взято из.

Выше приведена логика кода нашей простой системы блогов. В настоящее время есть только две страницы кода. Если вы хотите добавить страницу создания блога, процесс такой же, и вы можете добавить соответствующий маршрутизатор, контроллер и Сервис.В настоящее время автор работает через базу данных Tencent Cloud.Данные записываются непосредственно через интерфейс~.

Если мы хотим добавить функцию комментариев, нам нужно добавить новую таблицу для ее хранения.Конечно, вы можете расширить ее по своему желанию позже~

добиться эффекта

www.momentfly.com/

博客列表页

резюме

Создав простую систему блогов, мы узнали о практике бессерверных вычислений. За этот период мы рассмотрели, как создавать облачные функции, представили локальный подключаемый модуль облачных функций VSCode, собственное доменное имя облачной функции и сопоставление шлюза API, создание облачной базы данных. и подключение, облачная функция. Весь процесс очень легкий, и для работы и обслуживания на стороне сервера требуется не так много контента. Рост бессерверных технологий принесет большое удобство в нашу разработку. Крупные поставщики облачных услуг также улучшатся в более позднем Бессерверные сервисы для лучшего опыта DevOps.

Наконец, давайте вместе примем Serverless и будем бороться~

Возможные ямы

Некоторым друзьям не терпелось увидеть это, и они могут столкнуться с небольшой проблемой в процессе практического применения, вот унифицированное утверждение:

локальная отладка

Мы можем смоделировать API-шлюз локально, нам нужно настроить метод, путь и параметры запроса, как показано на рисунке ниже, мы можем нажать «Добавить тестовый шаблон», чтобы настроить

本地调试

Кроме того, для локального запуска простой системы блогов необходимо подключиться к локальной базе данных MySQL.Вы можете запросить локальную базу данных MySQL, изменив тестовый шаблон смоделированного запроса и передав определенные параметры для маркировки среды.

Кроме того, некоторые мелкие партнеры напрямую загружают код в официальной учетной записи в свои собственные облачные функции и обнаруживают, что они не могут работать.Здесь будьте осторожны, чтобы не заменить template.yaml своих собственных функций.Потому что template.yaml каждого облачная функция уникальна. Указывает на некоторые базовые конфигурации облачных функций, такие как ограничения памяти, переменные среды, конфигурации триггеров и т. д.

Маршрутизация для непользовательских доменных имен

У некоторых небольших партнеров еще нет собственного доменного имени, и к ним также можно получить доступ через URL-адрес шлюза API по умолчанию облачной функции, но мы должны обратить внимание на маршрутизацию:

service-20 в 5 заблокирует этот-1253736472.work.api на me.tencent.com/release/has…

URL-адрес выше, соответствующий маршрут

router
  .get("/yourFunctionName", homeController)

Получить полную демоверсию

Ответьте на serverless или code или demo на официальном аккаунте, вы можете получить полный демо-код~

наконец

  • Добро пожаловать, чтобы добавить меня в WeChat (winty230), привлечь вас в техническую группу, долгосрочный обмен и обучение...
  • Добро пожаловать, чтобы обратить внимание на «Front-end Q», серьезно изучить интерфейс и быть профессиональным техническим специалистом...

GitHub