web 框架源码阅读

gin 源码

gin 实现了 http.ServeHTTP(ResponseWriter, *Request) 接口;

engine context

  • 获取context;pool 较少gc压力;
  • 获取标准库request,包括:uri,method;
  • 路由匹配:engine.methodTrees 前缀树的匹配查找;
    • 找到HandlersChain
    • 解析请求参数
  • 遍历执行HandlersChain;
  • response 写入header;
  • render :根据request accept 协商render,渲染最终返回的格式数据;
    • html
    • json
    • msgpack
    • string
    • Jsonp
    • XML
    • YAML

http.ListenAndServe TCP server

  • onceListener
  • Accept
  • goroutine serve
    • panic recover
    • tls
    • read:bufioReaderPool
    • ServeHTTP
    • BufioWriter
    • close

路由功能

  • 路由前缀树(基树):空间换时间,提高路由性能,支持模糊匹配

详细说明:https://en.wikipedia.org/wiki/Radix_tree


go-micro 源码分析

代码启动流程

  • 新建服务

    • 客户端初始化:auth、trace等
    • 服务端初始化:auth、trace、Stats 等
  • 初始化

    • 初始化配置
    • 加载插件
    • 设置应用名字
    • 初始化cmd 的全部组件: 命令行配置
  • 注册服务

    • Pb 代码注册handler: context.Context, *XXXRequest, *XXXResponse
  • 启动

    • 产生一个auth account
      • 根据id、secret
      • 获得account
      • 生成 token
      • 独立协程
        • 定时任务
        • 过期刷新
        • 更新client token
    • 注册默认handler
      • DefaultLog
      • DefaultStats
      • DefaultTracer
    • 启动Profile
    • 启动Server,和指定的启动函数,以grpc 为例
      • net.Listener
      • Listen
      • 启动broker
      • 注册服务
      • 启动服务:和net 的tcp 是一样的
      • 定时刷新注册
      • 系统退出时
        • 卸载服务
        • 等待sub 停止
        • 优雅退出
        • disconnect broker

option 方式,提高扩展行

  • options struct 声明
  • option func(*options)
  • newOption(...option) 初始化:默认值、ops 修改

全部组件抽象 interface

  • Service
  • Client
  • Server
  • Auth
  • Borker
  • Cmd
  • Config
  • Store
  • Runtime
  • Transport
  • Profile
  • Tracer
  • Cmd
  • Registry
  • Selector
  // and initialising services.
type Service interface {
	// The service name
	Name() string
	// Init initialises options
	Init(...Option)
	// Options returns the current options
	Options() Options
	// Client is used to call services
	Client() client.Client
	// Server is for handling requests and events
	Server() server.Server
	// Run the service
	Run() error
	// The service implementation
	String() string
}

// Client is the interface used to make requests to services.
// It supports Request/Response via Transport and Publishing via the Broker.
// It also supports bidirectional streaming of requests.
type Client interface {
	Init(...Option) error
	Options() Options
	NewMessage(topic string, msg interface{}, opts ...MessageOption) Message
	NewRequest(service, endpoint string, req interface{}, reqOpts ...RequestOption) Request
	Call(ctx context.Context, req Request, rsp interface{}, opts ...CallOption) error
	Stream(ctx context.Context, req Request, opts ...CallOption) (Stream, error)
	Publish(ctx context.Context, msg Message, opts ...PublishOption) error
	String() string
}

// Server is a simple micro server abstraction
type Server interface {
	// Initialise options
	Init(...Option) error
	// Retrieve the options
	Options() Options
	// Register a handler
	Handle(Handler) error
	// Create a new handler
	NewHandler(interface{}, ...HandlerOption) Handler
	// Create a new subscriber
	NewSubscriber(string, interface{}, ...SubscriberOption) Subscriber
	// Register a subscriber
	Subscribe(Subscriber) error
	// Start the server
	Start() error
	// Stop the server
	Stop() error
	// Server implementation
	String() string
}

// Auth providers authentication and authorization
type Auth interface {
	// Init the auth
	Init(opts ...Option)
	// Options set for auth
	Options() Options
	// Generate a new account
	Generate(id string, opts ...GenerateOption) (*Account, error)
	// Grant access to a resource
	Grant(role string, res *Resource) error
	// Revoke access to a resource
	Revoke(role string, res *Resource) error
	// Verify an account has access to a resource
	Verify(acc *Account, res *Resource) error
	// Inspect a token
	Inspect(token string) (*Account, error)
	// Token generated using refresh token
	Token(opts ...TokenOption) (*Token, error)
	// String returns the name of the implementation
	String() string
}

// Broker is an interface used for asynchronous messaging.
type Broker interface {
	Init(...Option) error
	Options() Options
	Address() string
	Connect() error
	Disconnect() error
	Publish(topic string, m *Message, opts ...PublishOption) error
	Subscribe(topic string, h Handler, opts ...SubscribeOption) (Subscriber, error)
	String() string
}

type Cmd interface {
	// The cli app within this cmd
	App() *cli.App
	// Adds options, parses flags and initialise
	// exits on error
	Init(opts ...Option) error
	// Options set within this command
	Options() Options
}

type Config interface {
	// provide the reader.Values interface
	reader.Values
	// Init the config
	Init(opts ...Option) error
	// Options in the config
	Options() Options
	// Stop the config loader/watcher
	Close() error
	// Load config sources
	Load(source ...source.Source) error
	// Force a source changeset sync
	Sync() error
	// Watch a value for changes
	Watch(path ...string) (Watcher, error)
}

// Store is a data storage interface
type Store interface {
	// Init initialises the store. It must perform any required setup on the backing storage implementation and check that it is ready for use, returning any errors.
	Init(...Option) error
	// Options allows you to view the current options.
	Options() Options
	// Read takes a single key name and optional ReadOptions. It returns matching []*Record or an error.
	Read(key string, opts ...ReadOption) ([]*Record, error)
	// Write() writes a record to the store, and returns an error if the record was not written.
	Write(r *Record, opts ...WriteOption) error
	// Delete removes the record with the corresponding key from the store.
	Delete(key string, opts ...DeleteOption) error
	// List returns any keys that match, or an empty list with no error if none matched.
	List(opts ...ListOption) ([]string, error)
	// Close the store
	Close() error
	// String returns the name of the implementation.
	String() string
}

type Registry interface {
	Init(...Option) error
	Options() Options
	Register(*Service, ...RegisterOption) error
	Deregister(*Service, ...DeregisterOption) error
	GetService(string, ...GetOption) ([]*Service, error)
	ListServices(...ListOption) ([]*Service, error)
	Watch(...WatchOption) (Watcher, error)
	String() string
}


// Runtime is a service runtime manager
type Runtime interface {
	// Init initializes runtime
	Init(...Option) error
	// Create registers a service
	Create(*Service, ...CreateOption) error
	// Read returns the service
	Read(...ReadOption) ([]*Service, error)
	// Update the service in place
	Update(*Service, ...UpdateOption) error
	// Remove a service
	Delete(*Service, ...DeleteOption) error
	// Logs returns the logs for a service
	Logs(*Service, ...LogsOption) (LogStream, error)
	// Start starts the runtime
	Start() error
	// Stop shuts down the runtime
	Stop() error
	// String describes runtime
	String() string
}

// Transport is an interface which is used for communication between
// services. It uses connection based socket send/recv semantics and
// has various implementations; http, grpc, quic.
type Transport interface {
	Init(...Option) error
	Options() Options
	Dial(addr string, opts ...DialOption) (Client, error)
	Listen(addr string, opts ...ListenOption) (Listener, error)
	String() string
}

type Profile interface {
	// Start the profiler
	Start() error
	// Stop the profiler
	Stop() error
	// Name of the profiler
	String() string
}

// Tracer is an interface for distributed tracing
type Tracer interface {
	// Start a trace
	Start(ctx context.Context, name string) (context.Context, *Span)
	// Finish the trace
	Finish(*Span) error
	// Read the traces
	Read(...ReadOption) ([]*Span, error)
}

// Handler interface represents a request handler. It's generated
// by passing any type of public concrete object with endpoints into server.NewHandler.
// Most will pass in a struct.
//
// Example:
//
//      type Greeter struct {}
//
//      func (g *Greeter) Hello(context, request, response) error {
//              return nil
//      }
//
type Handler interface {
	Name() string
	Handler() interface{}
	Endpoints() []*registry.Endpoint
	Options() HandlerOptions
}

type Cmd interface {
	// The cli app within this cmd
	App() *cli.App
	// Adds options, parses flags and initialise
	// exits on error
	Init(opts ...Option) error
	// Options set within this command
	Options() Options
}

// Selector builds on the registry as a mechanism to pick nodes
// and mark their status. This allows host pools and other things
// to be built using various algorithms.
type Selector interface {
	Init(opts ...Option) error
	Options() Options
	// Select returns a function which should return the next node
	Select(service string, opts ...SelectOption) (Next, error)
	// Mark sets the success/error against a node
	Mark(service string, node *registry.Node, err error)
	// Reset returns state back to zero for a service
	Reset(service string)
	// Close renders the selector unusable
	Close() error
	// Name of the selector
	String() string


装饰器模式(包装器)

Wrapper 嵌入修饰对象接口,和特性的接口,然后实现对修饰对象和特性对象的联合

  • traceWrapper 实现对client 的追踪
  • authWrapper 实现对client 的鉴权
  • fromServiceWrapper 实现服务调用者名字设置
  • WrapHandler func(HandlerFunc) HandlerFunc

// TraceCall is a call tracing wrapper
func TraceCall(name string, t trace.Tracer, c client.Client) client.Client {
	return &traceWrapper{
		name:   name,
		trace:  t,
		Client: c,
	}
}

type traceWrapper struct {
	client.Client

	name  string
	trace trace.Tracer
}

func (c *traceWrapper) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error {
	newCtx, s := c.trace.Start(ctx, req.Service()+"."+req.Endpoint())

	s.Type = trace.SpanTypeRequestOutbound
	err := c.Client.Call(newCtx, req, rsp, opts...)
	if err != nil {
		s.Metadata["error"] = err.Error()
	}

	// finish the trace
	c.trace.Finish(s)

	return err
}




type authWrapper struct {
	client.Client
	auth func() auth.Auth
}

func (a *authWrapper) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error {
	// parse the options
	var options client.CallOptions
	for _, o := range opts {
		o(&options)
	}

	// check to see if the authorization header has already been set.
	// We dont't override the header unless the ServiceToken option has
	// been specified or the header wasn't provided
	if _, ok := metadata.Get(ctx, "Authorization"); ok && !options.ServiceToken {
		return a.Client.Call(ctx, req, rsp, opts...)
	}

	// if auth is nil we won't be able to get an access token, so we execute
	// the request without one.
	aa := a.auth()
	if aa == nil {
		return a.Client.Call(ctx, req, rsp, opts...)
	}

	// check to see if we have a valid access token
	aaOpts := aa.Options()
	if aaOpts.Token != nil && aaOpts.Token.Expiry.Unix() > time.Now().Unix() {
		ctx = metadata.Set(ctx, "Authorization", auth.BearerScheme+aaOpts.Token.AccessToken)
		return a.Client.Call(ctx, req, rsp, opts...)
	}

	// call without an auth token
	return a.Client.Call(ctx, req, rsp, opts...)
}

插件模式-插拔式

目的

  • 可以热更新式扩展应用程序的功能列表
  • 应对多变的业务需求,方便功能上下线
  • 对于任意的go应用,能进行增量架构、代码分发以及代码上下线
    Brokers    map[string]func(...broker.Option) broker.Broker
	Configs    map[string]func(...config.Option) (config.Config, error)
	Clients    map[string]func(...client.Option) client.Client
	Registries map[string]func(...registry.Option) registry.Registry
	Selectors  map[string]func(...selector.Option) selector.Selector
	Servers    map[string]func(...server.Option) server.Server
	Transports map[string]func(...transport.Option) transport.Transport
	Runtimes   map[string]func(...runtime.Option) runtime.Runtime
	Stores     map[string]func(...store.Option) store.Store
	Tracers    map[string]func(...trace.Option) trace.Tracer
	Auths      map[string]func(...auth.Option) auth.Auth
	Profiles   map[string]func(...profile.Option) profile.Profile
package main

func Add(x, y int) int {
	return x + y
}
func Subtract(x, y int) int {
	return x - y
}
//go build -buildmode=plugin -o aplugin.so aplugin.go


package main

import (
	"fmt"
	"plugin"
)

func main() {
	p, _ := plugin.Open("./aplugin.so")

	add, _ := p.Lookup("Add")
	subtract, _ := p.Lookup("Subtract")

	sum := add.(func(int, int) int)(11, 2)
	fmt.Println("sum=", sum)

	sub := subtract.(func(int, int) int)(11, 2)
	fmt.Println("sum=", sub)
}
WRITTEN BY:    陈贞

个人博客