42
Пишем функциональное, надежное и быстрое веб-приложение на Go Дмитрий Вьюков, dvyukov@ Google

Пишем функциональное, надежное и быстрое веб-приложение на Go

  • Upload
    rashad

  • View
    164

  • Download
    0

Embed Size (px)

DESCRIPTION

Дмитрий Вьюков, dvyukov@ Google. Пишем функциональное, надежное и быстрое веб-приложение на Go. План. Зачем новый язык? Привет, Мир! Пишем веб-приложение Инструментарий. История. Конец 2007: Rob Pike, Ken Thompson и RobertGriesemer начали проектировать Ноябрь 2009: open-source release - PowerPoint PPT Presentation

Citation preview

Page 1: Пишем функциональное, надежное и быстрое веб-приложение на Go

Пишем функциональное, надежное и быстрое веб-

приложение на GoДмитрий Вьюков, dvyukov@

Google

Page 2: Пишем функциональное, надежное и быстрое веб-приложение на Go

План

• Зачем новый язык?• Привет, Мир!• Пишем веб-приложение• Инструментарий

Page 3: Пишем функциональное, надежное и быстрое веб-приложение на Go

История Конец 2007: Rob Pike, Ken Thompson и RobertGriesemer

начали проектировать Ноябрь 2009: open-source release Март 2012: релиз Go1 Go1.1, Go1.2, Go1.3

Page 4: Пишем функциональное, надежное и быстрое веб-приложение на Go

Зачем?

Дизайн мотивирован нашими нуждами в Google:• Large-scale системы• Large-scale разработка• Время сборки• Эффективность• Масштабируемость• Concurrency• Безопасность

Page 5: Пишем функциональное, надежное и быстрое веб-приложение на Go

Что такое Go? Простой язык, который легко изучить и читать Статически-типизированный, но “чувствуется” как

динамический Компилируется в машинный код, но быстрая

разработка Быстрый и масштабируемый Сборка мусора Встроенная поддержка concurrency Стандартная библитека “с включенными батарейками” Open-source (400+ контрибьюторов)

Page 6: Пишем функциональное, надежное и быстрое веб-приложение на Go

Кто использует? Google: dl.google.co Google: vitess (MySQL scaling) Google: flywheel (mobile

proxy) BBC Worldwide Canonical Heroku Nokia SoundCloud Apple Yandex BitBucket

dotCloud github gov.uk Heroku Intel Iron.io Mozilla Percona Zynga Docker Packer

Page 7: Пишем функциональное, надежное и быстрое веб-приложение на Go

Крэш-курс

Page 8: Пишем функциональное, надежное и быстрое веб-приложение на Go

Привет, Мир!

package main

import "fmt"

func main() {

fmt.Printf("Привет, Мир!\n")

}

Page 9: Пишем функциональное, надежное и быстрое веб-приложение на Go

Привет, Net!func main() {

ln, err := net.Listen("tcp", "localhost:11500")

if err != nil {

log.Fatal(err)

}

for {

c, err := ln.Accept()

if err != nil {

log.Fatal(err)

}

fmt.Fprintf(c, "Привет, Net!\n")

c.Close()

}

}

Page 10: Пишем функциональное, надежное и быстрое веб-приложение на Go

Интерфейсыfmt.Fprintf(c, "Привет, Net!\n")

Duck typing!

type Writer interface {

Write(p []byte) (n int, err error)

}

type netFD struct {...}

func (fd *netFD) Write(p []byte) (nn int, err error)

Page 11: Пишем функциональное, надежное и быстрое веб-приложение на Go

Эхо-серверfunc main() {

ln, err := net.Listen("tcp", "localhost:11500")

if err != nil {

log.Fatal(err)

}

for {

c, err := ln.Accept()

if err != nil {

log.Fatal(err)

}

io.Copy(c, c)

}

}

Page 12: Пишем функциональное, надежное и быстрое веб-приложение на Go

Привет, concurrency!func main() {

ln, err := net.Listen("tcp", "localhost:11500")

if err != nil {

log.Fatal(err)

}

for {

c, err := ln.Accept()

if err != nil {

log.Fatal(err)

}

go io.Copy(c, c)

}

}

Page 13: Пишем функциональное, надежное и быстрое веб-приложение на Go

СoncurrencyГорутины:

go doFoo(a, b)

go conn.Handle()

go func() {doFoo(a, b)

notifyCompletion()

}()

Page 14: Пишем функциональное, надежное и быстрое веб-приложение на Go

ChannelsКаналы:

c := make(chan int)

c <- 42

fmt.Println(<-c)

Page 15: Пишем функциональное, надежное и быстрое веб-приложение на Go

Selectselect {

case inChan <- v:

fmt.Println("Отправлено")

case <-timeoutChan:

fmt.Println("Потрачено")

}

Page 16: Пишем функциональное, надежное и быстрое веб-приложение на Go

Запрос нескольких бэкендовfunc multiGet(urls []string) (results []*http.Response) {

res := make(chan *http.Response)

for _, url := range urls {

go func(url string) {

resp, _ := http.Get(url)

res <- resp

}(url)

}

for _ = range urls {

results = append(results, <-res)

}

return

}

Page 17: Пишем функциональное, надежное и быстрое веб-приложение на Go

Запрос с таймаутомt := time.After(time.Second)

for _ = range urls {

select {

case resp := <-res:

results = append(results, resp)

case <-t:

return

}

}

Page 18: Пишем функциональное, надежное и быстрое веб-приложение на Go

Файловерfunc getFailover(primary, secondary string) *http.Response {

res := make(chan *http.Response, 1)

go func() {

res <- requestServer(primary)

}()

select {

case resp := <-res:

return resp

case <-time.After(50 * time.Millisecond):

}

go func() {

res <- requestServer(secondary)

}()

return <-res

}

Page 19: Пишем функциональное, надежное и быстрое веб-приложение на Go

Батарейки включеныencoding/{json, xml, gob, base64}

compress/{gzip, bzip2, flate}

crypto/{aes, des, sha1, tls, x509}

net/{http, rpc, smtp}

database/sql

html/template

regexp

flag

Page 20: Пишем функциональное, надежное и быстрое веб-приложение на Go

В бой!

Page 21: Пишем функциональное, надежное и быстрое веб-приложение на Go

Флагиpackage main

import "flag"

var (

httpAddr = flag.String("http", ":8080", "address to serve http")

apiAddr = flag.String("api", ":8081", "address to serve api")

)

func main() {

flag.Parse()

...

Page 22: Пишем функциональное, надежное и быстрое веб-приложение на Go

HTTP серверimport "net/http"

func main() {

...

http.HandleFunc("/", handleWelcome)

http.HandleFunc("/chat", handleChat)

go http.ListenAndServe(*httpAddr, nil)

...

Page 23: Пишем функциональное, надежное и быстрое веб-приложение на Go

Websocket серверimport "code.google.com/p/go.net/websocket"

func main() {

...

http.Handle("/ws",

websocket.Handler(handleWebsocket))

...

Page 24: Пишем функциональное, надежное и быстрое веб-приложение на Go

API серверimport "net"

func main() {

...

ln, err := net.Listen("tcp", *apiAddr)

if err != nil {

log.Fatal(err)

}

go func() {

for {

c, err := ln.Accept()

if err != nil {

log.Fatal(err)

}

go handleApi(c)

}

}()

Page 25: Пишем функциональное, надежное и быстрое веб-приложение на Go

Бизнес логикаtype Message struct {

From string

Text string

}

type Client interface {

Send(m Message)

}

var (

clients = make(map[Client]bool)

clientsMutex sync.Mutex

)

Page 26: Пишем функциональное, надежное и быстрое веб-приложение на Go

Бизнес логика (2)func registerClient(c Client) {

clientsMutex.Lock()

clients[c] = true

clientsMutex.Unlock()

}

func unregisterClient(c Client) {

clientsMutex.Lock()

delete(clients, c)

clientsMutex.Unlock()

}

Page 27: Пишем функциональное, надежное и быстрое веб-приложение на Go

Бизнес логика (3)func broadcastMessage(m Message) {

clientsMutex.Lock()

for c := range clients {

c.Send(m)

}

clientsMutex.Unlock()

}

Page 28: Пишем функциональное, надежное и быстрое веб-приложение на Go

HTML шаблоныvar chatPageTempl = template.Must(template.New("").Parse(`

<html>

<body>

<b>Hi, {{.Name}}!</b>

<form>

<input type="text" id="chattext"></input>

<input type="button" value="Say"

onclick="sendMessage()"></input>

</form>

<textarea readonly=1 rows=20 id="alltext"></textarea>

</body>

</html>

`))

Page 29: Пишем функциональное, надежное и быстрое веб-приложение на Go

HTTP обработчикиfunc handleChat(w http.ResponseWriter, r *http.Request) {

name := r.FormValue("name")

log.Printf("serving chat page for '%v'", name)

type Params struct {

Name string

}

chatPageTempl.Execute(w, &Params{name})

}

Page 30: Пишем функциональное, надежное и быстрое веб-приложение на Go

Websocket обработчикtype WSClient struct {

conn *websocket.Conn

enc *json.Encoder

}

func (c *WSClient) Send(m Message) {

c.enc.Encode(m)

}

Page 31: Пишем функциональное, надежное и быстрое веб-приложение на Go

Websocket обработчик (2)func handleWebsocket(ws *websocket.Conn) {

c := &WSClient{ws, json.NewEncoder(ws)}

registerClient(c)

dec := json.NewDecoder(ws)

for {

var m Message

if err := dec.Decode(&m); err != nil {

log.Printf("error reading from websocket: %v", err)

break

}

broadcastMessage(m)

}

unregisterClient(c)

}

Page 32: Пишем функциональное, надежное и быстрое веб-приложение на Go

Демо

Page 33: Пишем функциональное, надежное и быстрое веб-приложение на Go

Инструментарий

Page 34: Пишем функциональное, надежное и быстрое веб-приложение на Go

Сборка

Нулевая конфигурация, нет MAKEFILE

$ go run myprog.go

$ go build myprog

$ go get code.google.com/p/go.new/websocket

Page 35: Пишем функциональное, надежное и быстрое веб-приложение на Go

Пишем код

$ go fmt mysource.go

$ go vet - статический анализ кода

$ godoc - документация

goimports/gocode/oracle: поддержка IDE

Page 36: Пишем функциональное, надежное и быстрое веб-приложение на Go

Тестируем

$ go test

$ go test -cover

$ go test -race

Информативные крэш-репорты

Page 37: Пишем функциональное, надежное и быстрое веб-приложение на Go

Оптимизируем

$ go test -bench

$ go test -bench -cpu=1,2,4

$ go test -benchmem

$ go test -cpuprofile

$ go test -memprofile

$ go test -blockprofile

Page 38: Пишем функциональное, надежное и быстрое веб-приложение на Go

Оптимизируем (2)

- Профайлер горутин

- Трейсер GC

- Трейсер планировщика

- Трейсер аллокатора памяти

- Статистика аллокатора памяти

- Дамп кучи

Page 39: Пишем функциональное, надежное и быстрое веб-приложение на Go

Мониторингimport "expvar"

var (

expMsgRecv = expvar.NewInt("msg_recv")

expMsgSend = expvar.NewInt("msg_send")

)

func broadcastMessage(m Message) {

...

expMsgRecv.Add(1)

expMsgSend.Add(int64(len(clients)))

}

Page 40: Пишем функциональное, надежное и быстрое веб-приложение на Go

Что дальше?

http://golang.orghttp://tour.golang.orggolang-nuts@

Книги: An Introduction to Programming in Go Network Programming with Go Programming in Go: Creating Applications for the 21st

Century

Page 41: Пишем функциональное, надежное и быстрое веб-приложение на Go

Другие доклады по Go

16:35 Common: Go: аналитика Рунета в реальном времени

17:45 Python: Go на Google App Engine - просто, надёжно, быстро и недорого.

19:30 Python: Juju и MaaS - эффективные инструменты развёртывания масштабных систем на "железе" и в "облаках".

Page 42: Пишем функциональное, надежное и быстрое веб-приложение на Go

Q&A

Спасибо!

Дмитрий Вьюков, dvyukov@http://golang.org