Страницы

Свой мессенджер, Не слабо!

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

   24 июля 2016 исторический день. Мы "на воздухе" обменялись сообщениями. Скринов первых публикаций не остались (потому что я пью стауты и он лагеры), потому покажу другие. 



   Что сказать, работы еще полным полно, до состояния конечного продукта еще очень далеко, но уже есть о чем говорить. Будем строить компанию, будем развиваться. (Потому как одному такие проекты конечно делать очень сложно)

Но вот, начнет мой ворчливый читатель и повторит мои же слова, сказанные несколькими месяцами ранее. Ну сколько можно. Ты же не сможешь победить Viber и WhatsUp. 
Нет! На этом поле не смогу. И не буду!

Все потому, что это не мессенджер вовсе. Я буду говорить про другое. Мессенджер - так, занятный артефакт, с которого можно начинать разговор. Разговор про удаленные и безопасные рабочие места и много еще про что. Даже в мессенджерах полно того, что я бы хотел для себя иметь. 

Все, замолкаю, ибо это - дела будущего и темы других публикаций.



Как интересно!
Гугл будет стримить облачные приложения, фактически используя парадигму терминальных решений (Citrix, NoMachine, etc.)

А ведь я в рамках Kalpa.Cloud догадался до логического стриминга. Когда на сторону клиента передаются не картинки.


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

Возвращение блудного пользователя (меня)

tumblr конечно прикольная штука. Но, несмотря на все фокусы с search console, индексирование страниц происходит крайне плохо. В поисковых системах статьи не появляются. А если и появляются, то со ссылкой на главную страницу, которая конечно уже не актуальна.

Хоть не очень blogger.com удобен и весел, но в поисковике гугла виден. И, кстати, что удивительно, хотя весь блогер в Китае закрыт, мои страницы видны. Надо думать ВКФ блокирует по dns.

Технические заметки будут в spirit.kalpa.ru

Наше технологическое.

Вот скажите! Как с этим жить.

Много много лет, для отслеживания разрывов соединений и восстановления связи, я использовал старый, известный способ - подправить параметры KeepAlive непосредственно для гнезда. Это работало много лет. Взялся подпереписать кусок с восстановлением связи.
И что вы думаете? Не работает. Ядро 4.0.5 на сервере. Линуксы и винды клиенты в virtualbox.

#ifdef Q_OS_LINUX
    int ka=1;

    if(setsockopt(mSocket->socketDescriptor(), SOL_SOCKET, SO_KEEPALIVE,
                  &ka, sizeof(ka))<0)
        ConsoleError()<<"Error setsockopt SOL_SOCKET, SO_KEEPALIVE";


    if(setsockopt(mSocket->socketDescriptor(), IPPROTO_TCP, TCP_KEEPIDLE,
                  &KeepAlive, sizeof(KeepAlive))<0)
        ConsoleError()<<"Error setsockopt IPPROTO_TCP, TCP_KEEPIDLE";

    if(setsockopt(mSocket->socketDescriptor(),IPPROTO_TCP, TCP_KEEPCNT,
                  &Count, sizeof(Count))<0)
        ConsoleError()<<"Error setcoskopt IPPROTO_TCP, TCP_KEEPCNT";

    if(setsockopt(mSocket->socketDescriptor(), IPPROTO_TCP, TCP_KEEPINTVL,
                  &Interval, sizeof(Interval))<0)
        ConsoleError()<<"Error setcoskopt IPPROTO_TCP, TCP_KEEPINTVL";

#endif


Вот этот текст прост и понятен. Не работает!
И у меня нет времени на многодневные исследования модуля на разных линуксах и разных ядрах. Просто нет. Естественно, желания менять системные настройки KeepAlive для всей машины у меня нет совершенно. 
А потом выяснится, что они в ядре какую-то штуку новую придумали. 
Но, блин, setsockopt!!! Как же так?!

----->
Походе дело именно в virtualbox. Народ оказывается давно на это жалуется. Правда дело в режиме nat, а я пробую в режиме bridge. Все одно.
Какое малопродуктивное занятие - искать ошибки еще и у других.

Насущное. (или асинхронность в базах)

Все наверное слышали (из предыдущих сообщений) что я пытаюсь захватить мир (не привлекая внимание санитаров) через создание большой отказоустойчивой системы в недрах которой будет крутиться много очень разных полезных человеку задач.
Проблема обеспечения отказоустойчивости и способности выносить значительные нагрузки всегда была серьезным вызовом и в различных системах всегда решалась особо. 

В заметке http://oleg.kalpa.ru/2015/02/3-databasecell.html говорилось об уровне 3 где живут базы данных. Про отказоустойчивость я бы хотел поговорить чуть позже, а сейчас хочу подумать об асинхронности. 

Вот Postgres и средства работы с ним - синхронен. Это значит, что когда вы отправляете запрос на сервер, то приходится сидеть и ждать ответа. А у меня в системе куча служб, которые живут на куче машин и обмениваются мыслями в тайне от внешнего мира. Значит нужна асинхронность в вопросе работы с базой данных. Значит нужно такую  службу учинить. 

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

Сказано-сделано. Тестирование показало, что асинхронный круг запроса на внешный сервер баз + запрос к прогретой базе (а это еще один сервер) оборачивается за 1 мс. Фактически замерялась связка клиент-сервер приложения-асинхронный сервер баз+postgres. 
Так что можно сказать, что протокол взаимодействия вполне рабочий.

Готов к следующему шагу.



«Косвенно тезисы Сноудена подтверждает опрос IT-специалистов, проведенный нами в конце 2014 года. 46% респондентов сообщили, что потеря их мобильного устройства и последующая кража корпоративной информации из его памяти подвергнут риску их компании», — сообщил «Газете.Ru» Оськин.
 А я в рамках проекта KalpaCloud давно именно об этом и говорил. Основа безопасности лежит в архитектуре программных систем.
Вы построили мир на вебе, публичной почте. Вы гоняете данные на сторону клиента, которые хранятся во внутренних кешах браузера.
Что же вы еще хотите? Безопасности?

Сравнение WiredTiger c Postgres (домашний тест)

Когда говорят интересно и показывают фигуры о прекрасном всегда хочется почесать затылок и понять что же есть на самом деле. Не скрою, я весьма воодушевился сообщением о выходе мотора баз данных WiredTiger. Он, как говорят, настолько хорош, что его взяли на вооружение в MongoDB.

Значит надо проверить.

Учинил простой тест. Создается таблица из двух полей. Ключ - строка, значение- строка. Ключ, понятное дело, primary key. Для поля "value" строится индекс. В варианте с Pg получается два индекса. (Как рулит первичным ключем  WT еще надо разбираться. Но фактически  WT создает только 2 файла а Pg 3(один с данными и 2 с индексами. Значит Pg будет оперировать собственно таблицей и двумя индексами, что всяко сложно)
Добавляемые строки - случайные UUID

В WT создание таблицы выглядит вот так.

ret = session->create(session, "table:access", key_format=S,value_format=S,columns=(key, value)");
ret = session->open_cursor(session, "table:access", NULL, NULL, &cursor);
session->create(session, "index:access:value", "columns=(value)");
Тест для Wt
QTime tm;
    tm.start();
    for(int i=0; i<1000000 font="" i="" nbsp="">{
        QByteArray keyarray=QUuid::createUuid().toString().remove('{').remove('}').toLocal8Bit();
        QByteArray valuearray=QUuid::createUuid().toString().remove('{').remove('}').toLocal8Bit();
        cursor->set_key(cursor, keyarray.data());
        cursor->set_value(cursor, valuearray.data());
        ret = cursor->insert(cursor);
   
    }
 

  qDebug()<<"Insert million of pairs"<

Тест для Pg
 for(int i=0; i<1000000 br="" i="" nbsp="">            Command.prepare("insert into test(id, value) values(:id, :value)");
            Command.bindValue(":id",    QUuid::createUuid().toString());
            Command.bindValue(":value", QUuid::createUuid().toString());
            Command.exec();
             }
WT использует отложенную модель записи, потому в PG отключим fsync.


Запускаем тест несколько раз и замерим время работы процедуры на пространстве возрастающих данны По итогу пяти прогонов для WiredTiger получил такие результаты в секундах
  1. 97    (Круто)
  2. 316  (Прилично)
  3. 743
  4. 1188
  5. 2193
Для Postgres получил
  1. 500
  2. 690
  3. 1000
  4. 1196
  5. 955
На пятом миллионе WT скис окончательно спустившись до 2193 секунд. При этом Postgres дает стабильные и прогнозируемые результаты.
Давайте не будем забывать, что WiredTiger это ядро, менеджер записей, а Postgres - полновесная база данных со всем набором вытекающих из этого сложностей.

Для очистки совести я добавил шестой миллион записей в Pg в одной транзакции. Получил результат 611.
Честно не очень понимаю что за фигуры показывают на презентации свидетели Wt и Mongo. 

Вывод. Конечно я не великий спец в тестировании и со своими драными лаптями зря полез в эту тему, но мне все же кажется, что лучшее - враг хорошего.потому, сижу спокойно на Postgresql иногда поглядывая на новомодные штуки.

WiredTiger. Просто взгляд.[update]

Открыл для себя  WiredTiger. Говорят это очень крутой NoSql мотор, который начали использовать в MongoDb. Решил попробовать и я, для чего прям из примера написал программку.


    WT_CONNECTION *Volume1Connection;
    //    WT_CONNECTION *Volume2Connection;
    WT_CURSOR *cursor;
    WT_SESSION *session;
    const char *key, *value;
    int ret;

    if ((ret = wiredtiger_open("./Volume", NULL, "create", &Volume1Connection)) != 0 ||
            (ret = Volume1Connection->open_session(Volume1Connection, NULL, NULL, &session)) != 0)
    {
        fprintf(stderr, "Error connecting to %s: %s\n",
                ".", wiredtiger_strerror(ret));
    }

    ret = session->create(session, "table:access", "key_format=S,value_format=S");
    qDebug()<<ret;
    ret = session->open_cursor(session, "table:access", NULL, NULL, &cursor);

    QHash<QUuid, QUuid> TempArray;
    for(int i=0; i<10; i++)
        TempArray.insert(QUuid::createUuid(), QUuid::createUuid());


    QHashIterator<QUuid, QUuid> i(TempArray);
    while (i.hasNext())
    {
        i.next();
        qDebug()<< i.key() << ": " << i.value();

        cursor->set_key(cursor,  i.key().toString().remove('{').remove('}').toLocal8Bit().data());        /* Insert a record. */
        cursor->set_value(cursor,i.value().toString().remove('{').remove('}').toLocal8Bit().data());
        ret = cursor->insert(cursor);
    }

    ret = cursor->reset(cursor);            /* Restart the scan. */
    while ((ret = cursor->next(cursor)) == 0)
    {
        cursor->get_key(cursor, &key);
        cursor->get_value(cursor, &value);
        printf("Got record: %s : %s\n", key, value);
    }

    i.toFront();
    while (i.hasNext())
    {
        i.next();
        qDebug()<< i.key() << ": " << i.value();
        cursor->set_key(cursor, i.key().toString().remove('{').remove('}').toLocal8Bit().data());
        const char* val;
        if(cursor->search(cursor)==0)
        {
            cursor->get_value(cursor, &val);
            qDebug()<<"---- key"<<i.key()<<"value from base"<<val;
        }
        else
            qDebug()<<"key not found";
        //cursor->search()
    }

    cursor->close(cursor);
    ret = Volume1Connection->close(Volume1Connection, NULL);


    quit();

В результате прогона программки получаем в базе мусор. Я как-то к этому не привык. Да и не хочется верить в то, что мотор не работает.
Конечно это я где-то что-то делаю не так.
Кто знает! Кто пробовал! Подсобите!
_______________
Разбрался. Строки для передачи курсору надо много тщятельней готовить принимая во внимание особенности api.
Должен отметить, что это очень интересный инструмент. И хоть я и готов даже говорить о замене существующего (пусть и неспешного) комфорта постгреса, но явно использовать в некоторых местах буду.
Ну а там, видно будет.

Уровень 3 (DatabaseCell)

   На этом уровне располагаются системы хранения данных. Это выделенные серверы баз данных, которые работают с системой по собственному протоколу и доступны только службам второго уровня.
Использую Postgres. Но, разумеется, куда без проблем и вопросов. Например, он не умеет работать с асинхронными запросами. А асинхронность в таких больший больших системемах - самая главная штука.

Потому был написан небольшой многопоточный серверок, который

  • Работает в качестве пула соединений
  • Запускает запрос в фон и по завершении информирует удаленный процесс и передает ему результаты.

Как обрабатывать огромные массивы данных? Прежде всего не надо эти огромные массивы создавать, не надо их хранить в огромных таблицах и не надо думать как эти таблицы горизонтально размазывать по серверам.

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

   К примеру,
  • каждый пользователь имеет отдельную зону системной информации, отдельную зону для обработки комментариев и сообщений. 
  • На уровне почтовых адресов каждый район населенного пункта имеет отдельную зону. 
  • На уровне задачи прогнозов в отдельную зону выделен каждый отдельный тип прогнозируемых событий. 
  • На уровне задачи ЖКХ, в отдельную зону выделен каждый дом.
  • Хранилища консолидированных данных также выделены в отдельные зоны. 
Конечно большое число таблиц и схем постгресу не нравится и я это прекрасно понимаю, но за возможность быстрой миграции томов и хранилищ надо чем-то платить.

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

Поддержка целостности записей, проблемы репликации и восстановления деградирующих после сбоя роев данных, лежит на плечах серверов 2 уровня(EntityServers), которые при работе с серверами данных самостоятельно принимают решение о тактике распределения данных и о сценариях их восстановления ( Об этом поговорим потом).
В более общем виде рой EntityServer уровня 2 может читать данные из всей совокупности обрабатываемых в задаче серверов данных (если надо конечно).

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

Следует отметить, что для всех машин 2 и 3 уровней надо применять стратеги географического распределения. Это значит, что при достаточной развитости дата-центра(ов) вторая реплика роя будет располагаться на машине в другом шкафу, третья в другом дата-центре.
Благодаря высокой степени стратификации  процесс реконфигурации массива данных будет проходить быстро и максимально незаметно для конечного пользователя и способен обработать огромные массивы данных.
Related Posts Plugin for WordPress, Blogger...