рдПрд▓рд┐рдЧреЗрдВрдЯ рдЧреЛ рд╕рд░реНрд╡рд░ (рдЧреНрд░реЗрд╕рдлреБрд▓ рд░рд┐рд╕реНрдЯрд╛рд░реНрдЯ)

рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ, рдореИрдВ Graceful Restart on Go рдХрд╛ рд╡рд░реНрдгрди рдХрд░рдиреЗ рдЬрд╛ рд░рд╣рд╛ рд╣реВрдБред рдЧреНрд░реЗрд╕рдлреБрд▓ рд░рд┐рд╕реНрдЯрд╛рд░реНрдЯ рдЧреЛ рд╡реЗрдм рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ рд▓рд┐рдП рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИред рдЧреЛ рдореЗрдВ рдПрдХ рдХрдореА рд╣реИред рдЧреЛ рдХреЗ рдкрд╛рд╕ рд░рдирдЯрд╛рдЗрдо рдкрд░ рдХреЛрдб рдкреБрдирдГ рд▓реЛрдб рдХрд░рдиреЗ рдХрд╛ рдХреЛрдИ рддрд░реАрдХрд╛ рдирд╣реАрдВ рд╣реИред рдЗрд╕рд▓рд┐рдП, рдЧреЛ рдкрд░ рдбреЗрд╡рд▓рдкрд░реНрд╕ рдХреЛ рдПрдХ рд╕рдорд╕реНрдпрд╛ рдХрд╛ рд╕рд╛рдордирд╛ рдХрд░рдирд╛ рдкрдбрд╝рддрд╛ рд╣реИ рдЬреЛ рдЬрд╛рд╡рд╛, .NET рдпрд╛ PHP рдореЗрдВ рд▓рд┐рдЦреЗ рдЧрдП рд╕рд░реНрд╡рд░реЛрдВ рдореЗрдВ рдирд╣реАрдВ рдкрд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдпрджрд┐ рдЖрдкрдХреЛ рдЧреЛ рдореЗрдВ рд▓рд┐рдЦреЗ рд╕рд░реНрд╡рд░ рдХреЛрдб рдХреЛ рдЕрдкрдбреЗрдЯ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рддреЛ рд╕рд░реНрд╡рд░ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреЛ рд░реЛрдХрдирд╛ рд╣реЛрдЧрд╛ рдФрд░ рдПрдХ рдирдИ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рд╢реБрд░реВ рд╣реЛрдиреА рдЪрд╛рд╣рд┐рдПред рдпрд╣ рдХреЛрдб рдХреЛ рдЕрдкрдбреЗрдЯ рдХрд░рддреЗ рд╕рдордп рд╕рд░реНрд╡рд░ рдХреА рдЙрдкрд▓рдмреНрдзрддрд╛ рдХреЛ рдХрдо рдХрд░рддрд╛ рд╣реИред

рдкрд┐рдЫрд▓реЗ рд▓реЗрдЦ рдореЗрдВ, рдореИрдВрдиреЗ 200 рдкрдВрдХреНрддрд┐рдпреЛрдВ рдореЗрдВ рдЧреЛ рдкрд░ рдмрд╛рд▓реНрдХрди рдХрд╛ рд╡рд░реНрдгрди рдХрд┐рдпрд╛ред рдмреИрд▓реЗрдВрд╕рд░ рдХреЗ рдЖрдзрд╛рд░ рдкрд░, рдЖрдк рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдЕрдкрдбреЗрдЯ рдХреЗ рджреМрд░рд╛рди рдЙрдЪреНрдЪ рдЙрдкрд▓рдмреНрдзрддрд╛ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдлрд┐рд░ рдХреИрд╕реЗ рдмреИрд▓реЗрдВрд╕рд░ рдХреЛ рдЕрдкрдбреЗрдЯ рдХрд░рдирд╛ рд╣реИред рдПрдХ рдмреИрд▓реЗрдВрд╕рд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдЕрдХреНрд╕рд░ рд╕рд┐рд░реНрдл рдЬрд╝рд░реВрд░рдд рд╕реЗ рдЬрд╝реНрдпрд╛рджрд╛ рд╣реЛ рд╕рдХрддрд╛ рд╣реИред рдпрджрд┐ рдЖрдкрдХрд╛ рд╕рд░реНрд╡рд░ рдореИрдХ рдУрдПрд╕ рдПрдХреНрд╕ рдпрд╛ рд▓рд┐рдирдХреНрд╕ рдкрд░ рдЪрд▓ рд░рд╣рд╛ рд╣реИ, рддреЛ рд╕рд░реНрд╡рд░ рдХреЛрдб рдХреЛ рдЕрдкрдбреЗрдЯ рдХрд░рдиреЗ рдФрд░ рд╕рд░реНрд╡рд░ рдкреБрдирд░рд╛рд░рдВрдн рдХреЗ рд╕рдордп рдкреНрд░рд╛рдкреНрдд рд╕рднреА рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЛ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░рдиреЗ рдХрд╛ рдПрдХ рдФрд░ рддрд░реАрдХрд╛ рд╣реИред рдпрд╣ рддрд░реАрдХрд╛ рд╣реИ рдЧреНрд░реЗрд╕рдлреБрд▓ рд░рд┐рд╕реНрдЯрд╛рд░реНрдЯред

рдЧреНрд░реЗрд╕рдлреБрд▓ рд░рд┐рд╕реНрдЯрд╛рд░реНрдЯ рдХрд╛ рд╕рд╛рд░ рдпрд╣ рд╣реИ рдХрд┐ рдпреВрдирд┐рдХреНрд╕ / рд▓рд┐рдирдХреНрд╕ рд╕рд┐рд╕реНрдЯрдореЛрдВ рдкрд░, рдЦреБрд▓реА рд╣реБрдИ рдлрд╛рдЗрд▓реЗрдВ рдФрд░ рд╕реЙрдХреЗрдЯреНрд╕ рд╕реНрдкреИрдиреНрдб рдкреНрд░рдХреНрд░рд┐рдпрд╛рдУрдВ рдХреЗ рд▓рд┐рдП рдЙрдкрд▓рдмреНрдз рд╣реИрдВред рдкреВрд░реНрд╡рдЬреЛрдВ рджреНрд╡рд╛рд░рд╛ рдЦреЛрд▓реА рдЧрдИ рдлрд╝рд╛рдЗрд▓ рдпрд╛ рд╕реЙрдХреЗрдЯ рддрдХ рдкрд╣реБрдВрдЪ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдирдХреЗ рд▓рд┐рдП рдлрд╝рд╛рдЗрд▓ рдбрд┐рд╕реНрдХреНрд░рд┐рдкреНрдЯрд░ (рдлрд╝рд╛рдЗрд▓ рдбрд┐рд╕реНрдХреНрд░рд┐рдкреНрдЯрд░ рдПрдХ рдкреВрд░реНрдгрд╛рдВрдХ рд╣реИ) рдХрд╛ рдореВрд▓реНрдп рдЬрд╛рдирдирд╛ рдкрд░реНрдпрд╛рдкреНрдд рд╣реИред

рдпрд╣рд╛рдБ рдЙрди рдореБрджреНрджреЛрдВ рдХреА рдПрдХ рд╕реВрдЪреА рд╣реИ, рдЬрд┐рдиреНрд╣реЗрдВ рдЖрдкрдХреЛ Graceful Restart on Go рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╣рд▓ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ

  1. рдЧреЛ рдореЗрдВ, рд╕рднреА рдЦреБрд▓реА рдлрд╛рдЗрд▓реЗрдВ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреЗ рдЕрдВрдд рдореЗрдВ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рдмрдВрдж рд╣реЛ рдЬрд╛рддреА рд╣реИрдВ (рдмрдВрдж-рдкрд░-рдирд┐рд╖реНрдкрд╛рджрди)
  2. рдкреВрд░реНрд╡рдЬрдиреНрдо рдореЗрдВ рдЦреБрд▓реЗ рд░рдЦрдиреЗ рд╡рд╛рд▓реЗ рдкреБрд░рд╛рдиреЗ рдХрдиреЗрдХреНрд╢рдиреЛрдВ рдХреЗ рд╕рд╛рде рдХреБрдЫ рдХрд░рдиреЗ рдХреА рдЬрд░реВрд░рдд рд╣реИ

рдкрд╣рд▓реА рд╕рдорд╕реНрдпрд╛ рджреЛ рддрд░реАрдХреЛрдВ рд╕реЗ рд╣рд▓ рд╣реЛрддреА рд╣реИред Fnctl рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ, рдЖрдк syscall.FD_CLOEXEC рдзреНрд╡рдЬ, рдпрд╛ syscall рдХреЛ рд╕рд╛рдлрд╝ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред Dup рдмрд┐рдирд╛ syscall.FD_CLOEXEC рдзреНрд╡рдЬ рдХреЗ рдлрд╝рд╛рдЗрд▓ рдбрд┐рд╕реНрдХреНрд░рд┐рдкреНрдЯрд░ рдХреА рдПрдХ рдкреНрд░рддрд┐ рдмрдирд╛рдПрдЧрд╛ред рдпреЗ рдХреЙрд▓ рдЧреЛ рдХреЗ рд╡рд┐рдВрдбреЛрдЬ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдореЗрдВ рдЙрдкрд▓рдмреНрдз рдирд╣реАрдВ рд╣реИрдВ, рдЗрд╕рд▓рд┐рдП рдпрд╣ рддрдХрдиреАрдХ рдореИрдХ рдУрдПрд╕ рдПрдХреНрд╕ рдФрд░ рд▓рд┐рдирдХреНрд╕ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рддреА рд╣реИред рдЗрд╕ рдЙрджрд╛рд╣рд░рдг рдореЗрдВ, рдореИрдВ syscall.Dup рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣рд╛ рд╣реВрдВред рдпрд╣ рдкрд╣рд▓реЗ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдХреА рддреБрд▓рдирд╛ рдореЗрдВ рд╕рд░рд▓ рд╣реИред

рдореИрдВ 10 рд╕реЗрдХрдВрдб рдореЗрдВ рдХрдиреЗрдХреНрд╢рди рдХреЗ рд▓рд┐рдП рдЯрд╛рдЗрдордЖрдЙрдЯ рд╕реЗрдЯ рдХрд░рдХреЗ рдФрд░ рдЧреНрд░реЗрд╕рдлреБрд▓ рд░рд┐рд╕реНрдЯрд╛рд░реНрдЯ рдХреЗ рдмрд╛рдж рд╕рд░реНрд╡рд░ 11 рд╕реЗрдХрдВрдб рдХреЛ рдмрдВрдж рдХрд░рдХреЗ рджреВрд╕рд░реА рд╕рдорд╕реНрдпрд╛ рд╣рд▓ рдХрд░рддрд╛ рд╣реВрдВред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рджреВрд╕рд░реА рд╕рдорд╕реНрдпрд╛ рдХреЛ рджреЛ рдЕрдиреНрдп рддрд░реАрдХреЛрдВ рд╕реЗ рд╣рд▓ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ: рдУрдкрди рдХрдиреЗрдХреНрд╢рди рдХреА рд╕рдВрдЦреНрдпрд╛ рдФрд░ рдкреВрд░реНрд╡рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдлрдВрдХ (рд╕реА * рдХреЙрди) рд╕рд░реНрд╡ () рдХреА рдЧрдгрдирд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд░реИрдкрд░ рдиреЗрдЯредрд▓рд┐рдВрдЯрд░ рджреНрд╡рд╛рд░рд╛, рдЬреЛ рдЧреЛ рдореЗрдВ рдХрд╛рдлреА рдореБрд╢реНрдХрд┐рд▓ рд╣реИред рдЕрдиреНрдп рд╡реНрдпрд╡рд╣рд╛рд░ рд╡рд╛рдВрдЫрдиреАрдп рд╣реЛ рд╕рдХрддрд╛ рд╣реИред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рддрд╛рдХрд┐ рдЧреНрд░реЗрд╕рдлреБрд▓ рд░рд┐рд╕реНрдЯрд╛рд░реНрдЯ рдХреЗ рдмрд╛рдж рдкреБрд░рд╛рдиреА рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдПрдХ рддреНрд░реБрдЯрд┐ рдХреА рд░рд┐рдкреЛрд░реНрдЯ рдХрд░реЗ рдФрд░ рдХрдиреЗрдХреНрд╢рди рдмрдВрдж рдХрд░ рджреЗред

рдпрд╣ рд╕рдордЭрдирд╛ рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИ рдХрд┐ рдЧреНрд░реЗрд╕рдлреБрд▓ рд░рд┐рд╕реНрдЯрд╛рд░реНрдЯ рдХреЗ рдмрд╛рдж, рдХреБрдЫ рд╡реЗрдм рдмреНрд░рд╛рдЙрдЬрд░ рдХреЛ рд░рдЦрдиреЗ рдХреЗ рдХрд╛рд░рдг рдкреБрд░рд╛рдиреЗ рд╕рд░реНрд╡рд░ рд╕реЗ рдЬреБрдбрд╝ рдЬрд╛рдПрдВрдЧреЗред рдирдП рдХрдиреЗрдХреНрд╢рди рдирдП рд╕рд░реНрд╡рд░ рдХреЗ рд╕рд╛рде рд╕реНрдерд╛рдкрд┐рдд рдХрд┐рдП рдЬрд╛рдПрдВрдЧреЗред рд╕реНрдкрд╖реНрдЯрддрд╛ рдХреЗ рд▓рд┐рдП, рдХреМрди рд╕рд╛ рд╕рд░реНрд╡рд░ рдХрд┐рд╕ рдЕрдиреБрд░реЛрдз рдХреЛ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░рддрд╛ рд╣реИ, рдореБрдЭреЗ рд╕рд░реНрд╡рд░ рд╕реЗ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдореЗрдВ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреЗ рдкреАрдЖрдИрдбреА тАЛтАЛрдХреЛ рдЗрдВрдЧрд┐рдд рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдПред

grace1.go


package main import ( "flag" "fmt" "net" "net/http" "os" "os/exec" "syscall" "time" "log" ) var FD *int = flag.Int("fd", 0, "Server socket FD") var PID int = syscall.Getpid() var listener1 net.Listener var file1 *os.File = nil var exit1 chan int = make(chan int) var stop1 = false func main() { fo1, err := os.Create(fmt.Sprintf("pid-%d.log", PID)) if err != nil { panic(err) } log.SetOutput(fo1) log.Println("Grace1 ", PID) flag.Parse() s := &http.Server{Addr: ":8080", ReadTimeout: 10 * time.Second, WriteTimeout: 10 * time.Second, } http.HandleFunc("/", DefHandler) http.HandleFunc("/stop", StopHandler) http.HandleFunc("/restart", RestartHandler) http.HandleFunc("/grace", GraceHandler) http.HandleFunc("/think", ThinkHandler) if *FD != 0 { log.Println("Starting with FD ", *FD) file1 = os.NewFile(uintptr(*FD), "parent socket") listener1, err = net.FileListener(file1) if err != nil { log.Fatalln("fd listener failed: ", err) } } else { log.Println("Virgin Start") listener1, err = net.Listen("tcp", s.Addr) if err != nil { log.Fatalln("listener failed: ", err) } } err = s.Serve(listener1) log.Println("EXITING", PID) <-exit1 log.Println("EXIT", PID) } func DefHandler(w http.ResponseWriter, req *http.Request) { fmt.Fprintf(w, "def handler %d %s", PID, time.Now().String()) } func ThinkHandler(w http.ResponseWriter, req *http.Request) { time.Sleep(5 * time.Second) fmt.Fprintf(w, "think handler %d %s", PID, time.Now().String()) } func StopHandler(w http.ResponseWriter, req *http.Request) { log.Println("StopHandler", req.Method) if(stop1){ fmt.Fprintf(w, "stopped %d %s", PID, time.Now().String()) } stop1 = true fmt.Fprintf(w, "stop %d %s", PID, time.Now().String()) go func() { listener1.Close() if file1 != nil { file1.Close() } exit1<-1 }() } func RestartHandler(w http.ResponseWriter, req *http.Request) { log.Println("RestartHandler", req.Method) if(stop1){ fmt.Fprintf(w, "stopped %d %s", PID, time.Now().String()) } stop1 = true fmt.Fprintf(w, "restart %d %s", PID, time.Now().String()) go func() { listener1.Close() if file1 != nil { file1.Close() } cmd := exec.Command("./grace1") err := cmd.Start() if err != nil { log.Fatalln("starting error:", err) } exit1<-1 }() } func GraceHandler(w http.ResponseWriter, req *http.Request) { log.Println("GraceHandler", req.Method) if(stop1){ fmt.Fprintf(w, "stopped %d %s", PID, time.Now().String()) } stop1 = true fmt.Fprintf(w, "grace %d %s", PID, time.Now().String()) go func() { defer func() { log.Println("GoodBye") }() listener2 := listener1.(*net.TCPListener) file2, err := listener2.File() if err != nil { log.Fatalln(err) } fd1 := int(file2.Fd()) fd2, err := syscall.Dup(fd1) if err != nil { log.Fatalln("Dup error:", err) } listener1.Close() if file1 != nil { file1.Close() } cmd := exec.Command("./grace1", fmt.Sprint("-fd=", fd2)) err = cmd.Start() if err != nil { log.Fatalln("grace starting error:", err) } log.Println("sleep11", PID) time.Sleep(10 * time.Second) log.Println("exit after sleep", PID) exit1<-1 }() } 


рдЗрд╕ рдХрд╛рд░реНрдпрдХреНрд░рдо рдХреЛ рдмрд┐рдирд╛ рдЪрд▓рд╛рдП рдЪрд▓рд╛рдПрдВ ред

 go build grace1.go ./grace1 


рдЕрдм рдЬрдм рд╕рд░реНрд╡рд░ рдЪрд▓ рд░рд╣рд╛ рд╣реИ, рддреЛ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд╣реИрдВрдбрд▓рд░ рд╣реИрдВ

http://127.0.0.1:8080/ - рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд╣реИрдВрдбрд▓рд░
http://127.0.0.1:8080/restart - рд╕рд╛рдорд╛рдиреНрдп рд╕рд░реНрд╡рд░ рдкреБрдирд░рд╛рд░рдВрдн
http://127.0.0.1:8080/grace - рдЧреНрд░реЗрд╕рдлреБрд▓ рд╕рд░реНрд╡рд░ рд░реАрд╕реНрдЯрд╛рд░реНрдЯ
http://127.0.0.1:8080/think - рд╡рд┐рд▓рдВрдмрд┐рдд рд╣реИрдВрдбрд▓рд░

рдпрд╣ рд╕рдм рдХреИрд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ, рдпрд╣ рдЬрд╛рдВрдЪрдиреЗ рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ рдЧреЛ рдкрд░ рдПрдХ рдФрд░ рдХрд╛рд░реНрдпрдХреНрд░рдо рд▓рд┐рдЦрд╛ред рдпрд╣ рд╕рд░реНрд╡рд░ рд╕реЗ рд▓рдЧрд╛рддрд╛рд░ рдЕрдиреБрд░реЛрдз рдХрд░рддрд╛ рд╣реИ, рдпрджрд┐ рдХреЛрдИ рддреНрд░реБрдЯрд┐ рдирд╣реАрдВ рд╣реИ, рддреЛ рдкрддреНрд░ рдЬреА рдкреНрд░рджрд░реНрд╢рд┐рдд рд╣реЛрддрд╛ рд╣реИ, рдпрджрд┐ рддреНрд░реБрдЯрд┐ рдИ рд╣реИ ред рдкреНрд░рддреНрдпреЗрдХ рдЕрдиреБрд░реЛрдз рдХреЗ рдмрд╛рдж, рдХрд╛рд░реНрдпрдХреНрд░рдо 10ms рдкрд░ рд╕реЛ рдЬрд╛рддрд╛ рд╣реИред

bench1.go


 package main import ( "net/http" "time" ) func main() { nerr := 0 ngood := 0 for i := 0; i < 10000; i++ { resp, err := http.Get("http://127.0.0.1:8080/") if err != nil { // error print("E") nerr++ }else{ print("g") ngood++ resp.Body.Close() } time.Sleep(10 * time.Millisecond) } println() println("Good:", ngood, "Error", nerr) } 


рдпрджрд┐ рдЖрдк рд▓реЛрдб рдХреЗ рддрд╣рдд рд╕рд░реНрд╡рд░ рдХреЛ рдкреБрдирд░рд╛рд░рдВрдн рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдмреЗрдВрдЪ 1редрдЧреЛ рдирд┐рдореНрди рдЪрд┐рддреНрд░ рджреЗрддрд╛ рд╣реИред

 gggggggggggggggggggggggggggggggggggggggggggggggggggggggEEEEEgggggggggggggggggggg gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg gggggggggggggggggggggggggggggggggEEggggggggggggggggggggggggggggggggggggggggggggg ggggggggggggggggggggggggggggggggggggggggggggggggEEgggggggggggggggggggggggggggggg ggggggggggggggggggggggggEggggggggggggggggggggggggggggggggggggggggggggggggggggggg gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg gggEEggggggggggggggggggEgggggggggggggggggggEggggggggggggggggEEgggggggggggggggggE gggggggggggggggggggggEEgggggggggggggggggEggggggggggggggggggggEggggggggggggggggEE gggggggggggggggggEEgggggggggggggggggEEggggggggggggggggggEgggggggggggggggEEgggggg 


рдПрдХ рдпрд╛ рдПрдХ рд╕реЗ рдЕрдзрд┐рдХ рдЕрдХреНрд╖рд░ E рд╕рд░реНрд╡рд░ рддреНрд░реБрдЯрд┐ рдФрд░ рдкреБрдирдГ рдЖрд░рдВрдн рдХреЗ рджреМрд░рд╛рди рдЕрдиреБрдкрд▓рдмреНрдзрддрд╛ рдХрд╛ рдкреНрд░рддреАрдХ рд╣реИред (рдореИрдВрдиреЗ рд╕рд░реНрд╡рд░ рдХреЛ рдХрдИ рдмрд╛рд░ рдУрд╡рд░рд▓реЛрдб рдХрд┐рдпрд╛, рдЗрд╕рд▓рд┐рдП рдЕрдХреНрд╖рд░ рдИ рдЖрдо рд╣реИрдВ)

рдЕрдЧрд░ рдЧреНрд░реЗрд╕рдлреБрд▓ рд░рд┐рд╕реНрдЯрд╛рд░реНрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рд╣реИ рддреЛ рдореИрдВрдиреЗ рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХрд╛ рдмрд┐рд▓реНрдХреБрд▓ рднреА рдЕрд╡рд▓реЛрдХрди рдирд╣реАрдВ рдХрд┐рдпрд╛ред

Source: https://habr.com/ru/post/In202584/


All Articles