diff --git a/cluster/cluster_impl/base_cluster_invoker.go b/cluster/cluster_impl/base_cluster_invoker.go
index 6cbed7748e496afb37f9a1e93dbc40e845c62b06..2426258b95e8a2ecf5067b2ed469eeb9a5617f18 100644
--- a/cluster/cluster_impl/base_cluster_invoker.go
+++ b/cluster/cluster_impl/base_cluster_invoker.go
@@ -25,6 +25,8 @@ import (
 import (
 	"github.com/apache/dubbo-go/cluster"
 	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/common/constant"
+	"github.com/apache/dubbo-go/common/extension"
 	"github.com/apache/dubbo-go/common/utils"
 	"github.com/apache/dubbo-go/protocol"
 	"github.com/apache/dubbo-go/version"
@@ -115,12 +117,24 @@ func (invoker *baseClusterInvoker) doSelect(lb cluster.LoadBalance, invocation p
 }
 
 func isInvoked(selectedInvoker protocol.Invoker, invoked []protocol.Invoker) bool {
-	if len(invoked) > 0 {
-		for _, i := range invoked {
-			if i == selectedInvoker {
-				return true
-			}
+	for _, i := range invoked {
+		if i == selectedInvoker {
+			return true
 		}
 	}
 	return false
 }
+
+func getLoadBalance(invoker protocol.Invoker, invocation protocol.Invocation) cluster.LoadBalance {
+	url := invoker.GetUrl()
+
+	methodName := invocation.MethodName()
+	//Get the service loadbalance config
+	lb := url.GetParam(constant.LOADBALANCE_KEY, constant.DEFAULT_LOADBALANCE)
+
+	//Get the service method loadbalance config if have
+	if v := url.GetMethodParam(methodName, constant.LOADBALANCE_KEY, ""); len(v) > 0 {
+		lb = v
+	}
+	return extension.GetLoadbalance(lb)
+}
diff --git a/cluster/cluster_impl/failfast_cluster.go b/cluster/cluster_impl/failfast_cluster.go
new file mode 100644
index 0000000000000000000000000000000000000000..6301d945626103226132b433dd21e8647f53a38b
--- /dev/null
+++ b/cluster/cluster_impl/failfast_cluster.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 cluster_impl
+
+import (
+	"github.com/apache/dubbo-go/cluster"
+	"github.com/apache/dubbo-go/common/extension"
+	"github.com/apache/dubbo-go/protocol"
+)
+
+type failfastCluster struct{}
+
+const failfast = "failfast"
+
+func init() {
+	extension.SetCluster(failfast, NewFailFastCluster)
+}
+
+func NewFailFastCluster() cluster.Cluster {
+	return &failfastCluster{}
+}
+
+func (cluster *failfastCluster) Join(directory cluster.Directory) protocol.Invoker {
+	return newFailFastClusterInvoker(directory)
+}
diff --git a/cluster/cluster_impl/failfast_cluster_invoker.go b/cluster/cluster_impl/failfast_cluster_invoker.go
new file mode 100644
index 0000000000000000000000000000000000000000..734ea2c6cb19bf54a338a76a10c9cfcc59d3954b
--- /dev/null
+++ b/cluster/cluster_impl/failfast_cluster_invoker.go
@@ -0,0 +1,51 @@
+/*
+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 cluster_impl
+
+import (
+	"github.com/apache/dubbo-go/cluster"
+	"github.com/apache/dubbo-go/protocol"
+)
+
+type failfastClusterInvoker struct {
+	baseClusterInvoker
+}
+
+func newFailFastClusterInvoker(directory cluster.Directory) protocol.Invoker {
+	return &failfastClusterInvoker{
+		baseClusterInvoker: newBaseClusterInvoker(directory),
+	}
+}
+
+func (invoker *failfastClusterInvoker) Invoke(invocation protocol.Invocation) protocol.Result {
+	invokers := invoker.directory.List(invocation)
+	err := invoker.checkInvokers(invokers, invocation)
+	if err != nil {
+		return &protocol.RPCResult{Err: err}
+	}
+
+	loadbalance := getLoadBalance(invokers[0], invocation)
+
+	err = invoker.checkWhetherDestroyed()
+	if err != nil {
+		return &protocol.RPCResult{Err: err}
+	}
+
+	ivk := invoker.doSelect(loadbalance, invocation, invokers, nil)
+	return ivk.Invoke(invocation)
+}
diff --git a/cluster/cluster_impl/failfast_cluster_test.go b/cluster/cluster_impl/failfast_cluster_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..7a19e80ccda15aa13a1c4fcf250e05a6effa7f0b
--- /dev/null
+++ b/cluster/cluster_impl/failfast_cluster_test.go
@@ -0,0 +1,97 @@
+/*
+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 cluster_impl
+
+import (
+	"context"
+	"testing"
+)
+
+import (
+	"github.com/golang/mock/gomock"
+	perrors "github.com/pkg/errors"
+	"github.com/stretchr/testify/assert"
+)
+
+import (
+	"github.com/apache/dubbo-go/cluster/directory"
+	"github.com/apache/dubbo-go/cluster/loadbalance"
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/common/extension"
+	"github.com/apache/dubbo-go/protocol"
+	"github.com/apache/dubbo-go/protocol/invocation"
+	"github.com/apache/dubbo-go/protocol/mock"
+)
+
+var (
+	failfastUrl, _ = common.NewURL(context.TODO(), "dubbo://192.168.1.1:20000/com.ikurento.user.UserProvider")
+)
+
+// registerFailfast register failfastCluster to cluster extension.
+func registerFailfast(t *testing.T, invoker *mock.MockInvoker) protocol.Invoker {
+	extension.SetLoadbalance("random", loadbalance.NewRandomLoadBalance)
+	failfastCluster := NewFailFastCluster()
+
+	invokers := []protocol.Invoker{}
+	invokers = append(invokers, invoker)
+
+	invoker.EXPECT().GetUrl().Return(failfastUrl)
+
+	staticDir := directory.NewStaticDirectory(invokers)
+	clusterInvoker := failfastCluster.Join(staticDir)
+	return clusterInvoker
+}
+
+func Test_FailfastInvokeSuccess(t *testing.T) {
+	ctrl := gomock.NewController(t)
+	defer ctrl.Finish()
+
+	invoker := mock.NewMockInvoker(ctrl)
+	clusterInvoker := registerFailfast(t, invoker)
+
+	invoker.EXPECT().GetUrl().Return(failfastUrl)
+
+	mockResult := &protocol.RPCResult{Rest: rest{tried: 0, success: true}}
+
+	invoker.EXPECT().Invoke(gomock.Any()).Return(mockResult)
+	result := clusterInvoker.Invoke(&invocation.RPCInvocation{})
+
+	assert.NoError(t, result.Error())
+	res := result.Result().(rest)
+	assert.True(t, res.success)
+	assert.Equal(t, 0, res.tried)
+}
+
+func Test_FailfastInvokeFail(t *testing.T) {
+	ctrl := gomock.NewController(t)
+	defer ctrl.Finish()
+
+	invoker := mock.NewMockInvoker(ctrl)
+	clusterInvoker := registerFailfast(t, invoker)
+
+	invoker.EXPECT().GetUrl().Return(failfastUrl)
+
+	mockResult := &protocol.RPCResult{Err: perrors.New("error")}
+
+	invoker.EXPECT().Invoke(gomock.Any()).Return(mockResult)
+	result := clusterInvoker.Invoke(&invocation.RPCInvocation{})
+
+	assert.NotNil(t, result.Error())
+	assert.Equal(t, "error", result.Error().Error())
+	assert.Nil(t, result.Result())
+}
diff --git a/cluster/cluster_impl/failover_cluster_invoker.go b/cluster/cluster_impl/failover_cluster_invoker.go
index cd17a85e00a1d4307b3b861467051e9719345d1a..69664269e2ccf362e6b7a12488fe006802d460e2 100644
--- a/cluster/cluster_impl/failover_cluster_invoker.go
+++ b/cluster/cluster_impl/failover_cluster_invoker.go
@@ -24,7 +24,6 @@ import (
 import (
 	"github.com/apache/dubbo-go/cluster"
 	"github.com/apache/dubbo-go/common/constant"
-	"github.com/apache/dubbo-go/common/extension"
 	"github.com/apache/dubbo-go/common/utils"
 	"github.com/apache/dubbo-go/protocol"
 	"github.com/apache/dubbo-go/version"
@@ -48,17 +47,11 @@ func (invoker *failoverClusterInvoker) Invoke(invocation protocol.Invocation) pr
 	if err != nil {
 		return &protocol.RPCResult{Err: err}
 	}
-	url := invokers[0].GetUrl()
 
-	methodName := invocation.MethodName()
-	//Get the service loadbalance config
-	lb := url.GetParam(constant.LOADBALANCE_KEY, constant.DEFAULT_LOADBALANCE)
+	loadbalance := getLoadBalance(invokers[0], invocation)
 
-	//Get the service method loadbalance config if have
-	if v := url.GetMethodParam(methodName, constant.LOADBALANCE_KEY, ""); v != "" {
-		lb = v
-	}
-	loadbalance := extension.GetLoadbalance(lb)
+	methodName := invocation.MethodName()
+	url := invokers[0].GetUrl()
 
 	//get reties
 	retries := url.GetParamInt(constant.RETRIES_KEY, constant.DEFAULT_RETRIES)
diff --git a/go.mod b/go.mod
index eb1fd6f17e23906e3b07403820f8442fa8c8b782..28a3fc7c4202212a7664193b710044cefb406955 100644
--- a/go.mod
+++ b/go.mod
@@ -2,8 +2,10 @@ module github.com/apache/dubbo-go
 
 require (
 	github.com/apache/dubbo-go-hessian2 v1.2.5-0.20190731020727-1697039810c8
+	github.com/davecgh/go-spew v1.1.1 // indirect
 	github.com/dubbogo/getty v1.2.0
 	github.com/dubbogo/gost v1.1.1
+	github.com/golang/mock v1.3.1
 	github.com/magiconair/properties v1.8.1
 	github.com/pkg/errors v0.8.1
 	github.com/samuel/go-zookeeper v0.0.0-20180130194729-c4fab1ac1bec
diff --git a/go.sum b/go.sum
index 4015d15f86f1ef605532112a9e6c35dcb7e44f1f..e2947876e1ec1d8b45c160bb9fff356798898e21 100644
--- a/go.sum
+++ b/go.sum
@@ -9,6 +9,8 @@ github.com/dubbogo/getty v1.2.0/go.mod h1:p9Pyk18a+5Aa0GZ546aCzlehEfvEof0jAF0+QQ
 github.com/dubbogo/gost v1.0.1-0.20190706005735-65c3ecbba418/go.mod h1:R7wZm1DrmrKGr50mBZVcg6C9ekG8aL5hP+sgWcIDwQg=
 github.com/dubbogo/gost v1.1.1 h1:JCM7vx5edPIjDA5ovJTuzEEXuw2t7xLyrlgi2mi5jHI=
 github.com/dubbogo/gost v1.1.1/go.mod h1:R7wZm1DrmrKGr50mBZVcg6C9ekG8aL5hP+sgWcIDwQg=
+github.com/golang/mock v1.3.1 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s=
+github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
 github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
 github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
 github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
@@ -31,12 +33,15 @@ go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/
 go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM=
 go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53 h1:kcXqo9vE6fsZY5X5Rd7R1l7fTgnWaDCVmln65REefiE=
 golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
diff --git a/protocol/invoker.go b/protocol/invoker.go
index fe6aab848caceed50fc3db3e657ce87c45eac2ed..f5d41a09ad2778c12c7e5e68167a4d0acc9e3f4c 100644
--- a/protocol/invoker.go
+++ b/protocol/invoker.go
@@ -22,6 +22,7 @@ import (
 	"github.com/apache/dubbo-go/common/logger"
 )
 
+//go:generate mockgen -source invoker.go -destination mock/mock_invoker.go  -self_package github.com/apache/dubbo-go/protocol/mock --package mock  Invoker
 // Extension - Invoker
 type Invoker interface {
 	common.Node
diff --git a/protocol/mock/mock_invoker.go b/protocol/mock/mock_invoker.go
new file mode 100644
index 0000000000000000000000000000000000000000..557dafa277e95c39d0b960436ac10ba8842c9186
--- /dev/null
+++ b/protocol/mock/mock_invoker.go
@@ -0,0 +1,87 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: invoker.go
+
+// Package mock is a generated GoMock package.
+package mock
+
+import (
+	"reflect"
+)
+
+import (
+	"github.com/golang/mock/gomock"
+)
+
+import (
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/protocol"
+)
+
+// MockInvoker is a mock of Invoker interface
+type MockInvoker struct {
+	ctrl     *gomock.Controller
+	recorder *MockInvokerMockRecorder
+}
+
+// MockInvokerMockRecorder is the mock recorder for MockInvoker
+type MockInvokerMockRecorder struct {
+	mock *MockInvoker
+}
+
+// NewMockInvoker creates a new mock instance
+func NewMockInvoker(ctrl *gomock.Controller) *MockInvoker {
+	mock := &MockInvoker{ctrl: ctrl}
+	mock.recorder = &MockInvokerMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use
+func (m *MockInvoker) EXPECT() *MockInvokerMockRecorder {
+	return m.recorder
+}
+
+// GetUrl mocks base method
+func (m *MockInvoker) GetUrl() common.URL {
+	ret := m.ctrl.Call(m, "GetUrl")
+	ret0, _ := ret[0].(common.URL)
+	return ret0
+}
+
+// GetUrl indicates an expected call of GetUrl
+func (mr *MockInvokerMockRecorder) GetUrl() *gomock.Call {
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUrl", reflect.TypeOf((*MockInvoker)(nil).GetUrl))
+}
+
+// IsAvailable mocks base method
+func (m *MockInvoker) IsAvailable() bool {
+	ret := m.ctrl.Call(m, "IsAvailable")
+	ret0, _ := ret[0].(bool)
+	return ret0
+}
+
+// IsAvailable indicates an expected call of IsAvailable
+func (mr *MockInvokerMockRecorder) IsAvailable() *gomock.Call {
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsAvailable", reflect.TypeOf((*MockInvoker)(nil).IsAvailable))
+}
+
+// Destroy mocks base method
+func (m *MockInvoker) Destroy() {
+	m.ctrl.Call(m, "Destroy")
+}
+
+// Destroy indicates an expected call of Destroy
+func (mr *MockInvokerMockRecorder) Destroy() *gomock.Call {
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Destroy", reflect.TypeOf((*MockInvoker)(nil).Destroy))
+}
+
+// Invoke mocks base method
+func (m *MockInvoker) Invoke(arg0 protocol.Invocation) protocol.Result {
+	ret := m.ctrl.Call(m, "Invoke", arg0)
+	ret0, _ := ret[0].(protocol.Result)
+	return ret0
+}
+
+// Invoke indicates an expected call of Invoke
+func (mr *MockInvokerMockRecorder) Invoke(arg0 interface{}) *gomock.Call {
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Invoke", reflect.TypeOf((*MockInvoker)(nil).Invoke), arg0)
+}