입니다.
- 그래픽 뷰어 유틸리티, Zviewer 5.1
- 화면 캡쳐 유틸리티, 캡순이 v5.02
- 일정 관리/메모 유틸리티, TransPlan
- 문서 구조를 편리하게, SmartDraw
- 마인드 맵 유틸리티, FreeMind
M$에서는 유능한 인재를 뽑지 못할 망정, 불적격자를 뽑지 말자.라고 했단다.
The preferred setup (for now) is to put Mongrel behind an Apache 2.2.3 server running mod_proxy_balancer. Apache is a proven web server, runs half the Internet, and is a pain to configure. These instructions should get you started, but refer to the Apache folks for anything more complex or weird.
When you’re just starting out, don’t bother with doing anything but running just Mongrel. Mongrel is slower than Apache, but not so slow that small installations will notice it. The worst thing you can do is try to learn Apache install when you’re also trying to learn Ruby on Rails and Mongrel too. Start small, then when you need, build up to the big stuff.
Start up a single mongrel instance on port 8000:
$ mongrel_rails start -d -p 8000 \
-e production -P /full/path/to/log/mongrel-1.pid
Now, we’ll tell Apache to simply proxy all requests to the mongrel server running on port 8000. Simply add the following to your httpd.conf or in a vhost.conf file:
<VirtualHost *:80>
ServerName myapp.com
ServerAlias www.myapp.com
ProxyPass / http://www.myapp.com:8000/
ProxyPassReverse / http://www.myapp.com:8000
ProxyPreserveHost on
</VirtualHost>
That’s it, in a nutshell. Several things to note in this configuration:
1) This configuration forwards all traffic to mongrel. This means mongrel will serve images, javascript, files, and everything else. It’s quite fast at this, but Apache can do it better.
Here are some basic proxypass rules you can add to tell the ProxyPass not to forward on requests to certain documents/requests:
ProxyPass /images !
ProxyPass /stylesheets !
#continue with other static files that should be served by apache
Alias /images /path/to/public/images
Alias /stylesheets /path/to/public/stylesheets
#continue with aliases for static content
For a more detailed set of rules for forwarding on all dynamic content to mongrel, see the more detailed configuration below for more details.
2) In this configuration, it is entirely possible that two users (web requests) could hit your application at the exact same time, and one would have to wait literally milliseconds until the first request is finished before having a turn at the mongrel instance. Unless you’ve got some really long HTTP processes, the nature of the HTTP protocol is pretty good at waiting in line. Only you can determine (through metrics) how long and how many users will come at your application at the exact same time.
Sufficient to say, if you’re ready to start scaling with multiple mongrel instances, read on.
First, let’s start up a few mongrel instances (*nix-style):
$ mongrel_rails start -d -p 8001 \
-e production -P log/mongrel-1.pid
$ mongrel_rails start -d -p 8002 \
-e production -P log/mongrel-2.pid
$ mongrel_rails start -d -p 8003 \
-e production -P log/mongrel-3.pid
$ mongrel_rails start -d -p 8004 \
-e production -P log/mongrel-4.pid
You can also use mongrel_cluster by Bradley Taylor for managing several mongrel instances with a configuration file (and sysv init scripts for *nix servers).
We’re going to be requiring the use of mod_proxy_balancer, a new feature in Apache 2.1/2.2 and above to proxy requests to our mongrel instances. This software based HTTP load balancer will distribute requests evenly (applying a weighting and selection algorithm) to our mongrel instance(s). It even comes with a swell load-balancing manager page for monitoring incoming requests. For more information, see: Apache’s mod_proxy_balancer Documentation.
I won’t go into too many details, as windows and the various linux distributions all have several methods for obtaining apache2, but you will need the use of the following modules:
If you’re compiling from source, this configuration should do the trick:
#./configure --enable-deflate --enable-proxy --enable-proxy-html \
--enable-proxy-balancer --enable-rewrite --enable-cache \
--enable-mem-cache --enable-ssl --enable-headers
A good practice is the separation of apache configuration files. Recommended by several other good guides, we’ll be storing information for our application in several different files. Put these files somewhere that apache2 knows about. Apache is quite good about scanning for all .conf files in certain directories.
Apache lets you include common configuration items into another configuration so you can cut down on repetition. What we’re going to do is make a file that has all the common junk that every Mongrel application needs to work at all, then we’ll just include this in little .conf files for any application we deploy.
Notice that this file doesn’t end in .conf since it’s not a real configuration file, but you can name it however you wish.
Important Update: typo fixed in IE deflate rules
ServerName myapp.com
DocumentRoot /var/www/myapp.com/current/public
<Directory "/var/www/myapp.com/current/public">
Options FollowSymLinks
AllowOverride None
Order allow,deny
Allow from all
</Directory>
RewriteEngine On
# Uncomment for rewrite debugging
#RewriteLog logs/myapp_rewrite_log
#RewriteLogLevel 9
# Check for maintenance file and redirect all requests
# ( this is for use with Capistrano's disable_web task )
RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f
RewriteCond %{SCRIPT_FILENAME} !maintenance.html
RewriteRule ^.*$ /system/maintenance.html [L]
# Rewrite index to check for static
RewriteRule ^/$ /index.html [QSA]
# Rewrite to check for Rails cached page
RewriteRule ^([^.]+)$ $1.html [QSA]
# Redirect all non-static requests to cluster
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
RewriteRule ^/(.*)$ balancer://mongrel_cluster%{REQUEST_URI} [P,QSA,L]
# Deflate
AddOutputFilterByType DEFLATE text/html text/plain text/css
# ... text/xml application/xml application/xhtml+xml text/javascript
BrowserMatch ^Mozilla/4 gzip-only-text/html
BrowserMatch ^Mozilla/4.0[678] no-gzip
BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
# Uncomment for deflate debugging
#DeflateFilterNote Input input_info
#DeflateFilterNote Output output_info
#DeflateFilterNote Ratio ratio_info
#LogFormat '"%r" %{output_info}n/%{input_info}n (%{ratio_info}n%%)' deflate
#CustomLog logs/myapp_deflate_log deflate
We then take the above commmon file and include it in our configuration file for this application deployment.
If you’re using virtual hosting (a pretty good idea, even when you’re the only one on the server), your sample configuration can be this simple:
<VirtualHost *:80>
Include /etc/httpd/conf.d/myapp.common
ErrorLog logs/myapp_errors_log
CustomLog logs/myapp_log combined
</VirtualHost>
This is the meat of our configuration, and goes hand in hand with our mongrel (or mongrel_cluster) configuration. This configuration tells the apache2 mod_proxy_balancer to proxy requests to 3 mongrel instances running on ports 8000, 8001, and 8002.
<Proxy balancer://mongrel_cluster>
BalancerMember http://127.0.0.1:8000
BalancerMember http://127.0.0.1:8001
BalancerMember http://127.0.0.1:8002
</Proxy>
If you had an seperate application server, you could balance to it easily by replacing the 127.0.0.1 with the ip or hostname of your application server, but be sure to make them listen on an external interface (rather than 127.0.0.1).
When you add an additional mongrel to your mongrel_cluster, you can simply add an additional BalancerMember to this file, restart apache (or reload) and you’re all set.
This optional file will setup the balancer-manager—a simple front-end for viewing how your requests are being handled. This balancer in the configuration below will only work from the localhost, so no one else (or possibly you) can view it unless you alter the “Deny” and “Allow” lines.
Listen 8080
<VirtualHost *:8080>
<Location />
SetHandler balancer-manager
Deny from all
Allow from localhost
</Location>
</VirtualHost>
In order for mongrel to know that this request has a forwarded protocol of https, we’ll need to add a special header (hence the addition of mod_header, included in most apache2 builds).
Include /etc/httpd/conf.d/myapp.common
# This is required to convince Rails (via mod_proxy_balancer) that we're
# actually using HTTPS.
RequestHeader set X_FORWARDED_PROTO 'https'
You need this mostly so that redirects go back to https and so you can spot when people are coming through SSL or not.
There are several great tools that automate the setup of Apache for use with
mongrel and mongrel_cluster. The RailsMachine gem can
automate an entire setup of a Rails application. Also, Slingshot Hosting has
a sample set of Capistrano recipes that automatically setup Apache2 and mongrel
through the rake remote:setup task. Be sure to check out both for some ideas.
The newest version of Mongrel supports multiple Rails applications through the use of the—prefix command. The Apache magic for proxying a single application is here assuming your prefix is app1:
ProxyPass /app1 http://127.0.0.1:3000/app1
ProxyPassReverse /app1 http://127.0.0.1:3000/app1
You need to have the proxy pass the new directory name.
Thanks to Joey Geiger and others of the mongrel list for these instructions.
Martins on the mongrel-list has submitted this simple apache configuration. It serves up static content with apache, and forwards dynamic content on to mongrel using ProxyPass. Thanks Martins:
<VirtualHost *>
ServerName myapp.tld
ServerAlias www.myapp.tld
DocumentRoot /var/www/sites/myapp/current/public
<Directory "/var/www/sites/myapp/current/public">
Options FollowSymLinks
AllowOverride None
Order allow,deny
Allow from all
</Directory>
RewriteEngine On
# Check for maintenance file. Let apache load it if it exists
RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f
RewriteRule . /system/maintenance.html [L]
# Let apache serve static files
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f
RewriteRule (.*) $1 [L]
# Don't do forward proxying
ProxyRequests Off
# Enable reverse proxying
<Proxy *>
Order deny,allow
Allow from all
</Proxy>
# Pass other requests to mongrel instance
ProxyPass / http://127.0.0.1:8200/
ProxyPassReverse / http://127.0.0.1:8200/
</VirtualHost>
Phillip Hallstrom has submitted this apache configuration, which includes support for having static directories handled by Apache, php support, and hiding svn directories.
<VirtualHost *:80>
ServerName myserver.com
DocumentRoot /path/to/my/app/public
<Directory "/path/to/my/app/public">
Options FollowSymLinks
AllowOverride None
Order allow,deny
Allow from all
</Directory>
<Proxy balancer://mongrel_cluster>
BalancerMember http://127.0.0.1:8805
</Proxy>
RewriteEngine On
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} -d
RewriteRule ^(.+[^/])$ $1/ [R]
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} \.php
RewriteRule ^(.*)$ $1 [QSA,L]
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME}/index.html -f
RewriteRule ^(.*)$ $1/index.html [QSA,L]
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME}/index.php -f
RewriteRule ^(.*)$ $1/index.php [QSA,L]
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} -d
RewriteRule ^(.*)[^/]$ $1/ [QSA,L]
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
RewriteRule ^/(.*)$ balancer://mongrel_cluster%{REQUEST_URI} [P,QSA,L]
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE application/x-javascript
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/xml
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE application/xhtml+xml
BrowserMatch ^Mozilla/4 gzip-only-text/html
BrowserMatch ^Mozilla/4.0[678] no-gzip
BrowserMatch bMSIE !no-gzip !gzip-only-text/html
php_value include_path /path/to/my/app/php:/usr/local/lib/php:.
php_value auto_prepend_file /path/to/my/app/php/auto_prepend.php
# this not only blocks access to .svn directories, but makes it appear
# as though they aren't even there, not just that they are forbidden
<DirectoryMatch "^/.*/\.svn/">
ErrorDocument 403 /404.html
Order allow,deny
Deny from all
Satisfy All
</DirectoryMatch>
</VirtualHost>
Jens Kraemer reports this differing proxy setup that uses the P option in Rewrite rules so as not to use the ProxyPass directive:
# Don't do forward proxying
ProxyRequests Off
# Enable reverse proxying
<Proxy *>
Order deny,allow
Allow from all
</Proxy>
RewriteEngine On
# Check for maintenance file. Let apache load it if it exists
RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f
RewriteRule . /system/maintenance.html [L]
# Rewrite index to check for static
RewriteRule ^/$ /index.html [QSA]
# Let apache serve static files (send everything via mod_proxy that
# is *no* static file (!-f)
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-f
RewriteRule .* http://127.0.0.1:8200%{REQUEST_URI} [L,P,QSA]
the P option to the last rule replaces the ProxyPass and ProxyPassReverse directives.
If you use svn to issue checkouts instead of exports, you’ll need to hide those pesky .svn directories. This works:
# this not only blocks access to .svn directories, but makes it appear
# as though they aren't even there, not just that they are forbidden
<DirectoryMatch "^/.*/\.svn/">
ErrorDocument 403 /404.html
Order allow,deny
Deny from all
Satisfy All
</DirectoryMatch>
</VirtualHost>
Jon Reads reports successfully reading the REMOTE_USER variable:
After many hours trying to solve the same problem I found this post: Forcing a proxied host to generate REMOTE_USER
and can confirm that the following works for me when put in the Proxy directive on Apache 2:
RewriteEngine On
RewriteCond %{LA-U:REMOTE_USER} (.+)
RewriteRule . - [E=RU:%1]
RequestHeader add X-Forwarded-User %{RU}e
[1] Time For A Grown-Up Server: Rails, Mongrel, Apache, Capistrano and You
[2] Bradley Taylor’s Fluxura and RailsMachine
[3] Slingshot Hosting Automated Capistrano Recipe
Thanks to many users on the mongrel list for making it easy for me to compile all these tips and tricks as they come across the list.

[그림 1] DMA 솔루션을 적용하기 전의 데이터 모델
오케이. 자 이제 고쳐봅시다.
개선된 데이터 모델 생각하기
우리는 이 테이블을 아주 간단하게 쪼갤 수 있다고 결정했습니다. [그림 2]에 보이는 것과 비슷하게 할 수 있습니다.

[그림 2] 전반적으로 설계를 개선시키는 뷰를 포함한 데이터 모델
주문 데이터를 두 테이블로 나누면 데이터 중복을 피할 수 있고 보다 견고한 데이터 모델을 유지할 수 있습니다. 하지만 현재의 구조에서 어떻게 그러한 모델로 다다를 수 있을까요?
의사소통이 핵심입니다. 코딩과 테스트 할 것이 거의 없다 하더라도 가장 중요한 요소입니다. 모든 관련된
이해관계자들(stakeholder)이 여러분의 새로운 설계를 설명할 때 참석하도록 하세요. 이해관계자들이란 이 데이터에 접근하는
다른 애플리케이션을 구현하고 있는 개발자, 새로운 데이터 모델을 유지보수 할 데이터베이스 관리자 그리고 마지막으로 데이터 모델이
어떻게 변해야 하는지 각자의 생각을 가지고 있을만한 기술 관리자와 기술 비즈니스 분석가를 말합니다. 의사소통의 중요성은 아무리
강조해도 지나치지 않습니다.
데이터베이스 뷰 만들기
우리가 원하는 구조를 이루기 위해서 전반적으로 역정규화되어 있는 테이블을 사용하고 있는 기존의 스키마에서
데이터베이스 뷰를 정의합니다. 당연히 이 뷰는 정규화 되어 있는 상태로 데이터를 보여주겠죠. ORDER_V 뷰는
CUST_ORDER 테이블을 그룹화 하고 간추린 버전입니다. (구체적인 주문 아이템 정보를 제거하고 그것들을 order_id로
묶었습니다.) 다음과 같이 뷰를 정의했습니다.
CREATE VIEW dma_example.order_v
AS select
dma_example.cust_order.order_id AS order_id,
dma_example.cust_order.order_cust AS order_cust,
max(dma_example.cust_order.order_date) AS order_date
from dma_example.cust_order
group by dma_example.cust_order.order_id;
ORDER_ITEM_V 뷰는 오직 주문 아이템에 대한 상세 정보만을 담고 있으며 고객의 id와 (ORDER_V 뷰에서 포착할 수 있는)데이터는 제외했습니다. 다음과 같이 ORDER_ITEM_V 를 정의했습니다.
지금까지 기본적으로 하나의 테이블을 둘로 나눴습니다.CREATE VIEW dma_example.order_item_v
AS select
dma_example.cust_order.order_id AS oi_order,
dma_example.cust_order.order_item AS oi_item,
dma_example.cust_order.order_item_price AS oi_price,
dma_example.cust_order.order_item_qty AS oi_qty
from dma_example.cust_order
where (dma_example.cust_order.order_item is not null);
create procedure insert_order_item
(in itemprice FLOAT, in itemqty INT, in orderid INT, in itemid INT)
LANGUAGE SQL
BEGIN
DECLARE p_order_id INT;
DECLARE p_cust_id INT;
DECLARE max_order_id INT;
DECLARE p_itemprice FLOAT;
-- apply the current price to the line item
if itemprice is null then
select prod_price into p_itemprice from product
where prod_id=itemid;
else
set p_itemprice = itemprice;
end if;
-- get the customer id.
select order_cust into p_cust_id
from cust_order where order_id=orderid limit 1;
insert into cust_order
(order_id, order_cust, order_date,
order_item, order_item_price, order_item_qty)
values
(orderid, p_cust_id, now(), itemid, p_itemprice, itemqty);
END
ORDER_ITEM_V 뷰에서 어떤 데이터를 제외시켰든지 상관없이 모든 데이터를 CUST_ORDER 테이블에 추가해야 합니다. 이 프로시저가 CUST_ORDER 테이블에 추가하는 작업을 성공적으로 완료하면 영향을 받는 row의 숫자인 1을 반환할 것입니다. 각각을 테이블(실제로는 뷰이지만)에서 스토어드 프로시저들을 하나의 row로 취급하기 때문에 하이버네이트가 스토어드 프로시저의 결과로 1또는 0을 기대하고 있다는 것을 아는 것이 중요합니다. 실제 그런지 확인하기 위해 스토어드 프로시저를 가지고 작은 실험을 해볼 수 있습니다. 예를 들어, 하나의 주문 아이템을 업데이트 하기 위한 스토어드 프로시저가 CUST_ORDER 테이블의 여러 row(모든 주문 아이템에서 한 개의 row)에 영향을 끼칠 수 있을 것입니다. 만약 주어진 주문 ID를 가지고 있는 모든 row를 수정하려고 한다면 값이 바뀐 row의 수가 1보다 크게 됩니다. 이렇게 하면 하이버네이트에서 문제를 발생시키기 때문에 작은 테이블을 사용하고 CUST_ORDER 테이블을 수정한 다음에 갱신할 것입니다. 이렇게 하면 스토어드 프로시저가 영향을 받은 row의 숫자로 1을 반환합니다. (예상한 수정이 오직 하나의 row에만 변화를 주었기 때문에) 다음에 수정하는 스토어드 프로시저를 확인할 수 있습니다.
POJO, 하이버네이트 맵핑, DAOcreate procedure update_order
(in ordercust INT, in orderdate DATETIME, in orderid INT)
LANGUAGE SQL
BEGIN
update cust_order set order_cust=ordercust,
order_date=orderdate
where order_id=orderid;
if row_count() > 0 then
update help_table set i=i+1;
end if;
END
이때 파리미터의 순서가 중요합니다. 하이버네이트 매뉴얼 중 custom SQL reference 부분을 참조하여 스토어드 프로시저의 파라미터 순서를 정하시기 바랍니다.<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="org.onjava.shared.vo.Order" table="order_v"
catalog="dma_example">
<id name="orderId" type="int" column="order_id" />
<property name="orderCust" type="int" column="order_cust" />
<property name="orderDate" type="timestamp" column="order_date"
length="19"/>
<set name="items" inverse="true" cascade="all-delete-orphan"
lazy="true">
<key column="oi_order"/>
<one-to-many class="org.onjava.shared.vo.OrderItem" />
</set>
<sql-insert callable="true">
{call insert_order(?, ?, ?)}
</sql-insert>
<sql-update callable="true">
{call update_order(?, ?, ?)}
</sql-update>
<sql-delete callable="true">{call delete_order(?)}</sql-delete>
</class>
</hibernate-mapping>

[그림 3] 기존 애플리케이션과 DMA 솔루션이 평화롭게 공존하고 있으며 같은 서로 다른 모델을 통해서 같은 데이터 셋을 사용하고 있습니다.
이제는 무엇을 해야 할까요? 기반이 되는 데이터 모델 이전하기
데이터모델을 수정하기 위해 멋진 해결책을 구현했습니다. 수 개월이 지나고 개발자들이 그들의 애플리케이션을 수정해 감으로써 점점
새로운 뷰 기반의 데이터 모델을 사용하기 시작했습니다. 하지만 그 기반이 되고 있던 역정규화 상태(또는 잘못 설계된)는 여전히
존재하고 있으며 그것을 제거하고 싶습니다. 하지만 어떻게 할까요? 여러분이 생각하는 것보다 실제는 더 간단합니
다. 다음에 단계별 가이드가 있습니다.
여러가지 방법이 있겠지만.. 가장 간단한 방법은 MozBackup이라는 유틸리티를 사용하는 것입니다. MozBackup은 파이어폭스와 썬더같은 모든 모질라 재단의 소프트웨어들을 백업할수 있으며, 파이어폭스에서는 북마크 / 사용기록 / 패스워드 / 쿠키 / 저장된 폼 / 다운로드된 파일목록 / 인증서를 백업할수 있습니다.
다만 확장기능의 경우는 이미 MozBackup에서 설정된 몇가지 유명한 확장기능만 백업할수 있기때문에 조금 다양한 종류의 확장기능을 사용한다면 FEBE라는 확장기능을 백업해주는 확장기능을 사용하시면 깔끔하게 백업할수 있습니다.
MozBackup은 이미 한글화가 된 프로그램이기 때문에 한글 언어 파일만 다운로드해서 설치 폴더에 덮어씌어주면 별다른 어려움없이 작업 할 수 있습니다. (한글화 작업해 주신 분들 감사합니다.. ^^*)
프로파일을 선택한후 백업할 요소들을 선택한 다음 백업하면 지정된 폴더에 .PCV라는 파일로 백업이 됩니다. 나중에 파이어폭스를 다시 깔면 MozBackup을 구동시켜 이 파일로 복원시키면 되겠습니다.
FEBE의 경우는 확장기능으로 설치되기 때문에 도구 메뉴의 FEBE에서 Perform Backup을 눌러주시면됩니다. 마찬가지로 복구는 Restore를 선택하고 복구할 확장기능이나 테마를 선택하면됩니다.
Options에서 백업할 폴더를 지정할수 있으며 확장기능 말고도 북마크 / 쿠키 같은 여러가지 다른 요소들도 백업하도록 설정할수 있습니다만 이미 여타 요소들은 MozBackup으로 백업하는게 편하기 때문에 FEBE는 단순히 확장기능만 백업하는 용도로 사용하는게 더 편한것 같습니다.
백업을 마치면 다음과 같은 깔끔한 리포트를 볼 수 있습니다.