本文正在参加「金石计划」
前言
本来以为作为一名单纯的练习两年半的Javaboy,把Java服务接入好Skywalking就完事了,谁曾想Python服务也要接入进来,只能说君让臣死,臣不得不死,由于不怎么属于python,虽然有点磕磕绊绊总体还是挺顺利,特此记录下接入的方案
1.安装
这个参考下**Skywalking官网的示例**
pip安装只需要pip install一下即可,不过要注意python版本是必须要求python3
pip install "apache-skywalking
2.使用及原理
2.1.使用
在python服务的启动文件加入以下
from skywalking import agent, config
config.init()
agent.start()
所有的配置均从环境变量读取,环境变量名可以在init方法里查看,源码里定义了各种常量。
2.2.原理
2.2.1.插件源码
- agent.start() 执行时会加载内置的插件,然后插件会拦截相关的函数,然后上报数据
- 以request为例
def install():
from requests import Session
_request = Session.request
def _sw_request(this: Session, method, url,
params=None, data=None, headers=None, cookies=None, files=None,
auth=None, timeout=None, allow_redirects=True, proxies=None,
hooks=None, stream=None, verify=None, cert=None, json=None):
from skywalking.utils.filter import sw_urlparse
url_param = sw_urlparse(url)
# ignore trace skywalking self request
if config.protocol == 'http' and config.collector_address.rstrip('/').endswith(url_param.netloc):
return _request(this, method, url, params, data, headers, cookies, files, auth, timeout,
allow_redirects, proxies, hooks, stream, verify, cert, json)
span = NoopSpan(NoopContext()) if config.ignore_http_method_check(method) \
else get_context().new_exit_span(op=url_param.path or "/", peer=url_param.netloc,
component=Component.Requests)
# skywakling.trace.Span上下文
# 退出是会执行__exit__ -> self.stop() -> 会上报数据
with span:
carrier = span.inject()
span.layer = Layer.Http
if headers is None:
headers = {}
# 将相关参数放置在请求头headers里 Sw8
for item in carrier:
headers[item.key] = item.val
span.tag(TagHttpMethod(method.upper()))
span.tag(TagHttpURL(url_param.geturl()))
# 执行requests函数本身的request函数并返回
res = _request(this, method, url, params, data, headers, cookies, files, auth, timeout,
allow_redirects, proxies, hooks, stream, verify, cert, json)
span.tag(TagHttpStatusCode(res.status_code))
if res.status_code >= 400:
span.error_occurred = True
return res
# 这里是替换了内部的request函数
Session.request = _sw_request
2.2.2.插件原理总结
1. 做一些前置操作, 如: requests包设置headers信息, web框架包解析headers信息
2. 执行本身包的操作
3. 做一些后置操作(上报数据)
4. 返回本身包执行的返回结果
插件非常类似Java的动态代理
2.2.3.headers的数据格式
接入后链路追踪通过Header获取相应数据,需要满足固定的格式
return '-'.join([
'1',
b64encode(self.trace_id),
b64encode(self.segment_id),
self.span_id,
b64encode(self.service),
b64encode(self.service_instance),
b64encode(self.endpoint),
b64encode(self.client_address),
])
注意项
我们的服务web框架是使用的tornado,当使用多进程时,使用grpc时会有bug,grpc不适配多进程,当tornado使用server.start(20)时只能使用http上报信息
解决方案: server.start(1),然后run使用run_on_executor线程池,通过supervisord管理,使用多个端口启动服务,再通过nginx做负载均衡(或使用nacos进行服务转发)**
3.相关配置及插件
3.1.配置
重点配置,通过环境变量配置, python初始话配置见 config.init() 文件
`SW_AGENT_NAME: 服务名称`
`SW_AGENT_NAMESPACE: 服务命名空间`
`SW_AGENT_COLLECTOR_BACKEND_SERVICES: 上报的地址`
`SW_AGENT_PROTOCOL: 上报的方式`
`SW_AGENT_LOGGING_LEVEL: skywalking日志等级`
`SW_AGENT_PROFILE_ACTIVE: 是否上报日志`
`SW_AGENT_LOG_REPORTER_LEVEL: 上报日志的等级`
官方文档的所有配置
skywalking.apache.org/docs/skywal…
3.2.插件
python支持的插件
skywalking.apache.org/docs/skywal…
`sw_aiohttp`
`sw_celery`
`sw_django`
`sw_elasticsearch`
`sw_falcon`
`sw_fastapi`
`sw_flask`
`sw_http_server`
`sw_http_server`
`sw_kafka`
`sw_mysqlclient`
`sw_psycopg`
`sw_psycopg2`
`sw_pymongo`
`sw_pymysql`
`sw_pyramid`
`sw_rabbitmq`
`sw_redis`
`sw_requests`
`sw_sanic`
`sw_tornado`
`sw_urllib3`
`sw_urllib_request`
基本支持了所有web框架,服务中只需要在启动类里config.init() agent.start()一下,插件会自动帮我们根据环境变量的Skywalking配置将服务注册到oap中。