Хабрахабр

Мозг + VPS за 30 рублей =?

Как приятно, когда все необходимые мелочи под рукой: хорошо пишущая ручка и блокнот, заточенный карандаш, удобная мышка, пара лишних проводов и т.д. Эти незаметные штуки не обращают на себя внимания, но добавляют жизни комфорта. Такая же история с различными мобильными и десктопными приложениями: для длинных скриншотов, для уменьшения размера картинки, для подсчёта личных финансов, словари, переводчики, конверторы и т.д. А есть ли у вас такой VPS — который стоит недорого, всегда под рукой и приносит много пользы? Нет, не тот который у вас в компании, а свой, «карманный». Мы подумали, что без небольшого VPS в 2019 году как-то грустно, прямо как без привычной авторучки на лекции. А чего грустить? Лето же. Ну как лето. Лето айтишника: сидеть дома, пилить любимые проекты безо всякого сожаления. В общем, подумали и сделали.


Коммунизм наступил, товарищи

Он такой свой — наш VPS за тридцатку

Мы начитались статей конкурентов и пользователей, которые 3-4 года назад писали о том, почему не нужен недорогой VPS. Ну правильно, тогда VPS «за копейки» был чистой воды маркетингом и не мог предложить нормальные рабочие возможности. Но времена меняются, стоимость виртуальных ресурсов становится всё ниже и за 30 рублей в месяц мы готовы предложить вот что:

  • Процессор: Intel Xeon 2 ГГц (1 ядро)
  • Система Linux (Debian, Ubuntu, CentOS на выбор)
  • 1 выделенный IPv4-адрес
  • 10 Гб для хранения данных на быстрых SSD-дисках корпоративного класса
  • Оперативная память: 512 Мб
  • Посекундная тарификация
  • Безлимитный трафик

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

Да почти всем: новичкам, энтузиастам, опытным разработчикам, DIY-фанатам и даже некоторым компаниям. Кому подойдёт такой виртуальный сервер?

Для чего подходит такой VPS?

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

  • Разместить свой несложный сайт, портфолио, резюме с кодом и проч. Конечно, собственный оформленный сайт производит на работодателя позитивное впечатление. Разместите его на своём VPS и отвечайте за безопасность и стабильность сайта самостоятельно, а не силами сотрудников обычных хостингов.
  • Использовать VPS для учебных целей: разместить свой проект, изучить особенности функционирования сервера и серверной операционной системы, поэкспериментировать с DNS, поковырять маленький учебный сайт.
  • Для телефонии. Иногда индивидуальному предпринимателю, фрилансеру или очень небольшой компании крайне нужна IP-телефония, а операторы этой самой телефонии весьма жадные. Всё просто: берём свой сервер, покупаем номер у оператора IP-телефонии, настраиваем виртуальную АТС и создаём внутренние номера (при необходимости). Экономия колоссальная.
  • Использовать сервер для тестирования своих приложений.
  • Использовать сервер для DIY-экспериментов, в том числе для управления и сбора данных с датчиков системы умного дома.
  • Необычный способ применения — разместить на сервере виртуального помощника биржевой торговли, торгового робота. Вы будете полностью отвечать за стабильность и безопасность сервера, а значит, получите подконтрольный инструмент для торгов на фондовы рынках. Ну вдруг кто увлекается или планирует 🙂

Есть такому VPS применение и в корпоративной сфере. Кроме уже названного телефонного сервиса, можно реализовать несколько интересных штук. Например:

  • Размещать небольшие базы данных и информацию, которые будут доступны командировочным сотрудникам на расстоянии, например, с помощью ftp. Это позволит очень быстро обменяться свежей аналитикой, обновлёнными конфигурациями для продажников, презентацией и т.д.
  • Давать временный доступ пользователям или клиентам для демонстрации программного обеспечения или мультимедиа.

Тест-драйв VPS за 30 рублей — сделали за вас

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

Цель — смоделировать высокую плотность размещения и нагрузку сопоставимую или большую, чем боевая. Хост находился под нагрузкой некоторого количества виртуальных машин, которые выполняли различные задачи на процессоре и активно использовали дисковую подсистему.

Все тестовые виртуальные машины имели одинаковую конфигурацию (1 ядро, RAM 512 Гб, SSD 10Гб), в качестве операционной системы выбран стандартный образ debian 9. Помимо постоянной нагрузки поставили 3 виртуальные машины, собирающие синтетические метрики с помощью sysbench, усредненные результаты которых привели ниже, и 50 виртуальных машин, которые создавали дополнительную нагрузку. 6, который предлагается пользователям на RUVDS.

Нагрузку имитировали по характеру и величине сопоставимую с боевой:

  • Часть виртуальных машин были запущены с низкой нагрузкой
  • Часть машин «крутили» тестовый сценарий, имитирующий нагрузку на процессор (с использованием утилиты stress)
  • На оставшейся части виртуалок мы запустили сценарий, использующий dd для копирования данных из заранее заготовленных данных на диск с ограничением, заданным с помощью pv (примеры можно посмотреть здесь и здесь).

Ещё, как вы помните, у нас были три машины, собирающие синтетические метрики.

На каждой машине циклически раз в 15 минут выполнялся скрипт, который запускает стандартные тесты sysbench для процессора, памяти и диска.

Cкрипт sysbench.sh

#!/bin/bash
date +"%Y-%m-%d %H:%M:%S" >> /root/sysbench/results.txt
sysbench --test=cpu run >> /root/sysbench/results.txt
sysbench --test=memory run >> /root/sysbench/results.txt
sysbench --test=fileio --file-test-mode=seqwr run >> /root/sysbench/results.txt
sysbench --test=fileio --file-test-mode=seqrd run >> /root/sysbench/results.txt
sysbench --test=fileio --file-test-mode=rndrw run >> /root/sysbench/results.txt

Результаты приведены для удобства в формате sysbench'а, но взяты средние значения за всё время тестирования со всех машин, итог можно посмотреть здесь:

Sysbanch-avg.txt

sysbench 0.4.12: multi-threaded system evaluation benchmark

Running the test with following options:
Number of threads: 1

Doing CPU performance benchmark

Threads started!
Done.

Maximum prime number checked in CPU test: 10000

2244s
total number of events: 10000
total time taken by event execution: 19. Test execution summary:
total time: 19. 43ms
avg: 1. 2104
per-request statistics:
min: 1. 00ms
approx. 92ms
max: 47. 02ms 95 percentile: 3.

0000/0. Threads fairness:
events (avg/stddev): 10000. 2104/0. 00
execution time (avg/stddev): 19. 00

4. sysbench 0. 12: multi-threaded system evaluation benchmark

Running the test with following options:
Number of threads: 1

Doing memory operations speed test
Memory block size: 1K

Memory transfer size: 102400M

Memory operations type: write
Memory scope type: global
Threads started!
Done.

79 ops/sec) Operations performed: 104857600 (328001.

00 MB transferred (320. 102400. 32 MB/sec)

9155s
total number of events: 104857600
total time taken by event execution: 244. Test execution summary:
total time: 320. 00ms
avg: 0. 8399
per-request statistics:
min: 0. 41ms
approx. 00ms
max: 139. 00ms 95 percentile: 0.

0000/0. Threads fairness:
events (avg/stddev): 104857600. 8399/0. 00
execution time (avg/stddev): 244. 00

4. sysbench 0. 12: multi-threaded system evaluation benchmark

Running the test with following options:
Number of threads: 1

Extra file open flags: 0
128 files, 16Mb each
2Gb total file size
Block size 16Kb
Periodic FSYNC enabled, calling fsync() each 100 requests.
Calling fsync() at the end of test, Enabled.
Using synchronous I/O mode
Doing sequential write (creation) test
Threads started!
Done.

1Mb/sec)
20251. Operations performed: 0 Read, 131072 Write, 128 Other = 131200 Total
Read 0b Written 2Gb Total transferred 2Gb (320. 32 Requests/sec executed

9972s
total number of events: 131072
total time taken by event execution: 5. Test execution summary:
total time: 6. 01ms
avg: 0. 2246
per-request statistics:
min: 0. 76ms
approx. 04ms
max: 96. 03ms 95 percentile: 0.

0000/0. Threads fairness:
events (avg/stddev): 131072. 2246/0. 00
execution time (avg/stddev): 5. 00

4. sysbench 0. 12: multi-threaded system evaluation benchmark

Running the test with following options:
Number of threads: 1

Extra file open flags: 0
128 files, 16Mb each
2Gb total file size
Block size 16Kb
Periodic FSYNC enabled, calling fsync() each 100 requests.
Calling fsync() at the end of test, Enabled.
Using synchronous I/O mode
Doing sequential read test
Threads started!
Done.

32Mb/sec)
5844. Operations performed: 131072 Read, 0 Write, 0 Other = 131072 Total
Read 2Gb Written 0b Total transferred 2Gb (91. 8 Requests/sec executed

1054s
total number of events: 131072
total time taken by event execution: 22. Test execution summary:
total time: 23. 00ms
avg: 0. 9933
per-request statistics:
min: 0. 75ms
approx. 18ms
max: 295. 77ms 95 percentile: 0.

0000/0. Threads fairness:
events (avg/stddev): 131072. 9933/0. 00
execution time (avg/stddev): 22. 00

4. sysbench 0. 12: multi-threaded system evaluation benchmark

Running the test with following options:
Number of threads: 1

50
Periodic FSYNC enabled, calling fsync() each 100 requests.
Calling fsync() at the end of test, Enabled.
Using synchronous I/O mode
Doing random r/w test
Threads started!
Done. Extra file open flags: 0
128 files, 16Mb each
2Gb total file size
Block size 16Kb
Number of random requests for random IO: 10000
Read/Write ratio for combined random IO test: 1.

75Mb Written 62. Operations performed: 6000 Read, 4000 Write, 12800 Other = 22800 Total
Read 93. 25Mb (1341. 5Mb Total transferred 156. 61 Requests/sec executed 5Kb/sec)
85.

9786s
total number of events: 10000
total time taken by event execution: 14. Test execution summary:
total time: 152. 01ms
avg: 1. 1879
per-request statistics:
min: 0. 22ms
approx. 41ms
max: 210. 95ms 95 percentile: 4.

0000/0. Threads fairness:
events (avg/stddev): 10000. 1879/0. 00
execution time (avg/stddev): 14. 00

Результаты показательны, но все же не стоит их воспринимать как QoS. 

Машины создающие дополнительную нагрузку

Софт:

  • apt-get update
  • apt-get upgrade
  • apt-get install python-pip
  • pip install mysql-connector-python-rf

Установлен MariaDB, Как тут:

apt-get install libmariadbclient-dev
mysql -e "INSTALL PLUGIN blackhole SONAME 'ha_blackhole.so';" -- нужно для test_employees_sha

Тестовая база взята отсюда:

База развернута как указано тут:

mysql -t < employees.sql
mysql -t < test_employees_sha.sql

Тестовая база маленького объема:
Примитивный тестовый сервис написан на коленке на питоне, он выполняет четыре операции:

  1. getState: возвращает статус
  2. getEmployee: возвращает из базы employee (+salaries, +titles)
  3. patchEmployee: изменяет поля employee
  4. insertSalary: выполняет вставку salary

Исходник сервиса (dbtest.py)

#!/usr/bin/python
import mysql.connector as mariadb
from flask import Flask, json, request, abort
from mysql.connector.constants import ClientFlag app = Flask(__name__) def getFields(cursor): results = column = 0 for d in cursor.description: results[d[0]] = column column = column + 1 return results PAGE_SIZE = 30 @app.route("/")
def main(): return "Hello!" @app.route("/employees/<page>", methods=['GET'])
def getEmployees(page): offset = (int(page) - 1) * PAGE_SIZE connection = mariadb.connect(user='admin', password='q5XpRomdSr', database='employees') cursor = connection.cursor() cursor.execute("SELECT * FROM employees LIMIT {} OFFSET {}".format(PAGE_SIZE, offset)) return {'employees': [i[0] for i in cursor.fetchall()]} @app.route("/employee/<id>", methods=['GET'])
def getEmployee(id): id = int(id) connection = mariadb.connect(user='admin', password='q5XpRomdSr', database='employees') cursor = connection.cursor() cursor.execute("SELECT * FROM employees WHERE emp_no = {}".format(id)) fields = getFields(cursor) employee = {} found = False for row in cursor.fetchall(): found = True employee = { "birth_date": row[fields["birth_date"]], "first_name": row[fields["first_name"]], "last_name": row[fields["last_name"]], "gender": row[fields["gender"]], "hire_date": row[fields["hire_date"]] } if not found: abort(404) cursor.execute("SELECT * FROM salaries WHERE emp_no = {}".format(id)) fields = getFields(cursor) salaries = [] for row in cursor.fetchall(): salary = { "salary": row[fields["salary"]], "from_date": row[fields["from_date"]], "to_date": row[fields["to_date"]] } salaries.append(salary) employee["salaries"] = salaries cursor.execute("SELECT * FROM titles WHERE emp_no = {}".format(id)) fields = getFields(cursor) titles = [] for row in cursor.fetchall(): title = { "title": row[fields["title"]], "from_date": row[fields["from_date"]], "to_date": row[fields["to_date"]] } titles.append(title) employee["titles"] = titles return json.dumps({ "status": "success", "employee": employee }) def isFieldValid(t, v): if t == "employee": return v in ["birdth_date", "first_name", "last_name", "hire_date"] else: return false @app.route("/employee/<id>", methods=['PATCH'])
def setEmployee(id): id = int(id) content = request.json print(content) setList = "" data = [] for k, v in content.iteritems(): if not isFieldValid("employee", k): continue if setList != "": setList = setList + ", " setList = setList + k + "=%s" data.append(v) data.append(id) print(setList) print(data) connection = mariadb.connect(user='admin', password='q5XpRomdSr', database='employees', client_flags=[ClientFlag.FOUND_ROWS]) cursor = connection.cursor() cursor.execute("UPDATE employees SET {} WHERE emp_no = %s".format(setList), data) connection.commit() if cursor.rowcount < 1: abort(404) return json.dumps({ "status": "success" }) @app.route("/salary", methods=['PUT'])
def putSalary(): content = request.json print(content) connection = mariadb.connect(user='admin', password='q5XpRomdSr', database='employees', client_flags=[ClientFlag.FOUND_ROWS]) cursor = connection.cursor() data = [content["emp_no"], content["salary"], content["from_date"], content["to_date"]] cursor.execute("INSERT INTO salaries (emp_no, salary, from_date, to_date) VALUES (%s, %s, %s, %s)", data) connection.commit() return json.dumps({ "status": "success" }) @app.route("/state", methods=['GET'])
def getState(): return json.dumps({ "status": "success", "state": "working" }) if __name__ == '__main__': app.run(host='0.0.0.0',port='5002')

Внимание! Ни в коем случае не стоит воспринимать этот сервис как пример или пособие!

Был запущен ряд тестов длительностью от 15 минут до 2 часов, без перерывов, изменялось процентное соотношение запросов, пропускная способность варьировалась от 300 до 600 запросов в минуту. Тесты выполняются с помощью старого доброго JMeter. Количество потоков от 50 до 500.

В силу того, что база совсем маленького размера, команда:

mysql -e "SHOW ENGINE INNODB STATUS"

Показывает что:

Buffer pool hit rate 923 / 1000, young-making rate 29 / 1000 not 32 / 1000

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

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть