30 rubl uchun miya + VPS =?

Barcha kerakli kichik narsalar qo'lda bo'lsa, bu juda yoqimli: yaxshi qalam va bloknot, o'tkir qalam, qulay sichqoncha, bir nechta qo'shimcha simlar va boshqalar. Bu ko'zga tashlanmaydigan narsalar e'tiborni jalb qilmaydi, balki hayotga qulaylik qo'shadi. Xuddi shu voqea turli xil mobil va ish stoli ilovalari bilan bog'liq: uzoq skrinshotlar uchun, rasm hajmini kamaytirish uchun, shaxsiy mablag'larni hisoblash uchun, lug'atlar, tarjimonlar, konvertorlar va boshqalar. Sizda bormi? VPS - qaysi biri arzon, har doim qo'l ostida va ko'p foyda keltiradi? Yo'q, sizning kompaniyangizda bo'lganingiz emas, balki o'zingizning "cho'ntak"ingiz. Biz 2019 yilda kichik VPSsiz, xuddi ma'ruzadagi odatiy qalamsiz bo'lgani kabi, qayg'uli bo'ladi deb o'yladik. Nega xafa bo'lish kerak? Yoz keldi. Yoz qanday? IT mutaxassisi uchun yoz: uyda o'tirib, hech qanday afsuslanmasdan sevimli loyihalaringiz ustida ishlash. Umuman olganda, biz o'yladik va qildik.

30 rubl uchun miya + VPS =?
Kommunizm keldi, o'rtoqlar.

U shunday - o'ttiz uchun bizning VPS

Biz 3-4 yil oldin nima uchun arzon VPS kerak emasligi haqida yozgan raqobatchilar va foydalanuvchilarning ko'plab maqolalarini o'qidik. To'g'ri, VPS "bir tiyinga" sof marketing edi va oddiy ish imkoniyatlarini taklif qila olmadi. Ammo vaqt o'zgarmoqda, virtual resurslarning narxi pasayib bormoqda va oyiga 30 rubl uchun biz buni taklif qilishga tayyormiz:

  • Protsessor: Intel Xeon 2 gigagertsli (1 yadroli)
  • Linux tizimi (tanlash uchun Debian, Ubuntu, CentOS)
  • 1 ta ajratilgan IPv4 manzili
  • Tezkor korporativ toifadagi SSD disklarida 10 Gb ma'lumotlarni saqlash
  • Operativ xotira: 512 MB
  • Bir soniya uchun hisob-kitob
  • Cheksiz trafik

Tarif qo'shimcha texnik cheklovlarga, tafsilotlarga bog'liq sahifa bizning ajoyib taklifimiz - 30 rubl uchun VPS. 

Ushbu virtual server kimga mos keladi? Ha, deyarli hamma uchun: yangi boshlanuvchilar, ishqibozlar, tajribali ishlab chiquvchilar, DIY muxlislari va hatto ba'zi kompaniyalar.

Bu VPS nimaga mos keladi?

O'ylaymizki, Habr o'quvchilari ushbu konfiguratsiyadan foydalanishning o'ziga xos usullarini topadilar, ammo biz o'z tanlovimizni tanlashga qaror qildik - agar kimgadir kerak bo'lsa-chi, lekin erkaklar buni bilishmasa?

  • Oddiy veb-saytingizni, portfelingizni, kodli rezyumeni va hokazolarni joylashtiring. Albatta, o'zingizning veb-saytingiz ish beruvchida ijobiy taassurot qoldiradi. Uni VPS-ga joylashtiring va sayt xavfsizligi va barqarorligi uchun oddiy xosting provayderlari xodimlari tomonidan emas, balki o'zingiz javobgar bo'ling.
  • VPS-dan ta'lim maqsadlarida foydalaning: loyihangizni o'tkazing, server va server operatsion tizimining xususiyatlarini o'rganing, DNS bilan tajriba o'tkazing, kichik o'quv sayti bilan ishlang.
  • Telefoniya uchun. Ba'zida yakka tartibdagi tadbirkor, frilanser yoki juda kichik kompaniya IP-telefoniyaga juda muhtoj va bu telefoniya operatorlari juda ochko'zdir. Hammasi oddiy: biz serverimizni olamiz, IP telefoniya operatoridan raqam sotib olamiz, virtual PBX o'rnatamiz va ichki raqamlarni yaratamiz (agar kerak bo'lsa). Tejamkorlik juda katta.
  • Ilovalaringizni sinab ko'rish uchun serverdan foydalaning.
  • Serverdan DIY tajribalari, jumladan, aqlli uy tizimi sensorlaridan maʼlumotlarni boshqarish va yigʻish uchun foydalaning.
  • Uni ishlatishning noodatiy usuli bu serverga virtual birja savdo yordamchisini, savdo robotini joylashtirishdir. Siz serverning barqarorligi va xavfsizligi uchun to'liq javobgar bo'lasiz, ya'ni siz fond bozorlarida savdo qilish uchun boshqariladigan vositani olasiz. Xo'sh, agar kimdir qiziqsa yoki rejalashtirsa :)

Korporativ sohada bunday VPS uchun ilovalar mavjud. Yuqorida aytib o'tilgan telefon xizmatiga qo'shimcha ravishda siz bir nechta qiziqarli narsalarni amalga oshirishingiz mumkin. Masalan:

  • Kichkina ma'lumotlar bazalari va ma'lumotlarni masofadan turib sayohat qiluvchi xodimlarga, masalan, ftp-dan foydalanib qo'ying. Bu sizga yangi tahliliy ma'lumotlarni, sotuvchilar uchun yangilangan konfiguratsiyalarni, taqdimotlarni va hokazolarni tezda almashish imkonini beradi.
  • Foydalanuvchilar yoki mijozlarga dasturiy ta'minot yoki ommaviy axborot vositalarini namoyish qilish uchun vaqtinchalik ruxsat bering.

30 rubl uchun VPS test drayveri - siz uchun qilingan

30 rubl juda oz, siz hatto to'lash va sinov uchun kartani olishni xohlamaysiz. Biz ham ba'zida juda dangasa bo'lamiz, lekin bu safar biz siz uchun hamma narsani qildik. Serverlarni jangga kirishdan oldin biz barcha tafsilotlarni tekshirish va serverlar ushbu tarifda nimaga qodirligini ko'rsatish uchun test o'tkazdik. Buni yanada qiziqarli qilish uchun biz ekstremal qo'shdik va agar zichlik va yuk biz o'rnatgan qiymatlardan oshsa, ushbu konfiguratsiya qanday ishlashini tekshirdik. 

Xost protsessorda turli vazifalarni bajaradigan va disk quyi tizimidan faol foydalanadigan bir qator virtual mashinalarning yuki ostida edi. Maqsad, joylashtirishning yuqori zichligini va jangovar bilan solishtiriladigan yoki undan kattaroq yukni taqlid qilishdir.

Doimiy yukga qo'shimcha ravishda biz sysbench yordamida sintetik ko'rsatkichlarni to'playdigan 3 ta virtual mashinani o'rnatdik, ularning o'rtacha natijalari quyida keltirilgan va qo'shimcha yuk yaratgan 50 ta virtual mashina. Barcha sinov virtual mashinalari bir xil konfiguratsiyaga ega edi (1 yadro, RAM 512 GB, SSD 10 GB), RUVDS-da foydalanuvchilarga taqdim etiladigan operatsion tizim sifatida standart debian 9.6 tasviri tanlangan.

Yuk tabiatda taqlid qilingan va kattaligi jangovar bilan taqqoslangan:

  • Ba'zi virtual mashinalar past yuk bilan ishga tushirildi
  • Ba'zi mashinalar protsessorga yukni taqlid qiluvchi sinov skriptini ishga tushirdi (yordamchi dastur yordamida stress)
  • Virtual mashinalarning qolgan qismida biz oldindan tayyorlangan ma'lumotlardan diskka pv yordamida o'rnatilgan chegara bilan ma'lumotlarni nusxalash uchun dd ishlatadigan skriptni ishga tushirdik (misollarni ko'rish mumkin) shu yerda и shu yerda).

Bundan tashqari, siz eslaganingizdek, bizda sintetik ko'rsatkichlarni to'playdigan uchta mashina bor edi.

Har bir mashinada protsessor, xotira va disk uchun standart sysbench testlarini o'tkazadigan skript har 15 daqiqada tsiklik ravishda bajarildi.

sysbench.sh skripti

#!/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

Natijalar qulaylik uchun sysbench formatida taqdim etilgan, ammo butun sinov davri uchun o'rtacha qiymatlar barcha mashinalardan olingan, natijani bu erda ko'rish mumkin:

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

Natijalar ko'rsatkichdir, ammo baribir QoS sifatida qabul qilinmasligi kerak. 

Qo'shimcha yuk yaratadigan mashinalar

Dasturiy ta'minot:

  • apt-get update
  • apt-get yangilanishi
  • apt-get install python-pip
  • pip o'rnating mysql-connector-python-rf

MariaDB o'rnatilgan, qanday qilish kerak shu yerda:

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

Sinov bazasi olindi shu yerda:

Ma'lumotlar bazasi belgilangan tartibda joylashtirilgan shu yerda:

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

Kichik sinov bazasi:

stol 

Qatorlar soni 

Maʼlumotlar hajmi (MB)

Indeks hajmi (KB)

idoralar 

9

0.02

16.00

dept_emp 

331143 

11.52

5648.00

dept_manager 

24 

0.02

16.00

xodimlar 

299379 

14.52

0.00

ish haqi 

2838426 

95.63

0.00 

sarlavhalar 

442783 

19.56

0.00

Pythonda ibtidoiy test xizmati tizzada yozilgan bo'lib, u to'rtta amalni bajaradi:

  1. getState: holatni qaytaradi
  2. getEmployee: ma'lumotlar bazasidan xodimlarni (+maoshlar, +unvonlar) qaytaradi
  3. patchEmployee: xodimlar maydonlarini o'zgartiradi
  4. insertSalary: ish haqini kiritadi

Xizmat manbai (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')

E'tibor bering! Hech qanday holatda bu xizmatni namuna yoki qo'llanma sifatida qabul qilmaslik kerak!

Sinovlar yaxshi eski JMeter yordamida amalga oshiriladi. 15 daqiqadan 2 soatgacha davom etadigan bir qator test sinovlari uzluksiz ishga tushirildi, so'rovlar foizi turlicha bo'lib, o'tkazish qobiliyati daqiqada 300 dan 600 tagacha bo'lgan. 50 dan 500 gacha bo'lgan iplar soni.

Ma'lumotlar bazasi juda kichik bo'lganligi sababli, buyruq:

mysql -e "SHOW ENGINE INNODB STATUS"

Buni ko'rsatadi:

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

Quyida so'rovlarga o'rtacha javob vaqtlari keltirilgan:

belgi

o'rtacha

Media

90% chiziq

95% chiziq

99% chiziq

min

Max

ol.Employee

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

patchXodim

161.42

83.29

308

492.57

1845.14

5

6639.4

ish haqi

167.21

86.93

315.34

501.07

1927.12

7

6722.44

Ushbu sintetik natijalarga ko'ra, ushbu VPS sizning aniq vazifalaringiz uchun qanchalik mos ekanligini aniqlash siz uchun qiyin bo'lishi mumkin va umuman olganda, sanab o'tilgan usullar biz u yoki bu shaklda hal qilishimiz kerak bo'lgan holatlar bilan cheklangan. to'liq emasligi aniq. Biz sizni o'zingizning xulosalaringizni chiqarishga va serverni haqiqiy ilovalaringiz va vazifalaringizga 30 rublga sinab ko'rishni taklif qilamiz va sharhlarda ushbu konfiguratsiya uchun variantlarni taklif qilamiz.

Manba: www.habr.com

a Izoh qo'shish