Go 하면 떠오르는 단어 Goroutines
실제로 Go를 구현하다가 뭔가 동시에 해야한다 싶으면 "go" 만 적으면 되니... 얼마나 편한가.
Goroutine 관련 자료는 매우 많아서 잘 찾으면 된다.
최근에 궁금한건 Go Server로 들어온 특정 Data를 local file 에 deadlock 없이 잘 Read/Write 하는 방법~
만약 request handler에서 goroutine을 생성했다면 channel 을 활용하면 될것같은데, 난 단순히 go server에서 알아서 goroutine 생성하여 호출된 handler 에서 뭔가 local file 로 deadlock 없이 작업을 하고 싶었다.
첫번째 접근) thread id 별로 file 을 append mode 로 만들면 되지 않을까?
그러기 위해서는 현재 호출된 handler의 Thread ID를 알아야 한다.
기본적으로 runtime.GOMAXPROCS 의 default가 runtime.NumCPU 니 thread 가 1개 이상은 될테니..
Q) handler가 실행된 goroutine이 어느 thread에서 돌고 있는지 알수 있을까?
go에서 얘기하는 concurrency 는 하나의 thread에서도 가능한 컨셉인데. 당연히 알수 없겠지.
알려면 runtime.LockOSThread 로 고정시키는 방법이 있겠지만, 그러면 성능이 떨어질것이다.
Q) 그럼 goroutine의 id를 알수 있을까?
의도적으로 go 에서는 goroutine id를 알수 없게 했다. https://go.dev/doc/faq#no_goroutine_id
두번째 접근) 안전하게 그럼 Mutex 를 쓰자
결국 Mutex를 써서 Lock/Unlock을 해야할텐데.
서버가 요청 몇개 받는것도 아니고... mutex 하나로 한다면 비효율적이지 않나?
여러 mutex를 사용해서 file 도 여러개 하면 좋을텐데.
Q) 요청을 잘 묶을 단위가 뭐가 있을까?
Request API를 보다보니, remoteAddr IP:port 를 제공하고 있고 보통 port는 일정 pool을 가지고 사용할테니. 이걸로 활용.
Q) port 별 mutex 를 관리하고 싶은데 어떻게 할까?
sync.Map 을 사용
func readFile(port string) {
mu := getFileMutex(port)
mu.Lock()
defer mu.Unlock()
contents, _ := os.ReadFile(port)
doSomething(contents)
}
func writeFile(port, data string) {
mu := getMutex(port)
mu.Lock()
defer mu.Unlock()
file, err := os.OpenFile(port, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666)
if err != nil {
fmt.Println(err)
return
}
defer file.Close()
_, err = file.Write([]byte(data))
if err != nil {
fmt.Println(err)
}
}
var mutexes sync.Map
func getMutex(fileName string) *sync.Mutex {
if mutex, ok := mutexes.Load(fileName); ok {
return mutex.(*sync.Mutex)
}
mutex := &sync.Mutex{}
mutexes.Store(fileName, mutex)
return mutex
}
local에서 Locust 로 3000 user 까지 테스트했을때 안정적으로 특별한 deadlock 문제 없이 동작 확인~
'자습' 카테고리의 다른 글
AWS ASG lifecycle Hook (remotely run shell command on EC2) (0) | 2024.03.29 |
---|---|
AWS EC2 X-Ray Enable (0) | 2024.02.24 |
Spring Native (0) | 2022.05.14 |
go gRPC Server & gRPC Gateway (0) | 2021.09.20 |
Kong Gateway + Konga (0) | 2021.08.29 |