Cerebro + VPS por 30 rublos =?

É tan bonito cando hai todas as pequenas cousas necesarias a man: un bo bolígrafo e un bo bloc de notas, un lapis afiado, un rato cómodo, un par de cables extra, etc. Estas cousas discretas non chaman a atención, pero engaden confort á vida. A mesma historia ocorre con varias aplicacións móbiles e de escritorio: para capturas de pantalla longas, para reducir o tamaño dunha imaxe, para calcular finanzas persoais, dicionarios, tradutores, conversores, etc. Tes un coma este? Estudantes - que é barato, sempre a man e trae moitos beneficios? Non, non a que tes na túa empresa, senón a túa propia, de “peto”. Pensamos que sen un pequeno VPS en 2019 era algo triste, igual que sen a pluma estilográfica habitual nunha conferencia. Por que estar triste? É verán. Que tal o verán? Verán para un especialista en informática: sentado na casa, traballando nos teus proxectos favoritos sen ningún arrepentimento. En xeral, pensamos e fixémolo.

Cerebro + VPS por 30 rublos =?
O comunismo chegou, compañeiros.

El é así: o noso VPS para trinta

Lemos moitos artigos de competidores e usuarios que escribiron hai 3-4 anos sobre por que non se necesita un VPS barato. Ben, iso é certo, entón VPS "por un centavo" era puro marketing e non podía ofrecer oportunidades laborais normais. Pero os tempos están cambiando, o custo dos recursos virtuais é cada vez máis baixo e por 30 rublos ao mes estamos preparados para ofrecer isto:

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

A tarifa está suxeita a restricións técnicas adicionais páxina a nosa oferta xenial - VPS por 30 rublos. 

Para quen é axeitado este servidor virtual? Si para case todos: principiantes, entusiastas, desenvolvedores experimentados, fans do bricolaxe e incluso algunhas empresas.

Para que é axeitado este VPS?

Pensamos que os lectores de Habr definitivamente atoparán o seu propio xeito de usar esta configuración, pero decidimos recoller a nosa propia selección de ideas: e se alguén o necesita, pero os homes non o saben?

  • Coloca o teu sitio web sinxelo, carteira, currículo con código, etc. Por suposto, o teu propio sitio web deseñado fai unha impresión positiva no empresario. Colócao no teu VPS e sexa responsable da seguridade e estabilidade do sitio, e non polo persoal dos provedores de hospedaxe habituais.
  • Use VPS con fins educativos: aloxe o seu proxecto, estude as características do servidor e do sistema operativo do servidor, experimente con DNS, retoque cun pequeno sitio educativo.
  • Para telefonía. Ás veces, un empresario individual, autónomo ou unha empresa moi pequena necesita desesperadamente a telefonía IP, e os operadores desta mesma telefonía son moi codiciosos. É sinxelo: collemos o noso servidor, compramos un número a un operador de telefonía IP, configuramos unha central virtual e creamos números internos (se é necesario). O aforro é enorme.
  • Use o servidor para probar as súas aplicacións.
  • Use o servidor para experimentos de bricolaxe, incluído o control e a recollida de datos dos sensores do sistema doméstico intelixente.
  • Unha forma inusual de usalo é colocar un asistente de negociación de intercambio virtual, un robot comercial, no servidor. Serás totalmente responsable da estabilidade e seguridade do servidor, o que significa que recibirás un instrumento controlado para negociar nas bolsas. Pois por se alguén está interesado ou planeando :)

Existen aplicacións para este tipo de VPS no ámbito corporativo. Ademais do servizo telefónico xa mencionado, podes implementar varias cousas interesantes. Por exemplo:

  • Coloque pequenas bases de datos e información que serán accesibles para os empregados que viaxan a distancia, por exemplo, mediante ftp. Isto permitirache intercambiar moi rapidamente análises novas, configuracións actualizadas para vendedores, presentacións, etc.
  • Dar acceso temporal aos usuarios ou clientes para demostrar software ou medios.

Test drive VPS por 30 rublos - feito por ti

30 rublos son tan poucos que nin sequera queres sacar unha tarxeta para pagar e probar. Ás veces tamén somos tan preguiceiros, pero esta vez fixemos todo por ti. Antes de lanzar os servidores á batalla, realizamos unha proba para comprobar todos os detalles e mostrar de que son capaces os servidores a esta tarifa. Para facelo máis interesante, engadimos extremo e comprobamos como se comportaría esta configuración se a densidade e a carga superasen os valores que establecemos. 

O host estaba baixo a carga dunha serie de máquinas virtuais que realizaban varias tarefas no procesador e usaban activamente o subsistema de disco. O obxectivo é simular unha alta densidade de colocación e unha carga comparable ou superior a unha de combate.

Ademais da carga constante, instalamos 3 máquinas virtuais que recolleron métricas sintéticas mediante sysbench, cuxos resultados medios se indican a continuación, e 50 máquinas virtuais que crearon carga adicional. Todas as máquinas virtuais de proba tiñan a mesma configuración (1 núcleo, RAM 512 GB, SSD 10 GB), seleccionouse a imaxe estándar debian 9.6 como sistema operativo, que se ofrece aos usuarios en RUVDS.

A carga foi simulada en natureza e magnitude comparable ao combate:

  • Algunhas máquinas virtuais lanzáronse con pouca carga
  • Algunhas máquinas executaron un script de proba que simulaba a carga do procesador (usando a utilidade estrés)
  • Na parte restante das máquinas virtuais, executamos un script que usaba dd para copiar datos de datos previamente preparados ao disco cun límite establecido usando pv (pódense ver exemplos). aquí и aquí).

Ademais, como lembras, tiñamos tres máquinas que recollían métricas sintéticas.

En cada máquina, executouse cíclicamente un script cada 15 minutos, que executa probas estándar de sysbench para o procesador, a memoria e o disco.

Script 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

Os resultados preséntanse por comodidade en formato sysbench, pero os valores medios para todo o período de proba foron tomados de todas as máquinas, o resultado pódese 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

Os resultados son indicativos, pero aínda non se deben tomar como QoS. 

Máquinas que crean carga adicional

Suave:

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

Instalou MariaDB, como aquí:

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

Base de proba tomada por iso:

A base de datos está implantada como se especifica aquí:

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

Base de proba pequena:

Táboa 

Conta de filas 

Tamaño dos datos (MB)

Tamaño do índice (KB)

departamentos 

9

0.02

16.00

departamento_emp 

331143 

11.52

5648.00

xerente_departamento 

24 

0.02

16.00

funcionarios 

299379 

14.52

0.00

salarios 

2838426 

95.63

0.00 

títulos 

442783 

19.56

0.00

Un servizo de proba primitivo está escrito no xeonllo en Python; realiza catro operacións:

  1. getState: devolve o estado
  2. getEmployee: devolve os empregados (+salarios, +títulos) da base de datos
  3. patchEmployee: cambia os campos dos empregados
  4. inserirSalario: insire un salario

Orixe do servizo (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! En ningún caso este servizo debe ser tomado como exemplo ou guía!

As probas realízanse usando un bo JMeter antigo. Púxose en marcha unha serie de probas de 15 minutos a 2 horas, sen interrupcións, a porcentaxe de solicitudes variou e o rendemento de 300 a 600 solicitudes por minuto. Número de fíos de 50 a 500.

Debido ao feito de que a base de datos é moi pequena, o comando:

mysql -e "SHOW ENGINE INNODB STATUS"

Mostra que:

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

Abaixo amósanse os tempos medios de resposta ás solicitudes:

etiqueta

media

Mediana

90% Liña

95% Liña

99% Liña

Min

Max

getEmployee

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

poñerSalario

167.21

86.93

315.34

501.07

1927.12

7

6722.44

Pode ser difícil para vostede xulgar a partir destes resultados sintéticos o axeitado que é este VPS para as súas tarefas específicas e, en xeral, os métodos enumerados limítanse a aqueles casos que tivemos que tratar dunha forma ou outra. Polo que a nosa lista é claramente non exhaustivo. Invitámosche a sacar as túas propias conclusións e probar o servidor por 30 rublos nas túas aplicacións e tarefas reais e suxerir as túas opcións para esta configuración nos comentarios.

Fonte: www.habr.com

Engadir un comentario