Skip to content

modules upstream

Doychin edited this page Oct 9, 2015 · 6 revisions

Upstream Modules или Proxy Handlers

Работата с ъпстрийми в момента е пакетирана в интерфейс. Това ни позволява да имаме различни видове ъпстрийм имплементации. Трябва по подобие на кеш и storage модулите да се направи намиране и използване на различни ъпстрийм имплементации с go generate.

Какво трябва да подържат upstream-ите

Група от адреси. Един vhost/location може да има няколко upstream адреса, които да отговарят за него. Пример:

[
  "http://first.example.com",
  "http://second.example.com",
  "http://third.example.com"
]

Когато има група, upstream-a може да вземе поискан файл от който и да е от сървърите в групата. Ако upstream time out–не или врзъката с него не е възможна - се избере съседен, който евентуално все още работи коректно.

Групите трябва да могат да се преизползват. Представям си го по подобие на кеш зоните. Ще дам примери със сегашната имплементация, където upstream-a е отделен модул. Същото би могло да се постигне и с handler ако поемем по този път.

{
  "upstreams": {

    "near_servers": {
       "addresses": [
         "http://near-one.example.cmm",
         "http://near-two.example.com",
         "http://alomost-near.example.com"
      ]
    },

    "far_servers": {
      "addresses": [
         "http://far-one.example.cmm",
         "http://far-two.example.com",
         "http://really-far.example.com"
      ]
    }

  }


  "virtual_hosts": {

     "cdn.example.com": {
        "upstream": "near_servers",
        ...
     },


     "different.example.com": {
        "upstream": "near_servers",
        ...
     }

     "slow.example.com": {
        "upstream": "far_servers",
        ...
     }

  }
}

Повторното изброяване на всяка група, с всичките й настройки, във vhost/location не е вариант.

Конфигуриран на Host хедър. Всеки vhost трябва да може да сложи Host хедъра при правене на заявка към upstream-а. Вариантите са три:

  • Хедъра не се променя по никакъв начин. Сегашната ни имплементация.

  • Да се сложи изричен хедър:

     // A vhost:
     "different.example.com": {
        "upstream": "near_servers",
        "host_header": "different.host.header.net",
        ...
     }
  • Да се запази хедъра от заявката на клиента. Все пак сме reverse proxy и това е една от основните ни функции:
     "different.example.com": {
        "upstream": "near_servers",
        "host_header_keep_original": true,
        ...
     }

Балансиране. Трафика между различните адреси в една група трябва да може да е балансиран. Обикновен round-robin не е достатъчен. Необходимите неща са:

  • Round robin - макар да не е достатъчен, то той е необходим. Може да се използва за default-ен алгоритъм за балансиране.
    "far_servers": {
      "balancing: "roundrobin",
      "addresses": [
         "http://far-one.example.cmm",
         "http://far-two.example.com",
         "http://really-far.example.com"
      ]
    }
  • Тегла - upstream-ите може да са с различен капацитет. nedomi трябва да може да праща различен трафик към всеки от тях. Пример: addresses: [http://far-one.example.cmm|30%, http://far-one.example.cmm|70%]

  • Ketama consistent hashing - това е балансиращ алгоритъм, който позвлява да има някаква стабилност на това кой кой обект в коя кошница ще бъде сложен. В нашия случай обект е файл, а кошница - upstream server. Огромното предимство на този алгоритъм е, че а) един и същи файл ще бъде взимам винаги от един и същи сървър и б) ако конфигурацията на кошниците/сървъри бъде променена, все пак повечето файлове все пак ще останат на същите места.

    "far_servers": {
      "balancing: "ketama",
      "addresses": [
         "http://far-one.example.com|5%",
         "http://far-two.example.com",
         "http://really-far.example.com"
      ]
    }
  • Rendezvous hashing - друг балансиращ алгоритъм, който гони същите цели като Ketama, но по друг начин. Предимството му е, че е много по - прост и се правят много по - малко сметки за взимане на решението от кой сървър да се вземе файл.
    "far_servers": {
      "balancing: "rendezvous",
      "addresses": [
         "http://far-one.example.cmm",
         "http://far-two.example.com|15%",
         "http://really-far.example.com"
      ]
    }

DNS resolve. Ако сървърите са ни дадени като домейни, а не като IP-та ще трябв да ги resolve-нем. Ако един адрес се resolve-а на повече от едно IP, то трябва да ползваме всичките IP-та. Също така, тези адреси могат да се променят с времето. Трябва от време на време (TTL на домейна?) да ги резуваме на ново по време на работа на сървъра.

Basic Authenticate. Upstream сървърите може да са защитени с HTTP Basic Auth. На всяка група трябва да може да се конфигурира и това. Това може да стане по два начина: изрично слагане на header-а, когато се говори с upstream-а или с юзър/парола в конфигурацията. На мен второто ми се вижда по - лесно за използване.

    "far_servers": {
      "set_headers: {"Basic-Auth": "ca37da232dac05d=="},
      "addresses": [
         "http://far-one.example.cmm",
         "http://far-two.example.com|15%",
         "http://really-far.example.com"
      ]
    }

или

    "far_servers": {
      "http_basich_auth: {"user": "pesho", "password: "baba"},
      "addresses": [
         "http://far-one.example.cmm",
         "http://far-two.example.com|15%",
         "http://really-far.example.com"
      ]
    }

Connection Limit. Трябва да можем да лимитираме общия брой кънекции към upstream сървър. Независимо в колко vhost-a е използван.

    "far_servers": {
      "max_connections_per_server: 100,
      "addresses": [
         "http://far-one.example.cmm",
         "http://far-two.example.com|15%",
         "http://really-far.example.com"
      ]
    }

Keep Alive. Най - добре ще е да имаме keep-alive кънекции към ъпстрийм сървърите, които го подържат. Това значително подобрява response времето на nedomi, а и пази задните сървъри от претоварване.

Как да го направим

Горните примери са с цел да ти покажат идеята ми, но никак не са задължителни. Аз (Дойчо) смятам, че ще е много по - лесно ако Upstream-а остане отделен вид обект, а не е handler, но мога да греша.

Важност

Не всички от изброените неща са задължителни. Тези, без които може да се мине първоначално са: keep-alive, connection limit и dns resolve. Не вярвам, че което и от тях ще е сериозен bottleneck.

Останалите неща, подредени от по - важно към по - малко важно са:

  • Групи
  • Host header
  • Балансиране с ketama
  • Тегла. Но някак чувствам, че теглата ще са просто конфигурация на всеки от балансиращите алгоритми.
  • Всички останали балансирания
  • Basic Auth - това може да бъде направено и с handler без промяна на ъпстриймите, като за начало.