웹 응용 프로그램 에서 자주 사용 하 는 각종 cache 상세 설명
다음은 3 층 의 설명도 로 후속 인용 에 편리 합 니 다.
1.클 라 이언 트 캐 시
한 클 라 이언 트 는 항상 같은 자원 을 방문 합 니 다.예 를 들 어 브 라 우 저 로 사이트 의 첫 페이지 를 방문 하거나 같은 글 을 보 거나 app 으로 같은 api 를 방문 합 니 다.만약 에 이 자원 이 그 가 이전에 방문 한 것 과 아무런 변화 가 없 으 면 http 규범 중의 304 Not Modified 응답 헤드(http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5)를 이용 하여 클 라 이언 트 의 캐 시 를 직접 사용 할 수 있 습 니 다.서버 에서 내용 을 다시 만 들 필요 가 없습니다.
레일 스에 fresh 가 내장 되 어 있 습 니 다.when 이 방법 은 코드 한 줄 로 완성 할 수 있 습 니 다.
class ArticlesController
def show
@article = Article.find(params[:id])
fresh_when :last_modified => @article.updated_at.utc, :etag => @article
end
end
다음 사용자 가 다시 방문 할 때 request header 에 있 는 If-Modified-Since 와 If-None-Match 를 비교 합 니 다.일치 하면 response body 가 생 성 되 지 않 고 304 로 돌아 갑 니 다.그러나 이렇게 하면 문제 가 발생 할 수 있 습 니 다.만약 에 저희 사이트 내 비게 이 션 에 사용자 정보 가 있다 고 가정 하면 한 사용자 가 로그 인하 지 않 은 주제 에 방문 한 다음 에 로그 인 한 후에 방문 하면 페이지 에 로그 인 되 지 않 은 상태 가 표 시 됩 니 다.또는 app 에서 글 을 방문 하여 소장 하고 다음 에 이 글 에 들 어가 면 소장 되 지 않 은 상 태 를 표시 합 니 다.이 문 제 를 해결 하 는 방법 은 매우 간단 합 니 다.사용자 와 관련 된 변 수 를 etag 의 계산 에 추가 합 니 다.
fresh_when :etag => [@article.cache_key, current_user.id]
fresh_when :etag => [@article.cache_key, current_user_favorited]
또 하나의 구 덩이 를 들 어 nginx 가 gzip 을 열 어 rails 가 실행 한 결 과 를 압축 하면 rails 가 출력 한 etag header 를 제거 할 것 이 라 고 말 했다.nginx 의 개발 자 는 rfc 규범 에 따라 proxypass 방식 처 리 는 반드시 이렇게 해 야 합 니 다(내용 이 바 뀌 었 기 때 문).그러나 저 는 개인 적 으로 그 럴 필요 가 없다 고 생각 하여 거 친 방법 으로 src/http/modules/ngx 를 직접http_gzip_filter_module.c 이 파일 에 있 는 이 줄 코드 설명 을 지우 고 nginx 를 다시 컴 파일 합 니 다.
//ngx_http_clear_etag(r);
또는 nginx 소스 코드 를 바 꾸 지 않 고 gzip 을 떨 어 뜨리 고 압축 을 Rack 미들웨어 로 처리 할 수 있 습 니 다.
config.middleware.use Rack::Deflater
controller 에 fresh 지정 하 는 것 외 에when 이외,rails 프레임 워 크 는 기본적으로 Rack::ETag middleware 를 사용 합 니 다.etag 가 없 는 response 에 etag 를 자동 으로 추가 하지만 freshwhen 에 비해 자동 etag 가 절약 할 수 있 는 것 은 클 라 이언 트 시간 일 뿐 입 니 다.서버 측은 모든 코드 를 실행 하고 curl 로 비교 합 니 다.Rack::ETag 자동 가입 etag:
curl -v http://localhost:3000/articles/1
< Etag: "bf328447bcb2b8706193a50962035619"
< X-Runtime: 0.286958
curl -v http://localhost:3000/articles/1 --header 'If-None-Match: "bf328447bcb2b8706193a50962035619"'
< X-Runtime: 0.293798
fresh_when:
curl -v http://localhost:3000/articles/1 --header 'If-None-Match: "bf328447bcb2b8706193a50962035619"'
< X-Runtime: 0.033884
2.Nginx 캐 시일부 자원 은 사용자 상태 와 상 관 없 이 많이 호출 될 수 있 으 며 변경 되 지 않 습 니 다.예 를 들 어 뉴스 app 의 목록 api,쇼핑 몰 에서 ajax 요청 분류 메뉴 는 Nginx 로 캐 시 를 하 는 것 을 고려 할 수 있 습 니 다.
주로 두 가지 실현 방법 이 있다.
A.동적 요청 정적 파일 화
rails 요청 이 완료 되면 결 과 를 정적 파일 로 저장 하고 후속 요청 은 nginx 에서 정적 파일 내용 을 직접 제공 합 니 다.afterfilter 구현:
class CategoriesController < ActionController::Base
after_filter :generate_static_file, :only => [:index]
def index
@categories = Category.all
end
def generate_static_file
File.open(Rails.root.join('public', 'categories'), 'w') do |f|
f.write response.body
end
end
end
또한 모든 분류 업데이트 시 이 파일 을 삭제 하고 캐 시가 새로 고침 되 지 않도록 해 야 합 니 다.
class Category < ActiveRecord::Base
after_save :delete_static_file
after_destroy :delete_static_file
def delete_static_file
File.delete Rails.root.join('public', 'categories')
end
end
Rails 4 전에 정적 파일 캐 시 생 성 을 처리 할 때 내 장 된 cachespage,rails 4 이후 하나의 독립 gem actionpack-pagecaching,수 동 코드 와 비교 해 보면,
class CategoriesController < ActionController::Base
caches_page :index
def update
#...
expire_page action: 'index'
end
end
서버 가 한 대 밖 에 없다 면 이 방법 은 간단 하고 실 용적 이지 만 여러 대의 서버 가 있다 면 업데이트 분 류 는 자신 만 의 서버 캐 시 를 새로 고 칠 수 있 는 문제 가 발생 할 수 있 습 니 다.nfs 로 정적 자원 디 렉 터 리 를 공유 하여 해결 하거나 두 번 째 로 해결 할 수 있 습 니 다.B.집중 캐 시 서비스 로 정적 화
우선 Nginx 가 캐 시 에 직접 접근 할 수 있 도록 해 야 합 니 다.
upstream redis {
server redis_server_ip:6379;
}
upstream ruby_backend {
server unicorn_server_ip1 fail_timeout=0;
server unicorn_server_ip2 fail_timeout=0;
}
location /categories {
set $redis_key $uri;
default_type text/html;
redis_pass redis;
error_page 404 = @httpapp;
}
location @httpapp {
proxy_pass http://ruby_backend;
}
Nginx 는 먼저 요청 한 uri 를 key 로 redis 에 가 져 옵 니 다.가 져 오지 못 하면(404)유 니 콘 에 게 전송 하여 처리 한 다음 generate 를 바 꿉 니 다.static_file 과 deletestatic_file 방법:
redis_cache.set('categories', response.body)
redis_cache.del('categories')
이렇게 하면 집중 관 리 를 제외 하고 캐 시 의 실효 시간 도 설정 할 수 있 습 니 다.실효 성 이 없 는 데 이 터 를 업데이트 할 때 새로 고침 체 제 를 처리 하지 않 고 간단하게 고정 시간 에 한 번 새로 고침 할 수 있 습 니 다.
redis_cache.setex('categories', 3.hours.to_i, response.body)
3.전체 페이지 캐 시Nginx 캐 시 는 매개 변수 자원 이나 사용자 상태 요청 을 처리 할 때 처리 하기 가 매우 어렵 습 니 다.이 럴 때 전체 페이지 캐 시 를 사용 할 수 있 습 니 다.
예 를 들 어 페이지 요청 목록 은 page 인 자 를 cache 에 추가 할 수 있 습 니 다.path:
class CategoriesController
caches_action :index, :expires_in => 1.day, :cache_path => proc {"categories/index/#{params[:page].to_i}"}
end
예 를 들 어 우 리 는 rss 출력 에 대해 8 시간 만 캐 시 해 야 합 니 다.
class ArticlesController
caches_action :index, :expires_in => 8.hours, :if => proc {request.format.rss?}
end
예 를 들 어 로그 인 하지 않 은 사용자 에 대해 우 리 는 첫 페이지 를 캐 시 할 수 있 습 니 다.
class HomeController
caches_action :index, :expires_in => 3.hours, :if => proc {!user_signed_in?}
end
4.세 션 캐 시앞의 두 가지 캐 시 에 사용 할 수 있 는 장면 이 제한 되 어 있다 면 세 션 캐 시 는 적용 성 이 가장 넓다.
장면 1:우 리 는 각 페이지 의 광고 코드 를 사용 하여 서로 다른 광 고 를 표시 해 야 합 니 다.만약 에 세 션 캐 시 를 사용 하지 않 으 면 모든 페이지 가 광고 코드 를 조회 하고 일정한 시간 을 들 여 html 코드 를 생 성 해 야 합 니 다.
- if advert = Advert.where(:name => request.controller_name + request.action_name, :enable => true).first
div.ad
= advert.content
세 션 캐 시 를 추가 하면 이 검색 을 줄 일 수 있 습 니 다.
- cache "adverts/#{request.controller_name}/#{request.action_name}", :expires_in => 1.day do
- if advert = Advert.where(:name => request.controller_name + request.action_name, :enable => true).first
div.ad
= advert.content
장면 2:글 을 읽 으 면 글 의 내용 이 비교적 오래 변 하지 않 을 수 있 습 니 다.자주 변 하 는 것 은 글 의 평론 일 수 있 습 니 다.글 의 주체 부분 에 세 션 캐 시 를 추가 할 수 있 습 니 다.
- cache "articles/#{@article.id}/#{@article.updated_at.to_i}" do
div.article
= @article.content.markdown2html
markdown 문법 을 html 로 변환 하 는 시간 을 절약 하 였 습 니 다.여기 서 글 의 마지막 업데이트 시간 을 cache key 의 일부분 으로 합 니 다.글 내용 이 바 뀌 면 캐 시 는 자동 으로 효력 을 잃 고 기본 activerecord 의 cachekey 방법 도 updatedat,당신 도 더 많은 인 자 를 추가 할 수 있 습 니 다.예 를 들 어 article 에 댓 글 수가 있 는 conter cache 는 댓 글 수 를 업데이트 할 때 글 시간 을 업데이트 하지 않 고 이 conter 도 key 의 일부분 에 추가 할 수 있 습 니 다.장면 3:복잡 한 페이지 구조의 생 성
데이터 구조 가 비교적 복잡 한 페이지 는 생 성 할 때 대량의 조회 와 html 렌 더 링 을 피 할 수 없습니다.세 션 캐 시 를 사용 하면 이 부분의 시간 을 크게 절약 할 수 있 습 니 다.우리 사이트 여행기 페이지http://chanyouji.com/trips/109123(작은 광 고 를 허용 하고 데 이 터 를 가 져 오 십시오)로 말 하면:
날씨 데이터,사진 데이터,텍스트 데이터 등 을 가 져 오 는 동시에 meta,keyword 등 seo 데 이 터 를 생 성 해 야 합 니 다.이 내용 들 은 다른 동적 내용 과 교차 되 고 세 션 캐 시 는 여러 개 로 나 눌 수 있 습 니 다.
- cache "trips/show/seo/#{@trip.fragment_cache_key}", :expires_in => 1.day do
title #{trip_name @trip}
meta name="description" content="..."
meta name="keywords" content="..."
body
div
...
- cache "trips/show/viewer/#{@trip.fragment_cache_key}", :expires_in => 1.day do
- @trip.eager_load_all
팁,트 립 대상 에 eager 를 추가 하 였 습 니 다.load_all 방법,캐 시가 명중 되 지 않 았 을 때 검색 할 때 n+1 문제 가 발생 하지 않도록 합 니 다.
def eager_load_all
ActiveRecord::Associations::Preloader.new([self], {:trip_days => [:weather_station_data, :nodes => [:entry, :notes => [:photo, :video, :audio]]]}).run
end
팁 1:조건 이 있 는 세 션 캐 시와 cachesaction 과 달리 rails 가 가지 고 있 는 세 션 캐 시 는 지원 되 지 않 습 니 다.예 를 들 어 로그 인 하지 않 은 사용자 가 세 션 캐 시 를 사용 하고 싶 지만 로그 인 사용자 가 사용 하지 않 으 면 쓰기 가 귀 찮 습 니 다.helper 를 바 꾸 면 됩 니 다.
def cache_if (condition, name = {}, cache_options = {}, &block)
if condition
cache(name, cache_options, &block)
else
yield
end
end
- cache_if !user_signed_in?, "xxx", :expires_in => 1.day do
팁 2:관련 대상 의 자동 업데이트상용 대상 updateat 시간 스탬프 는 cache key 로 서 관련 대상 에 touch 옵션 을 추가 하여 관련 대상 의 시간 스탬프 를 자동 으로 업데이트 할 수 있 습 니 다.예 를 들 어 우 리 는 글 댓 글 을 업데이트 하거나 삭제 할 때 자동 으로 업데이트 할 수 있 습 니 다.
class Article
has_many :comments
end
class Comment
belongs_to :article, :touch => true
end
5.데이터 조회 캐 시일반적으로 웹 응용 성능 병목 은 DB IO 에 나타 나 데이터 조회 캐 시 를 잘 하고 데이터 베 이 스 를 조회 하 는 횟수 를 줄 이면 전체적인 응답 시간 을 크게 향상 시 킬 수 있다.
데이터 조회 캐 시 는 2 가지 로 나 뉜 다.
A.같은 요청 주기 내의 캐 시
글 목록 을 보 여 주 는 예 를 들 어 글 제목 과 글 종 류 를 출력 합 니 다.해당 코드 는 다음 과 같 습 니 다.
# controller
def index
@articles = Article.first(10)
end
# view
- @articles.each do |article|
h1 = article.name
span = article.category.name
유사 한 sql 조회 10 개가 발생 합 니 다:
SELECT `categories`.* FROM `categories` WHERE `categories`.`id` = ?
rails 에는 query cache(https://github.com/rails/rails/blob/master/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb)가 내장 되 어 있 습 니 다.같은 요청 주기 에 update/delete/insert 작업 이 없 으 면 같은 sql 조 회 를 캐 시 합 니 다.글 유형 이 같 으 면 데이터 베 이 스 를 실제로 조회 하 는 것 은 1 번 뿐 입 니 다.문장 유형 이 다 르 면 N+1 조회 문제(흔히 볼 수 있 는 성능 병목)가 발생 한다.rails 가 추천 하 는 해결 방법 은 Eager Loading Associations(http://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations)이다.
def index
@articles = Article.includes(:category).first(10)
end
검색 어
SELECT `categories`.* FROM `categories` WHERE `categories`.`id` in (?,?,?...)
B.크로스 요청 주기 캐 시같은 요청 주기 캐 시가 가 져 오 는 성능 최 적 화 는 매우 제한 적 이다.많은 경우 에 우 리 는 크로스 요청 주기 캐 시 를 사용 하여 자주 사용 하 는 데이터(예 를 들 어 User model)캐 시 를 사용 해 야 한다.active record 에 있어 통 일 된 조회 인 터 페 이 스 를 이용 하여 fetch cache 를 사용 하고 callback 을 이용 하여 expire cache 를 사용 하면 쉽게 실현 할 수 있 으 며 기 존의 gem 도 사용 할 수 있다.
예 를 들 면 idenitycache ( https://github.com/Shopify/identity_cache )
class User < ActiveRecord::Base
include IdentityCache
end
class Article < ActiveRecord::Base
include IdentityCache
cached_belongs_to :user
end
#
User.fetch(1)
Article.find(2).user
이 gem 의 장점 은 코드 가 간단 하고 cache 설정 이 유연 하 며 확장 이 편리 하 다 는 것 이다.단점 은 서로 다른 조회 방법 명(fetch)과 추가 적 인 관계 정 의 를 사용 해 야 한 다 는 것 이다.데이터 캐 시 없 는 애플 리 케 이 션 에 빈 틈 없 이 캐 시 기능 을 추가 하려 면@hooopo 가 만 든 second 를 추천 합 니 다.level_cache ( https://github.com/hooopo/second_level_cache ) 。
class User < ActiveRecord::Base
acts_as_cached(:version => 1, :expires_in => 1.week)
end
\#find 방법 을 사용 하면 캐 시 에 명중 합 니 다.User.find(1)
\#다른 belongs 를 추가 로 사용 할 필요 가 없습니다정의
Article.find(2).user
실현 원 리 는 active record 바 텀 arel sql ast 처리(https://github.com/hooopo/second_level_cache/blob/master/lib/second_level_cache/arel/wheres.rb)를 확장 하 는 것 이다.
틈새 없 이 접속 하 는 것 이 장점 입 니 다.확장 이 어렵 고 소량의 필드 만 가 져 오 는 조회 에 캐 시 할 수 없 는 것 이 단점 입 니 다.
6.데이터베이스 캐 시
편집 중
이 6 가지 캐 시 는 클 라 이언 트 에서 서버 까지 서로 다른 위치 에 분포 되 어 있 으 며 절약 할 수 있 는 시간 도 많 고 적 게 순서대로 배열 되 어 있다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
linux2에 nginx 설치설치 가능한 nginx를 확인하고, 해당 nginx를 설치한다. localhost 혹은 해당 ip로 접속을 하면 nginx 화면을 볼 수 있다....
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.