2017-01-18 9 views
0

Я работаю в ad tech, и наша текущая инфраструктура использует MySQL для хранения кликов и журналов конверсий. До сих пор MySQL был полезен для нас, чтобы запускать специальные запросы против данных кликов. Мы рассматриваем возможность перехода на Кассандру, поскольку мы получаем огромные трафик в часы пик. Мало того, мы развиваемся очень быстрыми темпами, и мы получаем около 500-1000 кликов в секунду время от времени (в течение длительного времени, иногда в течение 20-30 минут). Я был доступным вариантом, и до сих пор мое исследование позволило мне поверить, что ничто не сравнится с Cassandra с точки зрения производительности записи. В настоящее время я создаю модель данных для хранения кликов. Основным компонентом кликам являются следующие:Cassandra для хранения журналов кликов

  1. Идентификатор кампании
  2. Pub ID
  3. Отметка
  4. Творческий идентификатор
  5. Код события (является ли он действительным щелчок или недействительный клик. Это значение int. Например, event_code = 0 является действительным кликом)

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

1. SELECT * FROM clicks WHERE campaign_id=? 
2. SELECT * FROM clicks WHERE campaign_id=? AND date_time>=? AND date_time <=? 
3. SELECT * FROM clicks WHERE campaign_id=? AND pub_id=? AND AND date_time>=? AND date_time <=? AND event_code=? 

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

CREATE TABLE clicks_by_campaign(
    camp_id int, 
    pub_id int, 
    date_time timestamp, 
    creative_id int, 
    event_code int, 
    //other fields like ip, user agent ,device etc, 
    PRIMARY KEY(camp_id,pub_id,date_time,event_code,creative_id)) 

Но существуют кампании, которые могут иметь миллионы строк , Например, у нас есть кампании с определенным id, например id = 3, которые имеют более 7 миллионов кликов. Разве это не создало бы проблему с большими рядами? Насколько я понимаю, все данные этой кампании будут храниться как один раздел на одной физической машине. Я считаю, что это правильно или я что-то упускаю? Обратите внимание, что другие запросы также должны поддерживаться. Например, мне, возможно, придется делиться журналами кликов для определенного издателя (независимо от идентификатора кампании). В этом случае запрос будет выглядеть следующим образом:

SELECT * FROM clicks_by_publisher WHERE pub_id=? 

Это, очевидно, означало бы, что я должен был бы создать еще одну таблицу под названием «clicks_by_publisher» и т.д.

Я хотел бы также отметить, что я будет использовать Apache Flink, который будет анализировать, агрегировать и группировать данные кликов в окне времени в 1 минуту. Эти результаты будут также сохранены в MySQL, чтобы обеспечить как можно большую поддержку специальных запросов.

В любом случае, я был бы признателен, если бы кто-то указал мне в правильном направлении. Есть ли другая стратегия, которую я могу использовать? Я что-то упускаю? Спасибо :)

ответ

1

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

campaign_id = PRIMARY_KEY 
event_code = CLUSTER_KEY 
date_time = CLUSTER_KEY 

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

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

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

Это приводит к spark. Spark будет обрабатывать ваш запрос на нескольких машинах и автоматически конкатенировать результаты для вас, делая то, что я описал выше, без накладных расходов на разработку.

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

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

1

Чтобы смоделировать ваши требования для быстрого чтения и распространяется право использовать под определение таблицы -

CREATE TABLE clicks_by_campaign(
camp_id int, 
createdon bigint, 
pub_id int, 
creative_id int, 
event_code int, 
//other fields like ip, user agent ,device etc, 
PRIMARY KEY((camp_id,createdon),event_code)) 

Это поможет распределить данные равномерно по разделам. Это также решает наш второй и третий запрос -

2. SELECT * FROM clicks WHERE campaign_id=? AND date_time>=? AND date_time <=? 
    Query will be - 
SELECT * FROM clicks_by_campaign WHERE token(camp_id, createdon) > token(100, '1111111111111') AND token(camp_id, createdon) <= token(100, '22222222222222') 


3. SELECT * FROM clicks WHERE campaign_id=? AND pub_id=? AND AND date_time>=? AND date_time <=? AND event_code=? 
The query will be - 
SELECT * FROM clicks_by_campaign WHERE token(camp_id, createdon) > token(100, '1111111111111') AND token(camp_id, createdon) <= token(100, '22222222222222') AND event_code=10 

Первый запрос -

1. SELECT * FROM clicks WHERE campaign_id=? 

Это действительно антипаттерн в Кассандре. Что бы я делал, обрабатывать данные кампании серийно, ежечасно - ежедневно - еженедельно - ежегодно. Вспомните снова идентификатор кампании, нужно ли обрабатывать все данные за раз. То же самое касается «clicks_by_publisher».

Edit 1

Could you elaborate on what you mean by 'token' ? 

Кассандры разделов строки с помощью ключа раздела. В приведенном выше определении таблицы мы объединили значения camp_id и createdon (camp_id и createdon, как и первичный ключ composit в RDBMS), чтобы сформировать ключ раздела. Разделитель cassandra вычисляет значение хэш-функции, объединяющее camp_id и createdon, и решает, какой раздел идет в строке. Чтобы получить такую ​​же строку, обозреватель должен пересчитать хэш-значение. Функция toke(), делает это.

Временная метка представляет собой время события щелчка, это значение в миллисекундах. Использование createdon (тип long) поможет равномерно распределить строки по разделам.

Например для вставки заявления

1. INSERT INTO clicks_by_campaign (camp_id,createdon ,....) values 100,1111111111111,......) the calculated hash, lets say 111 (combining values 100,1111111111111) -- this will go in partition 1 
2. INSERT INTO clicks_by_campaign (camp_id,createdon ,....) values (100,2222222222222,......) the calculated hash, lets say 222 (combining values 100,2222222222222) -- this will go in partition 2 

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

Фактически, ваш прецедент является подходящим кандидатом для разработки модели данных временных рядов.

+0

Спасибо за ваш ответ. Не могли бы вы рассказать о том, что вы подразумеваете под «токеном»? Более того, мне кажется, что вы предлагаете разбивать данные кампании по метке времени (так что если мы получим 5 кликов за 1 временную метку, это будет раздел с 5 строками). Это самый лучший способ сделать это, но я не могу представить 60 * 60 * 24 запросов, если я хочу получить сведения о клике для кампании в определенный день. – Ankush92

+0

@ Ankush92 Добавил несколько подробностей для ответа. – Gunwant

+0

Спасибо за объяснение. Я подумаю об этом подробнее. Действительно ценю это ! – Ankush92