Ad-social Bot

Smmok Bot

Vkserfing Bot

Vkstorm Bot

Vktarget Bot

Все программы

Запись опубликована: 23.02.2018

Привет, меня зовут Pavel Germanika

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


 

Может ли человек, проживая в унылом бесперспективном городе, чего-то добиться, имея под рукой лишь старый ноутбук и интернет? Можно ли без всяких офисов, начальных капиталов построить компанию, приносящую неплохую прибыль? Ответ на этот вопрос вы сможете узнать в моем блоге. Я Pavel Germanika, добро пожаловать!

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

И так проходила вся моя жизнь, пока, однажды, одним субботним утром не произошло чудо. Я до сих пор не могу ответить на вопрос, что же со мной произошло?. Почему меня переклинило? Но я вдруг перевел свою жизнь из пассивного состояния в активное. Я взял себя в руки и стал реализовывать все идеи, которые приходили в мою голову. И это коренным образом перевернуло все мое существование.

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

Мой Блог — это реалити-шоу обычного заурядного парня, который пытается добиться успеха с полного нуля. Никакого начального капитала, никаких знакомств, никаких особых способностей. Только идеи, анализ и компьютер. Я хочу быть максимально открытым и делиться с вами всеми своими мыслями и результатами работы.

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

Любой из вас может связаться со мной. Я рад каждому! Пишите на мой Telegram.

Метки: ,





Запись опубликована: 21.10.2018

Дайджест свежих материалов из мира фронтенда за последнюю неделю №335 (15 — 21 октября 2018)

Дайджест свежих материалов из мира фронтенда за последнюю неделю №335 (15 — 21 октября 2018)

Предлагаем вашему вниманию подборку с ссылками на новые материалы из области фронтенда и около него.

    Медиа    |    Веб-разработка    |    CSS    |    Javascript    |    Браузеры    |    Занимательное

Медиа

podcast Подкаст «Веб-стандарты», Выпуск №142: Safari и Edge, бюджет на перфоманс, новые теги в HTML, киевское сообщество, кто такие Котаны?
podcast Подкаст «Frontend Weekend» #75 – Никита Дубко о том, как за год стремительно прокачать свою карьеру frontend-разработчика
podcast Подкаст «CSSSR» Новости 512 — Выпуск №25 (15.10 — 21.10)
podcast Подкаст «Фронтенд Юность (18+)» #68 Бабуля стала олимпийским чемпионом по фронтенду

Веб-разработка

Google полностью отказался от схемы ajax сканирования
en История фронтенд фреймворков
en Как растет фронтенд долг?
en Умный бандлинг: как отдавать устаревший код старым браузерам
en Удивительный мир браузерной производительности – как быть производительным

CSS

habr Примеры использования Flexbox
habr CSS: интересные возможности border-radius
Свойство appearance и стандартизация стилей элементов форм: новая надежда
en Ритм в веб-типографике
en Негативные линии в гридах
en Использование определение функций, условные обозначения и группы с селекторами
en Стилизация блока с колонками в Gutenberg
en Справочник по CSS Layout на MDN

JavaScript

habr Школа магии TypeScript: дженерики и расширение типов
Джон Мюллер советует оптимизаторам учить JavaScript
0-day баг в популярном jQuery плагине эксплуатировали как минимум несколько лет
en 33 концепта, которые должен знать каждый JavaScript разработчик
en Testing Javascript — узнайте самый эффективный способ тестирования любого JavaScript приложения
en podcast Подкаст «JS Party» – Episode #48: Foundation foundations (live at Node + JS Interactive)

Браузеры

habr Chrome 70 поддерживает [список фич] и AV1 – почему поддержка этого кодека так важна?
Вышел Chrome 70 с возможностью отключения пресловутой функции автоматической авторизации и поддержкой приложений PWA на Windows
Модернизация TLS-подключений в Microsoft Edge и Internet Explorer 11
Firefox, Chrome, Edge и Safari прекратят поддержку TLS 1.0 и TLS 1.1
Mozilla экспериментирует с добавлением платного VPN в Firefox
Признаки «Оперы». Йон фон Течнер об идеологии браузера Vivaldi

Занимательное

Twenty Nineteen: первый взгляд на новую дефолтную тему в WordPress
Atlassian выпустила полностью переработанный Jira Software
Google добавила в Gmail интеграцию некоторых функций сервисов Dropbox, Box, Jira и Egnyte
Adobe Max 2018 и новые инструменты дизайна
«Грязное бельишко Google+»: исповедь бывшего сотрудника проекта, который возненавидел Google
Новый Winamp будет представлен в 2019 году

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

Дайджест за прошлую неделю.
Материал подготовили dersmoll и alekskorovin.

Source: habr1

Метки:





Запись опубликована: 21.10.2018

Вышла Oracle Database 18c XE

Oracle Database XE Logo
Свершилось! Можно открывать шампанское и закатывать вечеринку — спустя более, чем 7 лет с момента выпуска предыдущего релиза, для скачивания наконец доступна свежайшая Oracle Database 18c XE. Пока только для Linux x64, но версии для других платформ, также как и Docker и Vagrant образы обещают появиться совсем скоро.

Для тех, кто не в курсе, Oracle Database XE или Express Edition — это бесплатная редакция одной из самых мощных реляционных СУБД. Традиционно этот тип редакции обладал минимальным доступным функционалом, определенными ограничениями на используемые ресурсы, и малым размером дистрибутива. Тем не менее, даже эта версия СУБД всегда пользовалась большой популярностью среди тех, кто только познаёт возможности этой СУБД, небольших компаний, которых на данный момент устраивают все ограничения и они хотят оценить технологию и среди простых энтузиастов как мы с вами.

Новая же, 18-ая версия XE открывает просто небывалый простор для использования данной СУБД, так как в этот раз компания Oracle сменила тактику, и вместо предоставления минимального функционала, включила в эту редакцию практически все самые популярные опции самой дорогой и функциональной редакции Enterprise Edition. Но по-прежнему с ограничениями по используемым ресурсам.

Почему 18с?

Система версионности Oracle Database

Опять же для тех, кто не работает каждый день с СУБД от Oracle, поясню откуда взялась цифра 18. Дело в том, что после версии 12c Release 2 производитель решил изменить схему версионирования и перейти на годичный цикл выпуска новых версий своей СУБД. Таким образом, релиз 12.2.0.2 стали считать версией 18, а в будущем мы увидим 19, 20 и далее версии Oracle Database. Одновременно с этим, новый Product Manager по направлению Express Edition пообещал, что теперь и впредь мы будем наслаждаться новой версией XE практически одновременно с выпуском остальных редакций, т.е. также раз в год. Единственная разница будет состоять в том, что для XE не будет выпускаться патчей и исправлений безопасности, в отличие от SE и EE, но каждая следующая мажорная версия будет включать в себя все исправления и изменения, что, конечно не может не радовать. Особенно если учесть, что на протяжении 7 лет 11-ая версия XE также не получала никаких патчей, но всё равно была востребована у пользователей.

Что нового?

Итак, что же примечательного в новой версии Oracle Database 18c XE? На самом деле масса вещей. Но самое важное отличие от предыдущих версий данной редакции состоит в том, что на этот раз в неё включены практически все самые популярные опции из Standard и даже Enterprise Edition. Рассмотрим более подробно самые примечательные из них.

Multitenant

Начиная с 12c Oracle Database поддерживает так называемые Pluggable Databases — смысл в том, что база данных может быть «подключена» и «отключена» к инстансу буквально при помощи пары команд SQL*Plus. Это позволяет переносить базы данных между хостами и даже версиями СУБД без каких-либо сложностей. Обещают даже совместимость с более новыми версиями Oracle Database, т.е. процесс апгрейда будет выглядеть не сложнее, чем unplug-uninstall-install-plug. Также Multitenant-архитектура позволяет поддерживать, например, разные версии APEX в разных базах данных на одном хосте.

In-Memory Column Store и Aggregation

Одна из самых мощных опций Oracle Database — это in-memory column store, которая позволяет в прозрачном режиме хранить в памяти в колонкоориентированном формате копию данных для скорейшего доступа к ним.

Partitioning

Партиционирование не является чем-то новым и захватывающим, однако, всегда было доступно только для пользователей Enterprise Edition, хотя в конкурирующих СУБД эта опция в большинстве случаев есть, что называется, «из коробки». Вот, например, в недавно вышедшем Postgres 11 также было добавлено хэш-партиционирование. Также как теперь и в бесплатной редакции Oracle.

Advanced Analytics и Security

Это целый набор инструментов для Data Mining. Интерфейсы Data Mining SQL, R programming, Oracle Data Miner UI. Что касается Seciruty, то это всё, что касается прозрачного шифрования данных.

Online Index Rebuid

Как же мне не хватало этой возможности в одном из проектов. Теперь можно производить неблокирующее перестроение индекса «на лету».

Online Table Redefinition

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

Query Results Cache и PL/SQL Function Result Cache

Не секрет, что если речь идет о производительности, то она не может вестись без кэширования данных. Кэширование на уровне инстанса результатов SQL-запросов и PL/SQL-функций теперь доступно и может использоваться для лучшей производительсности ваших приложений.

Bitmap Indexes

Специальный вид индексов, использование которых обычно сопряжено с аналитическими системами. Это так, потому что данный тип индексов рекомендуется использовать только на таблицах, редко подверженных апдейтам. Однако, их преимущество состоит в том, что эти индексы могут комбинироваться для ещё большего ускорения доступа к данным, а также использоваться для использования нескольких источников (так называемые Bitmap Join Indexes).

Oracle Advanced Compression

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

Materialized View Query Rewrite

Опция, позволяющая оптимизатору автоматическое «переписывание» SQL-запросов на использование материализованных представлений для улучшения их производительности.

Oracle Spatial and Graph

Всё что касается хранения и работы с геоданными.

К сожалению, не завезли такие опции как Parallel Query, Block Media Recovery, Diagnostics pack и Tuning pack. Однако, Roadmap проекта предполагает включение последних двух в следующие версии XE.

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

Ну и конечно не стоит забывать о количестве исправлений ошибок и усовершенствований внутренних механизмов, которые СУБД претерпела с версии 11g. Только подумайте какой рывок был сделан в работе самой важной и самой уважаемой компоненты Oracle Database — её оптимизатора.

Ограничения

Где же ложка дегтя? В ограничениях на используемые данной версией СУБД ресурсы. Хотя и здесь был замечен логичный прирост:

  • Максимальный размер базы данных составляет 12 GB (против 11 GB в 11g XE);
  • До 2 GB оперативной памяти (против 1 GB в 11g XE);
  • До 2 потоков CPU (против 1 в 11g XE);
  • До 3 подключаемых баз данных (Pluggable Databases или PDB, в 11g XE такая функциональность отсутствовала).

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

Post Scriptum

RAD Badge

Стоит заметить, что в отличие от Oracle Database 11g XE, новая версия Express Edition поставляется без предустановленного Oracle APEX (Application Express — фреймворк для быстрой разработки data-driven веб-приложений), это обсусловлено как минимум контейнерной архитектурой СУБД.

Однако, установка так называемого Oracle RAD-стека (Rapid Application Development), состоящего из REST Data Services, APEX и Database, не составит большого труда. Последние версии данных компонент всегда можно найти на официальном сайте:

Я считаю эту новость грандиозной для всех разработчиков, так или иначе связанных с Oracle Database, так как вновь обретенная жизнь для XE может значить приток молодых специалистов в эту область, что всегда положительно отражается на комьюнити! Ура, товарищи!

Метки:

Похожие публикации

Source: habr1

Метки:





Запись опубликована: 21.10.2018

[Из песочницы] Бесполезный отложенный неблокирующий обмен сообщениями в MPI: лайт-аналитика и туториал для тех, кто немножечко «в теме»

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

Наше &laquoДано: &raquo

Итак, суть нашей, в сущности вычислительной задачи, заключается в том, чтобы сравнить во сколько раз программа, использующая неблокирующие отложенные двухточечные передачи быстрее той, что использует блокирующие двухточечные передачи. Измерения будем проводить для входных массивов размерностью 64, 256, 1024, 4096, 8192, 16384, 65536, 262144, 1048576, 4194304, 16777216, 33554432 элементов. По умолчанию предлагается решать ее четырьмя процессами. А вот, собственно, и то, что мы будем считать:

На выходе у нас должно получиться три вектора: Y1, Y2 и Y3, которые соберет у себя нулевой процесс. Все это дело я буду тестировать на своей системе на базе процессора Intel с 16 ГБ ОЗУ. Для разработки программ будем использовать реализацию стандарта MPI от Microsoft версии 9.0.1 (на момент написания статьи она актуальна), Visual Studio Community 2017 и не Fortran.

Матчасть

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

Блокирующий обмен

Для блокирующего обмена сообщениями типа точка-точка будем пользоваться функциями:

MPI_Send — осуществляет блокирующую отправку сообщения, т.е. после вызова функции процесс блокируется до тех пор пока отправляемые им данные не будут записаны из его памяти в внутрисистемный буфер среды MPI, после процесс продолжает работать дальше;
MPI_Recv — осуществляет блокирующий прием сообщения, т.е. после вызова функции процесс блокируется до тех пор пока не поступят данные от процесса-отправителя и пока эти данные не будут полностью записаны в буфер процесса-приемника средой MPI.

Отложенный неблокирующий обмен

Для отложенного неблокирующего обмена сообщениями типа точка-точка будем пользоваться функциями:

MPI_Send_init — в фоновом режиме подготавливает среду к посылке данных, которая произойдет в некотором будущем и никаких блокировок;
MPI_Recv_init — эта функция работает аналогично предыдущей, только на этот раз для приема данных;
MPI_Start — запускает сам процесс приема или передачи сообщения, он так же проходит в фоновом режиме а.к.а. без блокировки;
MPI_Wait — используется для проверки и, при необходимости, ожидания завершения посылки или приема сообщения, а вот она как раз и блочит процесс при необходимости (если данные «недоотправлены» или «недоприняты»). Например, процесс хочет использовать данные, которые к нему еще не дошли — не хорошо, поэтому вставляем MPI_Wait перед тем местом, где ему эти данные понадобятся (вставляем её даже если просто есть риск повреждения данных). Еще пример, процесс запустил фоновую передачу данных, а после запуска передачи данных сразу же стал эти данные как-то изменять — не хорошо, поэтому вставляем MPI_Wait перед тем местом в программе, где он начинает эти данные изменять (тут так же вставляем её даже если просто есть риск повреждения данных).

Таким образом семантически последовательность вызовов при отложенном неблокирующем обмене такая:

  1. MPI_Send_init / MPI_Recv_init — готовим среду к приему или передаче
  2. MPI_Start — запускаем процесс приема/передачи
  3. MPI_Wait — вызываем при риске повреждения (в т.ч. «недоотправки» и «недоприема») передаваемых или принимаемых данных

Так же я использовал в своих тестовых программах MPI_Startall, MPI_Waitall, смысл их в принципе аналогичен MPI_Start и MPI_Wait соответственно, только они оперируют несколькими посылками и/или передачами. Но это еще далеко не весь список функций старта и ожидания, есть еще несколько функций проверки завершенности операций.

Архитектура связей между процессами

Для наглядности построим граф выполнения вычислений четырьмя процессами. При этом надо постараться относительно равномерно распределить все векторные арифметические операции по процессам. Вот что у меня получилось:

Видите эти массивы T0-T2? Это буферы для хранения промежуточных результатов операций. Так же на графе при передаче сообщений от одного процесса к другому в начале стрелки стоит название массива, данные которого передаются, а в конце стрелки — массив, принимающий эти данные.

Ну что же, когда мы наконец ответили на вопросы:

  1. Что за задачу решаем?
  2. Какие средства будем использовать для ее решения?
  3. Как будем ее решать?

Осталось только ее решить…

Наше &laquoРешение: &raquo

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

Все векторные арифметические операции я вынес в отдельные процедуры (add, sub, mul, div) дабы увеличить читаемость кода. Все входные массивы инициализируются в соответствии с формулами, которые я указал почти что наобум. Так как нулевой процесс осуществляет сборку результатов работы со всех остальных процессов, следовательно, он работает дольше всех, поэтому время его работы логично считать равным времени выполнения программы (как мы помним, нас интересует: арифметика + меседжинг) и в первом и во втором случае. Измерение интервалов времени будем осуществлять с помощью функции MPI_Wtime и заодно я решил вывести какое у меня там разрешение часиков с помощью MPI_Wtick (где-то в душе я надеюсь, что они подвяжутся к моему инвариантному TSC, в этом случае, я даже готов простить им погрешность, связанную с временем вызова функции MPI_Wtime). Так вот, соберем воедино все о чем я писал выше и в соответствии с графом разработаем наконец эти программы (и отладим конечно же тоже).

Кому интересно посмотреть код:

Программа с блокирующими передачами данных

#include "pch.h"
#include <iostream>
#include <iomanip>
#include <fstream>
#include <mpi.h>
using namespace std;
void add(double *A, double *B, double *C, int n);
void sub(double *A, double *B, double *C, int n);
void mul(double *A, double *B, double *C, int n);
void div(double *A, double *B, double *C, int n);
int main(int argc, char **argv)
{
	if (argc < 2)
	{
		return 1;
	}
	int n = atoi(argv[1]);
	int rank;
	double start_time, end_time;
	MPI_Status status;
	double *A = new double[n];
	double *B = new double[n];
	double *C = new double[n];
	double *D = new double[n];
	double *E = new double[n];
	double *G = new double[n];
	double *T0 = new double[n];
	double *T1 = new double[n];
	double *T2 = new double[n];
	for (int i = 0; i < n; i++)
	{
		A[i] = double (2 * i + 1);
		B[i] = double(2 * i);
		C[i] = double(0.003 * (i + 1));
		D[i] = A[i] * 0.001;
		E[i] = B[i];
		G[i] = C[i];
	}
	cout.setf(ios::fixed);
	cout << fixed << setprecision(9);
	MPI_Init(&argc, &argv);
	MPI_Comm_rank(MPI_COMM_WORLD, &rank);
	if (rank == 0)
	{
		start_time = MPI_Wtime();
		sub(A, B, T0, n);
		MPI_Send(T0, n, MPI_DOUBLE, 1, 0, MPI_COMM_WORLD);
		MPI_Send(T0, n, MPI_DOUBLE, 2, 0, MPI_COMM_WORLD);
		div(T0, G, T1, n);
		MPI_Recv(T2, n, MPI_DOUBLE, 1, 0, MPI_COMM_WORLD, &status);
		add(T1, T2, T0, n);
		mul(T0, T1, T2, n);
		MPI_Recv(T0, n, MPI_DOUBLE, 2, 0, MPI_COMM_WORLD, &status);
		MPI_Send(T2, n, MPI_DOUBLE, 1, 0, MPI_COMM_WORLD);
		add(T0, T2, T1, n);
		MPI_Recv(T0, n, MPI_DOUBLE, 1, 0, MPI_COMM_WORLD, &status);
		MPI_Recv(T2, n, MPI_DOUBLE, 2, 0, MPI_COMM_WORLD, &status);
		end_time = MPI_Wtime();
		cout << "Clock resolution: " << MPI_Wtick() << " secs" << endl;
		cout << "Thread " << rank << " execution time: " << end_time - start_time << endl;
	}
	if (rank == 1)
	{
		add(C, C, T0, n);
		MPI_Recv(T1, n, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, &status);
		MPI_Send(T0, n, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD);
		mul(T1, G, T2, n);
		add(T2, C, T0, n);
		MPI_Recv(T1, n, MPI_DOUBLE, 2, 0, MPI_COMM_WORLD, &status);
		MPI_Send(T0, n, MPI_DOUBLE, 2, 0, MPI_COMM_WORLD);
		sub(T1, T0, T2, n);
		MPI_Recv(T0, n, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, &status);
		add(T0, T2, T1, n);
		MPI_Send(T1, n, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD);
	}
	if (rank == 2)
	{
		mul(C, C, T0, n);
		MPI_Recv(T1, n, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, &status);
		MPI_Recv(T2, n, MPI_DOUBLE, 3, 0, MPI_COMM_WORLD, &status);
		MPI_Send(T0, n, MPI_DOUBLE, 1, 0, MPI_COMM_WORLD);
		MPI_Send(T0, n, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD);
		add(T1, T2, T0, n);
		mul(T0, G, T1, n);
		MPI_Recv(T2, n, MPI_DOUBLE, 1, 0, MPI_COMM_WORLD, &status);
		mul(T1, T2, T0, n);
		MPI_Recv(T1, n, MPI_DOUBLE, 3, 0, MPI_COMM_WORLD, &status);
		mul(T0, T1, T2, n);
		MPI_Send(T2, n, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD);
	}
	if (rank == 3)
	{
		mul(E, D, T0, n);
		MPI_Send(T0, n, MPI_DOUBLE, 2, 0, MPI_COMM_WORLD);
		sub(T0, B, T1, n);
		mul(T1, T1, T2, n);
		sub(T1, G, T0, n);
		mul(T0, T2, T1, n);
		MPI_Send(T1, n, MPI_DOUBLE, 2, 0, MPI_COMM_WORLD);
	}
	MPI_Finalize();
	delete[] A, B, C, D, E, G, T0, T1, T2;
	return 0;
}
void add(double *A, double *B, double *C, int n)
{
	for (size_t i = 0; i < n; i++)
	{
		C[i] = A[i] + B[i];
	}
}
void sub(double *A, double *B, double *C, int n)
{
	for (size_t i = 0; i < n; i++)
	{
		C[i] = A[i] - B[i];
	}
}
void mul(double *A, double *B, double *C, int n)
{
	for (size_t i = 0; i < n; i++)
	{
		C[i] = A[i] * B[i];
	}
}
void div(double *A, double *B, double *C, int n)
{
	for (size_t i = 0; i < n; i++)
	{
		C[i] = A[i] / B[i];
	}
}

Программа с отложенными неблокирующими передачами данных

#include "pch.h"
#include <iostream>
#include <iomanip>
#include <fstream>
#include <mpi.h>
using namespace std;
void add(double *A, double *B, double *C, int n);
void sub(double *A, double *B, double *C, int n);
void mul(double *A, double *B, double *C, int n);
void div(double *A, double *B, double *C, int n);
int main(int argc, char **argv)
{
	if (argc < 2)
	{
		return 1;
	}
	int n = atoi(argv[1]);
	int rank;
	double start_time, end_time;
	MPI_Request request[7];
	MPI_Status statuses[4];
	double *A = new double[n];
	double *B = new double[n];
	double *C = new double[n];
	double *D = new double[n];
	double *E = new double[n];
	double *G = new double[n];
	double *T0 = new double[n];
	double *T1 = new double[n];
	double *T2 = new double[n];
	for (int i = 0; i < n; i++)
	{
		A[i] = double(2 * i + 1);
		B[i] = double(2 * i);
		C[i] = double(0.003 * (i + 1));
		D[i] = A[i] * 0.001;
		E[i] = B[i];
		G[i] = C[i];
	}
	cout.setf(ios::fixed);
	cout << fixed << setprecision(9);
	MPI_Init(&argc, &argv);
	MPI_Comm_rank(MPI_COMM_WORLD, &rank);
	if (rank == 0)
	{
		start_time = MPI_Wtime();
		MPI_Send_init(T0, n, MPI_DOUBLE, 1, 0, MPI_COMM_WORLD, &request[0]);//
		MPI_Send_init(T0, n, MPI_DOUBLE, 2, 0, MPI_COMM_WORLD, &request[1]);//
		MPI_Recv_init(T2, n, MPI_DOUBLE, 1, 0, MPI_COMM_WORLD, &request[2]);//
		MPI_Recv_init(T0, n, MPI_DOUBLE, 2, 0, MPI_COMM_WORLD, &request[3]);//
		MPI_Send_init(T2, n, MPI_DOUBLE, 1, 0, MPI_COMM_WORLD, &request[4]);//
		MPI_Recv_init(T0, n, MPI_DOUBLE, 1, 0, MPI_COMM_WORLD, &request[5]);//
		MPI_Recv_init(T2, n, MPI_DOUBLE, 2, 0, MPI_COMM_WORLD, &request[6]);//
		MPI_Start(&request[2]);
		sub(A, B, T0, n);
		MPI_Startall(2, &request[0]);
		div(T0, G, T1, n);
		MPI_Waitall(3, &request[0], statuses);
		add(T1, T2, T0, n);
		mul(T0, T1, T2, n);
		MPI_Startall(2, &request[3]);
		MPI_Wait(&request[3], &statuses[0]);
		add(T0, T2, T1, n);
		MPI_Startall(2, &request[5]);
		MPI_Wait(&request[4], &statuses[0]);
		MPI_Waitall(2, &request[5], statuses);
		end_time = MPI_Wtime();
		cout << "Clock resolution: " << MPI_Wtick() << " secs" << endl;
		cout << "Thread " << rank << " execution time: " << end_time - start_time << endl;
	}
	if (rank == 1)
	{
		MPI_Recv_init(T1, n, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, &request[0]);//
		MPI_Send_init(T0, n, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, &request[1]);//
		MPI_Recv_init(T1, n, MPI_DOUBLE, 2, 0, MPI_COMM_WORLD, &request[2]);//
		MPI_Send_init(T0, n, MPI_DOUBLE, 2, 0, MPI_COMM_WORLD, &request[3]);//
		MPI_Recv_init(T0, n, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, &request[4]);//
		MPI_Send_init(T1, n, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, &request[5]);//
		MPI_Start(&request[0]);
		add(C, C, T0, n);
		MPI_Start(&request[1]);
		MPI_Wait(&request[0], &statuses[0]);
		mul(T1, G, T2, n);
		MPI_Start(&request[2]);
		MPI_Wait(&request[1], &statuses[0]);
		add(T2, C, T0, n);
		MPI_Start(&request[3]);
		MPI_Wait(&request[2], &statuses[0]);
		sub(T1, T0, T2, n);
		MPI_Wait(&request[3], &statuses[0]);
		MPI_Start(&request[4]);
		MPI_Wait(&request[4], &statuses[0]);
		add(T0, T2, T1, n);
		MPI_Start(&request[5]);
		MPI_Wait(&request[5], &statuses[0]);
	}
	if (rank == 2)
	{
		MPI_Recv_init(T1, n, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, &request[0]);//
		MPI_Recv_init(T2, n, MPI_DOUBLE, 3, 0, MPI_COMM_WORLD, &request[1]);//
		MPI_Send_init(T0, n, MPI_DOUBLE, 1, 0, MPI_COMM_WORLD, &request[2]);//
		MPI_Send_init(T0, n, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, &request[3]);//
		MPI_Recv_init(T2, n, MPI_DOUBLE, 1, 0, MPI_COMM_WORLD, &request[4]);//
		MPI_Recv_init(T1, n, MPI_DOUBLE, 3, 0, MPI_COMM_WORLD, &request[5]);//
		MPI_Send_init(T2, n, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, &request[6]);//
		MPI_Startall(2, &request[0]);
		mul(C, C, T0, n);
		MPI_Startall(2, &request[2]);
		MPI_Waitall(4, &request[0], statuses);
		add(T1, T2, T0, n);
		MPI_Start(&request[4]);
		mul(T0, G, T1, n);
		MPI_Wait(&request[4], &statuses[0]);
		mul(T1, T2, T0, n);
		MPI_Start(&request[5]);
		MPI_Wait(&request[5], &statuses[0]);
		mul(T0, T1, T2, n);
		MPI_Start(&request[6]);
		MPI_Wait(&request[6], &statuses[0]);
	}
	if (rank == 3)
	{
		MPI_Send_init(T0, n, MPI_DOUBLE, 2, 0, MPI_COMM_WORLD, &request[0]);
		MPI_Send_init(T1, n, MPI_DOUBLE, 2, 0, MPI_COMM_WORLD, &request[1]);
		mul(E, D, T0, n);
		MPI_Start(&request[0]);
		sub(T0, B, T1, n);
		mul(T1, T1, T2, n);
		MPI_Wait(&request[0], &statuses[0]);
		sub(T1, G, T0, n);
		mul(T0, T2, T1, n);
		MPI_Start(&request[1]);
		MPI_Wait(&request[1], &statuses[0]);
	}
	MPI_Finalize();
	delete[] A, B, C, D, E, G, T0, T1, T2;
	return 0;
}
void add(double *A, double *B, double *C, int n)
{
	for (size_t i = 0; i < n; i++)
	{
		C[i] = A[i] + B[i];
	}
}
void sub(double *A, double *B, double *C, int n)
{
	for (size_t i = 0; i < n; i++)
	{
		C[i] = A[i] - B[i];
	}
}
void mul(double *A, double *B, double *C, int n)
{
	for (size_t i = 0; i < n; i++)
	{
		C[i] = A[i] * B[i];
	}
}
void div(double *A, double *B, double *C, int n)
{
	for (size_t i = 0; i < n; i++)
	{
		C[i] = A[i] / B[i];
	}
}

Тестирование и анализ

Давайте запустим наши программы для массивов разных размеров и посмотрим что из этого выйдет. Результаты тестов сведем в таблицу, в последнем столбце которой рассчитаем и запишем коэффициент ускорения, который определим так: Куск = Tотл. неблок. / Tблок.

Если посмотреть на эту таблицу чуть внимательнее чем обычно, то можно заметить, что при увеличении числа обрабатываемых элементов коэффициент ускорения убывает как-то так:

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

Вот, собственно, сама программа:

Измерение времени

#include "pch.h"
#include <iostream>
#include <iomanip>
#include <Windows.h>
#include <fstream>
using namespace std;
void add(double *A, double *B, double *C, int n);
void sub(double *A, double *B, double *C, int n);
void mul(double *A, double *B, double *C, int n);
void div(double *A, double *B, double *C, int n);
int main()
{
	struct res
	{
		double add;
		double sub;
		double mul;
		double div;
	};
	int i, j, k, n, loop;
	LARGE_INTEGER start_time, end_time, freq;
	ofstream fout("test_measuring.txt");
	int N[12] = { 64, 256, 1024, 4096, 8192, 16384, 65536, 262144, 1048576, 4194304, 16777216, 33554432 };
	SetConsoleOutputCP(1251);
	cout << "Введите число циклов loop: ";
	cin >> loop;
	fout << setiosflags(ios::fixed) << setiosflags(ios::right) << setprecision(9);
	fout << "Циклов измерений: " << loop << endl;
	fout << setw(10) << "n Элементов" << setw(30) << "Ср. время суммирования (c)" << setw(30) << "Ср. время вычитания (c)"
		<< setw(30) << "Ср.время умножения (c)" << setw(30) << "Ср. время деления (c)" << endl;
	QueryPerformanceFrequency(&freq);
	cout << "nЧастота счета: " << freq.QuadPart << " Гц" << endl;
	for (k = 0; k < sizeof(N) / sizeof(int); k++)
	{
		res output = {};
		n = N[k];
		double *A = new double[n];
		double *B = new double[n];
		double *C = new double[n];
		for (i = 0; i < n; i++)
		{
			A[i] = 2.0 * i;
			B[i] = 2.0 * i + 1;
			C[i] = 0;
		}
		for (j = 0; j < loop; j++)
		{
			QueryPerformanceCounter(&start_time);
			add(A, B, C, n);
			QueryPerformanceCounter(&end_time);
			output.add += double(end_time.QuadPart - start_time.QuadPart) / double(freq.QuadPart);
			QueryPerformanceCounter(&start_time);
			sub(A, B, C, n);
			QueryPerformanceCounter(&end_time);
			output.sub += double(end_time.QuadPart - start_time.QuadPart) / double(freq.QuadPart);
			QueryPerformanceCounter(&start_time);
			mul(A, B, C, n);
			QueryPerformanceCounter(&end_time);
			output.mul += double(end_time.QuadPart - start_time.QuadPart) / double(freq.QuadPart);
			QueryPerformanceCounter(&start_time);
			div(A, B, C, n);
			QueryPerformanceCounter(&end_time);
			output.div += double(end_time.QuadPart - start_time.QuadPart) / double(freq.QuadPart);
		}
		fout << setw(10) << n << setw(30) << output.add / loop << setw(30) << output.sub / loop
			<< setw(30) << output.mul / loop << setw(30) << output.div / loop << endl;
		delete[] A, B, C;
	}
	fout.close();
	cout << endl;
	system("pause");
	return 0;
}
void add(double *A, double *B, double *C, int n)
{
	for (size_t i = 0; i < n; i++)
	{
		C[i] = A[i] + B[i];
	}
}
void sub(double *A, double *B, double *C, int n)
{
	for (size_t i = 0; i < n; i++)
	{
		C[i] = A[i] - B[i];
	}
}
void mul(double *A, double *B, double *C, int n)
{
	for (size_t i = 0; i < n; i++)
	{
		C[i] = A[i] * B[i];
	}
}
void div(double *A, double *B, double *C, int n)
{
	for (size_t i = 0; i < n; i++)
	{
		C[i] = A[i] / B[i];
	}
}

При запуске она просит ввести число циклов измерений, я тестировал для 10000 циклов. На выходе получаем усредненный результат по каждой операции:

Для измерения времени я использовал высокоуровненую QueryPerformanceCounter. Настойчиво рекомендую почитать этот FAQ чтобы большинство вопросов по измерению времени этой функцией отпали сами собой. Она по моим наблюдениям цепляется за TSC (но теоретически может и не за него), а возвращает, согласно справке, текущее число тиков счетчика. Но дело в том, что мой счетчик физически не может измерить интервал времени 32 нс (см. первую строку таблицы результатов). Такой результат получается из-за того, что между двумя вызовами QueryPerformanceCounter проходит то 0 тиков, то 1. Для первой строки в таблице можно лишь заключить, что примерно треть результатов из 10000 равны 1 тик. Так что данные в этой таблице для 64, 256 и даже для 1024 элементов есть нечто совсем приблизительное. Теперь, давайте откроем любую из программ и посчитаем сколько всего операций каждого типа в ней встречается, традиционно все «размажем» по очередной таблице:

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

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

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

Итоги

Таким образом, продолжая увеличивать длину массивов вы придете к тому, что программа с отложенными неблокирующими передачами будет лишь совсем немного быстрее той, что использует блокирующий обмен. А если устремить длину массивов в бесконечность (ну или просто брать очень уж длинные массивы), то время работы вашей программы будет прочти на 100% определяться вычислениями, а коэффициент ускорения будет благополучно стремиться к 1.

Метки:

Похожие публикации

Source: habr1

Метки:





Запись опубликована: 21.10.2018

Анализ производительности WSGI-серверов: Часть вторая

Данная статья является переводом статьи Кевина Голдберга «A Performance Analysis of Python WSGI Servers: Part 2» dzone.com/articles/a-performance-analysis-of-python-wsgi-servers-part с небольшими дополнениями от переводчика.

image

Введение

В первой части этой серии Вы познакомились с WSGI и с шестью наиболее популярными по мнению автора WSGI-серверами. В этой части Вам будет показан результат анализа производительности этих серверов. С этой целью была создана специальная тестовая песочница.

Конкурсанты

Из-за нехватки времени исследование было ограничено шестью WSGI-серверами. Весь код с инструкциями по запуску для этого проекта размещен на GitHub. Возможно со временем проект будет расширяться и будут представлены анализы производительности для других WSGI-серверов. Но пока речь пойдёт о шести серверах:

  1. Bjoern описывает себя как « сверхбыстрый WSGI-сервер» и может похвастаться тем, что это «самый быстрый, самый маленький и легкий WSGI-сервер». Мы создали небольшое приложение, использующее большинство параметров библиотеки по умолчанию.
  2. CherryPy — чрезвычайно популярный и стабильный фреймворк и WSGI-сервер. Этот небольшой скрипт использовался для обслуживания нашего образца приложения через CherryPy.
  3. Gunicorn был вдохновлен сервером Unicorn от Ruby (отсюда и название). Он скромно утверждает, что он «просто реализован, легок в использовании и довольно быстрый». В отличие от Bjoern и CherryPy, Gunicorn является автономным сервером. Мы создали его с помощью этой команды. Параметр «WORKER_COUNT» был установлен в два раза больше доступных ядер процессора, плюс один. Это было сделано на основании рекомендаций из документации Gunicorn.
  4. Meinheld — это высокопроизводительный WSGI-совместимый веб-сервер, который утверждает, что он легкий. Основываясь на примере, указанном на сайте сервера, мы создали своё приложение.
  5. mod_wsgi создан тем же создателем, что и mod_python. Подобно mod_python, он доступен только для Apache. Однако он включает инструмент под названием «mod_wsgi express», который создаёт минимально возможный инстанс Apache. Мы сконфигурировали и использовали mod_wsgi express с помощью этой команды. Чтобы соответствовать Gunicorn, мы настроили mod_wsgi т.о, чтобы создать worker-ов вдвое больше чем ядер процессора.
  6. uWSGI — полнофункциональный сервер приложений. Как правило, uWSGI сопрягается с прокси-сервером (например: Nginx). Однако, чтобы лучше оценить производительность каждого сервера, мы попытались использовать только голые серверы и создали двух worker-ов для каждого доступного ядра процессора.

Бенчмарк

Чтобы сделать тест максимально объективным, был создан Docker-контейнер для изоляции тестируемого сервера от остальной части системы. Также использование Docker-контейнера гарантировало, что каждый запуск начинается с чистого листа.

Сервер:

  • Изолирован в Docker-контейнере.
  • Выделено 2 ядра процессора.
  • Оперативная память контейнера была ограничена до 512 МБ.

Тестирование:

  • wrk, современный инструмент HTTP-бенчмаркинга, запускал тесты.
  • Серверы были протестированы в произвольном порядке с увеличением числа одновременных соединений в диапазоне от 100 до 10000.
  • wrk был ограничен двумя ядрами ЦПУ, не используемыми Docker.
  • Каждый тест длился 30 секунд и повторялся 4 раза.

Метрика:

  • Среднее количество постоянных запросов, ошибок и задержек предоставлялось wrk.
  • Встроенный в Docker, мониторинг показывал уровни использования ЦПУ и ОЗУ.
  • Самые высокие и самые низкие показания были отброшены, а остальные значения были усреднены.
  • Для любопытных мы отправили полный скрипт на GitHub.

Результаты

Все исходные показатели производительности были включены в репозиторий проекта, а также предоставлен сводный CSV-файл. Также для визуализации были созданы графики в среде Google-doc.

Зависимость RPS от числа одновременных соединенинй

На этом графике показано среднее количество одновременных запросов; Чем выше число, тем лучше.

image

image

  • Bjoern: Явный победитель.
  • CherryPy: Несмотря на то, что он написан на чистом Python, он был лучшим исполнителем.
  • Meinheld: Отличные показатели, учитывая скудные ресурсы контейнера.
  • mod_wsgi: Не самый быстрый, но производительность была последовательной и адекватной.
  • Gunicorn: Хорошая производительность при более низких нагрузках, но прослеживается борьба при большом количестве соединений.
  • uWSGI: Разочаровал плохими результатами.

ПОБЕДИТЕЛЬ: Bjoern

Bjoern

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

uWSGI

Мы были разочарованы слабыми результатами uWSGI. Мы ожидали, что он окажется в лидерах. Во время тестирования мы заметили, что логи uWSGI печатает на экране, и первоначально мы объяснили отсутствие производительности дополнительной работой, которую выполнял сервер. Тем не менее, даже после добавленной опции «—disable-logging», uWSGI по-прежнему является самым медленным сервером.

Как упоминалось в руководстве uWSGI, оно обычно сопрягается с прокси-сервером, таким как Nginx. Однако мы не уверены, что это может объяснить такую ​​большую разницу.

Задержка

Задержка — это количество времени, прошедшего между запросом и его ответом. Более низкие цифры — лучше.

image

  • CherryPy: Хорошо справлялся с нагрузкой.
  • Bjoern: В целом низкие задержки, но лучше работает при меньшем количестве одновременных соединений.
  • Gunicorn: хорош и последователен.
  • mod_wsgi: Средняя производительность, даже при большом количестве одновременных соединений.
  • Meinheld: В целом, приемлемая производительность.
  • uWSGI: uWSGI снова на последнем месте.

ПОБЕДИТЕЛЬ: CherryPy

Использование ОЗУ

Эта метрика показывает требования к памяти и «легкость» каждого сервера. Более низкие цифры — лучше.

image

  • Bjoern: Чрезвычайно легкий. Использует всего лишь 9 МБ ОЗУ для обработки 10 000 одновременных запросов.
  • Meinheld: Такой же как Bjoern.
  • Gunicorn: Умело справляется с высокими нагрузками с едва заметным потреблением памяти.
  • CherryPy: Первоначально нуждался в небольшом количестве оперативной памяти, но её использование стремительно увеличивалось с ростом нагрузки.
  • mod_wsgi: На более низких уровнях он был одним из наиболее интенсивных в памяти, но оставался довольно последовательным.
  • uWSGI: Очевидно, что у тестируемой нами версии проблемы с количеством потребляемой памяти.

ПОБЕДИТЕЛИ: Bjoern и Meinheld

Количество ошибок

Ошибка возникает, когда сервер падает, прерывается или истекает время запроса. Чем ниже, тем лучше.

image

Для каждого сервера мы рассчитали отношение общее отношение количества запросов к числу ошибок:

  • CherryPy: коэффициент ошибок около 0, даже при высоком количестве соединений.
  • Bjoern: Ошибки встречались, но это компенсировалось количеством обработанных запросов.
  • mod_wsgi: Хорошо работает с приемлемой частотой ошибок 6%.
  • Gunicorn: Работает с 9-процентной частотой ошибок.
  • uWSGI: Учитывая низкое количество запросов, которые он обслуживал, он оказался с 34-процентной частотой ошибок.
  • Meinheld: Упал на более высоких нагрузках, выбросив более 10 000 ошибок во время самого требовательного теста.

ПОБЕДИТЕЛЬ: CherryPy

Использование ЦПУ

Высокое использование ЦПУ не является хорошим или плохим, если сервер работает хорошо. Однако, это даёт некоторые интересные сведения о работе сервера. Поскольку использовались два ядра ЦПУ, максимальное возможное использование составляет 200 процентов.

image

  • Bjoern: однопоточный сервер, о чем свидетельствует его последовательное использование на 100% ЦПУ.
  • CherryPy: многопоточный, но застрял на 150-ти процентах. Это может быть связано с GIL Python.
  • Gunicorn: использует несколько процессов с полным использованием ресурсов ЦПУ на более низких уровнях.
  • Meinheld: однопоточный сервер, использующий ресурсы ЦПУ как Bjoern.
  • mod_wsgi: Многопоточный сервер использующий все ядра ЦПУ на протяжении всех измерений
  • uWSGI: очень низкое использование ЦПУ. Потребление ресурсов ЦПУ не превышает 50-ти процентов. Это одно из доказательств того, что uWSGI неправильно сконфигурирован.

ПОБЕДИТЕЛЬ: Нет, поскольку это скорее наблюдение в поведении, чем сравнение в производительности.

Заключение

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

  • Bjoern: Оправдывает себя как «супербыстрый, ультралегкий WSGI-сервер».
  • CherryPy: Высокая производительность, маленькое потребление памяти и маленькое количество ошибок. Неплохо для чистого Python.
  • Gunicorn: Хороший сервер для средних нагрузок.
  • Meinheld: Хорошо работает и требует минимальных ресурсов. Тем не менее, борется с более высокими нагрузками.
  • mod_wsgi: Интегрируется в Apache и отлично работает.
  • uWSGI: Очень разочаровал. Либо мы неправильно сконфигурировали uWSGI, либо версия, которую мы установили, имеет базовые ошибки.
Метки:

Похожие публикации

Source: habr1

Метки:





Запись опубликована: 21.10.2018

Webpack 4 и разделение конфигурационного файла на модули

Привет Хабр! Сегодня я расскажу вам о Webpack 4 с разделением кода на отдельные модули, а также о интересных решениях, которые помогут вам быстрее собрать сборку на webpack 4. В конце, я предоставлю свою базовую сборку на webpack c самыми необходимыми инструментами, которую вы в последствие сможете расширить. Данная сборка вам поможет понять данный материал, а также возможно поможет быстрее написать свою реализацию и быстрее решить возможные проблемы.

Основная идеология данной сборки — это корректное разделения кода внутри конфигурационного файла для удобства использования, чтения и чистоты webpack.config.js. Необходимые модули и плагины для dev и prod версии(а также для разделения функционала в главном файле) будут находиться в отдельной папке webpack и из неё импортироваться для соединения с главным конфигом.

Зачем нужен такой подход?

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

Что нам понадобится?

Мы будем использоваться плагин webpack-merge.
Создаём папку webpack и выносим все отдельные модули в отдельные файлы. Например, webpack/pug.js, webpack/scss.js и экспортируем из них эти функции.

Файл pug.js

module.exports = function() {
  return {
    module: {
      rules: [
        {
          test: /.pug$/,
          loader: 'pug-loader',
          options: {
            pretty: true,
          },
        },
      ],
    },
  };
};

Файл webpack.config.js. В данном файле мы их подключаем, и с помощью данного плагина удобно и быстро соединяем.

const merge = require('webpack-merge');
const pug = require('./webpack/pug');
const common = merge([
  {
    entry: {
      'index': PATHS.source + '/pages/index/index.js',
      'blog': PATHS.source + '/pages/blog/blog.js',
    },
    output: {
      path: PATHS.build,
      filename: './js/[name].js',
    },
    plugins: […],
    optimization: { … },
  },
  pug(),
]);

Теперь если у нас есть новая задача, под которую нужен новый модуль, плагин, лоадер, то мы выносим его в отельный модуль(файл) и помещаем в папку webpack, а затем подключаем его в главный конфигурационный файл, сохраняя конфиг максимально чистым.

Настройки для production и development

Сейчас мы с помощью банального if закончим наше разделение, к которому мы стремились, и настроим наш вебпак под эти два типа разработки, благодаря чему станет окончательно удобно пользоваться данным инструментом, а так же в будущем сможем гибко и просто настраивать его под любой другой проект, или же расширять в текущем. Для экспорта в ноду(для самой работы вебпака) в webpack 4 мы используем следующую конструкцию:

module.exports = function(env, argv) {
  if (argv.mode === 'production') {
    return merge([
      common,
      extractCSS(),
      favicon(),
    ]);
  }
  if (argv.mode === 'development') {
    return merge([
      common,
      devserver(),
      sass(),
      css(),
      sourceMap(),
    ]);
  }

В объект common мы подключаем то, что используется и на проде и в разработке, а в условиях подключаем только те модули, которые необходимы в этих случаях.

Теперь хотелось бы поговорить об основных особенностях webpack 4 относительно webpack 3

  • Для быстрого запуска, webpack 4 не нуждается в webpack.config.js, ему теперь необходима лишь точка входа (index.js)
  • В новой версии webpack command line interface вынесен в отдельный пакет и нужно установить webpack-cli.
  • Для запуска webpack 4, нужно (иначе будет warning) в скриптах указать mode (режим работы) —mode production или —mode development, в зависимости от ключа меняется работа вебпака. Режим development направлен для ускорения сборки. В production варианте направлено всё на итоговую минификацию кода.
  • Для того что бы создать common.js и common.css файлы, более не используется CommonsChunkPlugin, за это теперь отвечают splitChunks и используется следующая конструкция:
        optimization: {
          splitChunks: {
            cacheGroups: {
              'common': {
                minChunks: 2,
                chunks: 'all',
                name: 'common',
                priority: 10,
                enforce: true,
              },
            },
          },
        },
    

    В вебпак 3 – это было бы так в plugins:

    new webpack.optimize.CommonsChunkPlugin({ name: 'common ', })

    Соответственно в чанках в HtmlWebpackPlugin подключаем (тут без изменений).

    
    plugins: [
          new HtmlWebpackPlugin({
            filename: 'index.html',
            chunks: ['index', 'common'],
            template: PATHS.source + '/pages/index/index.pug',
          }),
        ],
    

  • Следующий важный момент, для того чтобы создать sourceMap, теперь мы используем следующий подход — создаём файл sourceMap.js в папке webpack и подключаем в дев версии например (как указано выше):
    module.exports = function() {
      return {
        devtool: 'eval-sourcemap',
      };
    };
    

Теперь подход с plugins: [new webpack.optimize.UglifyJsPlugin({}) ] не работает.

На этом я хотел бы завершить свой рассказ и предоставить свою базовую сборку — ссылка на webpack 4, которая возможно вам поможет в работе и освоение. Спасибо за внимание!

Метки:

Похожие публикации

Source: habr1

Метки:





Запись опубликована: 21.10.2018

[Перевод] Курс MIT «Безопасность компьютерных систем». Лекция 12: «Сетевая безопасность», часть 3

Курс MIT «Безопасность компьютерных систем». Лекция 12: «Сетевая безопасность», часть 3

Массачусетский Технологический институт. Курс лекций #6.858. «Безопасность компьютерных систем». Николай Зельдович, Джеймс Микенс. 2014 год

Computer Systems Security — это курс о разработке и внедрении защищенных компьютерных систем. Лекции охватывают модели угроз, атаки, которые ставят под угрозу безопасность, и методы обеспечения безопасности на основе последних научных работ. Темы включают в себя безопасность операционной системы (ОС), возможности, управление потоками информации, языковую безопасность, сетевые протоколы, аппаратную защиту и безопасность в веб-приложениях.
Лекция 1: «Вступление: модели угроз» / Часть 2 / Часть 3
Лекция 2: «Контроль хакерских атак» Часть 1 / Часть 2 / Часть 3
Лекция 3: «Переполнение буфера: эксплойты и защита» Часть 1 / Часть 2 / Часть 3
Лекция 4: «Разделение привилегий» Часть 1 / Часть 2 / Часть 3
Лекция 5: «Откуда берутся ошибки систем безопасности» Часть 1 / Часть 2
Лекция 6: «Возможности» Часть 1 / Часть 2 / Часть 3
Лекция 7: «Песочница Native Client» Часть 1 / Часть 2 / Часть 3
Лекция 8: «Модель сетевой безопасности» Часть 1 / Часть 2 / Часть 3
Лекция 9: «Безопасность Web-приложений» Часть 1 / Часть 2 / Часть 3
Лекция 10: «Символьное выполнение» Часть 1 / Часть 2 / Часть 3
Лекция 11: «Язык программирования Ur/Web» Часть 1 / Часть 2 / Часть 3
Лекция 12: «Сетевая безопасность» Часть 1 / Часть 2 / Часть 3

Студент: есть ли какой-либо вид подписи для несуществующих доменов верхнего уровня?

Профессор: я думаю, что есть. Точечный домен — это просто еще один домен, и в нём реализован тот же механизм. Так что домены «точка» и «точка.ком» в наше время используют DNS SEC, и там есть все эти записи, в которых говорится, например, что .in — доменное имя, которое существует, и имя «точка» тоже существует, и больше между ними ничего нет. Так что в доменах верхнего уровня присутствуют все эти вещи.



Студент: кроме опасности атак DoS, почему мы так заботимся о повторении доменных имен в рамках mit.edu?

Профессор: точно не знаю. Во всяком случае, в AFS есть текстовый файл, в котором перечислены все эти доменные имена MIT. Но я думаю, что в целом, некоторые компании чувствуют себя немного неловко в этом смысле, потому что у них часто есть внутренние имена, которые находятся в DNS и которые нельзя выдавать посторонним. Думаю, что на самом деле, это нечеткая область, которая никогда не была формализована и которая не точно разъясняет, какие именно гарантии предоставляет пользователям DNS. Обычно люди предполагают, что если существует конфиденциальное имя, то в случае с DNS оно не будет разглашено.

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

Студент: можно ли установить срок действия подписи, выделив её каким-то образом?

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

Итак, можно считать, что мы обсудили атаки способом угадываня порядковых номеров TCP SYN. Еще одна интересная проблема, которая касается TCP — это DDoS-атака, которая использует тот факт, что сервер сохраняет некое состояние. Если вы посмотрите на это рукопожатие, которое было нарисовано на доске раньше, вы увидите, что когда клиент устанавливает соединение с сервером, сервер должен запомнить порядковый номер клиента SNc. Таким образом, сервер должен поддерживать некоторую структуру данных в отдельном блоке, которая показывает, что этот порядковый номер используется для этого соединения.



Это своего рода таблица, где хранится порядковый номер SN и то, что соединение клиент-сервер имеет порядковый номер SNc. Причина, по которой сервер должен хранить эту таблицу, состоит в том, что сервер должен выяснить, какое правильное значение порядковый номер SNc должен принять позже, например, SNc+1. Кроме того, сервер также нуждается в хранении номеров SNs, которые гораздо важнее, так как показывают серверу, что соединение установлено с «правильным парнем».

Проблема состоит в том, что эта таблица не имеет реальной границы. Таким образом, вы можете получить пакеты из какой-то машины, даже не зная, кто их посылает. Вы просто получаете пакет, который выглядит как C->S с адресом источника, который утверждает, что он С. Для потенциального принятия этого соединения с данного IP-адреса необходимо создать запись в таблице. Причём эти записи существуют длительное время, потому что, возможно, кто-то устанавливает с вами связь из очень далекого места и при этом много пакетов теряются. В худшем случае это может занимать, например, минуту, пока кто-то не закончит это TCP-рукопожатие. Так что вы должны хранить это состояние в стеке TCP в течение относительно длительного времени, и нет никакого способа угадать, будет ли это допустимым или нет.

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

Проблема в том, что в лучшем случае злоумышленник просто использует тот же IP-адрес источника. В этом случае вы можете просто сказать, что каждому клиенту разрешено всего две записи, или что-то вроде этого. И тогда злоумышленник cможет использовать максимум 2 две записи в таблице.

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

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

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

В целом, это проблема, о которой стоит знать и пытаться избежать в любом протоколе, который вы разрабатываете. Нужно указать, что сервер не должен сохранять состояние до тех пор, пока он не сможет аутентифицировать и идентифицировать клиента. Потому что только после проверки подлинности клиента можно принимать решение, разрешено ли ему подключаться, например всего один раз, и в этом случае серверу не нужно сохранять состояние для этого подключения.
Проблема в том, что вы гарантируете сохранение состояние ещё до того, как узнаете, кто к вам подключается. Давайте посмотрим, как можно противодействовать атаке «наводнения» SYN Flooding, которая состоит в том, что сервер накапливает слишком много состояния.
Вы могли бы снова изменить TCP, например, исправить это довольно легко с помощью криптографии или чего-то еще, или изменить то, что отвечает за сохранение какого-то состояния. Но дело в том, что нам нужно использовать TCP как он есть. Могли бы мы решить эту проблему, не изменяя существующий протокол TCP?

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

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

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

В этой функции есть IP-адрес источника, IP-адрес назначения, такие же вещи, как и раньше — порт источника, порт назначения, метка времени и ключ. И мы собираемся объединить эту функцию с временной меткой, довольно «крупнозернистой», величиной в несколько минут. Здесь имеется разделение между этими двумя частями заголовка – функцией и штампом времени, которому не нужно много битов. Я забыл, как именно этот протокол работает на реальном компьютере, но можно представить, что временная метка занимает 8 бит, а остальная часть формулы порядкового номера – 24 бита.

Итак, почему это хороший план? Что здесь вообще происходит? Зачем нужна эта странная формула? Вы должны помнить, что мы пытались получить от порядковых номеров. Здесь происходит две вещи.

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

Оказывается, что люди не могли найти лучше способ защититься от атак типа SYN Flooding, кроме как использовать этот план действий, который хорошо работает в некоторых ситуациях. Это был один план, а вот другой план – функция с временной меткой, где мы отказались от этого компонента старого стиля. Вместо этого мы сосредоточимся на том, чтобы убедиться, что если кто-то предоставит нам в ответ на пакет этот порядковый номер ACK (SNs), этот кто-то будет «правильным» клиентом.

Вы помните, что для предотвращения атак IP-спуфинга мы как бы полагаемся именно на это значение (SNs). Ведь если сервер посылает клиенту на втором шаге это значение SNs, мы ожидаем, что только этот клиент сможет послать нам назад исправленное значение SNs на третьем шаге, завершая установку соединения.

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

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

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

Студент: значит, SNc сохраняются только ограниченное время?

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

Таким образом, сервер может восстановить значение SNc, потому что клиент собирается включить его в этот пакет в любом случае. Раньше это не имело значения, но сейчас это как бы актуально. Мы не собираемся здесь ничего проверять, но существование такого поля само по себе хорошая вещь. Однако она имеет некоторые печальные последствия. Например, если используются некоторые сложные вещи, которыми здесь можно злоупотребить. Но это не так плохо, как переполнение памяти сервера клиентскими запросами.

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

Студент: нужно ли хранить временную метку?

Профессор: да, здесь имеется умная вещь! Когда мы на третьем шаге получаем значение порядкового номера SNs, нам нужно выяснить, как вычислить входные данные для этой функции F, чтобы проверить, что это значение правильно. Поэтому мы берем метку времени, расположенную в конце пакета, и используем её для вычисления внутри функции. Все остальное мы можем восстановить. Мы знаем, кто только что прислал нам третий шаг и пакет, у нас есть все эти поля и наш ключ, который, опять же, все еще является секретным, и метка времени из последних 8 бит последовательности. При этом может случиться так, что мы исключим слишком старые метки времени, просто запретив старые соединения.

Студент: я полагаю, что вы используете это, когда на вас нападают, только потому, что вы теряете 8 битов безопасности, или по какой-то другой причине?

Профессор: да, это не очень хорошо, оно имеет много плохих свойств. В некотором смысле, мы действительно теряем 8 бит безопасности. Потому что теперь неоспоримая часть — это всего 24 бита вместо 32.

Другая проблема состоит в том, что произойдёт, если вы потеряете определенные пакеты? В TCP принято считать, что если третий пакет потерян, то клиент, возможно, ничего не ждет. Или, извините, возможно, протокол, который мы запускаем поверх этого TCP-подключения — это протокол, который предполагает, что сервер изначально предполагает что-то сказать, так что я соединяюсь с ним и просто слушаю ответ. А в SMTP, например, сервер должен по протоколу мне послать что-то вроде приветствия. Предположим, что я подключаюсь к SMTP-серверу, отправляю третий пакет, считаю, что я всё сделал и просто жду, когда сервер мне ответит, например:

«Привет, это SMTP-сервер, пожалуйста, пришлите мне своё письмо»!

Так вот, этот третий пакет может потеряться. В реальном TCP сервер помнит, что на втором шаге он ответил клиенту, но так и не получил от него ответный третий пакет. Поэтому сервер пошлёт клиенту ещё раз второй пакет для перезапуска третьего пакета. Конечно, если сервер не хранит никакого состояния, он понятия не имеет, что отправлять. Это делает установку соединения несколько проблемным, потому что обе стороны будут ждать друг от друга ответного шага. Сервер даже не знает, что клиент ждёт от него ответ, а клиент ждёт ответ сервера, хотя тот не собирается отвечать, потому что не хранит состояние. Поэтому это еще одна причина, почему вы не используете продуктивный режим сервера постоянно.

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

Профессор: да, безусловно. Другое дело, что мы отказались от использования этого старого стиля порядкового номера ISN, что повысило независимость этих множественных соединений за короткий срок друг от друга. Я думаю, что здесь существует ряд компромиссов, мы просто поговорили о трёх из них, так что есть еще несколько причин для беспокойства.

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

Студент: должны быть SNs на втором и третьем шаге одинаковы?

Профессор: конечно, потому что иначе сервер не сможет сделать вывод, что этот клиент получил наш пакет. Если сервер не проверил, что этот SNs имеет то же значение, что и прежде, то может быть ещё хуже — ведь я мог бы подделать соединение с произвольного IP-адреса на первом шаге, а затем получить этот ответ на втором шаге. Или я бы даже не получил этот ответ, потому что он направлен на другой IP-адрес. Затем на третьем шаге я устанавливаю соединение ещё с какого-то другого IP-адреса. При этом сервер поддерживал бы установленное соединение, ждал бы, пока я отправлю данные, и так далее.

Студент: но ведь временная метка будет другой, верно? Как же сервер может пересчитать это с помощью новой временной метки, если он не хранит состояние?

Профессор: как я уже говорил, эти временные метки достаточно «крупнозернисты» и проградуированы в минутах. Если вы подключитесь в ту же минуту, то всё в порядке, если подключаетесь на границе минуты — это слишком плохо.

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

Студент: если злоумышленник контролирует большое количество IP-адресов и делает то, что вы сказали, даже если вы переключаетесь…

Профессор: да, на самом деле вы мало что можете сделать. Причина, по которой нас так заботила эта схема, состоит в том, что мы хотели отфильтровать или как-то различать атакующих и «хороших парней». Если злоумышленник имеет больше IP-адресов и просто контролирует больше машин, чем хорошие парни, тогда он может соединиться с нашим сервером, запросить множество веб-страниц или поддерживать связь.

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

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

Хочу упомянуть ещё одну интересную вещь – отказ сервиса DoS плох сам по себе, но ещё хуже, когда проведению такой атаки способствуют сами протоколы. Злоумышленник знает об этом и в первую очередь атакует системы именно с такими протоколами, как DNS. Протокол DNS включает в себя отправку клиентом запроса на сервер, а сервер отправляет ответ обратно клиенту. И во многих случаях объём ответа в байтах намного превышает объём запроса.

Вы спрашивали насчёт сервера mit.edu. Так вот, ответом на ваш запрос могут стать все записи, которые есть на сервере mit.edu — адрес электронной почты, почтовый сервер для mit.edu, назначенная запись, если она использует DNS SEC, и так далее.

Так что запрос может быть 100 байт, а ответ — более 1000 байт. Предположим, что вы хотите «зафлудить» какого-то парня большим количеством пакетов или использовать всю пропускную способность его канала связи. Вы можете использовать лишь немного своей пропускной способности, но зато можете организовать поддельные запросы к DNS-серверу от имени этого парня. Вам нужно отправить всего лишь 100 байт на какой-то DNS-сервер, сделав вид, что запрос исходит от этого бедняги, и в ответ сервер отправит ему 1000 байт от вашего имени.

Это проблемная особенность данного протокола, так как она позволяет увеличить пропускную способность атаки. И частично по той же причине, которую мы упоминали в случае с TCP SYN Flooding, DNS-серверу в этом случае очень трудно определить, является ли этот запрос действительным или нет. Потому что при продолжении обмена данными нет аутентификации или порядкового номера, говорящего, что соединение установлено с «правильным парнем».

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

Студент: если вы сможете увидеть запрос злоумышленника на DNS-сервере и не отвечать на него…

Профессор: да, существует определённая возможность модифицировать DNS-сервер таким образом, чтобы он хранил какое-то состояние.

Студент: так почему же данная схема используется до сих пор, если она не предусматривает сохранение состояния?

Профессор: я думаю, что сейчас некоторые люди начинают модифицировать DNS-сервер, чтобы попытаться сохранить состояние. Однако существует так много DNS-серверов, что это не имеет значения. Даже если вы делаете по 10 запросов к каждому DNS-серверу, каждый пакет усиливается некоторыми существенными факторами, и сервер должен на них отреагировать, потому что, возможно, эти запросы исходят от законного клиента. Так что это проблема. Да, вы правы, если бы это был один DNS-сервер, то его модификация не представляла бы такого труда.

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

Я думаю, что общий принцип, которому вы хотите следовать в любом протоколе, и это может быть хорошим принципом – это заставить клиента делать, по крайней мере, столько же работы, сколько делает сервер. Но проблема в том, что клиент не может делать столько же, сколько делает сервер. Поэтому сервер должен ему в этом помочь.

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

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

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

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

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

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

Проблема состоит в том, что пакет запроса DHCP просто вещает в локальной сети о попытке связаться с DHCP-сервером, потому что вы на самом деле заранее не знаете, что собирается делать DHCP-сервер. Вы просто подключаетесь к сети в первый раз и посылаете запрос, и ваш клиентский компьютер не знает, что делать и кому доверять. Следовательно, любая машина в локальной сети может перехватывать эти запросы DHCP и отвечать клиенту с любого IP-адреса, говоря: «эй, вы должны использовать мой DNS-сервер вместо реального»! Это даёт злоумышленнику возможность перехватить будущие запросы DNS от клиента и так далее.

Поэтому я думаю, что эти протоколы довольно сложно исправить. В глобальном масштабе такие протоколы, как BGP, позволяют любому участнику сети объявлять определенный префикс IP-адреса, чтобы отсортировать и маршрутизировать пакеты для злоумышленника. При этом случались атаки, в которых маршрутизатор, участвующий в BGP, говорил: «о, я знаю очень быстрый способ достичь этого конкретного IP-адреса!», и тогда все остальные маршрутизаторы отвечали ему: „ОК, конечно, мы отправим вам эти пакеты“.

Наверное, чаще всего этим злоупотребляют спамеры, которые хотят рассылать свой спам, но их старые IP-адреса везде занесены в черный список. Поэтому они просто выбирают случайный IP-адрес и объявляют, что да, их IP-адрес теперь расположен здесь. Затем они как бы объявляют этот IP-адрес в сети, отправляют с него спам и отключаются. Сейчас таких случаев становится все меньше, но полностью искоренить подобное трудно. Потому что для того, чтобы это исправить, вы должны знать, кто действительно владеет этим IP-адресом. Без этого трудно обойтись при создании глобальной базы данных криптографических ключей для каждого провайдера в мире, однако люди прилагают немало усилий, чтобы создать эту базу.

То же самое относится и к DNS SEC. Для того, чтобы знать, какую подпись искать в DNS, у вас должен быть криптографический ключ, связанный со всеми сетевыми сущностями в мире. На сегодня это невозможно, но к этому нужно стремиться, потому что, безусловно, это самая большая проблема для широкого распространения DNS SEC.

Итак, я полагаю, что из этой статьи следует выбрать информацию, чего вообще не следует делать в протоколах. Я хочу заострить ваше внимание на одной важной вещи: пока безопасность и целостность являются важными свойствами и движущей силой более высоких уровней абстракции, таких как криптографические протоколы в приложениях, которые мы рассмотрим в следующей лекции, основными требованиями, предъявляемыми к сети, должны стать доступность и сопротивляемость DoS — атакам. Потому что эти свойства гораздо труднее достигнуть в стеке на более высоких уровнях.

Таким образом, вы должны стремиться к тому, чтобы избежать таких вещей, как, атаки SYN Flooding и RST атаки, позволяющие разорвать соединение произвольного пользователя сети. Это вещи, которые действительно вредны на низком уровне и которые трудно исправить на высоком уровне. Но более–менее обеспечить целостность и конфиденциальность данных можно с помощью шифрования. О том, как это сделать, мы поговорим в следующей лекции о «Цербере».

Полная версия курса доступна здесь.

Спасибо, что остаётесь с нами. Вам нравятся наши статьи? Хотите видеть больше интересных материалов? Поддержите нас оформив заказ или порекомендовав знакомым, 30% скидка для пользователей Хабра на уникальный аналог entry-level серверов, который был придуман нами для Вас: Вся правда о VPS (KVM) E5-2650 v4 (6 Cores) 10GB DDR4 240GB SSD 1Gbps от $20 или как правильно делить сервер? (доступны варианты с RAID1 и RAID10, до 24 ядер и до 40GB DDR4).

VPS (KVM) E5-2650 v4 (6 Cores) 10GB DDR4 240GB SSD 1Gbps до декабря бесплатно при оплате на срок от полугода, заказать можно тут.

Dell R730xd в 2 раза дешевле? Только у нас 2 х Intel Dodeca-Core Xeon E5-2650v4 128GB DDR4 6x480GB SSD 1Gbps 100 ТВ от $249 в Нидерландах и США! Читайте о том Как построить инфраструктуру корп. класса c применением серверов Dell R730xd Е5-2650 v4 стоимостью 9000 евро за копейки?

Source: habr1

Метки:





Запись опубликована: 20.10.2018

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

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



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

И вот недавно, я начал поиски образовательных материалов на эту тему. Искать долго не пришлось, я открыл Youtube и очень быстро наткнулся на курс генетики от MIT, который читал замечательный профессор Eric Lander. С первых же лекций я влюбился как в этого харизматичного человека, так и в тот предмет, которому он учит. Позже я узнал, что мало кто из его студентов мог устоять перед его чарами, руководство MIT особо отмечало его заслуги как в создании выдающихся курсов, так и в его уникальной способности заражать студентов своей очевидной любовью к биологии и генетике.
Эрик Лэндер — очень заслуженный человек. Математик по своему основному образованию, который позже переквалифицировался в генетика. Член национальной академии наук США с 1997 года. Лауреат многих престижных премий. Труды в основном посвящены биоинформатике, геномике и генетике. Со второй половины 1980-х годов занимается дешифровкой генома человека и применением её результатов в медицине. Один из руководителей проекта «Геном человека». Его группа секвенсировала треть генома человека.

Однако моя радость была недолгой, очень быстро я понял, что это не курс, а какие-то обрывки. Дальше все это повторилось еще несколько раз, официальный курс на https://ocw.mit.edu/ , частью которого оказался тот курс генетики, также оказался изрезанными кусочками лекций, загруженными в случайном порядке.
Моему разочарованию не было предела, я был как перед разбитым зеркалом, которое представляет величайшую драгоценность, когда в нем можно увидеть целую картину, но в моих руках были лишь осколки, которые никак не хотели стыковаться вместе — многие из них были просто утеряны.
Потом каким-то чудом мне удалось найти этот курс целиком, с правильной нумерацией лекций, но картинка была ужасного качества. Но там, внизу, среди последних лекций были лекции како-то другого, очевидно, более нового курса. И тоже случайные куски без начала и без конца…
Однако, все, что нужно было сделать, это начать в поисковой строке Гугла набирать имя этого замечательного человека. В ответ на это всплывала подсказка: eric lander edx. И на второй строке поисковой выдачи лежит та самая “жемчужина”, которой я мечтаю с вами поделиться: Introduction to Biology — The Secret of Life

Это полный бесплатный курс со всеми необходимыми сопроводительными материалами, тестами и возможностью получить сертификат о его прохождении от MIT. Не просто информация, а настоящие знания, выложенные в открытый доступ.
Теперь, найдя, наконец, этот курс, я бесконечно счастлив, и могу наслаждаться интеллектуальным кайфом высшего качества. Профессор Лэндер рассказывает одну из самых интересных историй в мире, которая по напряженности превосходит современные сериалы типа WW, каждая новая лекция буквально взрывает голову.
Эрик Лэндер не просто знакомит своих студентов с научной фактологией, он в красках и лицах рассказывает захватывающие сюжеты из истории науки, которые приводили к великим открытиям в биологии. Учит их философии и методологии науки, интригуя, задавая вопросы, которые стояли перед учеными, заставляя студентов думать как те ученые, прививает им научный метод мышления.
Для понимания курса не требуется никаких предварительных знаний, хотя они и желательны в области биологии и химии.

Следует, конечно, сказать, что курс на английском языке. Я искренне сочувствую людям не знающим английского. Этот язык стоило бы выучить хотя бы ради того, чтобы познакомиться с этим курсом. Хотя и сам курс можно использовать как замечательный способ изучения английского языка — у Эрика Лэндера прекрасная артикуляция и очень ясное произношение. Множество вещей понятно из контекста. На самом сайте edX есть только английские и китайские субтитры, но есть способ добраться до русских субтитров.

Инструкция, как добраться до русских субтитров

Возможно, я тупой, но мне никак не удалось найти плейлист этого курса на Youtube. Если кто найдет, киньте, пожалуйста, ссылку. Однако есть способ открыть там любое видео курса “по ссылке”. В правом верхнем углу видео на сайте edX есть стрелочка “поделиться”. Нажимаем на нее, видим многоточие, нажимаем и попадаем на Youtube. Далее давим на значок шестеренки, выбираем субтитры, потом надо бы нажать “перевести”, но, по крайней мере в моем случае, эта кнопка становится активной только после того, как мы выбрали английский.
Дальше наслаждаемся машинным переводом, качество которого лично меня приятно удивило.

Конечно, есть курсы по биотехнологии и на русском языке:
МФТИ “Введение в молекулярную биологию и биомедицину”
Bioinformatics Institute “Биотехнологии: генная инженерия”
Bioinformatics Institute “Молекулярная биология и генетика”
Отзывы на платформе stepik.org о них хорошие, но лично мне не известно качество этих материалов.

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

А о такой замечательной платформе, как www.edx.org, к своему стыду и счастью, я узнал исключительно благодаря той истории, которую только что вам поведал.

Спасибо за внимание, и желаю прекрасного путешествия в мир молекулярной биологии!

Source: habr1

Метки:





Запись опубликована: 20.10.2018

[Перевод] Второй ретрокомпьютер-бейдж от Hackaday


Положительный опыт применения ретрокомпьютеров-бейджей на прошедшей в мае конференции в Белграде (новость на Хабре и на Hackaday) побудил руководство Hackaday повторить эксперимент на следующем мероприятии — Superconference, или сокращённо Supercon, которая пройдёт в ноябре в Пасадине. Новая модель гаджета ещё интереснее.

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

Как и прежде, он содержит цветной дисплей разрешением 320х240 пикселей, полную QWERTY-клавиатуру и неисчерпаемые возможности программирования. В его прошивке снова есть и Бейсик, и CP/M, но предустановленных игр теперь несколько, и появились пасхалки. А что выжмут из всего этого участники конференции за те три дня, в течение которых она будет проходить — посмотрим.

Разработчиком второй модели бейжда, как и первой, является Войя Антонич — тот самый, автор компьютера Galaksija, увидевшего свет в 1983 году. И новая разработка тоже может быть при желании повторена и вами. Выглядит устройство потрясающе, но ещё интереснее взять его в руки и набрать программу на Бейсике на клавиатуре, которая, как и у предыдущей модели, громко щёлкает. Представьте себе это число: 30000 кнопок. Столько их потребовалось, чтобы изготовить компьютеры для всех участников.

Как он устроен и что с ним можно сделать?

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

Самое интересное происходит на обратной стороне платы. Обработкой данных занимается микроконтроллер PIC32MX370, а микросхема SST26VF016BT добавляет 16 мегабайт (не гигабайт!) флеш-памяти. И то и другое подарено компанией Microchip.

Там же расположены усилитель и динамическая головка. Программировать трёхголосные мелодии можно на Бейсике и Си.

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

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

На предыдущей конференции к гребёнке чего только не подключали. Ещё до обеда на экране одного из бейджей можно было дистанционно порисовать со смартфона, сопряжённого с ним по WiFi. Другие компьютеры были «обучены» обмену данными по радиоканалу непосредственно между собой (вспоминаем Cybiko?).

Лезем в прошивку

Прошивка написана Яромиром Сукобой, и работа над ней продолжается на GitHub прямо сейчас. Он начал с готового токенайзера, доработал его, а затем добавил функции по управлению динамической головкой, RGB-светодиодом, GPIO, дисплеем, работой с ОЗУ при помощи команд PEEK и POKE, и.т.д. Как и прежде, здесь есть эмулятор Z80 и ОС CP/M, а микросхему дополнительной флеш-памяти можно использовать в качестве дискового пространства для этой ОС.

Рекомендуемые темы проектов:

  • программы на Бейсике
  • трёхголосная музыка
  • ПО для ОС CP/M
  • управление периферией по GPIO, I2C и последовательному порту

На предыдущей конференции многим понравилась двухпользовательская игра, где на экране компьютера одного из игроков корабль стрелял лазером, и луч «телепортировался» на экран компьютера другого игрока. А вы сможете сделать, например, четырёхпользовательскую версию такой игры?

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

Source: habr1

Метки:





Запись опубликована: 20.10.2018

ДНК. Механизмы хранения и обработки информации. Часть II

Привет Хабр! Сегодня мы продолжим прошлый рассказ о ДНК. В нем мы поговорили о том, сколько ее бывает, как ДНК хранится и почему так важно то, как она хранится. Сегодня мы начнем с исторической справки и закончим основами кодирования информации в ДНК.

История

Сама по себе ДНК была выделена еще в 1869 году Иоганном Фридрихом Мишером из лейкоцитов, которые он получал из гноя. Лейкоциты это белые клетки крови, выполняющие защитную функцию. В гное их довольно много, ведь они стремятся к поврежденным тканям, где «поедают» бактериальные клетки. Он выделил вещество, в состав которого входят азот и фосфор. Вначале оно получило название нуклеин, однако, когда у него обнаружили кислотные свойства, название изменили на нуклеиновую кислоту. Биологическая функция новооткрытого вещества была неясна, и долгое время считалась, что в нем запасается фосфор. Даже в начале XX века многие биологи считали, что ДНК не имеет никакого отношения к передаче информации, поскольку строение молекулы, как тогда казалось, было слишком однообразным и не могло закодировать столько информации.

К 1901 году Альбрехт Коссель выделил и описал пять азотистых оснований, входящих в состав ДНК и РНК. А еще чуть позже Петр Левен установил, что углеводным компонентом нуклеиновых кислот являются дезоксирибоза и рибоза. Нуклеиновые кислоты, в состав которых входит рибоза стали называть рибонуклеиновыми кислотами или, сокра­щенно, РНК, а те, которые содержали дезоксирибозу, дезоксирибонуклеиновыми кислотами, или ДНК.

Теперь, встал вопрос, как отдельные звенья соединены между собой. Для этого цепи ДНК нужно было разрушить и посмотреть на то, что получится после разрушения. Для этого полимер ДНК подвергался гидролизу. Однако Левен изменил метод гидролиз. Теперь вместо многочасового кипячения в закисленной среде он использовал ферменты. На этот раз из гидролизатов удалось выделить не только отдельные аденин, гуанин, тимин, цитозин, дезоксирибозу и фосфорную кислоту, но и более крупные фраг­менты, например соединения азотистых оснований с углеводом или углевода с фосфорной кислотой. Вместе с тем в гидролизатах нуклеиновых кислот не были обнаружены соедине­ния, состоящие из двух азотистых оснований, или соединения типа основание – фосфорная кислота. То есть стало понятно, что фосфорная кислота соединяется с сахаром, а он в свою очередь, с азотистым основанием. Соединения азотистых ос­нований с углеводом было предложено называть нуклеозидами, а фос­форные эфиры нуклеозидов назвали нуклеотидами.

В результате этих работ Левен пришел к выводу, что нуклеиновые кислоты являются полимерами. В качестве мономеров служат нуклео­тиды. Содержание каждого из четырех нуклеотидов в ДНК, или РНК, по данным химического анализа того времени, представлялось Левену равным. Поэтому Левен предложил следую­щую теорию строения нуклеиновых кислот: они являются поли­мерами, мономерами которых служат блоки из четырех нуклео­тидов, соединенных последовательно.
Теория тетрануклеотидного строения в то время выглядела вполне обоснованно, войдя во все учебники довоенного времени. Однако вопрос функции ДНК оставался неясным. Чтобы прояснить этот вопрос понадобилось почти полвека.

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

В то время научное сообщество всерьез полагало, что за хранение генетической информации ответственны именно белки. Традиционное представление о первичной роли белков в жизненном процессе не позволяло и думать о том, что столь важное ве­щество, как вещество наследственности, могло быть чем-либо, кроме белка. Белки были крайне разнообразны по своей структуре, чего тогда не могли сказать о нуклеиновых кислотах. Известный советский генетик-цитолог Н. К. Кольцов подсчитал, что, варьируя последовательность 20 аминокислот, входящих в состав белковой молекулы, можно создать триллионы непохожих друг на друга белков.

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

Действительно много… 20 в 20й… А ведь последовательности бывают куда длиннее чем 20 аминокислот.

А вот как пишет по этому поводу А. Р. Кизель – один из наиболее эрудированных биохимиков того времени.

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

Первый успех пришел из микробиологии. В 1944 г. были опубликованы результаты опытов Эвери и сотрудников (США) по трансформации бактерий. Пару слов о трансформации.

Сама трансформация была открыта в 1928 году микробиологом Гриффитсом.

Гриффит работал с культурами пневмококка (Streptococcus pneumoniae) возбудителя одной из форм пневмонии. Некоторые штаммы этой бактерии являются вирулентными, вызывая воспаление легких. Их клетки покрыты полисахаридной капсулой, защищающей бактерию от действия иммунной системы. В культуре такие бактерии образуют крупные гладкие колонии правильной сферической формы. Благодаря этому, они получили название S–штаммы (от английского smooth – гладкий).

Существуют различные вирулентные штаммы пневмококка, они отличаются по антителам, которые вырабатываются в организме при попадании в него бактерий. Их называют IS, IIS, IIIS и т. д. Время от времени некоторые клетки вирулентных штаммов S мутируют, утрачивая способность синтезировать полисахаридную оболочку, и становятся авирулентными. В культуре они образуют мелкие шероховатые колонии неправильной формы, из-за этого получили название R–штаммов (от английского rough – шероховатый). Иногда происходят обратные мутации, восстанавливающие способность к синтезу полисахаридной оболочки, но только в группах соответствующих штаммов:

IIS — IIR
IIIS — IIIR

Это говорит о том, что авирулентные R–штаммы всегда соответствуют родительскому вирулентному S–штамму.

Гриффит вводил разным группам лабораторных мышей вирулентный и авирулентный штамм пневмококка. В первой контрольной группе инъекция вирулентного штамма IIIS приводила к гибели животных. Животные второй контрольной группы после инъекции авирулентного штамма IIR оставались живы. После этого Гриффит нагревал раствор с культурой вирулентого штамма IIIS при температуре 60 °С, что привело к гибели бактерий. Убитые нагреванием бактерии он ввел третьей группе подопытных мышей. Животные остались живы, что в принципе и ожидалось. Однако это не все. Он ввел части выживших мышей бактерии авирулентного штамма IIR.

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

Тот факт, что вызывающие гибель мышей клетки синтезировали полисахаридную оболочку типа III, а не II, свидетельствовал о том, что они не могли возникнуть в результате обратной мутации IIR — IIS. Из этого Гриффит сделал очень важный вывод. Авирулентные бактерии штамма IIR могут трансформироваться в вирулентные как-то взаимодействуя с убитыми нагреванием бактериями штамма IIIS, которые еще оставались в теле мышей. Другими словами, авирулентные бактерии штамма IIR получают от мертвых бактерий штамма IIIS некий фактор, превращающий их в вирулентные. Однако, что это за фактор, Гриффит не знал.

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

Теперь вернемся к опытам Эвери. Схема их экспериментов несколько схожа с экспериментами Гриффитса. Эвери и сотрудники поставили перед собой задачу выяснить химическую природу трансформирующего агента. Они разру­шали суспензию пневмококков и удаляли из экстракта белки, капсульный полисахарид и РНК, однако трансформирующая активность экстракта сохранялась. Трансформирующая активность препарата не терялась при его обработке кристаллическим трипсином или химотрипсином (разрушающими белки), рибонуклеазой (разрушает РНК). Было ясно, что препарат не являлся ни белком, ни РНК. Однако трансформирующая активность препарата полностью утрачивалась при обработке его дезоксирибонуклеазой (разрушающей ДНК), причем ничтожные количества фермента вызывали полную инактивацию препарата. Таким образом, было установлено, что трансформирующий фактор у бактерий является чис­той ДНК. Этот вывод явился значительным открытием, и Эвери отлично сознавал это. Он писал, что это как раз то, о чем дав­но мечтали генетики, а именно вещество гена. Кажется вот оно доказательство. Но уж слишком сильна была вера в белок, как вещество наследственности. Некоторые считали, что трансформацию могут вызывать и те ничтожные примеси белка, которые оставались в препарате.

Новым доказательством прямой генетической роли ДНК явились опыты вирусологов Херши и Чейз. Они работали с бактериофагом Т2 (Бактериофаги — вирусы бактерий), который заражает бактерию Escherichia coli (кишечную палочку).

Собственно что они сделали. В состав ДНК одних бактериофагов они включили радиоактивный фосфор (P32), а в состав белков других — изотоп серы (S35). Для этого одни бактерии выращивались на среде с добавлением радиоактивного фосфора в составе фосфат иона, другие — на среде с добавлением радиоактивной серы в составе сульфат иона. Затем к этим бактериям добавлялся бактериофаг Т2, который, размножаясь в клетках бактерий, включал радиоактивную метку в свою ДНК (P есть в ДНК, но нет в белках), или белки (S есть в белках, но нет в ДНК).

После выделения радиоактивно-меченых бактериофагов их добавляли к культуре свежих (не содержащих изотопов) бактерий. Что приводило к инфицированию этих бактерий. Бактериофаг присоединяется к клетке бактерии и «впрыскивает» свою ДНК. После этого среду с бактериями подвергали энергичному встряхиванию в специальном смесителе (было показано, что при этом оболочки фага отделяются от поверхности бактериальных клеток), а затем инфицированных бактерий отделяли от среды. Когда в первом опыте к бактериям добавлялись меченые фосфором-32 бактериофаги, оказалось, что радиоактивная метка находилась в бактериальных клетках. Когда же во втором опыте к бактериям добавлялись бактериофаги, меченые серой-35, то метка была обнаружена во фракции среды с белковыми оболочками, но её не было в бактериальных клетках. Это подтвердило, что материалом, которым инфицировались бактерии, является ДНК. Поскольку внутри инфицированных бактерий формируются полные вирусные частицы, содержащие белки вируса, данный опыт стал одним из решающих доказательств того факта, что генетическая информация (информация о структуре белков) содержится в ДНК.

Эти открытия сильно повлияли на многих биологов того времени. В особенности на знаменитого своими правилами Чаргаффа. Он считал, что Эвери по сути открыл ‘новый язык’, или как минимум показал, где его искать.

Чаргафф при­нялся искать разницу в нуклеотидном составе и расположении нуклеотидов в препаратах ДНК, полученных из различных источников. И, поскольку методов позволяющих точно дать химическую характеристику ДНК, в то время не существовало… ему пришлось их придумать. Им было показано, что старая тетрануклеотидная теория строения нуклеиновых кислот неверна. ДНК у разных организмов по составу и строению сильно отличаются. При этом обнаружились новые факты, не установленные ранее для других природных полимеров, а именно регулярности в соотношении отдельных ос­нований в составе всех исследованных ДНК. Сейчас даже школьники знают их, как правила Чаргаффа.

  1. Количество аденина равно количеству тимина, а гуанина — цитозину: А=Т, Г=Ц.
  2. Количество пуринов равно количеству пиримидинов: А+Г=Т+Ц.
  3. Вытекает из первого и второго. Количество оснований с аминогруппами в положении 6 равно количеству оснований с кетогруппами в положении 6: А+Ц=Т+Г.

Механизм мы затрагивали в прошлой статье, поэтому тут я останавливаться на нем не буду.

Потихоньку мы подошли к двум легендарным людям, открывшим структуру ДНК. Фрэнсис Крик и Джеймс Уотсон встретились впервые в 1951 году. Уотсон тогда решил заняться структурой ДНК. Как биолог, он понимал, что при выборе определенной структуры ДНК нужно учитывать существование какого-то простого принципа удвоения молеку­лы ДНК, заложенного в ее структуре. Ведь одним из важнейших свойств генов является передача наследственной информации.
Криком же была создана теория дифракции рентгеновских лучей на спи­ралях, позволяющая опреде­лить, находится исследуемая структура в спиральной конформации или нет. В то вре­мя рентгенограммы ДНК уже существовали. Их получили в Лондоне Морис Уилкинс и Розалинд Фрэнклин.

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

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

Рассматривая возможные комбинации пар азоти­стых оснований, Уотсон обнаружил, что пары аденин–тимин и гуанин–цитозин имеют одинаковый размер и ста­билизируются водородными связями. Сразу же объяснялись и правила Чаргаффа: если в биспирали ДНК аденин одной цепи всегда соединяется с тимином другой цепи, а гуанин всегда входит в паре с цитозином, то аденина в составе ДНК должно быть всегда столько же, сколько тимина, а гуанина – столько же, сколько цитозина. Ясно было также, как должно происходить удвоение молекулы ДНК. Каждая цепь комплементарна другой, и в процессе репликации ДНК цепи биспирали должны разойтись и на каж­дой полинуклеотидной цепи должна достроиться комплемен­тарная к ней цепь. Тут тоже было несколько теорий, но о них через неделю, в следующей статье.

Кодирование информации

Итак, мы знаем, что ДНК — носитель информации, знаем из чего она состоит. Но как кодирует информацию — все еще не понятно.

Пойдем от задачи. ДНК кодирует 20 аминокислот (можно сказать, что 21, но селеноцистенин пока не трогаем). Нуклеотидов имеется 4 варианта. То есть один нуклеотид может кодировать 4 варианта, 2 — 16, 3 -64. Логично предположить, что код — триплетен (то есть три основания кодируют одну аминокислоту). Про экспериментальное подтверждение можете почитать здесь. Боюсь, что тут и без того много истории…

Собственно у нас есть 64 варианта и 20 аминокислот. Аминокислоты могут кодироваться разными кодонами. Так же существуют старт и стоп кодоны, с которых начинается считывание.
Не забываем, что сначала ДНК считывается в РНК, с которой уже происходит считывание в белок.
Таблица внизу — соответствие кодонов РНК аминокислотам. Помним, что в РНК нет тимина, вместо него идет урацил.

Если вы не нашли в таблице старт кодон — поищите AUG. Он кодирует метионин и одновременно является стартовым. При трансляции генов прокариот, пластидных и митохондриальных генов стартовой аминокислотой является N-формилметионин (это просто для справки)).

Если расписать весь путь от ДНК до белка, получим что-то такое.

На данном рисунке синтез идет с красной цепи. Как следствие РНК будет совпадать с синей цепью (не забываем про замену Т на У)

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

Тут мы немного затронем мутации. Они бывают разных типов. От хромосомных, когда целые куски хромосом удаляются из генома, меняются местами, дублируются, до точечных, когда происходит замена одного азотистого основания на другое. Сфокусируемся на точечных мутациях.

К чему могут привести точечные мутации?

Кодон может начать кодировать другую аминокислоту, что не всегда страшно. Такие мутации называются миссенс-мутацими (то есть со сменой смысла). Это может повлиять на структуру белка. Например если положительно заряженная аминокислота заменится на отрицательно заряженную — это может сделать белок нестабильным, или приведет к тому, что он свернется в другую конформацию (да, линейная последовательность аминокислот обычно сворачивается в определенную форму) и не сможет выполнять свои функции (или начнет делать это лучше, это уже попахивает эволюцией).

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

В молекуле гемоглобина Хикари аспарагин замещен на лизин, однако он все также хорошо перенести кислород.

Как пример с потерей функции рассмотрим гемоглобин M. Другая точечная мутация в гене гемоглобина приводит к полной утрате функции (гистидин меняется на тирозин в активном центре).

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

Что еще может произойти?

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

Есть еще третий тип мутации — сайленс-мутация. По сути происходит смена кодона на другой, кодирующий ту же аминокислоту. Свойства белка не меняются.

Подитожим общей схемой.

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

Сравним человека и… кишечную палочку (Escherichia coli) по частоте использования кодонов кодирующих цистеин.

Он кодируется двумя кодонами UGU и UGC.

Человек
UGU 10.6
UGC 12.6

Кишечная палочка (штамм O127:H6)
UGU 19.1
UGC 0.0

Цифры это встречаемость триплета на тысячу. Видно, что мы используем оба кодона примерно с одинаковой частотой, в то время как E. coli почти не использует UGC кодон.

Об этой особенности нужно помнить, особенно когда ты занимаешься геноинженерией и хочешь нарабатывать продукт гена одного организма в другом. Если ген человека, с частой встречаемость UGC кодона попытаться вставить в кишечную палочку данного штамма — вас ждет разочарование. В клетке аминокислоты связаны с транспортными РНК, каждая из которых соответствует своему кодону. Так вот тРНК соответствующих UGC кодону будет крайне мало, что сильно замедлит синтез.

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

Кодонный состав может сильно отличаться как у организмов разных видов, так и разных штаммов. Так у Escherichia coli O157:H7 EDL933 все более менее поровну в плане UGC и UGU. Или вот еще пример. У штаммов туберкулезной палочки выделенных в разных странах также отличается кодовый состав.

Подытожу

В этот раз было очень много истории и относительно мало биологии. Больше такого не будет. Мы поговорили о том, как стало понятно, что ДНК — носитель информации, как она хранится в самой ДНК. Поговорили об избыточности ген кода и о том, к чему это приводит. Немного затронули мутации и разницу в частоте использования определенных кодонов.

В следующий раз поговорим о репликации ДНК.

P.S.: там тоже будет история, но куда меньше. Постараюсь больше не делать таких пауз в написании.

Метки:

Похожие публикации

Source: habr1

Метки: