본문 바로가기
Web/Node.js

주기적으로 api 요청하기 (중간 서버의 역할) (공공데이터포털 기상청 단기예보)

by 가나닩 2024. 10. 17.

서버에 API 요청을 할때는 성능 저하를 고려해야한다. 예를들어 아주 방대한 양의 데이터를 여러 조건이나 필터에 의해 자주 액세스하고 주고 받아야할때는 그 데이터를 어디에 저장할지, 어디에서 불러와서 필터링은 어디에서 진행할지 등을 고려하게 된다. 데이터를 다루는 방식에 따라 서버 및 클라이언트의 부하, 속도저하에 차이가 발생하기 때문이다.

 

 

공공데이터 포털의 기상청 단기예보 데이터는 3시간을 간격으로 하여 요청한 시간을 기준으로 약 3일간의 일기예보를 제공한다. 제공되는 데이터는 시간별로 강수, 기온, 습도, 풍속 등 아주 다양한 정보를 제공하기때문에 꽤 많은 자료가 들어있다. 이러한 자료를 클라이언트에서 요청할때마다 받아오게 되면 공공데이터를 제공하는 서버에도 부담이 가며 수많은 데이터를 처리해야하는 클라이언트 쪽에도 큰 부하가 발생할 수 있다.

 

3시간 간격으로 제공되는 기상청 단기예보 데이터

 

이러한 한계를 어느정도 극복하기 위해 중간 서버를 만들었다.

 

 

1. 중간서버

중간서버(node.js의 express로 구현)를 사용하면 여러가지 장단점이 있다.

 

• 장점

  • 데이터 가공 : 외부 API에서 받은 데이터를 전처리 하여 클라이언트에 제공할 수 있다. 클라이언트 측에서 모든 데이터를 연산하면 부담이 커지는데 이를 어느정도 해소할 수 있다.
  • 데이터 캐싱 : 외부 API를 운영하는 서버도 방대한 데이터를 자주 제공하게 되면 부담이 될 수 있다. 보통은 이를 방지하기 위해 호출 횟수에 제한을 둔다. 데이터를 주기적으로 중간 서버에 캐싱(저장)하여 사용하면 외부 서버의 부하도 줄이면서 호출 횟수 제한의 영향을 비교적 덜 받을 수 있다. 이는 외부 API를 이용할때 뿐 아니라 DB나 추가서버를 운용할때도 마찬가지이다.
  • 보안 : 외부 API 호출에는 보통 서비스키가 필요하다. 이는 API를 이용하는 곳이 인증과 함께 개별로 발급받는 키 이므로 민감한 정보이다. 클라이언트에서 API를 직접 호출하게 되면 서비스키가 노출될 수 있다. 중간서버를 두어 외부 API 호출을 모두 처리하게 하면 서비스키 등의 민감한 정보를 숨길 수 있다.

• 단점

  • 추가적인 서버 운용 : 소규모 개인 프로젝트가 아닌 대규모 프로젝트를 진행할때는 중간서버가 늘어날수록 당연히 서버 운용비용이 늘어나고 각 서버들의 부하도 따로 관리해주어야 한다.
  • API 호출 지연 : 중간다리 역할의 서버가 존재하므로 클라이언트에서 특정 데이터를 요청했을때 비교적 시간이 오래 걸릴 수 있다. 이는 캐싱을 통해 어느정도 해소할 수 있다.

 

이 글에서는 데이터 캐싱에 대해 자세히 다룬다.

 

 

 

2. 데이터 캐싱

데이터를 캐싱하는 방식은 서버와 클라이언트 양쪽에게 성능상의 이점을 가져다준다. 특히 단기예보 데이터처럼 일정 시간을 기준으로 갱신되는 데이터는 갱신 시기에 맞춰 서버에 캐싱하기 매우 좋다.

더보기
const cron = require("node-cron");
require("dotenv").config();
const path = require("path");
const axios = require("axios");
const fs = require("fs");

// 모든 시간을 기준 시간으로 변경함 (2,5,8,11,14,17,20,23)
function groupByThreeHours(hours) {
    if (hours === 0 || hours === 1 || hours === 23) {
        return 23;
    }
    return Math.floor((hours + 1) / 3) * 3 - 1;
}

const fetchWeatherData = async () => {
    // API 호출을 위한 날짜 및 시간 변수 
    const time = new Date();
    const year = time.getFullYear().toString();
    const month = (time.getMonth() + 1).toString().padStart(2, "0");
    const day = time.getDate().toString().padStart(2, "0");
    const hour = time.getHours();
    const convertedHour = groupByThreeHours(hour).toString().padStart(2, "0");
    const nowDate = year + month + day;

    try {
        const response = await axios.get(
            `API 호출 URL`
        );

        // json 파일을 캐싱(저장) 하기위한 경로 지정
        const filePath = path.join(__dirname, "..", "json", "3daysWeatherData.json");

        // fs를 활용해 객체 데이터를 json 파일로 저장
        await fs.promises.writeFile(filePath, JSON.stringify(response.data, null, 2));

        // console에 json파일이 저장된 기준 시간을 표시
        console.log(`Success to save weather data : ${year}.${month}.${day} ${convertedHour}시`);
    } catch (error) {
        console.error("Failed to fetch weather data", error);
    }
};

const scheduleTask = () => {
    // 3시간 간격 각 11분마다 실행 (API 제공시간이 3시간 간격 각 10분마다 제공됨)
    cron.schedule("11 2,5,8,11,14,17,20,23 * * *", fetchWeatherData);
};

module.exports = scheduleTask;

 

2-1. fs를 이용한 파일 저장

// json 파일을 캐싱(저장) 하기위한 경로 지정
const filePath = path.join(__dirname, "..", "json", "3daysWeatherData.json");

// fs를 활용해 객체 데이터를 json 파일로 저장
await fs.promises.writeFile(filePath, JSON.stringify(response.data, null, 2));

 

파일 저장에 필요한것은 저장할 경로데이터이다.

  • path.join : 현재경로(__dirname)에서 상위폴더("..")로 이동한뒤 json폴더("json")로 이동하여 3daysWeatherData.json으로 파일을 저장하라는 의미이다. 반점을 추가하여 원하는만큼 경로를 추가하면 된다.
  • fs.writeFile : 파일을 생성할 수 있다. 저장할 경로와 데이터를 인자로 받으며 객체로 받은 데이터는 JSON 파일로 변환하여 저장하였다.

 

2-2. cron을 이용한 스케줄러

const scheduleTask = () => {
    // 3시간 간격 각 11분마다 실행 (API 제공시간이 3시간 간격 각 10분마다 제공됨)
    cron.schedule("11 2,5,8,11,14,17,20,23 * * *", fetchWeatherData);
};

 

cron은 특정 작업을 정해둔 시간에 맞춰 실행하는 기능을 한다.

  • 첫번째 인자 : 문자열로 "분 시 일 월 요일" 이다. 2,5,8,11,14,17,20,23시 11분 마다 실행하라는 의미이다. 사용하지 않는 부분은 *로 생략하면 되며 경우에 따라 초단위를 사용할수도 있다.
  • 두번째 인자 : 지정된 시간마다 실행할 내용을 넣으면 된다.

 

 

3. 결론

중간 서버에서는 앞서 말했듯이 데이터 가공, 캐싱을 통한 부하 관리와 보안의 측면에서 유리할 수 있다. 작성한 코드는 파일저장만을 담당하는 코드이지만 데이터를 가공하여 저장하도록 코드를 수정할수도 있다.

DB와 서버, 클라이언트의 부하를 예측하고 잘 분배하면 보안과 성능에서 여러가지 이점을 가져올 수 있을것이다.

'Web > Node.js' 카테고리의 다른 글

REST API & RESTful  (0) 2024.05.04
package.json, package-lock.json의 구조와 역할  (0) 2024.04.13