From a10d4b53a0ea0219f858998a531e1e9e6cdb1a7e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E9=BB=84=E5=AD=9F=E6=9F=B1?= <hmzzrcs@163.com>
Date: Tue, 20 Jul 2021 10:46:32 +0800
Subject: [PATCH] init

---
 .gitignore                                    |   1 +
 discover-eureka/config.go                     |  14 +
 discover-eureka/driver.go                     |  46 +++
 discover-eureka/eureka.go                     | 176 ++++++++++++
 discover-eureka/eureka_request.go             |  80 ++++++
 discover-eureka/eureka_test.go                |  34 +++
 discover-eureka/factory.go                    |  43 +++
 discover-nacos/config.go                      |  15 +
 discover-nacos/driver.go                      |  47 ++++
 discover-nacos/factory.go                     |  43 +++
 discover-nacos/nacos.go                       | 177 ++++++++++++
 discover-nacos/nacos_request.go               |  70 +++++
 discover-nacos/nacos_test.go                  |  27 ++
 discovery-consul/config.go                    |  13 +
 discovery-consul/consul.go                    | 143 ++++++++++
 discovery-consul/consul_test.go               |  29 ++
 discovery-consul/driver.go                    |  48 ++++
 discovery-consul/factory.go                   |  44 +++
 discovery-consul/utils.go                     |  85 ++++++
 discovery-static/config.go                    |  23 ++
 discovery-static/driver.go                    |  44 +++
 discovery-static/factory.go                   |  44 +++
 discovery-static/static.go                    | 212 ++++++++++++++
 discovery/app.go                              |  89 ++++++
 discovery/checker.go                          |  14 +
 discovery/discovery.go                        |  55 ++++
 discovery/node.go                             |  65 +++++
 discovery/services.go                         |  67 +++++
 example/config.go                             |   9 +
 example/driver.go                             |  26 ++
 example/employee.go                           |  48 ++++
 example/register.go                           |  37 +++
 go.mod                                        |  10 +
 go.sum                                        | 110 ++++++++
 health-check-http/agent.go                    |  25 ++
 health-check-http/check.go                    |  77 ++++++
 health-check-http/checker-demo.go             | 108 ++++++++
 health-check-http/config.go                   |  12 +
 health-check-http/http-check.go               | 142 ++++++++++
 http-proxy/http-proxy-request/request.go      | 239 ++++++++++++++++
 http-proxy/r.go                               |  57 ++++
 http-router/config.go                         |  30 ++
 http-router/driver.go                         |  32 +++
 http-router/register.go                       |  24 ++
 http-router/router.go                         |  34 +++
 listener-manager/listener.go                  |  67 +++++
 main.go                                       |   5 +
 router-http/Header.go                         |  74 +++++
 router-http/Host.go                           |  79 ++++++
 router-http/Location.go                       | 135 +++++++++
 router-http/Query.go                          |  74 +++++
 router-http/build.go                          | 165 +++++++++++
 router-http/demo_test.go                      |  94 +++++++
 router-http/endpoint.go                       |   9 +
 router-http/plan-multi.go                     |  26 ++
 router-http/plan-one.go                       |  33 +++
 router-http/reader-host.go                    |  13 +
 router-http/reader-location.go                |   9 +
 router-http/reader.go                         |  28 ++
 router-http/router-http-benchMark_test.go     |  45 +++
 router-http/router-http.go                    | 261 ++++++++++++++++++
 router-http/router-http_test.go               | 164 +++++++++++
 router-http/router-tree.go                    | 172 ++++++++++++
 router-http/target.go                         |  26 ++
 router-http/test_router_manager.yaml          |  98 +++++++
 .../test_router_manager_newEmployee.yaml      |   9 +
 router-k/chain.go                             |   4 +
 router-k/checker.go                           |  21 ++
 router-k/config.go                            |  16 ++
 router-k/manager.go                           |  98 +++++++
 router-k/match.go                             |  20 ++
 router-k/reader.go                            |   7 +
 router-k/router.go                            |  84 ++++++
 router-k/routers.go                           |  71 +++++
 router-k/server.go                            |  13 +
 router-k/tree.go                              |  15 +
 router/config.go                              |  26 ++
 router/employee.go                            |  37 +++
 router/factory.go                             |  59 ++++
 router/register.go                            |  55 ++++
 router/router.go                              |  73 +++++
 service-http/config.go                        |  17 ++
 service-http/driver.go                        |  73 +++++
 service-http/factory.go                       |  44 +++
 service-http/service.go                       | 119 ++++++++
 service/service.go                            |  34 +++
 service/service_test.go                       |  22 ++
 stores/register.go                            |  55 ++++
 stores/stores.go                              |   8 +
 stores/yaml/init.go                           |  90 ++++++
 stores/yaml/store.go                          |  89 ++++++
 upstream-http/config.go                       |  16 ++
 upstream-http/driver.go                       |  62 +++++
 upstream-http/factory.go                      |  44 +++
 .../http-proxy/http-proxy-request/request.go  | 239 ++++++++++++++++
 upstream-http/http-proxy/r.go                 |  57 ++++
 upstream-http/org.go                          |  62 +++++
 upstream-http/upstream.go                     | 120 ++++++++
 upstream-http_anonymous/config.go             |   7 +
 upstream-http_anonymous/driver.go             |  39 +++
 upstream-http_anonymous/factory.go            |  44 +++
 upstream-http_anonymous/org.go                |  68 +++++
 upstream/balance/balance.go                   |  84 ++++++
 upstream/round-robin/round_robin.go           | 107 +++++++
 upstream/upstream.go                          |  19 ++
 upstream/upstream_test.go                     |  14 +
 106 files changed, 6486 insertions(+)
 create mode 100644 discover-eureka/config.go
 create mode 100644 discover-eureka/driver.go
 create mode 100644 discover-eureka/eureka.go
 create mode 100644 discover-eureka/eureka_request.go
 create mode 100644 discover-eureka/eureka_test.go
 create mode 100644 discover-eureka/factory.go
 create mode 100644 discover-nacos/config.go
 create mode 100644 discover-nacos/driver.go
 create mode 100644 discover-nacos/factory.go
 create mode 100644 discover-nacos/nacos.go
 create mode 100644 discover-nacos/nacos_request.go
 create mode 100644 discover-nacos/nacos_test.go
 create mode 100644 discovery-consul/config.go
 create mode 100644 discovery-consul/consul.go
 create mode 100644 discovery-consul/consul_test.go
 create mode 100644 discovery-consul/driver.go
 create mode 100644 discovery-consul/factory.go
 create mode 100644 discovery-consul/utils.go
 create mode 100644 discovery-static/config.go
 create mode 100644 discovery-static/driver.go
 create mode 100644 discovery-static/factory.go
 create mode 100644 discovery-static/static.go
 create mode 100644 discovery/app.go
 create mode 100644 discovery/checker.go
 create mode 100644 discovery/discovery.go
 create mode 100644 discovery/node.go
 create mode 100644 discovery/services.go
 create mode 100644 example/config.go
 create mode 100644 example/driver.go
 create mode 100644 example/employee.go
 create mode 100644 example/register.go
 create mode 100644 go.mod
 create mode 100644 go.sum
 create mode 100644 health-check-http/agent.go
 create mode 100644 health-check-http/check.go
 create mode 100644 health-check-http/checker-demo.go
 create mode 100644 health-check-http/config.go
 create mode 100644 health-check-http/http-check.go
 create mode 100644 http-proxy/http-proxy-request/request.go
 create mode 100644 http-proxy/r.go
 create mode 100644 http-router/config.go
 create mode 100644 http-router/driver.go
 create mode 100644 http-router/register.go
 create mode 100644 http-router/router.go
 create mode 100644 listener-manager/listener.go
 create mode 100644 main.go
 create mode 100644 router-http/Header.go
 create mode 100644 router-http/Host.go
 create mode 100644 router-http/Location.go
 create mode 100644 router-http/Query.go
 create mode 100644 router-http/build.go
 create mode 100644 router-http/demo_test.go
 create mode 100644 router-http/endpoint.go
 create mode 100644 router-http/plan-multi.go
 create mode 100644 router-http/plan-one.go
 create mode 100644 router-http/reader-host.go
 create mode 100644 router-http/reader-location.go
 create mode 100644 router-http/reader.go
 create mode 100644 router-http/router-http-benchMark_test.go
 create mode 100644 router-http/router-http.go
 create mode 100644 router-http/router-http_test.go
 create mode 100644 router-http/router-tree.go
 create mode 100644 router-http/target.go
 create mode 100644 router-http/test_router_manager.yaml
 create mode 100644 router-http/test_router_manager_newEmployee.yaml
 create mode 100644 router-k/chain.go
 create mode 100644 router-k/checker.go
 create mode 100644 router-k/config.go
 create mode 100644 router-k/manager.go
 create mode 100644 router-k/match.go
 create mode 100644 router-k/reader.go
 create mode 100644 router-k/router.go
 create mode 100644 router-k/routers.go
 create mode 100644 router-k/server.go
 create mode 100644 router-k/tree.go
 create mode 100644 router/config.go
 create mode 100644 router/employee.go
 create mode 100644 router/factory.go
 create mode 100644 router/register.go
 create mode 100644 router/router.go
 create mode 100644 service-http/config.go
 create mode 100644 service-http/driver.go
 create mode 100644 service-http/factory.go
 create mode 100644 service-http/service.go
 create mode 100644 service/service.go
 create mode 100644 service/service_test.go
 create mode 100644 stores/register.go
 create mode 100644 stores/stores.go
 create mode 100644 stores/yaml/init.go
 create mode 100644 stores/yaml/store.go
 create mode 100644 upstream-http/config.go
 create mode 100644 upstream-http/driver.go
 create mode 100644 upstream-http/factory.go
 create mode 100644 upstream-http/http-proxy/http-proxy-request/request.go
 create mode 100644 upstream-http/http-proxy/r.go
 create mode 100644 upstream-http/org.go
 create mode 100644 upstream-http/upstream.go
 create mode 100644 upstream-http_anonymous/config.go
 create mode 100644 upstream-http_anonymous/driver.go
 create mode 100644 upstream-http_anonymous/factory.go
 create mode 100644 upstream-http_anonymous/org.go
 create mode 100644 upstream/balance/balance.go
 create mode 100644 upstream/round-robin/round_robin.go
 create mode 100644 upstream/upstream.go
 create mode 100644 upstream/upstream_test.go

diff --git a/.gitignore b/.gitignore
index 66fd13c9..d4d4f0d4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,3 +13,4 @@
 
 # Dependency directories (remove the comment below to include it)
 # vendor/
+/.idea/
\ No newline at end of file
diff --git a/discover-eureka/config.go b/discover-eureka/config.go
new file mode 100644
index 00000000..c491b75b
--- /dev/null
+++ b/discover-eureka/config.go
@@ -0,0 +1,14 @@
+package discover_eureka
+
+
+type Config struct {
+	Name     string `json:"name"`
+	Driver   string `json:"driver"`
+	Labels   map[string]string
+	Config   AccessConfig `json:"config"`
+}
+
+type AccessConfig struct {
+	Address []string
+	Params  map[string]string
+}
diff --git a/discover-eureka/driver.go b/discover-eureka/driver.go
new file mode 100644
index 00000000..47bde588
--- /dev/null
+++ b/discover-eureka/driver.go
@@ -0,0 +1,46 @@
+package discover_eureka
+
+import (
+	"errors"
+	"fmt"
+	"github.com/eolinker/eosc"
+	"github.com/eolinker/goku-eosc/discovery"
+	"reflect"
+)
+
+const (
+	driverName = "eureka"
+)
+//driver 实现github.com/eolinker/eosc.eosc.IProfessionDriver接口
+type driver struct {
+	profession string
+	name       string
+	driver     string
+	label      string
+	desc       string
+	configType reflect.Type
+	params     map[string]string
+}
+
+func (d *driver) ConfigType() reflect.Type {
+	return d.configType
+}
+
+func (d *driver) Create(id, name string, v interface{}, workers map[eosc.RequireId]interface{}) (eosc.IWorker, error) {
+	cfg, ok := v.(*Config)
+	if !ok {
+		return nil, errors.New(fmt.Sprintf("error struct type: %s, need struct type: %s", eosc.TypeNameOf(v), d.configType))
+	}
+	return &eureka{
+		id:             id,
+		name:           name,
+		address:        cfg.Config.Address,
+		params:         cfg.Config.Params,
+		labels:         cfg.Labels,
+		services:       discovery.NewServices(),
+		context:        nil,
+		cancelFunc:     nil,
+	}, nil
+
+}
+
diff --git a/discover-eureka/eureka.go b/discover-eureka/eureka.go
new file mode 100644
index 00000000..0958b1b3
--- /dev/null
+++ b/discover-eureka/eureka.go
@@ -0,0 +1,176 @@
+package discover_eureka
+
+import (
+	"context"
+	"encoding/xml"
+	"fmt"
+	"github.com/eolinker/eosc"
+	"github.com/eolinker/goku-eosc/discovery"
+	"io/ioutil"
+	"net/http"
+	"strings"
+	"time"
+)
+
+type eureka struct {
+	id           string
+	name         string
+	address      []string
+	params       map[string]string
+	labels       map[string]string
+	services     discovery.IServices
+	context      context.Context
+	cancelFunc   context.CancelFunc
+}
+
+func (e *eureka) GetApp(serviceName string) (discovery.IApp, error) {
+	app, err := e.Create(serviceName)
+	if err != nil {
+		return nil, err
+	}
+	err = e.services.Set(serviceName, app.Id(), app)
+	if err != nil {
+		return nil, err
+	}
+	return app, nil
+}
+func (e *eureka) Create(serviceName string) (discovery.IApp, error) {
+	nodes, err := e.GetNodeList(serviceName)
+	if err != nil {
+		return nil, err
+	}
+	attrs := make(discovery.Attrs)
+	app := discovery.NewApp(nil, e, attrs, nodes)
+	return app, nil
+}
+
+func (e *eureka) Remove(id string) error {
+	return e.services.Remove(id)
+}
+
+func (e *eureka) Id() string {
+	return e.id
+}
+
+func (e *eureka) Start() error {
+	ctx, cancelFunc := context.WithCancel(context.Background())
+	e.context = ctx
+	e.cancelFunc = cancelFunc
+	go func() {
+		ticker := time.NewTicker(5 * time.Second)
+		defer ticker.Stop()
+	EXIT:
+		for {
+			select {
+			case <-ctx.Done():
+				break EXIT
+			case <-ticker.C:
+				{
+					keys := e.services.AppKeys()
+					for _, serviceName := range keys {
+						res, err := e.GetNodeList(serviceName)
+						if err != nil {
+							continue
+						}
+						nodes := make([]discovery.INode, len(res))
+						for _, v := range res {
+							nodes = append(nodes, v)
+						}
+						e.services.Update(serviceName, nodes)
+					}
+				}
+			}
+
+		}
+	}()
+	return nil
+}
+
+func (e *eureka) Reset(conf interface{}, workers map[eosc.RequireId]interface{}) error {
+	cfg, ok := conf.(*Config)
+	if !ok {
+		return fmt.Errorf("need %s,now %s:%w", eosc.TypeNameOf((*Config)(nil)), eosc.TypeNameOf(conf), eosc.ErrorStructType)
+	}
+	e.address = cfg.Config.Address
+	e.params = cfg.Config.Params
+	e.labels = cfg.Labels
+	return nil
+}
+
+func (e *eureka) Stop() error {
+	e.cancelFunc()
+	return nil
+}
+
+func (e *eureka) CheckSkill(skill string) bool {
+	return discovery.CheckSkill(skill)
+}
+
+func (e *eureka) GetNodeList(serviceName string) (map[string]discovery.INode, error) {
+	nodes := make(map[string]discovery.INode)
+	for _, addr := range e.address {
+		// 获取每个ip中指定服务名的实例列表
+		app, err := e.GetApplication(addr, serviceName)
+		if err != nil {
+			return nil, err
+		}
+		for _, ins := range app.Instances {
+			if ins.Status != EurekaStatusUp {
+				continue
+			}
+			port := 0
+			if ins.Port.Enabled {
+				port = ins.Port.Port
+			} else if ins.SecurePort.Enabled {
+				port = ins.SecurePort.Port
+			}
+			label := map[string]string{
+				"app":      ins.App,
+				"hostName": ins.HostName,
+			}
+			//for k, v := range ins.Metadata {
+			//	label[k] = v
+			//}
+			node := discovery.NewNode(label, ins.InstanceID, ins.IPAddr, port)
+			if _, ok := nodes[node.Id()]; ok {
+				continue
+			}
+			nodes[node.Id()] = node
+		}
+	}
+	return nodes, nil
+}
+
+func (e *eureka) GetApplication(addr, serviceName string) (*Application, error) {
+
+	if !strings.Contains(addr, "http://") && !strings.Contains(addr, "https://") {
+		addr = fmt.Sprintf("http://%s", addr)
+		if v, ok := e.labels["schema"]; ok {
+			if v == "https" {
+				addr = fmt.Sprintf("https://%s", addr)
+			}
+		}
+	}
+	addr = fmt.Sprintf("%s/apps/%s", addr, serviceName)
+	res, err := http.Get(addr)
+	if err != nil {
+		return nil, err
+	}
+	respBody, err := ioutil.ReadAll(res.Body)
+	if err != nil {
+		return nil, err
+	}
+	err = res.Body.Close()
+	if err != nil {
+		return nil, err
+	}
+	if res.StatusCode != http.StatusOK {
+		return nil, err
+	}
+	var application = &Application{}
+	err = xml.Unmarshal(respBody, application)
+	if err != nil {
+		return nil, err
+	}
+	return application, err
+}
diff --git a/discover-eureka/eureka_request.go b/discover-eureka/eureka_request.go
new file mode 100644
index 00000000..f0951797
--- /dev/null
+++ b/discover-eureka/eureka_request.go
@@ -0,0 +1,80 @@
+package discover_eureka
+const EurekaStatusUp = "UP"
+
+//Application application
+type Application struct {
+	Name      string         `xml:"name"`
+	Instances []InstanceInfo `xml:"instance" json:"instance"`
+}
+
+//Instance instance
+type Instance struct {
+	Instance *InstanceInfo `xml:"instance" json:"instance"`
+}
+
+//InstanceInfo instanceInfo
+type InstanceInfo struct {
+	HostName                      string          `xml:"hostName" json:"hostName"`
+	HomePageURL                   string          `xml:"homePageUrl,omitempty" json:"homePageUrl,omitempty"`
+	StatusPageURL                 string          `xml:"statusPageUrl" json:"statusPageUrl"`
+	HealthCheckURL                string          `xml:"healthCheckUrl,omitempty" json:"healthCheckUrl,omitempty"`
+	App                           string          `xml:"app" json:"app"`
+	IPAddr                        string          `xml:"ipAddr" json:"ipAddr"`
+	VipAddress                    string          `xml:"vipAddress" json:"vipAddress"`
+	SecureVipAddress              string          `xml:"secureVipAddress,omitempty" json:"secureVipAddress,omitempty"`
+	Status                        string          `xml:"status" json:"status"`
+	Port                          *Port           `xml:"port,omitempty" json:"port,omitempty"`
+	SecurePort                    *Port           `xml:"securePort,omitempty" json:"securePort,omitempty"`
+	DataCenterInfo                *DataCenterInfo `xml:"dataCenterInfo" json:"dataCenterInfo"`
+	LeaseInfo                     *LeaseInfo      `xml:"leaseInfo,omitempty" json:"leaseInfo,omitempty"`
+	IsCoordinatingDiscoveryServer bool            `xml:"isCoordinatingDiscoveryServer,omitempty" json:"isCoordinatingDiscoveryServer,omitempty"`
+	LastUpdatedTimestamp          int             `xml:"lastUpdatedTimestamp,omitempty" json:"lastUpdatedTimestamp,omitempty"`
+	LastDirtyTimestamp            int             `xml:"lastDirtyTimestamp,omitempty" json:"lastDirtyTimestamp,omitempty"`
+	ActionType                    string          `xml:"actionType,omitempty" json:"actionType,omitempty"`
+	Overriddenstatus              string          `xml:"overriddenstatus,omitempty" json:"overriddenstatus,omitempty"`
+	CountryID                     int             `xml:"countryId,omitempty" json:"countryId,omitempty"`
+	InstanceID                    string          `xml:"instanceId" json:"instanceId"`
+	AppName                       string          `xml:"appName,omitempty" json:"appName,omitempty"`
+	AppGroupName                  string          `xml:"appGroupName,omitempty" json:"appGroupName,omitempty"`
+}
+
+
+
+//Port port
+type Port struct {
+	Port    int  `xml:",chardata" json:"$"`
+	Enabled bool `xml:"enabled,attr" json:"@enabled"`
+}
+
+//DataCenterInfo dataCenterInfo
+type DataCenterInfo struct {
+	Name     string              `xml:"name" json:"name"`
+	Class    string              `xml:"class,attr" json:"@class"`
+	Metadata *DataCenterMetadata `xml:"metadata,omitempty" json:"metadata,omitempty"`
+}
+
+//DataCenterMetadata dataCenterMetaData
+type DataCenterMetadata struct {
+	AmiLaunchIndex   string `xml:"ami-launch-index,omitempty" json:"ami-launch-index,omitempty"`
+	LocalHostname    string `xml:"local-hostname,omitempty" json:"local-hostname,omitempty"`
+	AvailabilityZone string `xml:"availability-zone,omitempty" json:"availability-zone,omitempty"`
+	InstanceID       string `xml:"instance-id,omitempty" json:"instance-id,omitempty"`
+	PublicIpv4       string `xml:"public-ipv4,omitempty" json:"public-ipv4,omitempty"`
+	PublicHostname   string `xml:"public-hostname,omitempty" json:"public-hostname,omitempty"`
+	AmiManifestPath  string `xml:"ami-manifest-path,omitempty" json:"ami-manifest-path,omitempty"`
+	LocalIpv4        string `xml:"local-ipv4,omitempty" json:"local-ipv4,omitempty"`
+	Hostname         string `xml:"hostname,omitempty" json:"hostname,omitempty"`
+	AmiID            string `xml:"ami-id,omitempty" json:"ami-id,omitempty"`
+	InstanceType     string `xml:"instance-type,omitempty" json:"instance-type,omitempty"`
+}
+
+//LeaseInfo leaseInfo
+type LeaseInfo struct {
+	EvictionDurationInSecs uint `xml:"evictionDurationInSecs,omitempty" json:"evictionDurationInSecs,omitempty"`
+	RenewalIntervalInSecs  int  `xml:"renewalIntervalInSecs,omitempty" json:"renewalIntervalInSecs,omitempty"`
+	DurationInSecs         int  `xml:"durationInSecs,omitempty" json:"durationInSecs,omitempty"`
+	RegistrationTimestamp  int  `xml:"registrationTimestamp,omitempty" json:"registrationTimestamp,omitempty"`
+	LastRenewalTimestamp   int  `xml:"lastRenewalTimestamp,omitempty" json:"lastRenewalTimestamp,omitempty"`
+	EvictionTimestamp      int  `xml:"evictionTimestamp,omitempty" json:"evictionTimestamp,omitempty"`
+	ServiceUpTimestamp     int  `xml:"serviceUpTimestamp,omitempty" json:"serviceUpTimestamp,omitempty"`
+}
diff --git a/discover-eureka/eureka_test.go b/discover-eureka/eureka_test.go
new file mode 100644
index 00000000..cc025b40
--- /dev/null
+++ b/discover-eureka/eureka_test.go
@@ -0,0 +1,34 @@
+package discover_eureka
+
+import (
+	"fmt"
+	"github.com/eolinker/goku-eosc/discovery"
+	"testing"
+)
+
+func TestGetApp(t *testing.T) {
+	serviceName := "DEMO"
+	e := &eureka{
+		id:   "1",
+		name: "eolinker",
+		address: []string{
+			"http://39.108.94.48:8761/eureka",
+		},
+		params: map[string]string{
+			"username": "test",
+			"password": "test",
+		},
+		labels:       nil,
+		services:     discovery.NewServices(),
+		context:      nil,
+		cancelFunc:   nil,
+	}
+
+	app, err := e.GetApp(serviceName)
+	if err!=nil {
+		fmt.Println("error:", err)
+	}
+	for _, node := range app.Nodes(){
+		fmt.Println(node.Id())
+	}
+}
diff --git a/discover-eureka/factory.go b/discover-eureka/factory.go
new file mode 100644
index 00000000..2095a56e
--- /dev/null
+++ b/discover-eureka/factory.go
@@ -0,0 +1,43 @@
+package discover_eureka
+
+import (
+	"github.com/eolinker/eosc"
+	"reflect"
+)
+
+func Register() {
+	eosc.DefaultProfessionDriverRegister.RegisterProfessionDriver("eolinker:goku:discover_eureka", NewFactory())
+}
+
+type factory struct {
+	profession string
+	name       string
+	label      string
+	desc       string
+	params     map[string]string
+}
+
+func NewFactory() *factory {
+	return &factory{}
+}
+
+func (f *factory) ExtendInfo() eosc.ExtendInfo {
+	return eosc.ExtendInfo{
+		ID:      "eolinker:goku:discover_eureka",
+		Group:   "eolinker",
+		Project: "goku",
+		Name:    "eureka",
+	}
+}
+
+func (f *factory) Create(profession string, name string, label string, desc string, params map[string]string) (eosc.IProfessionDriver, error) {
+	return &driver{
+		profession: profession,
+		name:       name,
+		label:      label,
+		desc:       desc,
+		driver:     driverName,
+		configType: reflect.TypeOf((*Config)(nil)),
+		params:     params,
+	}, nil
+}
diff --git a/discover-nacos/config.go b/discover-nacos/config.go
new file mode 100644
index 00000000..13f592cd
--- /dev/null
+++ b/discover-nacos/config.go
@@ -0,0 +1,15 @@
+package discover_nacos
+
+
+type Config struct {
+	Name     string `json:"name"`
+	Driver   string `json:"driver"`
+	Labels   map[string]string
+	Config   AccessConfig `json:"config"`
+}
+
+type AccessConfig struct {
+	Address []string
+	Params  map[string]string
+}
+
diff --git a/discover-nacos/driver.go b/discover-nacos/driver.go
new file mode 100644
index 00000000..51d74823
--- /dev/null
+++ b/discover-nacos/driver.go
@@ -0,0 +1,47 @@
+package discover_nacos
+
+import (
+	"errors"
+	"fmt"
+	"github.com/eolinker/eosc"
+	"github.com/eolinker/goku-eosc/discovery"
+	"reflect"
+)
+
+const (
+	driverName = "nacos"
+)
+//driver 实现github.com/eolinker/eosc.eosc.IProfessionDriver接口
+type driver struct {
+	profession string
+	name       string
+	driver     string
+	label      string
+	desc       string
+	configType reflect.Type
+	params     map[string]string
+}
+
+func (d *driver) ConfigType() reflect.Type {
+	return d.configType
+}
+
+func (d *driver) Create(id, name string, v interface{}, workers map[eosc.RequireId]interface{}) (eosc.IWorker, error) {
+	cfg, ok := v.(*Config)
+	if !ok {
+		return nil, errors.New(fmt.Sprintf("error struct type: %s, need struct type: %s", eosc.TypeNameOf(v), d.configType))
+	}
+	return &nacos{
+		id:             id,
+		name:           name,
+		address:        cfg.Config.Address,
+		params:         cfg.Config.Params,
+		labels:         cfg.Labels,
+		services:       discovery.NewServices(),
+		context:        nil,
+		cancelFunc:     nil,
+	}, nil
+
+}
+
+
diff --git a/discover-nacos/factory.go b/discover-nacos/factory.go
new file mode 100644
index 00000000..442721c6
--- /dev/null
+++ b/discover-nacos/factory.go
@@ -0,0 +1,43 @@
+package discover_nacos
+
+import (
+	"github.com/eolinker/eosc"
+	"reflect"
+)
+
+func Register() {
+	eosc.DefaultProfessionDriverRegister.RegisterProfessionDriver("eolinker:goku:discover_nacos", NewFactory())
+}
+
+type factory  struct {
+	profession string
+	name       string
+	label      string
+	desc       string
+	params     map[string]string
+}
+
+func NewFactory() *factory {
+	return &factory{}
+}
+
+func (f *factory) ExtendInfo() eosc.ExtendInfo {
+	return eosc.ExtendInfo{
+		ID:      "eolinker:goku:discover_nacos",
+		Group:   "eolinker",
+		Project: "goku",
+		Name:    "nacos",
+	}
+}
+
+func (f *factory) Create(profession string, name string, label string, desc string, params map[string]string) (eosc.IProfessionDriver, error) {
+	return &driver{
+		profession: profession,
+		name:       name,
+		label:      label,
+		desc:       desc,
+		driver:     driverName,
+		configType: reflect.TypeOf((*Config)(nil)),
+		params:     params,
+	}, nil
+}
diff --git a/discover-nacos/nacos.go b/discover-nacos/nacos.go
new file mode 100644
index 00000000..8900ad2e
--- /dev/null
+++ b/discover-nacos/nacos.go
@@ -0,0 +1,177 @@
+package discover_nacos
+
+import (
+	"context"
+	"encoding/json"
+	"fmt"
+	"github.com/eolinker/eosc"
+	"github.com/eolinker/goku-eosc/discovery"
+	"io/ioutil"
+	"net/http"
+	"strconv"
+	"strings"
+	"time"
+)
+
+const (
+	instancePath = "/nacos/v1/ns/instance/list"
+)
+
+type nacos struct {
+	id             string
+	name			string
+	address        []string
+	params         map[string]string
+	labels		 	map[string]string
+	services       discovery.IServices
+	context        context.Context
+	cancelFunc     context.CancelFunc
+}
+
+// return worker id
+func (n *nacos) Id() string {
+	return n.id
+}
+
+// check worker skill
+func (n *nacos) CheckSkill(skill string) bool {
+	return discovery.CheckSkill(skill)
+}
+
+// start worker
+func (n *nacos) Start() error {
+	ctx, cancelFunc := context.WithCancel(context.Background())
+	n.context = ctx
+	n.cancelFunc = cancelFunc
+	go func() {
+		ticker := time.NewTicker(5 * time.Second)
+		defer ticker.Stop()
+	EXIT:
+		for {
+			select {
+			case <-ctx.Done():
+				break EXIT
+			case <-ticker.C:
+				{
+					keys := n.services.AppKeys()
+					for _, serviceName := range keys {
+						query := n.getParams(serviceName)
+						res, err := n.GetNodeList(query)
+						if err != nil {
+							continue
+						}
+						nodes := make([]discovery.INode, len(res))
+						for _, v := range res {
+							nodes = append(nodes, v)
+						}
+						n.services.Update(serviceName, nodes)
+					}
+				}
+			}
+
+		}
+	}()
+	return nil
+}
+
+// update worker config
+func (n *nacos) Reset(conf interface{}, workers map[eosc.RequireId]interface{}) error {
+	cfg, ok := conf.(*Config)
+	if !ok {
+		return fmt.Errorf("need %s,now %s:%w", eosc.TypeNameOf((*Config)(nil)), eosc.TypeNameOf(conf), eosc.ErrorStructType)
+	}
+	n.address = cfg.Config.Address
+	n.params = cfg.Config.Params
+	n.labels = cfg.Labels
+	return nil
+}
+
+// stop worker
+func (n *nacos) Stop() error {
+	n.cancelFunc()
+	return nil
+}
+
+// remove app by app_id
+func (n *nacos) Remove(id string) error {
+	return n.services.Remove(id)
+}
+
+// new app according to serviceName
+func (n *nacos) GetApp(serviceName string) (discovery.IApp, error) {
+	app, err := n.Create(serviceName)
+	if err != nil {
+		return nil, err
+	}
+	n.services.Set(serviceName, app.Id(), app)
+	return app, nil
+}
+
+// create nacos app
+func (n *nacos) Create(serviceName string) (discovery.IApp, error) {
+	query := n.getParams(serviceName)
+	nodes, err := n.GetNodeList(query)
+	if err != nil {
+		return nil, err
+	}
+	app := discovery.NewApp(nil, n, query, nodes)
+	return app, nil
+}
+
+// get app node list
+func (n *nacos) GetNodeList(query map[string]string) (map[string]discovery.INode, error) {
+	nodes := make(map[string]discovery.INode)
+	for _, addr := range n.address {
+		// 获取每个ip中指定服务名的实例列表
+		ins, err := n.GetInstanceList(addr, query)
+		if err != nil {
+			return nil, err
+		}
+
+		for _, host := range ins.Hosts {
+			label := map[string]string{
+				"valid":    strconv.FormatBool(host.Valid),
+				"marked":   strconv.FormatBool(host.Marked),
+				"weight":   strconv.FormatFloat(host.Weight, 'f', -1, 64),
+			}
+			node := discovery.NewNode(label, host.InstanceId, host.Ip, host.Port)
+			if _, ok := nodes[node.Id()]; ok {
+				continue
+			}
+			nodes[node.Id()] = node
+		}
+	}
+	return nodes, nil
+}
+
+// get app instance list
+func (n *nacos) GetInstanceList(addr string, query map[string]string) (*Instance, error) {
+	addr = addr + instancePath
+	if !strings.HasPrefix(addr, "http://") && !strings.HasPrefix(addr, "https://") {
+		addr = fmt.Sprintf("http://%s", addr)
+		if v,ok := n.labels["schema"]; ok {
+			if v == "https" {
+				addr = fmt.Sprintf("https://%s", addr)
+			}
+		}
+	}
+	response, err := SendRequest(http.MethodGet, addr, query, nil)
+	if err != nil {
+		return nil, err
+	}
+	// 解析响应数据
+	rawResponseData, err := ioutil.ReadAll(response.Body)
+	if err != nil {
+		return nil, err
+	}
+	err = response.Body.Close()
+	if err != nil {
+		return nil, err
+	}
+	var instance = &Instance{}
+	err = json.Unmarshal(rawResponseData, instance)
+	if err != nil {
+		return nil, err
+	}
+	return instance, nil
+}
diff --git a/discover-nacos/nacos_request.go b/discover-nacos/nacos_request.go
new file mode 100644
index 00000000..ea435b11
--- /dev/null
+++ b/discover-nacos/nacos_request.go
@@ -0,0 +1,70 @@
+package discover_nacos
+
+import (
+	"encoding/json"
+	"io"
+	"net/http"
+	"net/url"
+	"strings"
+)
+
+// nacos 实例结构
+type Instance struct {
+	Hosts []struct {
+		Valid      bool                   `json:"valid"`
+		Marked     bool                   `json:"marked"`
+		InstanceId string                 `json:"instanceId"`
+		Port       int                    `json:"port"`
+		Ip         string                 `json:"ip"`
+		Weight     float64                `json:"weight"`
+	}
+}
+
+func MapToJson(param map[string]interface{}) string {
+	dataType, _ := json.Marshal(param)
+	dataString := string(dataType)
+	return dataString
+}
+
+func SendRequest(method string, request string, query map[string]string, body map[string]string) (*http.Response, error) {
+	// 构造url参数字符串
+	paramsUrl := url.Values{}
+	for key, value := range query {
+		paramsUrl.Add(key, value)
+	}
+	// 更新url
+	paramsUrlString := paramsUrl.Encode()
+	if paramsUrlString != "" {
+		request = request + "?" + paramsUrlString
+	}
+	var bodyReader io.Reader
+	// 构造urlencoded请求体
+	if method == http.MethodPost || method == http.MethodPut {
+		bodyUrl := url.Values{}
+		for key, value := range body {
+			bodyUrl.Add(key, value)
+		}
+		bodyUrlString := bodyUrl.Encode()
+		bodyReader = strings.NewReader(bodyUrlString)
+	}
+	req, err := http.NewRequest(method, request, bodyReader)
+	if err != nil {
+		return nil, err
+	}
+	httpClient := &http.Client{}
+	response, err := httpClient.Do(req)
+	if err != nil {
+		return nil, err
+	}
+	return response, nil
+}
+// get nacos query parameters
+func (n *nacos) getParams(serviceName string) map[string]string {
+	query := n.params
+	query["serviceName"] = serviceName
+	if _, ok := query["healthyOnly"]; !ok {
+		query["healthyOnly"] = "true"
+	}
+	return query
+}
+
diff --git a/discover-nacos/nacos_test.go b/discover-nacos/nacos_test.go
new file mode 100644
index 00000000..b1557393
--- /dev/null
+++ b/discover-nacos/nacos_test.go
@@ -0,0 +1,27 @@
+package discover_nacos
+
+import (
+	"fmt"
+	"github.com/eolinker/goku-eosc/discovery"
+	"testing"
+)
+
+func TestNacos_GetApp(t *testing.T) {
+	serviceName := "nacos.naming.serviceName"
+	n := &nacos{
+		address: []string{
+			"39.108.94.48:8848",
+		},
+		params: map[string]string{
+			"username": "test",
+			"password": "test",
+		},
+		services:       discovery.NewServices(),
+		context:        nil,
+		cancelFunc:     nil,
+	}
+	app, _ := n.GetApp(serviceName)
+	for _, node := range app.Nodes(){
+		fmt.Println(node.Id())
+	}
+}
diff --git a/discovery-consul/config.go b/discovery-consul/config.go
new file mode 100644
index 00000000..2775b16c
--- /dev/null
+++ b/discovery-consul/config.go
@@ -0,0 +1,13 @@
+package discovery_consul
+
+type Config struct {
+	Name   string            `json:"name"`
+	Driver string            `json:"driver"`
+	Labels map[string]string `json:"labels"`
+	Config AccessConfig      `json:"config"`
+}
+
+type AccessConfig struct {
+	Address []string          `json:"address"`
+	Params  map[string]string `json:"params"`
+}
diff --git a/discovery-consul/consul.go b/discovery-consul/consul.go
new file mode 100644
index 00000000..0b489476
--- /dev/null
+++ b/discovery-consul/consul.go
@@ -0,0 +1,143 @@
+package discovery_consul
+
+import (
+	"context"
+	"fmt"
+	"github.com/eolinker/eosc"
+	"github.com/eolinker/eosc/log"
+	"time"
+
+	"github.com/eolinker/goku-eosc/discovery"
+)
+
+type consul struct {
+	id         string
+	name       string
+	address    []string
+	params     map[string]string
+	labels     map[string]string
+	services   discovery.IServices
+	context    context.Context
+	cancelFunc context.CancelFunc
+}
+
+// Start 开始服务发现
+func (c *consul) Start() error {
+	ctx, cancelFunc := context.WithCancel(context.Background())
+	c.context = ctx
+	c.cancelFunc = cancelFunc
+
+	go func() {
+		ticker := time.NewTicker(5 * time.Second)
+		defer ticker.Stop()
+	EXIT:
+		for {
+			select {
+			case <-ctx.Done():
+				break EXIT
+			case <-ticker.C:
+				{
+					keys := c.services.AppKeys()
+					for _, serviceName := range keys {
+						nodeSet, err := c.getNodes(serviceName)
+						if err != nil {
+							log.Error(err)
+							continue
+						}
+
+						nodes := make([]discovery.INode, 0, len(nodeSet))
+						for _, node := range nodeSet {
+							nodes = append(nodes, node)
+						}
+						c.services.Update(serviceName, nodes)
+					}
+				}
+
+			}
+
+		}
+
+	}()
+	return nil
+}
+
+// Reset 重置服务发现配置
+func (c *consul) Reset(config interface{}, workers map[eosc.RequireId]interface{}) error {
+	workerConfig, ok := config.(*Config)
+	if !ok {
+		return fmt.Errorf("need %s,now %s:%w", eosc.TypeNameOf((*Config)(nil)), eosc.TypeNameOf(config), eosc.ErrorStructType)
+	}
+
+	c.address = workerConfig.Config.Address
+	c.params = workerConfig.Config.Params
+	c.labels = workerConfig.Labels
+
+	return nil
+}
+
+// Stop 停止服务发现
+func (c *consul) Stop() error {
+	c.cancelFunc()
+	return nil
+}
+
+func (c *consul) Remove(id string) error {
+	return c.services.Remove(id)
+}
+
+// GetApp 获取服务发现应用
+func (c *consul) GetApp(serviceName string) (discovery.IApp, error) {
+	nodes, err := c.getNodes(serviceName)
+	if err != nil {
+		return nil, err
+	}
+
+	app, err := c.Create(serviceName, c.labels, nodes)
+	if err != nil {
+		return nil, err
+	}
+	c.services.Set(serviceName, app.Id(), app)
+	return app, nil
+}
+
+// Create 创建服务发现应用
+func (c *consul) Create(serviceName string, attrs map[string]string, nodes map[string]discovery.INode) (discovery.IApp, error) {
+	return discovery.NewApp(nil, c, attrs, nodes), nil
+}
+
+// Id 返回 worker id
+func (n *consul) Id() string {
+	return n.id
+}
+
+func (n *consul) CheckSkill(skill string) bool {
+	return discovery.CheckSkill(skill)
+}
+
+//getNodes 通过接入地址获取节点信息
+func (c *consul) getNodes(service string) (map[string]discovery.INode, error) {
+	//TODO Labels怎么处理
+
+	nodeSet := make(map[string]discovery.INode)
+
+	for _, addr := range c.address {
+		if !validAddr(addr) {
+			log.Errorf("address:%s is invalid", addr)
+			continue
+		}
+		client, err := getConsulClient(addr, c.params)
+		if err != nil {
+			log.Error(err)
+			continue
+		}
+
+		clientNodes := getNodesFromClient(client, service)
+		for _, node := range clientNodes {
+			if _, has := nodeSet[node.Id()]; !has {
+				nodeSet[node.Id()] = node
+			}
+		}
+	}
+
+	return nodeSet, nil
+}
diff --git a/discovery-consul/consul_test.go b/discovery-consul/consul_test.go
new file mode 100644
index 00000000..6763382b
--- /dev/null
+++ b/discovery-consul/consul_test.go
@@ -0,0 +1,29 @@
+package discovery_consul
+
+import (
+	"github.com/eolinker/eosc/log"
+	"github.com/eolinker/goku-eosc/discovery"
+	"testing"
+)
+
+func TestConsulGetNodes(t *testing.T) {
+	//创建consul
+
+	newConsul := &consul{
+		id:         "newConsul",
+		address:    []string{"39.108.94.48:8500", "39.108.94.48:8501"},
+		params:     map[string]string{"token": "a92316d8-5c99-4fa0-b4cd-30b9e66718aa"}, //token在39.108.94.48下的/opt/consul/server_config/node_3/conf/acl.hcl文件里
+		labels:     map[string]string{"scheme": "http"},
+		services:   discovery.NewServices(),
+		context:    nil,
+		cancelFunc: nil,
+	}
+
+	newConsul.Start()
+
+	APP, _ := newConsul.GetApp("consul")
+
+	log.Infof("%s", APP)
+
+	select {}
+}
diff --git a/discovery-consul/driver.go b/discovery-consul/driver.go
new file mode 100644
index 00000000..42b1884c
--- /dev/null
+++ b/discovery-consul/driver.go
@@ -0,0 +1,48 @@
+package discovery_consul
+
+import (
+	"fmt"
+	"github.com/eolinker/eosc"
+	"github.com/eolinker/goku-eosc/discovery"
+	"reflect"
+)
+
+const (
+	driverName = "consul"
+)
+
+//driver 实现github.com/eolinker/eosc.eosc.IProfessionDriver接口
+type driver struct {
+	profession string
+	name       string
+	driver     string
+	label      string
+	desc       string
+	configType reflect.Type
+	params     map[string]string
+}
+
+func NewDriver() *driver {
+	return &driver{configType: reflect.TypeOf(new(Config))}
+}
+
+func (d *driver) ConfigType() reflect.Type {
+	return d.configType
+}
+
+func (d *driver) Create(id, name string, v interface{}, workers map[eosc.RequireId]interface{}) (eosc.IWorker, error) {
+	workerConfig, ok := v.(*Config)
+	if !ok {
+		return nil, fmt.Errorf("need %s,now %s:%w", eosc.TypeNameOf((*Config)(nil)), eosc.TypeNameOf(v), eosc.ErrorStructType)
+	}
+	return &consul{
+		id:         id,
+		name:       name,
+		address:    workerConfig.Config.Address,
+		params:     workerConfig.Config.Params,
+		labels:     workerConfig.Labels,
+		services:   discovery.NewServices(),
+		context:    nil,
+		cancelFunc: nil,
+	}, nil
+}
diff --git a/discovery-consul/factory.go b/discovery-consul/factory.go
new file mode 100644
index 00000000..87579376
--- /dev/null
+++ b/discovery-consul/factory.go
@@ -0,0 +1,44 @@
+package discovery_consul
+
+import (
+	"reflect"
+
+	"github.com/eolinker/eosc"
+)
+
+func Register() {
+	eosc.DefaultProfessionDriverRegister.RegisterProfessionDriver("eolinker:goku:discovery_consul", NewFactory())
+}
+
+type factory struct {
+	profession string
+	name       string
+	label      string
+	desc       string
+	params     map[string]string
+}
+
+func NewFactory() *factory {
+	return &factory{}
+}
+
+func (f *factory) ExtendInfo() eosc.ExtendInfo {
+	return eosc.ExtendInfo{
+		ID:      "eolinker:goku:discovery_consul",
+		Group:   "eolinker",
+		Project: "goku",
+		Name:    "consul",
+	}
+}
+
+func (f *factory) Create(profession string, name string, label string, desc string, params map[string]string) (eosc.IProfessionDriver, error) {
+	return &driver{
+		profession: profession,
+		name:       name,
+		label:      label,
+		desc:       desc,
+		driver:     driverName,
+		configType: reflect.TypeOf((*Config)(nil)),
+		params:     params,
+	}, nil
+}
diff --git a/discovery-consul/utils.go b/discovery-consul/utils.go
new file mode 100644
index 00000000..293772e0
--- /dev/null
+++ b/discovery-consul/utils.go
@@ -0,0 +1,85 @@
+package discovery_consul
+
+import (
+	"github.com/eolinker/eosc/log"
+	"github.com/eolinker/goku-eosc/discovery"
+	"github.com/hashicorp/consul/api"
+	"regexp"
+	"strconv"
+	"strings"
+)
+
+// getConsulClient 创建并返回consul客户端
+func getConsulClient(addr string, param map[string]string) (*api.Client, error) {
+	defaultConfig := api.DefaultConfig()
+	//配置信息写入进defaultConfig里
+	defaultConfig.Address = addr
+	if _, has := param["token"]; has {
+		defaultConfig.Token = param["token"]
+	}
+
+	client, err := api.NewClient(defaultConfig)
+	if err != nil {
+		return nil, err
+	}
+
+	return client, nil
+}
+
+// getNodesFromClient 从连接的客户端返回健康的节点信息
+func getNodesFromClient(client *api.Client, service string) []discovery.INode {
+	queryOptions := &api.QueryOptions{}
+	serviceEntryArr, _, err := client.Health().Service(service, "", true, queryOptions)
+	//log.Info(serviceEntryArr)
+	//catalogService, _, err := client.Catalog().Service(service, "", queryOptions)
+	if err != nil {
+		return nil
+	}
+
+	nodes := make([]discovery.INode, 0, len(serviceEntryArr))
+	for _, serviceEntry := range serviceEntryArr {
+		nodeAddr := serviceEntry.Node.Address
+		addrSlide := append(strings.Split(nodeAddr, ":"))
+		ip := addrSlide[0]
+		var port int
+		if len(addrSlide) > 1 {
+			port, err = strconv.Atoi(addrSlide[1])
+			if err != nil {
+				log.Error(err)
+				continue
+			}
+		}
+
+		newNode := discovery.NewNode(serviceEntry.Service.Meta, serviceEntry.Node.ID, ip, port)
+		nodes = append(nodes, newNode)
+	}
+
+	return nodes
+}
+
+// validAddr 判断地址是否合法
+func validAddr(addr string) bool {
+	c := strings.Split(addr, ":")
+	if len(c) < 2 {
+		return false
+	}
+	ip := c[0]
+	if !validIP(ip) {
+		return false
+	}
+	_, err := strconv.Atoi(c[1])
+	if err != nil {
+		return false
+	}
+
+	return true
+}
+
+//validIP 判断ip是否合法
+func validIP(ip string) bool {
+	match, err := regexp.MatchString(`^(?:(?:1[0-9][0-9]\.)|(?:2[0-4][0-9]\.)|(?:25[0-5]\.)|(?:[1-9][0-9]\.)|(?:[0-9]\.)){3}(?:(?:1[0-9][0-9])|(?:2[0-4][0-9])|(?:25[0-5])|(?:[1-9][0-9])|(?:[0-9]))$`, ip)
+	if err != nil {
+		return false
+	}
+	return match
+}
diff --git a/discovery-static/config.go b/discovery-static/config.go
new file mode 100644
index 00000000..fe1066c2
--- /dev/null
+++ b/discovery-static/config.go
@@ -0,0 +1,23 @@
+package discovery_static
+
+type Config struct {
+	Name     string            `json:"name"`
+	Driver   string            `json:"driver"`
+	Labels   map[string]string `json:"labels"`
+	Health   *HealthConfig     `json:"health"`
+	HealthOn bool              `json:"health_on"`
+}
+
+type AccessConfig struct {
+	Address []string          `json:"address"`
+	Params  map[string]string `json:"params"`
+}
+
+type HealthConfig struct {
+	Protocol    string `json:"protocol"`
+	Method      string `json:"method"`
+	Url         string `json:"url"`
+	SuccessCode int    `json:"success_code"`
+	Period      int    `json:"period"`
+	Timeout     int    `json:"timeout"`
+}
diff --git a/discovery-static/driver.go b/discovery-static/driver.go
new file mode 100644
index 00000000..0607c869
--- /dev/null
+++ b/discovery-static/driver.go
@@ -0,0 +1,44 @@
+package discovery_static
+
+import (
+	"reflect"
+	"sync"
+
+	"github.com/eolinker/goku-eosc/discovery"
+
+	"github.com/eolinker/eosc"
+)
+
+const (
+	driverName = "static"
+)
+
+//driver 实现github.com/eolinker/eosc.eosc.IProfessionDriver接口
+type driver struct {
+	profession string
+	name       string
+	driver     string
+	label      string
+	desc       string
+	configType reflect.Type
+	params     map[string]string
+}
+
+func NewDriver() *driver {
+	return &driver{configType: reflect.TypeOf(new(Config))}
+}
+
+func (d *driver) ConfigType() reflect.Type {
+	return d.configType
+}
+
+func (d *driver) Create(id, name string, v interface{}, workers map[eosc.RequireId]interface{}) (eosc.IWorker, error) {
+	s := &static{
+		id:     id,
+		name:   name,
+		locker: sync.RWMutex{},
+		apps:   make(map[string]discovery.IApp),
+	}
+	s.Reset(v, workers)
+	return s, nil
+}
diff --git a/discovery-static/factory.go b/discovery-static/factory.go
new file mode 100644
index 00000000..643c1345
--- /dev/null
+++ b/discovery-static/factory.go
@@ -0,0 +1,44 @@
+package discovery_static
+
+import (
+	"reflect"
+
+	"github.com/eolinker/eosc"
+)
+
+func Register() {
+	eosc.DefaultProfessionDriverRegister.RegisterProfessionDriver("eolinker:goku:discovery_static", NewFactory())
+}
+
+type factory struct {
+	profession string
+	name       string
+	label      string
+	desc       string
+	params     map[string]string
+}
+
+func NewFactory() *factory {
+	return &factory{}
+}
+
+func (f *factory) ExtendInfo() eosc.ExtendInfo {
+	return eosc.ExtendInfo{
+		ID:      "eolinker:goku:discovery_static",
+		Group:   "eolinker",
+		Project: "goku",
+		Name:    "consul",
+	}
+}
+
+func (f *factory) Create(profession string, name string, label string, desc string, params map[string]string) (eosc.IProfessionDriver, error) {
+	return &driver{
+		profession: profession,
+		name:       name,
+		label:      label,
+		desc:       desc,
+		driver:     driverName,
+		configType: reflect.TypeOf((*Config)(nil)),
+		params:     params,
+	}, nil
+}
diff --git a/discovery-static/static.go b/discovery-static/static.go
new file mode 100644
index 00000000..34287bb5
--- /dev/null
+++ b/discovery-static/static.go
@@ -0,0 +1,212 @@
+package discovery_static
+
+import (
+	"context"
+	"fmt"
+	"regexp"
+	"strconv"
+	"strings"
+	"sync"
+	"time"
+	"unicode"
+
+	health_check_http "github.com/eolinker/goku-eosc/health-check-http"
+
+	"github.com/eolinker/eosc"
+	"github.com/eolinker/goku-eosc/discovery"
+)
+
+const name = "static"
+
+type static struct {
+	id         string
+	name       string
+	labels     map[string]string
+	apps       map[string]discovery.IApp
+	locker     sync.RWMutex
+	healthOn   bool
+	checker    *health_check_http.HttpCheck
+	context    context.Context
+	cancelFunc context.CancelFunc
+}
+
+func (s *static) Id() string {
+	return s.id
+}
+
+func (s *static) Start() error {
+	s.context, s.cancelFunc = context.WithCancel(context.Background())
+
+	return nil
+}
+
+func (s *static) Reset(conf interface{}, workers map[eosc.RequireId]interface{}) error {
+	cfg, ok := conf.(*Config)
+	if !ok {
+		return fmt.Errorf("need %s,now %s:%w", eosc.TypeNameOf((*Config)(nil)), eosc.TypeNameOf(conf), eosc.ErrorStructType)
+	}
+	s.locker.Lock()
+	s.labels = cfg.Labels
+	s.locker.Unlock()
+	if cfg.Health == nil {
+		s.healthOn = false
+	} else {
+		s.healthOn = cfg.HealthOn
+	}
+	if s.healthOn {
+		if s.checker == nil {
+			s.checker = health_check_http.NewHttpCheck(
+				health_check_http.Config{
+					Protocol:    cfg.Health.Protocol,
+					Method:      cfg.Health.Method,
+					Url:         cfg.Health.Url,
+					SuccessCode: cfg.Health.SuccessCode,
+					Period:      time.Duration(cfg.Health.Period) * time.Second,
+					Timeout:     time.Duration(cfg.Health.Timeout) * time.Millisecond,
+				})
+		} else {
+			s.checker.Reset(
+				health_check_http.Config{
+					Protocol:    cfg.Health.Protocol,
+					Method:      cfg.Health.Method,
+					Url:         cfg.Health.Url,
+					SuccessCode: cfg.Health.SuccessCode,
+					Period:      time.Duration(cfg.Health.Period) * time.Second,
+					Timeout:     time.Duration(cfg.Health.Timeout) * time.Millisecond,
+				},
+			)
+		}
+	} else {
+		if s.checker != nil {
+			s.checker.Stop()
+			s.checker = nil
+		}
+	}
+
+	return nil
+}
+
+func (s *static) Stop() error {
+	for _, a := range s.apps {
+		a.Close()
+	}
+	return nil
+}
+
+func (s *static) CheckSkill(skill string) bool {
+	return discovery.CheckSkill(skill)
+}
+
+func (s *static) GetApp(config string) (discovery.IApp, error) {
+	app, err := s.decode(config)
+	if err != nil {
+		return nil, err
+	}
+	s.locker.Lock()
+	s.apps[app.Id()] = app
+	s.locker.Unlock()
+	return app, nil
+}
+
+func (s *static) Remove(id string) error {
+	s.locker.Lock()
+	delete(s.apps, id)
+	s.locker.Unlock()
+	return nil
+}
+
+type Node struct {
+	labels map[string]string
+	ip     string
+	port   int
+}
+
+func (s *static) decode(config string) (discovery.IApp, error) {
+	words := fields(config)
+
+	nodes := make(map[string]discovery.INode)
+
+	index := 0
+	var node *Node
+	attrs := make(discovery.Attrs)
+	for _, word := range words {
+
+		if word == ";" {
+			index = 0
+			node = nil
+			continue
+		}
+		l := len(word)
+		value := word
+		if word[l-1] == ';' {
+			value = word[:l-1]
+		}
+		switch index {
+		case 0:
+			{
+				// 域名+端口
+				node = new(Node)
+				vs := strings.Split(value, ":")
+				// 先判断是否是IP端口模式
+				if !validIP(vs[0]) {
+					// 若不是IP端口模式，则计入全局的属性
+					args := strings.Split(vs[0], "=")
+					if len(args) > 1 {
+						node.labels[args[0]] = args[1]
+					}
+					break
+				}
+				if len(vs) > 2 {
+					return nil, fmt.Errorf("decode ip:port failt for[%s]", value)
+				}
+				node.ip = vs[0]
+				if len(vs) == 2 {
+					port, _ := strconv.Atoi(vs[1])
+					node.port = port
+				}
+
+			}
+		default:
+			{
+				// label集合
+				args := strings.Split(value, "=")
+				if len(args) > 1 {
+					node.labels[args[0]] = args[1]
+				}
+			}
+		}
+
+		if word[l-1] == ';' {
+			n := discovery.NewNode(node.labels, fmt.Sprintf("%s:%d", node.ip, node.port), node.ip, node.port)
+			nodes[n.Id()] = n
+			index = 0
+			node = nil
+		} else {
+			index++
+		}
+	}
+	agent := (discovery.IHealthChecker)(nil)
+	if s.checker != nil {
+		agent, _ = s.checker.Agent()
+	}
+
+	app := discovery.NewApp(agent, s, attrs, nodes)
+	return app, nil
+}
+
+func fields(str string) []string {
+
+	words := strings.FieldsFunc(strings.Join(strings.Split(str, ";"), " ; "), func(r rune) bool {
+		return unicode.IsSpace(r)
+	})
+	return words
+}
+
+//validIP 判断ip是否合法
+func validIP(ip string) bool {
+	match, err := regexp.MatchString(`^(?:(?:1[0-9][0-9]\.)|(?:2[0-4][0-9]\.)|(?:25[0-5]\.)|(?:[1-9][0-9]\.)|(?:[0-9]\.)){3}(?:(?:1[0-9][0-9])|(?:2[0-4][0-9])|(?:25[0-5])|(?:[1-9][0-9])|(?:[0-9]))$`, ip)
+	if err != nil {
+		return false
+	}
+	return match
+}
diff --git a/discovery/app.go b/discovery/app.go
new file mode 100644
index 00000000..ef758581
--- /dev/null
+++ b/discovery/app.go
@@ -0,0 +1,89 @@
+package discovery
+
+import (
+	"sync"
+
+	"github.com/go-basic/uuid"
+)
+
+type app struct {
+	id            string
+	nodes         map[string]INode
+	healthChecker IHealthChecker
+	attrs         Attrs
+	locker        sync.RWMutex
+	container     IAppContainer
+}
+
+func (s *app) Reset(nodes []INode) {
+	tmp := make(map[string]INode)
+
+	for _, node := range nodes {
+
+		if n, has := s.nodes[node.Id()]; has {
+			n.Leave()
+		}
+		tmp[node.Id()] = node
+
+	}
+	s.locker.Lock()
+	s.nodes = tmp
+	s.locker.Unlock()
+}
+
+func (s *app) GetAttrs() Attrs {
+	return s.attrs
+}
+
+func (s *app) GetAttrByName(name string) (string, bool) {
+	attr, ok := s.attrs[name]
+	return attr, ok
+}
+
+func NewApp(checker IHealthChecker, container IAppContainer, attrs Attrs, nodes map[string]INode) IApp {
+	return &app{
+		attrs:         attrs,
+		nodes:         nodes,
+		locker:        sync.RWMutex{},
+		healthChecker: checker,
+		id:            uuid.New(),
+		container:     container,
+	}
+}
+
+func (s *app) Id() string {
+	return s.id
+}
+
+//Nodes 将运行中的节点列表返回
+func (s *app) Nodes() []INode {
+	s.locker.RLock()
+	defer s.locker.RUnlock()
+	nodes := make([]INode, 0, len(s.nodes))
+	for _, node := range s.nodes {
+		if node.Status() != Running {
+			continue
+		}
+		nodes = append(nodes, node)
+	}
+	return nodes
+}
+
+//NodeError 定时检查节点，当节点失败时，则返回错误
+func (s *app) NodeError(id string) error {
+	s.locker.Lock()
+	defer s.locker.Unlock()
+	if n, ok := s.nodes[id]; ok {
+		n.Down()
+		if s.healthChecker != nil {
+			err := s.healthChecker.AddToCheck(n)
+			return err
+		}
+	}
+	return nil
+}
+
+func (s *app) Close() error {
+	s.container.Remove(s.id)
+	return s.healthChecker.Stop()
+}
diff --git a/discovery/checker.go b/discovery/checker.go
new file mode 100644
index 00000000..5df27285
--- /dev/null
+++ b/discovery/checker.go
@@ -0,0 +1,14 @@
+package discovery
+
+//IHealthCheckerFactory 健康检查工厂类接口
+type IHealthCheckerFactory interface {
+	IHealthChecker
+	Agent() (IHealthChecker, error)
+	Reset(conf interface{}) error
+}
+
+//IHealthChecker 健康检查接口
+type IHealthChecker interface {
+	AddToCheck(node INode) error
+	Stop() error
+}
diff --git a/discovery/discovery.go b/discovery/discovery.go
new file mode 100644
index 00000000..79cd7268
--- /dev/null
+++ b/discovery/discovery.go
@@ -0,0 +1,55 @@
+package discovery
+
+func CheckSkill(skill string) bool {
+	return skill == "github.com/eolinker/goku-eosc/discovery.discovery.IDiscovery"
+}
+
+//IDiscovery 服务发现接口
+type IDiscovery interface {
+	GetApp(config string) (IApp, error)
+}
+
+//IApp app接口
+type IApp interface {
+	IAttributes
+	Id() string
+	Nodes() []INode
+	Reset([]INode)
+	NodeError(id string) error
+	Close() error
+}
+
+//IAppContainer app容器接口
+type IAppContainer interface {
+	Remove(id string) error
+}
+
+//INode 节点接口
+type INode interface {
+	IAttributes
+	Id() string
+	Ip() string
+	Port() int
+	Addr() string
+	Status() NodeStatus
+	Up()
+	Down()
+	Leave()
+}
+
+//Attrs 属性集合
+type Attrs map[string]string
+
+//IAttributes 属性接口
+type IAttributes interface {
+	GetAttrs() Attrs
+	GetAttrByName(name string) (string, bool)
+}
+
+type NodeStatus int
+
+const (
+	Running NodeStatus = 1
+	Down    NodeStatus = 2
+	Leave   NodeStatus = 3
+)
diff --git a/discovery/node.go b/discovery/node.go
new file mode 100644
index 00000000..02607961
--- /dev/null
+++ b/discovery/node.go
@@ -0,0 +1,65 @@
+package discovery
+
+import (
+	"fmt"
+)
+
+func NewNode(labels map[string]string, id string, ip string, port int) *Node {
+	return &Node{labels: labels, id: id, ip: ip, port: port, status: Running}
+}
+
+type Node struct {
+	labels Attrs
+	id     string
+	ip     string
+	port   int
+	status NodeStatus
+}
+
+func (n *Node) GetAttrs() Attrs {
+	return n.labels
+}
+
+func (n *Node) GetAttrByName(name string) (string, bool) {
+	v, ok := n.labels[name]
+	return v, ok
+}
+
+func (n *Node) Ip() string {
+	return n.ip
+}
+
+func (n *Node) Port() int {
+	return n.port
+}
+
+func (n *Node) Id() string {
+	return n.id
+}
+
+func (n *Node) Status() NodeStatus {
+	return n.status
+}
+
+func (n *Node) Labels() map[string]string {
+	return n.labels
+}
+
+func (n *Node) Addr() string {
+	if n.port == 0 {
+		return n.ip
+	}
+	return fmt.Sprintf("%s:%d", n.ip, n.port)
+}
+
+func (n *Node) Up() {
+	n.status = Running
+}
+
+func (n *Node) Down() {
+	n.status = Down
+}
+
+func (n *Node) Leave() {
+	n.status = Leave
+}
diff --git a/discovery/services.go b/discovery/services.go
new file mode 100644
index 00000000..4ee68580
--- /dev/null
+++ b/discovery/services.go
@@ -0,0 +1,67 @@
+package discovery
+
+import "github.com/eolinker/eosc/internal"
+
+type Services struct {
+	apps        internal.IUntyped
+	appNameOfId internal.IUntyped
+}
+
+func NewServices() *Services {
+	return &Services{apps: internal.NewUntyped(), appNameOfId: internal.NewUntyped()}
+}
+
+func (n *Services) get(namespace string) (internal.IUntyped, bool) {
+	v, ok := n.apps.Get(namespace)
+	if !ok {
+		return nil, ok
+	}
+	apps, ok := v.(internal.IUntyped)
+	return apps, ok
+}
+
+func (s *Services) Set(serviceName string, id string, app IApp) error {
+	s.appNameOfId.Set(id, serviceName)
+	if apps, ok := s.get(serviceName); ok {
+		apps.Set(id, app)
+		return nil
+	}
+	apps := internal.NewUntyped()
+	apps.Set(id, app)
+	s.apps.Set(serviceName, apps)
+	return nil
+}
+
+func (s *Services) Remove(id string) error {
+	v, has := s.appNameOfId.Del(id)
+	if has {
+		apps, ok := s.get(v.(string))
+		if ok {
+			apps.Del(id)
+		}
+	}
+	return nil
+}
+
+func (s *Services) Update(serviceName string, nodes []INode) error {
+	if apps, ok := s.get(serviceName); ok {
+		for _, r := range apps.List() {
+			v, ok := r.(IApp)
+			if ok {
+				v.Reset(nodes)
+			}
+		}
+	}
+	return nil
+}
+
+func (s *Services) AppKeys() []string {
+	return s.apps.Keys()
+}
+
+type IServices interface {
+	Set(serviceName string, id string, app IApp) error
+	Remove(id string) error
+	Update(serviceName string, nodes []INode) error
+	AppKeys() []string
+}
diff --git a/example/config.go b/example/config.go
new file mode 100644
index 00000000..5e5984aa
--- /dev/null
+++ b/example/config.go
@@ -0,0 +1,9 @@
+package example
+
+import "github.com/eolinker/eosc"
+
+type Config struct {
+	Name string `json:"name"`
+	Label string `json:"label"`
+	Target eosc.RequireId `json:"target"`
+}
diff --git a/example/driver.go b/example/driver.go
new file mode 100644
index 00000000..97419ad6
--- /dev/null
+++ b/example/driver.go
@@ -0,0 +1,26 @@
+package example
+
+import (
+	"errors"
+	"github.com/eolinker/eosc"
+	"reflect"
+)
+
+type Driver struct {
+	configType reflect.Type
+	params     map[string]string
+}
+
+func (h *Driver) Create(id, name string, v interface{}, workers map[eosc.RequireId]interface{}) (eosc.IWorker, error) {
+	config, ok := v.(*Config)
+	if !ok {
+		return nil, errors.New("error")
+	}
+
+	return NewExample(config, workers), nil
+}
+func (h *Driver) ConfigType() reflect.Type {
+
+	return reflect.TypeOf(new(Config))
+
+}
diff --git a/example/employee.go b/example/employee.go
new file mode 100644
index 00000000..a8ffa2f5
--- /dev/null
+++ b/example/employee.go
@@ -0,0 +1,48 @@
+package example
+
+import (
+	"github.com/eolinker/eosc"
+	"github.com/eolinker/goku-eosc/service"
+	"net/http"
+)
+
+var (
+	_ eosc.IWorker = (*Example)(nil)
+)
+
+type Example struct {
+	skill  map[string]bool
+	name   string
+	target service.IService
+}
+
+func (e *Example) Id() string {
+	panic("implement me")
+}
+
+func (e *Example) Start() error {
+	panic("implement me")
+}
+
+func (e *Example) Reset(conf interface{}, workers map[eosc.RequireId]interface{}) error {
+	panic("implement me")
+}
+
+func (e *Example) Stop() error {
+	panic("implement me")
+}
+
+func (e *Example) CheckSkill(skill string) bool {
+	panic("implement me")
+}
+
+func (e *Example) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+
+}
+
+func NewExample(c *Config, workers map[eosc.RequireId]interface{}) *Example {
+
+	return &Example{
+		name: c.Name,
+	}
+}
diff --git a/example/register.go b/example/register.go
new file mode 100644
index 00000000..c2d27060
--- /dev/null
+++ b/example/register.go
@@ -0,0 +1,37 @@
+package example
+
+import (
+	"github.com/eolinker/eosc"
+	"reflect"
+)
+
+func Register() {
+	eosc.DefaultProfessionDriverRegister.RegisterProfessionDriver("eolinker:goku:example", NewRouterDriverFactory())
+}
+
+type RouterDriverFactory struct {
+}
+
+func NewRouterDriverFactory() *RouterDriverFactory {
+	return &RouterDriverFactory{}
+}
+
+func (r *RouterDriverFactory) ExtendInfo() eosc.ExtendInfo {
+	return eosc.ExtendInfo{
+		ID:      "eolinker:goku:example",
+		Group:   "eolinker",
+		Project: "goku",
+		Name:    "example",
+	}
+}
+
+func (r *RouterDriverFactory) Create(profession, name, label, desc string, params map[string]string) (eosc.IProfessionDriver, error) {
+	if params == nil {
+		params = make(map[string]string)
+	}
+	return &Driver{
+
+		configType: reflect.TypeOf(new(Config)),
+		params:     params,
+	}, nil
+}
diff --git a/go.mod b/go.mod
new file mode 100644
index 00000000..4d931360
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,10 @@
+module github.com/eolinker/goku-eosc
+
+go 1.15
+
+require (
+	github.com/eolinker/eosc v0.0.0-20210719112509-35868a3fa3ed
+	github.com/ghodss/yaml v1.0.0
+	github.com/go-basic/uuid v1.0.0
+	github.com/hashicorp/consul/api v1.9.1
+)
diff --git a/go.sum b/go.sum
new file mode 100644
index 00000000..4b2dffa3
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,110 @@
+github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
+github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da h1:8GUt8eRujhVEGZFFEjBj46YV4rDjvGrNxb0KMWYkL2I=
+github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
+github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
+github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
+github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/eolinker/eosc v0.0.0-20210719112509-35868a3fa3ed h1:ohyziPArYFDUmaMkjfmy7h7v1vZKxmhERBwb1Vup39U=
+github.com/eolinker/eosc v0.0.0-20210719112509-35868a3fa3ed/go.mod h1:h9RyDaBnWKeg6fxQu8faG8TQq/sdG+ipaePTTVTEqqA=
+github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
+github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
+github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
+github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
+github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/go-basic/uuid v1.0.0 h1:Faqtetcr8uwOzR2qp8RSpkahQiv4+BnJhrpuXPOo63M=
+github.com/go-basic/uuid v1.0.0/go.mod h1:yVtVnsXcmaLc9F4Zw7hTV7R0+vtuQw00mdXi+F6tqco=
+github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/hashicorp/consul v1.10.1 h1:hVHyC7kdfZWS9c2QURt5hr87xqrOKT99zRXbxmo3e/8=
+github.com/hashicorp/consul/api v1.9.1 h1:SngrdG2L62qqLsUz85qcPhFZ78rPf8tcD5qjMgs6MME=
+github.com/hashicorp/consul/api v1.9.1/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M=
+github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms=
+github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM=
+github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
+github.com/hashicorp/go-hclog v0.12.0 h1:d4QkX8FRTYaKaCZBoXYY8zJX2BXjWxurN/GA2tkrmZM=
+github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
+github.com/hashicorp/go-immutable-radix v1.0.0 h1:AKDB1HM5PWEA7i4nhcpwOrO2byshxBjXVn/J/3+z5/0=
+github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
+github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
+github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
+github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
+github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc=
+github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
+github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
+github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
+github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo=
+github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
+github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY=
+github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=
+github.com/hashicorp/serf v0.9.5 h1:EBWvyu9tcRszt3Bxp3KNssBMP1KuHWyO51lz9+786iM=
+github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk=
+github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
+github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
+github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
+github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE=
+github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
+github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
+github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
+github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
+github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
+github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
+github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
+github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
+github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=
+github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
+github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
+github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
+github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
+github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
+github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
+github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
+golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
diff --git a/health-check-http/agent.go b/health-check-http/agent.go
new file mode 100644
index 00000000..0d2dce91
--- /dev/null
+++ b/health-check-http/agent.go
@@ -0,0 +1,25 @@
+package health_check_http
+
+import "github.com/eolinker/goku-eosc/discovery"
+
+type Agent struct {
+	agentId string
+	*HttpCheck
+}
+
+func NewAgent(agentId string) *Agent {
+	return &Agent{agentId: agentId}
+}
+
+func (a *Agent) AddToCheck(node discovery.INode) error {
+	a.addToCheck(&checkNode{
+		node:    node,
+		agentId: a.agentId,
+	})
+	return nil
+}
+
+func (a *Agent) Stop() error {
+	a.stop(a.agentId)
+	return nil
+}
diff --git a/health-check-http/check.go b/health-check-http/check.go
new file mode 100644
index 00000000..5062915f
--- /dev/null
+++ b/health-check-http/check.go
@@ -0,0 +1,77 @@
+package health_check_http
+
+//
+//type checker struct {
+//	ctx        context.Context
+//	cancelFunc context.CancelFunc
+//	ch         chan *checkNode
+//	config     *Config
+//	id         string
+//}
+//
+//func (c *checker) doCheckLoop() {
+//	nodes := make(map[string]map[string]discovery.INode)
+//	for {
+//		select {
+//		case <-c.ctx.Done():
+//			{
+//				return
+//			}
+//		case n, ok := <-c.ch:
+//			{
+//
+//			}
+//		}
+//	}
+//}
+//
+//func (c *checker) AddToCheck(node discovery.INode) error {
+//	n := &checkNode{
+//		node: node,
+//		from: c.id,
+//	}
+//	c.ch <- n
+//	return nil
+//}
+//
+//func (c *checker) Stop() error {
+//	c.cancelFunc()
+//	return nil
+//}
+//
+//type checkNode struct {
+//	node discovery.INode
+//	from string
+//}
+//
+//func NewHealthCheck(conf interface{}) (discovery.IHealthChecker, error) {
+//	ctx, cancel := context.WithCancel(context.Background())
+//	ch := make(chan *checkNode, 10)
+//	c := &checker{
+//		ctx:        ctx,
+//		cancelFunc: cancel,
+//		ch:         ch,
+//	}
+//	return c, nil
+//}
+//
+//func (c *checker) check() error {
+//	for _, checkNode := range c.nodes {
+//		uri := fmt.Sprintf("%s://%s/%s", c.config.Protocol, strings.TrimSuffix(checkNode.checkNode.Addr(), "/"), strings.TrimPrefix(c.config.Url, "/"))
+//		c.client.Timeout = c.config.Timeout
+//		request, err := http.NewRequest(c.config.Method, uri, nil)
+//		if err != nil {
+//			return err
+//		}
+//		resp, err := c.client.Do(request)
+//		if err != nil {
+//			return err
+//		}
+//		defer resp.Body.Close()
+//		if c.config.SuccessCode != resp.StatusCode {
+//			return errors.New("error status code")
+//		}
+//
+//	}
+//	return nil
+//}
diff --git a/health-check-http/checker-demo.go b/health-check-http/checker-demo.go
new file mode 100644
index 00000000..7c35835c
--- /dev/null
+++ b/health-check-http/checker-demo.go
@@ -0,0 +1,108 @@
+package health_check_http
+
+//var supportMethods = []string{
+//	"POST", "GET", "PUT", "DELETE", "OPTIONS", "HEAD", "OPTIONS",
+//}
+//
+//type checkerFactory struct {
+//	c          chan *checkNode
+//	ctx        context.Context
+//	cancelFunc context.CancelFunc
+//}
+//
+//type checkNode struct {
+//	checkNode discovery.INode
+//	from      string
+//	IsRemove  bool
+//}
+//
+//func NewCheckerFactory() *checkerFactory {
+//
+//	ctx, cancelFunc := context.WithCancel(context.Background())
+//	ch := make(chan *checkNode, 10)
+//
+//	c := checkerFactory{
+//		c:          ch,
+//		ctx:        ctx,
+//		cancelFunc: cancelFunc,
+//	}
+//	go c.doCheckLoop()
+//	return &c
+//}
+//func (c *checkerFactory) doCheckLoop() {
+//	for {
+//		select {
+//		case <-c.ctx.Done():
+//			{
+//				return
+//			}
+//		case checkNode, ok := <-c.c:
+//			{
+//
+//			}
+//
+//		}
+//	}
+//}
+//func (c *checkerFactory) Create(config interface{}) (discovery.IHealthChecker, error) {
+//	cfg, ok := config.(*Config)
+//	if !ok {
+//		return nil, errors.New("fail to create health checker")
+//	}
+//	validMethod := false
+//	for _, method := range supportMethods {
+//		if method == cfg.Method {
+//			validMethod = true
+//			break
+//		}
+//	}
+//	if !validMethod {
+//		return nil, errors.New("error request method")
+//	}
+//	return &checker{config: cfg, client: &http.Client{}}, nil
+//}
+//
+//type checker struct {
+//	id     string
+//	config *Config
+//	client *http.Client
+//	nodes  map[string]*checkNode
+//
+//	ch chan *checkNode
+//}
+//
+//func (c *checker) AddToCheck(checkNode discovery.INode) error {
+//	n := &checkNode{
+//		checkNode: checkNode,
+//		from:      c.id,
+//	}
+//	c.ch <- n
+//	c.nodes[checkNode.Id()] = n
+//	return nil
+//}
+//
+//func (c *checker) Stop() error {
+//
+//	return nil
+//}
+//
+//func (c *checker) check() error {
+//	for _, checkNode := range c.nodes {
+//		uri := fmt.Sprintf("%s://%s/%s", c.config.Protocol, strings.TrimSuffix(checkNode.checkNode.Addr(), "/"), strings.TrimPrefix(c.config.Url, "/"))
+//		c.client.Timeout = c.config.Timeout
+//		request, err := http.NewRequest(c.config.Method, uri, nil)
+//		if err != nil {
+//			return err
+//		}
+//		resp, err := c.client.Do(request)
+//		if err != nil {
+//			return err
+//		}
+//		defer resp.Body.Close()
+//		if c.config.SuccessCode != resp.StatusCode {
+//			return errors.New("error status code")
+//		}
+//
+//	}
+//	return nil
+//}
diff --git a/health-check-http/config.go b/health-check-http/config.go
new file mode 100644
index 00000000..2fa8aed2
--- /dev/null
+++ b/health-check-http/config.go
@@ -0,0 +1,12 @@
+package health_check_http
+
+import "time"
+
+type Config struct {
+	Protocol    string
+	Method      string
+	Url         string
+	SuccessCode int
+	Period      time.Duration
+	Timeout     time.Duration
+}
diff --git a/health-check-http/http-check.go b/health-check-http/http-check.go
new file mode 100644
index 00000000..4230bf88
--- /dev/null
+++ b/health-check-http/http-check.go
@@ -0,0 +1,142 @@
+package health_check_http
+
+import (
+	"context"
+	"fmt"
+	"net/http"
+	"strings"
+	"sync"
+	"time"
+
+	"github.com/eolinker/eosc/log"
+
+	"github.com/eolinker/goku-eosc/discovery"
+	"github.com/go-basic/uuid"
+)
+
+func NewHttpCheck(config Config) *HttpCheck {
+	ctx, cancel := context.WithCancel(context.Background())
+
+	checker := &HttpCheck{
+		config: &config,
+		ctx:    ctx,
+		cancel: cancel,
+		ch:     make(chan *checkNode, 10),
+		client: &http.Client{},
+		locker: sync.RWMutex{},
+	}
+	go checker.doCheckLoop()
+	return checker
+}
+
+type HttpCheck struct {
+	config *Config
+	ctx    context.Context
+	cancel context.CancelFunc
+	ch     chan *checkNode
+	delCh  chan string
+	client *http.Client
+	locker sync.RWMutex
+}
+
+func (h *HttpCheck) doCheckLoop() {
+	ticker := time.NewTicker(h.config.Period)
+	nodes := map[string]map[string]*checkNode{}
+	defer ticker.Stop()
+	for {
+		select {
+		case <-h.ctx.Done():
+			return
+		case <-ticker.C:
+			{
+				nodes = h.check(nodes)
+			}
+		case node, ok := <-h.ch:
+			{
+				if ok {
+					if _, ok := nodes[node.agentId]; !ok {
+						nodes[node.agentId] = make(map[string]*checkNode)
+					}
+					nodes[node.agentId][node.node.Id()] = node
+				}
+			}
+		case id, ok := <-h.delCh:
+			{
+				if ok {
+					delete(nodes, id)
+				}
+			}
+		}
+	}
+}
+
+func (h *HttpCheck) Agent() (discovery.IHealthChecker, error) {
+	return NewAgent(uuid.New()), nil
+}
+
+func (h *HttpCheck) Reset(conf Config) error {
+	h.config = &conf
+	return nil
+}
+
+func (h *HttpCheck) AddToCheck(node discovery.INode) error {
+	h.addToCheck(&checkNode{
+		node:    node,
+		agentId: "",
+	})
+	return nil
+}
+
+func (h *HttpCheck) addToCheck(node *checkNode) error {
+	h.ch <- node
+	return nil
+}
+
+func (h *HttpCheck) Stop() error {
+	h.cancel()
+	return nil
+}
+
+func (h *HttpCheck) stop(id string) {
+	h.delCh <- id
+}
+
+func (h *HttpCheck) check(nodes map[string]map[string]*checkNode) map[string]map[string]*checkNode {
+	newNodes := make(map[string][]*checkNode)
+	for _, ns := range nodes {
+		for _, n := range ns {
+			if n.node.Status() == discovery.Down {
+				newNodes[n.node.Addr()] = append(newNodes[n.node.Addr()], n)
+			}
+		}
+	}
+	for addr, ns := range newNodes {
+		uri := fmt.Sprintf("%s://%s/%s", h.config.Protocol, strings.TrimSuffix(addr, "/"), strings.TrimPrefix(h.config.Url, "/"))
+		h.client.Timeout = h.config.Timeout
+		request, err := http.NewRequest(h.config.Method, uri, nil)
+		if err != nil {
+			log.Error(err)
+			continue
+		}
+		resp, err := h.client.Do(request)
+		if err != nil {
+			log.Error(err)
+			continue
+		}
+		resp.Body.Close()
+		if h.config.SuccessCode != resp.StatusCode {
+			log.Error(err)
+			continue
+		}
+		for _, n := range ns {
+			n.node.Up()
+			delete(nodes[n.agentId], n.node.Id())
+		}
+	}
+	return nodes
+}
+
+type checkNode struct {
+	node    discovery.INode
+	agentId string
+}
diff --git a/http-proxy/http-proxy-request/request.go b/http-proxy/http-proxy-request/request.go
new file mode 100644
index 00000000..347ec230
--- /dev/null
+++ b/http-proxy/http-proxy-request/request.go
@@ -0,0 +1,239 @@
+package http_proxy_request
+
+import (
+	"bytes"
+	"crypto/tls"
+	"errors"
+	"io"
+	"net/http"
+	"net/url"
+
+	http_context "github.com/eolinker/eosc/node/http-context"
+
+	// "fmt"
+	"time"
+)
+
+//Version 版本号
+var Version = "2.0"
+
+var (
+	transport = &http.Transport{TLSClientConfig: &tls.Config{
+		InsecureSkipVerify: false,
+	}}
+	httpClient = &http.Client{
+		Transport: transport,
+	}
+)
+
+//SetCert 设置证书配置
+func SetCert(skip int, clientCerts []tls.Certificate) {
+	tlsConfig := &tls.Config{InsecureSkipVerify: skip == 1, Certificates: clientCerts}
+	transport.TLSClientConfig = tlsConfig
+}
+
+//Request request
+type Request struct {
+	client  *http.Client
+	method  string
+	url     string
+	headers map[string][]string
+	body    []byte
+
+	queryParams map[string][]string
+
+	timeout     time.Duration
+	httpRequest *http.Request
+}
+
+func (r *Request) SetQueryParams(queryParams url.Values) {
+	r.queryParams = queryParams
+}
+
+func (r *Request) SetHeaders(headers http.Header) {
+	r.headers = headers
+}
+
+func (r *Request) Body() []byte {
+	return r.body
+}
+
+func (r *Request) HttpRequest() *http.Request {
+	return r.httpRequest
+}
+
+//NewRequest 创建新请求
+func NewRequest(method string, URL *url.URL) (*Request, error) {
+	if method != "GET" && method != "POST" && method != "PUT" && method != "DELETE" &&
+		method != "HEAD" && method != "OPTIONS" && method != "PATCH" {
+		return nil, errors.New("Unsupported Request method")
+	}
+	return newRequest(method, URL)
+}
+
+//URLPath urlPath
+func URLPath(url string, query url.Values) string {
+	if len(query) < 1 {
+		return url
+	}
+	return url + "?" + query.Encode()
+}
+
+func newRequest(method string, URL *url.URL) (*Request, error) {
+	var urlPath string
+	queryParams := make(map[string][]string)
+	for key, values := range URL.Query() {
+		queryParams[key] = values
+	}
+	urlPath = URL.Scheme + "://" + URL.Host + URL.Path
+
+	r := &Request{
+
+		client:      httpClient,
+		method:      method,
+		url:         urlPath,
+		headers:     make(map[string][]string),
+		queryParams: queryParams,
+	}
+	return r, nil
+}
+
+//SetHeader 设置请求头
+func (r *Request) SetHeader(key string, values ...string) {
+	if len(values) > 0 {
+		r.headers[key] = values[:]
+	} else {
+		delete(r.headers, key)
+	}
+}
+
+//Headers 获取请求头
+func (r *Request) Headers() map[string][]string {
+	headers := make(map[string][]string)
+	for key, values := range r.headers {
+		headers[key] = values[:]
+	}
+	return headers
+}
+
+//SetQueryParam 设置Query参数
+func (r *Request) SetQueryParam(key string, values ...string) {
+	if len(values) > 0 {
+		r.queryParams[key] = values[:]
+	} else {
+		delete(r.queryParams, key)
+	}
+}
+
+//SetTimeout 设置请求超时时间
+func (r *Request) SetTimeout(timeout time.Duration) {
+	r.timeout = timeout
+}
+
+//send 发送请求
+func (r *Request) Send(ctx *http_context.Context) (*http.Response, error) {
+	req := r.HttpRequest()
+	req.Header.Set("Accept-Encoding", "gzip")
+	req.Header = parseHeaders(r.headers)
+
+	r.client.Timeout = r.timeout
+
+	httpResponse, err := r.client.Do(req)
+
+	return httpResponse, err
+}
+
+//QueryParams 获取query参数
+func (r *Request) QueryParams() map[string][]string {
+	params := make(map[string][]string)
+	for key, values := range r.queryParams {
+		params[key] = values[:]
+	}
+	return params
+}
+
+//URLPath 获取完整的URL路径
+func (r *Request) URLPath() string {
+	if len(r.queryParams) > 0 {
+		return r.url + "?" + parseParams(r.queryParams).Encode()
+	}
+	return r.url
+}
+
+//SetURL 设置URL
+func (r *Request) SetURL(url string) {
+	r.url = url
+}
+
+//SetRawBody 设置源数据
+func (r *Request) SetRawBody(body []byte) {
+	r.body = body
+}
+
+// 解析请求头
+func parseHeaders(headers map[string][]string) http.Header {
+	h := http.Header{}
+	for key, values := range headers {
+		for _, value := range values {
+			h.Add(key, value)
+		}
+	}
+
+	_, hasAccept := h["Accept"]
+	if !hasAccept {
+		h.Add("Accept", "*/*")
+	}
+	_, hasAgent := h["User-Agent"]
+	if !hasAgent {
+		h.Add("User-Agent", "goku-requests/"+Version)
+	}
+	return h
+}
+
+// 解析请求体
+func (r *Request) ParseBody() error {
+	if r.httpRequest == nil {
+		var body io.Reader = nil
+		if len(r.body) > 0 {
+			body = bytes.NewBuffer(r.body)
+		}
+		request, err := http.NewRequest(r.method, r.URLPath(), body)
+		if err != nil {
+			return err
+		}
+		r.httpRequest = request
+	}
+	return nil
+}
+
+// 解析参数
+func parseParams(params map[string][]string) url.Values {
+	v := url.Values{}
+	for key, values := range params {
+		for _, value := range values {
+			v.Add(key, value)
+		}
+	}
+	return v
+}
+
+// 解析URL
+func parseURL(urlPath string) (URL *url.URL, err error) {
+	URL, err = url.Parse(urlPath)
+	if err != nil {
+		return nil, err
+	}
+
+	if URL.Scheme != "http" && URL.Scheme != "https" {
+		urlPath = "http://" + urlPath
+		URL, err = url.Parse(urlPath)
+		if err != nil {
+			return nil, err
+		}
+
+		if URL.Scheme != "http" && URL.Scheme != "https" {
+			return nil, errors.New("[package requests] only HTTP and HTTPS are accepted")
+		}
+	}
+	return
+}
diff --git a/http-proxy/r.go b/http-proxy/r.go
new file mode 100644
index 00000000..2b0792ad
--- /dev/null
+++ b/http-proxy/r.go
@@ -0,0 +1,57 @@
+package http_proxy
+
+import (
+	"fmt"
+	"net/http"
+	"net/url"
+	"time"
+
+	http_proxy_request "github.com/eolinker/goku-eosc/http-proxy/http-proxy-request"
+	http_context "github.com/eolinker/eosc/node/http-context"
+)
+
+//DoRequest 构造请求
+func DoRequest(ctx *http_context.Context, uri string, timeout time.Duration) (*http.Response, error) {
+	if uri == "" {
+		return nil, fmt.Errorf("invaild url")
+	}
+
+	u, err := url.ParseRequestURI(uri)
+	if err != nil {
+		return nil, err
+	}
+
+	req, err := http_proxy_request.NewRequest(ctx.ProxyRequest.Method, u)
+	if err != nil {
+
+		return nil, err
+	}
+
+	queryDest := u.Query()
+	if ctx.ProxyRequest.Queries() != nil {
+		for k, vs := range ctx.ProxyRequest.Queries() {
+			for _, v := range vs {
+				queryDest.Add(k, v)
+			}
+		}
+	}
+
+	req.SetHeaders(ctx.ProxyRequest.Headers())
+
+	req.SetQueryParams(queryDest)
+	body, _ := ctx.ProxyRequest.RawBody()
+	req.SetRawBody(body)
+	if timeout != 0 {
+		req.SetTimeout(timeout * time.Millisecond)
+	}
+	err = req.ParseBody()
+	if err != nil {
+		return nil, err
+	}
+	response, err := req.Send(ctx)
+	if err != nil {
+		return nil, err
+	}
+
+	return response, err
+}
diff --git a/http-router/config.go b/http-router/config.go
new file mode 100644
index 00000000..5ca32443
--- /dev/null
+++ b/http-router/config.go
@@ -0,0 +1,30 @@
+package http_router
+
+import "net/http"
+
+type Config struct {
+	name    string
+	port    int
+	Rules   []RouterRule
+	host    []string
+	service http.Handler
+}
+
+type RouterRule struct {
+	location string
+	header   map[string]string
+	query    map[string]string
+}
+
+type RouterWork struct {
+	Service http.Handler
+	Config  Config
+}
+
+//func (r *RouterWork) Start() error {
+//	routerManager.Add(r.Config, r.Service)
+//}
+//
+//func (r *RouterWork) Stop() error {
+//	routerManager.Del(r.Config, r.Service)
+//}
diff --git a/http-router/driver.go b/http-router/driver.go
new file mode 100644
index 00000000..4265be48
--- /dev/null
+++ b/http-router/driver.go
@@ -0,0 +1,32 @@
+package http_router
+
+import (
+	"reflect"
+
+	"github.com/eolinker/eosc"
+)
+
+type HttpRouterDriver struct {
+	info       eosc.DriverInfo
+	configType reflect.Type
+}
+
+func (h *HttpRouterDriver) Create(id, name string, v interface{}, workers map[string]interface{}) (eosc.IWorker, error) {
+	panic("implement me")
+}
+
+func NewHttpRouter(profession, name, label, desc string, params map[string]string) *HttpRouterDriver {
+	return &HttpRouterDriver{
+		info: eosc.DriverInfo{
+			Name:       name,
+			Label:      label,
+			Desc:       desc,
+			Profession: profession,
+			Params:     params,
+		},
+	}
+}
+
+func (h *HttpRouterDriver) ConfigType() reflect.Type {
+	return h.configType
+}
diff --git a/http-router/register.go b/http-router/register.go
new file mode 100644
index 00000000..01424ce6
--- /dev/null
+++ b/http-router/register.go
@@ -0,0 +1,24 @@
+package http_router
+
+import "github.com/eolinker/eosc"
+
+func Register()  {
+	eosc.DefaultProfessionDriverRegister.RegisterProfessionDriver("eolinker:goku:http_router",NewRouterDriverFactory())
+}
+
+type RouterDriverFactory struct {
+
+}
+
+func (r *RouterDriverFactory) ExtendInfo() eosc.ExtendInfo {
+	panic("implement me")
+}
+
+func (r *RouterDriverFactory) Create(profession string, name string, label string, desc string, params map[string]string) (eosc.IProfessionDriver, error) {
+	panic("implement me")
+}
+
+func NewRouterDriverFactory() *RouterDriverFactory {
+	return &RouterDriverFactory{}
+}
+
diff --git a/http-router/router.go b/http-router/router.go
new file mode 100644
index 00000000..cf098086
--- /dev/null
+++ b/http-router/router.go
@@ -0,0 +1,34 @@
+package http_router
+
+import (
+	"github.com/eolinker/eosc"
+)
+
+type Router struct {
+}
+
+func (r *Router) Marshal() ([]byte, error) {
+	panic("implement me")
+}
+
+func (r *Router) Worker() (eosc.IWorker, error) {
+	panic("implement me")
+}
+
+func (r *Router) CheckSkill(skill string) bool {
+	panic("implement me")
+}
+
+func (r *Router) Info() eosc.WorkerInfo {
+	return eosc.WorkerInfo{
+		Id:     "",
+		Name:   "",
+		Driver: "",
+		Create: "",
+		Update: "",
+	}
+}
+
+func NewRouter(c *Config) *Router {
+	return &Router{}
+}
diff --git a/listener-manager/listener.go b/listener-manager/listener.go
new file mode 100644
index 00000000..96181541
--- /dev/null
+++ b/listener-manager/listener.go
@@ -0,0 +1,67 @@
+package listener_manager
+
+import (
+	"errors"
+	"fmt"
+	"net"
+	"sync"
+)
+
+const (
+	TCP = "tcp"
+	UDP = "udp"
+)
+
+var defaultListener = newListener()
+
+type listener struct {
+	tcpListeners map[int]net.Listener
+	udpListeners map[int]net.Listener
+	locker       sync.RWMutex
+}
+
+func newListener() *listener {
+	return &listener{tcpListeners: make(map[int]net.Listener), udpListeners: make(map[int]net.Listener), locker: sync.RWMutex{}}
+}
+
+func (l *listener) getTCPListener(port int) (net.Listener, error) {
+	l.locker.RLock()
+	defer l.locker.RUnlock()
+	if v, ok := l.tcpListeners[port]; ok {
+		return v, nil
+	}
+	return nil, errors.New("no listener in port")
+}
+
+func (l *listener) setTCPListener(port int, listen net.Listener) {
+	l.locker.Lock()
+	defer l.locker.Unlock()
+	l.tcpListeners[port] = listen
+}
+
+func (l *listener) deleteTCPListener(port int) {
+	l.locker.Lock()
+	defer l.locker.Unlock()
+	delete(l.tcpListeners, port)
+}
+
+func NewTCPListener(ip string, port int) (net.Listener, error) {
+	addr := fmt.Sprintf("%s:%d", ip, port)
+	l, err := net.Listen(TCP, addr)
+	if err != nil {
+		return nil, err
+	}
+	return l, nil
+}
+
+func GetTCPListener(port int) (net.Listener, error) {
+	return defaultListener.getTCPListener(port)
+}
+
+func SetTCPListener(port int, listen net.Listener) {
+	defaultListener.setTCPListener(port, listen)
+}
+
+func DeleteTCPListener(port int) {
+	defaultListener.deleteTCPListener(port)
+}
diff --git a/main.go b/main.go
new file mode 100644
index 00000000..fe7f767d
--- /dev/null
+++ b/main.go
@@ -0,0 +1,5 @@
+package main
+
+func main() {
+	
+}
diff --git a/router-http/Header.go b/router-http/Header.go
new file mode 100644
index 00000000..ff132a98
--- /dev/null
+++ b/router-http/Header.go
@@ -0,0 +1,74 @@
+package router_http
+
+import (
+	"encoding/json"
+	"net/http"
+	"sort"
+	"strings"
+)
+
+type HeaderSort []string
+type HeaderChecker string
+
+func (l HeaderSort) Len() int {
+	return len(l)
+}
+
+func (l HeaderSort) Less(i, j int) bool {
+	// 若l[i]或l[j]中有个是 * ，且只会有一个*结点， * 排到最后
+	if l[i] == "*" {
+		return false
+	}
+	if l[j] == "*"{
+		return true
+	}
+
+	mapI := make(map[string]string)
+	mapJ := make(map[string]string)
+
+	_ = json.Unmarshal([]byte(l[i]), &mapI)
+	_ = json.Unmarshal([]byte(l[j]), &mapJ)
+
+	// 需要满足key数量多的优先
+	if len(mapI) == len(mapJ) {
+		// key数量相同则按字母排序从小到大排序，先匹配完的优先
+		length := len(mapI)
+
+		KeyArrI := make([]string, 0, length)
+		KeyArrJ := make([]string, 0, length)
+
+		for key := range mapI {
+			KeyArrI = append(KeyArrI, strings.ToLower(key))
+		}
+		for key := range mapJ {
+			KeyArrJ = append(KeyArrJ, strings.ToLower(key))
+		}
+
+		sort.Strings(KeyArrI)
+		sort.Strings(KeyArrJ)
+
+		return KeyArrI[length - 1] < KeyArrI[length - 1]
+
+	}
+	return len(mapI) > len(mapJ)
+}
+
+func (l HeaderSort) Swap(i, j int) {
+	l[i],l[j] = l[j],l[i]
+}
+
+func(hc HeaderChecker) check(request *http.Request) bool{
+	if hc == "*"{
+		return true
+	}
+	headerMap := make(map[string]string)
+	json.Unmarshal([]byte(hc), &headerMap)
+
+	for key, value := range headerMap {
+		if request.Header.Get(strings.ToLower(key)) != value{
+			return false
+		}
+	}
+
+	return true
+}
\ No newline at end of file
diff --git a/router-http/Host.go b/router-http/Host.go
new file mode 100644
index 00000000..d3fd72d2
--- /dev/null
+++ b/router-http/Host.go
@@ -0,0 +1,79 @@
+package router_http
+
+import "strings"
+
+const (
+	// 完整域名匹配
+	hostPerfectMatchHostIndex = iota
+	// 子域名匹配
+	hostLongestMatchHostIndex
+	// 任意匹配
+	hostMatchAnyHostIndex
+)
+
+type HostSort []string
+
+func (l HostSort) Len() int {
+	return len(l)
+}
+
+func (l HostSort) Less(i, j int) bool {
+	s1,l1 := getHost(l[i])
+	s2,l2:= getHost(l[j])
+	if s1 == s2 { // 优先级
+		if len(l1) == len(l2){
+			// 长度相同，按字符排
+			return l1 < l2
+		}
+		// 按长度降序
+		return l1 > l2
+	}
+	return s1 < s2
+}
+
+func (l HostSort) Swap(i, j int) {
+	l[i],l[j] = l[j],l[i]
+}
+
+func createHost(location string) Checker_One {
+	t,s:= getHost(location)
+	switch t {
+	case hostPerfectMatchHostIndex:
+		return hostPerfectMatchType(s)
+	case hostLongestMatchHostIndex:
+		return hostSubHostMatchType(s)
+	default:
+		return hostMatchAnyType(s)
+	}
+}
+
+func getHost(s string) (int,string)  {
+	if s == "*"{
+		return hostMatchAnyHostIndex, s
+	}
+
+	if index := strings.LastIndex(s,"*"); index != -1{
+		return hostLongestMatchHostIndex, s[index + 1:]
+	}else{
+		return hostPerfectMatchHostIndex, s
+	}
+}
+
+type hostPerfectMatchType string
+
+func (l hostPerfectMatchType) check(v string) bool {
+	return string(l) == v
+}
+
+type hostSubHostMatchType string
+
+func (l hostSubHostMatchType) check(v string) bool {
+	return strings.HasSuffix(v, string(l))
+}
+
+type hostMatchAnyType string
+
+func (l hostMatchAnyType) check(v string) bool {
+	return true
+}
+
diff --git a/router-http/Location.go b/router-http/Location.go
new file mode 100644
index 00000000..52c91c5d
--- /dev/null
+++ b/router-http/Location.go
@@ -0,0 +1,135 @@
+package router_http
+
+import (
+	"regexp"
+	"strings"
+)
+
+const (
+	// 正则表达式（区分大小写）
+	locationRegularMatchCase = "~"
+	// 正则表达式（不区分大小写）
+	locationRegularNotMatchCase = "~*"
+	// 完全匹配
+	locationPerfectMatch = "="
+	// 最长匹配前缀
+	locationLongestMatch = ""
+	// 匹配任意
+	locationMatchAny = "*"
+)
+const (
+	// 完全匹配
+	locationPerfectMatchIndex = iota
+	// 最长匹配前缀
+	locationLongestMatchIndex
+	// 正则表达式（区分大小写）
+	locationRegularMatchCaseIndex
+	// 正则表达式（不区分大小写）
+	locationRegularNotMatchCaseIndex
+	// 匹配任意
+	locationMatchAnyIndex
+)
+
+type LocationSort []string
+
+func (l LocationSort) Len() int {
+	return len(l)
+}
+
+func (l LocationSort) Less(i, j int) bool {
+	s1,l1 := getLocation(l[i])
+	s2,l2:= getLocation(l[j])
+	if s1 == s2 { // 优先级
+		if len(l1) == len(l2){
+			// 长度相同，按字符排
+			return l1 < l2
+		}
+		// 按长度降序
+		return l1 > l2
+	}
+	return s1 < s2
+}
+
+func (l LocationSort) Swap(i, j int) {
+	l[i],l[j] = l[j],l[i]
+}
+
+func getLocation(s string) (int,string)  {
+
+	index := strings.IndexAny(s, "/")
+	if index != -1 {
+		switch s[:index] {
+		case locationPerfectMatch:
+			{
+				return locationPerfectMatchIndex, s[index:]
+			}
+		case locationLongestMatch:
+			{
+				return locationLongestMatchIndex, s[index:]
+			}
+		case locationRegularMatchCase:
+			{
+				return locationRegularMatchCaseIndex, s[index:]
+			}
+		case locationRegularNotMatchCase:
+			{
+				return locationRegularNotMatchCaseIndex, s[index:]
+			}
+		case locationMatchAny:
+			{
+				return locationMatchAnyIndex, "/"
+			}
+		default:
+			return locationLongestMatchIndex, "/"+s
+		}
+	}
+
+	return locationLongestMatchIndex, "/"+s
+
+}
+
+
+
+func createLocation(location string) Checker_One {
+	t, s := getLocation(location)
+	switch t {
+	case locationPerfectMatchIndex:
+		return locationPerfectMatchType(s)
+	case locationLongestMatchIndex:
+		return locationLongestMatchType(s)
+	case locationRegularMatchCaseIndex:
+		compile :=regexp.MustCompile(s)
+		return (*LocationRegularMatchType)(compile)
+	case locationRegularNotMatchCaseIndex:
+		compile := regexp.MustCompile("(?i)" + strings.Replace(s, " ", "[ \\._-]", -1))
+		return (*LocationRegularMatchType)(compile)
+	case locationMatchAnyIndex:
+		return locationMatchAnyType(s)
+	}
+	return locationLongestMatchType(s)
+}
+
+type locationPerfectMatchType string
+
+func (l locationPerfectMatchType) check(v string) bool {
+	return string(l) == v
+}
+
+type locationLongestMatchType string
+
+func (l locationLongestMatchType) check(v string) bool {
+	return strings.HasPrefix(v, string(l))
+}
+
+type LocationRegularMatchType regexp.Regexp
+
+func (l *LocationRegularMatchType) check(v string) bool {
+	return (*regexp.Regexp)(l).MatchString(v)
+}
+
+
+type locationMatchAnyType string
+
+func (l locationMatchAnyType) check(v string) bool {
+	return true
+}
diff --git a/router-http/Query.go b/router-http/Query.go
new file mode 100644
index 00000000..b94eaaad
--- /dev/null
+++ b/router-http/Query.go
@@ -0,0 +1,74 @@
+package router_http
+
+import (
+	"encoding/json"
+	"net/http"
+	"sort"
+	"strings"
+)
+
+type QuerySort []string
+type QueryChecker string
+
+func (l QuerySort) Len() int {
+	return len(l)
+}
+
+func (l QuerySort) Less(i, j int) bool {
+	// 若l[i]或l[j]中有个是 * ，且只会有一个*结点， * 排到最后
+	if l[i] == "*" {
+		return false
+	}
+	if l[j] == "*"{
+		return true
+	}
+
+	mapI := make(map[string]string)
+	mapJ := make(map[string]string)
+
+	_ = json.Unmarshal([]byte(l[i]), &mapI)
+	_ = json.Unmarshal([]byte(l[j]), &mapJ)
+
+	// 需要满足key数量多的优先
+	if len(mapI) == len(mapJ) {
+		// key数量相同则按字母排序从小到大排序，先匹配完的优先
+		length := len(mapI)
+
+		KeyArrI := make([]string, 0, length)
+		KeyArrJ := make([]string, 0, length)
+
+		for key := range mapI {
+			KeyArrI = append(KeyArrI, strings.ToLower(key))
+		}
+		for key := range mapJ {
+			KeyArrJ = append(KeyArrJ, strings.ToLower(key))
+		}
+
+		sort.Strings(KeyArrI)
+		sort.Strings(KeyArrJ)
+
+		return KeyArrI[length - 1] < KeyArrI[length - 1]
+
+	}
+	return len(mapI) > len(mapJ)
+}
+
+func (l QuerySort) Swap(i, j int) {
+	l[i],l[j] = l[j],l[i]
+}
+
+func(hc QueryChecker) check(request *http.Request) bool{
+	if hc == "*"{
+		return true
+	}
+	queryMap := make(map[string]string)
+	json.Unmarshal([]byte(hc), &queryMap)
+
+	for key, value := range queryMap {
+		if request.URL.Query().Get(key) != value{
+			return false
+		}
+	}
+
+	return true
+}
\ No newline at end of file
diff --git a/router-http/build.go b/router-http/build.go
new file mode 100644
index 00000000..75933b1f
--- /dev/null
+++ b/router-http/build.go
@@ -0,0 +1,165 @@
+package router_http
+
+import (
+	"fmt"
+	"github.com/eolinker/goku-eosc/router"
+	"sort"
+)
+
+//  路由树路径上经过的检测指标， 检测优先级 host>location>header>query
+var RouterPathType = []string{
+	"host",
+	"location",
+	"header",
+	"query",
+}
+
+type Tree map[string]interface{}
+
+func (t Tree) Append(pathValue []string, target string) error {
+	if len(pathValue) < 1 {
+		return fmt.Errorf("no path exist")
+	}
+	pv := pathValue[0]
+	if len(pathValue) == 1 {
+		// 若target冲突 则返回错误  一条路由不能对应多个target
+		if _, has := t[pv]; has {
+			return fmt.Errorf("router config conflict")
+		}
+		t[pv] = target
+	} else {
+		next, has := t[pv]
+		if !has {
+			nextM := make(Tree)
+			err := nextM.Append(pathValue[1:], target)
+			if err != nil {
+				return err
+			}
+			t[pv] = nextM
+		} else {
+			nextM := next.(Tree)
+			err := nextM.Append(pathValue[1:], target)
+			if err != nil {
+				return err
+			}
+		}
+	}
+	return nil
+}
+
+func createRouter(tree Tree, nodesType []string) router.IRouterHandler {
+	if len(nodesType) == 0 {
+		return nil
+	}
+
+	nodeType := nodesType[0]
+	nextNodesType := nodesType[1:]
+
+	switch nodeType {
+	case targetLocation:
+		pl := &_Plan_One{
+			reader:   CreateReader(nodeType),
+			checkers: nil,
+			nexts:    nil,
+		}
+		sorts := make(LocationSort, 0, len(tree))
+		for k := range tree {
+			sorts = append(sorts, k)
+		}
+		sort.Sort(sorts)
+		if len(nextNodesType) == 0 {
+			for _, s := range sorts {
+				v := tree[s]
+				pl.checkers = append(pl.checkers, createLocation(s))
+				pl.nexts = append(pl.nexts, endPoint(v.(string)))
+			}
+		} else {
+			for _, s := range sorts {
+				v := tree[s]
+				pl.checkers = append(pl.checkers, createLocation(s))
+				pl.nexts = append(pl.nexts, createRouter(v.(Tree), nextNodesType))
+			}
+		}
+
+		return pl
+
+	case targetHost:
+		pl := &_Plan_One{
+			reader:   CreateReader(nodeType),
+			checkers: nil,
+			nexts:    nil,
+		}
+		sorts := make(HostSort, 0, len(tree))
+		for k := range tree {
+			sorts = append(sorts, k)
+		}
+		sort.Sort(sorts)
+		if len(nextNodesType) == 0 {
+			for _, s := range sorts {
+				v := tree[s]
+				pl.checkers = append(pl.checkers, createHost(s))
+				pl.nexts = append(pl.nexts, endPoint(v.(string)))
+			}
+		} else {
+			for _, s := range sorts {
+				v := tree[s]
+				pl.checkers = append(pl.checkers, createHost(s))
+				pl.nexts = append(pl.nexts, createRouter(v.(Tree), nextNodesType))
+			}
+		}
+
+		return pl
+	case targetHeader:
+		pl := &_Plan_Multi{
+			checkers: nil,
+			nexts:    nil,
+		}
+		sorts := make(HeaderSort, 0, len(tree))
+		for k := range tree {
+			sorts = append(sorts, k)
+		}
+		sort.Sort(sorts)
+		if len(nextNodesType) == 0 {
+			for _, s := range sorts {
+				v := tree[s]
+				pl.checkers = append(pl.checkers, HeaderChecker(s))
+				pl.nexts = append(pl.nexts, endPoint(v.(string)))
+			}
+		} else {
+			for _, s := range sorts {
+				v := tree[s]
+				pl.checkers = append(pl.checkers, HeaderChecker(s))
+				pl.nexts = append(pl.nexts, createRouter(v.(Tree), nextNodesType))
+			}
+		}
+
+		return pl
+	default: //targetQuery
+		pl := &_Plan_Multi{
+			checkers: nil,
+			nexts:    nil,
+		}
+		sorts := make(QuerySort, 0, len(tree))
+		for k := range tree {
+			sorts = append(sorts, k)
+		}
+		sort.Sort(sorts)
+		if len(nextNodesType) == 0 {
+			for _, s := range sorts {
+
+				v := tree[s]
+				pl.checkers = append(pl.checkers, QueryChecker(s))
+				pl.nexts = append(pl.nexts, endPoint(v.(string)))
+			}
+		} else {
+			for _, s := range sorts {
+
+				v := tree[s]
+				pl.checkers = append(pl.checkers, QueryChecker(s))
+				pl.nexts = append(pl.nexts, createRouter(v.(Tree), nextNodesType))
+			}
+		}
+
+		return pl
+	}
+}
diff --git a/router-http/demo_test.go b/router-http/demo_test.go
new file mode 100644
index 00000000..55cf103c
--- /dev/null
+++ b/router-http/demo_test.go
@@ -0,0 +1,94 @@
+package router_http
+
+import (
+	"context"
+	"encoding/json"
+	"errors"
+	"net/http"
+	"sync"
+	"testing"
+
+	listener_manager "github.com/eolinker/goku-eosc/listener-manager"
+)
+
+type RouterManagerDemo struct {
+	servers map[int]*RouterServerDemo
+	locker  sync.RWMutex
+}
+
+func NewRouterManagerDemo() *RouterManagerDemo {
+	return &RouterManagerDemo{locker: sync.RWMutex{}, servers: make(map[int]*RouterServerDemo)}
+}
+
+func (r *RouterManagerDemo) Get(port int) (*RouterServerDemo, error) {
+	r.locker.RLock()
+	defer r.locker.RUnlock()
+	if v, ok := r.servers[port]; ok {
+		return v, nil
+	}
+	return nil, errors.New("")
+}
+
+func (r *RouterManagerDemo) Set(port int, server *RouterServerDemo) {
+	r.locker.Lock()
+	defer r.locker.Unlock()
+	r.servers[port] = server
+}
+
+type RouterServerDemo struct {
+	port   int
+	server *http.Server
+	hosts  []string
+}
+
+func (r *RouterServerDemo) AppendHost(host ...string) {
+	r.hosts = append(r.hosts, host...)
+}
+
+func (r *RouterServerDemo) Shutdown(ctx context.Context) error {
+	r.server.Shutdown(ctx)
+	return nil
+}
+func NewRouterServerDemo(port int, hosts []string) (*RouterServerDemo, error) {
+	ln, err := listener_manager.GetTCPListener(port)
+	if err == nil {
+		return nil, errors.New("the port is already occupied")
+	}
+	ln, err = listener_manager.NewTCPListener("0.0.0.0", port)
+	if err != nil {
+		return nil, err
+	}
+	listener_manager.SetTCPListener(port, ln)
+	r := &RouterServerDemo{port: port, hosts: hosts, server: &http.Server{}}
+	r.server.Handler = r
+	go r.server.Serve(ln)
+
+	return r, nil
+}
+
+func (r *RouterServerDemo) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
+	result := map[string]interface{}{
+		"port": r.port,
+		"host": r.hosts,
+	}
+	b, _ := json.Marshal(result)
+	writer.Write(b)
+}
+
+func TestRouter(t *testing.T) {
+	rm := NewRouterManagerDemo()
+	r, err := rm.Get(8080)
+	if err != nil {
+		r, err = NewRouterServerDemo(8080, []string{"www.baidu.com", "www.eolinker.com"})
+		if err != nil {
+			return
+		}
+	}
+
+	rm.Set(8080, r)
+	newR, err := rm.Get(8080)
+	if err == nil {
+		newR.AppendHost("www.goku.com", "www.apibee.com")
+	}
+	select {}
+}
diff --git a/router-http/endpoint.go b/router-http/endpoint.go
new file mode 100644
index 00000000..58b34c23
--- /dev/null
+++ b/router-http/endpoint.go
@@ -0,0 +1,9 @@
+package router_http
+
+import "net/http"
+
+type endPoint string
+
+func (e endPoint) Match(request *http.Request) (string, bool) {
+	return string(e),true
+}
\ No newline at end of file
diff --git a/router-http/plan-multi.go b/router-http/plan-multi.go
new file mode 100644
index 00000000..6bb43463
--- /dev/null
+++ b/router-http/plan-multi.go
@@ -0,0 +1,26 @@
+package router_http
+
+import (
+	"github.com/eolinker/goku-eosc/router"
+	"net/http"
+)
+
+type Checker_Multi interface {
+	check(request *http.Request) bool
+}
+
+// 适合从request检测多个值的类型，如header、query，读取request中需要检测的值在check中执行
+type _Plan_Multi struct {
+	checkers []Checker_Multi
+	nexts    []router.IRouterHandler
+}
+
+func (p *_Plan_Multi) Match(request *http.Request) (string, bool) {
+
+	for i, c := range p.checkers {
+		if c.check(request) {
+			return p.nexts[i].Match(request)
+		}
+	}
+	return "", false
+}
diff --git a/router-http/plan-one.go b/router-http/plan-one.go
new file mode 100644
index 00000000..7d9c80d8
--- /dev/null
+++ b/router-http/plan-one.go
@@ -0,0 +1,33 @@
+package router_http
+
+import (
+	"github.com/eolinker/goku-eosc/router"
+	"net/http"
+)
+
+type Checker_One interface {
+	check(v string) bool
+}
+
+// 适合从request检测单个值的类型，如host、location
+type _Plan_One struct {
+	reader   Reader
+	checkers []Checker_One
+	nexts    []router.IRouterHandler
+}
+
+func (p *_Plan_One) Match(request *http.Request) (string, bool) {
+	v := p.reader.read(request)
+
+	for i, c := range p.checkers {
+		if c.check(v) {
+			res, has := p.nexts[i].Match(request)
+			// 防止错失后面可能匹配成功的路径
+			if !has {
+				continue
+			}
+			return res, has
+		}
+	}
+	return "", false
+}
diff --git a/router-http/reader-host.go b/router-http/reader-host.go
new file mode 100644
index 00000000..171cce0d
--- /dev/null
+++ b/router-http/reader-host.go
@@ -0,0 +1,13 @@
+package router_http
+
+import (
+	"net/http"
+	"strings"
+)
+
+type HostReader int
+
+func (h HostReader) read(request *http.Request) string {
+	hosts := strings.Split(request.Host, ":")
+	return hosts[0]
+}
diff --git a/router-http/reader-location.go b/router-http/reader-location.go
new file mode 100644
index 00000000..24d23c55
--- /dev/null
+++ b/router-http/reader-location.go
@@ -0,0 +1,9 @@
+package router_http
+
+import "net/http"
+
+type LocationReader int
+
+func (l LocationReader) read(request *http.Request) string {
+	return request.URL.Path
+}
diff --git a/router-http/reader.go b/router-http/reader.go
new file mode 100644
index 00000000..d1932e74
--- /dev/null
+++ b/router-http/reader.go
@@ -0,0 +1,28 @@
+package router_http
+
+import (
+	"net/http"
+)
+
+const (
+	targetLocation = "location"
+	targetHost     = "host"
+	targetHeader   = "header"
+	targetQuery    = "query"
+)
+
+type Reader interface {
+	read(request *http.Request) string
+}
+
+func CreateReader(targetType string) Reader {
+
+	switch targetType {
+	case targetLocation:
+		return LocationReader(0)
+	case targetHost:
+		return HostReader(0)
+	}
+
+	return nil
+}
\ No newline at end of file
diff --git a/router-http/router-http-benchMark_test.go b/router-http/router-http-benchMark_test.go
new file mode 100644
index 00000000..b9b8a71d
--- /dev/null
+++ b/router-http/router-http-benchMark_test.go
@@ -0,0 +1,45 @@
+package router_http
+
+import (
+	"flag"
+	"log"
+	"net/http"
+	"testing"
+)
+
+func BenchmarkRouterMatch(b *testing.B) {
+	flag.Parse()
+	employeeArr := loadYamlEmployee()
+	if employeeArr == nil {
+		log.Fatalln("空employee切片")
+	}
+	RM, err := newRouterHttpManager(employeeArr)
+	if err != nil {
+		log.Fatalln(err)
+	}
+
+	RM.StartAllServer()
+
+	insertBenchMarkTests()
+
+	client := &http.Client{}
+
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		//for _, test := range benchMarkTests {
+		client.Do(benchMarkTests[0].request)
+		//}
+	}
+
+}
+
+var benchMarkTests = []testRequestStruct{}
+
+func insertBenchMarkTests() {
+
+	request, _ := http.NewRequest("GET", "http://127.0.0.1:80/abc?token=123", nil)
+	request.Header.Set("user", "abc")
+	request.Header.Set("token", "abc")
+	benchMarkTests = append(benchMarkTests, testRequestStruct{80, "test10", request, "serviceE_rule4"})
+
+}
diff --git a/router-http/router-http.go b/router-http/router-http.go
new file mode 100644
index 00000000..e7c67cee
--- /dev/null
+++ b/router-http/router-http.go
@@ -0,0 +1,261 @@
+package router_http
+
+import (
+	"encoding/json"
+	"fmt"
+	"github.com/eolinker/eosc"
+	"github.com/eolinker/goku-eosc/router"
+	"net/url"
+	"strconv"
+	"sync"
+)
+
+const (
+	routerProfession = "router"
+	driverName       = "http"
+)
+
+var (
+	employeeError = fmt.Errorf("router HTTP employees  not found")
+)
+
+func Register() {
+	router.RegisterFactory(driverName, newRouterFactory())
+}
+
+type routerHttpFactory struct {
+}
+
+func (r routerHttpFactory) Create(employeeArr []eosc.IEmployee) (router.IRouterManager, error) {
+	return newRouterHttpManager(employeeArr)
+}
+
+func newRouterFactory() *routerHttpFactory {
+	return &routerHttpFactory{}
+}
+
+type routerManager struct {
+	servers map[int]router.IRouter
+	locker  sync.RWMutex
+}
+
+// Create 创建路由管理器
+func newRouterHttpManager(employeeArr []eosc.IEmployee) (router.IRouterManager, error) {
+	if len(employeeArr) == 0 {
+		return nil, employeeError
+	}
+
+	configs, err := loadRouterHttpEmployee(employeeArr)
+	if err != nil {
+		return nil, err
+	}
+
+	RM := &routerManager{
+		servers: make(map[int]router.IRouter),
+		locker:  sync.RWMutex{},
+	}
+
+	for port, config := range configs {
+		p, _ := strconv.Atoi(port)
+		rt := &routerTree{
+			listenPort:  p,
+			serverState: ServerDown,
+			employees:   make(map[string]*httpEmployee),
+			targets:     make(map[string]*TargetConfig),
+			locker:      sync.RWMutex{},
+		}
+
+		rt.tree, err = buildTree(config)
+		if err != nil {
+			return nil, err
+		}
+		rt.employees = config
+		rt.targets = buildTargetsConfig(config)
+
+		RM.servers[p] = rt
+	}
+
+	return RM, nil
+}
+
+func (RM *routerManager) Set(port int, newEmployee eosc.IEmployee) error {
+	RM.locker.Lock()
+
+	_, has := RM.servers[port]
+	if !has {
+		rT := &routerTree{
+			listenPort:  port,
+			serverState: ServerDown,
+			employees:   make(map[string]*httpEmployee),
+			targets:     make(map[string]*TargetConfig),
+			locker:      sync.RWMutex{},
+		}
+		RM.servers[port] = rT
+	}
+	RM.locker.Unlock()
+
+	return RM.servers[port].Set(newEmployee)
+}
+
+func (RM *routerManager) Delete(port int, id string) error {
+	rT, has := RM.servers[port]
+	if !has {
+		return fmt.Errorf("the port corresponding to the router tree does not exist")
+	}
+	err := rT.Delete(id)
+	if err == NoEmployeeError {
+		RM.servers[port] = nil
+		return nil
+	}
+	return err
+}
+
+func (RM *routerManager) StartAllServer() {
+	for _, server := range RM.servers {
+		server.Serve()
+	}
+}
+
+func (RM *routerManager) ShutDownAllServer() {
+	for _, server := range RM.servers {
+		server.ShutDown()
+	}
+}
+
+func (RM *routerManager) StartServer(port int) error {
+	rT, has := RM.servers[port]
+	if !has {
+		return fmt.Errorf("the port corresponding to the router tree does not exist")
+	}
+
+	err := rT.Serve()
+	return err
+}
+
+func (RM *routerManager) ShutDownServer(port int) error {
+	rT, has := RM.servers[port]
+	if !has {
+		return fmt.Errorf("the port corresponding to the router tree does not exist")
+	}
+
+	err := rT.ShutDown()
+	return err
+}
+
+func loadRouterHttpEmployee(employeeArr []eosc.IEmployee) (map[string]map[string]*httpEmployee, error) {
+	conf := make(map[string]map[string]*httpEmployee, 0)
+
+	for _, employee := range employeeArr {
+		if employee.Driver() != driverName {
+			continue
+		}
+		cData := employee.Config()
+		var c router.Config
+		err := json.Unmarshal([]byte(cData), &c)
+		if err != nil {
+			return nil, fmt.Errorf("unmarshal routerEmployee Fail [err]: %s employee data: %s ", err, cData)
+		}
+
+		hE := &httpEmployee{
+			employeeConfig: cData,
+			config:         &c,
+		}
+
+		id := c.ID
+		if id == "" {
+			id = c.Name
+		}
+		if _, has := conf[c.Listen]; !has {
+			conf[c.Listen] = map[string]*httpEmployee{id: hE}
+			continue
+		}
+		conf[c.Listen][id] = hE
+	}
+
+	if len(conf) == 0 {
+		return nil, fmt.Errorf("router HTTP employees  not found")
+	}
+
+	return conf, nil
+}
+
+// 构建路由树，并排序匹配的顺序
+func buildTree(routerConfigs map[string]*httpEmployee) (router.IRouterHandler, error) {
+	tree := make(Tree)
+
+	pathConfigSet := toPathConfig(routerConfigs)
+	for _, pc := range pathConfigSet {
+		err := tree.Append(pc.pathValue, pc.target)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	return createRouter(tree, RouterPathType), nil
+}
+
+func toPathConfig(rcs map[string]*httpEmployee) []*pathConfig {
+	pathConfigSet := make([]*pathConfig, 0, len(rcs))
+
+	for _, rc := range rcs {
+		config := rc.config
+		hosts := config.Host
+		if config.Host == nil {
+			hosts = []string{"*"}
+		}
+		for _, host := range hosts {
+			for _, rule := range config.Rules {
+				location := rule.Location
+				if location == "" {
+					location = "*/"
+				}
+
+				header := "*"
+				if rule.Header != nil {
+					headerStr, _ := json.Marshal(rule.Header)
+					header = string(headerStr)
+				}
+
+				query := "*"
+				if rule.Query != nil {
+					queryStr, _ := json.Marshal(rule.Query)
+					query = string(queryStr)
+				}
+
+				pathConfigSet = append(pathConfigSet, &pathConfig{
+					pathValue: []string{host, location, header, query},
+					target:    rule.Target,
+				})
+			}
+		}
+	}
+	return pathConfigSet
+}
+
+func buildTargetsConfig(httpEmployees map[string]*httpEmployee) map[string]*TargetConfig {
+	targetConfigSet := make(map[string]*TargetConfig)
+	for _, hE := range httpEmployees {
+		config := hE.config
+
+		hosts := config.Host
+		if config.Host == nil {
+			hosts = []string{""}
+		}
+		for _, host := range hosts {
+			for _, rule := range config.Rules {
+				location := rule.Location
+				header := rule.Header
+
+				query := url.Values{}
+				if rule.Query != nil {
+					for k, v := range rule.Query {
+						query.Add(k, v)
+					}
+				}
+
+				targetConfigSet[rule.Target] = &TargetConfig{location, host, header, query}
+			}
+		}
+	}
+	return targetConfigSet
+}
diff --git a/router-http/router-http_test.go b/router-http/router-http_test.go
new file mode 100644
index 00000000..ebb80601
--- /dev/null
+++ b/router-http/router-http_test.go
@@ -0,0 +1,164 @@
+package router_http
+
+import (
+	"encoding/json"
+	"github.com/eolinker/eosc"
+	"github.com/eolinker/goku-eosc/router"
+	"github.com/ghodss/yaml"
+	"io/ioutil"
+	"log"
+	"net/http"
+	"testing"
+)
+
+type testRequestStruct struct {
+	port     int
+	testName string
+	request  *http.Request
+	want     string
+}
+
+var tests = []testRequestStruct{}
+
+func insertTests() {
+
+	request, _ := http.NewRequest("GET", "http://www.eolinker.com/ab?token=123", nil)
+	request.Header.Set("app", "goku")
+	request.Header.Set("user", "abc")
+	request.Header.Set("version", "1.0")
+	tests = append(tests, testRequestStruct{7777, "test1", request, "serviceA_rule1"})
+
+	request, _ = http.NewRequest("GET", "http://www.apishop.net/ab?token=123", nil)
+	request.Header.Set("app", "gokux")
+	request.Header.Set("version", "1.0")
+	tests = append(tests, testRequestStruct{7777, "test2", request, "serviceD_rule1"})
+
+	request, _ = http.NewRequest("GET", "http://www.apibee.com/ab?token=123", nil)
+	request.Header.Set("user", "abc")
+	tests = append(tests, testRequestStruct{7777, "test3", request, "serviceA_rule3"})
+
+	request, _ = http.NewRequest("GET", "http://www.apishop.net/abc?token=123", nil)
+	request.Header.Set("user", "abc")
+	tests = append(tests, testRequestStruct{7777, "test4", request, "serviceA_rule4"})
+
+	request, _ = http.NewRequest("GET", "http://www.apishop.net/cxz?token=123", nil)
+	request.Header.Set("user", "abc")
+	request.Header.Set("token", "abc")
+	tests = append(tests, testRequestStruct{7777, "test5", request, "serviceA_rule2"})
+
+	request, _ = http.NewRequest("GET", "http://www.eolinker.com/abcd?token=123", nil)
+	tests = append(tests, testRequestStruct{7777, "test6", request, "serviceB_rule1"})
+
+	request, _ = http.NewRequest("GET", "http://www.eolinker.com/cxz?token=123", nil)
+	tests = append(tests, testRequestStruct{7777, "test7", request, "serviceB_rule2"})
+
+	request, _ = http.NewRequest("GET", "http://www.apibee.com/ab?token=123&token2=321", nil)
+	request.Header.Set("user", "abc")
+	request.Header.Set("token", "abc")
+	tests = append(tests, testRequestStruct{7777, "test8", request, "serviceC_rule3"})
+
+	request, _ = http.NewRequest("GET", "http://www.apibee.com/ab?token=123", nil)
+	request.Header.Set("user", "abc")
+	request.Header.Set("token", "abc")
+	tests = append(tests, testRequestStruct{7777, "test9", request, "serviceC_rule2"})
+
+	request, _ = http.NewRequest("GET", "http://www.adasdavera.com/abc?token=123", nil)
+	request.Header.Set("user", "abc")
+	request.Header.Set("token", "abc")
+	tests = append(tests, testRequestStruct{80, "test10", request, "serviceE_rule4"})
+
+}
+
+func TestRM(t *testing.T) {
+	employeeArr := loadYamlEmployee()
+	if employeeArr == nil {
+		log.Fatalln("空employee切片")
+	}
+	RM, err := newRouterHttpManager(employeeArr)
+	if err != nil {
+		log.Fatalln(err)
+	}
+
+	//测试路由树正确性
+	//insertTests()
+	//NRM := RM.(*routerManager)
+	//for _, test := range tests {
+	//	t.Run(test.testName, func(t *testing.T) {
+	//		Tree := NRM.servers[test.port].(*routerTree)
+	//		target, _ := Tree.tree.Match(test.request)
+	//		if target != test.want {
+	//			log.Println(test.testName, "   target == ", target)
+	//			t.Fail()
+	//		}
+	//	})
+	//}
+
+	RM.StartAllServer()
+	//测试删除实例
+	//RM.Delete(80, "E")
+
+	//测试shutdown后再启动
+	//RM.ShutDownServer(80)
+	//RM.StartServer(80)
+
+	//测试新增实例
+	//newEmploye := loadNewEmployee()[0]
+	//RM.Set(80, newEmploye)
+
+	select {}
+
+}
+
+func loadYamlEmployee() []eosc.IEmployee {
+	data, err := ioutil.ReadFile("test_router_manager.yaml")
+	if err != nil {
+		return nil
+	}
+
+	convertData, err := yaml.YAMLToJSON(data)
+	if err != nil {
+		return nil
+	}
+
+	var cfg map[string][]router.Config
+	err = json.Unmarshal(convertData, &cfg)
+	if err != nil {
+		return nil
+	}
+
+	employeeArr := make([]eosc.IEmployee, 0, len(cfg["router"]))
+
+	for _, config := range cfg["router"] {
+		cdata, _ := json.Marshal(config)
+		employeeArr = append(employeeArr, router.NewEmployee(config.ID, config.Name, config.Driver, string(cdata)))
+	}
+
+	return employeeArr
+}
+
+func loadNewEmployee() []eosc.IEmployee {
+	data, err := ioutil.ReadFile("test_router_manager_newEmployee.yaml")
+	if err != nil {
+		return nil
+	}
+
+	convertData, err := yaml.YAMLToJSON(data)
+	if err != nil {
+		return nil
+	}
+
+	var cfg map[string][]router.Config
+	err = json.Unmarshal(convertData, &cfg)
+	if err != nil {
+		return nil
+	}
+
+	employeeArr := make([]eosc.IEmployee, 0, len(cfg["router"]))
+
+	for _, config := range cfg["router"] {
+		cdata, _ := json.Marshal(config)
+		employeeArr = append(employeeArr, router.NewEmployee(config.ID, config.Name, config.Driver, string(cdata)))
+	}
+
+	return employeeArr
+}
diff --git a/router-http/router-tree.go b/router-http/router-tree.go
new file mode 100644
index 00000000..65d0c4c3
--- /dev/null
+++ b/router-http/router-tree.go
@@ -0,0 +1,172 @@
+package router_http
+
+import (
+	"context"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"github.com/eolinker/eosc"
+	"github.com/eolinker/eosc/listener"
+	"github.com/eolinker/eosc/log"
+	listener_manager "github.com/eolinker/goku-eosc/listener-manager"
+	"github.com/eolinker/goku-eosc/router"
+	"net/http"
+	"sync"
+)
+
+const (
+	ServerUp   = "UP"
+	ServerDown = "DOWN"
+)
+
+var NoEmployeeError = errors.New("no employee exist")
+
+type routerTree struct {
+	listenPort  int
+	server      *http.Server
+	serverState string
+	tree        router.IRouterHandler
+	employees   map[string]*httpEmployee // key为实例id
+	targets     map[string]*TargetConfig // key为target
+	locker      sync.RWMutex
+}
+
+type httpEmployee struct {
+	employeeConfig string
+	config         *router.Config
+}
+
+type pathConfig struct {
+	pathValue []string
+	target    string
+}
+
+func (r *routerTree) Set(newEmployee eosc.IWorker) error {
+	r.locker.Lock()
+	defer r.locker.Unlock()
+
+	if newEmployee.Driver() != driverName {
+		return fmt.Errorf("router set employee fail. the employee's driver isn't HTTP ")
+	}
+
+	id := newEmployee.ID()
+	if id == "" {
+		id = newEmployee.Name()
+	}
+
+	// 若更新的实例在原有配置中已存在且配置相同，则直接返回
+	newEmployeeConfig := newEmployee.Config()
+	if oldHE, has := r.employees[id]; has && oldHE.employeeConfig == newEmployeeConfig {
+		return nil
+	}
+
+	TempEmployees := cloneEmployees(r.employees)
+	var c router.Config
+	err := json.Unmarshal([]byte(newEmployeeConfig), &c)
+	if err != nil {
+		return fmt.Errorf("unmarshal routerEmployee Fail [err]: %s employee data: %s ", err, newEmployeeConfig)
+	}
+	TempEmployees[id] = &httpEmployee{newEmployeeConfig, &c}
+
+	NewTree, err := buildTree(TempEmployees)
+	if err != nil {
+		return fmt.Errorf("set employee fail err: %s", err)
+	}
+
+	r.tree = NewTree
+	r.employees = TempEmployees
+	r.targets = buildTargetsConfig(r.employees)
+
+	return nil
+}
+
+func (r *routerTree) Delete(id string) error {
+	r.locker.Lock()
+	defer r.locker.Unlock()
+
+	if _, has := r.employees[id]; !has {
+		return fmt.Errorf("delete employee fail. Employee id %s not exist", id)
+	}
+
+	TempEmployees := cloneEmployees(r.employees)
+	delete(TempEmployees, id)
+	if len(TempEmployees) == 0 {
+		// 若该端口下已没有路由实例，则关闭Server 并在路由管理器中删除本路由树
+		r.ShutDown()
+		return NoEmployeeError
+	}
+
+	NewTree, err := buildTree(TempEmployees)
+	if err != nil {
+		return fmt.Errorf("delete employee fail err: %s", err)
+	}
+	r.tree = NewTree
+	r.employees = TempEmployees
+	r.targets = buildTargetsConfig(r.employees)
+
+	return nil
+}
+
+//启动路由树
+func (r *routerTree) Serve() error {
+	r.locker.Lock()
+	defer r.locker.Unlock()
+
+	if r.serverState == ServerUp {
+		return nil
+	}
+
+	r.server = &http.Server{}
+	r.server.Handler = r
+
+	ln, err := listener.ListenerTCP(r.listenPort, n)
+	if err != nil {
+
+	}
+	go func(srv *http.Server) {
+		err := srv.Serve(ln)
+		log.Error(err)
+	}(r.server)
+	r.serverState = ServerUp
+
+	return nil
+}
+
+func (r *routerTree) ShutDown() error {
+	r.locker.Lock()
+	defer r.locker.Unlock()
+
+	if r.serverState == ServerDown {
+		return nil
+	}
+
+	listener_manager.DeleteTCPListener(r.listenPort)
+	r.server.Shutdown(context.Background())
+	r.serverState = ServerDown
+	return nil
+}
+
+func (r *routerTree) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
+	//TODO
+
+	target, has := r.tree.Match(request)
+	if !has {
+		return
+	}
+	result := map[string]interface{}{
+		"location": r.targets[target].Location(),
+		"host":     r.targets[target].Host(),
+		"header":   r.targets[target].Header(),
+		"query":    r.targets[target].Query(),
+	}
+	data, _ := json.Marshal(result)
+	writer.Write(data)
+}
+
+func cloneEmployees(HES map[string]*httpEmployee) map[string]*httpEmployee {
+	NewHES := make(map[string]*httpEmployee)
+	for id, HE := range HES {
+		NewHES[id] = HE
+	}
+	return NewHES
+}
diff --git a/router-http/target.go b/router-http/target.go
new file mode 100644
index 00000000..652aa92c
--- /dev/null
+++ b/router-http/target.go
@@ -0,0 +1,26 @@
+package router_http
+
+import "net/url"
+
+type TargetConfig struct {
+	location string
+	host     string
+	header   map[string]string
+	query    url.Values
+}
+
+func (t *TargetConfig) Location() string {
+	return t.location
+}
+
+func (t *TargetConfig) Host() string {
+	return t.host
+}
+
+func (t *TargetConfig) Header() map[string]string {
+	return t.header
+}
+
+func (t *TargetConfig) Query() url.Values {
+	return t.query
+}
diff --git a/router-http/test_router_manager.yaml b/router-http/test_router_manager.yaml
new file mode 100644
index 00000000..a4134271
--- /dev/null
+++ b/router-http/test_router_manager.yaml
@@ -0,0 +1,98 @@
+router:
+  -
+    name: A
+    driver: http
+    listen: "7777"
+    host:
+      - www.eolinker.com
+      - www.apibee.com
+      - www.apishop.net
+    rules:
+      - location: "/ab"
+        header:
+          version: "1.0"
+          app: goku
+          user: abc
+        target: serviceA_rule1
+      - location: "*/"
+        header:
+          user: abc
+          token: abc
+        target: serviceA_rule2
+      - location: "*/"
+        header:
+          user: abc
+        target: serviceA_rule3
+      - location: "=/abc"
+        header:
+          user: abc
+        target: serviceA_rule4
+  - name: B
+    driver: http
+    listen: "7777"
+    host:
+      - www.eolinker.com
+    rules:
+      - location: "/ab"
+        target: serviceB_rule1
+      - location: "*/"
+        target: serviceB_rule2
+  - name: C
+    driver: http
+    listen: "7777"
+    host:
+      - www.apibee.com
+    rules:
+      - location: "/ab"
+        header:
+          version: "1.0"
+          app: goku
+        target: serviceC_rule1
+      - location: "*/"
+        header:
+          token: abc
+          user: abc
+        query:
+          token: "123"
+        target: serviceC_rule2
+      - location: "*/"
+        header:
+          user: abc
+          token: abc
+        query:
+          token: "123"
+          token2: "321"
+        target: serviceC_rule3
+  - name: D
+    driver: http
+    listen: "7777"
+    host:
+      - "*.apishop.net"
+    rules:
+      - location: "/ab"
+        query:
+          token: "123"
+        target: serviceD_rule1
+  - name: E
+    driver: http
+    listen: "80"
+    rules:
+      - location: "/ab"
+        header:
+          version: "1.0"
+          app: goku
+          user: abc
+        target: serviceE_rule1
+      - location: "*/"
+        header:
+          user: abc
+          token: abc
+        target: serviceE_rule2
+      - location: "*/"
+        header:
+          user: abc
+        target: serviceE_rule3
+      - location: "=/abc"
+        header:
+          user: abc
+        target: serviceE_rule4
\ No newline at end of file
diff --git a/router-http/test_router_manager_newEmployee.yaml b/router-http/test_router_manager_newEmployee.yaml
new file mode 100644
index 00000000..f638ca18
--- /dev/null
+++ b/router-http/test_router_manager_newEmployee.yaml
@@ -0,0 +1,9 @@
+router:
+  - name: E2
+    driver: http
+    listen: "80"
+    rules:
+      - location: "=/abcd"
+        header:
+          user: abc
+        target: serviceE_rule5
\ No newline at end of file
diff --git a/router-k/chain.go b/router-k/chain.go
new file mode 100644
index 00000000..8e0030c6
--- /dev/null
+++ b/router-k/chain.go
@@ -0,0 +1,4 @@
+package router
+
+type Chain struct {
+}
diff --git a/router-k/checker.go b/router-k/checker.go
new file mode 100644
index 00000000..3bb9a899
--- /dev/null
+++ b/router-k/checker.go
@@ -0,0 +1,21 @@
+package router
+
+import "regexp"
+
+type IChecker interface {
+	Check(v string) bool
+}
+
+func parseChecker(r string) IChecker {
+	// todo parse checker
+
+	return nil
+}
+
+type Prefix string
+
+type Regexp struct {
+	rule string
+	*regexp.Regexp
+}
+type Indistinct string
diff --git a/router-k/config.go b/router-k/config.go
new file mode 100644
index 00000000..2e2b70a1
--- /dev/null
+++ b/router-k/config.go
@@ -0,0 +1,16 @@
+package router
+
+import "github.com/eolinker/goku-eosc/service"
+
+type Rule struct {
+	Location string
+	Header   []string
+	Query    []string
+}
+
+type Config struct {
+	Id     string
+	Hosts  []string
+	Target service.IService
+	Rules  []Rule
+}
diff --git a/router-k/manager.go b/router-k/manager.go
new file mode 100644
index 00000000..9fff3659
--- /dev/null
+++ b/router-k/manager.go
@@ -0,0 +1,98 @@
+package router
+
+import (
+	"context"
+	"encoding/binary"
+	"encoding/hex"
+	"github.com/eolinker/eosc/listener"
+	"net"
+	"net/http"
+	"sync"
+	"time"
+)
+
+var _ iManager = (*Manager)(nil)
+var (
+	sign = ""
+)
+
+func init() {
+	n := time.Now().UnixNano()
+	data := make([]byte, 8)
+	binary.PutVarint(data, n)
+	sign = hex.EncodeToString(data)
+}
+
+type iManager interface {
+	Add(port int, id string, config *Config) error
+	Del(port int, id string) error
+}
+
+var manager = NewManager()
+
+type Manager struct {
+	locker    sync.Mutex
+	routers   IRouters
+	servers   map[int]*http.Server
+	listeners map[int]net.Listener
+}
+
+func NewManager() *Manager {
+	return &Manager{
+		routers: NewRouters(),
+	}
+}
+
+func (m *Manager) Add(port int, id string, config *Config) error {
+	m.locker.Lock()
+	defer m.locker.Unlock()
+	router, isCreate, err := m.routers.Set(port, id, config)
+	if err != nil {
+		return err
+	}
+	if isCreate {
+		s, has := m.servers[port]
+		if !has {
+			s = &http.Server{}
+			s.Handler = router
+			l, err := listener.ListenTCP(port, sign)
+			if err != nil {
+				return err
+			}
+			go s.Serve(l)
+			m.servers[port] = s
+			m.listeners[port] = l
+		}
+	}
+	return nil
+}
+
+func (m *Manager) Del(port int, id string) error {
+	m.locker.Lock()
+	defer m.locker.Unlock()
+	if r, has := m.routers.Del(port, id); has {
+		if r.Count() == 0 {
+			if s, has := m.servers[port]; has {
+				ctx := context.Background()
+				err := s.Shutdown(ctx)
+				if err != nil {
+					return err
+				}
+				delete(m.servers, port)
+				m.listeners[port].Close()
+				delete(m.listeners, port)
+			}
+		}
+	}
+
+	return nil
+
+}
+
+func Add(port int, id string, config *Config) error {
+	return manager.Add(port, id, config)
+}
+
+func Del(port int, id string) error {
+	return manager.Del(port, id)
+}
diff --git a/router-k/match.go b/router-k/match.go
new file mode 100644
index 00000000..6389e691
--- /dev/null
+++ b/router-k/match.go
@@ -0,0 +1,20 @@
+package router
+
+import "net/http"
+
+type IMatcher interface {
+	Match(req *http.Request) (http.Handler, bool)
+}
+
+type Matcher struct {
+	reader  IReader
+	checker IChecker
+}
+
+func (m *Matcher) Match(req *http.Request) (http.Handler, bool) {
+	v, has := m.reader.Reader(req)
+	if !has {
+		return nil, false
+	}
+
+}
diff --git a/router-k/reader.go b/router-k/reader.go
new file mode 100644
index 00000000..62f3eb5a
--- /dev/null
+++ b/router-k/reader.go
@@ -0,0 +1,7 @@
+package router
+
+import "net/http"
+
+type IReader interface {
+	Reader(req *http.Request) (string, bool)
+}
diff --git a/router-k/router.go b/router-k/router.go
new file mode 100644
index 00000000..1beaa50f
--- /dev/null
+++ b/router-k/router.go
@@ -0,0 +1,84 @@
+package router
+
+import (
+	"github.com/eolinker/eosc/internal"
+	"net/http"
+	"sync"
+)
+
+var _ IRouter = (*Router)(nil)
+
+type IRouter interface {
+	SetRouter(id string, config *Config) error
+	Count() int
+	Del(id string) int
+	http.Handler
+}
+
+type Router struct {
+	locker sync.Locker
+	data   internal.IUntyped
+	match  IMatcher
+}
+
+func NewRouter() *Router {
+	return &Router{
+		locker: &sync.Mutex{},
+	}
+}
+
+func (r *Router) Count() int {
+	return r.data.Count()
+}
+
+func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
+	h, has := r.match.Match(req)
+	if !has {
+		http.NotFound(w, req)
+		return
+	}
+	h.ServeHTTP(w, req)
+}
+
+func (r *Router) SetRouter(id string, config *Config) error {
+	r.locker.Lock()
+	defer r.locker.Unlock()
+	data := r.data.Clone()
+	data.Set(id, config)
+	list := data.List()
+	cs := make([]*Config, 0, len(list))
+	for _, i := range list {
+		cs = append(cs, i.(*Config))
+	}
+	matcher, err := parse(cs)
+	if err != nil {
+		return err
+	}
+	r.match = matcher
+	r.data = data
+	return nil
+}
+
+func (r *Router) Del(id string) int {
+	r.locker.Lock()
+	defer r.locker.Unlock()
+
+	data := r.data.Clone()
+	data.Del(id)
+	if data.Count() == 0 {
+		r.match = nil
+	} else {
+		list := data.List()
+		cs := make([]*Config, 0, len(list))
+		for _, i := range list {
+			cs = append(cs, i.(*Config))
+		}
+		m, err := parse(cs)
+		if err != nil {
+			return r.data.Count()
+		}
+		r.match = m
+	}
+
+	return r.data.Count()
+}
diff --git a/router-k/routers.go b/router-k/routers.go
new file mode 100644
index 00000000..60396f62
--- /dev/null
+++ b/router-k/routers.go
@@ -0,0 +1,71 @@
+package router
+
+import (
+	"github.com/eolinker/eosc/internal"
+	"strconv"
+)
+
+var _ IRouters = (*Routers)(nil)
+
+type IRouters interface {
+	Set(port int, id string, conf *Config) (IRouter, bool, error)
+	Get(port int) (IRouter, bool)
+	Del(port int, id string) (IRouter, bool)
+}
+type Routers struct {
+	data internal.IUntyped
+}
+
+func (rs *Routers) Set(port int, id string, conf *Config) (IRouter, bool, error) {
+	name := strconv.Itoa(port)
+	r, has := rs.data.Get(name)
+
+	if !has {
+		router := NewRouter()
+		err := router.SetRouter(id, conf)
+		if err != nil {
+			return nil, false, err
+		}
+		rs.data.Set(id, router)
+		return router, true, nil
+	} else {
+		router := r.(IRouter)
+		err := router.SetRouter(id, conf)
+		if err != nil {
+			return nil, false, err
+		}
+		return router, false, nil
+	}
+
+}
+
+func NewRouters() *Routers {
+	return &Routers{
+		data: internal.NewUntyped(),
+	}
+}
+
+func (rs *Routers) Get(port int) (IRouter, bool) {
+	name := strconv.Itoa(port)
+	r, has := rs.data.Get(name)
+	if !has {
+		var router IRouter = NewRouter()
+		rs.data.Set(name, router)
+		return router, true
+	}
+	return r.(IRouter), false
+}
+
+func (rs *Routers) Del(port int, id string) (IRouter, bool) {
+	name := strconv.Itoa(port)
+	if i, has := rs.data.Get(name); has {
+		r := i.(IRouter)
+		count := r.Del(id)
+		if count == 0 {
+			rs.data.Del(name)
+		}
+		return r, true
+	}
+	return nil, false
+
+}
diff --git a/router-k/server.go b/router-k/server.go
new file mode 100644
index 00000000..f1d1fb59
--- /dev/null
+++ b/router-k/server.go
@@ -0,0 +1,13 @@
+package router
+
+var _ iServer = (*Server)(nil)
+var _ iServers = (*Servers)(nil)
+
+type iServer interface {
+}
+type Server struct {
+}
+type iServers interface {
+}
+type Servers struct {
+}
diff --git a/router-k/tree.go b/router-k/tree.go
new file mode 100644
index 00000000..a90ad812
--- /dev/null
+++ b/router-k/tree.go
@@ -0,0 +1,15 @@
+package router
+
+import "net/http"
+
+type Tree struct {
+}
+
+func (t *Tree) Match(req *http.Request) (http.Handler, bool) {
+	panic("implement me")
+}
+
+func parse(cs []*Config) (IMatcher, error) {
+	//todo parse config to tree
+	return &Tree{}, nil
+}
diff --git a/router/config.go b/router/config.go
new file mode 100644
index 00000000..f94f7934
--- /dev/null
+++ b/router/config.go
@@ -0,0 +1,26 @@
+package router
+
+const (
+	group      = "goku"
+	version    = "v1.0"
+	label      = "http路由"
+	desc       = "http路由"
+	name       = "http"
+	profession = "router"
+)
+
+type Config struct {
+	ID     string   `json:"id"`
+	Name   string   `json:"name" yaml:"name"`
+	Driver string   `json:"driver" yaml:"driver"`
+	Listen string   `json:"listen" yaml:"listen"`
+	Host   []string `json:"host" yaml:"host"`
+	Rules  []Rule   `json:"rules" yaml:"rules"`
+}
+
+type Rule struct {
+	Location string            `json:"location" yaml:"location"`
+	Header   map[string]string `json:"header" yaml:"header"`
+	Query    map[string]string `json:"query" yaml:"query"`
+	Target   string            `json:"target" target:"target"`
+}
diff --git a/router/employee.go b/router/employee.go
new file mode 100644
index 00000000..a7f9f722
--- /dev/null
+++ b/router/employee.go
@@ -0,0 +1,37 @@
+package router
+
+func NewEmployee(id string, name string, driver string, config string) *Employee {
+	return &Employee{
+		id:     id,
+		name:   name,
+		driver: driver,
+		config: config,
+	}
+}
+
+type Employee struct {
+	id     string
+	name   string
+	driver string
+	config string
+}
+
+func (e *Employee) Technique() []string {
+	return []string{}
+}
+
+func (e *Employee) ID() string {
+	return e.id
+}
+
+func (e *Employee) Name() string {
+	return e.name
+}
+
+func (e *Employee) Driver() string {
+	return e.driver
+}
+
+func (e *Employee) Config() string {
+	return e.config
+}
diff --git a/router/factory.go b/router/factory.go
new file mode 100644
index 00000000..7e99a831
--- /dev/null
+++ b/router/factory.go
@@ -0,0 +1,59 @@
+package router
+
+import (
+	"fmt"
+
+	"github.com/eolinker/eosc"
+)
+
+//Factory 路由工厂，实现IDriverFactory方法
+type Factory struct {
+	id         string
+	name       string
+	group      string
+	profession string
+	version    string
+}
+
+func (f *Factory) Profession() string {
+	return f.profession
+}
+
+//ID 获取工厂ID
+func (f *Factory) ID() string {
+	return f.id
+}
+
+//Name 获取工厂名称
+func (f *Factory) Name() string {
+	return f.name
+}
+
+//Group 获取工厂分组
+func (f *Factory) Group() string {
+	return f.group
+}
+
+//Version 获取版本号
+func (f *Factory) Version() string {
+	return f.version
+}
+
+func Register() error {
+	return nil
+}
+
+func NewFactory() *Factory {
+	return &Factory{
+		id:         fmt.Sprintf("%s:%s_%s:%s", group, profession, name, version),
+		name:       name,
+		group:      group,
+		profession: profession,
+		version:    version,
+	}
+}
+
+func (f *Factory) Create(name string) (eosc.IProfessionDriver, error) {
+	r := NewRouter(name)
+	return r, nil
+}
diff --git a/router/register.go b/router/register.go
new file mode 100644
index 00000000..02f6d2d2
--- /dev/null
+++ b/router/register.go
@@ -0,0 +1,55 @@
+package router
+
+import "github.com/eolinker/eosc"
+
+var (
+	defaultDriverRegister iDriverRegister = newDriverManager()
+)
+
+type iDriverRegister interface {
+	RegisterDriverByKey(key string, factory IRouterHttpFactory)
+	GetDriverByKey(key string) (IRouterHttpFactory, bool)
+	Keys() []string
+}
+
+type DriverRegister struct {
+	register eosc.IRegister
+	keys     []string
+}
+
+func newDriverManager() *DriverRegister {
+	return &DriverRegister{
+		register: eosc.NewRegister(),
+		keys:     make([]string, 0, 10),
+	}
+}
+
+func (dm *DriverRegister) GetDriverByKey(key string) (IRouterHttpFactory, bool) {
+	o, has := dm.register.Get(key)
+	if has {
+		f, ok := o.(IRouterHttpFactory)
+		return f, ok
+	}
+	return nil, false
+}
+
+func (dm *DriverRegister) RegisterDriverByKey(key string, factory IRouterHttpFactory) {
+	dm.register.Register(key, factory, true)
+	dm.keys = append(dm.keys, key)
+}
+
+func (dm *DriverRegister) Keys() []string {
+	return dm.keys
+}
+
+func RegisterFactory(key string, factory IRouterHttpFactory) {
+	defaultDriverRegister.RegisterDriverByKey(key, factory)
+}
+
+func Get(key string) (IRouterHttpFactory, bool) {
+	return defaultDriverRegister.GetDriverByKey(key)
+}
+
+func Keys() []string {
+	return defaultDriverRegister.Keys()
+}
diff --git a/router/router.go b/router/router.go
new file mode 100644
index 00000000..5dc6a187
--- /dev/null
+++ b/router/router.go
@@ -0,0 +1,73 @@
+package router
+
+import (
+	"fmt"
+	"net/http"
+	"net/url"
+	"reflect"
+
+	"github.com/eolinker/eosc"
+)
+
+type IRouterHttpFactory interface {
+}
+
+type IRouterManager interface {
+	Delete(port int, id string) error
+	StartAllServer()
+	ShutDownAllServer()
+	StartServer(port int) error
+	ShutDownServer(port int) error
+}
+
+type IRouterHandler interface {
+	Match(request *http.Request) (string, bool)
+}
+
+type IRouter interface {
+	Delete(id string) error
+	Serve() error
+	ShutDown() error
+}
+
+type IRouterRule interface {
+	Location() string
+	Host() string
+	Header() map[string]string
+	Query() url.Values
+}
+
+func NewRouter(name string) *Router {
+	return &Router{
+		id:   fmt.Sprintf("%s:%s_%s:%s", group, profession, name, version),
+		name: name,
+	}
+}
+
+//Router 路由模块
+type Router struct {
+	id    string
+	name  string
+	label string
+}
+
+func (r *Router) ConfigType() reflect.Type {
+	panic("implement me")
+}
+
+func (r *Router) Create(id, name string, v interface{}, workers map[eosc.RequireId]interface{}) (eosc.IWorker, error) {
+	panic("implement me")
+}
+
+func (r *Router) Name() string {
+	return r.name
+}
+
+func (r *Router) Check(config string) error {
+	return nil
+	panic("implement me")
+}
+
+func (r *Router) Render() eosc.Render {
+	panic("implement me")
+}
diff --git a/service-http/config.go b/service-http/config.go
new file mode 100644
index 00000000..c726b08a
--- /dev/null
+++ b/service-http/config.go
@@ -0,0 +1,17 @@
+package service_http
+
+import (
+	"github.com/eolinker/eosc"
+)
+
+type Config struct {
+	id         string
+	Name       string         `json:"name"`
+	Driver     string         `json:"driver"`
+	Desc       string         `json:"desc"`
+	Timeout    int64          `json:"timeout"`
+	Retry      int            `json:"retry"`
+	Scheme     string         `json:"scheme"`
+	RewriteUrl string         `json:"rewrite_url"`
+	Upstream   eosc.RequireId `json:"upstream" skill:"github.com/eolinker/goku-eosc/upstream.upstream.IUpstream"`
+}
diff --git a/service-http/driver.go b/service-http/driver.go
new file mode 100644
index 00000000..ace95d17
--- /dev/null
+++ b/service-http/driver.go
@@ -0,0 +1,73 @@
+package service_http
+
+import (
+	"errors"
+	"fmt"
+	"reflect"
+	"time"
+
+	"github.com/eolinker/goku-eosc/upstream"
+
+	"github.com/eolinker/eosc"
+)
+
+const (
+	driverName = "http"
+)
+
+var (
+	ErrorStructType = "error struct type: %s, need struct type: %s"
+)
+
+//driver 实现github.com/eolinker/eosc.eosc.IProfessionDriver接口
+type driver struct {
+	profession string
+	name       string
+	driver     string
+	label      string
+	desc       string
+	configType reflect.Type
+	params     map[string]string
+}
+
+func (d *driver) ConfigType() reflect.Type {
+	return d.configType
+}
+
+func (d *driver) Create(id, name string, v interface{}, workers map[eosc.RequireId]interface{}) (eosc.IWorker, error) {
+	cfg, ok := v.(*Config)
+	if !ok {
+		return nil, errors.New(fmt.Sprintf("error struct type: %s, need struct type: %s", eosc.TypeNameOf(v), d.configType))
+	}
+	if work, has := workers[cfg.Upstream]; has {
+		w := &serviceWorker{
+			id:         id,
+			name:       name,
+			driver:     cfg.Driver,
+			desc:       cfg.Desc,
+			timeout:    time.Duration(cfg.Timeout) * time.Millisecond,
+			rewriteUrl: cfg.RewriteUrl,
+			retry:      cfg.Retry,
+			scheme:     cfg.Scheme,
+			upstream:   work.(upstream.IUpstream),
+		}
+		return w, nil
+	} else {
+		work, has = workers[eosc.RequireId(fmt.Sprintf("%s@%s", cfg.Upstream, "upstream"))]
+		if has {
+			w := &serviceWorker{
+				id:         id,
+				name:       name,
+				driver:     cfg.Driver,
+				desc:       cfg.Desc,
+				timeout:    time.Duration(cfg.Timeout) * time.Millisecond,
+				rewriteUrl: cfg.RewriteUrl,
+				retry:      cfg.Retry,
+				scheme:     cfg.Scheme,
+				upstream:   work.(upstream.IUpstream),
+			}
+			return w, nil
+		}
+	}
+	return nil, errors.New("fail to create serviceWorker")
+}
diff --git a/service-http/factory.go b/service-http/factory.go
new file mode 100644
index 00000000..b9ed70d7
--- /dev/null
+++ b/service-http/factory.go
@@ -0,0 +1,44 @@
+package service_http
+
+import (
+	"reflect"
+
+	"github.com/eolinker/eosc"
+)
+
+func Register() {
+	eosc.DefaultProfessionDriverRegister.RegisterProfessionDriver("eolinker:goku:service_http", NewFactory())
+}
+
+type factory struct {
+	profession string
+	name       string
+	label      string
+	desc       string
+	params     map[string]string
+}
+
+func NewFactory() *factory {
+	return &factory{}
+}
+
+func (f *factory) ExtendInfo() eosc.ExtendInfo {
+	return eosc.ExtendInfo{
+		ID:      "eolinker:goku:service_http",
+		Group:   "eolinker",
+		Project: "goku",
+		Name:    "service_http",
+	}
+}
+
+func (f *factory) Create(profession string, name string, label string, desc string, params map[string]string) (eosc.IProfessionDriver, error) {
+	return &driver{
+		profession: profession,
+		name:       name,
+		label:      label,
+		desc:       desc,
+		driver:     driverName,
+		configType: reflect.TypeOf((*Config)(nil)),
+		params:     params,
+	}, nil
+}
diff --git a/service-http/service.go b/service-http/service.go
new file mode 100644
index 00000000..0117fdcb
--- /dev/null
+++ b/service-http/service.go
@@ -0,0 +1,119 @@
+package service_http
+
+import (
+	"errors"
+	"fmt"
+	"net/http"
+	"strings"
+	"time"
+
+	"github.com/eolinker/eosc"
+	"github.com/eolinker/goku-eosc/upstream"
+
+	http_context "github.com/eolinker/eosc/node/http-context"
+
+	"github.com/eolinker/goku-eosc/service"
+)
+
+type serviceWorker struct {
+	id         string
+	name       string
+	driver     string
+	desc       string
+	timeout    time.Duration
+	rewriteUrl string
+	retry      int
+	scheme     string
+	proxyAddr  string
+	upstream   upstream.IUpstream
+}
+
+func (s *serviceWorker) Id() string {
+	return s.id
+}
+
+func (s *serviceWorker) Start() error {
+	return nil
+}
+
+func (s *serviceWorker) Reset(conf interface{}, workers map[eosc.RequireId]interface{}) error {
+	data, ok := conf.(*Config)
+	if !ok {
+		return errors.New(fmt.Sprintf(ErrorStructType, eosc.TypeNameOf(conf), eosc.TypeNameOf((*Config)(nil))))
+	}
+	if worker, has := workers[data.Upstream]; has {
+		s.desc = data.Desc
+		s.timeout = time.Duration(data.Timeout) * time.Millisecond
+		s.rewriteUrl = data.RewriteUrl
+		s.retry = data.Retry
+		s.scheme = data.Scheme
+		u, ok := worker.(upstream.IUpstream)
+		if ok {
+			s.upstream = u
+			return nil
+		}
+	} else {
+		worker, has = workers[eosc.RequireId(fmt.Sprintf("%s@%s", data.Upstream, "upstream"))]
+		if has {
+			s.desc = data.Desc
+			s.timeout = time.Duration(data.Timeout) * time.Millisecond
+			s.rewriteUrl = data.RewriteUrl
+			s.retry = data.Retry
+			s.scheme = data.Scheme
+			u, ok := worker.(upstream.IUpstream)
+			if ok {
+				s.upstream = u
+				return nil
+			}
+			return nil
+		}
+	}
+	return errors.New("fail to create serviceWorker")
+
+}
+
+func (s *serviceWorker) Stop() error {
+	return nil
+}
+
+func (s *serviceWorker) CheckSkill(skill string) bool {
+	return service.CheckSkill(skill)
+}
+
+func (s *serviceWorker) Name() string {
+	return s.name
+}
+
+func (s *serviceWorker) Desc() string {
+	return s.desc
+}
+
+func (s *serviceWorker) Retry() int {
+	return s.retry
+}
+
+func (s *serviceWorker) Timeout() time.Duration {
+	return s.timeout
+}
+
+func (s *serviceWorker) Scheme() string {
+	return s.scheme
+}
+
+func (s *serviceWorker) ProxyAddr() string {
+	return s.proxyAddr
+}
+
+func (s *serviceWorker) Handle(w http.ResponseWriter, r *http.Request, router service.IRouterRule) error {
+	// 构造context
+	ctx := http_context.NewContext(r, w)
+	// 设置目标URL
+	ctx.ProxyRequest.SetTargetURL(recombinePath(r.URL.Path, router.Location(), s.rewriteUrl))
+	s.upstream.Send(ctx, s)
+	return nil
+}
+
+func recombinePath(requestURL, location, targetURL string) string {
+	new := strings.Replace(requestURL, location, "", 1)
+	return fmt.Sprintf("%s/%s", strings.TrimSuffix(targetURL, "/"), strings.TrimPrefix(new, "/"))
+}
diff --git a/service/service.go b/service/service.go
new file mode 100644
index 00000000..a75c7ca4
--- /dev/null
+++ b/service/service.go
@@ -0,0 +1,34 @@
+// github.com/eolinker/goku-eosc/service.service.IService
+
+package service
+
+import (
+	"net/http"
+	"net/url"
+	"time"
+)
+
+func CheckSkill(skill string) bool {
+	return skill == "github.com/eolinker/goku-eosc/service.service.IService"
+}
+
+// IService github.com/eolinker/goku-eosc/service.service.IService
+type IService interface {
+	Handle(w http.ResponseWriter, r *http.Request, router IRouterRule) error
+}
+
+type IRouterRule interface {
+	Location() string
+	Host() string
+	Header() map[string]string
+	Query() url.Values
+}
+
+type IServiceDetail interface {
+	Name() string
+	Desc() string
+	Retry() int
+	Timeout() time.Duration
+	Scheme() string
+	ProxyAddr() string
+}
diff --git a/service/service_test.go b/service/service_test.go
new file mode 100644
index 00000000..4edd4d0e
--- /dev/null
+++ b/service/service_test.go
@@ -0,0 +1,22 @@
+package service
+
+import (
+	"fmt"
+	"reflect"
+	"testing"
+)
+
+func TestService(t *testing.T) {
+	fmt.Println(TypeNameOf((*IService)(nil)))
+}
+
+func TypeNameOf(v interface{}) string {
+	return TypeName(reflect.TypeOf(v))
+}
+
+func TypeName(t reflect.Type) string {
+	if t.Kind() == reflect.Ptr {
+		return TypeName(t.Elem())
+	}
+	return fmt.Sprintf("%s.%s", t.PkgPath(), t.String())
+}
diff --git a/stores/register.go b/stores/register.go
new file mode 100644
index 00000000..a9b01d32
--- /dev/null
+++ b/stores/register.go
@@ -0,0 +1,55 @@
+package stores
+
+import "github.com/eolinker/eosc"
+
+var (
+	defaultDriverRegister iDriverRegister = newDriverManager()
+)
+
+type iDriverRegister interface {
+	RegisterDriverByKey(key string, factory IStoresFactory)
+	GetDriverByKey(key string) (IStoresFactory, bool)
+	Keys() []string
+}
+
+type DriverRegister struct {
+	register eosc.IRegister
+	keys     []string
+}
+
+func newDriverManager() *DriverRegister {
+	return &DriverRegister{
+		register: eosc.NewRegister(),
+		keys:     make([]string, 0, 10),
+	}
+}
+
+func (dm *DriverRegister) GetDriverByKey(key string) (IStoresFactory, bool) {
+	o, has := dm.register.Get(key)
+	if has {
+		f, ok := o.(IStoresFactory)
+		return f, ok
+	}
+	return nil, false
+}
+
+func (dm *DriverRegister) RegisterDriverByKey(key string, factory IStoresFactory) {
+	dm.register.Register(key, factory, true)
+	dm.keys = append(dm.keys, key)
+}
+
+func (dm *DriverRegister) Keys() []string {
+	return dm.keys
+}
+
+func RegisterFactory(key string, factory IStoresFactory) {
+	defaultDriverRegister.RegisterDriverByKey(key, factory)
+}
+
+func Get(key string) (IStoresFactory, bool) {
+	return defaultDriverRegister.GetDriverByKey(key)
+}
+
+func Keys() []string {
+	return defaultDriverRegister.Keys()
+}
diff --git a/stores/stores.go b/stores/stores.go
new file mode 100644
index 00000000..65708125
--- /dev/null
+++ b/stores/stores.go
@@ -0,0 +1,8 @@
+package stores
+
+import "github.com/eolinker/eosc"
+
+type IStoresFactory interface{
+	CreateStore(config map[string]string) (eosc.IStore, error)
+}
+
diff --git a/stores/yaml/init.go b/stores/yaml/init.go
new file mode 100644
index 00000000..0ad32035
--- /dev/null
+++ b/stores/yaml/init.go
@@ -0,0 +1,90 @@
+package yaml
+
+import (
+	"encoding/json"
+	"errors"
+	"io/ioutil"
+
+	"github.com/ghodss/yaml"
+
+	"github.com/eolinker/eosc"
+	"github.com/eolinker/eosc/store"
+)
+
+const (
+	mode       = "yaml"
+	keyInclude = ":include"
+)
+
+func Register() error {
+	store.RegisterStoreFactory(mode, CreateStore)
+	return nil
+}
+
+//CreateStore 创建store
+func CreateStore(config map[string]string) (eosc.IStore, error) {
+	store := NewStore()
+	path, ok := config["conf"]
+	if !ok {
+		return nil, errors.New("conf path is empty")
+	}
+	data, err := ioutil.ReadFile(path)
+	if err != nil {
+		return nil, err
+	}
+
+	convertData, err := yaml.YAMLToJSON(data)
+	if err != nil {
+		return nil, err
+	}
+	var cfg Employees
+	err = json.Unmarshal(convertData, &cfg)
+	if err != nil {
+		return nil, err
+	}
+
+	store.SetEmployee(cfg)
+	return store, nil
+}
+
+type Employees map[string][]interface{}
+
+//TODO
+//func Register() {
+//	stores.RegisterFactory(mode, newStoreYamlFactory())
+//}
+//
+//type storeYamlFactory struct {
+//}
+//
+//func newStoreYamlFactory() *storeYamlFactory {
+//	return &storeYamlFactory{}
+//}
+//
+////CreateStore 创建store
+//func (s *storeYamlFactory) CreateStore(config map[string]string) (eosc.IStore, error) {
+//	store := NewStore()
+//	path, ok := config["conf"]
+//	if !ok {
+//		return nil, errors.New("conf path is empty")
+//	}
+//	data, err := ioutil.ReadFile(path)
+//	if err != nil {
+//		return nil, err
+//	}
+//
+//	convertData, err := yaml.YAMLToJSON(data)
+//	if err != nil {
+//		return nil, err
+//	}
+//	var cfg Employees
+//	err = json.Unmarshal(convertData, &cfg)
+//	if err != nil {
+//		return nil, err
+//	}
+//
+//	store.SetEmployee(cfg)
+//	return store, nil
+//}
+//
+//type Employees map[string][]interface{}
diff --git a/stores/yaml/store.go b/stores/yaml/store.go
new file mode 100644
index 00000000..dbf01a93
--- /dev/null
+++ b/stores/yaml/store.go
@@ -0,0 +1,89 @@
+package yaml
+
+import (
+	"encoding/json"
+	"errors"
+	"reflect"
+
+	"github.com/eolinker/eosc/log"
+
+	"github.com/eolinker/eosc"
+)
+
+func NewStore() *Store {
+	return &Store{
+		employees: make(map[string][]string),
+		drivers:   map[string][]eosc.IStore{},
+		canWrite:  false,
+	}
+}
+
+type Store struct {
+	employees   map[string][]string
+	professions []string
+	drivers     map[string][]eosc.IStore
+	canWrite    bool
+}
+
+func (s *Store) SetEmployee(employees Employees) {
+	for key, value := range employees {
+		if _, ok := s.employees[key]; !ok {
+			s.employees[key] = make([]string, 0, len(value))
+		}
+		for _, v := range value {
+			val := reflect.ValueOf(v)
+			result := make(map[string]interface{})
+			if val.Kind() == reflect.Map {
+				m := val.MapRange()
+				for m.Next() {
+					result[m.Key().Interface().(string)] = m.Value().Interface()
+				}
+			}
+			data, err := json.Marshal(result)
+			if err != nil {
+				log.Error(err)
+				continue
+			}
+			s.employees[key] = append(s.employees[key], string(data))
+		}
+		s.professions = append(s.professions, key)
+	}
+}
+
+func (s *Store) GetEmployee(profession string) ([]string, error) {
+	if v, ok := s.employees[profession]; ok {
+		return v, nil
+	}
+	return nil, errors.New("the employee does not exist")
+}
+
+func (s *Store) Professions() []string {
+	return s.professions
+}
+
+func (s *Store) Info(profession string, nameId string) (string, error) {
+	panic("implement me")
+}
+
+func (s *Store) All(profession string) (string, error) {
+	panic("implement me")
+}
+
+func (s *Store) Mode() string {
+	return mode
+}
+
+func (s *Store) InfoByID(id string) string {
+	if v, ok := s.employees[id]; ok {
+		data, err := json.Marshal(v)
+		if err != nil {
+			return ""
+		}
+		return string(data)
+	}
+	return ""
+}
+
+func (s *Store) CanWrite() bool {
+	return s.canWrite
+}
diff --git a/upstream-http/config.go b/upstream-http/config.go
new file mode 100644
index 00000000..cb0dce43
--- /dev/null
+++ b/upstream-http/config.go
@@ -0,0 +1,16 @@
+package upstream_http
+
+import (
+	"github.com/eolinker/eosc"
+)
+
+type Config struct {
+	id        string
+	Name      string         `json:"name"`
+	Driver    string         `json:"driver"`
+	Desc      string         `json:"desc"`
+	Scheme    string         `json:"scheme"`
+	Type      string         `json:"type"`
+	Config    string         `json:"config"`
+	Discovery eosc.RequireId `json:"upstream" skill:"github.com/eolinker/goku-eosc/discovery.discovery.IDiscovery"`
+}
diff --git a/upstream-http/driver.go b/upstream-http/driver.go
new file mode 100644
index 00000000..005f250a
--- /dev/null
+++ b/upstream-http/driver.go
@@ -0,0 +1,62 @@
+package upstream_http
+
+import (
+	"errors"
+	"fmt"
+	"reflect"
+
+	"github.com/eolinker/goku-eosc/discovery"
+
+	"github.com/eolinker/eosc"
+)
+
+const (
+	driverName = "http_proxy"
+)
+
+var (
+	ErrorStructType = "error struct type: %s, need struct type: %s"
+)
+
+//driver 实现github.com/eolinker/eosc.eosc.IProfessionDriver接口
+type driver struct {
+	profession string
+	name       string
+	driver     string
+	label      string
+	desc       string
+	configType reflect.Type
+	params     map[string]string
+}
+
+func (d *driver) ConfigType() reflect.Type {
+	return d.configType
+}
+
+func (d *driver) Create(id, name string, v interface{}, workers map[eosc.RequireId]interface{}) (eosc.IWorker, error) {
+	cfg, ok := v.(*Config)
+	if !ok {
+		return nil, errors.New(fmt.Sprintf(ErrorStructType, eosc.TypeNameOf(v), d.configType))
+	}
+	if factory, has := workers[cfg.Discovery]; has {
+		f, ok := factory.(discovery.IDiscovery)
+		if ok {
+			app, err := f.GetApp(cfg.Config)
+			if err != nil {
+				return nil, err
+			}
+			w := &httpUpstream{
+				id:          id,
+				name:        name,
+				driver:      cfg.Driver,
+				desc:        cfg.Desc,
+				scheme:      cfg.Scheme,
+				balanceType: cfg.Type,
+				app:         app,
+			}
+			return w, nil
+		}
+
+	}
+	return nil, errors.New("fail to create upstream worker")
+}
diff --git a/upstream-http/factory.go b/upstream-http/factory.go
new file mode 100644
index 00000000..0b123bac
--- /dev/null
+++ b/upstream-http/factory.go
@@ -0,0 +1,44 @@
+package upstream_http
+
+import (
+	"reflect"
+
+	"github.com/eolinker/eosc"
+)
+
+func Register() {
+	eosc.DefaultProfessionDriverRegister.RegisterProfessionDriver("eolinker:goku:http_proxy", NewFactory())
+}
+
+type factory struct {
+	profession string
+	name       string
+	label      string
+	desc       string
+	params     map[string]string
+}
+
+func NewFactory() *factory {
+	return &factory{}
+}
+
+func (f *factory) ExtendInfo() eosc.ExtendInfo {
+	return eosc.ExtendInfo{
+		ID:      "eolinker:goku:upstream_http_proxy",
+		Group:   "eolinker",
+		Project: "goku",
+		Name:    "http_proxy",
+	}
+}
+
+func (f *factory) Create(profession string, name string, label string, desc string, params map[string]string) (eosc.IProfessionDriver, error) {
+	return &driver{
+		profession: profession,
+		name:       name,
+		label:      label,
+		desc:       desc,
+		driver:     driverName,
+		configType: reflect.TypeOf((*Config)(nil)),
+		params:     params,
+	}, nil
+}
diff --git a/upstream-http/http-proxy/http-proxy-request/request.go b/upstream-http/http-proxy/http-proxy-request/request.go
new file mode 100644
index 00000000..347ec230
--- /dev/null
+++ b/upstream-http/http-proxy/http-proxy-request/request.go
@@ -0,0 +1,239 @@
+package http_proxy_request
+
+import (
+	"bytes"
+	"crypto/tls"
+	"errors"
+	"io"
+	"net/http"
+	"net/url"
+
+	http_context "github.com/eolinker/eosc/node/http-context"
+
+	// "fmt"
+	"time"
+)
+
+//Version 版本号
+var Version = "2.0"
+
+var (
+	transport = &http.Transport{TLSClientConfig: &tls.Config{
+		InsecureSkipVerify: false,
+	}}
+	httpClient = &http.Client{
+		Transport: transport,
+	}
+)
+
+//SetCert 设置证书配置
+func SetCert(skip int, clientCerts []tls.Certificate) {
+	tlsConfig := &tls.Config{InsecureSkipVerify: skip == 1, Certificates: clientCerts}
+	transport.TLSClientConfig = tlsConfig
+}
+
+//Request request
+type Request struct {
+	client  *http.Client
+	method  string
+	url     string
+	headers map[string][]string
+	body    []byte
+
+	queryParams map[string][]string
+
+	timeout     time.Duration
+	httpRequest *http.Request
+}
+
+func (r *Request) SetQueryParams(queryParams url.Values) {
+	r.queryParams = queryParams
+}
+
+func (r *Request) SetHeaders(headers http.Header) {
+	r.headers = headers
+}
+
+func (r *Request) Body() []byte {
+	return r.body
+}
+
+func (r *Request) HttpRequest() *http.Request {
+	return r.httpRequest
+}
+
+//NewRequest 创建新请求
+func NewRequest(method string, URL *url.URL) (*Request, error) {
+	if method != "GET" && method != "POST" && method != "PUT" && method != "DELETE" &&
+		method != "HEAD" && method != "OPTIONS" && method != "PATCH" {
+		return nil, errors.New("Unsupported Request method")
+	}
+	return newRequest(method, URL)
+}
+
+//URLPath urlPath
+func URLPath(url string, query url.Values) string {
+	if len(query) < 1 {
+		return url
+	}
+	return url + "?" + query.Encode()
+}
+
+func newRequest(method string, URL *url.URL) (*Request, error) {
+	var urlPath string
+	queryParams := make(map[string][]string)
+	for key, values := range URL.Query() {
+		queryParams[key] = values
+	}
+	urlPath = URL.Scheme + "://" + URL.Host + URL.Path
+
+	r := &Request{
+
+		client:      httpClient,
+		method:      method,
+		url:         urlPath,
+		headers:     make(map[string][]string),
+		queryParams: queryParams,
+	}
+	return r, nil
+}
+
+//SetHeader 设置请求头
+func (r *Request) SetHeader(key string, values ...string) {
+	if len(values) > 0 {
+		r.headers[key] = values[:]
+	} else {
+		delete(r.headers, key)
+	}
+}
+
+//Headers 获取请求头
+func (r *Request) Headers() map[string][]string {
+	headers := make(map[string][]string)
+	for key, values := range r.headers {
+		headers[key] = values[:]
+	}
+	return headers
+}
+
+//SetQueryParam 设置Query参数
+func (r *Request) SetQueryParam(key string, values ...string) {
+	if len(values) > 0 {
+		r.queryParams[key] = values[:]
+	} else {
+		delete(r.queryParams, key)
+	}
+}
+
+//SetTimeout 设置请求超时时间
+func (r *Request) SetTimeout(timeout time.Duration) {
+	r.timeout = timeout
+}
+
+//send 发送请求
+func (r *Request) Send(ctx *http_context.Context) (*http.Response, error) {
+	req := r.HttpRequest()
+	req.Header.Set("Accept-Encoding", "gzip")
+	req.Header = parseHeaders(r.headers)
+
+	r.client.Timeout = r.timeout
+
+	httpResponse, err := r.client.Do(req)
+
+	return httpResponse, err
+}
+
+//QueryParams 获取query参数
+func (r *Request) QueryParams() map[string][]string {
+	params := make(map[string][]string)
+	for key, values := range r.queryParams {
+		params[key] = values[:]
+	}
+	return params
+}
+
+//URLPath 获取完整的URL路径
+func (r *Request) URLPath() string {
+	if len(r.queryParams) > 0 {
+		return r.url + "?" + parseParams(r.queryParams).Encode()
+	}
+	return r.url
+}
+
+//SetURL 设置URL
+func (r *Request) SetURL(url string) {
+	r.url = url
+}
+
+//SetRawBody 设置源数据
+func (r *Request) SetRawBody(body []byte) {
+	r.body = body
+}
+
+// 解析请求头
+func parseHeaders(headers map[string][]string) http.Header {
+	h := http.Header{}
+	for key, values := range headers {
+		for _, value := range values {
+			h.Add(key, value)
+		}
+	}
+
+	_, hasAccept := h["Accept"]
+	if !hasAccept {
+		h.Add("Accept", "*/*")
+	}
+	_, hasAgent := h["User-Agent"]
+	if !hasAgent {
+		h.Add("User-Agent", "goku-requests/"+Version)
+	}
+	return h
+}
+
+// 解析请求体
+func (r *Request) ParseBody() error {
+	if r.httpRequest == nil {
+		var body io.Reader = nil
+		if len(r.body) > 0 {
+			body = bytes.NewBuffer(r.body)
+		}
+		request, err := http.NewRequest(r.method, r.URLPath(), body)
+		if err != nil {
+			return err
+		}
+		r.httpRequest = request
+	}
+	return nil
+}
+
+// 解析参数
+func parseParams(params map[string][]string) url.Values {
+	v := url.Values{}
+	for key, values := range params {
+		for _, value := range values {
+			v.Add(key, value)
+		}
+	}
+	return v
+}
+
+// 解析URL
+func parseURL(urlPath string) (URL *url.URL, err error) {
+	URL, err = url.Parse(urlPath)
+	if err != nil {
+		return nil, err
+	}
+
+	if URL.Scheme != "http" && URL.Scheme != "https" {
+		urlPath = "http://" + urlPath
+		URL, err = url.Parse(urlPath)
+		if err != nil {
+			return nil, err
+		}
+
+		if URL.Scheme != "http" && URL.Scheme != "https" {
+			return nil, errors.New("[package requests] only HTTP and HTTPS are accepted")
+		}
+	}
+	return
+}
diff --git a/upstream-http/http-proxy/r.go b/upstream-http/http-proxy/r.go
new file mode 100644
index 00000000..1bd22a09
--- /dev/null
+++ b/upstream-http/http-proxy/r.go
@@ -0,0 +1,57 @@
+package http_proxy
+
+import (
+	"fmt"
+	"net/http"
+	"net/url"
+	"time"
+
+	http_proxy_request "github.com/eolinker/goku-eosc/upstream-http/http-proxy/http-proxy-request"
+	http_context "github.com/eolinker/eosc/node/http-context"
+)
+
+//DoRequest 构造请求
+func DoRequest(ctx *http_context.Context, uri string, timeout time.Duration) (*http.Response, error) {
+	if uri == "" {
+		return nil, fmt.Errorf("invaild url")
+	}
+
+	u, err := url.ParseRequestURI(uri)
+	if err != nil {
+		return nil, err
+	}
+
+	req, err := http_proxy_request.NewRequest(ctx.ProxyRequest.Method, u)
+	if err != nil {
+
+		return nil, err
+	}
+
+	queryDest := u.Query()
+	if ctx.ProxyRequest.Queries() != nil {
+		for k, vs := range ctx.ProxyRequest.Queries() {
+			for _, v := range vs {
+				queryDest.Add(k, v)
+			}
+		}
+	}
+
+	req.SetHeaders(ctx.ProxyRequest.Headers())
+
+	req.SetQueryParams(queryDest)
+	body, _ := ctx.ProxyRequest.RawBody()
+	req.SetRawBody(body)
+	if timeout != 0 {
+		req.SetTimeout(timeout * time.Millisecond)
+	}
+	err = req.ParseBody()
+	if err != nil {
+		return nil, err
+	}
+	response, err := req.Send(ctx)
+	if err != nil {
+		return nil, err
+	}
+
+	return response, err
+}
diff --git a/upstream-http/org.go b/upstream-http/org.go
new file mode 100644
index 00000000..19b23941
--- /dev/null
+++ b/upstream-http/org.go
@@ -0,0 +1,62 @@
+package upstream_http
+
+import (
+	"fmt"
+	"net/http"
+	"reflect"
+
+	"github.com/eolinker/goku-eosc/service"
+
+	"github.com/eolinker/goku-eosc/upstream/balance"
+
+	http_proxy "github.com/eolinker/goku-eosc/upstream-http/http-proxy"
+
+	http_context "github.com/eolinker/eosc/node/http-context"
+
+	"github.com/eolinker/eosc/utils"
+)
+
+//Http org
+type httpUpstream struct {
+	Scheme string  `json:"scheme"`
+	Nodes  []*node `json:"nodes" yaml:"nodes"`
+	Type   string  `json:"type"`
+}
+
+type node struct {
+	IP     string            `json:"ip" yaml:"ip"`
+	Port   int               `json:"port" yaml:"port"`
+	Labels map[string]string `json:"labels" yaml:"labels"`
+}
+
+//send 请求发送，忽略重试
+func (h *httpUpstream) Send(ctx *http_context.Context, serviceDetail service.IServiceDetail, handler balance.IBalanceHandler) (*http.Response, error) {
+	var response *http.Response
+	var err error
+	path := utils.TrimPrefixAll(ctx.ProxyRequest.TargetURL(), "/")
+	node, err := handler.Next()
+	if err != nil {
+		return nil, err
+	}
+	for doTrice := serviceDetail.GetRetry() + 1; doTrice > 0; doTrice-- {
+
+		u := fmt.Sprintf("%s://%s/%s", h.Scheme, node.Addr(), path)
+		response, err = http_proxy.DoRequest(ctx, u, serviceDetail.GetTimeout())
+
+		if err != nil {
+			node, err = handler.Next()
+			if err != nil {
+				return nil, err
+			}
+			continue
+		} else {
+			return response, err
+		}
+	}
+
+	return response, err
+}
+
+func GetType() reflect.Type {
+	return reflect.TypeOf((*httpUpstream)(nil))
+}
diff --git a/upstream-http/upstream.go b/upstream-http/upstream.go
new file mode 100644
index 00000000..2c2d88b2
--- /dev/null
+++ b/upstream-http/upstream.go
@@ -0,0 +1,120 @@
+package upstream_http
+
+import (
+	"errors"
+	"fmt"
+	"net/http"
+	"reflect"
+
+	"github.com/eolinker/goku-eosc/upstream"
+
+	"github.com/eolinker/eosc"
+	"github.com/eolinker/goku-eosc/discovery"
+
+	"github.com/eolinker/goku-eosc/service"
+
+	"github.com/eolinker/goku-eosc/upstream/balance"
+
+	http_proxy "github.com/eolinker/goku-eosc/http-proxy"
+
+	http_context "github.com/eolinker/eosc/node/http-context"
+
+	"github.com/eolinker/eosc/utils"
+)
+
+//Http org
+type httpUpstream struct {
+	id             string
+	name           string
+	driver         string
+	desc           string
+	scheme         string
+	balanceType    string
+	app            discovery.IApp
+	balanceHandler balance.IBalanceHandler
+}
+
+func (h *httpUpstream) Id() string {
+	return h.id
+}
+
+func (h *httpUpstream) Start() error {
+	handler, err := balance.GetDriver(h.balanceType, h.app)
+	if err != nil {
+		return err
+	}
+	h.balanceHandler = handler
+	return nil
+}
+
+func (h *httpUpstream) Reset(conf interface{}, workers map[eosc.RequireId]interface{}) error {
+	cfg, ok := conf.(*Config)
+	if !ok {
+		return errors.New(fmt.Sprintf(ErrorStructType, eosc.TypeNameOf(conf), eosc.TypeNameOf((*Config)(nil))))
+	}
+	if factory, has := workers[cfg.Discovery]; has {
+		f, ok := factory.(discovery.IDiscovery)
+		if ok {
+			app, err := f.GetApp(cfg.Config)
+			if err != nil {
+				return err
+			}
+			h.desc = cfg.Desc
+			h.scheme = cfg.Scheme
+			h.balanceType = cfg.Type
+			h.app = app
+			handler, err := balance.GetDriver(h.balanceType, h.app)
+			if err != nil {
+				return err
+			}
+			h.balanceHandler = handler
+			return nil
+		}
+	}
+	return errors.New("fail to create upstream worker")
+}
+
+func (h *httpUpstream) Stop() error {
+	h.app.Close()
+	return nil
+}
+
+func (h *httpUpstream) CheckSkill(skill string) bool {
+	return upstream.CheckSkill(skill)
+}
+
+//send 请求发送，忽略重试
+func (h *httpUpstream) Send(ctx *http_context.Context, serviceDetail service.IServiceDetail) (*http.Response, error) {
+	var response *http.Response
+	var err error
+	path := utils.TrimPrefixAll(ctx.ProxyRequest.TargetURL(), "/")
+	node, err := h.balanceHandler.Next()
+	if err != nil {
+		return nil, err
+	}
+	for doTrice := serviceDetail.Retry() + 1; doTrice > 0; doTrice-- {
+
+		u := fmt.Sprintf("%s://%s/%s", h.scheme, node.Addr(), path)
+		response, err = http_proxy.DoRequest(ctx, u, serviceDetail.Timeout())
+
+		if err != nil {
+			if response == nil {
+				node.Down()
+			}
+			h.app.NodeError(node.Id())
+			node, err = h.balanceHandler.Next()
+			if err != nil {
+				return nil, err
+			}
+			continue
+		} else {
+			return response, err
+		}
+	}
+
+	return response, err
+}
+
+func GetType() reflect.Type {
+	return reflect.TypeOf((*httpUpstream)(nil))
+}
diff --git a/upstream-http_anonymous/config.go b/upstream-http_anonymous/config.go
new file mode 100644
index 00000000..f24464be
--- /dev/null
+++ b/upstream-http_anonymous/config.go
@@ -0,0 +1,7 @@
+package upstream_http_anonymous
+
+type Config struct {
+	id     string
+	Name   string `json:"name"`
+	Driver string `json:"driver"`
+}
diff --git a/upstream-http_anonymous/driver.go b/upstream-http_anonymous/driver.go
new file mode 100644
index 00000000..6f3efd96
--- /dev/null
+++ b/upstream-http_anonymous/driver.go
@@ -0,0 +1,39 @@
+package upstream_http_anonymous
+
+import (
+	"reflect"
+
+	"github.com/eolinker/eosc"
+)
+
+const (
+	driverName = "http_proxy_anonymous"
+)
+
+var (
+	ErrorStructType = "error struct type: %s, need struct type: %s"
+)
+
+//driver 实现github.com/eolinker/eosc.eosc.IProfessionDriver接口
+type driver struct {
+	profession string
+	name       string
+	driver     string
+	label      string
+	desc       string
+	configType reflect.Type
+	params     map[string]string
+}
+
+func (d *driver) ConfigType() reflect.Type {
+	return d.configType
+}
+
+func (d *driver) Create(id, name string, v interface{}, workers map[eosc.RequireId]interface{}) (eosc.IWorker, error) {
+	w := &httpUpstream{
+		id:     id,
+		name:   name,
+		driver: driverName,
+	}
+	return w, nil
+}
diff --git a/upstream-http_anonymous/factory.go b/upstream-http_anonymous/factory.go
new file mode 100644
index 00000000..633e3449
--- /dev/null
+++ b/upstream-http_anonymous/factory.go
@@ -0,0 +1,44 @@
+package upstream_http_anonymous
+
+import (
+	"reflect"
+
+	"github.com/eolinker/eosc"
+)
+
+func Register() {
+	eosc.DefaultProfessionDriverRegister.RegisterProfessionDriver("eolinker:goku:http_proxy", NewFactory())
+}
+
+type factory struct {
+	profession string
+	name       string
+	label      string
+	desc       string
+	params     map[string]string
+}
+
+func NewFactory() *factory {
+	return &factory{}
+}
+
+func (f *factory) ExtendInfo() eosc.ExtendInfo {
+	return eosc.ExtendInfo{
+		ID:      "eolinker:goku:upstream_http_proxy",
+		Group:   "eolinker",
+		Project: "goku",
+		Name:    "http_proxy",
+	}
+}
+
+func (f *factory) Create(profession string, name string, label string, desc string, params map[string]string) (eosc.IProfessionDriver, error) {
+	return &driver{
+		profession: profession,
+		name:       name,
+		label:      label,
+		desc:       desc,
+		driver:     driverName,
+		configType: reflect.TypeOf((*Config)(nil)),
+		params:     params,
+	}, nil
+}
diff --git a/upstream-http_anonymous/org.go b/upstream-http_anonymous/org.go
new file mode 100644
index 00000000..ae357d4a
--- /dev/null
+++ b/upstream-http_anonymous/org.go
@@ -0,0 +1,68 @@
+package upstream_http_anonymous
+
+import (
+	"fmt"
+	"net/http"
+	"reflect"
+
+	"github.com/eolinker/goku-eosc/upstream"
+
+	"github.com/eolinker/eosc"
+	"github.com/eolinker/goku-eosc/service"
+
+	http_proxy "github.com/eolinker/goku-eosc/http-proxy"
+
+	http_context "github.com/eolinker/eosc/node/http-context"
+
+	"github.com/eolinker/eosc/utils"
+)
+
+//Http org
+type httpUpstream struct {
+	id     string
+	name   string
+	driver string
+}
+
+func (h *httpUpstream) Id() string {
+	return h.id
+}
+
+func (h *httpUpstream) Start() error {
+	return nil
+}
+
+func (h *httpUpstream) Reset(conf interface{}, workers map[eosc.RequireId]interface{}) error {
+	return nil
+}
+
+func (h *httpUpstream) Stop() error {
+	return nil
+}
+
+func (h *httpUpstream) CheckSkill(skill string) bool {
+	return upstream.CheckSkill(skill)
+}
+
+//send 请求发送，忽略重试
+func (h *httpUpstream) Send(ctx *http_context.Context, serviceDetail service.IServiceDetail) (*http.Response, error) {
+	var response *http.Response
+	var err error
+	path := utils.TrimPrefixAll(ctx.ProxyRequest.TargetURL(), "/")
+	for doTrice := serviceDetail.Retry() + 1; doTrice > 0; doTrice-- {
+		u := fmt.Sprintf("%s://%s/%s", serviceDetail.Scheme(), serviceDetail.ProxyAddr(), path)
+		response, err = http_proxy.DoRequest(ctx, u, serviceDetail.Timeout())
+
+		if err != nil {
+			continue
+		} else {
+			return response, err
+		}
+	}
+
+	return response, err
+}
+
+func GetType() reflect.Type {
+	return reflect.TypeOf((*httpUpstream)(nil))
+}
diff --git a/upstream/balance/balance.go b/upstream/balance/balance.go
new file mode 100644
index 00000000..eb77f0f8
--- /dev/null
+++ b/upstream/balance/balance.go
@@ -0,0 +1,84 @@
+package balance
+
+import (
+	"errors"
+
+	"github.com/eolinker/eosc"
+	"github.com/eolinker/goku-eosc/discovery"
+)
+
+var (
+	defaultDriverRegister iDriverRegister = newDriverManager()
+)
+
+type IBalanceFactory interface {
+	Create(app discovery.IApp) (IBalanceHandler, error)
+}
+
+type IBalanceHandler interface {
+	Next() (discovery.INode, error)
+}
+
+type iDriverRegister interface {
+	RegisterDriverByKey(key string, factory IBalanceFactory)
+	GetDriverByKey(key string) (IBalanceFactory, bool)
+	Keys() []string
+}
+
+type DriverRegister struct {
+	register eosc.IRegister
+	keys     []string
+}
+
+func newDriverManager() *DriverRegister {
+	return &DriverRegister{
+		register: eosc.NewRegister(),
+		keys:     make([]string, 0, 10),
+	}
+}
+
+func (dm *DriverRegister) GetDriverByKey(key string) (IBalanceFactory, bool) {
+	o, has := dm.register.Get(key)
+	if has {
+		f, ok := o.(IBalanceFactory)
+		return f, ok
+	}
+	return nil, false
+}
+
+func (dm *DriverRegister) RegisterDriverByKey(key string, factory IBalanceFactory) {
+	dm.register.Register(key, factory, true)
+	dm.keys = append(dm.keys, key)
+}
+
+func (dm *DriverRegister) Keys() []string {
+	return dm.keys
+}
+
+func Register(key string, factory IBalanceFactory) {
+	defaultDriverRegister.RegisterDriverByKey(key, factory)
+}
+
+func Get(key string) (IBalanceFactory, bool) {
+	return defaultDriverRegister.GetDriverByKey(key)
+}
+
+func Keys() []string {
+	return defaultDriverRegister.Keys()
+}
+
+func GetDriver(name string, app discovery.IApp) (IBalanceHandler, error) {
+	factory, ok := Get(name)
+	if !ok {
+		for _, key := range Keys() {
+			factory, ok = Get(key)
+			if ok {
+				break
+			}
+		}
+		if factory == nil {
+			return nil, errors.New("no valid balance handler")
+		}
+	}
+	return factory.Create(app)
+}
diff --git a/upstream/round-robin/round_robin.go b/upstream/round-robin/round_robin.go
new file mode 100644
index 00000000..ce84f711
--- /dev/null
+++ b/upstream/round-robin/round_robin.go
@@ -0,0 +1,107 @@
+package round_robin
+
+import (
+	"errors"
+	"strconv"
+
+	"github.com/eolinker/goku-eosc/upstream/balance"
+
+	"github.com/eolinker/goku-eosc/discovery"
+)
+
+const (
+	name = "round-robin"
+)
+
+func Register() {
+	balance.Register(name, newRoundRobinFactory())
+}
+
+func newRoundRobinFactory() *roundRobinFactory {
+	return &roundRobinFactory{}
+}
+
+type roundRobinFactory struct {
+}
+
+func (r *roundRobinFactory) Create(app discovery.IApp) (balance.IBalanceHandler, error) {
+	rr := newRoundRobin(app.Nodes())
+	return rr, nil
+}
+
+type node struct {
+	weight int
+	discovery.INode
+}
+
+type roundRobin struct {
+	// nodes 节点列表
+	nodes []node
+	// 节点数量
+	size int
+	// index 当前索引
+	index int
+	// gcdWeight 权重最大公约数
+	gcdWeight int
+	// maxWeight 权重最大值
+	maxWeight int
+}
+
+func (r *roundRobin) Next() (discovery.INode, error) {
+	cw := 0
+	for {
+		r.index = (r.index + 1) % r.size
+		if r.index == 0 {
+			cw = cw - r.gcdWeight
+			if cw <= 0 {
+				cw = r.maxWeight
+				if cw == 0 {
+					return nil, errors.New("")
+				}
+			}
+		}
+		if r.nodes[r.index].weight >= cw {
+			return r.nodes[r.index], nil
+		}
+	}
+}
+
+func newRoundRobin(nodes []discovery.INode) *roundRobin {
+	size := len(nodes)
+	r := &roundRobin{
+		nodes: make([]node, 0, size),
+		size:  size,
+	}
+	for i, n := range r.nodes {
+		weight, _ := r.nodes[r.index].GetAttrByName("weight")
+		w, _ := strconv.Atoi(weight)
+		if w == 0 {
+			w = 1
+		}
+		nd := node{w, n}
+		r.nodes = append(r.nodes, nd)
+		if i == 0 {
+			r.maxWeight = w
+			r.gcdWeight = w
+			continue
+		}
+		r.gcdWeight = gcd(w, r.gcdWeight)
+		r.maxWeight = max(w, r.maxWeight)
+	}
+	return r
+}
+
+func gcd(a, b int) int {
+	c := a % b
+	if c == 0 {
+		return b
+	}
+	return gcd(b, c)
+}
+
+func max(a, b int) int {
+	if a > b {
+		return a
+	}
+	return b
+}
diff --git a/upstream/upstream.go b/upstream/upstream.go
new file mode 100644
index 00000000..a4a0c7d7
--- /dev/null
+++ b/upstream/upstream.go
@@ -0,0 +1,19 @@
+package upstream
+
+import (
+	"net/http"
+
+	"github.com/eolinker/goku-eosc/service"
+	http_context "github.com/eolinker/eosc/node/http-context"
+)
+
+func CheckSkill(skill string) bool {
+	return skill == "github.com/eolinker/goku-eosc/upstream.upstream.IUpstream"
+}
+
+type IUpstream interface {
+	Send(ctx *http_context.Context, serviceDetail service.IServiceDetail) (*http.Response, error)
+}
+
+type Factory struct {
+}
diff --git a/upstream/upstream_test.go b/upstream/upstream_test.go
new file mode 100644
index 00000000..f5f439fa
--- /dev/null
+++ b/upstream/upstream_test.go
@@ -0,0 +1,14 @@
+package upstream
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/eolinker/goku-eosc/discovery"
+
+	"github.com/eolinker/eosc"
+)
+
+func TestUpstream(t *testing.T) {
+	fmt.Println(eosc.TypeNameOf((*discovery.IDiscovery)(nil)))
+}
