줄리아로 웨이크서비스.
개요
줄리아콘 2020"Building microservices and applications in Julia" 세미나 토크를 보고 줄리아를 이용해 마이크로 서비스를 만드는 법을 배웠기 때문에 메모에 글을 쓴다.이른바'튜토리얼 시도'라는 기사다.
세미나는 음악 앨범 관리 응용을 예로 삼아 제작한 것으로 여기서 저는 이와 기본적으로 같은 간단한 논문 관리 응용을 만들고 싶습니다.마이크로 서비스이기 때문에 안내데스크를 하지 않고 HTTP로 JSON을 교환합니다.
쥬리아를 실제 서비스용으로 사용한 예는 전혀 들어본 적이 없지만, 최근 유행하는 마이크로 서비스화의 물결에 따라 사용하는 예가 늘어나면 좋겠다고 생각한다.
할 일
HTTP.jl
를 사용하여 어플리케이션에 액세스할 API 엔드포인트실현하고자 하는 구조는 다음과 같다.
"Building microservices 및 applications in Juria"
이 그림에 따르면 응용 프로그램은 크게 3층으로 나뉜다.
이루어지다
위의 구조에 근거하여 실현하다.
Papers.jl
Papers.jl
는 주요 모듈입니다.프로그램 라이브러리 사용자는 using Papers
에서 이 모듈을 도입한 후 사용합니다.이것은 흔히 볼 수 있는 줄리아 도서관의 서법이다.여기에 네 개의 서브 모듈을 불러오는 중입니다.위의 구성도와 비교해 보십시오.지금부터 이 네 가지를 각각 실시한다.
Papers.jl
module Papers
export Model, Mapper, Resource, Service
include("Model.jl")
using .Model
include("Mapper.jl")
using .Mapper
include("Service.jl")
using .Service
include("Resource.jl")
using .Resource
end
Model.jl
논문을 관리하는 응용 프로그램을 만들어야 하기 때문에 논문 한 편 한 편의 정보를 처리하는 구조체를 먼저 만들어야 한다.간단하게 보기 위해 논문이 가지고 있는 정보는 작가, 제목, 추상, 출판일이다.
Model.jl
module Model
import Base: ==
using StructTypes, Dates
export Paper
mutable struct Paper
id::Int64 # service-managed
title::String
abst::String
authors::Vector{String}
publishdate::Date
timespicked::Int64 # service-managed
end
==(x::Paper, y::Paper) = x.id == y.id
Paper() = Paper(0, "", "", String[], Date("1900-01-01", "y-m-d"), 0)
Paper(title, abst, authors, publishdate) = Paper(0, title, abst, authors, Date(publishdate, "y-m-d"), 0)
StructTypes.StructType(::Type{Paper}) = StructTypes.Mutable()
end
id
및 timespicked
는 서비스 관리 정보입니다.timespicked
잠시 후에 설명할게요.여기에는
StructTypes.jl
라는 프로그램 라이브러리를 사용하여 Juria의 정규 struct를 확장합니다.이후 JSON 라이브러리와 함께 구조체의 serialization을 진행해야 한다.Mapper.jl
이어서 논문을 수집하고 관리하는 데이터베이스와 조작을 제작한다.
Mapper.jl
module Mapper
using ..Model
const STORE = Dict{Int64,Paper}()
const COUNTER = Ref{Int64}(0)
function store!(paper)
if haskey(STORE, paper.id)
# updating
STORE[paper.id] = paper
else
# creating new
paper.id = COUNTER[] += 1
STORE[paper.id] = paper
end
return
end
function get(id)
return STORE[id]
end
function delete(id)
delete!(STORE, id)
return
end
function getAllPapers()
return collect(values(STORE))
end
end
STORE
를 논문 데이터베이스로 한다.여기에서 메모리를 시작하는 사전을 사용해서 모든 데이터를 얻을 수 있습니다.물론 진짜 서비스에 가입하면 안 되지만 이번엔 시위 행진이니까 간단하게 하기 위해서다.처음 소개한 담화에서도 데이터베이스를 정확하게 사용하는 방법을 소개했다.store!
,get
,delete
,getAllPapers
는 데이터베이스에 접근하는 함수이다.논문id
은 전 세계COUNTER
에서 수여한다.getAllPapers
는 데이터베이스 전체 논문을 얻는 함수다.Service.jl
다음은
Mapper.jl
의 원자 함수를 사용하여 응용 프로그램의 논리를 실현한다.데이터베이스에 새 데이터를 저장하고 기존 데이터를 업데이트/삭제할 수 있습니다.또 읽을 논문 한 편을 고르는 함수도 실현할 수 있다.Service.jl
module Service
using ..Model, ..Mapper
function createPaper(obj)
# 引数として json オブジェクトを受け取る。
# 必要なフィールドが入力に格納されているかをチェックし、
# 問題なければ新しい `Paper` オブジェクトを作成してデータベースへ保存。
@assert haskey(obj, :title) && !isempty(obj.title)
@assert haskey(obj, :abst) && !isempty(obj.abst)
@assert haskey(obj, :authors) && !isempty(obj.authors)
@assert haskey(obj, :publishdate) && !isempty(obj.publishdate)
paper = Paper(obj.title, obj.abst, obj.authors, obj.publishdate)
Mapper.store!(paper)
return paper
end
# データベースから論文のオブジェクトを取得
getPaper(id) = Mapper.get(id)
# 登録済みの論文オブジェクトをアップデート
function updatePaper(id, updated)
paper = Mapper.get(id)
paper.title = updated.title
paper.abst = updated.abst
paper.authors = updated.authors
paper.publishdate = updated.publishdate
Mapper.store!(paper)
return paper
end
# データベースから論文を削除
function deletePaper(id)
Mapper.delete(id)
return
end
function pickPaperToRead()
papers = Mapper.getAllPapers()
leastTimesPicked = minimum(x -> x.timespicked, papers)
leastPickedPapers = filter(x -> x.timespicked == leastTimesPicked, papers)
pickedPaper = rand(leastPickedPapers)
pickedPaper.timespicked += 1
Mapper.store!(pickedPaper)
return pickedPaper
end
end
pickPaperToRead
는 읽을 논문을 고르는 함수다.Paper
대상에 timespicked
라는 정보가 있는데 이것은 논문이 지금까지 선정된 횟수이다.데이터베이스에서 논문 횟수가 가장 적은 논문을 얻습니다. (여러 편이 있으면 무작위로 한 편을 선택하십시오.)Resource.jl
드디어 API 끝점을 생성합니다.Juria
HTTP.jl
를 사용하여 호출Service.jl
함수의 끝점은 다음과 같습니다.Resource.jl
module Resource
using HTTP, JSON3, Sockets
using ..Model, ..Service
const ROUTER = HTTP.Router()
health(req) = Dict("status"=>"ok")
HTTP.@register(ROUTER, "GET", "/", health)
createPaper(req) = Service.createPaper(JSON3.read(req.body))::Paper
HTTP.@register(ROUTER, "POST", "/paper", createPaper)
getPaper(req) = Service.getPaper(
parse(Int, HTTP.URIs.splitpath(req.target)[2]) #/paper/1 から1を取ってくる
)::Paper
HTTP.@register(ROUTER, "GET", "/paper/*", getPaper)
updatePaper(req) = Service.updatePaper(
parse(Int, HTTP.URIs.splitpath(req.target)[2]),
JSON3.read(req.body, Paper)
)::Paper
HTTP.@register(ROUTER, "PUT", "/paper/*", updatePaper)
deletePaper(req) = Service.deletePaper(
parse(Int, HTTP.URIs.splitpath(req.target)[2])
)
HTTP.@register(ROUTER, "DELETE", "/paper/*", deletePaper)
pickPaperToRead(req) = Service.pickPaperToRead()::Paper
HTTP.@register(ROUTER, "GET", "/paper", pickPaperToRead)
우선 중요한 것은 ROUTER
이다.HTTP 요청 라우팅을 수행하는 객체입니다.이 등록 단점을 사용하세요.이 매크로는 HTTP.@register
입니다.등록 방법 이름, 자원 이름과 호출 함수.이렇게 하면 공유기가POST/paper
를 받았을 때createPaper 함수가 호출됩니다.여기에 같은 이름의 함수는 confusing이다. 예를 들어 Resource 모듈 내의 함수
createPaper
, HTTP 요청을 읽고 논리를 실현하는 서비스 모듈createPaper
함수에 던지는 역할을 한다.마지막으로 HTTP 요청에 대한 프로세서 및 서비스용 함수를 설치합니다.아래의 느낌입니다.
Resource.jl
function requestHandler(req)
obj = HTTP.handle(ROUTER, req)
resp = HTTP.Response(200, JSON3.write(obj))
return resp
end
function run()
HTTP.serve(requestHandler, ip"0.0.0.0", 8080)
end
end # module
단점 공개
위에서 만든 프로그램을 실제 디버깅하고 테스트를 실행합니다.
프로그램 설계
응용 프로그램을 실행하기 위해 다음 스크립트를 썼습니다.
run.jl
로 저장합니다.run.jl
using Papers
Resource.run()
그런 다음 Docker file을 다음과 같이 씁니다.목록의 구성을 보십시오창고..Dockerfile
FROM julia:1.5.3
RUN mkdir /app
COPY ./ /app/
WORKDIR /app
RUN julia --project=. -e 'using Pkg; Pkg.instantiate(); Pkg.precompile()'
CMD ["julia", "--project=.", "run.jl"]
이 docker build을 docker hub push로 기억합니다.이번에는 일반적인 시위에 불과해 운용 등을 고려하지 않았기 때문에 어떤 어려운 일도 고려하지 않고 AWS의 일라스틱 빈스토크에서 디자인했다.아래
docker-compose.yml
라고 적어서 올리면 마음대로 할 수 있어요.간단해.docker-compose.yml
version: "3"
services:
paper:
image: docker/hub:latest # docker hub のイメージ
ports:
- 80:8080
실행 결과
현지에서 요구를 던져 보아라.
건강 검진
$ curl -X GET http://papers-env.xxx
{"status":"ok"}
논문 정보의 등록$ curl -X POST -d '{"title":"A Supersymmetry Primer","authors":["Stephen P. Martin"],"abst":"I provide a pedagogical introduction to supersymmetry...", "publishdate":"1997-09-16"}' http://papers-env.xxx/paper
{"id":1,"title":"A Supersymmetry Primer","abst":"I provide a pedagogical introduction to supersymmetry...","authors":["Stephen P. Martin"],"publishdate":"1997-09-16","timespicked":0}
$ curl -X POST -d '{"title":"Cooling Theory Faced with Old Warm Neutron Stars", "authors":["Keisuke Yanagi", "Natsumi Nagata", "Koichi Hamaguchi"], "abst":"Recent observations have found several candidates...", "publishdate":"2019-04-08"}' http://papers-env.xxx/paper
{"id":2,"title":"Cooling Theory Faced with Old Warm Neutron Stars","abst":"Recent observations have found several candidates...","authors":["Keisuke Yanagi","Natsumi Nagata","Koichi Hamaguchi"],"publishdate":"2019-04-08","timespicked":0}
읽어야 할 논문을 발췌하다$ curl -X GET http://papers-env.xxx/paper
{"id":2,"title":"Cooling Theory Faced with Old Warm Neutron Stars","abst":"Recent observations have found several candidates...","authors":["Keisuke Yanagi","Natsumi Nagata","Koichi Hamaguchi"],"publishdate":"2019-04-08","timespicked":1}
$ curl -X GET http://papers-env.xxx/paper
{"id":1,"title":"A Supersymmetry Primer","abst":"I provide a pedagogical introduction to supersymmetry...","authors":["Stephen P. Martin"],"publishdate":"1997-09-16","timespicked":1}
잘 돌아가고 있음을 확인합니다.감상
위에서 한 것은 정말 장난감 같은 시연이었고, 세미나에서는 이런 실복을 바탕으로 데이터베이스와 협업해 여러 사람이 이용할 수 있는 인증 시스템까지 만들었다.
원래 저는 웹 응용 프로그램의 개발 자체가 문외한이기 때문에 이런 의미에서 보면 배울 만한 세미나이기도 합니다.쥬리아는 지금까지 과학기술 컴퓨팅에서만 사용해 봤지만, 이렇게 API를 간단하게 만들 수 있어 생태계가 알차다는 인상을 준다.
Juria에도 이러한 웹 프레임워크가 있습니다.사용한 적은 없지만 완성된 웹 서비스를 만들어야 한다는 프레임워크도 사용할 수 있다.
Flash를 이용해 파이톤이 제작한 머신러닝 모델을 API 가져오기 서비스로 활용하면 흔한 모델인 것 같은데, 줄리아도 같은 일을 할 수 있지 않을까요?파이썬이라면 줄리아로 여러 가지 제약이 심한 부분을 쉽게 만들고 그냥 실용화했으면 좋겠어요.
Reference
이 문제에 관하여(줄리아로 웨이크서비스.), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://zenn.dev/yng/articles/julia-micro-service텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)