ks.dgoon.lee log

취미코딩 근황


2025/01/06 15:59:21 #dev #nginx #digital ocean #aws #linux #server #idc #selenium #headless #python #야크쉐이빙 #llama #llm #playwright #vultr #D-TaskQueue #ollama #api #만세력 #사주 #boinc
Attachments:

Ollama API wrapper

개인 머신에서 llama 돌려두고 쓰는게 꽤 유용해서, 밖에서도 쓸 수 있도록 API를 만들어 덮었다.

  • 2080 TI X 4 (VRAM 44GB) 윈도에 ollama로 llama3.3:70b 4Q 모델 띄우기
  • 윈도에서 nginx 띄워서 reverse proxy 로 ollama endpoint 감싸기
  • 바로 옆에 있는 리눅스 머신에서 FastAPI 로 proxy api server 만들어 띄우기 + JWT 기반 인증
  • 리눅스 머신에서 nginx 로 감싸고, virtualhost 설정 및 ssl offloading
  • 공유기에서는 포트포워딩 설정

이렇게 하면 https 엔드포인트에 jwt 인증을 필요로 하는 ollama endpoint 가 만들어진다. 이제 기존의 ollama api 를 사용하던 코드에 jwt 인증 절차만 추가하고 엔드포인트 바꿔주면 된다. 인증 절차 외에 나머지 API는 그대로 중계해주니까.

이렇게 해두고 세계 이곳저곳에 뿌려져있는 개인서버들에서 동작 테스트를 해보니 잘 된다. 굿.




D-TaskQueue

개인적으로 띄워둔 머신이 물리&가상 합쳐서 총 1X 개 정도 된다. 집, 작업실, IDC, AWS, DigitalOcean, Vultr 모두 사용중이고 지역적으로도 한국, 싱가폴, 미국, 시드니 등 여러나라에 걸쳐 있다. 가끔(이 아니라 자주) 브라우저로 scraping 할 일이 생기는데, playwright 나 selenium 으로 실제 브라우저를 띄우는 것은 아무리 내가 잘 해봐도 속도가 느리기 마련이고, 한 머신에서 너무 빠르게 긁으면 막히기 일쑤다. 그래서 여기저기 뿌려둔 서버들을 활용하고 싶은 생각이 들었는데...

하여 여러 머신들에 작업을 쫙~! 뿌리고 결과를 쫙! 모을 수 있는 플랫폼이 뭐 있나 찾아봤다. 지인들+LLM에게 물어보니 다양한 도구나 플랫폼들을 언급하더라.

ray, dask, k8s, airflow, EMR, spark, celery, kafka ... et cetera

병렬/분산 처리 플랫폼, 컨테이터 관리 도구, 분산 큐 등 다양한게 나왔는데 내가 하려는 작업을 간단하게 + 빠르게 + 안정적으로 할 수 있으려나 살펴보니 뭔가 이거다.. 싶은건 안 나왔다. 결국 나이브하게 boinc-like 시스템을 직접 만들어 쓰자고 결론. 이름은 D-TaskQueue 라고 지었다.

API

  • 토큰 발급을 비롯한 인증 APIs
  • Task 생성, 조회, 성공/실패 결과 보고, 결과 확인 등 Task 를 다루는 APIs

CLI

  • 커맨드라인에서 API 를 이용해서 작업을 할 수 있는 툴을 만들었다.
  • 워커는 한번 돌려두면 되고, 그 외에 task 를 제출하거나 상태 확인, 결과 모으기 등은 모두 커맨드라인을 사용해서 할 수 있었다.
(dtq) $ ./cli.py 
Usage: cli.py [OPTIONS] COMMAND [ARGS]...

  D-Task Queue CLI.

Options:
  --help  Show this message and exit.

Commands:
  get-result      Get the result for a specific task.
  get-task        Get a task for the specified worker.
  get-tasks       Get the list of all tasks with details.
  login           Log in to the API and save access token.
  notify-failure  Notify the API about a task failure.
  submit-result   Submit a result for a completed task.
  submit-task     Submit a new task with data type for executable and input.
(dtq) $ 
  • 여기에서 작업 코드와 입력파일 등을 준비해서 submit-task 를 하면 API 로 전달한다.

Worker

  • 워커는 API 로부터 get-task 로 작업을 하나 가져와서,
  • 해당 task 에 지정된 작업 코드와 입력파일을 획득하고,
  • 작업 코드 실행해서 출력 파일을 만들고,
  • 성공한 경우 submit-result / 실패인 경우 notify-failure 를 한다.
  • 그리고 다시 get-task 실행해서 다음 작업으로 넘어간다

Task manipulation

몇만개 정도 url 에 대해서 브라우저를 열어 페이지를 가져와야 했는데, 그냥 머신 하나에서 돌리니까 적당히 sleep 하면서 처리하면 예상시간이 40만초(대충 5일정도...)로 계산되더라...

이제 API, Worker 들이 준비되었으니, task 를 등록하기 시작했다.

  • url 을 파일 하나에 30개씩 들어가도록 쪼개어 저장했다. 아주 많은(4자리) 입력 파일이 생겼다.
  • url 목록 파일을 입력으로 받고, playwright 로 페이지를 열어서 필요한 정보를 추출한 후에, 결과를 파일로 저장하는 코드 작성. "work.py" 라고 하자. 일단 url 두세개에 대해서 잘 동작하는것 확인.
  • TASK-ID 는 "TASK-0000" 부터 1식 증가시키면서 할당
(base)$ ./cli.py submit-task
Usage: cli.py submit-task [OPTIONS] TASK_ID EXECUTABLE_FILE INPUT_FILE TIMEOUT
Try 'cli.py submit-task --help' for help.

Error: Missing argument 'TASK_ID'.
(base)$ 
  • 쉘 스크립트로 모든 입력 파일에 대해서, work.py 를 executable 로 하여 루프돌며 task 등록.
  • timeout은 task 를 할당한 후 지정 시간이 지나는 동안 보고가 없으면 실패 카운트를 늘리고 다른 worker 에게 다시 할당하는 기준 시간이다. url 30개씩이니까 오래 걸려봐야 10분을 안넘기겠지만, 혹시 몰라서 1800(=30분)을 주었다.

task 를 생성하기 시작하자 뿌려둔 worker 들이 하나씩 가져가서 각자 처리를 시작했다. 대충 task 하나 처리에 5~6분 정도 걸렸다. (url 하나에 10몇초 정도) 최종적으로 걸린 시간을 보니 400K seconds (약 5일) -> 25K seconds (7시간), 거의 붙인 worker 개수에 비례해서 그대로 단축되었다.

  • 완료된 task 에 대해서는 실행 결과 파일을 가져갈 수 있는 url 을 획득할 수 있다. 다 끝난 다음에 쉘스크립트로 루프 돌면서 curl RESULT_URL >> result.txt 하면 결과를 다 모을 수 있다. Task ID 순서대로 하면 원래 순서도 유지된다.
(base)$ ./cli.py get-result TASK-map_links_0516
Task ID: TASK-map_links_0516
Finished At: 2025-01-05T10:41:13.553292
Result URL: /results/TASK-map_links_0516_output.data

후속작업

  • executable 자체를 전달하는 방식이기 때문에, 임의의 사용자가 task 를 제출할 수 있다면 매우 위험하다. 혼자 쓰는 물건 수준을 넘어가려면 worker 를 컨테이너화 해야 할 것 같다. 하지만, 내가 필요한건 이미 얻었기에 특별한 일이 없다면 안할 것 같다.
  • CLI 말고 웹 인터페이스 만들면 좋겠다 싶지만, 역시 혼자 쓰는거라서... 나는 CLI 가 편하니까.
  • 써보니 꽤 유용했고, 딱히 에러도 없었다. 깜빡하고 서버 한대를 중간에 리붓해 버렸는데, 하던 task 는 타임아웃 처리되어 다시 할당되어 잘 완료되었다. 혹시 같은 task 를 여러 worker 가 할당받아 하더라도 각 단위 task 는 idempotent 하기 때문에 문제 없다.
  • 워커는 일이 없는 경우 리소스도 거의 안 쓰기 때문에 모든 개인머신에 시스템 재시작시 자동시작 되도록 설정했다.
  • 사실 더 열심히 찾아보면 굳이 직접 코드 안 만들고 가능했을지도 모른다. 하지만 야크쉐이빙은 항상 즐거우니까. 코드작업 + 서버 설정 + worker spawning 하는데 몇시간 정도 걸렸는데, 최종적으로 단축한 시간이 4일정도니까 가성비 나쁘지 않은 취미생활이었다.




유튜브 다운로더 - 인스타 릴스 다운로드 기능 추가

가족들이랑 같이 쓰려고 유튜브 URL 을 넣으면 다운로드 받을 수 있는 시스템을 만들어 두었다. Gifer 프로젝트가 발전해서, 구글로그인도 붙이고 다운로드 히스토리도 남게 했다. 원래 있던 기능으로는 오디오 파일만 다운로드 받기, 초 단위로 시작과 끝을 지정해서 클립 다운로드 받기, 퍼가기 쉽게 CDN 에 바로 업로드하기 등등이 가능.

기능 추가 요청을 받아서, 인스타그램 릴스도 다운로드 받을 수 있게 업데이트했다.






사주 세우기

요새 고위 정치인들이 빠져있다는 걸로 무속신앙에 대한 관심이 뜨겁다. 그거랑 직접적인 상관은 없지만, 취미삼아 만세력을 만들던게 있었다. 만세력 API를 먼저 만들고, 그 API 로 뷰를 그렸다.혹시 만세력 API 쓰고싶은분은 연락하세요~ 호호호

  • 한국 천문연구원에서 제공하는 1900년~2050년까지의 양력, 음력, 율리어스력, 천간지지 정보를 다 긁어서 DB 저장
  • ephem 패키지 가져다가 1900년부터 2100 년까지의 모든 절기 날짜와 시각을 계산해서 DB 저장
  • 생년월일시+성별 입력받아서, 우리나라 표준시 및 서머타임 보정 - 표준시 기준이 달랐던 적이 있다...
  • 연월일시에 대한 사주팔자 계산
  • 절기 정보 가져기 대운수 및 정확한 대운값 계산
  • 세운(연운) 계산
  • 월운 계산
  • 일진 달력
  • 여러가지 자료를 참고해서 신살 계산(귀인이나 살 같은거)
  • 음양+오행 기반으로 십신 계산해서 모든 천간 지지에 붙이기

까지 해두었다. 같은값 매번 입력하는게 성가셔서 저장해둘 수 있게 하려고 구글로그인도 붙여둠.

얼마 전 친구집에서 연말모임을 할 때에 아주 좋은 안줏거리였다. 재밌긴 재밌다.

사실 사주 말고, 별자리 운세도 책 보고 만들었던게 있는데 그건 수호행성이 어쩌고, 태양과 달과 수호행성과 지구가 이루는 각이 120도가 어쩌고 270도가 어쩌고 90도면 어쩌고 이런 식이더라. 역시 아스트로 패키지의 도움을 받아서 뚝딱뚝딱. 행운의 색이나 숫자는 수호행성 위치를 시드로 사용한 랜덤 ( ...) 그냥 재미다. ㅋㅋ


만세력에는 아직 버그가 하나 있다. 짬 나면 고쳐야 하는데 계속 미루는 중이다. 바로 "음력에는 2월 30일이 존재한다. 그런데 프로그래밍 언어의 Datetime 객체는 2월 30일을 넣을수가 없다" 는 것. 가장 최근 음력 2월 30일은, 양력 2024년 4월 8일이었다.


요새 이런 유사과학/미신 관련 코드를 만들면서 느낀 것은,

사주도 별자리도 코드로 만들어 보면 신비가 벗겨진다

는 것. 오늘의 마지막 짜투리 생각:

  • 코드로 만들면 사라지는 신비: 사주, 점성술
  • 코드로 (아직?) 만들 수 없는 신비: 신, 종교
  • 코드로 만들면 더 깊어지는 신비: 수학, 생명, 우주



댓글 0개