ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • walkerholic(Springboot + React) 프로젝트 ③ 성능개선하기
    학습로그 2022. 6. 3. 05:41

     

    이번엔 was서버에서 redis 캐시, 외부 API 비동기, index 설계 및 리버스프록시에서의  gzip, cache, http2, 부하분산 등의 적용을 통하여 성능을 개선시킨다. 

     

     

    성능개선 ② redis 캐시 및 @Async, index 설계의 적용

    1) Redis 캐시 

    Redis 캐시를 적용하기 위한 기본 내용은 이전의 블로그에서 작성해두었다. 

    https://dodop-blog.tistory.com/321

     

    화면 응답 개선하기

    이번엔 화면응답속도를 개선하는 방법에 대해 알아보자. 화면 응답 속도를 개선하는 방법에는 인터넷구간 성능 개선을 통한 방법과 데이터 조회 성능 개선의 방법이 존재한다. 인터넷 구간 성

    dodop-blog.tistory.com

    메인페이지에서 로딩하는 product와 post의 service 메소드에 @Cacheable을 적용해준다. 

        @Cacheable(value = "posts", key = "{#page, #sort}")
        public SimplePostResponses getHomePosts(Integer page, String sort) {
        }
        
        @Cacheable(value = "products", key = "{#page, #sort, #category, #keyword}")
        public ProductResponses getProducts(Integer page, String sort, String category, String keyword) {
        }

    추가로 application-prod.properties에 다음과 같이 cache 저장 기간을 설정해주었다. 

    spring.cache.type=redis
    spring.redis.host=localhost
    spring.redis.port=6379
    spring.cache.redis.defaultExpireTime=3600
    spring.cache.redis.expireTime.products=3600
    spring.cache.redis.expireTime.posts=3600

     

     

    2) 외부 API에 @Async 적용

    main페이지에서 사용되는 api는 아니지만 Notification을 보낼때 외부 API를 사용하는 메소드에서 처리를 기다리지 않도록 다음과 같이 @Async 어노테이션을 달아주었다. 

        @Override
        @Async
        public void sendCreateOrderNotification(Order order, User user) {
        }

     

    3) Index 설계

    이 부분 또한 메인페이지에서 적용되는 부분은 아니지만 상품검색에 사용되는 이름, 카테고리 및 작성글 검색시 사용되는 글제목에 다음과 같이 인덱스를 생성하여 검색시 Index Range Scan을 이루어 속도가 개선되도록 하였다. 

    @Entity
    @Table(name = "product",  indexes = {
        @Index(name = "idx_name", columnList = "name"),
        @Index(name = "idx_category_name", columnList = "category, name")
    })
    @Getter
    @NoArgsConstructor
    public class Product extends BaseTimeEntity {}
    
    @Entity
    @Table(name = "post", indexes = @Index(name = "idx_title", columnList = "title"))
    @NoArgsConstructor
    public class Post extends BaseTimeEntity {}

     

    여기까지 적용하였을 때 테스트 결과는 다음과 같다. 

    https://www.webpagetest.org/result/220602_AiDc12_8B3/

     

    WebPageTest Performance Test Results

    Check out these performance test results on WebPageTest.org...

    www.webpagetest.org

     

    1) smoke 테스트 적용 

     

    2) load 테스트 적용

     

     

    3) stress 테스트 적용

     

    성능개선 reverse proxy의 gzip 설정과 cache 설정 추가 

    이번엔 reverse proxy에서 다음과 같이 gzip 설정과 cache 설정을 추가해주었다. 

    ## nginx.conf
    
    events {}
    
    http {
      upstream app {
        server 172.17.0.1:8080;
      }
    
      # Redirect all traffic to HTTPS
      server {
        listen 80;
        return 301 https://$host$request_uri;
      }
    
      ## Proxy 캐시 파일 경로, 메모리상 점유할 크기, 캐시 유지기간, 전체 캐시의 최대 크기 등 설정
      proxy_cache_path /tmp/nginx levels=1:2 keys_zone=mycache:10m inactive=10m max_size=200M;
    
      ## 캐시를 구분하기 위한 Key 규칙
      proxy_cache_key "$scheme$host$request_uri $cookie_user";
    
    
      server {
        listen 443 ssl http2;
        ssl_certificate /etc/letsencrypt/live/walkerholic.n-e.kr/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/walkerholic.n-e.kr/privkey.pem;
    
        # Disable SSL
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    
        # 통신과정에서 사용할 암호화 알고리즘
        ssl_prefer_server_ciphers on;
        ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5;
    
        # Enable HSTS
        # client의 browser에게 http로 어떠한 것도 load 하지 말라고 규제합니다.
        # 이를 통해 http에서 https로 redirect 되는 request를 minimize 할 수 있습니다.
        add_header Strict-Transport-Security "max-age=31536000" always;
    
        # SSL sessions
        ssl_session_cache shared:SSL:10m;
        ssl_session_timeout 10m;
    
        gzip on; ## http 블록 수준에서 gzip 압축 활성화
        gzip_disable "msie6";
        gzip_comp_level 9;
        gzip_proxied any;
        gzip_vary on;
        gzip_types text/plain text/css text/js text/xml text/javascript application/json application/x-javascript application/javascript application/xml application/rss+xml image/svg+xml application/vnd.ms-fontobject application/x-font-ttf font/opentype;
    
        location / {
          proxy_pass http://app;
        }
    
        location ~* \.(?:css|js|gif|png|jpg|jpeg)$ {
          proxy_pass http://app;
    
          ## 캐시 설정 적용 및 헤더에 추가
          # 캐시 존을 설정 (캐시 이름)
          proxy_cache mycache;
          # X-Proxy-Cache 헤더에 HIT, MISS, BYPASS와 같은 캐시 적중 상태정보가 설정
          add_header X-Proxy-Cache $upstream_cache_status;
          # 200 302 코드는 20분간 캐싱
          proxy_cache_valid 200 302 10m;    
          # 만료기간을 1 달로 설정
          expires 1M;
          # access log 를 찍지 않는다.
          access_log off;
        }
      }
    }

     

    테스트 결과 다음과 같이 향상된 결과를 확인할 수 있었다. 

    https://www.webpagetest.org/result/220602_AiDcBB_A86/

     

    WebPageTest Performance Test Results

    Check out these performance test results on WebPageTest.org...

    www.webpagetest.org

     

    1) smoke 테스트 적용 

     

    2) load 테스트 적용

     

    3) stress 테스트 적용

    주고 받는 데이터의 양이 줄어드는 결과를 보여주기는 하였으나 http_req_duration은 변함없이 지속되고 있는 것을 확인할 수 있다. 

     

     

    성능개선  DB replication 적용 및 Flyway로 버전 관리 추가 

    이제 Master DB와 Slave DB를 구성하여 post, delete, put 등의 정보변경 요청이 올때는 master DB를 이용하고 ReadOnly = true 옵션이 적용된 get 요청은 Slave DB를 이용하도록 하여 데이터베이스의 요청 부하를 줄이도록 하였다. 이때, Flyway(DDL을 통한 데이터베이스 형상관리)를 이용하여 데이터베이스의 버전이 관리되도록하여 추후 리팩토링이 이루어져도 기존의 데이터 베이스에 안전하게 변경사항을 반영할 수 있도록 해보자.

     

    먼저 Flyway적용을 위해 dependency를 추가하자. 

    여기서 flway-mysql 옵션은 최신 버전의 flyway를 이용할 경우 mysql 8.0버전이 상호적용되지 않아 추가해주었다. 

    		<dependency>
    			<groupId>org.flywaydb</groupId>
    			<artifactId>flyway-core</artifactId>
    			<version>8.5.11</version>
    		</dependency>
    
    		<dependency>
    			<groupId>org.flywaydb</groupId>
    			<artifactId>flyway-mysql</artifactId>
    			<version>8.5.12</version>
    		</dependency>
    	</dependencies>

     

    배포 설정파일에 다음과 같이 flyway 옵션을 추가해준다. 

    #flyway
    spring.flyway.enabled=true
    spring.flyway.baseline-on-migrate=true
    spring.flyway.baseline-version=2

     

    여기서 프로젝트에 이미 데이터가 담겨있기 때문에 빈 파일의 V1__init.sql 파일을 작성해주었다. 

    resources>db>migration>V1__init.sql 파일을 생성해준다. 

     

     

     

    이제 DB replication을 진행해보자. 

    먼저 Master 서버에서 다음과 같이 진행해준다. 

    $ mysql -u root -p
    Enter password: 
    
    ## 복제용 사용자 생성 
    mysql> create user 'replication_user'@'%' identified with mysql_native_password by '비밀번호';
    Query OK, 0 rows affected (0.04 sec)
    
    ## 복제용 사용자로 지정 
    mysql> grant replication slave on *.* to 'replication_user'@'%' ;
    Query OK, 0 rows affected (0.00 sec)
    
    ## 사용자 생성 확인 
    mysql> use mysql ;
    mysql> select user, host from user;
    +------------------+-----------+
    | user             | host      |
    +------------------+-----------+
    | replication_user | %         |
    | user             | %         |
    | debian-sys-maint | localhost |
    | mysql.infoschema | localhost |
    | mysql.session    | localhost |
    | mysql.sys        | localhost |
    | root             | localhost |
    +------------------+-----------+
    7 rows in set (0.00 sec)
    
    ## 권한 반영 
    mysql> flush privileges;
    Query OK, 0 rows affected (0.00 sec)
    mysql> exit
    Bye
    
    ## Master DB 설정 (해당 설정 주석 해제)
    $ cd /etc/mysql/mysql.conf.d
    $ sudo vi mysqld.cnf
    server-id = 1
    log_bin = /var/log/mysql/mysql-bin.log
    
    ## 서버 재시작 
    $ sudo systemctl restart mysql
    
    ## 기존에 생성해둔 백업 데이터 복사해준다. (Slave 서버에 옮겨줄 것이다)
    $ cat backup.sql
    
    ## Master 상태 확인하기 
    $ mysql -u root -p;
    Enter password: 
    mysql> show master status;
    +------------------+----------+--------------+------------------+-------------------+
    | File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
    +------------------+----------+--------------+------------------+-------------------+
    | mysql-bin.000001 |      157 |              |                  |                   |
    +------------------+----------+--------------+------------------+-------------------+
    1 row in set (0.00 sec)
    
    mysql> exit
    Bye

     

     

    Slave DB 용 EC2를 만들고 다음과 같이 진행해준다. 

    ## mysql 설치 
    $ sudo apt-get update
    $ sudo apt-get install mysql-server
    $ sudo ufw allow mysql
    $ sudo systemctl start mysql
    $ sudo systemctl enable mysql
    
    ## mysql 접속
    $ sudo /usr/bin/mysql -u root -p 
    Enter password: 
    
    ## 데이터베이스 생성 
    mysql> use mysql;
    mysql> create database walkerholic;
    mysql> show databases;
    +--------------------+
    | Database           |
    +--------------------+
    | information_schema |
    | mysql              |
    | performance_schema |
    | sys                |
    | walkerholic.       |
    +--------------------+
    5 rows in set (0.00 sec)
    
    ## 프로그램에서 데이터베이스 연결시 사용할 사용자 생성 및 권한 부여 
    mysql> create user 'user'@'%' identified by '비밀번호';
    mysql> grant all privileges on walkerholic.* to 'user'@'%';
    Query OK, 0 rows affected (0.01 sec)
    mysql> flush privileges;
    Query OK, 0 rows affected (0.01 sec)
    
    ## Slave 데이터 베이스로 설정
    mysql> set global server_id = 2;
    Query OK, 0 rows affected (0.00 sec)
    
    ## Master 연결  
    mysql> CHANGE MASTER TO MASTER_HOST='[Master private ip]', MASTER_PORT=3306, MASTER_USER='replication_user', MASTER_PASSWORD='비밀번호', MASTER_LOG_FILE='mysql-bin.000001', MASTER_LOG_POS=157;
    Query OK, 0 rows affected, 9 warnings (0.04 sec)
    
    ## Slave 실행하고 상태 확인 
    mysql> start slave;
    Query OK, 0 rows affected, 1 warning (0.01 sec)
    mysql> show slave status\g;
    +----------------------------------+-------------+------------------+-------------+---------------+------------------+---------------------+---------------------------------+---------------+-----------------------+------------------+-------------------+-----------------+---------------------+--------------------+------------------------+-------------------------+-----------------------------+------------+------------+--------------+---------------------+-----------------+-----------------+----------------+---------------+--------------------+--------------------+--------------------+-----------------+-------------------+----------------+-----------------------+-------------------------------+---------------+---------------+----------------+----------------+-----------------------------+------------------+--------------------------------------+-------------------------+-----------+---------------------+----------------------------------------------------------+--------------------+-------------+-------------------------+--------------------------+----------------+--------------------+--------------------+-------------------+---------------+----------------------+--------------+--------------------+------------------------+-----------------------+-------------------+
    | Slave_IO_State                   | Master_Host | Master_User      | Master_Port | Connect_Retry | Master_Log_File  | Read_Master_Log_Pos | Relay_Log_File                  | Relay_Log_Pos | Relay_Master_Log_File | Slave_IO_Running | Slave_SQL_Running | Replicate_Do_DB | Replicate_Ignore_DB | Replicate_Do_Table | Replicate_Ignore_Table | Replicate_Wild_Do_Table | Replicate_Wild_Ignore_Table | Last_Errno | Last_Error | Skip_Counter | Exec_Master_Log_Pos | Relay_Log_Space | Until_Condition | Until_Log_File | Until_Log_Pos | Master_SSL_Allowed | Master_SSL_CA_File | Master_SSL_CA_Path | Master_SSL_Cert | Master_SSL_Cipher | Master_SSL_Key | Seconds_Behind_Master | Master_SSL_Verify_Server_Cert | Last_IO_Errno | Last_IO_Error | Last_SQL_Errno | Last_SQL_Error | Replicate_Ignore_Server_Ids | Master_Server_Id | Master_UUID                          | Master_Info_File        | SQL_Delay | SQL_Remaining_Delay | Slave_SQL_Running_State                                  | Master_Retry_Count | Master_Bind | Last_IO_Error_Timestamp | Last_SQL_Error_Timestamp | Master_SSL_Crl | Master_SSL_Crlpath | Retrieved_Gtid_Set | Executed_Gtid_Set | Auto_Position | Replicate_Rewrite_DB | Channel_Name | Master_TLS_Version | Master_public_key_path | Get_master_public_key | Network_Namespace |
    +----------------------------------+-------------+------------------+-------------+---------------+------------------+---------------------+---------------------------------+---------------+-----------------------+------------------+-------------------+-----------------+---------------------+--------------------+------------------------+-------------------------+-----------------------------+------------+------------+--------------+---------------------+-----------------+-----------------+----------------+---------------+--------------------+--------------------+--------------------+-----------------+-------------------+----------------+-----------------------+-------------------------------+---------------+---------------+----------------+----------------+-----------------------------+------------------+--------------------------------------+-------------------------+-----------+---------------------+----------------------------------------------------------+--------------------+-------------+-------------------------+--------------------------+----------------+--------------------+--------------------+-------------------+---------------+----------------------+--------------+--------------------+------------------------+-----------------------+-------------------+
    | Waiting for source to send event | 172.31.0.14 | replication_user |        3306 |            60 | mysql-bin.000001 |                 157 | ip-172-31-0-56-relay-bin.000002 |           326 | mysql-bin.000001      | Yes              | Yes               |                 |                     |                    |                        |                         |                             |          0 |            |            0 |                 157 |             545 | None            |                |             0 | No                 |                    |                    |                 |                   |                |                     0 | No                            |             0 |               |              0 |                |                             |                1 | 6c169aed-e3ef-11ec-b1ab-020fcea173ea | mysql.slave_master_info |         0 |                NULL | Replica has read all relay log; waiting for more updates |              86400 |             |                         |                          |                |                    |                    |                   |             0 |                      |              |                    |                        |                     0 |                   |
    +----------------------------------+-------------+------------------+-------------+---------------+------------------+---------------------+---------------------------------+---------------+-----------------------+------------------+-------------------+-----------------+---------------------+--------------------+------------------------+-------------------------+-----------------------------+------------+------------+--------------+---------------------+-----------------+-----------------+----------------+---------------+--------------------+--------------------+--------------------+-----------------+-------------------+----------------+-----------------------+-------------------------------+---------------+---------------+----------------+----------------+-----------------------------+------------------+--------------------------------------+-------------------------+-----------+---------------------+----------------------------------------------------------+--------------------+-------------+-------------------------+--------------------------+----------------+--------------------+--------------------+-------------------+---------------+----------------------+--------------+--------------------+------------------------+-----------------------+-------------------+
    1 row in set, 1 warning (0.00 sec)
    
    mysql> show slave status\G;
        Slave_IO_Running: Yes
        Slave_SQL_Running: Yes
    ## 만약 여기서 SQL_Running이 Yes가 아니라면 다음 실행 
    mysql> stop slave;
    mysql> SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1;
    mysql> start slave;
    
    ## mysqld 설정(해당 주석 해제하고 server-id = 2 설정)
    $ cd /etc/mysql/mysql.conf.d
    $ sudo vi mysqld.cnf
    	binding = 0.0.0.0
        server-id = 2
        log_bin = /var/log/mysql/mysql-bin.log
    $ sudo systemctl restart mysql
    
    ## 백업 DB 반영해주기
    $ mysql -u root -p -D with_employee < backup.sql;
    Enter password: 
    
    ## DB 반영 확인 
    mysql> use walkerholic;
    mysql> show tables;
    
    $ sudo systemctl restart mysql

     

    Slave 설정이 완료되면 Master에서 다음과 같이 프로세스를 확인할 수 있다. 

    ## 데이터 주고 받는 프로세스 확인 
    mysql> show processlist\g
    +----+------------------+------------------------------------------------------+---------------+-------------+------+-----------------------------------------------------------------+------------------+
    | Id | User             | Host                                                 | db            | Command     | Time | State                                                           | Info             |
    +----+------------------+------------------------------------------------------+---------------+-------------+------+-----------------------------------------------------------------+------------------+
    |  5 | event_scheduler  | localhost                                            | NULL          | Daemon      | 1409 | Waiting on empty queue                                          | NULL             |
    |  9 | root             | localhost                                            | NULL          | Query       |    0 | init                                                            | show processlist |
    | 24 | replication_user | ip-172-31-0-56.ap-northeast-2.compute.internal:      | NULL          | Binlog Dump |   29 | Source has sent all binlog to replica; waiting for more updates | NULL             |
    +----+------------------+------------------------------------------------------+---------------+-------------+------+-----------------------------------------------------------------+------------------+
    13 rows in set (0.00 sec)
    mysql> show processlist\G
    *************************** 9. row ***************************
         Id: 25
       User: replication_user
       Host: ip-172-31-0-56.ap-northeast-2.compute.internal:
         db: NULL
    Command: Binlog Dump
       Time: 284
      State: Source has sent all binlog to replica; waiting for more updates
       Info: NULL

     

     

    프로그램에 설정을 추가해준다. 이제 ReadOnly=true 트랜잭션에 대해서 Slave DB로 요청을 전달한다. 

    public class ReplicationRoutingDataSource extends AbstractRoutingDataSource {
        public static final String DATASOURCE_KEY_MASTER = "master";
        public static final String DATASOURCE_KEY_SLAVE = "slave";
    
        @Override
        protected Object determineCurrentLookupKey() {
            boolean isReadOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly();
            return (isReadOnly)
                ? DATASOURCE_KEY_SLAVE
                : DATASOURCE_KEY_MASTER;
        }
    }
    @Configuration
    @EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class})
    @EnableTransactionManagement
    @EnableJpaRepositories(basePackages = {"com.yunhalee.walkerholic"})
    class DataBaseConfig {
    
        @Bean
        @ConfigurationProperties(prefix = "spring.datasource.hikari.master")
        public DataSource masterDataSource() {
            return DataSourceBuilder.create().type(HikariDataSource.class).build();
        }
    
        @Bean
        @ConfigurationProperties(prefix = "spring.datasource.hikari.slave")
        public DataSource slaveDataSource() {
            return DataSourceBuilder.create().type(HikariDataSource.class).build();
        }
    
        @Bean
        public DataSource routingDataSource(@Qualifier("masterDataSource") DataSource master,
            @Qualifier("slaveDataSource") DataSource slave) {
            ReplicationRoutingDataSource routingDataSource = new ReplicationRoutingDataSource();
    
            HashMap<Object, Object> sources = new HashMap<>();
            sources.put(DATASOURCE_KEY_MASTER, master);
            sources.put(DATASOURCE_KEY_SLAVE, slave);
    
            routingDataSource.setTargetDataSources(sources);
            routingDataSource.setDefaultTargetDataSource(master);
    
            return routingDataSource;
        }
    
        @Primary
        @Bean
        public DataSource dataSource(@Qualifier("routingDataSource") DataSource routingDataSource) {
            return new LazyConnectionDataSourceProxy(routingDataSource);
        }
    }

     

     

    실행 설정 파일에 다음과 같이 DB replication 설정을 추가해준다. 

    spring.datasource.hikari.master.username=user
    spring.datasource.hikari.master.password=ThisIsUser1!
    spring.datasource.hikari.master.jdbc-url=jdbc:mysql://172.31.0.13:3306/walkerholic?useSSL=false&useUnicode=yes&characterEncoding=UTF-8&allowPublicKeyRetrieval=true&serverTimezone=UTC
    
    spring.datasource.hikari.slave.username=user
    spring.datasource.hikari.slave.password=ThisIsUser1!
    spring.datasource.hikari.slave.jdbc-url=jdbc:mysql://172.31.0.5:3306/walkerholic?useSSL=false&useUnicode=yes&characterEncoding=UTF-8&allowPublicKeyRetrieval=true&serverTimezone=UTC

     

     

     

    성능개선 nginx로 로드밸런싱 적용

    이번엔 네트워크 속도를 개선하기 위해서 nginx의 로드밸런싱을 이용한 부하분산을 적용시켜보도록 하자. 

    ec2에 새로운 public용 ec2를 생성하고 리버스 프록시의 적용없이 redis 캐시만 도커로 실행한 채 서버를 배포해준다.

    nginx.conf는 다음과 같이 수정하여 부하분산을 적용하도록 한다. 

    events {}
    
    http {
      upstream app {
        least_conn; ## 현재 connections이 가장 적은 server로 reqeust를 분배
        server 172.17.0.1:8080 max_fails=3 fail_timeout=3s;
        server 3.35.230.114:8080 max_fails=3 fail_timeout=3s;
      }
    
      # Redirect all traffic to HTTPS
      server {
        listen 80;
        return 301 https://$host$request_uri;
      }
    
      ## Proxy 캐시 파일 경로, 메모리상 점유할 크기, 캐시 유지기간, 전체 캐시의 최대 크기 등 설정
      proxy_cache_path /tmp/nginx levels=1:2 keys_zone=mycache:10m inactive=10m max_size=200M;
    
      ## 캐시를 구분하기 위한 Key 규칙
      proxy_cache_key "$scheme$host$request_uri $cookie_user";
      
    
      server {
        listen 443 ssl http2;
        ssl off;
        ssl_certificate /etc/letsencrypt/live/walkerholic.n-e.kr/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/walkerholic.n-e.kr/privkey.pem;
    
        # Disable SSL
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    
        # 통신과정에서 사용할 암호화 알고리즘
        ssl_prefer_server_ciphers on;
        ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5;
    
        # Enable HSTS
        # client의 browser에게 http로 어떠한 것도 load 하지 말라고 규제합니다.
        # 이를 통해 http에서 https로 redirect 되는 request를 minimize 할 수 있습니다.
        add_header Strict-Transport-Security "max-age=31536000" always;
    
        # SSL sessions
        ssl_session_cache shared:SSL:10m;
        ssl_session_timeout 10m;
    
      
        gzip on; ## http 블록 수준에서 gzip 압축 활성화
        gzip_disable "msie6";
        gzip_comp_level 9;
        gzip_proxied any;
        gzip_vary on;
        gzip_types text/plain text/css text/js text/xml text/javascript application/json application/x-javascript application/javascript application/xml application/rss+xml image/svg+xml application/vnd.ms-fontobject application/x-font-ttf font/opentype;
    
        location / {
          proxy_pass http://app;
        }
    
        location ~* \.(?:css|js|gif|png|jpg|jpeg)$ {
            proxy_pass http://app;
      
            ## 캐시 설정 적용 및 헤더에 추가
            # 캐시 존을 설정 (캐시 이름)
            proxy_cache mycache;
            # X-Proxy-Cache 헤더에 HIT, MISS, BYPASS와 같은 캐시 적중 상태정보가 설정
            add_header X-Proxy-Cache $upstream_cache_status;
            # 200 302 코드는 20분간 캐싱
            proxy_cache_valid 200 302 10m;    
            # 만료기간을 1 달로 설정
            expires 1M;
            # access log 를 찍지 않는다.
            access_log off;
        }
        
      }
    }

     

    이제 테스트를 진행해보자. 

     

    1) smoke 테스트 적용 

     

    2) load 테스트 적용

     

    3) stress 테스트 적용

     

     

    속도가 눈에 띄게 개선된 것을 확인할 수 있었다! 다시 WebPageTest로 다음과 같은 결과를 확인할 수 있었다. 

    https://www.webpagetest.org/result/220603_BiDcCA_9ZJ/

     

     

     

     

     

     

Designed by Tistory.