Статьи

Создание высокопроизводительных приложений с ColdFusion 9 и Ehcache 2.4


Создание высокопроизводительных приложений с ColdFusion 9 и Ehcache 2.4 Посмотрите на любой высокопроизводительный веб-сайт, такой как Facebook или Twitter, и независимо от операционной системы, сервера приложений, языка программирования или базы данных, на которой он построен, есть одна вещь, в которой вы можете быть абсолютно уверены из — широкое использование кэширования.
 Независимо от того, насколько быстро работает ваша сегментированная и кластеризованная база данных MySQL или насколько хорош ваш бэкэнд NoSQL, кэширование может обеспечить повышение производительности, часто на один или несколько порядков быстрее, чем вы могли бы достичь без него.

Реализация кэширования в Adobe® ColdFusion® 9 проста и легка.
  Когда Adobe выпустила ColdFusion 9.0, они включили автономную версию Ehcache от Terracotta (точнее, версию 2.0).
  Если вы не знакомы с Ehcache, его широко считают де-факто решением для кэширования приложений Java.
  Он поставляется как с открытым исходным кодом, так и с коммерческой версией с различными уровнями возможностей и поддержки.

Внутрипроцессный и внепроцессный кэш

ColdFusion 9 поставляется с базовой версией Ehcache с открытым исходным кодом.   По умолчанию кэш настроен как один узел и работает в том же процессе JVM, что и ваш сервер ColdFusion.   Это известно как внутрипроцессный или L1-кэш.   Поскольку ColdFusion и Ehcache совместно используют один и тот же контейнер JVM, они также имеют одинаковое распределение памяти.   Во многих случаях это нормально.    Однако существует предел масштабируемости, которую вы можете ожидать от внутрипроцессного кэша. 

Также возможно настроить Ehcache для работы в распределенном режиме.   В распределенном режиме добавляется кэш L2, называемый Terracotta Server, который запускается вне процесса в собственной JVM. Обычно кэш L2 устанавливается на отдельном сервере от вашего приложения и кэш L1.   Существует два варианта Terracotta Server: открытый и коммерческий.   Версия Terracotta с открытым исходным кодом ограничена одним активным и одним пассивным узлом.  Коммерческая версия, известная как Terracotta Server Array, позволяет вам масштабировать кэш, добавляя дополнительные узлы в кэш L2 вне процесса.   В результате получается один виртуальный кеш, состоящий из нескольких физических узлов.   Терракотовые серверные массивы легко масштабируются до нескольких терабайт. 

При настройке в распределенном режиме Ehcache использует многоуровневую архитектуру кэширования, в которой кэш L2 содержит полный набор кэшированных данных, а локальный для вашего приложения кэш L1 имеет настраиваемое подмножество наиболее часто используемых элементов кэша.   Шаблоны доступа к кэшу, как правило, следуют принципу Парето: 80% запросов к вашему кешу могут обслуживаться 20% элементов в кеше. Учитывая это, многоуровневая архитектура Ehcache предполагает, что размер кэша L1 должен быть таким, чтобы он содержал около 20% данных в кэше L2. Ehcache автоматически определяет, какие данные должны храниться в L1, с помощью алгоритма наименьшего количества недавно использовавшихся (LRU).     

Это одно из главных различий между Ehcache с Terracotta и другими чисто распределенными системами кэширования, такими как MemcacheD или так называемыми базами данных NoSQL.   В чисто распределенном кеше задержка сети увеличивает общее время поиска, превышающее 1 миллисекунду.   Однако в случае Ehcache элементы из кэша L1 извлекаются менее чем за 1 микросекунду, а элементы из кэша L2 извлекаются менее чем за 2 миллисекунды. Это общая разница в производительности между Ehcache и чисто распределенными системами кэширования на порядок [1] .

Использование дистрибутива Pareto означает, что 80% запросов к вашему кешу будут поступать из кеша L1 и возвращаться менее чем за 1 микросекунду. Остальные 20% запросов будут отправлены во внепроцессный кэш второго уровня и все равно будут возвращены менее чем за 2 миллисекунды.

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

Теперь, когда у вас есть лучшее представление об архитектуре Ehcache, давайте взглянем на обновление версии Ehcache, поставляемой с ColdFusion 9, а также на установку и настройку сервера Terracotta, чтобы мы могли создать высокопроизводительный кеш.

Обновление ColdFusion 9 до Ehcache 2.4 и установка сервера Terracotta

Прежде чем идти дальше, вам необходимо обновить версию Ehcache от ColdFusion с 2.0 (поставляется с ColdFusion 9.0.1) до последней версии, в настоящее время 2.4.1.   Хотя это само по себе не сложное задание, оно включает в себя загрузку нескольких наборов файлов из разных проектов, а также с оговоркой.   Хотя Terracotta (создатели Ehcache) делает все возможное для обеспечения обратной совместимости, нет гарантии, что замена версии Ehcache, поставляемой с ColdFusion, на последнюю и лучшую версию будет работать.   Проблем не должно быть, но если они есть, Adobe не будет оказывать поддержку, поскольку они только сертифицируют версию Ehcahe, поставляемую с ColdFusion.  Тем не менее, я обновил свою версию Ehcache несколько раз сейчас и не встретил никаких проблем на этом пути.

Поскольку мы собираемся заменить связанные с Ehcache файлы, которые поставляются с ColdFusion 9, на обновленные версии, первое, что нам нужно сделать, — это создать резервные копии исходных файлов.    Вместо того, чтобы удалять файлы или перемещать их в другое место, я предпочитаю переименовывать их на месте на случай, если мне потребуется вернуться к ним позже. Сначала остановите службу сервера ColdFusion.   Затем найдите каталог / lib. Расположение будет зависеть от того, используете ли вы автономную версию или версию ColdFusion с несколькими экземплярами.   Для автономного, каталог:

CFHOME / lib /

Для нескольких экземпляров это:

/ JRun4 / серверы / экземпляр / cfusion-ear / cfusion-war / WEB-INF / cfusion / bin

Здесь вы найдете четыре файла, которые нас интересуют:

·       Ehcache.jar

·       Ehcache-web.jar

·       Slf4j-api-1.5.6.jar

·       Slf4j-log4j12-1.5.6.jar

 

Как я уже упоминал, я вообще не люблю удалять эти файлы на всякий случай. Я просто переименую их с расширением «.original», чтобы Ehcache.jar стал ehcache.jar.original.   Таким образом, нет никакой путаницы в том, каким было исходное имя файла или расширение.

Для следующего набора шагов вам понадобится последняя сборка Terracotta Kit.   Terracotta Kit содержит Terracotta 3.5.0, Ehcache 2.4.1 и Quartz Scheduler 2.0.0.   В этой статье мы сосредоточимся на терракоте и Ehcache. Вы можете найти Terracotta Kit на веб-сайте Terracotta:

http://www.terracotta.org/dl/oss-download-catalog

Есть несколько версий комплекта. Для наших целей скачайте terracotta-3.5.0.tar.gz.   Как только у вас появится файл в вашей локальной системе, распакуйте его и распакуйте.   Вы должны увидеть структуру каталогов, подобную приведенной ниже:

Перейдите в каталог / lib и извлеките следующие файлы в каталог ColdFusion / lib:

·       Ehcache-core-2.4.1.jar

·       Ehcache-terracotta-2.4.1.jar

Затем вам нужно извлечь файл terracotta-toolkit-1.2-runtime-3.0.0.jar из / common в каталог ColdFusion / lib.

Извлеките весь каталог /terracotta-3.5.0 из архива и поместите его туда, куда вы обычно устанавливаете программы.   В моем случае на 64-битной машине с Windows 7 я поместил файлы в c: / program files / terracotta / terracotta-3.5.0.   Таким образом, если я хочу работать с несколькими версиями сервера Terracotta, у меня есть единственное место, где я могу держать их всех организованными.   В производственной среде вы обычно не запускаете Terracotta на том же физическом сервере, что и сервер приложений.   Частью использования распределенного кэширования является то, что вы можете распределять свой кэш по другим физическим ресурсам в сети по мере необходимости для достижения горизонтального масштаба.   Однако, в целях разработки, запуск сервера Terracotta на той же машине, что и ваш сервер приложений, будет работать нормально.

Вам также нужно обновить файл ehcache-web.jar в каталоге ColdFusion / lib. Этот файл необходимо загрузить отдельно и найти в пакете ehcache-web-2.0.3-distribution.tar.gz на веб-сайте Terracotta: http://www.terracotta.org/dl/ehcache-oss-download- каталог .   Файл, который вы хотите извлечь, это ehcache-web-2.0.3.jar.

Наконец, вам нужно загрузить обновления для SLF4J, фасада регистрации Java, который используется Ehcache и сервером Terracotta. Вы можете скачать необходимый файл JAR с их сайта.   Обратите внимание, что версия 1.6.1 — это то, что вам нужно для Terracotta 3.5.0 / Ehcache 2.4.1:

http://www.slf4j.org/download.html

Получив файл jar SLF4J, распакуйте следующие файлы и поместите их в каталог / lib:

·       Slf4j-api-1.6.1.jar

·       Slf4j-jdk14-1.6.1.jar

·       Slf4j-log4j12-1.6.1.jar

Вот и все, обновление завершено. Иди вперед и перезапусти свой сервер ColdFusion.

Основы кэширования

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

<cfoutput>

I'm dynamic data #now()# <br/>

</cfoutput>

 

<!--- cache this fragment for 5 seconds regardless of how many times it's accessed --->

<cfcache timespan="#createTimeSpan(0,0,0,5)#">

      <cfoutput>

      I'm cached dynamic data: #now()# <br/>

      </cfoutput>

</cfcache>

 

<!--- cache this item, then flush it if it's not accessed for 5 seconds --->

<cfcache idletime="#createTimeSpan(0,0,0,5)#">

      <cfoutput>

      I'm cached dynamic data too: #now()# <br/>

      </cfoutput>

</cfcache>

Если вы запустите этот код, вы увидите, что при начальной загрузке все три метки времени идентичны.   Теперь начните нажимать кнопку перезагрузки вашего браузера.   Как и следовало ожидать, отметка времени для некэшированного кода будет обновляться при каждой загрузке.   Однако две другие метки времени изначально не изменятся, так как значения будут возвращены из кэша.   Продолжайте нажимать перезагрузить.   Через 5 секунд вы также увидите значение изменения второй временной метки:

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

If you want to cache an entire page instead of individual fragments, the code is similar. However, instead of wrapping the entire page in <cfcache>… </cfcache> tags, you only need to place a single <cfcache> tag at the top of the page:

<cfcache timespan="#createTimeSpan(0,0,0,5)#">

 

<cfoutput>

Currently #timeFormat(now(),'hh:mm:ss')# <br />

</cfoutput>

 

<cfoutput>

Random number: #rand()#

</cfoutput>      

Running this code caches the entire page for 5 seconds.  As you can see, there are two different sections of dynamic values that are being output and cached.

If you want more control over caching in ColdFusion, consider using the object cache.  The object cache gives you granular control over putting items in and getting items out of the cache.  It also lets you store more than just pages and fragments.  Using the object cache, you can put any type of data that ColdFusion supports into the cache, including complex data types such as structures, arrays, queries and CFCs. Here’s a simple example that caches a query object from the sample database that installs with ColdFusion for 2 minutes:

<!--- Go to the cache. If the data isn’t there, go to the db then

      repopulate the cache --->

 

<cfset getArtists = cacheGet("artistQuery")>

 

<cfif isNull(getArtists)>

      <cfquery name="getArtists" datasource="cfartgallery">

            SELECT *

            from artists

      </cfquery>

     

      <cfset cachePut("artistQuery", getArtists, createTimeSpan(0,0,2,0))>

</cfif>

 

<h3>Query:</h3>

<cfdump var="#getArtists#">

In this code, the first thing we’re do is attempt to get the query from the cache using the cacheGet() function.  The cacheGet() function takes two arguments, the cached value’s key and an optional cache name.  Here, we’re just passing in “artistQuery” as the key.  The next bit of code checks to see if the cacheGet() returns Null.  If it does, we know that the query doesn’t exist in the cache so we immediately go back to the source system (in this case the cfartgallery database) and re-run the query.  After the results come back, we put them back in the cache using the cachePut() function, setting a timeout for the cached query of 2 minutes.  Finally, we return the query and dump it to the browser.

Scaling out with the Terracotta Server

So far, all of the examples we’ve walked through used the L1 in-process cache that’s part of Ehcache core.  Let’s up the ante a bit by adding a L2 out-of-process cache. 

You’ll need to open the XML file used by Ehcache for configuration.  This file is called ehcache.xml and it’s located in the same place as the Jar files we renamed earlier: CFHOME/lib/ for stand-alone ColdFusion or /JRun4/servers/instance/cfusion-ear/cfusion-war/WEB-INF/cfusion/bin for multi-instance.  If you scroll to the bottom of the file, you’ll see XML that looks like this:

<defaultCache

      maxElementsInMemory="10000"

      eternal="false"

      timeToIdleSeconds="86400"

      timeToLiveSeconds="86400"

      overflowToDisk="false"

      diskSpoolBufferSizeMB="30"

      maxElementsOnDisk="10000000"

      diskPersistent="false"

      diskExpiryThreadIntervalSeconds="3600"

      memoryStoreEvictionPolicy="LRU"

      clearOnFlush="true"

> 

</defaultCache>

This is the configuration ColdFusion and Ehcache use for every cache that gets created unless you specify otherwise.  It’s possible to create your own custom caches either programmatically at runtime, or by hard-coding them in the ehcache.xml file.  For the purposes of setting up our Terracotta server, let’s go ahead and add a custom cache to the ehcache.xml file.  Go ahead and stop your ColdFusion server.  Place the following code above the default configuration and save the file.

<cache

      name="terracottaTest"

      maxElementsInMemory="10000"

      eternal="false"

      timeToIdleSeconds="86400"

      timeToLiveSeconds="86400"

      overflowToDisk="false"

      diskSpoolBufferSizeMB="30"

      maxElementsOnDisk="10000000"

      diskPersistent="false"

      diskExpiryThreadIntervalSeconds="3600"

      memoryStoreEvictionPolicy="LRU"

      clearOnFlush="true"

      >

</cache>

What you’ve just done here is created a custom cache called terracottaTest. Right now, the cache is still configured to run in-process.  Go ahead and modify the code like this:

<terracottaConfig url="localhost:9510" />

 

<cache

      name="terracottaTest"

      maxElementsInMemory="10000"

      eternal="false"

      timeToIdleSeconds="86400"

      timeToLiveSeconds="86400"

      overflowToDisk="false"

      diskSpoolBufferSizeMB="30"

      maxElementsOnDisk="10000000"

      diskPersistent="false"

      diskExpiryThreadIntervalSeconds="3600"

      memoryStoreEvictionPolicy="LRU"

      clearOnFlush="true"

      >

      <terracotta clustered="true" />

</cache>

Your custom cache is now configured it for distributed caching with an L2 out-of-process Terracotta server and all it took was 2 additional lines of code! Before you start your ColdFusion server back up, we need to bring up the Terracotta server you installed earlier.  Open a command prompt and navigate to the Terracotta server’s /bin directory.  On my Windows 7 machine, that’s in:

C:/program files/terracotta/terracotta-3.5.0/bin

Go ahead and run start-tc-server.bat if you’re on Windows, or start-tc-server.sh if you’re on Linux/Unix.  If your server starts successfully, you should see a screen similar to this:

Once the Terracotta server is up and running and you see the “ready for work” message, go ahead and restart your ColdFusion server.  It’s important to note that if you have ColdFusion configured for distributed caching and you don’t have the Terracotta server running, it will hang your ColdFusion server.  Hopefully this is something Adobe will address in a future ColdFusion update.

Ehcache comes with a nice developer console you can use as you develop to gain insight into what’s happening with both your L1 and L2 caches.  To run the console, navigate to the same directory where you launched the Terracotta server and run the /dev-console.bat on Windows or /dev-console.sh on UNIX/Linux.  You’ll get a login screen like this:

Click Connect and you should see both your L1 local client node as well as the L2 Terracotta server you configured (Server Array).  If you expand out the Terracotta Cluster tree item, you’ll see a screen that should show that your TerracottaTest cache is configured in distributed mode:

Let’s run some sample code so you can watch as data is put in and then retrieved from the cache:

<!--- fill the cache with 10,000 items --->

<cfloop from="1" to="10000" index="i">

      <cfset cachePut(i, 'Item #i#', '#createTimeSpan(0,0,5,0)#', '#createTimeSpan(0,0,5,0)#', 'terracottaTest')>

</cfloop>

 

<!--- get from the cache 10 million times --->

<cfloop from="1" to="10000000" index="j">

      <cfset x = cacheGet(randRange(1,10000), 'terracottaTest')>

</cfloop>

This will put 10,000 items in the cache, then start randomly pulling items out 10 million times.  This should allow enough time for you to see what’s happening in the dev console:

Conclusion

This article really only begins to scratch the surface of what you can accomplish with ColdFusion and Ehcache.  There are several other features in Ehcache 2.4 that are beyond the scope of this article but worth exploring:

·       2nd level cache provider for ColdFusion’s Hibernate ORM implementation

·       Cache search

·       Distributed transactions

·       NonStopCache

·       Integration with Terracotta Big Memory

For more information on Ehcache and Terracotta’s other products, see their website at http://www.terracotta.org.

About the Author

Rob Brooks-Bilson is a consultant, author, and the director of architecture at Amkor Technology, a global leader in providing assembly and test services to semiconductor companies and electronics OEMs.  His responsibilities at Amkor include development of strategic technology direction, planning of effective resource utilization, coordinating and directing technical development teams, and more.   He’s a frequent speaker at industry conferences as well as local user groups. Brooks-Bilson is also the author of two O’Reilly books, «Programming ColdFusion» and «Programming ColdFusion MX.».

Outside of work, Rob’s a technophile, blogger, photographer, bed jumper, world traveler, hiker, mountain biker, and Adobe Community Professional for ColdFusion.