聶永的博客

          記錄工作/學(xué)習(xí)的點點滴滴。

          Apisix 1.5 升級到 2.2 踩坑備忘

          零、前言

          線上運行的 APISIX 為 1.5 版本,而社區(qū)已經(jīng)發(fā)布了 Apisix 2.2,是時候需要升級到最新版了,能夠享受最版本帶來的大量的BugFix,性能增強(qiáng),以及新增特性的支持等~

          從Apisix 1.5升級到Apisix 2.2過程中,不是一帆風(fēng)順的,中間踩了不少坑,所謂前車之鑒后事之師,這里給大家簡單梳理一下我們團(tuán)隊所在具體業(yè)務(wù)環(huán)境下,升級過程中踩的若干坑,以及一些需要避免的若干注意事項等。

          下文所說原先版本,皆指Apisix 1.5,新版則是Apisix 2.2版本。

          一、已有服務(wù)發(fā)現(xiàn)機(jī)制無法正常工作

          針對上游Upstream沒有使用服務(wù)發(fā)現(xiàn)的路由來講,本次升級沒有遇到什么問題。

          公司內(nèi)部線上業(yè)務(wù)大都基于Consul KV方式實現(xiàn)服務(wù)注冊和服務(wù)發(fā)現(xiàn),因此我們自行實現(xiàn)了一個 consul_kv.lua 模塊實現(xiàn)服務(wù)發(fā)現(xiàn)流程。

          這在Apisix 1.5下面一切工作正常。

          但在Apisix 2.2下面,就無法直接工作了,原因如下:

          • 服務(wù)發(fā)現(xiàn)配置指令變了
          • 上游對象包含服務(wù)發(fā)現(xiàn)時需增加字段 discovery_type 進(jìn)行索引

          2.1 服務(wù)發(fā)現(xiàn)配置指令變了

          原先運行中僅支持一種服務(wù)發(fā)現(xiàn)機(jī)制,需要配置在 apisix層級下面:

          apisix:
              ......
              discover: consul_kv
              ......    
          

          新版需要直接在config*.yaml文件中頂層層級下進(jìn)行配置,可支持多種不同的路由發(fā)現(xiàn)機(jī)制,如下:

          discovery:                      # service discovery center
            eureka:
              host:                       # it's possible to define multiple eureka hosts addresses of the same eureka cluster.
                - "http://127.0.0.1:8761"
              prefix: "/eureka/"
              fetch_interval: 30          # default 30s
              weight: 100                 # default weight for node
              timeout:
                connect: 2000             # default 2000ms
                send: 2000                # default 2000ms
                read: 5000
          

          我們有所變通,直接在配置文件頂層配置consul_kv多個集群相關(guān)參數(shù),避免 discovery 層級過深。

           discovery:
              consul_kv: 1
          consul_kv:
            servers:
              -
                host: "172.19.5.30"
                port: 8500
              -
                host: "172.19.5.31"
                port: 8500
            prefix: "upstreams"
            timeout:
              connect: 6000
              read: 6000
              wait: 60
            weight: 1
            delay: 5
            connect_type: "long" # long connect
            ......
          

          當(dāng)然,這僅僅保證了服務(wù)發(fā)現(xiàn)模塊能夠在啟動時被正常加載。

          推薦閱讀:

          2.2 upstream對象新增字段discovery_type

          Apisix當(dāng)前同時支持多種服務(wù)發(fā)現(xiàn)機(jī)制,這個很贊。對應(yīng)的代價,就是需要額外引入 discovery_type 字段,用于索引可能同時存在的多個服務(wù)發(fā)現(xiàn)機(jī)制。

          以 Cousul KV方式服務(wù)發(fā)現(xiàn)為例,那么需要在已有的 upstream 對象中需要添加該字段:

          "discovery_type" : "consul_kv"
          

          原先的一個upstream對象,僅僅需要 service_name 字段屬性指定服務(wù)發(fā)現(xiàn)相關(guān)地址即可:

          {
              "id": "d6c1d325-9003-4217-808d-249aaf52168e",
              "name": "grpc_upstream_hello",
              ......
              "service_name": "http://172.19.5.30:8500/v1/kv/upstreams/grpc/grpc_hello",
              "create_time": 1610437522,
              "desc": "demo grpc service",
              "type": "roundrobin"
          }
          

          而新版的則需要添加discovery_type字段,表明該service_name 字段對應(yīng)的具體模塊名稱,效果如下:

          {
              "id": "d6c1d325-9003-4217-808d-249aaf52168e",
              "name": "grpc_upstream_hello",
              ......
              "service_name": "http://172.19.5.30:8500/v1/kv/upstreams/grpc/grpc_hello",
              "create_time": 1610437522,
              "desc": "demo grpc service",
              "type": "roundrobin",
              "discovery_type":"consul_kv"
          }
          

          后面我們?nèi)糁С諧onsul Service或ETCD KV方式服務(wù)發(fā)現(xiàn)機(jī)制,則會非常彈性和清晰。

          調(diào)整了配置指令,添加上述字段之后,后端服務(wù)發(fā)現(xiàn)其實就已經(jīng)起作用了。

          但gRPC代理路由并不會生效……

          二、gRPC當(dāng)前不支持upstream_id

          在我們的系統(tǒng)中,上游和路由是需要單獨分開管理的,因此創(chuàng)建的HTTP或GRPC路由需要處理支持upstream_id的索引。

          這在1.5版本中,grpc路由是沒問題的,但到了apisix 2.2版本中,維護(hù)者 @spacewander 暫時沒做支持,原因是規(guī)劃grpc路由和dubbo路由處理邏輯趨于一致,更為緊湊。從維護(hù)角度我是認(rèn)可的,但作為使用者來講,這就有些不合理了,直接丟棄了針對以往數(shù)據(jù)的支持。

          作為當(dāng)前Geek一些方式,在 apisix/init.lua 中,最小成本 (優(yōu)雅和成本成反比)修改如下,找到如下代碼:

              -- todo: support upstream id
              api_ctx.matched_upstream = (route.dns_value and
                                          route.dns_value.upstream)
                                         or route.value.upstream 
          

          直接替換為下面代碼即可解決燃眉之急:

              local up_id = route.value.upstream_id
              if up_id then
                  local upstreams = core.config.fetch_created_obj("/upstreams")
                  if upstreams then
                      local upstream = upstreams:get(tostring(up_id))
                      if not upstream then
                          core.log.error("failed to find upstream by id: " .. up_id)
                          return core.response.exit(502)
                      end
                      if upstream.has_domain then
                          local err
                          upstream, err = lru_resolved_domain(upstream,
                                                              upstream.modifiedIndex,
                                                              parse_domain_in_up,
                                                              upstream)
                          if err then
                              core.log.error("failed to get resolved upstream: ", err)
                              return core.response.exit(500)
                          end
                      end
                      if upstream.value.pass_host then
                          api_ctx.pass_host = upstream.value.pass_host
                          api_ctx.upstream_host = upstream.value.upstream_host
                      end
                      core.log.info("parsed upstream: ", core.json.delay_encode(upstream))
                      api_ctx.matched_upstream = upstream.dns_value or upstream.value
                  end
              else
                  api_ctx.matched_upstream = (route.dns_value and
                                          route.dns_value.upstream)
                                         or route.value.upstream  
              end
          

          三、自定義auth插件需要微調(diào)

          新版的apisix auth授權(quán)插件支持多個授權(quán)插件串行執(zhí)行,這個功能也很贊,但此舉導(dǎo)致了先前為具體業(yè)務(wù)定制的授權(quán)插件無法正常工作,這時需要微調(diào)一下。

          原先調(diào)用方式:

              local consumers = core.lrucache.plugin(plugin_name, "consumers_key",
                      consumer_conf.conf_version,
                      create_consume_cache, consumer_conf)
          

          因為新版的lrucache不再提供 plugin 函數(shù),需要微調(diào)一下:

          local lrucache = core.lrucache.new({
            type = "plugin",
          })
          ......
              local consumers = lrucache("consumers_key", consumer_conf.conf_version,
                  create_consume_cache, consumer_conf)
          

          另一處是,順利授權(quán)之后,需要賦值consumer相關(guān)信息:

              ctx.consumer = consumer
              ctx.consumer_id = consumer.consumer_id
          

          此時需要替換成如下方式,為(可能存在的)后續(xù)的授權(quán)插件繼續(xù)作用。

          consumer_mod.attach_consumer(ctx, consumer, consumer_conf)
          

          更多請參考:apisix/plugins/key-auth.lua 源碼。

          四、ETCD V2數(shù)據(jù)遷移到V3

          遷移分為三步:

          1. 升級線上已有ETCD 3.3.*版本到3.4.*,滿足新版Apisix的要求,這時ETCD實例同時支持了V2和V3格式數(shù)據(jù)
          2. 遷移V2數(shù)據(jù)到V3
            • 因為數(shù)據(jù)量不是非常多,我采取了一個非常簡單和原始的方式
            • 使用 etcdctl 完成V2數(shù)據(jù)到導(dǎo)出
            • 然后使用文本編輯器vim等完成數(shù)據(jù)的替換,生成etcdctl v3格式的數(shù)據(jù)導(dǎo)入命令腳本
            • 運行之后V3數(shù)據(jù)導(dǎo)入腳本,完成V2到V3的數(shù)據(jù)導(dǎo)入
          3. 修改V3 /apisix/upstreams 中包含服務(wù)注冊的數(shù)據(jù),一一添加 "discovery_type" : "consul_kv"屬性

          基于以上操作之后,從而完成了ETCD V2到V3的數(shù)據(jù)遷移。

          五、啟動apisix后發(fā)現(xiàn)ETCD V3已有數(shù)據(jù)無法加載

          我們在運維層面,使用 /usr/local/openresty/bin/openresty -p /usr/local/apisix -g daemon off; 方式運行網(wǎng)關(guān)程序。

          這也就導(dǎo)致,自動忽略了官方提倡的:apisix start 命令自動提前為ETCD V3初始化的一些鍵值對內(nèi)容。

          因此,需要提前為ETCD V3建立以下鍵值對內(nèi)容:

          Key                         Value
          /apisix/routes          :   init_dir
          /apisix/upstreams       :   init_dir
          /apisix/services        :   init_dir
          /apisix/plugins         :   init_dir
          /apisix/consumers       :   init_dir
          /apisix/node_status     :   init_dir
          /apisix/ssl             :   init_dir
          /apisix/global_rules    :   init_dir
          /apisix/stream_routes   :   init_dir
          /apisix/proto           :   init_dir
          /apisix/plugin_metadata :   init_dir
          

          不提前建立的話,就會導(dǎo)致apisix重啟后,無法正常加載ETCD中已有數(shù)據(jù)。

          其實有一個補(bǔ)救措施,需要修改 apisix/init.lua 內(nèi)容,找到如下代碼:

                      if not dir_res.nodes then
                          dir_res.nodes = {}
                      end
          

          比較geek的行為,使用下面代碼替換一下即可完成兼容:

                          if dir_res.key then
                              dir_res.nodes = { clone_tab(dir_res) }
                          else
                              dir_res.nodes = {}
                          end
          

          六、apisix-dashboard的支持

          我們基于apisix-dashboard定制開發(fā)了大量的針對公司實際業(yè)務(wù)非常實用的企業(yè)級特性,但也導(dǎo)致了無法直接升級到最新版的apisix-dashboard。

          因為非常基礎(chǔ)的上游和路由沒有發(fā)生多大改變,因此這部分升級的需求可以忽略。

          實際上,只是在提交上游表單時,包含服務(wù)注冊信息JSON字符串中需要增加 discovery_type 字段和對應(yīng)值即可完成支持。

          七、小結(jié)

          花費了一些時間完成了從Apisix 1.5升級到Apisix 2.2的行為,雖然有些坑,但整體來講,還算順利。目前已經(jīng)上線并全量部署運行,目前運行良好。

          針對還停留在Apisix 1.5的用戶,新版增加了Control API以及多種服務(wù)發(fā)現(xiàn)等新特性支持,還是非常值得升級的。

          升級之前,不妨仔細(xì)閱讀每一個版本的升級日志(地址:https://github.com/apache/apisix/blob/2.2/CHANGELOG.md ),然后需要根據(jù)具體業(yè)務(wù)做好兼容測試準(zhǔn)備和準(zhǔn)備升級步驟,這些都是非常有必要的。

          針對我們團(tuán)隊來講,升級到最新版,一方面降低了版本升級的壓力,另一方面也能夠輔助我們能參與到開源社區(qū)中去,挺好~

          posted on 2021-02-23 14:57 nieyong 閱讀(3036) 評論(0)  編輯  收藏 所屬分類: HTTP移動后端

          公告

          所有文章皆為原創(chuàng),若轉(zhuǎn)載請標(biāo)明出處,謝謝~

          新浪微博,歡迎關(guān)注:

          導(dǎo)航

          <2021年2月>
          31123456
          78910111213
          14151617181920
          21222324252627
          28123456
          78910111213

          統(tǒng)計

          常用鏈接

          留言簿(58)

          隨筆分類(130)

          隨筆檔案(151)

          個人收藏

          最新隨筆

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 资阳市| 离岛区| 张掖市| 长寿区| 县级市| 武夷山市| 彰化市| 青神县| 新民市| 黔江区| 新沂市| 陆河县| 客服| 望奎县| 扶绥县| 仁寿县| 屯留县| 张家港市| 石首市| 灵川县| 郧西县| 福安市| 平湖市| 凌海市| 青州市| 青岛市| 新绛县| 平罗县| 施甸县| 宁海县| 青海省| 尉氏县| 调兵山市| 富顺县| 周至县| 绥中县| 万安县| 丹凤县| 耿马| 五台县| 神池县|