One place for hosting & domains

      запросов

      Обработка данных входящих запросов в Flask


      Введение

      Веб-приложениям часто требуется обрабатывать данные входящих запросов пользователей. Эта полезная нагрузка может иметь форму строк запросов, данных форм и объектов JSON. Flask, как и любая другая веб-инфраструктура, предоставляет доступ к данным запросов.

      В этом учебном модуле мы создадим приложение Flask с тремя маршрутами, которое будет принимать строки запросов, данные форм и объекты JSON.

      Предварительные требования

      Для данного обучающего руководства вам потребуется следующее:

      • Для данного проекта потребуется установить Python в локальной среде.
      • В этом проекте мы будем использовать инструмент Pipenv, предоставляющий отличные возможности упаковки для программирования на Python. Он предоставляет возможности Pipfile, pip и virtualenv в одной команде.
      • Для тестирования конечных точек API потребуется установить Postman или другой подобный инструмент.

      Для этого учебного модуля мы использовали версии Pipenv v2020.11.15, Python v3.9.0 и Flask v1.1.2.

      Настройка проекта

      Чтобы продемонстрировать разные способы использования запросов, мы создадим приложение Flask. Хотя в примере используется упрощенная структура отображения функций и маршрутов, уроки этого учебного модуля можно применить к любым методам организации представлений, включая представления на базе классов, эскизов или расширений, таких как Flask-Via.

      Прежде всего, вам нужно будет создать каталог для проекта. Откройте терминал и запустите следующую команду:

      • mkdir flask_request_example

      Затем перейдите в новый каталог:

      Затем установите Flask. Откройте терминал и запустите следующую команду:

      Команда pipenv создаст среду virtualenv для этого проекта, Pipfile, install flask и Pipfile.lock.

      Для активации virtualenv этого проекта запустите следующую команду:

      Чтобы получить доступ к входящим данным в Flask, вам нужно будет использовать объект request. В объекте request хранятся все входящие данные запроса, включая тип MIME, источник, IP-адрес, необработанные данные, метод HTTP, заголовки и т. д.

      Хотя вся информация в объекте request может быть полезной для наших целей, в этом учебном модуле мы уделим основное внимание данным, которые обычно предоставляются вызывающей стороной напрямую.

      Чтобы получить доступ к запрашиваемому объекту в Flask, вам потребуется импортировать его из библиотеки Flask:

      from flask import request
      

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

      Используйте редактор кода для создания файла app.py. Импортируйте Flask и объект request. Также установите маршруты для query-example, form-example и json-example:

      app.py

      # import main Flask class and request object
      from flask import Flask, request
      
      # create the Flask app
      app = Flask(__name__)
      
      @app.route('/query-example')
      def query_example():
          return 'Query String Example'
      
      @app.route('/form-example')
      def form_example():
          return 'Form Data Example'
      
      @app.route('/json-example')
      def json_example():
          return 'JSON Object Example'
      
      if __name__ == '__main__':
          # run app in debug mode on port 5000
          app.run(debug=True, port=5000)
      

      Затем откройте терминал и запустите приложение с помощью следующей команды:

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

      http://127.0.0.1:5000/query-example (or localhost:5000/query-example)
      http://127.0.0.1:5000/form-example (or localhost:5000/form-example)
      http://127.0.0.1:5000/json-example (or localhost:5000/json-example)
      

      Код устанавливает три маршрута, и при открытии каждого маршрута вы увидите сообщения "Query String Example", "Form Data Example" и "JSON Object Example".

      Использование аргументов запроса

      Аргументы URL, добавляемые в строку запроса, часто используются для передачи данных в веб-приложение. Возможно, вам уже приходилось видеть строку запроса на веб-страницах.

      Строка запроса выглядит следующим образом:

      example.com?arg1=value1&arg2=value2
      

      Строка запроса начинается после знака (?) вопроса:

      example.com?arg1=value1&arg2=value2
      

      В ней содержатся пары ключ-значение, разделенные символом амперсанда (&):

      example.com?arg1=value1&arg2=value2
      

      В каждой паре после ключа идет знак равенства (=), а затем идет значение.

      arg1 : value1
      arg2 : value2
      

      Строки запросов полезны для передачи данных, которые не требуют действий со стороны пользователя. Вы можете сгенерировать строку запроса в своем приложении и добавить ее к URL так, чтобы при запросе пользователя данные передавались автоматически. Строка запроса также может быть сгенерирована формами, использующими метод GET.

      Давайте добавим строку запроса в маршрут query-example. В этом гипотетическом примере, мы укажем имя языка программирования, которое будет отображаться на экране. Создайте ключ "language" и значение "Python":

      http://127.0.0.1:5000/query-example?language=Python
      

      Если вы запустите приложение и перейдете к этому URL, вы увидите сообщение "Query String Example".

      Вам нужно будет программировать часть, обрабатывающую аргументы запроса. Этот код считает ключ language, используя request.args.get('language') или request.args['language'].

      При вызове request.args.get('language') приложение продолжит работу, если ключ language отсутствует по указанному URL. В этом случае данный метод будет иметь результат None.

      При вызове request.args['language'] приложение возвращает ошибку 400, если ключ language отсутствует по указанному URL.

      При работе со строками запросов, рекомендуется использовать request.args.get(), чтобы предотвратить возможные сбои в работе приложения.

      Давайте прочитаем ключ language и выведем его.

      Измените маршрут query-example в app.py с помощью следующего кода:

      app.py

      @app.route('/query-example')
      def query_example():
          # if key doesn't exist, returns None
          language = request.args.get('language')
      
          return '''<h1>The language value is: {}</h1>'''.format(language)
      

      Затем запустите приложение и перейдите к URL:

      http://127.0.0.1:5000/query-example?language=Python
      

      Браузер должен вывести следующее сообщение:

      Output

      The language value is: Python

      Аргумент из URL привязывается к переменной language, а затем возвращается через браузер.

      Чтобы добавить дополнительные параметры запроса, вы можете добавить амперсанды и новые пары ключ-значение в конце URL. Создайте ключ "framework" и значение "Flask":

      http://127.0.0.1:5000/query-example?language=Python&framework=Flask
      

      Если вам нужно больше, продолжайте добавлять амперсанды и пары ключ-значение. Создайте ключ "website" и значение "DigitalOcean":

      http://127.0.0.1:5000/query-example?language=Python&framework=Flask&website=DigitalOcean
      

      Чтобы получить доступ к этим значениям, мы все равно используем request.args.get() или request.args[]. Давайте используем оба варианта, чтобы продемонстрировать, что произойдет при отсутствии ключа. Измените маршрут query_example, чтобы назначить значение результатов переменным и вывести их:

      @app.route('/query-example')
      def query_example():
          # if key doesn't exist, returns None
          language = request.args.get('language')
      
          # if key doesn't exist, returns a 400, bad request error
          framework = request.args['framework']
      
          # if key doesn't exist, returns None
          website = request.args.get('website')
      
          return '''
                    <h1>The language value is: {}</h1>
                    <h1>The framework value is: {}</h1>
                    <h1>The website value is: {}'''.format(language, framework, website)
      

      Затем запустите приложение и перейдите к URL:

      http://127.0.0.1:5000/query-example?language=Python&framework=Flask&website=DigitalOcean
      

      Браузер должен вывести следующее сообщение:

      Output

      The language value is: Python The framework value is: Flask The website value is: DigitalOcean

      Удалите ключ language из URL:

      http://127.0.0.1:5000/query-example?framework=Flask&website=DigitalOcean
      

      Браузер должен вывести следующее сообщение со словом None, если для language будет отсутствовать значение:

      Output

      The language value is: None The framework value is: Flask The website value is: DigitalOcean

      Удалите ключ framework из URL:

      http://127.0.0.1:5000/query-example?language=Python&website=DigitalOcean
      

      Браузер должен вывести сообщение об ошибке, потому что он ожидает получить значение framework:

      Output

      werkzeug.exceptions.BadRequestKeyError werkzeug.exceptions.BadRequestKeyError: 400 Bad Request: The browser (or proxy) sent a request that this server could not understand. KeyError: 'framework'

      Теперь вы должны понимать, как следует обрабатывать строки запросов. Перейдем к следующему типу входящих данных.

      Использование данных форм

      Данные форм поступают из форм, отправленных на маршрут в виде запроса POST. Вместо отображения данных в URL (кроме случаев отправки форм в виде запроса GET) данные форм передаются приложению незаметно. Хотя вы не видите передаваемые данные форм, ваше приложение может их считывать.

      Чтобы продемонстрировать это, давайте изменим маршрут form-example в app.py так, чтобы принимать запросы GET и POST и возвращать форму:

      app.py

      # allow both GET and POST requests
      @app.route('/form-example', methods=['GET', 'POST'])
      def form_example():
          return '''
                    <form method="POST">
                        <div><label>Language: <input type="text" name="language"></label></div>
                        <div><label>Framework: <input type="text" name="framework"></label></div>
                        <input type="submit" value="Submit">
                    </form>'''
      

      Затем запустите приложение и перейдите к URL:

      http://127.0.0.1:5000/form-example
      

      Браузер должен отображать форму с двумя полями ввода: одно language и одно для framework, а также кнопку отправки.

      Важнее всего знать об этой форме то, что она выполняет запрос POST к тому же маршруту, который сгенерировал форму. Все ключи, которые считываются в приложении, поступают от атрибутов name в полях ввода формы. В этом случае language и framework являются именами полей ввода, и поэтому у вас будет доступ к ним в приложении.

      Внутри функции просмотра вам нужно будет проверить метод запроса: GET или POST. Если это запрос GET, вы можете вывести форму. В противном случае это запрос POST, и вам нужно обработать входящие данные.

      Измените маршрут form-example в app.py, добавив следующий код:

      app.py

      # allow both GET and POST requests
      @app.route('/form-example', methods=['GET', 'POST'])
      def form_example():
          # handle the POST request
          if request.method == 'POST':
              language = request.form.get('language')
              framework = request.form.get('framework')
              return '''
                        <h1>The language value is: {}</h1>
                        <h1>The framework value is: {}</h1>'''.format(language, framework)
      
          # otherwise handle the GET request
          return '''
                 <form method="POST">
                     <div><label>Language: <input type="text" name="language"></label></div>
                     <div><label>Framework: <input type="text" name="framework"></label></div>
                     <input type="submit" value="Submit">
                 </form>'''
      

      Затем запустите приложение и перейдите к URL:

      http://127.0.0.1:5000/form-example
      

      Введите в поле language значение Python, а в поле framework — значение Flask. Затем нажмите кнопку Submit.

      Браузер должен вывести следующее сообщение:

      Output

      The language value is: Python The framework value is: Flask

      Теперь вы понимаете, как обрабатывать данные формы. Перейдем к следующему типу входящих данных.

      Использование данных JSON

      Данные JSON обычно создаются процессом, который вызывает маршрут.

      Пример объекта JSON:

      {
        "language": "Python",
        "framework": "Flask",
        "website": "Scotch",
        "version_info": {
          "python": "3.9.0",
          "flask": "1.1.2"
        },
        "examples": ["query", "form", "json"],
        "boolean_test": true
      }
      

      Такая структура позволяет передавать более сложные данные, чем строки запросов и данные форм. В этом примере вы видите вложенные объекты JSON и массив элементов. Этот формат данных может обрабатываться Flask.

      Измените маршрут form-example в app.py, чтобы принимать запросы POST и игнорировать другие запросы, в частности GET:

      app.py

      @app.route('/json-example', methods=['POST'])
      def json_example():
          return 'JSON Object Example'
      

      Для строк запросов и данных форм в этом учебном модуле мы использовали браузер, но для отправки объекта JSON мы используем Postman, чтобы отправлять персонализированные запросы в URL.

      Примечание. Если вам нужна помощь в навигации по интерфейсу Postman для отправки запросов, воспользуйтесь официальной документацией.

      Добавьте URL в Postman и измените тип на POST. На вкладке body переключитесь на raw и выберите JSON из раскрывающегося списка.

      Эти настройки необходимы, чтобы Postman мог правильно отправлять данные JSON и чтобы ваше приложение Flask понимало, что получает данные JSON:

      POST http://127.0.0.1:5000/json-example
      Body
      raw JSON
      

      Затем скопируйте в поле ввода текста предыдущий пример JSON.

      Отправьте запрос. Вы должны получить ответ "JSON Object Example". Это не так интересно, но это ожидаемо, потому что код для обработки ответа данных JSON еще нужно написать.

      Чтобы читать данные, вам нужно понимать, как Flask преобразует данные JSON в структуры данных Python:

      • Все объекты конвертируются в словари Python. {"key" : "value"} в JSON соответствуют somedict['key'], который возвращает значение в Python.
      • Массив в JSON конвертируется в список в Python. Поскольку синтаксис одинаковый, приведем список примеров: [1,2,3,4,5]
      • Значения в кавычках объекта JSON станут строками в Python.
      • Логические операторы true и false становятся True и False в Python.
      • Числа без кавычек становятся числами в Python.

      Теперь давайте поработаем с кодом, чтобы считывать входящие данные JSON.

      Вначале добавим все содержимое объекта JSON в переменную, используя request.get_json().

      request.get_json() конвертирует объект JSON в данные Python. Давайте назначим данные входящего запроса в переменные и выведем их, внеся следующие изменения в маршрут json-example:

      app.py

      # GET requests will be blocked
      @app.route('/json-example', methods=['POST'])
      def json_example():
          request_data = request.get_json()
      
          language = request_data['language']
          framework = request_data['framework']
      
          # two keys are needed because of the nested object
          python_version = request_data['version_info']['python']
      
          # an index is needed because of the array
          example = request_data['examples'][0]
      
          boolean_test = request_data['boolean_test']
      
          return '''
                 The language value is: {}
                 The framework value is: {}
                 The Python version is: {}
                 The item at index 0 in the example list is: {}
                 The boolean value is: {}'''.format(language, framework, python_version, example, boolean_test)
      

      Обратите внимание на процедуру доступа к элементам, находящимся не на верхнем уровне. Поскольку мы вводим вложенный объект, используется ['version']['python']. А ['examples'][0] используется для доступа к индексу 0 в массиве example.

      Если объект JSON, отправленный с запросом, не имеет ключа, доступ к которому осуществляется через функцию view, запрос не будет выполняться. Если вы не хотите, чтобы запрос выдавал сбой при отсутствии ключа, вам нужно будет проверить наличие ключа, прежде чем пытаться получить к нему доступ.

      app.py

      # GET requests will be blocked
      @app.route('/json-example', methods=['POST'])
      def json_example():
          request_data = request.get_json()
      
          language = None
          framework = None
          python_version = None
          example = None
          boolean_test = None
      
          if request_data:
              if 'language' in request_data:
                  language = request_data['language']
      
              if 'framework' in request_data:
                  framework = request_data['framework']
      
              if 'version_info' in request_data:
                  if 'python' in request_data['version_info']:
                      python_version = request_data['version_info']['python']
      
              if 'examples' in request_data:
                  if (type(request_data['examples']) == list) and (len(request_data['examples']) > 0):
                      example = request_data['examples'][0]
      
              if 'boolean_test' in request_data:
                  boolean_test = request_data['boolean_test']
      
          return '''
                 The language value is: {}
                 The framework value is: {}
                 The Python version is: {}
                 The item at index 0 in the example list is: {}
                 The boolean value is: {}'''.format(language, framework, python_version, example, boolean_test)
      

      Запустите приложение и отправьте пример запроса JSON с помощью Postman. В ответе вы увидите следующее:

      Output

      The language value is: Python The framework value is: Flask The Python version is: 3.9 The item at index 0 in the example list is: query The boolean value is: false

      Теперь вы должны понимать принципы обработки объектов JSON.

      Заключение

      В этом учебном модуле мы создали приложение Flask с тремя маршрутами, которое будет принимать строки запросов, данные форм и объекты JSON.

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

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

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



      Source link

      Использование параметров запросов в Angular


      Введение

      Параметры запросов в Angular позволяют передавать опциональные параметры по любым маршрутам в приложении. Параметры запросов отличаются от обычных параметров маршрутов, которые доступны только на одном маршруте и не являются опциональными (например, /product/:id).

      В этой статье мы рассмотрим пример приложения, которое отображает список продуктов. Мы зададим опциональные значения order и price-range, которые принимающий компонент сможет считывать, и на основе которых он сможет действовать. Заданные значения повлияют на порядок и фильтрацию списка продуктов.

      Использование параметров запросов с помощью Router.navigate

      Когда вы предписываете приложению перейти на маршрут с помощью Router.navigate, вы передаете параметры запроса с помощью queryParams.

      В нашем примере, если мы хотим направить посетителей к списку продуктов, отсортированному по популярности, это будет выглядеть так:

      goProducts() {
        this.router.navigate(["https://www.digitalocean.com/products"], { queryParams: { order: 'popular' } });
      }
      

      В результате мы получим следующий URL:

      http://localhost:4200/products?order=popular
      

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

      goProducts() {
        this.router.navigate(["https://www.digitalocean.com/products"], { queryParams: { order: 'popular', 'price-range': 'not-cheap' } });
      }
      

      В результате мы получим следующий URL:

      http://localhost:4200/products?order=popular&price-range=not-cheap
      

      Теперь вы понимаете, как использовать queryParams, чтобы задавать параметры запросов.

      Сохранение или объединение параметров запросов с помощью queryParamsHandling

      По умолчанию параметры запросов теряются при любых последующих действиях по навигации. Чтобы предотвратить это, вы можете задать для queryParamsHandling значение 'preserve' или 'merge'.

      В нашем примере, если мы хотим перенаправлять посетителей со страницы с параметром запроса { order: 'popular' } на страницу /users с сохранением параметров запроса, мы будем использовать 'preserve':

      goUsers() {
        this.router.navigate(['/users'], { queryParamsHandling: 'preserve' });
      }
      

      В результате мы получим следующий URL:

      http://localhost:4200/users?order=popular
      

      В нашем примере, если мы хотим перенаправлять посетителей со страницы с параметром запроса { order: 'popular' } на страницу /users с передачей параметра запроса { filter: 'new' }, мы будем использовать 'merge':

      goUsers() {
        this.router.navigate(['/users'], { queryParams: { filter: 'new' }, queryParamsHandling: 'merge' });
      }
      

      В результате мы получим следующий URL:

      http://localhost:4200/users?order=popular&filter=new
      

      Примечание. Ранее для сохранения параметров запроса нужно было задать для свойства preserveQueryParams значение true, но в Angular 4+ эта возможность заменена на queryParamsHandling.

      Теперь вы понимаете, как можно использовать queryParamsHandling для сохранения и объединения параметров запросов.

      В нашем примере, если мы используем директиву RouterLink для навигации по маршрут, мы используем queryParams следующим образом:

      <a [routerLink]="["https://www.digitalocean.com/products"]" [queryParams]="{ order: 'popular'}">
        Products
      </a>
      

      В нашем примере, если мы хотим использовать 'preserve' или 'merge' для сохранения или объединения параметров запроса, при последующей навигации queryParamsHandling используется следующим образом:

      <a [routerLink]="['/users']"
         [queryParams]="{ filter: 'new' }"
         queryParamsHandling="merge">
        Users
      </a>
      

      Теперь вы понимаете, как использовать queryParams и queryParamsHandling с RouterLink.

      Доступ к значениям параметров запроса

      Теперь мы знаем, как передавать опциональные параметры запроса в маршрут. Давайте посмотри, как получить доступ к этим значениям на полученных маршрутах. Класс ActivatedRoute имеет свойство queryParams, которое возвращает наблюдаемые параметры запроса, доступные на текущем URL.

      Возьмем следующий URL маршрута:

      http://localhost:4200/products?order=popular
      

      Мы можем получить доступ к параметру запроса order :следующим образом:

      // ...
      import { ActivatedRoute } from '@angular/router';
      import 'rxjs/add/operator/filter';
      
      @Component({ ... })
      export class ProductComponent implements OnInit {
        order: string;
        constructor(private route: ActivatedRoute) { }
      
        ngOnInit() {
          this.route.queryParams
            .filter(params => params.order)
            .subscribe(params => {
              console.log(params); // { order: "popular" }
      
              this.order = params.order;
              console.log(this.order); // popular
            }
          );
        }
      }
      

      В журнале консоли мы увидим объект params:

      Output

      { order: "popular" }

      И значение params.order:

      Output

      popular

      Также у нас имеется queryParamMap, возвращающая наблюдаемый объект paramMap.

      Возьмем следующий URL маршрута:

      http://localhost:4200/products?order=popular&filter=new
      

      Мы можем получить доступ к параметрам запроса следующим образом:

      this.route.queryParamMap
        .subscribe((params) => {
          this.orderObj = { ...params.keys, ...params };
        }
      );
      

      Здесь мы использовали оператор object spread, и вот так выглядит получившаяся форма данных в orderObj:

      {
        "0": "order",
        "1": "filter",
        "params": {
          "order": "popular",
          "filter": "new"
        }
      }
      

      Теперь вы понимаете, как можно использовать queryParams и queryParamMap для доступа к значениям на полученных в результате маршрутах.

      Заключение

      В этой статье мы использовали различные примеры для настройки и получения параметров запросов в Angular. Вы познакомились с опциями queryParams и queryParamsHandling при использовании Router.navigate и RouterLink. Также вы познакомились с опциями queryParams и queryParamMap при использовании ActivatedRoute.

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



      Source link

      Оптимизация запросов MySQL с помощью кеширования ProxySQL в Ubuntu 16.04


      Автор выбрал фонд Free Software Foundation для получения пожертвования в рамках программы Write for DOnations.

      Введение

      ProxySQL — это прокси-сервер SQL, который можно располагать между вашим приложением и базой данных. Он имеет множество функций, в том числе распределение нагрузки между несколькими серверами MySQL, и может выступать в качестве слоя кеширования для запросов. В этом обучающем руководстве основное внимание будет уделено функции кеширования ProxySQL и тому, как с ее помощью вы можете оптимизировать запросы для вашей базы данных MySQL.

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

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

      В этом обучающем руководстве мы будем использовать ProxySQL для настройки прозрачного кеширования для сервера MySQL в Ubuntu 16.04. Затем вы протестируете его производительность с помощью mysqlslap с кешированием и без него, чтобы продемонстрировать эффект кеширования и то, сколько времени с его помощью можно будет сэкономить при выполнении множества аналогичных запросов.

      Предварительные требования

      Для прохождения этого обучающего руководства вам потребуется следующее:

      Шаг 1 — Установка и настройка сервера MySQL

      Сначала мы установим сервер MySQL и настроим его для использования с ProxySQL в качестве сервера бэкэнда для обслуживания запросов клиентов.

      В Ubuntu 16.04 mysql-server можно установить с помощью этой команды:

      • sudo apt-get install mysql-server

      Нажмите Y для подтверждения установки.

      Затем вам будет предложено ввести пароль root пользователя MySQL. Введите надежный пароль и сохраните его для последующего использования.

      Теперь, когда у вас есть готовый сервер MySQL, необходимо настроить его для корректной работы с ProxySQL. Вам нужно добавить пользователя monitor для ProxySQL для мониторинга сервера MySQL, поскольку ProxySQL прослушивает сервер бэкэнда с помощью протокола SQL, не используя соединение TCP или запросы HTTP GET, чтобы убедиться, что сервер работает. monitor будет использовать пустое соединение SQL для определения того, запущен сервер или нет.

      Выполните вход в командную строку MySQL:

      -uroot позволяет выполнить вход, используя root пользователя MySQL, а -p запрашивает пароль пользователя root. Этот пользователь root отличается от пользователя root сервера, а пароль — это пароль, который вы вводили при установке пакета mysql-server.

      Введите пароль root и нажмите ENTER.

      Теперь мы создадим двух пользователей, первого с именем monitor для ProxySQL, а второго для использования при выполнении клиентских запросов и предоставления им нужных привилегий. В этом обучающем руководстве мы будем использовать пользователя с именем sammy.

      Создайте пользователя monitor:

      • CREATE USER 'monitor'@'%' IDENTIFIED BY 'monitor_password';

      Запрос CREATE USER используется для создания нового пользователя, который может подключаться с конкретных IP-адресов. Использование % означает, что пользователь может подключаться с любого IP-адреса. IDENTIFIED BY устанавливает пароль для нового пользователя, введите любой пароль, но обязательно запомните его для последующего использования.

      После создания пользователя monitor создайте пользователя sammy:

      • CREATE USER 'sammy'@'%' IDENTIFIED BY 'sammy_password';

      Затем предоставьте привилегии вашим новым пользователям. Запустите следующую команду для настройки monitor:

      • GRANT SELECT ON sys.* TO 'monitor'@'%';

      Запрос GRANT используется для предоставления привилегий пользователям. Здесь мы предоставили только SELECT для всех таблиц в базе данных sys пользователю monitor, ему нужна только эта привилегия для прослушивания сервера бэкэнда.

      Теперь мы предоставим все права доступа для всех баз данных пользователю sammy:

      • GRANT ALL PRIVILEGES on *.* TO 'sammy'@'%';

      Это позволяет sammy выполнять необходимые запросы для теста вашей базы данных позже.

      Примените изменения привилегий, выполнив следующую команду:

      После этого выйдите из командной строки mysql:

      Вы установили mysql-server и создали пользователя для ProxySQL для мониторинга сервера MySQL и еще одного пользователя для выполнения клиентских запросов. Далее мы установим и настроим ProxySQL.

      Шаг 2 — Установка и настройка сервера ProxySQL

      Теперь мы можем установить сервер ProxySQL, который будет использоваться в качестве слоя кеширования для ваших запросов. Слой кеширования представляет собой точку остановки между серверами вашего приложения и серверами бэкэнда базы данных; он используется для подключения к базе данных и сохранения результатов некоторых запросов в памяти для быстрого доступа.

      На странице релизов ProxySQL на GitHub вы найдете файлы установки для стандартных дистрибутивов Linux. Для этого обучающего руководства мы будем использовать wget для загрузки файла установки ProxySQL версии 2.0.4 Debian:

      • wget https://github.com/sysown/proxysql/releases/download/v2.0.4/proxysql_2.0.4-ubuntu16_amd64.deb

      Затем установите пакет с помощью dpkg:

      • sudo dpkg -i proxysql_2.0.4-ubuntu16_amd64.deb

      После установки запустите ProxySQL с помощью этой команды:

      • sudo systemctl start proxysql

      Вы можете проверить, выполнен ли запуск ProxySQL корректно, с помощью этой команды:

      • sudo systemctl status proxysql

      Результат должен выглядеть примерно так:

      Output

      root@ubuntu-s-1vcpu-2gb-sgp1-01:~# systemctl status proxysql ● proxysql.service - LSB: High Performance Advanced Proxy for MySQL Loaded: loaded (/etc/init.d/proxysql; bad; vendor preset: enabled) Active: active (exited) since Wed 2019-06-12 21:32:50 UTC; 6 months 7 days ago Docs: man:systemd-sysv-generator(8) Tasks: 0 Memory: 0B CPU: 0

      Теперь пришло время подключить ваш сервер ProxySQL к серверу MySQL. Для этой цели воспользуйтесь интерфейсом ProxySQL для администратора SQL, который по умолчанию слушает порт 6032 на localhost и использует admin в качестве имени пользователя и пароля.

      Установите подключение к интерфейсу с помощью следующей команды:

      • mysql -uadmin -p -h 127.0.0.1 -P6032

      Введите admin при запросе пароля.

      -uadmin задает значение admin для имени пользователя, а флаг -h указывает в качестве хоста localhost. Используется порт 6032, заданный с помощью флага -P.

      Здесь вам нужно явно задать хост и порт, поскольку по умолчанию клиент MySQL подключается с помощью файла локальных сокетов и порта 3306.

      Теперь, когда вы выполнили вход в командную строку mysql как admin, настройте пользователя monitor, чтобы ProxySQL мог его использовать. Для начала применим стандартные запросы SQL для установки значений двух глобальных переменных:

      • UPDATE global_variables SET variable_value='monitor' WHERE variable_name='mysql-monitor_username';
      • UPDATE global_variables SET variable_value='monitor_password' WHERE variable_name='mysql-monitor_password';

      Переменная mysql-monitor_username указывает имя пользователя MySQL, который будет использоваться для проверки того, запущен ли сервер бэкэнда. Переменная mysql-monitor_password указывает на пароль, который будет использоваться при подключении к серверу бэкэнда. Используйте пароль, созданный для пользователя monitor.

      Каждый раз, когда вы вносите изменение в интерфейсе администратора ProxySQL, вам нужно использовать команду LOAD для применения изменений для запущенного экземпляра ProxySQL. Вы изменили глобальные переменные MySQL, а для применения изменений нужно загрузить их в RUNTIME:

      • LOAD MYSQL VARIABLES TO RUNTIME;

      Затем с помощью SAVE сохраните изменения в базе данных на диске для сохранения изменений в случае перезапуска. ProxySQL использует собственную локальную базу данных SQLite для хранения собственных таблиц и переменных:

      • SAVE MYSQL VARIABLES TO DISK;

      Теперь мы сообщим ProxySQL о сервере бэкэнда. Таблица mysql_servers содержит информацию о каждом сервере бэкэнда, к которому ProxySQL может подключаться и выполнять запросы, поэтому добавьте новую запись с помощью стандартного SQL-оператора INSERT со следующими значениями для hostgroup_id, hostname и port:

      • INSERT INTO mysql_servers(hostgroup_id, hostname, port) VALUES (1, '127.0.0.1', 3306);

      Чтобы применить изменения, запустите LOAD и SAVE еще раз:

      • LOAD MYSQL SERVERS TO RUNTIME;
      • SAVE MYSQL SERVERS TO DISK;

      После этого мы укажем ProxySQL, какой пользователь будет подключаться к серверу бэкэнда; задайте sammy в качестве пользователя и замените sammy_password на созданный вами пароль:

      • INSERT INTO mysql_users(username, password, default_hostgroup) VALUES ('sammy', 'sammy_password', 1);

      Таблица mysql_users содержит информацию о пользователях, используемых для подключения к серверам бэкэнда; вы задали username, password и default_hostgroup.

      Воспользуйтесь командами LOAD и SAVE:

      • LOAD MYSQL USERS TO RUNTIME;
      • SAVE MYSQL USERS TO DISK;

      Затем выйдите из командной строки mysql:

      Чтобы убедиться, что вы можете подключиться к серверу бэкэнда с помощью ProxySQL, выполните следующий тестовый запрос:

      • mysql -usammy -h127.0.0.1 -p -P6033 -e "SELECT @@HOSTNAME as hostname"

      В этой команде мы используем флаг -e для выполнения запроса и закрытия подключения. Запрос выводит имя хоста сервера бэкэнда.

      Примечание. ProxySQL использует порт 6033 по умолчанию для прослушивания входящих соединений.

      Вывод будет выглядеть следующим образом, а вместо your_hostname будет использоваться ваше имя хоста:

      Output

      +----------------------------+ | hostname | +----------------------------+ | your_hostname | +----------------------------+

      Дополнительную информацию о конфигурации ProxySQL можно найти в шаге 3 руководства по использованию ProxySQL в качестве инструмента распределения нагрузки для MySQL в Ubuntu 16.04.

      Ранее мы настроили ProxySQL для использования сервера MySQL в качестве сервера бэкэнда и подключения к нему с помощью ProxySQL. Теперь мы готовы к использованию mysqlslap для оценки производительности запроса без кеширования.

      Шаг 3 — Тестирование с помощью mysqlslap без кеширования

      На этом шаге вы загрузите тестовую базу данных для выполнения запросов с помощью mysqlslap для проверки задержки без кеширования и определения скорости выполнения ваших запросов. Также вы узнаете, как ProxySQL хранит записи запросов в таблице stats_mysql_query_digest.

      mysqlslap — это клиент эмуляции нагрузки, который используется в качестве инструмента тестирования нагрузки для MySQL. Он позволяет протестировать сервер MySQL с помощью автоматически генерируемых запросов или пользовательских запросов для базы данных. Он входит в состав пакета клиента MySQL, поэтому вам не нужно устанавливать его, а для теста вам потребуется загрузить базу данных, с которой вы можете использовать mysqlslap.

      В этом обучающем руководстве мы будем использовать пример базы данных сотрудников. Вы будете использовать эту базу данных, поскольку она содержит большой набор данных, который может проиллюстрировать различия в оптимизации запросов. База данных содержит шесть таблиц, но во всех таблицах содержится более 300 000 записей о сотрудниках. Это поможет нам сымитировать большую рабочую нагрузку.

      Чтобы загрузить базу данных, выполните клонирование репозитория Github с помощью этой команды:

      • git clone https://github.com/datacharmer/test_db.git

      Затем откройте директорию test_db и загрузите базу данных на сервер MySQL с помощью этих команд:

      • cd test_db
      • mysql -uroot -p < employees.sql

      Эта команда использует перенаправление командной строки для считывания запросов SQL в файле employees.sql и выполнения их на сервере MySQL для создания структуры базы данных.

      Результат должен выглядеть следующим образом:

      Output

      INFO CREATING DATABASE STRUCTURE INFO storage engine: InnoDB INFO LOADING departments INFO LOADING employees INFO LOADING dept_emp INFO LOADING dept_manager INFO LOADING titles INFO LOADING salaries data_load_time_diff 00:00:32

      После загрузки базы данных на ваш сервер MySQL убедитесь, что mysqlslap работает, выполнив следующий запрос:

      • mysqlslap -usammy -p -P6033 -h127.0.0.1 --auto-generate-sql --verbose

      mysqlslap имеет аналогичные флаги для клиента mysql; в этой команде используются следующие флаги:

      • -u указывает пользователя, который будет подключаться к серверу.
      • -p запрашивает пароль пользователя.
      • -P выполняет подключение с помощью заданного порта.
      • -h подключается к заданному хосту.
      • --auto-generate-sql позволяет MySQL выполнять тестирование загрузки с помощью генерируемых самостоятельно запросов.
      • --verbose делает вывод более информативным.

      Результат должен выглядеть примерно следующим образом:

      Output

      Benchmark Average number of seconds to run all queries: 0.015 seconds Minimum number of seconds to run all queries: 0.015 seconds Maximum number of seconds to run all queries: 0.015 seconds Number of clients running queries: 1 Average number of queries per client: 0

      В этом выводе вы видите среднее, минимальное и максимальное количество секунд, потраченных на выполнение всех запросов. Это позволяет судить о количестве времени, необходимом для выполнения запросов согласно количеству клиентов. В этом выводе только один клиент используется для выполнения запросов.

      Затем необходимо выяснить, какие запросы mysqlslap выполнил в последней команде, изучив stats_mysql_query_digest в ProxySQL. Это позволит нам получить digest для запросов, представляющий собой нормализованную форму SQL-оператора, на которую можно будет ссылаться позднее для кеширования.

      Выполните вход в интерфейс администратора ProxySQL с помощью этой команды:

      • mysql -uadmin -p -h 127.0.0.1 -P6032

      Затем выполните этот запрос для получения информации в таблице stats_mysql_query_digest:

      • SELECT count_star,sum_time,hostgroup,digest,digest_text FROM stats_mysql_query_digest ORDER BY sum_time DESC;

      Вы увидите примерно следующий результат:

      +------------+----------+-----------+--------------------+----------------------------------+
      | count_star | sum_time | hostgroup | digest             | digest_text                      |
      +------------+----------+-----------+--------------------+----------------------------------+
      | 1          | 598      | 1         | 0xF8F780C47A8D1D82 | SELECT @@HOSTNAME as hostname    |
      | 1          | 0        | 1         | 0x226CD90D52A2BA0B | select @@version_comment limit ? |
      +------------+----------+-----------+--------------------+----------------------------------+
      2 rows in set (0.01 sec)
      

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

      • count_star: количество времени, затраченное на выполнение запроса.
      • sum_time: общее время в миллисекундах, которое требуется для выполнения этого запроса.
      • hostgroup: группа хостов, которая использовалась для выполнения запроса.
      • digest: дайджест выполненного запроса.
      • digest_text: фактический запрос. В нашем примере второй запрос параметризирован с помощью символов ?, используемых на месте переменных. select @@version_comment limit 1 и select @@version_comment limit 2, следовательно, группируются вместе как один запрос с одинаковым дайджестом.

      Теперь, когда мы знаем, как проверить данные запроса в таблице stats_mysql_query_digest, закройте командную строку mysql:

      Загружаемая база данных содержит несколько таблиц с демонстрационными данными. Теперь мы проверим запросы в таблице dept_emp, используя любые записи, для которых значение from_date больше 2000-04-20, и регистрируя среднее время исполнения.

      Используйте эту команду для запуска теста:

      • mysqlslap -usammy -P6033 -p -h127.0.0.1 --concurrency=100 --iterations=20 --create-schema=employees --query="SELECT * from dept_emp WHERE from_date>'2000-04-20'" --verbose

      Здесь мы используем следующие новые флаги:

      • --concurrency=100: задает число пользователей для симуляции, в данном случае 100.
      • --iterations=20: выполняет запуск теста 20 раз и вычисляет результаты для всех итераций.
      • --create-schema=employees: указывает в качестве базы данных employees.
      • --query="SELECT * from dept_emp WHERE from_date>'2000-04-20'": указывает запрос, выполняемый во время теста.

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

      Output

      Benchmark Average number of seconds to run all queries: 18.117 seconds Minimum number of seconds to run all queries: 8.726 seconds Maximum number of seconds to run all queries: 22.697 seconds Number of clients running queries: 100 Average number of queries per client: 1

      Полученные вами цифры могут отличаться. Сохраните эти цифры, чтобы сравнить их с результатами после активации кеширования.

      После теста ProxySQL без кеширования нужно снова запустить тот же тест, но в этот раз уже активировать кеширование.

      Шаг 4 — Тестирование с помощью mysqlslap с кешированием

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

      Чтобы активировать кеширование, вам нужно знать дайджесты запросов, которые будут кешироваться. Выполните вход в интерфейс администратора ProxySQL с помощью этой команды:

      • mysql -uadmin -p -h127.0.0.1 -P6032

      Затем выполните этот запрос снова для получения списка выполненных запросов и их дайджестов:

      • SELECT count_star,sum_time,hostgroup,digest,digest_text FROM stats_mysql_query_digest ORDER BY sum_time DESC;

      Результат должен выглядеть примерно так:

      Output

      +------------+-------------+-----------+--------------------+------------------------------------------+ | count_star | sum_time | hostgroup | digest | digest_text | +------------+-------------+-----------+--------------------+------------------------------------------+ | 2000 | 33727110501 | 1 | 0xC5DDECD7E966A6C4 | SELECT * from dept_emp WHERE from_date>? | | 1 | 601 | 1 | 0xF8F780C47A8D1D82 | SELECT @@HOSTNAME as hostname | | 1 | 0 | 1 | 0x226CD90D52A2BA0B | select @@version_comment limit ? | +------------+-------------+-----------+--------------------+------------------------------------------+ 3 rows in set (0.00 sec)

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

      Следующие несколько запросов будут добавлять новое правило запроса в ProxySQL, которое будет сопоставлять дайджест предыдущего запроса и добавлять для него значение cache_ttl. cache_ttl — это количество миллисекунд, в течение которых результат будет кешироваться в памяти:

      • INSERT INTO mysql_query_rules(active, digest, cache_ttl, apply) VALUES(1,'0xC5DDECD7E966A6C4',2000,1);

      В этой команде мы добавляем новую запись в таблицу mysql_query_rules; эта таблица хранит все правила, применяемые перед выполнением запроса. В этом примере мы добавляем значение столбца cache_ttl​​​, которое приводит к тому, что соответствующий запрос по указанному дайджесту будет кешироваться в течение определенного числа миллисекунд, указанного в этом столбце. Вы добавили 1 в столбце применения, чтобы гарантировать, что правило будет применяться к запросам.

      Воспользуйтесь командами LOAD и SAVE для этих изменений, после чего закройте командную строку mysql:

      • LOAD MYSQL QUERY RULES TO RUNTIME;
      • SAVE MYSQL QUERY RULES TO DISK;
      • exit;

      Теперь, когда кеширование активировано, перезапустите тест еще раз для проверки результата:

      • mysqlslap -usammy -P6033 -p -h127.0.0.1 --concurrency=100 --iterations=20 --create-schema=employees --query="SELECT * from dept_emp WHERE from_date>'2000-04-20'" --verbose

      Результат будет выглядеть примерно следующим образом:

      Output

      Benchmark Average number of seconds to run all queries: 7.020 seconds Minimum number of seconds to run all queries: 0.274 seconds Maximum number of seconds to run all queries: 23.014 seconds Number of clients running queries: 100 Average number of queries per client: 1

      Здесь вы можете увидеть большую разницу в среднем времени исполнения: оно падает с 18.117 секунд до 7.020.

      Заключение

      В этой статье вы задали прозрачное кеширование с помощью ProxySQL для кеширования результатов запросов к базе данных. Также вы протестировали скорость запроса без кеширования и с кешированием, чтобы увидеть разницу, которую дает использование кеша.

      В этом обучающем руководстве мы использовали один уровень кеширования. Вы также можете попробовать веб-кеширование, которое размещается перед веб-сервером и кеширует ответы для аналогичных запросов, отправляя ответ клиенту без обращения к серверам бэкэнда. Это очень похоже на кеширование с ProxySQL, но на другом уровне. Чтобы узнать больше о веб-кешировании, ознакомьтесь со статьей Основы веб-кеширования: терминология, HTTP-заголовки и стратегии кеширования.

      Сервер MySQL также имеет собственный кеш запросов; подробнее о нем вы можете узнать в нашем руководстве по оптимизации MySQL с помощью кеширования запросов в Ubuntu 18.04.



      Source link