개발/AWS

Athena

캐리캐리 2021. 12. 16. 13:00

Athena는 무엇이고  왜 사용할까요 

AWS를 이용하게 되면 S3에 로그 파일도 저장하고 기타 여러 가지 정보를 저장합니다.

이렇게 저장된 정보를 Amazon Athena를 통해 조회를 할 수 있습니다. 

Athena는 페이스북이 개발한 presto라는 엔진을 사용하는데 이유는 .. 아직 잘 모르겠는데

일반 RDB보다 속도가 대략 10배 정도 빠릅니다.

 

사용법은 

presto가 다른 mysql ,oracle db와 같이 안시쿼리를 지원하므로 기존과 동일하게 사용할 수 있습니다. 

다만 다른것이 아래와 같이 파티션으로 년, 월 , 일을 두어 특정 일자로 조회를 해야합니다. 

(구성에 따라 다를 수 있습니다. ) 

또한 문법적으로 살짝 다른 부분들이 있습니다. 

 

예를들면 mysql의 IFNULL = oracle의 decode = athena의 COALESCE이 있습니다. 

 

구현부를 만들어보겠습니다. 

저 같은 경우 mybatis와 연결을 하였으며 yml파일 내 관련 설정값을 불러와서 Config를 구성하였습니다. 

또한 마이바티스 내 config파일에 등록한것 외에도 모델 , 앨리어스 애노테이션으로 등록된 것을  세션 팩토리에 추가하였습니다. 

@Configuration
@EnableTransactionManagement
@MapperScan(
    basePackages = {"패키지"},
    annotationClass = AthenaDao.class, // AthenaDao 어노테이션이 붙은 DAO만 이 데이터소스를 사용한다.
    sqlSessionFactoryRef = "athenaSqlSessionFactory",
    sqlSessionTemplateRef = "athenaSqlSessionTemplate"
    
)
@RequiredArgsConstructor
public class AthenaConfig {

    private final ApplicationContext applicationContext;

    /*
    *데이터 소스를 만들기 위해 커넥션풀 프로퍼티 객체를 반환하는 빈 선언
    * prefix로 시작하는 값 주입
    * */
    @Bean(name = {"athenaDsConnectionProperties"})
    @ConfigurationProperties(prefix = "spring.multi-datasource.athena-ds")
    public PoolProperties getPoolProperties(){
        return new PoolProperties();
    }

    /*
    * athena 데이터소스를 반환하는 빈 선언
    * */
    @Bean(name = "athenaDatasource")
    public DataSource getDatasource(@Autowired @Qualifier("athenaDsConnectionProperties") PoolProperties property) {
       com.simba.athena.jdbc.DataSource ds = new com.simba.athena.jdbc.DataSource();
       ds.setURL(property.getUrl());

       return ds;
    }
    /*
    * Mybatis 관련 SqlSessionFactory 반환 빈 선언
    * */
    @Bean(name = "athenaSqlSessionFactory")
    public SqlSessionFactory athenaSqlSessionFactory(@Qualifier("athenaDatasource") final DataSource dataSource) throws Exception {

       SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean();
        sqlSessionFactory.setDataSource(dataSource);
        //컨피그에 등록 된 패키지 모델 앨리어스 추가
        sqlSessionFactory.setConfigLocation(applicationContext.getResource("classpath:mapper/mybatis-config.xml"));
        sqlSessionFactory.setMapperLocations(applicationContext.getResources("classpath:mapper/**/*Mapper.xml"));

        ClassLoader    runClassLoader = Thread.currentThread().getContextClassLoader();
        Reflections reflections      = new Reflections(ClasspathHelper.forPackage("패키지"), new SubTypesScanner(false));
        //Model의 이름을 가졌거나 Alias 애노테이션에 들어간 클래스를 추가
        List<Class<?>> typeAliasRegistryList = new ArrayList<>();
        reflections.getAllTypes().forEach(type -> {
            Class<?>   typeClass;

            try {
                typeClass  = Class.forName(type, false, runClassLoader);
                if (type.endsWith("Model") || typeClass.isAnnotationPresent(Alias.class)) {
                    typeAliasRegistryList.add(typeClass);
                }
            } catch (NoClassDefFoundError ignore) {
            } catch (ClassNotFoundException ignore) {
            }
        });
        Class<?>[] typeAliasRegistryArray = typeAliasRegistryList.toArray(new Class<?>[typeAliasRegistryList.size()]);
        sqlSessionFactory.setTypeAliases(typeAliasRegistryArray);

        return sqlSessionFactory.getObject();
    }

    @Bean(name = "athenaSqlSessionTemplate")
    public SqlSessionTemplate athenaSqlSessionTemplate(@Qualifier("athenaSqlSessionFactory") SqlSessionFactory athenaSqlSessionFactory){
       return new SqlSessionTemplate(athenaSqlSessionFactory);
    }
    /*
    * 트랜잭션 발생 시 롤백
    * */
   @Bean(name = "athenaTransactionManager")
   public DataSourceTransactionManager TransactionManager(@Autowired @Qualifier("athenaDatasource") DataSource DataSource) {
      return new DataSourceTransactionManager(DataSource);
   }


}

이러한 Config의 경우 AthenaDao 애노테이션이 호출하면 동작을 하며 Dao 내 해당 애노테이션을 추가하고 mappr.xml 내 Athena 관련 쿼리를 작성하면 정상 동작하는것이 확인이 됩니다.