Uber jaeger

Wesley13
• 阅读 836

Jaeger-Uber开源的一个基于Go的分布式追踪系统

最近因工作需要在研究traing系统,最后选了jaeger,下面是一些总结,同时摘抄了网上的一些资料,并结合自己实践过程中遇到的一些什么问题,欢迎指正,如你也在使用jaeger,或者想使用jaeger,途中遇到什么困难,可发邮件交流:honglouleiyan@163.com

前言

​ 随着公司的发展,业务不断的增加,模块的不断拆分,系统间业务调用就变得越复杂,对定位线上故障带来很大困难。整个调用链不透明,犹如系统被蒙上一块黑纱,当线上遇到故障时,整个技术部就陷入痛苦的漩涡。这时候分布式追踪系统应运而生,如揭开了黑纱,让阳光照进黑暗。

Opentracing相关文档

分布式追踪系统Jaeger

Jaeger是Uber开发的一套分布式追踪系统,已在Uber大规模使用。并在2017-9-13 加入CNCF 开源组织。使用Jaeger可以非常直观的展示整个分布式系统的调用链,由此可以很好发现和解决问题:

jaeger架构

jaeger官网网址

https://www.jaegertracing.io/docs/

jaeger github地址

https://github.com/jaegertracing/jaeger

jaeger 部署

使用docker部署官网资料和网站资料比较多,不过都是使用cassandra作为存储引擎,并且一般文章并没有给出具体的建表语句,官网文档也没有找到建表语句!

如果你需要使用cassandra作为存储引擎的话,这篇文章仅供参考:https://blog.csdn.net/niyuelin1990/article/details/80225305

文章中有对应的导入jaeger表结构部门:

导入Jaeger表结构,这里不得不吐槽一下Jaeger!Jaeger二进制安装包里根本没有数据sql文件,而且没有任何文档告诉你SQL文件在哪里找,没安装文档!我表示是崩溃的,最终在源码目录的一个角落中找到SQL文件,路径展示一下:

$GOPATH/src/github.com/jaegertracing/jaeger/plugin/storage/cassandra/schema/v001.cql.tmpl 12 格式: cqlsh -h HOST -p PORT -f fileName cqlsh 10.100.7.46 -f $GOPATH/src/github.com/jaegertracing/jaeger/plugin/storage/cassandra/schema/v001.cql.tmpl 123

上面的命令是我搜索来的,因为在导入之前我已经手动一条一条加进去了(>﹏<)!如果不好用的话,读者可以直接cqlsh一条一条黏上去!!!!

下面本文将介绍如何使用elasticsearch存储引擎部署jaeger!

Jaeger组件

Agent

Agent是一个网络守护进程,监听通过UDP发送过来的Span,它会将其批量发送给collector。按照设计,Agent要被部署到所有主机上,作为基础设施。Agent将collector和客户端之间的路由与发现机制抽象了出来。

Collector

Collector从Jaeger Agent接收Trace,并通过一个处理管道对其进行处理。目前的管道会校验Trace、建立索引、执行转换并最终进行存储。存储是一个可插入的组件,现在支持Cassandra和elasticsearch。

Query

Query服务会从存储中检索Trace并通过UI界面进行展现,该UI界面通过React技术实现,其页面UI如下图所示,展现了一条Trace的详细信息。

存储

jaeger采集到的数据必须存储到某个存储引擎,目前支持Cassandra和elasticsearch

docker + elasticsearch安装

首先,你安装jaeger时,需要使用docker环境,

然后使用docker安装一个elasticsearch

docker run -d  --name elasticsearch --restart=always -p 9200:9200 -p 9300:9300 -e ES_JAVA_OPTS="-Xms512m -Xmx512m" elasticsearch:latest

注意:

1、此elasticsearch为单机版且数据存内存,若生产环境,请自行解决如何使用docker安装elasticsearch集群并且数据写入磁盘,elasticsearch版本请选择5.X,原因如下(github issues:https://github.com/jaegertracing/jaeger/issues/665

jaeger elasticsearch版本请使用5.X的版本,官网上虽然说明使用5.X和6.X都行,但是亲测使用6.2.4的es,会出现数据丢失:collector将数据写入elsasticsearch时会出现索引已存在的报错:

error:"trace_id":"89c90e9c1bc48622","span_id":"89c90e9c1bc48622","error":"elastic: Error 400 (Bad Request): index [jaeger-span-2018-05-27/5JHNIPoLRBe3c560r7FJlQ] already exists [type=resource_already_exists_exception]

​ 若你需要把elsticsearc 9200暴露到公网上,你注意Elasticsearch服务安全加固,可参考:https://www.sojson.com/blog/213.html

2、请使用docker安装elasticsearch,若未使用docker安装,下一步安装collector时会出现报错:

docker: Error response from daemon: could not get container for elasticsearch: No such container: elasticsearch.

容器中找不到对应的elasticsearch

docker + collector安装

若你安装的collector和elasticsearch是在同一台机器上,使用docker容易的--link命令就可以将collector和elasticsearch关联上,安装命令如下:

docker run -d --name jaeger-collector --restart=always --link elasticsearch:elasticsearch -e SPAN_STORAGE_TYPE=elasticsearch -e ES_SERVER_URLS=http://elasticsearch:9200 -e ES_USERNAME=elastic -p 14267:14267 -p 14268:14268 -p 9411:9411 jaegertracing/jaeger-collector

注意:

​ --link elasticsearch:elasticsearch,代表docker容易关联,该名字必须和你安装elasticsearch —name的名字相同

​ --SPAN_STORAGE_TYPE=elasticsearch 代表安装jaeger选择elasticsearch作为存储

-e ES_SERVER_URLS=http://elasticsearch:9200次条目代表你选择容器安装的elasticsearch的9200端口

-e ES_USERNAME elasticsearch的用户名:默认elastic,下同

-e ES_PASSWORD elasticsearch的密码

-e 其实就是代表的环境变量,其他变量你可以使用以下语句查看:

docker run -e SPAN_STORAGE_TYPE=elasticsearch jaegertracing/jaeger-collector /go/bin/collector-linux --help

当然,一般生产环境你肯定不会将collector和elasticsearch安装到同一台机器,至少你可能会安装多个collector,所以,如何跨机器的用collector连接此elasticsearch呢?

你可以用用以下命令:

docker run -d --name jaeger-collector  --restart=always -e SPAN_STORAGE_TYPE=elasticsearch -e ES_SERVER_URLS=http://你的es ip:9200 -e ES_USERNAME=elastic -p 14267:14267 -p 14268:14268 -p 9411:9411 jaegertracing/jaeger-collector

区别在于,你无需使用—link来进行容器互连,只需ES_SERVER_URLS填写对应的ip和port即可;

如果你想看启动是否成功,你可将命令中的“-d”改为“--rm”并删除“--restart=always” ,这样启动日志会即时打印到控制台

--rm命令选项,等价于在容器退出后,执行docker rm -v

--restart=always,一直执行,异常退出尝试重启

启动成功日志:

{"level":"info","ts":1527673610.349252,"caller":"healthcheck/handler.go:99","msg":"Health Check server started","http-port":14269,"status":"unavailable"}

{"level":"info","ts":1527673610.7525811,"caller":"static/strategy_store.go:76","msg":"No sampling strategies provided, using defaults"}

{"level":"info","ts":1527673610.752815,"caller":"collector/main.go:142","msg":"Registering metrics handler with HTTP server","route":"/metrics"}

{"level":"info","ts":1527673610.7528777,"caller":"collector/main.go:150","msg":"Starting Jaeger Collector HTTP server","http-port":14268}

{"level":"info","ts":1527673610.7529178,"caller":"healthcheck/handler.go:133","msg":"Health Check state change","status":"ready"}

如你出现以下错误:

"caller":"collector/main.go:102","msg":"Failed to init storage factory","error":"health check timeout: no Elasticsearch node available","errorVerbose":"no Elasticsearch node available

请检查你的elasticsearch地址,

docker + query安装

同collector一样,若你安装的collector和elasticsearch是在同一台机器上,使用docker容易的--link命令就可以将query和elasticsearch关联上,安装命令如下:

docker run -d --name jaeger-query --restart=always --link elasticsearch:elasticsearch -e SPAN_STORAGE_TYPE=elasticsearch -e ES_SERVER_URLS=http://elasticsearch:9200 -e ES_USERNAME=elastic -e ES_PASSWORD=你的密码 -p 16686:16686/tcp jaegertracing/jaeger-query

其他对应的操作,你参考collector即可,到了这一步,如果你能将collector部署好,那么部署query也是一样的;

注意,ES_USERNAME、ES_PASSWORD这两个环境变量,当你的elasticsearch未设置账号密码时,你可以不填,也可以填上默认值,elasticsearch的默认ES_USERNAME=elastic,ES_PASSWORD=changeme

部署完成query之后,根据你暴露的端口号(-p 16686:16686/tcp),浏览器输入以下地址(将localhost换成你部署query的地址):

http://localhost:16686

你就会看到开篇的UI界面了,当然数据肯定是空空如也。

docker + agent安装

根据uber jaeger官网的架构,agent一般是和jaeger-client部署在一起,agent作为一个基础架构,每一台应用(接入jaeger-client的应用)所在的机器都需要部署一个agent;

根据数据采集原理,jaeger-client采集到数据之后,是通过UDP端口发送到agent的,jaeger-client和agent部署在一起的好处是UDP传输数据都在应用所在的机器,可避免UDP的跨网络传输,多一层安全保障。

当然,架构可能是多变的,你的agent可能不和jaeger-client所在的应用在一台机器,这个时候,jaeger-client就必须显示的指定其连接的agent的IP及port,具体做法后文jaeger-client对应模块会讲到。

前文提到,jaeger-client采集到数据之后,是通过UDP端口发送到agent的,agent接收到数据之后,使用Uber的Tchannel协议,将数据发送到collector,所以,agent是必须和collector相连的;

docker安装agent命令如下:

docker run   -d  --name jaeger-agent --restart=always -p 5775:5775/udp   -p 6831:6831/udp   -p 6832:6832/udp   -p 5778:5778/tcp   jaegertracing/jaeger-agent   /go/bin/agent-linux --collector.host-port=collector ip:14267

如前文所述,你可能不止一个collector,你可能需要这样:

docker run   -d  --name jaeger-agent --restart=always -p 5775:5775/udp   -p 6831:6831/udp   -p 6832:6832/udp   -p 5778:5778/tcp   jaegertracing/jaeger-agent   /go/bin/agent-linux --collector.host-port=collector ip1:14267,collector ip2:14267,collector ip3:14267

--collector.host-port=collector ip1:14267,collector ip2:14267,collector ip3:14267,用逗号分开,连接三个collector,这样的话,这三个collector只要一个存活,agent就可以吧数据传输完成,以避免单点故障

二进制安装jaeger

以上,使用docker容器化的安装jaeger是非常方便的,然后加上Kubernetes,可以很好的做好监控管理;

具体使用Kubernetes安装jaeger,你可自行研究,官方github地址:https://github.com/jaegertracing/jaeger-kubernetes

当然你也可以不使用docker,linux安装jaeger网上资料很多,如:https://blog.csdn.net/niyuelin1990/article/details/80225305

二进制安装包地址:

https://github.com/jaegertracing/jaeger/releases

如安装agent,如我们一般应用文件一样:

nohup ./jaeger-agent --collector.host-port=10.100.7.46:14267 1>1.log 2>2.log &

jaeger-client

目前jaeger官方支持以下客户端:

Language

GitHub Repo

Go

jaegertracing/jaeger-client-go

Java

jaegertracing/jaeger-client-java

Node.js

jaegertracing/jaeger-client-node

Python

jaegertracing/jaeger-client-python

C++

jaegertracing/jaeger-client-cpp

C#

jaegertracing/jaeger-client-csharp

请他语言也在开发中,具体请看: issue #366.

由于作者只会java开发,仅仅只能写点java client的东西;

Java-client

Jaeger tracing收集数据原理是第一个应用被调用的时候生成一个traceId,然后这个traceId会放到HTTP请求头里面将其传给下一个链路,然后每一个链路里面登录带有这个traceId,最后在elasticsearch/Cassandra里面讲采集到数据聚合成一个调用链路;

所以,jaeger应用场景为HTTP调用链相关的场景,对于dubbo这种RPC调用个人认为是不适用的。

以现有技术体系,目前成熟的框架有springmvc、springboot、springcloud,其中springboot、springcloud基本相同,本文只讲springmvc、springboot,因为二者有一些差别,需要特别处理;

springboot接入jaeger client

springboot 接入jaeger github地址如下:

http://planet.jboss.org/post/opentracing_spring_boot_instrumentation

1、在spring boot的项目pom.xml添加依赖

io.opentracing.contrib

opentracing-spring-web-autoconfigure

0.3.0

com.uber.jaeger

jaeger-core

0.26.0

2、注入jaeger bean

@Bean   public Tracer jaegerTracer() {   com.uber.jaeger.Configuration.SenderConfiguration senderConfiguration = new com.uber.jaeger.Configuration.SenderConfiguration();   com.uber.jaeger.Configuration.ReporterConfiguration reporterConfiguration = new com.uber.jaeger.Configuration.ReporterConfiguration().withSender(senderConfiguration).withLogSpans(false).withMaxQueueSize(1000).withFlushInterval(100);   com.uber.jaeger.Configuration.SamplerConfiguration samplerConfiguration = new com.uber.jaeger.Configuration.SamplerConfiguration().withType(ConstSampler.TYPE).withParam(1);   com.uber.jaeger.Configuration configuration = new com.uber.jaeger.Configuration(traceAppName).withReporter(reporterConfiguration).withSampler(samplerConfiguration);   return configuration.getTracer(); }

请注意,此bean所属的类必须随着spring容器启动,已确保spring启动是此bean被注入:

即加上@Configuration 注解即可;

SenderConfiguration可供你选择数据上报方式,使用with*方法选择对应的参数:

senderConfiguration.withAgentHost(agent ip) —— 默认值为本机

senderConfiguration.withAgentPort(6831) —— 默认值6831

如上例:SenderConfiguration什么参数都没有,即默认选择本机agent,6831 UDP端口上报采集到的数据

HTTP直接上报

你也可以选择绕过agent,直接使用HTTP协议将数据上报给collector,这样,你上文中就可以不必安装agent;

这是,你的SenderConfiguration设置以下参数:

senderConfiguration.withEndpoint("http://localhost:14268/api/traces");

localhost:14268 为你的collector的ip和端口号,这样你就可以把数据直接上报到collector

当然,你可能会有一些安全方面的考虑,你可以使用下面的方式设置你的用户名和密码,或者你的token

senderConfiguration.withAuthPassword(password);

senderConfiguration.withAuthUsername(username);

senderConfiguration.withAuthToken(authToken);

ReporterConfiguration参数:

withSender -------选择发送方式

withLogSpans -------是否日志上报

withMaxQueueSize -------数据最大累计量

withFlushInterval -------报告间隔的刷新( ms )

你可以根据你们业务系统给的数据量选择合适的参数;

根据uber jaeger"不怜悯"数据原则,若你选择withMaxQueueSize为1000(条),withFlushInterval为1000(ms),即1000毫秒以内只会有1000条数据上报,其他数据会丢掉

SamplerConfiguration 参数:

SamplerConfiguration可设置你的采样策略:

withType 采样策略:

  1. ConstSampler,全量采集

  2. ProbabilisticSampler ,概率采集,默认万份之一

  3. RateLimitingSampler ,限速采集,每秒只能采集一定量的数据

  4. RemotelyControlledSampler ,一种动态采集策略,根据当前系统的访问量调节采集策略

withParam 采样率

withManagerHostPort 采样策略配置 默认为:localhost:5778

当使用uber jaeger时,如果你要在嵌入tracing的应用里面发送HTTP请求,你可能需要用到RestTemplate,否则你用的HTTP client会导致trace id丢失,从而导致调用链断裂;

所以你还需要注入RestTemplate bean,方式和jaeger bean一样

@Bean public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) { return restTemplateBuilder.build(); }

说的再多,不过给你一个例子:

https://github.com/pavolloffay/opentracing-java-examples

Springmvc接入jaeger client

Springmvc 接入jaeger github地址如下:

https://github.com/opentracing-contrib/java-spring-web

1、在spring mvc的项目pom.xml添加依赖

   io.opentracing.contrib    opentracing-spring-web    0.3.0 com.uber.jaeger jaeger-core 0.26.0

注意和springboot的区别

想在spring mvc引入tracing功能,配置中是必须添加TracingFilter and TracingHandlerInterceptor,这两个类 是必须的,你可以通过手动注入或者CDI的方式注入

具体代码示例如下:

@EnableWebMvc @Configuration @Import({TracingBeansConfiguration.class}) public class SpringMVCConfiguration extends WebMvcConfigurerAdapter implements ServletContextListener { ​    @Autowired    private List spanDecorators; ​    @Autowired    private Tracer tracer;     ​    @Override    public void addInterceptors(InterceptorRegistry registry) {        GlobalTracer.register(tracer);        registry.addInterceptor(new TracingHandlerInterceptor(tracer, spanDecorators));   } ​ ​    @Bean    public RestTemplate restTemplate(Tracer tracer) {        RestTemplate restTemplate = new RestTemplate();        restTemplate.setInterceptors(Collections.singletonList(                new TracingRestTemplateInterceptor(tracer)));        return restTemplate;   } ​    @Override    public void contextInitialized(ServletContextEvent sce) {        sce.getServletContext().setAttribute(TracingFilter.SPAN_DECORATORS,                Collections.singletonList(ServletFilterSpanDecorator.STANDARD_TAGS));   } ​    @Override    public void contextDestroyed(ServletContextEvent sce) {  
  } }

这段代码:implements ServletContextListener

所以我们需要在web.xml里面讲这个listener 配置进去

     com.xxx.ecm.platform.gw.server.trace.SpringMVCConfiguration  

同事,我们看到里面 引入了这个类:@Import({TracingBeansConfiguration.class})

TracingBeansConfiguration代码如下:

@org.springframework.context.annotation.Configuration public class TracingBeansConfiguration { ​ @Value("${trace.app.name}") private String traceAppName; ​ @Bean    public Tracer jaegerTracer() {    com.uber.jaeger.Configuration.SenderConfiguration senderConfiguration = new com.uber.jaeger.Configuration.SenderConfiguration();    com.uber.jaeger.Configuration.ReporterConfiguration reporterConfiguration = new com.uber.jaeger.Configuration.ReporterConfiguration().withSender(senderConfiguration).withLogSpans(false).withMaxQueueSize(1000).withFlushInterval(100);    com.uber.jaeger.Configuration.SamplerConfiguration samplerConfiguration = new com.uber.jaeger.Configuration.SamplerConfiguration().withType(ConstSampler.TYPE).withParam(1);    com.uber.jaeger.Configuration configuration = new com.uber.jaeger.Configuration(traceAppName).withReporter(reporterConfiguration).withSampler(samplerConfiguration);    return configuration.getTracer(); } ​ @Bean public List spanDecorators() { return Arrays.asList(HandlerInterceptorSpanDecorator.STANDARD_LOGS, HandlerInterceptorSpanDecorator.HANDLER_METHOD_OPERATION_NAME); }

此class的作用就是初始化两个bean,Tracer bean和HandlerInterceptorSpanDecorator bean,以供SpringMVCConfiguration使用,

其中Tracer bean作用和配置和我们使用spring boot相同,详细配置请参考前文。

另外还需要把tracing filter 配置到配置文件:

  <filter>
    <filter-name>tracingFilter</filter-name>
    <filter-class>io.opentracing.contrib.web.servlet.filter.TracingFilter</filter-class>
    <async-supported>true</async-supported>
  </filter>
  <filter-mapping>
    <filter-name>tracingFilter</filter-name>
    <url-pattern>/\*</url-pattern>
  </filter-mapping>

OK!你已经在springmvc配置好你的系统了!(spring-web版本要4.3.8.RELEASE以上)

端口号说明

我们从前文中可以看到,我们安装jaeger各个组件的时候使用了很多端口号,具体这些端口号都是些什么作用呢?

下面将一一列举其作用:

elasticsearch暴露如下端口

端口号

协议

功能

9200

HTTP

通过http协议连接es使用的端口

9300

TCP

通过tcp协议连接es使用的端口

agent 暴露如下端口

端口号

协议

功能

5775

UDP

通过兼容性 thrift 协议,接收 zipkin thrift 类型的数据

6831

UDP

通过二进制 thrift 协议,接收 jaeger thrift 类型的数据

6832

UDP

通过二进制 thrift 协议,接收 jaeger thrift 类型的数据

5778

HTTP

可用于配置采样策略

collector 暴露如下端口

端口号

协议

功能

14267

TChannel

用于接收 jaeger-agent 发送来的 jaeger.thrift 格式的 span

14268

HTTP

能直接接收来自客户端的 jaeger.thrift 格式的 span

9411

HTTP

能通过 JSON 或 Thrift 接收 Zipkin spans,默认关闭

query 暴露如下端口

端口号

协议

功能

16686

HTTP

1. /api/* - API 端口路径 2. / - Jaeger UI 路径

jaeger dependencies

完成安装jaeger以后,你应该可以在jaeger ui上看到效果了,你可以采集到对应的数据,并且能够查询到调用链路。但是你会发现search按钮旁边,还有一个dependencies选项,你点开确什么也没有。

此时你还需要安装jaeger dependencies了,而且他需要定时执行,因为jaeger dependencies是在执行时去捞取对应的数据。

你可以定时执行以下代码:

STORAGE=elasticsearch ES_NODES=http://localhost:9200 java -jar jaeger-spark-dependencies.jar

ES_NODES为前面安装的es地址

jaeger-spark-dependencies.jar 怎么来的?

你可以搜索对应的资料下载,但是建议你下载官方源码,自己打包,github地址如下:

https://github.com/jaegertracing/spark-dependencies

下载源码执行mvn clean install -DskipTests打包,或许你可以crontab定时执行脚本,来跑每天的数据

另外,你也可以使用docker执行:

 docker run  --rm  --name  spark-dependencies  --env STORAGE=elasticsearch --env ES_NODES=http://localhost:9200 jaegertracing/spark-dependencies

ES_NODES为前面安装的es地址

当然,至于docker怎么执行定时任务,或者Kubernetes怎么执行CronJob,你可以自行研究dokcer或Kubernetes相关的知识。当然,你可以crontab定时执行脚本。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Stella981 Stella981
3年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
为什么mysql不推荐使用雪花ID作为主键
作者:毛辰飞背景在mysql中设计表的时候,mysql官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯一),而是推荐连续自增的主键id,官方的推荐是auto_increment,那么为什么不建议采用uuid,使用uuid究
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这