Repository: dragonflyoss/Dragonfly2
Pull request #1298 (2022-05-10 12:47:33)

feat: scheduler add seed peer
Signed-off-by: Gaius <gaius.qi@gmail.com>

<!--- Provide a general summary of your changes in the Title above -->

## Description
- Scheduler add seed peer.
<!--- Describe your changes in detail -->

## Related Issue

<!--- This project only accepts pull requests related to open issues -->
<!--- If suggesting a new feature or change, please discuss it in an issue first -->
<!--- If fixing a bug, there should be an issue describing it with steps to reproduce -->
<!--- Please link to the issue here: -->

## Motivation and Context

<!--- Why is this change required? What problem does it solve? -->

## Screenshots (if appropriate)

## Types of changes

<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->

- [ ] Bug fix (non-breaking change which fixes an issue)
- [x] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to change)
- [ ] Documentation Update (if none of the other choices apply)

## Checklist

<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->

- [ ] My change requires a change to the documentation.
- [ ] I have updated the documentation accordingly.
- [x] I have read the **CONTRIBUTING** document.
- [ ] I have added tests to cover my changes.


codecov-commenter: # [Codecov](https://codecov.io/gh/dragonflyoss/Dragonfly2/pull/1298?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dragonflyoss) Report
> Merging [#1298](https://codecov.io/gh/dragonflyoss/Dragonfly2/pull/1298?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dragonflyoss) (7669f1d) into [main](https://codecov.io/gh/dragonflyoss/Dragonfly2/commit/be64954454fdd34d125ef5626e437aa3e43dfc42?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dragonflyoss) (be64954) will **increase** coverage by `0.14%`.
> The diff coverage is `60.60%`.

[![Impacted file tree graph](https://codecov.io/gh/dragonflyoss/Dragonfly2/pull/1298/graphs/tree.svg?width=650&height=150&src=pr&token=PUICJYSAT7&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dragonflyoss)](https://codecov.io/gh/dragonflyoss/Dragonfly2/pull/1298?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dragonflyoss)

```diff
@@            Coverage Diff             @@
##             main    #1298      +/-   ##
==========================================
+ Coverage   46.32%   46.46%   +0.14%     
==========================================
  Files         137      139       +2     
  Lines       11625    11660      +35     
==========================================
+ Hits         5385     5418      +33     
- Misses       5649     5655       +6     
+ Partials      591      587       -4     
```

| Flag | Coverage Δ | |
|---|---|---|
| Object-compatibility-e2etests | `?` | |
| e2etests | `?` | |
| unittests | `46.46% <60.60%> (+0.14%)` | :arrow_up: |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dragonflyoss#carryforward-flags-in-the-pull-request-comment) to find out more.

| [Impacted Files](https://codecov.io/gh/dragonflyoss/Dragonfly2/pull/1298?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dragonflyoss) | Coverage Δ | |
|---|---|---|
| [scheduler/config/dynconfig.go](https://codecov.io/gh/dragonflyoss/Dragonfly2/pull/1298/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dragonflyoss#diff-c2NoZWR1bGVyL2NvbmZpZy9keW5jb25maWcuZ28=) | `32.53% <0.00%> (-5.19%)` | :arrow_down: |
| [scheduler/resource/resource\_mock.go](https://codecov.io/gh/dragonflyoss/Dragonfly2/pull/1298/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dragonflyoss#diff-c2NoZWR1bGVyL3Jlc291cmNlL3Jlc291cmNlX21vY2suZ28=) | `0.00% <0.00%> (ø)` | |
| [scheduler/resource/seed\_peer\_mock.go](https://codecov.io/gh/dragonflyoss/Dragonfly2/pull/1298/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dragonflyoss#diff-c2NoZWR1bGVyL3Jlc291cmNlL3NlZWRfcGVlcl9tb2NrLmdv) | `0.00% <0.00%> (ø)` | |
| [scheduler/rpcserver/rpcserver.go](https://codecov.io/gh/dragonflyoss/Dragonfly2/pull/1298/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dragonflyoss#diff-c2NoZWR1bGVyL3JwY3NlcnZlci9ycGNzZXJ2ZXIuZ28=) | `16.12% <ø> (ø)` | |
| [scheduler/storage/storage.go](https://codecov.io/gh/dragonflyoss/Dragonfly2/pull/1298/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dragonflyoss#diff-c2NoZWR1bGVyL3N0b3JhZ2Uvc3RvcmFnZS5nbw==) | `83.33% <ø> (ø)` | |
| [scheduler/resource/seed\_peer.go](https://codecov.io/gh/dragonflyoss/Dragonfly2/pull/1298/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dragonflyoss#diff-c2NoZWR1bGVyL3Jlc291cmNlL3NlZWRfcGVlci5nbw==) | `19.29% <19.29%> (ø)` | |
| [scheduler/resource/seed\_peer\_client\_mock.go](https://codecov.io/gh/dragonflyoss/Dragonfly2/pull/1298/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dragonflyoss#diff-c2NoZWR1bGVyL3Jlc291cmNlL3NlZWRfcGVlcl9jbGllbnRfbW9jay5nbw==) | `27.08% <27.08%> (ø)` | |
| [scheduler/resource/resource.go](https://codecov.io/gh/dragonflyoss/Dragonfly2/pull/1298/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dragonflyoss#diff-c2NoZWR1bGVyL3Jlc291cmNlL3Jlc291cmNlLmdv) | `82.60% <75.00%> (ø)` | |
| [scheduler/service/service.go](https://codecov.io/gh/dragonflyoss/Dragonfly2/pull/1298/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dragonflyoss#diff-c2NoZWR1bGVyL3NlcnZpY2Uvc2VydmljZS5nbw==) | `82.77% <92.85%> (-0.57%)` | :arrow_down: |
| [scheduler/resource/seed\_peer\_client.go](https://codecov.io/gh/dragonflyoss/Dragonfly2/pull/1298/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dragonflyoss#diff-c2NoZWR1bGVyL3Jlc291cmNlL3NlZWRfcGVlcl9jbGllbnQuZ28=) | `96.66% <96.66%> (ø)` | |
| ... and [13 more](https://codecov.io/gh/dragonflyoss/Dragonfly2/pull/1298/diff?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dragonflyoss) | |


Patch:
diff --git a/pkg/idgen/host_id.go b/pkg/idgen/host_id.go
index 894200aa..35db7b74 100644
--- a/pkg/idgen/host_id.go
+++ b/pkg/idgen/host_id.go
@@ -24,6 +24,10 @@ func HostID(hostname string, port int32) string {
 	return fmt.Sprintf("%s-%d", hostname, port)
 }
 
+func SeedHostID(hostname string, port int32) string {
+	return fmt.Sprintf("%s_Seed", HostID(hostname, port))
+}
+
 func CDNHostID(hostname string, port int32) string {
 	return fmt.Sprintf("%s_CDN", HostID(hostname, port))
 }
diff --git a/pkg/idgen/peer_id.go b/pkg/idgen/peer_id.go
index 50f02c59..49b3b527 100644
--- a/pkg/idgen/peer_id.go
+++ b/pkg/idgen/peer_id.go
@@ -29,10 +29,14 @@ func init() {
 	pid = os.Getpid()
 }
 
-func CDNPeerID(ip string) string {
-	return fmt.Sprintf("%s_%s", PeerID(ip), "CDN")
-}
-
 func PeerID(ip string) string {
 	return fmt.Sprintf("%s-%d-%s", ip, pid, uuid.New())
 }
+
+func SeedPeerID(ip string) string {
+	return fmt.Sprintf("%s_%s", PeerID(ip), "Seed")
+}
+
+func CDNPeerID(ip string) string {
+	return fmt.Sprintf("%s_%s", PeerID(ip), "CDN")
+}
diff --git a/scheduler/config/config.go b/scheduler/config/config.go
index 402b7c0e..f8b0a0df 100644
--- a/scheduler/config/config.go
+++ b/scheduler/config/config.go
@@ -43,8 +43,8 @@ type Config struct {
 	// Manager configuration.
 	Manager *ManagerConfig `yaml:"manager" mapstructure:"manager"`
 
-	// CDN configuration.
-	CDN *CDNConfig `yaml:"cdn" mapstructure:"cdn"`
+	// SeedPeer configuration.
+	SeedPeer *SeedPeerConfig `yaml:"seedPeer" mapstructure:"seedPeer"`
 
 	// Host configuration.
 	Host *HostConfig `yaml:"host" mapstructure:"host"`
@@ -93,7 +93,7 @@ func New() *Config {
 				Interval: 5 * time.Second,
 			},
 		},
-		CDN: &CDNConfig{
+		SeedPeer: &SeedPeerConfig{
 			Enable: true,
 		},
 		Job: &JobConfig{
@@ -307,9 +307,6 @@ type GCConfig struct {
 type DynConfig struct {
 	// RefreshInterval is refresh interval for manager cache.
 	RefreshInterval time.Duration `yaml:"refreshInterval" mapstructure:"refreshInterval"`
-
-	// CDNDir is cdn dir path.
-	CDNDir string `yaml:"cdnDir" mapstructure:"cdnDir"`
 }
 
 type HostConfig struct {
@@ -334,8 +331,8 @@ type ManagerConfig struct {
 	KeepAlive KeepAliveConfig `yaml:"keepAlive" mapstructure:"keepAlive"`
 }
 
-type CDNConfig struct {
-	// Enable is to enable cdn as P2P peer.
+type SeedPeerConfig struct {
+	// Enable is to enable seed peer as P2P peer.
 	Enable bool `yaml:"enable" mapstructure:"enable"`
 }
 
diff --git a/scheduler/config/dynconfig.go b/scheduler/config/dynconfig.go
index 505b2ffb..7bbfbc20 100644
--- a/scheduler/config/dynconfig.go
+++ b/scheduler/config/dynconfig.go
@@ -40,30 +40,52 @@ var (
 )
 
 type DynconfigData struct {
+	SeedPeers        []*SeedPeer       `yaml:"seedPeers" mapstructure:"seedPeers" json:"seed_peers"`
 	CDNs             []*CDN            `yaml:"cdns" mapstructure:"cdns" json:"cdns"`
 	SchedulerCluster *SchedulerCluster `yaml:"schedulerCluster" mapstructure:"schedulerCluster" json:"scheduler_cluster"`
 }
 
+type SeedPeer struct {
+	ID              uint             `yaml:"id" mapstructure:"id" json:"id"`
+	Hostname        string           `yaml:"hostname" mapstructure:"hostname" json:"host_name"`
+	Type            string           `yaml:"type" mapstructure:"type" json:"type"`
+	IDC             string           `yaml:"idc" mapstructure:"idc" json:"idc"`
+	NetTopology     string           `yaml:"netTopology" mapstructure:"netTopology" json:"net_topology"`
+	Location        string           `yaml:"location" mapstructure:"location" json:"location"`
+	IP              string           `yaml:"ip" mapstructure:"ip" json:"ip"`
+	Port            int32            `yaml:"port" mapstructure:"port" json:"port"`
+	DownloadPort    int32            `yaml:"downloadPort" mapstructure:"downloadPort" json:"download_port"`
+	SeedPeerCluster *SeedPeerCluster `yaml:"seedPeerCluster" mapstructure:"seedPeerCluster" json:"seed_peer_cluster"`
+}
+
+func (c *SeedPeer) GetSeedPeerClusterConfig() (types.SeedPeerClusterConfig, bool) {
+	if c.SeedPeerCluster == nil {
+		return types.SeedPeerClusterConfig{}, false
+	}
+
+	var config types.SeedPeerClusterConfig
+	if err := json.Unmarshal(c.SeedPeerCluster.Config, &config); err != nil {
+		return types.SeedPeerClusterConfig{}, false
+	}
+
+	return config, true
+}
+
+type SeedPeerCluster struct {
+	Config []byte `yaml:"config" mapstructure:"config" json:"config"`
+}
+
 type CDN struct {
 	ID           uint        `yaml:"id" mapstructure:"id" json:"id"`
 	Hostname     string      `yaml:"hostname" mapstructure:"hostname" json:"host_name"`
+	IDC          string      `yaml:"idc" mapstructure:"idc" json:"idc"`
+	Location     string      `yaml:"location" mapstructure:"location" json:"location"`
 	IP           string      `yaml:"ip" mapstructure:"ip" json:"ip"`
 	Port         int32       `yaml:"port" mapstructure:"port" json:"port"`
 	DownloadPort int32       `yaml:"downloadPort" mapstructure:"downloadPort" json:"download_port"`
-	Location     string      `yaml:"location" mapstructure:"location" json:"location"`
-	IDC          string      `yaml:"idc" mapstructure:"idc" json:"idc"`
 	CDNCluster   *CDNCluster `yaml:"cdnCluster" mapstructure:"cdnCluster" json:"cdn_cluster"`
 }
 
-type CDNCluster struct {
-	Config []byte `yaml:"config" mapstructure:"config" json:"config"`
-}
-
-type SchedulerCluster struct {
-	Config       []byte `yaml:"config" mapstructure:"config" json:"config"`
-	ClientConfig []byte `yaml:"clientConfig" mapstructure:"clientConfig" json:"client_config"`
-}
-
 func (c *CDN) GetCDNClusterConfig() (types.CDNClusterConfig, bool) {
 	if c.CDNCluster == nil {
 		return types.CDNClusterConfig{}, false
@@ -77,6 +99,15 @@ func (c *CDN) GetCDNClusterConfig() (types.CDNClusterConfig, bool) {
 	return config, true
 }
 
+type CDNCluster struct {
+	Config []byte `yaml:"config" mapstructure:"config" json:"config"`
+}
+
+type SchedulerCluster struct {
+	Config       []byte `yaml:"config" mapstructure:"config" json:"config"`
+	ClientConfig []byte `yaml:"clientConfig" mapstructure:"clientConfig" json:"client_config"`
+}
+
 type DynconfigInterface interface {
 	// Get the scheduler cluster config.
 	GetSchedulerClusterConfig() (types.SchedulerClusterConfig, bool)
@@ -84,9 +115,6 @@ type DynconfigInterface interface {
 	// Get the client config.
 	GetSchedulerClusterClientConfig() (types.SchedulerClusterClientConfig, bool)
 
-	// Get the cdn cluster config.
-	GetCDNClusterConfig(uint) (types.CDNClusterConfig, bool)
-
 	// Get the dynamic config from manager.
 	Get() (*DynconfigData, error)
 
@@ -115,17 +143,14 @@ type dynconfig struct {
 	*dc.Dynconfig
 	observers map[Observer]struct{}
 	done      chan bool
-	cdnDir    string
 	cachePath string
 }
 
-// TODO(Gaius) Rely on manager to delete cdnDirPath.
 func NewDynconfig(rawManagerClient managerclient.Client, cacheDir string, cfg *Config) (DynconfigInterface, error) {
 	cachePath := filepath.Join(cacheDir, cacheFileName)
 	d := &dynconfig{
 		observers: map[Observer]struct{}{},
 		done:      make(chan bool),
-		cdnDir:    cfg.DynConfig.CDNDir,
 		cachePath: cachePath,
 	}
 
@@ -182,35 +207,8 @@ func (d *dynconfig) GetSchedulerClusterClientConfig() (types.SchedulerClusterCli
 	return config, true
 }
 
-func (d *dynconfig) GetCDNClusterConfig(id uint) (types.CDNClusterConfig, bool) {
-	data, err := d.Get()
-	if err != nil {
-		return types.CDNClusterConfig{}, false
-	}
-
-	for _, cdn := range data.CDNs {
-		if cdn.ID == id {
-			var config types.CDNClusterConfig
-			if err := json.Unmarshal(cdn.CDNCluster.Config, &config); err == nil {
-				return config, true
-			}
-		}
-	}
-
-	return types.CDNClusterConfig{}, false
-}
-
 func (d *dynconfig) Get() (*DynconfigData, error) {
 	var config DynconfigData
-	if d.cdnDir != "" {
-		cdns, err := d.getCDNFromDirPath()
-		if err != nil {
-			return nil, err
-		}
-		config.CDNs = cdns
-		return &config, nil
-	}
-
 	if err := d.Unmarshal(&config); err != nil {
 		return nil, err
 	}
@@ -218,47 +216,6 @@ func (d *dynconfig) Get() (*DynconfigData, error) {
 	return &config, nil
 }
 
-func (d *dynconfig) getCDNFromDirPath() ([]*CDN, error) {
-	files, err := os.ReadDir(d.cdnDir)
-	if err != nil {
-		return nil, err
-	}
-
-	var data []*CDN
-	for _, file := range files {
-		// Skip directory.
-		if file.IsDir() {
-			continue
-		}
-
-		p := filepath.Join(d.cdnDir, file.Name())
-		if file.Type()&os.ModeSymlink != 0 {
-			stat, err := os.Stat(p)
-			if err != nil {
-				logger.Errorf("stat %s error: %s", file.Name(), err)
-				continue
-			}
-			// Skip symbol link directory.
-			if stat.IsDir() {
-				continue
-			}
-		}
-		b, err := os.ReadFile(p)
-		if err != nil {
-			return nil, err
-		}
-
-		var s *CDN
-		if err := json.Unmarshal(b, &s); err != nil {
-			return nil, err
-		}
-
-		data = append(data, s)
-	}
-
-	return data, nil
-}
-
 func (d *dynconfig) Register(l Observer) {
 	d.observers[l] = struct{}{}
 }
diff --git a/scheduler/config/mocks/dynconfig_mock.go b/scheduler/config/mocks/dynconfig_mock.go
index 7ee4208c..5353806e 100644
--- a/scheduler/config/mocks/dynconfig_mock.go
+++ b/scheduler/config/mocks/dynconfig_mock.go
@@ -62,21 +62,6 @@ func (mr *MockDynconfigInterfaceMockRecorder) Get() *gomock.Call {
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockDynconfigInterface)(nil).Get))
 }
 
-// GetCDNClusterConfig mocks base method.
-func (m *MockDynconfigInterface) GetCDNClusterConfig(arg0 uint) (types.CDNClusterConfig, bool) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "GetCDNClusterConfig", arg0)
-	ret0, _ := ret[0].(types.CDNClusterConfig)
-	ret1, _ := ret[1].(bool)
-	return ret0, ret1
-}
-
-// GetCDNClusterConfig indicates an expected call of GetCDNClusterConfig.
-func (mr *MockDynconfigInterfaceMockRecorder) GetCDNClusterConfig(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCDNClusterConfig", reflect.TypeOf((*MockDynconfigInterface)(nil).GetCDNClusterConfig), arg0)
-}
-
 // GetSchedulerClusterClientConfig mocks base method.
 func (m *MockDynconfigInterface) GetSchedulerClusterClientConfig() (types.SchedulerClusterClientConfig, bool) {
 	m.ctrl.T.Helper()
diff --git a/scheduler/job/job.go b/scheduler/job/job.go
index e6e2909f..11e14ed0 100644
--- a/scheduler/job/job.go
+++ b/scheduler/job/job.go
@@ -132,8 +132,8 @@ func (j *job) Stop() {
 }
 
 func (j *job) preheat(ctx context.Context, req string) error {
-	if !j.config.CDN.Enable {
-		return errors.New("scheduler has disabled cdn")
+	if !j.config.SeedPeer.Enable {
+		return errors.New("scheduler has disabled seed peer")
 	}
 
 	request := &internaljob.PreheatRequest{}
@@ -162,11 +162,11 @@ func (j *job) preheat(ctx context.Context, req string) error {
 
 	taskID := idgen.TaskID(request.URL, urlMeta)
 
-	// Trigger CDN download seeds.
+	// Trigger seed peer download seeds.
 	log := logger.WithTaskIDAndURL(taskID, request.URL)
 	log.Infof("preheat %s headers: %#v, tag: %s, range: %s, filter: %s, digest: %s",
 		request.URL, urlMeta.Header, urlMeta.Tag, urlMeta.Range, urlMeta.Filter, urlMeta.Digest)
-	stream, err := j.resource.CDN().Client().ObtainSeeds(ctx, &cdnsystem.SeedRequest{
+	stream, err := j.resource.SeedPeer().Client().ObtainSeeds(ctx, &cdnsystem.SeedRequest{
 		TaskId:  taskID,
 		Url:     request.URL,
 		UrlMeta: urlMeta,
diff --git a/scheduler/resource/cdn.go b/scheduler/resource/cdn.go
deleted file mode 100644
index 123d93cd..00000000
--- a/scheduler/resource/cdn.go
+++ /dev/null
@@ -1,331 +0,0 @@
-/*
- *     Copyright 2020 The Dragonfly Authors
- *
- * Licensed 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.
- */
-
-//go:generate mockgen -destination cdn_mock.go -source cdn.go -package resource
-
-package resource
-
-import (
-	"context"
-	"fmt"
-	"reflect"
-
-	"github.com/pkg/errors"
-	"google.golang.org/grpc"
-
-	logger "d7y.io/dragonfly/v2/internal/dflog"
-	"d7y.io/dragonfly/v2/pkg/dfnet"
-	"d7y.io/dragonfly/v2/pkg/idgen"
-	"d7y.io/dragonfly/v2/pkg/rpc/base/common"
-	"d7y.io/dragonfly/v2/pkg/rpc/cdnsystem"
-	cdnclient "d7y.io/dragonfly/v2/pkg/rpc/cdnsystem/client"
-	rpcscheduler "d7y.io/dragonfly/v2/pkg/rpc/scheduler"
-	"d7y.io/dragonfly/v2/pkg/util/timeutils"
-	"d7y.io/dragonfly/v2/scheduler/config"
-)
-
-const (
-	// Default value of biz tag for cdn peer.
-	cdnBizTag = "d7y/cdn"
-)
-
-type CDN interface {
-	// TriggerTask start to trigger cdn task.
-	TriggerTask(context.Context, *Task) (*Peer, *rpcscheduler.PeerResult, error)
-
-	// Client is cdn grpc client.
-	Client() CDNClient
-}
-
-type cdn struct {
-	// client is cdn dynamic client.
-	client CDNClient
-	// peerManager is peer manager.
-	peerManager PeerManager
-	// hostManager is host manager.
-	hostManager HostManager
-}
-
-// New cdn interface.
-func newCDN(peerManager PeerManager, hostManager HostManager, client CDNClient) CDN {
-	return &cdn{
-		client:      client,
-		peerManager: peerManager,
-		hostManager: hostManager,
-	}
-}
-
-// TriggerTask start to trigger cdn task.
-func (c *cdn) TriggerTask(ctx context.Context, task *Task) (*Peer, *rpcscheduler.PeerResult, error) {
-	stream, err := c.client.ObtainSeeds(ctx, &cdnsystem.SeedRequest{
-		TaskId:  task.ID,
-		Url:     task.URL,
-		UrlMeta: task.URLMeta,
-	})
-	if err != nil {
-		return nil, nil, err
-	}
-
-	var (
-		peer        *Peer
-		initialized bool
-	)
-
-	for {
-		piece, err := stream.Recv()
-		if err != nil {
-			// If the peer initialization succeeds and the download fails,
-			// set peer status is PeerStateFailed.
-			if peer != nil {
-				if err := peer.FSM.Event(PeerEventDownloadFailed); err != nil {
-					return nil, nil, err
-				}
-			}
-
-			return nil, nil, err
-		}
-
-		if !initialized {
-			initialized = true
-
-			// Initialize cdn peer.
-			peer, err = c.initPeer(task, piece)
-			if err != nil {
-				return nil, nil, err
-			}
-		}
-
-		// Handle begin of piece.
-		if piece.PieceInfo != nil && piece.PieceInfo.PieceNum == common.BeginOfPiece {
-			peer.Log.Infof("receive begin of piece from cdn: %#v %#v", piece, piece.PieceInfo)
-			if err := peer.FSM.Event(PeerEventDownload); err != nil {
-				return nil, nil, err
-			}
-			continue
-		}
-
-		// Handle end of piece.
-		if piece.Done {
-			peer.Log.Infof("receive end of from cdn: %#v %#v", piece, piece.PieceInfo)
-			return peer, &rpcscheduler.PeerResult{
-				TotalPieceCount: piece.TotalPieceCount,
-				ContentLength:   piece.ContentLength,
-			}, nil
-		}
-
-		// Handle piece download successfully.
-		peer.Log.Infof("receive piece from cdn: %#v %#v", piece, piece.PieceInfo)
-		peer.Pieces.Set(uint(piece.PieceInfo.PieceNum))
-		peer.AppendPieceCost(timeutils.SubNano(int64(piece.EndTime), int64(piece.BeginTime)).Milliseconds())
-		task.StorePiece(piece.PieceInfo)
-	}
-}
-
-// Initialize cdn peer.
-func (c *cdn) initPeer(task *Task, ps *cdnsystem.PieceSeed) (*Peer, error) {
-	// Load peer from manager.
-	peer, ok := c.peerManager.Load(ps.PeerId)
-	if ok {
-		return peer, nil
-	}
-	task.Log.Infof("can not find cdn peer: %s", ps.PeerId)
-
-	// Load host from manager.
-	host, ok := c.hostManager.Load(ps.HostUuid)
-	if !ok {
-		task.Log.Errorf("can not find cdn host uuid: %s", ps.HostUuid)
-		return nil, errors.Errorf("can not find host uuid: %s", ps.HostUuid)
-	}
-
-	// New cdn peer.
-	peer = NewPeer(ps.PeerId, task, host, WithBizTag(cdnBizTag))
-	peer.Log.Info("new cdn peer successfully")
-
-	// Store cdn peer.
-	c.peerManager.Store(peer)
-	peer.Log.Info("cdn peer has been stored")
-
-	if err := peer.FSM.Event(PeerEventRegisterNormal); err != nil {
-		return nil, err
-	}
-
-	return peer, nil
-}
-
-// Client is cdn grpc client.
-func (c *cdn) Client() CDNClient {
-	return c.client
-}
-
-type CDNClient interface {
-	// cdnclient is cdn grpc client interface.
-	cdnclient.CdnClient
-
-	// Observer is dynconfig observer interface.
-	config.Observer
-}
-
-type cdnClient struct {
-	// hostManager is host manager.
-	hostManager HostManager
-
-	// cdnClient is cdn grpc client instance.
-	cdnclient.CdnClient
-
-	// data is dynconfig data.
-	data *config.DynconfigData
-}
-
-// New cdn client interface.
-func newCDNClient(dynconfig config.DynconfigInterface, hostManager HostManager, opts ...grpc.DialOption) (CDNClient, error) {
-	config, err := dynconfig.Get()
-	if err != nil {
-		return nil, err
-	}
-
-	// Initialize cdn grpc client.
-	client, err := cdnclient.GetClientByAddr(cdnsToNetAddrs(config.CDNs), opts...)
-	if err != nil {
-		return nil, err
-	}
-
-	// Initialize cdn hosts.
-	for _, host := range cdnsToHosts(config.CDNs) {
-		hostManager.Store(host)
-	}
-
-	dc := &cdnClient{
-		hostManager: hostManager,
-		CdnClient:   client,
-		data:        config,
-	}
-
-	dynconfig.Register(dc)
-	return dc, nil
-}
-
-// Dynamic config notify function.
-func (c *cdnClient) OnNotify(data *config.DynconfigData) {
-	var cdns []config.CDN
-	for _, cdn := range data.CDNs {
-		cdns = append(cdns, *cdn)
-	}
-
-	if reflect.DeepEqual(c.data, data) {
-		logger.Infof("cdn addresses deep equal: %#v", cdns)
-		return
-	}
-
-	// If only the ip of the cdn host is changed,
-	// the cdn peer needs to be cleared.
-	diff := diffCDNs(c.data.CDNs, data.CDNs)
-	for _, v := range diff {
-		id := idgen.CDNHostID(v.Hostname, v.Port)
-		if host, ok := c.hostManager.Load(id); ok {
-			host.LeavePeers()
-			c.hostManager.Delete(id)
-		}
-	}
-
-	// Update host manager.
-	for _, host := range cdnsToHosts(data.CDNs) {
-		c.hostManager.Store(host)
-	}
-
-	// Update dynamic data.
-	c.data = data
-
-	// Update grpc cdn addresses.
-	c.UpdateState(cdnsToNetAddrs(data.CDNs))
-	logger.Infof("cdn addresses have been updated: %#v", cdns)
-}
-
-// cdnsToHosts coverts []*config.CDN to map[string]*Host.
-func cdnsToHosts(cdns []*config.CDN) map[string]*Host {
-	hosts := map[string]*Host{}
-	for _, cdn := range cdns {
-		var netTopology string
-		options := []HostOption{WithIsCDN(true)}
-		if config, ok := cdn.GetCDNClusterConfig(); ok && config.LoadLimit > 0 {
-			options = append(options, WithUploadLoadLimit(int32(config.LoadLimit)))
-			netTopology = config.NetTopology
-		}
-
-		id := idgen.CDNHostID(cdn.Hostname, cdn.Port)
-		hosts[id] = NewHost(&rpcscheduler.PeerHost{
-			Uuid:        id,
-			Ip:          cdn.IP,
-			RpcPort:     cdn.Port,
-			DownPort:    cdn.DownloadPort,
-			HostName:    cdn.Hostname,
-			Idc:         cdn.IDC,
-			Location:    cdn.Location,
-			NetTopology: netTopology,
-		}, options...)
-	}
-	return hosts
-}
-
-// cdnsToNetAddrs coverts []*config.CDN to []dfnet.NetAddr.
-func cdnsToNetAddrs(cdns []*config.CDN) []dfnet.NetAddr {
-	netAddrs := make([]dfnet.NetAddr, 0, len(cdns))
-	for _, cdn := range cdns {
-		netAddrs = append(netAddrs, dfnet.NetAddr{
-			Type: dfnet.TCP,
-			Addr: fmt.Sprintf("%s:%d", cdn.IP, cdn.Port),
-		})
-	}
-
-	return netAddrs
-}
-
-// diffCDNs get cdns with the same HostID but different IP.
-func diffCDNs(cx []*config.CDN, cy []*config.CDN) []*config.CDN {
-	var diff []*config.CDN
-	for _, x := range cx {
-		for _, y := range cy {
-			if x.Hostname != y.Hostname {
-				continue
-			}
-
-			if x.Port != y.Port {
-				continue
-			}
-
-			if x.IP == y.IP {
-				continue
-			}
-
-			diff = append(diff, x)
-		}
-	}
-
-	for _, x := range cx {
-		found := false
-		for _, y := range cy {
-			if idgen.CDNHostID(x.Hostname, x.Port) == idgen.CDNHostID(y.Hostname, y.Port) {
-				found = true
-				break
-			}
-		}
-
-		if !found {
-			diff = append(diff, x)
-		}
-	}
-
-	return diff
-}
diff --git a/scheduler/resource/cdn_mock.go b/scheduler/resource/cdn_mock.go
deleted file mode 100644
index 17138375..00000000
--- a/scheduler/resource/cdn_mock.go
+++ /dev/null
@@ -1,193 +0,0 @@
-// Code generated by MockGen. DO NOT EDIT.
-// Source: cdn.go
-
-// Package resource is a generated GoMock package.
-package resource
-
-import (
-	context "context"
-	reflect "reflect"
-
-	dfnet "d7y.io/dragonfly/v2/pkg/dfnet"
-	base "d7y.io/dragonfly/v2/pkg/rpc/base"
-	cdnsystem "d7y.io/dragonfly/v2/pkg/rpc/cdnsystem"
-	client "d7y.io/dragonfly/v2/pkg/rpc/cdnsystem/client"
-	scheduler "d7y.io/dragonfly/v2/pkg/rpc/scheduler"
-	config "d7y.io/dragonfly/v2/scheduler/config"
-	gomock "github.com/golang/mock/gomock"
-	grpc "google.golang.org/grpc"
-)
-
-// MockCDN is a mock of CDN interface.
-type MockCDN struct {
-	ctrl     *gomock.Controller
-	recorder *MockCDNMockRecorder
-}
-
-// MockCDNMockRecorder is the mock recorder for MockCDN.
-type MockCDNMockRecorder struct {
-	mock *MockCDN
-}
-
-// NewMockCDN creates a new mock instance.
-func NewMockCDN(ctrl *gomock.Controller) *MockCDN {
-	mock := &MockCDN{ctrl: ctrl}
-	mock.recorder = &MockCDNMockRecorder{mock}
-	return mock
-}
-
-// EXPECT returns an object that allows the caller to indicate expected use.
-func (m *MockCDN) EXPECT() *MockCDNMockRecorder {
-	return m.recorder
-}
-
-// Client mocks base method.
-func (m *MockCDN) Client() CDNClient {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "Client")
-	ret0, _ := ret[0].(CDNClient)
-	return ret0
-}
-
-// Client indicates an expected call of Client.
-func (mr *MockCDNMockRecorder) Client() *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Client", reflect.TypeOf((*MockCDN)(nil).Client))
-}
-
-// TriggerTask mocks base method.
-func (m *MockCDN) TriggerTask(arg0 context.Context, arg1 *Task) (*Peer, *scheduler.PeerResult, error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "TriggerTask", arg0, arg1)
-	ret0, _ := ret[0].(*Peer)
-	ret1, _ := ret[1].(*scheduler.PeerResult)
-	ret2, _ := ret[2].(error)
-	return ret0, ret1, ret2
-}
-
-// TriggerTask indicates an expected call of TriggerTask.
-func (mr *MockCDNMockRecorder) TriggerTask(arg0, arg1 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TriggerTask", reflect.TypeOf((*MockCDN)(nil).TriggerTask), arg0, arg1)
-}
-
-// MockCDNClient is a mock of CDNClient interface.
-type MockCDNClient struct {
-	ctrl     *gomock.Controller
-	recorder *MockCDNClientMockRecorder
-}
-
-// MockCDNClientMockRecorder is the mock recorder for MockCDNClient.
-type MockCDNClientMockRecorder struct {
-	mock *MockCDNClient
-}
-
-// NewMockCDNClient creates a new mock instance.
-func NewMockCDNClient(ctrl *gomock.Controller) *MockCDNClient {
-	mock := &MockCDNClient{ctrl: ctrl}
-	mock.recorder = &MockCDNClientMockRecorder{mock}
-	return mock
-}
-
-// EXPECT returns an object that allows the caller to indicate expected use.
-func (m *MockCDNClient) EXPECT() *MockCDNClientMockRecorder {
-	return m.recorder
-}
-
-// Close mocks base method.
-func (m *MockCDNClient) Close() error {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "Close")
-	ret0, _ := ret[0].(error)
-	return ret0
-}
-
-// Close indicates an expected call of Close.
-func (mr *MockCDNClientMockRecorder) Close() *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockCDNClient)(nil).Close))
-}
-
-// GetPieceTasks mocks base method.
-func (m *MockCDNClient) GetPieceTasks(ctx context.Context, addr dfnet.NetAddr, req *base.PieceTaskRequest, opts ...grpc.CallOption) (*base.PiecePacket, error) {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{ctx, addr, req}
-	for _, a := range opts {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "GetPieceTasks", varargs...)
-	ret0, _ := ret[0].(*base.PiecePacket)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// GetPieceTasks indicates an expected call of GetPieceTasks.
-func (mr *MockCDNClientMockRecorder) GetPieceTasks(ctx, addr, req interface{}, opts ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{ctx, addr, req}, opts...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPieceTasks", reflect.TypeOf((*MockCDNClient)(nil).GetPieceTasks), varargs...)
-}
-
-// ObtainSeeds mocks base method.
-func (m *MockCDNClient) ObtainSeeds(ctx context.Context, sr *cdnsystem.SeedRequest, opts ...grpc.CallOption) (*client.PieceSeedStream, error) {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{ctx, sr}
-	for _, a := range opts {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "ObtainSeeds", varargs...)
-	ret0, _ := ret[0].(*client.PieceSeedStream)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// ObtainSeeds indicates an expected call of ObtainSeeds.
-func (mr *MockCDNClientMockRecorder) ObtainSeeds(ctx, sr interface{}, opts ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{ctx, sr}, opts...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ObtainSeeds", reflect.TypeOf((*MockCDNClient)(nil).ObtainSeeds), varargs...)
-}
-
-// OnNotify mocks base method.
-func (m *MockCDNClient) OnNotify(arg0 *config.DynconfigData) {
-	m.ctrl.T.Helper()
-	m.ctrl.Call(m, "OnNotify", arg0)
-}
-
-// OnNotify indicates an expected call of OnNotify.
-func (mr *MockCDNClientMockRecorder) OnNotify(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnNotify", reflect.TypeOf((*MockCDNClient)(nil).OnNotify), arg0)
-}
-
-// SyncPieceTasks mocks base method.
-func (m *MockCDNClient) SyncPieceTasks(ctx context.Context, addr dfnet.NetAddr, ptr *base.PieceTaskRequest, opts ...grpc.CallOption) (cdnsystem.Seeder_SyncPieceTasksClient, error) {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{ctx, addr, ptr}
-	for _, a := range opts {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "SyncPieceTasks", varargs...)
-	ret0, _ := ret[0].(cdnsystem.Seeder_SyncPieceTasksClient)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// SyncPieceTasks indicates an expected call of SyncPieceTasks.
-func (mr *MockCDNClientMockRecorder) SyncPieceTasks(ctx, addr, ptr interface{}, opts ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{ctx, addr, ptr}, opts...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SyncPieceTasks", reflect.TypeOf((*MockCDNClient)(nil).SyncPieceTasks), varargs...)
-}
-
-// UpdateState mocks base method.
-func (m *MockCDNClient) UpdateState(addrs []dfnet.NetAddr) {
-	m.ctrl.T.Helper()
-	m.ctrl.Call(m, "UpdateState", addrs)
-}
-
-// UpdateState indicates an expected call of UpdateState.
-func (mr *MockCDNClientMockRecorder) UpdateState(addrs interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateState", reflect.TypeOf((*MockCDNClient)(nil).UpdateState), addrs)
-}
diff --git a/scheduler/resource/host.go b/scheduler/resource/host.go
index c3ef9e2e..612574a1 100644
--- a/scheduler/resource/host.go
+++ b/scheduler/resource/host.go
@@ -27,6 +27,22 @@ import (
 	"d7y.io/dragonfly/v2/scheduler/config"
 )
 
+type HostType int
+
+const (
+	// HostTypeNormal is the normal type of host.
+	HostTypeNormal HostType = iota
+
+	// HostTypeSuperSeed is the super seed type of host.
+	HostTypeSuperSeed
+
+	// HostTypeStrongSeed is the strong seed type of host.
+	HostTypeStrongSeed
+
+	// HostTypeWeakSeed is the weak seed type of host.
+	HostTypeWeakSeed
+)
+
 // HostOption is a functional option for configuring the host.
 type HostOption func(h *Host) *Host
 
@@ -46,10 +62,21 @@ func WithIsCDN(isCDN bool) HostOption {
 	}
 }
 
+// WithHostType sets host's type.
+func WithHostType(hostType HostType) HostOption {
+	return func(h *Host) *Host {
+		h.Type = hostType
+		return h
+	}
+}
+
 type Host struct {
 	// ID is host id.
 	ID string
 
+	// Type is host type.
+	Type HostType
+
 	// IP is host ip.
 	IP string
 
@@ -105,6 +132,7 @@ type Host struct {
 func NewHost(rawHost *scheduler.PeerHost, options ...HostOption) *Host {
 	h := &Host{
 		ID:              rawHost.Uuid,
+		Type:            HostTypeNormal,
 		IP:              rawHost.Ip,
 		Hostname:        rawHost.HostName,
 		Port:            rawHost.RpcPort,
diff --git a/scheduler/resource/host_manager.go b/scheduler/resource/host_manager.go
index 784e4243..225f3cf3 100644
--- a/scheduler/resource/host_manager.go
+++ b/scheduler/resource/host_manager.go
@@ -104,7 +104,10 @@ func (h *hostManager) RunGC() error {
 		host := value.(*Host)
 		elapsed := time.Since(host.UpdateAt.Load())
 
-		if elapsed > h.ttl && host.PeerCount.Load() == 0 && host.UploadPeerCount.Load() == 0 && !host.IsCDN {
+		if elapsed > h.ttl &&
+			host.PeerCount.Load() == 0 &&
+			host.UploadPeerCount.Load() == 0 &&
+			host.Type == HostTypeNormal {
 			host.Log.Info("host has been reclaimed")
 			h.Delete(host.ID)
 		}
diff --git a/scheduler/resource/peer.go b/scheduler/resource/peer.go
index d0790e31..a535b66a 100644
--- a/scheduler/resource/peer.go
+++ b/scheduler/resource/peer.go
@@ -152,7 +152,7 @@ type Peer struct {
 	// NeedBackToSource needs downloaded from source.
 	//
 	// When peer is registering, at the same time,
-	// scheduler needs to create the new corresponding task and the cdn is disabled,
+	// scheduler needs to create the new corresponding task and the seed peer is disabled,
 	// NeedBackToSource is set to true.
 	NeedBackToSource *atomic.Bool
 
@@ -378,7 +378,7 @@ func (p *Peer) Depth() int {
 	for node != nil {
 		depth++
 
-		if node.Host.IsCDN {
+		if node.Host.Type != HostTypeNormal {
 			break
 		}
 
diff --git a/scheduler/resource/resource.go b/scheduler/resource/resource.go
index 9f7ccb46..4a4b8e5f 100644
--- a/scheduler/resource/resource.go
+++ b/scheduler/resource/resource.go
@@ -26,8 +26,8 @@ import (
 )
 
 type Resource interface {
-	// CDN interface.
-	CDN() CDN
+	// SeedPeer interface.
+	SeedPeer() SeedPeer
 
 	// Host manager interface.
 	HostManager() HostManager
@@ -40,8 +40,8 @@ type Resource interface {
 }
 
 type resource struct {
-	// CDN interface.
-	cdn CDN
+	// seedPeer interface.
+	seedPeer SeedPeer
 
 	// Host manager interface.
 	hostManager HostManager
@@ -77,20 +77,21 @@ func New(cfg *config.Config, gc gc.GC, dynconfig config.DynconfigInterface, opts
 	}
 	resource.peerManager = peerManager
 
-	// Initialize cdn interface.
-	if cfg.CDN.Enable {
-		client, err := newCDNClient(dynconfig, hostManager, opts...)
+	// Initialize seed peer interface.
+	if cfg.SeedPeer.Enable {
+		client, err := newSeedPeerClient(dynconfig, hostManager, opts...)
 		if err != nil {
 			return nil, err
 		}
-		resource.cdn = newCDN(peerManager, hostManager, client)
+
+		resource.seedPeer = newSeedPeer(client, peerManager, hostManager)
 	}
 
 	return resource, nil
 }
 
-func (r *resource) CDN() CDN {
-	return r.cdn
+func (r *resource) SeedPeer() SeedPeer {
+	return r.seedPeer
 }
 
 func (r *resource) HostManager() HostManager {
diff --git a/scheduler/resource/resource_mock.go b/scheduler/resource/resource_mock.go
index 7f97d300..3a8602da 100644
--- a/scheduler/resource/resource_mock.go
+++ b/scheduler/resource/resource_mock.go
@@ -33,20 +33,6 @@ func (m *MockResource) EXPECT() *MockResourceMockRecorder {
 	return m.recorder
 }
 
-// CDN mocks base method.
-func (m *MockResource) CDN() CDN {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "CDN")
-	ret0, _ := ret[0].(CDN)
-	return ret0
-}
-
-// CDN indicates an expected call of CDN.
-func (mr *MockResourceMockRecorder) CDN() *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CDN", reflect.TypeOf((*MockResource)(nil).CDN))
-}
-
 // HostManager mocks base method.
 func (m *MockResource) HostManager() HostManager {
 	m.ctrl.T.Helper()
@@ -75,6 +61,20 @@ func (mr *MockResourceMockRecorder) PeerManager() *gomock.Call {
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PeerManager", reflect.TypeOf((*MockResource)(nil).PeerManager))
 }
 
+// SeedPeer mocks base method.
+func (m *MockResource) SeedPeer() SeedPeer {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "SeedPeer")
+	ret0, _ := ret[0].(SeedPeer)
+	return ret0
+}
+
+// SeedPeer indicates an expected call of SeedPeer.
+func (mr *MockResourceMockRecorder) SeedPeer() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SeedPeer", reflect.TypeOf((*MockResource)(nil).SeedPeer))
+}
+
 // TaskManager mocks base method.
 func (m *MockResource) TaskManager() TaskManager {
 	m.ctrl.T.Helper()
diff --git a/scheduler/resource/seed_peer.go b/scheduler/resource/seed_peer.go
new file mode 100644
index 00000000..391fd66d
--- /dev/null
+++ b/scheduler/resource/seed_peer.go
@@ -0,0 +1,164 @@
+/*
+ *     Copyright 2022 The Dragonfly Authors
+ *
+ * Licensed 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.
+ */
+
+//go:generate mockgen -destination seed_peer_mock.go -source seed_peer.go -package resource
+
+package resource
+
+import (
+	"context"
+
+	"github.com/pkg/errors"
+
+	"d7y.io/dragonfly/v2/pkg/rpc/base/common"
+	"d7y.io/dragonfly/v2/pkg/rpc/cdnsystem"
+	rpcscheduler "d7y.io/dragonfly/v2/pkg/rpc/scheduler"
+	"d7y.io/dragonfly/v2/pkg/util/timeutils"
+)
+
+const (
+	// Default value of biz tag for seed peer.
+	SeedBizTag = "d7y/seed"
+)
+
+type SeedPeer interface {
+	// TriggerTask triggers the seed peer to download the task.
+	TriggerTask(context.Context, *Task) (*Peer, *rpcscheduler.PeerResult, error)
+
+	// Client returns grpc client of seed peer.
+	Client() SeedPeerClient
+}
+
+type seedPeer struct {
+	// client is the dynamic client of seed peer.
+	client SeedPeerClient
+	// peerManager is PeerManager interface.
+	peerManager PeerManager
+	// hostManager is HostManager interface.
+	hostManager HostManager
+}
+
+// New SeedPeer interface.
+func newSeedPeer(client SeedPeerClient, peerManager PeerManager, hostManager HostManager) SeedPeer {
+	return &seedPeer{
+		client:      client,
+		peerManager: peerManager,
+		hostManager: hostManager,
+	}
+}
+
+// TriggerTask start to trigger seed peer task.
+func (s *seedPeer) TriggerTask(ctx context.Context, task *Task) (*Peer, *rpcscheduler.PeerResult, error) {
+	stream, err := s.client.ObtainSeeds(ctx, &cdnsystem.SeedRequest{
+		TaskId:  task.ID,
+		Url:     task.URL,
+		UrlMeta: task.URLMeta,
+	})
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var (
+		peer        *Peer
+		initialized bool
+	)
+
+	for {
+		piece, err := stream.Recv()
+		if err != nil {
+			// If the peer initialization succeeds and the download fails,
+			// set peer status is PeerStateFailed.
+			if peer != nil {
+				if err := peer.FSM.Event(PeerEventDownloadFailed); err != nil {
+					return nil, nil, err
+				}
+			}
+
+			return nil, nil, err
+		}
+
+		if !initialized {
+			initialized = true
+
+			// Initialize seed peer.
+			peer, err = s.initSeedPeer(task, piece)
+			if err != nil {
+				return nil, nil, err
+			}
+		}
+
+		// Handle begin of piece.
+		if piece.PieceInfo != nil && piece.PieceInfo.PieceNum == common.BeginOfPiece {
+			peer.Log.Infof("receive begin of piece from seed peer: %#v %#v", piece, piece.PieceInfo)
+			if err := peer.FSM.Event(PeerEventDownload); err != nil {
+				return nil, nil, err
+			}
+
+			continue
+		}
+
+		// Handle end of piece.
+		if piece.Done {
+			peer.Log.Infof("receive end of from seed peer: %#v %#v", piece, piece.PieceInfo)
+			return peer, &rpcscheduler.PeerResult{
+				TotalPieceCount: piece.TotalPieceCount,
+				ContentLength:   piece.ContentLength,
+			}, nil
+		}
+
+		// Handle piece download successfully.
+		peer.Log.Infof("receive piece from seed peer: %#v %#v", piece, piece.PieceInfo)
+		peer.Pieces.Set(uint(piece.PieceInfo.PieceNum))
+		peer.AppendPieceCost(timeutils.SubNano(int64(piece.EndTime), int64(piece.BeginTime)).Milliseconds())
+		task.StorePiece(piece.PieceInfo)
+	}
+}
+
+// Initialize seed peer.
+func (s *seedPeer) initSeedPeer(task *Task, ps *cdnsystem.PieceSeed) (*Peer, error) {
+	// Load peer from manager.
+	peer, ok := s.peerManager.Load(ps.PeerId)
+	if ok {
+		return peer, nil
+	}
+	task.Log.Infof("can not find seed peer: %s", ps.PeerId)
+
+	// Load host from manager.
+	host, ok := s.hostManager.Load(ps.HostUuid)
+	if !ok {
+		task.Log.Errorf("can not find seed host uuid: %s", ps.HostUuid)
+		return nil, errors.Errorf("can not find host uuid: %s", ps.HostUuid)
+	}
+
+	// New seed peer.
+	peer = NewPeer(ps.PeerId, task, host, WithBizTag(SeedBizTag))
+	peer.Log.Info("new seed peer successfully")
+
+	// Store seed peer.
+	s.peerManager.Store(peer)
+	peer.Log.Info("seed peer has been stored")
+
+	if err := peer.FSM.Event(PeerEventRegisterNormal); err != nil {
+		return nil, err
+	}
+
+	return peer, nil
+}
+
+// Client is seed peer grpc client.
+func (s *seedPeer) Client() SeedPeerClient {
+	return s.client
+}
diff --git a/scheduler/resource/seed_peer_client.go b/scheduler/resource/seed_peer_client.go
new file mode 100644
index 00000000..a4aca10a
--- /dev/null
+++ b/scheduler/resource/seed_peer_client.go
@@ -0,0 +1,316 @@
+/*
+ *     Copyright 2022 The Dragonfly Authors
+ *
+ * Licensed 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.
+ */
+
+//go:generate mockgen -destination seed_peer_client_mock.go -source seed_peer_client.go -package resource
+
+package resource
+
+import (
+	"fmt"
+	reflect "reflect"
+
+	"google.golang.org/grpc"
+
+	logger "d7y.io/dragonfly/v2/internal/dflog"
+	"d7y.io/dragonfly/v2/manager/model"
+	"d7y.io/dragonfly/v2/pkg/dfnet"
+	"d7y.io/dragonfly/v2/pkg/idgen"
+	client "d7y.io/dragonfly/v2/pkg/rpc/cdnsystem/client"
+	rpcscheduler "d7y.io/dragonfly/v2/pkg/rpc/scheduler"
+	"d7y.io/dragonfly/v2/scheduler/config"
+)
+
+type SeedPeerClient interface {
+	// client is seed peer grpc client interface.
+	client.CdnClient
+
+	// Observer is dynconfig observer interface.
+	config.Observer
+}
+
+type seedPeerClient struct {
+	// hostManager is host manager.
+	hostManager HostManager
+
+	// client is sedd peer grpc client instance.
+	client.CdnClient
+
+	// data is dynconfig data.
+	data *config.DynconfigData
+}
+
+// New seed peer client interface.
+func newSeedPeerClient(dynconfig config.DynconfigInterface, hostManager HostManager, opts ...grpc.DialOption) (SeedPeerClient, error) {
+	config, err := dynconfig.Get()
+	if err != nil {
+		return nil, err
+	}
+
+	// Initialize seed peer grpc client.
+	netAddrs := append(seedPeersToNetAddrs(config.SeedPeers), cdnsToNetAddrs(config.CDNs)...)
+	client, err := client.GetClientByAddr(netAddrs, opts...)
+	if err != nil {
+		return nil, err
+	}
+
+	// Initialize seed hosts.
+	for _, host := range seedPeersToHosts(config.SeedPeers) {
+		hostManager.Store(host)
+	}
+
+	// Initialize cdn hosts.
+	for _, host := range cdnsToHosts(config.CDNs) {
+		hostManager.Store(host)
+	}
+
+	dc := &seedPeerClient{
+		hostManager: hostManager,
+		CdnClient:   client,
+		data:        config,
+	}
+
+	dynconfig.Register(dc)
+	return dc, nil
+}
+
+// Dynamic config notify function.
+func (sc *seedPeerClient) OnNotify(data *config.DynconfigData) {
+	var seedPeers []config.SeedPeer
+	for _, seedPeer := range data.SeedPeers {
+		seedPeers = append(seedPeers, *seedPeer)
+	}
+
+	var cdns []config.CDN
+	for _, cdn := range data.CDNs {
+		cdns = append(cdns, *cdn)
+	}
+
+	if reflect.DeepEqual(sc.data, data) {
+		logger.Infof("addresses deep equal: %#v %#v", seedPeers, cdns)
+		return
+	}
+
+	// If only the ip of the seed peer is changed,
+	// the seed peer needs to be cleared.
+	diffSeedPeers := diffSeedPeers(sc.data.SeedPeers, data.SeedPeers)
+	for _, seedPeer := range diffSeedPeers {
+		id := idgen.SeedHostID(seedPeer.Hostname, seedPeer.Port)
+		if host, ok := sc.hostManager.Load(id); ok {
+			host.LeavePeers()
+			sc.hostManager.Delete(id)
+		}
+	}
+
+	// Update seed host in host manager.
+	for _, host := range seedPeersToHosts(data.SeedPeers) {
+		sc.hostManager.Store(host)
+	}
+
+	// If only the ip of the cdn host is changed,
+	// the cdn peer needs to be cleared.
+	diffCDNs := diffCDNs(sc.data.CDNs, data.CDNs)
+	for _, cdn := range diffCDNs {
+		id := idgen.CDNHostID(cdn.Hostname, cdn.Port)
+		if host, ok := sc.hostManager.Load(id); ok {
+			host.LeavePeers()
+			sc.hostManager.Delete(id)
+		}
+	}
+
+	// Update cdn in host manager.
+	for _, host := range cdnsToHosts(data.CDNs) {
+		sc.hostManager.Store(host)
+	}
+
+	// Update dynamic data.
+	sc.data = data
+
+	// Update grpc seed peer addresses.
+	netAddrs := append(seedPeersToNetAddrs(data.SeedPeers), cdnsToNetAddrs(data.CDNs)...)
+	sc.UpdateState(netAddrs)
+	logger.Infof("addresses have been updated: %#v %#v", seedPeers, cdns)
+}
+
+// seedPeersToHosts coverts []*config.SeedPeer to map[string]*Host.
+func seedPeersToHosts(seedPeers []*config.SeedPeer) map[string]*Host {
+	hosts := map[string]*Host{}
+	for _, seedPeer := range seedPeers {
+		options := []HostOption{WithHostType(seedPeerTypeToHostType(seedPeer.Type))}
+		if config, ok := seedPeer.GetSeedPeerClusterConfig(); ok && config.LoadLimit > 0 {
+			options = append(options, WithUploadLoadLimit(int32(config.LoadLimit)))
+		}
+
+		id := idgen.SeedHostID(seedPeer.Hostname, seedPeer.Port)
+		hosts[id] = NewHost(&rpcscheduler.PeerHost{
+			Uuid:        id,
+			Ip:          seedPeer.IP,
+			RpcPort:     seedPeer.Port,
+			DownPort:    seedPeer.DownloadPort,
+			HostName:    seedPeer.Hostname,
+			Idc:         seedPeer.IDC,
+			Location:    seedPeer.Location,
+			NetTopology: seedPeer.NetTopology,
+		}, options...)
+	}
+
+	return hosts
+}
+
+// seedPeerTypeToHostType coverts seed peer type to HostType.
+func seedPeerTypeToHostType(seedPeerType string) HostType {
+	switch seedPeerType {
+	case model.SeedPeerTypeSuperSeed:
+		return HostTypeSuperSeed
+	case model.SeedPeerTypeStrongSeed:
+		return HostTypeStrongSeed
+	case model.SeedPeerTypeWeakSeed:
+		return HostTypeWeakSeed
+	}
+
+	return HostTypeWeakSeed
+}
+
+// seedPeersToNetAddrs coverts []*config.SeedPeer to []dfnet.NetAddr.
+func seedPeersToNetAddrs(seedPeers []*config.SeedPeer) []dfnet.NetAddr {
+	netAddrs := make([]dfnet.NetAddr, 0, len(seedPeers))
+	for _, seedPeer := range seedPeers {
+		netAddrs = append(netAddrs, dfnet.NetAddr{
+			Type: dfnet.TCP,
+			Addr: fmt.Sprintf("%s:%d", seedPeer.IP, seedPeer.Port),
+		})
+	}
+
+	return netAddrs
+}
+
+// diffSeedPeers find out different seed peers.
+func diffSeedPeers(sx []*config.SeedPeer, sy []*config.SeedPeer) []*config.SeedPeer {
+	// Get seedPeers with the same HostID but different IP.
+	var diff []*config.SeedPeer
+	for _, x := range sx {
+		for _, y := range sy {
+			if x.Hostname != y.Hostname {
+				continue
+			}
+
+			if x.Port != y.Port {
+				continue
+			}
+
+			if x.IP == y.IP {
+				continue
+			}
+
+			diff = append(diff, x)
+		}
+	}
+
+	// Get the removed seed peers.
+	for _, x := range sx {
+		found := false
+		for _, y := range sy {
+			if idgen.SeedHostID(x.Hostname, x.Port) == idgen.SeedHostID(y.Hostname, y.Port) {
+				found = true
+				break
+			}
+		}
+
+		if !found {
+			diff = append(diff, x)
+		}
+	}
+
+	return diff
+}
+
+// cdnsToHosts coverts []*config.CDN to map[string]*Host.
+func cdnsToHosts(cdns []*config.CDN) map[string]*Host {
+	hosts := map[string]*Host{}
+	for _, cdn := range cdns {
+		var netTopology string
+		options := []HostOption{WithHostType(HostTypeSuperSeed), WithIsCDN(true)}
+		if config, ok := cdn.GetCDNClusterConfig(); ok && config.LoadLimit > 0 {
+			options = append(options, WithUploadLoadLimit(int32(config.LoadLimit)))
+			netTopology = config.NetTopology
+		}
+
+		id := idgen.CDNHostID(cdn.Hostname, cdn.Port)
+		hosts[id] = NewHost(&rpcscheduler.PeerHost{
+			Uuid:        id,
+			Ip:          cdn.IP,
+			RpcPort:     cdn.Port,
+			DownPort:    cdn.DownloadPort,
+			HostName:    cdn.Hostname,
+			Idc:         cdn.IDC,
+			Location:    cdn.Location,
+			NetTopology: netTopology,
+		}, options...)
+	}
+	return hosts
+}
+
+// cdnsToNetAddrs coverts []*config.CDN to []dfnet.NetAddr.
+func cdnsToNetAddrs(cdns []*config.CDN) []dfnet.NetAddr {
+	netAddrs := make([]dfnet.NetAddr, 0, len(cdns))
+	for _, cdn := range cdns {
+		netAddrs = append(netAddrs, dfnet.NetAddr{
+			Type: dfnet.TCP,
+			Addr: fmt.Sprintf("%s:%d", cdn.IP, cdn.Port),
+		})
+	}
+
+	return netAddrs
+}
+
+// diffCDNs find out different cdns.
+func diffCDNs(cx []*config.CDN, cy []*config.CDN) []*config.CDN {
+	// Get cdns with the same HostID but different IP.
+	var diff []*config.CDN
+	for _, x := range cx {
+		for _, y := range cy {
+			if x.Hostname != y.Hostname {
+				continue
+			}
+
+			if x.Port != y.Port {
+				continue
+			}
+
+			if x.IP == y.IP {
+				continue
+			}
+
+			diff = append(diff, x)
+		}
+	}
+
+	// Get the removed cdns.
+	for _, x := range cx {
+		found := false
+		for _, y := range cy {
+			if idgen.CDNHostID(x.Hostname, x.Port) == idgen.CDNHostID(y.Hostname, y.Port) {
+				found = true
+				break
+			}
+		}
+
+		if !found {
+			diff = append(diff, x)
+		}
+	}
+
+	return diff
+}
diff --git a/scheduler/resource/seed_peer_client_mock.go b/scheduler/resource/seed_peer_client_mock.go
new file mode 100644
index 00000000..b16973ee
--- /dev/null
+++ b/scheduler/resource/seed_peer_client_mock.go
@@ -0,0 +1,139 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: seed_peer_client.go
+
+// Package resource is a generated GoMock package.
+package resource
+
+import (
+	context "context"
+	reflect "reflect"
+
+	dfnet "d7y.io/dragonfly/v2/pkg/dfnet"
+	base "d7y.io/dragonfly/v2/pkg/rpc/base"
+	cdnsystem "d7y.io/dragonfly/v2/pkg/rpc/cdnsystem"
+	client "d7y.io/dragonfly/v2/pkg/rpc/cdnsystem/client"
+	config "d7y.io/dragonfly/v2/scheduler/config"
+	gomock "github.com/golang/mock/gomock"
+	grpc "google.golang.org/grpc"
+)
+
+// MockSeedPeerClient is a mock of SeedPeerClient interface.
+type MockSeedPeerClient struct {
+	ctrl     *gomock.Controller
+	recorder *MockSeedPeerClientMockRecorder
+}
+
+// MockSeedPeerClientMockRecorder is the mock recorder for MockSeedPeerClient.
+type MockSeedPeerClientMockRecorder struct {
+	mock *MockSeedPeerClient
+}
+
+// NewMockSeedPeerClient creates a new mock instance.
+func NewMockSeedPeerClient(ctrl *gomock.Controller) *MockSeedPeerClient {
+	mock := &MockSeedPeerClient{ctrl: ctrl}
+	mock.recorder = &MockSeedPeerClientMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockSeedPeerClient) EXPECT() *MockSeedPeerClientMockRecorder {
+	return m.recorder
+}
+
+// Close mocks base method.
+func (m *MockSeedPeerClient) Close() error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Close")
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// Close indicates an expected call of Close.
+func (mr *MockSeedPeerClientMockRecorder) Close() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockSeedPeerClient)(nil).Close))
+}
+
+// GetPieceTasks mocks base method.
+func (m *MockSeedPeerClient) GetPieceTasks(ctx context.Context, addr dfnet.NetAddr, req *base.PieceTaskRequest, opts ...grpc.CallOption) (*base.PiecePacket, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{ctx, addr, req}
+	for _, a := range opts {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "GetPieceTasks", varargs...)
+	ret0, _ := ret[0].(*base.PiecePacket)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// GetPieceTasks indicates an expected call of GetPieceTasks.
+func (mr *MockSeedPeerClientMockRecorder) GetPieceTasks(ctx, addr, req interface{}, opts ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{ctx, addr, req}, opts...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPieceTasks", reflect.TypeOf((*MockSeedPeerClient)(nil).GetPieceTasks), varargs...)
+}
+
+// ObtainSeeds mocks base method.
+func (m *MockSeedPeerClient) ObtainSeeds(ctx context.Context, sr *cdnsystem.SeedRequest, opts ...grpc.CallOption) (*client.PieceSeedStream, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{ctx, sr}
+	for _, a := range opts {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "ObtainSeeds", varargs...)
+	ret0, _ := ret[0].(*client.PieceSeedStream)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// ObtainSeeds indicates an expected call of ObtainSeeds.
+func (mr *MockSeedPeerClientMockRecorder) ObtainSeeds(ctx, sr interface{}, opts ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{ctx, sr}, opts...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ObtainSeeds", reflect.TypeOf((*MockSeedPeerClient)(nil).ObtainSeeds), varargs...)
+}
+
+// OnNotify mocks base method.
+func (m *MockSeedPeerClient) OnNotify(arg0 *config.DynconfigData) {
+	m.ctrl.T.Helper()
+	m.ctrl.Call(m, "OnNotify", arg0)
+}
+
+// OnNotify indicates an expected call of OnNotify.
+func (mr *MockSeedPeerClientMockRecorder) OnNotify(arg0 interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnNotify", reflect.TypeOf((*MockSeedPeerClient)(nil).OnNotify), arg0)
+}
+
+// SyncPieceTasks mocks base method.
+func (m *MockSeedPeerClient) SyncPieceTasks(ctx context.Context, addr dfnet.NetAddr, ptr *base.PieceTaskRequest, opts ...grpc.CallOption) (cdnsystem.Seeder_SyncPieceTasksClient, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{ctx, addr, ptr}
+	for _, a := range opts {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "SyncPieceTasks", varargs...)
+	ret0, _ := ret[0].(cdnsystem.Seeder_SyncPieceTasksClient)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// SyncPieceTasks indicates an expected call of SyncPieceTasks.
+func (mr *MockSeedPeerClientMockRecorder) SyncPieceTasks(ctx, addr, ptr interface{}, opts ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{ctx, addr, ptr}, opts...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SyncPieceTasks", reflect.TypeOf((*MockSeedPeerClient)(nil).SyncPieceTasks), varargs...)
+}
+
+// UpdateState mocks base method.
+func (m *MockSeedPeerClient) UpdateState(addrs []dfnet.NetAddr) {
+	m.ctrl.T.Helper()
+	m.ctrl.Call(m, "UpdateState", addrs)
+}
+
+// UpdateState indicates an expected call of UpdateState.
+func (mr *MockSeedPeerClientMockRecorder) UpdateState(addrs interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateState", reflect.TypeOf((*MockSeedPeerClient)(nil).UpdateState), addrs)
+}
diff --git a/scheduler/resource/seed_peer_mock.go b/scheduler/resource/seed_peer_mock.go
new file mode 100644
index 00000000..d38ffdfb
--- /dev/null
+++ b/scheduler/resource/seed_peer_mock.go
@@ -0,0 +1,66 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: seed_peer.go
+
+// Package resource is a generated GoMock package.
+package resource
+
+import (
+	context "context"
+	reflect "reflect"
+
+	scheduler "d7y.io/dragonfly/v2/pkg/rpc/scheduler"
+	gomock "github.com/golang/mock/gomock"
+)
+
+// MockSeedPeer is a mock of SeedPeer interface.
+type MockSeedPeer struct {
+	ctrl     *gomock.Controller
+	recorder *MockSeedPeerMockRecorder
+}
+
+// MockSeedPeerMockRecorder is the mock recorder for MockSeedPeer.
+type MockSeedPeerMockRecorder struct {
+	mock *MockSeedPeer
+}
+
+// NewMockSeedPeer creates a new mock instance.
+func NewMockSeedPeer(ctrl *gomock.Controller) *MockSeedPeer {
+	mock := &MockSeedPeer{ctrl: ctrl}
+	mock.recorder = &MockSeedPeerMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockSeedPeer) EXPECT() *MockSeedPeerMockRecorder {
+	return m.recorder
+}
+
+// Client mocks base method.
+func (m *MockSeedPeer) Client() SeedPeerClient {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Client")
+	ret0, _ := ret[0].(SeedPeerClient)
+	return ret0
+}
+
+// Client indicates an expected call of Client.
+func (mr *MockSeedPeerMockRecorder) Client() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Client", reflect.TypeOf((*MockSeedPeer)(nil).Client))
+}
+
+// TriggerTask mocks base method.
+func (m *MockSeedPeer) TriggerTask(arg0 context.Context, arg1 *Task) (*Peer, *scheduler.PeerResult, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "TriggerTask", arg0, arg1)
+	ret0, _ := ret[0].(*Peer)
+	ret1, _ := ret[1].(*scheduler.PeerResult)
+	ret2, _ := ret[2].(error)
+	return ret0, ret1, ret2
+}
+
+// TriggerTask indicates an expected call of TriggerTask.
+func (mr *MockSeedPeerMockRecorder) TriggerTask(arg0, arg1 interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TriggerTask", reflect.TypeOf((*MockSeedPeer)(nil).TriggerTask), arg0, arg1)
+}
diff --git a/scheduler/resource/task.go b/scheduler/resource/task.go
index 4c35e5ae..dde28aa7 100644
--- a/scheduler/resource/task.go
+++ b/scheduler/resource/task.go
@@ -54,7 +54,7 @@ const (
 	// Task has been created but did not start running.
 	TaskStatePending = "Pending"
 
-	// Task is downloading resources from CDN or back-to-source.
+	// Task is downloading resources from seed peer or back-to-source.
 	TaskStateRunning = "Running"
 
 	// Task has been downloaded successfully.
@@ -245,8 +245,8 @@ func (t *Task) HasAvailablePeer() bool {
 	return hasAvailablePeer
 }
 
-// LoadCDNPeer return latest cdn peer in peers sync map.
-func (t *Task) LoadCDNPeer() (*Peer, bool) {
+// LoadSeedPeer return latest seed peer in peers sync map.
+func (t *Task) LoadSeedPeer() (*Peer, bool) {
 	var peers []*Peer
 	t.Peers.Range(func(_, v interface{}) bool {
 		peer, ok := v.(*Peer)
@@ -254,7 +254,7 @@ func (t *Task) LoadCDNPeer() (*Peer, bool) {
 			return true
 		}
 
-		if peer.Host.IsCDN {
+		if peer.Host.Type != HostTypeNormal {
 			peers = append(peers, peer)
 		}
 
@@ -275,10 +275,10 @@ func (t *Task) LoadCDNPeer() (*Peer, bool) {
 	return nil, false
 }
 
-// IsCDNFailed returns whether the cdn in the task failed.
-func (t *Task) IsCDNFailed() bool {
-	cdnPeer, ok := t.LoadCDNPeer()
-	return ok && cdnPeer.FSM.Is(PeerStateFailed)
+// IsSeedPeerFailed returns whether the seed peer in the task failed.
+func (t *Task) IsSeedPeerFailed() bool {
+	seedPeer, ok := t.LoadSeedPeer()
+	return ok && seedPeer.FSM.Is(PeerStateFailed)
 }
 
 // LoadPiece return piece for a key.
diff --git a/scheduler/rpcserver/rpcserver.go b/scheduler/rpcserver/rpcserver.go
index 36fdc10a..93c05697 100644
--- a/scheduler/rpcserver/rpcserver.go
+++ b/scheduler/rpcserver/rpcserver.go
@@ -51,7 +51,7 @@ func New(service *service.Service, opts ...grpc.ServerOption) *grpc.Server {
 	return grpcServer
 }
 
-// RegisterPeerTask registers peer and triggers CDN download task.
+// RegisterPeerTask registers peer and triggers seed peer download task.
 func (s *Server) RegisterPeerTask(ctx context.Context, req *scheduler.PeerTaskRequest) (*scheduler.RegisterResult, error) {
 	bizTag := resource.DefaultBizTag
 	if req.UrlMeta.Tag != "" {
diff --git a/scheduler/scheduler/evaluator/evaluator_base.go b/scheduler/scheduler/evaluator/evaluator_base.go
index f41ac173..a8aea565 100644
--- a/scheduler/scheduler/evaluator/evaluator_base.go
+++ b/scheduler/scheduler/evaluator/evaluator_base.go
@@ -122,9 +122,9 @@ func calculateFreeLoadScore(host *resource.Host) float64 {
 // calculateHostTypeAffinityScore 0.0~1.0 larger and better.
 func calculateHostTypeAffinityScore(peer *resource.Peer) float64 {
 	// When the task is downloaded for the first time,
-	// peer will be scheduled to cdn first,
+	// peer will be scheduled to seed peer first,
 	// otherwise it will be scheduled to dfdaemon first.
-	if peer.Host.IsCDN {
+	if peer.Host.Type != resource.HostTypeNormal {
 		if peer.FSM.Is(resource.PeerStateReceivedNormal) ||
 			peer.FSM.Is(resource.PeerStateRunning) {
 			return maxScore
diff --git a/scheduler/scheduler/scheduler.go b/scheduler/scheduler/scheduler.go
index 9089d902..86abb33f 100644
--- a/scheduler/scheduler/scheduler.go
+++ b/scheduler/scheduler/scheduler.go
@@ -80,11 +80,11 @@ func (s *scheduler) ScheduleParent(ctx context.Context, peer *resource.Peer, blo
 		default:
 		}
 
-		// If the scheduling exceeds the RetryBackSourceLimit or the latest cdn peer state is PeerStateFailed,
+		// If the scheduling exceeds the RetryBackSourceLimit or the latest seed peer state is PeerStateFailed,
 		// peer will download the task back-to-source.
-		isCDNFailed := peer.Task.IsCDNFailed()
+		isSeedPeerFailed := peer.Task.IsSeedPeerFailed()
 		needBackToSource := peer.NeedBackToSource.Load()
-		if (n >= s.config.RetryBackSourceLimit || isCDNFailed || needBackToSource) &&
+		if (n >= s.config.RetryBackSourceLimit || isSeedPeerFailed || needBackToSource) &&
 			peer.Task.CanBackToSource() {
 			stream, ok := peer.LoadStream()
 			if !ok {
@@ -92,8 +92,8 @@ func (s *scheduler) ScheduleParent(ctx context.Context, peer *resource.Peer, blo
 				return
 			}
 
-			peer.Log.Infof("peer downloads back-to-source, scheduling %d times, cdn is failed %t, peer need back-to-source %t",
-				n, isCDNFailed, needBackToSource)
+			peer.Log.Infof("peer downloads back-to-source, scheduling %d times, seed peer is failed %t, peer need back-to-source %t",
+				n, isSeedPeerFailed, needBackToSource)
 
 			// Notify peer back-to-source.
 			if err := stream.Send(&rpcscheduler.PeerPacket{Code: base.Code_SchedNeedBackSource}); err != nil {
@@ -264,15 +264,15 @@ func (s *scheduler) filterCandidateParents(peer *resource.Peer, blocklist set.Sa
 
 		// Conditions for candidate parent to be a parent:
 		// 1. candidate parent has parent.
-		// 2. candidate parent is CDN.
+		// 2. candidate parent is seed peer.
 		// 3. candidate parent has been back-to-source.
 		// 4. candidate parent has been succeeded.
 		_, ok = candidateParent.LoadParent()
 		isBackToSource := candidateParent.IsBackToSource.Load()
-		if !ok && !candidateParent.Host.IsCDN && !isBackToSource &&
+		if !ok && candidateParent.Host.Type == resource.HostTypeNormal && !isBackToSource &&
 			!candidateParent.FSM.Is(resource.PeerStateSucceeded) {
-			peer.Log.Debugf("candidate parent %s is not selected, because its download state is %t %t %t %s",
-				candidateParent.ID, ok, candidateParent.Host.IsCDN, isBackToSource, candidateParent.FSM.Current())
+			peer.Log.Debugf("candidate parent %s is not selected, because its download state is %t %d %t %s",
+				candidateParent.ID, ok, int(candidateParent.Host.Type), isBackToSource, candidateParent.FSM.Current())
 			return true
 		}
 
diff --git a/scheduler/service/service.go b/scheduler/service/service.go
index bb671eb7..21acab84 100644
--- a/scheduler/service/service.go
+++ b/scheduler/service/service.go
@@ -74,9 +74,9 @@ func New(
 	}
 }
 
-// RegisterPeerTask registers peer and triggers CDN download task.
+// RegisterPeerTask registers peer and triggers seed peer download task.
 func (s *Service) RegisterPeerTask(ctx context.Context, req *rpcscheduler.PeerTaskRequest) (*rpcscheduler.RegisterResult, error) {
-	// Register task and trigger cdn download task.
+	// Register task and trigger seed peer download task.
 	task, needBackToSource, err := s.registerTask(ctx, req)
 	if err != nil {
 		msg := fmt.Sprintf("peer %s register is failed: %s", req.PeerId, err.Error())
@@ -88,7 +88,7 @@ func (s *Service) RegisterPeerTask(ctx context.Context, req *rpcscheduler.PeerTa
 	peer.Log.Infof("register peer task request: %#v %#v %#v", req, req.UrlMeta, req.HostLoad)
 
 	// When the peer registers for the first time and
-	// does not have a CDN, it will back-to-source.
+	// does not have a seed peer, it will back-to-source.
 	peer.NeedBackToSource.Store(needBackToSource)
 
 	// The task state is TaskStateSucceeded and SizeScope is not invalid.
@@ -521,9 +521,9 @@ func (s *Service) registerTask(ctx context.Context, req *rpcscheduler.PeerTaskRe
 		return nil, false, err
 	}
 
-	// Start trigger cdn task.
-	if s.config.CDN.Enable {
-		go s.triggerCDNTask(ctx, task)
+	// Start trigger seed peer task.
+	if s.config.SeedPeer.Enable {
+		go s.triggerSeedPeerTask(ctx, task)
 		return task, false, nil
 	}
 
@@ -567,19 +567,19 @@ func (s *Service) registerPeer(ctx context.Context, peerID string, task *resourc
 	return peer
 }
 
-// triggerCDNTask starts trigger cdn task.
-func (s *Service) triggerCDNTask(ctx context.Context, task *resource.Task) {
-	task.Log.Infof("trigger cdn download task and task status is %s", task.FSM.Current())
-	peer, endOfPiece, err := s.resource.CDN().TriggerTask(
+// triggerSeedPeerTask starts to trigger seed peer task.
+func (s *Service) triggerSeedPeerTask(ctx context.Context, task *resource.Task) {
+	task.Log.Infof("trigger seed peer download task and task status is %s", task.FSM.Current())
+	peer, endOfPiece, err := s.resource.SeedPeer().TriggerTask(
 		trace.ContextWithSpanContext(context.Background(), trace.SpanContextFromContext(ctx)), task)
 	if err != nil {
-		task.Log.Errorf("trigger cdn download task failed: %s", err.Error())
+		task.Log.Errorf("trigger seed peer download task failed: %s", err.Error())
 		s.handleTaskFail(ctx, task)
 		return
 	}
 
 	// Update the task status first to help peer scheduling evaluation and scoring.
-	peer.Log.Info("trigger cdn download task successfully")
+	peer.Log.Info("trigger seed peer download task successfully")
 	s.handleTaskSuccess(ctx, task, endOfPiece)
 	s.handlePeerSuccess(ctx, peer)
 }
@@ -662,21 +662,21 @@ func (s *Service) handlePieceFail(ctx context.Context, peer *resource.Peer, piec
 		}
 	case base.Code_ClientPieceNotFound:
 		// Dfdaemon downloading piece data from parent returns http error code 404.
-		// If the parent is not a CDN, reschedule parent for peer.
-		// If the parent is a CDN, scheduler need to trigger CDN to download again.
-		if !parent.Host.IsCDN {
-			peer.Log.Infof("parent %s is not cdn", piece.DstPid)
+		// If the parent is not a seed peer, reschedule parent for peer.
+		// If the parent is a seed peer, scheduler need to trigger seed peer to download again.
+		if parent.Host.Type == resource.HostTypeNormal {
+			peer.Log.Infof("parent %s host type is normal", piece.DstPid)
 			break
 		}
 
-		peer.Log.Infof("parent %s is cdn", piece.DstPid)
+		peer.Log.Infof("parent %s is seed peer", piece.DstPid)
 		fallthrough
 	case base.Code_CDNTaskNotFound:
-		s.handleLegacyCDNPeer(ctx, parent)
+		s.handleLegacySeedPeer(ctx, parent)
 
-		// Start trigger cdn task.
-		if s.config.CDN.Enable {
-			go s.triggerCDNTask(ctx, parent.Task)
+		// Start trigger seed peer task.
+		if s.config.SeedPeer.Enable {
+			go s.triggerSeedPeerTask(ctx, parent.Task)
 		}
 	default:
 	}
@@ -744,9 +744,9 @@ func (s *Service) handlePeerFail(ctx context.Context, peer *resource.Peer) {
 	})
 }
 
-// handleLegacyCDNPeer handles cdn server's task has left,
+// handleLegacySeedPeer handles seed server's task has left,
 // but did not notify the schduler to leave the task.
-func (s *Service) handleLegacyCDNPeer(ctx context.Context, peer *resource.Peer) {
+func (s *Service) handleLegacySeedPeer(ctx context.Context, peer *resource.Peer) {
 	if err := peer.FSM.Event(resource.PeerEventDownloadFailed); err != nil {
 		peer.Log.Errorf("peer fsm event failed: %s", err.Error())
 		return
@@ -771,7 +771,7 @@ func (s *Service) handleLegacyCDNPeer(ctx context.Context, peer *resource.Peer)
 }
 
 // Conditions for the task to switch to the TaskStateSucceeded are:
-// 1. CDN downloads the resource successfully.
+// 1. Seed peer downloads the resource successfully.
 // 2. Dfdaemon back-to-source to download successfully.
 // 3. Peer announces it has the task.
 func (s *Service) handleTaskSuccess(ctx context.Context, task *resource.Task, result *rpcscheduler.PeerResult) {
@@ -790,7 +790,7 @@ func (s *Service) handleTaskSuccess(ctx context.Context, task *resource.Task, re
 }
 
 // Conditions for the task to switch to the TaskStateSucceeded are:
-// 1. CDN downloads the resource falied.
+// 1. Seed peer downloads the resource falied.
 // 2. Dfdaemon back-to-source to download failed.
 func (s *Service) handleTaskFail(ctx context.Context, task *resource.Task) {
 	// If the number of failed peers in the task is greater than FailedPeerCountLimit,
@@ -827,6 +827,7 @@ func (s *Service) createRecord(peer *resource.Peer, peerState int, req *rpcsched
 		Location:        peer.Host.Location,
 		FreeUploadLoad:  peer.Host.FreeUploadLoad(),
 		State:           peerState,
+		HostType:        int(peer.Host.Type),
 		CreateAt:        peer.CreateAt.Load().UnixNano(),
 		UpdateAt:        peer.UpdateAt.Load().UnixNano(),
 	}
@@ -842,6 +843,7 @@ func (s *Service) createRecord(peer *resource.Peer, peerState int, req *rpcsched
 		record.ParentNetTopology = parent.Host.NetTopology
 		record.ParentLocation = parent.Host.Location
 		record.ParentFreeUploadLoad = parent.Host.FreeUploadLoad()
+		record.ParentHostType = int(parent.Host.Type)
 		record.ParentIsCDN = parent.Host.IsCDN
 		record.ParentCreateAt = parent.CreateAt.Load().UnixNano()
 		record.ParentUpdateAt = parent.UpdateAt.Load().UnixNano()
diff --git a/scheduler/storage/storage.go b/scheduler/storage/storage.go
index 8099def8..c96aec53 100644
--- a/scheduler/storage/storage.go
+++ b/scheduler/storage/storage.go
@@ -123,6 +123,9 @@ type Record struct {
 	// State is the download state of the peer.
 	State int `csv:"state"`
 
+	// HostType is peer host type.
+	HostType int `csv:"hostType"`
+
 	// CreateAt is peer create nanosecond time.
 	CreateAt int64 `csv:"createAt"`
 
@@ -161,6 +164,9 @@ type Record struct {
 	// ParentFreeUploadLoad is parent free upload load of host.
 	ParentFreeUploadLoad int32 `csv:"parentFreeUploadLoad"`
 
+	// ParentHostType is parent host type.
+	ParentHostType int `csv:"parentHostType"`
+
 	// ParentIsCDN is used as tag cdn.
 	ParentIsCDN bool `csv:"parentIsCDN"`
 


Test patch:
diff --git a/pkg/idgen/host_id_test.go b/pkg/idgen/host_id_test.go
index efb6b16b..c29c563b 100644
--- a/pkg/idgen/host_id_test.go
+++ b/pkg/idgen/host_id_test.go
@@ -65,6 +65,49 @@ func TestHostID(t *testing.T) {
 	}
 }
 
+func TestSeedHostID(t *testing.T) {
+	tests := []struct {
+		name     string
+		hostname string
+		port     int32
+		expect   func(t *testing.T, d string)
+	}{
+		{
+			name:     "generate SeedHostID with ipv4",
+			hostname: "foo",
+			port:     8000,
+			expect: func(t *testing.T, d string) {
+				assert := assert.New(t)
+				assert.Equal(d, "foo-8000_Seed")
+			},
+		},
+		{
+			name:     "generate SeedHostID with empty host",
+			hostname: "",
+			port:     8000,
+			expect: func(t *testing.T, d string) {
+				assert := assert.New(t)
+				assert.Equal(d, "-8000_Seed")
+			},
+		},
+		{
+			name:     "generate SeedHostID with zero port",
+			hostname: "foo",
+			port:     0,
+			expect: func(t *testing.T, d string) {
+				assert := assert.New(t)
+				assert.Equal(d, "foo-0_Seed")
+			},
+		},
+	}
+
+	for _, tc := range tests {
+		t.Run(tc.name, func(t *testing.T) {
+			tc.expect(t, SeedHostID(tc.hostname, tc.port))
+		})
+	}
+}
+
 func TestCDNHostID(t *testing.T) {
 	tests := []struct {
 		name     string
diff --git a/pkg/idgen/peer_id_test.go b/pkg/idgen/peer_id_test.go
index 3ec85347..2ec2adcd 100644
--- a/pkg/idgen/peer_id_test.go
+++ b/pkg/idgen/peer_id_test.go
@@ -62,6 +62,46 @@ func TestPeerID(t *testing.T) {
 	}
 }
 
+func TestSeedPeerID(t *testing.T) {
+	tests := []struct {
+		name   string
+		ip     string
+		expect func(t *testing.T, d interface{})
+	}{
+		{
+			name: "generate SeedPeerID with ipv4",
+			ip:   "127.0.0.1",
+			expect: func(t *testing.T, d interface{}) {
+				assert := assert.New(t)
+				assert.Regexp("127.0.0.1-.*-.*_Seed", d)
+			},
+		},
+		{
+			name: "generate SeedPeerID with ipv6",
+			ip:   "2001:0db8:3c4d:0015:0000:0000:1a2f:1a2b",
+			expect: func(t *testing.T, d interface{}) {
+				assert := assert.New(t)
+				assert.Regexp("2001:0db8:3c4d:0015:0000:0000:1a2f:1a2b-.*-.*_Seed", d)
+			},
+		},
+		{
+			name: "generate SeedPeerID with empty string",
+			ip:   "",
+			expect: func(t *testing.T, d interface{}) {
+				assert := assert.New(t)
+				assert.Regexp("-.*-.*_Seed", d)
+			},
+		},
+	}
+
+	for _, tc := range tests {
+		t.Run(tc.name, func(t *testing.T) {
+			data := SeedPeerID(tc.ip)
+			tc.expect(t, data)
+		})
+	}
+}
+
 func TestCDNPeerID(t *testing.T) {
 	tests := []struct {
 		name   string
diff --git a/scheduler/config/config_test.go b/scheduler/config/config_test.go
index 99a49f4c..c939f91a 100644
--- a/scheduler/config/config_test.go
+++ b/scheduler/config/config_test.go
@@ -59,7 +59,6 @@ func TestConfig_Load(t *testing.T) {
 		},
 		DynConfig: &DynConfig{
 			RefreshInterval: 5 * time.Minute,
-			CDNDir:          "foo",
 		},
 		Host: &HostConfig{
 			IDC:         "foo",
@@ -73,7 +72,7 @@ func TestConfig_Load(t *testing.T) {
 				Interval: 5 * time.Second,
 			},
 		},
-		CDN: &CDNConfig{
+		SeedPeer: &SeedPeerConfig{
 			Enable: true,
 		},
 		Job: &JobConfig{
@@ -151,7 +150,7 @@ func TestConfig_New(t *testing.T) {
 				Interval: 5 * time.Second,
 			},
 		},
-		CDN: &CDNConfig{
+		SeedPeer: &SeedPeerConfig{
 			Enable: true,
 		},
 		Job: &JobConfig{
diff --git a/scheduler/config/dynconfig_test.go b/scheduler/config/dynconfig_test.go
index 5dc0fed9..4761eeaf 100644
--- a/scheduler/config/dynconfig_test.go
+++ b/scheduler/config/dynconfig_test.go
@@ -70,6 +70,14 @@ func TestDynconfig_GetManagerSourceType(t *testing.T) {
 							DownloadPort: 8003,
 						},
 					},
+					SeedPeers: []*manager.SeedPeer{
+						{
+							HostName:     "bar",
+							Ip:           "127.0.0.1",
+							Port:         8001,
+							DownloadPort: 8003,
+						},
+					},
 				}, nil).Times(1)
 			},
 			expect: func(t *testing.T, data *DynconfigData, err error) {
@@ -78,6 +86,10 @@ func TestDynconfig_GetManagerSourceType(t *testing.T) {
 				assert.Equal(data.CDNs[0].IP, "127.0.0.1")
 				assert.Equal(data.CDNs[0].Port, int32(8001))
 				assert.Equal(data.CDNs[0].DownloadPort, int32(8003))
+				assert.Equal(data.SeedPeers[0].Hostname, "bar")
+				assert.Equal(data.SeedPeers[0].IP, "127.0.0.1")
+				assert.Equal(data.SeedPeers[0].Port, int32(8001))
+				assert.Equal(data.SeedPeers[0].DownloadPort, int32(8003))
 			},
 		},
 		{
@@ -102,6 +114,14 @@ func TestDynconfig_GetManagerSourceType(t *testing.T) {
 								DownloadPort: 8003,
 							},
 						},
+						SeedPeers: []*manager.SeedPeer{
+							{
+								HostName:     "bar",
+								Ip:           "127.0.0.1",
+								Port:         8001,
+								DownloadPort: 8003,
+							},
+						},
 					}, nil).Times(1),
 					m.GetScheduler(gomock.Any()).Return(nil, errors.New("foo")).Times(1),
 				)
@@ -112,6 +132,10 @@ func TestDynconfig_GetManagerSourceType(t *testing.T) {
 				assert.Equal(data.CDNs[0].IP, "127.0.0.1")
 				assert.Equal(data.CDNs[0].Port, int32(8001))
 				assert.Equal(data.CDNs[0].DownloadPort, int32(8003))
+				assert.Equal(data.SeedPeers[0].Hostname, "bar")
+				assert.Equal(data.SeedPeers[0].IP, "127.0.0.1")
+				assert.Equal(data.SeedPeers[0].Port, int32(8001))
+				assert.Equal(data.SeedPeers[0].DownloadPort, int32(8003))
 			},
 		},
 	}
@@ -136,52 +160,3 @@ func TestDynconfig_GetManagerSourceType(t *testing.T) {
 		})
 	}
 }
-
-func TestDynconfig_GetCDNFromDirPath(t *testing.T) {
-	mockCacheDir := t.TempDir()
-
-	tests := []struct {
-		name       string
-		cdnDirPath string
-		expect     func(t *testing.T, data *DynconfigData, err error)
-	}{
-		{
-			name:       "get CDN from directory",
-			cdnDirPath: filepath.Join("./testdata", "dynconfig", "cdn"),
-			expect: func(t *testing.T, data *DynconfigData, err error) {
-				assert := assert.New(t)
-				assert.Equal(data.CDNs[0].Hostname, "foo")
-				assert.Equal(data.CDNs[1].Hostname, "bar")
-				assert.Equal(data.CDNs[0].Port, int32(8001))
-				assert.Equal(data.CDNs[1].Port, int32(8001))
-				assert.Equal(data.CDNs[0].DownloadPort, int32(8003))
-				assert.Equal(data.CDNs[1].DownloadPort, int32(8003))
-			},
-		},
-		{
-			name:       "directory does not exist",
-			cdnDirPath: filepath.Join("./testdata", "foo"),
-			expect: func(t *testing.T, data *DynconfigData, err error) {
-				assert := assert.New(t)
-				assert.EqualError(err, "open testdata/foo: no such file or directory")
-			},
-		},
-	}
-
-	for _, tc := range tests {
-		t.Run(tc.name, func(t *testing.T) {
-
-			d, err := NewDynconfig(nil, mockCacheDir, &Config{
-				DynConfig: &DynConfig{
-					CDNDir: tc.cdnDirPath,
-				},
-			})
-			if err != nil {
-				t.Fatal(err)
-			}
-
-			data, err := d.Get()
-			tc.expect(t, data, err)
-		})
-	}
-}
diff --git a/scheduler/config/testdata/dynconfig/cdn/cdn_1.json b/scheduler/config/testdata/dynconfig/cdn/cdn_1.json
deleted file mode 100644
index 3d0c000c..00000000
--- a/scheduler/config/testdata/dynconfig/cdn/cdn_1.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-  "id": 1,
-  "host_name": "foo",
-  "idc": "foo",
-  "location": "foo",
-  "ip": "127.0.0.1",
-  "port": 8001,
-  "download_port": 8003,
-  "status": "active"
-}
diff --git a/scheduler/config/testdata/dynconfig/cdn/cdn_2.json b/scheduler/config/testdata/dynconfig/cdn/cdn_2.json
deleted file mode 100644
index f5bbb31d..00000000
--- a/scheduler/config/testdata/dynconfig/cdn/cdn_2.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-  "id": 2,
-  "host_name": "bar",
-  "idc": "bar",
-  "location": "bar",
-  "ip": "127.0.0.1",
-  "port": 8001,
-  "download_port": 8003,
-  "status": "active"
-}
diff --git a/scheduler/config/testdata/dynconfig/scheduler.yaml b/scheduler/config/testdata/dynconfig/scheduler.yaml
deleted file mode 100644
index 84c7adb4..00000000
--- a/scheduler/config/testdata/dynconfig/scheduler.yaml
+++ /dev/null
@@ -1,11 +0,0 @@
-dynconfig:
-  data:
-    cdns:
-      - hostname: "foo"
-        ip: "127.0.0.1"
-        port: 8001
-        downloadPort: 8003
-      - hostname: "bar"
-        ip: "127.0.0.1"
-        port: 8001
-        downloadPort: 8003
diff --git a/scheduler/config/testdata/scheduler.yaml b/scheduler/config/testdata/scheduler.yaml
index bc9fcd33..4ac5e7b9 100644
--- a/scheduler/config/testdata/scheduler.yaml
+++ b/scheduler/config/testdata/scheduler.yaml
@@ -22,7 +22,6 @@ scheduler:
 
 dynconfig:
   refreshInterval: 300000000000
-  cdnDir: foo
 
 host:
   idc: foo
@@ -35,7 +34,7 @@ manager:
   keepAlive:
     interval: 5000000000
 
-cdn:
+seedPeer:
   enable: true
 
 job:
diff --git a/scheduler/resource/host_manager_test.go b/scheduler/resource/host_manager_test.go
index a1f1cf07..7535eb60 100644
--- a/scheduler/resource/host_manager_test.go
+++ b/scheduler/resource/host_manager_test.go
@@ -356,20 +356,20 @@ func TestHostManager_RunGC(t *testing.T) {
 			},
 		},
 		{
-			name: "host is cdn",
+			name: "host is seed peer",
 			mock: func(m *gc.MockGCMockRecorder) {
 				m.Add(gomock.Any()).Return(nil).Times(1)
 			},
 			expect: func(t *testing.T, hostManager HostManager, mockHost *Host, mockPeer *Peer) {
 				assert := assert.New(t)
-				mockCDNHost := NewHost(mockRawCDNHost, WithIsCDN(true))
-				hostManager.Store(mockCDNHost)
+				mockSeedHost := NewHost(mockRawSeedHost, WithHostType(HostTypeSuperSeed))
+				hostManager.Store(mockSeedHost)
 				err := hostManager.RunGC()
 				assert.NoError(err)
 
-				host, ok := hostManager.Load(mockCDNHost.ID)
+				host, ok := hostManager.Load(mockSeedHost.ID)
 				assert.Equal(ok, true)
-				assert.Equal(host.ID, mockCDNHost.ID)
+				assert.Equal(host.ID, mockSeedHost.ID)
 			},
 		},
 	}
diff --git a/scheduler/resource/host_test.go b/scheduler/resource/host_test.go
index 58d873c1..a8f0b0da 100644
--- a/scheduler/resource/host_test.go
+++ b/scheduler/resource/host_test.go
@@ -39,6 +39,18 @@ var (
 		NetTopology:    "net_topology",
 	}
 
+	mockRawSeedHost = &scheduler.PeerHost{
+		Uuid:           idgen.SeedHostID("hostname", 8003),
+		Ip:             "127.0.0.1",
+		RpcPort:        8003,
+		DownPort:       8001,
+		HostName:       "hostname",
+		SecurityDomain: "security_domain",
+		Location:       "location",
+		Idc:            "idc",
+		NetTopology:    "net_topology",
+	}
+
 	mockRawCDNHost = &scheduler.PeerHost{
 		Uuid:           idgen.CDNHostID("hostname", 8003),
 		Ip:             "127.0.0.1",
@@ -65,6 +77,7 @@ func TestHost_NewHost(t *testing.T) {
 			expect: func(t *testing.T, host *Host) {
 				assert := assert.New(t)
 				assert.Equal(host.ID, mockRawHost.Uuid)
+				assert.Equal(host.Type, HostTypeNormal)
 				assert.Equal(host.IP, mockRawHost.Ip)
 				assert.Equal(host.Port, mockRawHost.RpcPort)
 				assert.Equal(host.DownloadPort, mockRawHost.DownPort)
@@ -82,20 +95,21 @@ func TestHost_NewHost(t *testing.T) {
 			},
 		},
 		{
-			name:    "new cdn host",
-			rawHost: mockRawCDNHost,
-			options: []HostOption{WithIsCDN(true)},
+			name:    "new seed host",
+			rawHost: mockRawSeedHost,
+			options: []HostOption{WithHostType(HostTypeSuperSeed), WithIsCDN(true)},
 			expect: func(t *testing.T, host *Host) {
 				assert := assert.New(t)
-				assert.Equal(host.ID, mockRawCDNHost.Uuid)
-				assert.Equal(host.IP, mockRawCDNHost.Ip)
-				assert.Equal(host.Port, mockRawCDNHost.RpcPort)
-				assert.Equal(host.DownloadPort, mockRawCDNHost.DownPort)
-				assert.Equal(host.Hostname, mockRawCDNHost.HostName)
-				assert.Equal(host.SecurityDomain, mockRawCDNHost.SecurityDomain)
-				assert.Equal(host.Location, mockRawCDNHost.Location)
-				assert.Equal(host.IDC, mockRawCDNHost.Idc)
-				assert.Equal(host.NetTopology, mockRawCDNHost.NetTopology)
+				assert.Equal(host.ID, mockRawSeedHost.Uuid)
+				assert.Equal(host.Type, HostTypeSuperSeed)
+				assert.Equal(host.IP, mockRawSeedHost.Ip)
+				assert.Equal(host.Port, mockRawSeedHost.RpcPort)
+				assert.Equal(host.DownloadPort, mockRawSeedHost.DownPort)
+				assert.Equal(host.Hostname, mockRawSeedHost.HostName)
+				assert.Equal(host.SecurityDomain, mockRawSeedHost.SecurityDomain)
+				assert.Equal(host.Location, mockRawSeedHost.Location)
+				assert.Equal(host.IDC, mockRawSeedHost.Idc)
+				assert.Equal(host.NetTopology, mockRawSeedHost.NetTopology)
 				assert.Equal(host.UploadLoadLimit.Load(), int32(config.DefaultClientLoadLimit))
 				assert.Equal(host.PeerCount.Load(), int32(0))
 				assert.Equal(host.IsCDN, true)
@@ -111,6 +125,7 @@ func TestHost_NewHost(t *testing.T) {
 			expect: func(t *testing.T, host *Host) {
 				assert := assert.New(t)
 				assert.Equal(host.ID, mockRawHost.Uuid)
+				assert.Equal(host.Type, HostTypeNormal)
 				assert.Equal(host.IP, mockRawHost.Ip)
 				assert.Equal(host.Port, mockRawHost.RpcPort)
 				assert.Equal(host.DownloadPort, mockRawHost.DownPort)
diff --git a/scheduler/resource/peer_test.go b/scheduler/resource/peer_test.go
index 0f2c763c..dd6af2de 100644
--- a/scheduler/resource/peer_test.go
+++ b/scheduler/resource/peer_test.go
@@ -36,8 +36,8 @@ import (
 )
 
 var (
-	mockPeerID    = idgen.PeerID("127.0.0.1")
-	mockCDNPeerID = idgen.CDNPeerID("127.0.0.1")
+	mockPeerID     = idgen.PeerID("127.0.0.1")
+	mockSeedPeerID = idgen.SeedPeerID("127.0.0.1")
 )
 
 func TestPeer_NewPeer(t *testing.T) {
@@ -492,18 +492,18 @@ func TestPeer_ReplaceParent(t *testing.T) {
 func TestPeer_Depth(t *testing.T) {
 	tests := []struct {
 		name   string
-		expect func(t *testing.T, peer *Peer, parent *Peer, cdnParent *Peer)
+		expect func(t *testing.T, peer *Peer, parent *Peer, seedPeerParent *Peer)
 	}{
 		{
 			name: "there is only one node in the tree",
-			expect: func(t *testing.T, peer *Peer, parent *Peer, cdnParent *Peer) {
+			expect: func(t *testing.T, peer *Peer, parent *Peer, seedPeerParent *Peer) {
 				assert := assert.New(t)
 				assert.Equal(peer.Depth(), 1)
 			},
 		},
 		{
 			name: "more than one node in the tree",
-			expect: func(t *testing.T, peer *Peer, parent *Peer, cdnParent *Peer) {
+			expect: func(t *testing.T, peer *Peer, parent *Peer, seedPeerParent *Peer) {
 				peer.StoreParent(parent)
 
 				assert := assert.New(t)
@@ -511,9 +511,9 @@ func TestPeer_Depth(t *testing.T) {
 			},
 		},
 		{
-			name: "node parent is cdn",
-			expect: func(t *testing.T, peer *Peer, parent *Peer, cdnParent *Peer) {
-				peer.StoreParent(cdnParent)
+			name: "node parent is seed peer",
+			expect: func(t *testing.T, peer *Peer, parent *Peer, seedPeerParent *Peer) {
+				peer.StoreParent(seedPeerParent)
 
 				assert := assert.New(t)
 				assert.Equal(peer.Depth(), 2)
@@ -521,7 +521,7 @@ func TestPeer_Depth(t *testing.T) {
 		},
 		{
 			name: "node parent is itself",
-			expect: func(t *testing.T, peer *Peer, parent *Peer, cdnParent *Peer) {
+			expect: func(t *testing.T, peer *Peer, parent *Peer, seedPeerParent *Peer) {
 				peer.StoreParent(peer)
 
 				assert := assert.New(t)
@@ -533,13 +533,13 @@ func TestPeer_Depth(t *testing.T) {
 	for _, tc := range tests {
 		t.Run(tc.name, func(t *testing.T) {
 			mockHost := NewHost(mockRawHost)
-			mockCDNHost := NewHost(mockRawCDNHost, WithIsCDN(true))
+			mockSeedHost := NewHost(mockRawSeedHost, WithHostType(HostTypeSuperSeed))
 			mockTask := NewTask(mockTaskID, mockTaskURL, TaskTypeNormal, mockTaskURLMeta, WithBackToSourceLimit(mockTaskBackToSourceLimit))
 			peer := NewPeer(mockPeerID, mockTask, mockHost)
 			parent := NewPeer(idgen.PeerID("127.0.0.2"), mockTask, mockHost)
-			cdnParent := NewPeer(mockCDNPeerID, mockTask, mockCDNHost)
+			seedPeerParent := NewPeer(mockSeedPeerID, mockTask, mockSeedHost)
 
-			tc.expect(t, peer, parent, cdnParent)
+			tc.expect(t, peer, parent, seedPeerParent)
 		})
 	}
 }
diff --git a/scheduler/resource/resource_test.go b/scheduler/resource/resource_test.go
index 8689f5d6..f06faf97 100644
--- a/scheduler/resource/resource_test.go
+++ b/scheduler/resource/resource_test.go
@@ -43,7 +43,7 @@ func TestResource_New(t *testing.T) {
 				gomock.InOrder(
 					gc.Add(gomock.Any()).Return(nil).Times(3),
 					dynconfig.Get().Return(&config.DynconfigData{
-						CDNs: []*config.CDN{{ID: 1}},
+						SeedPeers: []*config.SeedPeer{{ID: 1}},
 					}, nil).Times(1),
 					dynconfig.Register(gomock.Any()).Return().Times(1),
 				)
@@ -110,13 +110,13 @@ func TestResource_New(t *testing.T) {
 			},
 		},
 		{
-			name:   "new resource faild because of cdn list is empty",
+			name:   "new resource faild because of seed peer list is empty",
 			config: config.New(),
 			mock: func(gc *gc.MockGCMockRecorder, dynconfig *configmocks.MockDynconfigInterfaceMockRecorder) {
 				gomock.InOrder(
 					gc.Add(gomock.Any()).Return(nil).Times(3),
 					dynconfig.Get().Return(&config.DynconfigData{
-						CDNs: []*config.CDN{},
+						SeedPeers: []*config.SeedPeer{},
 					}, nil).Times(1),
 				)
 			},
@@ -126,7 +126,7 @@ func TestResource_New(t *testing.T) {
 			},
 		},
 		{
-			name: "new resource with cdn",
+			name: "new resource without seed peer",
 			config: &config.Config{
 				Scheduler: &config.SchedulerConfig{
 					GC: &config.GCConfig{
@@ -138,7 +138,7 @@ func TestResource_New(t *testing.T) {
 						HostTTL:        1000,
 					},
 				},
-				CDN: &config.CDNConfig{
+				SeedPeer: &config.SeedPeerConfig{
 					Enable: false,
 				},
 			},
diff --git a/scheduler/resource/cdn_test.go b/scheduler/resource/seed_peer_client_test.go
similarity index 54%
rename from scheduler/resource/cdn_test.go
rename to scheduler/resource/seed_peer_client_test.go
index 879f1a96..ae96f378 100644
--- a/scheduler/resource/cdn_test.go
+++ b/scheduler/resource/seed_peer_client_test.go
@@ -1,5 +1,5 @@
 /*
- *     Copyright 2020 The Dragonfly Authors
+ *     Copyright 2022 The Dragonfly Authors
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -17,93 +17,45 @@
 package resource
 
 import (
-	"context"
 	"encoding/json"
 	"errors"
 	"fmt"
-	"reflect"
 	"testing"
 
 	gomock "github.com/golang/mock/gomock"
 	"github.com/stretchr/testify/assert"
 
+	"d7y.io/dragonfly/v2/manager/model"
 	"d7y.io/dragonfly/v2/manager/types"
 	"d7y.io/dragonfly/v2/pkg/dfnet"
-	rpcscheduler "d7y.io/dragonfly/v2/pkg/rpc/scheduler"
 	"d7y.io/dragonfly/v2/scheduler/config"
 	configmocks "d7y.io/dragonfly/v2/scheduler/config/mocks"
 )
 
-func TestCDN_newCDN(t *testing.T) {
+func TestSeedPeerClient_newSeedPeerClient(t *testing.T) {
 	tests := []struct {
 		name   string
-		expect func(t *testing.T, cdn CDN)
-	}{
-		{
-			name: "new cdn",
-			expect: func(t *testing.T, cdn CDN) {
-				assert := assert.New(t)
-				assert.Equal(reflect.TypeOf(cdn).Elem().Name(), "cdn")
-			},
-		},
-	}
-
-	for _, tc := range tests {
-		t.Run(tc.name, func(t *testing.T) {
-			ctl := gomock.NewController(t)
-			defer ctl.Finish()
-			hostManager := NewMockHostManager(ctl)
-			peerManager := NewMockPeerManager(ctl)
-			client := NewMockCDNClient(ctl)
-
-			tc.expect(t, newCDN(peerManager, hostManager, client))
-		})
-	}
-}
-
-func TestCDN_TriggerTask(t *testing.T) {
-	tests := []struct {
-		name   string
-		mock   func(mc *MockCDNClientMockRecorder)
-		expect func(t *testing.T, peer *Peer, result *rpcscheduler.PeerResult, err error)
+		mock   func(dynconfig *configmocks.MockDynconfigInterfaceMockRecorder, hostManager *MockHostManagerMockRecorder)
+		expect func(t *testing.T, err error)
 	}{
 		{
-			name: "start obtain seed stream failed",
-			mock: func(mc *MockCDNClientMockRecorder) {
-				mc.ObtainSeeds(gomock.Any(), gomock.Any()).Return(nil, errors.New("foo")).Times(1)
+			name: "new seed peer client",
+			mock: func(dynconfig *configmocks.MockDynconfigInterfaceMockRecorder, hostManager *MockHostManagerMockRecorder) {
+				gomock.InOrder(
+					dynconfig.Get().Return(&config.DynconfigData{
+						SeedPeers: []*config.SeedPeer{{ID: 1}},
+					}, nil).Times(1),
+					hostManager.Store(gomock.Any()).Return().Times(1),
+					dynconfig.Register(gomock.Any()).Return().Times(1),
+				)
 			},
-			expect: func(t *testing.T, peer *Peer, result *rpcscheduler.PeerResult, err error) {
+			expect: func(t *testing.T, err error) {
 				assert := assert.New(t)
-				assert.EqualError(err, "foo")
+				assert.NoError(err)
 			},
 		},
-	}
-
-	for _, tc := range tests {
-		t.Run(tc.name, func(t *testing.T) {
-			ctl := gomock.NewController(t)
-			defer ctl.Finish()
-			hostManager := NewMockHostManager(ctl)
-			peerManager := NewMockPeerManager(ctl)
-			client := NewMockCDNClient(ctl)
-			tc.mock(client.EXPECT())
-
-			cdn := newCDN(peerManager, hostManager, client)
-			mockTask := NewTask(mockTaskID, mockTaskURL, TaskTypeNormal, mockTaskURLMeta, WithBackToSourceLimit(mockTaskBackToSourceLimit))
-			peer, result, err := cdn.TriggerTask(context.Background(), mockTask)
-			tc.expect(t, peer, result, err)
-		})
-	}
-}
-
-func TestCDNClient_newCDNClient(t *testing.T) {
-	tests := []struct {
-		name   string
-		mock   func(dynconfig *configmocks.MockDynconfigInterfaceMockRecorder, hostManager *MockHostManagerMockRecorder)
-		expect func(t *testing.T, err error)
-	}{
 		{
-			name: "new cdn client",
+			name: "new seed peer client with cdn",
 			mock: func(dynconfig *configmocks.MockDynconfigInterfaceMockRecorder, hostManager *MockHostManagerMockRecorder) {
 				gomock.InOrder(
 					dynconfig.Get().Return(&config.DynconfigData{
@@ -119,7 +71,7 @@ func TestCDNClient_newCDNClient(t *testing.T) {
 			},
 		},
 		{
-			name: "new cdn client failed because of dynconfig get error data",
+			name: "new seed peer client failed because of dynconfig get error data",
 			mock: func(dynconfig *configmocks.MockDynconfigInterfaceMockRecorder, hostManager *MockHostManagerMockRecorder) {
 				dynconfig.Get().Return(nil, errors.New("foo")).Times(1)
 			},
@@ -129,11 +81,11 @@ func TestCDNClient_newCDNClient(t *testing.T) {
 			},
 		},
 		{
-			name: "new cdn client failed because of cdn list is empty",
+			name: "new seed peer client failed because of seed peer list is empty",
 			mock: func(dynconfig *configmocks.MockDynconfigInterfaceMockRecorder, hostManager *MockHostManagerMockRecorder) {
 				gomock.InOrder(
 					dynconfig.Get().Return(&config.DynconfigData{
-						CDNs: []*config.CDN{},
+						SeedPeers: []*config.SeedPeer{},
 					}, nil).Times(1),
 				)
 			},
@@ -152,21 +104,27 @@ func TestCDNClient_newCDNClient(t *testing.T) {
 			hostManager := NewMockHostManager(ctl)
 			tc.mock(dynconfig.EXPECT(), hostManager.EXPECT())
 
-			_, err := newCDNClient(dynconfig, hostManager)
+			_, err := newSeedPeerClient(dynconfig, hostManager)
 			tc.expect(t, err)
 		})
 	}
 }
 
-func TestCDNClient_OnNotify(t *testing.T) {
+func TestSeedPeerClient_OnNotify(t *testing.T) {
 	tests := []struct {
 		name string
 		data *config.DynconfigData
 		mock func(dynconfig *configmocks.MockDynconfigInterfaceMockRecorder, hostManager *MockHostManagerMockRecorder)
 	}{
 		{
-			name: "notify client without different cdns",
+			name: "notify client without different seedPeers",
 			data: &config.DynconfigData{
+				SeedPeers: []*config.SeedPeer{{
+					ID:       1,
+					Hostname: "foo",
+					IP:       "0.0.0.0",
+					Port:     8080,
+				}},
 				CDNs: []*config.CDN{{
 					ID:       1,
 					Hostname: "foo",
@@ -177,6 +135,12 @@ func TestCDNClient_OnNotify(t *testing.T) {
 			mock: func(dynconfig *configmocks.MockDynconfigInterfaceMockRecorder, hostManager *MockHostManagerMockRecorder) {
 				gomock.InOrder(
 					dynconfig.Get().Return(&config.DynconfigData{
+						SeedPeers: []*config.SeedPeer{{
+							ID:       1,
+							Hostname: "foo",
+							IP:       "0.0.0.0",
+							Port:     8080,
+						}},
 						CDNs: []*config.CDN{{
 							ID:       1,
 							Hostname: "foo",
@@ -184,14 +148,19 @@ func TestCDNClient_OnNotify(t *testing.T) {
 							Port:     8080,
 						}},
 					}, nil).Times(1),
-					hostManager.Store(gomock.Any()).Return().Times(1),
+					hostManager.Store(gomock.Any()).Return().Times(2),
 					dynconfig.Register(gomock.Any()).Return().Times(1),
 				)
 			},
 		},
 		{
-			name: "notify client with different cdns",
+			name: "notify client with different seedPeers",
 			data: &config.DynconfigData{
+				SeedPeers: []*config.SeedPeer{{
+					ID:       1,
+					Hostname: "foo",
+					IP:       "0.0.0.0",
+				}},
 				CDNs: []*config.CDN{{
 					ID:       1,
 					Hostname: "foo",
@@ -202,23 +171,36 @@ func TestCDNClient_OnNotify(t *testing.T) {
 				mockHost := NewHost(mockRawHost)
 				gomock.InOrder(
 					dynconfig.Get().Return(&config.DynconfigData{
+						SeedPeers: []*config.SeedPeer{{
+							ID:       1,
+							Hostname: "foo",
+							IP:       "127.0.0.1",
+						}},
 						CDNs: []*config.CDN{{
 							ID:       1,
 							Hostname: "foo",
 							IP:       "127.0.0.1",
 						}},
 					}, nil).Times(1),
-					hostManager.Store(gomock.Any()).Return().Times(1),
+					hostManager.Store(gomock.Any()).Return().Times(2),
 					dynconfig.Register(gomock.Any()).Return().Times(1),
 					hostManager.Load(gomock.Any()).Return(mockHost, true).Times(1),
+					hostManager.Delete(gomock.Eq("foo-0_Seed")).Return().Times(1),
+					hostManager.Store(gomock.Any()).Return().Times(1),
+					hostManager.Load(gomock.Any()).Return(mockHost, true).Times(1),
 					hostManager.Delete(gomock.Eq("foo-0_CDN")).Return().Times(1),
 					hostManager.Store(gomock.Any()).Return().Times(1),
 				)
 			},
 		},
 		{
-			name: "notify client with different cdns and load host failed",
+			name: "notify client with different seed peers and load host failed",
 			data: &config.DynconfigData{
+				SeedPeers: []*config.SeedPeer{{
+					ID:       1,
+					Hostname: "foo",
+					IP:       "0.0.0.0",
+				}},
 				CDNs: []*config.CDN{{
 					ID:       1,
 					Hostname: "foo",
@@ -228,22 +210,33 @@ func TestCDNClient_OnNotify(t *testing.T) {
 			mock: func(dynconfig *configmocks.MockDynconfigInterfaceMockRecorder, hostManager *MockHostManagerMockRecorder) {
 				gomock.InOrder(
 					dynconfig.Get().Return(&config.DynconfigData{
+						SeedPeers: []*config.SeedPeer{{
+							ID:       1,
+							Hostname: "foo",
+							IP:       "127.0.0.1",
+						}},
 						CDNs: []*config.CDN{{
 							ID:       1,
 							Hostname: "foo",
 							IP:       "127.0.0.1",
 						}},
 					}, nil).Times(1),
-					hostManager.Store(gomock.Any()).Return().Times(1),
+					hostManager.Store(gomock.Any()).Return().Times(2),
 					dynconfig.Register(gomock.Any()).Return().Times(1),
 					hostManager.Load(gomock.Any()).Return(nil, false).Times(1),
 					hostManager.Store(gomock.Any()).Return().Times(1),
+					hostManager.Load(gomock.Any()).Return(nil, false).Times(1),
+					hostManager.Store(gomock.Any()).Return().Times(1),
 				)
 			},
 		},
 		{
-			name: "cdn list is deep equal",
+			name: "seed peer list is deep equal",
 			data: &config.DynconfigData{
+				SeedPeers: []*config.SeedPeer{{
+					ID: 1,
+					IP: "127.0.0.1",
+				}},
 				CDNs: []*config.CDN{{
 					ID: 1,
 					IP: "127.0.0.1",
@@ -252,12 +245,16 @@ func TestCDNClient_OnNotify(t *testing.T) {
 			mock: func(dynconfig *configmocks.MockDynconfigInterfaceMockRecorder, hostManager *MockHostManagerMockRecorder) {
 				gomock.InOrder(
 					dynconfig.Get().Return(&config.DynconfigData{
+						SeedPeers: []*config.SeedPeer{{
+							ID: 1,
+							IP: "127.0.0.1",
+						}},
 						CDNs: []*config.CDN{{
 							ID: 1,
 							IP: "127.0.0.1",
 						}},
 					}, nil).Times(1),
-					hostManager.Store(gomock.Any()).Return().Times(1),
+					hostManager.Store(gomock.Any()).Return().Times(2),
 					dynconfig.Register(gomock.Any()).Return().Times(1),
 				)
 			},
@@ -272,7 +269,7 @@ func TestCDNClient_OnNotify(t *testing.T) {
 			hostManager := NewMockHostManager(ctl)
 			tc.mock(dynconfig.EXPECT(), hostManager.EXPECT())
 
-			client, err := newCDNClient(dynconfig, hostManager)
+			client, err := newSeedPeerClient(dynconfig, hostManager)
 			if err != nil {
 				t.Fatal(err)
 			}
@@ -281,7 +278,353 @@ func TestCDNClient_OnNotify(t *testing.T) {
 	}
 }
 
-func TestCDNClient_cdnsToHosts(t *testing.T) {
+func TestSeedPeerClient_seedPeersToHosts(t *testing.T) {
+	mockSeedPeerClusterConfig, err := json.Marshal(&types.SeedPeerClusterConfig{
+		LoadLimit: 10,
+	})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	tests := []struct {
+		name      string
+		seedPeers []*config.SeedPeer
+		expect    func(t *testing.T, hosts map[string]*Host)
+	}{
+		{
+			name: "seed peers covert to hosts",
+			seedPeers: []*config.SeedPeer{
+				{
+					ID:           1,
+					Type:         model.SeedPeerTypeSuperSeed,
+					Hostname:     mockRawSeedHost.HostName,
+					IP:           mockRawSeedHost.Ip,
+					Port:         mockRawSeedHost.RpcPort,
+					DownloadPort: mockRawSeedHost.DownPort,
+					IDC:          mockRawSeedHost.Idc,
+					NetTopology:  mockRawSeedHost.NetTopology,
+					Location:     mockRawSeedHost.Location,
+					SeedPeerCluster: &config.SeedPeerCluster{
+						Config: mockSeedPeerClusterConfig,
+					},
+				},
+			},
+			expect: func(t *testing.T, hosts map[string]*Host) {
+				assert := assert.New(t)
+				assert.Equal(hosts[mockRawSeedHost.Uuid].ID, mockRawSeedHost.Uuid)
+				assert.Equal(hosts[mockRawSeedHost.Uuid].Type, HostTypeSuperSeed)
+				assert.Equal(hosts[mockRawSeedHost.Uuid].IP, mockRawSeedHost.Ip)
+				assert.Equal(hosts[mockRawSeedHost.Uuid].Hostname, mockRawSeedHost.HostName)
+				assert.Equal(hosts[mockRawSeedHost.Uuid].Port, mockRawSeedHost.RpcPort)
+				assert.Equal(hosts[mockRawSeedHost.Uuid].DownloadPort, mockRawSeedHost.DownPort)
+				assert.Equal(hosts[mockRawSeedHost.Uuid].IDC, mockRawSeedHost.Idc)
+				assert.Equal(hosts[mockRawSeedHost.Uuid].NetTopology, mockRawSeedHost.NetTopology)
+				assert.Equal(hosts[mockRawSeedHost.Uuid].Location, mockRawSeedHost.Location)
+				assert.Equal(hosts[mockRawSeedHost.Uuid].UploadLoadLimit.Load(), int32(10))
+				assert.Empty(hosts[mockRawSeedHost.Uuid].Peers)
+				assert.Equal(hosts[mockRawSeedHost.Uuid].IsCDN, false)
+				assert.NotEqual(hosts[mockRawSeedHost.Uuid].CreateAt.Load(), 0)
+				assert.NotEqual(hosts[mockRawSeedHost.Uuid].UpdateAt.Load(), 0)
+				assert.NotNil(hosts[mockRawSeedHost.Uuid].Log)
+			},
+		},
+		{
+			name: "seed peers covert to hosts without cluster config",
+			seedPeers: []*config.SeedPeer{
+				{
+					ID:           1,
+					Type:         model.SeedPeerTypeSuperSeed,
+					Hostname:     mockRawSeedHost.HostName,
+					IP:           mockRawSeedHost.Ip,
+					Port:         mockRawSeedHost.RpcPort,
+					DownloadPort: mockRawSeedHost.DownPort,
+					IDC:          mockRawSeedHost.Idc,
+					NetTopology:  mockRawSeedHost.NetTopology,
+					Location:     mockRawSeedHost.Location,
+				},
+			},
+			expect: func(t *testing.T, hosts map[string]*Host) {
+				assert := assert.New(t)
+				assert.Equal(hosts[mockRawSeedHost.Uuid].ID, mockRawSeedHost.Uuid)
+				assert.Equal(hosts[mockRawSeedHost.Uuid].Type, HostTypeSuperSeed)
+				assert.Equal(hosts[mockRawSeedHost.Uuid].IP, mockRawSeedHost.Ip)
+				assert.Equal(hosts[mockRawSeedHost.Uuid].Hostname, mockRawSeedHost.HostName)
+				assert.Equal(hosts[mockRawSeedHost.Uuid].Port, mockRawSeedHost.RpcPort)
+				assert.Equal(hosts[mockRawSeedHost.Uuid].DownloadPort, mockRawSeedHost.DownPort)
+				assert.Equal(hosts[mockRawSeedHost.Uuid].IDC, mockRawSeedHost.Idc)
+				assert.Equal(hosts[mockRawSeedHost.Uuid].NetTopology, mockRawSeedHost.NetTopology)
+				assert.Equal(hosts[mockRawSeedHost.Uuid].Location, mockRawSeedHost.Location)
+				assert.Equal(hosts[mockRawSeedHost.Uuid].UploadLoadLimit.Load(), int32(config.DefaultClientLoadLimit))
+				assert.Empty(hosts[mockRawSeedHost.Uuid].Peers)
+				assert.Equal(hosts[mockRawSeedHost.Uuid].IsCDN, false)
+				assert.NotEqual(hosts[mockRawSeedHost.Uuid].CreateAt.Load(), 0)
+				assert.NotEqual(hosts[mockRawSeedHost.Uuid].UpdateAt.Load(), 0)
+				assert.NotNil(hosts[mockRawSeedHost.Uuid].Log)
+			},
+		},
+		{
+			name:      "seed peers is empty",
+			seedPeers: []*config.SeedPeer{},
+			expect: func(t *testing.T, hosts map[string]*Host) {
+				assert := assert.New(t)
+				assert.Equal(len(hosts), 0)
+			},
+		},
+	}
+
+	for _, tc := range tests {
+		t.Run(tc.name, func(t *testing.T) {
+			tc.expect(t, seedPeersToHosts(tc.seedPeers))
+		})
+	}
+}
+
+func TestSeedPeerClient_seedPeersToNetAddrs(t *testing.T) {
+	tests := []struct {
+		name      string
+		seedPeers []*config.SeedPeer
+		expect    func(t *testing.T, netAddrs []dfnet.NetAddr)
+	}{
+		{
+			name: "seed peers covert to netAddr",
+			seedPeers: []*config.SeedPeer{
+				{
+					ID:           1,
+					Type:         model.SeedPeerTypeSuperSeed,
+					Hostname:     mockRawSeedHost.HostName,
+					IP:           mockRawSeedHost.Ip,
+					Port:         mockRawSeedHost.RpcPort,
+					DownloadPort: mockRawSeedHost.DownPort,
+					IDC:          mockRawSeedHost.Idc,
+					NetTopology:  mockRawSeedHost.NetTopology,
+					Location:     mockRawSeedHost.Location,
+				},
+			},
+			expect: func(t *testing.T, netAddrs []dfnet.NetAddr) {
+				assert := assert.New(t)
+				assert.Equal(netAddrs[0].Type, dfnet.TCP)
+				assert.Equal(netAddrs[0].Addr, fmt.Sprintf("%s:%d", mockRawSeedHost.Ip, mockRawSeedHost.RpcPort))
+			},
+		},
+		{
+			name:      "seed peers is empty",
+			seedPeers: []*config.SeedPeer{},
+			expect: func(t *testing.T, netAddrs []dfnet.NetAddr) {
+				assert := assert.New(t)
+				assert.Equal(len(netAddrs), 0)
+			},
+		},
+	}
+
+	for _, tc := range tests {
+		t.Run(tc.name, func(t *testing.T) {
+			tc.expect(t, seedPeersToNetAddrs(tc.seedPeers))
+		})
+	}
+}
+
+func TestSeedPeerClient_diffSeedPeers(t *testing.T) {
+	tests := []struct {
+		name   string
+		sx     []*config.SeedPeer
+		sy     []*config.SeedPeer
+		expect func(t *testing.T, diff []*config.SeedPeer)
+	}{
+		{
+			name: "same seed peer list",
+			sx: []*config.SeedPeer{
+				{
+					ID:       1,
+					Hostname: "foo",
+					IP:       "127.0.0.1",
+					Port:     8080,
+				},
+			},
+			sy: []*config.SeedPeer{
+				{
+					ID:       1,
+					Hostname: "foo",
+					IP:       "127.0.0.1",
+					Port:     8080,
+				},
+			},
+			expect: func(t *testing.T, diff []*config.SeedPeer) {
+				assert := assert.New(t)
+				assert.EqualValues(diff, []*config.SeedPeer(nil))
+			},
+		},
+		{
+			name: "different hostname",
+			sx: []*config.SeedPeer{
+				{
+					ID:       1,
+					Hostname: "bar",
+					IP:       "127.0.0.1",
+					Port:     8080,
+				},
+			},
+			sy: []*config.SeedPeer{
+				{
+					ID:       1,
+					Hostname: "foo",
+					IP:       "127.0.0.1",
+					Port:     8080,
+				},
+			},
+			expect: func(t *testing.T, diff []*config.SeedPeer) {
+				assert := assert.New(t)
+				assert.EqualValues(diff, []*config.SeedPeer{
+					{
+						ID:       1,
+						Hostname: "bar",
+						IP:       "127.0.0.1",
+						Port:     8080,
+					},
+				})
+			},
+		},
+		{
+			name: "different port",
+			sx: []*config.SeedPeer{
+				{
+					ID:       1,
+					Hostname: "foo",
+					IP:       "127.0.0.1",
+					Port:     8081,
+				},
+			},
+			sy: []*config.SeedPeer{
+				{
+					ID:       1,
+					Hostname: "foo",
+					IP:       "127.0.0.1",
+					Port:     8080,
+				},
+			},
+			expect: func(t *testing.T, diff []*config.SeedPeer) {
+				assert := assert.New(t)
+				assert.EqualValues(diff, []*config.SeedPeer{
+					{
+						ID:       1,
+						Hostname: "foo",
+						IP:       "127.0.0.1",
+						Port:     8081,
+					},
+				})
+			},
+		},
+		{
+			name: "different ip",
+			sx: []*config.SeedPeer{
+				{
+					ID:       1,
+					Hostname: "foo",
+					IP:       "0.0.0.0",
+					Port:     8080,
+				},
+			},
+			sy: []*config.SeedPeer{
+				{
+					ID:       1,
+					Hostname: "foo",
+					IP:       "127.0.0.1",
+					Port:     8080,
+				},
+			},
+			expect: func(t *testing.T, diff []*config.SeedPeer) {
+				assert := assert.New(t)
+				assert.EqualValues(diff, []*config.SeedPeer{
+					{
+						ID:       1,
+						Hostname: "foo",
+						IP:       "0.0.0.0",
+						Port:     8080,
+					},
+				})
+			},
+		},
+		{
+			name: "remove y seed peer",
+			sx: []*config.SeedPeer{
+				{
+					ID:       1,
+					Hostname: "foo",
+					IP:       "127.0.0.1",
+					Port:     8080,
+				},
+				{
+					ID:       2,
+					Hostname: "bar",
+					IP:       "127.0.0.1",
+					Port:     8080,
+				},
+			},
+			sy: []*config.SeedPeer{
+				{
+					ID:       1,
+					Hostname: "foo",
+					IP:       "127.0.0.1",
+					Port:     8080,
+				},
+			},
+			expect: func(t *testing.T, diff []*config.SeedPeer) {
+				assert := assert.New(t)
+				assert.EqualValues(diff, []*config.SeedPeer{
+					{
+						ID:       2,
+						Hostname: "bar",
+						IP:       "127.0.0.1",
+						Port:     8080,
+					},
+				})
+			},
+		},
+		{
+			name: "remove x seed peer",
+			sx: []*config.SeedPeer{
+				{
+					ID:       1,
+					Hostname: "foo",
+					IP:       "127.0.0.1",
+					Port:     8080,
+				},
+			},
+			sy: []*config.SeedPeer{
+				{
+					ID:       1,
+					Hostname: "baz",
+					IP:       "127.0.0.1",
+					Port:     8080,
+				},
+				{
+					ID:       2,
+					Hostname: "bar",
+					IP:       "127.0.0.1",
+					Port:     8080,
+				},
+			},
+			expect: func(t *testing.T, diff []*config.SeedPeer) {
+				assert := assert.New(t)
+				assert.EqualValues(diff, []*config.SeedPeer{
+					{
+						ID:       1,
+						Hostname: "foo",
+						IP:       "127.0.0.1",
+						Port:     8080,
+					},
+				})
+			},
+		},
+	}
+
+	for _, tc := range tests {
+		t.Run(tc.name, func(t *testing.T) {
+			tc.expect(t, diffSeedPeers(tc.sx, tc.sy))
+		})
+	}
+}
+
+func TestSeedPeerClient_cdnsToHosts(t *testing.T) {
 	mockCDNClusterConfig, err := json.Marshal(&types.CDNClusterConfig{
 		LoadLimit:   10,
 		NetTopology: "foo",
@@ -314,6 +657,7 @@ func TestCDNClient_cdnsToHosts(t *testing.T) {
 			expect: func(t *testing.T, hosts map[string]*Host) {
 				assert := assert.New(t)
 				assert.Equal(hosts[mockRawCDNHost.Uuid].ID, mockRawCDNHost.Uuid)
+				assert.Equal(hosts[mockRawCDNHost.Uuid].Type, HostTypeSuperSeed)
 				assert.Equal(hosts[mockRawCDNHost.Uuid].IP, mockRawCDNHost.Ip)
 				assert.Equal(hosts[mockRawCDNHost.Uuid].Hostname, mockRawCDNHost.HostName)
 				assert.Equal(hosts[mockRawCDNHost.Uuid].Port, mockRawCDNHost.RpcPort)
@@ -345,6 +689,7 @@ func TestCDNClient_cdnsToHosts(t *testing.T) {
 			expect: func(t *testing.T, hosts map[string]*Host) {
 				assert := assert.New(t)
 				assert.Equal(hosts[mockRawCDNHost.Uuid].ID, mockRawCDNHost.Uuid)
+				assert.Equal(hosts[mockRawCDNHost.Uuid].Type, HostTypeSuperSeed)
 				assert.Equal(hosts[mockRawCDNHost.Uuid].IP, mockRawCDNHost.Ip)
 				assert.Equal(hosts[mockRawCDNHost.Uuid].Hostname, mockRawCDNHost.HostName)
 				assert.Equal(hosts[mockRawCDNHost.Uuid].Port, mockRawCDNHost.RpcPort)
@@ -377,7 +722,7 @@ func TestCDNClient_cdnsToHosts(t *testing.T) {
 	}
 }
 
-func TestCDNClient_cdnsToNetAddrs(t *testing.T) {
+func TestSeedPeerClient_cdnsToNetAddrs(t *testing.T) {
 	tests := []struct {
 		name   string
 		cdns   []*config.CDN
@@ -419,7 +764,7 @@ func TestCDNClient_cdnsToNetAddrs(t *testing.T) {
 	}
 }
 
-func TestCDNClient_diffCDNs(t *testing.T) {
+func TestSeedPeerClient_diffCDNs(t *testing.T) {
 	tests := []struct {
 		name   string
 		cx     []*config.CDN
diff --git a/scheduler/resource/seed_peer_test.go b/scheduler/resource/seed_peer_test.go
new file mode 100644
index 00000000..f2f8df41
--- /dev/null
+++ b/scheduler/resource/seed_peer_test.go
@@ -0,0 +1,91 @@
+/*
+ *     Copyright 2022 The Dragonfly Authors
+ *
+ * Licensed 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 resource
+
+import (
+	"context"
+	"errors"
+	"reflect"
+	"testing"
+
+	gomock "github.com/golang/mock/gomock"
+	"github.com/stretchr/testify/assert"
+
+	rpcscheduler "d7y.io/dragonfly/v2/pkg/rpc/scheduler"
+)
+
+func TestSeedPeer_newSeedPeer(t *testing.T) {
+	tests := []struct {
+		name   string
+		expect func(t *testing.T, s SeedPeer)
+	}{
+		{
+			name: "new seed peer",
+			expect: func(t *testing.T, s SeedPeer) {
+				assert := assert.New(t)
+				assert.Equal(reflect.TypeOf(s).Elem().Name(), "seedPeer")
+			},
+		},
+	}
+
+	for _, tc := range tests {
+		t.Run(tc.name, func(t *testing.T) {
+			ctl := gomock.NewController(t)
+			defer ctl.Finish()
+			hostManager := NewMockHostManager(ctl)
+			peerManager := NewMockPeerManager(ctl)
+			client := NewMockSeedPeerClient(ctl)
+
+			tc.expect(t, newSeedPeer(client, peerManager, hostManager))
+		})
+	}
+}
+
+func TestSeedPeer_TriggerTask(t *testing.T) {
+	tests := []struct {
+		name   string
+		mock   func(mc *MockSeedPeerClientMockRecorder)
+		expect func(t *testing.T, peer *Peer, result *rpcscheduler.PeerResult, err error)
+	}{
+		{
+			name: "start obtain seed stream failed",
+			mock: func(mc *MockSeedPeerClientMockRecorder) {
+				mc.ObtainSeeds(gomock.Any(), gomock.Any()).Return(nil, errors.New("foo")).Times(1)
+			},
+			expect: func(t *testing.T, peer *Peer, result *rpcscheduler.PeerResult, err error) {
+				assert := assert.New(t)
+				assert.EqualError(err, "foo")
+			},
+		},
+	}
+
+	for _, tc := range tests {
+		t.Run(tc.name, func(t *testing.T) {
+			ctl := gomock.NewController(t)
+			defer ctl.Finish()
+			hostManager := NewMockHostManager(ctl)
+			peerManager := NewMockPeerManager(ctl)
+			client := NewMockSeedPeerClient(ctl)
+			tc.mock(client.EXPECT())
+
+			seedPeer := newSeedPeer(client, peerManager, hostManager)
+			mockTask := NewTask(mockTaskID, mockTaskURL, TaskTypeNormal, mockTaskURLMeta, WithBackToSourceLimit(mockTaskBackToSourceLimit))
+			peer, result, err := seedPeer.TriggerTask(context.Background(), mockTask)
+			tc.expect(t, peer, result, err)
+		})
+	}
+}
diff --git a/scheduler/resource/task_test.go b/scheduler/resource/task_test.go
index 69bc794e..7405a154 100644
--- a/scheduler/resource/task_test.go
+++ b/scheduler/resource/task_test.go
@@ -361,52 +361,52 @@ func TestTask_HasAvailablePeer(t *testing.T) {
 	}
 }
 
-func TestTask_LoadCDNPeer(t *testing.T) {
+func TestTask_LoadSeedPeer(t *testing.T) {
 	tests := []struct {
 		name   string
-		expect func(t *testing.T, task *Task, mockPeer *Peer, mockCDNPeer *Peer)
+		expect func(t *testing.T, task *Task, mockPeer *Peer, mockSeedPeer *Peer)
 	}{
 		{
-			name: "load cdn peer",
-			expect: func(t *testing.T, task *Task, mockPeer *Peer, mockCDNPeer *Peer) {
+			name: "load seed peer",
+			expect: func(t *testing.T, task *Task, mockPeer *Peer, mockSeedPeer *Peer) {
 				assert := assert.New(t)
 				task.StorePeer(mockPeer)
-				task.StorePeer(mockCDNPeer)
-				peer, ok := task.LoadCDNPeer()
+				task.StorePeer(mockSeedPeer)
+				peer, ok := task.LoadSeedPeer()
 				assert.True(ok)
-				assert.Equal(peer.ID, mockCDNPeer.ID)
+				assert.Equal(peer.ID, mockSeedPeer.ID)
 			},
 		},
 		{
-			name: "load latest cdn peer",
-			expect: func(t *testing.T, task *Task, mockPeer *Peer, mockCDNPeer *Peer) {
+			name: "load latest seed peer",
+			expect: func(t *testing.T, task *Task, mockPeer *Peer, mockSeedPeer *Peer) {
 				assert := assert.New(t)
-				mockPeer.Host.IsCDN = true
+				mockPeer.Host.Type = HostTypeSuperSeed
 				task.StorePeer(mockPeer)
-				task.StorePeer(mockCDNPeer)
+				task.StorePeer(mockSeedPeer)
 
 				mockPeer.UpdateAt.Store(time.Now())
-				mockCDNPeer.UpdateAt.Store(time.Now().Add(1 * time.Second))
+				mockSeedPeer.UpdateAt.Store(time.Now().Add(1 * time.Second))
 
-				peer, ok := task.LoadCDNPeer()
+				peer, ok := task.LoadSeedPeer()
 				assert.True(ok)
-				assert.Equal(peer.ID, mockCDNPeer.ID)
+				assert.Equal(peer.ID, mockSeedPeer.ID)
 			},
 		},
 		{
 			name: "peers is empty",
-			expect: func(t *testing.T, task *Task, mockPeer *Peer, mockCDNPeer *Peer) {
+			expect: func(t *testing.T, task *Task, mockPeer *Peer, mockSeedPeer *Peer) {
 				assert := assert.New(t)
-				_, ok := task.LoadCDNPeer()
+				_, ok := task.LoadSeedPeer()
 				assert.False(ok)
 			},
 		},
 		{
-			name: "cdn peers is empty",
-			expect: func(t *testing.T, task *Task, mockPeer *Peer, mockCDNPeer *Peer) {
+			name: "seed peers is empty",
+			expect: func(t *testing.T, task *Task, mockPeer *Peer, mockSeedPeer *Peer) {
 				assert := assert.New(t)
 				task.StorePeer(mockPeer)
-				_, ok := task.LoadCDNPeer()
+				_, ok := task.LoadSeedPeer()
 				assert.False(ok)
 			},
 		},
@@ -415,50 +415,50 @@ func TestTask_LoadCDNPeer(t *testing.T) {
 	for _, tc := range tests {
 		t.Run(tc.name, func(t *testing.T) {
 			mockHost := NewHost(mockRawHost)
-			mockCDNHost := NewHost(mockRawCDNHost, WithIsCDN(true))
+			mockSeedHost := NewHost(mockRawSeedHost, WithHostType(HostTypeSuperSeed))
 			task := NewTask(mockTaskID, mockTaskURL, TaskTypeNormal, mockTaskURLMeta, WithBackToSourceLimit(mockTaskBackToSourceLimit))
 			mockPeer := NewPeer(mockPeerID, task, mockHost)
-			mockCDNPeer := NewPeer(mockCDNPeerID, task, mockCDNHost)
+			mockSeedPeer := NewPeer(mockSeedPeerID, task, mockSeedHost)
 
-			tc.expect(t, task, mockPeer, mockCDNPeer)
+			tc.expect(t, task, mockPeer, mockSeedPeer)
 		})
 	}
 }
 
-func TestTask_IsCDNFailed(t *testing.T) {
+func TestTask_IsSeedPeerFailed(t *testing.T) {
 	tests := []struct {
 		name   string
-		expect func(t *testing.T, task *Task, mockPeer *Peer, mockCDNPeer *Peer)
+		expect func(t *testing.T, task *Task, mockPeer *Peer, mockSeedPeer *Peer)
 	}{
 		{
-			name: "cdn state is PeerStateFailed",
-			expect: func(t *testing.T, task *Task, mockPeer *Peer, mockCDNPeer *Peer) {
+			name: "seed peer state is PeerStateFailed",
+			expect: func(t *testing.T, task *Task, mockPeer *Peer, mockSeedPeer *Peer) {
 				assert := assert.New(t)
 				task.StorePeer(mockPeer)
-				task.StorePeer(mockCDNPeer)
-				mockCDNPeer.FSM.SetState(PeerStateFailed)
+				task.StorePeer(mockSeedPeer)
+				mockSeedPeer.FSM.SetState(PeerStateFailed)
 
-				assert.True(task.IsCDNFailed())
+				assert.True(task.IsSeedPeerFailed())
 			},
 		},
 		{
-			name: "can not find cdn peer",
-			expect: func(t *testing.T, task *Task, mockPeer *Peer, mockCDNPeer *Peer) {
+			name: "can not find seed peer",
+			expect: func(t *testing.T, task *Task, mockPeer *Peer, mockSeedPeer *Peer) {
 				assert := assert.New(t)
 				task.StorePeer(mockPeer)
 
-				assert.False(task.IsCDNFailed())
+				assert.False(task.IsSeedPeerFailed())
 			},
 		},
 		{
-			name: "cdn state is PeerStateSucceeded",
-			expect: func(t *testing.T, task *Task, mockPeer *Peer, mockCDNPeer *Peer) {
+			name: "seed peer state is PeerStateSucceeded",
+			expect: func(t *testing.T, task *Task, mockPeer *Peer, mockSeedPeer *Peer) {
 				assert := assert.New(t)
 				task.StorePeer(mockPeer)
-				task.StorePeer(mockCDNPeer)
-				mockCDNPeer.FSM.SetState(PeerStateSucceeded)
+				task.StorePeer(mockSeedPeer)
+				mockSeedPeer.FSM.SetState(PeerStateSucceeded)
 
-				assert.False(task.IsCDNFailed())
+				assert.False(task.IsSeedPeerFailed())
 			},
 		},
 	}
@@ -466,12 +466,12 @@ func TestTask_IsCDNFailed(t *testing.T) {
 	for _, tc := range tests {
 		t.Run(tc.name, func(t *testing.T) {
 			mockHost := NewHost(mockRawHost)
-			mockCDNHost := NewHost(mockRawCDNHost, WithIsCDN(true))
+			mockSeedHost := NewHost(mockRawSeedHost, WithHostType(HostTypeSuperSeed))
 			task := NewTask(mockTaskID, mockTaskURL, TaskTypeNormal, mockTaskURLMeta, WithBackToSourceLimit(mockTaskBackToSourceLimit))
 			mockPeer := NewPeer(mockPeerID, task, mockHost)
-			mockCDNPeer := NewPeer(mockCDNPeerID, task, mockCDNHost)
+			mockSeedPeer := NewPeer(mockSeedPeerID, task, mockSeedHost)
 
-			tc.expect(t, task, mockPeer, mockCDNPeer)
+			tc.expect(t, task, mockPeer, mockSeedPeer)
 		})
 	}
 }
diff --git a/scheduler/scheduler/evaluator/evaluator_base_test.go b/scheduler/scheduler/evaluator/evaluator_base_test.go
index 83e6d1f5..88301ff9 100644
--- a/scheduler/scheduler/evaluator/evaluator_base_test.go
+++ b/scheduler/scheduler/evaluator/evaluator_base_test.go
@@ -329,10 +329,10 @@ func TestEvaluatorBase_calculateHostTypeAffinityScore(t *testing.T) {
 			},
 		},
 		{
-			name: "host is cdn but peer state is PeerStateSucceeded",
+			name: "host is seed peer but peer state is PeerStateSucceeded",
 			mock: func(peer *resource.Peer) {
 				peer.FSM.SetState(resource.PeerStateSucceeded)
-				peer.Host.IsCDN = true
+				peer.Host.Type = resource.HostTypeSuperSeed
 			},
 			expect: func(t *testing.T, score float64) {
 				assert := assert.New(t)
@@ -340,10 +340,10 @@ func TestEvaluatorBase_calculateHostTypeAffinityScore(t *testing.T) {
 			},
 		},
 		{
-			name: "host is cdn but peer state is PeerStateRunning",
+			name: "host is seed peer but peer state is PeerStateRunning",
 			mock: func(peer *resource.Peer) {
-				peer.Host.IsCDN = true
 				peer.FSM.SetState(resource.PeerStateRunning)
+				peer.Host.Type = resource.HostTypeSuperSeed
 			},
 			expect: func(t *testing.T, score float64) {
 				assert := assert.New(t)
diff --git a/scheduler/scheduler/scheduler_test.go b/scheduler/scheduler/scheduler_test.go
index 17873fff..80eda589 100644
--- a/scheduler/scheduler/scheduler_test.go
+++ b/scheduler/scheduler/scheduler_test.go
@@ -59,8 +59,9 @@ var (
 		Idc:            "idc",
 		NetTopology:    "net_topology",
 	}
-	mockRawCDNHost = &rpcscheduler.PeerHost{
-		Uuid:           idgen.CDNHostID("hostname", 8003),
+
+	mockRawSeedHost = &rpcscheduler.PeerHost{
+		Uuid:           idgen.SeedHostID("hostname", 8003),
 		Ip:             "127.0.0.1",
 		RpcPort:        8003,
 		DownPort:       8001,
@@ -70,6 +71,7 @@ var (
 		Idc:            "idc",
 		NetTopology:    "net_topology",
 	}
+
 	mockTaskURLMeta = &base.UrlMeta{
 		Digest: "digest",
 		Tag:    "tag",
@@ -79,11 +81,12 @@ var (
 			"content-length": "100",
 		},
 	}
+
 	mockTaskBackToSourceLimit int32 = 200
 	mockTaskURL                     = "http://example.com/foo"
 	mockTaskID                      = idgen.TaskID(mockTaskURL, mockTaskURLMeta)
 	mockPeerID                      = idgen.PeerID("127.0.0.1")
-	mockCDNPeerID                   = idgen.CDNPeerID("127.0.0.1")
+	mockSeedPeerID                  = idgen.SeedPeerID("127.0.0.1")
 )
 
 func TestScheduler_New(t *testing.T) {
@@ -124,12 +127,12 @@ func TestScheduler_New(t *testing.T) {
 func TestScheduler_ScheduleParent(t *testing.T) {
 	tests := []struct {
 		name   string
-		mock   func(cancel context.CancelFunc, peer *resource.Peer, cdnPeer *resource.Peer, blocklist set.SafeSet, stream rpcscheduler.Scheduler_ReportPieceResultServer, mr *rpcschedulermocks.MockScheduler_ReportPieceResultServerMockRecorder, md *configmocks.MockDynconfigInterfaceMockRecorder)
+		mock   func(cancel context.CancelFunc, peer *resource.Peer, seedPeer *resource.Peer, blocklist set.SafeSet, stream rpcscheduler.Scheduler_ReportPieceResultServer, mr *rpcschedulermocks.MockScheduler_ReportPieceResultServerMockRecorder, md *configmocks.MockDynconfigInterfaceMockRecorder)
 		expect func(t *testing.T, peer *resource.Peer)
 	}{
 		{
 			name: "context was done",
-			mock: func(cancel context.CancelFunc, peer *resource.Peer, cdnPeer *resource.Peer, blocklist set.SafeSet, stream rpcscheduler.Scheduler_ReportPieceResultServer, mr *rpcschedulermocks.MockScheduler_ReportPieceResultServerMockRecorder, md *configmocks.MockDynconfigInterfaceMockRecorder) {
+			mock: func(cancel context.CancelFunc, peer *resource.Peer, seedPeer *resource.Peer, blocklist set.SafeSet, stream rpcscheduler.Scheduler_ReportPieceResultServer, mr *rpcschedulermocks.MockScheduler_ReportPieceResultServerMockRecorder, md *configmocks.MockDynconfigInterfaceMockRecorder) {
 				peer.FSM.SetState(resource.PeerStateRunning)
 				cancel()
 			},
@@ -139,13 +142,13 @@ func TestScheduler_ScheduleParent(t *testing.T) {
 			},
 		},
 		{
-			name: "cdn peer state is PeerStateFailed and peer stream load failed",
-			mock: func(cancel context.CancelFunc, peer *resource.Peer, cdnPeer *resource.Peer, blocklist set.SafeSet, stream rpcscheduler.Scheduler_ReportPieceResultServer, mr *rpcschedulermocks.MockScheduler_ReportPieceResultServerMockRecorder, md *configmocks.MockDynconfigInterfaceMockRecorder) {
+			name: "seed peer state is PeerStateFailed and peer stream load failed",
+			mock: func(cancel context.CancelFunc, peer *resource.Peer, seedPeer *resource.Peer, blocklist set.SafeSet, stream rpcscheduler.Scheduler_ReportPieceResultServer, mr *rpcschedulermocks.MockScheduler_ReportPieceResultServerMockRecorder, md *configmocks.MockDynconfigInterfaceMockRecorder) {
 				task := peer.Task
 				task.StorePeer(peer)
-				task.StorePeer(cdnPeer)
+				task.StorePeer(seedPeer)
 				peer.FSM.SetState(resource.PeerStateRunning)
-				cdnPeer.FSM.SetState(resource.PeerStateFailed)
+				seedPeer.FSM.SetState(resource.PeerStateFailed)
 			},
 			expect: func(t *testing.T, peer *resource.Peer) {
 				assert := assert.New(t)
@@ -153,14 +156,14 @@ func TestScheduler_ScheduleParent(t *testing.T) {
 			},
 		},
 		{
-			name: "cdn peer state is PeerStateFailed and send Code_SchedNeedBackSource code failed",
-			mock: func(cancel context.CancelFunc, peer *resource.Peer, cdnPeer *resource.Peer, blocklist set.SafeSet, stream rpcscheduler.Scheduler_ReportPieceResultServer, mr *rpcschedulermocks.MockScheduler_ReportPieceResultServerMockRecorder, md *configmocks.MockDynconfigInterfaceMockRecorder) {
+			name: "seed peer state is PeerStateFailed and send Code_SchedNeedBackSource code failed",
+			mock: func(cancel context.CancelFunc, peer *resource.Peer, seedPeer *resource.Peer, blocklist set.SafeSet, stream rpcscheduler.Scheduler_ReportPieceResultServer, mr *rpcschedulermocks.MockScheduler_ReportPieceResultServerMockRecorder, md *configmocks.MockDynconfigInterfaceMockRecorder) {
 				task := peer.Task
 				task.StorePeer(peer)
-				task.StorePeer(cdnPeer)
+				task.StorePeer(seedPeer)
 				peer.FSM.SetState(resource.PeerStateRunning)
-				cdnPeer.FSM.SetState(resource.PeerStateFailed)
-				peer.StoreParent(cdnPeer)
+				seedPeer.FSM.SetState(resource.PeerStateFailed)
+				peer.StoreParent(seedPeer)
 				peer.StoreStream(stream)
 
 				mr.Send(gomock.Eq(&rpcscheduler.PeerPacket{Code: base.Code_SchedNeedBackSource})).Return(errors.New("foo")).Times(1)
@@ -173,14 +176,14 @@ func TestScheduler_ScheduleParent(t *testing.T) {
 			},
 		},
 		{
-			name: "cdn peer state is PeerStateFailed and send Code_SchedNeedBackSource code success",
-			mock: func(cancel context.CancelFunc, peer *resource.Peer, cdnPeer *resource.Peer, blocklist set.SafeSet, stream rpcscheduler.Scheduler_ReportPieceResultServer, mr *rpcschedulermocks.MockScheduler_ReportPieceResultServerMockRecorder, md *configmocks.MockDynconfigInterfaceMockRecorder) {
+			name: "seed peer state is PeerStateFailed and send Code_SchedNeedBackSource code success",
+			mock: func(cancel context.CancelFunc, peer *resource.Peer, seedPeer *resource.Peer, blocklist set.SafeSet, stream rpcscheduler.Scheduler_ReportPieceResultServer, mr *rpcschedulermocks.MockScheduler_ReportPieceResultServerMockRecorder, md *configmocks.MockDynconfigInterfaceMockRecorder) {
 				task := peer.Task
 				task.StorePeer(peer)
-				task.StorePeer(cdnPeer)
-				cdnPeer.FSM.SetState(resource.PeerStateFailed)
+				task.StorePeer(seedPeer)
+				seedPeer.FSM.SetState(resource.PeerStateFailed)
 				peer.FSM.SetState(resource.PeerStateRunning)
-				peer.StoreParent(cdnPeer)
+				peer.StoreParent(seedPeer)
 				peer.StoreStream(stream)
 
 				mr.Send(gomock.Eq(&rpcscheduler.PeerPacket{Code: base.Code_SchedNeedBackSource})).Return(nil).Times(1)
@@ -195,7 +198,7 @@ func TestScheduler_ScheduleParent(t *testing.T) {
 		},
 		{
 			name: "peer need back-to-source and send Code_SchedNeedBackSource code success",
-			mock: func(cancel context.CancelFunc, peer *resource.Peer, cdnPeer *resource.Peer, blocklist set.SafeSet, stream rpcscheduler.Scheduler_ReportPieceResultServer, mr *rpcschedulermocks.MockScheduler_ReportPieceResultServerMockRecorder, md *configmocks.MockDynconfigInterfaceMockRecorder) {
+			mock: func(cancel context.CancelFunc, peer *resource.Peer, seedPeer *resource.Peer, blocklist set.SafeSet, stream rpcscheduler.Scheduler_ReportPieceResultServer, mr *rpcschedulermocks.MockScheduler_ReportPieceResultServerMockRecorder, md *configmocks.MockDynconfigInterfaceMockRecorder) {
 				task := peer.Task
 				task.StorePeer(peer)
 				peer.NeedBackToSource.Store(true)
@@ -213,15 +216,15 @@ func TestScheduler_ScheduleParent(t *testing.T) {
 			},
 		},
 		{
-			name: "cdn peer state is PeerStateFailed and task state is PeerStateFailed",
-			mock: func(cancel context.CancelFunc, peer *resource.Peer, cdnPeer *resource.Peer, blocklist set.SafeSet, stream rpcscheduler.Scheduler_ReportPieceResultServer, mr *rpcschedulermocks.MockScheduler_ReportPieceResultServerMockRecorder, md *configmocks.MockDynconfigInterfaceMockRecorder) {
+			name: "seed peer state is PeerStateFailed and task state is PeerStateFailed",
+			mock: func(cancel context.CancelFunc, peer *resource.Peer, seedPeer *resource.Peer, blocklist set.SafeSet, stream rpcscheduler.Scheduler_ReportPieceResultServer, mr *rpcschedulermocks.MockScheduler_ReportPieceResultServerMockRecorder, md *configmocks.MockDynconfigInterfaceMockRecorder) {
 				task := peer.Task
 				task.StorePeer(peer)
-				task.StorePeer(cdnPeer)
-				cdnPeer.FSM.SetState(resource.PeerStateFailed)
+				task.StorePeer(seedPeer)
+				seedPeer.FSM.SetState(resource.PeerStateFailed)
 				peer.FSM.SetState(resource.PeerStateRunning)
 				task.FSM.SetState(resource.TaskStateFailed)
-				peer.StoreParent(cdnPeer)
+				peer.StoreParent(seedPeer)
 				peer.StoreStream(stream)
 
 				mr.Send(gomock.Eq(&rpcscheduler.PeerPacket{Code: base.Code_SchedNeedBackSource})).Return(nil).Times(1)
@@ -235,15 +238,15 @@ func TestScheduler_ScheduleParent(t *testing.T) {
 			},
 		},
 		{
-			name: "cdn peer state is PeerStateFailed and task state is PeerStateFailed",
-			mock: func(cancel context.CancelFunc, peer *resource.Peer, cdnPeer *resource.Peer, blocklist set.SafeSet, stream rpcscheduler.Scheduler_ReportPieceResultServer, mr *rpcschedulermocks.MockScheduler_ReportPieceResultServerMockRecorder, md *configmocks.MockDynconfigInterfaceMockRecorder) {
+			name: "seed peer state is PeerStateFailed and task state is PeerStateFailed",
+			mock: func(cancel context.CancelFunc, peer *resource.Peer, seedPeer *resource.Peer, blocklist set.SafeSet, stream rpcscheduler.Scheduler_ReportPieceResultServer, mr *rpcschedulermocks.MockScheduler_ReportPieceResultServerMockRecorder, md *configmocks.MockDynconfigInterfaceMockRecorder) {
 				task := peer.Task
 				task.StorePeer(peer)
-				task.StorePeer(cdnPeer)
+				task.StorePeer(seedPeer)
 				peer.FSM.SetState(resource.PeerStateRunning)
-				cdnPeer.FSM.SetState(resource.PeerStateFailed)
+				seedPeer.FSM.SetState(resource.PeerStateFailed)
 				task.FSM.SetState(resource.TaskStateFailed)
-				peer.StoreParent(cdnPeer)
+				peer.StoreParent(seedPeer)
 				peer.StoreStream(stream)
 
 				mr.Send(gomock.Eq(&rpcscheduler.PeerPacket{Code: base.Code_SchedNeedBackSource})).Return(nil).Times(1)
@@ -258,7 +261,7 @@ func TestScheduler_ScheduleParent(t *testing.T) {
 		},
 		{
 			name: "schedule exceeds RetryBackSourceLimit and peer stream load failed",
-			mock: func(cancel context.CancelFunc, peer *resource.Peer, cdnPeer *resource.Peer, blocklist set.SafeSet, stream rpcscheduler.Scheduler_ReportPieceResultServer, mr *rpcschedulermocks.MockScheduler_ReportPieceResultServerMockRecorder, md *configmocks.MockDynconfigInterfaceMockRecorder) {
+			mock: func(cancel context.CancelFunc, peer *resource.Peer, seedPeer *resource.Peer, blocklist set.SafeSet, stream rpcscheduler.Scheduler_ReportPieceResultServer, mr *rpcschedulermocks.MockScheduler_ReportPieceResultServerMockRecorder, md *configmocks.MockDynconfigInterfaceMockRecorder) {
 				task := peer.Task
 				task.StorePeer(peer)
 				peer.FSM.SetState(resource.PeerStateRunning)
@@ -270,12 +273,12 @@ func TestScheduler_ScheduleParent(t *testing.T) {
 			},
 		},
 		{
-			name: "cdn peer state is PeerStateFailed and send Code_SchedNeedBackSource code failed",
-			mock: func(cancel context.CancelFunc, peer *resource.Peer, cdnPeer *resource.Peer, blocklist set.SafeSet, stream rpcscheduler.Scheduler_ReportPieceResultServer, mr *rpcschedulermocks.MockScheduler_ReportPieceResultServerMockRecorder, md *configmocks.MockDynconfigInterfaceMockRecorder) {
+			name: "seed peer state is PeerStateFailed and send Code_SchedNeedBackSource code failed",
+			mock: func(cancel context.CancelFunc, peer *resource.Peer, seedPeer *resource.Peer, blocklist set.SafeSet, stream rpcscheduler.Scheduler_ReportPieceResultServer, mr *rpcschedulermocks.MockScheduler_ReportPieceResultServerMockRecorder, md *configmocks.MockDynconfigInterfaceMockRecorder) {
 				task := peer.Task
 				task.StorePeer(peer)
 				peer.FSM.SetState(resource.PeerStateRunning)
-				peer.StoreParent(cdnPeer)
+				peer.StoreParent(seedPeer)
 				peer.StoreStream(stream)
 
 				gomock.InOrder(
@@ -291,12 +294,12 @@ func TestScheduler_ScheduleParent(t *testing.T) {
 			},
 		},
 		{
-			name: "cdn peer state is PeerStateFailed and send Code_SchedNeedBackSource code success",
-			mock: func(cancel context.CancelFunc, peer *resource.Peer, cdnPeer *resource.Peer, blocklist set.SafeSet, stream rpcscheduler.Scheduler_ReportPieceResultServer, mr *rpcschedulermocks.MockScheduler_ReportPieceResultServerMockRecorder, md *configmocks.MockDynconfigInterfaceMockRecorder) {
+			name: "seed peer state is PeerStateFailed and send Code_SchedNeedBackSource code success",
+			mock: func(cancel context.CancelFunc, peer *resource.Peer, seedPeer *resource.Peer, blocklist set.SafeSet, stream rpcscheduler.Scheduler_ReportPieceResultServer, mr *rpcschedulermocks.MockScheduler_ReportPieceResultServerMockRecorder, md *configmocks.MockDynconfigInterfaceMockRecorder) {
 				task := peer.Task
 				task.StorePeer(peer)
 				peer.FSM.SetState(resource.PeerStateRunning)
-				peer.StoreParent(cdnPeer)
+				peer.StoreParent(seedPeer)
 				peer.StoreStream(stream)
 
 				gomock.InOrder(
@@ -313,13 +316,13 @@ func TestScheduler_ScheduleParent(t *testing.T) {
 			},
 		},
 		{
-			name: "cdn peer state is PeerStateFailed and task state is PeerStateFailed",
-			mock: func(cancel context.CancelFunc, peer *resource.Peer, cdnPeer *resource.Peer, blocklist set.SafeSet, stream rpcscheduler.Scheduler_ReportPieceResultServer, mr *rpcschedulermocks.MockScheduler_ReportPieceResultServerMockRecorder, md *configmocks.MockDynconfigInterfaceMockRecorder) {
+			name: "seed peer state is PeerStateFailed and task state is PeerStateFailed",
+			mock: func(cancel context.CancelFunc, peer *resource.Peer, seedPeer *resource.Peer, blocklist set.SafeSet, stream rpcscheduler.Scheduler_ReportPieceResultServer, mr *rpcschedulermocks.MockScheduler_ReportPieceResultServerMockRecorder, md *configmocks.MockDynconfigInterfaceMockRecorder) {
 				task := peer.Task
 				task.StorePeer(peer)
 				peer.FSM.SetState(resource.PeerStateRunning)
 				task.FSM.SetState(resource.TaskStateFailed)
-				peer.StoreParent(cdnPeer)
+				peer.StoreParent(seedPeer)
 				peer.StoreStream(stream)
 
 				gomock.InOrder(
@@ -336,13 +339,13 @@ func TestScheduler_ScheduleParent(t *testing.T) {
 			},
 		},
 		{
-			name: "cdn peer state is PeerStateFailed and task state is PeerStateFailed",
-			mock: func(cancel context.CancelFunc, peer *resource.Peer, cdnPeer *resource.Peer, blocklist set.SafeSet, stream rpcscheduler.Scheduler_ReportPieceResultServer, mr *rpcschedulermocks.MockScheduler_ReportPieceResultServerMockRecorder, md *configmocks.MockDynconfigInterfaceMockRecorder) {
+			name: "seed peer state is PeerStateFailed and task state is PeerStateFailed",
+			mock: func(cancel context.CancelFunc, peer *resource.Peer, seedPeer *resource.Peer, blocklist set.SafeSet, stream rpcscheduler.Scheduler_ReportPieceResultServer, mr *rpcschedulermocks.MockScheduler_ReportPieceResultServerMockRecorder, md *configmocks.MockDynconfigInterfaceMockRecorder) {
 				task := peer.Task
 				task.StorePeer(peer)
 				peer.FSM.SetState(resource.PeerStateRunning)
 				task.FSM.SetState(resource.TaskStateFailed)
-				peer.StoreParent(cdnPeer)
+				peer.StoreParent(seedPeer)
 				peer.StoreStream(stream)
 
 				gomock.InOrder(
@@ -360,7 +363,7 @@ func TestScheduler_ScheduleParent(t *testing.T) {
 		},
 		{
 			name: "schedule exceeds RetryLimit and peer stream load failed",
-			mock: func(cancel context.CancelFunc, peer *resource.Peer, cdnPeer *resource.Peer, blocklist set.SafeSet, stream rpcscheduler.Scheduler_ReportPieceResultServer, mr *rpcschedulermocks.MockScheduler_ReportPieceResultServerMockRecorder, md *configmocks.MockDynconfigInterfaceMockRecorder) {
+			mock: func(cancel context.CancelFunc, peer *resource.Peer, seedPeer *resource.Peer, blocklist set.SafeSet, stream rpcscheduler.Scheduler_ReportPieceResultServer, mr *rpcschedulermocks.MockScheduler_ReportPieceResultServerMockRecorder, md *configmocks.MockDynconfigInterfaceMockRecorder) {
 				task := peer.Task
 				task.StorePeer(peer)
 				peer.FSM.SetState(resource.PeerStateRunning)
@@ -376,7 +379,7 @@ func TestScheduler_ScheduleParent(t *testing.T) {
 		},
 		{
 			name: "schedule exceeds RetryLimit and send Code_SchedTaskStatusError code failed",
-			mock: func(cancel context.CancelFunc, peer *resource.Peer, cdnPeer *resource.Peer, blocklist set.SafeSet, stream rpcscheduler.Scheduler_ReportPieceResultServer, mr *rpcschedulermocks.MockScheduler_ReportPieceResultServerMockRecorder, md *configmocks.MockDynconfigInterfaceMockRecorder) {
+			mock: func(cancel context.CancelFunc, peer *resource.Peer, seedPeer *resource.Peer, blocklist set.SafeSet, stream rpcscheduler.Scheduler_ReportPieceResultServer, mr *rpcschedulermocks.MockScheduler_ReportPieceResultServerMockRecorder, md *configmocks.MockDynconfigInterfaceMockRecorder) {
 				task := peer.Task
 				task.StorePeer(peer)
 				peer.FSM.SetState(resource.PeerStateRunning)
@@ -397,7 +400,7 @@ func TestScheduler_ScheduleParent(t *testing.T) {
 		},
 		{
 			name: "schedule exceeds RetryLimit and send Code_SchedTaskStatusError code success",
-			mock: func(cancel context.CancelFunc, peer *resource.Peer, cdnPeer *resource.Peer, blocklist set.SafeSet, stream rpcscheduler.Scheduler_ReportPieceResultServer, mr *rpcschedulermocks.MockScheduler_ReportPieceResultServerMockRecorder, md *configmocks.MockDynconfigInterfaceMockRecorder) {
+			mock: func(cancel context.CancelFunc, peer *resource.Peer, seedPeer *resource.Peer, blocklist set.SafeSet, stream rpcscheduler.Scheduler_ReportPieceResultServer, mr *rpcschedulermocks.MockScheduler_ReportPieceResultServerMockRecorder, md *configmocks.MockDynconfigInterfaceMockRecorder) {
 				task := peer.Task
 				task.StorePeer(peer)
 				peer.FSM.SetState(resource.PeerStateRunning)
@@ -418,12 +421,12 @@ func TestScheduler_ScheduleParent(t *testing.T) {
 		},
 		{
 			name: "schedule succeeded",
-			mock: func(cancel context.CancelFunc, peer *resource.Peer, cdnPeer *resource.Peer, blocklist set.SafeSet, stream rpcscheduler.Scheduler_ReportPieceResultServer, mr *rpcschedulermocks.MockScheduler_ReportPieceResultServerMockRecorder, md *configmocks.MockDynconfigInterfaceMockRecorder) {
+			mock: func(cancel context.CancelFunc, peer *resource.Peer, seedPeer *resource.Peer, blocklist set.SafeSet, stream rpcscheduler.Scheduler_ReportPieceResultServer, mr *rpcschedulermocks.MockScheduler_ReportPieceResultServerMockRecorder, md *configmocks.MockDynconfigInterfaceMockRecorder) {
 				task := peer.Task
 				task.StorePeer(peer)
-				task.StorePeer(cdnPeer)
+				task.StorePeer(seedPeer)
 				peer.FSM.SetState(resource.PeerStateRunning)
-				cdnPeer.FSM.SetState(resource.PeerStateRunning)
+				seedPeer.FSM.SetState(resource.PeerStateRunning)
 				peer.StoreStream(stream)
 				gomock.InOrder(
 					md.GetSchedulerClusterConfig().Return(types.SchedulerClusterConfig{}, false).Times(1),
@@ -452,11 +455,11 @@ func TestScheduler_ScheduleParent(t *testing.T) {
 			mockHost := resource.NewHost(mockRawHost)
 			mockTask := resource.NewTask(mockTaskID, mockTaskURL, resource.TaskTypeNormal, mockTaskURLMeta, resource.WithBackToSourceLimit(mockTaskBackToSourceLimit))
 			peer := resource.NewPeer(mockPeerID, mockTask, mockHost)
-			mockCDNHost := resource.NewHost(mockRawCDNHost, resource.WithIsCDN(true))
-			cdnPeer := resource.NewPeer(mockCDNPeerID, mockTask, mockCDNHost)
+			mockSeedHost := resource.NewHost(mockRawSeedHost, resource.WithHostType(resource.HostTypeSuperSeed))
+			seedPeer := resource.NewPeer(mockSeedPeerID, mockTask, mockSeedHost)
 			blocklist := set.NewSafeSet()
 
-			tc.mock(cancel, peer, cdnPeer, blocklist, stream, stream.EXPECT(), dynconfig.EXPECT())
+			tc.mock(cancel, peer, seedPeer, blocklist, stream, stream.EXPECT(), dynconfig.EXPECT())
 			scheduler := New(mockSchedulerConfig, dynconfig, mockPluginDir)
 			scheduler.ScheduleParent(ctx, peer, blocklist)
 			tc.expect(t, peer)
@@ -857,15 +860,15 @@ func TestScheduler_FindParent(t *testing.T) {
 			},
 		},
 		{
-			name: "find cdn parent",
+			name: "find seed peer parent",
 			mock: func(peer *resource.Peer, mockPeers []*resource.Peer, blocklist set.SafeSet, md *configmocks.MockDynconfigInterfaceMockRecorder) {
 				peer.FSM.SetState(resource.PeerStateRunning)
 				mockPeers[0].FSM.SetState(resource.PeerStateRunning)
 				mockPeers[1].FSM.SetState(resource.PeerStateRunning)
 				peer.Task.StorePeer(mockPeers[0])
 				peer.Task.StorePeer(mockPeers[1])
-				mockPeers[0].Host.IsCDN = true
-				mockPeers[1].Host.IsCDN = true
+				mockPeers[0].Host.Type = resource.HostTypeSuperSeed
+				mockPeers[1].Host.Type = resource.HostTypeSuperSeed
 				mockPeers[0].Pieces.Set(0)
 				mockPeers[1].Pieces.Set(0)
 				mockPeers[1].Pieces.Set(1)
diff --git a/scheduler/service/service_test.go b/scheduler/service/service_test.go
index eb04e58a..0fbaf2b1 100644
--- a/scheduler/service/service_test.go
+++ b/scheduler/service/service_test.go
@@ -56,6 +56,7 @@ var (
 		RetryInterval:        10 * time.Millisecond,
 		BackSourceCount:      int(mockTaskBackToSourceLimit),
 	}
+
 	mockRawHost = &rpcscheduler.PeerHost{
 		Uuid:           idgen.HostID("hostname", 8003),
 		Ip:             "127.0.0.1",
@@ -67,8 +68,9 @@ var (
 		Idc:            "idc",
 		NetTopology:    "net_topology",
 	}
-	mockRawCDNHost = &rpcscheduler.PeerHost{
-		Uuid:           idgen.CDNHostID("hostname", 8003),
+
+	mockRawSeedHost = &rpcscheduler.PeerHost{
+		Uuid:           idgen.SeedHostID("hostname", 8003),
 		Ip:             "127.0.0.1",
 		RpcPort:        8003,
 		DownPort:       8001,
@@ -78,6 +80,7 @@ var (
 		Idc:            "idc",
 		NetTopology:    "net_topology",
 	}
+
 	mockTaskURLMeta = &base.UrlMeta{
 		Digest: "digest",
 		Tag:    "tag",
@@ -87,11 +90,12 @@ var (
 			"content-length": "100",
 		},
 	}
+
 	mockTaskURL                     = "http://example.com/foo"
 	mockTaskBackToSourceLimit int32 = 200
 	mockTaskID                      = idgen.TaskID(mockTaskURL, mockTaskURLMeta)
 	mockPeerID                      = idgen.PeerID("127.0.0.1")
-	mockCDNPeerID                   = idgen.CDNPeerID("127.0.0.1")
+	mockSeedPeerID                  = idgen.SeedPeerID("127.0.0.1")
 	mockCID                         = "d7y://foo"
 )
 
@@ -127,7 +131,7 @@ func TestService_RegisterPeerTask(t *testing.T) {
 		name string
 		req  *rpcscheduler.PeerTaskRequest
 		mock func(
-			req *rpcscheduler.PeerTaskRequest, mockPeer *resource.Peer, mockCDNPeer *resource.Peer,
+			req *rpcscheduler.PeerTaskRequest, mockPeer *resource.Peer, mockSeedPeer *resource.Peer,
 			scheduler scheduler.Scheduler, res resource.Resource, hostManager resource.HostManager, taskManager resource.TaskManager, peerManager resource.PeerManager,
 			ms *mocks.MockSchedulerMockRecorder, mr *resource.MockResourceMockRecorder, mh *resource.MockHostManagerMockRecorder, mt *resource.MockTaskManagerMockRecorder, mp *resource.MockPeerManagerMockRecorder,
 		)
@@ -139,7 +143,7 @@ func TestService_RegisterPeerTask(t *testing.T) {
 				UrlMeta: &base.UrlMeta{},
 			},
 			mock: func(
-				req *rpcscheduler.PeerTaskRequest, mockPeer *resource.Peer, mockCDNPeer *resource.Peer,
+				req *rpcscheduler.PeerTaskRequest, mockPeer *resource.Peer, mockSeedPeer *resource.Peer,
 				scheduler scheduler.Scheduler, res resource.Resource, hostManager resource.HostManager, taskManager resource.TaskManager, peerManager resource.PeerManager,
 				ms *mocks.MockSchedulerMockRecorder, mr *resource.MockResourceMockRecorder, mh *resource.MockHostManagerMockRecorder, mt *resource.MockTaskManagerMockRecorder, mp *resource.MockPeerManagerMockRecorder,
 			) {
@@ -166,12 +170,12 @@ func TestService_RegisterPeerTask(t *testing.T) {
 				},
 			},
 			mock: func(
-				req *rpcscheduler.PeerTaskRequest, mockPeer *resource.Peer, mockCDNPeer *resource.Peer,
+				req *rpcscheduler.PeerTaskRequest, mockPeer *resource.Peer, mockSeedPeer *resource.Peer,
 				scheduler scheduler.Scheduler, res resource.Resource, hostManager resource.HostManager, taskManager resource.TaskManager, peerManager resource.PeerManager,
 				ms *mocks.MockSchedulerMockRecorder, mr *resource.MockResourceMockRecorder, mh *resource.MockHostManagerMockRecorder, mt *resource.MockTaskManagerMockRecorder, mp *resource.MockPeerManagerMockRecorder,
 			) {
 				mockPeer.Task.FSM.SetState(resource.TaskStateRunning)
-				mockPeer.Task.StorePeer(mockCDNPeer)
+				mockPeer.Task.StorePeer(mockSeedPeer)
 				gomock.InOrder(
 					mr.TaskManager().Return(taskManager).Times(1),
 					mt.LoadOrStore(gomock.Any()).Return(mockPeer.Task, true).Times(1),
@@ -198,12 +202,12 @@ func TestService_RegisterPeerTask(t *testing.T) {
 				},
 			},
 			mock: func(
-				req *rpcscheduler.PeerTaskRequest, mockPeer *resource.Peer, mockCDNPeer *resource.Peer,
+				req *rpcscheduler.PeerTaskRequest, mockPeer *resource.Peer, mockSeedPeer *resource.Peer,
 				scheduler scheduler.Scheduler, res resource.Resource, hostManager resource.HostManager, taskManager resource.TaskManager, peerManager resource.PeerManager,
 				ms *mocks.MockSchedulerMockRecorder, mr *resource.MockResourceMockRecorder, mh *resource.MockHostManagerMockRecorder, mt *resource.MockTaskManagerMockRecorder, mp *resource.MockPeerManagerMockRecorder,
 			) {
 				mockPeer.Task.FSM.SetState(resource.TaskStateRunning)
-				mockPeer.Task.StorePeer(mockCDNPeer)
+				mockPeer.Task.StorePeer(mockSeedPeer)
 				mockPeer.FSM.SetState(resource.PeerStateFailed)
 				gomock.InOrder(
 					mr.TaskManager().Return(taskManager).Times(1),
@@ -231,12 +235,12 @@ func TestService_RegisterPeerTask(t *testing.T) {
 				},
 			},
 			mock: func(
-				req *rpcscheduler.PeerTaskRequest, mockPeer *resource.Peer, mockCDNPeer *resource.Peer,
+				req *rpcscheduler.PeerTaskRequest, mockPeer *resource.Peer, mockSeedPeer *resource.Peer,
 				scheduler scheduler.Scheduler, res resource.Resource, hostManager resource.HostManager, taskManager resource.TaskManager, peerManager resource.PeerManager,
 				ms *mocks.MockSchedulerMockRecorder, mr *resource.MockResourceMockRecorder, mh *resource.MockHostManagerMockRecorder, mt *resource.MockTaskManagerMockRecorder, mp *resource.MockPeerManagerMockRecorder,
 			) {
 				mockPeer.Task.FSM.SetState(resource.TaskStateSucceeded)
-				mockPeer.Task.StorePeer(mockCDNPeer)
+				mockPeer.Task.StorePeer(mockSeedPeer)
 				mockPeer.Task.ContentLength.Store(-1)
 				gomock.InOrder(
 					mr.TaskManager().Return(taskManager).Times(1),
@@ -265,12 +269,12 @@ func TestService_RegisterPeerTask(t *testing.T) {
 				},
 			},
 			mock: func(
-				req *rpcscheduler.PeerTaskRequest, mockPeer *resource.Peer, mockCDNPeer *resource.Peer,
+				req *rpcscheduler.PeerTaskRequest, mockPeer *resource.Peer, mockSeedPeer *resource.Peer,
 				scheduler scheduler.Scheduler, res resource.Resource, hostManager resource.HostManager, taskManager resource.TaskManager, peerManager resource.PeerManager,
 				ms *mocks.MockSchedulerMockRecorder, mr *resource.MockResourceMockRecorder, mh *resource.MockHostManagerMockRecorder, mt *resource.MockTaskManagerMockRecorder, mp *resource.MockPeerManagerMockRecorder,
 			) {
 				mockPeer.Task.FSM.SetState(resource.TaskStateSucceeded)
-				mockPeer.Task.StorePeer(mockCDNPeer)
+				mockPeer.Task.StorePeer(mockSeedPeer)
 				mockPeer.Task.ContentLength.Store(1)
 				mockPeer.Task.TotalPieceCount.Store(1)
 				mockPeer.Task.DirectPiece = []byte{1}
@@ -303,12 +307,12 @@ func TestService_RegisterPeerTask(t *testing.T) {
 				},
 			},
 			mock: func(
-				req *rpcscheduler.PeerTaskRequest, mockPeer *resource.Peer, mockCDNPeer *resource.Peer,
+				req *rpcscheduler.PeerTaskRequest, mockPeer *resource.Peer, mockSeedPeer *resource.Peer,
 				scheduler scheduler.Scheduler, res resource.Resource, hostManager resource.HostManager, taskManager resource.TaskManager, peerManager resource.PeerManager,
 				ms *mocks.MockSchedulerMockRecorder, mr *resource.MockResourceMockRecorder, mh *resource.MockHostManagerMockRecorder, mt *resource.MockTaskManagerMockRecorder, mp *resource.MockPeerManagerMockRecorder,
 			) {
 				mockPeer.Task.FSM.SetState(resource.TaskStateSucceeded)
-				mockPeer.Task.StorePeer(mockCDNPeer)
+				mockPeer.Task.StorePeer(mockSeedPeer)
 				mockPeer.Task.ContentLength.Store(1)
 				mockPeer.Task.TotalPieceCount.Store(1)
 				mockPeer.Task.DirectPiece = []byte{1}
@@ -339,12 +343,12 @@ func TestService_RegisterPeerTask(t *testing.T) {
 				},
 			},
 			mock: func(
-				req *rpcscheduler.PeerTaskRequest, mockPeer *resource.Peer, mockCDNPeer *resource.Peer,
+				req *rpcscheduler.PeerTaskRequest, mockPeer *resource.Peer, mockSeedPeer *resource.Peer,
 				scheduler scheduler.Scheduler, res resource.Resource, hostManager resource.HostManager, taskManager resource.TaskManager, peerManager resource.PeerManager,
 				ms *mocks.MockSchedulerMockRecorder, mr *resource.MockResourceMockRecorder, mh *resource.MockHostManagerMockRecorder, mt *resource.MockTaskManagerMockRecorder, mp *resource.MockPeerManagerMockRecorder,
 			) {
 				mockPeer.Task.FSM.SetState(resource.TaskStateSucceeded)
-				mockPeer.Task.StorePeer(mockCDNPeer)
+				mockPeer.Task.StorePeer(mockSeedPeer)
 				mockPeer.Task.ContentLength.Store(1)
 				mockPeer.Task.TotalPieceCount.Store(1)
 				mockPeer.FSM.SetState(resource.PeerStateFailed)
@@ -375,12 +379,12 @@ func TestService_RegisterPeerTask(t *testing.T) {
 				},
 			},
 			mock: func(
-				req *rpcscheduler.PeerTaskRequest, mockPeer *resource.Peer, mockCDNPeer *resource.Peer,
+				req *rpcscheduler.PeerTaskRequest, mockPeer *resource.Peer, mockSeedPeer *resource.Peer,
 				scheduler scheduler.Scheduler, res resource.Resource, hostManager resource.HostManager, taskManager resource.TaskManager, peerManager resource.PeerManager,
 				ms *mocks.MockSchedulerMockRecorder, mr *resource.MockResourceMockRecorder, mh *resource.MockHostManagerMockRecorder, mt *resource.MockTaskManagerMockRecorder, mp *resource.MockPeerManagerMockRecorder,
 			) {
 				mockPeer.Task.FSM.SetState(resource.TaskStateSucceeded)
-				mockPeer.Task.StorePeer(mockCDNPeer)
+				mockPeer.Task.StorePeer(mockSeedPeer)
 				mockPeer.Task.ContentLength.Store(1)
 				mockPeer.Task.TotalPieceCount.Store(1)
 				gomock.InOrder(
@@ -411,19 +415,19 @@ func TestService_RegisterPeerTask(t *testing.T) {
 				},
 			},
 			mock: func(
-				req *rpcscheduler.PeerTaskRequest, mockPeer *resource.Peer, mockCDNPeer *resource.Peer,
+				req *rpcscheduler.PeerTaskRequest, mockPeer *resource.Peer, mockSeedPeer *resource.Peer,
 				scheduler scheduler.Scheduler, res resource.Resource, hostManager resource.HostManager, taskManager resource.TaskManager, peerManager resource.PeerManager,
 				ms *mocks.MockSchedulerMockRecorder, mr *resource.MockResourceMockRecorder, mh *resource.MockHostManagerMockRecorder, mt *resource.MockTaskManagerMockRecorder, mp *resource.MockPeerManagerMockRecorder,
 			) {
 				mockPeer.Task.FSM.SetState(resource.TaskStateSucceeded)
-				mockPeer.Task.StorePeer(mockCDNPeer)
+				mockPeer.Task.StorePeer(mockSeedPeer)
 				mockPeer.Task.ContentLength.Store(129)
 				mockPeer.Task.StorePiece(&base.PieceInfo{
 					PieceNum: 0,
 				})
 				mockPeer.Task.TotalPieceCount.Store(1)
 				mockPeer.FSM.SetState(resource.PeerStatePending)
-				mockCDNPeer.FSM.SetState(resource.PeerStateRunning)
+				mockSeedPeer.FSM.SetState(resource.PeerStateRunning)
 
 				gomock.InOrder(
 					mr.TaskManager().Return(taskManager).Times(1),
@@ -432,7 +436,7 @@ func TestService_RegisterPeerTask(t *testing.T) {
 					mh.Load(gomock.Eq(mockPeer.Host.ID)).Return(mockPeer.Host, true).Times(1),
 					mr.PeerManager().Return(peerManager).Times(1),
 					mp.LoadOrStore(gomock.Any()).Return(mockPeer, true).Times(1),
-					ms.FindParent(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockCDNPeer, true).Times(1),
+					ms.FindParent(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockSeedPeer, true).Times(1),
 				)
 			},
 			expect: func(t *testing.T, peer *resource.Peer, result *rpcscheduler.RegisterResult, err error) {
@@ -453,19 +457,19 @@ func TestService_RegisterPeerTask(t *testing.T) {
 				},
 			},
 			mock: func(
-				req *rpcscheduler.PeerTaskRequest, mockPeer *resource.Peer, mockCDNPeer *resource.Peer,
+				req *rpcscheduler.PeerTaskRequest, mockPeer *resource.Peer, mockSeedPeer *resource.Peer,
 				scheduler scheduler.Scheduler, res resource.Resource, hostManager resource.HostManager, taskManager resource.TaskManager, peerManager resource.PeerManager,
 				ms *mocks.MockSchedulerMockRecorder, mr *resource.MockResourceMockRecorder, mh *resource.MockHostManagerMockRecorder, mt *resource.MockTaskManagerMockRecorder, mp *resource.MockPeerManagerMockRecorder,
 			) {
 				mockPeer.Task.FSM.SetState(resource.TaskStateSucceeded)
-				mockPeer.Task.StorePeer(mockCDNPeer)
+				mockPeer.Task.StorePeer(mockSeedPeer)
 				mockPeer.Task.ContentLength.Store(129)
 				mockPeer.Task.StorePiece(&base.PieceInfo{
 					PieceNum: 0,
 				})
 				mockPeer.Task.TotalPieceCount.Store(1)
 				mockPeer.FSM.SetState(resource.PeerStateFailed)
-				mockCDNPeer.FSM.SetState(resource.PeerStateSucceeded)
+				mockSeedPeer.FSM.SetState(resource.PeerStateSucceeded)
 
 				gomock.InOrder(
 					mr.TaskManager().Return(taskManager).Times(1),
@@ -474,7 +478,7 @@ func TestService_RegisterPeerTask(t *testing.T) {
 					mh.Load(gomock.Eq(mockPeer.Host.ID)).Return(mockPeer.Host, true).Times(1),
 					mr.PeerManager().Return(peerManager).Times(1),
 					mp.LoadOrStore(gomock.Any()).Return(mockPeer, true).Times(1),
-					ms.FindParent(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockCDNPeer, true).Times(1),
+					ms.FindParent(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockSeedPeer, true).Times(1),
 				)
 			},
 			expect: func(t *testing.T, peer *resource.Peer, result *rpcscheduler.RegisterResult, err error) {
@@ -494,19 +498,19 @@ func TestService_RegisterPeerTask(t *testing.T) {
 				},
 			},
 			mock: func(
-				req *rpcscheduler.PeerTaskRequest, mockPeer *resource.Peer, mockCDNPeer *resource.Peer,
+				req *rpcscheduler.PeerTaskRequest, mockPeer *resource.Peer, mockSeedPeer *resource.Peer,
 				scheduler scheduler.Scheduler, res resource.Resource, hostManager resource.HostManager, taskManager resource.TaskManager, peerManager resource.PeerManager,
 				ms *mocks.MockSchedulerMockRecorder, mr *resource.MockResourceMockRecorder, mh *resource.MockHostManagerMockRecorder, mt *resource.MockTaskManagerMockRecorder, mp *resource.MockPeerManagerMockRecorder,
 			) {
 				mockPeer.Task.FSM.SetState(resource.TaskStateSucceeded)
-				mockPeer.Task.StorePeer(mockCDNPeer)
+				mockPeer.Task.StorePeer(mockSeedPeer)
 				mockPeer.Task.ContentLength.Store(129)
 				mockPeer.Task.StorePiece(&base.PieceInfo{
 					PieceNum: 0,
 				})
 				mockPeer.Task.TotalPieceCount.Store(1)
 				mockPeer.FSM.SetState(resource.PeerStateFailed)
-				mockCDNPeer.FSM.SetState(resource.PeerStateSucceeded)
+				mockSeedPeer.FSM.SetState(resource.PeerStateSucceeded)
 
 				gomock.InOrder(
 					mr.TaskManager().Return(taskManager).Times(1),
@@ -515,7 +519,7 @@ func TestService_RegisterPeerTask(t *testing.T) {
 					mh.Load(gomock.Eq(mockPeer.Host.ID)).Return(mockPeer.Host, true).Times(1),
 					mr.PeerManager().Return(peerManager).Times(1),
 					mp.LoadOrStore(gomock.Any()).Return(mockPeer, true).Times(1),
-					ms.FindParent(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockCDNPeer, true).Times(1),
+					ms.FindParent(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockSeedPeer, true).Times(1),
 				)
 			},
 			expect: func(t *testing.T, peer *resource.Peer, result *rpcscheduler.RegisterResult, err error) {
@@ -535,18 +539,18 @@ func TestService_RegisterPeerTask(t *testing.T) {
 				},
 			},
 			mock: func(
-				req *rpcscheduler.PeerTaskRequest, mockPeer *resource.Peer, mockCDNPeer *resource.Peer,
+				req *rpcscheduler.PeerTaskRequest, mockPeer *resource.Peer, mockSeedPeer *resource.Peer,
 				scheduler scheduler.Scheduler, res resource.Resource, hostManager resource.HostManager, taskManager resource.TaskManager, peerManager resource.PeerManager,
 				ms *mocks.MockSchedulerMockRecorder, mr *resource.MockResourceMockRecorder, mh *resource.MockHostManagerMockRecorder, mt *resource.MockTaskManagerMockRecorder, mp *resource.MockPeerManagerMockRecorder,
 			) {
 				mockPeer.Task.FSM.SetState(resource.TaskStateSucceeded)
-				mockPeer.Task.StorePeer(mockCDNPeer)
+				mockPeer.Task.StorePeer(mockSeedPeer)
 				mockPeer.Task.ContentLength.Store(129)
 				mockPeer.Task.StorePiece(&base.PieceInfo{
 					PieceNum: 0,
 				})
 				mockPeer.Task.TotalPieceCount.Store(1)
-				mockCDNPeer.FSM.SetState(resource.PeerStateSucceeded)
+				mockSeedPeer.FSM.SetState(resource.PeerStateSucceeded)
 
 				gomock.InOrder(
 					mr.TaskManager().Return(taskManager).Times(1),
@@ -555,7 +559,7 @@ func TestService_RegisterPeerTask(t *testing.T) {
 					mh.Load(gomock.Eq(mockPeer.Host.ID)).Return(mockPeer.Host, true).Times(1),
 					mr.PeerManager().Return(peerManager).Times(1),
 					mp.LoadOrStore(gomock.Any()).Return(mockPeer, true).Times(1),
-					ms.FindParent(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockCDNPeer, true).Times(1),
+					ms.FindParent(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockSeedPeer, true).Times(1),
 				)
 			},
 			expect: func(t *testing.T, peer *resource.Peer, result *rpcscheduler.RegisterResult, err error) {
@@ -576,12 +580,12 @@ func TestService_RegisterPeerTask(t *testing.T) {
 				},
 			},
 			mock: func(
-				req *rpcscheduler.PeerTaskRequest, mockPeer *resource.Peer, mockCDNPeer *resource.Peer,
+				req *rpcscheduler.PeerTaskRequest, mockPeer *resource.Peer, mockSeedPeer *resource.Peer,
 				scheduler scheduler.Scheduler, res resource.Resource, hostManager resource.HostManager, taskManager resource.TaskManager, peerManager resource.PeerManager,
 				ms *mocks.MockSchedulerMockRecorder, mr *resource.MockResourceMockRecorder, mh *resource.MockHostManagerMockRecorder, mt *resource.MockTaskManagerMockRecorder, mp *resource.MockPeerManagerMockRecorder,
 			) {
 				mockPeer.Task.FSM.SetState(resource.TaskStateSucceeded)
-				mockPeer.Task.StorePeer(mockCDNPeer)
+				mockPeer.Task.StorePeer(mockSeedPeer)
 				mockPeer.Task.ContentLength.Store(129)
 				mockPeer.Task.TotalPieceCount.Store(2)
 				mockPeer.FSM.SetState(resource.PeerStateFailed)
@@ -611,12 +615,12 @@ func TestService_RegisterPeerTask(t *testing.T) {
 				},
 			},
 			mock: func(
-				req *rpcscheduler.PeerTaskRequest, mockPeer *resource.Peer, mockCDNPeer *resource.Peer,
+				req *rpcscheduler.PeerTaskRequest, mockPeer *resource.Peer, mockSeedPeer *resource.Peer,
 				scheduler scheduler.Scheduler, res resource.Resource, hostManager resource.HostManager, taskManager resource.TaskManager, peerManager resource.PeerManager,
 				ms *mocks.MockSchedulerMockRecorder, mr *resource.MockResourceMockRecorder, mh *resource.MockHostManagerMockRecorder, mt *resource.MockTaskManagerMockRecorder, mp *resource.MockPeerManagerMockRecorder,
 			) {
 				mockPeer.Task.FSM.SetState(resource.TaskStateSucceeded)
-				mockPeer.Task.StorePeer(mockCDNPeer)
+				mockPeer.Task.StorePeer(mockSeedPeer)
 				mockPeer.Task.ContentLength.Store(129)
 				mockPeer.Task.TotalPieceCount.Store(2)
 				gomock.InOrder(
@@ -655,10 +659,10 @@ func TestService_RegisterPeerTask(t *testing.T) {
 			mockHost := resource.NewHost(mockRawHost)
 			mockTask := resource.NewTask(mockTaskID, mockTaskURL, resource.TaskTypeNormal, mockTaskURLMeta, resource.WithBackToSourceLimit(mockTaskBackToSourceLimit))
 			mockPeer := resource.NewPeer(mockPeerID, mockTask, mockHost)
-			mockCDNHost := resource.NewHost(mockRawCDNHost)
-			mockCDNPeer := resource.NewPeer(mockCDNPeerID, mockTask, mockCDNHost)
+			mockSeedHost := resource.NewHost(mockRawSeedHost)
+			mockSeedPeer := resource.NewPeer(mockSeedPeerID, mockTask, mockSeedHost)
 			tc.mock(
-				tc.req, mockPeer, mockCDNPeer,
+				tc.req, mockPeer, mockSeedPeer,
 				scheduler, res, hostManager, taskManager, peerManager,
 				scheduler.EXPECT(), res.EXPECT(), hostManager.EXPECT(), taskManager.EXPECT(), peerManager.EXPECT(),
 			)
@@ -1466,7 +1470,7 @@ func TestService_LeaveTask(t *testing.T) {
 	}{
 		{
 			name:  "peer not found",
-			peer:  resource.NewPeer(mockCDNPeerID, mockTask, mockHost),
+			peer:  resource.NewPeer(mockSeedPeerID, mockTask, mockHost),
 			child: resource.NewPeer(mockPeerID, mockTask, mockHost),
 			mock: func(peer *resource.Peer, child *resource.Peer, peerManager resource.PeerManager, ms *mocks.MockSchedulerMockRecorder, mr *resource.MockResourceMockRecorder, mp *resource.MockPeerManagerMockRecorder) {
 				peer.FSM.SetState(resource.PeerStatePending)
@@ -1485,7 +1489,7 @@ func TestService_LeaveTask(t *testing.T) {
 		},
 		{
 			name:  "peer state is PeerStatePending",
-			peer:  resource.NewPeer(mockCDNPeerID, mockTask, mockHost),
+			peer:  resource.NewPeer(mockSeedPeerID, mockTask, mockHost),
 			child: resource.NewPeer(mockPeerID, mockTask, mockHost),
 			mock: func(peer *resource.Peer, child *resource.Peer, peerManager resource.PeerManager, ms *mocks.MockSchedulerMockRecorder, mr *resource.MockResourceMockRecorder, mp *resource.MockPeerManagerMockRecorder) {
 				peer.FSM.SetState(resource.PeerStatePending)
@@ -1504,7 +1508,7 @@ func TestService_LeaveTask(t *testing.T) {
 		},
 		{
 			name:  "peer state is PeerStateReceivedSmall",
-			peer:  resource.NewPeer(mockCDNPeerID, mockTask, mockHost),
+			peer:  resource.NewPeer(mockSeedPeerID, mockTask, mockHost),
 			child: resource.NewPeer(mockPeerID, mockTask, mockHost),
 			mock: func(peer *resource.Peer, child *resource.Peer, peerManager resource.PeerManager, ms *mocks.MockSchedulerMockRecorder, mr *resource.MockResourceMockRecorder, mp *resource.MockPeerManagerMockRecorder) {
 				peer.FSM.SetState(resource.PeerStateReceivedSmall)
@@ -1523,7 +1527,7 @@ func TestService_LeaveTask(t *testing.T) {
 		},
 		{
 			name:  "peer state is PeerStateReceivedNormal",
-			peer:  resource.NewPeer(mockCDNPeerID, mockTask, mockHost),
+			peer:  resource.NewPeer(mockSeedPeerID, mockTask, mockHost),
 			child: resource.NewPeer(mockPeerID, mockTask, mockHost),
 			mock: func(peer *resource.Peer, child *resource.Peer, peerManager resource.PeerManager, ms *mocks.MockSchedulerMockRecorder, mr *resource.MockResourceMockRecorder, mp *resource.MockPeerManagerMockRecorder) {
 				peer.FSM.SetState(resource.PeerStateReceivedNormal)
@@ -1542,7 +1546,7 @@ func TestService_LeaveTask(t *testing.T) {
 		},
 		{
 			name:  "peer state is PeerStateRunning",
-			peer:  resource.NewPeer(mockCDNPeerID, mockTask, mockHost),
+			peer:  resource.NewPeer(mockSeedPeerID, mockTask, mockHost),
 			child: resource.NewPeer(mockPeerID, mockTask, mockHost),
 			mock: func(peer *resource.Peer, child *resource.Peer, peerManager resource.PeerManager, ms *mocks.MockSchedulerMockRecorder, mr *resource.MockResourceMockRecorder, mp *resource.MockPeerManagerMockRecorder) {
 				peer.FSM.SetState(resource.PeerStateRunning)
@@ -1561,7 +1565,7 @@ func TestService_LeaveTask(t *testing.T) {
 		},
 		{
 			name:  "peer state is PeerStateBackToSource",
-			peer:  resource.NewPeer(mockCDNPeerID, mockTask, mockHost),
+			peer:  resource.NewPeer(mockSeedPeerID, mockTask, mockHost),
 			child: resource.NewPeer(mockPeerID, mockTask, mockHost),
 			mock: func(peer *resource.Peer, child *resource.Peer, peerManager resource.PeerManager, ms *mocks.MockSchedulerMockRecorder, mr *resource.MockResourceMockRecorder, mp *resource.MockPeerManagerMockRecorder) {
 				peer.FSM.SetState(resource.PeerStateBackToSource)
@@ -1580,7 +1584,7 @@ func TestService_LeaveTask(t *testing.T) {
 		},
 		{
 			name:  "peer state is PeerStateLeave",
-			peer:  resource.NewPeer(mockCDNPeerID, mockTask, mockHost),
+			peer:  resource.NewPeer(mockSeedPeerID, mockTask, mockHost),
 			child: resource.NewPeer(mockPeerID, mockTask, mockHost),
 			mock: func(peer *resource.Peer, child *resource.Peer, peerManager resource.PeerManager, ms *mocks.MockSchedulerMockRecorder, mr *resource.MockResourceMockRecorder, mp *resource.MockPeerManagerMockRecorder) {
 				peer.FSM.SetState(resource.PeerStateLeave)
@@ -1599,7 +1603,7 @@ func TestService_LeaveTask(t *testing.T) {
 		},
 		{
 			name:  "peer state is PeerStateSucceeded and children need to be scheduled",
-			peer:  resource.NewPeer(mockCDNPeerID, mockTask, mockHost),
+			peer:  resource.NewPeer(mockSeedPeerID, mockTask, mockHost),
 			child: resource.NewPeer(mockPeerID, mockTask, mockHost),
 			mock: func(peer *resource.Peer, child *resource.Peer, peerManager resource.PeerManager, ms *mocks.MockSchedulerMockRecorder, mr *resource.MockResourceMockRecorder, mp *resource.MockPeerManagerMockRecorder) {
 				peer.StoreChild(child)
@@ -1624,7 +1628,7 @@ func TestService_LeaveTask(t *testing.T) {
 		},
 		{
 			name:  "peer state is PeerStateSucceeded and it has no children",
-			peer:  resource.NewPeer(mockCDNPeerID, mockTask, mockHost),
+			peer:  resource.NewPeer(mockSeedPeerID, mockTask, mockHost),
 			child: resource.NewPeer(mockPeerID, mockTask, mockHost),
 			mock: func(peer *resource.Peer, child *resource.Peer, peerManager resource.PeerManager, ms *mocks.MockSchedulerMockRecorder, mr *resource.MockResourceMockRecorder, mp *resource.MockPeerManagerMockRecorder) {
 				peer.FSM.SetState(resource.PeerStateSucceeded)
@@ -1648,7 +1652,7 @@ func TestService_LeaveTask(t *testing.T) {
 		},
 		{
 			name:  "peer state is PeerStateFailed and children need to be scheduled",
-			peer:  resource.NewPeer(mockCDNPeerID, mockTask, mockHost),
+			peer:  resource.NewPeer(mockSeedPeerID, mockTask, mockHost),
 			child: resource.NewPeer(mockPeerID, mockTask, mockHost),
 			mock: func(peer *resource.Peer, child *resource.Peer, peerManager resource.PeerManager, ms *mocks.MockSchedulerMockRecorder, mr *resource.MockResourceMockRecorder, mp *resource.MockPeerManagerMockRecorder) {
 				peer.StoreChild(child)
@@ -1673,7 +1677,7 @@ func TestService_LeaveTask(t *testing.T) {
 		},
 		{
 			name:  "peer state is PeerStateFailed and it has no children",
-			peer:  resource.NewPeer(mockCDNPeerID, mockTask, mockHost),
+			peer:  resource.NewPeer(mockSeedPeerID, mockTask, mockHost),
 			child: resource.NewPeer(mockPeerID, mockTask, mockHost),
 			mock: func(peer *resource.Peer, child *resource.Peer, peerManager resource.PeerManager, ms *mocks.MockSchedulerMockRecorder, mr *resource.MockResourceMockRecorder, mp *resource.MockPeerManagerMockRecorder) {
 				peer.FSM.SetState(resource.PeerStateFailed)
@@ -1719,13 +1723,13 @@ func TestService_registerTask(t *testing.T) {
 		name   string
 		config *config.Config
 		req    *rpcscheduler.PeerTaskRequest
-		run    func(t *testing.T, svc *Service, req *rpcscheduler.PeerTaskRequest, mockTask *resource.Task, mockPeer *resource.Peer, taskManager resource.TaskManager, cdn resource.CDN, mr *resource.MockResourceMockRecorder, mt *resource.MockTaskManagerMockRecorder, mc *resource.MockCDNMockRecorder)
+		run    func(t *testing.T, svc *Service, req *rpcscheduler.PeerTaskRequest, mockTask *resource.Task, mockPeer *resource.Peer, taskManager resource.TaskManager, seedPeer resource.SeedPeer, mr *resource.MockResourceMockRecorder, mt *resource.MockTaskManagerMockRecorder, mc *resource.MockSeedPeerMockRecorder)
 	}{
 		{
 			name: "task already exists and state is TaskStatePending",
 			config: &config.Config{
 				Scheduler: mockSchedulerConfig,
-				CDN: &config.CDNConfig{
+				SeedPeer: &config.SeedPeerConfig{
 					Enable: true,
 				},
 			},
@@ -1733,7 +1737,7 @@ func TestService_registerTask(t *testing.T) {
 				Url:     mockTaskURL,
 				UrlMeta: mockTaskURLMeta,
 			},
-			run: func(t *testing.T, svc *Service, req *rpcscheduler.PeerTaskRequest, mockTask *resource.Task, mockPeer *resource.Peer, taskManager resource.TaskManager, cdn resource.CDN, mr *resource.MockResourceMockRecorder, mt *resource.MockTaskManagerMockRecorder, mc *resource.MockCDNMockRecorder) {
+			run: func(t *testing.T, svc *Service, req *rpcscheduler.PeerTaskRequest, mockTask *resource.Task, mockPeer *resource.Peer, taskManager resource.TaskManager, seedPeer resource.SeedPeer, mr *resource.MockResourceMockRecorder, mt *resource.MockTaskManagerMockRecorder, mc *resource.MockSeedPeerMockRecorder) {
 				mockTask.FSM.SetState(resource.TaskStateRunning)
 				mockTask.StorePeer(mockPeer)
 				mockPeer.FSM.SetState(resource.PeerStateRunning)
@@ -1753,7 +1757,7 @@ func TestService_registerTask(t *testing.T) {
 			name: "task already exists and state is TaskStateRunning",
 			config: &config.Config{
 				Scheduler: mockSchedulerConfig,
-				CDN: &config.CDNConfig{
+				SeedPeer: &config.SeedPeerConfig{
 					Enable: true,
 				},
 			},
@@ -1761,7 +1765,7 @@ func TestService_registerTask(t *testing.T) {
 				Url:     mockTaskURL,
 				UrlMeta: mockTaskURLMeta,
 			},
-			run: func(t *testing.T, svc *Service, req *rpcscheduler.PeerTaskRequest, mockTask *resource.Task, mockPeer *resource.Peer, taskManager resource.TaskManager, cdn resource.CDN, mr *resource.MockResourceMockRecorder, mt *resource.MockTaskManagerMockRecorder, mc *resource.MockCDNMockRecorder) {
+			run: func(t *testing.T, svc *Service, req *rpcscheduler.PeerTaskRequest, mockTask *resource.Task, mockPeer *resource.Peer, taskManager resource.TaskManager, seedPeer resource.SeedPeer, mr *resource.MockResourceMockRecorder, mt *resource.MockTaskManagerMockRecorder, mc *resource.MockSeedPeerMockRecorder) {
 				mockTask.FSM.SetState(resource.TaskStateRunning)
 				mockTask.StorePeer(mockPeer)
 				mockPeer.FSM.SetState(resource.PeerStateRunning)
@@ -1781,7 +1785,7 @@ func TestService_registerTask(t *testing.T) {
 			name: "task already exists and state is TaskStateSucceeded",
 			config: &config.Config{
 				Scheduler: mockSchedulerConfig,
-				CDN: &config.CDNConfig{
+				SeedPeer: &config.SeedPeerConfig{
 					Enable: true,
 				},
 			},
@@ -1789,7 +1793,7 @@ func TestService_registerTask(t *testing.T) {
 				Url:     mockTaskURL,
 				UrlMeta: mockTaskURLMeta,
 			},
-			run: func(t *testing.T, svc *Service, req *rpcscheduler.PeerTaskRequest, mockTask *resource.Task, mockPeer *resource.Peer, taskManager resource.TaskManager, cdn resource.CDN, mr *resource.MockResourceMockRecorder, mt *resource.MockTaskManagerMockRecorder, mc *resource.MockCDNMockRecorder) {
+			run: func(t *testing.T, svc *Service, req *rpcscheduler.PeerTaskRequest, mockTask *resource.Task, mockPeer *resource.Peer, taskManager resource.TaskManager, seedPeer resource.SeedPeer, mr *resource.MockResourceMockRecorder, mt *resource.MockTaskManagerMockRecorder, mc *resource.MockSeedPeerMockRecorder) {
 				mockTask.FSM.SetState(resource.TaskStateSucceeded)
 				mockTask.StorePeer(mockPeer)
 				mockPeer.FSM.SetState(resource.PeerStateRunning)
@@ -1809,7 +1813,7 @@ func TestService_registerTask(t *testing.T) {
 			name: "task state is TaskStatePending",
 			config: &config.Config{
 				Scheduler: mockSchedulerConfig,
-				CDN: &config.CDNConfig{
+				SeedPeer: &config.SeedPeerConfig{
 					Enable: true,
 				},
 			},
@@ -1817,7 +1821,7 @@ func TestService_registerTask(t *testing.T) {
 				Url:     mockTaskURL,
 				UrlMeta: mockTaskURLMeta,
 			},
-			run: func(t *testing.T, svc *Service, req *rpcscheduler.PeerTaskRequest, mockTask *resource.Task, mockPeer *resource.Peer, taskManager resource.TaskManager, cdn resource.CDN, mr *resource.MockResourceMockRecorder, mt *resource.MockTaskManagerMockRecorder, mc *resource.MockCDNMockRecorder) {
+			run: func(t *testing.T, svc *Service, req *rpcscheduler.PeerTaskRequest, mockTask *resource.Task, mockPeer *resource.Peer, taskManager resource.TaskManager, seedPeer resource.SeedPeer, mr *resource.MockResourceMockRecorder, mt *resource.MockTaskManagerMockRecorder, mc *resource.MockSeedPeerMockRecorder) {
 				var wg sync.WaitGroup
 				wg.Add(2)
 				defer wg.Wait()
@@ -1826,7 +1830,7 @@ func TestService_registerTask(t *testing.T) {
 				gomock.InOrder(
 					mr.TaskManager().Return(taskManager).Times(1),
 					mt.LoadOrStore(gomock.Any()).Return(mockTask, false).Times(1),
-					mr.CDN().Do(func() { wg.Done() }).Return(cdn).Times(1),
+					mr.SeedPeer().Do(func() { wg.Done() }).Return(seedPeer).Times(1),
 					mc.TriggerTask(gomock.Any(), gomock.Any()).Do(func(ctx context.Context, task *resource.Task) { wg.Done() }).Return(mockPeer, &rpcscheduler.PeerResult{}, nil).Times(1),
 				)
 
@@ -1841,7 +1845,7 @@ func TestService_registerTask(t *testing.T) {
 			name: "task state is TaskStateFailed",
 			config: &config.Config{
 				Scheduler: mockSchedulerConfig,
-				CDN: &config.CDNConfig{
+				SeedPeer: &config.SeedPeerConfig{
 					Enable: true,
 				},
 			},
@@ -1849,7 +1853,7 @@ func TestService_registerTask(t *testing.T) {
 				Url:     mockTaskURL,
 				UrlMeta: mockTaskURLMeta,
 			},
-			run: func(t *testing.T, svc *Service, req *rpcscheduler.PeerTaskRequest, mockTask *resource.Task, mockPeer *resource.Peer, taskManager resource.TaskManager, cdn resource.CDN, mr *resource.MockResourceMockRecorder, mt *resource.MockTaskManagerMockRecorder, mc *resource.MockCDNMockRecorder) {
+			run: func(t *testing.T, svc *Service, req *rpcscheduler.PeerTaskRequest, mockTask *resource.Task, mockPeer *resource.Peer, taskManager resource.TaskManager, seedPeer resource.SeedPeer, mr *resource.MockResourceMockRecorder, mt *resource.MockTaskManagerMockRecorder, mc *resource.MockSeedPeerMockRecorder) {
 				var wg sync.WaitGroup
 				wg.Add(2)
 				defer wg.Wait()
@@ -1858,7 +1862,7 @@ func TestService_registerTask(t *testing.T) {
 				gomock.InOrder(
 					mr.TaskManager().Return(taskManager).Times(1),
 					mt.LoadOrStore(gomock.Any()).Return(mockTask, true).Times(1),
-					mr.CDN().Do(func() { wg.Done() }).Return(cdn).Times(1),
+					mr.SeedPeer().Do(func() { wg.Done() }).Return(seedPeer).Times(1),
 					mc.TriggerTask(gomock.Any(), gomock.Any()).Do(func(ctx context.Context, task *resource.Task) { wg.Done() }).Return(mockPeer, &rpcscheduler.PeerResult{}, nil).Times(1),
 				)
 
@@ -1870,10 +1874,10 @@ func TestService_registerTask(t *testing.T) {
 			},
 		},
 		{
-			name: "task state is TaskStatePending, but trigger cdn failed",
+			name: "task state is TaskStatePending, but trigger seedPeer failed",
 			config: &config.Config{
 				Scheduler: mockSchedulerConfig,
-				CDN: &config.CDNConfig{
+				SeedPeer: &config.SeedPeerConfig{
 					Enable: true,
 				},
 			},
@@ -1881,7 +1885,7 @@ func TestService_registerTask(t *testing.T) {
 				Url:     mockTaskURL,
 				UrlMeta: mockTaskURLMeta,
 			},
-			run: func(t *testing.T, svc *Service, req *rpcscheduler.PeerTaskRequest, mockTask *resource.Task, mockPeer *resource.Peer, taskManager resource.TaskManager, cdn resource.CDN, mr *resource.MockResourceMockRecorder, mt *resource.MockTaskManagerMockRecorder, mc *resource.MockCDNMockRecorder) {
+			run: func(t *testing.T, svc *Service, req *rpcscheduler.PeerTaskRequest, mockTask *resource.Task, mockPeer *resource.Peer, taskManager resource.TaskManager, seedPeer resource.SeedPeer, mr *resource.MockResourceMockRecorder, mt *resource.MockTaskManagerMockRecorder, mc *resource.MockSeedPeerMockRecorder) {
 				var wg sync.WaitGroup
 				wg.Add(2)
 				defer wg.Wait()
@@ -1890,7 +1894,7 @@ func TestService_registerTask(t *testing.T) {
 				gomock.InOrder(
 					mr.TaskManager().Return(taskManager).Times(1),
 					mt.LoadOrStore(gomock.Any()).Return(mockTask, false).Times(1),
-					mr.CDN().Do(func() { wg.Done() }).Return(cdn).Times(1),
+					mr.SeedPeer().Do(func() { wg.Done() }).Return(seedPeer).Times(1),
 					mc.TriggerTask(gomock.Any(), gomock.Any()).Do(func(ctx context.Context, task *resource.Task) { wg.Done() }).Return(mockPeer, &rpcscheduler.PeerResult{}, errors.New("foo")).Times(1),
 				)
 
@@ -1902,10 +1906,10 @@ func TestService_registerTask(t *testing.T) {
 			},
 		},
 		{
-			name: "task state is TaskStateFailed, but trigger cdn failed",
+			name: "task state is TaskStateFailed, but trigger seedPeer failed",
 			config: &config.Config{
 				Scheduler: mockSchedulerConfig,
-				CDN: &config.CDNConfig{
+				SeedPeer: &config.SeedPeerConfig{
 					Enable: true,
 				},
 			},
@@ -1913,7 +1917,7 @@ func TestService_registerTask(t *testing.T) {
 				Url:     mockTaskURL,
 				UrlMeta: mockTaskURLMeta,
 			},
-			run: func(t *testing.T, svc *Service, req *rpcscheduler.PeerTaskRequest, mockTask *resource.Task, mockPeer *resource.Peer, taskManager resource.TaskManager, cdn resource.CDN, mr *resource.MockResourceMockRecorder, mt *resource.MockTaskManagerMockRecorder, mc *resource.MockCDNMockRecorder) {
+			run: func(t *testing.T, svc *Service, req *rpcscheduler.PeerTaskRequest, mockTask *resource.Task, mockPeer *resource.Peer, taskManager resource.TaskManager, seedPeer resource.SeedPeer, mr *resource.MockResourceMockRecorder, mt *resource.MockTaskManagerMockRecorder, mc *resource.MockSeedPeerMockRecorder) {
 				var wg sync.WaitGroup
 				wg.Add(2)
 				defer wg.Wait()
@@ -1922,7 +1926,7 @@ func TestService_registerTask(t *testing.T) {
 				gomock.InOrder(
 					mr.TaskManager().Return(taskManager).Times(1),
 					mt.LoadOrStore(gomock.Any()).Return(mockTask, true).Times(1),
-					mr.CDN().Do(func() { wg.Done() }).Return(cdn).Times(1),
+					mr.SeedPeer().Do(func() { wg.Done() }).Return(seedPeer).Times(1),
 					mc.TriggerTask(gomock.Any(), gomock.Any()).Do(func(ctx context.Context, task *resource.Task) { wg.Done() }).Return(mockPeer, &rpcscheduler.PeerResult{}, errors.New("foo")).Times(1),
 				)
 
@@ -1934,10 +1938,10 @@ func TestService_registerTask(t *testing.T) {
 			},
 		},
 		{
-			name: "task state is TaskStatePending and disable cdn",
+			name: "task state is TaskStatePending and disable seed peer",
 			config: &config.Config{
 				Scheduler: mockSchedulerConfig,
-				CDN: &config.CDNConfig{
+				SeedPeer: &config.SeedPeerConfig{
 					Enable: false,
 				},
 			},
@@ -1945,7 +1949,7 @@ func TestService_registerTask(t *testing.T) {
 				Url:     mockTaskURL,
 				UrlMeta: mockTaskURLMeta,
 			},
-			run: func(t *testing.T, svc *Service, req *rpcscheduler.PeerTaskRequest, mockTask *resource.Task, mockPeer *resource.Peer, taskManager resource.TaskManager, cdn resource.CDN, mr *resource.MockResourceMockRecorder, mt *resource.MockTaskManagerMockRecorder, mc *resource.MockCDNMockRecorder) {
+			run: func(t *testing.T, svc *Service, req *rpcscheduler.PeerTaskRequest, mockTask *resource.Task, mockPeer *resource.Peer, taskManager resource.TaskManager, seedPeer resource.SeedPeer, mr *resource.MockResourceMockRecorder, mt *resource.MockTaskManagerMockRecorder, mc *resource.MockSeedPeerMockRecorder) {
 				mockTask.FSM.SetState(resource.TaskStatePending)
 				gomock.InOrder(
 					mr.TaskManager().Return(taskManager).Times(1),
@@ -1960,10 +1964,10 @@ func TestService_registerTask(t *testing.T) {
 			},
 		},
 		{
-			name: "task state is TaskStateFailed and disable cdn",
+			name: "task state is TaskStateFailed and disable seed peer",
 			config: &config.Config{
 				Scheduler: mockSchedulerConfig,
-				CDN: &config.CDNConfig{
+				SeedPeer: &config.SeedPeerConfig{
 					Enable: false,
 				},
 			},
@@ -1971,7 +1975,7 @@ func TestService_registerTask(t *testing.T) {
 				Url:     mockTaskURL,
 				UrlMeta: mockTaskURLMeta,
 			},
-			run: func(t *testing.T, svc *Service, req *rpcscheduler.PeerTaskRequest, mockTask *resource.Task, mockPeer *resource.Peer, taskManager resource.TaskManager, cdn resource.CDN, mr *resource.MockResourceMockRecorder, mt *resource.MockTaskManagerMockRecorder, mc *resource.MockCDNMockRecorder) {
+			run: func(t *testing.T, svc *Service, req *rpcscheduler.PeerTaskRequest, mockTask *resource.Task, mockPeer *resource.Peer, taskManager resource.TaskManager, seedPeer resource.SeedPeer, mr *resource.MockResourceMockRecorder, mt *resource.MockTaskManagerMockRecorder, mc *resource.MockSeedPeerMockRecorder) {
 				mockTask.FSM.SetState(resource.TaskStateFailed)
 				gomock.InOrder(
 					mr.TaskManager().Return(taskManager).Times(1),
@@ -2001,8 +2005,8 @@ func TestService_registerTask(t *testing.T) {
 			mockHost := resource.NewHost(mockRawHost)
 			mockTask := resource.NewTask(mockTaskID, mockTaskURL, resource.TaskTypeNormal, mockTaskURLMeta, resource.WithBackToSourceLimit(mockTaskBackToSourceLimit))
 			mockPeer := resource.NewPeer(mockPeerID, mockTask, mockHost)
-			cdn := resource.NewMockCDN(ctl)
-			tc.run(t, svc, tc.req, mockTask, mockPeer, taskManager, cdn, res.EXPECT(), taskManager.EXPECT(), cdn.EXPECT())
+			seedPeer := resource.NewMockSeedPeer(ctl)
+			tc.run(t, svc, tc.req, mockTask, mockPeer, taskManager, seedPeer, res.EXPECT(), taskManager.EXPECT(), seedPeer.EXPECT())
 		})
 	}
 }
@@ -2096,19 +2100,19 @@ func TestService_registerHost(t *testing.T) {
 	}
 }
 
-func TestService_triggerCDNTask(t *testing.T) {
+func TestService_triggerSeedPeerTask(t *testing.T) {
 	tests := []struct {
 		name   string
-		mock   func(task *resource.Task, peer *resource.Peer, cdn resource.CDN, mr *resource.MockResourceMockRecorder, mc *resource.MockCDNMockRecorder)
+		mock   func(task *resource.Task, peer *resource.Peer, seedPeer resource.SeedPeer, mr *resource.MockResourceMockRecorder, mc *resource.MockSeedPeerMockRecorder)
 		expect func(t *testing.T, task *resource.Task, peer *resource.Peer)
 	}{
 		{
-			name: "trigger cdn task",
-			mock: func(task *resource.Task, peer *resource.Peer, cdn resource.CDN, mr *resource.MockResourceMockRecorder, mc *resource.MockCDNMockRecorder) {
+			name: "trigger seed peer task",
+			mock: func(task *resource.Task, peer *resource.Peer, seedPeer resource.SeedPeer, mr *resource.MockResourceMockRecorder, mc *resource.MockSeedPeerMockRecorder) {
 				task.FSM.SetState(resource.TaskStateRunning)
 				peer.FSM.SetState(resource.PeerStateRunning)
 				gomock.InOrder(
-					mr.CDN().Return(cdn).Times(1),
+					mr.SeedPeer().Return(seedPeer).Times(1),
 					mc.TriggerTask(gomock.Any(), gomock.Any()).Return(peer, &rpcscheduler.PeerResult{
 						TotalPieceCount: 3,
 						ContentLength:   1024,
@@ -2124,11 +2128,11 @@ func TestService_triggerCDNTask(t *testing.T) {
 			},
 		},
 		{
-			name: "trigger cdn task failed",
-			mock: func(task *resource.Task, peer *resource.Peer, cdn resource.CDN, mr *resource.MockResourceMockRecorder, mc *resource.MockCDNMockRecorder) {
+			name: "trigger seed peer task failed",
+			mock: func(task *resource.Task, peer *resource.Peer, seedPeer resource.SeedPeer, mr *resource.MockResourceMockRecorder, mc *resource.MockSeedPeerMockRecorder) {
 				task.FSM.SetState(resource.TaskStateRunning)
 				gomock.InOrder(
-					mr.CDN().Return(cdn).Times(1),
+					mr.SeedPeer().Return(seedPeer).Times(1),
 					mc.TriggerTask(gomock.Any(), gomock.Any()).Return(peer, &rpcscheduler.PeerResult{}, errors.New("foo")).Times(1),
 				)
 			},
@@ -2147,14 +2151,14 @@ func TestService_triggerCDNTask(t *testing.T) {
 			res := resource.NewMockResource(ctl)
 			dynconfig := configmocks.NewMockDynconfigInterface(ctl)
 			storage := storagemocks.NewMockStorage(ctl)
-			cdn := resource.NewMockCDN(ctl)
+			seedPeer := resource.NewMockSeedPeer(ctl)
 			mockHost := resource.NewHost(mockRawHost)
 			task := resource.NewTask(mockTaskID, mockTaskURL, resource.TaskTypeNormal, mockTaskURLMeta, resource.WithBackToSourceLimit(mockTaskBackToSourceLimit))
 			peer := resource.NewPeer(mockPeerID, task, mockHost)
 			svc := New(&config.Config{Scheduler: mockSchedulerConfig}, res, scheduler, dynconfig, storage)
 
-			tc.mock(task, peer, cdn, res.EXPECT(), cdn.EXPECT())
-			svc.triggerCDNTask(context.Background(), task)
+			tc.mock(task, peer, seedPeer, res.EXPECT(), seedPeer.EXPECT())
+			svc.triggerSeedPeerTask(context.Background(), task)
 			tc.expect(t, task, peer)
 		})
 	}
@@ -2392,19 +2396,19 @@ func TestService_handlePieceFail(t *testing.T) {
 		piece  *rpcscheduler.PieceResult
 		peer   *resource.Peer
 		parent *resource.Peer
-		run    func(t *testing.T, svc *Service, peer *resource.Peer, parent *resource.Peer, piece *rpcscheduler.PieceResult, peerManager resource.PeerManager, cdn resource.CDN, ms *mocks.MockSchedulerMockRecorder, mr *resource.MockResourceMockRecorder, mp *resource.MockPeerManagerMockRecorder, mc *resource.MockCDNMockRecorder)
+		run    func(t *testing.T, svc *Service, peer *resource.Peer, parent *resource.Peer, piece *rpcscheduler.PieceResult, peerManager resource.PeerManager, seedPeer resource.SeedPeer, ms *mocks.MockSchedulerMockRecorder, mr *resource.MockResourceMockRecorder, mp *resource.MockPeerManagerMockRecorder, mc *resource.MockSeedPeerMockRecorder)
 	}{
 		{
 			name: "peer state is PeerStateBackToSource",
 			config: &config.Config{
 				Scheduler: mockSchedulerConfig,
-				CDN:       &config.CDNConfig{Enable: true},
+				SeedPeer:  &config.SeedPeerConfig{Enable: true},
 				Metrics:   &config.MetricsConfig{EnablePeerHost: true},
 			},
 			piece:  &rpcscheduler.PieceResult{},
 			peer:   resource.NewPeer(mockPeerID, mockTask, mockHost),
-			parent: resource.NewPeer(mockCDNPeerID, mockTask, mockHost),
-			run: func(t *testing.T, svc *Service, peer *resource.Peer, parent *resource.Peer, piece *rpcscheduler.PieceResult, peerManager resource.PeerManager, cdn resource.CDN, ms *mocks.MockSchedulerMockRecorder, mr *resource.MockResourceMockRecorder, mp *resource.MockPeerManagerMockRecorder, mc *resource.MockCDNMockRecorder) {
+			parent: resource.NewPeer(mockSeedPeerID, mockTask, mockHost),
+			run: func(t *testing.T, svc *Service, peer *resource.Peer, parent *resource.Peer, piece *rpcscheduler.PieceResult, peerManager resource.PeerManager, seedPeer resource.SeedPeer, ms *mocks.MockSchedulerMockRecorder, mr *resource.MockResourceMockRecorder, mp *resource.MockPeerManagerMockRecorder, mc *resource.MockSeedPeerMockRecorder) {
 				peer.FSM.SetState(resource.PeerStateBackToSource)
 
 				svc.handlePieceFail(context.Background(), peer, piece)
@@ -2416,19 +2420,19 @@ func TestService_handlePieceFail(t *testing.T) {
 			name: "can not found parent",
 			config: &config.Config{
 				Scheduler: mockSchedulerConfig,
-				CDN:       &config.CDNConfig{Enable: true},
+				SeedPeer:  &config.SeedPeerConfig{Enable: true},
 				Metrics:   &config.MetricsConfig{EnablePeerHost: true},
 			},
 			piece: &rpcscheduler.PieceResult{
 				Code:   base.Code_ClientWaitPieceReady,
-				DstPid: mockCDNPeerID,
+				DstPid: mockSeedPeerID,
 			},
 			peer:   resource.NewPeer(mockPeerID, mockTask, mockHost),
-			parent: resource.NewPeer(mockCDNPeerID, mockTask, mockHost),
-			run: func(t *testing.T, svc *Service, peer *resource.Peer, parent *resource.Peer, piece *rpcscheduler.PieceResult, peerManager resource.PeerManager, cdn resource.CDN, ms *mocks.MockSchedulerMockRecorder, mr *resource.MockResourceMockRecorder, mp *resource.MockPeerManagerMockRecorder, mc *resource.MockCDNMockRecorder) {
+			parent: resource.NewPeer(mockSeedPeerID, mockTask, mockHost),
+			run: func(t *testing.T, svc *Service, peer *resource.Peer, parent *resource.Peer, piece *rpcscheduler.PieceResult, peerManager resource.PeerManager, seedPeer resource.SeedPeer, ms *mocks.MockSchedulerMockRecorder, mr *resource.MockResourceMockRecorder, mp *resource.MockPeerManagerMockRecorder, mc *resource.MockSeedPeerMockRecorder) {
 				peer.FSM.SetState(resource.PeerStateRunning)
 				blocklist := set.NewSafeSet()
-				blocklist.Add(mockCDNPeerID)
+				blocklist.Add(mockSeedPeerID)
 				gomock.InOrder(
 					mr.PeerManager().Return(peerManager).Times(1),
 					mp.Load(gomock.Eq(parent.ID)).Return(nil, false).Times(1),
@@ -2444,16 +2448,16 @@ func TestService_handlePieceFail(t *testing.T) {
 			name: "piece result code is Code_PeerTaskNotFound and parent state set PeerEventDownloadFailed",
 			config: &config.Config{
 				Scheduler: mockSchedulerConfig,
-				CDN:       &config.CDNConfig{Enable: true},
+				SeedPeer:  &config.SeedPeerConfig{Enable: true},
 				Metrics:   &config.MetricsConfig{EnablePeerHost: true},
 			},
 			piece: &rpcscheduler.PieceResult{
 				Code:   base.Code_PeerTaskNotFound,
-				DstPid: mockCDNPeerID,
+				DstPid: mockSeedPeerID,
 			},
 			peer:   resource.NewPeer(mockPeerID, mockTask, mockHost),
-			parent: resource.NewPeer(mockCDNPeerID, mockTask, mockHost),
-			run: func(t *testing.T, svc *Service, peer *resource.Peer, parent *resource.Peer, piece *rpcscheduler.PieceResult, peerManager resource.PeerManager, cdn resource.CDN, ms *mocks.MockSchedulerMockRecorder, mr *resource.MockResourceMockRecorder, mp *resource.MockPeerManagerMockRecorder, mc *resource.MockCDNMockRecorder) {
+			parent: resource.NewPeer(mockSeedPeerID, mockTask, mockHost),
+			run: func(t *testing.T, svc *Service, peer *resource.Peer, parent *resource.Peer, piece *rpcscheduler.PieceResult, peerManager resource.PeerManager, seedPeer resource.SeedPeer, ms *mocks.MockSchedulerMockRecorder, mr *resource.MockResourceMockRecorder, mp *resource.MockPeerManagerMockRecorder, mc *resource.MockSeedPeerMockRecorder) {
 				peer.FSM.SetState(resource.PeerStateRunning)
 				parent.FSM.SetState(resource.PeerStateRunning)
 				blocklist := set.NewSafeSet()
@@ -2471,21 +2475,21 @@ func TestService_handlePieceFail(t *testing.T) {
 			},
 		},
 		{
-			name: "piece result code is Code_ClientPieceNotFound and parent is not CDN",
+			name: "piece result code is Code_ClientPieceNotFound and parent is not seed peer",
 			config: &config.Config{
 				Scheduler: mockSchedulerConfig,
-				CDN:       &config.CDNConfig{Enable: true},
+				SeedPeer:  &config.SeedPeerConfig{Enable: true},
 				Metrics:   &config.MetricsConfig{EnablePeerHost: true},
 			},
 			piece: &rpcscheduler.PieceResult{
 				Code:   base.Code_ClientPieceNotFound,
-				DstPid: mockCDNPeerID,
+				DstPid: mockSeedPeerID,
 			},
 			peer:   resource.NewPeer(mockPeerID, mockTask, mockHost),
-			parent: resource.NewPeer(mockCDNPeerID, mockTask, mockHost),
-			run: func(t *testing.T, svc *Service, peer *resource.Peer, parent *resource.Peer, piece *rpcscheduler.PieceResult, peerManager resource.PeerManager, cdn resource.CDN, ms *mocks.MockSchedulerMockRecorder, mr *resource.MockResourceMockRecorder, mp *resource.MockPeerManagerMockRecorder, mc *resource.MockCDNMockRecorder) {
+			parent: resource.NewPeer(mockSeedPeerID, mockTask, mockHost),
+			run: func(t *testing.T, svc *Service, peer *resource.Peer, parent *resource.Peer, piece *rpcscheduler.PieceResult, peerManager resource.PeerManager, seedPeer resource.SeedPeer, ms *mocks.MockSchedulerMockRecorder, mr *resource.MockResourceMockRecorder, mp *resource.MockPeerManagerMockRecorder, mc *resource.MockSeedPeerMockRecorder) {
 				peer.FSM.SetState(resource.PeerStateRunning)
-				peer.Host.IsCDN = false
+				peer.Host.Type = resource.HostTypeNormal
 				blocklist := set.NewSafeSet()
 				blocklist.Add(parent.ID)
 				gomock.InOrder(
@@ -2503,16 +2507,16 @@ func TestService_handlePieceFail(t *testing.T) {
 			name: "piece result code is Code_CDNError and parent state set PeerEventDownloadFailed",
 			config: &config.Config{
 				Scheduler: mockSchedulerConfig,
-				CDN:       &config.CDNConfig{Enable: true},
+				SeedPeer:  &config.SeedPeerConfig{Enable: true},
 				Metrics:   &config.MetricsConfig{EnablePeerHost: true},
 			},
 			piece: &rpcscheduler.PieceResult{
 				Code:   base.Code_CDNError,
-				DstPid: mockCDNPeerID,
+				DstPid: mockSeedPeerID,
 			},
 			peer:   resource.NewPeer(mockPeerID, mockTask, mockHost),
-			parent: resource.NewPeer(mockCDNPeerID, mockTask, mockHost),
-			run: func(t *testing.T, svc *Service, peer *resource.Peer, parent *resource.Peer, piece *rpcscheduler.PieceResult, peerManager resource.PeerManager, cdn resource.CDN, ms *mocks.MockSchedulerMockRecorder, mr *resource.MockResourceMockRecorder, mp *resource.MockPeerManagerMockRecorder, mc *resource.MockCDNMockRecorder) {
+			parent: resource.NewPeer(mockSeedPeerID, mockTask, mockHost),
+			run: func(t *testing.T, svc *Service, peer *resource.Peer, parent *resource.Peer, piece *rpcscheduler.PieceResult, peerManager resource.PeerManager, seedPeer resource.SeedPeer, ms *mocks.MockSchedulerMockRecorder, mr *resource.MockResourceMockRecorder, mp *resource.MockPeerManagerMockRecorder, mc *resource.MockSeedPeerMockRecorder) {
 				peer.FSM.SetState(resource.PeerStateRunning)
 				parent.FSM.SetState(resource.PeerStateRunning)
 				blocklist := set.NewSafeSet()
@@ -2533,16 +2537,16 @@ func TestService_handlePieceFail(t *testing.T) {
 			name: "piece result code is Code_CDNTaskDownloadFail and parent state set PeerEventDownloadFailed",
 			config: &config.Config{
 				Scheduler: mockSchedulerConfig,
-				CDN:       &config.CDNConfig{Enable: true},
+				SeedPeer:  &config.SeedPeerConfig{Enable: true},
 				Metrics:   &config.MetricsConfig{EnablePeerHost: true},
 			},
 			piece: &rpcscheduler.PieceResult{
 				Code:   base.Code_CDNTaskDownloadFail,
-				DstPid: mockCDNPeerID,
+				DstPid: mockSeedPeerID,
 			},
 			peer:   resource.NewPeer(mockPeerID, mockTask, mockHost),
-			parent: resource.NewPeer(mockCDNPeerID, mockTask, mockHost),
-			run: func(t *testing.T, svc *Service, peer *resource.Peer, parent *resource.Peer, piece *rpcscheduler.PieceResult, peerManager resource.PeerManager, cdn resource.CDN, ms *mocks.MockSchedulerMockRecorder, mr *resource.MockResourceMockRecorder, mp *resource.MockPeerManagerMockRecorder, mc *resource.MockCDNMockRecorder) {
+			parent: resource.NewPeer(mockSeedPeerID, mockTask, mockHost),
+			run: func(t *testing.T, svc *Service, peer *resource.Peer, parent *resource.Peer, piece *rpcscheduler.PieceResult, peerManager resource.PeerManager, seedPeer resource.SeedPeer, ms *mocks.MockSchedulerMockRecorder, mr *resource.MockResourceMockRecorder, mp *resource.MockPeerManagerMockRecorder, mc *resource.MockSeedPeerMockRecorder) {
 				peer.FSM.SetState(resource.PeerStateRunning)
 				parent.FSM.SetState(resource.PeerStateRunning)
 				blocklist := set.NewSafeSet()
@@ -2563,16 +2567,16 @@ func TestService_handlePieceFail(t *testing.T) {
 			name: "piece result code is Code_ClientPieceRequestFail",
 			config: &config.Config{
 				Scheduler: mockSchedulerConfig,
-				CDN:       &config.CDNConfig{Enable: true},
+				SeedPeer:  &config.SeedPeerConfig{Enable: true},
 				Metrics:   &config.MetricsConfig{EnablePeerHost: true},
 			},
 			piece: &rpcscheduler.PieceResult{
 				Code:   base.Code_ClientPieceRequestFail,
-				DstPid: mockCDNPeerID,
+				DstPid: mockSeedPeerID,
 			},
 			peer:   resource.NewPeer(mockPeerID, mockTask, mockHost),
-			parent: resource.NewPeer(mockCDNPeerID, mockTask, mockHost),
-			run: func(t *testing.T, svc *Service, peer *resource.Peer, parent *resource.Peer, piece *rpcscheduler.PieceResult, peerManager resource.PeerManager, cdn resource.CDN, ms *mocks.MockSchedulerMockRecorder, mr *resource.MockResourceMockRecorder, mp *resource.MockPeerManagerMockRecorder, mc *resource.MockCDNMockRecorder) {
+			parent: resource.NewPeer(mockSeedPeerID, mockTask, mockHost),
+			run: func(t *testing.T, svc *Service, peer *resource.Peer, parent *resource.Peer, piece *rpcscheduler.PieceResult, peerManager resource.PeerManager, seedPeer resource.SeedPeer, ms *mocks.MockSchedulerMockRecorder, mr *resource.MockResourceMockRecorder, mp *resource.MockPeerManagerMockRecorder, mc *resource.MockSeedPeerMockRecorder) {
 				peer.FSM.SetState(resource.PeerStateRunning)
 				parent.FSM.SetState(resource.PeerStateRunning)
 				blocklist := set.NewSafeSet()
@@ -2593,16 +2597,16 @@ func TestService_handlePieceFail(t *testing.T) {
 			name: "piece result code is Code_CDNTaskNotFound",
 			config: &config.Config{
 				Scheduler: mockSchedulerConfig,
-				CDN:       &config.CDNConfig{Enable: true},
+				SeedPeer:  &config.SeedPeerConfig{Enable: true},
 				Metrics:   &config.MetricsConfig{EnablePeerHost: true},
 			},
 			piece: &rpcscheduler.PieceResult{
 				Code:   base.Code_CDNTaskNotFound,
-				DstPid: mockCDNPeerID,
+				DstPid: mockSeedPeerID,
 			},
 			peer:   resource.NewPeer(mockPeerID, mockTask, mockHost),
-			parent: resource.NewPeer(mockCDNPeerID, mockTask, mockHost),
-			run: func(t *testing.T, svc *Service, peer *resource.Peer, parent *resource.Peer, piece *rpcscheduler.PieceResult, peerManager resource.PeerManager, cdn resource.CDN, ms *mocks.MockSchedulerMockRecorder, mr *resource.MockResourceMockRecorder, mp *resource.MockPeerManagerMockRecorder, mc *resource.MockCDNMockRecorder) {
+			parent: resource.NewPeer(mockSeedPeerID, mockTask, mockHost),
+			run: func(t *testing.T, svc *Service, peer *resource.Peer, parent *resource.Peer, piece *rpcscheduler.PieceResult, peerManager resource.PeerManager, seedPeer resource.SeedPeer, ms *mocks.MockSchedulerMockRecorder, mr *resource.MockResourceMockRecorder, mp *resource.MockPeerManagerMockRecorder, mc *resource.MockSeedPeerMockRecorder) {
 				var wg sync.WaitGroup
 				wg.Add(2)
 				defer wg.Wait()
@@ -2615,7 +2619,7 @@ func TestService_handlePieceFail(t *testing.T) {
 					mr.PeerManager().Return(peerManager).Times(1),
 					mp.Load(gomock.Eq(parent.ID)).Return(parent, true).Times(1),
 				)
-				mr.CDN().Do(func() { wg.Done() }).Return(cdn).Times(1)
+				mr.SeedPeer().Do(func() { wg.Done() }).Return(seedPeer).Times(1)
 				mc.TriggerTask(gomock.Any(), gomock.Any()).Do(func(ctx context.Context, task *resource.Task) { wg.Done() }).Return(peer, &rpcscheduler.PeerResult{}, nil).Times(1)
 				ms.ScheduleParent(gomock.Any(), gomock.Eq(peer), gomock.Eq(blocklist)).Return().AnyTimes()
 
@@ -2625,19 +2629,19 @@ func TestService_handlePieceFail(t *testing.T) {
 			},
 		},
 		{
-			name: "piece result code is Code_CDNTaskNotFound and disable cdn",
+			name: "piece result code is Code_CDNTaskNotFound and disable seed peer",
 			config: &config.Config{
 				Scheduler: mockSchedulerConfig,
-				CDN:       &config.CDNConfig{Enable: false},
+				SeedPeer:  &config.SeedPeerConfig{Enable: false},
 				Metrics:   &config.MetricsConfig{EnablePeerHost: true},
 			},
 			piece: &rpcscheduler.PieceResult{
 				Code:   base.Code_CDNTaskNotFound,
-				DstPid: mockCDNPeerID,
+				DstPid: mockSeedPeerID,
 			},
 			peer:   resource.NewPeer(mockPeerID, mockTask, mockHost),
-			parent: resource.NewPeer(mockCDNPeerID, mockTask, mockHost),
-			run: func(t *testing.T, svc *Service, peer *resource.Peer, parent *resource.Peer, piece *rpcscheduler.PieceResult, peerManager resource.PeerManager, cdn resource.CDN, ms *mocks.MockSchedulerMockRecorder, mr *resource.MockResourceMockRecorder, mp *resource.MockPeerManagerMockRecorder, mc *resource.MockCDNMockRecorder) {
+			parent: resource.NewPeer(mockSeedPeerID, mockTask, mockHost),
+			run: func(t *testing.T, svc *Service, peer *resource.Peer, parent *resource.Peer, piece *rpcscheduler.PieceResult, peerManager resource.PeerManager, seedPeer resource.SeedPeer, ms *mocks.MockSchedulerMockRecorder, mr *resource.MockResourceMockRecorder, mp *resource.MockPeerManagerMockRecorder, mc *resource.MockSeedPeerMockRecorder) {
 				peer.FSM.SetState(resource.PeerStateRunning)
 				parent.FSM.SetState(resource.PeerStateRunning)
 				blocklist := set.NewSafeSet()
@@ -2658,16 +2662,16 @@ func TestService_handlePieceFail(t *testing.T) {
 			name: "piece result code is unknow",
 			config: &config.Config{
 				Scheduler: mockSchedulerConfig,
-				CDN:       &config.CDNConfig{Enable: true},
+				SeedPeer:  &config.SeedPeerConfig{Enable: true},
 				Metrics:   &config.MetricsConfig{EnablePeerHost: true},
 			},
 			piece: &rpcscheduler.PieceResult{
 				Code:   base.Code_ClientPieceRequestFail,
-				DstPid: mockCDNPeerID,
+				DstPid: mockSeedPeerID,
 			},
 			peer:   resource.NewPeer(mockPeerID, mockTask, mockHost),
-			parent: resource.NewPeer(mockCDNPeerID, mockTask, mockHost),
-			run: func(t *testing.T, svc *Service, peer *resource.Peer, parent *resource.Peer, piece *rpcscheduler.PieceResult, peerManager resource.PeerManager, cdn resource.CDN, ms *mocks.MockSchedulerMockRecorder, mr *resource.MockResourceMockRecorder, mp *resource.MockPeerManagerMockRecorder, mc *resource.MockCDNMockRecorder) {
+			parent: resource.NewPeer(mockSeedPeerID, mockTask, mockHost),
+			run: func(t *testing.T, svc *Service, peer *resource.Peer, parent *resource.Peer, piece *rpcscheduler.PieceResult, peerManager resource.PeerManager, seedPeer resource.SeedPeer, ms *mocks.MockSchedulerMockRecorder, mr *resource.MockResourceMockRecorder, mp *resource.MockPeerManagerMockRecorder, mc *resource.MockSeedPeerMockRecorder) {
 				peer.FSM.SetState(resource.PeerStateRunning)
 				parent.FSM.SetState(resource.PeerStateRunning)
 				blocklist := set.NewSafeSet()
@@ -2695,10 +2699,10 @@ func TestService_handlePieceFail(t *testing.T) {
 			dynconfig := configmocks.NewMockDynconfigInterface(ctl)
 			storage := storagemocks.NewMockStorage(ctl)
 			peerManager := resource.NewMockPeerManager(ctl)
-			cdn := resource.NewMockCDN(ctl)
+			seedPeer := resource.NewMockSeedPeer(ctl)
 			svc := New(tc.config, res, scheduler, dynconfig, storage)
 
-			tc.run(t, svc, tc.peer, tc.parent, tc.piece, peerManager, cdn, scheduler.EXPECT(), res.EXPECT(), peerManager.EXPECT(), cdn.EXPECT())
+			tc.run(t, svc, tc.peer, tc.parent, tc.piece, peerManager, seedPeer, scheduler.EXPECT(), res.EXPECT(), peerManager.EXPECT(), seedPeer.EXPECT())
 		})
 	}
 }
@@ -2834,7 +2838,7 @@ func TestService_handlePeerFail(t *testing.T) {
 	}{
 		{
 			name:  "peer state is PeerStateFailed",
-			peer:  resource.NewPeer(mockCDNPeerID, mockTask, mockHost),
+			peer:  resource.NewPeer(mockSeedPeerID, mockTask, mockHost),
 			child: resource.NewPeer(mockPeerID, mockTask, mockHost),
 			mock: func(peer *resource.Peer, child *resource.Peer, ms *mocks.MockSchedulerMockRecorder) {
 				peer.FSM.SetState(resource.PeerStateFailed)
@@ -2846,7 +2850,7 @@ func TestService_handlePeerFail(t *testing.T) {
 		},
 		{
 			name:  "peer state is PeerStateLeave",
-			peer:  resource.NewPeer(mockCDNPeerID, mockTask, mockHost),
+			peer:  resource.NewPeer(mockSeedPeerID, mockTask, mockHost),
 			child: resource.NewPeer(mockPeerID, mockTask, mockHost),
 			mock: func(peer *resource.Peer, child *resource.Peer, ms *mocks.MockSchedulerMockRecorder) {
 				peer.FSM.SetState(resource.PeerStateLeave)
@@ -2858,7 +2862,7 @@ func TestService_handlePeerFail(t *testing.T) {
 		},
 		{
 			name:  "peer state is PeerStateRunning and children need to be scheduled",
-			peer:  resource.NewPeer(mockCDNPeerID, mockTask, mockHost),
+			peer:  resource.NewPeer(mockSeedPeerID, mockTask, mockHost),
 			child: resource.NewPeer(mockPeerID, mockTask, mockHost),
 			mock: func(peer *resource.Peer, child *resource.Peer, ms *mocks.MockSchedulerMockRecorder) {
 				peer.StoreChild(child)
@@ -2874,7 +2878,7 @@ func TestService_handlePeerFail(t *testing.T) {
 		},
 		{
 			name:  "peer state is PeerStateRunning and it has no children",
-			peer:  resource.NewPeer(mockCDNPeerID, mockTask, mockHost),
+			peer:  resource.NewPeer(mockSeedPeerID, mockTask, mockHost),
 			child: resource.NewPeer(mockPeerID, mockTask, mockHost),
 			mock: func(peer *resource.Peer, child *resource.Peer, ms *mocks.MockSchedulerMockRecorder) {
 				peer.FSM.SetState(resource.PeerStateRunning)