LINUX.ORG.RU
решено ФорумTalks

Выдержит ли SQLite нагрузку уровня linux.org.ru?

 ,


0

3

всем привет я пишу сайт на пхп четыре (из-за pdo это пока не получается, поэтому если есть замена pdo для работы с различными бд — подскажите)

главная фича моего движка в простой кодовой базе, в которой разберётся любой начинающий программист на html, css и php

есть поддержка виртуальных хостов. один движок может обслуживать сколько угодно сайтов, у каждого сайта может быть свой индивидуальный дизайн, при этом у них единая база данных с сообщениями и пользователями. например, на одном движке можно вести несколько сайтов, а затем «на лету» их смержить в один, объеденив область видимости нескольских сайтов в один, либо же наоборот, если проект разрастается и условная тема про собачек на сайте котиков набирает популярность — сайт можно раздробить на два, один про кошечек, второй про собачек, при этом пользователям не придётся создавать новые аккаунты на втором сайте.

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

все сообщения на сайте — как статьи на википедии, или как сообщения на ЛОРе, могут редактироваться сколько угодно раз и хранить всю историю изменений. весь ключевой вопрос лишь в том, способен ли выдержать SQLite такую нагрузку, или же придётся смотреть в сторону другой базы данных???

пользователи могут создавать сколько угодно аккаунтов и логиниться под разными аккаунтами, а затем переключаться между ними. считаю это прикольным.

у меня своя собственная реализация сессий, которая никак не связана со встроенными сессиями на пхп и никак их не использует. то есть session_*(); и $_SESSION не задействуются. моя реализация позволяет более тонко контролировать все нюансы, например, не создавать пустую сессию «в холостую», или например точно определить, что в папке на диске достаточно места для хранения данных сессии.

вот пример базы данных для сообщений. они хранят всю историю изменений.

CREATE TABLE IF NOT EXISTS 'post'
(
	'id' INTEGER PRIMARY KEY,
	'domain' NVARCHAR(255) DEFAULT NULL,
	'sub_reply' INTEGER DEFAULT NULL,
	'date_created' DATETIME DEFAULT CURRENT_TIMESTAMP,
	'date_modified' DATETIME DEFAULT NULL,
	'flags' NVARCHAR(200) DEFAULT NULL
);

CREATE TABLE IF NOT EXISTS 'post_history'
(
	'id' INTEGER PRIMARY KEY,
	'sub_post' INTEGER NOT NULL,
	'ref_text' INTEGER NOT NULL,
	'date_created' DATETIME DEFAULT CURRENT_TIMESTAMP,
	'date_modified' DATETIME DEFAULT NULL
);

CREATE TABLE IF NOT EXISTS 'post_text'
(
	'id' INTEGER PRIMARY KEY,
	'text' TEXT DEFAULT NULL,
	'text_headers' TEXT DEFAULT NULL
);

сам текст сообщений хранится отдельно в третьей таблице, это сделано потому, что у каждой базы данных (конкретно у MySQL и PostgreSQL) на этот счёт разное мнение. кто-то хранит TEXT и BLOB далеко за пределами основной таблицы, чтобы минимизировать нагрузку при выборке из базы, а кто-то хранит там же рядышком. правильнее будет хранить TEXT отдельно. поэтому храню.

я не осилил ООП и не смог написать на классах, поэтому я писал на функциях, и я их назвал неклассами.

в папочке ./src/noclass/ у меня лежат следующие неклассы.

database.noclass.php:

<?php

function db_directory_sqlite() {
    return dirname($_SERVER['DOCUMENT_ROOT']) . '/db';
}

function db_connect($db_dsn = null, $db_username = null, $db_password = null, $db_attributes = null) {

    $db = false;

    if (strpos($db_dsn, 'sqlite:') == 0) {
        $db_file = substr($db_dsn, strlen('sqlite:'));
        if ($db_file == ':memory:') {
            $db = true;
        }
        elseif (is_writeable(db_directory_sqlite())) {
            $db = true;
        }
    }

    if ($db == false) {
        return false;
    }

    $db = db_connect_retry($db_dsn, $db_username, $db_password, $db_attributes);

    return $db;

}

function db_connect_retry($db_dsn, $db_username, $db_password, $db_attributes) {

    $db = false;

    while ($db == false) {
        try {
            $db = new PDO($db_dsn, $db_username, $db_password, $db_attributes);
        }
        catch (Exception $e) {
            if (stripos($e->getMessage(), 'DATABASE IS LOCKED')) {
                usleep(50000);
                continue;
            }

            return false;
        }
    }

    return $db;

}

function db_open_sqlite_in_memory() {
    $db_file = false;
    $db_dsn = 'sqlite::memory:';

    $db = db_connect($db_dsn);

    return $db;
}

function db_open_sqlite($db_file) {

    if ($db_file == ':memory:') {
        $db = db_open_sqlite_in_memory();

        return $db;
    }

    $db_dsn = 'sqlite:' . $db_file;

    $db = db_connect($db_dsn);

    return $db;
}

function db_open($db_dsn) {
    $db = db_open_sqlite($db_dsn);

    return $db;
}

function db_exec($db, $query_string) {
    $query = $db->exec($query_string);

    return $query;
}

function db_query($db, $query_string) {
    $query = $db->query($query_string);

    return $query;
}

function db_run($db, $query_string, $query_args = false) {
    if ($query_args == false) {
        $query = db_query($db, $query_string);

        return $query;
    }

    $query = $db->prepare($query_string);
    $query->execute($query_args);

    return $query;
}

function db_begin_transaction($db) {
    $query = $db->beginTransaction();

    return $query;
}

function db_is_transaction($db) {
    $query = $db->inTransaction();

    return $query;
}

function db_rollback($db) {
    $query = $db->rollBack();

    return $query;
}

function db_commit($db) {
    $query = $db->commit();

    return $query;
}

function db_last_id($db) {
    $query = $db->lastInsertId();

    return $query;
}

function db_insert($db, $table, $values) {

    $keys = array_keys($values);

    $values = array_values($values);

    $columns = array();
    foreach ($keys as $item) {
        $columns[] = "'$item'";
    }
    $columns = implode(',', $columns);

    $placeholders = array();
    foreach ($keys as $item) {
        $placeholders[] = "?";
    }
    $placeholders = implode(',', $placeholders);

    $query = "INSERT INTO $table ($columns) VALUES ($placeholders);";

    $query = db_run($db, $query, $values);

    return $query;

}

function db_update($db, $table, $value, $where) {

    $collection = array_merge($value, $where);
    $collection = array_values($collection);

    $fields = array();
    foreach ($value as $item => $data) {
        $fields[] = "$item = ?";
    }
    $fields = implode(',', $fields);

    $places = array();
    foreach ($where as $item => $data) {
        $places[] = "$item = ?";
    }
    $places = implode(' AND ', $places);

    $query = "UPDATE $table SET $fields WHERE $places;";

    $query = db_run($db, $query, $collection);

    return $query;

}

function db($db_name) {
    $db_file = db_directory_sqlite() . DIRECTORY_SEPARATOR . $db_name;

    $db = db_open($db_file);

    return $db;
}

post.noclass.php:

<?php

function post_insert($text_headers, $text, $replyto = false) {

    $db = db('example.db');

    if ($db == false) {
        return false;
    }

    db_begin_transaction($db);

    if (db_post_insert($db, $text_headers, $text, $replyto)) {

        db_commit($db);

        return true;

    }

    db_rollback($db);

    return false;

}

function db_post_insert($db, $text_headers, $text, $replyto = false) {

    if ($replyto == false) {

        $id = db_post_insert_id($db);

        if ($id == false) {
            return false;
        }

    }
    else {

        $replyto = db_post_select_id_single($db, $replyto);

        if ($replyto == false) {
            return false;
        }
        else {

            $id = db_post_insert_id($db);

            if ($id == false) {
                return false;
            }

        }
 
    }

    if (db_post_insert_post($db, $id, $replyto)) {

        $ref_text = db_post_insert_post_text($db, $text_headers, $text);

        if ($ref_text == false) {
            return false;
        }

        if (db_post_insert_post_history($db, $id, $ref_text)) {
            return $id;
        }

    }

    return false;

}

function db_post_insert_id($db) {

    $value = array(
        'id' => null
    );
    
    db_insert($db, 'post', $value);

    return db_last_id($db);

}

function db_post_select_id_single($db, $id) {

    $value = array(
        'id' => $id
    );
    
    $query = 'SELECT id FROM post WHERE id = :id;';

    $query = db_run($db, $query, $value);

    $row = $query->fetch();

    return ($row == false) ? false : $row['id'];

}

function db_post_insert_post($db, $id, $replyto = false) {

    $date_created = date('Y-m-d H:i:s', time());
    $date_modified = null;

    $search = array(
        'id' => $id
    );
    
    $entry = array(
        'id' => null,
        'domain' => null,
        'sub_reply' => $replyto,
        'date_created' => $date_created,
        'date_modified' => $date_modified,
        'flags' => null
    );

    // remove false, null and other zero-values from entry
    $entry = array_filter($entry);

    if (db_update($db, 'post', $entry, $search)) {
        return $id;
    }

    return false;

}

function db_post_insert_post_text($db, $text_headers, $text) {

    if ($text_headers == false) {
        //nothing to do -- skip headers
    }
    else {
        $text_headers = serialize($text_headers);
    }

    $entry = array(
        'id' => null,
        'text' => $text,
        'text_headers' => $text_headers
    );

    // remove false, null and other zero-values from entry
    $entry = array_filter($entry);

    if (db_insert($db, 'post_text', $entry)) {
        return db_last_id($db);
    }

    return false;

}

function db_post_insert_post_history($db, $sub_post, $ref_text) {

    $date_created = date('Y-m-d H:i:s', time());
    $date_modified = null;

    $entry = array(
        'id' => null,
        'sub_post' => $sub_post,
        'ref_text' => $ref_text,
        'date_created' => $date_created,
        'date_modified' => $date_modified
    );

    // remove false, null and other zero-values from entry
    $entry = array_filter($entry);

    if (db_insert($db, 'post_history', $entry)) {
        return db_last_id($db);
    }

    return false;

}

function db_post_select_count($db) {

    $query = db_query($db, 'SELECT COUNT(*) as sizeof FROM post;');

    $row = $query->fetch();

    return $row['sizeof'];

}

function post_update($id, $text_headers, $text) {

    $db = db('example.db');

    if ($db == false) {
        return false;
    }

    db_begin_transaction($db);

    if (db_post_update($db, $id, $text_headers, $text)) {

        db_commit($db);

        return true;

    }

    db_rollback($db);

    return false;

}

function db_post_update($db, $id, $text_headers, $text) {

    $id = db_post_select_id_single($db, $id);

    if ($id == false) {
        return false;
    }

    if (db_post_update_post($db, $id)) {

        $ref_text = db_post_insert_post_text($db, $text_headers, $text);

        if ($ref_text == false) {
            return false;
        }

        if (db_post_insert_post_history($db, $id, $ref_text)) {
            return $id;
        }

    }

    return false;

}

function db_post_update_post($db, $id) {

    $date_created = null;
    $date_modified = date('Y-m-d H:i:s', time());

    $search = array(
        'id' => $id
    );
    
    $entry = array(
        'id' => null,
        'domain' => null,
        'sub_reply' => null,
        'date_created' => $date_created,
        'date_modified' => $date_modified,
        'flags' => null
    );

    // remove false, null and other zero-values from entry
    $entry = array_filter($entry);

    if (db_update($db, 'post', $entry, $search)) {
        return $id;
    }

    return false;

}

function db_post_select_id($db, $id = false) {

    if ($id == false) {
        return false;
    }

    $value = array(
        'id' => $id
    );

    $query = '
SELECT * FROM post
INNER JOIN post_history AS initial ON (initial.sub_post = post.id AND initial.id = (SELECT id FROM post_history WHERE sub_post = post.id ORDER BY id ASC LIMIT 1))
INNER JOIN post_history AS current ON (current.sub_post = post.id AND current.id = (SELECT id FROM post_history WHERE sub_post = post.id ORDER BY id DESC LIMIT 1))
INNER JOIN post_text ON post_text.id = current.ref_text
WHERE post.id = :id
';

    $query = db_run($db, $query, $value);

    $row = $query->fetch();

    $row = post_row($row);

    return $row;

}

function db_post_select_page($db, $page = false, $limit = 10) {

    $pages = (db_post_select_count($db) / $limit);
    $pages = ceil($pages);

    if ($page == false) {
        $page = $pages;
    }
    elseif ($page > $pages) {
        $page = $pages;
    }
    elseif ($page < 1) {
        $page = $pages;
    }

    $offset = ($page - 1) * $limit;

    // should I make it more stronger?
    // escape offset and limit
    $query = '
SELECT * FROM post
INNER JOIN post_history AS initial ON (initial.sub_post = post.id AND initial.id = (SELECT id FROM post_history WHERE sub_post = post.id ORDER BY id ASC LIMIT 1))
INNER JOIN post_history AS current ON (current.sub_post = post.id AND current.id = (SELECT id FROM post_history WHERE sub_post = post.id ORDER BY id DESC LIMIT 1))
INNER JOIN post_text ON post_text.id = current.ref_text
ORDER BY id DESC LIMIT ' . $limit . ' OFFSET ' . $offset . ';
';

    $query = db_query($db, $query);

    $array = array();

    while ($row = $query->fetch()) {

        $array[] = post_row($row);

    }

    return $array;

}

function post_row($row) {

    if ($row == false) {
        return false;
    }

    if ($row['date_created'] == null) {
        $row['date_created'] = '(unavailable)';
    }

    if ($row['date_modified'] == null) {
        $row['date_modified'] = '(unavailable)';
    }

    if (empty($row['text_headers'])) {
        $row['text_headers'] = array();
    }
    else {
        $row['text_headers'] = unserialize($row['text_headers']);
    }

    if (empty($row['text_headers']['title'])) {
        $row['text_headers']['title'] = '';
    }

    return $row;

}

function post_escape($text) {

    $text = htmlspecialchars($text, ENT_NOQUOTES, 'UTF-8');
    $text = nl2br($text);

    return $text;

}

function post_input_filtered($text) {

    $text = htmlspecialchars($text, ENT_QUOTES, 'UTF-8');

    return $text;

}

function post_text_filtered($text) {

    $text = htmlspecialchars($text, ENT_NOQUOTES, 'UTF-8');

    return $text;

}

session.noclass.php

<?php

function session_directory() {
    return dirname($_SERVER['DOCUMENT_ROOT']) . DIRECTORY_SEPARATOR . 'db' . DIRECTORY_SEPARATOR . 'sess';
}

function session_open($session_name = 'ident') {

    $session_id = session_open_if_cookie_is_set($session_name);

    if ($session_id == false) {
        $session_id = session_new($session_name);
    }

    return $session_id;

}

function session_open_if_cookie_is_set($session_name = 'ident') {

    if (isset($_COOKIE[$session_name])) {
        $session_id = $_COOKIE[$session_name];

        if (strlen(str_replace(array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'), '', $session_id)) > 0) {
            $session_id = session_new($session_name);
        }

        return $session_id;
    }

    return false;

}

function session_load($session_id) {

    $session_file = session_directory() . DIRECTORY_SEPARATOR . $session_id;
    $session_data = false;

    if ($fp = @fopen($session_file, 'r')) {
        flock($fp, LOCK_SH);
        $session_data = fread($fp, filesize($session_file));
        $session_data = unserialize($session_data);
        flock($fp, LOCK_UN);
        fclose($fp);
    }

    if (is_array($session_data)) {
        return $session_data;
    }

    return array();

}

function session_save($session_id, $session_data = array()) {

    $session_file = session_directory() . DIRECTORY_SEPARATOR . $session_id;
    $session_data = serialize($session_data);

    if ($fp = @fopen($session_file, 'w+')) {
        flock($fp, LOCK_EX);
        $bytes_written = fwrite($fp, $session_data);
        flock($fp, LOCK_UN);
        fclose($fp);
    }

    return $bytes_written;

}

function session_new($session_name) {

    if (headers_sent()) {
        return false;
    }

    $session_id = bin2hex(session_random_bytes(8));

    $cookie_lifetime = 0;
    $cookie_path = '/';
    $cookie_domain = '';
    $cookie_secure = false;
    $cookie_httponly = false;

    if (setcookie($session_name, $session_id, $cookie_lifetime, $cookie_path, $cookie_domain, $cookie_secure, $cookie_httponly) == false) {
        return false;
    }

    return $session_id;

}

function session_random_bytes($length = 32) {
    
    $random_bytes = '';

    for ($i = 0; $i < $length; $i++) {
        $random_bytes .= chr(rand(0, 255));
    }

    return $random_bytes;

}

function session() {

    $id = session_open();

    if ($id == false) {
        return false;
    }

    $session = session_load($id);

    return $session;

}

вот вам небольшая инструкция как использовать сессии

вы просто делаете $session = session(); и создаётся новая сессия и в переменную $session загружается массив со всеми данными сессии.

если вы хотите что-то сохранить в сессию, то вы должны проделать все действия вручую:

// создаём новую сессию
// в $id помещается идентификатор сессии, ну типа PHPSESSID
$id = session_open();

// загружаем данные сессии в переменную $session
// можно для этого использовать $_SESSION но я не хочу и не буду
$session = session_load($id);

// создаём в $session приветствие
$session = array('greeting' => 'hello world!');

// сохраняем данные сессии, за вас это никто не сделает
session_save($id, $session);

есть такой забавный момент, когда мы не хотим создавать сессию, если у пользователя её нету. для этого есть функция session_open_if_cookie_is_set();, которая запускает сессию только при наличии куки.

в целом моя реализация сессий лучше пхпшной т.к. она не создаёт пустых файлов!!! каждый момент вы контролируете сами!!!

теперь давайте я вам расскажу про сообщения а-ля википедия или лор.

для отправки сообщения я делаю так:

$headers = array(
    'title' => 'заголовок письма'
);

$content = 'текст письма';

post_insert($headers, $content);

как вы знаете у сообщения есть не только его содержимое, не только сам текст сообщения. у сообщения есть мета-данные, такие как заголовок, тэги, ну ещё что-нибудь может быть. поэтому все эти мета-данные помещаются в отдельный массив.

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

функция post_insert(); вернёт просто true в случае узбека. иначе false.

для того, чтобы отредактировать сообщение, есть функция post_update();, но первым параметром ещё нужно указать ID сообщения.

например мы только что добавили сообщение, его ID 1, теперь мы хотим его отредактировать.

$id = '1';

$headers = array(
    'title' => 'заголовок письма (отредактировано)'
);

$content = 'исправленный текст письма';

post_update($id, $headers, $content);

и теперь в базу будет сохранена новая версия сообщения.

выполняем sqlite example.db .dump и смотрим

INSERT INTO post VALUES(1,NULL,NULL,'2022-07-17 06:24:55','2022-07-17 06:25:26',NULL);

INSERT INTO post_history VALUES(1,1,1,'2022-07-17 06:24:55',NULL);
INSERT INTO post_history VALUES(2,1,2,'2022-07-17 06:25:26',NULL);

INSERT INTO post_text VALUES(1,'текст письма','a:1:{s:5:"title";s:31:"заголовок письма";}');
INSERT INTO post_text VALUES(2,'исправленный текст письма','a:1:{s:5:"title";s:64:"заголовок письма (отредактировано)";}');

по факту сообщение одно, а ревизии у него две! так-то!

для того, чтобы прочитать сообщение в массив мы подключаемся к базе данных и выполняем одну функцию, указав ID сообщения

$db = db('example.db');

if ($db == false) {
    return false;
}

$post = db_post_select_id($db, $_GET['id']);

var_dump($post);

для того, чтобы вывести страницу со списком сообщений есть функция db_post_select_page($db, $_GET['page']);

в целом мой код будет очень хорошо документирован, но это чуть попозже, пока только реализация.

мой код написан очень качественно на совесть, писал для себя.

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

главный вопрос — выдержит ли такая структура базы данных на SQLite нагрузку с бесконечным редактированием сообщений???

★★★★★

главный вопрос — выдержит ли такая структура базы данных на SQLite нагрузку с бесконечным редактированием сообщений???

Можно сделать клиент – эмулятор нагрузки и проверить.

X512 ★★★★ ()

У sqlite3 два режима — rollback journal и write-ahead log. Почитай про особенности работы обоих. С некоторой ощутимой нагрузкой на запись возможно лучше подойдёт wal.

PolarFox ★★★★★ ()
Ответ на: комментарий от Clayman

Создает новый Google, не иначе. Успешный московский парень :)

sanyo1234 ()

всем привет я пишу сайт на пхп четыре

«Medic!»

gremlin_the_red ★★★★★ ()
Ответ на: комментарий от X512

А чего спрашивать? Выдержит ли скулайт высокую мультипоточную нагрузку? Очевидно, нет. Для этого существуют субд. Какой-то тупой вопрос.

А вот зачем бесплатно писать движок сайта на пхп вопрос гораздо более насущный.

Clayman ()
Ответ на: комментарий от sanyo1234

Можно узнать, зачем ты это делаешь?

Как и все программисты, я - телепат, я знаю, но вслух произносить не буду, а то тред снесут. Сами догадывайтесь. 😛

xwicked ★★ ()
Ответ на: комментарий от Clayman

Очевидно, нет.

Во всех источниках в инете пишут, что до 100к запросов выдержвает легко, если больше, то лучше другая СУБД.

xwicked ★★ ()
Ответ на: комментарий от sanyo1234

здравствуйте

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

я делаю форк ЛОРа потому, что мою заявку в модераторы отклонили, — мне пояснили, что я не достоен ЛОРа, где я проводил каждый день последние дцать лет.

Spoofing ★★★★★ ()
Ответ на: комментарий от Spoofing

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

Так ведь ты хвастался, что теперь стал успешным московским железячным админом? Теперь даже хватит денег на курсы, чтобы обучиться на DevOps-а ? :)

я делаю форк ЛОРа потому, что мою заявку в модераторы отклонили, — мне пояснили, что я не достоен ЛОРа, где я проводил каждый день последние дцать лет.

Нагрузку где такую возмешь в 100K запросов? Сам будешь теребонькать свой сайт?

sanyo1234 ()
Последнее исправление: sanyo1234 (всего исправлений: 1)
Ответ на: комментарий от Spoofing

Движок лора открыт, зачем писать свой? Ты ниасилил java? Ставишь его на свой любимый крукс и сидишь смотришь на 0 посещений. Форков лора было уже штуки 3, туда уходили самые больные кликуши, но все они сдохли. Намекает.

untitl3d ()
Ответ на: комментарий от Psilocybe

IMHO Spoof - это какой-то фейковый акк, похожий на Шульмана.

На SQL.RU такие персонажи кратко назывались кодовым словом Поше :)

sanyo1234 ()
Последнее исправление: sanyo1234 (всего исправлений: 2)
Ответ на: комментарий от Spoofing

заявку в модераторы отклонили, — мне пояснили, что я не достоен ЛОРа

Не забанили же — значит, все еще достоин.

Nervous ★★★★★ ()

на одном движке можно вести несколько сайтов, а затем «на лету» их смержить в один

Не актуально. Это если и происходит, то раз в 10 лет. Никто не будет выбирать движок с расчётам на что-то через 10 лет. Все технологии к этому времени поменяются, либо автор, т.е. ты, к этому времени забьёт на поддержку этой фичи в движке и выпилит возможно разделять и мёржить сайты.

Движок будут выбирать по фичам, которые нужны вот прямо сейчас и каждый день. На этом нужно было сосредотачиваться.

ox55ff ★★★★★ ()
Ответ на: комментарий от sanyo1234

стал успешным московским железячным админом

всё так. через пару лет накоплю на кв. но этот факт никак не влияет на наличие второй половинки.

100K запросов

это нагрузка какая-то условная, я уверен, что имеется ввиду 100K INSERT'ов одной транзакцией.

потому что возьмём условный канал 100мбит, 100мбит это 12.5мбайт чистыми, но для чистоты эксперимента возьмём честные 10мбайт за вычетом всех TCP/IP заголовков.

так вот, 10мбайт это 10485760 байт, такова физическая пропускная способность ethernet-порта в идеальных условиях и отсутствия конкуренции со стороны других клиентов.

минимально-необходимый HTTP-запрос это

GET / HTTP/1.0 + CR + LF
Host: example.com + CR + LF
CR + LF

посчитайте, это 37 байт.

10485760 / 37 = 283398 запросов в секунду сможет отправить клиент.

но на минуточку, добавим сюда ещё User-Agent, Referer, Accept-*, Cookie заголовки.

F12 > Request Headers в моём браузере показывает что-то около 512 байт.

10485760 / 512 = 20480

в реальных полевых условиях на 100мбитном канале клиент сможет отправить на сервер лишь 20480 запросов и это будет уже фактически ддос канала, что никакой другой клиент не сможет достучаться до сервера.

фактически, если моя система управления сайтом на средней паршивости VPS сможет обрататывать 20480 запросов в секунду это будет абсолютная победа, — больше не имеет смысла, всё будет упираться в канал связи.

поэтому о каких именно 100к запросов в секунду идёт речь надо уточнять.

скорее всего, пишут об 100к INSERT'ах в базу данных одной транзакцией. это вот прям синтетика синтекикой.

живых это будет 20к запросов. так что нормально.

мой вопрос заключался скорее в большом объёме базы данных, сможет ли SQLite нормально ворочать условную базу в 50 гигов как на ЛОРе. чтобы запросы выполнялись так же быстро, в пределах одной секунды.

Spoofing ★★★★★ ()
Ответ на: комментарий от Spoofing

пишу свой сайт с нуля потому что у меня нет жены и нет детей, а девушки не хотят со мной встречаться

Какая-то очень странная логическая связь.

no-such-file ★★★★★ ()
Ответ на: комментарий от Spoofing

через пару лет накоплю на кв.

На взнос за первый кв. метр?

но этот факт никак не влияет на наличие второй половинки.

Запишись на курсы пикаперов.

мой вопрос заключался скорее в большом объёме базы данных, сможет ли SQLite нормально ворочать условную базу в 50 гигов как на ЛОРе. чтобы запросы выполнялись так же быстро, в пределах одной секунды.

Математика конечно отменная, но где ты возмешь такую аудиторию? Думаешь, мы сразу все ринемся к тебе, потому что нам Маском чем-то насолил? :)

sanyo1234 ()
Ответ на: комментарий от no-such-file

Какая-то очень странная логическая связь.

IMHO Spoof - это тролль, спецуха типа vaddd троллит под такими учетками, рекламируют Москву для понаехалов :) Это притом, что только ленивый не работает на удаленке.

Или Spoof записался в их клуб, и теперь один из них.

sanyo1234 ()
Последнее исправление: sanyo1234 (всего исправлений: 2)
Ответ на: комментарий от ox55ff

Движок будут выбирать по фичам, которые нужны вот прямо сейчас и каждый день. На этом нужно было сосредотачиваться.

This.

у меня в планах несколько проектов, под каждый проект создавать собственный виртуальный сервер (пусть даже бесплатный на локалхосте), под каждый проект деплоить ещё один WordPress, затем каждую из них поддерживать в отдельности, в каждую вкручивать фичи, мне кажется тут одним Ansible'ом даже не обойдёшься, чтобы тупо файлики зеркалировать.

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

это примерно тоже самое когда у вас 100500 серверов на линуксах и ведь каждый надо своевременно обновлять, поддерживать. но в отличии от серверов, сайты требуют ручного управления и индивидуального подхода. я этот момент сгруппировал как мог.

Spoofing ★★★★★ ()
Ответ на: комментарий от sanyo1234

Математика конечно отменная, но где ты возмешь такую аудиторию?

Нормальное состояние для новичка. Я тоже пилил cgi-скрипт(вы все видели) на С++ для разгадывания кроссвордов, чтобы нагрузку в 100500 запросов выдержал без повышения тарифа хостинга. Так что всё норм.

xwicked ★★ ()
Ответ на: комментарий от Spoofing

это примерно тоже самое когда у вас 100500 серверов на линуксах и ведь каждый надо своевременно обновлять, поддерживать. но в отличии от серверов, сайты требуют ручного управления и индивидуального подхода. я этот момент сгруппировал как мог.

Такой дорвейный талантище зря пропадает.

sanyo1234 ()
Ответ на: комментарий от sanyo1234

Запишись на курсы пикаперов.

Народ вы не понимаете. Изучите аюрведу. По энергетике человека определяется его конституция. Когда все 3 доши уравновешены, то и красота тела формируется идеальная, так как развивается максимальная скорость энергетики. Этот вихрь энергии и затягивает самок через глаза, даже когда они просто проходят мимо, то они сами хотят познакомиться, так как хотят получить б0льшую дозу этой энергии.
Обладатели капха-доши не имеют этой энергии и ему нужно сосредоточить все силы на изменение конституции тела для увеличения энергии. Только ему нужно будет 3-5 лет для этого и чтобы он чётко видел цель и знал что будет результат. Ваши пикапы работают только для определённого сочетания дош.

xwicked ★★ ()
Последнее исправление: xwicked (всего исправлений: 1)
Ответ на: комментарий от Spoofing

Поэтому и отклонили, что ты открыто демонстрируешь свою психологическую незрелость.

Модерилка тебе нужна ради компенсации недотраха, а не чтобы сайту помочь.

Порой не понятно где у тебя сарказм, а где реальность. Если вся твоя активность – это сублимация, а не искренний душевный порыв, то грош цена этому.

mono ★★★★★ ()

Нагрузку уровня linux.org.ru выдержит даже текстовый файл на 300-м селероне.

windows10 ★★★ ()

Спуф, не слушай никого.
Пиши код, а нагрузку и сам протестируешь.

imul ★★★★★ ()

Используй $_SESSION и MySQL, потому что их знают начинающие программисты PHP, к тому же для MySQL есть phpMyAdmin, и на шаред хостингах тоже. Еще $_SESSION можно через php.ini легко настраивать, перенести на Redis, а твои костыли-велосипеды? Это же PHP, используй его мощь, а не переделывай все заново, зачем тебе свои реализации сессий и шаблонизаторов? Лучше в обратную сторону упороться, и авторизацию передать apache2.

Зачем ты привязываешься конкретно к постам в своих функциях? Создай поверх MySQL свою виртуальную БД, где можно будет безболезненно добавлять новые колонки, удалять их, умно настраивать, и заодно к каждой виртуальной табличной сущности, можно будет использовать одну админ-страницу редактирования. Создай удобное API для работы с этими таблицами. И уже систему своих сообщений, постов, итд, сделаешь в виде плагина, который будет оперировать этими элементами виртуальной таблицы, добавит необходимые для постов поля если их нету, или будет настраиваться что бы добавлять поля которые по умолчанию отсутствуют.

Добавишь отдельно настройку для виртуальной таблицы, что бы хранить историю, или не хранить, это же полезно может быть не только для постов. А для много чего.

Кстати про шаблонизатор, его не используй, а используй ob_start. Подумай про кеширование, как ты его реализуешь? Я говорю не про использование Memcached, а про то как его можно сделать удобным, на БД его просто прицепить не выйдет, часто данные после получения из БД еще и обрабатываются сильно. Еще нужно будет кеш как то сбрасывать, например раз в час сбрасывать кеш всего неймспейса.

MOPKOBKA ★★ ()
Последнее исправление: MOPKOBKA (всего исправлений: 2)
Ответ на: комментарий от Spoofing

20480 запросов в секунду

1. это рендер / за 1/20480 секунды отданный пользователю?
2. а как ты разделяешь ддос от живых пользователей? что будет если тебя закроют syn flood-ом?
3. у тебя рендер всех, грубо говоря, роутов укладывается в 1/20480 секунды?

чтобы запросы выполнялись так же быстро, в пределах одной секунды.

если отталкиваться от IOPS, то RAM>SSD>HDD.
ну и плюс такие фичи как async io, pub sub, swarm, балансировка и прочии дево-псинные фишки

etwrq ★★★★★ ()

Возьмите Apache jMeter и нагрузите свой сайт. Там уже видно будет.

czan ()

А Ъ пацаны пишут на фортране.

peregrine ★★★★★ ()
Ответ на: комментарий от Spoofing

Это работа в никуда. Юзерам твой сайт/форум не нужен, там никого не будет. Программистам твоя CMS тоже не нужна будет, потому что PHP 4 (этого достаточно, не надо даже подробно разбирать сомнительные дизайнерские решения). Тебе он тоже не нужен по твоим словам, ты его пишешь просто со скуки.

Отвечая на твой вопрос

все сообщения на сайте — как статьи на википедии, или как сообщения на ЛОРе, могут редактироваться сколько угодно раз и хранить всю историю изменений. весь ключевой вопрос лишь в том, способен ли выдержать SQLite такую нагрузку, или же придётся смотреть в сторону другой базы данных???

— конечно сможет, даже с «редактироваться сколько угодно раз», потому как пользователей и нагрузки у тебя скорее всего не будет.

theNamelessOne ★★★★★ ()
Ответ на: комментарий от no-such-file

Нет, связь очень понятная. Я бы тоже занимался чем нибудь подобным если бы не депра.

eternal_sorrow ★★★★★ ()
Ответ на: комментарий от Spoofing

Земляк, запишись в зал и занимайся силовыми тренировками. Потом как доминант-самец будешь говорить: «Сиська у меня только одна, сосать будете по очереди», - а барышни в очередь за тобой выстроятся.

Hertz ★★★★★ ()

Можешь член сверху положить на sqlite, если повезет, выдержит.
Тем более на поцхп. Если бы у тебя было всё что угодно кроме, там можно было бы еще по выделываться с очередью, кэшами и периодическим сбросом на диск, с похапотой - нет, забудь.

crutch_master ★★★★★ ()
Последнее исправление: crutch_master (всего исправлений: 1)
Ответ на: комментарий от Spoofing

живых это будет 20к запросов. так что нормально.

Она у тебя встанет раком на 10-20 рандомных rqs, когда ты словишь какой-нибудь дедлок в своём похапе. Про то, что ты будешь делать, когда бд развалится, я вообще молчу.

crutch_master ★★★★★ ()
Последнее исправление: crutch_master (всего исправлений: 1)

Смех-смехом, но ты своим чудным постом закрашил хромиум на андроиде О_О

Anoxemian ★★★★★ ()

И вообще, ты это, взялся за пхп, когда уже подавляющему большинству давно понятно, что это - дерьма кусок. Пока все срались 10 лет назад по этому поводу, ты в сторонке стоял, а тут херак и, а не запилить ли мне свой форум на похапе?? slowpoke.png
А там еще всякие orm, фреймворки, cms, готовые движки, которые вообще давно мимо тебя проплыли.

crutch_master ★★★★★ ()
Последнее исправление: crutch_master (всего исправлений: 1)
Ответ на: комментарий от Spoofing

нет девушки - человечество (ненадолго) получит в свое распоряжение еще один говеный сайт

есть девушка - свадьба, спиногрызы, изнасилование мозга, побег в гараж (кстати, у тебя есть гараж? как нет? срочно покупай!) - еще один (никому не нужный) говеный сайт.

итого, касатик. как ни крутис без сайтика не обойтис. пиши, никого не слушай.

а бабы - ну чо бабы? как тебе, кстати, удается их избегать? они же везде! лайфхак в студию, крч.

olelookoe ★★ ()
Ответ на: комментарий от Spoofing

Ты вообще не о том думаешь. Пиши на SQLite и не дёргайся. Когда будешь разворачивать, то просто поменяешь connect options.

Oldboy ()
Ответ на: комментарий от Spoofing

сможет ли SQLite нормально ворочать условную базу в 50 гигов как на ЛОРе.

Нет, бери mysql и не выделуйся) И PHP7.

Ты думаешь твой проект кому-то пригодится? Он тебе пригодится, так как ты получишь новые знания, как с booty.

goingUp ★★★★★ ()
Последнее исправление: goingUp (всего исправлений: 2)
Закрыто добавление комментариев для недавно зарегистрированных пользователей (со score < 50)