Как инвестировать в криптовалюту и вовремя не потерять |
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Метки: author Jholinar финансы в it криптовалюта биткоин финансы инвестиции api blockchain |
Cisco Digital Network Architecture: основные возможности новой платформы |
Метки: author Orest_ua сетевые технологии серверная оптимизация it- инфраструктура cisco блог компании мук digital network architecture сети |
DLP и Закон: как правильно оформить внедрение системы для защиты от утечек |
Метки: author SolarSecurity информационная безопасность блог компании solar security dlp юридические тонкости юридические вопросы защита информации защита от утечек |
[Из песочницы] Автоматизация рыбной ловли для World of Warcraft |
import pyscreenshot as ImageGrab
screen_size = None
screen_start_point = None
screen_end_point = None
# Сперва мы проверяем размер экрана и берём начальную и конечную точку для будущих скриншотов
def check_screen_size():
print "Checking screen size"
img = ImageGrab.grab()
# img.save('temp.png')
global screen_size
global screen_start_point
global screen_end_point
# я так и не смог найти упоминания о коэффициенте в методе grab с параметром bbox, но на моем макбуке коэффициент составляет 2. то есть при создании скриншота с координатами x1=100, y1=100, x2=200, y2=200), размер картинки будет 200х200 (sic!), поэтому делим на 2
coefficient = 2
screen_size = (img.size[0] / coefficient, img.size[1] / coefficient)
# берем примерно девятую часть экрана примерно посередине.
screen_start_point = (screen_size[0] * 0.35, screen_size[1] * 0.35)
screen_end_point = (screen_size[0] * 0.65, screen_size[1] * 0.65)
print ("Screen size is " + str(screen_size))
def make_screenshot():
print 'Capturing screen'
screenshot = ImageGrab.grab(bbox=(screen_start_point[0], screen_start_point[1], screen_end_point[0], screen_end_point[1]))
# сохраняем скриншот, чтобы потом скормить его в OpenCV
screenshot_name = 'var/fishing_session_' + str(int(time.time())) + '.png'
screenshot.save(screenshot_name)
return screenshot_name
def main():
check_screensize()
make_screenshot()
import cv2
import numpy as np
from matplotlib import pyplot as plt
def find_float(screenshot_name):
print 'Looking for a float'
for x in range(0, 7):
# загружаем шаблон
template = cv2.imread('var/fishing_float_' + str(x) + '.png', 0)
# загружаем скриншот и изменяем его на чернобелый
src_rgb = cv2.imread(screenshot_name)
src_gray = cv2.cvtColor(src_rgb, cv2.COLOR_BGR2GRAY)
# берем ширину и высоту шаблона
w, h = template.shape[::-1]
# магия OpenCV, которая и находит наш темплейт на картинке
res = cv2.matchTemplate(src_gray, template, cv2.TM_CCOEFF_NORMED)
# понижаем порог соответствия нашего шаблона с 0.8 до 0.6, ибо поплавок шатается и освещение в локациях иногда изменяет его цвета, но не советую ставить ниже, а то и рыба будет похожа на поплавок
threshold = 0.6
# numpy фильтрует наши результаты по порогу
loc = np.where( res >= threshold)
# выводим результаты на картинку
for pt in zip(*loc[::-1]):
cv2.rectangle(src_rgb, pt, (pt[0] + w, pt[1] + h), (0,0,255), 2)
# и если результаты всё же есть, то возвращаем координаты и сохраняем картинку
if loc[0].any():
print 'Found float at ' + str(x)
cv2.imwrite('var/fishing_session_' + str(int(time.time())) + '_success.png', src_rgb)
return (loc[1][0] + w / 2) / 2, (loc[0][0] + h / 2) / 2 # опять мы ведь помним, что макбук играется с разрешениями? поэтому снова приходится делить на 2
def main():
check_screensize()
img_name = make_screenshot()
find_float(img_name)
import autopy
def move_mouse(place):
x,y = place[0], place[1]
print("Moving cursor to " + str(place))
autopy.mouse.smooth_move(int(screen_start_point[0]) + x , int(screen_start_point[1]) + y)
def main():
check_screensize()
img_name = make_screenshot()
cords = find_float(img_name)
move_mouse(cords)
import pyaudio
import wave
import audioop
from collections import deque
import time
import math
def listen():
print 'Listening for loud sounds...'
CHUNK = 1024
FORMAT = pyaudio.paInt16
CHANNELS = 2
RATE = 18000 # битрейт звука, который мы хотим слушать
THRESHOLD = 1200 # порог интенсивности звука, если интенсивность ниже, значит звук по нашим меркам слишком тихий
SILENCE_LIMIT = 1 # длительность тишины, если мы не слышим ничего это время, то начинаем слушать заново
# открываем стрим
p = pyaudio.PyAudio()
stream = p.open(format=FORMAT,
channels=CHANNELS,
rate=RATE,
# output=True, # на мак ос нет возможности слушать output, поэтому мне пришлось прибегнуть к использованию Soundflower, который умеет перенаправлять канал output в input, таким образом мы перехватываем звук игры будто это микрофон
input=True,
frames_per_buffer=CHUNK)
cur_data = ''
rel = RATE/CHUNK
slid_win = deque(maxlen=SILENCE_LIMIT * rel)
# начинаем слушать и по истечении 20 секунд (столько максимум длится каждый заброс поплавка), отменяем нашу слушалку.
success = False
listening_start_time = time.time()
while True:
try:
cur_data = stream.read(CHUNK)
slid_win.append(math.sqrt(abs(audioop.avg(cur_data, 4))))
if(sum([x > THRESHOLD for x in slid_win]) > 0):
print 'I heart something!'
success = True
break
if time.time() - listening_start_time > 20:
print 'I don't hear anything during 20 seconds!'
break
except IOError:
break
# обязательно закрываем стрим
stream.close()
p.terminate()
return success
def main():
check_screensize()
img_name = make_screenshot()
cords = find_float(img_name)
move_mouse(cords)
listen()
def snatch():
print('Snatching!')
autopy.mouse.click(autopy.mouse.RIGHT_BUTTON)
def main():
check_screensize()
img_name = make_screenshot()
cords = find_float(img_name)
move_mouse(cords)
if listen():
snatch()
Метки: author kio_tk python world of warcraft боты opencv |
[конспект админа] Меньше администраторов всем |
Продолжим про безопасность операционных систем – на этот раз «жертвой» станет MS Windows и принцип предоставления минимальных прав для задач системного администрирования.
Сотрудникам, ответственным за определенные серверы и рабочие станции совсем не обязательно выдавать права «администратор домена». Хоть не по злому умыслу, по ошибке, но это может подпортить всем жизнь, а то и стоить чьих-то выходных. Под катом детально разберем принцип предоставления минимальных прав как одну из технологий предоставления минимальных прав.
В качестве примера из практики могу привести грустную историю со счастливым концом. В организации исторически сложилось, что сервер печати находился на контроллере домена. В один прекрасный момент сотруднику отдела IT понадобилось перепрошить принтер, что он и проделал, запустив китайскую утилиту на сервере. Принтер заработал, но вот утилита в процессе перепрошивки перевела время на несколько лет назад. Active directory не очень любит путешественников во времени, и контроллер домена благополучно отправился в «захоронение» (tombstone).
Инцидент добавил седых волос, но второй контроллер домена спас ситуацию: роли FSMO перевели на него, а путешественника во времени повторно сделали контроллером домена. С тех пор в компании права «администратора домена» нужно заслужить.
Для профилактики подобных ситуаций неплохо будет выдавать желающим ровно столько прав, сколько нужно: если нужно администрировать только рабочие станции, достаточно выдать права только на компьютеры пользователей.
Когда компьютеров немного, включить доменную группу безопасности «helpdesk» в локальную группу «администраторы» можно и руками. А вот на большом объеме приходят на помощь групповые политики. Удобных способов два.
Первый способ: через Группы с ограниченным доступом (Restricted groups), расположенные в групповых политиках по адресу Конфигурация компьютера – Политики – Параметры безопасности.
Расположение политик Restricted groups.
Далее нужно создать группу «Администраторы» и добавить в нее нужную группу. Есть только один нюанс – если сделать именно так, то из локальной группы «Администраторы» исчезнут все, кроме встроенного администратора и самой группы. Даже Domain Admins:
Добавляем группу «Администраторы», в которую добавляем группу helpdesk.
И получаем локальную группу «Администраторы» без Domain admins.
Конечно, эту возможность можно использовать и во благо – зачистить локальные группы от лишних участников. Если же хочется избежать такой зачистки, то можно создать в «Группах ограниченного доступа» доменную группу и ее же назначить входящей в группу «Администраторы»:
При такой настройке локальная группа «Администраторы» не будет зачищена.
Вторым способом является настройка Предпочтения Групповых Политик (Group Policy Preference, далее – GPP). Искать следует в Конфигурации компьютера – Настройка – Локальные пользователи и группы.
Настройка группы безопасности через GPP.
Как и все настройки в GPP, эта проще в понимании и с более дружелюбным интерфейсом. Но если у вас в инфраструктуре присутствуют не обновленные Windows XP или даже Windows 2000, то остается только первый вариант.
Таким же способом можно дать права и на определенные серверы нужным сотрудникам. Например, дать права группе разработчиков на тестовый стенд.
Конечно, сотрудников отдела IT и системные учетные записи (например, под которыми выполняются задачи резервного копирования) проще сразу включить в группу «Enterprise Admins» и не знать горя.
Но из соображений безопасности лучше так не делать. В Windows существует набор встроенных учетных записей с набором типовых прав. Группы немного различаются для компьютера и для домена, а также ряд сервисов привносит свои группы.
Группа | Описание |
Администраторы | Полные права на систему. |
Пользователи | Возможность пользоваться без изменения системных параметров и без записи в системные разделы. Фактически пользователь – полноценный хозяин только в папке своего профиля. |
Операторы архива | Группа, предназначенная для выполнения резервного копирования и восстановления. Участники группы могут завершать работу системы на серверах и переопределять права доступа в целях резервного копирования. |
Опытные пользователи | Участники этой группы могут администрировать локальные учетные записи и группы (кроме администраторов), создавать сетевые ресурсы и управлять доступом на них, менять NTFS ACL (кроме смены владельца папки). |
Пользователи удаленного рабочего стола | Членство дает возможность подключаться к компьютеру по RDP |
Операторы печати | Операторы могут устанавливать и удалять принтеры, изменять их драйвера и настройки, останавливать и чистить очередь печати. |
Операторы настройки сети | Могут менять настройки сетевых интерфейсов. Это полезная группа на случай если нужно переназначать получение адреса сетевой картой с автоматического на статическое. Мобильные пользователи скажут спасибо, если добавить их в эту группу. |
Операторы учета | Пользователи в этой группе могут создавать/удалять/редактировать/перемещать учетные записи в Active Directory. Удобно дать эти права для сервиса, автоматически заводящего учетки сотрудников после приема на работу. |
Познакомиться со всеми группами и более полным описанием можно в официальной документации.
Если стандартных групп не хватает, то Windows позволяет настроить права доступа более тонко. Например, выдать отдельной группе пользователей право менять время или возможность принудительно завершать работу сервера по сети. Для этого существует механизм «назначение прав пользователей». Искать можно в локальной политике безопасности – secpol.msc или в групповой политике по адресу Конфигурация компьютера – Конфигурация Windows – Параметры безопасности – Локальные политики – Назначение прав пользователя.
Настройка прав доступа через групповые политики.
Использовать эту настройку я рекомендую в крайних случаях, и ее обязательно надо документировать. Помните о том, что когда-нибудь вас кто-то сменит и будет разбираться, почему работает так, а не иначе.
Вообще лучше всегда все документировать. Представьте ситуацию, что вы уволились из организации и вместо вас пришел человек с улицы. Поставьте себя на место этого человека. Если начал дергаться глаз или зашевелились волосы – посвятите время написанию документации. Пожалуйста!
Существует еще один хороший метод ограничения доступа к объектам – делегирование. Про эту технологию на Хабре уже писали, поэтому я лишь добавлю, что с помощью делегирования удобно выдаются права для ввода нового компьютера в домен.
Все эти технологии довольно давно существуют в системах Windows. С появлением Windows 10\2016 появилась еще одна интересная возможность ограничить учетные записи – речь о ней пойдет далее.
Just Enough Administration (JEA) – технология предоставления доступа к командлетам PowerShell. Работает на операционных системах вплоть до Windows 7 при установке Windows Management Framework 5.1 (правда, в самых старых операционных системах поддержка ограничена). Работа производится через так называемые «виртуальные аккаунты» и специально подготовленные файлы конфигурации. Примером использования JEA является выдача ограниченных прав на управление определенными виртуальными машинами – например, для ваших разработчиков.
Подробнее про JEA можно почитать в официальной документации, поэтому разберем конкретный пример предоставления возможности перезапуска виртуальной машины.
Сначала нам нужно разрешить удаленное подключение к серверу с помощью командлета Enable-PSRemoting, а заодно убедимся, что у нас Windows Management Framework нужной версии при помощи командлета $PSVersionTable.PSVersion.
Проверка версии и разрешение удаленных подключений при помощи PS.
Создадим группу безопасности и специального пользователя:
$VMOperatorGroup = New-ADGroup -Name "VM-operators" -GroupScope DomainLocal -PassThru
$OperatorUser = New-ADUser -Name "VMOperator" -AccountPassword (ConvertTo-SecureString 'P@ssword1' -AsPlainText -Force) -PassThru
Enable-ADAccount -Identity $OperatorUser
Add-ADGroupMember -Identity $VMOperatorGroup -Members $OperatorUser
Теперь создадим нужные для работы конфигурационные файлы и папки. Сначала общие:
New-Item -Path "C:\Program Files\WindowsPowerShell\Modules\Demo_Module" -ItemType Directory
New-ModuleManifest -Path "C:\Program Files\WindowsPowerShell\Modules\Demo_Module\Demo_Module.psd1"
New-Item -Path "C:\Program Files\WindowsPowerShell\Modules\Demo_Module\RoleCapabilities" -ItemType Directory
А затем создадим конкретный файл конфигурации для нашего оператора виртуальной машины с именем win. Для примера разрешим запуск и остановку виртуальной машины:
$VMRoleCapabilityParams = @{
Author = 'Сервер Молл'
Description = 'VM Role Capability File'
CompanyName = 'ServerMall'
VisibleCmdlets= 'Get-VM',
@{ Name='Start-VM'; Parameters=@{ Name='Name'; ValidateSet='win' } },
@{ Name = 'Stop-VM'; Parameters = @{ Name = 'Name'; ValidateSet = 'win'}}
New-PSRoleCapabilityFile -Path "$ENV:ProgramFiles\WindowsPowerShell\Modules\Demo_Module\RoleCapabilities\VMRoleCapability.psrc" @VMRoleCapabilityParams
Теперь необходимо подготовить файл сессии PowerShell:
$NonAdministrator = "DOMAIN\VM-win-Operators"
$ConfParams = @{
SessionType = 'RestrictedRemoteServer'
RunAsVirtualAccount = $true
RoleDefinitions = @{
$NonAdministrator = @{ RoleCapabilities = 'VMRoleCapability'}
}
TranscriptDirectory = "$env:ProgramData\JEAConfiguration\Transcripts"
}
New-Item -Path "$env:ProgramData\JEAConfiguration" -ItemType Directory
$SessionName = 'VM_OperatorSession'
New-PSSessionConfigurationFile -Path "$env:ProgramData\JEAConfiguration\VM.pssc" @ConfParams
Зарегистрируем файл сессии:
Register-PSSessionConfiguration -Name 'VM_OperatorSession' -Path "$env:ProgramData\JEAConfiguration\VM.pssc"
Теперь все готово для проверки. Попробуем подключиться к серверу с учетными данными созданного пользователя командлетом:
Enter-PSSession -ComputerName SERVERNAME -ConfigurationName VM_OperatorSession -Credential (Get-Credential)
Проверим список доступных команд командой get-command и попробуем остановить нашу виртуальную машину win, а затем другую машину win2.
Доступ к серверу ограничен управлением одной виртуальной машиной.
Для облегчения создания файлов конфигурации сообществом была создана утилита под названием JEA Toolkit Helper, где графический интерфейс поможет создать файлы с необходимыми параметрами.
Интерфейс JEA Toolkit Helper.
При необходимости есть возможность через групповые политики включить аудит выполнения модулей по адресу Конфигурация компьютера – Административные шаблоны – Windows Powershell – Включить ведение журнала модулей. Тогда в журнале Windows будут отображаться записи о том что, где и когда.
Журнал выполнения PowerShell.
Альтернативой будет включение записи в файл. Также через групповые политики настраивается параметр «Включить транскрипции PowerShell». Путь можно задать как в самой политике (и тогда запись туда будет вестись для всех модулей), так и в файле конфигурации сессии JEA в параметре TranscriptDirectory.
Файловый журнал JEA.
С помощью делегирования, назначения прав и JEA можно добиться отказа от использования учетных записей с администраторскими правами в повседневной работе. В конце-концов, к UAC в Windows ведь тоже привыкли и не отключаем просто потому, что «заткнись, я и так знаю что мне делать со своими файлами!».
Метки: author Tri-Edge системное администрирование powershell it- инфраструктура блог компании сервер молл настройка windows делегирование полномочий админстрирование windows |
Цифровая экономика и экосистема R |
Если смотреть прессу, словосочетание «цифровая экономика» ожидается одним из популярных в ближайшие несколько лет.
Но чтобы от перейти от слов к делу и действительно совершить цифровой скачок необходимо пересмотреть подходы и используемые инструменты. В рамках настоящей публикации, являющейся продолжением предыдущих публикаций, планирую кратко проиллюстрировать, тезис о том, что применение в бизнесе R экосистемы прекрасно вписывается в задачу перехода к цифровой экономике.
В эволюционного развития различных задач были пересмотрены различные методики и современные open-source средства. В результате сформировался достаточно универсальный стек общего назначения, общая архитектура которого выглядит следующим образом:
Ключевые компоненты решения
В зависимости от предметной области, типов и масштабов данных могут использоваться не все элементы стека. Но какая бы задачи ни была, аналитическим ядром, а также лицом системы с точки зрения пользователя остается R & Shiny соотвественно.
Как правило, большинство людей ожидают увидеть «отчеты», не детализируя, что именно они в это слово вкладывают. Экосистема R позволяет получать много больше типичных ожиданий:
Средой существования всех упомянутых типов отчетов и АРМ является Shiny Server\Connect Server. В платной или бесплатной редакции — зависит от требований, которые выходят за рамки аналитики и определяются требованиями по нагрузке, безопасности, централизованному управлению.
P.S.
Практика раз за разом показывает, что цифровые преобразования упираются отнюдь не в возможности инструментов (open-source), а в неготовность людей менять восприятие, изучать новое, мыслить стратегически или просто страх перемен.
Примером подобного типового пожелания является наличие «визуального» конструктора, так, чтобы только мышкой, без какого-либо программирования можно было получить результат неограниченной сложности. Однако, это красивое требование, культивируемое представителями BI визуализации, очень плохо сочетается с самим содержанием цифровых перемен которые ожидают человечество.
Парадокс этого требования вполне прозрачен. Повсеместно используя машины в качестве помощников крайне затруднительно общаться с ними с помощю ограниченного языка жестов или словаря Эллочки-людоедки. Даже из теории информации следует, что двумя-тремя кликами очень мало чего можно передать, если только это не код заранее досконально согласованного действия.
В цифровом мире язык програмимирования становится таким же важным знанием, как язык международного общения. Интересно, что в отдельных западных компаниях, воспринимавшихся ранее как классическое производство, программирование становится важным навыком даже для менеджеров. Прекрасный пример подобной трансформации — компания GE, подразделеие GE Digital. Ролик — Discover GE Digital: The Digital Industrial Company
Метки: author i_shutov data mining big data data science |
[Перевод] Apollo Link. Настраиваем клиент GraphQL «под себя» |
Возможно, вы встречали библиотеку, которая отвечает вашим потребностям, но не решает пару специфичных задач. И хотя эти задачи не относятся к основным функциям, но являются важной частью приложения. Нечто похожее бывает в современных клиентах GraphQL на сетевом уровне. В ответ на подобные вызовы мы создали библиотеку Apollo Link. Она дает каркас для управления ходом запросов GraphQL и для обработки результатов.
Чтобы ускорить разработку, стандартные модули Apollo Link реализуют основные функции сетевых стеков GraphQL от обычных HTTP-запросов до подписки на изменения через веб-сокеты и управления ходом запросов, включая повторную и пакетную отправку, фильтрацию дублирующихся запросов, синхронный периодический опрос ресурсов.
Примечание переводчика – В оригинальной статье сетевые модули называется словом Link. Это отражает сущность Apollo Link как компоновщика, соединяющего модули в цепочку. Однако дословный перевод Link искажает смысл, поэтому далее в статье модули называются коннекторами.
Чтобы создать клиент GraphQL с заданными свойствами, коннекторы Apollo Link соединяют с пользовательскими коннекторами в нужной последовательности. Добавленный в цепочку коннектор влияет на ход выполнения запроса, например обеспечивает повторную отправку. Результирующий коннектор может возвращать ExecutionResult
(данные + ошибки). Это могут быть, например, подменные данные для тестирования, локальное состояние приложения или, чаще всего, результат запроса к серверу GraphQL.
Рис. HTTP-коннектор.
Чтобы поддержать различные требования приложений, каждый ответ GraphQL представлен объектом Observable
. Обсерверы можно подписывать на события next
, error
, complete
и запускать обработчики событий с помощью одноименных методов. Метод next
можно вызвать любое количество раз прежде чем сработает келбек error
или complete
. Такая структура келбеков прекрасно подходит для работы с текущими и планируемыми результатами GraphQL, включая запросы, мутации, подписки и даже «живые» запросы.
В этой статье мы шаг за шагом создадим клиент GraphQL с Apollo Link. Результаты будут показываться в GraphiQL.
Основная задача всех GraphQL-клиентов – получать GraphQL-результаты. Поэтому начнем с создания коннектора, который делает HTTP-запросы. Он станет полезным примером для других коннекторов транспортного уровня, например для использования конечных точек Firebase, XHR, REST и других конечных точек GraphQL. Все коннекторы наследуют от базового класса, который содержит методы для соединения коннекторов и нужен для реализации метода request
.
Посмотрите реализацию в песочнице на CodeSandbox
Следующая задача после создания транспортного коннектора – объединить коннекторы в поток обработки запроса. Для этого создадим еще коннектор, который перехватывает ошибки и представляет их в виде результирующих данные GraphQL, и другой коннектор – для логирования операций и результатов. Первым будет применяться логирующий коннектор, затем перехватывающий ошибки и наконец HTTP-коннектор будет выполнять запрос.
Рис. Последовательность применения коннекторов.
Чтобы цепочка заработала, логирующий и перехватывающий коннекторы должны иметь доступ к следующему за ними коннектору. Для этого у метода request
есть аргумент forward
. Это функция, которая при вызове передает объект-операцию следующему коннектору и возвращает его обсервер. В конце примера коннекторы собираются в цепочку с помощью статического метода from
из Apollo Link.
Посмотрите пример этой цепочки в песочнице на CodeSandbox
Здорово! Теперь созданный GraphQL-клиент управляет ходом запросов и ответов. А что если для запросов и мутаций нужно разное поведение? В следующем примере используются другие конечные точки для мутаций, также ошибки перехватываются только при запросе данных и логируется вся сетевая активность.
Дополнительно к этому можно выборочно изменять операцию не меняя транспорт, например добавлять переменные запроса, если операция имеет определенное имя. С помощью метода split
Apollo Link позволяет выполнять те или иные части цепочки в зависимости от параметров операции.
Посмотрите пример в песочнице на CodeSandbox
Отлично! Теперь можно создать полностью настраиваемый клиент GraphQL, у которого логика выполнения и получение данных зависят от конкретного запроса. Apollo Link предлагает множество готовых коннекторов, которые можно комбинировать и расширять вашими собственными коннекторами для достижения нужного поведения. Готовые коннекторы можно найти в репозитории Apollo Link.
Экосистема Apollo Link постоянно развивается благодаря сообществу разработчиков. Если вы хотите поучаствовать в разработке или обсудить механизм настройки клиента GraphQL, пожалуйста создайте соответствующий запрос – issue или pull request. Если у вас есть предложения для сотрудничества, подключитесь к Apollo Slack и отправьте мне (evans) личное сообщение!
В скором времени ждите статьи о взаимодействии между коннекторами с помощью поля context
в операции GraphQL, о имеющих и не имеющих состояние коннекторах, о распространении конфигурации коннектора, о безопасном добавлении типа и другие!
Благодарю Sashko Stubailo, James Baxley III и Jonas Helfer за исчерпывающие поясненияо процессе разработки Apollo Link и за непрекращающуюся поддержку автора.
Перевод статьи Apollo Link: Creating your custom GraphQL client.
Автор оригинала Evans Hauser
Метки: author teux разработка веб-сайтов api apollo graphql apollo link |
Camunda представляет Open Source проект Zeebe для oркестрирование микросервисов инструментами BPMN |
Метки: author asushko тестирование веб-сервисов программирование camunda bpm- системы bpm микросервисы |
Новые инструменты Safari для отладки WebRTC |
Метки: author eyeofhell разработка веб-сайтов программирование safari javascript блог компании voximplant webrtc |
Запись вебинара «Как надежно защитить предприятие от неизвестных угроз и шифровальщиков» |
|
[Из песочницы] Chromebook для удаленной работы. Настраиваем VPN и RDP |
openvpn --mktun --dev tap0
openvpn --config /usr/local/vpn/openvpn.ovpn --dev tap0
openvpn --rmtun --dev tap0
Метки: author Zin4uk системное администрирование *nix cromebook remote linux vpn remmina rdp |
[Перевод] Погружение в F#. Пособие для C#-разработчиков |
Этот пост будет не о том, как «перевести» код с C# на F#: различные парадигмы делают каждый из этих языков лучшим для своего круга задач. Однако вы сможете оценить все достоинства функционального программирования быстрее, если не будете думать о переводе кода из одной парадигмы в другую. Настало время любопытных, пытливых и готовых изучать совершенно новые вещи. Давайте начнем!
Ранее, в посте «Почему вам следует использовать F#», мы рассказали, почему F# стоит попробовать прямо сейчас. Теперь мы разберем основы, необходимые для его успешного применения. Пост предназначен для людей, знакомых с C#, Java или другими объектно-ориентированными языками. Если вы уже пишете на F#, эти понятия должны быть вам хорошо знакомы.
Перед тем, как приступить к изучению понятий функционального программирования, давайте посмотрим на небольшой пример и определим, в чем F# отличается от C#. Это базовый пример с двумя функциями и выводом результата на экран:
let square x = x * x
let sumOfSquares n =
[1..n] // Создадим список с элементами от 1 до n
|> List.map square // Возведем в квадрат каждый элемент
|> List.sum // Просуммируем их!
printfn "Сумма квадратов первых 5 натуральных чисел равна %d" (sumOfSquares 5)
Обратите внимание, что здесь нет явного указания типов, отсутствуют точки с запятой или фигурные скобки. Скобки используются в единственном месте: для вызова функции sumOfSquares
с числом 5
в качестве входного значения и последующего вывода результата на экран. Конвейерный оператор |>
(pipeline operator) используется так же, как конвейеры (каналы, pipes) в Unix. square
— это функция, которая напрямую передается в функцию List.map
как параметр (функции в F# рассматриваются как значения, first-class functions).
Хотя различий на самом деле еще много, сперва стоит разобраться с фундаментальными вещами, поскольку они — ключ к пониманию F#.
Следующая таблица показывает соответствия между некоторыми ключевыми понятиями C# и F#. Это умышленно короткое и неполное описание, но так его проще запомнить в начале изучения F#.
C# и Объектно-Ориентированное Программирование | F# и Функциональное Программирование |
---|---|
Переменные | Неизменяемые значения |
Инструкции | Выражения |
Объекты с методами | Типы и функции |
Быстрая шпаргалка по некоторым терминам:
Переменные — это значения, которые могут меняться. Это следует из их названия!
Неизменяемые значения — это значения, которые не могут быть изменены после присваивания.
Инструкции — это команды, исполняемые после запуска программы.
Выражения — это фрагменты кода, которые можно вычислить и получить значения.
Стоит отметить, что все указанное в столбце C# так же возможно в F# (и довольно легко реализуется). В столбце F# также есть вещи, которые можно сделать в C#, хотя и намного сложнее. Следует упомянуть, что элементы в левом столбце не являются "плохими" в F#, и наоборот. Объекты с методами отлично подходят для использования в F# и часто являются лучшим решением в зависимости от вашей ситуации.
Одним из наиболее непривычных понятий в функциональном программировании является неизменяемость (иммутабельность, immutability). Ему часто уделяют недостаточно внимания в сообществе любителей функционального программирования. Но если вы никогда не использовали язык, в котором значения неизменяемы по умолчанию, это часто является первым и наиболее значимым препятствием для дальнейшего изучения. Неизменяемость является фундаментальным понятием практически во всех функциональных языках.
let x = 1
В предыдущем выражении значение 1
связано с именем x
. В течение всего времени существования имя x
теперь ссылается на значение 1
и не может быть изменено. Например, следующий код не может переназначить значение x
:
let x = 1
x = x + 1 // Это выражение ничего не присваивает!
Вместо этого, вторая строка является сравнением, определяющим, является ли x
равным x + 1
. Хотя существует способ изменить (мутировать, mutate) x
с помощью использования оператора <-
и модификатора mutable
(см. подробности в Mutable Variables), вы быстро поймете, что проще думать о решении задач без переприсвоения значений. Если не рассматривать F# как еще один императивный язык программирования, вы сможете использовать его самые сильные стороны.
Неизменяемость существенным образом преобразует ваши привычные подходы к решению задач. Например, циклы for
и другие базовые операции императивного программирования не так часто используются в F#.
Рассмотрим более конкретный пример: вы хотите возвести в квадрат числа из входного списка. Вот как это можно сделать в F#:
// Определим функцию, которая вычисляет квадрат значения
let square x = x * x
let getSquares items =
items |> List.map square
let lst = [ 1; 2; 3; 4; 5 ] // Создать список в F#
printfn "Квадрат числа %A равен %A" lst (getSquares lst)
Заметим, что в этом примере нет цикла for
. На концептуальном уровне это сильно отличается от императивного кода. Мы не возводим в квадрат каждый элемент списка. Мы применяем функцию square
к входному списку и получаем значения, возведенные в квадрат. Это очень тонкое различие, но на практике оно может приводить к значительно отличающемуся коду. Прежде всего, функция getSquares
на самом деле создает полностью новый список.
Неизменяемость — это гораздо более широкая концепция, чем просто иной способ управления данными в списках. Понятие ссылочной прозрачности (Referential Transparency) естественно для F#, и оказывает значительное влияние, как на разработку систем, так и на то, как части этих систем сочетаются. Функциональные характеристики системы становятся более предсказуемыми, когда значения не изменяются, если вы этого не ожидаете.
Более того, когда значения неизменяемы, конкурентное программирование становится проще. Некоторые сложные проблемы, возникающие в С# из-за изменяемого состояния, в F# не встречаются вообще. F# не может волшебным образом решить все ваши проблемы с многопоточностью и асинхронностью, однако он сделает многие вещи проще.
Как было упомянуто ранее, F# использует выражения (expressions). Это контрастирует с C#, где практически для всего используются инструкции (statements). Различие между ними может казаться на первый взгляд незначительным, однако есть одна вещь, о которой следует помнить: выражения производят значения. Инструкции — нет.
// 'getMessage' -- это функция, и `name` - ее входной параметр.
let getMessage name =
if name = "Phillip" then // 'if' - это выражение.
"Hello, Phillip!" // Эта строка тоже является выражением. Оно возвращает значение
else
"Hello, other person!" // То же самое с этой строкой.
let phillipMessage = getMessage "Phillip" // getMessage, при вызове, является выражением. Его значение связано с именем 'phillipMessage'.
let alfMessage = getMessage "Alf" // Это выражение связано с именем 'alfMessage'!
В предыдущем примере вы можете увидеть несколько моментов, которые отличают F# от императивных языков вроде C#:
if...then...else
— это выражение, а не инструкция.if
возвращает значение, которое в данном случае будет являться возвращаемым значением функции getMessage
.getMessage
— это выражение, которое принимает строку и возвращает строку.Этот подход сильно отличается от C#, но скорее всего он покажется вам естественным при написании кода на F#.
Если копнуть немного глубже, в F# даже инструкции описываются с помощью выражений. Такие выражения возвращают значение типа unit
. unit
немного похож на void
в C#:
let names = [ "Alf"; "Vasily"; "Shreyans"; "Jin Sun"; "Moulaye" ]
// Цикл `for`. Ключевое слово 'do' указывает, что выражение их внутренней области видимости должно иметь тип `unit`.
// Если это не так, то результат выражения неявно игнорируется.
for name in names do
printfn "My name is %s" name // printfn возвращает unit.
В предыдущем примере с циклом for
всё имеет тип unit
. Выражения типа unit
— это выражения, которые не имеют возвращаемого значения.
Предыдущие примеры кода использовали массивы и списки F#. В данном разделе разъясняются некоторые подробности.
F# предоставляет несколько типов коллекций и самые распространенные из них — это массивы, списки и последовательности.
IEnumerable
. Они вычисляются лениво.Массивы, списки и последовательности в F# также имеют особый синтаксис для выражений. Это очень удобно для различных задач, когда нужно генерировать данные программно.
// Создадим список квадратов первых 100 натуральных чисел
let first100Squares = [ for x in 1..100 -> x * x ]
// То же самое, но массив!
let first100SquaresArray = [| for x in 1..100 -> x * x |]
// Функция, которая генерирует бесконечную последовательность нечетных чисел
//
// Вызывать вместе с Seq.take!
let odds =
let rec loop x = // Использует рекурсивную локальную функцию
seq { yield x
yield! loop (x + 2) }
loop 1
printfn "Первые 3 нечетных числа: %A" (Seq.take 3 odds)
// Вывод: "Первые 3 нечетных числа: seq [1; 3; 5]
Если вы знакомы с методами LINQ, следующая таблица поможет вам понять аналогичные функции в F#.
LINQ | F# функция |
---|---|
Where |
filter |
Select |
map |
GroupBy |
groupBy |
SelectMany |
collect |
Aggregate |
fold или reduce |
Sum |
sum |
Вы также можете заметить, что такой же набор функций существует для модулей Seq
, List
и Array
. Функции модуля Seq
могут быть использованы для последовательностей, списков или массивов. Функции для массивов и списков могут быть использованы только для массивов и списков в F# соответственно. Также последовательности в F# ленивые, а списки и массивы — энергичные. Использование функций модуля Seq
на списках или массивах влечет за собой ленивое вычисление, а тип возвращаемого значения будет последовательностью.
Предыдущий раздел содержит в себе довольно много информации, но по мере написания программ на F# она станет интуитивно понятной.
Вы могли заметить, что оператор |>
используется в предыдущих примерах кода. Он очень похож на конвейеры в unix: принимает что-то слева от себя и передает на вход чему-то справа. Этот оператор (называется «pipe» или «pipeline») используется для создания функциональных конвейеров. Вот пример:
let square x = x * x
let isOdd x = x % 2 <> 0
let getOddSquares items =
items
|> Seq.filter isOdd
|> Seq.map square
В данном примере сначала items
передается на вход функции Seq.filter
. Затем возвращаемое значение Seq.filter
(последовательность) передается на вход функции Seq.map
. Результат выполнения Seq.map
является выходным значением функции getOddSquares
.
Конвейерный оператор очень удобно использовать, поэтому редко кто обходится без него. Возможно, это одна из самых любимых возможностей F#!
Поскольку F# — язык платформы .NET, в нем существуют те же примитивные типы, что и C#: string
, int
и так далее. Он использует объекты .NET и поддерживает четыре основных столпа объектно-ориентированного программирования. F# предоставляет кортежи (tuples), а также два основных типа, которые отсутствуют в C#: записи (records) и размеченные объединения (discriminated unions).
Запись — это группа упорядоченных именованных значений, которая автоматически реализует операцию сравнения — в самом буквальном смысле. Не нужно задумываться о том, как происходит сравнение: через равенство ссылок или с помощью пользовательского определения равенства между двумя объектами. Записи — это значения, а значения можно сравнивать. Они являются типами-произведениями, если говорить на языке теории категорий. У них есть множество применений, однако одно из самых очевидных — их можно использовать в качестве POCO или POJO.
open System
// Вот так вы можете определить тип-запись.
// Можно располагать метки на новых строках
type Person =
{ Name: string
Age: int
Birth: DateTime }
// Создать новую запись `Person` можно примерно так.
// Если метки расположены на одной строке, они разделяются точкой с запятой
let p1 = { Name="Charles"; Age=27; Birth=DateTime(1990, 1, 1) }
// Или же можно располагать метки на новых строках
let p2 =
{ Name="Moulaye"
Age=22
Birth=DateTime(1995, 1, 1) }
// Записи можно сравнивать на равенство. Не нужно определять метод Equals() и GetHasCode().
printfn "Они равны? %b" (p1 = p2) // Это выведет `false`, потому что они не равны.
Другой основной тип в F# — это размеченные объединения, или РО, или DU в англоязычной литературе. РО — это типы, представляющие некоторое количество именованных вариантов. На языке теории категорий это называется типом-суммой. Они также могут быть определены рекурсивно, что значительно упрощает описание иерархических данных.
// Определим обобщенное бинарное дерево поиска.
//
// Заметим, что обобщенный тип-параметр имеет ' в начале.
type BST<'T> =
| Empty
| Node of 'T * BST<'T> * BST<'T> // Каждый узел имеет левый и правый BST<'T>
// Развернем BST с помощью сопоставления с образцом!
let rec flip bst =
match bst with
| Empty -> bst
| Node(item, left, right) -> Node(item, flip right, flip left)
// Определим пример BST
let tree =
Node(10,
Node(3,
Empty,
Node(6,
Empty,
Empty)),
Node(55,
Node(16,
Empty,
Empty),
Empty))
// Развернем его!
printfn "%A" (flip tree)
Тадам! Вооружившись мощью размеченных объединений и F#, вы можете пройти любое собеседование, в котором требуется развернуть бинарное дерево поиска.
Наверняка вы увидели странный синтаксис в определении варианта Node
. Это на самом деле сигнатура кортежа. Это означает, что определенное нами BST может быть или пустым, или являться кортежем (значение, левое поддерево, правое поддерево)
. Более подробно про это написано в разделе о сигнатурах.
Следующий пример кода представлен с разрешения Скотта Влашина, героя сообщества F#, написавшего этот прекрасный обзор F# синтаксиса. Вы прочтете его примерно за минуту. Пример был немного отредактирован.
// Данный код представлен с разрешения автора, Скотта Влашина. Он был немного модифицирован.
// Для однострочных комментариев используется двойной слеш.
(*
Многострочные комментарии можно сделать вот так (хотя обычно используют двойной слеш).
*)
// ======== "Переменные" (на самом деле нет) ==========
// Ключевое слово "let" определяет неизменяемое (иммутабельное) значение
let myInt = 5
let myFloat = 3.14
let myString = "привет" // обратите внимание - указывать тип не нужно
// ======== Списки ============
let twoToFive = [ 2; 3; 4; 5 ] // Списки создаются с помощью квадратных скобок,
// для разделения значений используются точки с запятой.
let oneToFive = 1 :: twoToFive // оператор :: создает список с новым первым элементом
// Результат: [1; 2; 3; 4; 5]
let zeroToFive = [0;1] @ twoToFive // оператор @ объединяет два списка
// ВАЖНО: запятые никогда не используются для разделения значений, только точки с запятой!
// ======== Функции ========
// Ключевое слово "let" также определяет именованную функцию.
let square x = x * x // Обратите внимание - скобки не используются.
square 3 // А сейчас вызовем функцию. Снова никаких скобок.
let add x y = x + y // не используйте add (x,y)! Это означает
// совершенно другую вещь.
add 2 3 // Вызовем фукнкцию.
// чтобы определить многострочную функцию, просто используйте отступы.
// Точки с запятой не требуются.
let evens list =
let isEven x = x % 2 = 0 // Определет "isEven" как внутреннюю ("вложенную") функцию
List.filter isEven list // List.filter - это библиотечная функция
// с двумя параметрами: предикат
// и список, которые требуется отфильтровать
evens oneToFive // Вызовем функцию
// Вы можете использовать скобки, чтобы уточнить приоритет.
// В данном примере, сначала используем "map" с двумя аргументами,
// а потом вызываем "sum" для результата.
// Без скобок "List.map" была бы передана как аргумент в "List.sum"
let sumOfSquaresTo100 =
List.sum (List.map square [ 1 .. 100 ])
// Вы можете передать результат одной функции в следующую с помощью "|>"
// Вот та же самая функция sumOfSquares, переписанная с помощью конвейера
let sumOfSquaresTo100piped =
[ 1 .. 100 ] |> List.map square |> List.sum // "square" определена раньше
// вы можете определять лямбда-функции (анонимные функции)
// с помощью ключевого слова "fun"
let sumOfSquaresTo100withFun =
[ 1 .. 100 ] |> List.map (fun x -> x * x) |> List.sum
// В F# значения возвращаются неявно - ключевое слово "return" не используется
// Функция всегда возвращает значение последнего выражения в ее теле
// ======== Сопоставление с образцом ========
// Match..with.. - это case/switch инструкции "на стероидах".
let x = "a"
match x with
| "a" -> printfn "x - это a"
| "b" -> printfn "x - это b"
| _ -> printfn "x - это что-то другое" // подчеркивание соответствует "чему угодно"
// Some(..) и None приблизительно соответствуют оберткам Nullable
let validValue = Some(99)
let invalidValue = None
// В данном примере match..with сравнивает с "Some" и "None"
// и в то же время распаковывает значение в "Some".
let optionPatternMatch input =
match input with
| Some i -> printfn "целое число %d" i
| None -> printfn "входное значение отсутствует"
optionPatternMatch validValue
optionPatternMatch invalidValue
// ========= Сложные типы данных =========
// Кортежи - это пары, тройки значений и так далее.
// Кортежи используют запятые.
let twoTuple = (1, 2)
let threeTuple = ("a", 2, true)
// Записи имеют именованные поля. Точки с запятой являются разделителями.
type Person = { First: string; Last: string }
let person1 = { First="John"; Last="Doe" }
// Вы можете также использовать переносы на новую строку
// вместо точек с запятой.
let person2 =
{ First="Jane"
Last="Doe" }
// Объединения представляют варианты. Разделитель - вертикальная черта.
type Temp =
| DegreesC of float
| DegreesF of float
let temp = DegreesF 98.6
// Типы можно комбинировать рекурсивно различными путями.
// Например, вот тип-объединение, который содержит список
// элементов того же типа:
type Employee =
| Worker of Person
| Manager of Employee list
let jdoe = { First="John"; Last="Doe" }
let worker = Worker jdoe
// ========= Вывод на экран =========
// Функции printf/printfn схожи с функциями Console.Write/WriteLine из C#.
printfn "Вывод на экран значений типа int %i, float %f, bool %b" 1 2.0 true
printfn "Строка %s, и что-то обобщенное %A" "hello" [ 1; 2; 3; 4 ]
// все сложные типы имеют встроенный красивый вывод
printfn "twoTuple=%A,\nPerson=%A,\nTemp=%A,\nEmployee=%A"
twoTuple person1 temp worker
В дополнение, в нашей официальной документации для .NET и поддерживаемых языков есть материал «Тур по F#».
Всё описанное в данном посте — лишь поверхностные возможности F#. Мы надеемся, что после прочтения этой статьи вы сможете погрузиться в F# и функциональное программирование. Вот несколько примеров того, что можно написать в качестве упражнения для дальнейшего изучения F#:
Есть очень много других задач, для которых можно использовать F#; предыдущий список ни в коем случае не является исчерпывающим. F# используется в различных приложениях: от простых скриптов для сборки до бэкенда интернет-магазинов с миллиардной выручкой. Нет никаких ограничений по проектам, для которых вы можете использовать F#.
Для F# существует множество самоучителей, включая материалы для тех, кто пришел с опытом C# или Java. Следующие ссылки могут быть полезными по мере того, как вы будете глубже изучать F#:
Также описаны еще несколько способов, как начать изучение F#.
И наконец, сообщество F# очень дружелюбно к начинающим. Есть очень активный чат в Slack, поддерживаемый F# Software Foundation, с комнатами для начинающих, к которым вы можете свободно присоединиться. Рекомендуем вам это сделать!
Не забудьте посетить сайт русскоязычного сообщества F#! Если у вас возникнут вопросы по изучению языка, мы будем рады обсудить их в чатах:
#ru_general
в Slack-чате F# Software Foundation Статья переведена усилиями русскоязычного сообщества F#-разработчиков.
Мы также благодарим @schvepsss за подготовку данной статьи к публикации.
Метки: author Schvepsss программирование mono и moonlight c# .net блог компании microsoft microsoft f# fsharplangru microsoft research |
Дайджест свежих материалов из мира фронтенда за последнюю неделю №275 (7 — 13 августа 2017) |
Медиа |
Веб-разработка |
CSS |
Javascript |
Браузеры |
Занимательное |
Просим прощения за возможные опечатки или неработающие/дублирующиеся ссылки. Если вы заметили проблему — напишите пожалуйста в личку, мы стараемся оперативно их исправлять.
Метки: author alexzfort разработка веб-сайтов javascript html css дайджест фронтенд js es6 vue react angular html5 браузеры ссылки |
Цифровая экономика должна быть цифровой |
Источник
«Экономика должна быть экономной – таково требование времени»
Л.И.Брежнев (из отчетного доклада на XXVI съезде КПСС, 1981 г.)
Требования к экономике у каждого времени свои, и поднявшаяся в XXI веке до невероятных высот информатизация внесла в них свои серьезные коррективы. Появившаяся на мировой сцене, так называемая, цифровая экономика – это система экономических, социальных и культурных отношений, основанных на использовании цифровых информационно-коммуникационных технологий. Поговорим сегодня о приметах цифровой экономики, чего в ней на сегодняшний день не хватает, о вовлеченности в процесс перехода на «цифру» государства и его граждан и, конечно же, о последствиях цифровой трансформации.
Презентации конкретных решений и продуктов, относящихся к различным категориям экосистемы цифровой экономики производятся в наше время регулярно, и уже многие участники как мирового, так и отечественного рынка имеют ежедневный опыт создания элементов и продуктов онлайн-экономики. И потому нет ничего удивительного, что согласно опубликованному рейтингу самых дорогих брендов мира The BrandZ Global Top 100, на первом месте в нем расположилась компания Google со стоимостью бренда 245,6 млрд долларов США, а вслед за ней — еще четыре представителя Кремниевой долины: Apple, Microsoft, Amazon и Facebook. Российских брендов в сотне самых дорогих, правда, не оказалось. Это все интернет-гиганты, которые построены на мощных и инновационных платформах. Что касается пятерки лидеров, то за год она претерпела лишь одно изменение: теперь на четвертой строчке располагается не телекоммуникационный гигант AT&T, а крупнейший в мире онлайн-ритейлер Amazon. Что касается цифрового бизнеса, то это новая модель бизнеса, охватывающая людей/бизнес/вещи, масштабируемая глобально для всего мира за счет использования информационных технологий, интернета, и всех их свойств, предполагающая эффективное персональное обслуживание всех, везде, всегда.
В целом так называемый Data Driven бизнес или же, говоря простым языком, — бизнес, основной движущей силой которого являются данные, сегодня становится общей практикой для множества предприятий самых разных отраслей. А управление данными лежит в основе набирающей популярность цифровой трансформации бизнеса. По оценкам экспертов к 2020 г. объем данных, ежегодно обрабатываемых ЦОДами (центрами обработки данных), достигнет отметки 15,3 Зб (зетабайт), количество бизнес-пользователей превысит 325 млн., количество подключенных к Интернету устройств достигнет 20 млрд., заметно расширится спектр типов данных, 92% трафика данных в ЦОДах придется на «облачные вычисления», а на помощь миллиарду работников придет искусственный интеллект.
В декабре прошлого года регулятор развития транспортной инфраструктуры США объявил, что все новые автомобили в стране, выпуск которых начнется в 2023 году, должны быть оснащены системами обмена данными стандарта V2V (vehicle-to-vehicle, "автомобиль-автомобиль"), который предполагает обмен данными о маршрутах и скорости движения между всеми машинами на дороге, что должно принципиально снизить аварийность на дорогах.
Разработчики из Университета штата Огайо недавно получили правительственный грант на создание "умного" шоссе на 56-километровом участке трассы в пригороде Колумбуса, столицы штата. Речь идет о трассе стандарта V2I (vehicle-to-infrastructure, "автомобиль-инфраструктура"), который предусматривает обмен данными между объектами дорожной инфраструктуры (дорожными знаками, светофорами и различными датчиками) и движущимися автомобилями. Вдоль шоссе будет проложена волоконно-оптическая линия связи, которая соединит приемопередатчики, расположенные через каждые 600 метров. Благодаря полученной информации от дороги автомобиль сможет, к примеру, предупредить водителя о заторе по маршруту движения, просчитать объезд, а также спрогнозировать время простоя на светофоре.
Или вот настоящая «звезда блокчейна», любимец банкиров и журналистов, Виталий Бутерин, создавший Ethereum — платформу для создания децентрализованных интернет-сервисов (dapps), работающих на базе умных контрактов. Платформа запустилась 30 июля 2015 года. В марте этого года рыночная капитализация Ethereum превысила 1 млрд долларов США, а созданная на ее базе криптовалюта Ether заняла второе место после биткоина. В ходе недавнего Петербургского экономического форума (ПМЭФ) президент РФ Владимир Путин встречался и с основателем Ethereum, а первый вице-премьер российского правительства Игорь Шувалов в ходе панельной сессии на ПМЭФ заявил о том, что в России в настоящее время уже работают над тремя направлениями развития технологии блокчейн. По его словам, среди задач, требующих оперативного решения — обеспечение «цифровой прослеживаемости товаров», создание общей платформы на основе блокчейна для идентификации личности и электронная защита титула собственника.
Мобильное приложение «Помощник Москвы», позволяющее направлять фото неправильно запаркованных авто «куда надо», работает с середины 2015 г. и только за первый год работы позволило выписать около 25 тыс. штрафов. В масштабах Москвы, конечно, немного, но процесс запущен. Использование краудфандинга и различных мобильных приложений для исполнения некоторых публичных функций сегодня модно во всем мире. Поэтому нарушения правил парковки могут фиксировать не только дорожные полицейские, зарплату которым в каждом государстве, кстати, платят граждане, но и сами граждане, вооруженные смартфоном со специальным приложением. Мотивацию сознательных граждан можно стимулировать переводом на банковскую карточку процентами с оплаченных штрафов. Можно и «геймифицировать» процесс, чтобы подросткам стало интересным фиксировать нарушителей из спортивного интереса.
В целом же подобных примеров из сегодняшней жизни можно привести множество. Экономика, как процесс создания материальных и духовных ценностей, несомненно, получает с цифровой трансформацией дополнительный импульс, поставляя новые виды контента и программных продуктов. Экономика в прямом смысле также получает свой импульс, позволяя получать несоизмеримо больше информации обо всех процессах, что крайне полезно при формировании систем мониторинга и управления, а также повышении эффективности самих процессов. Информационный обмен, на котором стоит весь бизнес и все государственное управление, обеспечивается с помощью цифровых каналов передачи данных, во многом беспроводных, а также электронным документооборотом, что открывает новые просторы для дальнейшего совершенствования бизнес-моделей и бизнес-процессов. Финансы начинают присматриваться к цифровым валютам. Социальная часть «сидит» в социальных сетях, подчас занимая все свободное и даже несвободное время граждан. Зрелища представлены не только новыми видами контента, но и играми, трафик от которых уже конкурирует с другими видами трафика.
Вовлечение граждан в управление государством также упрощается в эпоху цифровой экономики. Считается, что к 2024 году в сфере инфраструктуры в России будет устранено цифровое неравенство, во всех труднодоступных районах страны появится связь. К 2024 году в России должна быть сформирована основа для развития цифровой экономики. В ключевых отраслях в результате трансформации должны возникнуть национальные лидеры в своей области, которые станут операторами цифровых платформ. На базе этих платформ будет формироваться определенная система взаимодействия участников. Бизнес и государство должны будут пересмотреть правила и форматы онлайн-взаимодействия с гражданами. В рамках платформы участники не будут ограничены в создании новых способов взаимодействия друг с другом, в создании добавленной стоимости. Казалось бы, «цифра» везде, и вот она, цифровая экономика.
Хотя нет, из известной формулы «хлеба и зрелищ» в цифровой экономике не хватает именно хлеба. То есть поучаствовать в приобретении, хранении, выращивании, сборе и переработке зерна, а также в поставке и продаже готового продукта она может. Теоретически может даже создать цифровую очередь за хлебом в интернет-магазине, но вот сотворить из данных непосредственно хлеб ей пока не под силу. Цифры нельзя кушать, цифру на себя не наденешь и на цифре не поедешь. И это оставляет шансы всем религиям мира, где Господь умеет-таки создавать все сущее, в том числе и хлеб.
То есть углубить и улучшить бизнес-процессы, это — пожалуйста, но вот создать полезные ископаемые, биосферу и пр. и пр. цифровая экономика не может. Поэтому, как считают некоторые специалисты, целесообразно было бы говорить не о цифровой экономике, а об экономике знаний, креаномике. И вкладывать деньги в науку и научно-технические проекты на чем, в частности, серьезно поднялся Китай. Причем сами по себе высокие технологии – не товар. Их еще нужно применить в реальном производстве, каковое все-таки должно быть в стране. От текстильной до космической.
Впрочем, возможно, что бурно развивающиеся биотехнологии со временем позволят синтезировать пищу по заказу, о чем полвека назад популярно рассказал Илья Варшавский в рассказе «Молекулярное кафе». Может быть, со временем получится и что-то более продвинутое, о чем рассказывалось, к примеру, в «Трудно быть Богом» Стругацких:
«Хрустя каблуками по битому стеклу, Румата пробрался в дальний угол и включил электрический фонарик. Там под грудой хлама стоял в прочном силикетовом сейфе малогабаритный полевой синтезатор «Мидас». Румата разбросал хлам, набрал на диске комбинацию цифр и поднял крышку сейфа. Даже в белом электрическом свете синтезатор выглядел странно среди развороченного мусора. Румата бросил в приемную воронку несколько лопат опилок, и синтезатор тихонько запел, автоматически включив индикаторную панель. Румата носком ботфорта придвинул к выходному желобу ржавое ведро. И сейчас же — дзинь, дзинь, дзинь! — посыпались на мятое жестяное дно золотые кружочки с аристократическим профилем Пица Шестого, короля Арканарского».
Правда, братья Стругацкие забыли уточнить, что «Мидас» был цифровым, но мы-то с вами уже понимаем, в чем там дело. Таким образом, пока человечество не научится делать золото хотя бы из опилок, говорить о полной победе цифровой экономики несколько преждевременно. Но о бизнес-моделях и бизнес-процессах поговорить стоит.
Не стоит также забывать, что введение «цифры» должно всесторонне улучшать бизнес-процессы с помощью оперативности доставки, прозрачности и достоверности данных. Собственно, именно поэтому цифровая экономика и призвана быть именно цифровой. С оперативностью, вроде бы, понятно, а что с прозрачностью и достоверностью? Вернее, насколько это всем понравится?
К примеру, даже если польза вовлечения сограждан в различные процессы контроля над общественным порядком очевидна, само это вовлечение во многом зависит от доверия граждан государству. На граждан можно переложить значительную часть функций по контролю за соблюдением общественного порядка, многие вопросы пожарного надзора, контроля безопасности строительства и многих других видов контроля. С одной стороны, лишние деньги не помешают, а, с другой, — ябедничать нехорошо.
Еще и ябеду отыщут по IP-адресам с неизвестными для него, но весьма прогнозируемыми последствиями. Любое государство, существующее по роду своему как институт принуждения, объективно заинтересовано во все большем обладании информацией о своих гражданах, но гражданам это перестает нравиться, если, к примеру, эта информация плохо защищена. Говорят, что лишь десятилетия разумного и последовательного поведения очень постепенно формируют в обществе доверие к тому, что полученная информация будет использована властью во благо, а не во вред. Если же граждане воспринимают государство как нечто учрежденное самими гражданами для защиты собственных прав и интересов, то для них логично помогать этому государству и приветствовать подобную помощь от других членов сообщества. И если государство исполнит свои функции хорошо, то выиграют все за исключением злостных нарушителей.
Возможности цифровой экономики становятся тем шире, чем более честно ведет себя само общество, и эта честность имеет с цифровой экономикой положительную обратную связь. Именно благодаря научно-техническому прогрессу мир будет становиться все более и более прозрачным. Если этот тренд сохранится, человечеству откроются многие тайны. В дополнение ожидается, что в ближайшие годы у человечества появятся чисто технические возможности для вскрытия лжи и идентификации честного поведения, для чего сегодня существует много государственных институтов вроде юристов и пр. Сто лет назад скрыть правду было гораздо проще. К примеру, даже массовые преступления можно было замолчать или оттянуть правду о них на годы. И потому возможности вмешаться и противодействовать практически не было. Сегодня все совсем по-другому, и мир узнает о подобных и других событиях почти мгновенно. Впрочем, и эту информацию теперь можно сфальсифицировать.
Несмотря на обилие реальных и потенциальных преимуществ цифровая экономика подтачивается изнутри не менее широкими возможностями цифровых преступлений, фальсификации данных и коррупцией. Воровство финансовых средств и интеллектуальной собственности, шантаж, вымогательство, взлом информационных хранилищ, получение несанкционированного доступа к чужим персональным данным для нарушений закона – далеко не полный перечень известных преступлений из мира цифровой экономики. По вполне объективным причинам любое государство не в состоянии защитить граждан от всего перечисленного хотя бы потому, что нападение всегда на шаг впереди защиты.
Еще лет десять назад политики и военные представить не могли, что тысячи страниц секретных материалов могут быть обнародованы вместе с их откровенными частными беседами. Сейчас подобные утечки стали обыденным делом. Взять хотя бы длящуюся уже давно истерику в США по части якобы хакерского взлома у них чего-либо. Простите, ребята, а разве это не вы в течение десятилетий гордились наличием у себя системы «Эшелон», «стригущей» любую информацию на планете, позже привлекали для этого интернет-ресурсы, создавали кибервойска и пр.? Большего саморазоблачения творцов, в том числе и цифровой экономики, и придумать сложно. Либо это ложь во спасение каких-то своих политических целей, потому что не в традициях разведок столь публично заявлять о своих провалах, либо настоящее бессилие перед выпущенным из бутылки джинном. Причем и то, и другое не внушает оптимизма по поводу перспектив цифровой экономики.
Именно поэтому, в частности, среди населения растет популярность мессенджеров. «Конфиденциальность и безопасность заложены в нашей ДНК… — говорится на официальном сайте мессенджера WhatsApp. — Сквозное шифрование обеспечивает защиту ваших сообщений и звонков. Таким образом, только вы и человек, с которым вы общаетесь, можете прочитать или прослушать содержимое, и никто другой». Именно поэтому мессенжеры вызывают закономерное беспокойство спецслужб, которым по роду деятельности нужно не только ловить преступников, террористов и т.п., но и предупреждать подобные преступления.
Одним из последствий новой цифровой трансформации будет, в частности, более глубокое видение того, что люди делают в компаниях. Это важно, поскольку сейчас люди составляют половину активов компаний. Активы типичной компании сейчас на 25% состоят из физических активов, на 50% из сотрудников и на 25% из стоимости бренда и других нематериальных активов. Специалисты отмечают, что при цифровой экономике обязательно будут проигравшие и среди простых граждан. Какие-то специальности станут ненужными, кого-то заменит искусственный интеллект. «Новый уклад разрушает многие традиционные сектора, растут отрицательные эмоции среди тех, кто там работал. Цифровые технологии могут усугублять социально-экономическое неравенство», – признают даже во Всемирном банке.
А теперь представим, что вожделенная «цифра» победила, и каждый член общества, каждый представитель бизнеса, каждый чиновник, каждый супруг, каждый член коллектива имеет полный доступ к любой информации, которая может его касаться. Впрочем, и о другой тоже. И все тайное вдруг станет явным. Все узнают, кто, где, когда и сколько украл, кого обманул, какие интриги плел, кого подставил, засадил в тюрьму или даже убил… Трудно представить, что будет с бизнесом, с финансовыми взаимоотношениями и, конечно, с политиками. Искусство возможного чаще всего конфликтует с честностью. Катастрофические последствия всеобщего прозрения ощутят на себе не только политики и чиновники, бизнесмены и банкиры, но и самые простые граждане.
Кто-то считает, что подобное развитие событий может стать реальным уже в ближайшем будущем и окажется сродни тому, что принято называть Апокалипсисом. К сведению любителей теорий катастроф в переводе с греческого Апокалипсис — это «открытие, снятие покрова, разоблачение». Иначе — всеобщее прозрение. И что самое забавное, к этому прозрению человечество толкает банальное развитие цифровой экономики, а отнюдь не только вдруг снизошедшая откуда-то способность к телепатии. Указанный перелом в истории человечества предсказан не только лишь Иисусом Христом, который, кстати, и обещал, что однажды «все тайное станет явным», но и многими пророками, которые видели приход «Золотого века» и появление нового, более честного и справедливого общества. Американский Университет Сингулярности, созданный NASA и Google, опубликовал недавно «Предсказания человечеству на следующие 20 лет», где его эксперты утверждают, что до 2020 года появятся интернет-приложения, способные с высокой вероятностью распознавать правду и ложь. И очень даже может быть, что уже через пять-семь лет такие мини-детекторы лжи начнут входить в стандартный набор функций многих смартфонов.
Сегодня ложь пронизывает все сферы бытия, начиная от политики и кончая отношениями в семье. В связи с этим ожидается, что человечество в целом и каждая страна в отдельности совершат грандиозный рывок в своем развитии, как только люди перестанут лгать и воровать, что, как мы видели выше, может стать «станцией назначения» поезда цифровой экономики. Но подобное развитие цифровой экономики нанесло бы удар по огромному количеству богатых, влиятельных, прекрасно себя чувствующих людей, вызвав с их стороны логичное противодействие. Интересно, подозревают ли об этом те, кто собирается на всем этом заработать?
По материалам: tass.ru, ng.ru, cnews.ru, helionews.ru, pcweek.ru, forum-msk.org, nplus1.ru, dic.academic.ru, mk.ru, arb.ru, 3rm.info
Автор публикации:
Александр ГОЛЫШКО, системный аналитик ГК «Техносерв»
Метки: author TS_Telecom законодательство и it-бизнес блог компании техносерв цифровая экономика цифровая трансформация техносерв |
Бесплатный аудит безопасности сети с помощью Fortinet. Часть 2 |
config system interface
edit port1 //имя сетевого интерфейса
set ip 10.10.10.112/24 //IP адрес и маска сети
end
config router static
edit 1 //номер маршрута в списке
set gateway 10.10.10.254
set device port1
end
config system interface
edit port1 //имя сетевого интерфейса
set ip 10.10.10.113/24 //IP адрес и маска сети
end
config system route
edit 1 //номер маршрута в списке
set gateway 10.10.10.254
set device port1
end
|
Рынок источников бесперебойного питания вырос впервые за четыре года |
Метки: author 1cloud it- инфраструктура блог компании 1cloud.ru 1cloud ибп рынок |
[recovery mode] Выпущен релиз 15.5 SP1 и 3CX Firewall Checker с проверкой SIP ALG |
wget -O- http://downloads.3cx.com/downloads/3cxpbx/public.key | apt-key add -
echo "deb http://downloads.3cx.com/downloads/3cxpbx/ /" | tee /etc/apt/sources.list.d/3cxpbx.list
apt-get update
apt-get install 3cxpbx
|
Построение рекомендаций для сайта вакансий. Лекция в Яндексе |
|
Интеграция Intel Threading Building Blocks в ваш CMake проект |
TBB_FOUND |
флаг успешности поиска Intel TBB |
TBB_ |
флаг успешности поиска отдельного компонента |
TBB_IMPORTED_TARGETS |
все созданные импортированные цели |
TBB_VERSION |
версия Intel TBB (формат: |
TBB_INTERFACE_VERSION |
версия интерфейса Intel TBB |
TBB_ROOT |
путь до корневой папки бибилотеки, которую нужно собрать |
CONFIG_DIR |
переменная, в которую запишется полный путь к папке с созданными конфигурационными файлами; значение |
MAKE_ARGS |
настраиваемые аргументы для make-команды; следующие аргументы определяются и передаются автоматически, если они не переопределены в :
|
include(/TBBBuild.cmake)
tbb_build(TBB_ROOT CONFIG_DIR TBB_DIR)
find_package(TBB )
TBB_ROOT |
переменная, в которую будет записан полный путь к корневой папке скачанного и распакованного пакета; значение |
RELEASE_TAG |LATEST |
тег релиза для скачивания; по умолчанию используется значение LATEST |
SAVE_TO |
путь для распаковки скачанного пакета; по умолчанию используется ${CMAKE_CURRENT_BINARY_DIR}/tbb_downloaded |
SYSTEM_NAME Linux|Windows|Darwin |
ОС, для которой необходимо скачать бинарный пакет; по умолчанию используется значение переменной CMAKE_SYSTEM_NAME |
CONFIG_DIR |
переменная, в которую будет записан полный путь до конфигурационных файлов; параметр игнорируется, если указан флаг SOURCE_CODE |
SOURCE_CODE |
флаг, сигнализирующий о необходимости скачивания пакета с исходным кодом вместо бинарного пакета |
include(/TBBGet.cmake)
tbb_get(TBB_ROOT tbb_root CONFIG_DIR TBB_DIR)
find_package(TBB )
include(/TBBGet.cmake)
include(/TBBBuild.cmake)
tbb_get(TBB_ROOT tbb_root SOURCE_CODE)
tbb_build(TBB_ROOT ${tbb_root} CONFIG_DIR TBB_DIR)
find_package(TBB )
cmake_minimum_required(VERSION 3.0.0 FATAL_ERROR)
project(sub_string_finder CXX)
add_executable(sub_string_finder sub_string_finder.cpp)
# Функция find_package ищет TBBConfig, используя переменные
# CMAKE_PREFIX_PATH и TBB_DIR.
find_package(TBB REQUIRED tbb)
# "TBB::tbb" можно использовать вместо "${TBB_IMPORTED_TARGETS}"
target_link_libraries(sub_string_finder ${TBB_IMPORTED_TARGETS})
mkdir ~/demo_tbb_cmake
cd ~/demo_tbb_cmake
git clone https://github.com/01org/tbb.git
cmake_minimum_required(VERSION 3.0.0 FATAL_ERROR)
project(sub_string_finder CXX)
add_executable(sub_string_finder sub_string_finder.cpp)
include(${TBB_ROOT}/cmake/TBBBuild.cmake)
# Строим Intel TBB с включенными Community Preview Features (CPF).
tbb_build(TBB_ROOT ${TBB_ROOT} CONFIG_DIR TBB_DIR MAKE_ARGS tbb_cpf=1)
find_package(TBB REQUIRED tbb_preview)
# "TBB::tbb_preview" можно использовать вместо "${TBB_IMPORTED_TARGETS}".
target_link_libraries(sub_string_finder ${TBB_IMPORTED_TARGETS})
mkdir ~/demo_tbb_cmake/tbb/examples/GettingStarted/sub_string_finder/build
cd ~/demo_tbb_cmake/tbb/examples/GettingStarted/sub_string_finder/build
cmake -DTBB_ROOT=${HOME}/demo_tbb_cmake/tbb ..
make
./sub_string_finder
Метки: author moslex программирование c++ блог компании intel intel tbb intel open source cmake integration |
Comedy. Встречайте акторы в Node.JS |
Привет, хабравчане!
В этой статье я познакомлю вас с фреймворком Comedy — реализацией акторов в Node.JS.
Акторы позволяют масштабировать отдельные модули вашего Node.JS приложения без изменения кода.
Хотя модель акторов довольно популярна сегодня, не все про неё знают. Несмотря на несколько устрашающую статью в Википедии, акторы — это очень просто.
Что такое актор? Это такая штука, которая умеет:
Единственный способ что-либо сделать с актором — это отправить ему сообщение. Внутренне состояние актора полностью изолировано от внешнего мира. Благодаря этому актор является универсальной единицей масштабирования приложения. А его способность порождать дочерние акторы позволяет сформировать понятную структуру модулей с чётким разделением обязанностей.
Понимаю, звучит несколько абстрактно. Чуть ниже мы разберём на конкретном живом примере, как происходит работа с акторами и Comedy. Но сперва...
… сперва мотивация.
Все, кто программируют на Node.JS (ваш покорный среди них) прекрасно знают, что Node.JS — однопоточный. С одной стороны, это хорошо, поскольку избавляет нас от целого класса очень стрёмных и трудновоспроизводимых багов — многопоточных багов. В наших приложениях таких багов быть принципиально не может, и это сильно удешевляет и ускоряет разработку.
С другой стороны, это ограничивает область применимости Node.JS. Он отлично подходит для network-intensive приложений с относительно небольшой вычислительной нагрузкой, а вот для CPU-intensive приложений подходит плохо, поскольку интенсивные вычисления блокируют наш драгоценный единственный поток, и всё встаёт колом. Мы это прекрасно знаем.
Знаем мы также и то, что любое реальное приложение какое-то количество CPU всё равно потребляет (даже если у нас совсем нет бизнес-логики, нам нужно обрабатывать сетевой трафик на уровне приложения — HTTP там, протоколы баз данных и прочее). И по мере роста нагрузки мы всё равно рано или поздно приходим к ситуации, когда наш единственный поток потребляет 100% мощности ядра. А что происходит в этом случае? Мы не успеваем обрабатывать сообщения, очередь задач накапливается, время отклика растёт, а потом бац! — out of memory.
И тут мы приходим к ситуации, когда нам нужно отмасштабировать наше приложение уже на несколько ядер CPU. И в идеале, мы не хотим себя ограничивать ядрами только на одной машине — нам может потребоваться несколько машин. И при этом мы хотим как можно меньше переписывать наше приложение. Здорово, если приложение будет масштабироваться простым изменением конфигурации. А ещё лучше — автоматически, в зависимости от нагрузки.
И вот тут нам на помощь приходят акторы.
Для того, чтобы продемонстрировать, как работает Comedy, я набросал небольшой пример: микросервис, который находит простые числа. Доступ к сервису осуществляется через REST API.
Конечно, поиск простых чисел — это в чистом виде CPU-intensive задача. Если бы мы в реальной жизни проектировали такой сервис, нам бы стоило десять раз подумать, прежде чем выбрать Node.JS. Но в данном случае, мы как раз намеренно выбрали вычислительную задачу, чтобы было проще воспроизвести ситуацию, когда одного ядра не хватает.
Итак. Давайте начнём с самой сути нашего сервиса — реализуем актор, находящий простые числа. Вот его код:
/**
* Actor that finds prime numbers.
*/
class PrimeFinderActor {
/**
* Finds next prime, starting from a given number (not inclusive).
*
* @param {Number} n Positive number to start from.
* @returns {Number} Prime number next to n.
*/
nextPrime(n) {
if (n < 1) throw new Error('Illegal input');
const n0 = n + 1;
if (this._isPrime(n0)) return n0;
return this.nextPrime(n0);
}
/**
* Checks if a given number is prime.
*
* @param {Number} x Number to check.
* @returns {Boolean} True if number is prime, false otherwise.
* @private
*/
_isPrime(x) {
for (let i = 2; i < x; i++) {
if (x % i === 0) return false;
}
return true;
}
}
Метод nextPrime()
находит простое число, следующее за указанным (не обязательно простым). В методе используется хвостовая рекурсия, которая точно поддерживается в Node.JS 8 (для запуска примера нужно будет взять Node.JS не ниже 8 версии, поскольку там ещё async-await будет). В методе используется вспомогательный метод _isPrime()
, проверяющий число на простоту. Это не самый оптимальный алгоритм подобной проверки, но для нашего примера это только лучше.
То, что мы видим в коде выше, с одной стороны — обычный класс. С другой стороны, для нас, это, так называемое, определение актора, то есть описание поведения актора. Класс описывает, какие сообщения актор может принимать (каждый метод — обработчик сообщения с одноимённым топиком), что он делает, приняв эти сообщения (реализация метода) и какой выдаёт результат (возвращаемое значение).
При этом, поскольку это обычный класс, мы можем написать на него unit-тест и легко протестировать корректность его реализации.
describe('PrimeFinderActor', () => {
it('should correctly find next prime', () => {
const pf = new PrimeFinderActor();
expect(pf.nextPrime(1)).to.be.equal(2);
expect(pf.nextPrime(2)).to.be.equal(3);
expect(pf.nextPrime(3)).to.be.equal(5);
expect(pf.nextPrime(30)).to.be.equal(31);
});
it('should only accept positive numbers', () => {
const pf = new PrimeFinderActor();
expect(() => pf.nextPrime(0)).to.throw();
expect(() => pf.nextPrime(-1)).to.throw();
});
});
Теперь у нас есть актор-искатель простых чисел.
Наш следующий шаг — реализовать актор REST-сервера. Вот как будет выглядеть его определение:
const restify = require('restify');
const restifyErrors = require('restify-errors');
const P = require('bluebird');
/**
* Prime numbers REST server actor.
*/
class RestServerActor {
/**
* Actor initialization hook.
*
* @param {Actor} selfActor Self actor instance.
* @returns {Promise} Initialization promise.
*/
async initialize(selfActor) {
this.log = selfActor.getLog();
this.primeFinder = await selfActor.createChild(PrimeFinderActor);
return this._initializeServer();
}
/**
* Initializes REST server.
*
* @returns {Promise} Initialization promise.
* @private
*/
_initializeServer() {
const server = restify.createServer({
name: 'prime-finder'
});
// Set 10 minutes response timeout.
server.server.setTimeout(60000 * 10);
// Define REST method for prime number search.
server.get('/next-prime/:n', (req, res, next) => {
this.log.info(`Handling next-prime request for number ${req.params.n}`);
this.primeFinder.sendAndReceive('nextPrime', parseInt(req.params.n))
.then(result => {
this.log.info(`Handled next-prime request for number ${req.params.n}, result: ${result}`);
res.header('Content-Type', 'text/plain');
res.send(200, result.toString());
})
.catch(err => {
this.log.error(`Failed to handle next-prime request for number ${req.params.n}`, err);
next(new restifyErrors.InternalError(err));
});
});
return P.fromCallback(cb => {
server.listen(8080, cb);
});
}
}
Что в нём происходит? Главное и единственное — в нём есть метод initialize()
. Этот метод будет вызван Comedy при инициализации актора. В него передаётся экземпляр актора. Это та самая штука, в которую можно передавать сообщения. У экземпляра есть ещё ряд полезный методов. getLog()
возвращает логгер для актора (он нам пригодится), а с помощью метода createChild()
мы создаём дочерний актор — тот самый PrimeFinderActor
, который мы реализовали в самом начале. В createChild()
мы передаём определение актора, а получаем в ответ промис, который разрешится, как только дочерний актор будет проинициализирован, и выдаст нам экземпляр созданного дочернего актора.
Как вы заметили, инициализация актора — асинхронная операция. Наш метод initialize()
тоже асинхронный (он возвращает промис). Соответственно наш RestServerActor
будет считаться инициализированным только тогда, когда зарезолвится промис (ну не писать же "выполниться обещание"), отданный методом initialize()
.
Окей, мы создали дочерний PrimeFinderActor
, дождались его инициализации и присвоили ссылку на экземпляр полю primeFinder
. Осталась мелочёвка — сконфигурировать REST-сервер. Мы это делаем в методе _initializeServer()
(он тоже асинхронный), используя библиотеку Restify
.
Мы создаём один-единственный обработчик запроса ("ручку") — для метода GET /next-prime/:n
, который вычисляет следующее за указанным целое число, отправляя сообщение дочернему PrimeFinderActor
актору и получая от него ответ. Сообщение мы отправляем с помощью метода sendAndReceive()
, первым параметром идёт название топика (nextPrime
, по имени метода) следующим параметром — сообщение. В данном случае сообщением является просто число, но там может быть и строка, и объект с данными, и массив. Метод sendAndReceive()
асинхронный, возвращает промис с результатом.
Почти готово. Нам осталась ещё одна мелочь: запустить всё это. Мы добавляем в наш пример ещё пару строк:
const actors = require('comedy');
actors({ root: RestServerActor });
Здесь мы создаём систему акторов. В качестве параметров мы указываем определение корневого (самого родительского) актора. Им у нас является RestServerActor
.
Получается вот такая иерархия:
С иерархией нам повезло, она довольно простая!
Ну что, запускаем приложение и тестируем?
$ nodejs prime-finder.js
Mon Aug 07 2017 15:34:37 GMT+0300 (MSK) - info: Resulting actor configuration: {}
$ curl http://localhost:8080/next-prime/30; echo
31
Работает! Давайте ещё поэкспериментируем:
$ time curl http://localhost:8080/next-prime/30
31
real 0m0.015s
user 0m0.004s
sys 0m0.000s
$ time curl http://localhost:8080/next-prime/3000000
3000017
real 0m0.045s
user 0m0.008s
sys 0m0.000s
$ time curl http://localhost:8080/next-prime/300000000
300000007
real 0m2.395s
user 0m0.004s
sys 0m0.004s
$ time curl http://localhost:8080/next-prime/3000000000
3000000019
real 5m11.817s
user 0m0.016s
sys 0m0.000s
По мере возрастания стартового числа время обработки запроса растёт. Особенно впечатляет переход с трёхсот миллионов до трёх миллиардов. Давайте попробуем параллельные запросы:
$ curl http://localhost:8080/next-prime/3000000000 &
[1] 32440
$ curl http://localhost:8080/next-prime/3000000000 &
[2] 32442
В top-е видим, что одно ядро полностью занято.
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
32401 weekens 20 0 955664 55588 20956 R 100,0 0,7 1:45.19 node
В логе сервера видим:
Mon Aug 07 2017 16:05:45 GMT+0300 (MSK) - info: InMemoryActor(5988659a897e307e91fbc2a5, RestServerActor): Handling next-prime request for number 3000000000
То есть первый запрос выполняется, а второй просто ждёт.
$ jobs
[1]- Выполняется curl http://localhost:8080/next-prime/3000000000 &
[2]+ Выполняется curl http://localhost:8080/next-prime/3000000000 &
Это в точности та ситуация, которая и была описана: нам не хватает одного ядра. Нам нужно больше ядер!
Итак, настало время мастшабироваться. Все наши дальнейшие действия не потребуют модификации кода.
Давайте вначале выделим PrimeFinderActor
в отдельный подпроцесс. Само по себе это действие довольно бесполезно, но хочется вводить вас в курс дела постепенно.
Мы создаём в корневой директории проекта файл actors.json
вот с таким содержимым:
{
"PrimeFinderActor": {
"mode": "forked"
}
}
И перезапускаем пример. Что произошло? Смотрим в список процессов:
$ ps ax | grep nodejs
12917 pts/19 Sl+ 0:00 nodejs prime-finder.js
12927 pts/19 Sl+ 0:00 /usr/bin/nodejs /home/weekens/workspace/comedy-examples/node_modules/comedy/lib/forked-actor-worker.js PrimeFinderActor
$ pstree -a -p 12917
nodejs,12917 prime-finder.js
+-nodejs,12927 /home/weekens/workspace/comedy-examples/node_modules/comedy/lib/forked-actor-worker.js PrimeFinderActor
| +-{V8 WorkerThread},12928
| +-{V8 WorkerThread},12929
| +-{V8 WorkerThread},12930
| +-{V8 WorkerThread},12931
| +-{nodejs},12932
+-{V8 WorkerThread},12918
+-{V8 WorkerThread},12919
+-{V8 WorkerThread},12920
+-{V8 WorkerThread},12921
+-{nodejs},12922
+-{nodejs},12923
+-{nodejs},12924
+-{nodejs},12925
+-{nodejs},12926
Мы видим, что процессов теперь два. Один — наш главный, "пусковой" процесс. Второй — дочерний процесс, в котором теперь крутится PrimeFinderActor
, поскольку он теперь работает в режиме "forked"
. Мы это сконфигурировали с помощью файла actors.json
, ничего не меняя в коде.
Получилась вот такая картина:
Запускаем тест снова:
$ curl http://localhost:8080/next-prime/3000000000 &
[1] 13240
$ curl http://localhost:8080/next-prime/3000000000 &
[2] 13242
Смотрим лог:
Tue Aug 08 2017 08:54:41 GMT+0300 (MSK) - info: InMemoryActor(5989504694b4a23275ba5d29, RestServerActor): Handling next-prime request for number 3000000000
Tue Aug 08 2017 08:54:43 GMT+0300 (MSK) - info: InMemoryActor(5989504694b4a23275ba5d29, RestServerActor): Handling next-prime request for number 3000000000
Хорошая новость: всё по-прежнему работает. Плохая новость: всё работает, почти как и раньше. Ядро по-прежнему не справляется, и запросы встают в очередь. Только теперь ядро нагружено нашим дочерним процессом (обратите внимание на PID):
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
12927 weekens 20 0 907160 40892 20816 R 100,0 0,5 0:20.05 nodejs
Давайте сделаем больше процессов: кластеризуем PrimeFinderActor
до 4-х экземпляров. Меняем actors.json
:
{
"PrimeFinderActor": {
"mode": "forked",
"clusterSize": 4
}
}
Перезапускаем сервис. Что видим?
$ ps ax | grep nodejs
15943 pts/19 Sl+ 0:01 nodejs prime-finder.js
15953 pts/19 Sl+ 0:00 /usr/bin/nodejs /home/weekens/workspace/comedy-examples/node_modules/comedy/lib/forked-actor-worker.js PrimeFinderActor
15958 pts/19 Sl+ 0:00 /usr/bin/nodejs /home/weekens/workspace/comedy-examples/node_modules/comedy/lib/forked-actor-worker.js PrimeFinderActor
15963 pts/19 Sl+ 0:00 /usr/bin/nodejs /home/weekens/workspace/comedy-examples/node_modules/comedy/lib/forked-actor-worker.js PrimeFinderActor
15968 pts/19 Sl+ 0:00 /usr/bin/nodejs /home/weekens/workspace/comedy-examples/node_modules/comedy/lib/forked-actor-worker.js PrimeFinderActor
Дочерних процессов стало 4. Всё как мы и хотели. Простым изменением конфигурации мы поменяли иерархию, которая теперь выглядит так:
То есть Comedy размножил PrimeFinderActor
до количества 4-х штук, каждый запустил в отдельном процессе, и между этими акторами и родительским RestServerActor
-ом воткнул промежуточный актор, который будет раскидывать запросы по дочерним акторам раунд-робином.
Запускаем тест:
$ curl http://localhost:8080/next-prime/3000000000 &
[1] 20076
$ curl http://localhost:8080/next-prime/3000000000 &
[2] 20078
И видим, что теперь занято два ядра:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
15953 weekens 20 0 909096 38336 20980 R 100,0 0,5 0:13.52 nodejs
15958 weekens 20 0 909004 38200 21044 R 100,0 0,5 0:12.75 nodejs
В логе приложения видим два параллельно обрабатывающихся запроса:
Tue Aug 08 2017 11:51:51 GMT+0300 (MSK) - info: InMemoryActor(5989590ef554453e4798e965, RestServerActor): Handling next-prime request for number 3000000000
Tue Aug 08 2017 11:51:52 GMT+0300 (MSK) - info: InMemoryActor(5989590ef554453e4798e965, RestServerActor): Handling next-prime request for number 3000000000
Tue Aug 08 2017 11:57:24 GMT+0300 (MSK) - info: InMemoryActor(5989590ef554453e4798e965, RestServerActor): Handled next-prime request for number 3000000000, result: 3000000019
Tue Aug 08 2017 11:57:24 GMT+0300 (MSK) - info: InMemoryActor(5989590ef554453e4798e965, RestServerActor): Handled next-prime request for number 3000000000, result: 3000000019
Масштабирование работает!
Наш сервис сейчас может обрабатывать параллельно 4 запроса на нахождение простого числа. Остальные запросы встают в очередь. На моей машине всего 4 ядра. Если я хочу обрабатывать больше параллельных запросов, мне надо масштабироваться на соседние машины. Давайте сделаем это!
Вначале немного теории. В прошлом примере мы перевели PrimeFinderActor
в режим "forked"
. Каждый актор может находиться в одном из трёх режимов:
"in-memory"
(по-умолчанию): актор работает в том же процессе, что и создавший его код. Отправка сообщений такому актору сводится к вызову его методов. Накладные расходы на коммуникацию с "in-memory"
актором нулевые (или близкие к нулевым);"forked"
: актор запускается в отдельном процессе на той же машине, где работает создавший его код. Коммуникация с актором осуществляется через IPC (Unix pipes в Unix-е, named pipes в Windows)."remote"
: актор запускается в отдельном процессе на удалённой машине. Коммуникация с актором осуществляется через TCP/IP.Как вы поняли, теперь нам нужно перевести PrimeFinderActor
из "forked"
режима в "remote"
. Мы хотим получить такую схему:
Давайте отредактируем файл actors.json
. Просто указать режим "remote"
в данном случае недостаточно: нужно ещё указать хост, на котором мы хотим запустить актор. У меня есть по соседству машинка с адресом 192.168.1.101
. Её я и использую:
{
"PrimeFinderActor": {
"mode": "remote",
"host": "192.168.1.101",
"clusterSize": 4
}
}
Только вот беда: эта самая соседняя машинка не знает ничего про Comedy. Нам нужно запустить на ней специальный процесс слушатель на известном порту. Делается это так:
$ ssh weekens@192.168.1.101
...
weekens@192.168.1.101 $ mkdir comedy
weekens@192.168.1.101 $ cd comedy
weekens@192.168.1.101 $ npm install comedy
...
weekens@192.168.1.101 $ node_modules/.bin/comedy-node
Thu Aug 10 2017 19:29:51 GMT+0300 (MSK) - info: Listening on :::6161
Теперь процесс-слушатель готов принимать запросы на создание акторов по известному порту 6161
. Пробуем:
$ nodejs prime-finder.js
$ curl http://localhost:8080/next-prime/3000000000 &
$ curl http://localhost:8080/next-prime/3000000000 &
Смотрим top на локальной машине. Никакой активности (если не считать Chromium):
$ top
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
25247 weekens 20 0 1978768 167464 51652 S 13,6 2,2 32:34.70 chromium-browse
Смотрим на удалённой машине:
weekens@192.168.1.101 $ top
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
27956 weekens 20 0 908612 40764 21072 R 100,1 0,1 0:14.97 nodejs
27961 weekens 20 0 908612 40724 21020 R 100,1 0,1 0:11.59 nodejs
Идёт вычисление целых чисел, всё как мы и хотели.
Остался лишь один маленький штрих: использовать ядра и на локальной, и на удалённой машине. Это очень просто: мы указываем в actors.json
не один хост, а несколько:
{
"PrimeFinderActor": {
"mode": "remote",
"host": ["127.0.0.1", "192.168.1.101"],
"clusterSize": 4
}
}
Comedy распределит акторы равномерно между указанными хостами и будет раздавать им сообщения round robin-ом. Давайте проверим.
Сперва запустим процесс слушатель дополнительно на локальной машине:
$ node_modules/.bin/comedy-node
Fri Aug 11 2017 15:37:26 GMT+0300 (MSK) - info: Listening on :::6161
Теперь запустим пример:
$ nodejs prime-finder.js
Посмотрим список процессов на локальной машине:
$ ps ax | grep nodejs
22869 pts/19 Sl+ 0:00 /usr/bin/nodejs /home/weekens/workspace/comedy-examples/node_modules/comedy/lib/forked-actor-worker.js PrimeFinderActor
22874 pts/19 Sl+ 0:00 /usr/bin/nodejs /home/weekens/workspace/comedy-examples/node_modules/comedy/lib/forked-actor-worker.js PrimeFinderActor
И на удалённой машине:
192.168.1.101 $ ps ax | grep node
5925 pts/4 Sl+ 0:00 /usr/bin/nodejs /home/weekens/comedy/node_modules/comedy/lib/forked-actor-worker.js PrimeFinderActor
5930 pts/4 Sl+ 0:00 /usr/bin/nodejs /home/weekens/comedy/node_modules/comedy/lib/forked-actor-worker.js PrimeFinderActor
По два на каждой, как и хотели (понадобится больше — увеличим clusterSize
). Отправляем запросы:
$ curl http://localhost:8080/next-prime/3000000000 &
[1] 23000
$ curl http://localhost:8080/next-prime/3000000000 &
[2] 23002
Смотрим загрузку на локальной машине:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
22869 weekens 20 0 908080 40344 21724 R 106,7 0,5 0:07.40 nodejs
Смотрим загрузку на удалённой машине:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
5925 weekens 20 0 909000 40912 21044 R 100,2 0,1 0:14.17 nodejs
Загружено по одному ядру на каждой машине. То есть мы теперь распределяем нагрузку равномерно по обоим машинам. Заметьте, мы добились этого, не поменяв ни одной строчки кода. И нам помог в этом Comedy и модель акторов.
Мы рассмотрели пример гибкого масштабирования приложения с помощью модели акторов и её реализации в Node.JS — Comedy. Алгоритм наших действий выглядел следующим образом:
Как описывать приложение в терминах акторов? Это аналог вопроса "Как описать приложение в терминах объектов и классов?". Программирование на акторах очень похоже на ООП. Можно сказать, что это ООП++. В ООП есть различные устоявшиеся и успешные паттерны проектирования. Аналогичным образом, и для модели акторов есть свои паттерны. Вот книга по ним. Эти паттерны можно использовать, и они вам наверняка помогут, но, если вы уже владеете ООП, у вас точно не будет с акторами проблем.
Что если ваше приложение уже написано? Нужно ли "переписывать его на акторы"? Конечно, модификация кода в этом случае потребуется. Но не обязательно делать масштабный рефакторинг. Можно выделить несколько основных, "крупных" акторов, и после этого вы уже можете масштабироваться. "Крупные" акторы можно со временем раздробить на более мелкие. Опять же, если ваше приложение уже описано в терминах ООП, переход на акторы будет, скорее всего, безболезненным. Единственный момент, с которым, возможно, придётся поработать: акторы полностью изолированы друг от друга, в отличие от простых объектов.
Насчёт зрелости фреймворка. Первая рабочая версия Comedy была разработана внутри проекта SAYMON в июне 2016 года. Фреймворк с самой первой версии работал в продакшене в боевых условиях. В апреле 2017 года библиотека была выпущена в Open Source под Eclipse Public License. Comedy при этом продолжает быть частью SAYMON и используется для масштабирования системы и обеспечения её отказоустойчивости.
Список планируемых фич здесь.
В этой статье я не упомянул о целом ряде функциональный возможностей Comedy: о fault tolerance ("respawn" акторов), об инъекции ресурсов в акторы, об именованных кластерах, о маршаллинге пользовательских классов, о поддержке TypeScript. Но большую часть вышеперечисленного вы найдёте в документации, а то, что в ней ещё не описано — в тестах и примерах. Плюс, возможно, я напишу ещё статьи о Comedy и акторах в Node.JS, если тема пойдёт в массы.
Используйте Comedy! Создавайте issues! Жду ваших комментариев!
Метки: author weekens node.js акторы масштабирование |