Перейти к основному содержимому

AWS Gen AI meetup

· 2 мин. чтения

Visited Gen AI meetup organized by AWS. Strangely, the meetup had a "Chatham House Rule" so I'm not sure if I can reveal who talked about what.

neither the identity nor the affiliation of the speaker(s), nor that of any other participant, may be revealed

So I'll say that:

  • someone talked about high-level topics. Amazon-specific culture (like "Working backwards", "One-way door vs two-way door", "You build it, you own it"), some of their services, being customer-centric, gathering data, building AI organization. I was interested here in agents. Two things were mentioned - RUFUS (some sort of shopping assistant) and AWS Connect (or was it Agent Assist?) I got lost with names 🫣
    I liked the demo of an agent taking a call and answering a specific question. Having such transcript to have follow-up emails and analyze data later on is great. I once talked to an AI agent over the phone for 20 minutes and it was good experience too.

  • someone talked about business intelligence. Again cultural topic of "juniors can overrule seniors if they have the data" sounded logical. Gave a demo of querying data, getting graphs (Supersimple or Databricks came to my mind). I'm not sure it will be that viable with agents, I think they will be capable of querying data from my local machine. Amazon Q agent was mentioned, but nothing specific was shown so I suppose its still in development or wasn't fit for this meeting

  • someone talked about a sensitive topic. I may have misunderstood it. But it was about AI tracking news (to combat money laundering?), extracting relevancy to a specific topic. I was triggered that it may be used for AI surveillance, but who knows, maybe GDPR or AI Act is not applicable here. The workflow for processing data seemed complex and impressive though

And later in networking, I got to talk to a startup that is working on making onboarding for sales/GTM easier using AI.

AGI: Beyond the Hype, Before the Storm

· 6 мин. чтения

Visited another AI meetup on promoting Estonia as AI nation. After opening words from Vattan PS and Allan Martinson:

First talk from Linnar Viik about usage of OpenAI / Anthropic in education. I support it, AI is great at having student-tailored approach. There are however 2 dangers I see - model bias/ hallucinations in models and using closed API models as providers.

I think Estonian schools should use locally hosted models that are trained in collaboration with Estonian Ministry of Education and maybe Clarifai could help with that.

Second set of talks, was about local AI startups and their 5-min pitches from some of them: Askel.ai, Supersimple, Targum, Align (getalign.com), Forgemaster AI. I like Askel a lot, because its about agents and I'm very optimistic and bullish on that, using and building some myself.

I asked bunch of scary questions about agents and how they are going to distrupt their business, so Vattan banned me from scaring the panel speakers later on 😅

Finally, a panel discussion "AGI: Beyond the Hype, Before the Storm".

Decentralized AI event

· 4 мин. чтения

Just attended Decentralized AI event at TalTech organized by Astra Tikas and it was an inspiring evening that made me think and take some notes.

First, I think main motivation and problem defined was ownership. We are afraid that LLM models are not transparent on their architecture, training dataset. We are afraid of monopolies serving AI models. Monopolies that can deprecate models, inject own biases, political will and be a more serious way to control population. So instead of search engines and social networks creating a bubble effect, we may be brainwashed by AI. Or worse, give control over education, infrastructure or military, to unknown LLMs that can backfire without proper evaluation.

Secondly, I saw there is a lot of confusion about definition of decentralized AI. Seemed like every speaker saw it as a piece of a puzzle and had own impression of it. I see decentralized AI as layers and each one of those can be confused for true decentralized AI

  • distributed deployment - you have multiple devices instead of single machine
  • partition tolerant - AI nodes can go down and come back online
  • governance & ownership - it runs on machines owned by different people
  • open - you can see the source code, model weights, detailed research paper, trained dataset (but it may have custom license!)
  • offline-first and edge deployment - it can work offline on low-power device using local data
  • distributed state - if AI needs a global storage (that cannot be deleted at whim of some corporation), it uses blockchain
  • privacy-first - decentralized AI nodes can share confidential end user authentication, payment and health data without risk of leaks
  • distributed operation payments - AI nodes sell their operation work and can bill end user with tiny costs (death by thousand cuts problem)
  • agentic - AI nodes, are processes running in a loop, performing tasks from other agents using own or external resources

Picking one property does not make it a decentralized AI.

Tallinn AI meetup

· 2 мин. чтения

Another day, another AI meetup 😀
Apparently now there is a dedicated TallinnAI meetup (https://lnkd.in/dPG-AzpP), hopefully it can become a recurring one

First talk by Andrei Sbitnev was about https://figurix.com/ and 3d model generation using AI. Specifically, given a photo, generate a cartoon-like 3d avatar with animation. Uses ComfyUI https://github.com/comfyanonymous/ComfyUI and https://www.tripo3d.ai/ under the hood. I liked the lean mindset of using home server to run this (I'm at similar phase of bee detections).

I also like visual workflows and Clarifai has workflows as a major feature. I was wondering if open-source has sufficiently advanced capabilities like streaming and video support. Workflows can become hard to manage if there are too many node types as combinatorics grows and you need to know what use-cases are compatible. It becomes a programming language quite fast.

Second talk was by Mikhail Dunaev on https://www.hexagen.world/ . An infinite canvas project with hexagonal ai-generated tiles that make up a cool map that over 8 thousand users tried out. Most of it coded also using cursor, making author 2x more efficient, shifting work into more product-oriented thinking.

AI meetup notes

· 5 мин. чтения

Visited local AI meetup organized by Vattan, Astra & co, Hosted by Helmes https://lu.ma/0045px5e

I liked quote by Astra Tikas (targeted towards individual presenters). I think it summarizes AI ecosystem well :D

"You are not special" "No, you are special, all of you are special"

Intros and use-cases

  • Elisa
  • ESGrid
  • Impactly
  • Up Catalyst
  • TalTech

кино/The Wild Robot

· 1 мин. чтения

Очень хорошая анимация и музыка, местами 10/10 где есть сочетание всех элементов в том числе музыки - я аж всплакнул. Советую сходить, детям подойдет.

https://www.imdb.com/title/tt29623480/

Из недостатков - местами с ритмом повествования приходят странности, возникает растянутость и предсказуемость, нелогичность или не проработанность мира. Мол хочу обратно - не хочу обратно - сожгу все - опять хочу. Художественные условности - робот у которого любые отсеки, жгутики и механизмы появляются на ходу а память неизвестно как работает.

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

Product team models - project based, feature factory and product operating model

· 4 мин. чтения

Listened to the podcast https://www.tpg.ee/p/product-team-models-project-based

Was interesting to listen and reflect how organizations tend to have indeed different structures. I suppose the project-based is a tendency in small and outsourcing companies, while more mature product-orinented companies go with feature-factories. I don't think I've seen a good implementation of the described product operating model myself. It seems hard to do such a company-wise mindset shift because people are narrow-focused on their role and thinking outside the box requires jumping through multiple layers. Even if companies are matrix-shaped and have vertical teams, they are not representing all layers. For example sales, marketing, support and infrastructure likely won't be part of the the team.

So I do wonder how does Aive Uus break those mindsets 😄 Hopefully we'll see more of this

Как записывать экран с круглой камерой

· 1 мин. чтения

Часто приходится по работе записывать видео скринкасты для репорта багов, описания глубоких сценариев их возникновения, неудобного UI; Кроме того я использую видео для описания pull-request'ов в дополнение к тексту.

Как сделать результат более профессиональным? Используйте камеру что-бы люди видели ваши эмоции. Это особенно важно в современной асинхронной коммуникации где все работают удаленно.

Asuur Keraamika

· 1 мин. чтения

Are you planning a team building event and bored of bowling and billiard?

Try pottery. Clay is like playdough and looks simple, but it's like programming and can reveal personal taste. You have a product vision, tight deadlines and extra features you want to include.

You can go straight in and fail fast to quickly recover (like I did) . Or you can plan ahead, cut different parts and assemble it like a puzzle, waterfall-style. Naturally you must be aware of tools and integration tricks.

Finally you ship it for glazing and hope that users will find it useful and beautiful

Thanks Artjom Shestajev for organizing Clarifai Estonia event at asuurkeraamika.com

CUDA

· 1 мин. чтения

Послушал случайную онлайн лекцию по CUDA и поскольку это интересно, скопировал себе немного слайдов

cuda_example.ipynb

(From public video stream workshop)

Katana meetup

· 1 мин. чтения

Katana Cloud Inventory & ProductTank (Anna Albert + Olesia Kucheryk) hosting AI meetup ( https://lnkd.in/dhUbzDE6 )

Got to listen about opengenie.ai, Align, Databricks usage to analyze company data by auto generating SQL, summarization of support, customer research, lead/demo calls. Thx to Andres Aava. Reminded me a bit about Supersimple.

Second talk was about EU AI Act by Krete Paal
https://lnkd.in/dgDZEGcd

Personally, I see more and more risks with AI getting used. Privacy of LLM calls,
AI bots in youtube comments, bots creating meaningless PRs (looking at dependabot), creating fake and hallucinated issues (like CURL incident - https://lnkd.in/dUmR3ucK ) not to mention health ( https://lnkd.in/dCkAPVVE )

Digit Tartu conference 2024

· 2 мин. чтения

At Digit Conference

Jaroslav Judin expanded on prior credit-card anti-fraud talk that Elizaveta Lebedeva did. This time focus was on redis. Sandbox - https://lnkd.in/d78gmwZm

Swedbank talk by Lehar Oha & Markus Reimegård was somewhat high-level about adding AI (similar to what Clarifai does as a service). As I understood, pdf parsing for RAG might be hard, just to get right embeddings. But I hope I will be able to ask Swedbank GPT about my contracts (leasing or insurance) for preliminary analysis. Just add a notice that it's an automated tool doing an analysis.

Dmytro Hnatiuk talked about databases. The insight there as I understood is that its similar to Security. If you have DB not performing well, its not that much of DB engineer problem, its developer's problem. Developers need to think in advance about storage, queries, sharding, domain separation, archival etc.

Arne Ansper was advocating for UML and state machines. I sort of like to document high-level things with mermaidjs, but at times I question if UML is that intuitive (and that you should not reinvent new modelling language), if it needs to be source of truth with code generation or that one needs to first model the system with RUP
https://lnkd.in/da-sxSCn

Eddy Vinck was promoting Astro https://astro.build/ - a javascript framework to generate static websites with some extensions. I was thinking of migrating my blog and merging it with second-brain data from notion/obsidian and publishing that as a static website to have less CMS/DB management overhead. Maybe this static generation would help, but I'm worried about search, including vector search for recomendations.

Tallinn JS meetup

· 2 мин. чтения

Attended TallinnJS meetup organized by Stefano Amorelli at LIFT99. Won ticket to Digit Conference. Almost won a hoodie from Printify but figured that googling an answer was not fair 🤐

First talk was by Dmitrii Baranov about telegram bots using telegraf.js telegraf.js - v4.16.3

Second talk was by Jan Johannes about workerd, a js runtime
GitHub - cloudflare/workerd: The JavaScript / Wasm runtime that powers Cloudflare Workers

I think having a bot is a nice interface extension to any app, in addition to the usual web, mobile, desktop and cli apps. Telegram, discord, slack bots can improve support reaction time, push app alerting/notifications and more. I wish telegraf supported text and video streaming though.

Then it could also be more seamlessly integrated with LLMs, say if you had a Clarifai bot streaming AI questions and answers, switching ML model on the fly would you use it over a web UI? With bots and AI element to it, apps could become much more interactive and lose UI entirely. You can see that change on the example of google search -> perplexity & chatgpt transition.

Об этике пчеловодства

· 3 мин. чтения

Эрнест Бондаренко, мне вот захотелось так же публично ответить тебе, раз латвийская команда ForQueenBee на презентации в Prototron не смогла, и естественно Jana Budkovskaja не могла им ( Guntis Laurins,  Anete Grosberga ) дать дополнительного во время общего питча.

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

Dream of scalable & enriched graphql-subscriptions

· 12 мин. чтения

Originally posted in Medium

https://miro.medium.com/max/1400/1*Rvb94EOQA-BzsmYJ4TklGg.jpeg

Stylized photo of Jagala juga (Estonia), original photo by Aleksandr Abrosimov, Wikimedia Commons

Last time, I wrote about 5-year long journey of having GraphQL in Pipedrive. Now, let me tell you about a 10-year long journey of delivering websocket events to frontend.. and maybe help you out with it too.

https://miro.medium.com/max/1400/1*xffiu2fshUMbBFm-JlSAGw.gif

Journey to a Federated GraphQL

· 15 мин. чтения

Original post at medium

https://miro.medium.com/max/1400/1*6ADAF1r2LFunXgdklnMRzw.png

Image taken from dgraph.io

Engineers tend to love good stories, so hopefully our 5-year journey of moving towards API composition with GraphQL now in production (serving at peak 110 requests per second at 100ms latency) provides a good story.

[If you’re in a hurry, scroll down to Lessons learned and check out the open-sourced graphql-schema-registry.]

https://miro.medium.com/max/1400/1*d32xg4FUICDlOm9q0PCLkw.png

schema registry with some example schema

Путь к Федеративному GraphQL

· 14 мин. чтения

Картинка с dgraph.io

Программисты любят хорошие истории, поэтому надеюсь что пятилетний путь к композитному API с помощью GraphQL в боевой среде (на пике выдающей 110 запросов в секунду при 100мс задержке) будет интересен.

[Если вы спешите, проскрольте ниже к урокам и гляньте на открытый код graphql-schema-registry]

schema registry с примером тестовой схемы

Задача

Годами, Pipedrive (которому в начале 2020 стукнуло уже 10 лет), давал публичный REST API где были и недокументированные пути для нашего веб приложения. Один из них /users/self, который изначально задумывался для загрузки информации о пользователе, нормально с течением времени стал грузить все что надо для первой загрузки страницы, доходя до 30 разных типов сущностей. Сам он выдавался PHP монолитом, который по натуре синхронный. Мы пытались его распараллелить, но неудачно. /users/self распределение задержки для оставшегося траффика

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

Прототип с прямым доступом к БД

Давайте вернемся назад в прошлое, когда наши разработчики стали экспериментировать с graphql.

Года 3-4 назад, в команде разработки рынка приложений, я услышал от Паши, нашего фулл-стек разработчика новенькие для меня термины - elixir и graphql. Он участвовал в тестовом проекте в котором напрямую работал с MySQL и выдавал основные сущности Pipedrive по /graphql.

На локальной машине работало прекрасно, но это не масштабировалось на весь код, потому что функционал - не обычный CRUD, а весь монолит переписывать никто не хотел.

Прототип со склейкой

Переносимся в 2019, когда я заметил еще один тестовый репозиторий от другого коллеги, который стал использовать GraphQL stitching с определением сущностей с помощью graphql-compose и резолверами которые делали запрос уже к нашему REST API. Как можете представить, это уже было значительным улучшением, потому что нам не надо было переопределять всю бизнес-логику и graphql становился просто приятной оберткой.

Из недостатков этого решения:

  • Производительность. Небыло dataloader'а, поэтому был риск N+1 сетевых запросов. Небыло ограничения сложности запроса и какого-либо промежуточного кеширования.

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

Подготовка

В Октябре 2019, я стал готовиться к миссии, которая превратила бы прошлое решение в рабочее с помощью Apollo федерации, которая вышла чуть ранее в этом же году. Кроме того, результат приземлился бы в команде Core, которая стала бы поддерживать его в долгосрочной перспективе.

Сбор ожиданий разработчиков

В компании некоторые разработчики были довольно скептичны и предлагали построить свое решение просто склеивая запросы воедино, отправляя по POST и надеясь на свой gateway который будет распараллеливать обработку.

Другие считали что graphql еще слишком сырой что-бы использовать в жизни и лучше подождать. Третьи предлагали рассмотреть альтернативы, типа Protobuf и Thrift, а в качестве транспорта рассмотреть GRPCOData.

Четвертые напротив, на полном ходу писали graphql под одиночные сервисы (insights, teams) и выкатывали в лайв, однако не могли повторно использовать сущности (например User). В Праге ребята написали все на typescript + relay на фронтенде, который нам еще предстоит перенести в федерацию.

Изучать новую технологию было круто.

Строгий, само-документирующийся API для фронтендеров? Глобально определяемые сущности уменьшающие дублирование и улучшающие прозрачность и владение среди всех команд? Gateway который автоматом делает под-запросы и между сервисами без избыточной выборки? Ухх.

Впрочем, я знал что нам понадобится управлять схемой как-то динамически, что-бы не полагаться на захардкоженые значения и видеть что происходит. Нечно типа Confluent’s schema-registry или Atlassian’s Braid, но они либо под Кафку делались, либо на Java, которую мы не хотели поддерживать.

План

Я выступил с инженерной миссией у которой было 3 цели:

  • Уменьшение первичной загрузки страницы (воронка продаж) на 15%. Достижимо если заменить некоторые REST запросы в один /graphql

  • Уменьшение траффика на 30%. Достижимо если перенести загрузку всех сделок для воронки продаж в graphql и спрашивать меньше свойств.

  • Использовать строгую типизацию (что-бы фронтендерам надо было писать меньше кода в защитном стиля)

Мне повезло, трое разработчиков присоединились к миссии, в т.ч. автор прототипа.

Сетевые запросы по мере загрузки веб-приложения

Изначальный план по сервисам выглядел так:

Сервисы над которыми предстояло бы работать

Тут schema-registry был бы общим сервисом, который мог бы хранить схему любого типа, получая на входе что вы в него кинете (swagger, typescript, graphql, avro, proto). На выходе он мог бы так же выдавать что вы хотите.

Gateway периодически опрашивал бы schema-registry и вызывал бы уже сервисы которые владеют данными согласно запросу и схеме. В свою очередь frontend компоненты могли бы скачивать актуальную схему для autocomplete и самих запросов.

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

Итоги

Главную цель по замене /users/self в веб-приложении мы сделали в течение первых двух недель ? (ничоси!). А вот полировка всего решения что-бы оно быстро и надежно работало, заняло все оставшееся время.

К концу миссии (в феврале 2020), мы каким-то чудом достигли 13% ускорения первой загрузки страницы и 25% ускорения при повторной загрузке (из-за добавленного кеширования), согласно синтетическому UI тесту который мы гоняли на Datadog.

Уменьшить трафик нам не удалось, потому что мы не достигли рефакторинга вида воронки продаж - там все еще REST.

Что-бы ускорить добавление сервисов в федерацию другими командами (у нас 600+ человек), мы записали обучающие видео что-бы все были в курсе как оно все работает вместе. После окончания миссии IOS- и Android- клиенты тоже мигрировали на graphql и в целом были рады.

Выученные уроки

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

Управляйте своей схемой

_Могли бы мы построить это сами? Возможно, но это не было бы так отполировано.
_Mark Stuart, Paypal Engineering

В течение первых пары дней я попробовал Apollo studio и их инструментарий для терминала по проверке схемы. Сервис прекрасный и работает из коробки с минимальными настройками gateway.

Написанный нами инструментарий для валидации схемы

Написанный нами инструментарий для валидации схемы

Однако несмотря на все фишки этого облачного сервиса, я посчитал что для такого важного дела как маршрутизация траффика было бы опрометчиво полагаться на сторонний сервис из-за рисков для жизнеспособности нашего дела, несмотря на богатый функционал и сколько-то выгодные расценки. Поэтому мы написали свой сервис с минимально нужным функционалом и теперь отправили его в opensource -  graphql-schema-registry .

Вторая причина была в том что-бы следовать модели распределенной архитектруры датацентров Pipedrive. У нас нет центрального датацентра, каждый DC самодостаточен. Это дает нам как более высокую надежность, так и способность открывать новые датацентры в Китае, России, Иране или на Марсе ?

Версионируйте свою схему

Федеративная схема и graphql gateway очень хрупкие. Если у вас появится конфликт имен у типов или неверная ссылка между типами в одном из сервисов, то gateway может этого не пережить.

По умолчанию, gateway напрямую опрашивает все сервисы касательно их схемы, поэтому достаточно одного из сервисов с ошибкой что-бы поломать всем трафик. Apollo studio решает это посредством проверки схемы еще до деплоя и отказе если видит какой-то конфликт.

Проверка совместимости схем правильный подход, но конкретное решение у Apollo зависит от их внутреннего состояния, т.к. они хранят правильную склеенную схему на данный момент. Это делает протокол регистрации сложным и зависящим от времени.

Мы же напротив, связали версии микросервисов (генерируемые на основе хешей докер-образов) со схемой. Микросервисы регистрируют уже в ходе своей работы и делают это один раз без последующих повторений. Gateway делает выборку всех федерированных сервисов из консула и спрашивает schema-registry составить схему /schema/compose , предоставляя их версии.

Если schema-registry видит что предоставленные версии несовместимы, она откатывается на прошлые версии

Регистрация схемы при старте сервиса

Микросервисы могут выдавать как REST так и Graphql API, поэтому мы используем оповещения тревоги при неудачной регистрации схемы, оставляя при этом работу REST.

Определение схемы на основе REST не просто

Поскольку я не знал как лучше перенести схему из нашего REST в graphql, я сначала попробовал openapi-to-graphql, нормально наша документация на тот момент не имела детального описания запросов и ответов.

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

В дальнейшем это нам аукнулось, так как оказалось что REST API иногда зависит от того кто делает запрос, либо зависит от внутреннего состояния и логики.

Например после настраиваемые поля данных меняют REST API в зависимости от пользователя. Если его добавить к сделке, то он оно будет выдаваться с ключем-хешем на уровне deal.pipeline_id. С федеративным graphql, динамическая схема невозможно, поэтому нам пришлось передвигать эти настраиваемые поля в отдельный список

Другая проблема это стиль наименований в json-ответе. Мы хотели поддерживать верблюжийСтиль, но почти весь REST отвечал нам в змеином_стиле, пришлось пока остаться на смешанном.

федеративный граф данных Pipedrive (слева) с 2 сервисами (из 539) и еще-не-федеративный граф сервиса leads (справа)

CQRS и кеш

Модель данных в Pipedrive не может полагаться на простой TTL-кеш.

Например, когда инженер поддержки создает глобальное оповещение о предстоящем техническом обслуживании приложения из нашей админки, он ожидает что сообщение будет сразу же видно пользователям. Эти глобальные оповещения могут быть адресованы как всем пользователям, так и конкретным компаниям и индивидуальным людям. Чистить такой кеш приходится используя 3 разных ключа.

Что-бы делать параллельные запросы к PHP-монолиту, мы написали сервис на nodejs (назвали его monograph), который кеширует все что отвечает монолит в memcached. Этот кеш надо чистить из монолита в зависимости от бизнес-логики. Это немного антипаттерн, потому что кеш получается общим для разных сервисов и сильно их связывает.

Тут можно заметить CQRS pattern. Впрочем, такой кеш позволяет ускорять 80% запросов и дает итоговую среднюю задержку такую же как и у монолита.

Время средней задержки ответа монолита (слева) и graphql gateway (справа) в регионе US на основе NewRelic

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

Identity владеет данными пользователей, поэтому мы сделали так что он кидает событие через kafka, которое ловит monograph и чистит все нужные кеши. Тут есть недостаток, что событие приходит с задержкой (может максимум 1 сек), поэтому чистка кеша происходит не мгновенно. Нормально это не критично, потому что пользователь не так быстро уходит со страницы что-бы сделать повторный запрос к бекенду и заметить что в кешах еще старый язык.

Следите за производительностью

Производительность была главной целью и для этого нам пришлось хорошо прокачаться в знании APM и выслеживании распределенных запросов между микросервисами что-бы определить самые медленные места. Мы на тот момент использовали Datadog и он хорошо себя зарекомендовал.

Для ускорения, мы кешировали все 30 параллельных запросов в memcached. Но по ходу дела возникали проблемы. Например на картинке слева видно что некоторые резолверы делают запрос в memcached и получают ответ за 10мс, а другие тупят, словно жду своей очереди выростая до 220мс. Как оказалось, это было из-за того что я использовал один и тот же хост mcrouter. Как только я стал их ротировать, мемкеш стал отдавать все за 20мс максимум.

Что-бы уменьшить количество этих сетевых запросов к мемкешу, мы склеили его в один используя getMulti функцию. Получается что несмотря на то что все resolver'ы выполняются независимо, они блочатся на 5мс с помощью debounce и склеиваются воедино.

На картинке справа видна другая проблема. Эти желтые линии это налог graphql gateway на приведение данных к строгому типу. Причем чем больше данных вы гоняете через сервис, тем дольше будет эта фаза выполнятся.

Вобщем по ходу миссии постоянно приходилось мониторить какие же запросы нам надо еще закешировать и под конец стало бесить что скажем 28 из 30 запросов прекрасно кешируются, а оставшиеся два мало того что отвечают целых 500мс, так их еще и невозможно легко закешировать.

Нам пришлось вынести их в отдельный graphql запрос, который делается после первого /graphql запроса на инициализацю страницы. Так что сейчас мы на деле делаем уже порядка 3-5 независимых запросов, в зависимости от тайминга фронтенда (там тоже debounce зависящий от параллельной подгрузки FE компонентов)

Не следите за производительностью

Казалось бы полностью противоположный урок, но на деле это значит что в лайв-среде вам лучше отключить мониторинг приложения (APM) и tracing:true, если вы используете их.

Отключение отслеживания у нас ускорило среднюю задержку в два раза с 700мс до 300мс для нашей тестовой компании. Насколько я понимаю, причина крылась в функциях которые замеряют время (типа performance.now()), которые необходимы для замера каждого резолвера.

Мы делали профайлинг graphql gateway с помощью  Chrome DevTools, но так просто вызов этих мелких функций, раскиданных повсюду не заметишь.

Бен тут делал замеры и тоже пришел к этому.

Попробуйте ранний запрос

На фронтенде, время создания graphql запроса для нас оказалось сложновато. Я хотел передвинуть первый /graphql как можно раньше (даже до загрузки всего кода в vendors.js) в графике сетевых запросов. Мы смогли это сделать, но веб-приложение из-за этого стало значительно сложней.

Что-бы делать запрос вам понадобится graphql клиент и парсинг gql литералов для определения самого запроса. Дальше его надо либо выдавать в отдельном bundle, либо отказываться от всех удобств и использовтать сырой fetch. Даже если делать сырой запрос, дальше надо что-то делать с ответом - распределять данные по моделям либо сохранять в глобальную переменную. Вобщем мы решили отказаться от этого и надеяться на server-side-rendering и service workers в будущем.

Перенос /graphql запроса левей

Оценивайте сложность запроса

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

Сначала мы попробовали graphql-cost-analysis библиотеку, но в итоге написали свою, поскольку захотели больше фич - множителях при выдаче списков данных, вложенности и рекурсии, а так же определении типов влияния на инфраструктуру (сетевой запрос, БД, CPU, работа с файлами). Тут сложней всего оказалось внедрять поддержку своей директивы в gateway и schema-registry. Надеюсь мы нашу библиотеку тоже опубликуем.

У схемы много лиц

Работать со схемой в js/typescript на низком уровне порой мучительно. Это начинаешь понимать когда пробуешь интегрировать существующий graphql сервис в федерацию.

Например настройки koa-graphql и apollo-server-koa ожидают что вы создадите вложенный объект  GraphQLSchema  который включает и сами резолверы. Но федеративный apollo/server хочет схему и резолверы отдельно:

buildFederatedSchema([{typeDefs, resolvers}])

В другом случае, как я уже писал, вам захочется определить схему с помощью gql литерала, или сохранить схему в schema.graphql файл, а когда вам надо будетделать проход по всей схеме для оценки сложности, понадобится ASTNode (и функции parse / buildASTSchema)

Плавная canary деплой

Во время миссии мы выкатывали изменения сначала всем разработчикам что-бы отследить очевидные ошибки.

Под конец миссии в феврале, мы выкатили graphql только на 100 компаний-"везунчиков". Дальше мы медленно выкатывали их до 1000 компаний, потом 1%, 10%, 30%, 50% и наконец в июне выкатили всем.

Деплоили мы просто используя логику деления company ID без остатка. В дополнение, у нас было несколько настроек - кому еще включать, кому не включить никогда и рубильник выключающий graphql сразу у всех на фронтенде. Было очень полезно во время инцидентов сразу избавиться от подозрений что это все из-за нового graphql и упростить дебаг.

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

Надежды и мечты

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

Как только наш graphql API станет стабильным и достаточным для использования любыми пользователями, его можно выкатить в качестве второй версии нашего API. Для публикации впрочем понадобятся еще директивы для ограничения доступа к сущностям согласно OAuth видимости (для приложений из рынка) и согласно нашим продуктам.

В самой schema-registry надо добавить отслеживание клиентов, связать ее gateway для получения аналитики трафика что-бы проще было понять какие поля можно удалять, надо добавить фильтрацию и подсветку сущностей в зависимости от директив цены и видимости, валидировать именование, хранить постоянные запросы (persisted query), публиковать историю изменений итоговой схемы для сторонних разработчиков.

Кроме того, поскольку у нас есть сервисы на go, еще непонятно как стоит делать внутренний трафик - стоит ли использовать GRPC из-за скорости и надежности, либо использовать независимые graphql эндпоинты, либо ставить централизованный внутренний gateway. Если GRPC лучше только из-за его бинарности, может мы можем написать библиотечку которая тоже упакует graphql данные с помощью msgpack?

Что касается внешнего мира, надеюсь Apollo со своим проектом Constellation ускорят обработку запроса на Rust что-бы небыло этих 10% налога на производительность и смогут федерировать graphql сервисы без серьезных изменений последних.

Вобщем прекрасное время что-бы наслаждаться разработкой где уйма сложности!

Техническое интервью как нейрон

· 4 мин. чтения

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

Шпаргалка по golang

· 3 мин. чтения

После php и node начал писать на go, поэтому по-аналогии с unix-шпаргалкой, выпишу для себя основы..

Запуск

go run main.go → компиляция и запуск exe
go build main.go → только компиляция и создание exe, без запуска
go get -u https://github.com/x/y → импортирование зависимостей

Переменные и типы

типдекларациязначение по умолчанию
целыеint8, int 16, int32, int64, uint, uint640
бинарныеbyte
битboolfalse
с плавающей точкойfloat, float32, float640
строкаstring, rune(пустая строка)
var i int = 10;
var myfirstvar, mysecondvar int = 3, 4; // объявление разом
var autoInt = -10 // компилятор сам подберёт тип
var mystring = "test\n" // двойные для строк, всё в уникоде
var mysymbol = '\u2318' // один символ
var rawBinary = '\x27' // одинарные кавычки для символа

myNewDeclared := 42 // быстрая инициализация
myMathVar = 7+3i // математикам

Приведение типов

int(myfloat)
float64(myInt)
string(48) //будет номер символа, а не строчка "48"
bin := []byte(mystr) //перевод строки в массив байтов для итерации по байтам

Константа

const fullName = "Artjom"

//объявление нескольких переменных с инкрементом
const (
one = iota + 1 //iota начало итерации с нуля
_ // пропуск "двойки"
KB uint64 = 1 << (10*iota)
)

Массив

Низкоуровневый тип. Длина массива фиксирована.

var a1 [3]int //длина массива, сразу заполнится [0 0 0]
var a1 [2*size]bool //длина зависит от перменной
a3:=[...]int (1,2,3) //инициализирование значениями
var aa[3][3] int //массив массивов

len(mystring) //длина строк и массивов

Слайс (резиновый массив)

Более сложная структура. Состоит из массива с фиксированной длиной (capacity) в которую записано меньшее количество элементов (length). Как только length превышает capacity, размер capacity удваивается

var s1 []int //без размера
append(s1, 100) // добавление
len(s1)
cap(s1) // узнать capacity
s2:= []int(1,2,3,4); //создание со значениями

s1 = append (s1, s2...) //Соединение слайсов через оператор развёртывания значений
s3 := make([]int, 10) //Создание слайса сразу нужной длины, значения уже будут заполнены
s4 := make([]int, 10, 15) // Создание слайса с нужной capacity
copy(s7, s6) // копирование значений, но размер целевого слайса должен совпадать
fmt.Println( s7[1:5] ) // часть слайса

// слайс из массива
a:=[...]int(5,6)
b:=a[:] //слайс теперь ссылается на массив

Мап (ассоциативный массив)

var myEmptyMap map[string]string // [тип ключа] и тип данных, но пустой, в него нельзя писать

var mm1 map[string]string = map[string]string{} //пустой интерфейс
mm2 := map[string]string{}
mm3 = make(map[string]string)

mm2["firstName"] = "Artjom" //write
fmt.Println(mm2["firstName"]) //read
delete(mm3, "somekey") //delete

fmt.Println(mm3["nonexistingkey"]) //выдаст значение по умолчанию (пустая строка)

_, exists = mm3["missing"] // проверка есть ли такой ключ

Ключевые слова в управляющих конструкциях

  • fallthrough - проваливание в switch case

  • break - выход из  switch

  • range - итерирование по символам строки, например

  • for indexval := range mystr

Функция

init() - вызывается при старте программы в любом из пакетов (порядок неконтролируемый)

//аргументы передаются по значению
func avg(x int) float{ //возвращаемый тип в конце
}

func multipleArgs(severalInts ...int){ //развёртывание аргументов в слайс
}

func avg2(y int) (res float){ //сокращение return res в конце
res := 3
}

func mysql(file File, bool x){
file.open()
defer file.close() //заранее объявляет что надо вызвать в конце исполнения функции

if(x) return 0
//do more lots of stuff
return 1
}

См. также

Dashboard на основе Grafana и InfluxDB

· 2 мин. чтения

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

Поэтому я решил поизучать бесплатный dashboard и графико-генератор на основе Grafana. Зарегился и упёрся в то что он сам не хранит данные. Он умеет только подключаться к внешним источникам и делать запросы туда. 

Новый MySQL мне не хотелось поднимать, а открывать существующий тем более. Cloudwatch от Амазона - видимо полезен для мониторинга сервисов если вы активно пользуетесь этой инфраструктурой. Prometheus я могу и на работе посмотреть. Выбрал InfluxDB - специальную БД для хранения временных событий.

Ставить Influx было достаточно просто. Сложней было связать графану с influx.

Сервис гоняется на 8086 порту и Grafana хочет SSL и CORS. Поэтому пришлось делать proxy на nginx и добавлять header:

location /influx/ {
proxy_set_header HOST $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
add_header 'Access-Control-Allow-Credentials' 'true';

proxy_pass http://localhost:8086/;
}

Теперь встаёт вопрос как данные добавить в influx. Писать будет процесс на node, поэтому я по-быстрому нашёл библиотечку и пример подключения: 

const Influx = require('influx');

const influx = new Influx.InfluxDB({
host: 'localhost',
database: 'home',
schema: [
{
measurement: 'response_times',
fields: {
boiler_smoketemp: Influx.FieldType.FLOAT,
boiler_output: Influx.FieldType.FLOAT,
boiler_power: Influx.FieldType.FLOAT,
boiler_light: Influx.FieldType.FLOAT,
boiler_oxygen: Influx.FieldType.FLOAT,
boiler_oxygenlow: Influx.FieldType.FLOAT,
boiler_oxygenmid: Influx.FieldType.FLOAT,
boiler_oxygenhigh: Influx.FieldType.FLOAT,
boiler_connectionindex: Influx.FieldType.FLOAT,
boiler_return: Influx.FieldType.FLOAT,
zone_1: Influx.FieldType.FLOAT,
zone_2: Influx.FieldType.FLOAT
},
tags: [
'host'
]
}
]
});

//заполняем data..

influx.writePoints([
{
measurement: 'heating',
fields: data
}
]).catch(err => {
console.error(`Error saving data to InfluxDB! ${err.stack}`)
});

Теперь что-бы проверить записались ли данные, можно использовать хронограф - скачиваемый UI-сервис который в более ранних версиях был встроен в influx в виде админ-панели.

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

Hacking essentials

· 2 мин. чтения

Прошёл двухдневный workshop компании Clarified Security по основам взлома в сети и серверы. Оплатил это Pipedrive, но вы можете заказать себе такую же тренировку. Тренинги построены по шагам с такой оценочной системой, что какое-то время можно самому искать решение, потом тебе объясняют как это сделать в действительности.

Спешу поделиться самым интересным. Вначале было введение в историю, в т.ч. последние уязвимости типа KRACK

Потом был пример взлома по-старинке - старый апач с уязвимостью на переполнение буфера. Как раньше приходилось искать код на C, компилировать. Как в ходе этого gcc ругался на отсутсвующие хедер-файлы.

Второй день мы провели в Kali Linux за двумя главными программками - Meterpreter и Armitage. Первая это библиотека эксплоитов с их поддержкой в виде сервера, а вторая это UI для управления атакой.

Итог пугающий. Уязвимости в java, flash и прочих неизвестных 0-day штуках позволяет влезть через веб к человеку на комп. Дальше обычно приходится делать повышение привилегий процесса. В винде можно прыгать с процесса на процесс, так что если клиент заразился через открытый word файл, то связь со злоумышленником остаётся переходом под более постоянный процесс, типа explorer. Повышение привилегий даёт в итоге полный контроль над машиной. Дальше можно захватывать компьютеры во внутренней сети, менять настройки файрволла так что-бы ничего не заподозрил владелец. Можно взламывать и линуксовые машины, так же поднимаясь до рута.

Кроме этих двух утилит в Kali предустановлены wordlistы, с которыми можно перебирать пароли к линуксовым shadow-файлам, есть сканеры путей для вебсайта и проч.

Code review и конфликт в динамике команды

· 9 мин. чтения

Команды программистов из 3-7 человек это идеальная машина по быстрому созданию качественного продукта. Слишком много - и все погрязнут в бесконечных обсуждениях, слишком мало - будет сбиваться ритм и снижаться продуктивность и качество.

Я мало что понимаю в менеджменте, поэтому меня больше интересуют вопросы конфликтов и улучшение инспекции кода для улучшения продукта и сплочения команды.

Умный дом — отопление с пеллетным котлом

· 9 мин. чтения

Год назад мы взяли в кредит дом. Старенький, с деревянными продуваемыми окнами, без утепления и с основным дровяным отоплением. Коллеги брали наоборот новые, рядные дома где всё уже готово. Я расчитывал что так я выиграю в цене, гибкости, а в итоге и в качестве. 

Заказав 16 м³ дров за ~700€ и протопив сезон, я понял что это вам не квартирные удобства. Хотя дрова самые дешёвые и экологические в отоплении, с ними неудобно

  • Надо дровник и тратить пару дней на их переноску и выкладывание

  • Дрова бывают разные и по-разному разгораются (берёза лучше осины)

  • Зимой надо минимум 2-3 вязанки дров за вечер что-бы натопить. Таскать их в мороз и складировать у плиты — то ещё удовольствие.

  • Топить через маленькую плиту, подбрасывая дрова каждые пол-часа/час. Это слишком отвлекает от домашнего быта.

  • Температура  неравномерна и не постоянна

Когда топишь то возле плиты воздух может быть 30˚C уже, тогда как где-то в дальнем углу ещё 18˚C. 

Приходишь домой — дома 15˚C, надо ждать 2 часа покуда прогреется часть этажа. Встаёшь утром - тоже холодно, душ принимать становится просто опасным для здоровья — легко простудиться.

Кроме того, есть теплонасос воздух-воздух, но его мощности хватало только на четверть дома, он достаточно шумный и при морозах его мощность сильно падала. Поэтому приходилось дополнительно топить электрическими конвекторами. Но электричество достаточно дорогое — примерно +50€/мес при отоплении только спальни. Отапливать весь дом электрическими обогревателями влетело бы в ~300 €/мес.

Итого, Требования

  • ​Автономность (1-2 недель беспрерывной работы, что-бы можно было съездить в отпуск зимой)

  • Равномерность отопления дома

  • Достаточная мощность при морозах в -30˚C (объём дома ~ 350м³ без внешнего утепления)

Варианты

Уже исходя из требований, выходит что минимальная мощность источника отопления при зимних тепло-потерях — 20 квт

Я рассматривал разные источники тепла: 

  • Газ хоть и дешёвый, но проводить трассу от Eesti energia, или создавать поземное хранилище вышло бы слишком дорого. Баллоны таскать было бы слишком напряжно, да и с точки зрения безопасности казалось опасным
  • Дизелем топит сосед. Достаточно дорого, на зиму запас проблематично делать, нужен большой бак. Удобно если бы у меня была машина на дизеле
  • Воздух-вода очень заманчивый вариант экономичностью и автономностью, но как и воздух-воздух, эти насосы теряют мощность при низких температурах. Грубо говоря при -30 градусах, насос который рекламируется как 15 квт, и стоит 8 к€ станет работать как 3 квт, периодически подключая ТЭН
  • Вода-вода, или как у нас рекламируют maaküte ("отопление земли"). Закапывать трубы на участке вертикально (15м) или горизонтально (пару км) мне кажется сомнительным — будет промораживать землю, да и подходящего места нет.
  • Камин. Если продолжать топить дровами то вместо старой узкой печки можно использовать камин. Но для этого надо установить металлическую сердцевину и провести в разные комнаты отводы тёплого воздуха — это улучшит равномерность прогревания, но не автономность

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

Победитель RTB30

Я получил 3 предложения от 5 фирм, в итоге одно из них выбрал и чуть-чуть поменял.

Выбрал я в итоге пеллетный котёл от датской NBE, RTB30 (30квт). Степень сгорания более 91%, что значит что для смены бака надо сжечь порядка тонны пеллетов (т.е. менять золу надо будет раз в пару месяцев)

Вместе с котлом поставляется компрессор, который подключён к горелке. После прогорания, горелка автоматически чистится воздухом под давлением

Интерфейс

На самом котле есть dashboard где показано подключение и состояние в целом. Внутри - меню offline управление.

Котёл подключается по wi-fi к интернету к порталу stokkercloud.dk, где можно посмотреть как публичную информацию разных котлов в мире, так и залогиниться в админку своего котла (об этом ниже). Админка кстати написана на ангуляре, а бэкэнд на php

Теперь что можно делать в интернете..

Радиаторы и трубы

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

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

Сеть из труб достаточно интересная и полна нюансов. 

  1. сразу на выходе из котла стоит труба соединяющая горячую воду сразу со входом. Эта обратка разрывается как только котёл достаточно нагреется.
  2. у котла внизу есть предохранительный клапан, который откроется самостоятельно если в трубах будет критическое давление воды
  3. вода в бойлере и вода в радиаторной сети никак не связаны и нагрев происходит за счёт теплоотдачи, т.е. вода в радиаторах никуда не девается и циркулирует по кругу
  4. поскольку горячая вода находится в подвале, то при открытии крана, ей прийдётся подняться на высоту 3м по трубам длиной ~20 м, под давлением насосной мембраны в 2.5 атмосфер. Это достаточно долго (30 секунд) и хочется мгновенной горячей воды. Поэтому горячая вода замкнута в цикл и гоняется она постоянно циркуляционным насосом.

Что-бы понять нюансы советую послушать специалиста...

Недостатки

Из проблем или неудобств, стоит выделить высокую минимальную мощность. Минимально настраиваемая мощность в 10% потребляет достаточно много топлива и быстро нагревает дом до 26˚C для экономии осенью проще поставить вариацию по времени (включение через каждые 2 часа), но частое включение горелки плохо сказывается на её надёжности. В этом плане идеально было бы подключить дополнительно систему воздух-вода для температур 0 — +10˚C. Ближе к зиме я настрою постоянное включение

Факапы установки

Устанавливали всё товарищи из Küttemeister.

Первый факап - котёл должен иметь металлический дымоход, что-бы кирпичная кладка не разрушалась из-за конденсата который образуется из-за низких температур дыма. Этот конденсат стекает по трубе вниз в ведро (можно увидеть на фото). Чисто эстетически это неприятно, но факап установки в том, что установив трубу мне перекрыли дымоход из бани. Отчасти это была моя вина, прийдётся делать электрическую баню.

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

Я было уже начал думать что сам котёл слишком мощный вышел, а трубы и батареи хилые, но..

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

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

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

Топливо

Пеллетные гранулы бывают 6мм и 8мм в длину. Разница лишь в том, что это влияет на объём который забирает hopper из бака (для распаливания 40г например надо).

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

В Эстонии заказать можно машину (2-4 тонны), а можно купить пакетами по 15-25 кг. Расчитывая расход осенью в 10кг в день (как вы видели на скриншотах выше), получается 300кг в месяц (40 евро/мес). В зимний период я думаю расход будет раза в два больше (под 100 евро/мес). Оптовые производители:

  • Pro Wood (165 евро за тонну, в 15 кг пакетах чуть дороже, но в строительных их же продукция в магазинах выходит аж по 230 евро за тонну)
  • Pelletiküte (160-180 евро за тонну) - увы эти товарищи в Таллинне складов не имеют, можно только заказать доставку (4 тонны самое оптимальное)
  • Nordic Pellets (в строительных последние можно найти по 215 евро за тонну, 20 кг пакеты)
  • Briketipoisid

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

Опыт работы

После нескольких месяцев отопления, пришёл к таким заключениям..

  • ​Автоматика работает по приоритетам - сначала нагрев воды (DHW), потом нагрев первого этажа (zone 1), потом уже нагрев второго этажа.
  • Если вы поставите скажем на zone 1 заведомо недостижимую температуру (80 градусов при температуре котла в 65), то весь напор воды будет идти только на первый этаж, а второй будет в холоде
  • Температура котла прыгает волнами, что-бы выровнять её, можно повысить минимальную мощность

Умный дом в перспективе

В идеале умный дом должен в себя включать

  • датчики аварии (протечки воды, пожара, электроотключения)

  • датчики безопасности (открытия дверей, окон, движения на участке)

  • видео-трансляция и запись

  • управление освещением (умный свет внутри дома и освещение участка, гардины/жалюзи)

  • управление поливом газона (в зависимости от прогноза погоды)

  • электрические замки/ключи

Умная техника

  • плита которая оповещает вас если вы забыли её выключить

  • холодиль​ник, в который можно посмотреть удалённо

  • стиралка, которую можно удалённо приостановить

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

  • Собственный источник воды, смягчитель с промывкой солью, питьевой фильтр обратного осмоса
  • Электрические панели, инвертор и батарея
  • Вентиляция с удержанием тепла

Микросервисы 2

· 3 мин. чтения

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

Docker

Я сразу скажу что не знаю как настраивать production с докер-контейнерами, но сервисы в рабочем окружении поднимаются тривиально

Концепции

Images (образы) это изолированная среда, как правило с конкретным языком (node, php) или библиотекой. За это отвечает Dockerfile, который ссылается на существующий, скачиваемый образ на докер хабе.

Что-бы увидеть установленные образы, есть комманда  docker images . 

Контейнеры  это запущенные образы которые изолированы от host-машины. Обычно контейнер поднимается для какого-то сервиса, поэтому у него есть своё название, явно объявлен маппинг сетевых портов на host-машину и способ монтирования файловой системы -  за это отвечает docker-compose.yml

Что-бы увидеть установленные образы, есть комманда  docker images . 

Контейнеры  это запущенные образы которые изолированы от host-машины. Обычно контейнер поднимается для какого-то сервиса, поэтому у него есть своё название, явно объявлен маппинг сетевых портов на host-машину и способ монтирования файловой системы -  за это отвечает docker-compose.yml

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

Что-бы увидеть запущенные контейнеры, есть комманда  docker ps  (а лучше dry)

Что-бы запустить текущую папку есть  docker-compose down && docker-compose up  — это основная комманда которой вы будете пользоваться в разработке если будете делать изменения

Для автоматизации перезагрузки контейнера при изменении файлов на hostе, для node надо копать в сторону pm2-docker

Consul

Консул это сервер, который служит для связывания сервисов воедино (service discovery), поддержания их состояния здоровья (healthcheck) и для их конфигурации без перезапуска (key-value storage)

Каждый поднимающийся сервис сам должен зарегистрировать себя в консуле, указать на каком IP/порте он работает. Сам должен открыть HTTP endpoint который будет выдавать состояние здоровья

Сложности

При создании микросервисов самая сложная часть это граница и управление.  Сервис должен отвечать за конкретную бизнес-функцию и доменную область. Это вертикальный срез приложения.  Но при этом сервис должен выполнять весь стек работы — ui, backend, db storage, queue processor. Впихивать столько ответсвенности в один сервис технологически сложно, поэтому приходится дробить вертикальный стек ещё на несколько горизонтальных слоёв. Образно был article-manager - стал article-frontend, article-server, article-worker, над которыми нависают ещё всякие сервисы мониторинга. Это тяжело связывать вместе и деплоить разом.

Node

Поскольку нода висит постоянно в памяти, в отличие от php, который запускается при запросе, то возникает проблема перезагрузки кода при его изменении. Вот как выглядит Dockerfile с PM2:

FROM node:6-alpine
USER root
ENV PORT=3000
EXPOSE 3000
RUN npm install pm2 -g
WORKDIR /app
CMD ["pm2-docker", "start", "pm2.json", "--watch"]

Теперь в pm2.json описывается при каком случае надо перезапускать докер сервис

{
"apps": [
{
"name": "article-manager",
"script": "index.js",
"env": {
"PORT": 3000,
"CONSUL_IP": "192.168.10.10",
"CONSUL_PORT": 8500,
"SERVICE_NAME": "article-manager"
},
"watch": true,
"ignore_watch": [
"node_modules",
"npm-debug.log",
".idea",
".git",
"test/coverage"
],
"watch_options": {
"followSymlinks": false
}
}
]
}

Redis

Очень быстрая in-memory база для кеширования данных

version: '2'
services:
redis-master:
image: 'redis:2.8'
network_mode: bridge
volumes:
- ./data:/data
ports:
- 6379:6379
command: redis-server --appendonly yes

Alias

Для удобства, советую добавить в ваш ~/.bashrc или ~/.zshrc алиас на быстрое поднятие контейнера:

alias doc='docker-compose down && docker-compose up'