반응형

자바8의 스트림 API 특징

선언형: 더 간결하고 가독성이 좋아진다.
조립할수있음: 유연성이 좋아진다.
병렬화: 성능이 좋아진다.

스트림이란 '데이터 처리 연산을 지원하도록 소스에서 추출된 연속된 요소'로 정의할 수 있다.
[딱 한번만 탐색할 수 있다]

스트림은 단 한번만 소비할 수 있다.

스트림 연산

java.util.stream.Stream 인터페이스는 많은 연산을 정의

filter, map, limit는 서로 연결되어 파이프라인을 형성한다. - 중간연산
collect로 파이프라인을 실행한 다음에 닫는다. - 최종연산

중간연산

filter나 sorted 같은 중간 연산은 다른 스트림을 반환
중간 연산의 중요한 특징은 단말 연산을 스트림 파이프라인에 실행하기 전까지는 아무 연산도 수행하지 않는다는 것이다.
즉 lazy하다는 것이다

최종연산

보통 최종 연산에 의해 List, Integer, void 등 스트림 이외의 결과가 반환.
forEach, count, collect처럼 스트림 파이프라인을 처리해서 스트림이 아닌 결과를 반환하는 연산을 최종 연산

반응형
반응형

LocalDate

현재시간

LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));

스트링 date 파싱하기

String date parse

LocalDate endDate = LocalDate.parse(endTime, DateTimeFormatter.ofPattern("yyyyMMdd"));

 

 

LocalDateTime

현재시간 알기

LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));

스트링 date 파싱하기

String date parse

LocalDateTime endDateTime = LocalDateTime.parse(endTime, DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));

날짜 데이터로 반환

LocalDate targetDate = LocalDate.of(2019,11,12);
 //결과 : 2019-11-12

 

mybatis-typehandlers-jsr310 아티팩트는 데이터베이스 컬럼의 날짜/시간 타입을 

Java 8부터 추가된 LocalDateLocalTimeLocalDateTimeYearMonth 클래스로의 자동 맵핑을 지원한다. 

 

MyBatis 3.4 버전부터 자동 지원되며 이전 버전은 별도의 typeHandler 등록이 필요하다.

3.4 이후부터는 별도로 등록없이 사용가능하다.

type 핸들러에 localDate 관련된 클래스 있는지 확인해보면 된다.

 

 

반응형
반응형

도커 젠킨스 이미지 찾기

docker search jenkins

제일 위에 검색되는 jenkins 를 pull 받아보니 설치가 안되어 그 아래 jenkins/jenkins 를 받아본다.

 

docker pull jenkins/jenkins:lts

위와 같이 이미지를 받아도 되고, 

나 같은 경우는 docker compose 로 그냥 실행했다.

 

version: "3.3" # 파일 규격 버전
services: # 이 항목 밑에 실행하려는 컨테이너 들을 정의
  jenkins:
    image: jenkins/jenkins
    container_name: jenkins
    ports: 
      - "8080:8080"
      - "50000:50000"
    volumes:
      - /Users/유저명/폴더명:/var/jenkins_home

8080 포트는 바꾸면 설정을 따로 변경해 주지 않는 이상 디폴트로 처음에는 8080 으로 bind 시켜줘야 한다.

 

docker 로 jenkins 를 설치해주고 나면

Administrator password 를 입력해주라고 한다.

 

이 비번을 알려면 

docker exec -it jenkins /bin/bash 접속

cd /var/jenkins_home/secrets

cat initialAdminPassword

위 처럼 docker jenkins 에 접속해서 initalAdminPassword 를 조회 하면 된다.

 

 

 

 

비밀번호만 입력해주고 나오는 화면 그냥 클릭만 했더니 jenkins 앱은 올라갔다.

 

 

반응형
반응형

스프링에서 okhttp3 를 사용중 로그에 다음과 같은 오류 메시지가 떴다.

 

okhttp3 사용 중에 간헐적으로 unexpected end of stream on [주소] 가 나왔다.

 

request 를 요청받는 서버 설정마다 다른 것 같다.

해당 원인은

요청받는 서버의 keep_alive timeout 이 okhttp 로 요청하는 클라이언트 서버보다 timeout 시간이 낫기 떄문이다.

다시 말하면 클라이언트 서버가 timeout 이 받아주는 서버 timout 보다 길다.

 

나의 경우는 Okhttp3 로 요청하고 나서 프로세스가 조금 긴 경우에 다음과 같은 현상이 나왔다.

 

클라이언트가 서버에서 데이터를 받고나서 서버의 keep_alive timeout 시간이 지났음에도 클라이언트에서는 프로세스가 끝나지 않기 때문에 발생한다.

이런 경우 간단하게 해결 방법은 okhttp request 객체에 

addHeader("Connection","close") 

만 추가해주면 됐다.

 

Request request = new Request.Builder()
                .url(requestUrl)
                .addHeader("Connection", "close")
                .get()
                .build();

 

 

 

나의 경우 서버에서 데이터를 받아와서 처리하는데 많은 로직이 있어 처리시간이 짧지 않았고, 프로세스를 처리 하는 도중 요청받는 서버의 keep_alive timeout 시간이 지나 다음 오류를 뱉었다.

데이터를 받아 온 후라 다음 오류가 나도 상관없었지만, 오류를 모니터링 할때 보기 안좋기 때문에 해결해 주었다.

 

예를 들어 keep_alive timeout 이 긴 서버의 경우는 해당 오류가 나지 않을 것이다.

 

참고문헌

github.com/square/okhttp/issues/2738

 

반응형
반응형

Index 란

DB의 검색을 빠르게 하기 위해 미리 데이터의 순서를 정리해두는 과정

Index는 MongoDB에서 데이터 쿼리를 더욱 효율적으로 할 수 있게 해준다.

인덱스가 없이는, MongoDB는 collection scan – 컬렉션의 데이터를 하나하나 조회 – 방식으로 스캔을 하게 된다.

모든 도큐먼트를 스캔해야되는 비효율성을 줄임

 

한 쿼리당 하나의 index 만 유효하다.

두개의 index가 필요하다면 복합 index를 사용하면 된다.

 

* B트리

: 내부적으로 B-Tree 알고리즘을 이용하여 인덱스를 구성한다.

 

사용시 주의할 점

: 모든 인덱스를 갱신해야 하기 떄문에 모든 쓰기 작업은 인덱스 때문에 더 오래 걸림

: Collection 당 최대 64개까지 인덱스를 지닐수있지만, 2~3개만 지니는게 좋다.

: 몽고디비의 인덱스는 RDBMS와 유사하게 작동함

: 인덱스 구축시 background 옵션을 사용하면, 비동기로 작업이 가능하긴하지만 느리다.

 

 

Index 종류 

기본 인덱스 _id

모든 MongoDB의 컬렉션은 기본적으로 _id 필드에 인덱스가 존재합니다. 만약에 컬렉션을 만들 때  _id 필드를 따로 지정하지 않으면 mongod드라이버가 자동으로 _id 필드 값을 ObjectId로 설정해준다.

Single(단일) 필드 인덱스

사용자가 지정 할 수 있는 단일 필드 인덱스가 있다.

Compound (복합)  필드 인덱스,

두개 이상의 필드를 사용하는 인덱스를 복합 인덱스라고 부른다. 다음 이미지와 같이 첫번째 필드 (userid)는 오름차순으로, 두번째 필드 (score)는 내림차순으로 정렬 해야 하는 상황이 있을때 사용한다.

Multikey 인덱스

필드 타입이 배열인 필드에 인덱스를 적용 할 때는 Multikey 인덱스가 사용됩니다. 이 인덱스를 통하여 배열에 특정 값이 포함되어 있는 document를 효율적으로 스캔

Geospatial(공간적) Index

지도의 좌표와 같은 데이터를 효율적으로 쿼리하기 위해서 (예: 특정 좌표 반경 x 에 해당되는 데이터를 찾을 때) 사용되는 인덱스

Text 인덱스

텍스트 관련 데이터를 효율적으로 쿼리하기 위한 인덱스

해쉬 (hashed) 인덱스

이 인덱스를 사용하면 B Tree가아닌 Hash 자료구조를 사용합니다. Hash는 검색 효율이 B Tree보다 좋지만, 정렬을 하지 않습니다.

 

인덱스 사용

인덱스 확인

> db.[컬렉션명].getIndexes()    //    Collection의 인덱스 확인

인덱스 생성

> db.[컬렉션명].ensureIndex({name:1})    //    1이면 오름차순, -1 이면 내림차순

인덱스 생성(백그라운드에서 생성, 비동기방식)

 

> db.[컬렉션명].ensureIndex({name:1},{background:true})
인덱스 생성시 오래걸리면 백그라운드에서 생산해야함.

 

인덱스 생성( 고유인덱스 

> db.[컬렉션명].ensureIndex({name:1},{unique:true})    //    unique 속성을 지정해서 중복데이터가 저장되지 못하게 하여, 데이터 저장과 검색속도를 늘린다.

 

* 인덱스 생성( 중복데이터 삭제 )

> db.[컬렉션명].ensureIndex({name:1},{unique:true, dropDups:true})    //    Unique 하게 했을 때 이미 중복된 데이터가 있을 경우 중복되는 데이터는 삭제하고 인덱스를 저장한다

 

* Partial (부분적) 속성

> partial 속성은 document의 조건을 정하여 일부 document에만 인덱스를 적용 할 때 사용된다,.

partial 속성을 사용하면, 필요한 부분에만 인덱싱을 사용하여 저장공간도 아끼고 속도를 더 높일수 있다.

visitors 값이 1000 보다 높은 document에만 name 필드에 인덱스 적용

db.[컬렉션명].createIndex( { name: 1 }, { partialFilterExpression: { visitors: { $gt: 1000 } } } )

 

* ttl 속성 인덱스 생성

db.[컬렉션명].createIndex( { "notifiedDate": 1 }, { expireAfterSeconds: 3600 } )

예제: notifiedDate 가 현재 시각과 1시간 이상 차이나면 제거

document가 만료되어 제거 될 때, 시간이 아주 정확하지는 않다. 만료되는 document를 제거하는 thread는 매 60초마다 실행된다.

 

인덱스 삭제 

> db.[컬렉션명].dropIndex({name:1})    //    해당 인덱스 제거

 

* 인덱스 삭제( 모든 인덱스)

> db.[컬렉션명].dropIndexes()    //    _id를 제외한 모든 인덱스 제거

 

 

몽고디비 공식 문서 (인덱스 가이드)

docs.mongodb.com/manual/indexes/

 

Indexes — MongoDB Manual

MongoDB provides a number of different index types to support specific types of data and queries. Text Indexes MongoDB provides a text index type that supports searching for string content in a collection. These text indexes do not store language-specific

docs.mongodb.com

 

반응형
반응형

vue prop data 를 사용하다가

 

Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders

이 오류를 본 적이 있다.

 

이 오류가 난 경우는 props data 를 받고 이 props 데이터를 변경해주었더니 생긴 오류다.

이 props 데이터를 위로 올리고 이 올린 데이터를 또 props 로 내려서 하위 자식에서 쓰려했더니 생긴 오류다.

 

props 에 대한 vue 의 공식 문서 설명이다.

일반적으로 prop을 변경시키고 싶은 유혹을 불러 일으킬 수있는 두 가지 경우가 있습니다.
1. 이 prop는 초기 값을 전달 하는데만 사용되며 하위 컴포넌트는 이후에 이를 로컬 데이터 속성으로 사용하기만 합니다.
2. prop는 변경되어야 할 원시 값으로 전달됩니다.

https://kr.vuejs.org/v2/guide/components.html#%EB%8B%A8%EB%B0%A9%ED%96%A5-%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%9D%90%EB%A6%84

- vue 공식문서

 

자식으로 내려온 props 데이터를 고치면 부모 데이터도 수시로 바뀐다고 생각했지만, 데이터 흐림이 단방향이므로 하위 데이터를 바꾼다 하더라도 부모의 데이터를 바꿀수 없었다..

 

그래서 eventBus 를 통해서 부모의 데이터를 바꿔준다.

 

여기까지는 괜찮지만 초기 렌더링시에 문제가 생길 수 있다.

이유는 데이터가 비동기적인 데이터를 가져오기 때문인데, 

 

인스턴스 생성 순서는 부모 -> 자식이며, 마운팅 순서는 자식->부모 

이기 떄문에 비동기적으로 데이터를 부모에서 자식으로 줄때 문제가 생긴다. 이런 문제를 아래 코드를 예시로 해결하자.

 

 

비동기적인 상황에서

부모가 자식에게 데이터를 내려주고 부모 컴포넌트가 바뀐데이터를 받는 방법

부모 컴포넌트

<template>
<date-picker
:propDate="dateData"
v-on:update:dateSettting="setDate"
/>
</template>
<script>
export default {
  data () {
    return {
    	dateData: '' // 비동기 데이터
    }
  },
  methods: {
    get () { // 비동기호출데티어
        http
          .get('sampleUrl')
          .then(response => {
            this.dateData = response.data
          })
          .catch(e => {
           
          })
          .finally(() => {
          })
      }
    },
    setDate (value) { // 이벤트버스 호출시 실행
      this.dateData = value
    },
  }  
</script>

자식 컴포넌트

<template>
  <div >
    <datepicker
      class="datepicker"
      placeholder="예) 2019-07-27"
      :language="languages['ko']"
      format="yyyy-MM-dd"
      ref="openDate"
      v-model="date"
    />
  </div>
</template>

<script>
import Datepicker from 'vuejs-datepicker/dist/vuejs-datepicker.esm.js'
import * as lang from 'vuejs-datepicker/dist/locale'

export default {
  props: {
    propDate: String
  },
  data () {
    return {
      languages: lang
      // date: this.propDate // 하위 컴포넌트부터 값이 정해지므로 초기렌더링시 값이 안내려온다
    }
  },
  computed: {
    date: {
      get () {
        console.log('get')
        return this.propDate
      },
      set (newVal) {)
        this.$emit('update:dateSettting', newVal)
      }
    }
  },
  components: {
    Datepicker
  }
}
</script>

 

부모가 먼저 생기지만 마운팅 순서는 자식이 먼저이기 때문에 초기 렌더링시 값이 비어있다.

이러한 이유로 위 코드에서 처럼 자식에 props 데이터를 자식 데이터에 연결해서 쓸때 data() 속성을 사용하지 않고,

computed 를 통해서 사용해야 한다.

 

이런 비동기적인 props를 전달받는 상황이라면 computed속성을 사용하는 것이 맞다

 

참고문헌

https://kjwsx23.tistory.com/357
[Vue.js] props로 받은 데이터를 data로 사용하기

https://stackoverflow.com/questions/45943682/how-to-initialize-data-properties-with-prop-values
How to Initialize Data Properties with Prop Values

 

반응형
반응형

local 에서 docker 를 이용햇 kafka 서버를 구축하자

 

docker search kafka 를 통해 검색해 보면 

wurstmeister/kafka  가 스타가 제일 많다.

https://hub.docker.com/r/wurstmeister/kafka -- 여기에서 kafka docker 관련 옵션 설명 확인가능하다.

 

kafka in docker 구조

도커 카프카 네트워킹에 대한 설명 레퍼런스이다.

github.com/wurstmeister/kafka-docker/wiki/Connectivity 

docker 로 kafka 를 올리면 다음과 같은 구조가 된다.

multiple 카프카 브로커로 설정도 가능하다.

이런식으로 구성해주면 

다음과 같이 9092 단일포트로 브로커가 구성된다.

 

 

단일 카프카 브로커일때는 

# KAFKA_ADVERTISED_HOST_NAME 옵션을 127.0.0.1 로 하겠지만 multiple 로 할때는 외부에서 접근 가능한 ip 를 넣어야 한다.

 

docker-compose-yml 작성

version: '3.3'
services:
  zookeeper:
    image: wurstmeister/zookeeper
    container_name: zookeeper
    ports:
      - "2181:2181"
  kafka:
    image: wurstmeister/kafka:2.12-2.5.0
    container_name: kafka
    ports:
      - "9092:9092"
    environment:
      KAFKA_ADVERTISED_HOST_NAME: 127.0.0.1
      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock

KAFKA_ADVERTISED_HOST_NAME는 본인의 docker host ip로 수정

multi broker를 사용하지 않고 로컬용이므로, 127.0.0.1로 사용

 

kafka 확인

카프카 툴로 접속 확인

또는 docker 로 접속 후 kafka-topics.sh 를 실행하여 확인가능하다.

# docker container exec -it kafka bash
# kafka-topics.sh --list --bootstrap-server localhost:9092 

kafka 도커에 접속 후 kafka 토픽 리스트를 조회할 수 있다.

 

카프카 공식 문서

kafka.apache.org/quickstart

반응형
반응형

mysql 에는 rownum 이라는 키워드가 없다,

그래서 변수 선언을 통해서 임의로 rownum 을 표시할 수 있다.

 

rownum 생성 방법

SELECT
  @rownum:=@rownum+1 as no
  table.*
FROM
  table 
where 
  (@rownum:0)=0

where 절에서 변수를 초기화 하고 사용하는 방법이다.

select 절보다 where 절에서 먼저 실행되기 때문에 where 절에서 변수 선운 후 사용 가능하다.

 

또는 아래와 같은 set 키워드로 변수를 선언 가능하다.

SET @rownum:=0;
SELECT
  @rownum:=@rownum+1 as no
  table.*
FROM
 table;

 

반응형

+ Recent posts