diff --git a/.gitignore b/.gitignore
index fabff68b874df4c2a7de15ce91798e9bb963b358..8158b497e3620a15fc5a52e91020e1fcebd5be41 100644
--- a/.gitignore
+++ b/.gitignore
@@ -29,6 +29,8 @@ config_center/zookeeper/zookeeper-4unittest/
 registry/zookeeper/zookeeper-4unittest/
 metadata/report/zookeeper/zookeeper-4unittest/
 registry/consul/agent*
+metadata/report/consul/agent*
+remoting/consul/agent*
 config_center/apollo/mockDubbog.properties.json
 
 # vim stuff
diff --git a/common/constant/default.go b/common/constant/default.go
index 629aa32392a0151046eaaea67287618eae02158d..4165942a615e220f6384a898b07c04bafd39c3b0 100644
--- a/common/constant/default.go
+++ b/common/constant/default.go
@@ -45,6 +45,7 @@ const (
 	DEFAULT_REST_CLIENT        = "resty"
 	DEFAULT_REST_SERVER        = "go-restful"
 	DEFAULT_PORT               = 20000
+	DEFAULT_SERIALIZATION      = HESSIAN2_SERIALIZATION
 )
 
 const (
diff --git a/common/constant/key.go b/common/constant/key.go
index fe8c5baaf0ed8ba0745dba0949782dc7b14d6fae..943338f8e6f13512d96cfed4cbc4f275d6aab2cb 100644
--- a/common/constant/key.go
+++ b/common/constant/key.go
@@ -22,31 +22,32 @@ const (
 )
 
 const (
-	PORT_KEY               = "port"
-	GROUP_KEY              = "group"
-	VERSION_KEY            = "version"
-	INTERFACE_KEY          = "interface"
-	PATH_KEY               = "path"
-	PROTOCOL_KEY           = "protocol"
-	SERVICE_KEY            = "service"
-	METHODS_KEY            = "methods"
-	TIMEOUT_KEY            = "timeout"
-	CATEGORY_KEY           = "category"
-	CHECK_KEY              = "check"
-	ENABLED_KEY            = "enabled"
-	SIDE_KEY               = "side"
-	OVERRIDE_PROVIDERS_KEY = "providerAddresses"
-	BEAN_NAME_KEY          = "bean.name"
-	GENERIC_KEY            = "generic"
-	CLASSIFIER_KEY         = "classifier"
-	TOKEN_KEY              = "token"
-	LOCAL_ADDR             = "local-addr"
-	REMOTE_ADDR            = "remote-addr"
-	PATH_SEPARATOR         = "/"
-	DUBBO_KEY              = "dubbo"
-	RELEASE_KEY            = "release"
-	ANYHOST_KEY            = "anyhost"
-	SSL_ENABLED_KEY        = "ssl-enabled"
+	GROUP_KEY                = "group"
+	VERSION_KEY              = "version"
+	INTERFACE_KEY            = "interface"
+	PATH_KEY                 = "path"
+	SERVICE_KEY              = "service"
+	METHODS_KEY              = "methods"
+	TIMEOUT_KEY              = "timeout"
+	CATEGORY_KEY             = "category"
+	CHECK_KEY                = "check"
+	ENABLED_KEY              = "enabled"
+	SIDE_KEY                 = "side"
+	OVERRIDE_PROVIDERS_KEY   = "providerAddresses"
+	BEAN_NAME_KEY            = "bean.name"
+	GENERIC_KEY              = "generic"
+	CLASSIFIER_KEY           = "classifier"
+	TOKEN_KEY                = "token"
+	LOCAL_ADDR               = "local-addr"
+	REMOTE_ADDR              = "remote-addr"
+	DEFAULT_REMOTING_TIMEOUT = 3000
+	RELEASE_KEY              = "release"
+	ANYHOST_KEY              = "anyhost"
+	PORT_KEY                 = "port"
+	PROTOCOL_KEY             = "protocol"
+	PATH_SEPARATOR           = "/"
+	DUBBO_KEY                = "dubbo"
+	SSL_ENABLED_KEY          = "ssl-enabled"
 )
 
 const (
@@ -81,6 +82,7 @@ const (
 	EXECUTE_REJECTED_EXECUTION_HANDLER_KEY = "execute.limit.rejected.handler"
 	PROVIDER_SHUTDOWN_FILTER               = "pshutdown"
 	CONSUMER_SHUTDOWN_FILTER               = "cshutdown"
+	SERIALIZATION_KEY                      = "serialization"
 	PID_KEY                                = "pid"
 	SYNC_REPORT_KEY                        = "sync.report"
 	RETRY_PERIOD_KEY                       = "retry.period"
diff --git a/common/constant/serializtion.go b/common/constant/serializtion.go
new file mode 100644
index 0000000000000000000000000000000000000000..f27598ccf5cf04a72d14d4ef97ae9298076efe1a
--- /dev/null
+++ b/common/constant/serializtion.go
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package constant
+
+const (
+	S_Hessian2 byte = 2
+	S_Proto    byte = 21
+)
+
+const (
+	HESSIAN2_SERIALIZATION = "hessian2"
+	PROTOBUF_SERIALIZATION = "protobuf"
+)
diff --git a/common/url.go b/common/url.go
index 0ff3e8f03473b681b77b00ee1e0ba23f9796822a..5a3e57406bf221a341d9a3ea120943144a35aca0 100644
--- a/common/url.go
+++ b/common/url.go
@@ -18,6 +18,7 @@
 package common
 
 import (
+	"bytes"
 	"encoding/base64"
 	"fmt"
 	"math"
@@ -325,12 +326,15 @@ func (c URL) Key() string {
 
 // ServiceKey gets a unique key of a service.
 func (c URL) ServiceKey() string {
-	intf := c.GetParam(constant.INTERFACE_KEY, strings.TrimPrefix(c.Path, "/"))
+	return ServiceKey(c.GetParam(constant.INTERFACE_KEY, strings.TrimPrefix(c.Path, "/")),
+		c.GetParam(constant.GROUP_KEY, ""), c.GetParam(constant.VERSION_KEY, ""))
+}
+
+func ServiceKey(intf string, group string, version string) string {
 	if intf == "" {
 		return ""
 	}
-	var buf strings.Builder
-	group := c.GetParam(constant.GROUP_KEY, "")
+	buf := &bytes.Buffer{}
 	if group != "" {
 		buf.WriteString(group)
 		buf.WriteString("/")
@@ -338,7 +342,6 @@ func (c URL) ServiceKey() string {
 
 	buf.WriteString(intf)
 
-	version := c.GetParam(constant.VERSION_KEY, "")
 	if version != "" && version != "0.0.0" {
 		buf.WriteString(":")
 		buf.WriteString(version)
diff --git a/config/service_config.go b/config/service_config.go
index 8968bac88f55c614841462517c5a5a4ecbe6f594..48632a1b1e295eb5ec3027bd495ef8d19e978ec4 100644
--- a/config/service_config.go
+++ b/config/service_config.go
@@ -59,6 +59,7 @@ type ServiceConfig struct {
 	Methods                     []*MethodConfig   `yaml:"methods"  json:"methods,omitempty" property:"methods"`
 	Warmup                      string            `yaml:"warmup"  json:"warmup,omitempty"  property:"warmup"`
 	Retries                     string            `yaml:"retries"  json:"retries,omitempty" property:"retries"`
+	Serialization               string            `yaml:"serialization" json:"serialization" property:"serialization"`
 	Params                      map[string]string `yaml:"params"  json:"params,omitempty" property:"params"`
 	Token                       string            `yaml:"token" json:"token,omitempty" property:"token"`
 	AccessLog                   string            `yaml:"accesslog" json:"accesslog,omitempty" property:"accesslog"`
@@ -270,7 +271,8 @@ func (c *ServiceConfig) getUrlMap() url.Values {
 	urlMap.Set(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER))
 	urlMap.Set(constant.RELEASE_KEY, "dubbo-golang-"+constant.Version)
 	urlMap.Set(constant.SIDE_KEY, (common.RoleType(common.PROVIDER)).Role())
-
+	// todo: move
+	urlMap.Set(constant.SERIALIZATION_KEY, c.Serialization)
 	// application info
 	urlMap.Set(constant.APPLICATION_KEY, providerConfig.ApplicationConfig.Name)
 	urlMap.Set(constant.ORGANIZATION_KEY, providerConfig.ApplicationConfig.Organization)
diff --git a/metadata/service/exporter/configurable/exporter_test.go b/metadata/service/exporter/configurable/exporter_test.go
index 9fdbd76757815af0aa975ec6e5f1b20fa5f1a83e..b304b9153f92f1a7ab8176236fd9648e09f4366b 100644
--- a/metadata/service/exporter/configurable/exporter_test.go
+++ b/metadata/service/exporter/configurable/exporter_test.go
@@ -30,15 +30,15 @@ import (
 	"github.com/apache/dubbo-go/config"
 	_ "github.com/apache/dubbo-go/filter/filter_impl"
 	"github.com/apache/dubbo-go/metadata/service/inmemory"
-	"github.com/apache/dubbo-go/protocol/dubbo"
 	_ "github.com/apache/dubbo-go/protocol/dubbo"
+	"github.com/apache/dubbo-go/remoting/getty"
 )
 
 func TestConfigurableExporter(t *testing.T) {
-	dubbo.SetServerConfig(dubbo.ServerConfig{
+	getty.SetServerConfig(getty.ServerConfig{
 		SessionNumber:  700,
 		SessionTimeout: "20s",
-		GettySessionParam: dubbo.GettySessionParam{
+		GettySessionParam: getty.GettySessionParam{
 			CompressEncoding: false,
 			TcpNoDelay:       true,
 			TcpKeepAlive:     true,
diff --git a/protocol/dubbo/client.go b/protocol/dubbo/client.go
deleted file mode 100644
index 8c71c57939cecb73df340f8bb02b0186272febd1..0000000000000000000000000000000000000000
--- a/protocol/dubbo/client.go
+++ /dev/null
@@ -1,362 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dubbo
-
-import (
-	"math/rand"
-	"strings"
-	"sync"
-	"time"
-)
-
-import (
-	"github.com/apache/dubbo-getty"
-	gxsync "github.com/dubbogo/gost/sync"
-	perrors "github.com/pkg/errors"
-	"go.uber.org/atomic"
-	"gopkg.in/yaml.v2"
-)
-
-import (
-	"github.com/apache/dubbo-go/common"
-	"github.com/apache/dubbo-go/common/constant"
-	"github.com/apache/dubbo-go/common/logger"
-	"github.com/apache/dubbo-go/config"
-	"github.com/apache/dubbo-go/protocol/dubbo/hessian2"
-)
-
-var (
-	errInvalidCodecType  = perrors.New("illegal CodecType")
-	errInvalidAddress    = perrors.New("remote address invalid or empty")
-	errSessionNotExist   = perrors.New("session not exist")
-	errClientClosed      = perrors.New("client closed")
-	errClientReadTimeout = perrors.New("client read timeout")
-
-	clientConf   *ClientConfig
-	clientGrpool *gxsync.TaskPool
-)
-
-func init() {
-	// load clientconfig from consumer_config
-	// default use dubbo
-	consumerConfig := config.GetConsumerConfig()
-	if consumerConfig.ApplicationConfig == nil {
-		return
-	}
-	protocolConf := config.GetConsumerConfig().ProtocolConf
-	defaultClientConfig := GetDefaultClientConfig()
-	if protocolConf == nil {
-		logger.Info("protocol_conf default use dubbo config")
-	} else {
-		dubboConf := protocolConf.(map[interface{}]interface{})[DUBBO]
-		if dubboConf == nil {
-			logger.Warnf("dubboConf is nil")
-			return
-		}
-		dubboConfByte, err := yaml.Marshal(dubboConf)
-		if err != nil {
-			panic(err)
-		}
-		err = yaml.Unmarshal(dubboConfByte, &defaultClientConfig)
-		if err != nil {
-			panic(err)
-		}
-	}
-	clientConf = &defaultClientConfig
-	if err := clientConf.CheckValidity(); err != nil {
-		logger.Warnf("[CheckValidity] error: %v", err)
-		return
-	}
-	setClientGrpool()
-
-	rand.Seed(time.Now().UnixNano())
-}
-
-// SetClientConf set dubbo client config.
-func SetClientConf(c ClientConfig) {
-	clientConf = &c
-	err := clientConf.CheckValidity()
-	if err != nil {
-		logger.Warnf("[ClientConfig CheckValidity] error: %v", err)
-		return
-	}
-	setClientGrpool()
-}
-
-// GetClientConf get dubbo client config.
-func GetClientConf() ClientConfig {
-	return *clientConf
-}
-
-func setClientGrpool() {
-	if clientConf.GrPoolSize > 1 {
-		clientGrpool = gxsync.NewTaskPool(
-			gxsync.WithTaskPoolTaskPoolSize(clientConf.GrPoolSize),
-			gxsync.WithTaskPoolTaskQueueLength(clientConf.QueueLen),
-			gxsync.WithTaskPoolTaskQueueNumber(clientConf.QueueNumber),
-		)
-	}
-}
-
-// Options is option for create dubbo client
-type Options struct {
-	// connect timeout
-	ConnectTimeout time.Duration
-	// request timeout
-	RequestTimeout time.Duration
-}
-
-//AsyncCallbackResponse async response for dubbo
-type AsyncCallbackResponse struct {
-	common.CallbackResponse
-	Opts      Options
-	Cause     error
-	Start     time.Time // invoke(call) start time == write start time
-	ReadStart time.Time // read start time, write duration = ReadStart - Start
-	Reply     interface{}
-}
-
-// Client is dubbo protocol client.
-type Client struct {
-	opts     Options
-	conf     ClientConfig
-	pool     *gettyRPCClientPool
-	sequence atomic.Uint64
-
-	pendingResponses *sync.Map
-}
-
-// NewClient create a new Client.
-func NewClient(opt Options) *Client {
-	switch {
-	case opt.ConnectTimeout == 0:
-		opt.ConnectTimeout = 3 * time.Second
-		fallthrough
-	case opt.RequestTimeout == 0:
-		opt.RequestTimeout = 3 * time.Second
-	}
-
-	// make sure that client request sequence is an odd number
-	initSequence := uint64(rand.Int63n(time.Now().UnixNano()))
-	if initSequence%2 == 0 {
-		initSequence++
-	}
-
-	c := &Client{
-		opts:             opt,
-		pendingResponses: new(sync.Map),
-		conf:             *clientConf,
-	}
-	c.sequence.Store(initSequence)
-	c.pool = newGettyRPCClientConnPool(c, clientConf.PoolSize, time.Duration(int(time.Second)*clientConf.PoolTTL))
-
-	return c
-}
-
-// Request is dubbo protocol request.
-type Request struct {
-	addr   string
-	svcUrl common.URL
-	method string
-	args   interface{}
-	atta   map[string]interface{}
-}
-
-// NewRequest create a new Request.
-func NewRequest(addr string, svcUrl common.URL, method string, args interface{}, atta map[string]interface{}) *Request {
-	return &Request{
-		addr:   addr,
-		svcUrl: svcUrl,
-		method: method,
-		args:   args,
-		atta:   atta,
-	}
-}
-
-// Response is dubbo protocol response.
-type Response struct {
-	reply interface{}
-	atta  map[string]interface{}
-}
-
-// NewResponse creates a new Response.
-func NewResponse(reply interface{}, atta map[string]interface{}) *Response {
-	return &Response{
-		reply: reply,
-		atta:  atta,
-	}
-}
-
-// CallOneway call by one way
-func (c *Client) CallOneway(request *Request) error {
-	return perrors.WithStack(c.call(CT_OneWay, request, NewResponse(nil, nil), nil))
-}
-
-// Call call remoting by two way or one way, if @response.reply is nil, the way of call is one way.
-func (c *Client) Call(request *Request, response *Response) error {
-	ct := CT_TwoWay
-	if response.reply == nil {
-		ct = CT_OneWay
-	}
-
-	return perrors.WithStack(c.call(ct, request, response, nil))
-}
-
-// AsyncCall call remoting by async with callback.
-func (c *Client) AsyncCall(request *Request, callback common.AsyncCallback, response *Response) error {
-	return perrors.WithStack(c.call(CT_TwoWay, request, response, callback))
-}
-
-func (c *Client) call(ct CallType, request *Request, response *Response, callback common.AsyncCallback) error {
-	p := &DubboPackage{}
-	p.Service.Path = strings.TrimPrefix(request.svcUrl.Path, "/")
-	p.Service.Interface = request.svcUrl.GetParam(constant.INTERFACE_KEY, "")
-	p.Service.Version = request.svcUrl.GetParam(constant.VERSION_KEY, "")
-	p.Service.Group = request.svcUrl.GetParam(constant.GROUP_KEY, "")
-	p.Service.Method = request.method
-	c.pool.sslEnabled = request.svcUrl.GetParamBool(constant.SSL_ENABLED_KEY, false)
-
-	p.Service.Timeout = c.opts.RequestTimeout
-	var timeout = request.svcUrl.GetParam(strings.Join([]string{constant.METHOD_KEYS, request.method + constant.RETRIES_KEY}, "."), "")
-	if len(timeout) != 0 {
-		if t, err := time.ParseDuration(timeout); err == nil {
-			p.Service.Timeout = t
-		}
-	}
-
-	p.Header.SerialID = byte(S_Dubbo)
-	p.Body = hessian2.NewRequest(request.args, request.atta)
-
-	var rsp *PendingResponse
-	if ct != CT_OneWay {
-		p.Header.Type = hessian2.PackageRequest_TwoWay
-		rsp = NewPendingResponse()
-		rsp.response = response
-		rsp.callback = callback
-	} else {
-		p.Header.Type = hessian2.PackageRequest
-	}
-
-	var (
-		err     error
-		session getty.Session
-		conn    *gettyRPCClient
-	)
-	conn, session, err = c.selectSession(request.addr)
-	if err != nil {
-		return perrors.WithStack(err)
-	}
-	if session == nil {
-		return errSessionNotExist
-	}
-	defer func() {
-		if err == nil {
-			c.pool.put(conn)
-			return
-		}
-		conn.close()
-	}()
-
-	if err = c.transfer(session, p, rsp); err != nil {
-		return perrors.WithStack(err)
-	}
-
-	if ct == CT_OneWay || callback != nil {
-		return nil
-	}
-
-	select {
-	case <-getty.GetTimeWheel().After(c.opts.RequestTimeout):
-		c.removePendingResponse(SequenceType(rsp.seq))
-		return perrors.WithStack(errClientReadTimeout)
-	case <-rsp.done:
-		err = rsp.err
-	}
-
-	return perrors.WithStack(err)
-}
-
-// Close close the client pool.
-func (c *Client) Close() {
-	if c.pool != nil {
-		c.pool.close()
-	}
-	c.pool = nil
-}
-
-func (c *Client) selectSession(addr string) (*gettyRPCClient, getty.Session, error) {
-	rpcClient, err := c.pool.getGettyRpcClient(DUBBO, addr)
-	if err != nil {
-		return nil, nil, perrors.WithStack(err)
-	}
-	return rpcClient, rpcClient.selectSession(), nil
-}
-
-func (c *Client) heartbeat(session getty.Session) error {
-	return c.transfer(session, nil, NewPendingResponse())
-}
-
-func (c *Client) transfer(session getty.Session, pkg *DubboPackage, rsp *PendingResponse) error {
-	var (
-		sequence uint64
-		err      error
-	)
-
-	sequence = c.sequence.Add(1)
-
-	if pkg == nil {
-		pkg = &DubboPackage{}
-		pkg.Body = hessian2.NewRequest([]interface{}{}, nil)
-		pkg.Body = []interface{}{}
-		pkg.Header.Type = hessian2.PackageHeartbeat
-		pkg.Header.SerialID = byte(S_Dubbo)
-	}
-	pkg.Header.ID = int64(sequence)
-
-	// cond1
-	if rsp != nil {
-		rsp.seq = sequence
-		c.addPendingResponse(rsp)
-	}
-
-	err = session.WritePkg(pkg, c.opts.RequestTimeout)
-	if err != nil {
-		c.removePendingResponse(SequenceType(rsp.seq))
-	} else if rsp != nil { // cond2
-		// cond2 should not merged with cond1. cause the response package may be returned very
-		// soon and it will be handled by other goroutine.
-		rsp.readStart = time.Now()
-	}
-
-	return perrors.WithStack(err)
-}
-
-func (c *Client) addPendingResponse(pr *PendingResponse) {
-	c.pendingResponses.Store(SequenceType(pr.seq), pr)
-}
-
-func (c *Client) removePendingResponse(seq SequenceType) *PendingResponse {
-	if c.pendingResponses == nil {
-		return nil
-	}
-	if presp, ok := c.pendingResponses.Load(seq); ok {
-		c.pendingResponses.Delete(seq)
-		return presp.(*PendingResponse)
-	}
-	return nil
-}
diff --git a/protocol/dubbo/client_test.go b/protocol/dubbo/client_test.go
deleted file mode 100644
index a3b194ad407aa8579ced04b591588a2656423c2c..0000000000000000000000000000000000000000
--- a/protocol/dubbo/client_test.go
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dubbo
-
-import (
-	"bytes"
-	"context"
-	"fmt"
-	"sync"
-	"testing"
-	"time"
-)
-
-import (
-	hessian "github.com/apache/dubbo-go-hessian2"
-	perrors "github.com/pkg/errors"
-	"github.com/stretchr/testify/assert"
-)
-
-import (
-	"github.com/apache/dubbo-go/common"
-	"github.com/apache/dubbo-go/common/proxy/proxy_factory"
-	"github.com/apache/dubbo-go/protocol"
-)
-
-const (
-	mockMethodNameGetUser   = "GetUser"
-	mockMethodNameGetBigPkg = "GetBigPkg"
-	mockAddress             = "127.0.0.1:20000"
-)
-
-func TestClientCallOneway(t *testing.T) {
-	proto, url := InitTest(t)
-
-	c := &Client{
-		pendingResponses: new(sync.Map),
-		conf:             *clientConf,
-		opts: Options{
-			ConnectTimeout: 3e9,
-			RequestTimeout: 6e9,
-		},
-	}
-	c.pool = newGettyRPCClientConnPool(c, clientConf.PoolSize, time.Duration(int(time.Second)*clientConf.PoolTTL))
-
-	err := c.CallOneway(NewRequest(mockAddress, url, mockMethodNameGetUser, []interface{}{"1", "username"}, nil))
-	assert.NoError(t, err)
-
-	// destroy
-	proto.Destroy()
-}
-
-func TestClientCall(t *testing.T) {
-	proto, url := InitTest(t)
-
-	c := &Client{
-		pendingResponses: new(sync.Map),
-		conf:             *clientConf,
-		opts: Options{
-			ConnectTimeout: 3e9,
-			RequestTimeout: 10e9,
-		},
-	}
-	c.pool = newGettyRPCClientConnPool(c, clientConf.PoolSize, time.Duration(int(time.Second)*clientConf.PoolTTL))
-
-	var (
-		user *User
-		err  error
-	)
-
-	user = &User{}
-	err = c.Call(NewRequest(mockAddress, url, mockMethodNameGetBigPkg, []interface{}{nil}, nil), NewResponse(user, nil))
-	assert.NoError(t, err)
-	assert.NotEqual(t, "", user.Id)
-	assert.NotEqual(t, "", user.Name)
-
-	user = &User{}
-	err = c.Call(NewRequest(mockAddress, url, mockMethodNameGetUser, []interface{}{"1", "username"}, nil), NewResponse(user, nil))
-	assert.NoError(t, err)
-	assert.Equal(t, User{Id: "1", Name: "username"}, *user)
-
-	user = &User{}
-	err = c.Call(NewRequest(mockAddress, url, "GetUser0", []interface{}{"1", nil, "username"}, nil), NewResponse(user, nil))
-	assert.NoError(t, err)
-	assert.Equal(t, User{Id: "1", Name: "username"}, *user)
-
-	err = c.Call(NewRequest(mockAddress, url, "GetUser1", []interface{}{}, nil), NewResponse(user, nil))
-	assert.NoError(t, err)
-
-	err = c.Call(NewRequest(mockAddress, url, "GetUser2", []interface{}{}, nil), NewResponse(user, nil))
-	assert.EqualError(t, err, "error")
-
-	user2 := []interface{}{}
-	err = c.Call(NewRequest(mockAddress, url, "GetUser3", []interface{}{}, nil), NewResponse(&user2, nil))
-	assert.NoError(t, err)
-	assert.Equal(t, &User{Id: "1", Name: "username"}, user2[0])
-
-	user2 = []interface{}{}
-	err = c.Call(NewRequest(mockAddress, url, "GetUser4", []interface{}{[]interface{}{"1", "username"}}, nil), NewResponse(&user2, nil))
-	assert.NoError(t, err)
-	assert.Equal(t, &User{Id: "1", Name: "username"}, user2[0])
-
-	user3 := map[interface{}]interface{}{}
-	err = c.Call(NewRequest(mockAddress, url, "GetUser5", []interface{}{map[interface{}]interface{}{"id": "1", "name": "username"}}, nil), NewResponse(&user3, nil))
-	assert.NoError(t, err)
-	assert.NotNil(t, user3)
-	assert.Equal(t, &User{Id: "1", Name: "username"}, user3["key"])
-
-	user = &User{}
-	err = c.Call(NewRequest(mockAddress, url, "GetUser6", []interface{}{0}, nil), NewResponse(user, nil))
-	assert.NoError(t, err)
-	assert.Equal(t, User{Id: "", Name: ""}, *user)
-
-	user = &User{}
-	err = c.Call(NewRequest(mockAddress, url, "GetUser6", []interface{}{1}, nil), NewResponse(user, nil))
-	assert.NoError(t, err)
-	assert.Equal(t, User{Id: "1", Name: ""}, *user)
-
-	user = &User{}
-	r1 := "v1"
-	r2 := &AttaTestObject{Ti: 45, Desc: "v2"}
-	err = c.Call(NewRequest(mockAddress, url, "GetUserForAttachment", []interface{}{1}, map[string]interface{}{"sim": r1, "comp": r2}), NewResponse(user, nil))
-	assert.NoError(t, err)
-	// the param is transfered from client to server by attachment, and the server will return the attachment value.
-	// the test should check the value came back from server.
-	assert.Equal(t, User{Id: r1, Name: fmt.Sprintf("%+v", *r2)}, *user)
-
-	// destroy
-	proto.Destroy()
-}
-
-func TestClientAsyncCall(t *testing.T) {
-	proto, url := InitTest(t)
-
-	c := &Client{
-		pendingResponses: new(sync.Map),
-		conf:             *clientConf,
-		opts: Options{
-			ConnectTimeout: 3e9,
-			RequestTimeout: 6e9,
-		},
-	}
-	c.pool = newGettyRPCClientConnPool(c, clientConf.PoolSize, time.Duration(int(time.Second)*clientConf.PoolTTL))
-
-	user := &User{}
-	lock := sync.Mutex{}
-	lock.Lock()
-	err := c.AsyncCall(NewRequest(mockAddress, url, mockMethodNameGetUser, []interface{}{"1", "username"}, nil), func(response common.CallbackResponse) {
-		r := response.(AsyncCallbackResponse)
-		assert.Equal(t, User{Id: "1", Name: "username"}, *r.Reply.(*Response).reply.(*User))
-		lock.Unlock()
-	}, NewResponse(user, nil))
-	assert.NoError(t, err)
-	assert.Equal(t, User{}, *user)
-
-	// destroy
-	lock.Lock()
-	proto.Destroy()
-	lock.Unlock()
-}
-
-func InitTest(t *testing.T) (protocol.Protocol, common.URL) {
-
-	hessian.RegisterPOJO(&User{})
-	hessian.RegisterPOJO(&AttaTestObject{})
-
-	methods, err := common.ServiceMap.Register("com.ikurento.user.UserProvider", "dubbo", &UserProvider{})
-	assert.NoError(t, err)
-	assert.Equal(t, "GetBigPkg,GetUser,GetUser0,GetUser1,GetUser2,GetUser3,GetUser4,GetUser5,GetUser6,GetUserForAttachment", methods)
-
-	// config
-	SetClientConf(ClientConfig{
-		ConnectionNum:   2,
-		HeartbeatPeriod: "5s",
-		SessionTimeout:  "20s",
-		PoolTTL:         600,
-		PoolSize:        64,
-		GettySessionParam: GettySessionParam{
-			CompressEncoding: false,
-			TcpNoDelay:       true,
-			TcpKeepAlive:     true,
-			KeepAlivePeriod:  "120s",
-			TcpRBufSize:      262144,
-			TcpWBufSize:      65536,
-			PkgWQSize:        512,
-			TcpReadTimeout:   "4s",
-			TcpWriteTimeout:  "5s",
-			WaitTimeout:      "1s",
-			MaxMsgLen:        10240000000,
-			SessionName:      "client",
-		},
-	})
-	assert.NoError(t, clientConf.CheckValidity())
-	SetServerConfig(ServerConfig{
-		SessionNumber:  700,
-		SessionTimeout: "20s",
-		GettySessionParam: GettySessionParam{
-			CompressEncoding: false,
-			TcpNoDelay:       true,
-			TcpKeepAlive:     true,
-			KeepAlivePeriod:  "120s",
-			TcpRBufSize:      262144,
-			TcpWBufSize:      65536,
-			PkgWQSize:        512,
-			TcpReadTimeout:   "1s",
-			TcpWriteTimeout:  "5s",
-			WaitTimeout:      "1s",
-			MaxMsgLen:        10240000000,
-			SessionName:      "server",
-		}})
-	assert.NoError(t, srvConf.CheckValidity())
-
-	// Export
-	proto := GetProtocol()
-	url, err := common.NewURL("dubbo://127.0.0.1:20000/UserProvider?anyhost=true&" +
-		"application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&" +
-		"environment=dev&interface=com.ikurento.user.UserProvider&ip=192.168.56.1&methods=GetUser%2C&" +
-		"module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&" +
-		"side=provider&timeout=3000&timestamp=1556509797245&bean.name=UserProvider")
-	assert.NoError(t, err)
-	proto.Export(&proxy_factory.ProxyInvoker{
-		BaseInvoker: *protocol.NewBaseInvoker(url),
-	})
-
-	time.Sleep(time.Second * 2)
-
-	return proto, url
-}
-
-//////////////////////////////////
-// provider
-//////////////////////////////////
-
-type (
-	User struct {
-		Id   string `json:"id"`
-		Name string `json:"name"`
-	}
-
-	UserProvider struct {
-		user map[string]User
-	}
-)
-
-// size:4801228
-func (u *UserProvider) GetBigPkg(ctx context.Context, req []interface{}, rsp *User) error {
-	argBuf := new(bytes.Buffer)
-	for i := 0; i < 4000; i++ {
-		argBuf.WriteString("击鼓其镗,踊跃用兵。土国城漕,我独南行。从孙子仲,平陈与宋。不我以归,忧心有忡。爰居爰处?爰丧其马?于以求之?于林之下。死生契阔,与子成说。执子之手,与子偕老。于嗟阔兮,不我活兮。于嗟洵兮,不我信兮。")
-		argBuf.WriteString("击鼓其镗,踊跃用兵。土国城漕,我独南行。从孙子仲,平陈与宋。不我以归,忧心有忡。爰居爰处?爰丧其马?于以求之?于林之下。死生契阔,与子成说。执子之手,与子偕老。于嗟阔兮,不我活兮。于嗟洵兮,不我信兮。")
-	}
-	rsp.Id = argBuf.String()
-	rsp.Name = argBuf.String()
-	return nil
-}
-
-func (u *UserProvider) GetUser(ctx context.Context, req []interface{}, rsp *User) error {
-	rsp.Id = req[0].(string)
-	rsp.Name = req[1].(string)
-	return nil
-}
-
-func (u *UserProvider) GetUser0(id string, k *User, name string) (User, error) {
-	return User{Id: id, Name: name}, nil
-}
-
-func (u *UserProvider) GetUser1() error {
-	return nil
-}
-
-func (u *UserProvider) GetUser2() error {
-	return perrors.New("error")
-}
-
-func (u *UserProvider) GetUser3(rsp *[]interface{}) error {
-	*rsp = append(*rsp, User{Id: "1", Name: "username"})
-	return nil
-}
-
-func (u *UserProvider) GetUser4(ctx context.Context, req []interface{}) ([]interface{}, error) {
-
-	return []interface{}{User{Id: req[0].([]interface{})[0].(string), Name: req[0].([]interface{})[1].(string)}}, nil
-}
-
-func (u *UserProvider) GetUser5(ctx context.Context, req []interface{}) (map[interface{}]interface{}, error) {
-	return map[interface{}]interface{}{"key": User{Id: req[0].(map[interface{}]interface{})["id"].(string), Name: req[0].(map[interface{}]interface{})["name"].(string)}}, nil
-}
-
-func (u *UserProvider) GetUser6(id int64) (*User, error) {
-	if id == 0 {
-		return nil, nil
-	}
-	return &User{Id: "1"}, nil
-}
-
-func (u *UserProvider) GetUserForAttachment(context context.Context, id int64) (*User, error) {
-	if id == 0 {
-		return nil, nil
-	}
-	var attachments = context.Value("attachment").(map[string]interface{})
-	Id := attachments["sim"].(string)
-	name := fmt.Sprintf("%+v", *(attachments["comp"].(*AttaTestObject)))
-	return &User{Id: Id, Name: name}, nil
-}
-
-func (u *UserProvider) Reference() string {
-	return "UserProvider"
-}
-
-func (u User) JavaClassName() string {
-	return "com.ikurento.user.User"
-}
-
-type AttaTestObject struct {
-	Ti   int64
-	Desc string
-}
-
-func (u *AttaTestObject) JavaClassName() string {
-	return "UserProvider"
-}
diff --git a/protocol/dubbo/codec.go b/protocol/dubbo/codec.go
deleted file mode 100644
index c33c92dfd924803b32a513d3767cbfaaa51f372c..0000000000000000000000000000000000000000
--- a/protocol/dubbo/codec.go
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dubbo
-
-import (
-	"bufio"
-	"bytes"
-	"fmt"
-	"time"
-)
-
-import (
-	"github.com/apache/dubbo-go/common"
-	perrors "github.com/pkg/errors"
-)
-
-import (
-	"github.com/apache/dubbo-go/protocol/dubbo/hessian2"
-)
-
-//SerialID serial ID
-type SerialID byte
-
-const (
-	// S_Dubbo dubbo serial id
-	S_Dubbo SerialID = 2
-)
-
-//CallType call type
-type CallType int32
-
-const (
-	// CT_UNKNOWN unknown call type
-	CT_UNKNOWN CallType = 0
-	// CT_OneWay call one way
-	CT_OneWay CallType = 1
-	// CT_TwoWay call in request/response
-	CT_TwoWay CallType = 2
-)
-
-////////////////////////////////////////////
-// dubbo package
-////////////////////////////////////////////
-
-// SequenceType sequence type
-type SequenceType int64
-
-// nolint
-type DubboPackage struct {
-	Header  hessian2.DubboHeader
-	Service hessian2.Service
-	Body    interface{}
-	Err     error
-}
-
-// String prints dubbo package detail include header、path、body etc.
-func (p DubboPackage) String() string {
-	return fmt.Sprintf("DubboPackage: Header-%v, Path-%v, Body-%v", p.Header, p.Service, p.Body)
-}
-
-// Marshal encode hessian package.
-func (p *DubboPackage) Marshal() (*bytes.Buffer, error) {
-	codec := hessian2.NewHessianCodec(nil)
-
-	pkg, err := codec.Write(p.Service, p.Header, p.Body)
-	if err != nil {
-		return nil, perrors.WithStack(err)
-	}
-
-	return bytes.NewBuffer(pkg), nil
-}
-
-// Unmarshal decodes hessian package.
-func (p *DubboPackage) Unmarshal(buf *bytes.Buffer, opts ...interface{}) error {
-	// fix issue https://github.com/apache/dubbo-go/issues/380
-	bufLen := buf.Len()
-	if bufLen < hessian2.HEADER_LENGTH {
-		return perrors.WithStack(hessian2.ErrHeaderNotEnough)
-	}
-
-	codec := hessian2.NewHessianCodec(bufio.NewReaderSize(buf, bufLen))
-
-	// read header
-	err := codec.ReadHeader(&p.Header)
-	if err != nil {
-		return perrors.WithStack(err)
-	}
-
-	if len(opts) != 0 { // for client
-		client, ok := opts[0].(*Client)
-		if !ok {
-			return perrors.Errorf("opts[0] is not of type *Client")
-		}
-
-		if p.Header.Type&hessian2.PackageRequest != 0x00 {
-			// size of this array must be '7'
-			// https://github.com/apache/dubbo-go-hessian2/blob/master/request.go#L272
-			p.Body = make([]interface{}, 7)
-		} else {
-			pendingRsp, ok := client.pendingResponses.Load(SequenceType(p.Header.ID))
-			if !ok {
-				return perrors.Errorf("client.GetPendingResponse(%v) = nil", p.Header.ID)
-			}
-			p.Body = &hessian2.DubboResponse{RspObj: pendingRsp.(*PendingResponse).response.reply}
-		}
-	}
-
-	// read body
-	err = codec.ReadBody(p.Body)
-	return perrors.WithStack(err)
-}
-
-////////////////////////////////////////////
-// PendingResponse
-////////////////////////////////////////////
-
-// PendingResponse is a pending response.
-type PendingResponse struct {
-	seq       uint64
-	err       error
-	start     time.Time
-	readStart time.Time
-	callback  common.AsyncCallback
-	response  *Response
-	done      chan struct{}
-}
-
-// NewPendingResponse create a PendingResponses.
-func NewPendingResponse() *PendingResponse {
-	return &PendingResponse{
-		start:    time.Now(),
-		response: &Response{},
-		done:     make(chan struct{}),
-	}
-}
-
-// GetCallResponse get AsyncCallbackResponse.
-func (r PendingResponse) GetCallResponse() common.CallbackResponse {
-	return AsyncCallbackResponse{
-		Cause:     r.err,
-		Start:     r.start,
-		ReadStart: r.readStart,
-		Reply:     r.response,
-	}
-}
diff --git a/protocol/dubbo/dubbo_codec.go b/protocol/dubbo/dubbo_codec.go
new file mode 100644
index 0000000000000000000000000000000000000000..5e859a7fa2254ba0e4806bc60c037c47777bc641
--- /dev/null
+++ b/protocol/dubbo/dubbo_codec.go
@@ -0,0 +1,290 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package dubbo
+
+import (
+	"bytes"
+	"strconv"
+	"time"
+)
+
+import (
+	hessian "github.com/apache/dubbo-go-hessian2"
+	perrors "github.com/pkg/errors"
+)
+
+import (
+	"github.com/apache/dubbo-go/common/constant"
+	"github.com/apache/dubbo-go/common/logger"
+	"github.com/apache/dubbo-go/protocol"
+	"github.com/apache/dubbo-go/protocol/dubbo/impl"
+	"github.com/apache/dubbo-go/protocol/invocation"
+	"github.com/apache/dubbo-go/remoting"
+)
+
+//SerialID serial ID
+type SerialID byte
+
+func init() {
+	codec := &DubboCodec{}
+	// this is for registry dubboCodec of dubbo protocol
+	remoting.RegistryCodec("dubbo", codec)
+}
+
+// DubboCodec. It is implements remoting.Codec
+type DubboCodec struct {
+}
+
+// encode request for transport
+func (c *DubboCodec) EncodeRequest(request *remoting.Request) (*bytes.Buffer, error) {
+	if request.Event {
+		return c.encodeHeartbeartReqeust(request)
+	}
+
+	invoc, ok := request.Data.(*protocol.Invocation)
+	if !ok {
+		err := perrors.Errorf("encode request failed for parameter type :%+v", request)
+		logger.Errorf(err.Error())
+		return nil, err
+	}
+	invocation := *invoc
+
+	svc := impl.Service{}
+	svc.Path = invocation.AttachmentsByKey(constant.PATH_KEY, "")
+	svc.Interface = invocation.AttachmentsByKey(constant.INTERFACE_KEY, "")
+	svc.Version = invocation.AttachmentsByKey(constant.VERSION_KEY, "")
+	svc.Group = invocation.AttachmentsByKey(constant.GROUP_KEY, "")
+	svc.Method = invocation.MethodName()
+	timeout, err := strconv.Atoi(invocation.AttachmentsByKey(constant.TIMEOUT_KEY, strconv.Itoa(constant.DEFAULT_REMOTING_TIMEOUT)))
+	if err != nil {
+		// it will be wrapped in readwrite.Write .
+		return nil, perrors.WithStack(err)
+	}
+	svc.Timeout = time.Duration(timeout)
+
+	header := impl.DubboHeader{}
+	serialization := invocation.AttachmentsByKey(constant.SERIALIZATION_KEY, constant.HESSIAN2_SERIALIZATION)
+	if serialization == constant.PROTOBUF_SERIALIZATION {
+		header.SerialID = constant.S_Proto
+	} else {
+		header.SerialID = constant.S_Hessian2
+	}
+	header.ID = request.ID
+	if request.TwoWay {
+		header.Type = impl.PackageRequest_TwoWay
+	} else {
+		header.Type = impl.PackageRequest
+	}
+
+	pkg := &impl.DubboPackage{
+		Header:  header,
+		Service: svc,
+		Body:    impl.NewRequestPayload(invocation.Arguments(), invocation.Attachments()),
+		Err:     nil,
+		Codec:   impl.NewDubboCodec(nil),
+	}
+
+	if err := impl.LoadSerializer(pkg); err != nil {
+		return nil, perrors.WithStack(err)
+	}
+
+	return pkg.Marshal()
+}
+
+// encode heartbeart request
+func (c *DubboCodec) encodeHeartbeartReqeust(request *remoting.Request) (*bytes.Buffer, error) {
+	header := impl.DubboHeader{
+		Type:     impl.PackageHeartbeat,
+		SerialID: constant.S_Hessian2,
+		ID:       request.ID,
+	}
+
+	pkg := &impl.DubboPackage{
+		Header:  header,
+		Service: impl.Service{},
+		Body:    impl.NewRequestPayload([]interface{}{}, nil),
+		Err:     nil,
+		Codec:   impl.NewDubboCodec(nil),
+	}
+
+	if err := impl.LoadSerializer(pkg); err != nil {
+		return nil, err
+	}
+	return pkg.Marshal()
+}
+
+// encode response
+func (c *DubboCodec) EncodeResponse(response *remoting.Response) (*bytes.Buffer, error) {
+	var ptype = impl.PackageResponse
+	if response.IsHeartbeat() {
+		ptype = impl.PackageHeartbeat
+	}
+	resp := &impl.DubboPackage{
+		Header: impl.DubboHeader{
+			SerialID:       response.SerialID,
+			Type:           ptype,
+			ID:             response.ID,
+			ResponseStatus: response.Status,
+		},
+	}
+	if !response.IsHeartbeat() {
+		resp.Body = &impl.ResponsePayload{
+			RspObj:      response.Result.(protocol.RPCResult).Rest,
+			Exception:   response.Result.(protocol.RPCResult).Err,
+			Attachments: response.Result.(protocol.RPCResult).Attrs,
+		}
+	}
+
+	codec := impl.NewDubboCodec(nil)
+
+	pkg, err := codec.Encode(*resp)
+	if err != nil {
+		return nil, perrors.WithStack(err)
+	}
+
+	return bytes.NewBuffer(pkg), nil
+}
+
+// Decode data, including request and response.
+func (c *DubboCodec) Decode(data []byte) (remoting.DecodeResult, int, error) {
+	if c.isRequest(data) {
+		req, len, err := c.decodeRequest(data)
+		if err != nil {
+			return remoting.DecodeResult{}, len, perrors.WithStack(err)
+		}
+		return remoting.DecodeResult{IsRequest: true, Result: req}, len, perrors.WithStack(err)
+	}
+
+	resp, len, err := c.decodeResponse(data)
+	if err != nil {
+		return remoting.DecodeResult{}, len, perrors.WithStack(err)
+	}
+	return remoting.DecodeResult{IsRequest: false, Result: resp}, len, perrors.WithStack(err)
+}
+
+func (c *DubboCodec) isRequest(data []byte) bool {
+	if data[2]&byte(0x80) == 0x00 {
+		return false
+	}
+	return true
+}
+
+// decode request
+func (c *DubboCodec) decodeRequest(data []byte) (*remoting.Request, int, error) {
+	var request *remoting.Request = nil
+	buf := bytes.NewBuffer(data)
+	pkg := impl.NewDubboPackage(buf)
+	pkg.SetBody(make([]interface{}, 7))
+	err := pkg.Unmarshal()
+	if err != nil {
+		originErr := perrors.Cause(err)
+		if originErr == hessian.ErrHeaderNotEnough || originErr == hessian.ErrBodyNotEnough {
+			//FIXME
+			return nil, 0, originErr
+		}
+		logger.Errorf("pkg.Unmarshal(len(@data):%d) = error:%+v", buf.Len(), err)
+
+		return request, 0, perrors.WithStack(err)
+	}
+	request = &remoting.Request{
+		ID:       pkg.Header.ID,
+		SerialID: pkg.Header.SerialID,
+		TwoWay:   pkg.Header.Type&impl.PackageRequest_TwoWay != 0x00,
+		Event:    pkg.Header.Type&impl.PackageHeartbeat != 0x00,
+	}
+	if (pkg.Header.Type & impl.PackageHeartbeat) == 0x00 {
+		// convert params of request
+		req := pkg.Body.(map[string]interface{})
+
+		//invocation := request.Data.(*invocation.RPCInvocation)
+		var methodName string
+		var args []interface{}
+		attachments := make(map[string]interface{})
+		if req[impl.DubboVersionKey] != nil {
+			//dubbo version
+			request.Version = req[impl.DubboVersionKey].(string)
+		}
+		//path
+		attachments[constant.PATH_KEY] = pkg.Service.Path
+		//version
+		attachments[constant.VERSION_KEY] = pkg.Service.Version
+		//method
+		methodName = pkg.Service.Method
+		args = req[impl.ArgsKey].([]interface{})
+		attachments = req[impl.AttachmentsKey].(map[string]interface{})
+		invoc := invocation.NewRPCInvocationWithOptions(invocation.WithAttachments(attachments),
+			invocation.WithArguments(args), invocation.WithMethodName(methodName))
+		request.Data = invoc
+
+	}
+	return request, hessian.HEADER_LENGTH + pkg.Header.BodyLen, nil
+}
+
+// decode response
+func (c *DubboCodec) decodeResponse(data []byte) (*remoting.Response, int, error) {
+	buf := bytes.NewBuffer(data)
+	pkg := impl.NewDubboPackage(buf)
+	response := &remoting.Response{}
+	err := pkg.Unmarshal()
+	if err != nil {
+		originErr := perrors.Cause(err)
+		// if the data is very big, so the receive need much times.
+		if originErr == hessian.ErrHeaderNotEnough || originErr == hessian.ErrBodyNotEnough {
+			return nil, 0, originErr
+		}
+		logger.Errorf("pkg.Unmarshal(len(@data):%d) = error:%+v", buf.Len(), err)
+
+		return nil, 0, perrors.WithStack(err)
+	}
+	response = &remoting.Response{
+		ID: pkg.Header.ID,
+		//Version:  pkg.Header.,
+		SerialID: pkg.Header.SerialID,
+		Status:   pkg.Header.ResponseStatus,
+		Event:    (pkg.Header.Type & impl.PackageHeartbeat) != 0,
+	}
+	var error error
+	if pkg.Header.Type&impl.PackageHeartbeat != 0x00 {
+		if pkg.Header.Type&impl.PackageResponse != 0x00 {
+			logger.Debugf("get rpc heartbeat response{header: %#v, body: %#v}", pkg.Header, pkg.Body)
+			if pkg.Err != nil {
+				logger.Errorf("rpc heartbeat response{error: %#v}", pkg.Err)
+				error = pkg.Err
+			}
+		} else {
+			logger.Debugf("get rpc heartbeat request{header: %#v, service: %#v, body: %#v}", pkg.Header, pkg.Service, pkg.Body)
+			response.Status = hessian.Response_OK
+			//reply(session, p, hessian.PackageHeartbeat)
+		}
+		return response, hessian.HEADER_LENGTH + pkg.Header.BodyLen, error
+	}
+	logger.Debugf("get rpc response{header: %#v, body: %#v}", pkg.Header, pkg.Body)
+	rpcResult := &protocol.RPCResult{}
+	response.Result = rpcResult
+	if pkg.Header.Type&impl.PackageRequest == 0x00 {
+		if pkg.Err != nil {
+			rpcResult.Err = pkg.Err
+		} else if pkg.Body.(*impl.ResponsePayload).Exception != nil {
+			rpcResult.Err = pkg.Body.(*impl.ResponsePayload).Exception
+			response.Error = rpcResult.Err
+		}
+		rpcResult.Attrs = pkg.Body.(*impl.ResponsePayload).Attachments
+		rpcResult.Rest = pkg.Body.(*impl.ResponsePayload).RspObj
+	}
+
+	return response, hessian.HEADER_LENGTH + pkg.Header.BodyLen, nil
+}
diff --git a/protocol/dubbo/dubbo_invoker.go b/protocol/dubbo/dubbo_invoker.go
index 983a05dcec1ff444e6637c5094d691c266f6c855..bce33508bec92b706a1722c3bbc0ed0607e66643 100644
--- a/protocol/dubbo/dubbo_invoker.go
+++ b/protocol/dubbo/dubbo_invoker.go
@@ -20,6 +20,7 @@ package dubbo
 import (
 	"context"
 	"strconv"
+	"strings"
 	"sync"
 	"sync/atomic"
 	"time"
@@ -34,8 +35,10 @@ import (
 	"github.com/apache/dubbo-go/common"
 	"github.com/apache/dubbo-go/common/constant"
 	"github.com/apache/dubbo-go/common/logger"
+	"github.com/apache/dubbo-go/config"
 	"github.com/apache/dubbo-go/protocol"
 	invocation_impl "github.com/apache/dubbo-go/protocol/invocation"
+	"github.com/apache/dubbo-go/remoting"
 )
 
 var (
@@ -46,24 +49,35 @@ var (
 )
 
 var (
-	attachmentKey = []string{constant.INTERFACE_KEY, constant.GROUP_KEY, constant.TOKEN_KEY, constant.TIMEOUT_KEY}
+	attachmentKey = []string{constant.INTERFACE_KEY, constant.GROUP_KEY, constant.TOKEN_KEY, constant.TIMEOUT_KEY,
+		constant.VERSION_KEY}
 )
 
-// DubboInvoker is dubbo client invoker.
+// DubboInvoker is implement of protocol.Invoker. A dubboInvoker refer to one service and ip.
 type DubboInvoker struct {
 	protocol.BaseInvoker
-	client   *Client
+	// the exchange layer, it is focus on network communication.
+	client   *remoting.ExchangeClient
 	quitOnce sync.Once
+	// timeout for service(interface) level.
+	timeout time.Duration
 	// Used to record the number of requests. -1 represent this DubboInvoker is destroyed
 	reqNum int64
 }
 
-// NewDubboInvoker create dubbo client invoker.
-func NewDubboInvoker(url common.URL, client *Client) *DubboInvoker {
+// NewDubboInvoker constructor
+func NewDubboInvoker(url common.URL, client *remoting.ExchangeClient) *DubboInvoker {
+	requestTimeout := config.GetConsumerConfig().RequestTimeout
+
+	requestTimeoutStr := url.GetParam(constant.TIMEOUT_KEY, config.GetConsumerConfig().Request_Timeout)
+	if t, err := time.ParseDuration(requestTimeoutStr); err == nil {
+		requestTimeout = t
+	}
 	return &DubboInvoker{
 		BaseInvoker: *protocol.NewBaseInvoker(url),
 		client:      client,
 		reqNum:      0,
+		timeout:     requestTimeout,
 	}
 }
 
@@ -84,6 +98,8 @@ func (di *DubboInvoker) Invoke(ctx context.Context, invocation protocol.Invocati
 	defer atomic.AddInt64(&(di.reqNum), -1)
 
 	inv := invocation.(*invocation_impl.RPCInvocation)
+	// init param
+	inv.SetAttachments(constant.PATH_KEY, di.GetUrl().GetParam(constant.INTERFACE_KEY, ""))
 	for _, k := range attachmentKey {
 		if v := di.GetUrl().GetParam(k, ""); len(v) > 0 {
 			inv.SetAttachments(k, v)
@@ -94,35 +110,57 @@ func (di *DubboInvoker) Invoke(ctx context.Context, invocation protocol.Invocati
 	di.appendCtx(ctx, inv)
 
 	url := di.GetUrl()
+	// default hessian2 serialization, compatible
+	if url.GetParam(constant.SERIALIZATION_KEY, "") == "" {
+		url.SetParam(constant.SERIALIZATION_KEY, constant.HESSIAN2_SERIALIZATION)
+	}
 	// async
 	async, err := strconv.ParseBool(inv.AttachmentsByKey(constant.ASYNC_KEY, "false"))
 	if err != nil {
 		logger.Errorf("ParseBool - error: %v", err)
 		async = false
 	}
-	response := NewResponse(inv.Reply(), nil)
+	//response := NewResponse(inv.Reply(), nil)
+	rest := &protocol.RPCResult{}
+	timeout := di.getTimeout(inv)
 	if async {
 		if callBack, ok := inv.CallBack().(func(response common.CallbackResponse)); ok {
-			result.Err = di.client.AsyncCall(NewRequest(url.Location, url, inv.MethodName(), inv.Arguments(), inv.Attachments()), callBack, response)
+			//result.Err = di.client.AsyncCall(NewRequest(url.Location, url, inv.MethodName(), inv.Arguments(), inv.Attachments()), callBack, response)
+			result.Err = di.client.AsyncRequest(&invocation, url, timeout, callBack, rest)
 		} else {
-			result.Err = di.client.CallOneway(NewRequest(url.Location, url, inv.MethodName(), inv.Arguments(), inv.Attachments()))
+			result.Err = di.client.Send(&invocation, url, timeout)
 		}
 	} else {
 		if inv.Reply() == nil {
 			result.Err = ErrNoReply
 		} else {
-			result.Err = di.client.Call(NewRequest(url.Location, url, inv.MethodName(), inv.Arguments(), inv.Attachments()), response)
+			result.Err = di.client.Request(&invocation, url, timeout, rest)
 		}
 	}
 	if result.Err == nil {
 		result.Rest = inv.Reply()
-		result.Attrs = response.atta
+		result.Attrs = rest.Attrs
 	}
 	logger.Debugf("result.Err: %v, result.Rest: %v", result.Err, result.Rest)
 
 	return &result
 }
 
+// get timeout including methodConfig
+func (di *DubboInvoker) getTimeout(invocation *invocation_impl.RPCInvocation) time.Duration {
+	var timeout = di.GetUrl().GetParam(strings.Join([]string{constant.METHOD_KEYS, invocation.MethodName(), constant.TIMEOUT_KEY}, "."), "")
+	if len(timeout) != 0 {
+		if t, err := time.ParseDuration(timeout); err == nil {
+			// config timeout into attachment
+			invocation.SetAttachments(constant.TIMEOUT_KEY, strconv.Itoa(int(t.Milliseconds())))
+			return t
+		}
+	}
+	// set timeout into invocation at method level
+	invocation.SetAttachments(constant.TIMEOUT_KEY, strconv.Itoa(int(di.timeout.Milliseconds())))
+	return di.timeout
+}
+
 // Destroy destroy dubbo client invoker.
 func (di *DubboInvoker) Destroy() {
 	di.quitOnce.Do(func() {
diff --git a/protocol/dubbo/dubbo_invoker_test.go b/protocol/dubbo/dubbo_invoker_test.go
index bf352c082c47d86e6382135bb036be6709ed804d..4d32c29a222e8bb73486d664b2ed2e0038a4b3f5 100644
--- a/protocol/dubbo/dubbo_invoker_test.go
+++ b/protocol/dubbo/dubbo_invoker_test.go
@@ -18,6 +18,7 @@
 package dubbo
 
 import (
+	"bytes"
 	"context"
 	"sync"
 	"testing"
@@ -25,40 +26,37 @@ import (
 )
 
 import (
+	hessian "github.com/apache/dubbo-go-hessian2"
 	"github.com/opentracing/opentracing-go"
+	perrors "github.com/pkg/errors"
 	"github.com/stretchr/testify/assert"
 )
 
 import (
 	"github.com/apache/dubbo-go/common"
 	"github.com/apache/dubbo-go/common/constant"
+	"github.com/apache/dubbo-go/common/proxy/proxy_factory"
+	"github.com/apache/dubbo-go/protocol"
 	"github.com/apache/dubbo-go/protocol/invocation"
+	"github.com/apache/dubbo-go/remoting"
+	"github.com/apache/dubbo-go/remoting/getty"
 )
 
 func TestDubboInvokerInvoke(t *testing.T) {
 	proto, url := InitTest(t)
 
-	c := &Client{
-		pendingResponses: new(sync.Map),
-		conf:             *clientConf,
-		opts: Options{
-			ConnectTimeout: 3 * time.Second,
-			RequestTimeout: 6 * time.Second,
-		},
-	}
-	c.pool = newGettyRPCClientConnPool(c, clientConf.PoolSize, time.Duration(int(time.Second)*clientConf.PoolTTL))
+	c := getExchangeClient(url)
 
 	invoker := NewDubboInvoker(url, c)
 	user := &User{}
 
-	inv := invocation.NewRPCInvocationWithOptions(invocation.WithMethodName(mockMethodNameGetUser), invocation.WithArguments([]interface{}{"1", "username"}),
+	inv := invocation.NewRPCInvocationWithOptions(invocation.WithMethodName("GetUser"), invocation.WithArguments([]interface{}{"1", "username"}),
 		invocation.WithReply(user), invocation.WithAttachments(map[string]interface{}{"test_key": "test_value"}))
 
 	// Call
 	res := invoker.Invoke(context.Background(), inv)
 	assert.NoError(t, res.Error())
 	assert.Equal(t, User{Id: "1", Name: "username"}, *res.Result().(*User))
-	assert.Equal(t, "test_value", res.Attachments()["test_key"]) // test attachments for request/response
 
 	// CallOneway
 	inv.SetAttachments(constant.ASYNC_KEY, "true")
@@ -69,8 +67,10 @@ func TestDubboInvokerInvoke(t *testing.T) {
 	lock := sync.Mutex{}
 	lock.Lock()
 	inv.SetCallBack(func(response common.CallbackResponse) {
-		r := response.(AsyncCallbackResponse)
-		assert.Equal(t, User{Id: "1", Name: "username"}, *r.Reply.(*Response).reply.(*User))
+		r := response.(remoting.AsyncCallbackResponse)
+		rst := *r.Reply.(*remoting.Response).Result.(*protocol.RPCResult)
+		assert.Equal(t, User{Id: "1", Name: "username"}, *(rst.Rest.(*User)))
+		//assert.Equal(t, User{ID: "1", Name: "username"}, *r.Reply.(*Response).reply.(*User))
 		lock.Unlock()
 	})
 	res = invoker.Invoke(context.Background(), inv)
@@ -92,3 +92,143 @@ func TestDubboInvokerInvoke(t *testing.T) {
 	proto.Destroy()
 	lock.Unlock()
 }
+
+func InitTest(t *testing.T) (protocol.Protocol, common.URL) {
+
+	hessian.RegisterPOJO(&User{})
+
+	methods, err := common.ServiceMap.Register("", "dubbo", &UserProvider{})
+	assert.NoError(t, err)
+	assert.Equal(t, "GetBigPkg,GetUser,GetUser0,GetUser1,GetUser2,GetUser3,GetUser4,GetUser5,GetUser6", methods)
+
+	// config
+	getty.SetClientConf(getty.ClientConfig{
+		ConnectionNum:   2,
+		HeartbeatPeriod: "5s",
+		SessionTimeout:  "20s",
+		PoolTTL:         600,
+		PoolSize:        64,
+		GettySessionParam: getty.GettySessionParam{
+			CompressEncoding: false,
+			TcpNoDelay:       true,
+			TcpKeepAlive:     true,
+			KeepAlivePeriod:  "120s",
+			TcpRBufSize:      262144,
+			TcpWBufSize:      65536,
+			PkgWQSize:        512,
+			TcpReadTimeout:   "4s",
+			TcpWriteTimeout:  "5s",
+			WaitTimeout:      "1s",
+			MaxMsgLen:        10240000000,
+			SessionName:      "client",
+		},
+	})
+	getty.SetServerConfig(getty.ServerConfig{
+		SessionNumber:  700,
+		SessionTimeout: "20s",
+		GettySessionParam: getty.GettySessionParam{
+			CompressEncoding: false,
+			TcpNoDelay:       true,
+			TcpKeepAlive:     true,
+			KeepAlivePeriod:  "120s",
+			TcpRBufSize:      262144,
+			TcpWBufSize:      65536,
+			PkgWQSize:        512,
+			TcpReadTimeout:   "1s",
+			TcpWriteTimeout:  "5s",
+			WaitTimeout:      "1s",
+			MaxMsgLen:        10240000000,
+			SessionName:      "server",
+		}})
+
+	// Export
+	proto := GetProtocol()
+	url, err := common.NewURL("dubbo://127.0.0.1:20702/UserProvider?anyhost=true&" +
+		"application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&" +
+		"environment=dev&interface=com.ikurento.user.UserProvider&ip=192.168.56.1&methods=GetUser%2C&" +
+		"module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&" +
+		"side=provider&timeout=3000&timestamp=1556509797245&bean.name=UserProvider")
+	assert.NoError(t, err)
+	proto.Export(&proxy_factory.ProxyInvoker{
+		BaseInvoker: *protocol.NewBaseInvoker(url),
+	})
+
+	time.Sleep(time.Second * 2)
+
+	return proto, url
+}
+
+//////////////////////////////////
+// provider
+//////////////////////////////////
+
+type (
+	User struct {
+		Id   string `json:"id"`
+		Name string `json:"name"`
+	}
+
+	UserProvider struct {
+		user map[string]User
+	}
+)
+
+// size:4801228
+func (u *UserProvider) GetBigPkg(ctx context.Context, req []interface{}, rsp *User) error {
+	argBuf := new(bytes.Buffer)
+	for i := 0; i < 400; i++ {
+		// use chinese for test
+		argBuf.WriteString("击鼓其镗,踊跃用兵。土国城漕,我独南行。从孙子仲,平陈与宋。不我以归,忧心有忡。爰居爰处?爰丧其马?于以求之?于林之下。死生契阔,与子成说。执子之手,与子偕老。于嗟阔兮,不我活兮。于嗟洵兮,不我信兮。")
+		argBuf.WriteString("击鼓其镗,踊跃用兵。土国城漕,我独南行。从孙子仲,平陈与宋。不我以归,忧心有忡。爰居爰处?爰丧其马?于以求之?于林之下。死生契阔,与子成说。执子之手,与子偕老。于嗟阔兮,不我活兮。于嗟洵兮,不我信兮。")
+	}
+	rsp.Id = argBuf.String()
+	rsp.Name = argBuf.String()
+	return nil
+}
+
+func (u *UserProvider) GetUser(ctx context.Context, req []interface{}, rsp *User) error {
+	rsp.Id = req[0].(string)
+	rsp.Name = req[1].(string)
+	return nil
+}
+
+func (u *UserProvider) GetUser0(id string, k *User, name string) (User, error) {
+	return User{Id: id, Name: name}, nil
+}
+
+func (u *UserProvider) GetUser1() error {
+	return nil
+}
+
+func (u *UserProvider) GetUser2() error {
+	return perrors.New("error")
+}
+
+func (u *UserProvider) GetUser3(rsp *[]interface{}) error {
+	*rsp = append(*rsp, User{Id: "1", Name: "username"})
+	return nil
+}
+
+func (u *UserProvider) GetUser4(ctx context.Context, req []interface{}) ([]interface{}, error) {
+
+	return []interface{}{User{Id: req[0].([]interface{})[0].(string), Name: req[0].([]interface{})[1].(string)}}, nil
+}
+
+func (u *UserProvider) GetUser5(ctx context.Context, req []interface{}) (map[interface{}]interface{}, error) {
+	return map[interface{}]interface{}{"key": User{Id: req[0].(map[interface{}]interface{})["id"].(string), Name: req[0].(map[interface{}]interface{})["name"].(string)}}, nil
+}
+
+func (u *UserProvider) GetUser6(id int64) (*User, error) {
+	if id == 0 {
+		return nil, nil
+	}
+	return &User{Id: "1"}, nil
+}
+
+func (u *UserProvider) Reference() string {
+	return "UserProvider"
+}
+
+func (u User) JavaClassName() string {
+	return "com.ikurento.user.User"
+}
diff --git a/protocol/dubbo/dubbo_protocol.go b/protocol/dubbo/dubbo_protocol.go
index 9eeefd079279d82241da8e21df5edfe77b8003e0..8dda52b6b9b79e5d20a730db52f9a376422ccd63 100644
--- a/protocol/dubbo/dubbo_protocol.go
+++ b/protocol/dubbo/dubbo_protocol.go
@@ -18,10 +18,16 @@
 package dubbo
 
 import (
+	"context"
+	"fmt"
 	"sync"
 	"time"
 )
 
+import (
+	"github.com/opentracing/opentracing-go"
+)
+
 import (
 	"github.com/apache/dubbo-go/common"
 	"github.com/apache/dubbo-go/common/constant"
@@ -29,14 +35,23 @@ import (
 	"github.com/apache/dubbo-go/common/logger"
 	"github.com/apache/dubbo-go/config"
 	"github.com/apache/dubbo-go/protocol"
+	"github.com/apache/dubbo-go/protocol/invocation"
+	"github.com/apache/dubbo-go/remoting"
+	"github.com/apache/dubbo-go/remoting/getty"
 )
 
-// dubbo protocol constant
 const (
 	// DUBBO is dubbo protocol name
 	DUBBO = "dubbo"
 )
 
+var (
+	// Make the connection can be shared.
+	// It will create one connection for one address (ip+port)
+	exchangeClientMap = new(sync.Map)
+	exchangeLock      = new(sync.Map)
+)
+
 func init() {
 	extension.SetProtocol(DUBBO, GetProtocol)
 }
@@ -45,10 +60,12 @@ var (
 	dubboProtocol *DubboProtocol
 )
 
-// DubboProtocol is a dubbo protocol implement.
+// It support dubbo protocol. It implements Protocol interface for dubbo protocol.
 type DubboProtocol struct {
 	protocol.BaseProtocol
-	serverMap  map[string]*Server
+	// It is store relationship about serviceKey(group/interface:version) and ExchangeServer
+	// The ExchangeServer is introduced to replace of Server. Because Server is depend on getty directly.
+	serverMap  map[string]*remoting.ExchangeServer
 	serverLock sync.Mutex
 }
 
@@ -56,7 +73,7 @@ type DubboProtocol struct {
 func NewDubboProtocol() *DubboProtocol {
 	return &DubboProtocol{
 		BaseProtocol: protocol.NewBaseProtocol(),
-		serverMap:    make(map[string]*Server),
+		serverMap:    make(map[string]*remoting.ExchangeServer),
 	}
 }
 
@@ -67,7 +84,6 @@ func (dp *DubboProtocol) Export(invoker protocol.Invoker) protocol.Exporter {
 	exporter := NewDubboExporter(serviceKey, invoker, dp.ExporterMap())
 	dp.SetExporterMap(serviceKey, exporter)
 	logger.Infof("Export service: %s", url.String())
-
 	// start server
 	dp.openServer(url)
 	return exporter
@@ -75,18 +91,12 @@ func (dp *DubboProtocol) Export(invoker protocol.Invoker) protocol.Exporter {
 
 // Refer create dubbo service reference.
 func (dp *DubboProtocol) Refer(url common.URL) protocol.Invoker {
-	//default requestTimeout
-	var requestTimeout = config.GetConsumerConfig().RequestTimeout
-
-	requestTimeoutStr := url.GetParam(constant.TIMEOUT_KEY, config.GetConsumerConfig().Request_Timeout)
-	if t, err := time.ParseDuration(requestTimeoutStr); err == nil {
-		requestTimeout = t
+	exchangeClient := getExchangeClient(url)
+	if exchangeClient == nil {
+		logger.Warnf("can't dial the server: %+v", url.Location)
+		return nil
 	}
-
-	invoker := NewDubboInvoker(url, NewClient(Options{
-		ConnectTimeout: config.GetConsumerConfig().ConnectTimeout,
-		RequestTimeout: requestTimeout,
-	}))
+	invoker := NewDubboInvoker(url, exchangeClient)
 	dp.SetInvokers(invoker)
 	logger.Infof("Refer service: %s", url.String())
 	return invoker
@@ -116,9 +126,12 @@ func (dp *DubboProtocol) openServer(url common.URL) {
 		dp.serverLock.Lock()
 		_, ok = dp.serverMap[url.Location]
 		if !ok {
-			srv := NewServer()
+			handler := func(invocation *invocation.RPCInvocation) protocol.RPCResult {
+				return doHandleRequest(invocation)
+			}
+			srv := remoting.NewExchangeServer(url, getty.NewServer(url, handler))
 			dp.serverMap[url.Location] = srv
-			srv.Start(url)
+			srv.Start()
 		}
 		dp.serverLock.Unlock()
 	}
@@ -131,3 +144,91 @@ func GetProtocol() protocol.Protocol {
 	}
 	return dubboProtocol
 }
+
+func doHandleRequest(rpcInvocation *invocation.RPCInvocation) protocol.RPCResult {
+	exporter, _ := dubboProtocol.ExporterMap().Load(rpcInvocation.ServiceKey())
+	result := protocol.RPCResult{}
+	if exporter == nil {
+		err := fmt.Errorf("don't have this exporter, key: %s", rpcInvocation.ServiceKey())
+		logger.Errorf(err.Error())
+		result.Err = err
+		//reply(session, p, hessian.PackageResponse)
+		return result
+	}
+	invoker := exporter.(protocol.Exporter).GetInvoker()
+	if invoker != nil {
+		// FIXME
+		ctx := rebuildCtx(rpcInvocation)
+
+		invokeResult := invoker.Invoke(ctx, rpcInvocation)
+		if err := invokeResult.Error(); err != nil {
+			result.Err = invokeResult.Error()
+			//p.Header.ResponseStatus = hessian.Response_OK
+			//p.Body = hessian.NewResponse(nil, err, result.Attachments())
+		} else {
+			result.Rest = invokeResult.Result()
+			//p.Header.ResponseStatus = hessian.Response_OK
+			//p.Body = hessian.NewResponse(res, nil, result.Attachments())
+		}
+	} else {
+		result.Err = fmt.Errorf("don't have the invoker, key: %s", rpcInvocation.ServiceKey())
+	}
+	return result
+}
+
+func getExchangeClient(url common.URL) *remoting.ExchangeClient {
+	clientTmp, ok := exchangeClientMap.Load(url.Location)
+	if !ok {
+		var exchangeClientTmp *remoting.ExchangeClient
+		func() {
+			// lock for NewExchangeClient and store into map.
+			_, loaded := exchangeLock.LoadOrStore(url.Location, 0x00)
+			// unlock
+			defer exchangeLock.Delete(url.Location)
+			if loaded {
+				// retry for 5 times.
+				for i := 0; i < 5; i++ {
+					if clientTmp, ok = exchangeClientMap.Load(url.Location); ok {
+						break
+					} else {
+						// if cannot get, sleep a while.
+						time.Sleep(time.Duration(i*100) * time.Millisecond)
+					}
+				}
+				return
+			}
+			// new ExchangeClient
+			exchangeClientTmp = remoting.NewExchangeClient(url, getty.NewClient(getty.Options{
+				ConnectTimeout: config.GetConsumerConfig().ConnectTimeout,
+				RequestTimeout: config.GetConsumerConfig().RequestTimeout,
+			}), config.GetConsumerConfig().ConnectTimeout, false)
+			// input store
+			if exchangeClientTmp != nil {
+				exchangeClientMap.Store(url.Location, exchangeClientTmp)
+			}
+		}()
+		if exchangeClientTmp != nil {
+			return exchangeClientTmp
+		}
+	}
+	// cannot dial the server
+	if clientTmp == nil {
+		return nil
+	}
+	return clientTmp.(*remoting.ExchangeClient)
+}
+
+// rebuildCtx rebuild the context by attachment.
+// Once we decided to transfer more context's key-value, we should change this.
+// now we only support rebuild the tracing context
+func rebuildCtx(inv *invocation.RPCInvocation) context.Context {
+	ctx := context.WithValue(context.Background(), "attachment", inv.Attachments())
+
+	// actually, if user do not use any opentracing framework, the err will not be nil.
+	spanCtx, err := opentracing.GlobalTracer().Extract(opentracing.TextMap,
+		opentracing.TextMapCarrier(filterContext(inv.Attachments())))
+	if err == nil {
+		ctx = context.WithValue(ctx, constant.TRACING_REMOTE_SPAN_CTX, spanCtx)
+	}
+	return ctx
+}
diff --git a/protocol/dubbo/dubbo_protocol_test.go b/protocol/dubbo/dubbo_protocol_test.go
index 6f3892be67be533dea09dc7bd54de56844dbc79c..9eba90e9da564453649b378f061bc0179ffedc5e 100644
--- a/protocol/dubbo/dubbo_protocol_test.go
+++ b/protocol/dubbo/dubbo_protocol_test.go
@@ -28,7 +28,9 @@ import (
 import (
 	"github.com/apache/dubbo-go/common"
 	"github.com/apache/dubbo-go/common/constant"
+	"github.com/apache/dubbo-go/common/proxy/proxy_factory"
 	"github.com/apache/dubbo-go/protocol"
+	"github.com/apache/dubbo-go/remoting/getty"
 )
 
 const (
@@ -39,14 +41,56 @@ const (
 		"side=provider&timeout=3000&timestamp=1556509797245"
 )
 
-func TestDubboProtocolExport(t *testing.T) {
+func initDubboInvokerTest() {
+	getty.SetServerConfig(getty.ServerConfig{
+		SessionNumber:  700,
+		SessionTimeout: "20s",
+		GettySessionParam: getty.GettySessionParam{
+			CompressEncoding: false,
+			TcpNoDelay:       true,
+			TcpKeepAlive:     true,
+			KeepAlivePeriod:  "120s",
+			TcpRBufSize:      262144,
+			TcpWBufSize:      65536,
+			PkgWQSize:        512,
+			TcpReadTimeout:   "1s",
+			TcpWriteTimeout:  "5s",
+			WaitTimeout:      "1s",
+			MaxMsgLen:        10240000000,
+			SessionName:      "server",
+		}})
+	getty.SetClientConf(getty.ClientConfig{
+		ConnectionNum:   1,
+		HeartbeatPeriod: "3s",
+		SessionTimeout:  "20s",
+		PoolTTL:         600,
+		PoolSize:        64,
+		GettySessionParam: getty.GettySessionParam{
+			CompressEncoding: false,
+			TcpNoDelay:       true,
+			TcpKeepAlive:     true,
+			KeepAlivePeriod:  "120s",
+			TcpRBufSize:      262144,
+			TcpWBufSize:      65536,
+			PkgWQSize:        512,
+			TcpReadTimeout:   "4s",
+			TcpWriteTimeout:  "5s",
+			WaitTimeout:      "1s",
+			MaxMsgLen:        10240000000,
+			SessionName:      "client",
+		},
+	})
+}
+
+func TestDubboProtocol_Export(t *testing.T) {
+	initDubboInvokerTest()
+	srvCfg := getty.GetDefaultServerConfig()
+	getty.SetServerConfig(srvCfg)
 	// Export
 	proto := GetProtocol()
-	srvConf = &ServerConfig{}
 	url, err := common.NewURL(mockCommonUrl)
 	assert.NoError(t, err)
 	exporter := proto.Export(protocol.NewBaseInvoker(url))
-
 	// make sure url
 	eq := exporter.GetInvoker().GetUrl().URLEqual(url)
 	assert.True(t, eq)
@@ -60,10 +104,10 @@ func TestDubboProtocolExport(t *testing.T) {
 	assert.True(t, eq2)
 
 	// make sure exporterMap after 'Unexport'
-	_, ok := proto.(*DubboProtocol).ExporterMap().Load(url.ServiceKey())
+	_, ok := proto.(*DubboProtocol).ExporterMap().Load(url2.ServiceKey())
 	assert.True(t, ok)
-	exporter.Unexport()
-	_, ok = proto.(*DubboProtocol).ExporterMap().Load(url.ServiceKey())
+	exporter2.Unexport()
+	_, ok = proto.(*DubboProtocol).ExporterMap().Load(url2.ServiceKey())
 	assert.False(t, ok)
 
 	// make sure serverMap after 'Destroy'
@@ -74,14 +118,29 @@ func TestDubboProtocolExport(t *testing.T) {
 	assert.False(t, ok)
 }
 
-func TestDubboProtocolRefer(t *testing.T) {
+func TestDubboProtocolReferNoConnect(t *testing.T) {
 	// Refer
+	initDubboInvokerTest()
 	proto := GetProtocol()
 	url, err := common.NewURL(mockCommonUrl)
 	assert.NoError(t, err)
-	clientConf = &ClientConfig{}
 	invoker := proto.Refer(url)
+	assert.Nil(t, invoker)
+}
+
+func TestDubboProtocol_Refer(t *testing.T) {
+	initDubboInvokerTest()
+	cliCfg := getty.GetDefaultClientConfig()
+	getty.SetClientConf(cliCfg)
+	// Refer
+	proto := GetProtocol()
 
+	url, err := common.NewURL(mockCommonUrl)
+	proto.Export(&proxy_factory.ProxyInvoker{
+		BaseInvoker: *protocol.NewBaseInvoker(url),
+	})
+	assert.NoError(t, err)
+	invoker := proto.Refer(url)
 	// make sure url
 	eq := invoker.GetUrl().URLEqual(url)
 	assert.True(t, eq)
diff --git a/protocol/dubbo/impl/codec.go b/protocol/dubbo/impl/codec.go
new file mode 100644
index 0000000000000000000000000000000000000000..c139f3547b2af5196a38be9bc83f49251bfcf043
--- /dev/null
+++ b/protocol/dubbo/impl/codec.go
@@ -0,0 +1,291 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package impl
+
+import (
+	"bufio"
+	"encoding/binary"
+)
+
+import (
+	hessian "github.com/apache/dubbo-go-hessian2"
+	perrors "github.com/pkg/errors"
+)
+
+import (
+	"github.com/apache/dubbo-go/common/constant"
+	"github.com/apache/dubbo-go/common/logger"
+	"github.com/apache/dubbo-go/remoting"
+)
+
+type ProtocolCodec struct {
+	reader     *bufio.Reader
+	pkgType    PackageType
+	bodyLen    int
+	serializer Serializer
+	headerRead bool
+}
+
+func (c *ProtocolCodec) ReadHeader(header *DubboHeader) error {
+	var err error
+	if c.reader.Size() < HEADER_LENGTH {
+		return hessian.ErrHeaderNotEnough
+	}
+	buf, err := c.reader.Peek(HEADER_LENGTH)
+	if err != nil { // this is impossible
+		return perrors.WithStack(err)
+	}
+	_, err = c.reader.Discard(HEADER_LENGTH)
+	if err != nil { // this is impossible
+		return perrors.WithStack(err)
+	}
+
+	//// read header
+	if buf[0] != MAGIC_HIGH && buf[1] != MAGIC_LOW {
+		return hessian.ErrIllegalPackage
+	}
+
+	// Header{serialization id(5 bit), event, two way, req/response}
+	if header.SerialID = buf[2] & SERIAL_MASK; header.SerialID == Zero {
+		return perrors.Errorf("serialization ID:%v", header.SerialID)
+	}
+
+	flag := buf[2] & FLAG_EVENT
+	if flag != Zero {
+		header.Type |= PackageHeartbeat
+	}
+	flag = buf[2] & FLAG_REQUEST
+	if flag != Zero {
+		header.Type |= PackageRequest
+		flag = buf[2] & FLAG_TWOWAY
+		if flag != Zero {
+			header.Type |= PackageRequest_TwoWay
+		}
+	} else {
+		header.Type |= PackageResponse
+		header.ResponseStatus = buf[3]
+		if header.ResponseStatus != Response_OK {
+			header.Type |= PackageResponse_Exception
+		}
+	}
+
+	// Header{req id}
+	header.ID = int64(binary.BigEndian.Uint64(buf[4:]))
+
+	// Header{body len}
+	header.BodyLen = int(binary.BigEndian.Uint32(buf[12:]))
+	if header.BodyLen < 0 {
+		return hessian.ErrIllegalPackage
+	}
+
+	c.pkgType = header.Type
+	c.bodyLen = header.BodyLen
+
+	if c.reader.Buffered() < c.bodyLen {
+		return hessian.ErrBodyNotEnough
+	}
+	c.headerRead = true
+	return perrors.WithStack(err)
+}
+
+func (c *ProtocolCodec) EncodeHeader(p DubboPackage) []byte {
+	header := p.Header
+	bs := make([]byte, 0)
+	switch header.Type {
+	case PackageHeartbeat:
+		if header.ResponseStatus == Zero {
+			bs = append(bs, hessian.DubboRequestHeartbeatHeader[:]...)
+		} else {
+			bs = append(bs, hessian.DubboResponseHeartbeatHeader[:]...)
+		}
+	case PackageResponse:
+		bs = append(bs, hessian.DubboResponseHeaderBytes[:]...)
+		if header.ResponseStatus != 0 {
+			bs[3] = header.ResponseStatus
+		}
+	case PackageRequest_TwoWay:
+		bs = append(bs, hessian.DubboRequestHeaderBytesTwoWay[:]...)
+	}
+	bs[2] |= header.SerialID & hessian.SERIAL_MASK
+	binary.BigEndian.PutUint64(bs[4:], uint64(header.ID))
+	return bs
+}
+
+func (c *ProtocolCodec) Encode(p DubboPackage) ([]byte, error) {
+	// header
+	if c.serializer == nil {
+		return nil, perrors.New("serializer should not be nil")
+	}
+	header := p.Header
+	switch header.Type {
+	case PackageHeartbeat:
+		if header.ResponseStatus == Zero {
+			return packRequest(p, c.serializer)
+		}
+		return packResponse(p, c.serializer)
+
+	case PackageRequest, PackageRequest_TwoWay:
+		return packRequest(p, c.serializer)
+
+	case PackageResponse:
+		return packResponse(p, c.serializer)
+
+	default:
+		return nil, perrors.Errorf("Unrecognised message type: %v", header.Type)
+	}
+}
+
+func (c *ProtocolCodec) Decode(p *DubboPackage) error {
+	if !c.headerRead {
+		if err := c.ReadHeader(&p.Header); err != nil {
+			return err
+		}
+	}
+	body, err := c.reader.Peek(p.GetBodyLen())
+	if err != nil {
+		return err
+	}
+	if p.IsResponseWithException() {
+		logger.Infof("response with exception: %+v", p.Header)
+		decoder := hessian.NewDecoder(body)
+		exception, err := decoder.Decode()
+		if err != nil {
+			return perrors.WithStack(err)
+		}
+		rsp, ok := p.Body.(*ResponsePayload)
+		if !ok {
+			return perrors.Errorf("java exception:%s", exception.(string))
+		}
+		rsp.Exception = perrors.Errorf("java exception:%s", exception.(string))
+		return nil
+	} else if p.IsHeartBeat() {
+		// heartbeat no need to unmarshal contents
+		return nil
+	}
+	if c.serializer == nil {
+		return perrors.New("Codec serializer is nil")
+	}
+	if p.IsResponse() {
+		p.Body = &ResponsePayload{
+			RspObj: remoting.GetPendingResponse(remoting.SequenceType(p.Header.ID)).Reply,
+		}
+	}
+	return c.serializer.Unmarshal(body, p)
+}
+
+func (c *ProtocolCodec) SetSerializer(serializer Serializer) {
+	c.serializer = serializer
+}
+
+func packRequest(p DubboPackage, serializer Serializer) ([]byte, error) {
+	var (
+		byteArray []byte
+		pkgLen    int
+	)
+
+	header := p.Header
+
+	//////////////////////////////////////////
+	// byteArray
+	//////////////////////////////////////////
+	// magic
+	switch header.Type {
+	case PackageHeartbeat:
+		byteArray = append(byteArray, DubboRequestHeartbeatHeader[:]...)
+	case PackageRequest_TwoWay:
+		byteArray = append(byteArray, DubboRequestHeaderBytesTwoWay[:]...)
+	default:
+		byteArray = append(byteArray, DubboRequestHeaderBytes[:]...)
+	}
+
+	// serialization id, two way flag, event, request/response flag
+	// SerialID is id of serialization approach in java dubbo
+	byteArray[2] |= header.SerialID & SERIAL_MASK
+	// request id
+	binary.BigEndian.PutUint64(byteArray[4:], uint64(header.ID))
+
+	//////////////////////////////////////////
+	// body
+	//////////////////////////////////////////
+	if p.IsHeartBeat() {
+		byteArray = append(byteArray, byte('N'))
+		pkgLen = 1
+	} else {
+		body, err := serializer.Marshal(p)
+		if err != nil {
+			return nil, err
+		}
+		pkgLen = len(body)
+		if pkgLen > int(DEFAULT_LEN) { // 8M
+			return nil, perrors.Errorf("Data length %d too large, max payload %d", pkgLen, DEFAULT_LEN)
+		}
+		byteArray = append(byteArray, body...)
+	}
+	binary.BigEndian.PutUint32(byteArray[12:], uint32(pkgLen))
+	return byteArray, nil
+}
+
+func packResponse(p DubboPackage, serializer Serializer) ([]byte, error) {
+	var (
+		byteArray []byte
+	)
+	header := p.Header
+	hb := p.IsHeartBeat()
+
+	// magic
+	if hb {
+		byteArray = append(byteArray, DubboResponseHeartbeatHeader[:]...)
+	} else {
+		byteArray = append(byteArray, DubboResponseHeaderBytes[:]...)
+	}
+	// set serialID, identify serialization types, eg: fastjson->6, hessian2->2
+	byteArray[2] |= header.SerialID & SERIAL_MASK
+	// response status
+	if header.ResponseStatus != 0 {
+		byteArray[3] = header.ResponseStatus
+	}
+
+	// request id
+	binary.BigEndian.PutUint64(byteArray[4:], uint64(header.ID))
+
+	// body
+	body, err := serializer.Marshal(p)
+	if err != nil {
+		return nil, err
+	}
+
+	pkgLen := len(body)
+	if pkgLen > int(DEFAULT_LEN) { // 8M
+		return nil, perrors.Errorf("Data length %d too large, max payload %d", pkgLen, DEFAULT_LEN)
+	}
+	// byteArray{body length}
+	binary.BigEndian.PutUint32(byteArray[12:], uint32(pkgLen))
+	byteArray = append(byteArray, body...)
+	return byteArray, nil
+}
+
+func NewDubboCodec(reader *bufio.Reader) *ProtocolCodec {
+	s, _ := GetSerializerById(constant.S_Hessian2)
+	return &ProtocolCodec{
+		reader:     reader,
+		pkgType:    0,
+		bodyLen:    0,
+		headerRead: false,
+		serializer: s.(Serializer),
+	}
+}
diff --git a/protocol/dubbo/codec_test.go b/protocol/dubbo/impl/codec_test.go
similarity index 50%
rename from protocol/dubbo/codec_test.go
rename to protocol/dubbo/impl/codec_test.go
index 6dfb87ea009394a2319c4b353e8f9cadc7b50e81..1c379282383c90ef27628af19ddaaafb2a4db9a6 100644
--- a/protocol/dubbo/codec_test.go
+++ b/protocol/dubbo/impl/codec_test.go
@@ -15,45 +15,46 @@
  * limitations under the License.
  */
 
-package dubbo
+package impl
 
 import (
-	"bytes"
 	"testing"
 	"time"
 )
 
 import (
-	perrors "github.com/pkg/errors"
 	"github.com/stretchr/testify/assert"
 )
 
 import (
-	"github.com/apache/dubbo-go/protocol/dubbo/hessian2"
+	"github.com/apache/dubbo-go/common/constant"
 )
 
-func TestDubboPackageMarshalAndUnmarshal(t *testing.T) {
-	pkg := &DubboPackage{}
+func TestDubboPackage_MarshalAndUnmarshal(t *testing.T) {
+	pkg := NewDubboPackage(nil)
 	pkg.Body = []interface{}{"a"}
-	pkg.Header.Type = hessian2.PackageHeartbeat
-	pkg.Header.SerialID = byte(S_Dubbo)
+	pkg.Header.Type = PackageHeartbeat
+	pkg.Header.SerialID = constant.S_Hessian2
 	pkg.Header.ID = 10086
+	pkg.SetSerializer(HessianSerializer{})
 
 	// heartbeat
 	data, err := pkg.Marshal()
 	assert.NoError(t, err)
 
-	pkgres := &DubboPackage{}
+	pkgres := NewDubboPackage(data)
+	pkgres.SetSerializer(HessianSerializer{})
+
 	pkgres.Body = []interface{}{}
-	err = pkgres.Unmarshal(data)
+	err = pkgres.Unmarshal()
 	assert.NoError(t, err)
-	assert.Equal(t, hessian2.PackageHeartbeat|hessian2.PackageRequest|hessian2.PackageRequest_TwoWay, pkgres.Header.Type)
-	assert.Equal(t, byte(S_Dubbo), pkgres.Header.SerialID)
+	assert.Equal(t, PackageHeartbeat|PackageRequest|PackageRequest_TwoWay, pkgres.Header.Type)
+	assert.Equal(t, constant.S_Hessian2, pkgres.Header.SerialID)
 	assert.Equal(t, int64(10086), pkgres.Header.ID)
 	assert.Equal(t, 0, len(pkgres.Body.([]interface{})))
 
 	// request
-	pkg.Header.Type = hessian2.PackageRequest
+	pkg.Header.Type = PackageRequest
 	pkg.Service.Interface = "Service"
 	pkg.Service.Path = "path"
 	pkg.Service.Version = "2.6"
@@ -62,25 +63,27 @@ func TestDubboPackageMarshalAndUnmarshal(t *testing.T) {
 	data, err = pkg.Marshal()
 	assert.NoError(t, err)
 
-	pkgres = &DubboPackage{}
+	pkgres = NewDubboPackage(data)
+	pkgres.SetSerializer(HessianSerializer{})
 	pkgres.Body = make([]interface{}, 7)
-	err = pkgres.Unmarshal(data)
+	err = pkgres.Unmarshal()
+	reassembleBody := pkgres.GetBody().(map[string]interface{})
 	assert.NoError(t, err)
-	assert.Equal(t, hessian2.PackageRequest, pkgres.Header.Type)
-	assert.Equal(t, byte(S_Dubbo), pkgres.Header.SerialID)
+	assert.Equal(t, PackageRequest, pkgres.Header.Type)
+	assert.Equal(t, constant.S_Hessian2, pkgres.Header.SerialID)
 	assert.Equal(t, int64(10086), pkgres.Header.ID)
-	assert.Equal(t, "2.0.2", pkgres.Body.([]interface{})[0])
-	assert.Equal(t, "path", pkgres.Body.([]interface{})[1])
-	assert.Equal(t, "2.6", pkgres.Body.([]interface{})[2])
-	assert.Equal(t, "Method", pkgres.Body.([]interface{})[3])
-	assert.Equal(t, "Ljava/lang/String;", pkgres.Body.([]interface{})[4])
-	assert.Equal(t, []interface{}{"a"}, pkgres.Body.([]interface{})[5])
-	assert.Equal(t, map[string]interface{}{"dubbo": "2.0.2", "interface": "Service", "path": "path", "timeout": "1000", "version": "2.6"}, pkgres.Body.([]interface{})[6])
-}
-
-func TestIssue380(t *testing.T) {
-	pkg := &DubboPackage{}
-	buf := bytes.NewBuffer([]byte("hello"))
-	err := pkg.Unmarshal(buf)
-	assert.True(t, perrors.Cause(err) == hessian2.ErrHeaderNotEnough)
+	assert.Equal(t, "2.0.2", reassembleBody["dubboVersion"].(string))
+	assert.Equal(t, "path", pkgres.Service.Path)
+	assert.Equal(t, "2.6", pkgres.Service.Version)
+	assert.Equal(t, "Method", pkgres.Service.Method)
+	assert.Equal(t, "Ljava/lang/String;", reassembleBody["argsTypes"].(string))
+	assert.Equal(t, []interface{}{"a"}, reassembleBody["args"])
+	tmpData := map[string]interface{}{
+		"dubbo":     "2.0.2",
+		"interface": "Service",
+		"path":      "path",
+		"timeout":   "1000",
+		"version":   "2.6",
+	}
+	assert.Equal(t, tmpData, reassembleBody["attachments"])
 }
diff --git a/protocol/dubbo/impl/const.go b/protocol/dubbo/impl/const.go
new file mode 100644
index 0000000000000000000000000000000000000000..70d8bae6cad63d436f5d9f1ef69c397ee8a052f3
--- /dev/null
+++ b/protocol/dubbo/impl/const.go
@@ -0,0 +1,252 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package impl
+
+import (
+	"reflect"
+	"regexp"
+
+	"github.com/pkg/errors"
+)
+
+const (
+	DUBBO = "dubbo"
+)
+
+const (
+	mask = byte(127)
+	flag = byte(128)
+)
+
+const (
+	// Zero : byte zero
+	Zero = byte(0x00)
+)
+
+// constansts
+const (
+	TAG_READ        = int32(-1)
+	ASCII_GAP       = 32
+	CHUNK_SIZE      = 4096
+	BC_BINARY       = byte('B') // final chunk
+	BC_BINARY_CHUNK = byte('A') // non-final chunk
+
+	BC_BINARY_DIRECT  = byte(0x20) // 1-byte length binary
+	BINARY_DIRECT_MAX = byte(0x0f)
+	BC_BINARY_SHORT   = byte(0x34) // 2-byte length binary
+	BINARY_SHORT_MAX  = 0x3ff      // 0-1023 binary
+
+	BC_DATE        = byte(0x4a) // 64-bit millisecond UTC date
+	BC_DATE_MINUTE = byte(0x4b) // 32-bit minute UTC date
+
+	BC_DOUBLE = byte('D') // IEEE 64-bit double
+
+	BC_DOUBLE_ZERO  = byte(0x5b)
+	BC_DOUBLE_ONE   = byte(0x5c)
+	BC_DOUBLE_BYTE  = byte(0x5d)
+	BC_DOUBLE_SHORT = byte(0x5e)
+	BC_DOUBLE_MILL  = byte(0x5f)
+
+	BC_FALSE = byte('F') // boolean false
+
+	BC_INT = byte('I') // 32-bit int
+
+	INT_DIRECT_MIN = -0x10
+	INT_DIRECT_MAX = byte(0x2f)
+	BC_INT_ZERO    = byte(0x90)
+
+	INT_BYTE_MIN     = -0x800
+	INT_BYTE_MAX     = 0x7ff
+	BC_INT_BYTE_ZERO = byte(0xc8)
+
+	BC_END = byte('Z')
+
+	INT_SHORT_MIN     = -0x40000
+	INT_SHORT_MAX     = 0x3ffff
+	BC_INT_SHORT_ZERO = byte(0xd4)
+
+	BC_LIST_VARIABLE           = byte(0x55)
+	BC_LIST_FIXED              = byte('V')
+	BC_LIST_VARIABLE_UNTYPED   = byte(0x57)
+	BC_LIST_FIXED_UNTYPED      = byte(0x58)
+	_listFixedTypedLenTagMin   = byte(0x70)
+	_listFixedTypedLenTagMax   = byte(0x77)
+	_listFixedUntypedLenTagMin = byte(0x78)
+	_listFixedUntypedLenTagMax = byte(0x7f)
+
+	BC_LIST_DIRECT         = byte(0x70)
+	BC_LIST_DIRECT_UNTYPED = byte(0x78)
+	LIST_DIRECT_MAX        = byte(0x7)
+
+	BC_LONG         = byte('L') // 64-bit signed integer
+	LONG_DIRECT_MIN = -0x08
+	LONG_DIRECT_MAX = byte(0x0f)
+	BC_LONG_ZERO    = byte(0xe0)
+
+	LONG_BYTE_MIN     = -0x800
+	LONG_BYTE_MAX     = 0x7ff
+	BC_LONG_BYTE_ZERO = byte(0xf8)
+
+	LONG_SHORT_MIN     = -0x40000
+	LONG_SHORT_MAX     = 0x3ffff
+	BC_LONG_SHORT_ZERO = byte(0x3c)
+
+	BC_LONG_INT = byte(0x59)
+
+	BC_MAP         = byte('M')
+	BC_MAP_UNTYPED = byte('H')
+
+	BC_NULL = byte('N') // x4e
+
+	BC_OBJECT     = byte('O')
+	BC_OBJECT_DEF = byte('C')
+
+	BC_OBJECT_DIRECT  = byte(0x60)
+	OBJECT_DIRECT_MAX = byte(0x0f)
+
+	BC_REF = byte(0x51)
+
+	BC_STRING       = byte('S') // final string
+	BC_STRING_CHUNK = byte('R') // non-final string
+
+	BC_STRING_DIRECT  = byte(0x00)
+	STRING_DIRECT_MAX = byte(0x1f)
+	BC_STRING_SHORT   = byte(0x30)
+	STRING_SHORT_MAX  = 0x3ff
+
+	BC_TRUE = byte('T')
+
+	P_PACKET_CHUNK = byte(0x4f)
+	P_PACKET       = byte('P')
+
+	P_PACKET_DIRECT   = byte(0x80)
+	PACKET_DIRECT_MAX = byte(0x7f)
+
+	P_PACKET_SHORT   = byte(0x70)
+	PACKET_SHORT_MAX = 0xfff
+	ARRAY_STRING     = "[string"
+	ARRAY_INT        = "[int"
+	ARRAY_DOUBLE     = "[double"
+	ARRAY_FLOAT      = "[float"
+	ARRAY_BOOL       = "[boolean"
+	ARRAY_LONG       = "[long"
+
+	PATH_KEY      = "path"
+	GROUP_KEY     = "group"
+	INTERFACE_KEY = "interface"
+	VERSION_KEY   = "version"
+	TIMEOUT_KEY   = "timeout"
+
+	STRING_NIL   = ""
+	STRING_TRUE  = "true"
+	STRING_FALSE = "false"
+	STRING_ZERO  = "0.0"
+	STRING_ONE   = "1.0"
+)
+
+// ResponsePayload related consts
+const (
+	Response_OK                byte = 20
+	Response_CLIENT_TIMEOUT    byte = 30
+	Response_SERVER_TIMEOUT    byte = 31
+	Response_BAD_REQUEST       byte = 40
+	Response_BAD_RESPONSE      byte = 50
+	Response_SERVICE_NOT_FOUND byte = 60
+	Response_SERVICE_ERROR     byte = 70
+	Response_SERVER_ERROR      byte = 80
+	Response_CLIENT_ERROR      byte = 90
+
+	// According to "java dubbo" There are two cases of response:
+	// 		1. with attachments
+	// 		2. no attachments
+	RESPONSE_WITH_EXCEPTION                  int32 = 0
+	RESPONSE_VALUE                           int32 = 1
+	RESPONSE_NULL_VALUE                      int32 = 2
+	RESPONSE_WITH_EXCEPTION_WITH_ATTACHMENTS int32 = 3
+	RESPONSE_VALUE_WITH_ATTACHMENTS          int32 = 4
+	RESPONSE_NULL_VALUE_WITH_ATTACHMENTS     int32 = 5
+)
+
+/**
+ * the dubbo protocol header length is 16 Bytes.
+ * the first 2 Bytes is magic code '0xdabb'
+ * the next 1 Byte is message flags, in which its 16-20 bit is serial id, 21 for event, 22 for two way, 23 for request/response flag
+ * the next 1 Bytes is response state.
+ * the next 8 Bytes is package DI.
+ * the next 4 Bytes is package length.
+ **/
+const (
+	// header length.
+	HEADER_LENGTH = 16
+
+	// magic header
+	MAGIC      = uint16(0xdabb)
+	MAGIC_HIGH = byte(0xda)
+	MAGIC_LOW  = byte(0xbb)
+
+	// message flag.
+	FLAG_REQUEST = byte(0x80)
+	FLAG_TWOWAY  = byte(0x40)
+	FLAG_EVENT   = byte(0x20) // for heartbeat
+	SERIAL_MASK  = 0x1f
+
+	DUBBO_VERSION                          = "2.5.4"
+	DUBBO_VERSION_KEY                      = "dubbo"
+	DEFAULT_DUBBO_PROTOCOL_VERSION         = "2.0.2" // Dubbo RPC protocol version, for compatibility, it must not be between 2.0.10 ~ 2.6.2
+	LOWEST_VERSION_FOR_RESPONSE_ATTACHMENT = 2000200
+	DEFAULT_LEN                            = 8388608 // 8 * 1024 * 1024 default body max length
+)
+
+// regular
+const (
+	JAVA_IDENT_REGEX = "(?:[_$a-zA-Z][_$a-zA-Z0-9]*)"
+	CLASS_DESC       = "(?:L" + JAVA_IDENT_REGEX + "(?:\\/" + JAVA_IDENT_REGEX + ")*;)"
+	ARRAY_DESC       = "(?:\\[+(?:(?:[VZBCDFIJS])|" + CLASS_DESC + "))"
+	DESC_REGEX       = "(?:(?:[VZBCDFIJS])|" + CLASS_DESC + "|" + ARRAY_DESC + ")"
+)
+
+// Dubbo request response related consts
+var (
+	DubboRequestHeaderBytesTwoWay = [HEADER_LENGTH]byte{MAGIC_HIGH, MAGIC_LOW, FLAG_REQUEST | FLAG_TWOWAY}
+	DubboRequestHeaderBytes       = [HEADER_LENGTH]byte{MAGIC_HIGH, MAGIC_LOW, FLAG_REQUEST}
+	DubboResponseHeaderBytes      = [HEADER_LENGTH]byte{MAGIC_HIGH, MAGIC_LOW, Zero, Response_OK}
+	DubboRequestHeartbeatHeader   = [HEADER_LENGTH]byte{MAGIC_HIGH, MAGIC_LOW, FLAG_REQUEST | FLAG_TWOWAY | FLAG_EVENT}
+	DubboResponseHeartbeatHeader  = [HEADER_LENGTH]byte{MAGIC_HIGH, MAGIC_LOW, FLAG_EVENT}
+)
+
+// Error part
+var (
+	ErrHeaderNotEnough = errors.New("header buffer too short")
+	ErrBodyNotEnough   = errors.New("body buffer too short")
+	ErrJavaException   = errors.New("got java exception")
+	ErrIllegalPackage  = errors.New("illegal package!")
+)
+
+// DescRegex ...
+var DescRegex, _ = regexp.Compile(DESC_REGEX)
+
+var NilValue = reflect.Zero(reflect.TypeOf((*interface{})(nil)).Elem())
+
+// Body map keys
+var (
+	DubboVersionKey = "dubboVersion"
+	ArgsTypesKey    = "argsTypes"
+	ArgsKey         = "args"
+	ServiceKey      = "service"
+	AttachmentsKey  = "attachments"
+)
diff --git a/protocol/dubbo/impl/hessian.go b/protocol/dubbo/impl/hessian.go
new file mode 100644
index 0000000000000000000000000000000000000000..b686d5728d026fdb1e37180d5a9d24d32bf4b7bc
--- /dev/null
+++ b/protocol/dubbo/impl/hessian.go
@@ -0,0 +1,526 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package impl
+
+import (
+	"math"
+	"reflect"
+	"strconv"
+	"strings"
+	"time"
+)
+
+import (
+	hessian "github.com/apache/dubbo-go-hessian2"
+	"github.com/apache/dubbo-go-hessian2/java_exception"
+	perrors "github.com/pkg/errors"
+)
+
+import (
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/common/constant"
+	"github.com/apache/dubbo-go/common/logger"
+)
+
+type Object interface{}
+
+type HessianSerializer struct {
+}
+
+func (h HessianSerializer) Marshal(p DubboPackage) ([]byte, error) {
+	encoder := hessian.NewEncoder()
+	if p.IsRequest() {
+		return marshalRequest(encoder, p)
+	}
+	return marshalResponse(encoder, p)
+}
+
+func (h HessianSerializer) Unmarshal(input []byte, p *DubboPackage) error {
+	if p.IsHeartBeat() {
+		return nil
+	}
+	if p.IsRequest() {
+		return unmarshalRequestBody(input, p)
+	}
+	return unmarshalResponseBody(input, p)
+}
+
+func marshalResponse(encoder *hessian.Encoder, p DubboPackage) ([]byte, error) {
+	header := p.Header
+	response := EnsureResponsePayload(p.Body)
+	if header.ResponseStatus == Response_OK {
+		if p.IsHeartBeat() {
+			encoder.Encode(nil)
+		} else {
+			var version string
+			if attachmentVersion, ok := response.Attachments[DUBBO_VERSION_KEY]; ok {
+				version = attachmentVersion.(string)
+			}
+			atta := isSupportResponseAttachment(version)
+
+			var resWithException, resValue, resNullValue int32
+			if atta {
+				resWithException = RESPONSE_WITH_EXCEPTION_WITH_ATTACHMENTS
+				resValue = RESPONSE_VALUE_WITH_ATTACHMENTS
+				resNullValue = RESPONSE_NULL_VALUE_WITH_ATTACHMENTS
+			} else {
+				resWithException = RESPONSE_WITH_EXCEPTION
+				resValue = RESPONSE_VALUE
+				resNullValue = RESPONSE_NULL_VALUE
+			}
+
+			if response.Exception != nil { // throw error
+				encoder.Encode(resWithException)
+				if t, ok := response.Exception.(java_exception.Throwabler); ok {
+					encoder.Encode(t)
+				} else {
+					encoder.Encode(java_exception.NewThrowable(response.Exception.Error()))
+				}
+			} else {
+				if response.RspObj == nil {
+					encoder.Encode(resNullValue)
+				} else {
+					encoder.Encode(resValue)
+					encoder.Encode(response.RspObj) // result
+				}
+			}
+
+			if atta {
+				encoder.Encode(response.Attachments) // attachments
+			}
+		}
+	} else {
+		if response.Exception != nil { // throw error
+			encoder.Encode(response.Exception.Error())
+		} else {
+			encoder.Encode(response.RspObj)
+		}
+	}
+	bs := encoder.Buffer()
+	// encNull
+	bs = append(bs, byte('N'))
+	return bs, nil
+}
+
+func marshalRequest(encoder *hessian.Encoder, p DubboPackage) ([]byte, error) {
+	service := p.Service
+	request := EnsureRequestPayload(p.Body)
+	encoder.Encode(DEFAULT_DUBBO_PROTOCOL_VERSION)
+	encoder.Encode(service.Path)
+	encoder.Encode(service.Version)
+	encoder.Encode(service.Method)
+
+	args, ok := request.Params.([]interface{})
+
+	if !ok {
+		logger.Infof("request args are: %+v", request.Params)
+		return nil, perrors.Errorf("@params is not of type: []interface{}")
+	}
+	types, err := getArgsTypeList(args)
+	if err != nil {
+		return nil, perrors.Wrapf(err, " PackRequest(args:%+v)", args)
+	}
+	encoder.Encode(types)
+	for _, v := range args {
+		encoder.Encode(v)
+	}
+
+	request.Attachments[PATH_KEY] = service.Path
+	request.Attachments[VERSION_KEY] = service.Version
+	if len(service.Group) > 0 {
+		request.Attachments[GROUP_KEY] = service.Group
+	}
+	if len(service.Interface) > 0 {
+		request.Attachments[INTERFACE_KEY] = service.Interface
+	}
+	if service.Timeout != 0 {
+		request.Attachments[TIMEOUT_KEY] = strconv.Itoa(int(service.Timeout / time.Millisecond))
+	}
+
+	encoder.Encode(request.Attachments)
+	return encoder.Buffer(), nil
+
+}
+
+var versionInt = make(map[string]int)
+
+// https://github.com/apache/dubbo/blob/dubbo-2.7.1/dubbo-common/src/main/java/org/apache/dubbo/common/Version.java#L96
+// isSupportResponseAttachment is for compatibility among some dubbo version
+func isSupportResponseAttachment(version string) bool {
+	if version == "" {
+		return false
+	}
+
+	v, ok := versionInt[version]
+	if !ok {
+		v = version2Int(version)
+		if v == -1 {
+			return false
+		}
+	}
+
+	if v >= 2001000 && v <= 2060200 { // 2.0.10 ~ 2.6.2
+		return false
+	}
+	return v >= LOWEST_VERSION_FOR_RESPONSE_ATTACHMENT
+}
+
+func version2Int(version string) int {
+	var v = 0
+	varr := strings.Split(version, ".")
+	length := len(varr)
+	for key, value := range varr {
+		v0, err := strconv.Atoi(value)
+		if err != nil {
+			return -1
+		}
+		v += v0 * int(math.Pow10((length-key-1)*2))
+	}
+	if length == 3 {
+		return v * 100
+	}
+	return v
+}
+
+func unmarshalRequestBody(body []byte, p *DubboPackage) error {
+	if p.Body == nil {
+		p.SetBody(make([]interface{}, 7))
+	}
+	decoder := hessian.NewDecoder(body)
+	var (
+		err                                                     error
+		dubboVersion, target, serviceVersion, method, argsTypes interface{}
+		args                                                    []interface{}
+	)
+	req, ok := p.Body.([]interface{})
+	if !ok {
+		return perrors.Errorf("@reqObj is not of type: []interface{}")
+	}
+	dubboVersion, err = decoder.Decode()
+	if err != nil {
+		return perrors.WithStack(err)
+	}
+	req[0] = dubboVersion
+
+	target, err = decoder.Decode()
+	if err != nil {
+		return perrors.WithStack(err)
+	}
+	req[1] = target
+
+	serviceVersion, err = decoder.Decode()
+	if err != nil {
+		return perrors.WithStack(err)
+	}
+	req[2] = serviceVersion
+
+	method, err = decoder.Decode()
+	if err != nil {
+		return perrors.WithStack(err)
+	}
+	req[3] = method
+
+	argsTypes, err = decoder.Decode()
+	if err != nil {
+		return perrors.WithStack(err)
+	}
+	req[4] = argsTypes
+
+	ats := hessian.DescRegex.FindAllString(argsTypes.(string), -1)
+	var arg interface{}
+	for i := 0; i < len(ats); i++ {
+		arg, err = decoder.Decode()
+		if err != nil {
+			return perrors.WithStack(err)
+		}
+		args = append(args, arg)
+	}
+	req[5] = args
+
+	attachments, err := decoder.Decode()
+	if err != nil {
+		return perrors.WithStack(err)
+	}
+
+	if v, ok := attachments.(map[interface{}]interface{}); ok {
+		v[DUBBO_VERSION_KEY] = dubboVersion
+		req[6] = ToMapStringInterface(v)
+		buildServerSidePackageBody(p)
+		return nil
+	}
+	return perrors.Errorf("get wrong attachments: %+v", attachments)
+}
+
+func unmarshalResponseBody(body []byte, p *DubboPackage) error {
+	decoder := hessian.NewDecoder(body)
+	rspType, err := decoder.Decode()
+	if p.Body == nil {
+		p.SetBody(&ResponsePayload{})
+	}
+	if err != nil {
+		return perrors.WithStack(err)
+	}
+	response := EnsureResponsePayload(p.Body)
+
+	switch rspType {
+	case RESPONSE_WITH_EXCEPTION, RESPONSE_WITH_EXCEPTION_WITH_ATTACHMENTS:
+		expt, err := decoder.Decode()
+		if err != nil {
+			return perrors.WithStack(err)
+		}
+		if rspType == RESPONSE_WITH_EXCEPTION_WITH_ATTACHMENTS {
+			attachments, err := decoder.Decode()
+			if err != nil {
+				return perrors.WithStack(err)
+			}
+			if v, ok := attachments.(map[interface{}]interface{}); ok {
+				atta := ToMapStringInterface(v)
+				response.Attachments = atta
+			} else {
+				return perrors.Errorf("get wrong attachments: %+v", attachments)
+			}
+		}
+
+		if e, ok := expt.(error); ok {
+			response.Exception = e
+		} else {
+			response.Exception = perrors.Errorf("got exception: %+v", expt)
+		}
+		return nil
+
+	case RESPONSE_VALUE, RESPONSE_VALUE_WITH_ATTACHMENTS:
+		rsp, err := decoder.Decode()
+		if err != nil {
+			return perrors.WithStack(err)
+		}
+		if rspType == RESPONSE_VALUE_WITH_ATTACHMENTS {
+			attachments, err := decoder.Decode()
+			if err != nil {
+				return perrors.WithStack(err)
+			}
+			if v, ok := attachments.(map[interface{}]interface{}); ok {
+				atta := ToMapStringInterface(v)
+				response.Attachments = atta
+			} else {
+				return perrors.Errorf("get wrong attachments: %+v", attachments)
+			}
+		}
+
+		return perrors.WithStack(hessian.ReflectResponse(rsp, response.RspObj))
+
+	case RESPONSE_NULL_VALUE, RESPONSE_NULL_VALUE_WITH_ATTACHMENTS:
+		if rspType == RESPONSE_NULL_VALUE_WITH_ATTACHMENTS {
+			attachments, err := decoder.Decode()
+			if err != nil {
+				return perrors.WithStack(err)
+			}
+			if v, ok := attachments.(map[interface{}]interface{}); ok {
+				atta := ToMapStringInterface(v)
+				response.Attachments = atta
+			} else {
+				return perrors.Errorf("get wrong attachments: %+v", attachments)
+			}
+		}
+		return nil
+	}
+	return nil
+}
+
+func buildServerSidePackageBody(pkg *DubboPackage) {
+	req := pkg.GetBody().([]interface{}) // length of body should be 7
+	if len(req) > 0 {
+		var dubboVersion, argsTypes string
+		var args []interface{}
+		var attachments map[string]interface{}
+		svc := Service{}
+		if req[0] != nil {
+			dubboVersion = req[0].(string)
+		}
+		if req[1] != nil {
+			svc.Path = req[1].(string)
+		}
+		if req[2] != nil {
+			svc.Version = req[2].(string)
+		}
+		if req[3] != nil {
+			svc.Method = req[3].(string)
+		}
+		if req[4] != nil {
+			argsTypes = req[4].(string)
+		}
+		if req[5] != nil {
+			args = req[5].([]interface{})
+		}
+		if req[6] != nil {
+			attachments = req[6].(map[string]interface{})
+		}
+		if svc.Path == "" && attachments[constant.PATH_KEY] != nil && len(attachments[constant.PATH_KEY].(string)) > 0 {
+			svc.Path = attachments[constant.PATH_KEY].(string)
+		}
+		if _, ok := attachments[constant.INTERFACE_KEY]; ok {
+			svc.Interface = attachments[constant.INTERFACE_KEY].(string)
+		} else {
+			svc.Interface = svc.Path
+		}
+		if _, ok := attachments[constant.GROUP_KEY]; ok {
+			svc.Group = attachments[constant.GROUP_KEY].(string)
+		}
+		pkg.SetService(svc)
+		pkg.SetBody(map[string]interface{}{
+			"dubboVersion": dubboVersion,
+			"argsTypes":    argsTypes,
+			"args":         args,
+			"service":      common.ServiceMap.GetService(DUBBO, svc.Path), // path as a key
+			"attachments":  attachments,
+		})
+	}
+}
+
+func getArgsTypeList(args []interface{}) (string, error) {
+	var (
+		typ   string
+		types string
+	)
+
+	for i := range args {
+		typ = getArgType(args[i])
+		if typ == "" {
+			return types, perrors.Errorf("cat not get arg %#v type", args[i])
+		}
+		if !strings.Contains(typ, ".") {
+			types += typ
+		} else if strings.Index(typ, "[") == 0 {
+			types += strings.Replace(typ, ".", "/", -1)
+		} else {
+			// java.util.List -> Ljava/util/List;
+			types += "L" + strings.Replace(typ, ".", "/", -1) + ";"
+		}
+	}
+
+	return types, nil
+}
+
+func getArgType(v interface{}) string {
+	if v == nil {
+		return "V"
+	}
+
+	switch v.(type) {
+	// Serialized tags for base types
+	case nil:
+		return "V"
+	case bool:
+		return "Z"
+	case []bool:
+		return "[Z"
+	case byte:
+		return "B"
+	case []byte:
+		return "[B"
+	case int8:
+		return "B"
+	case []int8:
+		return "[B"
+	case int16:
+		return "S"
+	case []int16:
+		return "[S"
+	case uint16: // Equivalent to Char of Java
+		return "C"
+	case []uint16:
+		return "[C"
+	// case rune:
+	//	return "C"
+	case int:
+		return "J"
+	case []int:
+		return "[J"
+	case int32:
+		return "I"
+	case []int32:
+		return "[I"
+	case int64:
+		return "J"
+	case []int64:
+		return "[J"
+	case time.Time:
+		return "java.util.Date"
+	case []time.Time:
+		return "[Ljava.util.Date"
+	case float32:
+		return "F"
+	case []float32:
+		return "[F"
+	case float64:
+		return "D"
+	case []float64:
+		return "[D"
+	case string:
+		return "java.lang.String"
+	case []string:
+		return "[Ljava.lang.String;"
+	case []Object:
+		return "[Ljava.lang.Object;"
+	case map[interface{}]interface{}:
+		// return  "java.util.HashMap"
+		return "java.util.Map"
+	case hessian.POJOEnum:
+		return v.(hessian.POJOEnum).JavaClassName()
+	//  Serialized tags for complex types
+	default:
+		t := reflect.TypeOf(v)
+		if reflect.Ptr == t.Kind() {
+			t = reflect.TypeOf(reflect.ValueOf(v).Elem())
+		}
+		switch t.Kind() {
+		case reflect.Struct:
+			return "java.lang.Object"
+		case reflect.Slice, reflect.Array:
+			if t.Elem().Kind() == reflect.Struct {
+				return "[Ljava.lang.Object;"
+			}
+			// return "java.util.ArrayList"
+			return "java.util.List"
+		case reflect.Map: // Enter here, map may be map[string]int
+			return "java.util.Map"
+		default:
+			return ""
+		}
+	}
+
+	// unreachable
+	// return "java.lang.RuntimeException"
+}
+
+func ToMapStringInterface(origin map[interface{}]interface{}) map[string]interface{} {
+	dest := make(map[string]interface{}, len(origin))
+	for k, v := range origin {
+		if kv, ok := k.(string); ok {
+			if v == nil {
+				dest[kv] = ""
+				continue
+			}
+			dest[kv] = v
+		}
+	}
+	return dest
+}
+
+func init() {
+	SetSerializer("hessian2", HessianSerializer{})
+}
diff --git a/protocol/dubbo/impl/package.go b/protocol/dubbo/impl/package.go
new file mode 100644
index 0000000000000000000000000000000000000000..6f6d2ea9753a513412a4f5099c396dd90cf454ba
--- /dev/null
+++ b/protocol/dubbo/impl/package.go
@@ -0,0 +1,171 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package impl
+
+import (
+	"bufio"
+	"bytes"
+	"fmt"
+	"time"
+)
+
+import (
+	"github.com/pkg/errors"
+)
+
+type PackageType int
+
+// enum part
+const (
+	PackageError              = PackageType(0x01)
+	PackageRequest            = PackageType(0x02)
+	PackageResponse           = PackageType(0x04)
+	PackageHeartbeat          = PackageType(0x08)
+	PackageRequest_TwoWay     = PackageType(0x10)
+	PackageResponse_Exception = PackageType(0x20)
+	PackageType_BitSize       = 0x2f
+)
+
+type DubboHeader struct {
+	SerialID       byte
+	Type           PackageType
+	ID             int64
+	BodyLen        int
+	ResponseStatus byte
+}
+
+// Service defines service instance
+type Service struct {
+	Path      string
+	Interface string
+	Group     string
+	Version   string
+	Method    string
+	Timeout   time.Duration // request timeout
+}
+
+type DubboPackage struct {
+	Header  DubboHeader
+	Service Service
+	Body    interface{}
+	Err     error
+	Codec   *ProtocolCodec
+}
+
+func (p DubboPackage) String() string {
+	return fmt.Sprintf("HessianPackage: Header-%v, Path-%v, Body-%v", p.Header, p.Service, p.Body)
+}
+
+func (p *DubboPackage) ReadHeader() error {
+	return p.Codec.ReadHeader(&p.Header)
+}
+
+func (p *DubboPackage) Marshal() (*bytes.Buffer, error) {
+	if p.Codec == nil {
+		return nil, errors.New("Codec is nil")
+	}
+	pkg, err := p.Codec.Encode(*p)
+	if err != nil {
+		return nil, errors.WithStack(err)
+	}
+	return bytes.NewBuffer(pkg), nil
+}
+
+func (p *DubboPackage) Unmarshal() error {
+	if p.Codec == nil {
+		return errors.New("Codec is nil")
+	}
+	return p.Codec.Decode(p)
+}
+
+func (p DubboPackage) IsHeartBeat() bool {
+	return p.Header.Type&PackageHeartbeat != 0
+}
+
+func (p DubboPackage) IsRequest() bool {
+	return p.Header.Type&(PackageRequest_TwoWay|PackageRequest) != 0
+}
+
+func (p DubboPackage) IsResponse() bool {
+	return p.Header.Type == PackageResponse
+}
+
+func (p DubboPackage) IsResponseWithException() bool {
+	flag := PackageResponse | PackageResponse_Exception
+	return p.Header.Type&flag == flag
+}
+
+func (p DubboPackage) GetBodyLen() int {
+	return p.Header.BodyLen
+}
+
+func (p DubboPackage) GetLen() int {
+	return HEADER_LENGTH + p.Header.BodyLen
+}
+
+func (p DubboPackage) GetBody() interface{} {
+	return p.Body
+}
+
+func (p *DubboPackage) SetBody(body interface{}) {
+	p.Body = body
+}
+
+func (p *DubboPackage) SetHeader(header DubboHeader) {
+	p.Header = header
+}
+
+func (p *DubboPackage) SetService(svc Service) {
+	p.Service = svc
+}
+
+func (p *DubboPackage) SetID(id int64) {
+	p.Header.ID = id
+}
+
+func (p DubboPackage) GetHeader() DubboHeader {
+	return p.Header
+}
+
+func (p DubboPackage) GetService() Service {
+	return p.Service
+}
+
+func (p *DubboPackage) SetResponseStatus(status byte) {
+	p.Header.ResponseStatus = status
+}
+
+func (p *DubboPackage) SetSerializer(serializer Serializer) {
+	p.Codec.SetSerializer(serializer)
+}
+
+func NewDubboPackage(data *bytes.Buffer) *DubboPackage {
+	var codec *ProtocolCodec
+	if data == nil {
+		codec = NewDubboCodec(nil)
+	} else {
+		codec = NewDubboCodec(bufio.NewReaderSize(data, len(data.Bytes())))
+	}
+	return &DubboPackage{
+		Header:  DubboHeader{},
+		Service: Service{},
+		Body:    nil,
+		Err:     nil,
+		Codec:   codec,
+	}
+}
diff --git a/protocol/dubbo/impl/request.go b/protocol/dubbo/impl/request.go
new file mode 100644
index 0000000000000000000000000000000000000000..ef520083e6457f0ceaf3e80778f79d3e0ce686ab
--- /dev/null
+++ b/protocol/dubbo/impl/request.go
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package impl
+
+type RequestPayload struct {
+	Params      interface{}
+	Attachments map[string]interface{}
+}
+
+func NewRequestPayload(args interface{}, atta map[string]interface{}) *RequestPayload {
+	if atta == nil {
+		atta = make(map[string]interface{})
+	}
+	return &RequestPayload{
+		Params:      args,
+		Attachments: atta,
+	}
+}
+
+func EnsureRequestPayload(body interface{}) *RequestPayload {
+	if req, ok := body.(*RequestPayload); ok {
+		return req
+	}
+	return NewRequestPayload(body, nil)
+}
diff --git a/protocol/dubbo/impl/response.go b/protocol/dubbo/impl/response.go
new file mode 100644
index 0000000000000000000000000000000000000000..9fde1eb249c40e546bdabc54d15e4a3b6d1ea399
--- /dev/null
+++ b/protocol/dubbo/impl/response.go
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package impl
+
+type ResponsePayload struct {
+	RspObj      interface{}
+	Exception   error
+	Attachments map[string]interface{}
+}
+
+// NewResponse create a new ResponsePayload
+func NewResponsePayload(rspObj interface{}, exception error, attachments map[string]interface{}) *ResponsePayload {
+	if attachments == nil {
+		attachments = make(map[string]interface{})
+	}
+	return &ResponsePayload{
+		RspObj:      rspObj,
+		Exception:   exception,
+		Attachments: attachments,
+	}
+}
+
+func EnsureResponsePayload(body interface{}) *ResponsePayload {
+	if res, ok := body.(*ResponsePayload); ok {
+		return res
+	}
+	if exp, ok := body.(error); ok {
+		return NewResponsePayload(nil, exp, nil)
+	}
+	return NewResponsePayload(body, nil, nil)
+}
diff --git a/protocol/dubbo/impl/serialization.go b/protocol/dubbo/impl/serialization.go
new file mode 100644
index 0000000000000000000000000000000000000000..7ce76a87c17376cfb17983b6b6b3bdaf2771c22e
--- /dev/null
+++ b/protocol/dubbo/impl/serialization.go
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package impl
+
+import (
+	"fmt"
+)
+
+import (
+	"github.com/apache/dubbo-go/common/constant"
+)
+
+var (
+	serializers = make(map[string]interface{})
+	nameMaps    = make(map[byte]string)
+)
+
+func init() {
+	nameMaps = map[byte]string{
+		constant.S_Hessian2: constant.HESSIAN2_SERIALIZATION,
+		constant.S_Proto:    constant.PROTOBUF_SERIALIZATION,
+	}
+}
+
+func SetSerializer(name string, serializer interface{}) {
+	serializers[name] = serializer
+}
+
+func GetSerializerById(id byte) (interface{}, error) {
+	name, ok := nameMaps[id]
+	if !ok {
+		panic(fmt.Sprintf("serialId %d not found", id))
+	}
+	serializer, ok := serializers[name]
+	if !ok {
+		panic(fmt.Sprintf("serialization %s not found", name))
+	}
+	return serializer, nil
+}
diff --git a/protocol/dubbo/impl/serialize.go b/protocol/dubbo/impl/serialize.go
new file mode 100644
index 0000000000000000000000000000000000000000..1f913f7caae2a2c758764a92e4e63a0d9555ff1a
--- /dev/null
+++ b/protocol/dubbo/impl/serialize.go
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package impl
+
+import (
+	"github.com/apache/dubbo-go/common/constant"
+)
+
+type Serializer interface {
+	Marshal(p DubboPackage) ([]byte, error)
+	Unmarshal([]byte, *DubboPackage) error
+}
+
+func LoadSerializer(p *DubboPackage) error {
+	// NOTE: default serialID is S_Hessian
+	serialID := p.Header.SerialID
+	if serialID == 0 {
+		serialID = constant.S_Hessian2
+	}
+	serializer, err := GetSerializerById(serialID)
+	if err != nil {
+		panic(err)
+	}
+	p.SetSerializer(serializer.(Serializer))
+	return nil
+}
diff --git a/protocol/dubbo/listener.go b/protocol/dubbo/listener.go
deleted file mode 100644
index 180fd176f9262871d9250a2d9402735ff1b3b731..0000000000000000000000000000000000000000
--- a/protocol/dubbo/listener.go
+++ /dev/null
@@ -1,368 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dubbo
-
-import (
-	"context"
-	"fmt"
-	"net/url"
-	"sync"
-	"sync/atomic"
-	"time"
-)
-
-import (
-	"github.com/apache/dubbo-getty"
-	perrors "github.com/pkg/errors"
-)
-
-import (
-	"github.com/apache/dubbo-go/common"
-	"github.com/apache/dubbo-go/common/constant"
-	"github.com/apache/dubbo-go/common/logger"
-	"github.com/apache/dubbo-go/protocol"
-	"github.com/apache/dubbo-go/protocol/dubbo/hessian2"
-	"github.com/apache/dubbo-go/protocol/invocation"
-)
-
-// todo: writePkg_Timeout will entry *.yml
-const (
-	writePkg_Timeout = 5 * time.Second
-)
-
-var (
-	errTooManySessions = perrors.New("too many sessions")
-)
-
-type rpcSession struct {
-	session getty.Session
-	reqNum  int32
-}
-
-// AddReqNum adds total request number safely
-func (s *rpcSession) AddReqNum(num int32) {
-	atomic.AddInt32(&s.reqNum, num)
-}
-
-// GetReqNum gets total request number safely
-func (s *rpcSession) GetReqNum() int32 {
-	return atomic.LoadInt32(&s.reqNum)
-}
-
-// //////////////////////////////////////////
-// RpcClientHandler
-// //////////////////////////////////////////
-
-// RpcClientHandler is handler of RPC Client
-type RpcClientHandler struct {
-	conn *gettyRPCClient
-}
-
-// NewRpcClientHandler creates RpcClientHandler with @gettyRPCClient
-func NewRpcClientHandler(client *gettyRPCClient) *RpcClientHandler {
-	return &RpcClientHandler{conn: client}
-}
-
-// OnOpen notified when RPC client session opened
-func (h *RpcClientHandler) OnOpen(session getty.Session) error {
-	h.conn.addSession(session)
-	return nil
-}
-
-// OnError notified when RPC client session got any error
-func (h *RpcClientHandler) OnError(session getty.Session, err error) {
-	logger.Warnf("session{%s} got error{%v}, will be closed.", session.Stat(), err)
-	h.conn.removeSession(session)
-}
-
-// OnOpen notified when RPC client session closed
-func (h *RpcClientHandler) OnClose(session getty.Session) {
-	logger.Infof("session{%s} is closing......", session.Stat())
-	h.conn.removeSession(session)
-}
-
-// OnMessage notified when RPC client session got any message in connection
-func (h *RpcClientHandler) OnMessage(session getty.Session, pkg interface{}) {
-	p, ok := pkg.(*DubboPackage)
-	if !ok {
-		logger.Errorf("illegal package")
-		return
-	}
-
-	if p.Header.Type&hessian2.PackageHeartbeat != 0x00 {
-		if p.Header.Type&hessian2.PackageResponse != 0x00 {
-			logger.Debugf("get rpc heartbeat response{header: %#v, body: %#v}", p.Header, p.Body)
-			if p.Err != nil {
-				logger.Errorf("rpc heartbeat response{error: %#v}", p.Err)
-			}
-			h.conn.pool.rpcClient.removePendingResponse(SequenceType(p.Header.ID))
-		} else {
-			logger.Debugf("get rpc heartbeat request{header: %#v, service: %#v, body: %#v}", p.Header, p.Service, p.Body)
-			p.Header.ResponseStatus = hessian2.Response_OK
-			reply(session, p, hessian2.PackageHeartbeat)
-		}
-		return
-	}
-	logger.Debugf("get rpc response{header: %#v, body: %#v}", p.Header, p.Body)
-
-	h.conn.updateSession(session)
-
-	pendingResponse := h.conn.pool.rpcClient.removePendingResponse(SequenceType(p.Header.ID))
-	if pendingResponse == nil {
-		logger.Errorf("failed to get pending response context for response package %s", *p)
-		return
-	}
-
-	if p.Err != nil {
-		pendingResponse.err = p.Err
-	}
-
-	pendingResponse.response.atta = p.Body.(*Response).atta
-
-	if pendingResponse.callback == nil {
-		pendingResponse.done <- struct{}{}
-	} else {
-		pendingResponse.callback(pendingResponse.GetCallResponse())
-	}
-}
-
-// OnCron notified when RPC client session got any message in cron job
-func (h *RpcClientHandler) OnCron(session getty.Session) {
-	clientRpcSession, err := h.conn.getClientRpcSession(session)
-	if err != nil {
-		logger.Errorf("client.getClientSession(session{%s}) = error{%v}",
-			session.Stat(), perrors.WithStack(err))
-		return
-	}
-	if h.conn.pool.rpcClient.conf.sessionTimeout.Nanoseconds() < time.Since(session.GetActive()).Nanoseconds() {
-		logger.Warnf("session{%s} timeout{%s}, reqNum{%d}",
-			session.Stat(), time.Since(session.GetActive()).String(), clientRpcSession.reqNum)
-		h.conn.removeSession(session) // -> h.conn.close() -> h.conn.pool.remove(h.conn)
-		return
-	}
-
-	h.conn.pool.rpcClient.heartbeat(session)
-}
-
-// //////////////////////////////////////////
-// RpcServerHandler
-// //////////////////////////////////////////
-
-// RpcServerHandler is handler of RPC Server
-type RpcServerHandler struct {
-	maxSessionNum  int
-	sessionTimeout time.Duration
-	sessionMap     map[getty.Session]*rpcSession
-	rwlock         sync.RWMutex
-}
-
-// NewRpcServerHandler creates RpcServerHandler with @maxSessionNum and @sessionTimeout
-func NewRpcServerHandler(maxSessionNum int, sessionTimeout time.Duration) *RpcServerHandler {
-	return &RpcServerHandler{
-		maxSessionNum:  maxSessionNum,
-		sessionTimeout: sessionTimeout,
-		sessionMap:     make(map[getty.Session]*rpcSession),
-	}
-}
-
-// OnOpen notified when RPC server session opened
-func (h *RpcServerHandler) OnOpen(session getty.Session) error {
-	var err error
-	h.rwlock.RLock()
-	if h.maxSessionNum <= len(h.sessionMap) {
-		err = errTooManySessions
-	}
-	h.rwlock.RUnlock()
-	if err != nil {
-		return perrors.WithStack(err)
-	}
-
-	logger.Infof("got session:%s", session.Stat())
-	h.rwlock.Lock()
-	h.sessionMap[session] = &rpcSession{session: session}
-	h.rwlock.Unlock()
-	return nil
-}
-
-// OnError notified when RPC server session got any error
-func (h *RpcServerHandler) OnError(session getty.Session, err error) {
-	logger.Warnf("session{%s} got error{%v}, will be closed.", session.Stat(), err)
-	h.rwlock.Lock()
-	delete(h.sessionMap, session)
-	h.rwlock.Unlock()
-}
-
-// OnOpen notified when RPC server session closed
-func (h *RpcServerHandler) OnClose(session getty.Session) {
-	logger.Infof("session{%s} is closing......", session.Stat())
-	h.rwlock.Lock()
-	delete(h.sessionMap, session)
-	h.rwlock.Unlock()
-}
-
-// OnMessage notified when RPC server session got any message in connection
-func (h *RpcServerHandler) OnMessage(session getty.Session, pkg interface{}) {
-	h.rwlock.Lock()
-	if _, ok := h.sessionMap[session]; ok {
-		h.sessionMap[session].reqNum++
-	}
-	h.rwlock.Unlock()
-
-	p, ok := pkg.(*DubboPackage)
-	if !ok {
-		logger.Errorf("illegal package{%#v}", pkg)
-		return
-	}
-	p.Header.ResponseStatus = hessian2.Response_OK
-
-	// heartbeat
-	if p.Header.Type&hessian2.PackageHeartbeat != 0x00 {
-		logger.Debugf("get rpc heartbeat request{header: %#v, service: %#v, body: %#v}", p.Header, p.Service, p.Body)
-		reply(session, p, hessian2.PackageHeartbeat)
-		return
-	}
-
-	twoway := true
-	// not twoway
-	if p.Header.Type&hessian2.PackageRequest_TwoWay == 0x00 {
-		twoway = false
-	}
-
-	defer func() {
-		if e := recover(); e != nil {
-			p.Header.ResponseStatus = hessian2.Response_SERVER_ERROR
-			if err, ok := e.(error); ok {
-				logger.Errorf("OnMessage panic: %+v", perrors.WithStack(err))
-				p.Body = perrors.WithStack(err)
-			} else if err, ok := e.(string); ok {
-				logger.Errorf("OnMessage panic: %+v", perrors.New(err))
-				p.Body = perrors.New(err)
-			} else {
-				logger.Errorf("OnMessage panic: %+v, this is impossible.", e)
-				p.Body = e
-			}
-
-			if !twoway {
-				return
-			}
-			reply(session, p, hessian2.PackageResponse)
-		}
-
-	}()
-
-	u := common.NewURLWithOptions(common.WithPath(p.Service.Path), common.WithParams(url.Values{}),
-		common.WithParamsValue(constant.GROUP_KEY, p.Service.Group),
-		common.WithParamsValue(constant.INTERFACE_KEY, p.Service.Interface),
-		common.WithParamsValue(constant.VERSION_KEY, p.Service.Version))
-	exporter, _ := dubboProtocol.ExporterMap().Load(u.ServiceKey())
-	if exporter == nil {
-		err := fmt.Errorf("don't have this exporter, key: %s", u.ServiceKey())
-		logger.Errorf(err.Error())
-		p.Header.ResponseStatus = hessian2.Response_OK
-		p.Body = err
-		reply(session, p, hessian2.PackageResponse)
-		return
-	}
-	invoker := exporter.(protocol.Exporter).GetInvoker()
-	if invoker != nil {
-		attachments := p.Body.(map[string]interface{})["attachments"].(map[string]interface{})
-		attachments[constant.LOCAL_ADDR] = session.LocalAddr()
-		attachments[constant.REMOTE_ADDR] = session.RemoteAddr()
-
-		args := p.Body.(map[string]interface{})["args"].([]interface{})
-		inv := invocation.NewRPCInvocation(p.Service.Method, args, attachments)
-
-		ctx := rebuildCtx(inv)
-
-		result := invoker.Invoke(ctx, inv)
-		if err := result.Error(); err != nil {
-			p.Header.ResponseStatus = hessian2.Response_OK
-			p.Body = hessian2.NewResponse(nil, err, result.Attachments())
-		} else {
-			res := result.Result()
-			p.Header.ResponseStatus = hessian2.Response_OK
-			p.Body = hessian2.NewResponse(res, nil, result.Attachments())
-		}
-	}
-
-	if !twoway {
-		return
-	}
-	reply(session, p, hessian2.PackageResponse)
-}
-
-// OnCron notified when RPC server session got any message in cron job
-func (h *RpcServerHandler) OnCron(session getty.Session) {
-	var (
-		flag   bool
-		active time.Time
-	)
-
-	h.rwlock.RLock()
-	if _, ok := h.sessionMap[session]; ok {
-		active = session.GetActive()
-		if h.sessionTimeout.Nanoseconds() < time.Since(active).Nanoseconds() {
-			flag = true
-			logger.Warnf("session{%s} timeout{%s}, reqNum{%d}",
-				session.Stat(), time.Since(active).String(), h.sessionMap[session].reqNum)
-		}
-	}
-	h.rwlock.RUnlock()
-
-	if flag {
-		h.rwlock.Lock()
-		delete(h.sessionMap, session)
-		h.rwlock.Unlock()
-		session.Close()
-	}
-}
-
-// rebuildCtx rebuild the context by attachment.
-// Once we decided to transfer more context's key-value, we should change this.
-// now we only support rebuild the tracing context
-func rebuildCtx(inv *invocation.RPCInvocation) context.Context {
-	ctx := context.Background()
-
-	// actually, if user do not use any opentracing framework, the err will not be nil.
-	spanCtx, err := extractTraceCtx(inv)
-	if err == nil {
-		ctx = context.WithValue(ctx, constant.TRACING_REMOTE_SPAN_CTX, spanCtx)
-	}
-	return ctx
-}
-
-func reply(session getty.Session, req *DubboPackage, tp hessian2.PackageType) {
-	resp := &DubboPackage{
-		Header: hessian2.DubboHeader{
-			SerialID:       req.Header.SerialID,
-			Type:           tp,
-			ID:             req.Header.ID,
-			ResponseStatus: req.Header.ResponseStatus,
-		},
-	}
-
-	if req.Header.Type&hessian2.PackageRequest != 0x00 {
-		resp.Body = req.Body
-	} else {
-		resp.Body = nil
-	}
-
-	if err := session.WritePkg(resp, writePkg_Timeout); err != nil {
-		logger.Errorf("WritePkg error: %#v, %#v", perrors.WithStack(err), req.Header)
-	}
-}
diff --git a/protocol/dubbo/readwriter.go b/protocol/dubbo/readwriter.go
deleted file mode 100644
index a7b37aae76c208a8facb87c390ec446e1a26b51a..0000000000000000000000000000000000000000
--- a/protocol/dubbo/readwriter.go
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dubbo
-
-import (
-	"bytes"
-	"reflect"
-)
-
-import (
-	"github.com/apache/dubbo-getty"
-	perrors "github.com/pkg/errors"
-)
-
-import (
-	"github.com/apache/dubbo-go/common"
-	"github.com/apache/dubbo-go/common/constant"
-	"github.com/apache/dubbo-go/common/logger"
-	"github.com/apache/dubbo-go/protocol/dubbo/hessian2"
-)
-
-////////////////////////////////////////////
-// RpcClientPackageHandler
-////////////////////////////////////////////
-
-// RpcClientPackageHandler handle package for client in getty.
-type RpcClientPackageHandler struct {
-	client *Client
-}
-
-// NewRpcClientPackageHandler create a RpcClientPackageHandler.
-func NewRpcClientPackageHandler(client *Client) *RpcClientPackageHandler {
-	return &RpcClientPackageHandler{client: client}
-}
-
-// Read decode @data to DubboPackage.
-func (p *RpcClientPackageHandler) Read(ss getty.Session, data []byte) (interface{}, int, error) {
-	pkg := &DubboPackage{}
-
-	buf := bytes.NewBuffer(data)
-	err := pkg.Unmarshal(buf, p.client)
-	if err != nil {
-		originErr := perrors.Cause(err)
-		if originErr == hessian2.ErrHeaderNotEnough || originErr == hessian2.ErrBodyNotEnough {
-			return nil, 0, nil
-		}
-
-		logger.Errorf("pkg.Unmarshal(ss:%+v, len(@data):%d) = error:%+v", ss, len(data), err)
-
-		return nil, 0, perrors.WithStack(err)
-	}
-
-	if pkg.Header.Type&hessian2.PackageRequest == 0x00 {
-		pkg.Err = pkg.Body.(*hessian2.DubboResponse).Exception
-		pkg.Body = NewResponse(pkg.Body.(*hessian2.DubboResponse).RspObj, pkg.Body.(*hessian2.DubboResponse).Attachments)
-	}
-
-	return pkg, hessian2.HEADER_LENGTH + pkg.Header.BodyLen, nil
-}
-
-// Write encode @pkg.
-func (p *RpcClientPackageHandler) Write(ss getty.Session, pkg interface{}) ([]byte, error) {
-	req, ok := pkg.(*DubboPackage)
-	if !ok {
-		logger.Errorf("illegal pkg:%+v\n", pkg)
-		return nil, perrors.New("invalid rpc request")
-	}
-
-	buf, err := req.Marshal()
-	if err != nil {
-		logger.Warnf("binary.Write(req{%#v}) = err{%#v}", req, perrors.WithStack(err))
-		return nil, perrors.WithStack(err)
-	}
-
-	return buf.Bytes(), nil
-}
-
-////////////////////////////////////////////
-// RpcServerPackageHandler
-////////////////////////////////////////////
-
-var (
-	rpcServerPkgHandler = &RpcServerPackageHandler{}
-)
-
-// RpcServerPackageHandler handle package for server in getty.
-type RpcServerPackageHandler struct{}
-
-// Read decode @data to DubboPackage.
-func (p *RpcServerPackageHandler) Read(ss getty.Session, data []byte) (interface{}, int, error) {
-	pkg := &DubboPackage{
-		Body: make([]interface{}, 7),
-	}
-
-	buf := bytes.NewBuffer(data)
-	err := pkg.Unmarshal(buf)
-	if err != nil {
-		originErr := perrors.Cause(err)
-		if originErr == hessian2.ErrHeaderNotEnough || originErr == hessian2.ErrBodyNotEnough {
-			return nil, 0, nil
-		}
-
-		logger.Errorf("pkg.Unmarshal(ss:%+v, len(@data):%d) = error:%+v", ss, len(data), err)
-
-		return nil, 0, perrors.WithStack(err)
-	}
-
-	if pkg.Header.Type&hessian2.PackageHeartbeat == 0x00 {
-		// convert params of request
-		req := pkg.Body.([]interface{}) // length of body should be 7
-		if len(req) > 0 {
-			var dubboVersion, argsTypes string
-			var args []interface{}
-			var attachments map[string]interface{}
-			if req[0] != nil {
-				dubboVersion = req[0].(string)
-			}
-			if req[1] != nil {
-				pkg.Service.Path = req[1].(string)
-			}
-			if req[2] != nil {
-				pkg.Service.Version = req[2].(string)
-			}
-			if req[3] != nil {
-				pkg.Service.Method = req[3].(string)
-			}
-			if req[4] != nil {
-				argsTypes = req[4].(string)
-			}
-			if req[5] != nil {
-				args = req[5].([]interface{})
-			}
-			if req[6] != nil {
-				attachments = req[6].(map[string]interface{})
-			}
-			if pkg.Service.Path == "" && attachments[constant.PATH_KEY] != nil && len(attachments[constant.PATH_KEY].(string)) > 0 {
-				pkg.Service.Path = attachments[constant.PATH_KEY].(string)
-			}
-			if inter, ok := attachments[constant.INTERFACE_KEY]; ok && inter != nil {
-				pkg.Service.Interface = inter.(string)
-			} else {
-				pkg.Service.Interface = pkg.Service.Path
-			}
-			if attachments[constant.GROUP_KEY] != nil && len(attachments[constant.GROUP_KEY].(string)) > 0 {
-				pkg.Service.Group = attachments[constant.GROUP_KEY].(string)
-			}
-			pkg.Body = map[string]interface{}{
-				"dubboVersion": dubboVersion,
-				"argsTypes":    argsTypes,
-				"args":         args,
-				"service":      common.ServiceMap.GetService(DUBBO, pkg.Service.Path), // path as a key
-				"attachments":  attachments,
-			}
-		}
-	}
-
-	return pkg, hessian2.HEADER_LENGTH + pkg.Header.BodyLen, nil
-}
-
-// Write encode @pkg.
-func (p *RpcServerPackageHandler) Write(ss getty.Session, pkg interface{}) ([]byte, error) {
-	res, ok := pkg.(*DubboPackage)
-	if !ok {
-		logger.Errorf("illegal pkg:%+v\n, it is %+v", pkg, reflect.TypeOf(pkg))
-		return nil, perrors.New("invalid rpc response")
-	}
-
-	buf, err := res.Marshal()
-	if err != nil {
-		logger.Warnf("binary.Write(res{%#v}) = err{%#v}", res, perrors.WithStack(err))
-		return nil, perrors.WithStack(err)
-	}
-
-	return buf.Bytes(), nil
-}
diff --git a/protocol/invocation/rpcinvocation.go b/protocol/invocation/rpcinvocation.go
index 35d12965e811fb9ac6c312a83615c51204f9b993..4e806324bf7b236d80a932a92898ba117fb1638d 100644
--- a/protocol/invocation/rpcinvocation.go
+++ b/protocol/invocation/rpcinvocation.go
@@ -23,6 +23,8 @@ import (
 )
 
 import (
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/common/constant"
 	"github.com/apache/dubbo-go/protocol"
 )
 
@@ -186,6 +188,11 @@ func (r *RPCInvocation) SetCallBack(c interface{}) {
 	r.callBack = c
 }
 
+func (r *RPCInvocation) ServiceKey() string {
+	return common.ServiceKey(r.AttachmentsByKey(constant.INTERFACE_KEY, ""),
+		r.AttachmentsByKey(constant.GROUP_KEY, ""), r.AttachmentsByKey(constant.VERSION_KEY, ""))
+}
+
 // /////////////////////////
 // option
 // /////////////////////////
diff --git a/protocol/jsonrpc/http_test.go b/protocol/jsonrpc/http_test.go
index 576591940dd3021e7bbd9d2eda0ac5498391a1f7..4a9645e828a3b092c938c62091fb400b05605b67 100644
--- a/protocol/jsonrpc/http_test.go
+++ b/protocol/jsonrpc/http_test.go
@@ -75,7 +75,7 @@ func TestHTTPClientCall(t *testing.T) {
 
 	// call GetUser
 	ctx := context.WithValue(context.Background(), constant.DUBBOGO_CTX_KEY, map[string]string{
-		"X-Proxy-Id": "dubbogo",
+		"X-Proxy-ID": "dubbogo",
 		"X-Services": url.Path,
 		"X-Method":   "GetUser",
 	})
@@ -89,7 +89,7 @@ func TestHTTPClientCall(t *testing.T) {
 
 	// call GetUser0
 	ctx = context.WithValue(context.Background(), constant.DUBBOGO_CTX_KEY, map[string]string{
-		"X-Proxy-Id": "dubbogo",
+		"X-Proxy-ID": "dubbogo",
 		"X-Services": url.Path,
 		"X-Method":   "GetUser0",
 	})
@@ -102,7 +102,7 @@ func TestHTTPClientCall(t *testing.T) {
 
 	// call GetUser1
 	ctx = context.WithValue(context.Background(), constant.DUBBOGO_CTX_KEY, map[string]string{
-		"X-Proxy-Id": "dubbogo",
+		"X-Proxy-ID": "dubbogo",
 		"X-Services": url.Path,
 		"X-Method":   "GetUser1",
 	})
@@ -114,7 +114,7 @@ func TestHTTPClientCall(t *testing.T) {
 
 	// call GetUser2
 	ctx = context.WithValue(context.Background(), constant.DUBBOGO_CTX_KEY, map[string]string{
-		"X-Proxy-Id": "dubbogo",
+		"X-Proxy-ID": "dubbogo",
 		"X-Services": url.Path,
 		"X-Method":   "GetUser2",
 	})
@@ -126,7 +126,7 @@ func TestHTTPClientCall(t *testing.T) {
 
 	// call GetUser3
 	ctx = context.WithValue(context.Background(), constant.DUBBOGO_CTX_KEY, map[string]string{
-		"X-Proxy-Id": "dubbogo",
+		"X-Proxy-ID": "dubbogo",
 		"X-Services": url.Path,
 		"X-Method":   "GetUser3",
 	})
@@ -138,7 +138,7 @@ func TestHTTPClientCall(t *testing.T) {
 
 	// call GetUser4
 	ctx = context.WithValue(context.Background(), constant.DUBBOGO_CTX_KEY, map[string]string{
-		"X-Proxy-Id": "dubbogo",
+		"X-Proxy-ID": "dubbogo",
 		"X-Services": url.Path,
 		"X-Method":   "GetUser4",
 	})
@@ -149,7 +149,7 @@ func TestHTTPClientCall(t *testing.T) {
 	assert.Equal(t, &User{Id: "", Name: ""}, reply)
 
 	ctx = context.WithValue(context.Background(), constant.DUBBOGO_CTX_KEY, map[string]string{
-		"X-Proxy-Id": "dubbogo",
+		"X-Proxy-ID": "dubbogo",
 		"X-Services": url.Path,
 		"X-Method":   "GetUser4",
 	})
diff --git a/remoting/codec.go b/remoting/codec.go
new file mode 100644
index 0000000000000000000000000000000000000000..607d1643cc1967e93bf5288d8d4c0788c73a735e
--- /dev/null
+++ b/remoting/codec.go
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package remoting
+
+import (
+	"bytes"
+)
+
+// codec for exchangeClient
+type Codec interface {
+	EncodeRequest(request *Request) (*bytes.Buffer, error)
+	EncodeResponse(response *Response) (*bytes.Buffer, error)
+	Decode(data []byte) (DecodeResult, int, error)
+}
+
+type DecodeResult struct {
+	IsRequest bool
+	Result    interface{}
+}
+
+var (
+	codec = make(map[string]Codec, 2)
+)
+
+func RegistryCodec(protocol string, codecTmp Codec) {
+	codec[protocol] = codecTmp
+}
+
+func GetCodec(protocol string) Codec {
+	return codec[protocol]
+}
diff --git a/remoting/exchange.go b/remoting/exchange.go
new file mode 100644
index 0000000000000000000000000000000000000000..848d9cbbcc23b0f565c45b646cf443be3f811efc
--- /dev/null
+++ b/remoting/exchange.go
@@ -0,0 +1,144 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package remoting
+
+import (
+	"time"
+)
+
+import (
+	"go.uber.org/atomic"
+)
+
+import (
+	"github.com/apache/dubbo-go/common"
+)
+
+var (
+	// generate request ID for global use
+	sequence atomic.Int64
+)
+
+func init() {
+	// init request ID
+	sequence.Store(0)
+}
+
+func SequenceId() int64 {
+	// increse 2 for every request as the same before.
+	// We expect that the request from client to server, the requestId is even; but from server to client, the requestId is odd.
+	return sequence.Add(2)
+}
+
+// this is request for transport layer
+type Request struct {
+	ID int64
+	// protocol version
+	Version string
+	// serial ID (ignore)
+	SerialID byte
+	// Data
+	Data   interface{}
+	TwoWay bool
+	Event  bool
+}
+
+// NewRequest aims to create Request.
+// The ID is auto increase.
+func NewRequest(version string) *Request {
+	return &Request{
+		ID:      SequenceId(),
+		Version: version,
+	}
+}
+
+// this is response for transport layer
+type Response struct {
+	ID       int64
+	Version  string
+	SerialID byte
+	Status   uint8
+	Event    bool
+	Error    error
+	Result   interface{}
+}
+
+// NewResponse create to a new Response.
+func NewResponse(id int64, version string) *Response {
+	return &Response{
+		ID:      id,
+		Version: version,
+	}
+}
+
+// the response is heartbeat
+func (response *Response) IsHeartbeat() bool {
+	return response.Event && response.Result == nil
+}
+
+type Options struct {
+	// connect timeout
+	ConnectTimeout time.Duration
+}
+
+//AsyncCallbackResponse async response for dubbo
+type AsyncCallbackResponse struct {
+	common.CallbackResponse
+	Opts      Options
+	Cause     error
+	Start     time.Time // invoke(call) start time == write start time
+	ReadStart time.Time // read start time, write duration = ReadStart - Start
+	Reply     interface{}
+}
+
+// the client sends requst to server, there is one pendingResponse at client side to wait the response from server
+type PendingResponse struct {
+	seq       int64
+	Err       error
+	start     time.Time
+	ReadStart time.Time
+	Callback  common.AsyncCallback
+	response  *Response
+	Reply     interface{}
+	Done      chan struct{}
+}
+
+// NewPendingResponse aims to create PendingResponse.
+// Id is always from ID of Request
+func NewPendingResponse(id int64) *PendingResponse {
+	return &PendingResponse{
+		seq:      id,
+		start:    time.Now(),
+		response: &Response{},
+		Done:     make(chan struct{}),
+	}
+}
+
+func (r *PendingResponse) SetResponse(response *Response) {
+	r.response = response
+}
+
+// GetCallResponse is used for callback of async.
+// It is will return AsyncCallbackResponse.
+func (r PendingResponse) GetCallResponse() common.CallbackResponse {
+	return AsyncCallbackResponse{
+		Cause:     r.Err,
+		Start:     r.start,
+		ReadStart: r.ReadStart,
+		Reply:     r.response,
+	}
+}
diff --git a/remoting/exchange_client.go b/remoting/exchange_client.go
new file mode 100644
index 0000000000000000000000000000000000000000..efcfca55868e7042b685adb5fb2452dd2d3a65c0
--- /dev/null
+++ b/remoting/exchange_client.go
@@ -0,0 +1,227 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package remoting
+
+import (
+	"errors"
+	"sync"
+	"time"
+)
+
+import (
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/common/logger"
+	"github.com/apache/dubbo-go/protocol"
+)
+
+var (
+	// store requestID and response
+	pendingResponses = new(sync.Map)
+)
+
+type SequenceType int64
+
+// It is interface of client for network communication.
+// If you use getty as network communication, you should define GettyClient that implements this interface.
+type Client interface {
+	SetExchangeClient(client *ExchangeClient)
+	// responseHandler is used to deal with msg
+	SetResponseHandler(responseHandler ResponseHandler)
+	// connect url
+	Connect(url common.URL) error
+	// close
+	Close()
+	// send request to server.
+	Request(request *Request, timeout time.Duration, response *PendingResponse) error
+}
+
+// This is abstraction level. it is like facade.
+type ExchangeClient struct {
+	// connect server timeout
+	ConnectTimeout time.Duration
+	// to dial server address. The format: ip:port
+	address string
+	// the client that will deal with the transport. It is interface, and it will use gettyClient by default.
+	client Client
+	// the tag for init.
+	init bool
+}
+
+// handle the message from server
+type ResponseHandler interface {
+	Handler(response *Response)
+}
+
+// create ExchangeClient
+func NewExchangeClient(url common.URL, client Client, connectTimeout time.Duration, lazyInit bool) *ExchangeClient {
+	exchangeClient := &ExchangeClient{
+		ConnectTimeout: connectTimeout,
+		address:        url.Location,
+		client:         client,
+	}
+	client.SetExchangeClient(exchangeClient)
+	if !lazyInit {
+		if err := exchangeClient.doInit(url); err != nil {
+			return nil
+		}
+	}
+
+	client.SetResponseHandler(exchangeClient)
+	return exchangeClient
+}
+
+func (cl *ExchangeClient) doInit(url common.URL) error {
+	if cl.init {
+		return nil
+	}
+	if cl.client.Connect(url) != nil {
+		//retry for a while
+		time.Sleep(100 * time.Millisecond)
+		if cl.client.Connect(url) != nil {
+			logger.Errorf("Failed to connect server %+v " + url.Location)
+			return errors.New("Failed to connect server " + url.Location)
+		}
+	}
+	//FIXME atomic operation
+	cl.init = true
+	return nil
+}
+
+// two way request
+func (client *ExchangeClient) Request(invocation *protocol.Invocation, url common.URL, timeout time.Duration,
+	result *protocol.RPCResult) error {
+	if er := client.doInit(url); er != nil {
+		return er
+	}
+	request := NewRequest("2.0.2")
+	request.Data = invocation
+	request.Event = false
+	request.TwoWay = true
+
+	rsp := NewPendingResponse(request.ID)
+	rsp.response = NewResponse(request.ID, "2.0.2")
+	rsp.Reply = (*invocation).Reply()
+	AddPendingResponse(rsp)
+
+	err := client.client.Request(request, timeout, rsp)
+	// request error
+	if err != nil {
+		result.Err = err
+		return err
+	}
+	if resultTmp, ok := rsp.response.Result.(*protocol.RPCResult); ok {
+		result.Rest = resultTmp.Rest
+		result.Attrs = resultTmp.Attrs
+		result.Err = resultTmp.Err
+	}
+	return nil
+}
+
+// async two way request
+func (client *ExchangeClient) AsyncRequest(invocation *protocol.Invocation, url common.URL, timeout time.Duration,
+	callback common.AsyncCallback, result *protocol.RPCResult) error {
+	if er := client.doInit(url); er != nil {
+		return er
+	}
+	request := NewRequest("2.0.2")
+	request.Data = invocation
+	request.Event = false
+	request.TwoWay = true
+
+	rsp := NewPendingResponse(request.ID)
+	rsp.response = NewResponse(request.ID, "2.0.2")
+	rsp.Callback = callback
+	rsp.Reply = (*invocation).Reply()
+	AddPendingResponse(rsp)
+
+	err := client.client.Request(request, timeout, rsp)
+	if err != nil {
+		result.Err = err
+		return err
+	}
+	result.Rest = rsp.response
+	return nil
+}
+
+// oneway request
+func (client *ExchangeClient) Send(invocation *protocol.Invocation, url common.URL, timeout time.Duration) error {
+	if er := client.doInit(url); er != nil {
+		return er
+	}
+	request := NewRequest("2.0.2")
+	request.Data = invocation
+	request.Event = false
+	request.TwoWay = false
+
+	rsp := NewPendingResponse(request.ID)
+	rsp.response = NewResponse(request.ID, "2.0.2")
+
+	err := client.client.Request(request, timeout, rsp)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+// close client
+func (client *ExchangeClient) Close() {
+	client.client.Close()
+}
+
+// handle the response from server
+func (client *ExchangeClient) Handler(response *Response) {
+
+	pendingResponse := removePendingResponse(SequenceType(response.ID))
+	if pendingResponse == nil {
+		logger.Errorf("failed to get pending response context for response package %s", *response)
+		return
+	}
+
+	pendingResponse.response = response
+
+	if pendingResponse.Callback == nil {
+		pendingResponse.Err = pendingResponse.response.Error
+		pendingResponse.Done <- struct{}{}
+	} else {
+		pendingResponse.Callback(pendingResponse.GetCallResponse())
+	}
+}
+
+// store response into map
+func AddPendingResponse(pr *PendingResponse) {
+	pendingResponses.Store(SequenceType(pr.seq), pr)
+}
+
+// get and remove response
+func removePendingResponse(seq SequenceType) *PendingResponse {
+	if pendingResponses == nil {
+		return nil
+	}
+	if presp, ok := pendingResponses.Load(seq); ok {
+		pendingResponses.Delete(seq)
+		return presp.(*PendingResponse)
+	}
+	return nil
+}
+
+// get response
+func GetPendingResponse(seq SequenceType) *PendingResponse {
+	if presp, ok := pendingResponses.Load(seq); ok {
+		return presp.(*PendingResponse)
+	}
+	return nil
+}
diff --git a/remoting/exchange_server.go b/remoting/exchange_server.go
new file mode 100644
index 0000000000000000000000000000000000000000..a31e994d7411df2da94c210a1b3d4b24aae9fcba
--- /dev/null
+++ b/remoting/exchange_server.go
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package remoting
+
+import (
+	"github.com/apache/dubbo-go/common"
+)
+
+// It is interface of server for network communication.
+// If you use getty as network communication, you should define GettyServer that implements this interface.
+type Server interface {
+	//invoke once for connection
+	Start()
+	//it is for destroy
+	Stop()
+}
+
+// This is abstraction level. it is like facade.
+type ExchangeServer struct {
+	Server Server
+	Url    common.URL
+}
+
+// Create ExchangeServer
+func NewExchangeServer(url common.URL, server Server) *ExchangeServer {
+	exchangServer := &ExchangeServer{
+		Server: server,
+		Url:    url,
+	}
+	return exchangServer
+}
+
+// start server
+func (server *ExchangeServer) Start() {
+	server.Server.Start()
+}
+
+// stop server
+func (server *ExchangeServer) Stop() {
+	server.Server.Stop()
+}
diff --git a/protocol/dubbo/config.go b/remoting/getty/config.go
similarity index 96%
rename from protocol/dubbo/config.go
rename to remoting/getty/config.go
index b47ec1cc3422dcbcac921f08888c7a777e72e246..dcf59d0821b90c052f736d1976400a1efe7d3445 100644
--- a/protocol/dubbo/config.go
+++ b/remoting/getty/config.go
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package dubbo
+package getty
 
 import (
 	"time"
@@ -30,7 +30,7 @@ import (
 )
 
 type (
-	// GettySessionParam is session configuration for getty.
+	// GettySessionParam is session configuration for getty
 	GettySessionParam struct {
 		CompressEncoding bool   `default:"false" yaml:"compress_encoding" json:"compress_encoding,omitempty"`
 		TcpNoDelay       bool   `default:"true" yaml:"tcp_no_delay" json:"tcp_no_delay,omitempty"`
@@ -52,6 +52,8 @@ type (
 
 	// ServerConfig holds supported types by the multiconfig package
 	ServerConfig struct {
+		SSLEnabled bool
+
 		// session
 		SessionTimeout string `default:"60s" yaml:"session_timeout" json:"session_timeout,omitempty"`
 		sessionTimeout time.Duration
@@ -95,7 +97,7 @@ type (
 	}
 )
 
-// GetDefaultClientConfig gets client default configuration.
+// GetDefaultClientConfig gets client default configuration
 func GetDefaultClientConfig() ClientConfig {
 	return ClientConfig{
 		ReconnectInterval: 0,
@@ -123,7 +125,7 @@ func GetDefaultClientConfig() ClientConfig {
 		}}
 }
 
-// GetDefaultServerConfig gets server default configuration.
+// GetDefaultServerConfig gets server default configuration
 func GetDefaultServerConfig() ServerConfig {
 	return ServerConfig{
 		SessionTimeout: "180s",
@@ -148,7 +150,7 @@ func GetDefaultServerConfig() ServerConfig {
 	}
 }
 
-// CheckValidity confirm getty sessian params.
+// CheckValidity confirm getty sessian params
 func (c *GettySessionParam) CheckValidity() error {
 	var err error
 
@@ -193,7 +195,7 @@ func (c *ClientConfig) CheckValidity() error {
 	return perrors.WithStack(c.GettySessionParam.CheckValidity())
 }
 
-// CheckValidity confirm server params.
+// CheckValidity confirm server params
 func (c *ServerConfig) CheckValidity() error {
 	var err error
 
diff --git a/remoting/getty/dubbo_codec_for_test.go b/remoting/getty/dubbo_codec_for_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..b91fc9f4ccf69299870f9daf3707521d913cd4c0
--- /dev/null
+++ b/remoting/getty/dubbo_codec_for_test.go
@@ -0,0 +1,276 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package getty
+
+// copy from dubbo/dubbo_codec.go .
+// it is used to unit test.
+import (
+	"bytes"
+	"strconv"
+	"time"
+)
+
+import (
+	hessian "github.com/apache/dubbo-go-hessian2"
+	perrors "github.com/pkg/errors"
+)
+
+import (
+	"github.com/apache/dubbo-go/common/constant"
+	"github.com/apache/dubbo-go/protocol"
+	"github.com/apache/dubbo-go/protocol/dubbo/impl"
+	"github.com/apache/dubbo-go/protocol/invocation"
+	"github.com/apache/dubbo-go/remoting"
+)
+
+func init() {
+	codec := &DubboTestCodec{}
+	remoting.RegistryCodec("dubbo", codec)
+}
+
+type DubboTestCodec struct {
+}
+
+// encode request for transport
+func (c *DubboTestCodec) EncodeRequest(request *remoting.Request) (*bytes.Buffer, error) {
+	if request.Event {
+		return c.encodeHeartbeartReqeust(request)
+	}
+
+	invoc, ok := request.Data.(*invocation.RPCInvocation)
+	if !ok {
+		return nil, perrors.Errorf("encode request failed for parameter type :%+v", request)
+	}
+	invocation := *invoc
+
+	svc := impl.Service{}
+	svc.Path = invocation.AttachmentsByKey(constant.PATH_KEY, "")
+	svc.Interface = invocation.AttachmentsByKey(constant.INTERFACE_KEY, "")
+	svc.Version = invocation.AttachmentsByKey(constant.VERSION_KEY, "")
+	svc.Group = invocation.AttachmentsByKey(constant.GROUP_KEY, "")
+	svc.Method = invocation.MethodName()
+	timeout, err := strconv.Atoi(invocation.AttachmentsByKey(constant.TIMEOUT_KEY, strconv.Itoa(constant.DEFAULT_REMOTING_TIMEOUT)))
+	if err != nil {
+		// it will be wrapped in readwrite.Write .
+		return nil, perrors.WithStack(err)
+	}
+	svc.Timeout = time.Duration(timeout)
+
+	header := impl.DubboHeader{}
+	serialization := invocation.AttachmentsByKey(constant.SERIALIZATION_KEY, constant.HESSIAN2_SERIALIZATION)
+	if serialization == constant.PROTOBUF_SERIALIZATION {
+		header.SerialID = constant.S_Proto
+	} else {
+		header.SerialID = constant.S_Hessian2
+	}
+	header.ID = request.ID
+	if request.TwoWay {
+		header.Type = impl.PackageRequest_TwoWay
+	} else {
+		header.Type = impl.PackageRequest
+	}
+
+	pkg := &impl.DubboPackage{
+		Header:  header,
+		Service: svc,
+		Body:    impl.NewRequestPayload(invocation.Arguments(), invocation.Attachments()),
+		Err:     nil,
+		Codec:   impl.NewDubboCodec(nil),
+	}
+
+	if err := impl.LoadSerializer(pkg); err != nil {
+		return nil, perrors.WithStack(err)
+	}
+
+	return pkg.Marshal()
+}
+
+// encode heartbeart request
+func (c *DubboTestCodec) encodeHeartbeartReqeust(request *remoting.Request) (*bytes.Buffer, error) {
+	header := impl.DubboHeader{
+		Type:     impl.PackageHeartbeat,
+		SerialID: constant.S_Hessian2,
+		ID:       request.ID,
+	}
+
+	pkg := &impl.DubboPackage{
+		Header:  header,
+		Service: impl.Service{},
+		Body:    impl.NewRequestPayload([]interface{}{}, nil),
+		Err:     nil,
+		Codec:   impl.NewDubboCodec(nil),
+	}
+
+	if err := impl.LoadSerializer(pkg); err != nil {
+		return nil, err
+	}
+	return pkg.Marshal()
+}
+
+// encode response
+func (c *DubboTestCodec) EncodeResponse(response *remoting.Response) (*bytes.Buffer, error) {
+	var ptype = impl.PackageResponse
+	if response.IsHeartbeat() {
+		ptype = impl.PackageHeartbeat
+	}
+	resp := &impl.DubboPackage{
+		Header: impl.DubboHeader{
+			SerialID:       response.SerialID,
+			Type:           ptype,
+			ID:             response.ID,
+			ResponseStatus: response.Status,
+		},
+	}
+	if !response.IsHeartbeat() {
+		resp.Body = &impl.ResponsePayload{
+			RspObj:      response.Result.(protocol.RPCResult).Rest,
+			Exception:   response.Result.(protocol.RPCResult).Err,
+			Attachments: response.Result.(protocol.RPCResult).Attrs,
+		}
+	}
+
+	codec := impl.NewDubboCodec(nil)
+
+	pkg, err := codec.Encode(*resp)
+	if err != nil {
+		return nil, perrors.WithStack(err)
+	}
+
+	return bytes.NewBuffer(pkg), nil
+}
+
+// Decode data, including request and response.
+func (c *DubboTestCodec) Decode(data []byte) (remoting.DecodeResult, int, error) {
+	if c.isRequest(data) {
+		req, len, err := c.decodeRequest(data)
+		if err != nil {
+			return remoting.DecodeResult{}, len, perrors.WithStack(err)
+		}
+		return remoting.DecodeResult{IsRequest: true, Result: req}, len, perrors.WithStack(err)
+	} else {
+		resp, len, err := c.decodeResponse(data)
+		if err != nil {
+			return remoting.DecodeResult{}, len, perrors.WithStack(err)
+		}
+		return remoting.DecodeResult{IsRequest: false, Result: resp}, len, perrors.WithStack(err)
+	}
+}
+
+func (c *DubboTestCodec) isRequest(data []byte) bool {
+	if data[2]&byte(0x80) == 0x00 {
+		return false
+	}
+	return true
+}
+
+// decode request
+func (c *DubboTestCodec) decodeRequest(data []byte) (*remoting.Request, int, error) {
+	var request *remoting.Request = nil
+	buf := bytes.NewBuffer(data)
+	pkg := impl.NewDubboPackage(buf)
+	pkg.SetBody(make([]interface{}, 7))
+	err := pkg.Unmarshal()
+	if err != nil {
+		originErr := perrors.Cause(err)
+		if originErr == hessian.ErrHeaderNotEnough || originErr == hessian.ErrBodyNotEnough {
+			//FIXME
+			return nil, 0, originErr
+		}
+		return request, 0, perrors.WithStack(err)
+	}
+	request = &remoting.Request{
+		ID:       pkg.Header.ID,
+		SerialID: pkg.Header.SerialID,
+		TwoWay:   pkg.Header.Type&impl.PackageRequest_TwoWay != 0x00,
+		Event:    pkg.Header.Type&impl.PackageHeartbeat != 0x00,
+	}
+	if (pkg.Header.Type & impl.PackageHeartbeat) == 0x00 {
+		// convert params of request
+		req := pkg.Body.(map[string]interface{})
+
+		//invocation := request.Data.(*invocation.RPCInvocation)
+		var methodName string
+		var args []interface{}
+		attachments := make(map[string]interface{})
+		if req[impl.DubboVersionKey] != nil {
+			//dubbo version
+			request.Version = req[impl.DubboVersionKey].(string)
+		}
+		//path
+		attachments[constant.PATH_KEY] = pkg.Service.Path
+		//version
+		attachments[constant.VERSION_KEY] = pkg.Service.Version
+		//method
+		methodName = pkg.Service.Method
+		args = req[impl.ArgsKey].([]interface{})
+		attachments = req[impl.AttachmentsKey].(map[string]interface{})
+		invoc := invocation.NewRPCInvocationWithOptions(invocation.WithAttachments(attachments),
+			invocation.WithArguments(args), invocation.WithMethodName(methodName))
+		request.Data = invoc
+
+	}
+	return request, hessian.HEADER_LENGTH + pkg.Header.BodyLen, nil
+}
+
+// decode response
+func (c *DubboTestCodec) decodeResponse(data []byte) (*remoting.Response, int, error) {
+	buf := bytes.NewBuffer(data)
+	pkg := impl.NewDubboPackage(buf)
+	response := &remoting.Response{}
+	err := pkg.Unmarshal()
+	if err != nil {
+		originErr := perrors.Cause(err)
+		// if the data is very big, so the receive need much times.
+		if originErr == hessian.ErrHeaderNotEnough || originErr == hessian.ErrBodyNotEnough {
+			return nil, 0, originErr
+		}
+		return nil, 0, perrors.WithStack(err)
+	}
+	response = &remoting.Response{
+		ID: pkg.Header.ID,
+		//Version:  pkg.Header.,
+		SerialID: pkg.Header.SerialID,
+		Status:   pkg.Header.ResponseStatus,
+		Event:    (pkg.Header.Type & impl.PackageHeartbeat) != 0,
+	}
+	var error error
+	if pkg.Header.Type&impl.PackageHeartbeat != 0x00 {
+		if pkg.Header.Type&impl.PackageResponse != 0x00 {
+			if pkg.Err != nil {
+				error = pkg.Err
+			}
+		} else {
+			response.Status = hessian.Response_OK
+			//reply(session, p, hessian.PackageHeartbeat)
+		}
+		return response, hessian.HEADER_LENGTH + pkg.Header.BodyLen, error
+	}
+	rpcResult := &protocol.RPCResult{}
+	response.Result = rpcResult
+	if pkg.Header.Type&impl.PackageRequest == 0x00 {
+		if pkg.Err != nil {
+			rpcResult.Err = pkg.Err
+		} else if pkg.Body.(*impl.ResponsePayload).Exception != nil {
+			rpcResult.Err = pkg.Body.(*impl.ResponsePayload).Exception
+			response.Error = rpcResult.Err
+		}
+		rpcResult.Attrs = pkg.Body.(*impl.ResponsePayload).Attachments
+		rpcResult.Rest = pkg.Body.(*impl.ResponsePayload).RspObj
+	}
+
+	return response, hessian.HEADER_LENGTH + pkg.Header.BodyLen, nil
+}
diff --git a/remoting/getty/getty_client.go b/remoting/getty/getty_client.go
new file mode 100644
index 0000000000000000000000000000000000000000..6af3971f5c1f9ff5b0fafbc00ae2ba3f44eb34b5
--- /dev/null
+++ b/remoting/getty/getty_client.go
@@ -0,0 +1,227 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package getty
+
+import (
+	"math/rand"
+	"time"
+)
+
+import (
+	"github.com/apache/dubbo-getty"
+	gxsync "github.com/dubbogo/gost/sync"
+	perrors "github.com/pkg/errors"
+	"gopkg.in/yaml.v2"
+)
+
+import (
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/common/constant"
+	"github.com/apache/dubbo-go/common/logger"
+	"github.com/apache/dubbo-go/config"
+	"github.com/apache/dubbo-go/remoting"
+)
+
+var (
+	errInvalidCodecType  = perrors.New("illegal CodecType")
+	errInvalidAddress    = perrors.New("remote address invalid or empty")
+	errSessionNotExist   = perrors.New("session not exist")
+	errClientClosed      = perrors.New("client closed")
+	errClientReadTimeout = perrors.New("client read timeout")
+
+	clientConf   *ClientConfig
+	clientGrpool *gxsync.TaskPool
+)
+
+// it is init client for single protocol.
+func initClient(protocol string) {
+	if protocol == "" {
+		return
+	}
+
+	// load clientconfig from consumer_config
+	// default use dubbo
+	consumerConfig := config.GetConsumerConfig()
+	if consumerConfig.ApplicationConfig == nil {
+		return
+	}
+	protocolConf := config.GetConsumerConfig().ProtocolConf
+	defaultClientConfig := GetDefaultClientConfig()
+	if protocolConf == nil {
+		logger.Info("protocol_conf default use dubbo config")
+	} else {
+		dubboConf := protocolConf.(map[interface{}]interface{})[protocol]
+		if dubboConf == nil {
+			logger.Warnf("dubboConf is nil")
+			return
+		}
+		dubboConfByte, err := yaml.Marshal(dubboConf)
+		if err != nil {
+			panic(err)
+		}
+		err = yaml.Unmarshal(dubboConfByte, &defaultClientConfig)
+		if err != nil {
+			panic(err)
+		}
+	}
+	clientConf = &defaultClientConfig
+	if err := clientConf.CheckValidity(); err != nil {
+		logger.Warnf("[CheckValidity] error: %v", err)
+		return
+	}
+	setClientGrpool()
+
+	rand.Seed(time.Now().UnixNano())
+}
+
+// Config ClientConf
+func SetClientConf(c ClientConfig) {
+	clientConf = &c
+	err := clientConf.CheckValidity()
+	if err != nil {
+		logger.Warnf("[ClientConfig CheckValidity] error: %v", err)
+		return
+	}
+	setClientGrpool()
+}
+
+func setClientGrpool() {
+	if clientConf.GrPoolSize > 1 {
+		clientGrpool = gxsync.NewTaskPool(gxsync.WithTaskPoolTaskPoolSize(clientConf.GrPoolSize), gxsync.WithTaskPoolTaskQueueLength(clientConf.QueueLen),
+			gxsync.WithTaskPoolTaskQueueNumber(clientConf.QueueNumber))
+	}
+}
+
+// Options : param config
+type Options struct {
+	// connect timeout
+	// remove request timeout, it will be calulate for every request
+	ConnectTimeout time.Duration
+	// request timeout
+	RequestTimeout time.Duration
+}
+
+// Client : some configuration for network communication.
+type Client struct {
+	addr            string
+	opts            Options
+	conf            ClientConfig
+	pool            *gettyRPCClientPool
+	codec           remoting.Codec
+	responseHandler remoting.ResponseHandler
+	ExchangeClient  *remoting.ExchangeClient
+}
+
+// create client
+func NewClient(opt Options) *Client {
+	switch {
+	case opt.ConnectTimeout == 0:
+		opt.ConnectTimeout = 3 * time.Second
+		fallthrough
+	case opt.RequestTimeout == 0:
+		opt.RequestTimeout = 3 * time.Second
+	}
+
+	c := &Client{
+		opts: opt,
+	}
+	return c
+}
+
+func (c *Client) SetExchangeClient(client *remoting.ExchangeClient) {
+	c.ExchangeClient = client
+}
+func (c *Client) SetResponseHandler(responseHandler remoting.ResponseHandler) {
+	c.responseHandler = responseHandler
+}
+
+// init client and try to connection.
+func (c *Client) Connect(url common.URL) error {
+	initClient(url.Protocol)
+	c.conf = *clientConf
+	// new client
+	c.pool = newGettyRPCClientConnPool(c, clientConf.PoolSize, time.Duration(int(time.Second)*clientConf.PoolTTL))
+	c.pool.sslEnabled = url.GetParamBool(constant.SSL_ENABLED_KEY, false)
+
+	// codec
+	c.codec = remoting.GetCodec(url.Protocol)
+	c.addr = url.Location
+	_, _, err := c.selectSession(c.addr)
+	if err != nil {
+		logger.Errorf("try to connect server %v failed for : %v", url.Location, err)
+	}
+	return err
+}
+
+// close network connection
+func (c *Client) Close() {
+	if c.pool != nil {
+		c.pool.close()
+	}
+	c.pool = nil
+}
+
+// send request
+func (c *Client) Request(request *remoting.Request, timeout time.Duration, response *remoting.PendingResponse) error {
+	_, session, err := c.selectSession(c.addr)
+	if err != nil {
+		return perrors.WithStack(err)
+	}
+	if session == nil {
+		return errSessionNotExist
+	}
+
+	if err = c.transfer(session, request, timeout); err != nil {
+		return perrors.WithStack(err)
+	}
+
+	if !request.TwoWay || response.Callback != nil {
+		return nil
+	}
+
+	select {
+	case <-getty.GetTimeWheel().After(timeout):
+		return perrors.WithStack(errClientReadTimeout)
+	case <-response.Done:
+		err = response.Err
+	}
+
+	return perrors.WithStack(err)
+}
+
+func (c *Client) selectSession(addr string) (*gettyRPCClient, getty.Session, error) {
+	rpcClient, err := c.pool.getGettyRpcClient(addr)
+	if err != nil {
+		return nil, nil, perrors.WithStack(err)
+	}
+	return rpcClient, rpcClient.selectSession(), nil
+}
+
+func (c *Client) heartbeat(session getty.Session) error {
+	req := remoting.NewRequest("2.0.2")
+	req.TwoWay = true
+	req.Event = true
+	resp := remoting.NewPendingResponse(req.ID)
+	remoting.AddPendingResponse(resp)
+	return c.transfer(session, req, 3*time.Second)
+}
+
+func (c *Client) transfer(session getty.Session, request *remoting.Request, timeout time.Duration) error {
+	err := session.WritePkg(request, timeout)
+	return perrors.WithStack(err)
+}
diff --git a/remoting/getty/getty_client_test.go b/remoting/getty/getty_client_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..41ca3108a8a8d578c6aaaf374dc9f5fa6300a8b0
--- /dev/null
+++ b/remoting/getty/getty_client_test.go
@@ -0,0 +1,492 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package getty
+
+import (
+	"bytes"
+	"context"
+	"reflect"
+	"sync"
+	"testing"
+	"time"
+)
+
+import (
+	hessian "github.com/apache/dubbo-go-hessian2"
+	perrors "github.com/pkg/errors"
+	"github.com/stretchr/testify/assert"
+)
+
+import (
+	"github.com/apache/dubbo-go/common"
+	. "github.com/apache/dubbo-go/common/constant"
+	"github.com/apache/dubbo-go/common/proxy/proxy_factory"
+	"github.com/apache/dubbo-go/config"
+	"github.com/apache/dubbo-go/protocol"
+	"github.com/apache/dubbo-go/protocol/invocation"
+	"github.com/apache/dubbo-go/remoting"
+)
+
+func TestRunSuite(t *testing.T) {
+	svr, url := InitTest(t)
+	client := getClient(url)
+	testRequestOneWay(t, svr, url, client)
+	testClient_Call(t, svr, url, client)
+	testClient_AsyncCall(t, svr, url, client)
+	svr.Stop()
+}
+
+func testRequestOneWay(t *testing.T, svr *Server, url common.URL, client *Client) {
+
+	request := remoting.NewRequest("2.0.2")
+	up := &UserProvider{}
+	invocation := createInvocation("GetUser", nil, nil, []interface{}{[]interface{}{"1", "username"}, up},
+		[]reflect.Value{reflect.ValueOf([]interface{}{"1", "username"}), reflect.ValueOf(up)})
+	attachment := map[string]string{INTERFACE_KEY: "com.ikurento.user.UserProvider"}
+	setAttachment(invocation, attachment)
+	request.Data = invocation
+	request.Event = false
+	request.TwoWay = false
+	//user := &User{}
+	err := client.Request(request, 3*time.Second, nil)
+	assert.NoError(t, err)
+}
+
+func createInvocation(methodName string, callback interface{}, reply interface{}, arguments []interface{},
+	parameterValues []reflect.Value) *invocation.RPCInvocation {
+	return invocation.NewRPCInvocationWithOptions(invocation.WithMethodName(methodName),
+		invocation.WithArguments(arguments), invocation.WithReply(reply),
+		invocation.WithCallBack(callback), invocation.WithParameterValues(parameterValues))
+}
+
+func setAttachment(invocation *invocation.RPCInvocation, attachments map[string]string) {
+	for key, value := range attachments {
+		invocation.SetAttachments(key, value)
+	}
+}
+
+func getClient(url common.URL) *Client {
+	client := NewClient(Options{
+		ConnectTimeout: config.GetConsumerConfig().ConnectTimeout,
+	})
+
+	exchangeClient := remoting.NewExchangeClient(url, client, 5*time.Second, false)
+	client.SetExchangeClient(exchangeClient)
+	client.Connect(url)
+	client.SetResponseHandler(exchangeClient)
+	return client
+}
+
+func testClient_Call(t *testing.T, svr *Server, url common.URL, c *Client) {
+	c.pool = newGettyRPCClientConnPool(c, clientConf.PoolSize, time.Duration(int(time.Second)*clientConf.PoolTTL))
+
+	testGetBigPkg(t, c)
+	testGetUser(t, c)
+	testGetUser0(t, c)
+	testGetUser1(t, c)
+	testGetUser2(t, c)
+	testGetUser3(t, c)
+	testGetUser4(t, c)
+	testGetUser5(t, c)
+	testGetUser6(t, c)
+	testGetUser61(t, c)
+}
+
+func testGetBigPkg(t *testing.T, c *Client) {
+	user := &User{}
+	request := remoting.NewRequest("2.0.2")
+	invocation := createInvocation("GetBigPkg", nil, nil, []interface{}{[]interface{}{nil}, user},
+		[]reflect.Value{reflect.ValueOf([]interface{}{nil}), reflect.ValueOf(user)})
+	attachment := map[string]string{INTERFACE_KEY: "com.ikurento.user.UserProvider"}
+	setAttachment(invocation, attachment)
+	request.Data = invocation
+	request.Event = false
+	request.TwoWay = true
+	pendingResponse := remoting.NewPendingResponse(request.ID)
+	pendingResponse.Reply = user
+	remoting.AddPendingResponse(pendingResponse)
+	err := c.Request(request, 8*time.Second, pendingResponse)
+	assert.NoError(t, err)
+	assert.NotEqual(t, "", user.Id)
+	assert.NotEqual(t, "", user.Name)
+}
+
+func testGetUser(t *testing.T, c *Client) {
+	user := &User{}
+	request := remoting.NewRequest("2.0.2")
+	invocation := createInvocation("GetUser", nil, nil, []interface{}{"1", "username"},
+		[]reflect.Value{reflect.ValueOf("1"), reflect.ValueOf("username")})
+	attachment := map[string]string{INTERFACE_KEY: "com.ikurento.user.UserProvider"}
+	setAttachment(invocation, attachment)
+	request.Data = invocation
+	request.Event = false
+	request.TwoWay = true
+	pendingResponse := remoting.NewPendingResponse(request.ID)
+	pendingResponse.Reply = user
+	remoting.AddPendingResponse(pendingResponse)
+	err := c.Request(request, 3*time.Second, pendingResponse)
+	assert.NoError(t, err)
+	assert.Equal(t, User{Id: "1", Name: "username"}, *user)
+}
+
+func testGetUser0(t *testing.T, c *Client) {
+	var (
+		user *User
+		err  error
+	)
+	user = &User{}
+	request := remoting.NewRequest("2.0.2")
+	invocation := createInvocation("GetUser0", nil, nil, []interface{}{"1", nil, "username"},
+		[]reflect.Value{reflect.ValueOf("1"), reflect.ValueOf(nil), reflect.ValueOf("username")})
+	attachment := map[string]string{INTERFACE_KEY: "com.ikurento.user.UserProvider"}
+	setAttachment(invocation, attachment)
+	request.Data = invocation
+	request.Event = false
+	request.TwoWay = true
+	rsp := remoting.NewPendingResponse(request.ID)
+	rsp.SetResponse(remoting.NewResponse(request.ID, "2.0.2"))
+	remoting.AddPendingResponse(rsp)
+	rsp.Reply = user
+	err = c.Request(request, 3*time.Second, rsp)
+	assert.NoError(t, err)
+	assert.Equal(t, User{Id: "1", Name: "username"}, *user)
+}
+
+func testGetUser1(t *testing.T, c *Client) {
+	var (
+		err error
+	)
+	request := remoting.NewRequest("2.0.2")
+	invocation := createInvocation("GetUser1", nil, nil, []interface{}{},
+		[]reflect.Value{})
+	attachment := map[string]string{INTERFACE_KEY: "com.ikurento.user.UserProvider"}
+	setAttachment(invocation, attachment)
+	request.Data = invocation
+	request.Event = false
+	request.TwoWay = true
+	pendingResponse := remoting.NewPendingResponse(request.ID)
+	user := &User{}
+	pendingResponse.Reply = user
+	remoting.AddPendingResponse(pendingResponse)
+	err = c.Request(request, 3*time.Second, pendingResponse)
+	assert.NoError(t, err)
+}
+
+func testGetUser2(t *testing.T, c *Client) {
+	var (
+		err error
+	)
+	request := remoting.NewRequest("2.0.2")
+	invocation := createInvocation("GetUser2", nil, nil, []interface{}{},
+		[]reflect.Value{})
+	attachment := map[string]string{INTERFACE_KEY: "com.ikurento.user.UserProvider"}
+	setAttachment(invocation, attachment)
+	request.Data = invocation
+	request.Event = false
+	request.TwoWay = true
+	pendingResponse := remoting.NewPendingResponse(request.ID)
+	remoting.AddPendingResponse(pendingResponse)
+	err = c.Request(request, 3*time.Second, pendingResponse)
+	assert.EqualError(t, err, "error")
+}
+
+func testGetUser3(t *testing.T, c *Client) {
+	var (
+		err error
+	)
+	request := remoting.NewRequest("2.0.2")
+	invocation := createInvocation("GetUser3", nil, nil, []interface{}{},
+		[]reflect.Value{})
+	attachment := map[string]string{INTERFACE_KEY: "com.ikurento.user.UserProvider"}
+	setAttachment(invocation, attachment)
+	request.Data = invocation
+	request.Event = false
+	request.TwoWay = true
+	pendingResponse := remoting.NewPendingResponse(request.ID)
+	user2 := []interface{}{}
+	pendingResponse.Reply = &user2
+	remoting.AddPendingResponse(pendingResponse)
+	err = c.Request(request, 3*time.Second, pendingResponse)
+	assert.NoError(t, err)
+	assert.Equal(t, &User{Id: "1", Name: "username"}, user2[0])
+}
+
+func testGetUser4(t *testing.T, c *Client) {
+	var (
+		err error
+	)
+	request := remoting.NewRequest("2.0.2")
+	invocation := invocation.NewRPCInvocation("GetUser4", []interface{}{[]interface{}{"1", "username"}}, nil)
+	attachment := map[string]string{INTERFACE_KEY: "com.ikurento.user.UserProvider"}
+	setAttachment(invocation, attachment)
+	request.Data = invocation
+	request.Event = false
+	request.TwoWay = true
+	pendingResponse := remoting.NewPendingResponse(request.ID)
+	user2 := []interface{}{}
+	pendingResponse.Reply = &user2
+	remoting.AddPendingResponse(pendingResponse)
+	err = c.Request(request, 3*time.Second, pendingResponse)
+	assert.NoError(t, err)
+	assert.Equal(t, &User{Id: "1", Name: "username"}, user2[0])
+}
+
+func testGetUser5(t *testing.T, c *Client) {
+	var (
+		err error
+	)
+	request := remoting.NewRequest("2.0.2")
+	invocation := invocation.NewRPCInvocation("GetUser5", []interface{}{map[interface{}]interface{}{"id": "1", "name": "username"}}, nil)
+	attachment := map[string]string{INTERFACE_KEY: "com.ikurento.user.UserProvider"}
+	setAttachment(invocation, attachment)
+	request.Data = invocation
+	request.Event = false
+	request.TwoWay = true
+	pendingResponse := remoting.NewPendingResponse(request.ID)
+	user3 := map[interface{}]interface{}{}
+	pendingResponse.Reply = &user3
+	remoting.AddPendingResponse(pendingResponse)
+	err = c.Request(request, 3*time.Second, pendingResponse)
+	assert.NoError(t, err)
+	assert.NotNil(t, user3)
+	assert.Equal(t, &User{Id: "1", Name: "username"}, user3["key"])
+}
+
+func testGetUser6(t *testing.T, c *Client) {
+	var (
+		user *User
+		err  error
+	)
+	user = &User{}
+	request := remoting.NewRequest("2.0.2")
+	invocation := invocation.NewRPCInvocation("GetUser6", []interface{}{0}, nil)
+	attachment := map[string]string{INTERFACE_KEY: "com.ikurento.user.UserProvider"}
+	setAttachment(invocation, attachment)
+	request.Data = invocation
+	request.Event = false
+	request.TwoWay = true
+	pendingResponse := remoting.NewPendingResponse(request.ID)
+	pendingResponse.Reply = user
+	remoting.AddPendingResponse(pendingResponse)
+	err = c.Request(request, 3*time.Second, pendingResponse)
+	assert.NoError(t, err)
+	assert.Equal(t, User{Id: "", Name: ""}, *user)
+}
+
+func testGetUser61(t *testing.T, c *Client) {
+	var (
+		user *User
+		err  error
+	)
+	user = &User{}
+	request := remoting.NewRequest("2.0.2")
+	invocation := invocation.NewRPCInvocation("GetUser6", []interface{}{1}, nil)
+	attachment := map[string]string{INTERFACE_KEY: "com.ikurento.user.UserProvider"}
+	setAttachment(invocation, attachment)
+	request.Data = invocation
+	request.Event = false
+	request.TwoWay = true
+	pendingResponse := remoting.NewPendingResponse(request.ID)
+	pendingResponse.Reply = user
+	remoting.AddPendingResponse(pendingResponse)
+	err = c.Request(request, 3*time.Second, pendingResponse)
+	assert.NoError(t, err)
+	assert.Equal(t, User{Id: "1", Name: ""}, *user)
+}
+
+func testClient_AsyncCall(t *testing.T, svr *Server, url common.URL, client *Client) {
+	user := &User{}
+	lock := sync.Mutex{}
+	request := remoting.NewRequest("2.0.2")
+	invocation := createInvocation("GetUser0", nil, nil, []interface{}{"4", nil, "username"},
+		[]reflect.Value{reflect.ValueOf("4"), reflect.ValueOf(nil), reflect.ValueOf("username")})
+	attachment := map[string]string{INTERFACE_KEY: "com.ikurento.user.UserProvider"}
+	setAttachment(invocation, attachment)
+	request.Data = invocation
+	request.Event = false
+	request.TwoWay = true
+	rsp := remoting.NewPendingResponse(request.ID)
+	rsp.SetResponse(remoting.NewResponse(request.ID, "2.0.2"))
+	remoting.AddPendingResponse(rsp)
+	rsp.Reply = user
+	rsp.Callback = func(response common.CallbackResponse) {
+		r := response.(remoting.AsyncCallbackResponse)
+		rst := *r.Reply.(*remoting.Response).Result.(*protocol.RPCResult)
+		assert.Equal(t, User{Id: "4", Name: "username"}, *(rst.Rest.(*User)))
+		lock.Unlock()
+	}
+	lock.Lock()
+	err := client.Request(request, 3*time.Second, rsp)
+	assert.NoError(t, err)
+	assert.Equal(t, User{}, *user)
+	time.Sleep(1 * time.Second)
+}
+
+func InitTest(t *testing.T) (*Server, common.URL) {
+
+	hessian.RegisterPOJO(&User{})
+	remoting.RegistryCodec("dubbo", &DubboTestCodec{})
+
+	methods, err := common.ServiceMap.Register("", "dubbo", &UserProvider{})
+	assert.NoError(t, err)
+	assert.Equal(t, "GetBigPkg,GetUser,GetUser0,GetUser1,GetUser2,GetUser3,GetUser4,GetUser5,GetUser6", methods)
+
+	// config
+	SetClientConf(ClientConfig{
+		ConnectionNum:   2,
+		HeartbeatPeriod: "5s",
+		SessionTimeout:  "20s",
+		PoolTTL:         600,
+		PoolSize:        64,
+		GettySessionParam: GettySessionParam{
+			CompressEncoding: false,
+			TcpNoDelay:       true,
+			TcpKeepAlive:     true,
+			KeepAlivePeriod:  "120s",
+			TcpRBufSize:      262144,
+			TcpWBufSize:      65536,
+			PkgWQSize:        512,
+			TcpReadTimeout:   "4s",
+			TcpWriteTimeout:  "5s",
+			WaitTimeout:      "1s",
+			MaxMsgLen:        10240000000,
+			SessionName:      "client",
+		},
+	})
+	assert.NoError(t, clientConf.CheckValidity())
+	SetServerConfig(ServerConfig{
+		SessionNumber:  700,
+		SessionTimeout: "20s",
+		GettySessionParam: GettySessionParam{
+			CompressEncoding: false,
+			TcpNoDelay:       true,
+			TcpKeepAlive:     true,
+			KeepAlivePeriod:  "120s",
+			TcpRBufSize:      262144,
+			TcpWBufSize:      65536,
+			PkgWQSize:        512,
+			TcpReadTimeout:   "1s",
+			TcpWriteTimeout:  "5s",
+			WaitTimeout:      "1s",
+			MaxMsgLen:        10240000000,
+			SessionName:      "server",
+		}})
+	assert.NoError(t, srvConf.CheckValidity())
+
+	url, err := common.NewURL("dubbo://127.0.0.1:20060/UserProvider?anyhost=true&" +
+		"application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&" +
+		"environment=dev&interface=com.ikurento.user.UserProvider&ip=127.0.0.1&methods=GetUser%2C&" +
+		"module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&" +
+		"side=provider&timeout=3000&timestamp=1556509797245&bean.name=UserProvider")
+	// init server
+	userProvider := &UserProvider{}
+	common.ServiceMap.Register("", url.Protocol, userProvider)
+	invoker := &proxy_factory.ProxyInvoker{
+		BaseInvoker: *protocol.NewBaseInvoker(url),
+	}
+	handler := func(invocation *invocation.RPCInvocation) protocol.RPCResult {
+		//result := protocol.RPCResult{}
+		r := invoker.Invoke(context.Background(), invocation)
+		result := protocol.RPCResult{
+			Err:   r.Error(),
+			Rest:  r.Result(),
+			Attrs: r.Attachments(),
+		}
+		return result
+	}
+	server := NewServer(url, handler)
+	server.Start()
+
+	time.Sleep(time.Second * 2)
+
+	return server, url
+}
+
+//////////////////////////////////
+// provider
+//////////////////////////////////
+
+type (
+	User struct {
+		Id   string `json:"id"`
+		Name string `json:"name"`
+	}
+
+	UserProvider struct {
+		user map[string]User
+	}
+)
+
+// size:4801228
+func (u *UserProvider) GetBigPkg(ctx context.Context, req []interface{}, rsp *User) error {
+	argBuf := new(bytes.Buffer)
+	for i := 0; i < 400; i++ {
+		argBuf.WriteString("击鼓其镗,踊跃用兵。土国城漕,我独南行。从孙子仲,平陈与宋。不我以归,忧心有忡。爰居爰处?爰丧其马?于以求之?于林之下。死生契阔,与子成说。执子之手,与子偕老。于嗟阔兮,不我活兮。于嗟洵兮,不我信兮。")
+		argBuf.WriteString("击鼓其镗,踊跃用兵。土国城漕,我独南行。从孙子仲,平陈与宋。不我以归,忧心有忡。爰居爰处?爰丧其马?于以求之?于林之下。死生契阔,与子成说。执子之手,与子偕老。于嗟阔兮,不我活兮。于嗟洵兮,不我信兮。")
+	}
+	rsp.Id = argBuf.String()
+	rsp.Name = argBuf.String()
+	return nil
+}
+
+func (u *UserProvider) GetUser(ctx context.Context, req []interface{}, rsp *User) error {
+	rsp.Id = req[0].(string)
+	rsp.Name = req[1].(string)
+	return nil
+}
+
+func (u *UserProvider) GetUser0(id string, k *User, name string) (User, error) {
+	return User{Id: id, Name: name}, nil
+}
+
+func (u *UserProvider) GetUser1() error {
+	return nil
+}
+
+func (u *UserProvider) GetUser2() error {
+	return perrors.New("error")
+}
+
+func (u *UserProvider) GetUser3(rsp *[]interface{}) error {
+	*rsp = append(*rsp, User{Id: "1", Name: "username"})
+	return nil
+}
+
+func (u *UserProvider) GetUser4(ctx context.Context, req []interface{}) ([]interface{}, error) {
+
+	return []interface{}{User{Id: req[0].([]interface{})[0].(string), Name: req[0].([]interface{})[1].(string)}}, nil
+}
+
+func (u *UserProvider) GetUser5(ctx context.Context, req []interface{}) (map[interface{}]interface{}, error) {
+	return map[interface{}]interface{}{"key": User{Id: req[0].(map[interface{}]interface{})["id"].(string), Name: req[0].(map[interface{}]interface{})["name"].(string)}}, nil
+}
+
+func (u *UserProvider) GetUser6(id int64) (*User, error) {
+	if id == 0 {
+		return nil, nil
+	}
+	return &User{Id: "1"}, nil
+}
+
+func (u *UserProvider) Reference() string {
+	return "UserProvider"
+}
+
+func (u User) JavaClassName() string {
+	return "com.ikurento.user.User"
+}
diff --git a/protocol/dubbo/server.go b/remoting/getty/getty_server.go
similarity index 66%
rename from protocol/dubbo/server.go
rename to remoting/getty/getty_server.go
index b693b06f49c8276650c7b434dd14d47acb3b38a9..7c8fa29a622b4b746801d1d2ce878f8b353c1a76 100644
--- a/protocol/dubbo/server.go
+++ b/remoting/getty/getty_server.go
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package dubbo
+package getty
 
 import (
 	"crypto/tls"
@@ -25,7 +25,7 @@ import (
 
 import (
 	"github.com/apache/dubbo-getty"
-	"github.com/dubbogo/gost/sync"
+	gxsync "github.com/dubbogo/gost/sync"
 	perrors "github.com/pkg/errors"
 	"gopkg.in/yaml.v2"
 )
@@ -35,6 +35,9 @@ import (
 	"github.com/apache/dubbo-go/common/constant"
 	"github.com/apache/dubbo-go/common/logger"
 	"github.com/apache/dubbo-go/config"
+	"github.com/apache/dubbo-go/protocol"
+	"github.com/apache/dubbo-go/protocol/invocation"
+	"github.com/apache/dubbo-go/remoting"
 )
 
 var (
@@ -42,7 +45,7 @@ var (
 	srvGrpool *gxsync.TaskPool
 )
 
-func init() {
+func initServer(protocol string) {
 	// load clientconfig from provider_config
 	// default use dubbo
 	providerConfig := config.GetProviderConfig()
@@ -54,7 +57,7 @@ func init() {
 	if protocolConf == nil {
 		logger.Info("protocol_conf default use dubbo config")
 	} else {
-		dubboConf := protocolConf.(map[interface{}]interface{})[DUBBO]
+		dubboConf := protocolConf.(map[interface{}]interface{})[protocol]
 		if dubboConf == nil {
 			logger.Warnf("dubboConf is nil")
 			return
@@ -73,7 +76,7 @@ func init() {
 	if err := srvConf.CheckValidity(); err != nil {
 		panic(err)
 	}
-	setServerGrpool()
+	SetServerGrpool()
 }
 
 // SetServerConfig set dubbo server config.
@@ -84,15 +87,16 @@ func SetServerConfig(s ServerConfig) {
 		logger.Warnf("[ServerConfig CheckValidity] error: %v", err)
 		return
 	}
-	setServerGrpool()
+	SetServerGrpool()
 }
 
-// GetServerConfig get dubbo server config.
+// GetServerConfig get getty server config.
 func GetServerConfig() ServerConfig {
 	return *srvConf
 }
 
-func setServerGrpool() {
+// SetServerGrpool set getty server GrPool
+func SetServerGrpool() {
 	if srvConf.GrPoolSize > 1 {
 		srvGrpool = gxsync.NewTaskPool(
 			gxsync.WithTaskPoolTaskPoolSize(srvConf.GrPoolSize),
@@ -102,19 +106,33 @@ func setServerGrpool() {
 	}
 }
 
-// Server is dubbo protocol server.
+// Server define getty server
 type Server struct {
-	conf       ServerConfig
-	tcpServer  getty.Server
-	rpcHandler *RpcServerHandler
+	conf           ServerConfig
+	addr           string
+	codec          remoting.Codec
+	tcpServer      getty.Server
+	rpcHandler     *RpcServerHandler
+	requestHandler func(*invocation.RPCInvocation) protocol.RPCResult
 }
 
-// NewServer create a new Server.
-func NewServer() *Server {
-	return &Server{
-		conf:       *srvConf,
-		rpcHandler: NewRpcServerHandler(srvConf.SessionNumber, srvConf.sessionTimeout),
+// NewServer create a new Server
+func NewServer(url common.URL, handlers func(*invocation.RPCInvocation) protocol.RPCResult) *Server {
+	//init
+	initServer(url.Protocol)
+
+	srvConf.SSLEnabled = url.GetParamBool(constant.SSL_ENABLED_KEY, false)
+
+	s := &Server{
+		conf:           *srvConf,
+		addr:           url.Location,
+		codec:          remoting.GetCodec(url.Protocol),
+		requestHandler: handlers,
 	}
+
+	s.rpcHandler = NewRpcServerHandler(s.conf.SessionNumber, s.conf.sessionTimeout, s)
+
+	return s
 }
 
 func (s *Server) newSession(session getty.Session) error {
@@ -128,6 +146,23 @@ func (s *Server) newSession(session getty.Session) error {
 	if conf.GettySessionParam.CompressEncoding {
 		session.SetCompressType(getty.CompressZip)
 	}
+	if _, ok = session.Conn().(*tls.Conn); ok {
+		session.SetName(conf.GettySessionParam.SessionName)
+		session.SetMaxMsgLen(conf.GettySessionParam.MaxMsgLen)
+		session.SetPkgHandler(NewRpcServerPackageHandler(s))
+		session.SetEventListener(s.rpcHandler)
+		session.SetWQLen(conf.GettySessionParam.PkgWQSize)
+		session.SetReadTimeout(conf.GettySessionParam.tcpReadTimeout)
+		session.SetWriteTimeout(conf.GettySessionParam.tcpWriteTimeout)
+		session.SetCronPeriod((int)(conf.sessionTimeout.Nanoseconds() / 1e6))
+		session.SetWaitTime(conf.GettySessionParam.waitTimeout)
+		logger.Debugf("server accepts new session:%s\n", session.Stat())
+		session.SetTaskPool(srvGrpool)
+		return nil
+	}
+	if tcpConn, ok = session.Conn().(*net.TCPConn); !ok {
+		panic(fmt.Sprintf("%s, session.conn{%#v} is not tcp connection\n", session.Stat(), session.Conn()))
+	}
 
 	if _, ok = session.Conn().(*tls.Conn); !ok {
 		if tcpConn, ok = session.Conn().(*net.TCPConn); !ok {
@@ -155,7 +190,7 @@ func (s *Server) newSession(session getty.Session) error {
 
 	session.SetName(conf.GettySessionParam.SessionName)
 	session.SetMaxMsgLen(conf.GettySessionParam.MaxMsgLen)
-	session.SetPkgHandler(rpcServerPkgHandler)
+	session.SetPkgHandler(NewRpcServerPackageHandler(s))
 	session.SetEventListener(s.rpcHandler)
 	session.SetWQLen(conf.GettySessionParam.PkgWQSize)
 	session.SetReadTimeout(conf.GettySessionParam.tcpReadTimeout)
@@ -167,18 +202,18 @@ func (s *Server) newSession(session getty.Session) error {
 	return nil
 }
 
-// Start start dubbo server.
-func (s *Server) Start(url common.URL) {
+// Start dubbo server.
+func (s *Server) Start() {
 	var (
 		addr      string
 		tcpServer getty.Server
 	)
 
-	addr = url.Location
-	if url.GetParamBool(constant.SSL_ENABLED_KEY, false) {
+	addr = s.addr
+	if s.conf.SSLEnabled {
 		tcpServer = getty.NewTCPServer(
 			getty.WithLocalAddress(addr),
-			getty.WithServerSslEnabled(url.GetParamBool(constant.SSL_ENABLED_KEY, false)),
+			getty.WithServerSslEnabled(s.conf.SSLEnabled),
 			getty.WithServerTlsConfigBuilder(config.GetServerTlsConfigBuilder()),
 		)
 	} else {
@@ -187,11 +222,11 @@ func (s *Server) Start(url common.URL) {
 		)
 	}
 	tcpServer.RunEventLoop(s.newSession)
-	logger.Debugf("s bind addr{%s} ok!", addr)
+	logger.Debugf("s bind addr{%s} ok!", s.addr)
 	s.tcpServer = tcpServer
 }
 
-// Stop stop dubbo server.
+// Stop dubbo server
 func (s *Server) Stop() {
 	s.tcpServer.Close()
 }
diff --git a/remoting/getty/listener.go b/remoting/getty/listener.go
new file mode 100644
index 0000000000000000000000000000000000000000..8d1a63f1c4a34f56de2b2538f61ffb2aa56d7382
--- /dev/null
+++ b/remoting/getty/listener.go
@@ -0,0 +1,319 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package getty
+
+import (
+	"fmt"
+	"sync"
+	"sync/atomic"
+	"time"
+)
+
+import (
+	"github.com/apache/dubbo-getty"
+	hessian "github.com/apache/dubbo-go-hessian2"
+	perrors "github.com/pkg/errors"
+)
+
+import (
+	"github.com/apache/dubbo-go/common/constant"
+	"github.com/apache/dubbo-go/common/logger"
+	"github.com/apache/dubbo-go/protocol/invocation"
+	"github.com/apache/dubbo-go/remoting"
+)
+
+// todo: WritePkg_Timeout will entry *.yml
+const (
+	// WritePkg_Timeout ...
+	WritePkg_Timeout = 5 * time.Second
+)
+
+var (
+	errTooManySessions = perrors.New("too many sessions")
+)
+
+type rpcSession struct {
+	session getty.Session
+	reqNum  int32
+}
+
+func (s *rpcSession) AddReqNum(num int32) {
+	atomic.AddInt32(&s.reqNum, num)
+}
+
+func (s *rpcSession) GetReqNum() int32 {
+	return atomic.LoadInt32(&s.reqNum)
+}
+
+// //////////////////////////////////////////
+// RpcClientHandler
+// //////////////////////////////////////////
+
+// RpcClientHandler ...
+type RpcClientHandler struct {
+	conn *gettyRPCClient
+}
+
+// NewRpcClientHandler ...
+func NewRpcClientHandler(client *gettyRPCClient) *RpcClientHandler {
+	return &RpcClientHandler{conn: client}
+}
+
+// OnOpen ...
+func (h *RpcClientHandler) OnOpen(session getty.Session) error {
+	h.conn.addSession(session)
+	return nil
+}
+
+// OnError ...
+func (h *RpcClientHandler) OnError(session getty.Session, err error) {
+	logger.Infof("session{%s} got error{%v}, will be closed.", session.Stat(), err)
+	h.conn.removeSession(session)
+}
+
+// OnClose ...
+func (h *RpcClientHandler) OnClose(session getty.Session) {
+	logger.Infof("session{%s} is closing......", session.Stat())
+	h.conn.removeSession(session)
+}
+
+// OnMessage ...
+func (h *RpcClientHandler) OnMessage(session getty.Session, pkg interface{}) {
+	result, ok := pkg.(remoting.DecodeResult)
+	if !ok {
+		logger.Errorf("illegal package")
+		return
+	}
+	// get heartbeart request from server
+	if result.IsRequest {
+		req := result.Result.(*remoting.Request)
+		if req.Event {
+			logger.Debugf("get rpc heartbeat request{%#v}", req)
+			resp := remoting.NewResponse(req.ID, req.Version)
+			resp.Status = hessian.Response_OK
+			resp.Event = req.Event
+			resp.SerialID = req.SerialID
+			resp.Version = "2.0.2"
+			reply(session, resp, hessian.PackageHeartbeat)
+			return
+		}
+		logger.Errorf("illegal request but not heartbeart. {%#v}", req)
+		return
+	}
+
+	p := result.Result.(*remoting.Response)
+	// get heartbeart
+	if p.Event {
+		logger.Debugf("get rpc heartbeat response{%#v}", p)
+		if p.Error != nil {
+			logger.Errorf("rpc heartbeat response{error: %#v}", p.Error)
+		}
+		h.conn.pool.rpcClient.responseHandler.Handler(p)
+		return
+	}
+	if result.IsRequest {
+		logger.Errorf("illegal package for it is response type. {%#v}", pkg)
+		return
+	}
+
+	logger.Debugf("get rpc response{%#v}", p)
+
+	h.conn.updateSession(session)
+
+	h.conn.pool.rpcClient.responseHandler.Handler(p)
+}
+
+// OnCron ...
+func (h *RpcClientHandler) OnCron(session getty.Session) {
+	rpcSession, err := h.conn.getClientRpcSession(session)
+	if err != nil {
+		logger.Errorf("client.getClientSession(session{%s}) = error{%v}",
+			session.Stat(), perrors.WithStack(err))
+		return
+	}
+	if h.conn.pool.rpcClient.conf.sessionTimeout.Nanoseconds() < time.Since(session.GetActive()).Nanoseconds() {
+		logger.Warnf("session{%s} timeout{%s}, reqNum{%d}",
+			session.Stat(), time.Since(session.GetActive()).String(), rpcSession.reqNum)
+		h.conn.removeSession(session) // -> h.conn.close() -> h.conn.pool.remove(h.conn)
+		return
+	}
+
+	h.conn.pool.rpcClient.heartbeat(session)
+}
+
+// //////////////////////////////////////////
+// RpcServerHandler
+// //////////////////////////////////////////
+
+// RpcServerHandler implement EventListener of getty.
+type RpcServerHandler struct {
+	maxSessionNum  int
+	sessionTimeout time.Duration
+	sessionMap     map[getty.Session]*rpcSession
+	rwlock         sync.RWMutex
+	server         *Server
+}
+
+// NewRpcServerHandler ...
+func NewRpcServerHandler(maxSessionNum int, sessionTimeout time.Duration, serverP *Server) *RpcServerHandler {
+	return &RpcServerHandler{
+		maxSessionNum:  maxSessionNum,
+		sessionTimeout: sessionTimeout,
+		sessionMap:     make(map[getty.Session]*rpcSession),
+		server:         serverP,
+	}
+}
+
+// OnOpen ...
+func (h *RpcServerHandler) OnOpen(session getty.Session) error {
+	var err error
+	h.rwlock.RLock()
+	if h.maxSessionNum <= len(h.sessionMap) {
+		err = errTooManySessions
+	}
+	h.rwlock.RUnlock()
+	if err != nil {
+		return perrors.WithStack(err)
+	}
+
+	logger.Infof("got session:%s", session.Stat())
+	h.rwlock.Lock()
+	h.sessionMap[session] = &rpcSession{session: session}
+	h.rwlock.Unlock()
+	return nil
+}
+
+// OnError ...
+func (h *RpcServerHandler) OnError(session getty.Session, err error) {
+	logger.Infof("session{%s} got error{%v}, will be closed.", session.Stat(), err)
+	h.rwlock.Lock()
+	delete(h.sessionMap, session)
+	h.rwlock.Unlock()
+}
+
+// OnClose ...
+func (h *RpcServerHandler) OnClose(session getty.Session) {
+	logger.Infof("session{%s} is closing......", session.Stat())
+	h.rwlock.Lock()
+	delete(h.sessionMap, session)
+	h.rwlock.Unlock()
+}
+
+// OnMessage ...
+func (h *RpcServerHandler) OnMessage(session getty.Session, pkg interface{}) {
+	h.rwlock.Lock()
+	if _, ok := h.sessionMap[session]; ok {
+		h.sessionMap[session].reqNum++
+	}
+	h.rwlock.Unlock()
+
+	decodeResult, ok := pkg.(remoting.DecodeResult)
+	if !ok {
+		logger.Errorf("illegal package{%#v}", pkg)
+		return
+	}
+	if !decodeResult.IsRequest {
+		logger.Errorf("illegal package for it is response type. {%#v}", pkg)
+		return
+	}
+	req := decodeResult.Result.(*remoting.Request)
+
+	resp := remoting.NewResponse(req.ID, req.Version)
+	resp.Status = hessian.Response_OK
+	resp.Event = req.Event
+	resp.SerialID = req.SerialID
+	resp.Version = "2.0.2"
+
+	// heartbeat
+	if req.Event {
+		logger.Debugf("get rpc heartbeat request{%#v}", resp)
+		reply(session, resp, hessian.PackageHeartbeat)
+		return
+	}
+
+	defer func() {
+		if e := recover(); e != nil {
+			resp.Status = hessian.Response_SERVER_ERROR
+			if err, ok := e.(error); ok {
+				logger.Errorf("OnMessage panic: %+v", perrors.WithStack(err))
+				resp.Error = perrors.WithStack(err)
+			} else if err, ok := e.(string); ok {
+				logger.Errorf("OnMessage panic: %+v", perrors.New(err))
+				resp.Error = perrors.New(err)
+			} else {
+				logger.Errorf("OnMessage panic: %+v, this is impossible.", e)
+				resp.Error = fmt.Errorf("OnMessage panic unknow exception. %+v", e)
+			}
+
+			if !req.TwoWay {
+				return
+			}
+			reply(session, resp, hessian.PackageResponse)
+		}
+
+	}()
+
+	invoc, ok := req.Data.(*invocation.RPCInvocation)
+	if !ok {
+		panic("create invocation occur some exception for the type is not suitable one.")
+		return
+	}
+	attachments := invoc.Attachments()
+	attachments[constant.LOCAL_ADDR] = session.LocalAddr()
+	attachments[constant.REMOTE_ADDR] = session.RemoteAddr()
+
+	result := h.server.requestHandler(invoc)
+	if !req.TwoWay {
+		return
+	}
+	resp.Result = result
+	reply(session, resp, hessian.PackageResponse)
+}
+
+// OnCron ...
+func (h *RpcServerHandler) OnCron(session getty.Session) {
+	var (
+		flag   bool
+		active time.Time
+	)
+
+	h.rwlock.RLock()
+	if _, ok := h.sessionMap[session]; ok {
+		active = session.GetActive()
+		if h.sessionTimeout.Nanoseconds() < time.Since(active).Nanoseconds() {
+			flag = true
+			logger.Warnf("session{%s} timeout{%s}, reqNum{%d}",
+				session.Stat(), time.Since(active).String(), h.sessionMap[session].reqNum)
+		}
+	}
+	h.rwlock.RUnlock()
+
+	if flag {
+		h.rwlock.Lock()
+		delete(h.sessionMap, session)
+		h.rwlock.Unlock()
+		session.Close()
+	}
+}
+
+func reply(session getty.Session, resp *remoting.Response, tp hessian.PackageType) {
+
+	if err := session.WritePkg(resp, WritePkg_Timeout); err != nil {
+		logger.Errorf("WritePkg error: %#v, %#v", perrors.WithStack(err), resp)
+	}
+}
diff --git a/protocol/dubbo/listener_test.go b/remoting/getty/listener_test.go
similarity index 71%
rename from protocol/dubbo/listener_test.go
rename to remoting/getty/listener_test.go
index 5ab73fd465c9eed508969387513df913433a3c4c..7e7ac5fed440a02188057d520a944b48c8bf7b64 100644
--- a/protocol/dubbo/listener_test.go
+++ b/remoting/getty/listener_test.go
@@ -15,21 +15,22 @@
  * limitations under the License.
  */
 
-package dubbo
+package getty
 
 import (
+	"context"
 	"testing"
 )
 
 import (
-	"github.com/opentracing/opentracing-go"
-	"github.com/opentracing/opentracing-go/mocktracer"
 	"github.com/stretchr/testify/assert"
 )
 
 import (
 	"github.com/apache/dubbo-go/common/constant"
 	"github.com/apache/dubbo-go/protocol/invocation"
+	"github.com/opentracing/opentracing-go"
+	"github.com/opentracing/opentracing-go/mocktracer"
 )
 
 // test rebuild the ctx
@@ -47,7 +48,9 @@ func TestRebuildCtx(t *testing.T) {
 
 	span, ctx := opentracing.StartSpanFromContext(ctx, "Test-Client")
 
-	injectTraceCtx(span, inv)
+	err := injectTraceCtx(span, inv)
+	assert.NoError(t, err)
+
 	// rebuild the context success
 	inv = invocation.NewRPCInvocation("MethodName", []interface{}{"OK", "Hello"}, attach)
 	ctx = rebuildCtx(inv)
@@ -55,3 +58,18 @@ func TestRebuildCtx(t *testing.T) {
 	assert.NotNil(t, ctx)
 	assert.NotNil(t, ctx.Value(constant.TRACING_REMOTE_SPAN_CTX))
 }
+
+// rebuildCtx rebuild the context by attachment.
+// Once we decided to transfer more context's key-value, we should change this.
+// now we only support rebuild the tracing context
+func rebuildCtx(inv *invocation.RPCInvocation) context.Context {
+	ctx := context.WithValue(context.Background(), "attachment", inv.Attachments())
+
+	// actually, if user do not use any opentracing framework, the err will not be nil.
+	spanCtx, err := opentracing.GlobalTracer().Extract(opentracing.TextMap,
+		opentracing.TextMapCarrier(filterContext(inv.Attachments())))
+	if err == nil {
+		ctx = context.WithValue(ctx, constant.TRACING_REMOTE_SPAN_CTX, spanCtx)
+	}
+	return ctx
+}
diff --git a/remoting/getty/opentracing.go b/remoting/getty/opentracing.go
new file mode 100644
index 0000000000000000000000000000000000000000..7db733cbe919f2bef46cfc477bda836dc2da0d45
--- /dev/null
+++ b/remoting/getty/opentracing.go
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package getty
+
+import (
+	"github.com/opentracing/opentracing-go"
+)
+import (
+	invocation_impl "github.com/apache/dubbo-go/protocol/invocation"
+)
+
+func injectTraceCtx(currentSpan opentracing.Span, inv *invocation_impl.RPCInvocation) error {
+	// inject opentracing ctx
+	traceAttachments := filterContext(inv.Attachments())
+	carrier := opentracing.TextMapCarrier(traceAttachments)
+	err := opentracing.GlobalTracer().Inject(currentSpan.Context(), opentracing.TextMap, carrier)
+	if err == nil {
+		fillTraceAttachments(inv.Attachments(), traceAttachments)
+	}
+	return err
+}
+
+func extractTraceCtx(inv *invocation_impl.RPCInvocation) (opentracing.SpanContext, error) {
+	traceAttachments := filterContext(inv.Attachments())
+	// actually, if user do not use any opentracing framework, the err will not be nil.
+	spanCtx, err := opentracing.GlobalTracer().Extract(opentracing.TextMap,
+		opentracing.TextMapCarrier(traceAttachments))
+	return spanCtx, err
+}
+
+func filterContext(attachments map[string]interface{}) map[string]string {
+	var traceAttchment = make(map[string]string)
+	for k, v := range attachments {
+		if r, ok := v.(string); ok {
+			traceAttchment[k] = r
+		}
+	}
+	return traceAttchment
+}
+
+func fillTraceAttachments(attachments map[string]interface{}, traceAttachment map[string]string) {
+	for k, v := range traceAttachment {
+		attachments[k] = v
+	}
+}
diff --git a/protocol/dubbo/pool.go b/remoting/getty/pool.go
similarity index 91%
rename from protocol/dubbo/pool.go
rename to remoting/getty/pool.go
index 6a7d211b496d3f6905c8a84e2f1bd648718ebb92..464cff956e0b4667944942be1c4721a05845bd33 100644
--- a/protocol/dubbo/pool.go
+++ b/remoting/getty/pool.go
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package dubbo
+package getty
 
 import (
 	"crypto/tls"
@@ -38,10 +38,10 @@ import (
 )
 
 type gettyRPCClient struct {
-	once     sync.Once
-	protocol string
-	addr     string
-	active   int64 // zero, not create or be destroyed
+	once sync.Once
+	//protocol string
+	addr   string
+	active int64 // zero, not create or be destroyed
 
 	pool *gettyRPCClientPool
 
@@ -54,7 +54,7 @@ var (
 	errClientPoolClosed = perrors.New("client pool closed")
 )
 
-func newGettyRPCClientConn(pool *gettyRPCClientPool, protocol, addr string) (*gettyRPCClient, error) {
+func newGettyRPCClientConn(pool *gettyRPCClientPool, addr string) (*gettyRPCClient, error) {
 	var (
 		gettyClient getty.Client
 		sslEnabled  bool
@@ -76,7 +76,6 @@ func newGettyRPCClientConn(pool *gettyRPCClientPool, protocol, addr string) (*ge
 		)
 	}
 	c := &gettyRPCClient{
-		protocol:    protocol,
 		addr:        addr,
 		pool:        pool,
 		gettyClient: gettyClient,
@@ -117,7 +116,6 @@ func (c *gettyRPCClient) newSession(session getty.Session) error {
 		conf       ClientConfig
 		sslEnabled bool
 	)
-
 	conf = c.pool.rpcClient.conf
 	sslEnabled = c.pool.sslEnabled
 	if conf.GettySessionParam.CompressEncoding {
@@ -255,25 +253,25 @@ func (c *gettyRPCClient) updateSession(session getty.Session) {
 
 func (c *gettyRPCClient) getClientRpcSession(session getty.Session) (rpcSession, error) {
 	var (
-		err              error
-		rpcClientSession rpcSession
+		err        error
+		rpcSession rpcSession
 	)
 	c.lock.RLock()
 	defer c.lock.RUnlock()
 	if c.sessions == nil {
-		return rpcClientSession, errClientClosed
+		return rpcSession, errClientClosed
 	}
 
 	err = errSessionNotExist
 	for _, s := range c.sessions {
 		if s.session == session {
-			rpcClientSession = *s
+			rpcSession = *s
 			err = nil
 			break
 		}
 	}
 
-	return rpcClientSession, perrors.WithStack(err)
+	return rpcSession, perrors.WithStack(err)
 }
 
 func (c *gettyRPCClient) isAvailable() bool {
@@ -338,7 +336,8 @@ func newGettyRPCClientConnPool(rpcClient *Client, size int, ttl time.Duration) *
 		rpcClient: rpcClient,
 		size:      size,
 		ttl:       int64(ttl.Seconds()),
-		conns:     make([]*gettyRPCClient, 0, 16),
+		// init capacity : 2
+		conns: make([]*gettyRPCClient, 0, 2),
 	}
 }
 
@@ -352,11 +351,15 @@ func (p *gettyRPCClientPool) close() {
 	}
 }
 
-func (p *gettyRPCClientPool) getGettyRpcClient(protocol, addr string) (*gettyRPCClient, error) {
+func (p *gettyRPCClientPool) getGettyRpcClient(addr string) (*gettyRPCClient, error) {
 	conn, err := p.get()
 	if err == nil && conn == nil {
 		// create new conn
-		conn, err = newGettyRPCClientConn(p, protocol, addr)
+		rpcClientConn, err := newGettyRPCClientConn(p, addr)
+		if err == nil {
+			p.put(rpcClientConn)
+		}
+		return rpcClientConn, perrors.WithStack(err)
 	}
 	return conn, perrors.WithStack(err)
 }
@@ -369,10 +372,15 @@ func (p *gettyRPCClientPool) get() (*gettyRPCClient, error) {
 	if p.conns == nil {
 		return nil, errClientPoolClosed
 	}
-
-	for len(p.conns) > 0 {
-		conn := p.conns[len(p.conns)-1]
-		p.conns = p.conns[:len(p.conns)-1]
+	for num := len(p.conns); num > 0; {
+		var conn *gettyRPCClient
+		if num != 1 {
+			conn = p.conns[rand.Int31n(int32(num))]
+		} else {
+			conn = p.conns[0]
+		}
+		// This will recreate gettyRpcClient for remove last position
+		//p.conns = p.conns[:len(p.conns)-1]
 
 		if d := now - conn.getActive(); d > p.ttl {
 			p.remove(conn)
@@ -389,21 +397,17 @@ func (p *gettyRPCClientPool) put(conn *gettyRPCClient) {
 	if conn == nil || conn.getActive() == 0 {
 		return
 	}
-
 	p.Lock()
 	defer p.Unlock()
-
 	if p.conns == nil {
 		return
 	}
-
 	// check whether @conn has existed in p.conns or not.
 	for i := range p.conns {
 		if p.conns[i] == conn {
 			return
 		}
 	}
-
 	if len(p.conns) >= p.size {
 		// delete @conn from client pool
 		// p.remove(conn)
diff --git a/remoting/getty/readwriter.go b/remoting/getty/readwriter.go
new file mode 100644
index 0000000000000000000000000000000000000000..c6585c2dc610d41fe36327b1e74a8ab3a6ead93f
--- /dev/null
+++ b/remoting/getty/readwriter.go
@@ -0,0 +1,136 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package getty
+
+import (
+	"reflect"
+)
+
+import (
+	"github.com/apache/dubbo-getty"
+	hessian "github.com/apache/dubbo-go-hessian2"
+	perrors "github.com/pkg/errors"
+)
+
+import (
+	"github.com/apache/dubbo-go/common/logger"
+	"github.com/apache/dubbo-go/remoting"
+)
+
+////////////////////////////////////////////
+// RpcClientPackageHandler
+////////////////////////////////////////////
+
+// RpcClientPackageHandler Read data from server and Write data to server
+type RpcClientPackageHandler struct {
+	client *Client
+}
+
+// NewRpcClientPackageHandler create a RpcClientPackageHandler
+func NewRpcClientPackageHandler(client *Client) *RpcClientPackageHandler {
+	return &RpcClientPackageHandler{client: client}
+}
+
+// Read data from server. if the package size from server is larger than 4096 byte, server will read 4096 byte
+// and send to client each time. the Read can assemble it.
+func (p *RpcClientPackageHandler) Read(ss getty.Session, data []byte) (interface{}, int, error) {
+	resp, length, err := (p.client.codec).Decode(data)
+	//err := pkg.Unmarshal(buf, p.client)
+	if err != nil {
+		err = perrors.Cause(err)
+		if err == hessian.ErrHeaderNotEnough || err == hessian.ErrBodyNotEnough {
+			return nil, 0, nil
+		}
+
+		logger.Errorf("pkg.Unmarshal(ss:%+v, len(@data):%d) = error:%+v", ss, len(data), err)
+
+		return nil, length, err
+	}
+
+	return resp, length, nil
+}
+
+// Write send the data to server
+func (p *RpcClientPackageHandler) Write(ss getty.Session, pkg interface{}) ([]byte, error) {
+	req, ok := pkg.(*remoting.Request)
+	if !ok {
+		logger.Errorf("illegal pkg:%+v\n", pkg)
+		return nil, perrors.New("invalid rpc request")
+	}
+
+	buf, err := (p.client.codec).EncodeRequest(req)
+	if err != nil {
+		logger.Warnf("binary.Write(req{%#v}) = err{%#v}", req, perrors.WithStack(err))
+		return nil, perrors.WithStack(err)
+	}
+
+	return buf.Bytes(), nil
+}
+
+////////////////////////////////////////////
+// RpcServerPackageHandler
+////////////////////////////////////////////
+
+//var (
+//	rpcServerPkgHandler = &RpcServerPackageHandler{}
+//)
+
+// RpcServerPackageHandler Read data from client and Write data to client
+type RpcServerPackageHandler struct {
+	server *Server
+}
+
+func NewRpcServerPackageHandler(server *Server) *RpcServerPackageHandler {
+	return &RpcServerPackageHandler{server: server}
+}
+
+// Read data from client. if the package size from client is larger than 4096 byte, client will read 4096 byte
+// and send to client each time. the Read can assemble it.
+func (p *RpcServerPackageHandler) Read(ss getty.Session, data []byte) (interface{}, int, error) {
+	req, length, err := (p.server.codec).Decode(data)
+	//resp,len, err := (*p.).DecodeResponse(buf)
+
+	if err != nil {
+		if err == hessian.ErrHeaderNotEnough || err == hessian.ErrBodyNotEnough {
+			return nil, 0, nil
+		}
+
+		logger.Errorf("pkg.Unmarshal(ss:%+v, len(@data):%d) = error:%+v", ss, len(data), err)
+
+		return nil, 0, err
+	}
+
+	return req, length, err
+}
+
+// Write send the data to client
+func (p *RpcServerPackageHandler) Write(ss getty.Session, pkg interface{}) ([]byte, error) {
+	res, ok := pkg.(*remoting.Response)
+	if !ok {
+		logger.Errorf("illegal pkg:%+v\n, it is %+v", pkg, reflect.TypeOf(pkg))
+		return nil, perrors.New("invalid rpc response")
+	}
+
+	buf, err := (p.server.codec).EncodeResponse(res)
+	if err != nil {
+		logger.Warnf("binary.Write(res{%#v}) = err{%#v}", res, perrors.WithStack(err))
+		return nil, perrors.WithStack(err)
+	}
+
+	return buf.Bytes(), nil
+}
diff --git a/test/integrate/dubbo/go-client/go.mod b/test/integrate/dubbo/go-client/go.mod
index b0be45ae9c820dc200a1e642a8c73535b13e9f4d..8428a513adedd114b96168a2028bb8920c58956e 100644
--- a/test/integrate/dubbo/go-client/go.mod
+++ b/test/integrate/dubbo/go-client/go.mod
@@ -1,7 +1,5 @@
 module github.com/apache/dubbo-go/test/integrate/dubbo/go-client
 
-require (
-	github.com/apache/dubbo-go-hessian2 v1.6.0-rc1.0.20200906044240-6c1fb5c3bd44
-)
+require github.com/apache/dubbo-go-hessian2 v1.6.0-rc1.0.20200906044240-6c1fb5c3bd44
 
 go 1.13
diff --git a/test/integrate/dubbo/go-client/go.sum b/test/integrate/dubbo/go-client/go.sum
new file mode 100644
index 0000000000000000000000000000000000000000..7bb51161b1a85755531e6c3ad5245e5918cb9680
--- /dev/null
+++ b/test/integrate/dubbo/go-client/go.sum
@@ -0,0 +1,10 @@
+github.com/apache/dubbo-go-hessian2 v1.6.0-rc1.0.20200906044240-6c1fb5c3bd44/go.mod h1:7rEw9guWABQa6Aqb8HeZcsYPHsOS7XT1qtJvkmI6c5w=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/dubbogo/gost v1.9.0/go.mod h1:pPTjVyoJan3aPxBPNUX0ADkXjPibLo+/Ib0/fADXSG8=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff --git a/test/integrate/dubbo/go-server/go.mod b/test/integrate/dubbo/go-server/go.mod
index 6c530f6a5973c379e98d9c2cca5d7511eabab830..6a56b189e16fced03130c7870302a7bef9d0e1b5 100644
--- a/test/integrate/dubbo/go-server/go.mod
+++ b/test/integrate/dubbo/go-server/go.mod
@@ -1,7 +1,5 @@
 module github.com/apache/dubbo-go/test/integrate/dubbo/go-server
 
-require (
-	github.com/apache/dubbo-go-hessian2 v1.6.0-rc1.0.20200906044240-6c1fb5c3bd44
-)
+require github.com/apache/dubbo-go-hessian2 v1.6.0-rc1.0.20200906044240-6c1fb5c3bd44
 
 go 1.13
diff --git a/test/integrate/dubbo/go-server/go.sum b/test/integrate/dubbo/go-server/go.sum
new file mode 100644
index 0000000000000000000000000000000000000000..7bb51161b1a85755531e6c3ad5245e5918cb9680
--- /dev/null
+++ b/test/integrate/dubbo/go-server/go.sum
@@ -0,0 +1,10 @@
+github.com/apache/dubbo-go-hessian2 v1.6.0-rc1.0.20200906044240-6c1fb5c3bd44/go.mod h1:7rEw9guWABQa6Aqb8HeZcsYPHsOS7XT1qtJvkmI6c5w=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/dubbogo/gost v1.9.0/go.mod h1:pPTjVyoJan3aPxBPNUX0ADkXjPibLo+/Ib0/fADXSG8=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=