Cerveau + VPS pour 30 roubles =?

C'est tellement agréable quand toutes les petites choses nécessaires sont à portée de main : un bon stylo et un bon bloc-notes, un crayon bien taillé, une souris confortable, quelques fils supplémentaires, etc. Ces choses discrètes n'attirent pas l'attention, mais ajoutent du confort à la vie. La même histoire se produit avec diverses applications mobiles et de bureau : pour de longues captures d'écran, pour réduire la taille d'une image, pour calculer ses finances personnelles, des dictionnaires, des traducteurs, des convertisseurs, etc. Avez-vous une? VPS - qui est peu coûteux, toujours à portée de main et apporte de nombreux avantages ? Non, pas celui que vous avez dans votre entreprise, mais le vôtre, « de poche ». Nous pensions que sans un petit VPS en 2019, c'était en quelque sorte triste, tout comme sans le stylo-plume habituel lors d'une conférence. Pourquoi être triste ? C'est l'été. Comment se passe l'été ? L'été pour un informaticien : assis à la maison, travaillant sur vos projets préférés sans aucun regret. En général, nous l'avons pensé et fait.

Cerveau + VPS pour 30 roubles =?
Le communisme est arrivé, camarades.

Il est comme ça - notre VPS depuis trente ans

Nous avons lu de nombreux articles de concurrents et d'utilisateurs qui ont écrit il y a 3 ou 4 ans pourquoi un VPS bon marché n'est pas nécessaire. Eh bien, c'est vrai, alors le VPS « pour un centime » était du pur marketing et ne pouvait pas offrir des opportunités de travail normales. Mais les temps changent, le coût des ressources virtuelles devient de plus en plus bas, et pour 30 roubles par mois, nous sommes prêts à offrir ceci :

  • Processeur : Intel Xeon 2 GHz (1 cœur)
  • Système Linux (Debian, Ubuntu, CentOS au choix)
  • 1 adresse IPv4 dédiée
  • 10 Go de stockage de données sur des disques SSD rapides de classe entreprise
  • RAM : 512 Mo
  • Facturation à la seconde
  • Trafic illimité

Le tarif est soumis à des restrictions techniques supplémentaires, détails sur page notre offre intéressante - VPS pour 30 roubles. 

À qui s’adresse ce serveur virtuel ? Oui à presque tout le monde : débutants, passionnés, développeurs confirmés, fans de DIY et même certaines entreprises.

A quoi convient ce VPS ?

Nous pensons que les lecteurs de Habr trouveront certainement leur propre façon d'utiliser cette configuration, mais nous avons décidé de rassembler notre propre sélection d'idées - et si quelqu'un en avait besoin, mais que les hommes ne le savent pas ?

  • Placez votre site Web simple, votre portfolio, votre CV avec code, etc. Bien entendu, votre propre site Web fait une impression positive sur l’employeur. Placez-le sur votre VPS et soyez responsable de la sécurité et de la stabilité du site vous-même, et non par le personnel des hébergeurs habituels.
  • Utilisez le VPS à des fins pédagogiques : hébergez votre projet, étudiez les fonctionnalités du serveur et du système d'exploitation du serveur, expérimentez le DNS, bricolez un petit site pédagogique.
  • Pour la téléphonie. Parfois, un entrepreneur individuel, un indépendant ou une très petite entreprise a désespérément besoin de téléphonie IP, et les opérateurs de cette même téléphonie sont très gourmands. C'est simple : nous prenons notre serveur, achetons un numéro auprès d'un opérateur de téléphonie IP, mettons en place un PBX virtuel et créons des numéros internes (si nécessaire). Les économies sont colossales.
  • Utilisez le serveur pour tester vos applications.
  • Utilisez le serveur pour des expériences de bricolage, notamment le contrôle et la collecte de données à partir des capteurs du système de maison intelligente.
  • Une façon inhabituelle de l'utiliser consiste à placer un assistant virtuel de trading en bourse, un robot de trading, sur le serveur. Vous serez entièrement responsable de la stabilité et de la sécurité du serveur, ce qui signifie que vous recevrez un instrument contrôlé pour négocier sur les marchés boursiers. Eh bien, au cas où quelqu'un serait intéressé ou envisageait :)

Il existe des applications pour de tels VPS dans le domaine des entreprises. En plus du service téléphonique déjà évoqué, vous pouvez mettre en œuvre plusieurs choses intéressantes. Par exemple:

  • Placez de petites bases de données et des informations qui seront accessibles à distance aux employés en déplacement, par exemple via FTP. Cela vous permettra d'échanger très rapidement de nouvelles analyses, des configurations mises à jour pour les commerciaux, des présentations, etc.
  • Accordez un accès temporaire aux utilisateurs ou aux clients pour faire une démonstration de logiciels ou de médias.

Essai routier VPS pour 30 roubles - fait pour vous

30 roubles, c'est si peu que vous ne voulez même pas sortir une carte pour payer et tester. Nous aussi sommes parfois paresseux, mais cette fois nous avons tout fait pour vous. Avant de lancer les serveurs au combat, nous avons effectué un test pour vérifier tous les détails et montrer de quoi les serveurs sont capables à ce tarif. Pour le rendre plus intéressant, nous avons ajouté des valeurs extrêmes et vérifié comment cette configuration se comporterait si la densité et la charge dépassaient les valeurs que nous avons définies. 

L'hôte était sous la charge d'un certain nombre de machines virtuelles qui effectuaient diverses tâches sur le processeur et utilisaient activement le sous-système de disque. L'objectif est de simuler une haute densité de placement et une charge comparable ou supérieure à celle de combat.

En plus de la charge constante, nous avons installé 3 machines virtuelles qui collectaient des métriques synthétiques à l'aide de sysbench, dont les résultats moyens étaient donnés ci-dessous, et 50 machines virtuelles qui créaient une charge supplémentaire. Toutes les machines virtuelles de test avaient la même configuration (1 cœur, RAM 512 Go, SSD 10 Go), l'image standard Debian 9.6 a été sélectionnée comme système d'exploitation, qui est proposé aux utilisateurs sur RUVDS.

La charge a été simulée en nature et en ampleur comparable au combat :

  • Certaines machines virtuelles ont été lancées avec une faible charge
  • Certaines machines exécutaient un script de test simulant la charge sur le processeur (à l'aide de l'utilitaire stress)
  • Sur la partie restante des machines virtuelles, nous avons exécuté un script qui utilisait dd pour copier les données des données pré-préparées sur le disque avec une limite définie à l'aide de pv (des exemples peuvent être vus ici и ici).

De plus, comme vous vous en souvenez, nous avions trois machines qui collectaient des métriques synthétiques.

Sur chaque machine, un script était exécuté cycliquement toutes les 15 minutes, qui exécutait des tests Sysbench standard pour le processeur, la mémoire et le disque.

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

Les résultats sont présentés pour plus de commodité au format sysbench, mais les valeurs moyennes pour toute la période de test ont été prises sur toutes les machines, le résultat peut être vu ici :

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

Les résultats sont indicatifs, mais ne doivent toujours pas être considérés comme une qualité de service. 

Machines qui créent une charge supplémentaire

Doux:

  • apt-get update
  • apt-get mise à niveau
  • apt-get installer python-pip
  • pip installe mysql-connecteur-python-rf

MariaDB installé, comment ici:

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

Base de test effectuée par conséquent,:

La base de données est déployée comme spécifié ici:

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

Petite base de test :

lampe de table 

Nombre de lignes 

Taille des données (Mo)

Taille de l'index (Ko)

départements 

9

0.02

16.00

département_emp 

331143 

11.52

5648.00

gestionnaire_dept 

24 

0.02

16.00

employés 

299379 

14.52

0.00

les salaires 

2838426 

95.63

0.00 

titres 

442783 

19.56

0.00

Un service de test primitif est écrit sur le genou en Python ; il effectue quatre opérations :

  1. getState : renvoie le statut
  2. getEmployee : renvoie les employés (+ salaires, + titres) de la base de données
  3. patchEmployee : modifie les champs des employés
  4. insertSalary : insère un salaire

Source du service (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')

Attention! En aucun cas ce service ne doit être pris comme exemple ou guide !

Les tests sont effectués à l'aide du bon vieux JMeter. Une série de tests d'une durée de 15 minutes à 2 heures a été lancée, sans interruption, le pourcentage de requêtes variait et le débit variait de 300 à 600 requêtes par minute. Nombre de fils de 50 à 500.

Du fait que la base de données est très petite, la commande :

mysql -e "SHOW ENGINE INNODB STATUS"

Montre que:

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

Vous trouverez ci-dessous les délais de réponse moyens aux demandes :

Libellé

Moyen

Moyenne

90% ligne

95% ligne

99% ligne

Min

Max

obtenirEmployé

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

patchEmployé

161.42

83.29

308

492.57

1845.14

5

6639.4

mettreSalaire

167.21

86.93

315.34

501.07

1927.12

7

6722.44

Il peut être difficile pour vous de juger à partir de ces résultats synthétiques dans quelle mesure ce VPS est adapté à vos tâches spécifiques et, en général, les méthodes répertoriées se limitent aux cas que nous avons dû traiter sous une forme ou une autre. évidemment pas exhaustif. Nous vous invitons à tirer vos propres conclusions et à tester le serveur pour 30 roubles sur vos applications et tâches réelles et à suggérer vos options pour cette configuration dans les commentaires.

Source: habr.com

Ajouter un commentaire