Создание счетчика посещений с использованием кеша или области приложения

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

У меня есть идеи до сих пор:.

Идея 1

  1. Создайте структуру приложения или кэша для хранения пары ключ-значение pageId и pageHits.
  2. При каждом обращении к странице проверяйте наличие cookie-файла pageId/ip-адреса.
  3. а. Если он существует, ничего не делайте.
  4. б. Если это не так, установите его и обновите структуру обращений в приложении или кеше.

Проблема: я не знаю, как получать данные структуры в базу данных с перерывами/по истечении определенного времени. Запланированное мероприятие?

Идея 2

Нет печенья; сохранить pageId/IP-адрес в своей собственной структуре кеша/приложения.

Проблема Я не знаю, как структурировать структуры/массивы данных для хранения информации. Кажется сложным с циклами массива и поиском структуры. И у меня все еще та же проблема, что и у идеи.

Есть советы, идеи, критика? В частности, мне нужна помощь в определении структур данных для идеи 2. Меня больше интересует производительность, чем целостность данных, и я доволен только решением CF9. Должен добавить, что я хочу денормализировать данные в столбце посещений страниц для каждого идентификатора страницы. Мне не нужны нормализованные таблицы данных.


person Mohamad    schedule 31.05.2011    source источник


Ответы (2)


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

Используйте log = fileRead('log.txt', 'read') и периодически повторяйте line fileReadLine(log) через <cfschedule/>. Для каждого пакета вы можете использовать способ, который вы уже описали, а затем использовать любой подход к базе данных для INSERT/UPDATE (обычно используется ключевое слово MERGE, но MySQL отличается) на основе IP-адреса, если это то, что вам нужно. Если это сайт с очень высоким трафиком, рассмотрите возможность изменения типа данных столбцу IP-адреса в целочисленный тип данных для ускорения поиска по индексу.

Обновить

Используйте следующий код для настройки ссылки на файловый объект:

<cflock name="logparser" type="exclusive" timeout="1" throwontimeout="false">
    <cfif NOT structKeyExists(application, "logFile")>
        <cfset application.logFile =
            fileOpen('/path/to/log.txt', 'read')>
    </cfif>
    <cfloop condition="NOT FileisEOF(application.logFile)">
        <!--- replace with an appropriate algorithm --->
        <cfoutput>
            #fileReadLine(application.logFile)#
            <br />
        </cfoutput>
    </cfloop>
</cflock>

При этом ссылка устанавливается один раз (например, fileOpen()), которая отслеживает, на какой строке она находится. Затем, когда <cfschedule/> снова попадает в этот код, он использует существующую ссылку, если она присутствует, и выполняет итерацию вперед оттуда. Блокировка гарантирует, что только один поток выполняет алгоритм, поэтому вам не нужно беспокоиться об ограничении времени, просто позвольте ему продолжаться столько, сколько нужно.

person orangepips    schedule 31.05.2011
comment
спасибо, что прояснили это. Я забыл упомянуть одну вещь: я денормализую данные о посещениях в один столбец обращений к странице, поскольку сами страницы сохраняются в БД): если я запускаю эту службу каждые 60 секунд, а файлы журнала становятся действительно большими, как я могу читать? всего 60 секунд строк журнала? Если в моем файле журнала 10 000 строк, но мне нужны только строки, созданные за последние 60 секунд... будет ли этот подход практичным? Я не ищу нормализованные данные. - person Mohamad; 31.05.2011
comment
@Mohamad: см. мое обновление. Короткий ответ: не беспокойтесь об ограничении времени, вместо этого используйте <cflock/> со ссылкой fileOpen(). - person orangepips; 31.05.2011
comment
Я еще не начал реализовывать это, но я попробую в эти выходные. Я думал сегодня утром, хотя, и мне пришло в голову: Как бы вы отследили уникальные хиты! Если бы каждый посетитель считался уникальным посещением через 3 часа, алгоритму пришлось бы анализировать каждую строку и выяснять, есть ли повторяющееся значение с последним x разом... будет ли это практично? - person Mohamad; 03.06.2011
comment
@Mohamad: я бы, наверное, поместил каждое попадание в таблицу базы данных, включая IP-адрес, URL-адрес и отметку времени. Затем запустите DISTINCT для этих строк и используйте предложение WHERE, чтобы ограничить период времени. Это должно дать вам информацию, которую вы хотите. - person orangepips; 03.06.2011

Идея 1: да, <cfschedule> твой друг

Идея 2: сохранить pageId/ip-адрес? Я думаю, что лучше использовать Set из Java, но структура тоже будет работать, если вы присвоите ей пустое значение...

pageIDs["1"]["192.0.0.1"] = "";
hitsOfPage1 = structCount(pageIDs[1]));

Однако, если я снова зайду на страницу tmr, я не буду засчитан?

person Henry    schedule 31.05.2011
comment
почему бы мне не сделать что-то вроде hits[1].page = { pageId = 1, ipAddress = 192.0.0.0 } или что-то в этом роде? Мне трудно визуализировать структуру данных в таком сценарии! Кроме того, в сценарии с файлами cookie срок их действия может истечь через несколько часов. Во второй идее я пока не знаю, как это будет работать. - person Mohamad; 31.05.2011
comment
потому что наиболее частый ответ, который вам нужен для счетчика посещений, это... сколько посещений для pageID = X. Вам нужна структура данных, которая поддерживает это. Ваша целевая структура данных не может легко ответить на часть where pageId = 1. - person Henry; 31.05.2011