fastcampus java 온라인 강의를 들으면서 정리한 내용입니다.

Customizing the Nature of a Bean

  • Lifecycle Callbacks
  • ApplicationContextAware and BeanNameAware

LifeCycle

객체들을 관리 , 객체를 만들때(new), 객체를 없앨 때(destroy)

new라는 객체를 만들기 전

특정 빈에 대해서 자원 없앨때 close에 대한 함수

  • InitializingBean
  • DisposableBean
  • xml -init method / destroy

실행

ApplicationContext context = new ClassPathXmlApplicationContext("dao.xml");

ConnectionFactory connectionFactory = context.getBean("connectionFactory",ConnectionFactory.class);
log.info("result : "+connectionFactory.getConnection());
  1. Initializing Bean (Interface)

    bean이 생성 될때 미리 생성됨 : 컨테이너가 빈에 필요한 모든 속성을 설정 한 후 빈 초기화 작업을 수행

    InitializingBean 인터페이스는 afterPropertiesSet 하나의 메서드를 가진다.

    void afterPropertiesSet() throws Exception;

예제 dao.xml

<bean id="connectionFactory" class="kr.co.fastcampus.cli.ConnectionFactory" >
  <constructor-arg name="driverClass" value="org.h2.Driver"/>
  <constructor-arg name="url" value="jdbc:h2:mem:test"/>
  <constructor-arg name="user" value="sa"/>
  <constructor-arg name="password" value=""/>
</bean>

<bean id = "connection" class="java.sql.Connection"
      factory-bean = "connectionFactory"
      factory-method="createConnection"
      />

<bean id="dao" class="kr.co.fastcampus.cli.Dao">
  <constructor-arg ref="connection"></constructor-arg>
</bean>

ConnectionFactory.java

public class ConnectionFactory implements InitializingBean {
    private String driverClass;
    private String url;
    private String user;
    private String password;
    //bean을 만들지면서 Connection을 미리 생성 하기
    @Getter
    private Connection connection=null;

    public ConnectionFactory(String driverClass,String url, String user, String password) {
        this.driverClass = driverClass;
        this.url = url;
        this.user = user;
        this.password = password;
    }

    public Connection createConnection() throws SQLException {
        try {
            Class.forName("org.h2.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        String url = "jdbc:h2:mem:test;MODE=MySQL;";
        return DriverManager.getConnection(this.url,this.user,this.password);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        this.connection = createConnection();
    }
}
  1. Initializing Bean (xml)

    init-method 에 는 빈 팩토리를 불러올 때 실행될 메서드이름을 지정해서 사용할 수 있다.

    dao.xml

    <bean id="connectionFactory" class="kr.co.fastcampus.cli.ConnectionFactory" init-method="init" >

    ConnectionFactory.java

    public class ConnectionFactory {
        private String driverClass;
        private String url;
        private String user;
        private String password;
        //bean을 만들지면서 Connection을 미리 생성 하기
        @Getter
        private Connection connection=null;
    
        public ConnectionFactory( String driverClass,String url, String user, String password) {
            this.driverClass = driverClass;
            this.url = url;
            this.user = user;
            this.password = password;
        }
        //bean 메서드(xml)의 init의 메서드를 지정해주면 bean이 초기화될때 생성된다.
        public void init() throws Exception {
            this.connection = createConnection();
        }
    
        public Connection createConnection() throws SQLException {
            try {
                Class.forName("org.h2.Driver");
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
            String url = "jdbc:h2:mem:test;MODE=MySQL;";
            return DriverManager.getConnection(this.url,this.user,this.password);
        }
    }

###DisposableBean

Bean을 포함하는 컨테이너가 소멸 될 때 Bean이 콜백을 얻을 수 있습니다.

1.Disposable Bean (Interface)

DisposableBean 인터페이스는 destroy 메서드를 가진다.

void destroy() throws Exception;

ConnectionFactory.java

@Slf4j
public class ConnectionFactory implements DisposableBean {
    private String driverClass;
    private String url;
    private String user;
    private String password;
    //bean을 만들지면서 Connection을 미리 생성 하기
    @Getter
    private Connection connection=null;

    public ConnectionFactory( String driverClass,String url, String user, String password) {
        this.driverClass = driverClass;
        this.url = url;
        this.user = user;
        this.password = password;
    }
    //bean 메서드(xml)의 init의 메서드를 지정해주면 bean이 초기화될때 생성된다.
    public void init() throws Exception {
        this.connection = createConnection();
    }

    public Connection createConnection() throws SQLException {
        try {
            Class.forName("org.h2.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        String url = "jdbc:h2:mem:test;MODE=MySQL;";
        return DriverManager.getConnection(this.url,this.user,this.password);
    }

    @Override
    public void destroy() throws Exception {
        log.info("destory connection");
        if(this.connection!=null){
            this.connection.close();
        }
    }
}

이렇게 해주고 위에서 getbean을 사용해서 사용했지만, 여기서는 ApplicationContext 보다 ApplicationContext클래스를 상속받고 있는 ConfigurableApplicationContext 를 사용해서 테스트를 진행해야 한다.

ConfigurableApplicationContextApplicationContext, Lifecycle, Closeable 를 상속 받고 있다.

테스트를 위한 실행

ConfigurableApplicationContext context = new ClassPathXmlApplicationContext("dao.xml");

ConnectionFactory connectionFactory = context.getBean("connectionFactory",ConnectionFactory.class);
log.info("result : "+connectionFactory.getConnection());
context.close();

결과

00:58:37.149 [main] INFO  kr.co.fastcampus.cli.Main - result : conn0: url=jdbc:h2:mem:test user=SA
00:58:37.151 [main] INFO  k.c.fastcampus.cli.ConnectionFactory - destory connection

2.DisposableBean Bean (xml)

위의 initializing Bean을 xml 로 설정한것과 같다.destroy-method 속성을 추가 해주면 된다.

<bean id="connectionFactory" class="kr.co.fastcampus.cli.ConnectionFactory" init-method="init" destroy-method="destroy">
@Slf4j
public class ConnectionFactory {
    private String driverClass;
    private String url;
    private String user;
    private String password;
    //bean을 만들지면서 Connection을 미리 생성 하기
    @Getter
    private Connection connection=null;

    public ConnectionFactory( String driverClass,String url, String user, String password) {
        this.driverClass = driverClass;
        this.url = url;
        this.user = user;
        this.password = password;
    }
    //bean 메서드(xml)의 init의 메서드를 지정해주면 bean이 초기화될때 생성된다.
    public void init() throws Exception {
        this.connection = createConnection();
    }

    public Connection createConnection() throws SQLException {
        try {
            Class.forName("org.h2.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        String url = "jdbc:h2:mem:test;MODE=MySQL;";
        return DriverManager.getConnection(this.url,this.user,this.password);
    }

    public void destroy() throws Exception {
        log.info("destory connection");
        if(this.connection!=null){
            this.connection.close();
        }
    }
}

결과는 똑같이 나온다.

01:08:23.145 [main] INFO  kr.co.fastcampus.cli.Main - result : conn0: url=jdbc:h2:mem:test user=SA
01:08:23.148 [main] INFO  k.c.fastcampus.cli.ConnectionFactory - destory connection

##Default init, destroy

default-init-method , default-destroy-method 를 beans에 추가 해주면 기본적으로 bean에서 특정 메서드로 사용이 가능하다.

<beans default-init-method="init"
       default-destroy-method="destroy"
       xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

LifeCycle

Lifecycle 인터페이스

  • void start();

  • void stop();

  • boolean isRunning();

context가 실행 중인지 아닌지 lifeCycle의 상태를 조회 가능하다.

ConfigurableApplicationContext context = new ClassPathXmlApplicationContext("dao.xml");
Lifecycle lifecycle = context.getBean(Lifecycle.class);
log.info("lifeCycle is Running ? "+lifecycle.isRunning());
context.close();
log.info("lifeCycle is Running ? "+lifecycle.isRunning());

결과

01:37:25.064 [main] INFO  kr.co.fastcampus.cli.Main - lifeCycle is Running ? true
01:37:25.069 [main] INFO  k.c.fastcampus.cli.ConnectionFactory - destory connection
01:37:25.070 [main] INFO  kr.co.fastcampus.cli.Main - lifeCycle is Running ? false

###ApplicationContextAware

특정 빈에서 application Context를 사용 하고 싶을때 사용

public interface ApplicationContextAware {
    void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}

https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans-factory-nature

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

Bean Scope  (0) 2020.02.11
ClassPath Scanning and Managed Components  (0) 2020.02.08
DI (Dependency Injection)  (0) 2020.02.01
Spring-Core  (0) 2020.01.19
SpringCore - IoC Container(1)  (0) 2020.01.19

fastcampus java 강의를 보면서 정리를 한 것입니다.
Spring IoC의 핵심

의존성 하나 이상의 오브젝트로 실행 되는데, 오브젝트들 간에 함께 의존하고 있음

Di 예제

public Main(){
  public static void main(String []args){
    B b = new B(true);
    A a = new A(b);
    a.println();
  }
}

객체가 객체를 의존하고 있으면, 코드 유지보수가 어려워짐

디커플링 할수록 간결하게 변화함

코드에서 관계를 맺어주는것이 아니다.

의존성을 상위 코드에서 생성하여 객체를 주입하므로 a 에서는 B에 의존하는 값을 가지고 있지 않아도된다.

이것을 framework 화 한것이 IoC Container

  • 설정을 보고 관계를 눈으로 미리 볼수 있다.

  • 비지니스 로직만 집중할 수 있음 .

  • 테스트를 더 쉽게 가능하다.

  • 생성자 주입 / setter 주입

    생성자 주입

    객체가 생성될때 만들어짐

    public class A{
      private B b;
        public void setB(B b){
        this.b=b;
      }
      ...
    }
    <bean id="a" class="kr.co.fastcampus.cli.di.A">
      <constructor-arg ref="b"/>
    </bean>
    <bean id="b" class="kr.co.fastcampus.cli.di.B">
      <constructor-arg value="true"></constructor-arg>
    </bean>

    Setter 주입

    코드가 돌다가 객체가 언제든지 관계가 재설정이 되었을 때

    <bean id="a" class="kr.co.fastcampus.cli.di.A">
      <property name="b" ref="b"/>
    </bean>
    <bean id="b" class="kr.co.fastcampus.cli.di.B">
      <constructor-arg value="true"></constructor-arg>
    </bean>

circulate Dependency

상호 참조 dependecy 서로 참조를 하게 되면 stack overflow가 발생할수 있음.

https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans-dependencies

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

Bean Scope  (0) 2020.02.11
ClassPath Scanning and Managed Components  (0) 2020.02.08
Customizing the Nature of a Bean  (0) 2020.02.01
Spring-Core  (0) 2020.01.19
SpringCore - IoC Container(1)  (0) 2020.01.19

Spring-Core

Spring FrameworkOverview

스프링은 Java EE(엔터프라이즈)를 쉽게 만들수 있다.

엔터프라이즈 어플리케이션 Java EE 는 커뮤니티 프로세스가 주도하는 소프트웨어 ,JS360,370...등등을 볼수 있다.

엔터프라이즈 소프트웨어 : 비지니스를 풀려고 할때 모든 셋에 대한 정의가 되어있다는 점

javax 패키지

Java Servlet도 Java EE에 대한 기능

역사

2003년부터 시작, J2EE가 너무 복잡함 , 복합함을 해결하기 위해서 POJO라는 개념이 나오기도함.

무조건 JavaEE Spec에 따라서 해야했는데,

IoC Container

core : ioc, eventresource, ibn validation, databinding, spel, aop..

Spring : Inversion of Control 을 구현한 프레임워크

왜 inversion of Controll이 좋은가?, Di 의 개념은?

ApplicationContext를 통해서 ioc를 진행하고있음

ApplicationContext는 aop, eventpublication, ....등 다양한 것들을 구현하고있다.

interface ApplicationContext 란 ?

여러 구현체들과 설명이 많이 있음 spring의 핵심

spring container를 통해서 pojo비지니스 오브젝트를 configuration 메타 데이터를 만들어놓으면 spring이 자동으로 만들어주고 활용할수 있게 해준다.

Instantiating a Container

구현체를 통해서 applicationContext를 사용할 수 있게 된다.

코드로 객체를 생성하는것이 아니라 xml을통해서 configuration Metadata를 만들고 비지니스 로직을 만들고 spring container를 통해서 동작(실행)이 하게된다.

applicationContext의 인터페이스를 구현한 것이 springcontainer임 !!

Spring Container설정은 아래와같다.

ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");

Dao dao = new Dao()

객체 생성 관련 설정

<beans....>
    <bean class="kr.morris.cli.dao"></bean>
</beans....>

객체의 타입에 맞게 context를 사용해서 객체를 가지고 옴 .

Dao dao = context.getBean(Dao.class);

Configuration Metadata

  • xml
    • 특정 namespace을 가지고 있다.
    • 라는 태그 안에 < bean /> 을 설정 할 수 있다.
  • annotation
  • java

Bean

Naming Bean

기존의 빈

<bean class="kr.morris.cli.Dao"/>
  • id 는 그대로 하나만 가지고 있어야한다.
    unique 하더라도 spring에서 다르게 관리하는 bean을 만들수도 있다.

    <bean id='dao'.../>
  • name으로도 추가가 가능하다

    <bean name='dao1, dao2'.../>
  • 같은 클래스를 가리키더라도 id,name이 다르면 새로운 객체를 만드는 것이기 때문에 둘의 객체의 hash값이 다르게 출력된다.

bean을 지정하면 기본 생성자에대해서 객체를 생성한다.

매개변수를 받는 생성자를 입력받게 된다면 ApplicationContext에서 bean을 불러 올때 에러가난다. (beanCreateionException)

static factory method를 사용해서 만들 수도 있다.

Dao 설정에 factory-method 속성에 createDao라는 매서드를 입력해주주면된다.

<bean id="dao" class="kr.morris.cli.Dao" factory-method="createDao"></bean>

public class Dao {
    public stataic Dao createDao(){
          return new Dao();
    }
}

instance Factory method

인스턴스 Method를 이용해 bean 객체를 생성이 가능하다

Factory bean 인터페이스를 구현한 팩토리 빈이 바로 팩토리 빈 오브젝트의 메소드를 이용해 bean 객체를 생성하는 대표적인 방법

두 개의 bean이 필요함.

  • 하나는 빈을 만들어줄 클래스가 정의된 빈 (Dao.class)

  • 우리가 사용할 빈 (DaoFactory)
    특정외부 자원들을 사용할때 팩토리 매서드를 사용해서 보는 경우가 있음

    public class DaoFactory{

    public Dao createDao(){
      return new Dao();
    }

    }

    public class Dao{

    }

동작을 해보면 팩토리메서드를 통해서 실제로 daofactory를 통해서 bean이 생성된 것을 알 수 있다.

참고 :

패스트 캠퍼스 Java Spring 강의중 Spring-Core

https://cornswrold.tistory.com/101

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

Bean Scope  (0) 2020.02.11
ClassPath Scanning and Managed Components  (0) 2020.02.08
Customizing the Nature of a Bean  (0) 2020.02.01
DI (Dependency Injection)  (0) 2020.02.01
SpringCore - IoC Container(1)  (0) 2020.01.19

IoC Container

Spring IoC Container

ApplicationContext 인터페이스는 Spring IoC 컨테이너를 나타내며, 인스턴스 구성 및 bean 조립을 담당

아래는 Spring의 작동 방식을 개략적으로 보여줌

Springframework 용어 정리

Bean 빈 또는 빈 오브젝트는 스프링이 IOC 방식으로 관리하는 오브젝트를 말함 Spring Application에서 사용하는 모든 오브젝트가 빈이라고 불리는것이 아니라, 스프링이 직접 생성과 제어를 담당하는 오브젝트를 빈이라고 부른다.

빈 팩토리 스프링의 ioc 를 담당하는 컨테이너를 가리킴 빈을 등록하고, 생성하고 조회하고 부가적인 관리 기능을 담당 beanFactory를 바로 사용하지 않고, 확장한 application context를 이용한다.

애플리케이션 컨텍스트 빈 팩토리를 확장한 IOC 컨테이너, 빈을 등록하고 관리하는 기본적인 기능은 빈팩토리와 동일하다. 스프링에서 빈팩토리기능 말고도 부가적인 서비스를 추가로 제공함. 빈 팩토리라고 부를때는 주로 빈의 생성과 제어의 관점, 애플리케이션 컨텍스트라고 할 때는 스프링이 제공하는 애플리케이션 지원 기능을 모두 포함해서 이야기 하는 것이라고 보면된다.

applicationContext는 beanFactory를 상속한다.

설정정보/설정 메타 정보 스프링 애플리케이션 컨텍스트 또는 빈 팩토리가 ioc를 적용하기 위해 사용되는 메타정보 (xml이 될수도있고, java 어노테이션, java 코드 로 표기 될 수 있다.)

컨테이너 또는 ioc 컨테이너 IoC 방식으로 빈을 관리한다는 의미에서 애플리케이션 컨텍스트나 빈 팩토리를 컨테이너 또는 IoC container라고 한다.

스프링 프레임워크 스프링 프레임워크는 IoC 컨테이너, 애플리케이션 컨텍스트를 포함해서 스프링이 제공하는 모든 기능을 통틀어 말할 때 주로 사용

Spring Java API

API를 찾아서 들어가게 되면 아래와 같이 확인을 할 수 있다.

ApplicationContext API

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/ApplicationContext.html

BeanFactory API

All Known Implementing Classes들은 아래와 같다. AbstractApplicationContext, AbstractAutowireCapableBeanFactory, AbstractBeanFactory, AbstractRefreshableApplicationContext, AbstractRefreshableConfigApplicationContext, AbstractRefreshableWebApplicationContext, AbstractXmlApplicationContext, AnnotationConfigApplicationContext, AnnotationConfigWebApplicationContext, ClassPathXmlApplicationContext, DefaultListableBeanFactory, FileSystemXmlApplicationContext, GenericApplicationContext, GenericGroovyApplicationContext, GenericWebApplicationContext, GenericXmlApplicationContext, GroovyWebApplicationContext, ResourceAdapterApplicationContext, SimpleJndiBeanFactory, StaticApplicationContext, StaticListableBeanFactory, StaticWebApplicationContext, XmlBeanFactory, XmlWebApplicationContext

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/BeanFactory.html

참고 :

토비의 스프링
[https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html]

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

Bean Scope  (0) 2020.02.11
ClassPath Scanning and Managed Components  (0) 2020.02.08
Customizing the Nature of a Bean  (0) 2020.02.01
DI (Dependency Injection)  (0) 2020.02.01
Spring-Core  (0) 2020.01.19

# Http 상태 코드

 

내가 자주 보았던 Http 응답 코드는 404, 500, 200, 등등이었는데 앞자리에 따라서 의미가 다르다. 잘 몰랐지만 이번에 정리를 해보자

 

http 응답 상태는 3자리 숫자로 나타낸다.

 

첫번째 숫자는 응답의 클래스(분류)로 구분된다.

마지막 두 자리는 클래스나 분류 역할을 하지는 않지만 분류에 따라 다양하다.



| 앞 번호 | 의미 |

|-|-|

|1 (조건부 응답)| 요청을 받았으며, 프로세스를 계속 한다.|

|2 (성공)| 요청을 성공적으로 받았으며, 인식했고 수용하였다. |

|3 (리다이렉션 완료)| 요청완료를 위해 추가 작업 조치가 필요함|

|4 (요청 오류)| 요청의 문법이 잘못됬거나 요청을 처리 할 수 없다.|

|5 (서버 오류)| 서버가 명백히 유효한 요청에 대해 충족을 실패 했다.|

 

**예시**

100 : 요청자는 요청을 계속 한다. 서버는 이 코드를 제공하여 요청의 첫번째 부분을 받았으며 나머지를 기다리고 있음을 나타냄.

101 : 요청자가 서버에 프로토콜을 전환을 요청했고, 서버는 이를 승인하는 중.

 

200 : 서버가 요청을 제대로 처리 했다.

201 : 성공적으로 요청되었으며 서버가 새로운 리소스를 작성함

202 : 서버가 요청을 접수는 했는데, 아직 처리가 되지 않음

204 : 콘텐츠 없음, 서버가 요청을 성공적으로 처리 했지만 콘텐츠를 제공하지 않음

205 : 서버가 요청을 성공적으로 처리 했지만, 콘텐츠를 표시하지 않는다.

206 : 서버가 get 요청의 일부만 성공적으로 처리함

 

301 : 요청한 페이지를 새 위치로 영구적으로 이동( GET Head 요청에 대한 응답으로 이 응답을 표시하면 요청자가 자동으로 새 위치로 전달됨)

302 : 현채 서버가 다른 위치의 페이지로 요청을 응답하고 있지만, 요청자는 향후 요청시 원래 위치를 계속 사용함.

 

400 : 서버가 요청 구문을 인식하지 못할때

401 : 인증이 필요한 요청이지만, 권한이 없음, 또는 인증안됨을 뜻함

403 : forbidden 에러 : 서버가 요청을 거부!!

404 : 서버가 요청한 페이지를 찾을 수 없을 때

408 : 서버의 요청 대기가 시간을 초과 하였다.

 

500 : 서버에 오류가 발생하여 요청을 수행 할 수 없다.

501 : 서버에 요청을 수행할 수 있는 기능이 없다

502 : 서버가 게이트웨이나 프록시 역할을 하고 있거나 또는 업스트림 서버에 잘못된 응답을 받았다.

504 : 서버가 게이트웨이나 프록시 역할을 하고 있거나, 업스트림 서버에서 제때 요청을 받지 못함

...이외에도 다양한 응답 상태가 존재한다.





참고 : [Http 상태 코드 /위키백과](https://ko.wikipedia.org/wiki/HTTP_%EC%83%81%ED%83%9C_%EC%BD%94%EB%93%9C)

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

[gradle] CreateProcess error=206  (0) 2020.04.25
Git remote: Permission to  (0) 2020.03.08
CQRS란 ?  (1) 2020.01.19
STORM 정리  (0) 2017.12.18

CQRS

*Command Query Responsibility Segregation : *
명령과 쿼리의 역할을 구분한다는 의미

Command란? CURD(Create-Insert-Update, Delete)를 나타낸다.
Query란 ? Select(데이터 조회)의 책임을 분리한다는것이다.
버란트 마이어의 CQS가 CQRS의 출발이고, CQRS를 처음 소개 한 분은 Greg Young이다.

탄생
전통적인 CURD 아키텍처 기반에서 Application을 개발 및 운영 하다 보면 자연스럽게 Domain Model의 복잡도가 증가된다.
이때 유지보수에 대한 Cost는 증가되고, Domain Model은 점점 설계시 의도한 방향과는다르게 변질된다. Application Business 정책이나 제약은 거의 대 부분 데이터 변경작업에서 처리되고 Read는 단순 조회가 대부분이기 때문에, 이 두 업무를 동일한 도메인 모델로 처리하게 되면 도메인의 속성들의 복잡도가 증가하고, 설계와는 다르게 다른 방향으로 변질이 된다.

그래서 나온것이 '명령을 처리하는 책임!', '조회를 처리하는 책임!' 을 분리 구현하자! 라는 개념이 CQRS의 핵심이다.

참고 : 나만 모르고 있던 CQRS & EventSourcing
추가 자료 최신-기술-cqrs-처음-도입하기

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

[gradle] CreateProcess error=206  (0) 2020.04.25
Git remote: Permission to  (0) 2020.03.08
http 상태 코드  (0) 2020.01.19
STORM 정리  (0) 2017.12.18

yum Repository 만들기

  1. 이전 (1) 에서 미리 R설치에 대한 rpm 파일을 모두 다운 받았뒀다. 기본의 yum들을 백업 함

    $cd /etc/yum.repos.d
    //root 계정 로그인
    #su
    //백업 폴더 생성
    #mkdir bak
    // /etc/yum.repos.d/ 하위 repository, bak 폴더로 이동
    #mv . bak
    #ls
    bak

  2. 다운받았던 rpm 디렉토리(/home/morriskim/data/rpm)를 repository파일로 등록

vi /etc/yum.repos.d/morris.repo

[rpm]
name=morrisRepository
baseurl=file:///home/pduser/data/rpm
enabled=1
gpgcheck=0
  1. createRepository

    #createrepo /home/pduser/data/rpm

  2. yum repo 리스트 확인

이전의 PuzzleRepository 가 있는 지 확인

# yum repolist
Loaded plugins: fastestmirror, langpacks
Loading mirror speeds from cached hostfile
rpm                                                                                           | 2.9 kB  00:00:00
rpm/primary_db                                                                                | 247 kB  00:00:00
repo id                                            repo name                                                   status
rpm                                                morrisRepository                                            268
  1. yum 을 통한 설치

    $sudo yum install R

참고

local repository 만들기

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

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

내부 인터넷을 사용하는 곳에서는 다양한 yum install 에 있어서 설치가 불가능 할경우가 많다. 그래서 offline 으로 미리 다운을 받아가야한다. 그래서 local yum repository를 생성해 가기로 했다.

curl 이나 wget 으로 rpm 을 다운받아서할수 있지만 패키지 의 의존성을 각자 개별적으로 다운을 받아야한다 이럴때 함께 다운받으려면 ?

rpm 다운로드 하기

쉽게 다운로드 하려면 다음과 두 가지 메서드를 이용하면 패키지를 동시에 다운받을 수 있다.

  1. downloadonly

    $sudo yum install yum-plugin-downloadonly

    $sudo yum install --downloadonly

위의 명령어를 사용하면 default location 으로 /var/cache/yum/ rhel-{arch}-channel/packages 에 다운로드된다.

지정된 위치를 사용하려면

$sudo yum install --downloadonly --downloaddir=<directory> <package-name>
  1. yumdownloader

    $sudo yum install yum-utils

    // 단일 패키지만 다운로드
    $sudo yumdownloader

    // 의존성 rpm 들이 한꺼번에 다운로드됨
    $sudo yumdownloader --resolve

    //위치 지정해서 패키지 다운로드
    $sudo yumdownloader --resolve --destdir=
    $sudo yumdownloader --resolve --destdir

참고

How to Download A RPM Package with All Dependencies In CentOS

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

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

개인적인 테스트를 진행한 결과를 정리한 개인의 생각이므로, 제가 잘못알고 있는 것이면 댓글 달아주세요.

index segments _max count = 1 ?

인덱스를 고정하기 전에 먼저 force_merge를 실행하는 것이 좋습니다. 그러면 샤드별로 디스크에 하나의 세그먼트만 있게 됩니다. 또한, 압축률이 훨씬 향상되고, 고정 인덱스에 대해 집계 또는 정렬된 검색 요청을 실행할 때 필요한 데이터 구조가 간소화됩니다. 여러 세그먼트가 있는 고정 인덱스에 대한 검색을 실행하면 최대 수백 배의 성능 오버헤드가 발생할 수 있습니다.

POST /sampledata/_forcemerge?max_num_segments=1

https://www.elastic.co/kr/blog/creating-frozen-indices-with-the-elasticsearch-freeze-index-api

실습

기존 인덱스의 segments 의 수를 보자

아래를 보면 하나의 샤드당 segments 카운트는 8개로 나뉘어져있다.

이것을 하나의 세그먼트로 force merge를 해보자

$car_wash/_forcemerge?max_num_segments=1

해보기전

$curl -X GET "localhost:9200/car_wash/_segments?verbose=true&pretty" > car_wash_segments_default

Max_segments 크기 변경

$curl -X POST "localhost:9200/car_wash/_forcemerge/?max_num_segments=1&pretty"

{
  "_shards" : {
    "total" : 10,
    "successful" : 5,
    "failed" : 0
  }
}

변경 후 force merge

$curl -X GET "localhost:9200/car_wash/_segments?verbose=true&pretty" > car_wash_segments_forcemerge

car_wash_segments_default 와 car_was_segments_forcemenrge 두개의 파일을 비교 해보자

car_wash_segments_default는 한 샤드당 9개의 세그먼트로 각 세그먼트당 "memory_in_bytes" 의 값을 더해보았다.

값을 다 더해보면 61158 의 값이 나왔고,

"_shards" : {
    3     "total" : 10,
    4     "successful" : 5,
    5     "failed" : 0
    6   },
    7   "indices" : {
    8     "car_wash" : {
    9       "shards" : {
   10         "0" : [
   11           {
   12             "routing" : {
   13               "state" : "STARTED",
   14               "primary" : true,
   15               "node" : "uCyuJNg-TVu3E7g7nzRAZw"
   16             },
   17             "num_committed_segments" : 9,
   18             "num_search_segments" : 9,
   19             "segments" : {
   20               "_0" : {
   21                 "generation" : 0,
   22                 "num_docs" : 25,
   23                 "deleted_docs" : 0,
   24                 "size_in_bytes" : 23400,
   25                 "memory_in_bytes" : 6033,
   26                 "committed" : true,
   27                 "search" : true,
   28                 "version" : "7.5.0",
   29                 "compound" : true,
   30                 "ram_tree" : [
   31                   {
   32                     "description" : "postings [PerFieldPostings(segment=_0 formats=1)]",
   33                     "size_in_bytes" : 4794,
   34                     "children" : [
   35                       {
   36                         "description" : "format 'Lucene50_0' [BlockTreeTermsReader(fields=21,delegate=Lucene50Po      stingsReader(positions=true,payloads=false))]",
   37                         "size_in_bytes" : 4594,
   ....

car_was_segments_forcemenrge 의 segments의 갯수는 하나이고,

memory_in_bytes 의 값은 12268로 메모리가 줄어든 것을 확인할 수 있었다.

7   "indices" : {
   8     "car_wash" : {
   9       "shards" : {
  10         "0" : [
  11           {
  12             "routing" : {
  13               "state" : "STARTED",
  14               "primary" : true,
  15               "node" : "uCyuJNg-TVu3E7g7nzRAZw"
  16             },
  17             "num_committed_segments" : 1,
  18             "num_search_segments" : 1,
  19             "segments" : {
  20               "_9" : {
  21                 "generation" : 9,
  22                 "num_docs" : 2774,
  23                 "deleted_docs" : 0,
  24                 "size_in_bytes" : 1128655,
  25                 "memory_in_bytes" : 12268,
  26                 "committed" : true,
  27                 "search" : true,
  28                 "version" : "7.5.0",
  29                 "compound" : false,
  30                 "ram_tree" : [
  31                   {
  32                     "description" : "postings [PerFieldPostings(segment=_9 formats=1)]",
  33                     "size_in_bytes" : 11073,
  34                     "children" : [
  35                       {
  36                         "description" : "format 'Lucene50_0' [BlockTreeTermsReader(fields=21,delegate=Lucene50Pos     tingsReader(positions=true,payloads=false))]",
  37                         "size_in_bytes" : 10873,

일반적인 샤드의 segments의 크기는 61158

forcemerge 한 세그먼트의 메모리 byte 크기12268

Force merge 의 세그먼트의 메모리가 확 줄어든것을 볼수 있다.

세그먼트의 verbose로 살펴본 결과 segments.compound 의 값이 변경된것을 알수 있다. 무엇을 의미 하는것일까 ?

compound
    (Boolean) If true, Lucene merged all files from the segment into a single file to save file descriptors.

왜 그런것일까 ??

https://discuss.elastic.co/t/what-is-in-segments-memory/61651

indices.segments.terms_memory_in_bytes ??

역인덱싱 으로 되어있어서, segments로 나뉘어있어서, 하나로 합쳐지니까 메모리가 줄여지는거 아닐까??

아래의 내용들은 답을 이해 하기 위해 찾다가 참고가 된 문서인데 확실하지는 않지만, segments 에서 Terms 이 동일한것이 많아서 줄어들거나,

참고

Lucene Merge 설명

https://juanggrande.wordpress.com/2011/02/07/merge-policy-internals/

Maybe in your case some segments shares same terms or something else that duplicates in memory but belongs to different segments. After segment reduction same terms merged and so you have a little gain in memory. But it just my guess.

https://discuss.elastic.co/t/segments-memory-in-bytes-goes-down-after-reduction-of-segments-restart/41258/7

In my case, after merging segments into 1 segment using force merge 46, segments.terms_memory was decreased by 30%. (note that this percentage depends on your index characteristics)

I hope segment merging help you prevent adding more nodes (or resources, or money).

https://discuss.elastic.co/t/reducing-heap-usage-dedicated-to-indices-segments-terms-memory-in-bytes/68899

생각과 추측이 맞는지 테스트 해보기segments의 크기를 1로 테스트 해보기

조건 : 같은 데이터를 사용해서 segments가 여러개일때와 segments를 하나로 합쳤을때의 결과를 비교해봤다.

아래는 테스트 내용이다.

##인덱스 생성
PUT segments_test
##세그먼트 확인
GET segments_test/_segments



##데이터 삽입 X 3번 
POST segments_test/_doc
{
  "name":"cup",
  "text" : "the bowllike part of a goblet or the like."
}

3번의 데이터를 삽입한 결과 1번 샤드에 두개의 도큐먼트가 삽입된것을 알수 있다. 같은 도큐먼트 이지만, 메모리는 각 세그먼트 마다 가지고 있다.

{
  "_shards" : {
    "total" : 10,
    "successful" : 5,
    "failed" : 0
  },
  "indices" : {
    "segments_test" : {
      "shards" : {
        "0" : [
          {
            "routing" : {
              "state" : "STARTED",
              "primary" : true,
              "node" : "uCyuJNg-TVu3E7g7nzRAZw"
            },
            "num_committed_segments" : 0,
            "num_search_segments" : 0,
            "segments" : { }
          }
        ],
        "1" : [
          {
            "routing" : {
              "state" : "STARTED",
              "primary" : true,
              "node" : "uCyuJNg-TVu3E7g7nzRAZw"
            },
            "num_committed_segments" : 0,
            "num_search_segments" : 2,
            "segments" : {
              "_0" : {
                "generation" : 0,
                "num_docs" : 1,
                "deleted_docs" : 0,
                "size_in_bytes" : 4092,
                "memory_in_bytes" : 1698,
                "committed" : false,
                "search" : true,
                "version" : "7.5.0",
                "compound" : true,
                "attributes" : {
                  "Lucene50StoredFieldsFormat.mode" : "BEST_SPEED"
                }
              },
              "_1" : {
                "generation" : 1,
                "num_docs" : 1,
                "deleted_docs" : 0,
                "size_in_bytes" : 4092,
                "memory_in_bytes" : 1698,
                "committed" : false,
                "search" : true,
                "version" : "7.5.0",
                "compound" : true,
                "attributes" : {
                  "Lucene50StoredFieldsFormat.mode" : "BEST_SPEED"
                }
              }
            }
          }
        ],
        "2" : [
          {
            "routing" : {
              "state" : "STARTED",
              "primary" : true,
              "node" : "uCyuJNg-TVu3E7g7nzRAZw"
            },
            "num_committed_segments" : 0,
            "num_search_segments" : 1,
            "segments" : {
              "_0" : {
                "generation" : 0,
                "num_docs" : 1,
                "deleted_docs" : 0,
                "size_in_bytes" : 4092,
                "memory_in_bytes" : 1698,
                "committed" : false,
                "search" : true,
                "version" : "7.5.0",
                "compound" : true,
                "attributes" : {
                  "Lucene50StoredFieldsFormat.mode" : "BEST_SPEED"
                }
              }
            }
          }
        ],
        "3" : [
          {
            "routing" : {
              "state" : "STARTED",
              "primary" : true,
              "node" : "uCyuJNg-TVu3E7g7nzRAZw"
            },
            "num_committed_segments" : 0,
            "num_search_segments" : 0,
            "segments" : { }
          }
        ],
        "4" : [
          {
            "routing" : {
              "state" : "STARTED",
              "primary" : true,
              "node" : "uCyuJNg-TVu3E7g7nzRAZw"
            },
            "num_committed_segments" : 0,
            "num_search_segments" : 0,
            "segments" : { }
          }
        ]
      }
    }
  }
}

여기서 segments 의 크기를 병합 후에 확인 한다면?

POST segments_test/_forcemerge/?max_num_segments=1

GET segments_test/_segments

아래의 결과대로 1번의 샤드의 사용되는 메모리는 1698 바이트 의 두배가 되어야한다고 생각했지만, 메모리의 사용량은 1698 바이트 그대로 인것을 보면 segments의 term이 중복되는 경우에는 메모리의 양이 줄어든 것을 알수 있다.

{
  "_shards" : {
    "total" : 10,
    "successful" : 5,
    "failed" : 0
  },
  "indices" : {
    "segments_test" : {
      "shards" : {
        "0" : [
          {
            "routing" : {
              "state" : "STARTED",
              "primary" : true,
              "node" : "uCyuJNg-TVu3E7g7nzRAZw"
            },
            "num_committed_segments" : 0,
            "num_search_segments" : 0,
            "segments" : { }
          }
        ],
        "1" : [
          {
            "routing" : {
              "state" : "STARTED",
              "primary" : true,
              "node" : "uCyuJNg-TVu3E7g7nzRAZw"
            },
            "num_committed_segments" : 1,
            "num_search_segments" : 1,
            "segments" : {
              "_2" : {
                "generation" : 2,
                "num_docs" : 2,
                "deleted_docs" : 0,
                "size_in_bytes" : 4165,
                "memory_in_bytes" : 1698,
                "committed" : true,
                "search" : true,
                "version" : "7.5.0",
                "compound" : false,
                "attributes" : {
                  "Lucene50StoredFieldsFormat.mode" : "BEST_SPEED"
                }
              }
            }
          }
        ],
        "2" : [
          {
            "routing" : {
              "state" : "STARTED",
              "primary" : true,
              "node" : "uCyuJNg-TVu3E7g7nzRAZw"
            },
            "num_committed_segments" : 1,
            "num_search_segments" : 1,
            "segments" : {
              "_0" : {
                "generation" : 0,
                "num_docs" : 1,
                "deleted_docs" : 0,
                "size_in_bytes" : 4092,
                "memory_in_bytes" : 1698,
                "committed" : true,
                "search" : true,
                "version" : "7.5.0",
                "compound" : true,
                "attributes" : {
                  "Lucene50StoredFieldsFormat.mode" : "BEST_SPEED"
                }
              }
            }
          }
        ],
        "3" : [
          {
            "routing" : {
              "state" : "STARTED",
              "primary" : true,
              "node" : "uCyuJNg-TVu3E7g7nzRAZw"
            },
            "num_committed_segments" : 0,
            "num_search_segments" : 0,
            "segments" : { }
          }
        ],
        "4" : [
          {
            "routing" : {
              "state" : "STARTED",
              "primary" : true,
              "node" : "uCyuJNg-TVu3E7g7nzRAZw"
            },
            "num_committed_segments" : 0,
            "num_search_segments" : 0,
            "segments" : { }
          }
        ]
      }
    }
  }
}

주변 세차장 찾기 (2)

현재 위치를 중심으로 쿼리 만들기

현재 위치는 다양한맵의 주소에서 찾을수 있다.

구글 맵에서 검색을 하게 되면 쿼리 파라미터에 위도경도가 나오는것을 알수 있다.

https://www.google.co.kr/maps/place/%EC%8B%A0%EB%8F%84%EB%A6%BC%EC%97%AD/@37.5088099,126.8890174,17z/data=!3m1!4b1!4m5!3m4!1s0x357c9e5dbb76b179:0x2f88a2d1152886e2!8m2!3d37.5088099!4d126.8912061?hl=ko

위도 경도를 찾아서 다음과 같은 정보를 얻을수 있다.

이제 쿼리를 만들어보자

위치를 사용한 쿼리는 아래와같이 4가지의 종류가 있다.

  • Geo_shape
    • Intersects, disjoint, within, contains 등의 모양에 맞게 검색
    • Geoshape document
  • Geo_bounding_box
    • 사각형의 범위를 가지며 왼쪽 상단, 오른쪽 하단의 위도 경도를 사용하여 범위안의 값을 찾음
      bounding_box docuemnt
  • Geo_distance
    • 특정 위도 경도와의 거리를 사용하여 특정 거리안의 범위값을 찾음
      distance document
  • Geo_polygon
    • 특정 지점들을 연결연결 하여 다각형을 그리고 그 구역내의 범위를 찾음
      polygon document

스터디를 하는곳인 신도림역 37.5088099,126.8890174 을 중심으로 10Km 안에 주차장이 어디에 있는지 검색을 해봤다.

GET car_wash/_search
{
  "query": {
        "bool" : {
            "must" : {
                "match_all" : {}
            },
            "filter" : {
                "geo_distance" : {
                    "distance" : "10km",
                    "location": {
                        "lat" : 37.5088099,
                        "lon" : 126.8890174 
                    }
                }
            }
        }
    },"size":5
}

결과값

{
  "took" : 8,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 584,
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "car_wash",
        "_type" : "_doc",
        "_id" : "I_HOcW4BGQw9X5k0OQxe",
        "_score" : 1.0,
        "_source" : {
          "privider_name" : "3170000",
          "column12" : "서울특별시 금천구",
          "name" : "화성자동차정비공업사",
          "state" : "서울특별시",
          "location" : "37.460736,126.898655",
          "water_quality" : "433",
          "sector" : "정비업소",
          "address" : "서울특별시 금천구 시흥대로 304 (독산동)",
          "phone" : "02-3286-8572",
          "city" : "금천구",
          "date,provider_id" : "2019.9.10"
        }
      },
      {
        "_index" : "car_wash",
        "_type" : "_doc",
        "_id" : "J_HOcW4BGQw9X5k0OQxe",
        "_score" : 1.0,
        "_source" : {
          "privider_name" : "3170000",
          "column12" : "서울특별시 금천구",
          "name" : "금천자동차검사정비센타",
          "state" : "서울특별시",
          "location" : "37.441008,126.902064",
          "water_quality" : "559",
          "sector" : "정비업소",
          "address" : "서울특별시 금천구 시흥대로27길 26 (시흥동)",
          "phone" : "02-893-5500",
          "city" : "금천구",
          "date,provider_id" : "2019.9.10"
        }
      },
      {
        "_index" : "car_wash",
        "_type" : "_doc",
        "_id" : "n_HOcW4BGQw9X5k0OwxT",
        "_score" : 1.0,
        "_source" : {
          "privider_name" : "3170000",
          "column12" : "서울특별시 금천구",
          "name" : "동해자동차정비",
          "state" : "서울특별시",
          "location" : "37.470815,126.891905",
          "water_quality" : "273",
          "sector" : "정비업소",
          "address" : "서울특별시 금천구 두산로7길 10 (독산동)",
          "phone" : "02-851-4972",
          "city" : "금천구",
          "date,provider_id" : "2019.9.10"
        }
      },
      {
        "_index" : "car_wash",
        "_type" : "_doc",
        "_id" : "pPHOcW4BGQw9X5k0OwxT",
        "_score" : 1.0,
        "_source" : {
          "privider_name" : "3170000",
          "column12" : "서울특별시 금천구",
          "name" : "SK에너지(주)이가주유소",
          "state" : "서울특별시",
          "location" : "37.472984,126.897897",
          "water_quality" : "50",
          "sector" : "주유소",
          "address" : "서울특별시 금천구 시흥대로 441 (독산동)",
          "phone" : "02-861-2241",
          "city" : "금천구",
          "date,provider_id" : "2019.9.10"
        }
      },
      {
        "_index" : "car_wash",
        "_type" : "_doc",
        "_id" : "HfHOcW4BGQw9X5k0PQ0y",
        "_score" : 1.0,
        "_source" : {
          "privider_name" : "3170000",
          "column12" : "서울특별시 금천구",
          "name" : "대하운수(주)",
          "state" : "서울특별시",
          "location" : "37.466048,126.894731",
          "water_quality" : "53",
          "sector" : "운수업 등",
          "address" : "서울특별시 금천구 범안로16길 8 (독산동)",
          "phone" : "02-805-0487",
          "city" : "금천구",
          "date,provider_id" : "2019.9.10"
        }
      }
    ]
  }
}

+ Recent posts