среда, 29 сентября 2010 г.

Производительность языка Google Go

В последнее время на хабре проскальзывало несколько постов посвященных языку программирования Go, но все они по большей части носили достаточно поверхностный и ознакомительных характер. Это натолкнуло меня на мысль провести более глубокое тестировани этого языка. Для начала пару слов почему меня заинтересовал именно этот язык, а не Python, Ruby, Java и тд. Основным языком разработки последние 4 годя для меня является PHP, и поэтому я давно чуствовал потребность в изучении языка который удовлетворял бы следующим критериям:
  1. Быстрота. Уточню - не на 15-25% быстрее чем в PHP/Perl/Ruby (в хорошую погоду / с попутным ветром / в цикле вычисляющем число с тремя единичками/<добавьте свое условие>), а реально быстрее - в разы, а еще лучше на порядок быстрее чем популярные интерпретируемые языки.
  2. Простота написания. Да писать на C/C++ это круто, это для настоящих суровых программеров(а еще лучше взять и отдельные куски кода на asm переписать, чтобы "еще быстрее" стало), но этот путь не для меня.
  3. Удобство написания демонов. Конечно на их Perl/PHP тоже пишут.. но я я думаю все согласяться что по надежности и стабильности работы они никогда не сравняться с аналогами написанными на C/C++.
На мой взгляд Go идеально подходит под эти критерии - хотя я уверен у каждого из читателей будет свое мнение на эту тему. Python/Perl/<....> тоже идеально подходят для этого, но этот пост не о них. Так как язык Go привлек меня в первую очередь с точки зрения написания сетевых демонов, то и тестировать его я буду на сетевых задачах. В качестве тестовой задачи я выбрал написание echo демона работающего по websockets протоколу.
Другой важной особенностью языка Go о которой обычно забывают упоминуть - это реализация в нем легковесных процессов(как например в Erlang или OCaml). В теории это должно резко повысить масштабируемость сетевых приложений написанных на Go, но хотелось бы узнать как дело обстоит на самом деле.

И так приступим непосредственно к тестам. На удивление написание сервера не заняло много времни:

//echod.go
package echod
import (
"http"
"io"
"websocket"
)

//Обработчик соединения
func EchoServer(ws *websocket.Conn) {
io.Copy(ws, ws)
}

func main() {
http.Handle("/echo", websocket.Handler(EchoServer))
err := http.ListenAndServe(":12345", nil)
if (err != nil) {
panic("ListenAndServe: " + err.String())
}
}

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

//echoclient.go
package echoclient;

import (
"websocket"
"log"
)

func echo() {
ws, err := websocket.Dial("ws://localhost:12345/echo", "", "http://localhost/")
defer ws.Close()

if err != nil {
panic("Dial: " + err.String())
}
pingMsg := "Hello, echod!\n"
if _, err := ws.Write([]byte(pingMsg)); err != nil {
panic("Write: " + err.String())
}
var receivedMsg = make([]byte, len(pingMsg) + 1);
if n, err := ws.Read(receivedMsg); err != nil {
panic("Read: " + err.String())
} else {
receivedMsg = receivedMsg[0:n]
}
if receivedStr := string(receivedMsg); pingMsg != receivedStr {
log.Stdoutf("Strings not equal !%s!,!%s!, %i, %i ", pingMsg, receivedStr, len(receivedStr), len(pingMsg))
}
}

func main() {
echo()
}

Как вы можете убедиться написание websocket клиента заняло еще меньше времени. Но запускать каждый тесты вручную и замерять время нехочтся, поэтому я использовал для этих целей встроенный в язык Go механизм юнит тестировния и профилирования. Для этого достаточно создать файл echoclient_test.go и написать в нем функции вида:
func TestEcho(t *testing.T) {} - для выполнения юнит тестирования и
func BenchmarkEcho(b *testing.B) {} - для выполнения профилирования соответсвенно.
Ниже исходный код функции которую я использовал для профилирования:

package echoclient;

import (
"testing"
)
//Функция используемая для запуска echo клиента в отдельном процессе
func echoRoutine(c chan int, index int) {
//Обработка ошибок, об этом подробнее ниже по тексту
defer func() {
//проверяем была ли какая-нибуть ошибка
if err := recover(); err != nil {
print("Routine failed:", err, "\n")
c <- -index } else { c <- index print("Exit go routine\n") } }() echo() } // Непосредственно сам бенчмарк func BenchmarkCSP(b *testing.B) { //b.N = 2000; - если нужно подсказываем профилировщику сколько раз мы хотим прогнать тест // канал используемый для синхронизации потоков c := make(chan int) for i:= 0; i < b.N; i++ { // запускаем каждый клиент в отдельной goroutine go echoRoutine(c, i) } print("Fork all routines \n") var ( success, failed int ) for i:= 0; i < b.N; i++ { //ждем когда поток вернет результат выполнения // если он отрицательный тест провален, если положительный соответсвенно выполнен index := <- c if index < 0 { failed++ print(i, ". Goroutine failed:", -index, "\n") } else { success++ print(i, ". Goroutine:", index, "\n") } } print("Totals, success:", success," failed: ", failed, " \n") }

Теперь для того чтобы прогнать тесты нам достаточно запустить утилиту gotest и усказать ей регулярные выражения для выбора запускаемых тестов и бенчмарков. Несколько слов о том что же делает данный код - он одновременно запускает заданное количество легковесных потоков (goroutines), каждый из которых пингует наш echo сервер.
Остановлюсь немного подробнее на обработке ошибок. В Go она построена на основе 3-х встроенных функций - defer, recover и panic. Это аналог конструкции try ... catch в других языках программирования, который позволяет поймать и обработать абсолютно любую ошибку. Ключевое defer говорит компилятору о том что данную функцию необходимо выполнить непосредственно при выходе из текущей функции, причем независимо от того каким образом завершилось ее выполнение - в результате какой-либо ошибки(panic) или обычным образом. Если исполнение функции завершилось в результате ошибки то мы можем восстановить нормальное выполнение программы путем вызова функции recover.
Результаты тестов
image
В первой колонке находиться количество одновременных соединений, вторая колонка - среднее время выполнения одного пинга в наносекундах, последующие - соответсвенно количество успешных и проваленных попыток. Ниже небольшой график зависимости среднего времени затрачиваемого на одно соединение от количества одновременных соединений:
image
А также зависимость количества успешных/провальных попыток от количества одновременных соединений:
image
Немного об условиях проведения тестов:
И клиент и сервер запускались на одной и тойже машине, с весьма скромными характеристиками -
Intel® Pentium® Processor T2390 (1M Cache, 1.86 GHz, 533 MHz FSB), 2GB RAM.
Выводы
Язык показал довольно высокую производительность в сетевых приложениях, но он еще недостаточно стабилен. В ходе проведения тестов обнаружилось что при нагрузке выше 1500 одновременных соединений сам сервер начал регулярно падать. Возможно дело в том что я исползовал 32 битный компилятор, в то время как основной разработчики считают именно 64 битную версию. Хочется верить что к моменту выхода протокола websockets в массы разработчики смогут довести язык Go до стабильности, достаточной для использования его в качестве основного языка для написания высоконагруженных websocket демонов.

http://smotri.com/video/view/?id=v6507567740

пятница, 17 сентября 2010 г.

Отношение к России и русским

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

Автомобили

Вообще что меня в финляндии удивило - большое количество очень старых(старше 10 лет) машин. И этому есть свои причины.. и главная из них драконовские налоги. Если к примеру ты решишь купить новую машину к примеру стоимостью 20 тысяч евро, то тебе придется заплатить еще около 10 тысяч евро налогов. Это просто ахтунг. Отсюда мораль - боготворите свои 13% налога... 13% это круто.
Хотя есть у них и свои прелести - кредиты очень дешевые.. всего 2-3% годовых..
Однаждый в центре Оулу я нашел заблудшее дитя советского автопрома:


Ну и в нагрузку кран:














он к советскому автопрому отношения не имеет, но он мне просто понравился.. потому что он здоровый =)

Мобильная связь

Сегодня пытался сменить свою pre-paid симку на post-paid, чтобы можно было по человечески интернет использовать. На pre-paid тарифе он стоит 1.5 евро за мегабит, на post-paid - 3 евро за месяц безлимитного интернета на скорости 385кб/с(это минимальная скорость).   Пытался сначала получить такую симку в Saunalahtie - они сначала сказали все нормально.. дали договор..  симку..  прихожу домой пытаюсь вставить симку - херушки.. непашет.. на следующий день спрашиваю - в чем дело.. почему симка неактивирована .. они - вы знаете.. так как вы проживаете в финляндии меньше 2-х лет мы не можем вам просто так оформить контракт.. вам необходимо внести предоплату в размере 300 евро - и это при абонентской плате в 5.95 евро в месяц!!! Это все равно что заплатить за 5 лет вперед.. Хрен с вами.. пошли в dna... там картина прямо обратная.. они конечно тоже спросили сколько времени я живу в финляндии - но спокойно предоставили post-paid контракт - без требования всяких лишних бумажек.. единственное что им нужно social security number и паспорт. В салоне связи у них бесплатно предлагают кофе с молоком и мороженное.. последнее меня особенно шокировало.. просто пришел себе симку оформить.. а пока они там все это делают - перекусываешь кофем/мороженным на халяву. В общем пусть это будет маленькой рекламой dna. 
Сам интернет тоже просто отличный..  и это при том что я выбрал тарифный план с миниальной скоростью.

пятница, 10 сентября 2010 г.

Финские рассказы

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

Финские рассказы

Вроде бы бомж как бомж.. все как полагается... спит на скамейке... но он спит на подушке!!

четверг, 9 сентября 2010 г.

Финские рассказы

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

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

Финские рассказы

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

понедельник, 6 сентября 2010 г.

Финские рассказы

Нет я могу понять - что в Финляндии бензин по полтора евро... что продукты обычно в 2-3 раза дороже чем в России... что проезд в автобусе по 3 евро стоит.. но зачем такие  вводить такие идиотские налоги - типа налога на телевизор - я не пойму... не дешевый кстати налог... как и все в Финляндии..
одно только успокаивает что никто не контролирует собираемость этого налога - поэтому русские его никогда не платят

Финские рассказы

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

пятница, 21 мая 2010 г.

Microsoft в очередной раз лажанулся =)

Всё просто. Текст пунктов меню имеет font-family: Segoe UI, Verdana, Arial, Sans-Serif.
Ладно, можно долго спорить на темы «хорошо или плохо использовать неправославные шрифты в вебе» и «не проверять вёрстку на случай их отсутствия — тяжкий грех»

Но запись урлов через бэкслеши — это, сука, высший пилотаж!


На экране браузера картина получается фееричная.
Источник - http://habrahabr.ru/blogs/code_wtf/94187/

В рот мне ноги

Всетаки забавный у гугла переводчик... с юморком ;-)

четверг, 29 апреля 2010 г.

Скачать коммерческие разширения для Magento от Aitoc, MageWorx ?

Нет ничего проще - http://svn2.assembla.com/svn/spm-mage/app/code/local/
куча платных разширений лежит в открытом доступе - качай сколько угодно.
Исходники не зашифрованы. Похоже какой-то умник решил использовать
Free Public Workspaces от http://www.assembla.com/plans для размещения исходников своего магазина.
Дибилизм в общем. Мало того что исходники собственного магазина опубликовал, еще и производителей модулей подвел.
ЗЫ
написал об этом производителям модулей(Aitoc, MageWorx) - как никак коллеги по цеху. Посмотрим удасться ли им убедить assembla.com закрыть этот репозиторий.


среда, 28 апреля 2010 г.

Прием платежей через кредитные карты и Paypal

Каждый человек, решившийся открыть интернет магазин, задается вопросом - как организовать прием платежей с кредитных карточек и Paypal аккаунтов с минимальной комиссией ?
Если с кредитными карточками все более-менее решаемо - практически каждый  уважающий себя платежный шлюз предлагает даную услугу, то с Paypal - совсем туго. Официально Paypal не аботает с мерчантами(продвацами) из России и стран бывшего союза. Т.е. даже если кто-то вам переведет деньги на paypal аккаунт напрямую - вывести вы их от туда не сможете. 
           Лично я для себя нашел приемлемое решение 2Checkout. Вот уже полтора года как я пользуюсь услугами этого платежного шлюза - и никаких серьзеных нареканий. Я бы даже сказал мне просто не приходиться с ними контактировать - они по тихому берут свою комиссию - 5%, я по тихому сливаю все остальное себе. В отличии от других платежных шлюзов сдесь нет скрытых  поборов. Выводить деньги от туда еще проще - заказываешь пластиковую карту MasterCard (через партнерскую программу с Payoneer.com).
              Через 2-3 недели тебе приходит конверт с пластиковой карточкой, которую нужно сначала активировать на сайте payoneer.com, а потом привязать к своему 2Checkout аккаунту. Вывод  денег с   2Checkout аккаунта на пластиковую карточку бесплатный, осуществляется примерно разв неделю - когда ваш баланс превысит установленный вами же лимит. Минимальный размер данного лимита - 20$.
            Теперь вам осталось пройти последний шаг - верификацию вашего мерчант аккаунта. Это обычно занимает 2-3 дня, не больше. Вам необходимо будет прислать сканы документа удостоверяющего личность - паспорт, водительское удостоверение, загран паспорт и заполненные бланки договоров. И что самое главное - вам совершенно не обязательно иметь официальную регистрацию - просто указываете в договоре что вы ведете бизнес как частное лицо. Эта возможность особенно актуальна для фрилансеров и мелких магазинов.  Также вам необходимо предоставить документы подтверждающие ваш адрес - квитанции об оплате за комунальные услуги или выписки из банка обычно более чем достаточно. В случае с квитанцией об оплате комунальных услуг - достаточно только совпадения фамилии, они в принципе ребята здравомыслящие - понимают что  жилье может быть оформлено на другого члена семьи.
           После того как верификация пройдена - вы можете смело начинать торговать - для этого вам понадобиться платежный модуль для вашего магазина. Для большинства бесплатных магазинов они уже давно написаны. Что касается непосредственно Magento - то модуль для приема платежей через 2Checkout  тоже давно написан.
          Последнее что я хочу отметить - это защита от чарджбеков(chargeback), или по другому - anti-fraud. У 2Checkout эта защита на высоте, жаль только что не real-time. У меня за полтора года еще  ни разу не было такого чтобы платеж прошел проверку, а потом на него пришел charge-back. Вы также имеете возможность отстаивать свои интересы при арбитраже конфликтных ситуаций в paypal. В этом случае сотрудник 2Checkout будет выступать там от вашего имени, правда услуга эта не бесплатна - участие в арбитраже стоит 15$. Но я думаю это не столь серьезная плата за возможность отстоять свои права - абсолютное большинство других платежный шлюзов в подобной ситуации просто возвращают платеж назад - да еще и вас могут оштрафовать за это. 

четверг, 22 апреля 2010 г.

Коровья суперсила APT

сегодня набрав sudo apt-get help я узнал что в APT есть коровья суперсила. Не верите ? Прочитайте внимательно последнюю строку на скриншоте консоли:

суббота, 13 февраля 2010 г.

юмор

— Ну что там у нас с сеткой?
— Вирус Кашпировский просто свирепая скотина, сначала упал игровой сервер Пентагона, потом база данных проституток…

воскресенье, 31 января 2010 г.

Америкосы тоже умеют шутить =)

Вчера ночью играл в покер на одном сайте, и один из игроков по имени Tom такую фразу зарядил:
Пара на тузах - она как Курникова, выглядит класно, но никогда не выигрывает!

суббота, 9 января 2010 г.

Написание платежных модулей

Я хочу поделиться своим, в общем-то немалым (уже более десятка модулей), опытом написания платежных модулей для Magento. Я не буду заниматься пересказом статьи из Magento wiki освещающей основы создания платежных модулей. Я просто напишу несколько совсем не очевидных, но тем не менее, весьма полезных приемов/советов которые я вывел для себя.  Они не являются обязательными, но если вы последуете им то пользователи ваших модулей скажут вам спасибо.
1. Всегда храните важные данные платежных модулей(пароли, секретные слова для формирования подписи и тд) зашифрованными:
  1. <security_code translate="label">
  2.     <label>Security code</label>
  3.     <frontend_type>text</frontend_type>
  4.     <backend_model>adminhtml/system_config_backend_encrypted</backend_model>
  5.     <sort_order>50</sort_order>
  6.     <show_in_default>1</show_in_default>
  7.     <show_in_website>1</show_in_website>
  8.     <show_in_store>1</show_in_store>
  9. </security_code>
* This source code was highlighted with Source Code Highlighter.
Расшифровывать их совсем не сложно:
  1. Mage::helper('core')->decrypt($this->getConfigData("security_code"));
* This source code was highlighted with Source Code Highlighter.
2. Не ленитесь выносить в конфиг название платежки, флаг для включения/выключения платежки и поле для сортировки платежек на странице чекаута. Это не потребует от вас много усилий, но зато сильно упростит жизнь вашим пользователям. Нужно только прописать в конфиге поля с именами "active", "title", "sort_order", остальное Magento берет на себя:
  1. <active translate="label">
  2.     <label>Enabled</label>
  3.     <frontend_type>select</frontend_type>
  4.     <source_model>adminhtml/system_config_source_yesno</source_model>
  5.     <sort_order>10</sort_order>
  6.     <show_in_default>1</show_in_default>
  7.     <show_in_website>1</show_in_website>
  8.     <show_in_store>0</show_in_store>
  9. </active>
  10. <title translate="label">
  11.     <label>Title</label>
  12.     <frontend_type>text</frontend_type>
  13.     <sort_order>60</sort_order>
  14.     <show_in_default>1</show_in_default>
  15.     <show_in_website>1</show_in_website>
  16.     <show_in_store>1</show_in_store>
  17. </title>
  18. <sort_order translate="label">
  19.     <label>Sort order</label>
  20.     <frontend_type>text</frontend_type>
  21.     <sort_order>70</sort_order>
  22.     <show_in_default>1</show_in_default>
  23.     <show_in_website>1</show_in_website>
  24.     <show_in_store>1</show_in_store>
  25. </sort_order>
* This source code was highlighted with Source Code Highlighter.
Вы можете задастся вопросом, почему эти переменные должны называться именно "active", "title", "sort_order". Ответ кроется в классе Mage_Payment_Model_Method_Abstract, от которого наследуются все модели платежных модулей.

3. Сохраняйте в ордере идентификаторы полученные от платежной системы(transaction id и тд) чтобы можно было легко соотносить ордера со статистикой предоставляемой платежной системой . Для этого нужно добавить атрибут для сущности 'order_payment':
  1. /sql/mymodule_setup/mysql4-install-1.0.0.php:
  2. $setup = new Mage_Eav_Model_Entity_Setup('core_setup');
  3.  
  4. //create attribute for order
  5. $setup->addAttribute('order_payment', 'some_transaction_number', array(
  6.      'type' => 'varchar',
  7.      'user_defined' => 0,
  8.      'input' => '',
  9.      'visible' => 1,
  10.      'label' => 'Some transaction number',
  11.      'global' => 1,
  12.      'is_configurable' => 1,
  13.      'group' => 'General',
  14.      'default' => ''
  15.      )
  16. );
* This source code was highlighted with Source Code Highlighter.
Написать в /etc/config.xml о том что мы хотим выполнить кое-какие скрипты при установке:
  1. <global>
  2.     ......
  3.     <resources>
  4.         <alertpay_setup>
  5.             <setup>
  6.                 <module>Cool_Module</module>
  7.             </setup>
  8.             <connection>
  9.                 <use>core_setup</use>
  10.             </connection>
  11.         </alertpay_setup>
  12.         <alertpay_write>
  13.             <use>core_write</use>
  14.         </alertpay_write>
  15.         <alertpay_read>
  16.             <use>core_read</use>
  17.         </alertpay_read>
  18.     </resources>
  19.     .....
  20. </global>
* This source code was highlighted with Source Code Highlighter.
И при получении подтверждения о совершении платежа сохранять эту информацию в ордер:
  1. $order->getPayment()->setData('some_transaction_number', $some_transaction_number);
  2. .....
  3. $order->save();
* This source code was highlighted with Source Code Highlighter.
4. Выносите отношения <статус платежа> ->  <статус ордера> в конфиг, если не все то по крайней мере основные:
  1. <new_order_status translate="label">
  2.     <label>New payment status</label>
  3.     <frontend_type>select</frontend_type>
  4.     <source_model>adminhtml/system_config_source_order_status</source_model>
  5.     <sort_order>80</sort_order>
  6.     <show_in_default>1</show_in_default>
  7.     <show_in_website>1</show_in_website>
  8.     <show_in_store>0</show_in_store>
  9. </new_order_status>
  10. <approved_order_status translate="label">
  11.     <label>Approved payment status</label>
  12.     <frontend_type>select</frontend_type>
  13.     <source_model>adminhtml/system_config_source_order_status</source_model>
  14.     <sort_order>90</sort_order>
  15.     <show_in_default>1</show_in_default>
  16.     <show_in_website>1</show_in_website>
  17.     <show_in_store>0</show_in_store>
  18. </approved_order_status>
* This source code was highlighted with Source Code Highlighter.
Если вам кажется что это же очевидно, новый ордер - ставим в pending, оплаченный ордер в processing - то я вас огорчу. Всегда найдется десяток индивидуумов со своим "особым" видением бизнес логики, у которых все будет ровным счетом наоборот. И они вам непременно напишут, при чем в независимости от того какой модуль - платный или нет. Поэтому лучше дать возможность пользователю самому выбрать, этим вы сбережете нервы и себе и своим клиентам.
5. Еще один достаточно спорный вопрос - это посылка email оповещения об ордере. Лично для себя я решил посылать это оповещение только при получении подтверждения оплаты:
  1. $order->sendNewOrderEmail();
  2. $order->setEmailSent(true);
  3. $order->save();
* This source code was highlighted with Source Code Highlighter.

6. Если разрабатываемый платежный метод может быть использован из админки(оформление заказа по телефону/факсу/email), то следует добавить в модель платежного метода строку:
  1. protected $_canUseInternal         = true;
  2. // И возможно эту, если платежный модуль должен использоваться только из админки:
  3. protected $_canUseCheckout         = true;
* This source code was highlighted with Source Code Highlighter.