Cerebro + VPS por 30 rublos =?

Es muy agradable tener a mano todas las pequeñas cosas necesarias: un buen bolígrafo y una libreta, un lápiz afilado, un ratón cómodo, un par de cables extra, etc. Estas cosas discretas no llaman la atención, pero añaden comodidad a la vida. Lo mismo ocurre con varias aplicaciones móviles y de escritorio: para capturas de pantalla largas, para reducir el tamaño de una imagen, para calcular finanzas personales, diccionarios, traductores, conversores, etc. ¿Tienes uno? VPS - ¿Qué es económico, está siempre a mano y aporta muchos beneficios? No, no el que tienes en tu empresa, sino el tuyo propio, “de bolsillo”. Pensamos que sin un pequeño VPS en 2019 sería algo triste, como sin la habitual pluma estilográfica en una conferencia. ¿Por qué estar triste? Es verano. ¿Cómo va el verano? Verano para un especialista en TI: sentado en casa, trabajando en tus proyectos favoritos sin ningún arrepentimiento. En general, lo pensamos y lo hicimos.

Cerebro + VPS por 30 rublos =?
El comunismo ha llegado, camaradas.

Él es así: nuestro VPS por treinta.

Hemos leído muchos artículos de competidores y usuarios que escribieron hace 3 o 4 años sobre por qué no se necesita un VPS económico. Bueno, así es, entonces el VPS "por un centavo" era puro marketing y no podía ofrecer oportunidades laborales normales. Pero los tiempos están cambiando, el costo de los recursos virtuales es cada vez menor, y por 30 rublos al mes estamos listos para ofrecer esto:

  • Procesador: Intel Xeon 2 GHz (1 núcleo)
  • Sistema Linux (Debian, Ubuntu, CentOS para elegir)
  • 1 dirección IPv4 dedicada
  • 10 GB de almacenamiento de datos en unidades SSD rápidas de clase empresarial
  • RAM: 512 MB
  • Facturación por segundo
  • Tráfico ilimitado

La tarifa está sujeta a restricciones técnicas adicionales, detalles sobre página nuestra interesante oferta: VPS por 30 rublos. 

¿Para quién es adecuado este servidor virtual? Sí a casi todo el mundo: principiantes, entusiastas, desarrolladores experimentados, aficionados al bricolaje e incluso algunas empresas.

¿Para qué es adecuado este VPS?

Creemos que los lectores de Habr definitivamente encontrarán su propia manera de usar esta configuración, pero decidimos recopilar nuestra propia selección de ideas: ¿qué pasa si alguien lo necesita, pero los hombres no lo saben?

  • Coloque su sitio web sencillo, portafolio, currículum con código, etc. Por supuesto, un sitio web diseñado por usted mismo causa una impresión positiva al empleador. Colóquelo en su VPS y sea responsable de la seguridad y estabilidad del sitio usted mismo, y no el personal de los proveedores de alojamiento habituales.
  • Utilice VPS con fines educativos: aloje su proyecto, estudie las características del servidor y el sistema operativo del servidor, experimente con DNS, juegue con un pequeño sitio educativo.
  • Para telefonía. A veces, un empresario individual, un autónomo o una empresa muy pequeña necesita desesperadamente telefonía IP, y los operadores de esta misma telefonía son muy codiciosos. Es muy sencillo: cogemos nuestro servidor, compramos un número a un operador de telefonía IP, configuramos una centralita virtual y creamos números internos (si es necesario). Los ahorros son colosales.
  • Utilice el servidor para probar sus aplicaciones.
  • Utilice el servidor para experimentos de bricolaje, incluido el control y la recopilación de datos de sensores de sistemas domésticos inteligentes.
  • Una forma inusual de utilizarlo es colocar un asistente de operaciones de intercambio virtual, un robot de operaciones, en el servidor. Usted será totalmente responsable de la estabilidad y seguridad del servidor, lo que significa que recibirá un instrumento controlado para operar en los mercados de valores. Bueno, por si alguien está interesado o planeando :)

Existen aplicaciones para este tipo de VPS en el ámbito corporativo. Además del servicio telefónico ya mencionado, puedes implementar varias cosas interesantes. Por ejemplo:

  • Coloque pequeñas bases de datos e información a la que puedan acceder los empleados que viajan a distancia, por ejemplo, mediante ftp. Esto le permitirá intercambiar muy rápidamente análisis nuevos, configuraciones actualizadas para el personal de ventas, presentaciones, etc.
  • Dar acceso temporal a usuarios o clientes para demostrar software o medios.

Prueba de manejo de VPS por 30 rublos: hecho para usted

30 rublos es tan poco que ni siquiera querrás sacar una tarjeta para pagar y realizar la prueba. A veces también somos muy vagos, pero esta vez hicimos todo por ti. Antes de lanzar los servidores a la batalla, realizamos una prueba para comprobar todos los detalles y mostrar de qué son capaces los servidores con esta tarifa. Para hacerlo más interesante, agregamos extremo y verificamos cómo se comportaría esta configuración si la densidad y la carga excedieran los valores que establecimos. 

El host estaba bajo la carga de varias máquinas virtuales que realizaban diversas tareas en el procesador y utilizaban activamente el subsistema de disco. El objetivo es simular una alta densidad de colocación y una carga comparable o superior a la de combate.

Además de la carga constante, instalamos 3 máquinas virtuales que recopilaron métricas sintéticas usando sysbench, cuyos resultados promedio se detallan a continuación, y 50 máquinas virtuales que crearon una carga adicional. Todas las máquinas virtuales de prueba tenían la misma configuración (1 núcleo, RAM 512 GB, SSD 10 GB), se seleccionó la imagen estándar debian 9.6 como sistema operativo, que se ofrece a los usuarios en RUVDS.

La carga fue simulada en naturaleza y magnitud comparable al combate:

  • Algunas máquinas virtuales se iniciaron con poca carga.
  • Algunas máquinas ejecutaron un script de prueba que simulaba la carga en el procesador (usando la utilidad estrés)
  • En la parte restante de las máquinas virtuales, ejecutamos un script que usaba dd para copiar datos de datos preparados previamente al disco con un límite establecido usando pv (se pueden ver ejemplos aquí и aquí).

Además, como recordarán, teníamos tres máquinas que recopilaban métricas sintéticas.

En cada máquina, se ejecutó cíclicamente un script cada 15 minutos, que ejecuta pruebas de sysbench estándar para el procesador, la memoria y el disco.

Guión 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

Para mayor comodidad, los resultados se presentan en formato sysbench, pero los valores promedio para todo el período de prueba se tomaron de todas las máquinas; el resultado se puede ver aquí:

Sysbanch-avg.txtsysbench 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

Test execution summary:
total time: 19.2244s
total number of events: 10000
total time taken by event execution: 19.2104
per-request statistics:
min: 1.43ms
avg: 1.92ms
max: 47.00ms
approx. 95 percentile: 3.02ms

Threads fairness:
events (avg/stddev): 10000.0000/0.00
execution time (avg/stddev): 19.2104/0.00

sysbench 0.4.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.

Operations performed: 104857600 (328001.79 ops/sec)

102400.00 MB transferred (320.32 MB/sec)

Test execution summary:
total time: 320.9155s
total number of events: 104857600
total time taken by event execution: 244.8399
per-request statistics:
min: 0.00ms
avg: 0.00ms
max: 139.41ms
approx. 95 percentile: 0.00ms

Threads fairness:
events (avg/stddev): 104857600.0000/0.00
execution time (avg/stddev): 244.8399/0.00

sysbench 0.4.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.

Operations performed: 0 Read, 131072 Write, 128 Other = 131200 Total
Read 0b Written 2Gb Total transferred 2Gb (320.1Mb/sec)
20251.32 Requests/sec executed

Test execution summary:
total time: 6.9972s
total number of events: 131072
total time taken by event execution: 5.2246
per-request statistics:
min: 0.01ms
avg: 0.04ms
max: 96.76ms
approx. 95 percentile: 0.03ms

Threads fairness:
events (avg/stddev): 131072.0000/0.00
execution time (avg/stddev): 5.2246/0.00

sysbench 0.4.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.

Operations performed: 131072 Read, 0 Write, 0 Other = 131072 Total
Read 2Gb Written 0b Total transferred 2Gb (91.32Mb/sec)
5844.8 Requests/sec executed

Test execution summary:
total time: 23.1054s
total number of events: 131072
total time taken by event execution: 22.9933
per-request statistics:
min: 0.00ms
avg: 0.18ms
max: 295.75ms
approx. 95 percentile: 0.77ms

Threads fairness:
events (avg/stddev): 131072.0000/0.00
execution time (avg/stddev): 22.9933/0.00

sysbench 0.4.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
Number of random requests for random IO: 10000
Read/Write ratio for combined random IO test: 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.

Operations performed: 6000 Read, 4000 Write, 12800 Other = 22800 Total
Read 93.75Mb Written 62.5Mb Total transferred 156.25Mb (1341.5Kb/sec)
85.61 Requests/sec executed

Test execution summary:
total time: 152.9786s
total number of events: 10000
total time taken by event execution: 14.1879
per-request statistics:
min: 0.01ms
avg: 1.41ms
max: 210.22ms
approx. 95 percentile: 4.95ms

Threads fairness:
events (avg/stddev): 10000.0000/0.00
execution time (avg/stddev): 14.1879/0.00

Los resultados son indicativos, pero aún así no deben tomarse como QoS. 

Máquinas que crean carga adicional.

Suave:

  • apt-get update
  • actualización apt-get
  • apt-get install python-pip
  • pip instala el conector mysql-python-rf

MariaDB instalada, cómo aquí:

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

Base de prueba tomada por lo tanto:

La base de datos se implementa según lo especificado. aquí:

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

Pequeña base de prueba:

Mesa 

Número de filas 

Tamaño de datos (MB)

Tamaño del índice (KB)

departamentos 

9

0.02

16.00

departamento_emp 

331143 

11.52

5648.00

gerente_depto 

24 

0.02

16.00

personas 

299379 

14.52

0.00

salarios 

2838426 

95.63

0.00 

títulos 

442783 

19.56

0.00

Un servicio de prueba primitivo está escrito en Python; realiza cuatro operaciones:

  1. getState: devuelve el estado
  2. getEmployee: devuelve empleados (+salarios, +títulos) de la base de datos
  3. patchEmployee: cambia los campos de los empleados
  4. insertSalary: inserta un salario

Fuente del servicio (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')

¡Atención! ¡Bajo ninguna circunstancia se debe tomar este servicio como ejemplo o guía!

Las pruebas se realizan utilizando el viejo JMeter. Se lanzaron una serie de pruebas con una duración de 15 minutos a 2 horas, sin interrupciones, el porcentaje de solicitudes varió y el rendimiento varió de 300 a 600 solicitudes por minuto. Número de hilos de 50 a 500.

Debido a que la base de datos es muy pequeña, el comando:

mysql -e "SHOW ENGINE INNODB STATUS"

Muestra que:

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

A continuación se detallan los tiempos promedio de respuesta para las solicitudes:

Label

Normal

Mediana

Línea 90%

Línea 95%

Línea 99%

Min

Max

obtener empleado

37.64

12.57

62.28

128.5

497.57

5

4151.78

getState

17

7.57

30.14

58.71

193

3

2814.71

parcheEmpleado

161.42

83.29

308

492.57

1845.14

5

6639.4

ponerSalario

167.21

86.93

315.34

501.07

1927.12

7

6722.44

Puede resultarle difícil juzgar a partir de estos resultados sintéticos qué tan adecuado es este VPS para sus tareas específicas y, en general, los métodos enumerados se limitan a aquellos casos que tuvimos que abordar de una forma u otra. Por eso nuestra lista es claramente no exhaustivo. Lo invitamos a sacar sus propias conclusiones y probar el servidor por 30 rublos en sus aplicaciones y tareas reales y sugerirle sus opciones para esta configuración en los comentarios.

Fuente: habr.com

Añadir un comentario