Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add more visibility to IP address resolution when using DNS #556

Merged
merged 26 commits into from May 5, 2022
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
e6cd0b1
Add log to show the ip address DNS resolve to
wuhaoyujerry Apr 22, 2022
15b92fc
Add GetIpAddress method HTTPClient
wuhaoyujerry Apr 27, 2022
0bfe637
Fast client get ip address report
wuhaoyujerry Apr 28, 2022
243d759
get ip address for std client
wuhaoyujerry Apr 28, 2022
ff6d3b9
Merge branch 'fortio:master' into master
wuhaoyujerry Apr 28, 2022
a96fb27
remove todo and add error handling
wuhaoyujerry Apr 28, 2022
2ffe6bb
resolve code climate comments
wuhaoyujerry Apr 28, 2022
bc18497
fix the data race issue
wuhaoyujerry Apr 28, 2022
df56f48
run go lint
wuhaoyujerry Apr 28, 2022
f976f40
fix typo
wuhaoyujerry Apr 28, 2022
2cef96c
change fmt.Print to log.Info
wuhaoyujerry Apr 28, 2022
53a5138
sort ip address by its usage count
wuhaoyujerry Apr 28, 2022
b5c6807
fix go lint
wuhaoyujerry Apr 28, 2022
85f467b
update the log to show ip address per thread
wuhaoyujerry Apr 28, 2022
c606fcf
revert the go lint change
wuhaoyujerry Apr 28, 2022
26b433d
remove go routine to get ip address when using stdclient
wuhaoyujerry Apr 28, 2022
e58dfb5
add socket count for stdclient and add unit test
wuhaoyujerry Apr 28, 2022
fad9e7d
Add a todo to move the IPCountMap field
wuhaoyujerry Apr 28, 2022
aff79ab
Add unit test for ip distribution
wuhaoyujerry Apr 29, 2022
ee34952
revert diff
wuhaoyujerry May 3, 2022
626f6d5
change the sort ip distribution list logic
wuhaoyujerry May 4, 2022
433bacf
fix lint
wuhaoyujerry May 4, 2022
1ce5b9b
move the getIPUsageCount to httprunner_test.go
wuhaoyujerry May 4, 2022
031b469
change the client init order to avoid using pointer for socket count
wuhaoyujerry May 4, 2022
f3c54aa
Fix the issue that can cause nil pointer error and add unit test to c…
wuhaoyujerry May 5, 2022
db3d86e
Fix lint
wuhaoyujerry May 5, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion dflag/configmap/updater_test.go
Expand Up @@ -124,7 +124,8 @@ type (

// eventually tries a given Assert function 5 times over the period of time.
func eventually(t *testing.T, duration time.Duration,
af assertFunc, expected interface{}, actual getter, msgFmt string, msgArgs ...interface{}) {
af assertFunc, expected interface{}, actual getter, msgFmt string, msgArgs ...interface{},
) {
ldemailly marked this conversation as resolved.
Show resolved Hide resolved
increment := duration / 5
for i := 0; i < 5; i++ {
time.Sleep(increment)
Expand Down
3 changes: 2 additions & 1 deletion dflag/dynstringset.go
Expand Up @@ -78,7 +78,8 @@ func (d *DynStringSetValue) WithValidator(validator func(map[string]struct{}) er
// WithNotifier adds a function that is called every time a new value is successfully set.
// Each notifier is executed asynchronously in a new go-routine.
func (d *DynStringSetValue) WithNotifier(notifier func(oldValue map[string]struct{},
newValue map[string]struct{})) *DynStringSetValue {
newValue map[string]struct{}),
) *DynStringSetValue {
ldemailly marked this conversation as resolved.
Show resolved Hide resolved
d.notifier = notifier
return d
}
Expand Down
23 changes: 23 additions & 0 deletions fhttp/http_client.go
Expand Up @@ -46,6 +46,8 @@ type Fetcher interface {
// Close() cleans up connections and state - must be paired with NewClient calls.
// returns how many sockets have been used (Fastclient only)
Close() int
// GetIPAddress() get the ip address that DNS resolves to
GetIPAddress() string
}

const (
Expand All @@ -62,6 +64,7 @@ var (
connectionCloseHeader = []byte("\r\nconnection: close")
chunkedHeader = []byte("\r\nTransfer-Encoding: chunked")
rander = NewSyncReader(rand.New(rand.NewSource(time.Now().UnixNano())))
stdClientIP = make(chan string)
)

// NewHTTPOptions creates and initialize a HTTPOptions object.
Expand Down Expand Up @@ -396,6 +399,11 @@ func (c *Client) Fetch() (int, []byte, int) {
return code, data, 0
}

// GetIPAddress get the ip address that DNS resolves to when using stdClient.
func (c *Client) GetIPAddress() string {
wuhaoyujerry marked this conversation as resolved.
Show resolved Hide resolved
return <-stdClientIP
ldemailly marked this conversation as resolved.
Show resolved Hide resolved
}

// NewClient creates either a standard or fast client (depending on
// the DisableFastClient flag).
func NewClient(o *HTTPOptions) (Fetcher, error) {
Expand Down Expand Up @@ -426,6 +434,16 @@ func NewStdClient(o *HTTPOptions) (*Client, error) {
if o.Resolve != "" {
addr = o.Resolve + addr[strings.LastIndex(addr, ":"):]
}
// TODO: Find out how many time this get called. Should be num of conn + error
ldemailly marked this conversation as resolved.
Show resolved Hide resolved
conn, err := net.Dial(network, addr)
ldemailly marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
log.Errf("Fail to dial addr %s, err msg: %s\n", addr, err)
}

go func() {
ldemailly marked this conversation as resolved.
Show resolved Hide resolved
stdClientIP <- conn.RemoteAddr().String()
}()

return (&net.Dialer{
Timeout: o.HTTPReqTimeOut,
}).DialContext(ctx, network, addr)
Expand Down Expand Up @@ -511,6 +529,11 @@ type FastClient struct {
tlsConfig *tls.Config
}

// GetIPAddress get the ip address that DNS resolves to when using fast client.
func (c *FastClient) GetIPAddress() string {
wuhaoyujerry marked this conversation as resolved.
Show resolved Hide resolved
return c.dest.String()
}

// Close cleans up any resources used by FastClient.
func (c *FastClient) Close() int {
log.Debugf("Closing %p %s socket count %d", c, c.url, c.socketCount)
Expand Down
12 changes: 11 additions & 1 deletion fhttp/httprunner.go
Expand Up @@ -37,6 +37,7 @@ type HTTPRunnerResults struct {
periodic.RunnerResults
client Fetcher
RetCodes map[int]int64
IPCount map[string]int64
ldemailly marked this conversation as resolved.
Show resolved Hide resolved
// internal type/data
sizes *stats.Histogram
headerSizes *stats.Histogram
Expand Down Expand Up @@ -98,6 +99,7 @@ func RunHTTPTest(o *HTTPRunnerOptions) (*HTTPRunnerResults, error) {
total := HTTPRunnerResults{
HTTPOptions: o.HTTPOptions,
RetCodes: make(map[int]int64),
IPCount: make(map[string]int64),
sizes: stats.NewHistogram(0, 100),
headerSizes: stats.NewHistogram(0, 5),
AbortOn: o.AbortOn,
Expand Down Expand Up @@ -182,6 +184,11 @@ func RunHTTPTest(o *HTTPRunnerOptions) (*HTTPRunnerResults, error) {
// unused ones. We also must cleanup all the created clients.
keys := []int{}
for i := 0; i < numThreads; i++ {
// Get the report on the IP address each thread use to send traffic
ip := httpstate[i].client.GetIPAddress()
log.Infof("[%d] Host %s resolve to IP address: %s \n", i, o.URL, ip)
ldemailly marked this conversation as resolved.
Show resolved Hide resolved
total.IPCount[ip]++

total.SocketCount += httpstate[i].client.Close()
// Q: is there some copying each time stats[i] is used?
for k := range httpstate[i].RetCodes {
Expand All @@ -201,6 +208,9 @@ func RunHTTPTest(o *HTTPRunnerOptions) (*HTTPRunnerResults, error) {
_, _ = fmt.Fprintf(out, "Sockets used: %d (for perfect keepalive, would be %d)\n", total.SocketCount, r.Options().NumThreads)
}
_, _ = fmt.Fprintf(out, "Uniform: %t, Jitter: %t\n", total.Uniform, total.Jitter)
for k, v := range total.IPCount {
_, _ = fmt.Fprintf(out, "IP address %s usage count: %d\n", k, v)
ldemailly marked this conversation as resolved.
Show resolved Hide resolved
}
for _, k := range keys {
_, _ = fmt.Fprintf(out, "Code %3d : %d (%.1f %%)\n", k, total.RetCodes[k], 100.*float64(total.RetCodes[k])/totalCount)
}
Expand All @@ -216,7 +226,7 @@ func RunHTTPTest(o *HTTPRunnerOptions) (*HTTPRunnerResults, error) {
return &total, nil
}

// A errgroup is a collection of goroutines working on subtasks that are part of
// An errgroup is a collection of goroutines working on subtasks that are part of
// the same overall task.
type errgroup struct {
wg sync.WaitGroup
Expand Down
1 change: 0 additions & 1 deletion stats/stats_test.go
Expand Up @@ -726,7 +726,6 @@ func TestBucketLookUp(t *testing.T) {
input float64 // input
start float64 // start
end float64 // end

}{
{input: 11, start: 10, end: 11},
{input: 171, start: 160, end: 180},
Expand Down
3 changes: 2 additions & 1 deletion ui/restHandler.go
Expand Up @@ -236,7 +236,8 @@ func RESTRunHandler(w http.ResponseWriter, r *http.Request) { // nolint: funlen

// Run executes the run (can be called async or not, writer is nil for async mode).
func Run(w http.ResponseWriter, r *http.Request, jd map[string]interface{},
runner, url string, ro periodic.RunnerOptions, httpopts *fhttp.HTTPOptions) {
runner, url string, ro periodic.RunnerOptions, httpopts *fhttp.HTTPOptions,
) {
ldemailly marked this conversation as resolved.
Show resolved Hide resolved
// go func() {
var res periodic.HasRunnerResult
var err error
Expand Down