[Go] To-do list 만들기

0xDave·2022년 8월 22일

Go

목록 보기
10/10
post-thumbnail

유튜브 튜토리얼을 보고 진행했지만, 사용한 mgo 패키지가 너무 오래돼서 그런지 서버 연결에 에러가 발생한다..🙀 가장 최신 패키지인 github.com/mongodb/mongo-go-driver를 사용해서 심폐소생술을 해보려 했지만 코드를 전부 다 뜯어고쳐야 하는 상황이 발생해서 아예 다른 프로젝트를 시작하는게 낫다고 판단했다. 그래도 튜토리얼을 진행하면서 여러 패키지의 용도와 공부했던 개념들을 정리하고자 글로 남겨본다.

사용한 패키지


1. chi ✨

chi는 HTTP 서비스를 만들 때 라우터를 만들어주는 라이브러리다. 라우터는 요청이 들어오는 웹페이지 주소와 들어오는 요청을 담당하는 함수를 서로 연결하는 역할을 한다. chicontext 패키지를 통해 만들어졌으며, 가볍고 빠르다는 장점이 있다. context는 특정 고루틴에 작업 가능한 시간, 작업 취소, 특정 데이터를 넣어주는 등 작업의 흐름을 제어하는데 사용되는 패키지다. context에 대한 자세한 얘기는 밑에서 더 설명하기로 하고, 예제 코드에서 사용된 부분을 살펴보자.

func main() {
	r := chi.NewRouter() //라우터 생성
	r.Use(middleware.Logger) // Logger는 각 요청의 시작과 끝을 기록하는 미들웨어. 요청 사항, 응답 상태 등에 대한 유용한 데이터를 제공
	r.Get("/", homeHandler) // 홈페이지로 요청이 들어오면 homeHandler 실행
	r.Mount("/todo", todoHandlers()) //다른 핸들러 붙임

	//http.Server는 struct 구조
	srv := &http.Server{
		Addr: port,
		Handler: r,
		ReadTimeout: 60*time.Second, //request를 읽는 최대 시간 설정
		WriteTimeout: 60*time.Second, //response를 작성하는 최대 시간 설정
		IdleTimeout: 60*time.Second, // 다음 요청을 기다리는 최대 시간 설정
	}
	}



2. os ⚙️


os는 low level에서 운영체제 기능에 대한 플랫폼과는 독립적인 인터페이스를 제공하는 패키지이다. 예제에서 사용한 것은 Signal이다. Signalsoftware interrupt라고 하는데, 외부에서 발생한 예상치 못한 비동기적 이벤트를 말한다.

단순한 예로 프로그램 실행 중에 터미널에서 Ctrl + c를 누르면 프로그램이 중단되는데, 이 때 Signal이 발생하는 것이다. Signal이 발생하면 kernel에 보관했다가 해당 프로세스에 전달된다. 전달된 Signal은 무시(ignore)하거나 처리 가능한 방법으로 해결하는 등 지정된 방법에 따라 처리된다.

대표적인 시그널의 종류는 다음과 같다.

예제에서 사용된 것은 signal.Nofity다.

	//signal 타입의 채널 생성
	stopChan := make(chan os.Signal)
    //Notify로 채널에 Interrupt signal 전송
	signal.Notify(stopChan, os.Interrupt)

os.Interrupt는 SIGINT를 의미한다.


3. mgo 📚


mgo는 MongoDB 패키지다. Dial()을 통해 url에 해당하는 새로운 세션을 만들고 SetMode를 통해 read preference를 설정한다.

	//url을 받아서 세션 생성
	sess, err := mgo.Dial(hostName)
	checkErr(err)
	//세션의 read-preference 설정
	sess.SetMode(mgo.Monotonic, true)
    //DB 생성
	db = sess.DB(dbName)

Read preference 종류

MongoDB에서 DB 노드가 장애가 나거나 문제가 발생하는 경우를 대비해 노드를 복제하는 Replication 기능을 제공한다. MongoDB 인스턴스에 문제가 생기면 복제 노드가 장애 노드를 즉시 대체한다. 그런데 문제가 없는 상황에서는 주(Primary) 데이어베이스에서만 데이터를 주고 받기 때문에 MongoDB 서버를 3대를 사용함에도 작업 분산 효과를 누리지 못한다. 이러한 비효율을 개서하는 방법으로 Read 작업을 다른 노드에서 처리할 수 있도록 설정 할 수 있다.

  1. Primary : 모든 read와 write 명령이 primary 노드에서 수행된다.
  2. primaryPreferred : 기본적으로 1번과 동일하지만 primary 노드가 문제가 생겼을 때 read 명령을 secondary 노드에서 수행한다.
  3. secondary : primary에서는 write 작업만 하고 read 명령은 secondary 노드에서 수행한다.
  4. secondaryPreferred : 기본적으로 3번과 동일하지만 secondary 노드가 문제가 생겼을 때 read 명령을 primary 노드에서 수행한다.
  5. nearest : write 명령은 primary 노드에서 수행하고, read 명령은 primary / secondary 상관없이 network latency 가 가장 적은 인스턴스에서 처리한다.

예제에서 사용한 Monotonic 모드는 첫 write 명령 이전에는 secondaryPreferred 모드와 같지만 그 이후에는 Primary 모드와 같다.


🍬 필요했던 개념


1. Context

고루틴에 다양한 기능을 추가해서 고루틴을 제어할 수 있게 하는 패키지다. 일정 시간 동안 고루틴이 진행되게 하거나, 외부에서 고루틴의 작업을 중단시킬 때 주로 사용한다. 쉽게 말해 고루틴에게 명령을 할 수 있다는 것이다.

a) 새로운 context 생성

context.Background()

Background 메소드로 빈 context를 만들 수 있다.


b) 취소 기능 context 생성(WithCancel)

ctx, cancel := context.WithCancel(context.Background())

WithCancel 메소드는 기존의 context를 인자로 받아서 취소 기능이 있는 context로 만들어준다. 이 때 취소 기능이 추가된 context와 함께 cancel 함수가 리턴되고, 새로운 Done 채널을 리턴한다. Done채널은 아래 조건에서 닫힌다.

  1. cancel 함수가 호출되거나
  2. 기존 context의 Done 채널이 닫힐 때 같이 닫힌다.

좀 더 자세한 사항은 이곳에 매우 매우 잘 설명돼있다.(읽다가 감동할 수도 있다.)


c) 시간이 포함된 취소 기능 context 생성(WithDeadline)

ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(2 * time.Second))

WithDeadline 메소드는 기존의 context와 시간을 인자로 받아서 기능이 추가된 context와 cancel 함수를 리턴한다. 여기서 만들어진 context는 인자로 받은 시간(Deadline)이 지나면 자동으로 cancel 되고, 그 전에 cancel 함수를 실행하면 작업이 중단된다.


d) 시간이 포함된 취소 기능 context 생성(WithTimeout)

ctx, cancel := context.WithTimeout(context.Background(), time.Duration(150)*time.Millisecond)

WithDeadline 메소드와 비슷하지만 인자로 받은 시간을 지금 시간과 더해서 내부적으로 Deadline을 설정한다는 점이 다르다. 타이머에서 시간을 설정할 때 생각하면 쉽게 이해할 수 있다.


e) key-value pair context 생성(WithValue)

context에 key를 입력했을 때 해당하는 value가 있다면 그 value를 리턴해준다.


2. 세션

세션에 대해 잘 설명되어 있는 글이 있어서 가져왔다.


3. BSON vs JSON

type (
	todoModel struct {
		ID        bson.ObjectId `bson:"_id,omitempty"`
		Title     string        `bson:"title"`
		Completed bool          `bson:"completed"`
		CreatedAt time.Time     `bson:"createAt"`
	}

	todo struct {
		ID        string    `josn:"id"`
		Title     string    `josn:"title"`
		Completed string    `josn:"completed"`
		CreatedAt time.Time `josn:"CreatedAt"`
	}
)

예제에서 2개의 struct를 사용했는데 하나는 bson형태로, 나머지 하나는 json 형태로 만들었다. BSON은 binary JSON으로, JSON과 동일한 구조이지만 binary 형태로 변경된 구조다. MongoDB에서 처음에는 JSON으로 개발을 했다고 한다. 하지만 JSON은 텍스트 기반이기 때문에 구문 분석이 매우 느리고, 공간 효율성이 떨어져서 binary 형태의 JSON을 고안하게 된 것이다.


4. sync.WaitGroup


출처 및 참고자료


  1. Golang 2021 Project - Build A Todo List In Golang - Part 2

  2. https://github.com/go-chi/chi

  3. [golang] 콘텍스트 (context)란? - 1탄 간략한 소개

  4. Go 언어 웹 프로그래밍 철저 입문: 5.3.4 sync.WaitGroup

  5. [Tucker의 Go 언어 프로그래밍] 25장 채널과 컨텍스트

  6. Go WaitGroup에 1외에 다른 값을 Add 하면?

  7. [Golang] 컨텍스트

  8. Go의 context 패키지 이해하기

  9. Golang Middleware

  10. 리눅스 시스템 프로그래밍 6장 - Signal

  11. [SP] 8강-1. 시그널(signal) 이란? (시그널 1/5)

  12. Session 이란?

  13. AWS DocumentDB(MongoDB) Replication 과 MongoEngine 설정 (Read Preference)

  14. [MongoDB] MongoDB에서 사용하는 JSON vs BSON

profile
Just BUIDL :)

0개의 댓글