├── ch13-seckill ├── 架构图.jpeg ├── framework.png ├── sk-core │ ├── main.go │ ├── service │ │ ├── srv_err │ │ │ └── error.go │ │ ├── service.go │ │ ├── srv_limit │ │ │ └── sec_limit.go │ │ ├── srv_user │ │ │ └── user_history.go │ │ └── srv_product │ │ │ └── product_count.go │ ├── bootstrap.yaml │ └── setup │ │ ├── redis.go │ │ ├── service.go │ │ └── zk.go ├── pkg │ ├── common │ │ └── service_instance.go │ ├── config │ │ └── need_config.conf │ ├── bootstrap │ │ ├── BootstrapProperty.go │ │ └── bootstrap_config.go │ ├── ratelimiter │ │ └── instruments.go │ ├── discover │ │ └── discovery_client.go │ ├── mysql │ │ └── mysql.go │ ├── client │ │ ├── user_test.go │ │ ├── oauth.go │ │ └── user.go │ └── loadbalance │ │ └── loadbalance.go ├── pb │ ├── user.proto │ ├── seckill.proto │ ├── oauth.proto │ └── activity.proto ├── user-service │ ├── bootstrap.yaml │ ├── user-script.sql │ ├── transport │ │ ├── grpc.go │ │ └── user_model.go │ ├── service │ │ └── service.go │ ├── plugins │ │ ├── logging.go │ │ └── instrument.go │ ├── config │ │ └── config.go │ ├── model │ │ └── user.go │ └── endpoint │ │ └── endpoints.go ├── sk-admin │ ├── bootstrap.yaml │ ├── setup │ │ ├── zk.go │ │ ├── etcd.go │ │ ├── etcd_test.go │ │ └── zk_test.go │ ├── service │ │ ├── service.go │ │ └── product.go │ ├── main.go │ ├── etcd_test.go │ ├── model │ │ └── product.go │ └── config │ │ └── config.go ├── sk-app │ ├── bootstrap.yaml │ ├── main.go │ ├── service │ │ ├── srv_limit │ │ │ ├── sec_limit.go │ │ │ └── min_limit.go │ │ ├── srv_err │ │ │ └── error.go │ │ └── srv_redis │ │ │ └── redis_proc.go │ ├── model │ │ └── model.go │ ├── plugins │ │ └── logging.go │ └── setup │ │ └── zk.go ├── oauth-service │ ├── bootstrap.yaml │ ├── model │ │ ├── user.go │ │ └── token.go │ ├── service │ │ ├── common_service.go │ │ ├── client_service.go │ │ └── user_service.go │ ├── oauth-script.sql │ ├── transport │ │ └── grpc.go │ ├── plugins │ │ └── instrument.go │ ├── config │ │ └── config.go │ └── client_test.go ├── gateway │ ├── bootstrap.yaml │ └── config │ │ ├── AuthPermission.go │ │ └── config.go └── README.md ├── ch4-feature ├── main │ ├── hello.go │ └── main.go ├── compute │ └── add.go ├── concurrency │ ├── first_concurrency.go │ └── channel.go └── synch │ ├── wait_group.go │ ├── mutex.go │ ├── rw_mutex.go │ └── sync_map.go ├── ch5-web ├── SimpleServer.go ├── forms │ └── login.tpl ├── mysql │ └── script.sql ├── helloweb.go ├── writeresponse.go ├── beego │ └── main.go ├── webForm.go ├── memory │ └── memory.go ├── mongo │ └── mongo.go └── gin │ └── main.go ├── ch8-config ├── config │ └── resume_config.yaml ├── resume.go └── ViperDemo.go ├── ch11-security ├── model │ ├── user.go │ ├── client.go │ └── token.go ├── config │ └── config.go └── service │ ├── common_service.go │ ├── user_service.go │ └── client_service.go ├── ch7-rpc ├── README.md ├── pb │ └── string.proto ├── basic │ ├── server.go │ ├── client.go │ └── string-service │ │ └── service.go ├── stream-pb │ └── stream_string.proto ├── stream │ ├── server.go │ ├── string-service │ │ └── service.go │ └── client.go ├── grpc │ ├── server.go │ ├── client.go │ └── string-service │ │ └── service.go └── go-kit │ ├── server.go │ ├── client.go │ └── string-service │ ├── logging.go │ ├── service.go │ └── transports.go ├── ch12-trace ├── zipkin-go │ └── string-services │ │ ├── Makefile │ │ ├── svc2 │ │ ├── service.go │ │ ├── httpserver.go │ │ ├── cmd │ │ │ └── main.go │ │ ├── httpclient.go │ │ └── implementation.go │ │ ├── svc1 │ │ ├── service.go │ │ ├── implementation.go │ │ ├── cmd │ │ │ └── main.go │ │ └── httpserver.go │ │ └── README.md ├── README.md └── zipkin-kit │ ├── pb │ └── string.proto │ ├── docker │ ├── prometheus.yml │ └── docker-compose.yml │ ├── client │ ├── string.go │ └── stringModel.go │ ├── string-service │ ├── grpc.go │ ├── register.go │ ├── logging.go │ └── service │ │ └── service.go │ └── cmd │ └── client_test.go ├── ch3-basic ├── Callback.go ├── Variable.go ├── Embed.go ├── Anonymous.go ├── List.go ├── Map.go ├── Flag.go ├── Array.go ├── FunctionImplementor.go ├── Counter.go ├── Foreach.go ├── Pointer.go ├── Compose.go ├── Slice.go ├── StructImplementor.go ├── TypeAlias.go ├── Append.go ├── Person.go └── HelloGo.go ├── ch6-discovery ├── config │ └── config.go ├── string-service │ ├── config │ │ └── config.go │ ├── plugins │ │ └── logging.go │ ├── service │ │ └── service.go │ └── endpoint │ │ └── endpoints.go ├── discover │ └── discover_client.go ├── service │ └── service.go └── endpoint │ └── endpoints.go ├── ch10-resiliency ├── string-service │ ├── config │ │ └── config.go │ ├── plugins │ │ └── logging.go │ ├── service │ │ └── service.go │ ├── endpoint │ │ └── endpoints.go │ └── transport │ │ └── http.go ├── use-string-service │ ├── config │ │ └── config.go │ ├── plugins │ │ └── logging.go │ └── endpoint │ │ └── endpoints.go ├── hystrix-example.go └── gateway.go ├── README.md ├── common ├── loadbalance │ ├── loadbalance_test.go │ └── loadbalance.go └── discover │ └── discover_client.go ├── LICENSE └── ch9-gateway └── string-service ├── register.go ├── logging.go ├── service.go ├── endpoints.go ├── main.go └── transports.go /ch13-seckill/架构图.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longjoy/micro-go-book/HEAD/ch13-seckill/架构图.jpeg -------------------------------------------------------------------------------- /ch13-seckill/framework.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longjoy/micro-go-book/HEAD/ch13-seckill/framework.png -------------------------------------------------------------------------------- /ch4-feature/main/hello.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func sayHello() { 6 | fmt.Println("Hello World") 7 | } -------------------------------------------------------------------------------- /ch5-web/SimpleServer.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "net/http" 4 | 5 | func main() { 6 | http.ListenAndServe("127.0.0.1:8080",nil) 7 | } 8 | -------------------------------------------------------------------------------- /ch8-config/config/resume_config.yaml: -------------------------------------------------------------------------------- 1 | RegisterTime: "2019-6-18 10:00:00" 2 | Address: "Shanghai" 3 | ResumeInformation: 4 | Name: "aoho" 5 | Sex: "male" 6 | Age: 20 7 | Habits: 8 | - "Basketball" 9 | - "Running" 10 | -------------------------------------------------------------------------------- /ch11-security/model/user.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | 4 | type UserDetails struct { 5 | // 用户标识 6 | UserId int64 7 | // 用户名 唯一 8 | Username string 9 | // 用户密码 10 | Password string 11 | // 用户具有的权限 12 | Authorities []string // 具备的权限 13 | } 14 | -------------------------------------------------------------------------------- /ch13-seckill/sk-core/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/longjoy/micro-go-book/ch13-seckill/sk-core/setup" 5 | ) 6 | 7 | func main() { 8 | 9 | setup.InitZk() 10 | setup.InitRedis() 11 | setup.RunService() 12 | 13 | } 14 | -------------------------------------------------------------------------------- /ch13-seckill/pkg/common/service_instance.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | 4 | type ServiceInstance struct { 5 | Host string // Host 6 | Port int // Port 7 | Weight int // 权重 8 | CurWeight int // 当前权重 9 | 10 | GrpcPort int 11 | } 12 | 13 | -------------------------------------------------------------------------------- /ch7-rpc/README.md: -------------------------------------------------------------------------------- 1 | #### 安装 protobuf 2 | rpc 部分涉及到 protobuf 3 | 4 | ``` 5 | protoc --version 6 | go get github.com/golang/protobuf 7 | go install github.com/golang/protobuf/protoc-gen-go/ 8 | ``` 9 | 10 | ``` 11 | protoc string.proto --go_out=plugins=grpc:. 12 | ``` -------------------------------------------------------------------------------- /ch4-feature/main/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/longjoy/micro-go-book/ch4-feature/compute" 6 | ) 7 | 8 | func main() { 9 | 10 | params := &compute.IntParams{ 11 | P1:1, 12 | P2:2, 13 | } 14 | fmt.Println(params.Add()) 15 | 16 | } -------------------------------------------------------------------------------- /ch12-trace/zipkin-go/string-services/Makefile: -------------------------------------------------------------------------------- 1 | # builds the Cli and Svc1 & Svc2 projects 2 | 3 | all: clean 4 | @go get -v ./... 5 | @go build -v -o build/svc1 ./svc1/cmd 6 | @go build -v -o build/svc2 ./svc2/cmd 7 | @go build -v -o build/cli ./cli 8 | 9 | clean: 10 | @rm -rf build 11 | -------------------------------------------------------------------------------- /ch5-web/forms/login.tpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
7 | 用户名: 8 | 密码: 9 | 10 |
11 | 12 | -------------------------------------------------------------------------------- /ch3-basic/Callback.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func proc(input string, processor func(str string)) { 6 | processor(input) 7 | } 8 | 9 | func main() { 10 | 11 | proc("王小二", func(str string) { 12 | for _, v := range str{ 13 | fmt.Printf("%c\n", v) 14 | } 15 | }) 16 | } -------------------------------------------------------------------------------- /ch3-basic/Variable.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | func main() { 5 | var a int = 100 6 | var b = "100" 7 | c := 0.17 8 | fmt.Printf("a value is %v, type is %T\n", a, a) 9 | fmt.Printf("b value is %v, type is %T\n", b, b) 10 | fmt.Printf("c value is %v, type is %T\n", c, c) 11 | 12 | } 13 | -------------------------------------------------------------------------------- /ch12-trace/README.md: -------------------------------------------------------------------------------- 1 | ## start consul 2 | 3 | ``` 4 | sudo docker-compose -f docker/docker-compose.yml up 5 | ``` 6 | 7 | 8 | ## start register-service 9 | 10 | ``` 11 | ./register -consul.host localhost -consul.port 8500 -service.host 192.168.1.100 -service.port 9000 12 | ``` 13 | 14 | ## start discover-service -------------------------------------------------------------------------------- /ch13-seckill/sk-core/service/srv_err/error.go: -------------------------------------------------------------------------------- 1 | package srv_err 2 | 3 | const ( 4 | ErrServiceBusy = 1001 5 | ErrSecKillSucc = 1002 6 | ErrNotFoundProduct = 1003 7 | ErrSoldout = 1004 8 | ErrRetry = 1005 9 | ErrAlreadyBuy = 1006 10 | ) 11 | 12 | const ( 13 | ProductStatusSoldout = 2001 14 | ) 15 | -------------------------------------------------------------------------------- /ch3-basic/Embed.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type Wheel struct { 6 | shape string 7 | } 8 | 9 | type Car struct { 10 | Wheel 11 | Name string 12 | } 13 | 14 | func main() { 15 | 16 | car := &Car{ 17 | Wheel{ 18 | "圆形的", 19 | }, 20 | "福特", 21 | } 22 | fmt.Println(car.Name, car.shape, " ") 23 | } 24 | -------------------------------------------------------------------------------- /ch4-feature/compute/add.go: -------------------------------------------------------------------------------- 1 | package compute 2 | 3 | type AddOperator interface { 4 | 5 | /** 6 | * 算术增加 7 | */ 8 | Add() interface{} 9 | 10 | } 11 | 12 | type IntParams struct{ 13 | P1 int // 加数 14 | P2 int // 被加数 15 | } 16 | 17 | func (params *IntParams) Add() interface{} { 18 | return params.P1 + params.P2 19 | } 20 | 21 | 22 | -------------------------------------------------------------------------------- /ch5-web/mysql/script.sql: -------------------------------------------------------------------------------- 1 | create database user; 2 | 3 | drop table if exists `user`; 4 | CREATE TABLE `user` 5 | ( 6 | `id` INT(10) NOT NULL AUTO_INCREMENT, 7 | `name` VARCHAR(64) NULL DEFAULT NULL, 8 | `habits` VARCHAR(128) NULL DEFAULT NULL, 9 | `created_time` DATE NULL DEFAULT NULL, 10 | PRIMARY KEY (`id`) 11 | ); -------------------------------------------------------------------------------- /ch13-seckill/pb/user.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package pb; 4 | 5 | service UserService{ 6 | rpc Check(UserRequest) returns (UserResponse){} 7 | } 8 | 9 | message UserRequest { 10 | string username = 1; 11 | string password = 2; 12 | } 13 | 14 | message UserResponse { 15 | bool result = 1; 16 | int64 userId = 2; 17 | string err = 3; 18 | } -------------------------------------------------------------------------------- /ch3-basic/Anonymous.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // 返回一个人的姓和名 4 | func getName() (string, string){ 5 | return "王", "小二" 6 | } 7 | 8 | func main() { 9 | //surname,_ := getName() // 使用匿名变量 10 | //_, personalName := getName() // 使用匿名变量 11 | // 12 | //fmt.Printf("My surname is %v and my personal name is %v", surname, personalName) 13 | 14 | 15 | 16 | 17 | 18 | } 19 | -------------------------------------------------------------------------------- /ch12-trace/zipkin-kit/pb/string.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package pb; 4 | 5 | service StringService{ 6 | rpc Diff(StringRequest) returns (StringResponse){} 7 | } 8 | 9 | message StringRequest { 10 | string request_type = 1; 11 | string a = 2; 12 | string b = 3; 13 | } 14 | 15 | message StringResponse { 16 | string result = 1; 17 | string err = 2; 18 | } -------------------------------------------------------------------------------- /ch13-seckill/sk-core/bootstrap.yaml: -------------------------------------------------------------------------------- 1 | http: 2 | host: localhost 3 | port: 9032 4 | 5 | rpc: 6 | host: localhost 7 | port: 9132 8 | 9 | discover: 10 | Host: 114.67.98.210 11 | port: 8500 12 | instanceId: sk-core-localhost 13 | serviceName: sk-core # 要缓存sk-app 14 | weight: 10 15 | 16 | 17 | config: 18 | id: config-service 19 | profile: "dev" 20 | label: "master" -------------------------------------------------------------------------------- /ch13-seckill/user-service/bootstrap.yaml: -------------------------------------------------------------------------------- 1 | 2 | http: 3 | host: 114.67.98.210 4 | port: 9009 5 | 6 | rpc: 7 | host: localhost 8 | port: 9108 9 | 10 | discover: 11 | Host: 114.67.98.210 12 | port: 8500 13 | instanceId: user-service-localhost 14 | serviceName: user 15 | weight: 10 16 | 17 | config: 18 | id: config-service 19 | profile: "dev" 20 | label: "master" -------------------------------------------------------------------------------- /ch13-seckill/sk-admin/bootstrap.yaml: -------------------------------------------------------------------------------- 1 | 2 | http: 3 | host: localhost 4 | port: 9030 5 | 6 | rpc: 7 | host: localhost 8 | port: 9132 9 | 10 | discover: 11 | Host: 114.67.98.210 12 | port: 8500 13 | instanceId: sk-admin-localhost 14 | serviceName: sk-admin 15 | weight: 10 16 | 17 | 18 | config: 19 | id: config-service 20 | profile: "dev" 21 | label: "master" 22 | -------------------------------------------------------------------------------- /ch13-seckill/sk-app/bootstrap.yaml: -------------------------------------------------------------------------------- 1 | 2 | http: 3 | host: localhost 4 | port: 9031 5 | 6 | 7 | rpc: 8 | host: localhost 9 | port: 9132 10 | 11 | discover: 12 | Host: 114.67.98.210 13 | port: 8500 14 | instanceId: sk-app-localhost 15 | serviceName: sk-app # 要缓存sk-app 16 | weight: 10 17 | 18 | 19 | config: 20 | id: config-service 21 | profile: "dev" 22 | label: "master" -------------------------------------------------------------------------------- /ch13-seckill/oauth-service/bootstrap.yaml: -------------------------------------------------------------------------------- 1 | 2 | http: 3 | host: 114.67.98.210 4 | port: 9019 5 | 6 | 7 | rpc: 8 | host: localhost 9 | port: 9018 10 | 11 | 12 | discover: 13 | Host: 114.67.98.210 14 | port: 8500 15 | instanceId: oauth-service-localhost 16 | serviceName: oauth 17 | weight: 10 18 | 19 | config: 20 | id: config-service 21 | profile: "dev" 22 | label: "master" -------------------------------------------------------------------------------- /ch11-security/model/client.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | 4 | type ClientDetails struct { 5 | // client 的标识 6 | ClientId string 7 | // client 的密钥 8 | ClientSecret string 9 | // 访问令牌有效时间,秒 10 | AccessTokenValiditySeconds int 11 | // 刷新令牌有效时间,秒 12 | RefreshTokenValiditySeconds int 13 | // 重定向地址,授权码类型中使用 14 | RegisteredRedirectUri string 15 | // 可以使用的授权类型 16 | AuthorizedGrantTypes []string 17 | } 18 | -------------------------------------------------------------------------------- /ch3-basic/List.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "container/list" 5 | "fmt" 6 | ) 7 | 8 | func main() { 9 | 10 | 11 | tmpList := list.New() 12 | 13 | for i:= 1 ; i <= 10 ; i++ { 14 | tmpList.PushBack(i) 15 | } 16 | 17 | first := tmpList.PushFront(0) 18 | tmpList.Remove(first) 19 | 20 | for l := tmpList.Front(); l != nil; l = l.Next(){ 21 | fmt.Print(l.Value, " ") 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /ch7-rpc/pb/string.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package pb; 4 | 5 | service StringService{ 6 | rpc Concat(StringRequest) returns (StringResponse) {} 7 | rpc Diff(StringRequest) returns (StringResponse) {} 8 | 9 | } 10 | 11 | message StringRequest { 12 | string A = 1; 13 | string B = 2; 14 | } 15 | 16 | message StringResponse { 17 | string Ret = 1; 18 | string err = 2; 19 | } 20 | -------------------------------------------------------------------------------- /ch13-seckill/sk-core/service/service.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | // Service Define a service interface 4 | type Service interface { 5 | 6 | // Divide calculate a/b 7 | SecKill() (int, error) 8 | } 9 | 10 | //ArithmeticService implement Service interface 11 | type SecKillService struct { 12 | } 13 | 14 | // Add implement Add method 15 | func (s SecKillService) SecKill(a, b int) int { 16 | return a + b 17 | } -------------------------------------------------------------------------------- /ch13-seckill/oauth-service/model/user.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | 4 | type UserDetails struct { 5 | // 用户标识 6 | UserId int64 7 | // 用户名 唯一 8 | Username string 9 | // 用户密码 10 | Password string 11 | // 用户具有的权限 12 | Authorities []string // 具备的权限 13 | } 14 | 15 | 16 | func (userDetails *UserDetails) IsMatch (username string, password string) bool { 17 | 18 | return userDetails.Password == password && userDetails.Username == username 19 | } -------------------------------------------------------------------------------- /ch3-basic/Map.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | 7 | classMates1 := make(map[int]string) 8 | 9 | // 添加映射关系 10 | classMates1[0] = "小明" 11 | classMates1[1] = "小红" 12 | classMates1[2] = "小张" 13 | 14 | fmt.Printf("id %v is %v\n", 1, classMates1[1]) 15 | 16 | // 在声明时初始化数据 17 | classMates2 := map[int]string{ 18 | 0 : "小明", 19 | 1 : "小红", 20 | 2 : "小张", 21 | } 22 | 23 | fmt.Printf("id %v is %v\n", 3, classMates2[3]) 24 | 25 | } -------------------------------------------------------------------------------- /ch3-basic/Flag.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | ) 7 | 8 | func main() { 9 | 10 | 11 | //参数依次是命令行参数的名称,默认值,提示 12 | surname := flag.String("surname", "王", "您的姓") 13 | //除了返回结果,还可以直接传入变量地址获取参数值 14 | var personalName string 15 | flag.StringVar(&personalName, "personalName", "小二", "您的名") 16 | id := flag.Int("id", 0, "您的ID") 17 | //解析命令行参数 18 | flag.Parse() 19 | fmt.Printf("I am %v %v, and my id is %v\n", *surname, personalName, *id) 20 | 21 | 22 | } -------------------------------------------------------------------------------- /ch13-seckill/sk-admin/setup/zk.go: -------------------------------------------------------------------------------- 1 | package setup 2 | 3 | import ( 4 | "fmt" 5 | conf "github.com/longjoy/micro-go-book/ch13-seckill/pkg/config" 6 | "github.com/samuel/go-zookeeper/zk" 7 | "time" 8 | ) 9 | 10 | //初始化Etcd 11 | func InitZk() { 12 | var hosts = []string{"39.98.179.73:2181"} 13 | conn, _, err := zk.Connect(hosts, time.Second*5) 14 | if err != nil { 15 | fmt.Println(err) 16 | return 17 | } 18 | conf.Zk.ZkConn = conn 19 | conf.Zk.SecProductKey = "/product" 20 | } 21 | -------------------------------------------------------------------------------- /ch13-seckill/user-service/user-script.sql: -------------------------------------------------------------------------------- 1 | create database user; 2 | 3 | drop table if exists `user`; 4 | CREATE TABLE `user` 5 | ( 6 | `user_id` INT(10) NOT NULL AUTO_INCREMENT, 7 | `user_name` VARCHAR(64) NULL DEFAULT NULL, 8 | `password` VARCHAR(128) NULL DEFAULT NULL, 9 | `age` INT(10) NULL DEFAULT NULL, 10 | 11 | 12 | PRIMARY KEY (`user_id`) 13 | ); 14 | 15 | insert into user (`user_name`, `password`, `age`) values ('user', 'password', 25); -------------------------------------------------------------------------------- /ch13-seckill/oauth-service/service/common_service.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | 4 | 5 | type Service interface { 6 | // HealthCheck check service health status 7 | HealthCheck() bool 8 | } 9 | 10 | type CommentService struct { 11 | 12 | } 13 | 14 | // HealthCheck implement Service method 15 | // 用于检查服务的健康状态,这里仅仅返回true 16 | func (s *CommentService) HealthCheck() bool { 17 | return true 18 | } 19 | 20 | func NewCommentService() *CommentService { 21 | return &CommentService{} 22 | } 23 | 24 | -------------------------------------------------------------------------------- /ch13-seckill/sk-app/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/longjoy/micro-go-book/ch13-seckill/pkg/bootstrap" 5 | "github.com/longjoy/micro-go-book/ch13-seckill/sk-app/setup" 6 | ) 7 | 8 | func main() { 9 | //mysql.InitMysql(conf.MysqlConfig.Host, conf.MysqlConfig.Port, conf.MysqlConfig.User, conf.MysqlConfig.Pwd, conf.MysqlConfig.Db) // conf.MysqlConfig.Db 10 | setup.InitZk() 11 | setup.InitRedis() 12 | setup.InitServer(bootstrap.HttpConfig.Host, bootstrap.HttpConfig.Port) 13 | } 14 | -------------------------------------------------------------------------------- /ch6-discovery/config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | kitlog "github.com/go-kit/kit/log" 5 | "log" 6 | "os" 7 | ) 8 | 9 | 10 | var Logger *log.Logger 11 | var KitLogger kitlog.Logger 12 | 13 | 14 | func init() { 15 | Logger = log.New(os.Stderr, "", log.LstdFlags) 16 | 17 | KitLogger = kitlog.NewLogfmtLogger(os.Stderr) 18 | KitLogger = kitlog.With(KitLogger, "ts", kitlog.DefaultTimestampUTC) 19 | KitLogger = kitlog.With(KitLogger, "caller", kitlog.DefaultCaller) 20 | 21 | } 22 | 23 | -------------------------------------------------------------------------------- /ch12-trace/zipkin-go/string-services/svc2/service.go: -------------------------------------------------------------------------------- 1 | // +build go1.7 2 | 3 | package svc2 4 | 5 | import ( 6 | "context" 7 | "errors" 8 | ) 9 | 10 | // Service constants 11 | const ( 12 | Int64Max = 1<<63 - 1 13 | Int64Min = -(Int64Max + 1) 14 | ) 15 | 16 | // Service errors 17 | var ( 18 | ErrIntOverflow = errors.New("integer overflow occurred") 19 | ) 20 | 21 | // Service interface to our svc2 service. 22 | type Service interface { 23 | Sum(ctx context.Context, a int64, b int64) (int64, error) 24 | } 25 | -------------------------------------------------------------------------------- /ch13-seckill/sk-admin/service/service.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | // Service Define a service interface 4 | type Service interface { 5 | // HealthCheck check service health status 6 | HealthCheck() bool 7 | } 8 | 9 | //UserService implement Service interface 10 | type SkAdminService struct { 11 | } 12 | 13 | // HealthCheck implement Service method 14 | // 用于检查服务的健康状态,这里仅仅返回true 15 | func (s SkAdminService) HealthCheck() bool { 16 | return true 17 | } 18 | 19 | type ServiceMiddleware func(Service) Service 20 | -------------------------------------------------------------------------------- /ch4-feature/concurrency/first_concurrency.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func setVTo1(v *int) { 8 | 9 | *v = 1 10 | } 11 | 12 | func setVTo2(v *int) { 13 | *v = 2 14 | } 15 | 16 | func main() { 17 | 18 | v := new(int) 19 | go setVTo1(v) 20 | go setVTo2(v) 21 | fmt.Println(*v) 22 | 23 | 24 | //go func(name string) { 25 | // fmt.Println("Hello " + name ) 26 | //}("xuan") 27 | //// 主 goroutine 阻塞 1 s 28 | //time.Sleep(time.Second) 29 | 30 | } 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /ch11-security/config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | kitlog "github.com/go-kit/kit/log" 5 | "log" 6 | "os" 7 | ) 8 | 9 | 10 | var Logger *log.Logger 11 | var KitLogger kitlog.Logger 12 | 13 | 14 | func init() { 15 | Logger = log.New(os.Stderr, "", log.LstdFlags) 16 | 17 | KitLogger = kitlog.NewLogfmtLogger(os.Stderr) 18 | KitLogger = kitlog.With(KitLogger, "ts", kitlog.DefaultTimestampUTC) 19 | KitLogger = kitlog.With(KitLogger, "caller", kitlog.DefaultCaller) 20 | 21 | 22 | } 23 | 24 | 25 | -------------------------------------------------------------------------------- /ch12-trace/zipkin-go/string-services/svc1/service.go: -------------------------------------------------------------------------------- 1 | // +build go1.7 2 | 3 | package svc1 4 | 5 | import ( 6 | "context" 7 | "errors" 8 | ) 9 | 10 | // Service constants 11 | const ( 12 | StrMaxSize = 1024 13 | ) 14 | 15 | // Service errors 16 | var ( 17 | ErrMaxSize = errors.New("maximum size of 1024 bytes exceeded") 18 | ) 19 | 20 | // Service interface 21 | type Service interface { 22 | Concat(ctx context.Context, a, b string) (string, error) 23 | Sum(ctx context.Context, a, b int64) (int64, error) 24 | } 25 | -------------------------------------------------------------------------------- /ch10-resiliency/string-service/config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | kitlog "github.com/go-kit/kit/log" 5 | "log" 6 | "os" 7 | ) 8 | 9 | 10 | var Logger *log.Logger 11 | var KitLogger kitlog.Logger 12 | 13 | 14 | func init() { 15 | Logger = log.New(os.Stderr, "", log.LstdFlags) 16 | 17 | KitLogger = kitlog.NewLogfmtLogger(os.Stderr) 18 | KitLogger = kitlog.With(KitLogger, "ts", kitlog.DefaultTimestampUTC) 19 | KitLogger = kitlog.With(KitLogger, "caller", kitlog.DefaultCaller) 20 | 21 | 22 | } 23 | 24 | 25 | -------------------------------------------------------------------------------- /ch6-discovery/string-service/config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | kitlog "github.com/go-kit/kit/log" 5 | "log" 6 | "os" 7 | ) 8 | 9 | 10 | var Logger *log.Logger 11 | var KitLogger kitlog.Logger 12 | 13 | 14 | func init() { 15 | Logger = log.New(os.Stderr, "", log.LstdFlags) 16 | 17 | KitLogger = kitlog.NewLogfmtLogger(os.Stderr) 18 | KitLogger = kitlog.With(KitLogger, "ts", kitlog.DefaultTimestampUTC) 19 | KitLogger = kitlog.With(KitLogger, "caller", kitlog.DefaultCaller) 20 | 21 | 22 | } 23 | 24 | 25 | -------------------------------------------------------------------------------- /ch10-resiliency/use-string-service/config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | kitlog "github.com/go-kit/kit/log" 5 | "log" 6 | "os" 7 | ) 8 | 9 | 10 | var Logger *log.Logger 11 | var KitLogger kitlog.Logger 12 | 13 | 14 | func init() { 15 | Logger = log.New(os.Stderr, "", log.LstdFlags) 16 | 17 | KitLogger = kitlog.NewLogfmtLogger(os.Stderr) 18 | KitLogger = kitlog.With(KitLogger, "ts", kitlog.DefaultTimestampUTC) 19 | KitLogger = kitlog.With(KitLogger, "caller", kitlog.DefaultCaller) 20 | 21 | 22 | } 23 | 24 | 25 | -------------------------------------------------------------------------------- /ch11-security/model/token.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import "time" 4 | 5 | type OAuth2Token struct { 6 | 7 | // 刷新令牌 8 | RefreshToken *OAuth2Token 9 | // 令牌类型 10 | TokenType string 11 | // 令牌 12 | TokenValue string 13 | // 过期时间 14 | ExpiresTime *time.Time 15 | 16 | } 17 | 18 | 19 | func (oauth2Token *OAuth2Token) IsExpired() bool { 20 | return oauth2Token.ExpiresTime != nil && 21 | oauth2Token.ExpiresTime.Before(time.Now()) 22 | } 23 | 24 | type OAuth2Details struct { 25 | Client *ClientDetails 26 | User *UserDetails 27 | } -------------------------------------------------------------------------------- /ch12-trace/zipkin-kit/docker/prometheus.yml: -------------------------------------------------------------------------------- 1 | global: 2 | scrape_interval: 15s 3 | external_labels: 4 | monitor: 'string-service-monitor' 5 | 6 | scrape_configs: 7 | - job_name: 'prometheus' 8 | scrape_interval: 5s 9 | static_configs: 10 | - targets: ['localhost:9090'] 11 | labels: 12 | group: 'local' 13 | 14 | - job_name: 'string-service' 15 | scrape_interval: 5s 16 | static_configs: 17 | - targets: ['localhost:9000'] 18 | labels: 19 | group: 'string-service' 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Go语言高并发与微服务实战 2 | 近年来云原生技术发展迅猛,帮助开发者在云上快速和频繁地构建、发布和部署应用,以提高开发效率和快速定位故障。 3 | 4 | 微服务作为开展云原生技术落地的核心,它将复杂的单体应用按照业务划分并进行有效地拆分,每个微服务都可以进行独立部署和开发,大大提升了应用开发效率。Go语言作为新生代的编译型编程语言,具备语法简单、高并发性能良好和编译速度快等特点,是微服务架构落地实践的绝妙利器。 5 | 6 | 本书围绕云原生、微服务和Go语言,介绍如何通过Go语言进行微服务架构开发与实践。旨在帮助读者深入理解微服务架构并使用Go语言快速加入到微服务开发中。 7 | 8 | ### 环境搭建 9 | 10 | #### golang 安装 11 | 本书基于的 Go 版本为 1.12.4,使用 go mod 管理依赖。具体使用可参见本书基础部分。 12 | 13 | #### setup 14 | 15 | ```sh 16 | go mod tidy 17 | ``` 18 | ### Q&A 19 | 如有问题,可在 [链接](https://github.com/longjoy/micro-go-book) 提出 issue。 20 | -------------------------------------------------------------------------------- /ch3-basic/Array.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | 7 | var classMates1 [3]string 8 | 9 | classMates1[0] = "小明" 10 | classMates1[1] = "小红" 11 | classMates1[2] = "小李" 12 | fmt.Println(classMates1) 13 | fmt.Println("The No.1 student is " + classMates1[0]) 14 | 15 | classMates2 := [...]string{"小明", "小红", "小李"} 16 | fmt.Println(classMates2) 17 | 18 | 19 | classMates3 := new([3]string) 20 | classMates3[0] = "小明" 21 | classMates3[1] = "小红" 22 | classMates3[2] = "小李" 23 | fmt.Println(*classMates3) 24 | 25 | 26 | } -------------------------------------------------------------------------------- /ch3-basic/FunctionImplementor.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type Printer interface { 6 | Print(p interface{}) 7 | } 8 | 9 | 10 | // 函数定义为类型 11 | type FuncCaller func(p interface{}) 12 | 13 | // 实现Printer的Print方法 14 | func (funcCaller FuncCaller) Print(p interface{}) { 15 | // 调用funcCaller函数本体 16 | funcCaller(p) 17 | } 18 | 19 | func main() { 20 | var printer Printer 21 | // 将匿名函数强转为FuncCaller赋值给printer 22 | printer = FuncCaller(func(p interface{}) { 23 | fmt.Println(p) 24 | }) 25 | printer.Print("Golang is Good!") 26 | } 27 | -------------------------------------------------------------------------------- /ch13-seckill/sk-core/setup/redis.go: -------------------------------------------------------------------------------- 1 | package setup 2 | 3 | import ( 4 | "github.com/go-redis/redis" 5 | conf "github.com/longjoy/micro-go-book/ch13-seckill/pkg/config" 6 | "log" 7 | ) 8 | 9 | //初始化redis 10 | func InitRedis() { 11 | client := redis.NewClient(&redis.Options{ 12 | Addr: conf.Redis.Host, 13 | Password: conf.Redis.Password, 14 | DB: conf.Redis.Db, 15 | }) 16 | 17 | _, err := client.Ping().Result() 18 | if err != nil { 19 | log.Printf("Connect redis failed. Error : %v", err) 20 | } 21 | conf.Redis.RedisConn = client 22 | } 23 | -------------------------------------------------------------------------------- /ch13-seckill/gateway/bootstrap.yaml: -------------------------------------------------------------------------------- 1 | 2 | http: 3 | host: 114.67.98.210 4 | port: 9090 5 | 6 | 7 | discover: 8 | Host: 114.67.98.210 9 | port: 8500 10 | instanceId: gateway-service-localhost 11 | serviceName: gateway 12 | weight: 10 13 | 14 | 15 | config: 16 | id: config-service 17 | profile: "dev" 18 | label: "master" 19 | 20 | trace: 21 | host: 114.67.98.210 22 | port: 9411 23 | url: /api/v2/spans 24 | 25 | rpc: 26 | port: 1111 27 | 28 | auth: 29 | permitAll: 30 | - 31 | /oauth/** 32 | - 33 | /string/** 34 | 35 | -------------------------------------------------------------------------------- /ch7-rpc/basic/server.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/longjoy/micro-go-book/ch7-rpc/basic/string-service" 5 | "log" 6 | "net" 7 | "net/http" 8 | "net/rpc" 9 | ) 10 | 11 | func main() { 12 | stringService := new(service.StringService) 13 | registerError := rpc.Register(stringService) 14 | if registerError != nil { 15 | log.Fatal("Register error: ", registerError) 16 | } 17 | rpc.HandleHTTP() 18 | l, e := net.Listen("tcp", "127.0.0.1:1234") 19 | if e != nil { 20 | log.Fatal("listen error:", e) 21 | } 22 | http.Serve(l, nil) 23 | } 24 | -------------------------------------------------------------------------------- /ch13-seckill/oauth-service/model/token.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import "time" 4 | 5 | type OAuth2Token struct { 6 | 7 | // 刷新令牌 8 | RefreshToken *OAuth2Token 9 | // 令牌类型 10 | TokenType string 11 | // 令牌 12 | TokenValue string 13 | // 过期时间 14 | ExpiresTime *time.Time 15 | 16 | } 17 | 18 | 19 | func (oauth2Token *OAuth2Token) IsExpired() bool { 20 | return oauth2Token.ExpiresTime != nil && 21 | oauth2Token.ExpiresTime.Before(time.Now()) 22 | } 23 | 24 | type OAuth2Details struct { 25 | 26 | 27 | Client *ClientDetails 28 | 29 | User *UserDetails 30 | 31 | } -------------------------------------------------------------------------------- /ch4-feature/synch/wait_group.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | "sync" 7 | "time" 8 | ) 9 | 10 | func main() { 11 | 12 | var waitGroup sync.WaitGroup 13 | 14 | 15 | waitGroup.Add(5) 16 | 17 | for i := 0 ; i < 5 ; i++{ 18 | go func(i int) { 19 | fmt.Println("work " + strconv.Itoa(i) + " is done at " + time.Now().String()) 20 | // 等待 1 s 后减少等待数 21 | time.Sleep(time.Second) 22 | waitGroup.Done() 23 | }(i) 24 | } 25 | 26 | waitGroup.Wait() 27 | 28 | fmt.Println("all works are done at " + time.Now().String()) 29 | 30 | } 31 | -------------------------------------------------------------------------------- /ch13-seckill/sk-admin/setup/etcd.go: -------------------------------------------------------------------------------- 1 | package setup 2 | 3 | import ( 4 | "github.com/coreos/etcd/clientv3" 5 | conf "github.com/longjoy/micro-go-book/ch13-seckill/pkg/config" 6 | "log" 7 | "time" 8 | ) 9 | 10 | //初始化Etcd 11 | func InitEtcd() { 12 | 13 | cli, err := clientv3.New(clientv3.Config{ 14 | Endpoints: []string{"39.98.179.73:2379"}, // conf.Etcd.Host 15 | DialTimeout: 5 * time.Second, 16 | }) 17 | if err != nil { 18 | log.Printf("Connect etcd failed. Error : %v", err) 19 | } 20 | conf.Etcd.EtcdSecProductKey = "product" 21 | conf.Etcd.EtcdConn = cli 22 | } 23 | -------------------------------------------------------------------------------- /ch13-seckill/sk-core/service/srv_limit/sec_limit.go: -------------------------------------------------------------------------------- 1 | package srv_limit 2 | 3 | //每秒限制 4 | type SecLimit struct { 5 | count int //次数 6 | preTime int64 //上一次记录时间 7 | } 8 | 9 | //当前秒的访问次数 10 | func (p *SecLimit) Count(nowTime int64) (curCount int) { 11 | if p.preTime != nowTime { 12 | p.count = 1 13 | p.preTime = nowTime 14 | curCount = p.count 15 | return 16 | } 17 | 18 | p.count++ 19 | curCount = p.count 20 | return 21 | } 22 | 23 | func (p *SecLimit) Check(nowTime int64) int { 24 | if p.preTime != nowTime { 25 | return 0 26 | } 27 | return p.count 28 | } 29 | -------------------------------------------------------------------------------- /ch8-config/resume.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/longjoy/micro-go-book/ch8-config/conf" 6 | "github.com/spf13/viper" 7 | "log" 8 | "net/http" 9 | ) 10 | 11 | func main() { 12 | http.HandleFunc("/resumes", func(w http.ResponseWriter, req *http.Request) { 13 | //q := events.goreq.URL.Query().Get("q") 14 | _, _ = fmt.Fprintf(w, "个人信息:\n") 15 | _, _ = fmt.Fprintf(w, "姓名:%s,\n性别:%s,\n年龄 %d!", viper.GetString("resume.name"), conf.Resume.Sex, conf.Resume.Age) //这个写入到w的是输出到客户端的 16 | }) 17 | log.Fatal(http.ListenAndServe(":8081", nil)) 18 | } 19 | 20 | -------------------------------------------------------------------------------- /ch3-basic/Counter.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | 6 | type Tank interface{ 7 | Walk() 8 | Fire() 9 | } 10 | 11 | func createCounter(initial int) func() int { 12 | 13 | if initial < 0{ 14 | initial = 0 15 | } 16 | 17 | // 引用initial,创建一个闭包 18 | return func() int{ 19 | initial++ 20 | // 返回当前计数 21 | return initial; 22 | } 23 | 24 | } 25 | 26 | func main() { 27 | 28 | // 计数器1 29 | c1 := createCounter(1) 30 | 31 | fmt.Println(c1()) // 2 32 | fmt.Println(c1()) // 3 33 | 34 | // 计数器2 35 | c2 := createCounter(10) 36 | 37 | fmt.Println(c2()) // 11 38 | fmt.Println(c1()) // 4 39 | 40 | } -------------------------------------------------------------------------------- /ch7-rpc/stream-pb/stream_string.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package stream_pb; 4 | 5 | service StringService{ 6 | rpc Concat(StringRequest) returns (StringResponse) {} 7 | rpc LotsOfServerStream(StringRequest) returns (stream StringResponse) {} 8 | rpc LotsOfClientStream(stream StringRequest) returns (StringResponse) {} 9 | rpc LotsOfServerAndClientStream(stream StringRequest) returns (stream StringResponse) {} 10 | } 11 | 12 | message StringRequest { 13 | string A = 1; 14 | string B = 2; 15 | } 16 | 17 | message StringResponse { 18 | string Ret = 1; 19 | string err = 2; 20 | } 21 | -------------------------------------------------------------------------------- /common/loadbalance/loadbalance_test.go: -------------------------------------------------------------------------------- 1 | package loadbalance 2 | 3 | //func TestMain(m *testing.M) { 4 | // instances := make([]*discover.ServiceInstance, 10) 5 | // for i := 0; i < len(instances); i++ { 6 | // instances[i] = &discover.ServiceInstance{ 7 | // Host: string(i), 8 | // Port: i, 9 | // GrpcPort: (i + 1), 10 | // Weight: i, 11 | // CurWeight: 0, 12 | // } 13 | // } 14 | // 15 | // load := &WeightRoundRobinLoadBalance{} 16 | // for i := 0; i < 2*len(instances); i++ { 17 | // service, _ := load.SelectService(instances) 18 | // fmt.Println("service is : ", service.Host) 19 | // } 20 | // 21 | //} 22 | -------------------------------------------------------------------------------- /ch13-seckill/sk-admin/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/longjoy/micro-go-book/ch13-seckill/pkg/bootstrap" 5 | conf "github.com/longjoy/micro-go-book/ch13-seckill/pkg/config" 6 | "github.com/longjoy/micro-go-book/ch13-seckill/pkg/mysql" 7 | "github.com/longjoy/micro-go-book/ch13-seckill/sk-admin/setup" 8 | ) 9 | 10 | func main() { 11 | mysql.InitMysql(conf.MysqlConfig.Host, conf.MysqlConfig.Port, conf.MysqlConfig.User, conf.MysqlConfig.Pwd, conf.MysqlConfig.Db) // conf.MysqlConfig.Db 12 | //setup.InitEtcd() 13 | setup.InitZk() 14 | setup.InitServer(bootstrap.HttpConfig.Host, bootstrap.HttpConfig.Port) 15 | 16 | } 17 | -------------------------------------------------------------------------------- /ch7-rpc/stream/server.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | pb "github.com/longjoy/micro-go-book/ch7-rpc/stream-pb" 6 | "github.com/longjoy/micro-go-book/ch7-rpc/stream/string-service" 7 | "github.com/prometheus/common/log" 8 | "google.golang.org/grpc" 9 | "net" 10 | ) 11 | 12 | func main() { 13 | flag.Parse() 14 | lis, err := net.Listen("tcp", "127.0.0.1:1234") 15 | if err != nil { 16 | log.Fatalf("failed to listen: %v", err) 17 | } 18 | grpcServer := grpc.NewServer() 19 | stringService := new(string_service.StringService) 20 | pb.RegisterStringServiceServer(grpcServer, stringService) 21 | grpcServer.Serve(lis) 22 | } 23 | -------------------------------------------------------------------------------- /ch13-seckill/pkg/config/need_config.conf: -------------------------------------------------------------------------------- 1 | ### 秒杀性能配置 2 | 3 | service: 4 | ip_sec_access_limit: 1000 5 | ip_min_access_limit: 1000 6 | user_sec_access_limit: 1000 7 | user_min_access_limit: 1000 8 | write_proxy2layer_goroutine_num: 100 9 | read_proxy2layer_goroutine_num: 100 10 | cookie_secretkey: zxfyazzaa 11 | refer_whitelist: 12 | - test 13 | 14 | 15 | redis: 16 | host: localhost 17 | password: 6378 18 | db: 0 19 | proxy2layer_queue_name: name 20 | ip_black_list_hash: 12 21 | id_black_list_queue: 12 22 | 23 | etcd: 24 | host: localhost 25 | product_key: zxfyazzaa 26 | 27 | http: 28 | host: localhost 29 | 30 | -------------------------------------------------------------------------------- /ch7-rpc/grpc/server.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | string_service "github.com/longjoy/micro-go-book/ch7-rpc/grpc/string-service" 6 | "github.com/longjoy/micro-go-book/ch7-rpc/pb" 7 | "github.com/prometheus/common/log" 8 | "google.golang.org/grpc" 9 | "net" 10 | ) 11 | 12 | func main() { 13 | flag.Parse() 14 | lis, err := net.Listen("tcp", "127.0.0.1:1234") 15 | if err != nil { 16 | log.Fatalf("failed to listen: %v", err) 17 | } 18 | grpcServer := grpc.NewServer() 19 | stringService := new(string_service.StringService) 20 | pb.RegisterStringServiceServer(grpcServer, stringService) 21 | grpcServer.Serve(lis) 22 | } 23 | -------------------------------------------------------------------------------- /ch7-rpc/grpc/client.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "github.com/longjoy/micro-go-book/ch7-rpc/pb" 7 | "google.golang.org/grpc" 8 | ) 9 | 10 | func main() { 11 | serviceAddress := "127.0.0.1:1234" 12 | conn, err := grpc.Dial(serviceAddress, grpc.WithInsecure()) 13 | if err != nil { 14 | panic("connect error") 15 | } 16 | defer conn.Close() 17 | bookClient := pb.NewStringServiceClient(conn) 18 | stringReq := &pb.StringRequest{A: "A", B: "B"} 19 | reply, _ := bookClient.Concat(context.Background(), stringReq) 20 | fmt.Printf("StringService Concat : %s concat %s = %s\n", stringReq.A, stringReq.B, reply.Ret) 21 | } 22 | -------------------------------------------------------------------------------- /ch13-seckill/gateway/config/AuthPermission.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "regexp" 5 | "strings" 6 | ) 7 | 8 | var ( 9 | AuthPermitConfig AuthPermitAll 10 | ) 11 | 12 | //Http配置 13 | type AuthPermitAll struct { 14 | PermitAll []interface{} 15 | } 16 | 17 | func Match(str string) bool { 18 | if len(AuthPermitConfig.PermitAll) > 0 { 19 | targetValue := AuthPermitConfig.PermitAll 20 | for i := 0; i < len(targetValue); i++ { 21 | s := targetValue[i].(string) 22 | res, _ := regexp.MatchString(strings.ReplaceAll(s, "**", "(.*?)"), str) 23 | if res { 24 | return true 25 | } 26 | 27 | } 28 | } 29 | 30 | return false 31 | } 32 | -------------------------------------------------------------------------------- /ch13-seckill/sk-app/service/srv_limit/sec_limit.go: -------------------------------------------------------------------------------- 1 | package srv_limit 2 | 3 | type Limit struct { 4 | secLimit TimeLimit 5 | minLimit TimeLimit 6 | } 7 | 8 | //秒限制 9 | type SecLimit struct { 10 | count int 11 | curTime int64 12 | } 13 | 14 | //一秒内访问的次数 15 | func (p *SecLimit) Count(nowTime int64) (curCount int) { 16 | if p.curTime != nowTime { 17 | p.count = 1 18 | p.curTime = nowTime 19 | curCount = p.count 20 | return 21 | } 22 | 23 | p.count++ 24 | curCount = p.count 25 | return 26 | } 27 | 28 | //检查用户访问的次数 29 | func (p *SecLimit) Check(nowTime int64) int { 30 | if p.curTime != nowTime { 31 | return 0 32 | } 33 | return p.count 34 | } 35 | -------------------------------------------------------------------------------- /ch3-basic/Foreach.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func main() { 8 | 9 | // 数组的遍历 10 | nums := [...]int{1,2,3,4,5,6,7,8} 11 | 12 | for k, v:= range nums{ 13 | // k为下标,v为对应的值 14 | fmt.Println(k, v, " ") 15 | } 16 | 17 | fmt.Println() 18 | 19 | // 切片的遍历 20 | slis := []int{1,2,3,4,5,6,7,8} 21 | for k, v:= range slis{ 22 | // k为下标,v为对应的值 23 | fmt.Println(k, v, " ") 24 | } 25 | 26 | fmt.Println() 27 | 28 | 29 | // 字典的遍历 30 | tmpMap := map[int]string{ 31 | 0 : "小明", 32 | 1 : "小红", 33 | 2 : "小张", 34 | } 35 | 36 | for k, v:= range tmpMap{ 37 | // k为键值,v为对应值 38 | fmt.Println(k, v, " ") 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /ch13-seckill/sk-core/service/srv_user/user_history.go: -------------------------------------------------------------------------------- 1 | package srv_user 2 | 3 | import "sync" 4 | 5 | //用户购买历史记录 6 | type UserBuyHistory struct { 7 | History map[int]int 8 | Lock sync.RWMutex 9 | } 10 | 11 | func (p *UserBuyHistory) GetProductBuyCount(productId int) int { 12 | p.Lock.RLock() 13 | defer p.Lock.RUnlock() 14 | 15 | count, _ := p.History[productId] 16 | return count 17 | } 18 | 19 | func (p *UserBuyHistory) Add(productId, count int) { 20 | p.Lock.Lock() 21 | defer p.Lock.Unlock() 22 | 23 | cur, ok := p.History[productId] 24 | if !ok { 25 | cur = count 26 | } else { 27 | cur += count 28 | } 29 | 30 | p.History[productId] = cur 31 | } 32 | -------------------------------------------------------------------------------- /ch13-seckill/pkg/bootstrap/BootstrapProperty.go: -------------------------------------------------------------------------------- 1 | package bootstrap 2 | 3 | var ( 4 | HttpConfig HttpConf 5 | DiscoverConfig DiscoverConf 6 | ConfigServerConfig ConfigServerConf 7 | RpcConfig RpcConf 8 | ) 9 | 10 | //Http配置 11 | type HttpConf struct { 12 | Host string 13 | Port string 14 | } 15 | 16 | // RPC配置 17 | type RpcConf struct { 18 | Port string 19 | } 20 | 21 | //服务发现与注册配置 22 | type DiscoverConf struct { 23 | Host string 24 | Port string 25 | ServiceName string 26 | Weight int 27 | InstanceId string 28 | } 29 | 30 | //配置中心 31 | type ConfigServerConf struct { 32 | Id string 33 | Profile string 34 | Label string 35 | } 36 | -------------------------------------------------------------------------------- /ch13-seckill/pb/seckill.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package pb; 4 | 5 | service SecKillService{ 6 | rpc secKill(SecRequest) returns (SecResponse){} 7 | } 8 | 9 | 10 | message SecRequest { 11 | int64 ProductId = 1; 12 | string Source = 2; 13 | string AuthCode = 3; 14 | string SecTime = 4; 15 | string Nance = 5; 16 | int64 UserId = 6; 17 | string UserAuthSign = 7; 18 | int64 AccessTime = 8; 19 | string ClientAddr = 9; 20 | string ClientRefence = 10; 21 | } 22 | 23 | message SecResponse { 24 | int64 ProductId = 1; 25 | int64 UserId = 2; 26 | string Token = 3; 27 | int64 TokenTime = 4; 28 | int64 Code = 5; 29 | } 30 | 31 | 32 | -------------------------------------------------------------------------------- /ch13-seckill/sk-app/service/srv_limit/min_limit.go: -------------------------------------------------------------------------------- 1 | package srv_limit 2 | 3 | type TimeLimit interface { 4 | Count(nowTIme int64) (curCount int) 5 | Check(nowTIme int64) int 6 | } 7 | 8 | //分钟限制 9 | type MinLimit struct { 10 | count int 11 | curTime int64 12 | } 13 | 14 | //在1分钟之内访问的次数 15 | func (p *MinLimit) Count(nowTime int64) (curCount int) { 16 | if nowTime-p.curTime > 60 { 17 | p.count = 1 18 | p.curTime = nowTime 19 | curCount = p.count 20 | return 21 | } 22 | 23 | p.count++ 24 | curCount = p.count 25 | return 26 | } 27 | 28 | //检查用户访问的次数 29 | func (p *MinLimit) Check(nowTime int64) int { 30 | if nowTime-p.curTime > 60 { 31 | return 0 32 | } 33 | return p.count 34 | } 35 | -------------------------------------------------------------------------------- /ch3-basic/Pointer.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | 7 | 8 | str := "Golang is Good!" 9 | strPrt := &str 10 | 11 | fmt.Printf("str type is %T, value is %v, address is %p\n", str, str, &str) 12 | fmt.Printf("strPtr type is %T, and value is %v\n", strPrt, strPrt) 13 | 14 | newStr := *strPrt //获取指针对应变量的值 15 | fmt.Printf("newStr type is %T, value is %v, and address is %p\n", newStr, newStr, &newStr) 16 | 17 | *strPrt = "Java is Good too!" //通过指针对变量进行赋值 18 | fmt.Printf("newStr type is %T, value is %v, and address is %p\n", newStr, newStr, &newStr) 19 | fmt.Printf("str type is %T, value is %v, address is %p\n", str, str, &str) 20 | 21 | 22 | 23 | 24 | 25 | 26 | } -------------------------------------------------------------------------------- /ch13-seckill/README.md: -------------------------------------------------------------------------------- 1 | ### 简介 2 | 配套《Go语言高并发与微服务实战》使用,具体讲解见图书13章 3 | 4 | ### 依赖基础组件 5 | - redis 6 | - zookeeper 7 | - git仓库 8 | - consul 9 | 10 | #### 部署 11 | - 1 部署 consul 12 | 参考书籍第六章6.3小节内容,安装部署 consul 13 | - 2 部署 Redis,Zookeeper,MySQL。 14 | 参考对应组件的官方部署文档,安装完MySQL后,可以导入主目录下的seckill.sql 15 | - 3 新建git repo 16 | 可以参考 https://gitee.com/cloud-source/config-repo 创建对应项目的文件,修改Redis,MySQL,Zookeeper等组件的配置 17 | - 4 部署 Config-Service 18 | 参考书籍第八章8.3.1小节 在ch8-config文件夹下有 config-service项目,参考书上章节构建或者使用仓库 https://github.com/longjoy/config-server 进行构建。 19 | 在yml文件中配置对应的git项目地址和consul地址,构建并运行Java程序,将config-service注册到consul上 20 | - 5 修改bootstrap文件 21 | 修改各个项目中的bootstrap.yml文件discover相关的consul地址和config-service的相关配置 22 | 23 | -------------------------------------------------------------------------------- /ch3-basic/Compose.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | // 游泳特性 6 | type Swimming struct { 7 | } 8 | 9 | func (swim *Swimming) swim() { 10 | fmt.Println("swimming is my ability") 11 | } 12 | 13 | // 飞行特性 14 | type Flying struct { 15 | } 16 | 17 | func (fly *Flying) fly() { 18 | fmt.Println("flying is my ability") 19 | } 20 | 21 | // 野鸭,具备飞行和游泳特性 22 | type WildDuck struct { 23 | Swimming 24 | Flying 25 | } 26 | 27 | // 家鸭,具备游泳特性 28 | type DomesticDuck struct { 29 | Swimming 30 | } 31 | 32 | func main() { 33 | 34 | // 声明一只野鸭,可以飞,也可以游泳 35 | wild := WildDuck{} 36 | wild.fly() 37 | wild.swim() 38 | 39 | // 声明一只家鸭,只会游泳 40 | domestic := DomesticDuck{} 41 | domestic.swim() 42 | 43 | 44 | } -------------------------------------------------------------------------------- /ch4-feature/synch/mutex.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | "time" 7 | ) 8 | 9 | 10 | func main() { 11 | var lock sync.Mutex 12 | go func() { 13 | // 加锁 14 | lock.Lock() 15 | defer lock.Unlock() 16 | fmt.Println("func1 get lock at " + time.Now().String()) 17 | time.Sleep(time.Second) 18 | fmt.Println("func1 release lock " + time.Now().String()) 19 | }() 20 | 21 | time.Sleep(time.Second / 10) 22 | 23 | go func() { 24 | lock.Lock() 25 | defer lock.Unlock() 26 | fmt.Println("func2 get lock " + time.Now().String()) 27 | time.Sleep(time.Second) 28 | fmt.Println("func2 release lock " + time.Now().String()) 29 | }() 30 | 31 | // 等待 所有 goroutine 执行完毕 32 | time.Sleep(time.Second * 4) 33 | } 34 | -------------------------------------------------------------------------------- /ch3-basic/Slice.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | 7 | 8 | source := [...]int{1,2,3} 9 | sli := source[0:1] 10 | 11 | fmt.Printf("sli value is %v\n", sli) 12 | fmt.Printf("sli len is %v\n", len(sli)) 13 | fmt.Printf("sli cap is %v\n", cap(sli)) 14 | 15 | sli[0] = 4 16 | fmt.Printf("sli value is %v\n", sli) 17 | fmt.Printf("source value is %v\n", source) 18 | 19 | 20 | sli = make([]int, 2, 4) 21 | fmt.Printf("sli value is %v\n", sli) 22 | fmt.Printf("sli len is %v\n", len(sli)) 23 | fmt.Printf("sli cap is %v\n", cap(sli)) 24 | 25 | ex := []int{1,2,3} 26 | fmt.Printf("ex value is %v\n", ex) 27 | fmt.Printf("ex len is %v\n", len(ex)) 28 | fmt.Printf("ex cap is %v\n", cap(ex)) 29 | 30 | 31 | } 32 | -------------------------------------------------------------------------------- /ch13-seckill/sk-core/setup/service.go: -------------------------------------------------------------------------------- 1 | package setup 2 | 3 | import ( 4 | "fmt" 5 | register "github.com/longjoy/micro-go-book/ch13-seckill/pkg/discover" 6 | "github.com/longjoy/micro-go-book/ch13-seckill/sk-core/service/srv_redis" 7 | "os" 8 | "os/signal" 9 | "syscall" 10 | ) 11 | 12 | func RunService() { 13 | //启动处理线程 14 | srv_redis.RunProcess() 15 | errChan := make(chan error) 16 | //http server 17 | go func() { 18 | //启动前执行注册 19 | register.Register() 20 | }() 21 | 22 | go func() { 23 | c := make(chan os.Signal, 1) 24 | signal.Notify(c, syscall.SIGINT, syscall.SIGTERM) 25 | errChan <- fmt.Errorf("%s", <-c) 26 | }() 27 | 28 | error := <-errChan 29 | //服务退出取消注册 30 | register.Deregister() 31 | fmt.Println(error) 32 | 33 | } 34 | -------------------------------------------------------------------------------- /ch5-web/helloweb.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/http" 7 | "strings" 8 | ) 9 | 10 | func sayHello(w http.ResponseWriter, r *http.Request) { 11 | _ = r.ParseForm() //解析参数,默认是不会解析的 12 | fmt.Println(r.Form) //这些信息是输出到服务器端的打印信息 13 | fmt.Println("Path: ", r.URL.Path) 14 | fmt.Println("Host: ", r.Host) 15 | for k, v := range r.Form { 16 | fmt.Println("key:", k) 17 | fmt.Println("val:", strings.Join(v, "")) 18 | } 19 | _, _ = fmt.Fprintf(w, "Hello Web, %s!", r.Form.Get("name")) //写入到 w 的是输出到客户端的内容 20 | } 21 | 22 | func main() { 23 | http.HandleFunc("/", sayHello) //设置访问的路由 24 | err := http.ListenAndServe(":8080", nil) //设置监听的端口 25 | if err != nil { 26 | log.Fatal("ListenAndServe: ", err) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /ch5-web/writeresponse.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "log" 6 | "net/http" 7 | ) 8 | 9 | type User struct { 10 | Name string 11 | Habits []string 12 | } 13 | 14 | func write(w http.ResponseWriter, r *http.Request) { 15 | w.Header().Set("Content-Type", "application/json") 16 | w.Header().Set("X-Custom-Header", "custom") 17 | w.WriteHeader(201) 18 | user := &User{ 19 | Name: "aoho", 20 | Habits: []string{"balls", "running", "hiking"}, 21 | } 22 | json, _ := json.Marshal(user) 23 | w.Write(json) 24 | } 25 | 26 | func main() { 27 | http.HandleFunc("/write", write) //设置访问的路由 28 | err := http.ListenAndServe(":8080", nil) //设置监听的端口 29 | if err != nil { 30 | log.Fatal("ListenAndServe: ", err) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /ch3-basic/StructImplementor.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | // Cat接口 6 | type Cat interface { 7 | // 抓老鼠 8 | CatchMouse() 9 | } 10 | 11 | // Dog接口 12 | type Dog interface { 13 | // 吠叫 14 | Bark() 15 | } 16 | 17 | type CatDog struct { 18 | Name string 19 | } 20 | 21 | // 实现Cat接口 22 | func (catDog *CatDog) CatchMouse() { 23 | fmt.Printf("%v caught the mouse and ate it!\n", catDog.Name) 24 | } 25 | 26 | // Dog接口 27 | func (catDog *CatDog) Bark() { 28 | fmt.Printf("%v barked loudly!\n", catDog.Name) 29 | } 30 | 31 | func main() { 32 | catDog := &CatDog{ 33 | "Lucy", 34 | } 35 | 36 | // 声明一个Cat接口,并将catDog指针类型赋值给cat 37 | var cat Cat 38 | cat = catDog 39 | cat.CatchMouse() 40 | 41 | // 声明一个Dog接口,并将catDog指针类型赋值给dog 42 | var dog Dog 43 | dog = catDog 44 | dog.Bark() 45 | } -------------------------------------------------------------------------------- /ch12-trace/zipkin-kit/docker/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | 3 | services: 4 | # prometheus: 5 | # image: prom/prometheus 6 | # ports: 7 | # - 9090:9090 8 | # volumes: 9 | # - ./prometheus.yml:/etc/prometheus/prometheus.yml 10 | # grafana: 11 | # image: grafana/grafana 12 | # ports: 13 | # - 3000:3000 14 | # environment: 15 | # - GF_SECURITY_ADMIN_PASSWORD=password 16 | # volumes: 17 | # - $PWD/extra/grafana_db:/var/lib/grafana grafana/grafana 18 | 19 | consul: 20 | image: progrium/consul:latest 21 | ports: 22 | - 8400:8400 23 | - 8500:8500 24 | - 8600:53/udp 25 | hostname: consulserver 26 | command: -server -bootstrap -ui-dir /ui 27 | 28 | zipkin: 29 | image: openzipkin/zipkin 30 | ports: 31 | - 9411:9411 -------------------------------------------------------------------------------- /ch13-seckill/pb/oauth.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package pb; 4 | 5 | 6 | service OAuthService{ 7 | // token 校验 8 | rpc CheckToken(CheckTokenRequest) returns (CheckTokenResponse); 9 | } 10 | 11 | message CheckTokenRequest { 12 | string token = 1; 13 | } 14 | 15 | 16 | message ClientDetails { 17 | string clientId = 1; 18 | int32 accessTokenValiditySeconds = 2; 19 | int32 refreshTokenValiditySeconds = 3; 20 | repeated string authorizedGrantTypes = 4; 21 | } 22 | 23 | message UserDetails { 24 | int64 userId = 1; 25 | string username = 2; 26 | repeated string authorities = 3; 27 | } 28 | 29 | 30 | message CheckTokenResponse{ 31 | UserDetails userDetails = 1; 32 | ClientDetails clientDetails = 2; 33 | bool isValidToken = 3; 34 | string err = 4; 35 | } -------------------------------------------------------------------------------- /ch13-seckill/sk-admin/etcd_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "github.com/coreos/etcd/clientv3" 6 | conf "github.com/longjoy/micro-go-book/ch13-seckill/pkg/config" 7 | "log" 8 | "testing" 9 | "time" 10 | ) 11 | 12 | func TestMain(m *testing.M) { 13 | 14 | cli, err := clientv3.New(clientv3.Config{ 15 | Endpoints: []string{"39.98.179.73:2379"}, // conf.Etcd.Host 16 | DialTimeout: 5 * time.Second, 17 | }) 18 | if err != nil { 19 | log.Printf("Connect etcd failed. Error : %v", err) 20 | } 21 | conf.Etcd.EtcdSecProductKey = "product" 22 | conf.Etcd.EtcdConn = cli 23 | 24 | ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) 25 | defer cancel() 26 | rsp, err := conf.Etcd.EtcdConn.Get(ctx, "product") 27 | log.Printf("get from etcd %v", rsp) 28 | } 29 | -------------------------------------------------------------------------------- /common/discover/discover_client.go: -------------------------------------------------------------------------------- 1 | package discover 2 | 3 | import ( 4 | "log" 5 | ) 6 | 7 | type DiscoveryClient interface { 8 | 9 | /** 10 | * 服务注册接口 11 | * @param serviceName 服务名 12 | * @param instanceId 服务实例Id 13 | * @param instancePort 服务实例端口 14 | * @param healthCheckUrl 健康检查地址 15 | * @param instanceHost 服务实例地址 16 | * @param meta 服务实例元数据 17 | */ 18 | Register(serviceName, instanceId, healthCheckUrl string, instanceHost string, instancePort int, meta map[string]string, logger *log.Logger) bool 19 | 20 | /** 21 | * 服务注销接口 22 | * @param instanceId 服务实例Id 23 | */ 24 | DeRegister(instanceId string, logger *log.Logger) bool 25 | 26 | /** 27 | * 发现服务实例接口 28 | * @param serviceName 服务名 29 | */ 30 | DiscoverServices(serviceName string, logger *log.Logger) []interface{} 31 | } 32 | 33 | -------------------------------------------------------------------------------- /ch6-discovery/discover/discover_client.go: -------------------------------------------------------------------------------- 1 | package discover 2 | 3 | import ( 4 | "log" 5 | ) 6 | 7 | type DiscoveryClient interface { 8 | 9 | /** 10 | * 服务注册接口 11 | * @param serviceName 服务名 12 | * @param instanceId 服务实例Id 13 | * @param instancePort 服务实例端口 14 | * @param healthCheckUrl 健康检查地址 15 | * @param instanceHost 服务实例地址 16 | * @param meta 服务实例元数据 17 | */ 18 | Register(serviceName, instanceId, healthCheckUrl string, instanceHost string, instancePort int, meta map[string]string, logger *log.Logger) bool 19 | 20 | /** 21 | * 服务注销接口 22 | * @param instanceId 服务实例Id 23 | */ 24 | DeRegister(instanceId string, logger *log.Logger) bool 25 | 26 | /** 27 | * 发现服务实例接口 28 | * @param serviceName 服务名 29 | */ 30 | DiscoverServices(serviceName string, logger *log.Logger) []interface{} 31 | } 32 | 33 | -------------------------------------------------------------------------------- /ch13-seckill/oauth-service/oauth-script.sql: -------------------------------------------------------------------------------- 1 | create database oauth; 2 | 3 | drop table if exists `client_details`; 4 | CREATE TABLE `client_details` 5 | ( 6 | `client_id` VARCHAR(128) NOT NULL, 7 | `client_secret` VARCHAR(128) NOT NULL, 8 | `access_token_validity_seconds` INT(10) NOT NULL, 9 | `refresh_token_validity_seconds` INT(10) NOT NULL, 10 | `registered_redirect_uri` VARCHAR(128) NOT NULL, 11 | `authorized_grant_types` VARCHAR(128) NOT NULL, 12 | 13 | PRIMARY KEY (`client_id`) 14 | ); 15 | 16 | insert into client_details (`client_id`, `client_secret`, `access_token_validity_seconds`, `refresh_token_validity_seconds`, `registered_redirect_uri`, `authorized_grant_types`) values ('clientId', 'clientSecret', 1800, 18000, 'http://127.0.0.1','["password","refresh_token"]'); -------------------------------------------------------------------------------- /ch4-feature/synch/rw_mutex.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | "sync" 7 | "time" 8 | ) 9 | 10 | 11 | var rwLock sync.RWMutex 12 | 13 | 14 | func main() { 15 | 16 | // 获取读锁 17 | for i := 0 ; i < 5 ;i ++{ 18 | go func(i int) { 19 | rwLock.RLock() 20 | defer rwLock.RUnlock() 21 | fmt.Println("read func " + strconv.Itoa(i) +" get rlock at " + time.Now().String()) 22 | time.Sleep(time.Second) 23 | }(i) 24 | } 25 | 26 | time.Sleep(time.Second / 10) 27 | // 获取写锁 28 | for i := 0 ; i < 5; i++{ 29 | go func(i int) { 30 | rwLock.Lock() 31 | defer rwLock.Unlock() 32 | fmt.Println("write func " + strconv.Itoa(i) +" get wlock at " + time.Now().String()) 33 | time.Sleep(time.Second) 34 | }(i) 35 | } 36 | 37 | // 保证所有的 goroutine 执行结束 38 | time.Sleep(time.Second * 10) 39 | } 40 | -------------------------------------------------------------------------------- /ch13-seckill/gateway/config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "github.com/go-kit/kit/log" 5 | conf "github.com/longjoy/micro-go-book/ch13-seckill/pkg/config" 6 | "github.com/spf13/viper" 7 | "os" 8 | ) 9 | 10 | const ( 11 | kConfigType = "CONFIG_TYPE" 12 | ) 13 | 14 | var Logger log.Logger 15 | 16 | func init() { 17 | Logger = log.NewLogfmtLogger(os.Stderr) 18 | Logger = log.With(Logger, "ts", log.DefaultTimestampUTC) 19 | Logger = log.With(Logger, "caller", log.DefaultCaller) 20 | viper.AutomaticEnv() 21 | initDefault() 22 | 23 | if err := conf.LoadRemoteConfig(); err != nil { 24 | Logger.Log("Fail to load remote config", err) 25 | } 26 | if err := conf.Sub("auth", &AuthPermitConfig); err != nil { 27 | Logger.Log("Fail to parse config", err) 28 | } 29 | } 30 | func initDefault() { 31 | viper.SetDefault(kConfigType, "yaml") 32 | } 33 | -------------------------------------------------------------------------------- /ch11-security/service/common_service.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | 4 | 5 | type Service interface { 6 | 7 | SimpleData(username string) string 8 | 9 | AdminData(username string) string 10 | 11 | // HealthCheck check service health status 12 | HealthCheck() bool 13 | } 14 | 15 | type CommonService struct { 16 | 17 | } 18 | 19 | func (s *CommonService) SimpleData(username string) string { 20 | return "hello " + username + " ,simple data, with simple authority" 21 | } 22 | 23 | func (s *CommonService) AdminData(username string) string { 24 | return "hello " + username + " ,admin data, with admin authority" 25 | 26 | } 27 | 28 | // HealthCheck implement Service method 29 | // 用于检查服务的健康状态,这里仅仅返回true 30 | func (s *CommonService) HealthCheck() bool { 31 | return true 32 | } 33 | 34 | func NewCommonService() *CommonService { 35 | return &CommonService{} 36 | } 37 | 38 | -------------------------------------------------------------------------------- /ch12-trace/zipkin-kit/client/string.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | grpctransport "github.com/go-kit/kit/transport/grpc" 5 | kitgrpc "github.com/go-kit/kit/transport/grpc" 6 | "github.com/longjoy/micro-go-book/ch12-trace/zipkin-kit/pb" 7 | endpts "github.com/longjoy/micro-go-book/ch12-trace/zipkin-kit/string-service/endpoint" 8 | "github.com/longjoy/micro-go-book/ch12-trace/zipkin-kit/string-service/service" 9 | "google.golang.org/grpc" 10 | ) 11 | 12 | func StringDiff(conn *grpc.ClientConn, clientTracer kitgrpc.ClientOption) service.Service { 13 | 14 | var ep = grpctransport.NewClient(conn, 15 | "pb.StringService", 16 | "Diff", 17 | EncodeGRPCStringRequest, 18 | DecodeGRPCStringResponse, 19 | pb.StringResponse{}, 20 | clientTracer, 21 | ).Endpoint() 22 | 23 | StringEp := endpts.StringEndpoints{ 24 | StringEndpoint: ep, 25 | } 26 | return StringEp 27 | } 28 | -------------------------------------------------------------------------------- /ch13-seckill/sk-core/service/srv_product/product_count.go: -------------------------------------------------------------------------------- 1 | package srv_product 2 | 3 | import ( 4 | "sync" 5 | ) 6 | 7 | //商品数量管理 8 | type ProductCountMgr struct { 9 | productCount map[int]int 10 | lock sync.RWMutex 11 | } 12 | 13 | func NewProductCountMgr() *ProductCountMgr { 14 | productMgr := &ProductCountMgr{ 15 | productCount: make(map[int]int, 128), 16 | } 17 | return productMgr 18 | } 19 | 20 | //商品数量 21 | func (p *ProductCountMgr) Count(productId int) (count int) { 22 | p.lock.RLock() 23 | defer p.lock.RUnlock() 24 | 25 | count = p.productCount[productId] 26 | return 27 | } 28 | 29 | //添加商品 30 | func (p *ProductCountMgr) Add(productId, count int) { 31 | p.lock.Lock() 32 | defer p.lock.Unlock() 33 | 34 | cur, ok := p.productCount[productId] 35 | if !ok { 36 | cur = count 37 | } else { 38 | cur += count 39 | } 40 | p.productCount[productId] = cur 41 | } 42 | -------------------------------------------------------------------------------- /ch7-rpc/basic/client.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/longjoy/micro-go-book/ch7-rpc/basic/string-service" 6 | "log" 7 | "net/rpc" 8 | ) 9 | 10 | func main() { 11 | client, err := rpc.DialHTTP("tcp", "127.0.0.1:1234") 12 | if err != nil { 13 | log.Fatal("dialing:", err) 14 | } 15 | 16 | stringReq := &service.StringRequest{"A", "B"} 17 | // Synchronous call 18 | var reply string 19 | err = client.Call("StringService.Concat", stringReq, &reply) 20 | if err != nil { 21 | log.Fatal("StringService error:", err) 22 | } 23 | fmt.Printf("StringService Concat : %s concat %s = %s\n", stringReq.A, stringReq.B, reply) 24 | 25 | stringReq = &service.StringRequest{"ACD", "BDF"} 26 | call := client.Go("StringService.Diff", stringReq, &reply, nil) 27 | _ = <-call.Done 28 | fmt.Printf("StringService Diff : %s diff %s = %s\n", stringReq.A, stringReq.B, reply) 29 | 30 | } 31 | -------------------------------------------------------------------------------- /ch13-seckill/user-service/transport/grpc.go: -------------------------------------------------------------------------------- 1 | package transport 2 | 3 | import ( 4 | "context" 5 | "github.com/go-kit/kit/transport/grpc" 6 | "github.com/longjoy/micro-go-book/ch13-seckill/pb" 7 | endpts "github.com/longjoy/micro-go-book/ch13-seckill/user-service/endpoint" 8 | ) 9 | 10 | type grpcServer struct { 11 | check grpc.Handler 12 | } 13 | 14 | func (s *grpcServer) Check(ctx context.Context, r *pb.UserRequest) (*pb.UserResponse, error) { 15 | _, resp, err := s.check.ServeGRPC(ctx, r) 16 | if err != nil { 17 | return nil, err 18 | } 19 | return resp.(*pb.UserResponse), nil 20 | } 21 | 22 | func NewGRPCServer(ctx context.Context, endpoints endpts.UserEndpoints, serverTracer grpc.ServerOption) pb.UserServiceServer { 23 | return &grpcServer{ 24 | check: grpc.NewServer( 25 | endpoints.UserEndpoint, 26 | DecodeGRPCUserRequest, 27 | EncodeGRPCUserResponse, 28 | serverTracer, 29 | ), 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /ch3-basic/TypeAlias.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type aliasInt = int // 定义一个类型别名 6 | type myInt int // 定义一个新的类型 7 | 8 | func main() { 9 | 10 | var alias aliasInt 11 | fmt.Printf("alias value is %v, type is %T\n", alias, alias) 12 | 13 | var myint myInt 14 | fmt.Printf("myint value is %v, type is %T\n", myint, myint) 15 | 16 | name := "小红" 17 | switch name { 18 | case "小明": 19 | fmt.Println("扫地") 20 | case "小红": 21 | fmt.Println("擦黑板") 22 | case "小刚": 23 | fmt.Println("倒垃圾") 24 | default: 25 | fmt.Println("没人干活") 26 | } 27 | 28 | score := 90 29 | switch { 30 | case score < 100 && score >= 90: 31 | fmt.Println("优秀") 32 | case score < 90 && score >= 80: 33 | fmt.Println("良好") 34 | case score < 80 && score >= 60: 35 | fmt.Println("及格") 36 | case score < 60 : 37 | fmt.Println("不及格") 38 | default: 39 | fmt.Println("分数错误") 40 | 41 | } 42 | 43 | 44 | 45 | 46 | 47 | } 48 | 49 | -------------------------------------------------------------------------------- /ch4-feature/synch/sync_map.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | "sync" 7 | ) 8 | var syncMap sync.Map 9 | var waitGroup sync.WaitGroup 10 | 11 | func main() { 12 | 13 | routineSize := 5 14 | // 让主线程等待数据添加完毕 15 | waitGroup.Add(routineSize) 16 | // 并发添加数据 17 | for i := 0 ; i < routineSize; i++{ 18 | go addNumber(i * 10) 19 | } 20 | 21 | // 开始等待 22 | waitGroup.Wait() 23 | var size int 24 | // 统计数量 25 | syncMap.Range(func(key, value interface{}) bool { 26 | size++ 27 | //fmt.Println("key-value pair is", key, value, " ") 28 | return true 29 | }) 30 | fmt.Println("syncMap current size is " + strconv.Itoa(size)) 31 | // 获取键为 0 的值 32 | value, ok := syncMap.Load(0); if ok{ 33 | fmt.Println("key 0 has value", value, " ") 34 | } 35 | 36 | } 37 | 38 | func addNumber(begin int) { 39 | // 往 syncMap 中放入数据 40 | for i := begin ; i < begin + 3 ; i++{ 41 | syncMap.Store(i, i) 42 | } 43 | // 通知数据已添加完毕 44 | waitGroup.Done() 45 | } 46 | -------------------------------------------------------------------------------- /ch13-seckill/sk-app/service/srv_err/error.go: -------------------------------------------------------------------------------- 1 | package srv_err 2 | 3 | import ( 4 | "errors" 5 | ) 6 | 7 | const ( 8 | ErrInvalidRequest = 1101 9 | ErrNotFoundProductId = 1102 10 | ErrUserCheckAuthFailed = 1103 11 | ErrUserServiceBusy = 1104 12 | ErrActiveNotStart = 1105 13 | ErrActiveAlreadyEnd = 1106 14 | ErrActiveSaleOut = 1107 15 | ErrProcessTimeout = 1108 16 | ErrClientClosed = 1109 17 | ) 18 | 19 | const ( 20 | ErrServiceBusy = 1001 21 | ErrSecKillSucc = 1002 22 | ErrNotFoundProduct = 1003 23 | ErrSoldout = 1004 24 | ErrRetry = 1005 25 | ErrAlreadyBuy = 1006 26 | ) 27 | 28 | var errMsg = map[int]string{ 29 | ErrServiceBusy: "服务器错误", 30 | ErrSecKillSucc: "抢购成功", 31 | ErrNotFoundProduct: "没有该商品", 32 | ErrSoldout: "商品售罄", 33 | ErrRetry: "请重试", 34 | ErrAlreadyBuy: "已经抢购", 35 | } 36 | 37 | func GetErrMsg(code int) error { 38 | return errors.New(errMsg[code]) 39 | } 40 | -------------------------------------------------------------------------------- /ch13-seckill/oauth-service/transport/grpc.go: -------------------------------------------------------------------------------- 1 | package transport 2 | 3 | import ( 4 | "context" 5 | "github.com/go-kit/kit/transport/grpc" 6 | endpts "github.com/longjoy/micro-go-book/ch13-seckill/oauth-service/endpoint" 7 | "github.com/longjoy/micro-go-book/ch13-seckill/pb" 8 | ) 9 | 10 | type grpcServer struct { 11 | checkTokenServer grpc.Handler 12 | } 13 | 14 | func (s *grpcServer) CheckToken(ctx context.Context, r *pb.CheckTokenRequest) (*pb.CheckTokenResponse, error) { 15 | _, resp, err := s.checkTokenServer.ServeGRPC(ctx, r) 16 | if err != nil { 17 | return nil, err 18 | } 19 | return resp.(*pb.CheckTokenResponse), nil 20 | } 21 | 22 | func NewGRPCServer(ctx context.Context, endpoints endpts.OAuth2Endpoints, serverTracer grpc.ServerOption) pb.OAuthServiceServer { 23 | return &grpcServer{ 24 | checkTokenServer: grpc.NewServer( 25 | endpoints.GRPCCheckTokenEndpoint, 26 | DecodeGRPCCheckTokenRequest, 27 | EncodeGRPCCheckTokenResponse, 28 | serverTracer, 29 | ), 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /ch13-seckill/sk-admin/setup/etcd_test.go: -------------------------------------------------------------------------------- 1 | package setup 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "go.etcd.io/etcd/clientv3" 7 | "log" 8 | "testing" 9 | "time" 10 | ) 11 | 12 | func TestInitEtcd(t *testing.T) { 13 | cli, err := clientv3.New(clientv3.Config{ 14 | Endpoints: []string{"39.98.179.73:2379"}, 15 | DialTimeout: 5 * time.Second, 16 | }) 17 | if err != nil { 18 | log.Printf("Connect etcd failed. Error : %v", err) 19 | } 20 | 21 | ctx, cancel := context.WithTimeout(context.Background(), time.Second) 22 | defer cancel() 23 | _, err1 := cli.Put(ctx, "sec_kill_product", "sample") 24 | if err1 != nil { 25 | log.Printf("Get falied. Error : %v", err) 26 | } 27 | 28 | ctx, cancel = context.WithTimeout(context.Background(), time.Second) 29 | defer cancel() 30 | nresp, err := cli.Get(ctx, "sec_kill_product") 31 | 32 | if err != nil { 33 | log.Printf("Get falied. Error : %v", err) 34 | } 35 | 36 | for _, ev := range nresp.Kvs { 37 | fmt.Printf("%s : %s\n", ev.Key, ev.Value) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /ch13-seckill/sk-app/model/model.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type SecRequest struct { 4 | ProductId int `json:"product_id"` //商品ID 5 | Source string `json:"source"` 6 | AuthCode string `json:"auth_code"` 7 | SecTime int64 `json:"sec_time"` 8 | Nance string `json:"nance"` 9 | UserId int `json:"user_id"` 10 | UserAuthSign string `json:"user_auth_sign"` //用户授权签名 11 | AccessTime int64 `json:"access_time"` 12 | ClientAddr string `json:"client_addr"` 13 | ClientRefence string `json:"client_refence"` 14 | CloseNotify <-chan bool `json:"-"` 15 | ResultChan chan *SecResult `json:"-"` 16 | } 17 | 18 | type SecResult struct { 19 | ProductId int `json:"product_id"` //商品ID 20 | UserId int `json:"user_id"` //用户ID 21 | Token string `json:"token"` //Token 22 | TokenTime int64 `json:"token_time"` //Token生成时间 23 | Code int `json:"code"` //状态码 24 | } 25 | -------------------------------------------------------------------------------- /ch12-trace/zipkin-kit/string-service/grpc.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "github.com/go-kit/kit/transport/grpc" 6 | "github.com/longjoy/micro-go-book/ch12-trace/zipkin-kit/client" 7 | "github.com/longjoy/micro-go-book/ch12-trace/zipkin-kit/pb" 8 | "github.com/longjoy/micro-go-book/ch12-trace/zipkin-kit/string-service/endpoint" 9 | ) 10 | 11 | type grpcServer struct { 12 | diff grpc.Handler 13 | } 14 | 15 | func (s *grpcServer) Diff(ctx context.Context, r *pb.StringRequest) (*pb.StringResponse, error) { 16 | _, resp, err := s.diff.ServeGRPC(ctx, r) 17 | if err != nil { 18 | return nil, err 19 | } 20 | return resp.(*pb.StringResponse), nil 21 | 22 | } 23 | 24 | func NewGRPCServer(ctx context.Context, endpoints endpoint.StringEndpoints, serverTracer grpc.ServerOption) pb.StringServiceServer { 25 | return &grpcServer{ 26 | diff: grpc.NewServer( 27 | endpoints.StringEndpoint, 28 | client.DecodeGRPCStringRequest, 29 | client.EncodeGRPCStringResponse, 30 | serverTracer, 31 | ), 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /ch13-seckill/pb/activity.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package pb; 4 | 5 | service ActivityService{ 6 | rpc secKill(SecRequest) returns (SecResponse){} 7 | } 8 | 9 | 10 | message Activity { 11 | int64 ActivityId = 1; // 活动Id 12 | string ActivityName = 2; // 活动名称 13 | int64 ProductId = 3; // 商品Id 14 | int64 StartTime = 4; // 开始时间 15 | int64 EndTime = 5; // 结束时间 16 | int64 Total = 6; // 商品总数 17 | int64 Status = 7; // 状态 18 | string StartTimeStr = 8; // 19 | string EndTimeStr = 9; 20 | string StatusStr = 10; 21 | int64 Speed = 11; 22 | int64 BuyLimit = 12; 23 | double BuyRate = 13; 24 | } 25 | 26 | message SecProductInfoConf { 27 | int64 ProductId = 1; // 商品id 28 | int64 StartTime = 2; // 开始时间 29 | int64 EndTime = 3; // 结束时间 30 | int64 Status = 4; // 状态 31 | int64 Total = 5; // 商品总数 32 | int64 Left = 6; // 剩余商品数量 33 | int64 OnePersonBuyLimit = 7; // 一个人购买限制 34 | double BuyRate = 8; // 买中几率 35 | int64 SoldMaxLimit = 9; // 每秒最多能卖多少个 36 | } -------------------------------------------------------------------------------- /ch13-seckill/sk-admin/service/product.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "github.com/gohouse/gorose/v2" 5 | "github.com/longjoy/micro-go-book/ch13-seckill/sk-admin/model" 6 | "log" 7 | ) 8 | 9 | type ProductService interface { 10 | CreateProduct(product *model.Product) error 11 | GetProductList() ([]gorose.Data, error) 12 | } 13 | 14 | type ProductServiceMiddleware func(ProductService) ProductService 15 | 16 | type ProductServiceImpl struct { 17 | } 18 | 19 | func (p ProductServiceImpl) CreateProduct(product *model.Product) error { 20 | productEntity := model.NewProductModel() 21 | err := productEntity.CreateProduct(product) 22 | if err != nil { 23 | log.Printf("ProductEntity.CreateProduct, err : %v", err) 24 | return err 25 | } 26 | return nil 27 | } 28 | 29 | func (p ProductServiceImpl) GetProductList() ([]gorose.Data, error) { 30 | productEntity := model.NewProductModel() 31 | productList, err := productEntity.GetProductList() 32 | if err != nil { 33 | log.Printf("ProductEntity.CreateProduct, err : %v", err) 34 | return nil, err 35 | } 36 | return productList, nil 37 | } 38 | -------------------------------------------------------------------------------- /ch13-seckill/pkg/ratelimiter/instruments.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "github.com/go-kit/kit/endpoint" 7 | "golang.org/x/time/rate" 8 | "time" 9 | ) 10 | 11 | var ErrLimitExceed = errors.New("Rate limit exceed!") 12 | 13 | // NewTokenBucketLimitterWithBuildIn 使用x/time/rate创建限流中间件 14 | func NewTokenBucketLimitterWithBuildIn(bkt *rate.Limiter) endpoint.Middleware { 15 | return func(next endpoint.Endpoint) endpoint.Endpoint { 16 | return func(ctx context.Context, request interface{}) (response interface{}, err error) { 17 | if !bkt.Allow() { 18 | return nil, ErrLimitExceed 19 | } 20 | return next(ctx, request) 21 | } 22 | } 23 | } 24 | 25 | func DynamicLimitter(interval int, burst int) endpoint.Middleware { 26 | bucket := rate.NewLimiter(rate.Every(time.Second*time.Duration(interval)), burst) 27 | return func(next endpoint.Endpoint) endpoint.Endpoint { 28 | return func(ctx context.Context, request interface{}) (response interface{}, err error) { 29 | if !bucket.Allow() { 30 | return nil, ErrLimitExceed 31 | } 32 | return next(ctx, request) 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 kidme 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /ch13-seckill/user-service/service/service.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "context" 5 | "github.com/longjoy/micro-go-book/ch13-seckill/user-service/model" 6 | "log" 7 | ) 8 | 9 | // Service Define a service interface 10 | type Service interface { 11 | Check(ctx context.Context, username, password string) (int64, error) 12 | 13 | // HealthCheck check service health status 14 | HealthCheck() bool 15 | } 16 | 17 | //UserService implement Service interface 18 | type UserService struct { 19 | } 20 | 21 | // Add implement check method 22 | func (s UserService) Check(ctx context.Context, username string, password string) (int64, error) { 23 | userEntity := model.NewUserModel() 24 | res, err := userEntity.CheckUser(username, password) 25 | if err != nil { 26 | log.Printf("UserEntity.CreateUser, err : %v", err) 27 | return 0, err 28 | } 29 | return res.UserId, nil 30 | } 31 | 32 | // HealthCheck implement Service method 33 | // 用于检查服务的健康状态,这里仅仅返回true 34 | func (s UserService) HealthCheck() bool { 35 | return true 36 | } 37 | 38 | // ServiceMiddleware define service middleware 39 | type ServiceMiddleware func(Service) Service 40 | -------------------------------------------------------------------------------- /ch13-seckill/oauth-service/plugins/instrument.go: -------------------------------------------------------------------------------- 1 | package plugins 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "github.com/go-kit/kit/endpoint" 7 | "github.com/juju/ratelimit" 8 | "golang.org/x/time/rate" 9 | ) 10 | 11 | var ErrLimitExceed = errors.New("Rate limit exceed!") 12 | 13 | // NewTokenBucketLimitterWithJuju 使用juju/ratelimit创建限流中间件 14 | func NewTokenBucketLimitterWithJuju(bkt *ratelimit.Bucket) endpoint.Middleware { 15 | return func(next endpoint.Endpoint) endpoint.Endpoint { 16 | return func(ctx context.Context, request interface{}) (response interface{}, err error) { 17 | if bkt.TakeAvailable(1) == 0 { 18 | return nil, ErrLimitExceed 19 | } 20 | return next(ctx, request) 21 | } 22 | } 23 | } 24 | 25 | // NewTokenBucketLimitterWithBuildIn 使用x/time/rate创建限流中间件 26 | func NewTokenBucketLimitterWithBuildIn(bkt *rate.Limiter) endpoint.Middleware { 27 | return func(next endpoint.Endpoint) endpoint.Endpoint { 28 | return func(ctx context.Context, request interface{}) (response interface{}, err error) { 29 | if !bkt.Allow() { 30 | return nil, ErrLimitExceed 31 | } 32 | return next(ctx, request) 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /ch13-seckill/pkg/discover/discovery_client.go: -------------------------------------------------------------------------------- 1 | package discover 2 | 3 | import ( 4 | "github.com/go-kit/kit/sd/consul" 5 | "github.com/hashicorp/consul/api" 6 | "github.com/longjoy/micro-go-book/ch13-seckill/pkg/common" 7 | "log" 8 | "sync" 9 | ) 10 | 11 | type DiscoveryClientInstance struct { 12 | Host string // Host 13 | Port int // Port 14 | // 连接 consul 的配置 15 | config *api.Config 16 | client consul.Client 17 | mutex sync.Mutex 18 | // 服务实例缓存字段 19 | instancesMap sync.Map 20 | } 21 | 22 | type DiscoveryClient interface { 23 | /** 24 | * 服务注册接口 25 | * @param serviceName 服务名 26 | * @param instanceId 服务实例Id 27 | * @param instancePort 服务实例端口 28 | * @param healthCheckUrl 健康检查地址 29 | * @param weight 权重 30 | * @param meta 服务实例元数据 31 | */ 32 | Register(instanceId, svcHost, healthCheckUrl, svcPort string, svcName string, weight int, meta map[string]string, tags []string, logger *log.Logger) bool 33 | 34 | /** 35 | * 服务注销接口 36 | * @param instanceId 服务实例Id 37 | */ 38 | DeRegister(instanceId string, logger *log.Logger) bool 39 | 40 | /** 41 | * 发现服务实例接口 42 | * @param serviceName 服务名 43 | */ 44 | DiscoverServices(serviceName string, logger *log.Logger) []*common.ServiceInstance 45 | } 46 | -------------------------------------------------------------------------------- /ch13-seckill/oauth-service/service/client_service.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "github.com/longjoy/micro-go-book/ch13-seckill/oauth-service/model" 7 | ) 8 | 9 | 10 | var ( 11 | 12 | ErrClientMessage = errors.New("invalid client") 13 | 14 | ) 15 | 16 | // Service Define a service interface 17 | type ClientDetailsService interface { 18 | 19 | GetClientDetailByClientId(ctx context.Context, clientId string, clientSecret string)(*model.ClientDetails, error) 20 | 21 | } 22 | 23 | 24 | type MysqlClientDetailsService struct { 25 | } 26 | 27 | func NewMysqlClientDetailsService() ClientDetailsService { 28 | return &MysqlClientDetailsService{} 29 | } 30 | 31 | func (service *MysqlClientDetailsService)GetClientDetailByClientId(ctx context.Context, clientId string, clientSecret string)(*model.ClientDetails, error) { 32 | 33 | clientDetailsModel := model.NewClientDetailsModel(); 34 | if clientDetails, err := clientDetailsModel.GetClientDetailsByClientId(clientId); err == nil{ 35 | if clientSecret == clientDetails.ClientSecret { 36 | return clientDetails, nil 37 | }else { 38 | return nil, ErrClientMessage 39 | } 40 | }else { 41 | return nil, err; 42 | } 43 | 44 | 45 | } 46 | 47 | 48 | -------------------------------------------------------------------------------- /ch10-resiliency/hystrix-example.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/afex/hystrix-go/hystrix" 6 | "strconv" 7 | "time" 8 | ) 9 | 10 | func main() { 11 | 12 | hystrix.ConfigureCommand("test_command", hystrix.CommandConfig{ 13 | // 设置参数 14 | Timeout: hystrix.DefaultTimeout, 15 | }) 16 | 17 | err := hystrix.Do("test_command", func() error { 18 | // 远程调用&或者其他需要保护的方法 19 | return nil 20 | }, func(err error) error { 21 | // 失败回滚方法 22 | return nil 23 | }) 24 | 25 | if err != nil { 26 | fmt.Println(err) 27 | } 28 | 29 | resultChan := make(chan interface{}, 1) 30 | errChan := hystrix.Go("test_command", func() error { 31 | // 远程调用&或者其他需要保护的方法 32 | resultChan <- "success" 33 | return nil 34 | }, func(e error) error { 35 | // 失败回滚方法 36 | return nil 37 | }) 38 | 39 | select { 40 | case err := <-errChan: 41 | // 执行失败 42 | fmt.Println(err) 43 | case result := <-resultChan: 44 | // 执行成功 45 | fmt.Println(result) 46 | case <-time.After(2 * time.Second): // 超时设置 47 | fmt.Println("Time out") 48 | return 49 | } 50 | 51 | circuit, _, _ := hystrix.GetCircuit("test_command") 52 | fmt.Println("command test_command's circuit open is " + strconv.FormatBool(circuit.IsOpen())) 53 | 54 | } 55 | -------------------------------------------------------------------------------- /ch13-seckill/pkg/mysql/mysql.go: -------------------------------------------------------------------------------- 1 | package mysql 2 | 3 | import ( 4 | "fmt" 5 | _ "github.com/go-sql-driver/mysql" 6 | "github.com/gohouse/gorose/v2" 7 | ) 8 | 9 | var engin *gorose.Engin 10 | var err error 11 | 12 | func InitMysql(hostMysql, portMysql, userMysql, pwdMysql, dbMysql string) { 13 | fmt.Printf(userMysql) 14 | fmt.Printf(dbMysql) 15 | 16 | DbConfig := gorose.Config{ 17 | // Default database configuration 18 | Driver: "mysql", // Database driver(mysql,sqlite,postgres,oracle,mssql) 19 | Dsn: userMysql + ":" + pwdMysql + "@tcp(" + hostMysql + ":" + portMysql + ")/" + dbMysql + "?charset=utf8&parseTime=true", // 数据库链接 20 | Prefix: "", // Table prefix 21 | // (Connection pool) Max open connections, default value 0 means unlimit. 22 | SetMaxOpenConns: 300, 23 | // (Connection pool) Max idle connections, default value is 1. 24 | SetMaxIdleConns: 10, 25 | } 26 | 27 | engin, err = gorose.Open(&DbConfig) 28 | if err != nil { 29 | fmt.Println(err) 30 | return 31 | } 32 | } 33 | 34 | func DB() gorose.IOrm { 35 | return engin.NewOrm() 36 | } 37 | -------------------------------------------------------------------------------- /ch3-basic/Append.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | 7 | 8 | arr1 := [...]int{1,2,3,4} 9 | arr2 := [...]int{1,2,3,4} 10 | 11 | sli1 := arr1[0:2] // 长度为2,容量为4 12 | sli2 := arr2[2:4] // 长度为2,容量为2 13 | 14 | fmt.Printf("sli1 pointer is %p, len is %v, cap is %v, value is %v\n", &sli1, len(sli1), cap(sli1), sli1) 15 | fmt.Printf("sli2 pointer is %p, len is %v, cap is %v, value is %v\n", &sli2, len(sli2), cap(sli2), sli2) 16 | 17 | newSli1 := append(sli1, 5) 18 | fmt.Printf("newSli1 pointer is %p, len is %v, cap is %v, value is %v\n", &newSli1, len(newSli1), cap(newSli1), newSli1) 19 | fmt.Printf("source arr1 become %v\n", arr1) 20 | 21 | newSli2 := append(sli2, 5) 22 | fmt.Printf("newSli2 pointer is %p, len is %v, cap is %v, value is %v\n", &newSli2, len(newSli2), cap(newSli2), newSli2) 23 | fmt.Printf("source arr2 become %v\n", arr2) 24 | 25 | arr3 := [...]int{1,2,3,4} 26 | sli3 := arr3[0:2:2] // 长度为2,容量为2 27 | 28 | fmt.Printf("sli3 pointer is %p, len is %v, cap is %v, value is %v\n", &sli3, len(sli3), cap(sli3), sli3) 29 | 30 | newSli3 := append(sli3,5) 31 | fmt.Printf("newSli3 pointer is %p, len is %v, cap is %v, value is %v\n", &newSli3, len(newSli3), cap(newSli3), newSli3) 32 | fmt.Printf("source arr3 become %v\n", arr3) 33 | 34 | 35 | } 36 | -------------------------------------------------------------------------------- /ch13-seckill/sk-admin/model/product.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "github.com/gohouse/gorose/v2" 5 | "github.com/longjoy/micro-go-book/ch13-seckill/pkg/mysql" 6 | "log" 7 | ) 8 | 9 | type Product struct { 10 | ProductId int `json:"product_id"` //商品Id 11 | ProductName string `json:"product_name"` //商品名称 12 | Total int `json:"total"` //商品数量 13 | Status int `json:"status"` //商品状态 14 | } 15 | 16 | type ProductModel struct { 17 | } 18 | 19 | func NewProductModel() *ProductModel { 20 | return &ProductModel{} 21 | } 22 | 23 | func (p *ProductModel) getTableName() string { 24 | return "product" 25 | } 26 | 27 | func (p *ProductModel) GetProductList() ([]gorose.Data, error) { 28 | conn := mysql.DB() 29 | list, err := conn.Table(p.getTableName()).Get() 30 | if err != nil { 31 | log.Printf("Error : %v", err) 32 | return nil, err 33 | } 34 | return list, nil 35 | } 36 | 37 | func (p *ProductModel) CreateProduct(product *Product) error { 38 | conn := mysql.DB() 39 | _, err := conn.Table(p.getTableName()).Data(map[string]interface{}{ 40 | "product_name": product.ProductName, 41 | "total": product.Total, 42 | "status": product.Status, 43 | }).Insert() 44 | if err != nil { 45 | log.Printf("Error : %v", err) 46 | return err 47 | } 48 | return nil 49 | } 50 | -------------------------------------------------------------------------------- /ch7-rpc/go-kit/server.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "flag" 6 | "github.com/go-kit/kit/log" 7 | service "github.com/longjoy/micro-go-book/ch7-rpc/go-kit/string-service" 8 | "github.com/longjoy/micro-go-book/ch7-rpc/pb" 9 | "google.golang.org/grpc" 10 | "net" 11 | "os" 12 | ) 13 | 14 | func main() { 15 | 16 | flag.Parse() 17 | 18 | ctx := context.Background() 19 | 20 | var logger log.Logger 21 | { 22 | logger = log.NewLogfmtLogger(os.Stderr) 23 | logger = log.With(logger, "ts", log.DefaultTimestampUTC) 24 | logger = log.With(logger, "caller", log.DefaultCaller) 25 | } 26 | 27 | var svc service.Service 28 | svc = service.StringService{} 29 | 30 | // add logging middleware 31 | svc = service.LoggingMiddleware(logger)(svc) 32 | 33 | endpoint := service.MakeStringEndpoint(svc) 34 | 35 | //创建健康检查的Endpoint 36 | healthEndpoint := service.MakeHealthCheckEndpoint(svc) 37 | 38 | //把算术运算Endpoint和健康检查Endpoint封装至StringEndpoints 39 | endpts := service.StringEndpoints{ 40 | StringEndpoint: endpoint, 41 | HealthCheckEndpoint: healthEndpoint, 42 | } 43 | 44 | handler := service.NewStringServer(ctx, endpts) 45 | 46 | ls, _ := net.Listen("tcp", "127.0.0.1:8080") 47 | gRPCServer := grpc.NewServer() 48 | pb.RegisterStringServiceServer(gRPCServer, handler) 49 | gRPCServer.Serve(ls) 50 | 51 | } 52 | -------------------------------------------------------------------------------- /ch13-seckill/pkg/client/user_test.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "github.com/longjoy/micro-go-book/ch13-seckill/pb" 7 | "github.com/opentracing/opentracing-go" 8 | zipkin "github.com/openzipkin-contrib/zipkin-go-opentracing" 9 | "log" 10 | "testing" 11 | ) 12 | 13 | func TestUserClientImpl_CheckUser(t *testing.T) { 14 | client, _ := NewUserClient("user", nil, genTracerAct(nil)) 15 | 16 | if response, err := client.CheckUser(context.Background(), nil, &pb.UserRequest{ 17 | Username: "xuan", 18 | Password: "xuan", 19 | }); err == nil { 20 | fmt.Println(response.Result) 21 | } else { 22 | fmt.Println(err.Error()) 23 | } 24 | } 25 | 26 | func genTracerAct(tracer opentracing.Tracer) opentracing.Tracer { 27 | if tracer != nil { 28 | return tracer 29 | } 30 | zipkinUrl := "http://114.67.98.210:9411/api/v2/spans" 31 | zipkinRecorder := "localhost:12344" 32 | collector, err := zipkin.NewHTTPCollector(zipkinUrl) 33 | if err != nil { 34 | log.Fatalf("zipkin.NewHTTPCollector err: %v", err) 35 | } 36 | 37 | recorder := zipkin.NewRecorder(collector, false, zipkinRecorder, "user-client") 38 | 39 | res, err := zipkin.NewTracer( 40 | recorder, zipkin.ClientServerSameSpan(true), 41 | ) 42 | if err != nil { 43 | log.Fatalf("zipkin.NewTracer err: %v", err) 44 | } 45 | return res 46 | 47 | } 48 | -------------------------------------------------------------------------------- /ch3-basic/Person.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | 6 | type Person struct { 7 | Name string // 姓名 8 | Birth string // 生日 9 | ID int64 // 身份证号 10 | } 11 | 12 | // 指针类型,修改个人信息 13 | func (person *Person) changeName(name string) { 14 | person.Name = name 15 | } 16 | 17 | // 非指针类型,打印个人信息 18 | func (person Person) printMess() { 19 | fmt.Printf("My name is %v, and my birthday is %v, and my id is %v\n", 20 | person.Name, person.Birth, person.ID) 21 | 22 | // 尝试修改个人信息,但是对原接收器并没有影响 23 | // person.ID = 3 24 | 25 | } 26 | 27 | func main() { 28 | p1 := Person{ 29 | Name:"王小二", 30 | Birth: "1990-12-23", 31 | ID:1, 32 | } 33 | 34 | p1.printMess() 35 | p1.changeName("王老二") 36 | p1.printMess() 37 | 38 | } 39 | 40 | 41 | //func main() { 42 | // // 声明实例化 43 | // var p1 Person 44 | // p1.Name = "王小二" 45 | // p1.Birth = "1990-12-11" 46 | // 47 | // 48 | // // new函数实例化 49 | // p2 := new(Person) 50 | // p2.Name = "王二小" 51 | // p2.Birth = "1990-12-22" 52 | // 53 | // 54 | // // 取址实例化 55 | // p3 := &Person{} 56 | // p3.Name = "王三小" 57 | // p3.Birth = "1990-12-23" 58 | // 59 | // // 初始化 60 | // p4 := Person{ 61 | // Name:"王小四", 62 | // Birth: "1990-12-23", 63 | // } 64 | // 65 | // // 初始化 66 | // p5 := &Person{ 67 | // "王五", 68 | // "1990-12-23", 69 | // 5, 70 | // } 71 | // 72 | // 73 | // 74 | // 75 | // 76 | //} 77 | -------------------------------------------------------------------------------- /ch13-seckill/pkg/bootstrap/bootstrap_config.go: -------------------------------------------------------------------------------- 1 | package bootstrap 2 | 3 | import ( 4 | "fmt" 5 | "github.com/spf13/viper" 6 | "log" 7 | ) 8 | 9 | func init() { 10 | viper.AutomaticEnv() 11 | initBootstrapConfig() 12 | //读取yaml文件 13 | //v := viper.New() 14 | 15 | if err := viper.ReadInConfig(); err != nil { 16 | fmt.Printf("err:%s\n", err) 17 | } 18 | if err := subParse("http", &HttpConfig); err != nil { 19 | log.Fatal("Fail to parse Http config", err) 20 | } 21 | if err := subParse("discover", &DiscoverConfig); err != nil { 22 | log.Fatal("Fail to parse Discover config", err) 23 | } 24 | if err := subParse("config", &ConfigServerConfig); err != nil { 25 | log.Fatal("Fail to parse config server", err) 26 | } 27 | 28 | if err := subParse("rpc", &RpcConfig); err != nil { 29 | log.Fatal("Fail to parse rpc server", err) 30 | } 31 | } 32 | func initBootstrapConfig() { 33 | //设置读取的配置文件 34 | viper.SetConfigName("bootstrap") 35 | //添加读取的配置文件路径 36 | viper.AddConfigPath("./") 37 | //windows环境下为%GOPATH,linux环境下为$GOPATH 38 | viper.AddConfigPath("$GOPATH/src/") 39 | //设置配置文件类型 40 | viper.SetConfigType("yaml") 41 | } 42 | 43 | func subParse(key string, value interface{}) error { 44 | log.Printf("配置文件的前缀为:%v", key) 45 | sub := viper.Sub(key) 46 | sub.AutomaticEnv() 47 | sub.SetEnvPrefix(key) 48 | return sub.Unmarshal(value) 49 | } 50 | -------------------------------------------------------------------------------- /ch13-seckill/user-service/plugins/logging.go: -------------------------------------------------------------------------------- 1 | package plugins 2 | 3 | import ( 4 | "context" 5 | "github.com/go-kit/kit/log" 6 | "github.com/longjoy/micro-go-book/ch13-seckill/user-service/service" 7 | "time" 8 | ) 9 | 10 | // loggingMiddleware Make a new type 11 | // that contains Service interface and logger instance 12 | type loggingMiddleware struct { 13 | service.Service 14 | logger log.Logger 15 | } 16 | 17 | // LoggingMiddleware make logging middleware 18 | func LoggingMiddleware(logger log.Logger) service.ServiceMiddleware { 19 | return func(next service.Service) service.Service { 20 | return loggingMiddleware{next, logger} 21 | } 22 | } 23 | 24 | func (mw loggingMiddleware) Check(ctx context.Context, a, b string) (ret int64, err error) { 25 | 26 | defer func(begin time.Time) { 27 | _ = mw.logger.Log( 28 | "function", "Check", 29 | "username", a, 30 | "pwd", b, 31 | "result", ret, 32 | "took", time.Since(begin), 33 | ) 34 | }(time.Now()) 35 | 36 | ret, err = mw.Service.Check(ctx, a, b) 37 | return ret, err 38 | } 39 | 40 | func (mw loggingMiddleware) HealthCheck() (result bool) { 41 | defer func(begin time.Time) { 42 | _ = mw.logger.Log( 43 | "function", "HealthChcek", 44 | "result", result, 45 | "took", time.Since(begin), 46 | ) 47 | }(time.Now()) 48 | result = mw.Service.HealthCheck() 49 | return 50 | } 51 | -------------------------------------------------------------------------------- /ch5-web/beego/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/astaxie/beego/orm" 6 | _ "github.com/go-sql-driver/mysql" // import your used driver 7 | ) 8 | 9 | // Model Struct 10 | type User struct { 11 | UserId int `orm:"pk"` 12 | Name string `orm:"size(100)"` 13 | } 14 | 15 | func init() { 16 | // set default database 17 | orm.RegisterDataBase("default", "mysql", "root:root_test@tcp(114.67.98.210:3396)/user_tmp?charset=utf8", 30) 18 | 19 | // register model 20 | orm.RegisterModel(new(User)) 21 | 22 | // create table 23 | orm.RunSyncdb("default", false, true) 24 | } 25 | 26 | func main() { 27 | o := orm.NewOrm() 28 | 29 | user := User{Name: "aoho"} 30 | 31 | // insert 32 | id, err := o.Insert(&user) 33 | fmt.Printf("ID: %d, ERR: %v\n", id, err) 34 | 35 | // update 36 | user.Name = "boho" 37 | num, err := o.Update(&user) 38 | fmt.Printf("NUM: %d, ERR: %v\n", num, err) 39 | 40 | // read one 41 | u := User{UserId: user.UserId} 42 | err = o.Read(&u) 43 | fmt.Printf("ERR: %v\n", err) 44 | 45 | var maps []orm.Params 46 | 47 | res, err := o.Raw("SELECT * FROM user").Values(&maps) 48 | fmt.Printf("NUM: %d, ERR: %v\n", res, err) 49 | for _, term := range maps { 50 | fmt.Println(term["user_id"], ":", term["name"]) 51 | } 52 | // delete 53 | num, err = o.Delete(&u) 54 | fmt.Printf("NUM: %d, ERR: %v\n", num, err) 55 | } 56 | -------------------------------------------------------------------------------- /ch13-seckill/user-service/transport/user_model.go: -------------------------------------------------------------------------------- 1 | package transport 2 | 3 | import ( 4 | "context" 5 | "github.com/longjoy/micro-go-book/ch13-seckill/pb" 6 | "github.com/longjoy/micro-go-book/ch13-seckill/user-service/endpoint" 7 | ) 8 | 9 | func EncodeGRPCUserRequest(_ context.Context, r interface{}) (interface{}, error) { 10 | req := r.(pb.UserRequest) 11 | return &pb.UserRequest{ 12 | Username: string(req.Username), 13 | Password: string(req.Password), 14 | }, nil 15 | } 16 | 17 | func DecodeGRPCUserRequest(ctx context.Context, r interface{}) (interface{}, error) { 18 | req := r.(*pb.UserRequest) 19 | return endpoint.UserRequest{ 20 | Username: string(req.Username), 21 | Password: string(req.Password), 22 | }, nil 23 | } 24 | 25 | func EncodeGRPCUserResponse(_ context.Context, r interface{}) (interface{}, error) { 26 | resp := r.(endpoint.UserResponse) 27 | 28 | if resp.Error != nil { 29 | return &pb.UserResponse{ 30 | Result: bool(resp.Result), 31 | Err: "error", 32 | }, nil 33 | } 34 | 35 | return &pb.UserResponse{ 36 | Result: bool(resp.Result), 37 | UserId:resp.UserId, 38 | Err: "", 39 | }, nil 40 | } 41 | 42 | func DecodeGRPCUserResponse(_ context.Context, r interface{}) (interface{}, error) { 43 | resp := r.(*pb.UserResponse) 44 | return pb.UserResponse{ 45 | Result: bool(resp.Result), 46 | Err: resp.Err, 47 | }, nil 48 | } 49 | -------------------------------------------------------------------------------- /ch10-resiliency/use-string-service/plugins/logging.go: -------------------------------------------------------------------------------- 1 | package plugins 2 | 3 | import ( 4 | "github.com/go-kit/kit/log" 5 | "github.com/longjoy/micro-go-book/ch10-resiliency/use-string-service/service" 6 | "time" 7 | ) 8 | 9 | // loggingMiddleware Make a new type 10 | // that contains Service interface and logger instance 11 | type loggingMiddleware struct { 12 | service.Service 13 | logger log.Logger 14 | } 15 | 16 | // LoggingMiddleware make logging middleware 17 | func LoggingMiddleware(logger log.Logger) service.ServiceMiddleware { 18 | return func(next service.Service) service.Service { 19 | return loggingMiddleware{next, logger} 20 | } 21 | } 22 | 23 | 24 | func (mw loggingMiddleware) UseStringService(operationType, a, b string) (ret string, err error) { 25 | 26 | defer func(begin time.Time) { 27 | mw.logger.Log( 28 | "function", "UseStringService", 29 | "a", a, 30 | "b", b, 31 | "result", ret, 32 | "took", time.Since(begin), 33 | ) 34 | }(time.Now()) 35 | 36 | ret, err = mw.Service.UseStringService(operationType, a, b) 37 | return ret, err 38 | } 39 | 40 | func (mw loggingMiddleware) HealthCheck() (result bool) { 41 | defer func(begin time.Time) { 42 | mw.logger.Log( 43 | "function", "HealthChcek", 44 | "result", result, 45 | "took", time.Since(begin), 46 | ) 47 | }(time.Now()) 48 | result = mw.Service.HealthCheck() 49 | return 50 | } 51 | 52 | 53 | -------------------------------------------------------------------------------- /ch7-rpc/go-kit/client.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "flag" 6 | "fmt" 7 | grpctransport "github.com/go-kit/kit/transport/grpc" 8 | service "github.com/longjoy/micro-go-book/ch7-rpc/go-kit/string-service" 9 | "github.com/longjoy/micro-go-book/ch7-rpc/pb" 10 | "google.golang.org/grpc" 11 | "time" 12 | ) 13 | 14 | func main() { 15 | flag.Parse() 16 | ctx := context.Background() 17 | conn, err := grpc.Dial("127.0.0.1:8080", grpc.WithInsecure(), grpc.WithTimeout(1*time.Second)) 18 | if err != nil { 19 | fmt.Println("gRPC dial err:", err) 20 | } 21 | defer conn.Close() 22 | 23 | svr := NewStringClient(conn) 24 | result, err := svr.Concat(ctx, "A", "B") 25 | if err != nil { 26 | fmt.Println("Check error", err.Error()) 27 | } 28 | 29 | fmt.Println("result=", result) 30 | } 31 | 32 | func NewStringClient(conn *grpc.ClientConn) service.Service { 33 | 34 | var ep = grpctransport.NewClient(conn, 35 | "pb.StringService", 36 | "Concat", 37 | DecodeStringRequest, 38 | EncodeStringResponse, 39 | pb.StringResponse{}, 40 | ).Endpoint() 41 | 42 | userEp := service.StringEndpoints{ 43 | StringEndpoint: ep, 44 | } 45 | return userEp 46 | } 47 | 48 | func DecodeStringRequest(ctx context.Context, r interface{}) (interface{}, error) { 49 | return r, nil 50 | } 51 | 52 | func EncodeStringResponse(_ context.Context, r interface{}) (interface{}, error) { 53 | return r, nil 54 | } 55 | -------------------------------------------------------------------------------- /ch12-trace/zipkin-go/string-services/svc1/implementation.go: -------------------------------------------------------------------------------- 1 | // +build go1.7 2 | 3 | package svc1 4 | 5 | import ( 6 | "context" 7 | 8 | "github.com/opentracing/opentracing-go" 9 | 10 | "github.com/openzipkin-contrib/zipkin-go-opentracing/examples/cli_with_2_services/svc2" 11 | ) 12 | 13 | // svc1 is our actual service implementation 14 | type svc1 struct { 15 | svc2Client svc2.Service 16 | } 17 | 18 | func (s *svc1) Concat(ctx context.Context, a, b string) (string, error) { 19 | // test for length overflow 20 | if len(a)+len(b) > StrMaxSize { 21 | // pull span from context (has already been created by our middleware) 22 | span := opentracing.SpanFromContext(ctx) 23 | span.SetTag("error", ErrMaxSize.Error()) 24 | return "", ErrMaxSize 25 | } 26 | 27 | return a + b, nil 28 | } 29 | 30 | func (s *svc1) Sum(ctx context.Context, a, b int64) (int64, error) { 31 | // pull span from context (has already been created by our middleware) 32 | span := opentracing.SpanFromContext(ctx) 33 | span.SetTag("proxy-to", "svc2") 34 | 35 | // proxy request to svc2 36 | result, err := s.svc2Client.Sum(ctx, a, b) 37 | if err != nil { 38 | span.SetTag("error", err.Error()) 39 | return 0, err 40 | } 41 | 42 | return result, nil 43 | } 44 | 45 | // NewService returns a new implementation of our Service. 46 | func NewService(svc2Client svc2.Service) Service { 47 | return &svc1{ 48 | svc2Client: svc2Client, 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /ch9-gateway/string-service/register.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/go-kit/kit/log" 5 | "github.com/go-kit/kit/sd" 6 | "github.com/go-kit/kit/sd/consul" 7 | "github.com/hashicorp/consul/api" 8 | "github.com/pborman/uuid" 9 | "os" 10 | "strconv" 11 | ) 12 | 13 | func Register(consulHost, consulPort, svcHost, svcPort string, logger log.Logger) (registar sd.Registrar) { 14 | 15 | // 创建Consul客户端连接 16 | var client consul.Client 17 | { 18 | consulCfg := api.DefaultConfig() 19 | consulCfg.Address = consulHost + ":" + consulPort 20 | consulClient, err := api.NewClient(consulCfg) 21 | if err != nil { 22 | logger.Log("create consul client error:", err) 23 | os.Exit(1) 24 | } 25 | 26 | client = consul.NewClient(consulClient) 27 | } 28 | 29 | // 设置Consul对服务健康检查的参数 30 | check := api.AgentServiceCheck{ 31 | HTTP: "http://" + svcHost + ":" + svcPort + "/health", 32 | Interval: "10s", 33 | Timeout: "1s", 34 | Notes: "Consul check service health status.", 35 | } 36 | 37 | port, _ := strconv.Atoi(svcPort) 38 | 39 | //设置微服务Consul的注册信息 40 | reg := api.AgentServiceRegistration{ 41 | ID: "string-service" + uuid.New(), 42 | Name: "string-service", 43 | Address: svcHost, 44 | Port: port, 45 | Tags: []string{"string-service", "aoho"}, 46 | Check: &check, 47 | } 48 | 49 | // 执行注册 50 | registar = consul.NewRegistrar(client, ®, logger) 51 | return 52 | } 53 | -------------------------------------------------------------------------------- /ch12-trace/zipkin-kit/string-service/register.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/go-kit/kit/log" 5 | "github.com/go-kit/kit/sd" 6 | "github.com/go-kit/kit/sd/consul" 7 | "github.com/hashicorp/consul/api" 8 | "github.com/pborman/uuid" 9 | "os" 10 | "strconv" 11 | ) 12 | 13 | func Register(consulHost, consulPort, svcHost, svcPort string, logger log.Logger) (registar sd.Registrar) { 14 | 15 | // 创建Consul客户端连接 16 | var client consul.Client 17 | { 18 | consulCfg := api.DefaultConfig() 19 | consulCfg.Address = consulHost + ":" + consulPort 20 | consulClient, err := api.NewClient(consulCfg) 21 | if err != nil { 22 | logger.Log("create consul client error:", err) 23 | os.Exit(1) 24 | } 25 | 26 | client = consul.NewClient(consulClient) 27 | } 28 | 29 | // 设置Consul对服务健康检查的参数 30 | check := api.AgentServiceCheck{ 31 | HTTP: "http://" + svcHost + ":" + svcPort + "/health", 32 | Interval: "10s", 33 | Timeout: "1s", 34 | Notes: "Consul check service health status.", 35 | } 36 | 37 | port, _ := strconv.Atoi(svcPort) 38 | 39 | //设置微服务想Consul的注册信息 40 | reg := api.AgentServiceRegistration{ 41 | ID: "string-service" + uuid.New(), 42 | Name: "string-service", 43 | Address: svcHost, 44 | Port: port, 45 | Tags: []string{"string-service"}, 46 | Check: &check, 47 | } 48 | 49 | // 执行注册 50 | registar = consul.NewRegistrar(client, ®, logger) 51 | return 52 | } 53 | -------------------------------------------------------------------------------- /ch7-rpc/grpc/string-service/service.go: -------------------------------------------------------------------------------- 1 | package string_service 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "github.com/longjoy/micro-go-book/ch7-rpc/pb" 7 | "strings" 8 | ) 9 | 10 | const ( 11 | StrMaxSize = 1024 12 | ) 13 | 14 | // Service errors 15 | var ( 16 | ErrMaxSize = errors.New("maximum size of 1024 bytes exceeded") 17 | 18 | ErrStrValue = errors.New("maximum size of 1024 bytes exceeded") 19 | ) 20 | 21 | type StringService struct{} 22 | 23 | func (s *StringService) Concat(ctx context.Context, req *pb.StringRequest) (*pb.StringResponse, error) { 24 | if len(req.A)+len(req.B) > StrMaxSize { 25 | response := pb.StringResponse{Ret: ""} 26 | return &response, nil 27 | } 28 | response := pb.StringResponse{Ret: req.A + req.B} 29 | return &response, nil 30 | } 31 | 32 | func (s *StringService) Diff(ctx context.Context, req *pb.StringRequest) (*pb.StringResponse, error) { 33 | if len(req.A) < 1 || len(req.B) < 1 { 34 | response := pb.StringResponse{Ret: ""} 35 | return &response, nil 36 | } 37 | res := "" 38 | if len(req.A) >= len(req.B) { 39 | for _, char := range req.B { 40 | if strings.Contains(req.A, string(char)) { 41 | res = res + string(char) 42 | } 43 | } 44 | } else { 45 | for _, char := range req.A { 46 | if strings.Contains(req.B, string(char)) { 47 | res = res + string(char) 48 | } 49 | } 50 | } 51 | response := pb.StringResponse{Ret: res} 52 | return &response, nil 53 | } 54 | -------------------------------------------------------------------------------- /ch5-web/webForm.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "html/template" 6 | "log" 7 | "net/http" 8 | "strings" 9 | ) 10 | 11 | func login(w http.ResponseWriter, r *http.Request) { 12 | fmt.Println("method:", r.Method) //获取请求的方法 13 | if r.Method == "GET" { 14 | t, _ := template.ParseFiles("login.tpl") 15 | log.Println(t.Execute(w, nil)) 16 | } else { 17 | //请求的是登录数据,那么执行登录的逻辑判断 18 | _ = r.ParseForm() 19 | fmt.Println("username:", r.Form["username"]) 20 | fmt.Println("password:", r.Form["password"]) 21 | if pwd := r.Form.Get("password"); pwd == "123456" { // 验证密码是否正确 22 | fmt.Fprintf(w, "欢迎登陆,Hello %s!", r.Form.Get("username")) //这个写入到w的是输出到客户端的 23 | } else { 24 | fmt.Fprintf(w, "密码错误,请重新输入!") 25 | } 26 | } 27 | } 28 | 29 | func sayHelloName(w http.ResponseWriter, r *http.Request) { 30 | _ = r.ParseForm() //解析url传递的参数,对于POST则解析响应包的主体(request body) 31 | //注意:如果没有调用ParseForm方法,下面无法获取表单的数据 32 | fmt.Println(r.Form) //这些信息是输出到服务器端的打印信息 33 | fmt.Println("path", r.URL.Path) 34 | for k, v := range r.Form { 35 | fmt.Println("key:", k) 36 | fmt.Println("val:", strings.Join(v, "")) 37 | } 38 | fmt.Fprintf(w, "Hello aoho!") //这个写入到w的是输出到客户端的 39 | } 40 | 41 | func main() { 42 | http.HandleFunc("/", sayHelloName) //设置访问的路由 43 | http.HandleFunc("/login", login) //设置访问的路由 44 | err := http.ListenAndServe(":8080", nil) //设置监听的端口 45 | if err != nil { 46 | log.Fatal("ListenAndServe: ", err) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /ch13-seckill/pkg/loadbalance/loadbalance.go: -------------------------------------------------------------------------------- 1 | package loadbalance 2 | 3 | import ( 4 | "errors" 5 | "github.com/longjoy/micro-go-book/ch13-seckill/pkg/common" 6 | "math/rand" 7 | ) 8 | 9 | // 负载均衡器 10 | type LoadBalance interface { 11 | SelectService(service []*common.ServiceInstance) (*common.ServiceInstance, error) 12 | } 13 | 14 | type RandomLoadBalance struct { 15 | } 16 | 17 | // 随机负载均衡 18 | func (loadBalance *RandomLoadBalance) SelectService(services []*common.ServiceInstance) (*common.ServiceInstance, error) { 19 | 20 | if services == nil || len(services) == 0 { 21 | return nil, errors.New("service instances are not exist") 22 | } 23 | 24 | return services[rand.Intn(len(services))], nil 25 | } 26 | 27 | type WeightRoundRobinLoadBalance struct { 28 | } 29 | 30 | // 权重平滑负载均衡 31 | func (loadBalance *WeightRoundRobinLoadBalance) SelectService(services []*common.ServiceInstance) (best *common.ServiceInstance, err error) { 32 | 33 | if services == nil || len(services) == 0 { 34 | return nil, errors.New("service instances are not exist") 35 | } 36 | 37 | total := 0 38 | for i := 0; i < len(services); i++ { 39 | w := services[i] 40 | if w == nil { 41 | continue 42 | } 43 | 44 | w.CurWeight += w.Weight 45 | 46 | total += w.Weight 47 | if best == nil || w.CurWeight > best.CurWeight { 48 | best = w 49 | } 50 | } 51 | 52 | if best == nil { 53 | return nil, nil 54 | } 55 | 56 | best.CurWeight -= total 57 | return best, nil 58 | } 59 | -------------------------------------------------------------------------------- /ch10-resiliency/gateway.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | kitlog "github.com/go-kit/kit/log" 7 | "github.com/longjoy/micro-go-book/common/discover" 8 | "github.com/longjoy/micro-go-book/common/loadbalance" 9 | "log" 10 | "net/http" 11 | "os" 12 | "os/signal" 13 | "syscall" 14 | ) 15 | 16 | func main() { 17 | 18 | // 创建环境变量 19 | var ( 20 | consulHost = flag.String("consul.host", "127.0.0.1", "consul server ip address") 21 | consulPort = flag.Int("consul.port", 8500, "consul server port") 22 | ) 23 | flag.Parse() 24 | 25 | //创建日志组件 26 | var logger kitlog.Logger 27 | { 28 | logger = kitlog.NewLogfmtLogger(os.Stderr) 29 | logger = kitlog.With(logger, "ts", kitlog.DefaultTimestampUTC) 30 | logger = kitlog.With(logger, "caller", kitlog.DefaultCaller) 31 | } 32 | 33 | 34 | 35 | consulClient, err := discover.NewKitDiscoverClient(*consulHost, *consulPort) 36 | 37 | if err != nil { 38 | logger.Log("err", err) 39 | os.Exit(1) 40 | } 41 | 42 | //创建反向代理 43 | proxy := NewHystrixHandler(consulClient, new(loadbalance.RandomLoadBalance), log.New(os.Stderr, "", log.LstdFlags)) 44 | 45 | errc := make(chan error) 46 | go func() { 47 | c := make(chan os.Signal) 48 | signal.Notify(c, syscall.SIGINT, syscall.SIGTERM) 49 | errc <- fmt.Errorf("%s", <-c) 50 | }() 51 | 52 | //开始监听 53 | go func() { 54 | logger.Log("transport", "HTTP", "addr", "9090") 55 | errc <- http.ListenAndServe(":9090", proxy) 56 | }() 57 | 58 | // 开始运行,等待结束 59 | logger.Log("exit", <-errc) 60 | } 61 | -------------------------------------------------------------------------------- /ch6-discovery/service/service.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "github.com/longjoy/micro-go-book/ch6-discovery/config" 7 | "github.com/longjoy/micro-go-book/ch6-discovery/discover" 8 | ) 9 | 10 | type Service interface { 11 | 12 | 13 | // HealthCheck check service health status 14 | HealthCheck() bool 15 | 16 | // sayHelloService 17 | SayHello() string 18 | 19 | // discovery service from consul by serviceName 20 | DiscoveryService(ctx context.Context, serviceName string) ([]interface{}, error) 21 | 22 | } 23 | 24 | 25 | var ErrNotServiceInstances = errors.New("instances are not existed") 26 | 27 | type DiscoveryServiceImpl struct { 28 | discoveryClient discover.DiscoveryClient 29 | } 30 | 31 | func NewDiscoveryServiceImpl(discoveryClient discover.DiscoveryClient) Service { 32 | return &DiscoveryServiceImpl{ 33 | discoveryClient:discoveryClient, 34 | } 35 | } 36 | 37 | func (*DiscoveryServiceImpl) SayHello() string { 38 | return "Hello World!" 39 | } 40 | 41 | func (service *DiscoveryServiceImpl) DiscoveryService(ctx context.Context, serviceName string) ([]interface{}, error) { 42 | 43 | instances := service.discoveryClient.DiscoverServices(serviceName, config.Logger) 44 | 45 | if instances == nil || len(instances) == 0 { 46 | return nil, ErrNotServiceInstances 47 | } 48 | return instances, nil 49 | } 50 | 51 | 52 | // HealthCheck implement Service method 53 | // 用于检查服务的健康状态,这里仅仅返回true 54 | func (*DiscoveryServiceImpl) HealthCheck() bool { 55 | return true 56 | } 57 | 58 | -------------------------------------------------------------------------------- /ch12-trace/zipkin-kit/client/stringModel.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "context" 5 | "github.com/longjoy/micro-go-book/ch12-trace/zipkin-kit/pb" 6 | "github.com/longjoy/micro-go-book/ch12-trace/zipkin-kit/string-service/endpoint" 7 | "github.com/pkg/errors" 8 | ) 9 | 10 | func EncodeGRPCStringRequest(_ context.Context, r interface{}) (interface{}, error) { 11 | req := r.(endpoint.StringRequest) 12 | return &pb.StringRequest{ 13 | RequestType: string(req.RequestType), 14 | A: string(req.A), 15 | B: string(req.B), 16 | }, nil 17 | } 18 | 19 | func DecodeGRPCStringRequest(ctx context.Context, r interface{}) (interface{}, error) { 20 | req := r.(*pb.StringRequest) 21 | return endpoint.StringRequest{ 22 | RequestType: string(req.RequestType), 23 | A: string(req.A), 24 | B: string(req.B), 25 | }, nil 26 | } 27 | 28 | func EncodeGRPCStringResponse(_ context.Context, r interface{}) (interface{}, error) { 29 | resp := r.(endpoint.StringResponse) 30 | 31 | if resp.Error != nil { 32 | return &pb.StringResponse{ 33 | Result: string(resp.Result), 34 | Err: resp.Error.Error(), 35 | }, nil 36 | } 37 | 38 | return &pb.StringResponse{ 39 | Result: string(resp.Result), 40 | Err: "", 41 | }, nil 42 | } 43 | 44 | func DecodeGRPCStringResponse(_ context.Context, r interface{}) (interface{}, error) { 45 | resp := r.(*pb.StringResponse) 46 | return endpoint.StringResponse{ 47 | Result: string(resp.Result), 48 | Error: errors.New(resp.Err), 49 | }, nil 50 | } 51 | -------------------------------------------------------------------------------- /ch9-gateway/string-service/logging.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/go-kit/kit/log" 5 | "time" 6 | ) 7 | 8 | // loggingMiddleware Make a new type 9 | // that contains Service interface and logger instance 10 | type loggingMiddleware struct { 11 | Service 12 | logger log.Logger 13 | } 14 | 15 | // LoggingMiddleware make logging middleware 16 | func LoggingMiddleware(logger log.Logger) ServiceMiddleware { 17 | return func(next Service) Service { 18 | return loggingMiddleware{next, logger} 19 | } 20 | } 21 | 22 | func (mw loggingMiddleware) Concat(a, b string) (ret string, err error) { 23 | 24 | defer func(begin time.Time) { 25 | mw.logger.Log( 26 | "function", "Concat", 27 | "a", a, 28 | "b", b, 29 | "result", ret, 30 | "took", time.Since(begin), 31 | ) 32 | }(time.Now()) 33 | 34 | ret, err = mw.Service.Concat(a, b) 35 | return ret, err 36 | } 37 | 38 | func (mw loggingMiddleware) Diff(a, b string) (ret string, err error) { 39 | 40 | defer func(begin time.Time) { 41 | mw.logger.Log( 42 | "function", "Diff", 43 | "a", a, 44 | "b", b, 45 | "result", ret, 46 | "took", time.Since(begin), 47 | ) 48 | }(time.Now()) 49 | 50 | ret, err = mw.Service.Diff(a, b) 51 | return ret, err 52 | } 53 | 54 | func (mw loggingMiddleware) HealthCheck() (result bool) { 55 | defer func(begin time.Time) { 56 | mw.logger.Log( 57 | "function", "HealthChcek", 58 | "result", result, 59 | "took", time.Since(begin), 60 | ) 61 | }(time.Now()) 62 | result = mw.Service.HealthCheck() 63 | return 64 | } 65 | -------------------------------------------------------------------------------- /common/loadbalance/loadbalance.go: -------------------------------------------------------------------------------- 1 | package loadbalance 2 | 3 | import ( 4 | "errors" 5 | "github.com/hashicorp/consul/api" 6 | "math/rand" 7 | ) 8 | 9 | // 负载均衡器 10 | type LoadBalance interface { 11 | SelectService(service []*api.AgentService) (*api.AgentService, error) 12 | } 13 | 14 | var ErrNoInstances = errors.New("service instances are not existed") 15 | 16 | type RandomLoadBalance struct { 17 | } 18 | 19 | // 随机负载均衡 20 | func (loadBalance *RandomLoadBalance) SelectService(services []*api.AgentService) (*api.AgentService, error) { 21 | 22 | if services == nil || len(services) == 0 { 23 | return nil, ErrNoInstances 24 | } 25 | 26 | return services[rand.Intn(len(services))], nil 27 | } 28 | 29 | type WeightRoundRobinLoadBalance struct { 30 | } 31 | 32 | //// 权重平滑负载均衡 33 | //func (loadBalance *WeightRoundRobinLoadBalance) SelectService(services []*discover.ServiceInstance) (best *discover.ServiceInstance, err error) { 34 | // 35 | // if services == nil || len(services) == 0 { 36 | // return nil, errors.New("service instances are not exist") 37 | // } 38 | // 39 | // total := 0 40 | // for i := 0; i < len(services); i++ { 41 | // w := services[i] 42 | // if w == nil { 43 | // continue 44 | // } 45 | // 46 | // w.CurWeight += w.Weight 47 | // 48 | // total += w.Weight 49 | // if w.Weight < w.Weight { 50 | // w.Weight++ 51 | // } 52 | // if best == nil || w.CurWeight > best.CurWeight { 53 | // best = w 54 | // } 55 | // } 56 | // 57 | // if best == nil { 58 | // return nil, nil 59 | // } 60 | // 61 | // best.CurWeight -= total 62 | // return best, nil 63 | //} 64 | -------------------------------------------------------------------------------- /ch11-security/service/user_service.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "github.com/longjoy/micro-go-book/ch11-security/model" 7 | ) 8 | 9 | var ( 10 | ErrUserNotExist = errors.New("username is not exist") 11 | ErrPassword = errors.New("invalid password") 12 | ) 13 | // Service Define a service interface 14 | type UserDetailsService interface { 15 | // Get UserDetails By username 16 | GetUserDetailByUsername(ctx context.Context, username, password string) (*model.UserDetails, error) 17 | } 18 | 19 | //UserService implement Service interface 20 | type InMemoryUserDetailsService struct { 21 | userDetailsDict map[string]*model.UserDetails 22 | 23 | } 24 | 25 | func (service *InMemoryUserDetailsService) GetUserDetailByUsername(ctx context.Context, username, password string) (*model.UserDetails, error) { 26 | 27 | 28 | // 根据 username 获取用户信息 29 | userDetails, ok := service.userDetailsDict[username]; if ok{ 30 | // 比较 password 是否匹配 31 | if userDetails.Password == password{ 32 | return userDetails, nil 33 | }else { 34 | return nil, ErrPassword 35 | } 36 | }else { 37 | return nil, ErrUserNotExist 38 | } 39 | 40 | 41 | } 42 | 43 | func NewInMemoryUserDetailsService(userDetailsList []*model.UserDetails) *InMemoryUserDetailsService { 44 | userDetailsDict := make(map[string]*model.UserDetails) 45 | 46 | if userDetailsList != nil { 47 | for _, value := range userDetailsList { 48 | userDetailsDict[value.Username] = value 49 | } 50 | } 51 | 52 | return &InMemoryUserDetailsService{ 53 | userDetailsDict:userDetailsDict, 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /ch7-rpc/go-kit/string-service/logging.go: -------------------------------------------------------------------------------- 1 | package string_service 2 | 3 | import ( 4 | "context" 5 | "github.com/go-kit/kit/log" 6 | "time" 7 | ) 8 | 9 | // loggingMiddleware Make a new type 10 | // that contains Service interface and logger instance 11 | type loggingMiddleware struct { 12 | Service 13 | logger log.Logger 14 | } 15 | 16 | // LoggingMiddleware make logging middleware 17 | func LoggingMiddleware(logger log.Logger) ServiceMiddleware { 18 | return func(next Service) Service { 19 | return loggingMiddleware{next, logger} 20 | } 21 | } 22 | 23 | func (mw loggingMiddleware) Concat(ctx context.Context, a, b string) (ret string, err error) { 24 | 25 | defer func(begin time.Time) { 26 | mw.logger.Log( 27 | "function", "Concat", 28 | "a", a, 29 | "b", b, 30 | "result", ret, 31 | "took", time.Since(begin), 32 | ) 33 | }(time.Now()) 34 | 35 | ret, err = mw.Service.Concat(ctx, a, b) 36 | return ret, err 37 | } 38 | 39 | func (mw loggingMiddleware) Diff(ctx context.Context, a, b string) (ret string, err error) { 40 | 41 | defer func(begin time.Time) { 42 | mw.logger.Log( 43 | "function", "Diff", 44 | "a", a, 45 | "b", b, 46 | "result", ret, 47 | "took", time.Since(begin), 48 | ) 49 | }(time.Now()) 50 | 51 | ret, err = mw.Service.Diff(ctx, a, b) 52 | return ret, err 53 | } 54 | 55 | func (mw loggingMiddleware) HealthCheck() (result bool) { 56 | defer func(begin time.Time) { 57 | mw.logger.Log( 58 | "function", "HealthChcek", 59 | "result", result, 60 | "took", time.Since(begin), 61 | ) 62 | }(time.Now()) 63 | result = true 64 | return 65 | } 66 | -------------------------------------------------------------------------------- /ch7-rpc/basic/string-service/service.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "errors" 5 | "strings" 6 | ) 7 | 8 | // Service constants 9 | const ( 10 | StrMaxSize = 1024 11 | ) 12 | 13 | // Service errors 14 | var ( 15 | ErrMaxSize = errors.New("maximum size of 1024 bytes exceeded") 16 | 17 | ErrStrValue = errors.New("maximum size of 1024 bytes exceeded") 18 | ) 19 | 20 | type StringRequest struct { 21 | A string 22 | B string 23 | } 24 | 25 | type Service interface { 26 | // Concat a and b 27 | Concat(req StringRequest, ret *string) error 28 | 29 | // a,b pkg string value 30 | Diff(req StringRequest, ret *string) error 31 | } 32 | 33 | //ArithmeticService implement Service interface 34 | type StringService struct { 35 | } 36 | 37 | func (s StringService) Concat(req StringRequest, ret *string) error { 38 | // test for length overflow 39 | if len(req.A)+len(req.B) > StrMaxSize { 40 | *ret = "" 41 | return ErrMaxSize 42 | } 43 | *ret = req.A + req.B 44 | return nil 45 | } 46 | 47 | func (s StringService) Diff(req StringRequest, ret *string) error { 48 | if len(req.A) < 1 || len(req.B) < 1 { 49 | *ret = "" 50 | return nil 51 | } 52 | res := "" 53 | if len(req.A) >= len(req.B) { 54 | for _, char := range req.B { 55 | if strings.Contains(req.A, string(char)) { 56 | res = res + string(char) 57 | } 58 | } 59 | } else { 60 | for _, char := range req.A { 61 | if strings.Contains(req.B, string(char)) { 62 | res = res + string(char) 63 | } 64 | } 65 | } 66 | *ret = res 67 | return nil 68 | } 69 | 70 | // ServiceMiddleware define service middleware 71 | type ServiceMiddleware func(Service) Service 72 | -------------------------------------------------------------------------------- /ch13-seckill/pkg/client/oauth.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "context" 5 | "github.com/longjoy/micro-go-book/ch13-seckill/pb" 6 | "github.com/longjoy/micro-go-book/ch13-seckill/pkg/discover" 7 | "github.com/longjoy/micro-go-book/ch13-seckill/pkg/loadbalance" 8 | "github.com/opentracing/opentracing-go" 9 | ) 10 | 11 | type OAuthClient interface { 12 | CheckToken(ctx context.Context, tracer opentracing.Tracer, request *pb.CheckTokenRequest) (*pb.CheckTokenResponse, error) 13 | } 14 | 15 | type OAuthClientImpl struct { 16 | manager ClientManager 17 | serviceName string 18 | loadBalance loadbalance.LoadBalance 19 | tracer opentracing.Tracer 20 | } 21 | 22 | func (impl *OAuthClientImpl) CheckToken(ctx context.Context, tracer opentracing.Tracer, request *pb.CheckTokenRequest) (*pb.CheckTokenResponse, error) { 23 | response := new(pb.CheckTokenResponse) 24 | if err := impl.manager.DecoratorInvoke("/pb.OAuthService/CheckToken", "token_check", tracer, ctx, request, response); err == nil { 25 | return response, nil 26 | } else { 27 | return nil, err 28 | } 29 | } 30 | func NewOAuthClient(serviceName string, lb loadbalance.LoadBalance, tracer opentracing.Tracer) (OAuthClient, error) { 31 | if serviceName == "" { 32 | serviceName = "oauth" 33 | } 34 | if lb == nil { 35 | lb = defaultLoadBalance 36 | } 37 | 38 | return &OAuthClientImpl{ 39 | manager: &DefaultClientManager{ 40 | serviceName: serviceName, 41 | loadBalance: lb, 42 | discoveryClient:discover.ConsulService, 43 | logger:discover.Logger, 44 | }, 45 | serviceName: serviceName, 46 | loadBalance: lb, 47 | tracer: tracer, 48 | }, nil 49 | 50 | } 51 | -------------------------------------------------------------------------------- /ch7-rpc/go-kit/string-service/service.go: -------------------------------------------------------------------------------- 1 | package string_service 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "fmt" 7 | "strings" 8 | ) 9 | 10 | // Service constants 11 | const ( 12 | StrMaxSize = 1024 13 | ) 14 | 15 | // Service errors 16 | var ( 17 | ErrMaxSize = errors.New("maximum size of 1024 bytes exceeded") 18 | 19 | ErrStrValue = errors.New("maximum size of 1024 bytes exceeded") 20 | ) 21 | 22 | // Service Define a service interface 23 | type Service interface { 24 | // Concat a and b 25 | Concat(ctx context.Context, a, b string) (string, error) 26 | 27 | // a,b pkg string value 28 | Diff(ctx context.Context, a, b string) (string, error) 29 | } 30 | 31 | //ArithmeticService implement Service interface 32 | type StringService struct { 33 | } 34 | 35 | func (s StringService) Concat(ctx context.Context, a, b string) (string, error) { 36 | // test for length overflow 37 | if len(a)+len(b) > StrMaxSize { 38 | return "", ErrMaxSize 39 | } 40 | fmt.Printf("StringService Concat return %s", a+b) 41 | return a + b, nil 42 | } 43 | 44 | func (s StringService) Diff(ctx context.Context, a, b string) (string, error) { 45 | if len(a) < 1 || len(b) < 1 { 46 | return "", nil 47 | } 48 | res := "" 49 | if len(a) >= len(b) { 50 | for _, char := range b { 51 | if strings.Contains(a, string(char)) { 52 | res = res + string(char) 53 | } 54 | } 55 | } else { 56 | for _, char := range a { 57 | if strings.Contains(b, string(char)) { 58 | res = res + string(char) 59 | } 60 | } 61 | } 62 | return res, nil 63 | } 64 | 65 | // ServiceMiddleware define service middleware 66 | type ServiceMiddleware func(Service) Service 67 | -------------------------------------------------------------------------------- /ch11-security/service/client_service.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "github.com/longjoy/micro-go-book/ch11-security/model" 7 | ) 8 | 9 | var ( 10 | 11 | ErrClientNotExist = errors.New("clientId is not exist") 12 | ErrClientSecret = errors.New("invalid clientSecret") 13 | 14 | ) 15 | 16 | // Service Define a service interface 17 | type ClientDetailsService interface { 18 | 19 | GetClientDetailByClientId(ctx context.Context, clientId string, clientSecret string)(*model.ClientDetails, error) 20 | 21 | } 22 | 23 | type InMemoryClientDetailsService struct { 24 | clientDetailsDict map[string]*model.ClientDetails 25 | 26 | } 27 | 28 | func NewInMemoryClientDetailService(clientDetailsList []*model.ClientDetails ) *InMemoryClientDetailsService{ 29 | clientDetailsDict := make(map[string]*model.ClientDetails) 30 | 31 | if clientDetailsList != nil { 32 | for _, value := range clientDetailsList { 33 | clientDetailsDict[value.ClientId] = value 34 | } 35 | } 36 | 37 | return &InMemoryClientDetailsService{ 38 | clientDetailsDict:clientDetailsDict, 39 | } 40 | } 41 | 42 | 43 | func (service *InMemoryClientDetailsService)GetClientDetailByClientId(ctx context.Context, clientId string, clientSecret string)(*model.ClientDetails, error) { 44 | 45 | // 根据 clientId 获取 clientDetails 46 | clientDetails, ok := service.clientDetailsDict[clientId]; if ok{ 47 | // 比较 clientSecret 是否正确 48 | if clientDetails.ClientSecret == clientSecret{ 49 | return clientDetails, nil 50 | }else { 51 | return nil, ErrClientSecret 52 | } 53 | }else { 54 | return nil, ErrClientNotExist 55 | } 56 | 57 | 58 | 59 | } 60 | 61 | 62 | -------------------------------------------------------------------------------- /ch13-seckill/pkg/client/user.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "context" 5 | "github.com/longjoy/micro-go-book/ch13-seckill/pb" 6 | "github.com/longjoy/micro-go-book/ch13-seckill/pkg/discover" 7 | "github.com/longjoy/micro-go-book/ch13-seckill/pkg/loadbalance" 8 | "github.com/opentracing/opentracing-go" 9 | ) 10 | 11 | type UserClient interface { 12 | CheckUser(ctx context.Context, tracer opentracing.Tracer, request *pb.UserRequest) (*pb.UserResponse, error) 13 | } 14 | 15 | type UserClientImpl struct { 16 | /** 17 | * 可以配置负载均衡策略,重试、等机制。也可以配置invokeAfter和invokerBefore 18 | */ 19 | manager ClientManager 20 | serviceName string 21 | loadBalance loadbalance.LoadBalance 22 | tracer opentracing.Tracer 23 | } 24 | 25 | func (impl *UserClientImpl) CheckUser(ctx context.Context, tracer opentracing.Tracer, request *pb.UserRequest) (*pb.UserResponse, error) { 26 | response := new(pb.UserResponse) 27 | if err := impl.manager.DecoratorInvoke("/pb.UserService/Check", "user_check", tracer, ctx, request, response); err == nil { 28 | return response, nil 29 | } else { 30 | return nil, err 31 | } 32 | } 33 | 34 | func NewUserClient(serviceName string, lb loadbalance.LoadBalance, tracer opentracing.Tracer) (UserClient, error) { 35 | if serviceName == "" { 36 | serviceName = "user" 37 | } 38 | if lb == nil { 39 | lb = defaultLoadBalance 40 | } 41 | 42 | return &UserClientImpl{ 43 | manager: &DefaultClientManager{ 44 | serviceName: serviceName, 45 | loadBalance: lb, 46 | discoveryClient:discover.ConsulService, 47 | logger:discover.Logger, 48 | }, 49 | serviceName: serviceName, 50 | loadBalance: lb, 51 | tracer: tracer, 52 | }, nil 53 | 54 | } 55 | -------------------------------------------------------------------------------- /ch9-gateway/string-service/service.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "strings" 6 | ) 7 | 8 | // Service constants 9 | const ( 10 | StrMaxSize = 1024 11 | ) 12 | 13 | // Service errors 14 | var ( 15 | ErrMaxSize = errors.New("maximum size of 1024 bytes exceeded") 16 | 17 | ErrStrValue = errors.New("maximum size of 1024 bytes exceeded") 18 | ) 19 | 20 | // Service Define a service interface 21 | type Service interface { 22 | // Concat a and b 23 | Concat(a, b string) (string, error) 24 | 25 | // a,b pkg string value 26 | Diff(a, b string) (string, error) 27 | 28 | // HealthCheck check service health status 29 | HealthCheck() bool 30 | } 31 | 32 | //ArithmeticService implement Service interface 33 | type StringService struct { 34 | } 35 | 36 | func (s StringService) Concat(a, b string) (string, error) { 37 | // test for length overflow 38 | if len(a)+len(b) > StrMaxSize { 39 | return "", ErrMaxSize 40 | } 41 | return a + b, nil 42 | } 43 | 44 | func (s StringService) Diff(a, b string) (string, error) { 45 | if len(a) < 1 || len(b) < 1 { 46 | return "", nil 47 | } 48 | res := "" 49 | if len(a) >= len(b) { 50 | for _, char := range b { 51 | if strings.Contains(a, string(char)) { 52 | res = res + string(char) 53 | } 54 | } 55 | } else { 56 | for _, char := range a { 57 | if strings.Contains(b, string(char)) { 58 | res = res + string(char) 59 | } 60 | } 61 | } 62 | return res, nil 63 | } 64 | 65 | // HealthCheck implement Service method 66 | // 用于检查服务的健康状态,这里仅仅返回true。 67 | func (s StringService) HealthCheck() bool { 68 | return true 69 | } 70 | 71 | // ServiceMiddleware define service middleware 72 | type ServiceMiddleware func(Service) Service 73 | -------------------------------------------------------------------------------- /ch13-seckill/oauth-service/service/user_service.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "github.com/longjoy/micro-go-book/ch13-seckill/oauth-service/model" 7 | "github.com/longjoy/micro-go-book/ch13-seckill/pb" 8 | "github.com/longjoy/micro-go-book/ch13-seckill/pkg/client" 9 | ) 10 | 11 | var ( 12 | InvalidAuthentication = errors.New("invalid auth") 13 | InvalidUserInfo = errors.New("invalid user info") 14 | 15 | ) 16 | // Service Define a service interface 17 | type UserDetailsService interface { 18 | // Get UserDetails By username 19 | GetUserDetailByUsername(ctx context.Context, username, password string) (*model.UserDetails, error) 20 | } 21 | 22 | //UserService implement Service interface 23 | type RemoteUserService struct { 24 | 25 | userClient client.UserClient 26 | 27 | 28 | } 29 | 30 | func (service *RemoteUserService) GetUserDetailByUsername(ctx context.Context, username, password string) (*model.UserDetails, error) { 31 | 32 | response, err := service.userClient.CheckUser(ctx, nil, &pb.UserRequest{ 33 | Username:username, 34 | Password:password, 35 | }) 36 | 37 | if err == nil{ 38 | if response.UserId != 0 { 39 | return &model.UserDetails{ 40 | UserId:response.UserId, 41 | Username:username, 42 | Password:password, 43 | }, nil 44 | }else { 45 | return nil, InvalidUserInfo 46 | } 47 | } 48 | return nil, err 49 | 50 | } 51 | 52 | func NewRemoteUserDetailService() *RemoteUserService { 53 | 54 | userClient, _ := client.NewUserClient("user", nil, nil) 55 | return &RemoteUserService{ 56 | userClient:userClient, 57 | } 58 | } 59 | 60 | // ServiceMiddleware define service middleware 61 | type ServiceMiddleware func(Service) Service 62 | -------------------------------------------------------------------------------- /ch6-discovery/string-service/plugins/logging.go: -------------------------------------------------------------------------------- 1 | package plugins 2 | 3 | import ( 4 | "github.com/go-kit/kit/log" 5 | "github.com/longjoy/micro-go-book/ch6-discovery/string-service/service" 6 | "time" 7 | ) 8 | 9 | // loggingMiddleware Make a new type 10 | // that contains Service interface and logger instance 11 | type loggingMiddleware struct { 12 | service.Service 13 | logger log.Logger 14 | } 15 | 16 | // LoggingMiddleware make logging middleware 17 | func LoggingMiddleware(logger log.Logger) service.ServiceMiddleware { 18 | return func(next service.Service) service.Service { 19 | return loggingMiddleware{next, logger} 20 | } 21 | } 22 | 23 | func (mw loggingMiddleware) Concat(a, b string) (ret string, err error) { 24 | // 函数执行结束后打印日志 25 | defer func(begin time.Time) { 26 | mw.logger.Log( 27 | "function", "Concat", 28 | "a", a, 29 | "b", b, 30 | "result", ret, 31 | "took", time.Since(begin), 32 | ) 33 | }(time.Now()) 34 | 35 | ret, err = mw.Service.Concat(a, b) 36 | return ret, err 37 | } 38 | 39 | func (mw loggingMiddleware) Diff(a, b string) (ret string, err error) { 40 | // 函数执行结束后打印日志 41 | defer func(begin time.Time) { 42 | mw.logger.Log( 43 | "function", "Diff", 44 | "a", a, 45 | "b", b, 46 | "result", ret, 47 | "took", time.Since(begin), 48 | ) 49 | }(time.Now()) 50 | 51 | ret, err = mw.Service.Diff(a, b) 52 | return ret, err 53 | } 54 | 55 | func (mw loggingMiddleware) HealthCheck() (result bool) { 56 | defer func(begin time.Time) { 57 | mw.logger.Log( 58 | "function", "HealthChcek", 59 | "result", result, 60 | "took", time.Since(begin), 61 | ) 62 | }(time.Now()) 63 | result = mw.Service.HealthCheck() 64 | return 65 | } 66 | 67 | 68 | -------------------------------------------------------------------------------- /ch10-resiliency/string-service/plugins/logging.go: -------------------------------------------------------------------------------- 1 | package plugins 2 | 3 | import ( 4 | "github.com/go-kit/kit/log" 5 | "github.com/longjoy/micro-go-book/ch10-resiliency/string-service/service" 6 | "time" 7 | ) 8 | 9 | // loggingMiddleware Make a new type 10 | // that contains Service interface and logger instance 11 | type loggingMiddleware struct { 12 | service.Service 13 | logger log.Logger 14 | } 15 | 16 | // LoggingMiddleware make logging middleware 17 | func LoggingMiddleware(logger log.Logger) service.ServiceMiddleware { 18 | return func(next service.Service) service.Service { 19 | return loggingMiddleware{next, logger} 20 | } 21 | } 22 | 23 | func (mw loggingMiddleware) Concat(a, b string) (ret string, err error) { 24 | // 函数执行结束后打印日志 25 | defer func(begin time.Time) { 26 | mw.logger.Log( 27 | "function", "Concat", 28 | "a", a, 29 | "b", b, 30 | "result", ret, 31 | "took", time.Since(begin), 32 | ) 33 | }(time.Now()) 34 | 35 | ret, err = mw.Service.Concat(a, b) 36 | return ret, err 37 | } 38 | 39 | func (mw loggingMiddleware) Diff(a, b string) (ret string, err error) { 40 | // 函数执行结束后打印日志 41 | defer func(begin time.Time) { 42 | mw.logger.Log( 43 | "function", "Diff", 44 | "a", a, 45 | "b", b, 46 | "result", ret, 47 | "took", time.Since(begin), 48 | ) 49 | }(time.Now()) 50 | 51 | ret, err = mw.Service.Diff(a, b) 52 | return ret, err 53 | } 54 | 55 | func (mw loggingMiddleware) HealthCheck() (result bool) { 56 | defer func(begin time.Time) { 57 | mw.logger.Log( 58 | "function", "HealthChcek", 59 | "result", result, 60 | "took", time.Since(begin), 61 | ) 62 | }(time.Now()) 63 | result = mw.Service.HealthCheck() 64 | return 65 | } 66 | 67 | 68 | -------------------------------------------------------------------------------- /ch12-trace/zipkin-kit/string-service/logging.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "github.com/go-kit/kit/log" 6 | "github.com/longjoy/micro-go-book/ch12-trace/zipkin-kit/string-service/service" 7 | "time" 8 | ) 9 | 10 | // loggingMiddleware Make a new type 11 | // that contains Service interface and logger instance 12 | type loggingMiddleware struct { 13 | service.Service 14 | logger log.Logger 15 | } 16 | 17 | // LoggingMiddleware make logging middleware 18 | func LoggingMiddleware(logger log.Logger) service.ServiceMiddleware { 19 | return func(next service.Service) service.Service { 20 | return loggingMiddleware{next, logger} 21 | } 22 | } 23 | 24 | func (mw loggingMiddleware) Concat(a, b string) (ret string, err error) { 25 | 26 | defer func(begin time.Time) { 27 | mw.logger.Log( 28 | "function", "Concat", 29 | "a", a, 30 | "b", b, 31 | "result", ret, 32 | "took", time.Since(begin), 33 | ) 34 | }(time.Now()) 35 | 36 | ret, err = mw.Service.Concat(a, b) 37 | return ret, err 38 | } 39 | 40 | func (mw loggingMiddleware) Diff(ctx context.Context, a, b string) (ret string, err error) { 41 | 42 | defer func(begin time.Time) { 43 | mw.logger.Log( 44 | "function", "Diff", 45 | "a", a, 46 | "b", b, 47 | "result", ret, 48 | "took", time.Since(begin), 49 | ) 50 | }(time.Now()) 51 | 52 | ret, err = mw.Service.Diff(ctx, a, b) 53 | return ret, err 54 | } 55 | 56 | func (mw loggingMiddleware) HealthCheck() (result bool) { 57 | defer func(begin time.Time) { 58 | mw.logger.Log( 59 | "function", "HealthChcek", 60 | "result", result, 61 | "took", time.Since(begin), 62 | ) 63 | }(time.Now()) 64 | result = mw.Service.HealthCheck() 65 | return 66 | } 67 | -------------------------------------------------------------------------------- /ch10-resiliency/string-service/service/service.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "errors" 5 | "strings" 6 | ) 7 | 8 | // Service constants 9 | const ( 10 | StrMaxSize = 1024 11 | ) 12 | 13 | // Service errors 14 | var ( 15 | ErrMaxSize = errors.New("maximum size of 1024 bytes exceeded") 16 | 17 | ErrStrValue = errors.New("maximum size of 1024 bytes exceeded") 18 | ) 19 | 20 | // Service Define a service interface 21 | type Service interface { 22 | // Concat a and b 23 | Concat(a, b string) (string, error) 24 | 25 | // a,b pkg string value 26 | Diff(a, b string) (string, error) 27 | 28 | // HealthCheck check service health status 29 | HealthCheck() bool 30 | } 31 | 32 | //ArithmeticService implement Service interface 33 | type StringService struct { 34 | } 35 | 36 | func (s StringService) Concat(a, b string) (string, error) { 37 | // test for length overflow 38 | if len(a)+len(b) > StrMaxSize { 39 | return "", ErrMaxSize 40 | } 41 | return a + b, nil 42 | } 43 | 44 | func (s StringService) Diff(a, b string) (string, error) { 45 | if len(a) < 1 || len(b) < 1 { 46 | return "", nil 47 | } 48 | res := "" 49 | if len(a) >= len(b) { 50 | for _, char := range b { 51 | if strings.Contains(a, string(char)) { 52 | res = res + string(char) 53 | } 54 | } 55 | } else { 56 | for _, char := range a { 57 | if strings.Contains(b, string(char)) { 58 | res = res + string(char) 59 | } 60 | } 61 | } 62 | return res, nil 63 | } 64 | 65 | // HealthCheck implement Service method 66 | // 用于检查服务的健康状态,这里仅仅返回true。 67 | func (s StringService) HealthCheck() bool { 68 | return true 69 | } 70 | 71 | // ServiceMiddleware define service middleware 72 | type ServiceMiddleware func(Service) Service 73 | -------------------------------------------------------------------------------- /ch12-trace/zipkin-go/string-services/README.md: -------------------------------------------------------------------------------- 1 | ## Zipkin tracing using OpenTracing API 2 | 3 | This directory contains a super simple command line client and two HTTP services 4 | which are instrumented using the OpenTracing API using the 5 | [zipkin-go-opentracing](https://github.com/openzipkin-contrib/zipkin-go-opentracing) 6 | tracer. 7 | 8 | The code is a quick hack to solely demonstrate the usage of 9 | [OpenTracing](http://opentracing.io) with a [Zipkin](http://zipkin.io) backend. 10 | 11 | ``` 12 | note: the examples will only compile with Go 1.7 or higher 13 | ``` 14 | 15 | ## Usage: 16 | 17 | Build `svc1`, `svc2` and `cli` with `make` and start both compiled services 18 | found in the newly created `build` subdirectory. 19 | 20 | When you call the `cli` program it will trigger two calls to `svc1` of which one 21 | call will be proxied from `svc1` over to `svc2` to handle the method and by that 22 | generating a couple of spans across services. 23 | 24 | Methods have been instrumented with some examples of 25 | [OpenTracing](http://opentracing.io) Tags which will be transformed into 26 | [Zipkin](http://zipkin.io) binary annotations and 27 | [OpenTracing](http://opentracing.io) LogEvents which will be transformed into 28 | [Zipkin](http://zipkin.io) annotations. 29 | 30 | The most interesting piece of code is found in `examples/middleware` which is 31 | kind of the missing link for people looking for a tracing framework. I advise 32 | you to seriously look into using [Go kit](https://gokit.io) and use its 33 | abstractions and OpenTracing middleware with which this Tracer is fully 34 | compatible, instead of rolling your own. If you still want to roll your own you 35 | can use `examples/middleware` as a starting point. 36 | -------------------------------------------------------------------------------- /ch6-discovery/string-service/service/service.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "errors" 5 | "strings" 6 | ) 7 | 8 | // Service constants 9 | const ( 10 | StrMaxSize = 1024 11 | ) 12 | 13 | // Service errors 14 | var ( 15 | ErrMaxSize = errors.New("maximum size of 1024 bytes exceeded") 16 | 17 | ErrStrValue = errors.New("maximum size of 1024 bytes exceeded") 18 | ) 19 | 20 | // Service Define a service interface 21 | type Service interface { 22 | // Concat a and b 23 | Concat(a, b string) (string, error) 24 | 25 | // a,b pkg string value 26 | Diff(a, b string) (string, error) 27 | 28 | // HealthCheck check service health status 29 | HealthCheck() bool 30 | } 31 | 32 | //ArithmeticService implement Service interface 33 | type StringService struct { 34 | } 35 | 36 | func (s StringService) Concat(a, b string) (string, error) { 37 | // test for length overflow 38 | if len(a)+len(b) > StrMaxSize { 39 | return "", ErrMaxSize 40 | } 41 | return a + b, nil 42 | } 43 | 44 | func (s StringService) Diff(a, b string) (string, error) { 45 | if len(a) < 1 || len(b) < 1 { 46 | return "", nil 47 | } 48 | res := "" 49 | if len(a) >= len(b) { 50 | for _, char := range b { 51 | if strings.Contains(a, string(char)) { 52 | res = res + string(char) 53 | } 54 | } 55 | } else { 56 | for _, char := range a { 57 | if strings.Contains(b, string(char)) { 58 | res = res + string(char) 59 | } 60 | } 61 | } 62 | return res, nil 63 | } 64 | 65 | // HealthCheck implement Service method 66 | // 用于检查服务的健康状态,这里仅仅返回true。 67 | func (s StringService) HealthCheck() bool { 68 | return true 69 | } 70 | 71 | // ServiceMiddleware define service middleware 72 | type ServiceMiddleware func(Service) Service 73 | -------------------------------------------------------------------------------- /ch12-trace/zipkin-kit/string-service/service/service.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "strings" 7 | ) 8 | 9 | // Service constants 10 | const ( 11 | StrMaxSize = 1024 12 | ) 13 | 14 | // Service errors 15 | var ( 16 | ErrMaxSize = errors.New("maximum size of 1024 bytes exceeded") 17 | 18 | ErrStrValue = errors.New("error str value to Integer") 19 | ) 20 | 21 | // Service Define a service interface 22 | type Service interface { 23 | // Concat a and b 24 | Concat(a, b string) (string, error) 25 | 26 | // a,b pkg string value 27 | Diff(ctx context.Context, a, b string) (string, error) 28 | 29 | // HealthCheck check service health status 30 | HealthCheck() bool 31 | } 32 | 33 | //ArithmeticService implement Service interface 34 | type StringService struct { 35 | } 36 | 37 | func (s StringService) Concat(a, b string) (string, error) { 38 | // test for length overflow 39 | if len(a)+len(b) > StrMaxSize { 40 | return "", ErrMaxSize 41 | } 42 | return a + b, nil 43 | } 44 | 45 | func (s StringService) Diff(ctx context.Context, a, b string) (string, error) { 46 | if len(a) < 1 || len(b) < 1 { 47 | return "", nil 48 | } 49 | res := "" 50 | if len(a) >= len(b) { 51 | for _, char := range b { 52 | if strings.Contains(a, string(char)) { 53 | res = res + string(char) 54 | } 55 | } 56 | } else { 57 | for _, char := range a { 58 | if strings.Contains(b, string(char)) { 59 | res = res + string(char) 60 | } 61 | } 62 | } 63 | return res, nil 64 | } 65 | 66 | // HealthCheck implement Service method 67 | // 用于检查服务的健康状态,这里仅仅返回true。 68 | func (s StringService) HealthCheck() bool { 69 | return true 70 | } 71 | 72 | // ServiceMiddleware define service middleware 73 | type ServiceMiddleware func(Service) Service 74 | -------------------------------------------------------------------------------- /ch12-trace/zipkin-go/string-services/svc2/httpserver.go: -------------------------------------------------------------------------------- 1 | // +build go1.7 2 | 3 | package svc2 4 | 5 | import ( 6 | "fmt" 7 | "net/http" 8 | "strconv" 9 | 10 | opentracing "github.com/opentracing/opentracing-go" 11 | 12 | "github.com/openzipkin-contrib/zipkin-go-opentracing/examples/middleware" 13 | ) 14 | 15 | type httpService struct { 16 | service Service 17 | } 18 | 19 | // sumHandler is our HTTP Handlerfunc for a Sum request. 20 | func (s *httpService) sumHandler(w http.ResponseWriter, req *http.Request) { 21 | // parse query parameters 22 | v := req.URL.Query() 23 | a, err := strconv.ParseInt(v.Get("a"), 10, 64) 24 | if err != nil { 25 | http.Error(w, err.Error(), http.StatusBadRequest) 26 | return 27 | } 28 | b, err := strconv.ParseInt(v.Get("b"), 10, 64) 29 | if err != nil { 30 | http.Error(w, err.Error(), http.StatusBadRequest) 31 | return 32 | } 33 | // call our Sum binding 34 | result, err := s.service.Sum(req.Context(), a, b) 35 | if err != nil { 36 | http.Error(w, err.Error(), http.StatusBadRequest) 37 | return 38 | } 39 | // return the result 40 | w.Write([]byte(fmt.Sprintf("%d", result))) 41 | } 42 | 43 | // NewHTTPHandler returns a new HTTP handler our svc2. 44 | func NewHTTPHandler(tracer opentracing.Tracer, service Service) http.Handler { 45 | // Create our HTTP Service. 46 | svc := &httpService{service: service} 47 | 48 | // Create the mux. 49 | mux := http.NewServeMux() 50 | 51 | // Create the Sum handler. 52 | var sumHandler http.Handler 53 | sumHandler = http.HandlerFunc(svc.sumHandler) 54 | 55 | // Wrap the Sum handler with our tracing middleware. 56 | sumHandler = middleware.FromHTTPRequest(tracer, "Sum")(sumHandler) 57 | 58 | // Wire up the mux. 59 | mux.Handle("/sum/", sumHandler) 60 | 61 | // Return the mux. 62 | return mux 63 | } 64 | -------------------------------------------------------------------------------- /ch13-seckill/sk-admin/setup/zk_test.go: -------------------------------------------------------------------------------- 1 | package setup 2 | 3 | import ( 4 | "fmt" 5 | conf "github.com/longjoy/micro-go-book/ch13-seckill/pkg/config" 6 | "github.com/samuel/go-zookeeper/zk" 7 | "log" 8 | "testing" 9 | "time" 10 | ) 11 | 12 | func ZkStateStringFormat(s *zk.Stat) string { 13 | return fmt.Sprintf("Czxid:%d\nMzxid: %d\nCtime: %d\nMtime: %d\nVersion: %d\nCversion: %d\nAversion: %d\nEphemeralOwner: %d\nDataLength: %d\nNumChildren: %d\nPzxid: %d\n", 14 | s.Czxid, s.Mzxid, s.Ctime, s.Mtime, s.Version, s.Cversion, s.Aversion, s.EphemeralOwner, s.DataLength, s.NumChildren, s.Pzxid) 15 | } 16 | 17 | func waitSecProductEvent(event zk.Event) { 18 | log.Print(">>>>>>>>>>>>>>>>>>>") 19 | log.Println("path:", event.Path) 20 | log.Println("type:", event.Type.String()) 21 | log.Println("state:", event.State.String()) 22 | log.Println("<<<<<<<<<<<<<<<<<<<") 23 | if event.Path == conf.Zk.SecProductKey { 24 | 25 | } 26 | } 27 | 28 | func TestInitZK(t *testing.T) { 29 | var hosts = []string{"39.98.179.73:2181"} 30 | option := zk.WithEventCallback(waitSecProductEvent) 31 | conn, _, err := zk.Connect(hosts, time.Second*5, option) 32 | if err != nil { 33 | fmt.Println(err) 34 | return 35 | } 36 | 37 | var path = "/zk_test_g1o" 38 | var data = []byte("hello") 39 | var flags int32 = 0 40 | // permission 41 | var acls = zk.WorldACL(zk.PermAll) 42 | 43 | // create 44 | p, err_create := conn.Create(path, data, flags, acls) 45 | if err_create != nil { 46 | fmt.Println(err_create) 47 | return 48 | } 49 | fmt.Println("created:", p) 50 | 51 | // get 52 | v, s, err := conn.Get(path) 53 | if err != nil { 54 | fmt.Println(err) 55 | return 56 | } 57 | 58 | fmt.Printf("value of path[%s]=[%s].\n", path, v) 59 | fmt.Printf("state:\n") 60 | fmt.Printf("%s\n", ZkStateStringFormat(s)) 61 | 62 | defer conn.Close() 63 | } 64 | -------------------------------------------------------------------------------- /ch9-gateway/string-service/endpoints.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "github.com/go-kit/kit/endpoint" 7 | "strings" 8 | ) 9 | 10 | // CalculateEndpoint define endpoint 11 | type StringEndpoints struct { 12 | StringEndpoint endpoint.Endpoint 13 | HealthCheckEndpoint endpoint.Endpoint 14 | } 15 | 16 | var ( 17 | ErrInvalidRequestType = errors.New("RequestType has only two type: Concat, Diff") 18 | ) 19 | 20 | // StringRequest define request struct 21 | type StringRequest struct { 22 | RequestType string `json:"request_type"` 23 | A string `json:"a"` 24 | B string `json:"b"` 25 | } 26 | 27 | // StringResponse define response struct 28 | type StringResponse struct { 29 | Result string `json:"result"` 30 | Error error `json:"error"` 31 | } 32 | 33 | // MakeStringEndpoint make endpoint 34 | func MakeStringEndpoint(svc Service) endpoint.Endpoint { 35 | return func(ctx context.Context, request interface{}) (response interface{}, err error) { 36 | req := request.(StringRequest) 37 | 38 | var ( 39 | res, a, b string 40 | opError error 41 | ) 42 | 43 | a = req.A 44 | b = req.B 45 | 46 | if strings.EqualFold(req.RequestType, "Concat") { 47 | res, _ = svc.Concat(a, b) 48 | } else if strings.EqualFold(req.RequestType, "Diff") { 49 | res, _ = svc.Diff(a, b) 50 | } else { 51 | return nil, ErrInvalidRequestType 52 | } 53 | 54 | return StringResponse{Result: res, Error: opError}, nil 55 | } 56 | } 57 | 58 | // HealthRequest 健康检查请求结构 59 | type HealthRequest struct{} 60 | 61 | // HealthResponse 健康检查响应结构 62 | type HealthResponse struct { 63 | Status bool `json:"status"` 64 | } 65 | 66 | // MakeHealthCheckEndpoint 创建健康检查Endpoint 67 | func MakeHealthCheckEndpoint(svc Service) endpoint.Endpoint { 68 | return func(ctx context.Context, request interface{}) (response interface{}, err error) { 69 | status := svc.HealthCheck() 70 | return HealthResponse{status}, nil 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /ch7-rpc/stream/string-service/service.go: -------------------------------------------------------------------------------- 1 | package string_service 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "github.com/longjoy/micro-go-book/ch7-rpc/stream-pb" 7 | "io" 8 | "log" 9 | "strings" 10 | ) 11 | 12 | const ( 13 | StrMaxSize = 1024 14 | ) 15 | 16 | // Service errors 17 | var ( 18 | ErrMaxSize = errors.New("maximum size of 1024 bytes exceeded") 19 | 20 | ErrStrValue = errors.New("maximum size of 1024 bytes exceeded") 21 | ) 22 | 23 | type StringService struct{} 24 | 25 | func (s *StringService) LotsOfServerStream(req *stream_pb.StringRequest, qs stream_pb.StringService_LotsOfServerStreamServer) error { 26 | response := stream_pb.StringResponse{Ret: req.A + req.B} 27 | for i := 0; i < 10; i++ { 28 | qs.Send(&response) 29 | } 30 | return nil 31 | } 32 | 33 | func (s *StringService) LotsOfClientStream(qs stream_pb.StringService_LotsOfClientStreamServer) error { 34 | var params []string 35 | for { 36 | in, err := qs.Recv() 37 | if err == io.EOF { 38 | qs.SendAndClose(&stream_pb.StringResponse{Ret: strings.Join(params, "")}) 39 | return nil 40 | } 41 | if err != nil { 42 | log.Printf("failed to recv: %v", err) 43 | return err 44 | } 45 | params = append(params, in.A, in.B) 46 | } 47 | } 48 | func (s *StringService) LotsOfServerAndClientStream(qs stream_pb.StringService_LotsOfServerAndClientStreamServer) error { 49 | for { 50 | in, err := qs.Recv() 51 | if err == io.EOF { 52 | return nil 53 | } 54 | if err != nil { 55 | log.Printf("failed to recv %v", err) 56 | return err 57 | } 58 | qs.Send(&stream_pb.StringResponse{Ret: in.A + in.B}) 59 | } 60 | return nil 61 | } 62 | 63 | func (s *StringService) Concat(ctx context.Context, req *stream_pb.StringRequest) (*stream_pb.StringResponse, error) { 64 | if len(req.A)+len(req.B) > StrMaxSize { 65 | response := stream_pb.StringResponse{Ret: ""} 66 | return &response, nil 67 | } 68 | response := stream_pb.StringResponse{Ret: req.A + req.B} 69 | return &response, nil 70 | } 71 | -------------------------------------------------------------------------------- /ch13-seckill/sk-app/service/srv_redis/redis_proc.go: -------------------------------------------------------------------------------- 1 | package srv_redis 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | conf "github.com/longjoy/micro-go-book/ch13-seckill/pkg/config" 7 | "github.com/longjoy/micro-go-book/ch13-seckill/sk-app/config" 8 | "github.com/longjoy/micro-go-book/ch13-seckill/sk-app/model" 9 | "log" 10 | "time" 11 | ) 12 | 13 | //写数据到Redis 14 | func WriteHandle() { 15 | for { 16 | fmt.Println("wirter data to redis.") 17 | req := <-config.SkAppContext.SecReqChan 18 | fmt.Println("accessTime : ", req.AccessTime) 19 | conn := conf.Redis.RedisConn 20 | 21 | data, err := json.Marshal(req) 22 | if err != nil { 23 | log.Printf("json.Marshal req failed. Error : %v, req : %v", err, req) 24 | continue 25 | } 26 | 27 | err = conn.LPush(conf.Redis.Proxy2layerQueueName, string(data)).Err() 28 | if err != nil { 29 | log.Printf("lpush req failed. Error : %v, req : %v", err, req) 30 | continue 31 | } 32 | log.Printf("lpush req success. req : %v", string(data)) 33 | } 34 | } 35 | 36 | //从redis读取数据 37 | func ReadHandle() { 38 | for { 39 | conn := conf.Redis.RedisConn 40 | //阻塞弹出 41 | data, err := conn.BRPop(time.Second, conf.Redis.Layer2proxyQueueName).Result() 42 | if err != nil { 43 | continue 44 | } 45 | 46 | var result *model.SecResult 47 | err = json.Unmarshal([]byte(data[1]), &result) 48 | if err != nil { 49 | log.Printf("json.Unmarshal failed. Error : %v", err) 50 | continue 51 | } 52 | 53 | userKey := fmt.Sprintf("%d_%d", result.UserId, result.ProductId) 54 | fmt.Println("userKey : ", userKey) 55 | config.SkAppContext.UserConnMapLock.Lock() 56 | resultChan, ok := config.SkAppContext.UserConnMap[userKey] 57 | config.SkAppContext.UserConnMapLock.Unlock() 58 | if !ok { 59 | log.Printf("user not found : %v", userKey) 60 | continue 61 | } 62 | log.Printf("request result send to chan") 63 | 64 | resultChan <- result 65 | log.Printf("request result send to chan succeee, userKey : %v", userKey) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /ch9-gateway/string-service/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "flag" 6 | "fmt" 7 | "github.com/go-kit/kit/log" 8 | "net/http" 9 | "os" 10 | "os/signal" 11 | "syscall" 12 | ) 13 | 14 | func main() { 15 | 16 | var ( 17 | consulHost = flag.String("consul.host", "114.67.98.210", "consul ip address") 18 | consulPort = flag.String("consul.port", "8500", "consul port") 19 | serviceHost = flag.String("service.host", "localhost", "service ip address") 20 | servicePort = flag.String("service.port", "8080", "service port") 21 | ) 22 | 23 | flag.Parse() 24 | 25 | ctx := context.Background() 26 | errChan := make(chan error) 27 | 28 | var logger log.Logger 29 | { 30 | logger = log.NewLogfmtLogger(os.Stderr) 31 | logger = log.With(logger, "ts", log.DefaultTimestampUTC) 32 | logger = log.With(logger, "caller", log.DefaultCaller) 33 | } 34 | 35 | var svc Service 36 | svc = StringService{} 37 | 38 | // add logging middleware 39 | svc = LoggingMiddleware(logger)(svc) 40 | 41 | endpoint := MakeStringEndpoint(svc) 42 | 43 | //创建健康检查的Endpoint 44 | healthEndpoint := MakeHealthCheckEndpoint(svc) 45 | 46 | //把算术运算Endpoint和健康检查Endpoint封装至StringEndpoints 47 | endpts := StringEndpoints{ 48 | StringEndpoint: endpoint, 49 | HealthCheckEndpoint: healthEndpoint, 50 | } 51 | 52 | //创建http.Handler 53 | r := MakeHttpHandler(ctx, endpts, logger) 54 | 55 | //创建注册对象 56 | //TODO replace with pkg consul 57 | registar := Register(*consulHost, *consulPort, *serviceHost, *servicePort, logger) 58 | 59 | go func() { 60 | fmt.Println("Http Server start at port:" + *servicePort) 61 | //启动前执行注册 62 | registar.Register() 63 | handler := r 64 | errChan <- http.ListenAndServe(":"+*servicePort, handler) 65 | }() 66 | 67 | go func() { 68 | c := make(chan os.Signal, 1) 69 | signal.Notify(c, syscall.SIGINT, syscall.SIGTERM) 70 | errChan <- fmt.Errorf("%s", <-c) 71 | }() 72 | 73 | error := <-errChan 74 | //服务退出取消注册 75 | registar.Deregister() 76 | fmt.Println(error) 77 | } 78 | -------------------------------------------------------------------------------- /ch4-feature/concurrency/channel.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "os" 7 | "time" 8 | ) 9 | 10 | func printInput(ch chan string) { 11 | 12 | 13 | // 使用 for 循环从 channel 中读取数据 14 | for val := range ch{ 15 | // 读取到结束符号 16 | if val == "EOF"{ 17 | break 18 | } 19 | fmt.Printf("Input is %s\n", val) 20 | } 21 | 22 | 23 | } 24 | 25 | func consume(ch chan int) { 26 | 27 | // 线程休息 100s 再从 channel 读取数据 28 | time.Sleep(time.Second * 100) 29 | <- ch 30 | 31 | } 32 | 33 | 34 | 35 | func main() { 36 | 37 | // 创建一个无缓冲的 channel 38 | ch := make(chan string) 39 | go printInput(ch) 40 | 41 | // 从命令行读取输入 42 | scanner := bufio.NewScanner(os.Stdin) 43 | for scanner.Scan() { 44 | val := scanner.Text() 45 | ch <- val 46 | if val == "EOF"{ 47 | fmt.Println("End the game!") 48 | break 49 | } 50 | } 51 | // 程序最后关闭 ch 52 | defer close(ch) 53 | 54 | 55 | //// 创建一个长度为 2 的 channel 56 | //ch := make(chan int, 2) 57 | //go consume(ch) 58 | // 59 | //ch <- 0 60 | //ch <- 1 61 | //// 发送数据不被阻塞 62 | //fmt.Println("I am free!") 63 | //ch <- 2 64 | //fmt.Println("I can not go there within 100s!") 65 | // 66 | //time.Sleep(time.Second) 67 | 68 | 69 | //ch1 := make(chan int) 70 | //ch2 := make(chan int) 71 | // 72 | //go send(ch1, 0) 73 | //go send(ch2, 10) 74 | // 75 | //// 主 goroutine 休眠 1s,保证调度成功 76 | //time.Sleep(time.Second) 77 | // 78 | //for { 79 | // select { 80 | // case val := <- ch1: // 从 ch1 读取数据 81 | // fmt.Printf("get value %d from ch1\n", val) 82 | // case val := <- ch2 : // 从 ch2 读取数据 83 | // fmt.Printf("get value %d from ch2\n", val) 84 | // case <-time.After(2 * time.Second): // 超时设置 85 | // fmt.Println("Time out") 86 | // return 87 | // } 88 | //} 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | } 97 | 98 | func send(ch chan int, begin int ) { 99 | 100 | for i :=begin ; i< begin + 10 ;i++{ 101 | ch <- i 102 | 103 | } 104 | 105 | } 106 | -------------------------------------------------------------------------------- /ch13-seckill/sk-app/plugins/logging.go: -------------------------------------------------------------------------------- 1 | package plugins 2 | 3 | import ( 4 | "github.com/go-kit/kit/log" 5 | "github.com/longjoy/micro-go-book/ch13-seckill/sk-app/model" 6 | "github.com/longjoy/micro-go-book/ch13-seckill/sk-app/service" 7 | "time" 8 | ) 9 | 10 | // loggingMiddleware Make a new type 11 | // that contains Service interface and logger instance 12 | type skAppLoggingMiddleware struct { 13 | service.Service 14 | logger log.Logger 15 | } 16 | 17 | // LoggingMiddleware make logging middleware 18 | func SkAppLoggingMiddleware(logger log.Logger) service.ServiceMiddleware { 19 | return func(next service.Service) service.Service { 20 | return skAppLoggingMiddleware{next, logger} 21 | } 22 | } 23 | 24 | func (mw skAppLoggingMiddleware) HealthCheck() (result bool) { 25 | defer func(begin time.Time) { 26 | _ = mw.logger.Log( 27 | "function", "HealthChcek", 28 | "result", result, 29 | "took", time.Since(begin), 30 | ) 31 | }(time.Now()) 32 | 33 | result = mw.Service.HealthCheck() 34 | return 35 | } 36 | 37 | func (mw skAppLoggingMiddleware) SecInfo(productId int) map[string]interface{} { 38 | 39 | defer func(begin time.Time) { 40 | _ = mw.logger.Log( 41 | "function", "Check", 42 | "took", time.Since(begin), 43 | ) 44 | }(time.Now()) 45 | 46 | ret := mw.Service.SecInfo(productId) 47 | return ret 48 | } 49 | 50 | func (mw skAppLoggingMiddleware) SecInfoList() ([]map[string]interface{}, int, error) { 51 | 52 | defer func(begin time.Time) { 53 | _ = mw.logger.Log( 54 | "function", "Check", 55 | "took", time.Since(begin), 56 | ) 57 | }(time.Now()) 58 | 59 | data, num, error := mw.Service.SecInfoList() 60 | return data, num, error 61 | } 62 | 63 | func (mw skAppLoggingMiddleware) SecKill(req *model.SecRequest) (map[string]interface{}, int, error) { 64 | defer func(begin time.Time) { 65 | _ = mw.logger.Log( 66 | "function", "Check", 67 | "took", time.Since(begin), 68 | ) 69 | }(time.Now()) 70 | 71 | result, num, error := mw.Service.SecKill(req) 72 | return result, num, error 73 | } 74 | -------------------------------------------------------------------------------- /ch5-web/memory/memory.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "html/template" 6 | "log" 7 | "net/http" 8 | ) 9 | 10 | type User struct { 11 | Id int 12 | Name string 13 | Password string 14 | } 15 | 16 | var UserById = make(map[int]*User) 17 | var UserByName = make(map[string][]*User) 18 | 19 | var tpl = ` 20 | 21 | 22 | 23 | 24 |
25 | 用户名: 26 | 密码: 27 | 28 |
29 | 30 | ` 31 | 32 | func loginMemory(w http.ResponseWriter, r *http.Request) { 33 | fmt.Println("method:", r.Method) //获取请求的方法 34 | if r.Method == "GET" { 35 | var t *template.Template 36 | t = template.New("Products") //创建一个模板 37 | t, _ = t.Parse(tpl) 38 | log.Println(t.Execute(w, nil)) 39 | } else { 40 | //请求的是登录数据,那么执行登录的逻辑判断 41 | _ = r.ParseForm() 42 | fmt.Println("username:", r.Form["username"]) 43 | fmt.Println("password:", r.Form["password"]) 44 | user1 := User{1, r.Form.Get("username"), r.Form.Get("password")} 45 | store(user1) 46 | if pwd := r.Form.Get("password"); pwd == "123456" { // 验证密码是否正确 47 | fmt.Fprintf(w, "欢迎登陆,Hello %s!", r.Form.Get("username")) //这个写入到w的是输出到客户端的 48 | } else { 49 | fmt.Fprintf(w, "密码错误,请重新输入!") 50 | } 51 | } 52 | } 53 | 54 | func store(user User) { 55 | UserById[user.Id] = &user 56 | UserByName[user.Name] = append(UserByName[user.Name], &user) 57 | } 58 | func userInfo(w http.ResponseWriter, r *http.Request) { 59 | fmt.Println(UserById[1]) 60 | r.ParseForm() 61 | 62 | for _, user := range UserByName[r.Form.Get("username")] { 63 | fmt.Println(user) 64 | fmt.Fprintf(w," %v",user ) //这个写入到w的是输出到客户端的 65 | } 66 | } 67 | 68 | func main() { 69 | 70 | http.HandleFunc("/login", loginMemory) //设置访问的路由 71 | http.HandleFunc("/info", userInfo) //设置访问的路由 72 | err := http.ListenAndServe(":8080", nil) //设置监听的端口 73 | if err != nil { 74 | log.Fatal("ListenAndServe: ", err) 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /ch6-discovery/endpoint/endpoints.go: -------------------------------------------------------------------------------- 1 | package endpoint 2 | 3 | import ( 4 | "context" 5 | "github.com/go-kit/kit/endpoint" 6 | "github.com/longjoy/micro-go-book/ch6-discovery/service" 7 | ) 8 | 9 | type DiscoveryEndpoints struct { 10 | SayHelloEndpoint endpoint.Endpoint 11 | DiscoveryEndpoint endpoint.Endpoint 12 | HealthCheckEndpoint endpoint.Endpoint 13 | } 14 | 15 | // 打招呼请求结构体 16 | type SayHelloRequest struct { 17 | } 18 | // 打招呼响应结构体 19 | type SayHelloResponse struct { 20 | Message string `json:"message"` 21 | 22 | } 23 | // 创建打招呼 Endpoint 24 | func MakeSayHelloEndpoint(svc service.Service) endpoint.Endpoint { 25 | return func(ctx context.Context, request interface{}) (response interface{}, err error) { 26 | message := svc.SayHello() 27 | return SayHelloResponse{ 28 | Message:message, 29 | }, nil 30 | } 31 | } 32 | 33 | // 服务发现请求结构体 34 | type DiscoveryRequest struct { 35 | ServiceName string 36 | } 37 | // 服务发现响应结构体 38 | type DiscoveryResponse struct { 39 | Instances []interface{} `json:"instances"` 40 | Error string `json:"error"` 41 | } 42 | // 创建服务发现的 Endpoint 43 | func MakeDiscoveryEndpoint(svc service.Service) endpoint.Endpoint { 44 | return func(ctx context.Context, request interface{}) (response interface{}, err error) { 45 | req := request.(DiscoveryRequest) 46 | instances, err := svc.DiscoveryService(ctx, req.ServiceName) 47 | var errString = "" 48 | if err != nil{ 49 | errString = err.Error() 50 | } 51 | return &DiscoveryResponse{ 52 | Instances:instances, 53 | Error:errString, 54 | }, nil 55 | } 56 | } 57 | 58 | // HealthRequest 健康检查请求结构 59 | type HealthRequest struct{} 60 | // HealthResponse 健康检查响应结构 61 | type HealthResponse struct { 62 | Status bool `json:"status"` 63 | } 64 | // MakeHealthCheckEndpoint 创建健康检查Endpoint 65 | func MakeHealthCheckEndpoint(svc service.Service) endpoint.Endpoint { 66 | return func(ctx context.Context, request interface{}) (response interface{}, err error) { 67 | status := svc.HealthCheck() 68 | return HealthResponse{ 69 | Status:status, 70 | }, nil 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /ch12-trace/zipkin-go/string-services/svc2/cmd/main.go: -------------------------------------------------------------------------------- 1 | // +build go1.7 2 | 3 | package main 4 | 5 | import ( 6 | "fmt" 7 | "github.com/longjoy/micro-go-book/ch12-trace/zipkin-go/string-services/svc2" 8 | "net/http" 9 | "os" 10 | 11 | "github.com/opentracing/opentracing-go" 12 | 13 | zipkin "github.com/openzipkin-contrib/zipkin-go-opentracing" 14 | //"github.com/openzipkin-contrib/zipkin-go-opentracing/examples/string-services/svc2" 15 | ) 16 | 17 | const ( 18 | // Our service name. 19 | serviceName = "svc2" 20 | 21 | // Host + port of our service. 22 | hostPort = "127.0.0.1:61002" 23 | 24 | // Endpoint to send Zipkin spans to. 25 | zipkinHTTPEndpoint = "http://114.67.98.210:9411/api/v1/spans" 26 | 27 | // Debug mode. 28 | debug = false 29 | 30 | // same span can be set to true for RPC style spans (Zipkin V1) vs Node style (OpenTracing) 31 | sameSpan = true 32 | 33 | // make Tracer generate 128 bit traceID's for root spans. 34 | traceID128Bit = true 35 | ) 36 | 37 | //svc2 38 | func main() { 39 | // create collector. 40 | collector, err := zipkin.NewHTTPCollector(zipkinHTTPEndpoint) 41 | if err != nil { 42 | fmt.Printf("unable to create Zipkin HTTP collector: %+v\n", err) 43 | os.Exit(-1) 44 | } 45 | 46 | // create recorder. 47 | recorder := zipkin.NewRecorder(collector, debug, hostPort, serviceName) 48 | 49 | // create tracer. 50 | tracer, err := zipkin.NewTracer( 51 | recorder, 52 | zipkin.ClientServerSameSpan(sameSpan), 53 | zipkin.TraceID128Bit(traceID128Bit), 54 | ) 55 | if err != nil { 56 | fmt.Printf("unable to create Zipkin tracer: %+v\n", err) 57 | os.Exit(-1) 58 | } 59 | 60 | // explicitly set our tracer to be the default tracer. 61 | opentracing.InitGlobalTracer(tracer) 62 | 63 | // create the service implementation 64 | service := svc2.NewService() 65 | 66 | // create the HTTP Server Handler for the service 67 | handler := svc2.NewHTTPHandler(tracer, service) 68 | 69 | // start the service 70 | fmt.Printf("Starting %s on %s\n", serviceName, hostPort) 71 | http.ListenAndServe(hostPort, handler) 72 | } 73 | -------------------------------------------------------------------------------- /ch6-discovery/string-service/endpoint/endpoints.go: -------------------------------------------------------------------------------- 1 | package endpoint 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "github.com/go-kit/kit/endpoint" 7 | "github.com/longjoy/micro-go-book/ch10-resiliency/string-service/service" 8 | "strings" 9 | ) 10 | 11 | // StringEndpoint define endpoint 12 | type StringEndpoints struct { 13 | StringEndpoint endpoint.Endpoint 14 | HealthCheckEndpoint endpoint.Endpoint 15 | } 16 | 17 | 18 | var ( 19 | ErrInvalidRequestType = errors.New("RequestType has only two type: Concat, Diff") 20 | ) 21 | 22 | // StringRequest define request struct 23 | type StringRequest struct { 24 | RequestType string `json:"request_type"` 25 | A string `json:"a"` 26 | B string `json:"b"` 27 | } 28 | 29 | // StringResponse define response struct 30 | type StringResponse struct { 31 | Result string `json:"result"` 32 | Error error `json:"error"` 33 | } 34 | 35 | // MakeStringEndpoint make endpoint 36 | func MakeStringEndpoint(svc service.Service) endpoint.Endpoint { 37 | return func(ctx context.Context, request interface{}) (response interface{}, err error) { 38 | req := request.(StringRequest) 39 | 40 | var ( 41 | res, a, b string 42 | opError error 43 | ) 44 | 45 | a = req.A 46 | b = req.B 47 | // 根据请求操作类型请求具体的操作方法 48 | if strings.EqualFold(req.RequestType, "Concat") { 49 | res, _ = svc.Concat(a, b) 50 | } else if strings.EqualFold(req.RequestType, "Diff") { 51 | res, _ = svc.Diff(a, b) 52 | } else { 53 | return nil, ErrInvalidRequestType 54 | } 55 | 56 | return StringResponse{Result: res, Error: opError}, nil 57 | } 58 | } 59 | 60 | // HealthRequest 健康检查请求结构 61 | type HealthRequest struct{} 62 | 63 | // HealthResponse 健康检查响应结构 64 | type HealthResponse struct { 65 | Status bool `json:"status"` 66 | } 67 | 68 | // MakeHealthCheckEndpoint 创建健康检查Endpoint 69 | func MakeHealthCheckEndpoint(svc service.Service) endpoint.Endpoint { 70 | return func(ctx context.Context, request interface{}) (response interface{}, err error) { 71 | status := svc.HealthCheck() 72 | return HealthResponse{status}, nil 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /ch10-resiliency/string-service/endpoint/endpoints.go: -------------------------------------------------------------------------------- 1 | package endpoint 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "github.com/go-kit/kit/endpoint" 7 | "github.com/longjoy/micro-go-book/ch10-resiliency/string-service/service" 8 | "strings" 9 | ) 10 | 11 | // CalculateEndpoint define endpoint 12 | type StringEndpoints struct { 13 | StringEndpoint endpoint.Endpoint 14 | HealthCheckEndpoint endpoint.Endpoint 15 | } 16 | 17 | 18 | var ( 19 | ErrInvalidRequestType = errors.New("RequestType has only two type: Concat, Diff") 20 | ) 21 | 22 | // StringRequest define request struct 23 | type StringRequest struct { 24 | RequestType string `json:"request_type"` 25 | A string `json:"a"` 26 | B string `json:"b"` 27 | } 28 | 29 | // StringResponse define response struct 30 | type StringResponse struct { 31 | Result string `json:"result"` 32 | Error error `json:"error"` 33 | } 34 | 35 | // MakeStringEndpoint make endpoint 36 | func MakeStringEndpoint(svc service.Service) endpoint.Endpoint { 37 | return func(ctx context.Context, request interface{}) (response interface{}, err error) { 38 | req := request.(StringRequest) 39 | 40 | var ( 41 | res, a, b string 42 | opError error 43 | ) 44 | 45 | a = req.A 46 | b = req.B 47 | // 根据请求操作类型请求具体的操作方法 48 | if strings.EqualFold(req.RequestType, "Concat") { 49 | res, _ = svc.Concat(a, b) 50 | } else if strings.EqualFold(req.RequestType, "Diff") { 51 | res, _ = svc.Diff(a, b) 52 | } else { 53 | return nil, ErrInvalidRequestType 54 | } 55 | 56 | return StringResponse{Result: res, Error: opError}, nil 57 | } 58 | } 59 | 60 | // HealthRequest 健康检查请求结构 61 | type HealthRequest struct{} 62 | 63 | // HealthResponse 健康检查响应结构 64 | type HealthResponse struct { 65 | Status bool `json:"status"` 66 | } 67 | 68 | // MakeHealthCheckEndpoint 创建健康检查Endpoint 69 | func MakeHealthCheckEndpoint(svc service.Service) endpoint.Endpoint { 70 | return func(ctx context.Context, request interface{}) (response interface{}, err error) { 71 | status := svc.HealthCheck() 72 | return HealthResponse{status}, nil 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /ch13-seckill/sk-admin/config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "github.com/go-kit/kit/log" 5 | "github.com/longjoy/micro-go-book/ch13-seckill/pkg/bootstrap" 6 | _ "github.com/longjoy/micro-go-book/ch13-seckill/pkg/bootstrap" 7 | conf "github.com/longjoy/micro-go-book/ch13-seckill/pkg/config" 8 | "github.com/openzipkin/zipkin-go" 9 | zipkinhttp "github.com/openzipkin/zipkin-go/reporter/http" 10 | _ "github.com/openzipkin/zipkin-go/reporter/recorder" 11 | "github.com/spf13/viper" 12 | "os" 13 | ) 14 | 15 | const ( 16 | kConfigType = "CONFIG_TYPE" 17 | ) 18 | 19 | var ZipkinTracer *zipkin.Tracer 20 | var Logger log.Logger 21 | 22 | func init() { 23 | Logger = log.NewLogfmtLogger(os.Stderr) 24 | Logger = log.With(Logger, "ts", log.DefaultTimestampUTC) 25 | Logger = log.With(Logger, "caller", log.DefaultCaller) 26 | viper.AutomaticEnv() 27 | initDefault() 28 | 29 | if err := conf.LoadRemoteConfig(); err != nil { 30 | Logger.Log("Fail to load remote config", err) 31 | } 32 | 33 | if err := conf.Sub("mysql", &conf.MysqlConfig); err != nil { 34 | Logger.Log("Fail to parse mysql", err) 35 | } 36 | if err := conf.Sub("trace", &conf.TraceConfig); err != nil { 37 | Logger.Log("Fail to parse trace", err) 38 | } 39 | zipkinUrl := "http://" + conf.TraceConfig.Host + ":" + conf.TraceConfig.Port + conf.TraceConfig.Url 40 | Logger.Log("zipkin url", zipkinUrl) 41 | } 42 | 43 | func initDefault() { 44 | viper.SetDefault(kConfigType, "yaml") 45 | } 46 | 47 | func initTracer(zipkinURL string) { 48 | var ( 49 | err error 50 | useNoopTracer = zipkinURL == "" 51 | reporter = zipkinhttp.NewReporter(zipkinURL) 52 | ) 53 | //defer reporter.Close() 54 | zEP, _ := zipkin.NewEndpoint(bootstrap.DiscoverConfig.ServiceName, bootstrap.HttpConfig.Port) 55 | ZipkinTracer, err = zipkin.NewTracer( 56 | reporter, zipkin.WithLocalEndpoint(zEP), zipkin.WithNoopTracer(useNoopTracer), 57 | ) 58 | if err != nil { 59 | Logger.Log("err", err) 60 | os.Exit(1) 61 | } 62 | if !useNoopTracer { 63 | Logger.Log("tracer", "Zipkin", "type", "Native", "URL", zipkinURL) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /ch13-seckill/user-service/config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "github.com/go-kit/kit/log" 5 | "github.com/longjoy/micro-go-book/ch13-seckill/pkg/bootstrap" 6 | _ "github.com/longjoy/micro-go-book/ch13-seckill/pkg/bootstrap" 7 | conf "github.com/longjoy/micro-go-book/ch13-seckill/pkg/config" 8 | "github.com/openzipkin/zipkin-go" 9 | zipkinhttp "github.com/openzipkin/zipkin-go/reporter/http" 10 | _ "github.com/openzipkin/zipkin-go/reporter/recorder" 11 | "github.com/spf13/viper" 12 | "os" 13 | ) 14 | 15 | const ( 16 | kConfigType = "CONFIG_TYPE" 17 | ) 18 | 19 | var ZipkinTracer *zipkin.Tracer 20 | var Logger log.Logger 21 | 22 | func init() { 23 | Logger = log.NewLogfmtLogger(os.Stderr) 24 | Logger = log.With(Logger, "ts", log.DefaultTimestampUTC) 25 | Logger = log.With(Logger, "caller", log.DefaultCaller) 26 | viper.AutomaticEnv() 27 | initDefault() 28 | 29 | if err := conf.LoadRemoteConfig(); err != nil { 30 | Logger.Log("Fail to load remote config", err) 31 | } 32 | 33 | if err := conf.Sub("mysql", &conf.MysqlConfig); err != nil { 34 | Logger.Log("Fail to parse mysql", err) 35 | } 36 | if err := conf.Sub("trace", &conf.TraceConfig); err != nil { 37 | Logger.Log("Fail to parse trace", err) 38 | } 39 | zipkinUrl := "http://" + conf.TraceConfig.Host + ":" + conf.TraceConfig.Port + conf.TraceConfig.Url 40 | Logger.Log("zipkin url", zipkinUrl) 41 | initTracer(zipkinUrl) 42 | } 43 | 44 | func initDefault() { 45 | viper.SetDefault(kConfigType, "yaml") 46 | } 47 | 48 | func initTracer(zipkinURL string) { 49 | var ( 50 | err error 51 | useNoopTracer = zipkinURL == "" 52 | reporter = zipkinhttp.NewReporter(zipkinURL) 53 | ) 54 | //defer reporter.Close() 55 | zEP, _ := zipkin.NewEndpoint(bootstrap.DiscoverConfig.ServiceName, bootstrap.HttpConfig.Port) 56 | ZipkinTracer, err = zipkin.NewTracer( 57 | reporter, zipkin.WithLocalEndpoint(zEP), zipkin.WithNoopTracer(useNoopTracer), 58 | ) 59 | if err != nil { 60 | Logger.Log("err", err) 61 | os.Exit(1) 62 | } 63 | if !useNoopTracer { 64 | Logger.Log("tracer", "Zipkin", "type", "Native", "URL", zipkinURL) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /ch13-seckill/oauth-service/config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "github.com/go-kit/kit/log" 5 | "github.com/longjoy/micro-go-book/ch13-seckill/pkg/bootstrap" 6 | _ "github.com/longjoy/micro-go-book/ch13-seckill/pkg/bootstrap" 7 | conf "github.com/longjoy/micro-go-book/ch13-seckill/pkg/config" 8 | "github.com/openzipkin/zipkin-go" 9 | zipkinhttp "github.com/openzipkin/zipkin-go/reporter/http" 10 | _ "github.com/openzipkin/zipkin-go/reporter/recorder" 11 | "github.com/spf13/viper" 12 | "os" 13 | ) 14 | 15 | const ( 16 | kConfigType = "CONFIG_TYPE" 17 | ) 18 | 19 | var ZipkinTracer *zipkin.Tracer 20 | var Logger log.Logger 21 | 22 | func init() { 23 | Logger = log.NewLogfmtLogger(os.Stderr) 24 | Logger = log.With(Logger, "ts", log.DefaultTimestampUTC) 25 | Logger = log.With(Logger, "caller", log.DefaultCaller) 26 | viper.AutomaticEnv() 27 | initDefault() 28 | 29 | if err := conf.LoadRemoteConfig(); err != nil { 30 | Logger.Log("Fail to load remote config", err) 31 | } 32 | 33 | if err := conf.Sub("mysql", &conf.MysqlConfig); err != nil { 34 | Logger.Log("Fail to parse mysql", err) 35 | } 36 | if err := conf.Sub("trace", &conf.TraceConfig); err != nil { 37 | Logger.Log("Fail to parse trace", err) 38 | } 39 | zipkinUrl := "http://" + conf.TraceConfig.Host + ":" + conf.TraceConfig.Port + conf.TraceConfig.Url 40 | Logger.Log("zipkin url", zipkinUrl) 41 | initTracer(zipkinUrl) 42 | } 43 | 44 | func initDefault() { 45 | viper.SetDefault(kConfigType, "yaml") 46 | } 47 | 48 | func initTracer(zipkinURL string) { 49 | var ( 50 | err error 51 | useNoopTracer = zipkinURL == "" 52 | reporter = zipkinhttp.NewReporter(zipkinURL) 53 | ) 54 | //defer reporter.Close() 55 | zEP, _ := zipkin.NewEndpoint(bootstrap.DiscoverConfig.ServiceName, bootstrap.HttpConfig.Port) 56 | ZipkinTracer, err = zipkin.NewTracer( 57 | reporter, zipkin.WithLocalEndpoint(zEP), zipkin.WithNoopTracer(useNoopTracer), 58 | ) 59 | if err != nil { 60 | Logger.Log("err", err) 61 | os.Exit(1) 62 | } 63 | if !useNoopTracer { 64 | Logger.Log("tracer", "Zipkin", "type", "Native", "URL", zipkinURL) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /ch13-seckill/oauth-service/client_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "github.com/longjoy/micro-go-book/ch13-seckill/pb" 7 | "github.com/longjoy/micro-go-book/ch13-seckill/pkg/client" 8 | "testing" 9 | ) 10 | 11 | func TestOauthClientImpl_Check(t *testing.T) { 12 | client, _ := client.NewOAuthClient("user", nil, nil) 13 | 14 | if response, err := client.CheckToken(context.Background(), nil, &pb.CheckTokenRequest{ 15 | Token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVc2VyRGV0YWlscyI6eyJVc2VySWQiOjEsIlVzZXJuYW1lIjoidXNlcm5hbWUiLCJQYXNzd29yZCI6IiIsIkF1dGhvcml0aWVzIjpbIkFkbWluIiwiU3VwZXIiXX0sIkNsaWVudERldGFpbHMiOnsiQ2xpZW50SWQiOiJjbGllbnRJZCIsIkNsaWVudFNlY3JldCI6IiIsIkFjY2Vzc1Rva2VuVmFsaWRpdHlTZWNvbmRzIjoxODAwLCJSZWZyZXNoVG9rZW5WYWxpZGl0eVNlY29uZHMiOjE4MDAwLCJSZWdpc3RlcmVkUmVkaXJlY3RVcmkiOiJodHRwOi8vMTI3LjAuMC4xIiwiQXV0aG9yaXplZEdyYW50VHlwZXMiOlsicGFzc3dvcmQiLCJyZWZyZXNoX3Rva2VuIl19LCJSZWZyZXNoVG9rZW4iOnsiUmVmcmVzaFRva2VuIjpudWxsLCJUb2tlblR5cGUiOiJqd3QiLCJUb2tlblZhbHVlIjoiZXlKaGJHY2lPaUpJVXpJMU5pSXNJblI1Y0NJNklrcFhWQ0o5LmV5SlZjMlZ5UkdWMFlXbHNjeUk2ZXlKVmMyVnlTV1FpT2pFc0lsVnpaWEp1WVcxbElqb2lkWE5sY201aGJXVWlMQ0pRWVhOemQyOXlaQ0k2SWlJc0lrRjFkR2h2Y21sMGFXVnpJanBiSWtGa2JXbHVJaXdpVTNWd1pYSWlYWDBzSWtOc2FXVnVkRVJsZEdGcGJITWlPbnNpUTJ4cFpXNTBTV1FpT2lKamJHbGxiblJKWkNJc0lrTnNhV1Z1ZEZObFkzSmxkQ0k2SWlJc0lrRmpZMlZ6YzFSdmEyVnVWbUZzYVdScGRIbFRaV052Ym1Seklqb3hPREF3TENKU1pXWnlaWE5vVkc5clpXNVdZV3hwWkdsMGVWTmxZMjl1WkhNaU9qRTRNREF3TENKU1pXZHBjM1JsY21Wa1VtVmthWEpsWTNSVmNta2lPaUpvZEhSd09pOHZNVEkzTGpBdU1DNHhJaXdpUVhWMGFHOXlhWHBsWkVkeVlXNTBWSGx3WlhNaU9sc2ljR0Z6YzNkdmNtUWlMQ0p5WldaeVpYTm9YM1J2YTJWdUlsMTlMQ0pTWldaeVpYTm9WRzlyWlc0aU9uc2lVbVZtY21WemFGUnZhMlZ1SWpwdWRXeHNMQ0pVYjJ0bGJsUjVjR1VpT2lJaUxDSlViMnRsYmxaaGJIVmxJam9pSWl3aVJYaHdhWEpsYzFScGJXVWlPbTUxYkd4OUxDSmxlSEFpT2pFMU56TTFOemN6TURRc0ltbHpjeUk2SWxONWMzUmxiU0o5LmJneEdtaGJyVmVVQWljMk1ZRWtmeFJFVFVvVHhPYUZmQXFTa2xoQk50N2ciLCJFeHBpcmVzVGltZSI6IjIwMTktMTEtMTNUMDA6NDg6MjQuMzU2OTY4KzA4OjAwIn0sImV4cCI6MTU3MzU2MTEwNCwiaXNzIjoiU3lzdGVtIn0.CRXA_vadztUpOuKPth7HSb-E4l0otZEr6YNU5ZQcEcc", 16 | }); err == nil { 17 | fmt.Println("Check error", err.Error()) 18 | } else { 19 | fmt.Println("result=", response.ClientDetails.ClientId) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ch13-seckill/user-service/model/user.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "github.com/gohouse/gorose/v2" 5 | "github.com/longjoy/micro-go-book/ch13-seckill/pkg/mysql" 6 | "log" 7 | ) 8 | 9 | type User struct { 10 | UserId int64 `json:"user_id"` //Id 11 | UserName string `json:"user_name"` //用户名称 12 | Password string `json:"password"` //密码 13 | Age int `json:"age"` //年龄 14 | 15 | } 16 | 17 | type UserModel struct { 18 | } 19 | 20 | func NewUserModel() *UserModel { 21 | return &UserModel{} 22 | } 23 | 24 | func (p *UserModel) getTableName() string { 25 | return "user" 26 | } 27 | 28 | func (p *UserModel) GetUserList() ([]gorose.Data, error) { 29 | conn := mysql.DB() 30 | list, err := conn.Table(p.getTableName()).Get() 31 | if err != nil { 32 | log.Printf("Error : %v", err) 33 | return nil, err 34 | } 35 | return list, nil 36 | } 37 | 38 | /*func (p *UserModel) GetUserByUsername(username string) (*User, error) { 39 | 40 | conn := mysql.DB() 41 | if result, err := conn.Table(p.getTableName()).Where(map[string]interface{}{"username": username}).First(); err == nil{ 42 | 43 | }else { 44 | return nil, err 45 | } 46 | 47 | }*/ 48 | 49 | func (p *UserModel) CheckUser(username string, password string) (*User, error) { 50 | conn := mysql.DB() 51 | data, err := conn.Table(p.getTableName()).Where(map[string]interface{}{"user_name": username, "password": password}).First() 52 | if err != nil { 53 | log.Printf("Error : %v", err) 54 | return nil, err 55 | } 56 | user := &User{ 57 | UserId:data["user_id"].(int64), 58 | UserName:data["user_name"].(string), 59 | Password:data["password"].(string), 60 | Age:int(data["age"].(int64)), 61 | 62 | 63 | } 64 | return user, nil 65 | } 66 | 67 | 68 | 69 | func (p *UserModel) CreateUser(user *User) error { 70 | conn := mysql.DB() 71 | _, err := conn.Table(p.getTableName()).Data(map[string]interface{}{ 72 | "user_id": user.UserId, 73 | "user_name": user.UserName, 74 | "password": user.Password, 75 | "age": user.Age, 76 | 77 | }).Insert() 78 | if err != nil { 79 | log.Printf("Error : %v", err) 80 | return err 81 | } 82 | return nil 83 | } 84 | -------------------------------------------------------------------------------- /ch13-seckill/sk-core/setup/zk.go: -------------------------------------------------------------------------------- 1 | package setup 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | conf "github.com/longjoy/micro-go-book/ch13-seckill/pkg/config" 7 | "github.com/samuel/go-zookeeper/zk" 8 | "log" 9 | "time" 10 | ) 11 | 12 | //初始化Etcd 13 | func InitZk() { 14 | var hosts = []string{"39.98.179.73:2181"} 15 | option := zk.WithEventCallback(waitSecProductEvent) 16 | conn, _, err := zk.Connect(hosts, time.Second*5, option) 17 | if err != nil { 18 | fmt.Println(err) 19 | return 20 | } 21 | 22 | conf.Zk.ZkConn = conn 23 | conf.Zk.SecProductKey = "/product" 24 | go loadSecConf(conn) 25 | } 26 | 27 | //加载秒杀商品信息 28 | func loadSecConf(conn *zk.Conn) { 29 | log.Printf("Connect zk sucess %s", conf.Etcd.EtcdSecProductKey) 30 | v, _, err := conn.Get(conf.Zk.SecProductKey) //conf.Etcd.EtcdSecProductKey 31 | if err != nil { 32 | log.Printf("get product info failed, err : %v", err) 33 | return 34 | } 35 | log.Printf("get product info ") 36 | var secProductInfo []*conf.SecProductInfoConf 37 | err1 := json.Unmarshal(v, &secProductInfo) 38 | if err1 != nil { 39 | log.Printf("Unmsharl second product info failed, err : %v", err1) 40 | } 41 | 42 | updateSecProductInfo(secProductInfo) 43 | } 44 | 45 | func waitSecProductEvent(event zk.Event) { 46 | if event.Path == conf.Zk.SecProductKey { 47 | 48 | } 49 | } 50 | 51 | //监听秒杀商品配置 52 | //for wrsp := range rch { 53 | // for _, ev := range wrsp.Events { 54 | // //删除事件 55 | // if ev.Type == mvccpb.DELETE { 56 | // continue 57 | // } 58 | // 59 | // //更新事件 60 | // if ev.Type == mvccpb.PUT && string(ev.Kv.Key) == key { 61 | // err := json.Unmarshal(ev.Kv.Value, &secProductInfo) 62 | // if err != nil { 63 | // getConfSucc = false 64 | // continue 65 | // } 66 | // } 67 | // } 68 | // 69 | // if getConfSucc { 70 | // updateSecProductInfo(secProductInfo) 71 | // } 72 | //} 73 | 74 | //更新秒杀商品信息 75 | func updateSecProductInfo(secProductInfo []*conf.SecProductInfoConf) { 76 | tmp := make(map[int]*conf.SecProductInfoConf, 1024) 77 | for _, v := range secProductInfo { 78 | tmp[v.ProductId] = v 79 | } 80 | conf.SecKill.RWBlackLock.Lock() 81 | conf.SecKill.SecProductInfoMap = tmp 82 | conf.SecKill.RWBlackLock.Unlock() 83 | } 84 | -------------------------------------------------------------------------------- /ch7-rpc/go-kit/string-service/transports.go: -------------------------------------------------------------------------------- 1 | package string_service 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "github.com/go-kit/kit/transport/grpc" 7 | "github.com/longjoy/micro-go-book/ch7-rpc/pb" 8 | ) 9 | 10 | var ( 11 | ErrorBadRequest = errors.New("invalid request parameter") 12 | ) 13 | 14 | type grpcServer struct { 15 | concat grpc.Handler 16 | diff grpc.Handler 17 | } 18 | 19 | func (s *grpcServer) Concat(ctx context.Context, r *pb.StringRequest) (*pb.StringResponse, error) { 20 | _, resp, err := s.concat.ServeGRPC(ctx, r) 21 | if err != nil { 22 | return nil, err 23 | } 24 | return resp.(*pb.StringResponse), nil 25 | } 26 | 27 | func (s *grpcServer) Diff(ctx context.Context, r *pb.StringRequest) (*pb.StringResponse, error) { 28 | _, resp, err := s.diff.ServeGRPC(ctx, r) 29 | if err != nil { 30 | return nil, err 31 | } 32 | return resp.(*pb.StringResponse), nil 33 | } 34 | 35 | func NewStringServer(ctx context.Context, endpoints StringEndpoints) pb.StringServiceServer { 36 | return &grpcServer{ 37 | concat: grpc.NewServer( 38 | endpoints.StringEndpoint, 39 | DecodeConcatStringRequest, 40 | EncodeStringResponse, 41 | ), 42 | diff: grpc.NewServer( 43 | endpoints.StringEndpoint, 44 | DecodeDiffStringRequest, 45 | EncodeStringResponse, 46 | ), 47 | } 48 | } 49 | 50 | func DecodeConcatStringRequest(ctx context.Context, r interface{}) (interface{}, error) { 51 | req := r.(*pb.StringRequest) 52 | return StringRequest{ 53 | RequestType: "Concat", 54 | A: string(req.A), 55 | B: string(req.B), 56 | }, nil 57 | } 58 | 59 | func DecodeDiffStringRequest(ctx context.Context, r interface{}) (interface{}, error) { 60 | req := r.(*pb.StringRequest) 61 | return StringRequest{ 62 | RequestType: "Diff", 63 | A: string(req.A), 64 | B: string(req.B), 65 | }, nil 66 | } 67 | 68 | func EncodeStringResponse(_ context.Context, r interface{}) (interface{}, error) { 69 | resp := r.(StringResponse) 70 | 71 | if resp.Error != nil { 72 | return &pb.StringResponse{ 73 | Ret: resp.Result, 74 | Err: resp.Error.Error(), 75 | }, nil 76 | } 77 | 78 | return &pb.StringResponse{ 79 | Ret: resp.Result, 80 | Err: "", 81 | }, nil 82 | } 83 | -------------------------------------------------------------------------------- /ch5-web/mongo/mongo.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "gopkg.in/mgo.v2" 6 | "gopkg.in/mgo.v2/bson" 7 | "html/template" 8 | "log" 9 | "net/http" 10 | ) 11 | 12 | type User struct { 13 | Id string 14 | Name string 15 | Habits string 16 | CreatedTime string 17 | } 18 | 19 | var tpl = ` 20 | 21 | 22 | 23 | 24 |
25 | 用户名: 26 | 兴趣爱好: 27 | 28 |
29 | 30 | ` 31 | 32 | func connect(cName string) (*mgo.Session, *mgo.Collection) { 33 | session, err := mgo.Dial("mongodb://47.96.140.41:27017/") //Mongodb's connection 34 | checkErr(err) 35 | session.SetMode(mgo.Monotonic, true) 36 | //return a instantiated collect 37 | return session, session.DB("test").C(cName) 38 | } 39 | 40 | func queryByName(name string) []User { 41 | var user []User 42 | s, c := connect("user") 43 | defer s.Close() 44 | err := c.Find(bson.M{"name": name}).All(&user) 45 | checkErr(err) 46 | return user 47 | } 48 | 49 | func checkErr(err error) { 50 | if err != nil { 51 | panic(err) 52 | } 53 | } 54 | 55 | func submitForm(w http.ResponseWriter, r *http.Request) { 56 | fmt.Println("method:", r.Method) //获取请求的方法 57 | var t *template.Template 58 | t = template.New("Products") //创建一个模板 59 | t, _ = t.Parse(tpl) 60 | log.Println(t.Execute(w, nil)) 61 | } 62 | 63 | func store(user User) error { 64 | //插入数据 65 | s, c := connect("user") 66 | defer s.Close() 67 | user.Id = bson.NewObjectId().Hex() 68 | return c.Insert(&user) 69 | } 70 | 71 | func userInfo(w http.ResponseWriter, r *http.Request) { 72 | //请求的是登录数据,那么执行登录的逻辑判断 73 | _ = r.ParseForm() 74 | if r.Method == "POST" { 75 | user1 := User{Name: r.Form.Get("username"), Habits: r.Form.Get("habits")} 76 | store(user1) 77 | fmt.Fprintf(w, " %v", queryByName("aoho")) //这个写入到w的是输出到客户端的 78 | } 79 | } 80 | 81 | func main() { 82 | http.HandleFunc("/form", submitForm) //设置访问的路由 83 | http.HandleFunc("/info", userInfo) //设置访问的路由 84 | err := http.ListenAndServe(":8080", nil) //设置监听的端口 85 | if err != nil { 86 | log.Fatal("ListenAndServe: ", err) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /ch9-gateway/string-service/transports.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "errors" 7 | "github.com/go-kit/kit/log" 8 | kithttp "github.com/go-kit/kit/transport/http" 9 | "github.com/gorilla/mux" 10 | "github.com/prometheus/client_golang/prometheus/promhttp" 11 | "net/http" 12 | ) 13 | 14 | var ( 15 | ErrorBadRequest = errors.New("invalid request parameter") 16 | ) 17 | 18 | // MakeHttpHandler make http handler use mux 19 | func MakeHttpHandler(ctx context.Context, endpoints StringEndpoints, logger log.Logger) http.Handler { 20 | r := mux.NewRouter() 21 | 22 | options := []kithttp.ServerOption{ 23 | kithttp.ServerErrorLogger(logger), 24 | kithttp.ServerErrorEncoder(kithttp.DefaultErrorEncoder), 25 | } 26 | 27 | r.Methods("POST").Path("/op/{type}/{a}/{b}").Handler(kithttp.NewServer( 28 | endpoints.StringEndpoint, 29 | decodeStringRequest, 30 | encodeStringResponse, 31 | options..., 32 | )) 33 | 34 | r.Path("/metrics").Handler(promhttp.Handler()) 35 | 36 | // create health check handler 37 | r.Methods("GET").Path("/health").Handler(kithttp.NewServer( 38 | endpoints.HealthCheckEndpoint, 39 | decodeHealthCheckRequest, 40 | encodeStringResponse, 41 | options..., 42 | )) 43 | 44 | return r 45 | } 46 | 47 | // decodeStringRequest decode request params to struct 48 | func decodeStringRequest(_ context.Context, r *http.Request) (interface{}, error) { 49 | vars := mux.Vars(r) 50 | requestType, ok := vars["type"] 51 | if !ok { 52 | return nil, ErrorBadRequest 53 | } 54 | 55 | pa, ok := vars["a"] 56 | if !ok { 57 | return nil, ErrorBadRequest 58 | } 59 | 60 | pb, ok := vars["b"] 61 | if !ok { 62 | return nil, ErrorBadRequest 63 | } 64 | 65 | return StringRequest{ 66 | RequestType: requestType, 67 | A: pa, 68 | B: pb, 69 | }, nil 70 | } 71 | 72 | // encodeStringResponse encode response to return 73 | func encodeStringResponse(ctx context.Context, w http.ResponseWriter, response interface{}) error { 74 | w.Header().Set("Content-Type", "application/json;charset=utf-8") 75 | return json.NewEncoder(w).Encode(response) 76 | } 77 | 78 | // decodeHealthCheckRequest decode request 79 | func decodeHealthCheckRequest(ctx context.Context, r *http.Request) (interface{}, error) { 80 | return HealthRequest{}, nil 81 | } 82 | -------------------------------------------------------------------------------- /ch8-config/ViperDemo.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "github.com/spf13/viper" 7 | "log" 8 | "reflect" 9 | ) 10 | 11 | var Resume ResumeInformation 12 | 13 | func init() { 14 | viper.AutomaticEnv() 15 | initDefault() 16 | //读取yaml文件 17 | //v := viper.New() 18 | 19 | if err := viper.ReadInConfig(); err != nil { 20 | fmt.Printf("err:%s\n", err) 21 | } 22 | if err := sub("ResumeInformation", &Resume); err != nil { 23 | log.Fatal("Fail to parse config", err) 24 | } 25 | } 26 | func initDefault() { 27 | //设置读取的配置文件 28 | viper.SetConfigName("resume_config") 29 | //添加读取的配置文件路径 30 | viper.AddConfigPath("./ch8-config/config/") 31 | //windows环境下为%GOPATH,linux环境下为$GOPATH 32 | viper.AddConfigPath("$GOPATH/src/") 33 | //设置配置文件类型 34 | viper.SetConfigType("yaml") 35 | } 36 | func main() { 37 | fmt.Printf( 38 | "姓名: %s\n爱好: %s\n性别: %s \n年龄: %d \n", 39 | Resume.Name, 40 | Resume.Habits, 41 | Resume.Sex, 42 | Resume.Age, 43 | ) 44 | //反序列化 45 | parseYaml(viper.GetViper()) 46 | fmt.Println(Contains("Basketball", Resume.Habits)) 47 | } 48 | 49 | func Contains(obj interface{}, target interface{}) (bool, error) { 50 | targetValue := reflect.ValueOf(target) 51 | switch reflect.TypeOf(target).Kind() { 52 | case reflect.Slice, reflect.Array: 53 | for i := 0; i < targetValue.Len(); i++ { 54 | if targetValue.Index(i).Interface() == obj { 55 | return true, nil 56 | } 57 | } 58 | case reflect.Map: 59 | if targetValue.MapIndex(reflect.ValueOf(obj)).IsValid() { 60 | return true, nil 61 | } 62 | } 63 | 64 | return false, errors.New("not in array") 65 | } 66 | 67 | type ResumeInformation struct { 68 | Name string 69 | Sex string 70 | Age int 71 | Habits []interface{} 72 | } 73 | 74 | type ResumeSetting struct { 75 | RegisterTime string 76 | Address string 77 | ResumeInformation ResumeInformation 78 | } 79 | 80 | func parseYaml(v *viper.Viper) { 81 | var resumeConfig ResumeSetting 82 | if err := v.Unmarshal(&resumeConfig); err != nil { 83 | fmt.Printf("err:%s", err) 84 | } 85 | fmt.Println("resume config:\n ", resumeConfig) 86 | } 87 | func sub(key string, value interface{}) error { 88 | log.Printf("配置文件的前缀为:%v", key) 89 | sub := viper.Sub(key) 90 | sub.AutomaticEnv() 91 | sub.SetEnvPrefix(key) 92 | return sub.Unmarshal(value) 93 | } 94 | -------------------------------------------------------------------------------- /ch3-basic/HelloGo.go: -------------------------------------------------------------------------------- 1 | // 每一个可执行的golang程序必定具备一个main包,并在该main包下具有执行函数main的go文件 2 | package main 3 | 4 | // 引入相关依赖 5 | import ( 6 | "bytes" 7 | "encoding/json" 8 | "fmt" 9 | "io/ioutil" 10 | "math/rand" 11 | "net/http" 12 | "time" 13 | ) 14 | 15 | // HelloGo.go 16 | // 基于图灵API一个简单的聊天机器人 17 | 18 | // 请求体结构体 19 | type requestBody struct { 20 | Key string `json:"key"` 21 | Info string `json:"info"` 22 | UserId string `json:"userid"` 23 | } 24 | 25 | 26 | // 结果体结构体 27 | type responseBody struct { 28 | Code int `json:"code"` 29 | Text string `json:"text"` 30 | List []string `json:"list"` 31 | Url string `json:"url"` 32 | } 33 | 34 | // 请求机器人 35 | func process(inputChan <-chan string, userid string) { 36 | for{ 37 | // 从通道中接受输入 38 | input := <- inputChan 39 | if input == "EOF"{ 40 | break 41 | } 42 | // 构建请求体 43 | reqData := &requestBody{ 44 | Key: "792bcf45156d488c92e9d11da494b085", 45 | Info : input, 46 | UserId: userid, 47 | } 48 | // 转义为json 49 | byteData,_ := json.Marshal(&reqData) 50 | // 请求聊天机器人接口 51 | req, err := http.NewRequest("POST", 52 | "http://www.tuling123.com/openapi/api", 53 | bytes.NewReader(byteData)) 54 | 55 | req.Header.Set("Content-Type", "application/json;charset=UTF-8") 56 | 57 | client := http.Client{ 58 | Timeout: 2 * time.Second, 59 | 60 | } 61 | 62 | resp, err := client.Do(req) 63 | 64 | if err != nil { 65 | fmt.Println("Network Error!") 66 | fmt.Println(err) 67 | }else { 68 | // 将结果从json中解析并输出到命令行 69 | body, _ := ioutil.ReadAll(resp.Body) 70 | var respData responseBody 71 | json.Unmarshal(body, &respData) 72 | fmt.Println("AI: " + respData.Text) 73 | 74 | } 75 | if resp != nil { 76 | resp.Body.Close() 77 | } 78 | } 79 | } 80 | 81 | func main() { 82 | 83 | var input string 84 | fmt.Println("Enter 'EOF' to shut down: ") 85 | // 创建通道 86 | channel := make(chan string) 87 | // main结束时关闭通道 88 | defer close(channel) 89 | // 启动goroutine运行机器人回答线程 90 | go process(channel, string(rand.Int63())) 91 | 92 | for { 93 | // 从命令行中读取输入 94 | fmt.Scanf("%s", &input) 95 | // 将输入放到通道中 96 | channel <- input 97 | // 结束程序 98 | if input == "EOF"{ 99 | fmt.Println("Bye!") 100 | break 101 | } 102 | 103 | } 104 | 105 | } -------------------------------------------------------------------------------- /ch5-web/gin/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/gin-gonic/gin" 6 | "net/http" 7 | ) 8 | 9 | func getApi(c *gin.Context) { 10 | fmt.Println(c.Query("id")) 11 | c.String(http.StatusOK, "ok") 12 | } 13 | 14 | func postApi(c *gin.Context) { 15 | fmt.Println(c.PostForm("id")) 16 | c.String(http.StatusOK, "ok") 17 | } 18 | 19 | func postjson(c *gin.Context) { 20 | var data = &struct { 21 | Name string `json:"title"` 22 | }{} 23 | 24 | c.BindJSON(data) 25 | 26 | fmt.Println(data) 27 | c.String(http.StatusOK, "ok") 28 | 29 | } 30 | 31 | //全局中间件 允许跨域 32 | func GlobalMiddleware(c *gin.Context) { 33 | c.Header("Access-Control-Allow-Origin", "*") 34 | c.Header("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CSRF-Token, Authorization, Token") 35 | c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS") 36 | c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type") 37 | c.Header("Access-Control-Allow-Credentials", "true") 38 | c.Next() 39 | } 40 | func AuthMiddleWare() gin.HandlerFunc { 41 | return func(c *gin.Context) { 42 | token := c.Request.Header.Get("Authorization") 43 | authorized := check(token) //调用认证方法 44 | if authorized { 45 | c.Next() 46 | return 47 | } 48 | c.JSON(http.StatusUnauthorized, gin.H{ 49 | "error": "Unauthorized", 50 | }) 51 | c.Abort() 52 | return 53 | } 54 | } 55 | 56 | func main() { 57 | r := gin.Default() 58 | 59 | r.GET("/home", AuthMiddleWare(), func(c *gin.Context) { 60 | c.JSON(http.StatusOK, gin.H{"data": "home"}) 61 | }) 62 | r.GET("/", func(c *gin.Context) { 63 | c.String(http.StatusOK, "Hello World") 64 | }) 65 | r.GET("/ping", func(c *gin.Context) { 66 | c.JSON(200, gin.H{ 67 | "message": "pong", 68 | }) 69 | }) 70 | r.GET("/user/:name", func(c *gin.Context) { 71 | name := c.Param("name") 72 | c.String(http.StatusOK, "Hello %s", name) 73 | }) 74 | r.GET("/user/:name/*action", func(c *gin.Context) { 75 | name := c.Param("name") 76 | action := c.Param("action") 77 | message := name + " is " + action 78 | c.String(http.StatusOK, message) 79 | }) 80 | r.GET("/getApi", getApi) //注册接口 81 | r.POST("/postApi", postApi) //注册接口 82 | r.POST("/postjson", postjson) //注册接口 83 | //r.Use(GlobalMiddleware) 84 | _ = r.Run(":8000") 85 | } 86 | -------------------------------------------------------------------------------- /ch12-trace/zipkin-go/string-services/svc1/cmd/main.go: -------------------------------------------------------------------------------- 1 | // +build go1.7 2 | 3 | package main 4 | 5 | import ( 6 | "fmt" 7 | "github.com/longjoy/micro-go-book/ch12-trace/zipkin-go/string-services/svc1" 8 | "github.com/longjoy/micro-go-book/ch12-trace/zipkin-go/string-services/svc2" 9 | "net/http" 10 | "os" 11 | 12 | "github.com/opentracing/opentracing-go" 13 | 14 | zipkin "github.com/openzipkin-contrib/zipkin-go-opentracing" 15 | //"github.com/openzipkin-contrib/zipkin-go-opentracing/examples/string-services/svc1" 16 | //"github.com/openzipkin-contrib/zipkin-go-opentracing/examples/string-services/svc2" 17 | ) 18 | 19 | const ( 20 | // Our service name. 21 | serviceName = "svc1" 22 | 23 | // Host + port of our service. 24 | hostPort = "127.0.0.1:61001" 25 | 26 | // Endpoint to send Zipkin spans to. 27 | zipkinHTTPEndpoint = "http://114.67.98.210:9411/api/v1/spans" 28 | 29 | // Debug mode. 30 | debug = false 31 | 32 | // Base endpoint of our SVC2 service. 33 | svc2Endpoint = "http://localhost:61002" 34 | 35 | // same span can be set to true for RPC style spans (Zipkin V1) vs Node style (OpenTracing) 36 | sameSpan = true 37 | 38 | // make Tracer generate 128 bit traceID's for root spans. 39 | traceID128Bit = true 40 | ) 41 | 42 | //svc1 43 | func main() { 44 | // create collector. 45 | collector, err := zipkin.NewHTTPCollector(zipkinHTTPEndpoint) 46 | if err != nil { 47 | fmt.Printf("unable to create Zipkin HTTP collector: %+v\n", err) 48 | os.Exit(-1) 49 | } 50 | 51 | // create recorder. 52 | recorder := zipkin.NewRecorder(collector, debug, hostPort, serviceName) 53 | 54 | // create tracer. 55 | tracer, err := zipkin.NewTracer( 56 | recorder, 57 | zipkin.TraceID128Bit(traceID128Bit), 58 | ) 59 | if err != nil { 60 | fmt.Printf("unable to create Zipkin tracer: %+v\n", err) 61 | os.Exit(-1) 62 | } 63 | 64 | // explicitly set our tracer to be the default tracer. 65 | opentracing.InitGlobalTracer(tracer) 66 | 67 | // create the client to svc2 68 | svc2Client := svc2.NewHTTPClient(tracer, svc2Endpoint) 69 | 70 | // create the service implementation 71 | service := svc1.NewService(svc2Client) 72 | 73 | // create the HTTP Server Handler for the service 74 | handler := svc1.NewHTTPHandler(tracer, service) 75 | 76 | // start the service 77 | fmt.Printf("Starting %s on %s\n", serviceName, hostPort) 78 | http.ListenAndServe(hostPort, handler) 79 | } 80 | -------------------------------------------------------------------------------- /ch12-trace/zipkin-go/string-services/svc2/httpclient.go: -------------------------------------------------------------------------------- 1 | // +build go1.7 2 | 3 | package svc2 4 | 5 | import ( 6 | "context" 7 | "fmt" 8 | "io/ioutil" 9 | "net/http" 10 | "strconv" 11 | 12 | opentracing "github.com/opentracing/opentracing-go" 13 | 14 | "github.com/openzipkin-contrib/zipkin-go-opentracing/examples/middleware" 15 | ) 16 | 17 | // client is our actual client implementation 18 | type client struct { 19 | baseURL string 20 | httpClient *http.Client 21 | tracer opentracing.Tracer 22 | traceRequest middleware.RequestFunc 23 | } 24 | 25 | // Sum implements our Service interface. 26 | func (c *client) Sum(ctx context.Context, a int64, b int64) (int64, error) { 27 | // create new span using span found in context as parent (if none is found, 28 | // our span becomes the trace root). 29 | span, ctx := opentracing.StartSpanFromContext(ctx, "Sum") 30 | defer span.Finish() 31 | 32 | // assemble URL query 33 | url := fmt.Sprintf("%s/sum/?a=%d&b=%d", c.baseURL, a, b) 34 | 35 | // create the HTTP request 36 | req, err := http.NewRequest("GET", url, nil) 37 | if err != nil { 38 | return 0, err 39 | } 40 | 41 | // use our middleware to propagate our trace 42 | req = c.traceRequest(req.WithContext(ctx)) 43 | 44 | // execute the HTTP request 45 | resp, err := c.httpClient.Do(req) 46 | if err != nil { 47 | // annotate our span with the error condition 48 | span.SetTag("error", err.Error()) 49 | return 0, err 50 | } 51 | defer resp.Body.Close() 52 | 53 | // read the http response body 54 | data, err := ioutil.ReadAll(resp.Body) 55 | if err != nil { 56 | // annotate our span with the error condition 57 | span.SetTag("error", err.Error()) 58 | return 0, err 59 | } 60 | 61 | // convert html response to expected result type (int64) 62 | result, err := strconv.ParseInt(string(data), 10, 64) 63 | if err != nil { 64 | // annotate our span with the error condition 65 | span.SetTag("error", err.Error()) 66 | return 0, err 67 | } 68 | 69 | // return the result 70 | return result, nil 71 | } 72 | 73 | // NewHTTPClient returns a new client instance to our svc2 using the HTTP 74 | // transport. 75 | func NewHTTPClient(tracer opentracing.Tracer, baseURL string) Service { 76 | return &client{ 77 | baseURL: baseURL, 78 | httpClient: &http.Client{}, 79 | tracer: tracer, 80 | traceRequest: middleware.ToHTTPRequest(tracer), 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /ch12-trace/zipkin-kit/cmd/client_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "flag" 6 | "fmt" 7 | "github.com/go-kit/kit/log" 8 | kitzipkin "github.com/go-kit/kit/tracing/zipkin" 9 | "github.com/longjoy/micro-go-book/ch12-trace/zipkin-kit/client" 10 | "github.com/openzipkin/zipkin-go" 11 | zipkinhttp "github.com/openzipkin/zipkin-go/reporter/http" 12 | "google.golang.org/grpc" 13 | "os" 14 | "testing" 15 | "time" 16 | ) 17 | 18 | func TestMain(m *testing.M) { 19 | var ( 20 | grpcAddr = flag.String("addr", ":9008", "gRPC address") 21 | serviceHost = flag.String("service.host", "localhost", "service ip address") 22 | servicePort = flag.String("service.port", "8009", "service port") 23 | zipkinURL = flag.String("zipkin.url", "http://114.67.98.210:9411/api/v2/spans", "Zipkin server url") 24 | ) 25 | flag.Parse() 26 | var logger log.Logger 27 | { 28 | logger = log.NewLogfmtLogger(os.Stderr) 29 | logger = log.With(logger, "ts", log.DefaultTimestampUTC) 30 | logger = log.With(logger, "caller", log.DefaultCaller) 31 | } 32 | var zipkinTracer *zipkin.Tracer 33 | { 34 | var ( 35 | err error 36 | hostPort = *serviceHost + ":" + *servicePort 37 | serviceName = "test-service" 38 | useNoopTracer = (*zipkinURL == "") 39 | reporter = zipkinhttp.NewReporter(*zipkinURL) 40 | ) 41 | defer reporter.Close() 42 | zEP, _ := zipkin.NewEndpoint(serviceName, hostPort) 43 | zipkinTracer, err = zipkin.NewTracer( 44 | reporter, zipkin.WithLocalEndpoint(zEP), zipkin.WithNoopTracer(useNoopTracer), 45 | ) 46 | if err != nil { 47 | logger.Log("err", err) 48 | os.Exit(1) 49 | } 50 | if !useNoopTracer { 51 | logger.Log("tracer", "Zipkin", "type", "Native", "URL", *zipkinURL) 52 | } 53 | } 54 | tr := zipkinTracer 55 | parentSpan := tr.StartSpan("test") 56 | defer parentSpan.Flush() 57 | 58 | ctx := zipkin.NewContext(context.Background(), parentSpan) 59 | 60 | clientTracer := kitzipkin.GRPCClientTrace(tr) 61 | conn, err := grpc.Dial(*grpcAddr, grpc.WithInsecure(), grpc.WithTimeout(1*time.Second)) 62 | if err != nil { 63 | fmt.Println("gRPC dial err:", err) 64 | } 65 | defer conn.Close() 66 | 67 | svr := client.StringDiff(conn, clientTracer) 68 | result, err := svr.Diff(ctx, "Add", "ppsdd") 69 | if err != nil { 70 | fmt.Println("Diff error", err.Error()) 71 | 72 | } 73 | 74 | fmt.Println("result =", result) 75 | } 76 | -------------------------------------------------------------------------------- /ch10-resiliency/use-string-service/endpoint/endpoints.go: -------------------------------------------------------------------------------- 1 | package endpoint 2 | 3 | import ( 4 | "context" 5 | "github.com/go-kit/kit/endpoint" 6 | "github.com/longjoy/micro-go-book/ch10-resiliency/use-string-service/service" 7 | ) 8 | 9 | // CalculateEndpoint define endpoint 10 | type UseStringEndpoints struct { 11 | UseStringEndpoint endpoint.Endpoint 12 | HealthCheckEndpoint endpoint.Endpoint 13 | } 14 | 15 | 16 | // StringRequest define request struct 17 | type UseStringRequest struct { 18 | RequestType string `json:"request_type"` 19 | A string `json:"a"` 20 | B string `json:"b"` 21 | } 22 | 23 | // StringResponse define response struct 24 | type UseStringResponse struct { 25 | Result string `json:"result"` 26 | Error string `json:"error"` 27 | } 28 | 29 | //// MakeStringEndpoint make endpoint 30 | //func MakeUseStringEndpoint(svc service.Service) endpoint.Endpoint { 31 | // return func(ctx context.Context, request interface{}) (response interface{}, err error) { 32 | // req := request.(UseStringRequest) 33 | // 34 | // var ( 35 | // res, a, b, opErrorString string 36 | // opError error 37 | // ) 38 | // 39 | // a = req.A 40 | // b = req.B 41 | // 42 | // res, opError = svc.UseStringService(req.RequestType, a, b) 43 | // 44 | // if opError != nil{ 45 | // opErrorString = opError.Error() 46 | // } 47 | // 48 | // return UseStringResponse{Result: res, Error: opErrorString}, nil 49 | // } 50 | //} 51 | 52 | func MakeUseStringEndpoint(svc service.Service) endpoint.Endpoint { 53 | return func(ctx context.Context, request interface{}) (response interface{}, err error) { 54 | req := request.(UseStringRequest) 55 | 56 | var ( 57 | res, a, b string 58 | opError error 59 | ) 60 | 61 | a = req.A 62 | b = req.B 63 | 64 | res, opError = svc.UseStringService(req.RequestType, a, b) 65 | 66 | return UseStringResponse{Result: res}, opError 67 | } 68 | } 69 | 70 | 71 | // HealthRequest 健康检查请求结构 72 | type HealthRequest struct{} 73 | 74 | // HealthResponse 健康检查响应结构 75 | type HealthResponse struct { 76 | Status bool `json:"status"` 77 | } 78 | 79 | // MakeHealthCheckEndpoint 创建健康检查Endpoint 80 | func MakeHealthCheckEndpoint(svc service.Service) endpoint.Endpoint { 81 | return func(ctx context.Context, request interface{}) (response interface{}, err error) { 82 | status := svc.HealthCheck() 83 | return HealthResponse{status}, nil 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /ch7-rpc/stream/client.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "github.com/longjoy/micro-go-book/ch7-rpc/stream-pb" 7 | "google.golang.org/grpc" 8 | "io" 9 | "log" 10 | "strconv" 11 | ) 12 | 13 | func main() { 14 | serviceAddress := "127.0.0.1:1234" 15 | conn, err := grpc.Dial(serviceAddress, grpc.WithInsecure()) 16 | if err != nil { 17 | panic("connect error") 18 | } 19 | defer conn.Close() 20 | stringClient := stream_pb.NewStringServiceClient(conn) 21 | stringReq := &stream_pb.StringRequest{A: "A", B: "B"} 22 | stream, _ := stringClient.LotsOfServerStream(context.Background(), stringReq) 23 | for { 24 | item, stream_error := stream.Recv() 25 | if stream_error == io.EOF { 26 | break 27 | } 28 | if stream_error != nil { 29 | log.Printf("failed to recv: %v", stream_error) 30 | } 31 | fmt.Printf("StringService Concat : %s concat %s = %s\n", stringReq.A, stringReq.B, item.GetRet()) 32 | } 33 | 34 | sendClientStreamRequest(stringClient) 35 | 36 | //sendClientAndServerStreamRequest(stringClient) 37 | } 38 | 39 | func sendClientStreamRequest(client stream_pb.StringServiceClient) { 40 | fmt.Printf("test sendClientStreamRequest \n") 41 | 42 | stream, err := client.LotsOfClientStream(context.Background()) 43 | for i := 0; i < 10; i++ { 44 | if err != nil { 45 | log.Printf("failed to call: %v", err) 46 | break 47 | } 48 | stream.Send(&stream_pb.StringRequest{A: strconv.Itoa(i), B: strconv.Itoa(i + 1)}) 49 | } 50 | reply, err := stream.CloseAndRecv() 51 | if err != nil { 52 | fmt.Printf("failed to recv: %v", err) 53 | } 54 | log.Printf("sendClientStreamRequest ret is : %s", reply.Ret) 55 | } 56 | 57 | func sendClientAndServerStreamRequest(client stream_pb.StringServiceClient) { 58 | fmt.Printf("test sendClientAndServerStreamRequest \n") 59 | var err error 60 | stream, err := client.LotsOfServerAndClientStream(context.Background()) 61 | if err != nil { 62 | log.Printf("failed to call: %v", err) 63 | return 64 | } 65 | var i int 66 | for { 67 | err1 := stream.Send(&stream_pb.StringRequest{A: strconv.Itoa(i), B: strconv.Itoa(i + 1)}) 68 | if err1 != nil { 69 | log.Printf("failed to send: %v", err) 70 | break 71 | } 72 | reply, err2 := stream.Recv() 73 | if err2 != nil { 74 | log.Printf("failed to recv: %v", err) 75 | break 76 | } 77 | log.Printf("sendClientAndServerStreamRequest Ret is : %s", reply.Ret) 78 | i++ 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /ch13-seckill/sk-app/setup/zk.go: -------------------------------------------------------------------------------- 1 | package setup 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | conf "github.com/longjoy/micro-go-book/ch13-seckill/pkg/config" 7 | "github.com/samuel/go-zookeeper/zk" 8 | "log" 9 | "time" 10 | ) 11 | 12 | //初始化Etcd 13 | func InitZk() { 14 | var hosts = []string{"39.98.179.73:2181"} 15 | //option := zk.WithEventCallback(waitSecProductEvent) 16 | conn, _, err := zk.Connect(hosts, time.Second*5) 17 | if err != nil { 18 | fmt.Println(err) 19 | return 20 | } 21 | 22 | conf.Zk.ZkConn = conn 23 | conf.Zk.SecProductKey = "/product" 24 | loadSecConf(conn) 25 | } 26 | 27 | //加载秒杀商品信息 28 | func loadSecConf(conn *zk.Conn) { 29 | log.Printf("Connect zk sucess %s", conf.Zk.SecProductKey) 30 | v, _, err := conn.Get(conf.Zk.SecProductKey) //conf.Etcd.EtcdSecProductKey 31 | if err != nil { 32 | log.Printf("get product info failed, err : %v", err) 33 | return 34 | } 35 | log.Printf("get product info ") 36 | var secProductInfo []*conf.SecProductInfoConf 37 | err1 := json.Unmarshal(v, &secProductInfo) 38 | if err1 != nil { 39 | log.Printf("Unmsharl second product info failed, err : %v", err1) 40 | } 41 | updateSecProductInfo(secProductInfo) 42 | } 43 | 44 | func waitSecProductEvent(event zk.Event) { 45 | log.Print(">>>>>>>>>>>>>>>>>>>") 46 | log.Println("path:", event.Path) 47 | log.Println("type:", event.Type.String()) 48 | log.Println("state:", event.State.String()) 49 | log.Println("<<<<<<<<<<<<<<<<<<<") 50 | if event.Path == conf.Zk.SecProductKey { 51 | 52 | } 53 | } 54 | 55 | //监听秒杀商品配置 56 | //for wrsp := range rch { 57 | // for _, ev := range wrsp.Events { 58 | // //删除事件 59 | // if ev.Type == mvccpb.DELETE { 60 | // continue 61 | // } 62 | // 63 | // //更新事件 64 | // if ev.Type == mvccpb.PUT && string(ev.Kv.Key) == key { 65 | // err := json.Unmarshal(ev.Kv.Value, &secProductInfo) 66 | // if err != nil { 67 | // getConfSucc = false 68 | // continue 69 | // } 70 | // } 71 | // } 72 | // 73 | // if getConfSucc { 74 | // updateSecProductInfo(secProductInfo) 75 | // } 76 | //} 77 | 78 | //更新秒杀商品信息 79 | func updateSecProductInfo(secProductInfo []*conf.SecProductInfoConf) { 80 | tmp := make(map[int]*conf.SecProductInfoConf, 1024) 81 | for _, v := range secProductInfo { 82 | log.Printf("updateSecProductInfo %v", v) 83 | tmp[v.ProductId] = v 84 | } 85 | conf.SecKill.RWBlackLock.Lock() 86 | conf.SecKill.SecProductInfoMap = tmp 87 | conf.SecKill.RWBlackLock.Unlock() 88 | } 89 | -------------------------------------------------------------------------------- /ch12-trace/zipkin-go/string-services/svc2/implementation.go: -------------------------------------------------------------------------------- 1 | // +build go1.7 2 | 3 | package svc2 4 | 5 | import ( 6 | "context" 7 | "time" 8 | 9 | "github.com/opentracing/opentracing-go" 10 | "github.com/opentracing/opentracing-go/ext" 11 | ) 12 | 13 | // svc2 is our actual service implementation. 14 | type svc2 struct{} 15 | 16 | // NewService returns a new implementation of our Service. 17 | func NewService() Service { 18 | return &svc2{} 19 | } 20 | 21 | // Sum implements our Service interface. 22 | func (s *svc2) Sum(ctx context.Context, a int64, b int64) (int64, error) { 23 | // We love starting up slow 24 | time.Sleep(5 * time.Millisecond) 25 | 26 | // Pull span from context. 27 | span := opentracing.SpanFromContext(ctx) 28 | 29 | // Example binary annotations. 30 | span.SetTag("service", "svc2") 31 | span.SetTag("string", "some value") 32 | span.SetTag("int", 123) 33 | span.SetTag("bool", true) 34 | 35 | // Example annotation 36 | span.LogEvent("MyEventAnnotation") 37 | 38 | // Let's wait a little so it shows up nicely in our tracing graphics. 39 | time.Sleep(10 * time.Millisecond) 40 | 41 | // Let's assume we want to trace a call we do to a database. 42 | s.fakeDBCall(span) 43 | 44 | // Check for Int overflow condition. 45 | if (b > 0 && a > (Int64Max-b)) || (b < 0 && a < (Int64Min-b)) { 46 | span.SetTag("error", ErrIntOverflow.Error()) 47 | return 0, ErrIntOverflow 48 | } 49 | 50 | // calculate and return the result (all that boilerplate for this?) ;) 51 | return a + b, nil 52 | } 53 | 54 | func (s *svc2) fakeDBCall(span opentracing.Span) { 55 | resourceSpan := opentracing.StartSpan( 56 | "myComplexQuery", 57 | opentracing.ChildOf(span.Context()), 58 | ) 59 | defer resourceSpan.Finish() 60 | // mark span as resource type 61 | ext.SpanKind.Set(resourceSpan, "resource") 62 | // name of the resource we try to reach 63 | ext.PeerService.Set(resourceSpan, "PostgreSQL") 64 | // hostname of the resource 65 | ext.PeerHostname.Set(resourceSpan, "localhost") 66 | // port of the resource 67 | ext.PeerPort.Set(resourceSpan, 3306) 68 | // let's binary annotate the query we run 69 | resourceSpan.SetTag( 70 | "query", "SELECT recipes FROM cookbook WHERE topic = 'world domination'", 71 | ) 72 | 73 | // Let's assume the query is going to take some time. Finding the right 74 | // world domination recipes is like searching for a needle in a haystack. 75 | time.Sleep(20 * time.Millisecond) 76 | 77 | // sweet... all done 78 | } 79 | -------------------------------------------------------------------------------- /ch10-resiliency/string-service/transport/http.go: -------------------------------------------------------------------------------- 1 | package transport 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "errors" 7 | "github.com/go-kit/kit/log" 8 | "github.com/go-kit/kit/transport" 9 | kithttp "github.com/go-kit/kit/transport/http" 10 | "github.com/gorilla/mux" 11 | "github.com/longjoy/micro-go-book/ch10-resiliency/string-service/endpoint" 12 | "github.com/prometheus/client_golang/prometheus/promhttp" 13 | "net/http" 14 | ) 15 | 16 | var ( 17 | ErrorBadRequest = errors.New("invalid request parameter") 18 | ) 19 | 20 | // MakeHttpHandler make http handler use mux 21 | func MakeHttpHandler(ctx context.Context, endpoints endpoint.StringEndpoints, logger log.Logger) http.Handler { 22 | r := mux.NewRouter() 23 | 24 | options := []kithttp.ServerOption{ 25 | kithttp.ServerErrorHandler(transport.NewLogErrorHandler(logger)), 26 | kithttp.ServerErrorEncoder(kithttp.DefaultErrorEncoder), 27 | } 28 | 29 | r.Methods("POST").Path("/op/{type}/{a}/{b}").Handler(kithttp.NewServer( 30 | endpoints.StringEndpoint, 31 | decodeStringRequest, 32 | encodeStringResponse, 33 | options..., 34 | )) 35 | 36 | r.Path("/metrics").Handler(promhttp.Handler()) 37 | 38 | // create health check handler 39 | r.Methods("GET").Path("/health").Handler(kithttp.NewServer( 40 | endpoints.HealthCheckEndpoint, 41 | decodeHealthCheckRequest, 42 | encodeStringResponse, 43 | options..., 44 | )) 45 | 46 | return r 47 | } 48 | 49 | // decodeStringRequest decode request params to struct 50 | func decodeStringRequest(_ context.Context, r *http.Request) (interface{}, error) { 51 | vars := mux.Vars(r) 52 | requestType, ok := vars["type"] 53 | if !ok { 54 | return nil, ErrorBadRequest 55 | } 56 | 57 | pa, ok := vars["a"] 58 | if !ok { 59 | return nil, ErrorBadRequest 60 | } 61 | 62 | pb, ok := vars["b"] 63 | if !ok { 64 | return nil, ErrorBadRequest 65 | } 66 | 67 | return endpoint.StringRequest{ 68 | RequestType: requestType, 69 | A: pa, 70 | B: pb, 71 | }, nil 72 | } 73 | 74 | // encodeStringResponse encode response to return 75 | func encodeStringResponse(ctx context.Context, w http.ResponseWriter, response interface{}) error { 76 | w.Header().Set("Content-Type", "application/json;charset=utf-8") 77 | return json.NewEncoder(w).Encode(response) 78 | } 79 | 80 | // decodeHealthCheckRequest decode request 81 | func decodeHealthCheckRequest(ctx context.Context, r *http.Request) (interface{}, error) { 82 | return endpoint.HealthRequest{}, nil 83 | } 84 | -------------------------------------------------------------------------------- /ch13-seckill/user-service/endpoint/endpoints.go: -------------------------------------------------------------------------------- 1 | package endpoint 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "github.com/go-kit/kit/endpoint" 7 | "github.com/longjoy/micro-go-book/ch13-seckill/user-service/service" 8 | "reflect" 9 | ) 10 | 11 | type UserEndpoints struct { 12 | UserEndpoint endpoint.Endpoint 13 | HealthCheckEndpoint endpoint.Endpoint 14 | } 15 | 16 | // UserEndpoint define endpoint 17 | func (u *UserEndpoints) Check(ctx context.Context, username string, password string) (int64, error) { 18 | //ctx := context.Background() 19 | reflect.TypeOf(UserEndpoints{}) 20 | resp, err := u.UserEndpoint(ctx, UserRequest{ 21 | Username: username, 22 | Password: password, 23 | }) 24 | response := resp.(UserResponse) 25 | err = errors.New("bad request!") 26 | return response.UserId, err 27 | } 28 | 29 | func (ue *UserEndpoints) HealthCheck() bool { 30 | return false 31 | } 32 | 33 | var ( 34 | ErrInvalidRequestType = errors.New("invalid username, password") 35 | ) 36 | 37 | // UserRequest define request struct 38 | type UserRequest struct { 39 | Username string `json:"username"` 40 | Password string `json:"password"` 41 | } 42 | 43 | // UserResponse define response struct 44 | type UserResponse struct { 45 | Result bool `json:"result"` 46 | UserId int64 `json:"user_id"` 47 | Error error `json:"error"` 48 | } 49 | 50 | // make endpoint 51 | func MakeUserEndpoint(svc service.Service) endpoint.Endpoint { 52 | return func(ctx context.Context, request interface{}) (response interface{}, err error) { 53 | req := request.(UserRequest) 54 | 55 | var ( 56 | username, password string 57 | userId int64 58 | calError error 59 | ) 60 | 61 | username = req.Username 62 | password = req.Password 63 | 64 | userId, calError = svc.Check(ctx, username, password) 65 | if calError != nil { 66 | return UserResponse{Result: false, Error: calError}, nil 67 | } 68 | return UserResponse{Result: true, UserId:userId, Error: calError}, nil 69 | } 70 | } 71 | 72 | // HealthRequest 健康检查请求结构 73 | type HealthRequest struct{} 74 | 75 | // HealthResponse 健康检查响应结构 76 | type HealthResponse struct { 77 | Status bool `json:"status"` 78 | } 79 | 80 | // MakeHealthCheckEndpoint 创建健康检查Endpoint 81 | func MakeHealthCheckEndpoint(svc service.Service) endpoint.Endpoint { 82 | return func(ctx context.Context, request interface{}) (response interface{}, err error) { 83 | status := svc.HealthCheck() 84 | return HealthResponse{status}, nil 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /ch13-seckill/user-service/plugins/instrument.go: -------------------------------------------------------------------------------- 1 | package plugins 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "github.com/go-kit/kit/endpoint" 7 | "github.com/go-kit/kit/metrics" 8 | "github.com/juju/ratelimit" 9 | "github.com/longjoy/micro-go-book/ch13-seckill/user-service/service" 10 | "golang.org/x/time/rate" 11 | "time" 12 | ) 13 | 14 | var ErrLimitExceed = errors.New("Rate limit exceed!") 15 | 16 | // NewTokenBucketLimitterWithJuju 使用juju/ratelimit创建限流中间件 17 | func NewTokenBucketLimitterWithJuju(bkt *ratelimit.Bucket) endpoint.Middleware { 18 | return func(next endpoint.Endpoint) endpoint.Endpoint { 19 | return func(ctx context.Context, request interface{}) (response interface{}, err error) { 20 | if bkt.TakeAvailable(1) == 0 { 21 | return nil, ErrLimitExceed 22 | } 23 | return next(ctx, request) 24 | } 25 | } 26 | } 27 | 28 | // NewTokenBucketLimitterWithBuildIn 使用x/time/rate创建限流中间件 29 | func NewTokenBucketLimitterWithBuildIn(bkt *rate.Limiter) endpoint.Middleware { 30 | return func(next endpoint.Endpoint) endpoint.Endpoint { 31 | return func(ctx context.Context, request interface{}) (response interface{}, err error) { 32 | if !bkt.Allow() { 33 | return nil, ErrLimitExceed 34 | } 35 | return next(ctx, request) 36 | } 37 | } 38 | } 39 | 40 | // metricMiddleware 定义监控中间件,嵌入Service 41 | // 新增监控指标项:requestCount和requestLatency 42 | type metricMiddleware struct { 43 | service.Service 44 | requestCount metrics.Counter 45 | requestLatency metrics.Histogram 46 | } 47 | 48 | // Metrics 封装监控方法 49 | func Metrics(requestCount metrics.Counter, requestLatency metrics.Histogram) service.ServiceMiddleware { 50 | return func(next service.Service) service.Service { 51 | return metricMiddleware{ 52 | next, 53 | requestCount, 54 | requestLatency} 55 | } 56 | } 57 | 58 | func (mw metricMiddleware) Check(ctx context.Context, a, b string) (ret int64, err error) { 59 | 60 | defer func(beign time.Time) { 61 | lvs := []string{"method", "Add"} 62 | mw.requestCount.With(lvs...).Add(1) 63 | mw.requestLatency.With(lvs...).Observe(time.Since(beign).Seconds()) 64 | }(time.Now()) 65 | 66 | ret, err = mw.Service.Check(ctx, a, b) 67 | return ret, err 68 | } 69 | 70 | func (mw metricMiddleware) HealthCheck() (result bool) { 71 | 72 | defer func(begin time.Time) { 73 | lvs := []string{"method", "HealthCheck"} 74 | mw.requestCount.With(lvs...).Add(1) 75 | mw.requestLatency.With(lvs...).Observe(time.Since(begin).Seconds()) 76 | }(time.Now()) 77 | 78 | result = mw.Service.HealthCheck() 79 | return 80 | } 81 | -------------------------------------------------------------------------------- /ch12-trace/zipkin-go/string-services/svc1/httpserver.go: -------------------------------------------------------------------------------- 1 | // +build go1.7 2 | 3 | package svc1 4 | 5 | import ( 6 | "fmt" 7 | "net/http" 8 | "strconv" 9 | 10 | "github.com/opentracing/opentracing-go" 11 | 12 | "github.com/openzipkin-contrib/zipkin-go-opentracing/examples/middleware" 13 | ) 14 | 15 | type httpService struct { 16 | service Service 17 | } 18 | 19 | // concatHandler is our HTTP HandlerFunc for a Concat request. 20 | func (s *httpService) concatHandler(w http.ResponseWriter, req *http.Request) { 21 | // parse query parameters 22 | v := req.URL.Query() 23 | result, err := s.service.Concat(req.Context(), v.Get("a"), v.Get("b")) 24 | if err != nil { 25 | http.Error(w, err.Error(), http.StatusBadRequest) 26 | return 27 | } 28 | // return the result 29 | w.Write([]byte(result)) 30 | } 31 | 32 | // sumHandler is our HTTP Handlerfunc for a Sum request. 33 | func (s *httpService) sumHandler(w http.ResponseWriter, req *http.Request) { 34 | // parse query parameters 35 | v := req.URL.Query() 36 | a, err := strconv.ParseInt(v.Get("a"), 10, 64) 37 | if err != nil { 38 | http.Error(w, err.Error(), http.StatusBadRequest) 39 | return 40 | } 41 | b, err := strconv.ParseInt(v.Get("b"), 10, 64) 42 | if err != nil { 43 | http.Error(w, err.Error(), http.StatusBadRequest) 44 | return 45 | } 46 | // call our Sum binding 47 | result, err := s.service.Sum(req.Context(), a, b) 48 | if err != nil { 49 | http.Error(w, err.Error(), http.StatusBadRequest) 50 | return 51 | } 52 | // return the result 53 | w.Write([]byte(fmt.Sprintf("%d", result))) 54 | } 55 | 56 | // NewHTTPHandler returns a new HTTP handler our svc1. 57 | func NewHTTPHandler(tracer opentracing.Tracer, service Service) http.Handler { 58 | // Create our HTTP Service. 59 | svc := &httpService{service: service} 60 | 61 | // Create the mux. 62 | mux := http.NewServeMux() 63 | 64 | // Create the Concat handler. 65 | var concatHandler http.Handler 66 | concatHandler = http.HandlerFunc(svc.concatHandler) 67 | 68 | // Wrap the Concat handler with our tracing middleware. 69 | concatHandler = middleware.FromHTTPRequest(tracer, "Concat")(concatHandler) 70 | 71 | // Create the Sum handler. 72 | var sumHandler http.Handler 73 | sumHandler = http.HandlerFunc(svc.sumHandler) 74 | 75 | // Wrap the Sum handler with our tracing middleware. 76 | sumHandler = middleware.FromHTTPRequest(tracer, "Sum")(sumHandler) 77 | 78 | // Wire up the mux. 79 | mux.Handle("/concat/", concatHandler) 80 | mux.Handle("/sum/", sumHandler) 81 | 82 | // Return the mux. 83 | return mux 84 | } 85 | --------------------------------------------------------------------------------