diff --git a/config/metric_config.go b/config/metric_config.go
index e3dacdaad691e1cba5cd2ae60e09b6ee42e80fa5..7b9222f29b3eef93868ea7a852979876aea2c87e 100644
--- a/config/metric_config.go
+++ b/config/metric_config.go
@@ -17,9 +17,14 @@
 
 package config
 
+var (
+	defaultHistogramBucket = []float64{10, 50, 100, 200, 500, 1000, 10000}
+)
+
 // This is the config struct for all metrics implementation
 type MetricConfig struct {
-	Reporters []string `yaml:"reporters" json:"reporters,omitempty"`
+	Reporters       []string  `yaml:"reporters" json:"reporters,omitempty"`
+	HistogramBucket []float64 `yaml:"histogram_bucket" json:"histogram_bucket,omitempty"`
 }
 
 // find the MetricConfig
@@ -30,3 +35,12 @@ func GetMetricConfig() *MetricConfig {
 	}
 	return metricConfig
 }
+
+// find the histogram bucket
+// if it's empty, the default value will be return
+func (mc *MetricConfig) GetHistogramBucket() []float64 {
+	if len(mc.HistogramBucket) == 0 {
+		mc.HistogramBucket = defaultHistogramBucket
+	}
+	return mc.HistogramBucket
+}
diff --git a/metrics/prometheus/reporter.go b/metrics/prometheus/reporter.go
index 5a2ec2016a34989508f8ded1be0870964727d756..8914902ab034fcce836e66062f023b366b72fa52 100644
--- a/metrics/prometheus/reporter.go
+++ b/metrics/prometheus/reporter.go
@@ -32,6 +32,7 @@ import (
 	"github.com/apache/dubbo-go/common/constant"
 	"github.com/apache/dubbo-go/common/extension"
 	"github.com/apache/dubbo-go/common/logger"
+	"github.com/apache/dubbo-go/config"
 	"github.com/apache/dubbo-go/metrics"
 	"github.com/apache/dubbo-go/protocol"
 )
@@ -48,15 +49,28 @@ const (
 
 	providerKey = "provider"
 	consumerKey = "consumer"
+
+	// to identify the metric's type
+	histogramSuffix = "_histogram"
+	// to identify the metric's type
+	summarySuffix = "_summary"
+)
+
+var (
+	labelNames = []string{serviceKey, groupKey, versionKey, methodKey, timeoutKey, remoteKey, localKey}
 )
 
 // should initialize after loading configuration
 func init() {
 	rpt := &PrometheusReporter{
-		consumerVec: newSummaryVec(consumerKey),
-		providerVec: newSummaryVec(providerKey),
+		consumerSummaryVec: newSummaryVec(consumerKey),
+		providerSummaryVec: newSummaryVec(providerKey),
+
+		consumerHistogramVec: newHistogramVec(consumerKey),
+		providerHistogramVec: newHistogramVec(providerKey),
 	}
-	prometheus.MustRegister(rpt.consumerVec, rpt.providerVec)
+	prometheus.MustRegister(rpt.consumerSummaryVec, rpt.providerSummaryVec,
+		rpt.consumerHistogramVec, rpt.providerHistogramVec)
 	extension.SetMetricReporter(reporterName, rpt)
 }
 
@@ -65,27 +79,35 @@ func init() {
 // https://prometheus.io/docs/guides/go-application/
 type PrometheusReporter struct {
 
-	// report the consumer-side's data
-	consumerVec *prometheus.SummaryVec
-	// report the provider-side's data
-	providerVec *prometheus.SummaryVec
+	// report the consumer-side's summary data
+	consumerSummaryVec *prometheus.SummaryVec
+	// report the provider-side's summary data
+	providerSummaryVec *prometheus.SummaryVec
+
+	// report the provider-side's histogram data
+	providerHistogramVec *prometheus.HistogramVec
+	// report the consumer-side's histogram data
+	consumerHistogramVec *prometheus.HistogramVec
 }
 
 // report the duration to Prometheus
 func (reporter *PrometheusReporter) Report(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation, cost time.Duration, res protocol.Result) {
 	url := invoker.GetUrl()
 	var sumVec *prometheus.SummaryVec
+	var hisVec *prometheus.HistogramVec
 	if isProvider(url) {
-		sumVec = reporter.providerVec
+		sumVec = reporter.providerSummaryVec
+		hisVec = reporter.providerHistogramVec
 	} else if isConsumer(url) {
-		sumVec = reporter.consumerVec
+		sumVec = reporter.consumerSummaryVec
+		hisVec = reporter.consumerHistogramVec
 	} else {
 		logger.Warnf("The url is not the consumer's or provider's, "+
 			"so the invocation will be ignored. url: %s", url.String())
 		return
 	}
 
-	sumVec.With(prometheus.Labels{
+	labels := prometheus.Labels{
 		serviceKey: url.Service(),
 		groupKey:   url.GetParam(groupKey, ""),
 		versionKey: url.GetParam(versionKey, ""),
@@ -93,7 +115,24 @@ func (reporter *PrometheusReporter) Report(ctx context.Context, invoker protocol
 		timeoutKey: url.GetParam(timeoutKey, ""),
 		remoteKey:  invocation.AttachmentsByKey(constant.REMOTE_ADDR, ""),
 		localKey:   invocation.AttachmentsByKey(constant.REMOTE_ADDR, ""),
-	}).Observe(float64(cost.Nanoseconds() / constant.MsToNanoRate))
+	}
+
+	costMs := float64(cost.Nanoseconds() / constant.MsToNanoRate)
+	sumVec.With(labels).Observe(costMs)
+	hisVec.With(labels).Observe(costMs)
+}
+
+func newHistogramVec(side string) *prometheus.HistogramVec {
+	mc := config.GetMetricConfig()
+	return prometheus.NewHistogramVec(
+		prometheus.HistogramOpts{
+			Namespace: metrics.NameSpace,
+			Subsystem: side,
+			Name:      serviceKey + histogramSuffix,
+			Help:      "This is the dubbo's histogram metrics",
+			Buckets:   mc.GetHistogramBucket(),
+		},
+		labelNames)
 }
 
 // whether this url represents the application received the request as server
@@ -115,9 +154,9 @@ func newSummaryVec(side string) *prometheus.SummaryVec {
 	return prometheus.NewSummaryVec(
 		prometheus.SummaryOpts{
 			Namespace: metrics.NameSpace,
-			Help:      "this is the dubbo's metrics",
+			Help:      "This is the dubbo's summary metrics",
 			Subsystem: side,
-			Name:      serviceKey,
+			Name:      serviceKey + summarySuffix,
 			Objectives: map[float64]float64{
 				0.5:   0.01,
 				0.75:  0.01,
@@ -127,6 +166,6 @@ func newSummaryVec(side string) *prometheus.SummaryVec {
 				0.999: 0.0001,
 			},
 		},
-		[]string{serviceKey, groupKey, versionKey, methodKey, timeoutKey, remoteKey, localKey},
+		labelNames,
 	)
 }
diff --git a/metrics/prometheus/reporter_test.go b/metrics/prometheus/reporter_test.go
index 52e8b50c57f65e1495931354bb5a55861cbb457b..d1741d16d03f09ffc19b227e6a405f60bf306f9b 100644
--- a/metrics/prometheus/reporter_test.go
+++ b/metrics/prometheus/reporter_test.go
@@ -49,4 +49,24 @@ func TestPrometheusReporter_Report(t *testing.T) {
 	assert.False(t, isConsumer(url))
 	ctx := context.Background()
 	reporter.Report(ctx, invoker, inv, 100*time.Millisecond, nil)
+
+	// consumer side
+	url, _ = common.NewURL(context.Background(),
+		"dubbo://:20000/UserProvider?app.version=0.0.1&application=BDTService&bean.name=UserProvider"+
+			"&cluster=failover&environment=dev&group=&interface=com.ikurento.user.UserProvider&loadbalance=random&methods.GetUser."+
+			"loadbalance=random&methods.GetUser.retries=1&methods.GetUser.weight=0&module=dubbogo+user-info+server&name="+
+			"BDTService&organization=ikurento.com&owner=ZX&registry.role=0&retries=&"+
+			"service.filter=echo%2Ctoken%2Caccesslog&timestamp=1569153406&token=934804bf-b007-4174-94eb-96e3e1d60cc7&version=&warmup=100")
+	invoker = protocol.NewBaseInvoker(url)
+	reporter.Report(ctx, invoker, inv, 100*time.Millisecond, nil)
+
+	// invalid role
+	url, _ = common.NewURL(context.Background(),
+		"dubbo://:20000/UserProvider?app.version=0.0.1&application=BDTService&bean.name=UserProvider"+
+			"&cluster=failover&environment=dev&group=&interface=com.ikurento.user.UserProvider&loadbalance=random&methods.GetUser."+
+			"loadbalance=random&methods.GetUser.retries=1&methods.GetUser.weight=0&module=dubbogo+user-info+server&name="+
+			"BDTService&organization=ikurento.com&owner=ZX&registry.role=9&retries=&"+
+			"service.filter=echo%2Ctoken%2Caccesslog&timestamp=1569153406&token=934804bf-b007-4174-94eb-96e3e1d60cc7&version=&warmup=100")
+	invoker = protocol.NewBaseInvoker(url)
+	reporter.Report(ctx, invoker, inv, 100*time.Millisecond, nil)
 }