The service discovery mechanism in Kubernetes works as follows:
Service registration:
When a service is created in Kubernetes, it is assigned a unique DNS name and IP address.
DNS resolution:
Other services within the Kubernetes cluster can resolve the DNS name of a service to obtain its corresponding IP address.
Load balancing:
When a service receives requests from other services, Kubernetes automatically load balances the traffic across the available pods that belong to that service. This ensures scalability and fault tolerance.
Service updates:
If the number of pods associated with a service changes (e.g., due to scaling or failures), Kubernetes dynamically updates the service’s DNS record to reflect the current set of available endpoints.
Service registration:
When a service is created in Kubernetes, it is assigned a unique DNS name and IP address.
DNS resolution:
Other services within the Kubernetes cluster can resolve the DNS name of a service to obtain its corresponding IP address.
Load balancing:
When a service receives requests from other services, Kubernetes automatically load balances the traffic across the available pods that belong to that service. This ensures scalability and fault tolerance.
Service updates:
If the number of pods associated with a service changes (e.g., due to scaling or failures), Kubernetes dynamically updates the service’s DNS record to reflect the current set of available endpoints.
vertical disaggregation, where network functions decouple software from hardware,
allowing multiple combinations to be used
• horizontal disaggregation, where established network functions are decomposed into
more granular elements and new interfaces are designed and specified
allowing multiple combinations to be used
• horizontal disaggregation, where established network functions are decomposed into
more granular elements and new interfaces are designed and specified
پوینتی که همیشه باید مد نظر بگیرید :
هیچوقت کانسپت های مهندسی نرم افزار و برنامه نویسی رو به زبان فارسی نخونید.
هیچوقت کانسپت های مهندسی نرم افزار و برنامه نویسی رو به زبان فارسی نخونید.
👍2
mux http server with rate limiter
package main
import (
"encoding/json"
"errors"
"fmt"
"github.com/gorilla/mux"
"go.uber.org/ratelimit"
"log"
"net"
"net/http"
"sync"
"time"
)
const PORT = 8080
const RATELIMIT = 2
// RateLimit middleware.
func RateLimit(rate int) func(next http.Handler) http.Handler {
var lmap sync.Map
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
host, _, err := net.SplitHostPort(r.RemoteAddr)
if err != nil {
http.Error(w, fmt.Sprintf("invalid RemoteAddr: %s", err), http.StatusInternalServerError)
return
}
lif, ok := lmap.Load(host)
if !ok {
lif = ratelimit.New(rate)
}
lm, ok := lif.(ratelimit.Limiter)
if !ok {
http.Error(w, "internal middleware error: typecast failed", http.StatusInternalServerError)
return
}
log.Println("req:", r.RemoteAddr, "Rate:", rate, "Time:", time.Now())
lm.Take()
lmap.Store(host, lm)
next.ServeHTTP(w, r)
})
}
}
func getHello(w http.ResponseWriter, r *http.Request) {
var user = map[string]interface{}{
"name": "John Doe",
"age": 42,
"message": "Hello world!",
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusAccepted)
json.NewEncoder(w).Encode(user)
}
func main() {
r := mux.NewRouter()
r.Use(RateLimit(RATELIMIT))
r.HandleFunc("/api", getHello)
fmt.Printf("listening on port %d\n", PORT)
err := http.ListenAndServe(fmt.Sprintf(":%d", PORT), r)
if errors.Is(err, http.ErrServerClosed) {
log.Fatal("server closed\n")
}
if err != nil {
log.Fatal("error occurred :", err)
}
}
👍2
Programming Notes ✍️
mux http server with rate limiter package main import ( "encoding/json" "errors" "fmt" "github.com/gorilla/mux" "go.uber.org/ratelimit" "log" "net" "net/http" "sync" "time" ) const PORT = 8080 const RATELIMIT = 2 // RateLimit middleware.…
code for testing using curl :
for i in {1..2000}; do echo "Counter $i" && curl localhost:8080/api; done👍2
Note: Only the sender should close a channel, never the receiver. Sending on a closed channel will cause a panic.
Another note: Channels aren't like files; you don't usually need to close them. Closing is only necessary when the receiver must be told there are no more values coming, such as to terminate a range loop.
Another note: Channels aren't like files; you don't usually need to close them. Closing is only necessary when the receiver must be told there are no more values coming, such as to terminate a range loop.
Atomicity: All operations in a transaction either succeed or all are rolled back.
Consistent: The database integrity constraints are valid on completion of the transaction.
Isolated: Simultaneously occurring transactions do not interfere with each other. Contentious concurrent access is moderated by the
database so that transactions appear to run sequentially.
Durable: Irrespective of hardware or software failures, the updates made by the transaction are permanent.
Consistent: The database integrity constraints are valid on completion of the transaction.
Isolated: Simultaneously occurring transactions do not interfere with each other. Contentious concurrent access is moderated by the
database so that transactions appear to run sequentially.
Durable: Irrespective of hardware or software failures, the updates made by the transaction are permanent.
👍2
Clear dependencies
Clear syntax
Clear semantics
Composition over inheritance
Simplicity provided by the programming model (garbage collection, concurrency)
Easy tooling (the go tool, gofmt, godoc, gofix)
Clear syntax
Clear semantics
Composition over inheritance
Simplicity provided by the programming model (garbage collection, concurrency)
Easy tooling (the go tool, gofmt, godoc, gofix)
🔥1
Binary search using type casting an interface to []int
var numbers = []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28}
func binarySearch(in interface{}, target int) int {
var num = in.([]int)
left, right := 0, len(num)-1
for left <= right {
mid := left + (right-left)/2
guess := num[mid]
if target == guess {
return mid
}
if target > guess {
left = mid + 1 // the guess was too high
}
if target < guess {
right = mid - 1 // the guess was too low
}
}
return -1
}
func main() {
fmt.Println(binarySearch(numbers, 20))
}
🔥1
running simple search & binary search in diffrenet gorutines and signaling using channels :
this proccess waits until the sig chan recive true or the time out get triggerd.
var TIMEOUT = 2 * time.Second
var numbers = []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28}
func simpleSearch(input []int, target int) int {
for i := 0; i < len(input); i++ {
if input[i] == target {
return i
}
}
return 0
}
func binarySearch(in interface{}, target int) int {
var num = in.([]int)
left, right := 0, len(num)-1
for left <= right {
mid := left + (right-left)/2
guess := num[mid]
if target == guess {
return mid
}
if target > guess {
left = mid + 1 // the guess was too high
}
if target < guess {
right = mid - 1 // the guess was too low
}
}
return -1
}
func run(signal chan bool) {
var fun1 chan bool
fun1 = make(chan bool)
go func() {
timeBinary := time.Now()
fmt.Println(binarySearch(numbers, 20))
fmt.Println(time.Since(timeBinary))
fun1 <- true
}()
var fun2 chan bool
fun2 = make(chan bool)
go func() {
timeSimple := time.Now()
fmt.Println(simpleSearch(numbers, 20))
fmt.Println(time.Since(timeSimple))
time.Sleep(10 * time.Second)
fun2 <- true
}()
if <-fun1 && <-fun2 {
signal <- true
}
}
func main() {
sig := make(chan bool)
go run(sig)
fmt.Println("Welcome to the playground!")
select {
case <-sig:
fmt.Println("Runner Finished!!!")
case <-time.After(TIMEOUT):
fmt.Println("Timed out")
}
}
this proccess waits until the sig chan recive true or the time out get triggerd.
🔥1