2019独角兽企业重金招聘Python工程师标准>>>
在使用微服务会面临最大的一个问题也就是在服务数量增加带来的排查成本和监控成本,大家为了解决这些成本也衍生出了很多工作,当然在Istio中也很好的融合了这些组件,默认安装下就已经带上了这些组件(zipkin + jaeger , prometheus + grafana),本节就来看看怎么来使用这些组件
附上:
喵了个咪的博客:w-blog.cn
Istio官方地址:https://preliminary.istio.io/zh
Istio中文文档:https://preliminary.istio.io/zh/docs/
PS : 此处基于当前最新istio版本1.0.3版本进行搭建和演示
一. 清理bookinfo重新创建
先重置官方示例bookinfo回到最初的状态:
运行清理bookinfo脚本,并且重新创建
> ./istio-1.0.3/samples/bookinfo/platform/kube/cleanup.sh
namespace ? [default] istio-test
using NAMESPACE=istio-test
Deleted config: destinationrules details
...
Application cleanup successful
# 重新初始化
> kubectl apply -n istio-test -f istio-1.0.3/samples/bookinfo/platform/kube/bookinfo.yaml
> kubectl apply -n istio-test -f istio-1.0.3/samples/bookinfo/networking/bookinfo-gateway.yaml
> kubectl apply -n istio-test -f istio-1.0.3/samples/bookinfo/networking/destination-rule-all.yaml
二. 链路监控
在微服务中往往一次请求会尽力N多服务,那么每个服务的响应状态这个业务经过哪些服务对开发或问题排查就显得额外重要,链路监控是其中的一种解决方案,把微服务中的调用链进行记录并且通过可视化的方式进行展示,行业中相对成熟的解决方案就是zipkin,但是因为zipkin的界面并不是那么友好一般我们配合着jaeger进行使用,istio也对它进行了整合.
2.1 访问使用jaeger
通过内部映射的方式映射到本机的
> kubectl port-forward -n istio-system $(kubectl get pod -n istio-system -l app=jaeger -o jsonpath='{.items[0].metadata.name}') 16686:16686
或者也可修改成nodeport端口:
> kubectl edit svc jaeger-query -n istio-system
ports:
- name: query-http
port: 16686
protocol: TCP
targetPort: 16686
nodePort: 30686
selector:
app: jaeger
sessionAffinity: None
type: NodePort
在 Jaeger dashboard里从Service下选择productpage,点击Find Traces 按钮,可以看到跟踪信息:
进到下一层可以看到每个服务的调用层次以及总体消耗时间的分布:
在展开可以看到更多的相关内容
2.2 链路监控的必要条件 Headers 传递
为什么使用服务网格之后还需要传递指定的Headers呢? 这里就要从链路监控的机制来说了,在服务网格之前需要链路监控每个程序都需要向链路监控服务器发送消息,由第一个程序找链接监控发起ID获取,接下来的每个程序被调用的时候都需要告知链路监控系统我是在这个链路ID之中,此时才能关联整个链路.
虽然 Istio 代理能够自动发送 Span 信息,但还是需要一些辅助手段来把整个跟踪过程统一起来。应用程序应该自行传播跟踪相关的 HTTP Header,这样在代理发送 Span 信息的时候,才能正确的把同一个跟踪过程统一起来。
为了完成跟踪的传播过程,应用应该从请求源头中收集下列的 HTTP Header,并传播给外发请求:
- x-request-id
- x-b3-traceid
- x-b3-spanid
- x-b3-parentspanid
- x-b3-sampled
- x-b3-flags
- x-ot-span-context
如果查看示例服务,可以看到productpage服务(Python)从HTTP请求中提取所需的标头:
def getForwardHeaders(request):
headers = {}
if 'user' in session:
headers['end-user'] = session['user']
incoming_headers = [ 'x-request-id',
'x-b3-traceid',
'x-b3-spanid',
'x-b3-parentspanid',
'x-b3-sampled',
'x-b3-flags',
'x-ot-span-context'
]
for ihdr in incoming_headers:
val = request.headers.get(ihdr)
if val is not None:
headers[ihdr] = val
#print "incoming: "+ihdr+":"+val
return headers
2.3 采集控制
Istio 默认捕获所有请求的跟踪。例如,何时每次访问时都使用上面的 Bookinfo 示例应用程序 / productpage你在 Jaeger 看到了相应的痕迹仪表板。链路监控每次和链路服务器通讯也是有性能消耗的,在一个每天千万pv的业务下把所有链路全部采集下来是不合适的,无论从CPU还是磁盘空间都很容易出现瓶颈,并且链路监控并不是日志是一种排查手段,所以我们需要在生产环境下进行采集频率的限制:
找到pilot中PILOT_TRACE_SAMPLING环境变量从100%修改成10%的采集率:
> kubectl -n istio-system edit deploy istio-pilot
...
- name: PILOT_TRACE_SAMPLING
value: "10"
...
> :wq
再去刷新页面10次在JaegerUI只会看到一次调用,这边最小精度是0.01%有效值是0.0~100.0(不需要此功能可以完全不开启)
三, 数据采集
Istio集成的另外一个利器就是prometheus + grafana了, prometheus作为基础数据采集和存储方式grafana进行了可定制化报表展示以及报警等机制,先使用样的方式开启外部端口或映射端口到本地:
> kubectl -n istio-system port-forward $(kubectl -n istio-system get pod -l app=prometheus -o jsonpath='{.items[0].metadata.name}') 9090:9090
> kubectl edit svc prometheus -n istio-system
ports:
- name: http-prometheus
port: 9090
protocol: TCP
targetPort: 9090
nodePort: 30090
selector:
app: prometheus
sessionAffinity: None
type: NodePort
就可以查询各种指标了
例子一 :
# productpage服务的所有请求总数
> istio_requests_total{destination_service="productpage.istio-test.svc.cluster.local"}
例子二 :
# reviews 服务的 v3版本的所有请求总数
> istio_requests_total{destination_service="reviews.istio-test.svc.cluster.local", destination_version="v3"}
例子三 :
# 过去 5 分钟对所有 productpage 服务的请求比例
> rate(istio_requests_total{destination_service=~"productpage.*", response_code="200"}[5m])
四, 监控可视化
当然直接使用prometheus并不是很方便对于用户并不是特别友好,也不能做很多的预设,一般会配合grafana一起使用
> kubectl -n istio-system port-forward $(kubectl -n istio-system get pod -l app=grafana -o jsonpath='{.items[0].metadata.name}') 3000:3000
> kubectl edit svc grafana -n istio-system
ports:
- name: http
port: 3000
protocol: TCP
targetPort: 3000
nodePort: 33000
selector:
app: grafana
sessionAffinity: None
type: NodePort
让后就可以指定各种各样的指标了