아래의 예제 대로 실행을 하면 Before, test,After 가 순차적으로 진행이 되어야한다.

public class BeforeAfter {

    @Before
    public void SetUp(){
        System.out.println("Before");
    }

    @Test
    void transformation() {
        System.out.println("test");
    }
    @After
    public void after(){
        System.out.println("After");
    }

}

하지만 test 밖에 출력이 되지 않았다. 왜 그런걸까 찾아보니 JUnit5 에서는 @Before, @After 가 @BeforeEach, @AfterEach 로 설정을 해야한다.

JUnit5 의 어노테이션으로 아래의 코드로 다시 실행을 하니 다시 실행이 된다.

public class BeforeAfter {

    @BeforeEach
    public void SetUp(){
        System.out.println("Before");
    }

    @Test
    void transformation() {
        System.out.println("test");
    }
    @AfterEach
    public void after(){
        System.out.println("After");
    }

}

SpringBoot에서 JUnit이 몇버전인지 알고 싶을때 아래로 확인하고 변경하면 된다.

생각없이 그냥 springInitializer에서 다운을 받으면 아래와 같은 설정이 있는데, springboot-2.2.X 이후부터는 Junit5로 설정이 되어있는 것 같다.

    testImplementation('org.springframework.boot:spring-boot-starter-test') {
        exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
    }

https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.2-Release-Notes

spark를 실행 하고 있으면 cleaned accumulator 숫자

INFO org.apache.spark.ContextCleaner - Cleaned accumulator 126 의 형태를 볼수 있다 무엇을 의미 하는 것 일까 ?

 

19:17:36.899 [Spark Context Cleaner] INFO org.apache.spark.ContextCleaner - Cleaned accumulator 126 19:17:36.899 [Spark Context Cleaner] INFO org.apache.spark.ContextCleaner - Cleaned accumulator 145 19:17:36.899 [Spark Context Cleaner] INFO org.apache.spark.ContextCleaner - Cleaned accumulator 152 19:17:36.899 [Spark Context Cleaner] INFO org.apache.spark.ContextCleaner - Cleaned accumulator 130 19:17:36.899 [Spark Context Cleaner] INFO org.apache.spark.ContextCleaner - Cleaned accumulator 144 19:17:36.899 [Spark Context Cleaner] INFO org.apache.spark.ContextCleaner - Cleaned accumulator 142

 

 

org.apache.spark.ContextCleaner 클래스 API 설명

 

RDD, 셔플 및 브로드캐스트 상태를 위한 비동기식 클리너

관련 object가 응용 프로그램 범위를 벗어날대, 처리 될 각 RDD, shuffleDependency 및 관심이 있는 브로드 캐스트에 대한 약한 참조는 유지됩니다.실제로 처리는 별도의 데몬 스레드에서 수행됨.

https://spark.apache.org/docs/1.2.0/api/java/org/apache/spark/ContextCleaner.html

 

stackoverflow 답변 중

 

ContextCleaner는 드라이버에서 실행 된다. SparkContext가 시작될때 작성되고 즉시 시작된다. RDD, 셔플 및 브로드캐스트 상태, accumulate를 정리하는 컨텍스트 클리너 스레드(keepCleaning 메소드 사용). context-cleaner-periodic-gc는 JVM 가비지 콜렉터를 요청함.

https://stackoverflow.com/questions/55452892/contextcleaner-cleaned-accumulator-what-does-it-mean-in-scala-spark

Git remote: Permission to

깃허브 사용중에 아래와같은 에러가 발생하는 경우가 있었다.

remote: Permission to elasticsearchstudy/SaturdaySpring.git denied to DaeyunKim.

fatal: unable to access 'https://github.com/elasticsearchstudy/SaturdaySpring.git': The requested URL returned error: 403

처음엔 프로젝트에서 권한 문제인줄알았는데

찾아보니 아래와 같이 다시 터미널에서 입력해주고 다시 시도하니 된다.

$ git remote set-url origin git@github.com:elasticsearchstudy/SaturdaySpring.git

해결 : https://stackoverflow.com/questions/47465644/github-remote-permission-denied

'BackEnd > ETC' 카테고리의 다른 글

[gradle] CreateProcess error=206  (0) 2020.04.25
http 상태 코드  (0) 2020.01.19
CQRS란 ?  (1) 2020.01.19
STORM 정리  (0) 2017.12.18

SparkUI 에러 InjectionManagerFactory not found

springframework 에서 spark를 조작하는데 spark UI에서 executor를 실행하면 아래와 같은 오류가 발생한다.

Caused by: java.lang.IllegalStateException: InjectionManagerFactory not found.

    at org.glassfish.jersey.internal.inject.Injections.lambda$lookupInjectionManagerFactory$0(Injections.java:74)
    at java.util.Optional.orElseThrow(Optional.java:290)
    at org.glassfish.jersey.internal.inject.Injections.lookupInjectionManagerFactory(Injections.java:74)
    at org.glassfish.jersey.internal.inject.Injections.createInjectionManager(Injections.java:69)
    at org.glassfish.jersey.server.ApplicationHandler.<init>(ApplicationHandler.java:259)
    at org.glassfish.jersey.servlet.WebComponent.<init>(WebComponent.java:311)
    at org.glassfish.jersey.servlet.ServletContainer.init(ServletContainer.java:154)
    at org.glassfish.jersey.servlet.ServletContainer.init(ServletContainer.java:346)
    at javax.servlet.GenericServlet.init(GenericServlet.java:203)
    at org.spark_project.jetty.servlet.ServletHolder.initServlet(ServletHolder.java:643)
    ... 23 common frames omitted

해결방법은 아래의 dependency를 추가해주면된다.

implementation 'org.glassfish.jersey.inject:jersey-hk2:2.30'

'BackEnd > Spark' 카테고리의 다른 글

Spark SQL API  (0) 2020.03.09
cleaned accumulator [number]  (0) 2020.03.09
[Spark] RDD Persistence 와 Caching  (0) 2020.03.05
스파크 SQL 사용하여 파일로 보내기  (0) 2020.03.02
java.io.InvalidClassException: org.apache.spark.rdd.RDD  (0) 2020.02.18


RDD의 persistence, Caching에 대해서 정리

Persistence와 Cache가 무엇인가가?

RDD 를 영구적으로 저장하는 기술로 결과를 즉시 저장해두었다가 이후에 필요하면 다시 불러와서 사용이 가능하다. 이것으로 컴퓨팅오버헤드를 줄일 수 있다.

이럴때 RDD를 저장하는 방법은 cache() 와 persist() 메서드가 있다.

cache() 메서드는 모든 메모리의 모든 RDD를 저장할 수 있다. 그리고 RDD를 메모리에 유지하고 병렬작업에서 효율적으로 사용 할 수 있다.

Cache()와 Persist()의 메서드의 차이는 ?

cache()와 persist()의 차이점 : cache()를 사용하면 기본 저장 장소가 MEMORY_ONRY 이고 persist를 하면 다양한 저장소에 수준을 저장할 수 있다.

RDD의 파티션이 손실되면 원래 생성한 변환작업을 통해 다시 복구한다.

Spark 에서 Persist가 필요한 이유

RDD 와 RDD 에서 호출하는 액션들에 대한 모든 의존성을 재연산하게 되는데, 호출하는 액션들에 대한 모든의존성을 재연산하게 된다.

이때 데이터를 여러번 스캔하는 반복알고리즘들에 대해서는 매우 무거운 작업일 수 있다.

persist 함으로서 반복적인 알고리즘과 메모리의 소비를 줄 일 수 있다.

여러번 반복 연산하는 것을 피하려면 스파크에 데이터 영속화(persist/persistence)를 요청할 수 있다.

RDD 영속화에 대한 요청을 하면 RDD를 계산한 노드들은 그 파티션들을 저장하고 있게 된다.

자바에서는 기본적으로 persist()가 데이터를 JVM 힙(heap) 에 직렬화되지 않는 객체 형태로 저장.

  




레벨  공간사용  CPU 사용시간 메모리에 저장 디스크에 저장 비고
MEMORY_ONLY  높음  낮음  예  아니오  
MEMORY_ONLY_SER    낮음 높음   아니오  
MEMORY_AND_DISK     높음 중간 일부  일부 메모리에 넣기에 데이터가 너무 많으면 디스크에 나눠 저장
MEMORY_AND_DISK_SER     낮음 높음 일부  일부 메모리에 넣기에 데이터가 너무 많으면 디스크에 나눠 저장.메모리에 직렬화된 형태로 저장


DISK_ONLY 낮음 높음 아니오 예

persist() 호출은 연산을 강제로 수행하지않는다.

메모리에 많은 데이터를 올리려고 시도하면 스파크는 LRU 캐시 정책에 따라 오래된 파티션들을 자동으로 버림.

예제 코드

import org.apache.spark.storage.StorageLevel

val result = input map(x => x*x)
result.persist(StorageLevel.DISK_ONLY)
println(result.count())
println(result.collect().mkString(","))



Dataset<Row> 또한 데이터가 아니라 변환작업들을 저장하고 있어 불러올 때 마다 값이 달라질 수도있는데, 이것을 persist 하면 cached 된 데이터를 사용하기 때문에 다시 계산할 필요없다.

https://data-flair.training/blogs/apache-spark-rdd-persistence-caching/

구분자 사용해서 뽑아오기
\구분자
`(single qutoation)로 감싸주면 됨 `{print $열번호}`

cat test.txt | awk -F \| '{print $4","$5","$6","$17","$18}' > busan.csv

원본 :

26110|2608|2611010100|부산광역시|중구|영주동|261103006001|초량상로|0|1|4||48910|근린생활시설|0|영주제1동|1139873.245417|1680775.057503

결과

$ cat busan.csv
부산광역시,중구,영주동,1139873.245417,1680775.057503

'BackEnd > Linux' 카테고리의 다른 글

Yum Repository 만들기 (2)  (0) 2019.12.24
Yum Repository 만들기 (1)  (0) 2019.12.23
[Linux]NoLogin  (0) 2019.10.08
Swap 메모리 늘리기  (0) 2019.09.17
cache 삭제하기  (0) 2019.08.27

스파크 SQL 을 파일로 보내기
coalesce(1) 을 해주는 이유는 RDD 로 분산되어있는 파티션을 하나로 모아주기 위해서

 session.sql("select * from temp").coalesce(1).write().format("com.databriccks.spark.csv").option("header","true").csv("./data/morris.csv");

인프런 백기선님의 SpringMVC 강의를 보고 정리한 내용입니다.
DispatcherServlet

이전의 글에서 SpringWebMVC에서는 FrontController로 DispatcherServlet 이라는 것구현해놓았다고 했다.

mvc context hierarchy

ServletWebApplicationContext 에서 Controller 설정만 가지고 와서 특정 url에 따른 처리를 해주고

Root WebApplicationContext 에는 Service, Repository 는 모든곳에서 사용할 수 있게 구분을 할 수 있게 하는 구조로 되어있다.

DispatcherServlet 사용하기

위와 같이 Controller는 ServletWebApplicationContext에 등록하고, Service,Repository의 설정은 Root WebApplication에 등록을 해주기

web.xml

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
  <display-name>Archetype Created Web Application</display-name>

  <context-param>
    <param-name>contextClass</param-name>
    <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
  </context-param>

  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>me.morris.AppConfig</param-value>
  </context-param>

  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>

  <servlet>
    <servlet-name>app</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextClass</param-name>
      <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
    </init-param>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>me.morris.WebConfig</param-value>
    </init-param>
  </servlet>

  <servlet-mapping>
    <servlet-name>app</servlet-name>
    <url-pattern>/app/*</url-pattern>
  </servlet-mapping>

</web-app>

AppConfig.java : Controller를 제외한 ApplicationContext

WebConfig.java : Controller를 포함한 ApplicationContext

AppConfig.java

package me.morris;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Controller;

@Configuration
@ComponentScan(excludeFilters = @ComponentScan.Filter(Controller.class))
public class AppConfig {

}

WebConfig.java

package me.morris;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Controller;

@Configuration
@ComponentScan(useDefaultFilters = false, includeFilters = @ComponentScan.Filter(Controller.class))
public class WebConfig {

}

HelloController.java

package me.morris;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {
    @Autowired
    HelloService helloService;
    @GetMapping("/hello")
    public String hello(){
        return "Hello, "+ helloService.getName();
    }
}

HelloService.java

package me.morris;

import org.springframework.stereotype.Service;

@Service
public class HelloService {
    public String getName(){
        return "morrisKim";
    }
}

이렇게 RootWebApplicationContext와 Servlet WebapplicattionContext에 나눠서 설정을 할 수 있다.


간단하게 하면 Root WebApplicationContext에 Controller와 Service, Repository 등을 전부 등록하여 사용이 가능하다.

web.xml

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>

  <servlet>
    <servlet-name>app</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextClass</param-name>
      <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
    </init-param>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>me.morris.WebConfig</param-value>
    </init-param>
  </servlet>

  <servlet-mapping>
    <servlet-name>app</servlet-name>
    <url-pattern>/app/*</url-pattern>
  </servlet-mapping>

</web-app>

WebConfig.java : ComponentScan을 전체로 등록함

package me.morris;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Controller;

@Configuration
@ComponentScan
public class WebConfig {

}

IOC Container 연동

인프런 Spring WEB MVC 강의를 듣고 정리 한 내용입니다.

SpringIOC 를 Servlet에 연동을 하려고한다.

maven 의 pom.xml 의존성을 추가함

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-webmvc</artifactId>
  <version>5.1.3.RELEASE</version>
</dependency>

web.xml 변경

  • 이전 서블릿에서 사용했던 servlet listener (ServletContextListener 구현체) 대신에 Spring에서 지원하는 ContextLoaderListener로 변경 해줌

변경 전

<listener>
  <listener-class>me.morris.MyListener</listener-class>
</listener>

spring에서 지원하는 org.springframework.web.context.ContextLoaderListener

: 스프링 IOC 컨테이너 applicationcontext 를 servlet의 생명주기에 맞춰서 servletcontext에 등록해주고 , 종료할때 applicationcontext를 제거하는 역할을 함

변경 후

<listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

applicationcontext의 위치, 파일 을 파라미터로 지정해줘야함

contextClass 등록

ContextLoader를 통해 ApplicationContext를 등록 해줘야한다.

web.xml

contextClass : applicationContext를 어떤 방법으로 등록을 할것인가?(Java Configure, Xml Configure ...)

<context-param>
  <param-name>contextClass</param-name>
  <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</context-param>

<context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>me.morris.AppConfig</param-value>
</context-param>

me.morris.AppConfig.java

package me.morris;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan
public class AppConfig {

}

HelloService.java 서비스 빈으로 등록

package me.morris;

import org.springframework.stereotype.Service;

@Service
public class HelloService {
    public String getName(){
        return "morrisKim";
    }
}

web.xml에 아래와 같이 오류가 난다고 한다면??아래의 순서대로 태그를 나열하면 해결된다.

The content of element type "web-app" must match "(icon?,display-name?,description?,distributable?,context-param*,filter*,filter-mapping*,listener*,servlet*,servlet-mapping*,session-config?,mime-mapping*,welcome-file-list?,error-page*,taglib*,resource-env-ref*,resource-ref*,security-constraint*,login-config?,security-role*,env-entry*,ejb-ref*,ejb-local-ref*)".

Web ApplicationContext 불러오기

아래를 보면 ContextLoaderListener.class가 initwebApplicationContext를 통하여 context를 지정해준다.

99 servletContext.setAttribute(applicationContextName, context);

servletContext에 등록이 되는 것을 알 수 있다.

그 이후에는 이전에 만들었던 HelloServlet.java 클래스로 이동해서 doGet메서드에 서 ApplicationContext를 불러 와보자.

servletContext에 WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE 라는 이름으로 ApplicationContext가 등록이 되어있으므로, 아래와 같이 불러와서 BeanFactory에서 HelloService.class 를 불러와서 사용이 가능하다.

HelloServlet.java

...
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

  ApplicationContext context = (ApplicationContext) getServletContext().getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
  HelloService helloService = context.getBean(HelloService.class);

  System.out.println("doGet");
  resp.getWriter().println("" +
                           "<html>\n" +
                           "<body>\n" +
                           "<h2>Hello Servlet!" +helloService.getName()+"</h2>\n" +
                           "</body>\n" +
                           "</html>\n");
}
...

이로써 IOC 컨테이너를 Servlet에서 사용 할 수 있는 방법을 알 아 볼 수 있었다.

url 하나당 서블릿 하나씩 만들어 나간다면, 설정이 계속 추가가 되며, 여러 서블릿에서 공통적으로 쓰는 것들을 어떻게 해결을 할수 있을까?

그래서 나온것이 FrontController

FrontController의 역할을 하는 하나의 Servlet을 설정해주고 url을 구분하는 방법을 나타냄

SpringWebMVC에서는FrontController로 DispatcherServlet 이라는 것구현해놓았다.

+ Recent posts