-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.html
1346 lines (506 loc) · 51.3 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<html class="theme-next pisces use-motion" lang="zh-CN">
<head>
<meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2"/>
<meta name="theme-color" content="#222">
<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />
<meta name="google-site-verification" content="65D1eihzztOzjS1twny-PiRjuyHeC82caCdMevIHWOg" />
<link href="/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css" />
<link href="/css/main.css?v=6.3.0" rel="stylesheet" type="text/css" />
<link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png?v=6.3.0">
<link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png?v=6.3.0">
<link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png?v=6.3.0">
<link rel="mask-icon" href="/images/logo.svg?v=6.3.0" color="#222">
<script type="text/javascript" id="hexo.configurations">
var NexT = window.NexT || {};
var CONFIG = {
root: '/',
scheme: 'Pisces',
version: '6.3.0',
sidebar: {"position":"left","display":"post","offset":12,"b2t":false,"scrollpercent":false,"onmobile":false},
fancybox: false,
fastclick: false,
lazyload: false,
tabs: true,
motion: {"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},
algolia: {
applicationID: '',
apiKey: '',
indexName: '',
hits: {"per_page":10},
labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
}
};
</script>
<meta name="description" content="记录一些编程点滴">
<meta name="keywords" content="PHP,Python,MySQL,JavaScript,HTML5,Lua">
<meta property="og:type" content="website">
<meta property="og:title" content="刘勇的平凡之路">
<meta property="og:url" content="http://ayonliu.github.io/index.html">
<meta property="og:site_name" content="刘勇的平凡之路">
<meta property="og:description" content="记录一些编程点滴">
<meta property="og:locale" content="zh-CN">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="刘勇的平凡之路">
<meta name="twitter:description" content="记录一些编程点滴">
<link rel="canonical" href="http://ayonliu.github.io/"/>
<script type="text/javascript" id="page.configurations">
CONFIG.page = {
sidebar: "",
};
</script>
<title>刘勇的平凡之路</title>
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-122568303-1"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-122568303-1');
</script>
<noscript>
<style type="text/css">
.use-motion .motion-element,
.use-motion .brand,
.use-motion .menu-item,
.sidebar-inner,
.use-motion .post-block,
.use-motion .pagination,
.use-motion .comments,
.use-motion .post-header,
.use-motion .post-body,
.use-motion .collection-title { opacity: initial; }
.use-motion .logo,
.use-motion .site-title,
.use-motion .site-subtitle {
opacity: initial;
top: initial;
}
.use-motion {
.logo-line-before i { left: initial; }
.logo-line-after i { right: initial; }
}
</style>
</noscript>
</head>
<body itemscope itemtype="http://schema.org/WebPage" lang="zh-CN">
<div class="container sidebar-position-left
page-home">
<div class="headband"></div>
<header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
<div class="header-inner"><div class="site-brand-wrapper">
<div class="site-meta ">
<div class="custom-logo-site-title">
<a href="/" class="brand" rel="start">
<span class="logo-line-before"><i></i></span>
<span class="site-title">刘勇的平凡之路</span>
<span class="logo-line-after"><i></i></span>
</a>
</div>
<p class="site-subtitle">不积跬步无以至千里</p>
</div>
<div class="site-nav-toggle">
<button aria-label="切换导航栏">
<span class="btn-bar"></span>
<span class="btn-bar"></span>
<span class="btn-bar"></span>
</button>
</div>
</div>
<nav class="site-nav">
<ul id="menu" class="menu">
<li class="menu-item menu-item-home menu-item-active">
<a href="/" rel="section">
<i class="menu-item-icon fa fa-fw fa-home"></i> <br />首页</a>
</li>
<li class="menu-item menu-item-about">
<a href="/about/" rel="section">
<i class="menu-item-icon fa fa-fw fa-user"></i> <br />关于</a>
</li>
<li class="menu-item menu-item-tags">
<a href="/tags/" rel="section">
<i class="menu-item-icon fa fa-fw fa-tags"></i> <br />标签</a>
</li>
<li class="menu-item menu-item-categories">
<a href="/categories/" rel="section">
<i class="menu-item-icon fa fa-fw fa-th"></i> <br />分类</a>
</li>
<li class="menu-item menu-item-archives">
<a href="/archives/" rel="section">
<i class="menu-item-icon fa fa-fw fa-archive"></i> <br />归档</a>
</li>
<li class="menu-item menu-item-sitemap">
<a href="/sitemap.xml" rel="section">
<i class="menu-item-icon fa fa-fw fa-sitemap"></i> <br />站点地图</a>
</li>
</ul>
</nav>
</div>
</header>
<main id="main" class="main">
<div class="main-inner">
<div class="content-wrap">
<div id="content" class="content">
<section id="posts" class="posts-expand">
<article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
<div class="post-block">
<link itemprop="mainEntityOfPage" href="http://ayonliu.github.io/profiling-php-code-with-xhprof/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="name" content="William Liu">
<meta itemprop="description" content="记录一些编程点滴">
<meta itemprop="image" content="https://s.gravatar.com/avatar/95673ef5d3710a6664b1ac1e28c2620b?s=80">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="刘勇的平凡之路">
</span>
<header class="post-header">
<h1 class="post-title" itemprop="name headline">
<a class="post-title-link" href="/profiling-php-code-with-xhprof/" itemprop="url">
利用 XHProf 对 PHP 代码进行性能分析
</a>
</h1>
<div class="post-meta">
<span class="post-time">
<span class="post-meta-item-icon">
<i class="fa fa-calendar-o"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="创建时间:2018-11-23 19:38:15 / 修改时间:21:16:01" itemprop="dateCreated datePublished" datetime="2018-11-23T19:38:15+08:00">2018-11-23</time>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<p>遇到程序执行速度慢的情况,除了看服务器系统状态、mysql slow log外,还可以对代码进行性能分析来定位问题。最简单常用的办法是代码不同的地方记录日志来分析程序各个节点的执行时间。<a href="http://pecl.php.net/package/xhprof" target="_blank" rel="noopener">XHProf</a>可以高效地对php代码进行性能分析。</p>
<h2 id="介绍"><a href="#介绍" class="headerlink" title="介绍"></a>介绍</h2><p>XHProf 是一个轻量级的分层性能测量分析器的PHP扩展。 可以跟踪调用次数、运行时间、CPU 计算时间和内存开销,展示程序动态调用的路径。XHProf 提供一个基于 HTML 的简单用户界面来展示分析数据,也支持图片的形式查看调用路径。</p>
<h2 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h2><p>Centos</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pecl install xhprof</span><br></pre></td></tr></table></figure>
<p>这是会报如下错误:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">Failed to download pecl/xhprof within preferred state “stable”, </span><br><span class="line">latest release is version 0.9.4, stability “beta”, </span><br><span class="line">use “channel://pecl.php.net/xhprof-0.9.4” to install</span><br></pre></td></tr></table></figure></p>
<p>因为 xhprof 是 beta 版本,不是 stable 版,要用下面命令安装:<br><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pecl install channel://pecl.php.net/xhprof-0.9.4</span><br></pre></td></tr></table></figure></p>
<p>为了后面可以用图片的形式展示,需要安装 graphviz:<br><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">yum install graphviz # 支持图形化展示结果</span><br></pre></td></tr></table></figure></p>
<p>在 php.ini 中加载扩展,配置生成 profile 数据的存放目录:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">extension=xhprof.so</span><br><span class="line">xhprof.output_dir=生成数据的存放目录</span><br></pre></td></tr></table></figure>
<p>要通过 web 形式查看分析结果,需要<a href="http://pecl.php.net/get/xhprof-0.9.4.tgz" target="_blank" rel="noopener">下载xhprof源码</a>(里面包括图形化展示分析结果所需的代码和相关类库)放到 web 可以访问到的目录。xhprof 目录结构如下所示:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">bin</span><br><span class="line">CHANGELOG</span><br><span class="line">CREDITS</span><br><span class="line">examples</span><br><span class="line">extension</span><br><span class="line">LICENSE</span><br><span class="line">package.xml</span><br><span class="line">README</span><br><span class="line">scripts</span><br><span class="line">support</span><br><span class="line">xhprof_html</span><br><span class="line">xhprof_lib</span><br></pre></td></tr></table></figure>
<h2 id="使用"><a href="#使用" class="headerlink" title="使用"></a>使用</h2><p>以一段简单的代码举例:<br><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta"><?php</span></span><br><span class="line"><span class="keyword">include</span>(realpath(dirname(<span class="keyword">__FILE__</span>).<span class="string">"/vendor/autoload.php"</span>));</span><br><span class="line"></span><br><span class="line"><span class="comment">// 在开始分析的地方加上 xhprof_enable() 方法</span></span><br><span class="line"><span class="comment">// XHPROF_FLAGS_NO_BUILTINS 表示不分析 PHP内置函数</span></span><br><span class="line">xhprof_enable(XHPROF_FLAGS_NO_BUILTINS);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// 需要分析的代码开始</span></span><br><span class="line"><span class="comment">// 具体逻辑不用关心</span></span><br><span class="line"><span class="keyword">use</span> <span class="title">Simplelog</span>\<span class="title">Simplelog</span>;</span><br><span class="line"></span><br><span class="line">$logFile = <span class="string">"/tmp/simple.log"</span>;</span><br><span class="line">$log = <span class="keyword">new</span> Simplelog($logFile);</span><br><span class="line">$log->debug(<span class="string">'skimlinks'</span>, <span class="keyword">array</span>(<span class="string">'affid'</span>=><span class="string">'223'</span>));</span><br><span class="line"><span class="comment">// 需要分析的代码结束</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 结束分析</span></span><br><span class="line"><span class="comment">// 分析结果存在数组 $xhprof_data 里</span></span><br><span class="line">$xhprof_data = xhprof_disable();</span><br><span class="line"></span><br><span class="line"><span class="comment">// 将分析结果存到 php.ini 中配置的 xhprof.output_dir 目录中</span></span><br><span class="line"><span class="comment">// 下面代码可以封装,这里只做简单演示用</span></span><br><span class="line"><span class="comment">// xhprof/xhprof_lib/ 是下载源码中的 xhprof_lib,即上图标2的文件夹</span></span><br><span class="line"><span class="keyword">include_once</span> <span class="string">"xhprof/xhprof_lib/utils/xhprof_lib.php"</span>;</span><br><span class="line"><span class="keyword">include_once</span> <span class="string">"xhprof/xhprof_lib/utils/xhprof_runs.php"</span>;</span><br><span class="line"></span><br><span class="line">$xhprof_runs = <span class="keyword">new</span> XHProfRuns_Default();</span><br><span class="line"></span><br><span class="line"><span class="comment">// "xhprof_foo" 是命名空间,可自定义.</span></span><br><span class="line"><span class="comment">// run_id 生成的唯一id,供下面通过 url 的形式访问查看</span></span><br><span class="line">$run_id = $xhprof_runs->save_run($xhprof_data, <span class="string">"xhprof_foo"</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// xhprof/xhprof_html/ 是下载源码中的 xhprof_html,即上图标1的文件夹</span></span><br><span class="line"><span class="comment">// xhprof_html 须放到 web 可以访问到的目录</span></span><br><span class="line"><span class="comment">// link 为可以查看分析结果的地址</span></span><br><span class="line">$link = <span class="string">"http://yourdomain.com/xhprof_html/index.php?run=$run_id&source=xhprof_foo"</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">echo</span> <span class="string">"<a href='{$link}' target='_blank'>{$link}</a>"</span>;</span><br></pre></td></tr></table></figure></p>
<h2 id="结果分析"><a href="#结果分析" class="headerlink" title="结果分析"></a>结果分析</h2><p>上一步中生成的分析结果,可以通过下面地址查看:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">http://yourdomain.com/xhprof_html/index.php?run=5be28a5486b02&source=xhprof_foo</span><br></pre></td></tr></table></figure></p>
<p>通过上面地址,可以看到类似下面的列表展示,可以从不同的维度来看各方法的性能:执行时长,CPU占用等信息<br><img src="https://raw.githubusercontent.com/ayonliu/exercise/master/images/xhprof_report.png" alt="xhprof report list"></p>
<h3 id="主要参数说明"><a href="#主要参数说明" class="headerlink" title="主要参数说明"></a>主要参数说明</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">Calls 调用次数</span><br><span class="line">Calls% 调用百分比</span><br><span class="line">Incl. Wall Time 调用的包括子函数所有花费时间,以微秒算</span><br><span class="line">IWall% 调用的包括子函数所有花费时间的百分比</span><br><span class="line">Excl. Wall Time 函数执行本身花费的时间,不包括子树执行时间,以微秒算</span><br><span class="line">EWall% 函数执行本身花费的时间的百分比不包括子树执行时间</span><br><span class="line">Incl. CPU(microsecs) 方法执行花费的CPU时间,包括子方法的执行时间</span><br><span class="line">ICPU% 方法执行花费的CPU时间百分比</span><br><span class="line">Excl. CPU(microsec) 方法本身执行花费的CPU时间,不包括子方法的执行时间</span><br><span class="line">ECPU% 方法本身执行花费的CPU时间百分比</span><br><span class="line">Incl.MemUse(bytes) 方法执行占用的内存,包括子方法执行占用的内存。(单位:字节)</span><br><span class="line">IMemUse% 方法执行占用的内存百分比。</span><br><span class="line">Excl.MemUse(bytes) 方法本身执行占用的内存,不包括子方法执行占用的内存。(单位:字节)</span><br><span class="line">EMemUse% 方法本身执行占用的内存百分比。</span><br></pre></td></tr></table></figure>
<h2 id="图片展示"><a href="#图片展示" class="headerlink" title="图片展示"></a>图片展示</h2><p>点击上面列表展示中的“View Full Callgraph”,就可以跳转到下图的的图片展示的界面。<br>通过下图可以看到各方法的调用路径以及执行所花费的时间,红色块是执行时间最长的,黄色块是其次。这样就能快速找到对性能影响较大的节点,然后到相应的节点里分析到底是代码还是 mysql 的问题就很方便了。</p>
<p><img src="https://raw.githubusercontent.com/ayonliu/exercise/master/images/xhprof_graph.png" alt="xhprof report graph"></p>
<p>参考:<br><a href="http://pecl.php.net/package/xhprof" target="_blank" rel="noopener">XHProf</a><br><a href="http://php.net/manual/zh/book.xhprof.php" target="_blank" rel="noopener">层次式性能分析器</a><br><a href="https://www.kam24.ru/xhprof/docs/index.html#ui_setup" target="_blank" rel="noopener">https://www.kam24.ru/xhprof/docs/index.html#ui_setup</a></p>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</div>
</article>
<article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
<div class="post-block">
<link itemprop="mainEntityOfPage" href="http://ayonliu.github.io/start-google-ads-api-with-test-accounts/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="name" content="William Liu">
<meta itemprop="description" content="记录一些编程点滴">
<meta itemprop="image" content="https://s.gravatar.com/avatar/95673ef5d3710a6664b1ac1e28c2620b?s=80">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="刘勇的平凡之路">
</span>
<header class="post-header">
<h1 class="post-title" itemprop="name headline">
<a class="post-title-link" href="/start-google-ads-api-with-test-accounts/" itemprop="url">
用测试账户调试Google Ads API
</a>
</h1>
<div class="post-meta">
<span class="post-time">
<span class="post-meta-item-icon">
<i class="fa fa-calendar-o"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="创建时间:2018-09-14 10:50:58" itemprop="dateCreated datePublished" datetime="2018-09-14T10:50:58+08:00">2018-09-14</time>
<span class="post-meta-divider">|</span>
<span class="post-meta-item-icon">
<i class="fa fa-calendar-check-o"></i>
</span>
<span class="post-meta-item-text">更新于</span>
<time title="修改时间:2018-09-16 21:51:30" itemprop="dateModified" datetime="2018-09-16T21:51:30+08:00">2018-09-16</time>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h2 id="申请生产经理账号和开发者令牌"><a href="#申请生产经理账号和开发者令牌" class="headerlink" title="申请生产经理账号和开发者令牌"></a>申请生产经理账号和开发者令牌</h2><p>申请生产经理账号(production manager account)后可以申请生产经理开发者令牌(后面称 Developer Token),Developer Token 会让 AdWords API 识别你的应用。只有经过批准的令牌才能连接到生产 AdWords 帐号的 API;待处理令牌只能连接到测试帐号。一旦 Developer Token 获得批准,就可以将同一令牌用于针对所有 AdWords 帐号的请求,即使它们未关联到与此开发者令牌相关联的经理帐号,也就是说 Developer Token 不仅可以在正式环境中使用,也可以在测试环境中使用。</p>
<ol>
<li><a href="https://ads.google.com/home/tools/manager-accounts/" target="_blank" rel="noopener">创建生产经理帐号</a></li>
<li>[在生产经理帐号中请求开发者令牌(production manager developer token)]<br>注册 AdWords API 时,系统会自动生成一个开发者令牌。提出申请后,令牌立刻进入待审批状态。在令牌获得批准后,可以指定在生产环境中使用的目标 AdWords 帐号。<br>(<a href="https://developers.google.com/adwords/api/docs/guides/signup" target="_blank" rel="noopener">https://developers.google.com/adwords/api/docs/guides/signup</a>)</li>
</ol>
<p>请求成功后在 TOOLS -> API Center 中可以看到相应的 Developer Token。<br><img src="https://raw.githubusercontent.com/ayonliu/exercise/master/images/product-manager-account.png" alt="Developer Token"></p>
<p><strong>可以使用开发者令牌来指定任何目标 AdWords 帐号,因此,只需使用目标帐号(或其某一个经理帐号,包括测试账号)的 OAuth2 凭据来授权你的请求即可(<a href="#测试经理帐号(test-manager-account)">见下文</a>)。</strong></p>
<p>在下面的流程中,对测试经理帐号发出请求时,就会使用到这里的生产经理帐号开发者令牌。</p>
<h2 id="测试经理帐号(test-manager-account)"><a href="#测试经理帐号(test-manager-account)" class="headerlink" title="测试经理帐号(test manager account)"></a>测试经理帐号(test manager account)</h2><ul>
<li><a href="https://adwords.google.com/um/Welcome/?sf=mt" target="_blank" rel="noopener">申请测试经理帐号</a><br>测试经理帐号申请成功,登录后可以看到一个红色的标签 Test account,说明是测试经理帐号,如果没有在 AdWords 帐号页上看到红色的“Test account”标签,那么该帐号是一个生产帐号。<br><img src="https://raw.githubusercontent.com/ayonliu/exercise/master/images/test-manager-account.png" alt="test account"></li>
</ul>
<h2 id="申请测试客户账号(test-client-account)"><a href="#申请测试客户账号(test-client-account)" class="headerlink" title="申请测试客户账号(test client account)"></a>申请测试客户账号(test client account)</h2><p>测试经理帐号申请成功后才能进行这一步。</p>
<ol>
<li>使用 AdWords 网页界面,在之前创建的测试经理帐号下创建测试客户帐号。当您以测试经理帐号登录 AdWords 时,您创建的所有客户帐号都将自动成为测试帐号。<br><img src="https://raw.githubusercontent.com/ayonliu/exercise/master/images/creat-test-client-account.png" alt="create test client account"></li>
<li>记下新测试客户帐号的客户 ID (Client Customer ID)并保存:稍后您需要将其添加到配置文件中。客户帐号的 Client Customer ID 如下所示:<br><img src="https://raw.githubusercontent.com/ayonliu/exercise/master/images/test-client-customer-id.png" alt="client customer ID"></li>
<li>使用 AdWords 网页界面,在测试客户帐号下创建几个测试广告系列(test campaigns),比如我这里创建一个名为“test1”的 campaign,生成的 id 为1557850521(后面会用到)。</li>
</ol>
<h2 id="设置-OAuth2-身份验证,将-OAuth2-与测试帐号配合使用"><a href="#设置-OAuth2-身份验证,将-OAuth2-与测试帐号配合使用" class="headerlink" title="设置 OAuth2 身份验证,将 OAuth2 与测试帐号配合使用"></a>设置 OAuth2 身份验证,将 OAuth2 与测试帐号配合使用</h2><p>应用必须先获取授予 API 访问权限的 OAuth2 访问令牌,才可以使用 API 访问非公开数据。通过 OAuth2 进行身份验证后可让应用代表你的帐号进行各种操作。要使用 OAuth2 访问测试帐号,测试经理帐号用户必须向客户端应用授予权限。授权后,应用就可以用授权账户提供的 OAuth2 客户端 ID (Client ID)和客户端密钥(Client Secret)来访问 API。</p>
<h3 id="生成-OAuth2-凭据(Credentials)"><a href="#生成-OAuth2-凭据(Credentials)" class="headerlink" title="生成 OAuth2 凭据(Credentials)"></a>生成 OAuth2 凭据(Credentials)</h3><ol>
<li>使用经理帐号凭据登录后,打开 <a href="https://console.developers.google.com/apis/credentials" target="_blank" rel="noopener">Google API 控制台凭据页面</a>。</li>
<li>从项目下拉菜单中,选择 <strong>新建项目</strong>,输入项目的名称,然后点击 <strong>创建</strong>。</li>
<li>选择 <strong>创建凭据</strong>,然后选择 <strong>OAuth 客户端 ID</strong>。</li>
<li>点击 <strong>配置同意屏幕(Configure consent screen)</strong>,提供要求的信息,然后点击 <strong>保存</strong> 以返回到<strong>凭据(Credentials)</strong>屏幕。</li>
<li>在<strong>应用类型</strong>下,选择<strong>其他</strong>。在提供的空间中输入名称。</li>
<li>点击<strong>创建</strong>。系统会显示 OAuth2 客户端 ID (Client ID)和客户端密钥(Client Secret)。复制并保存这些信息。在下一步中将它们添加到配置文件中。<br><img src="https://raw.githubusercontent.com/ayonliu/exercise/master/images/oauth2-client-id-secret.png" alt="oauth2 client id & client secret"></li>
</ol>
<h3 id="获取-OAuth2-刷新令牌(Refresh-token)"><a href="#获取-OAuth2-刷新令牌(Refresh-token)" class="headerlink" title="获取 OAuth2 刷新令牌(Refresh token)"></a>获取 OAuth2 刷新令牌(Refresh token)</h3><p>由于 OAuth2 访问权限会在限定时间后过期,因此使用 OAuth2 刷新令牌来自动更新 OAuth2 访问权限。当请求 OAuth2 刷新令牌时,请确保您以测试经理帐号用户身份登录,以获取测试经理帐号对应的 OAuth2 客户端 ID (client ID)和客户端密钥(client secret)。在针对测试经理帐号提出请求时需要使用生产经理帐号的<a href="#申请生产经理账号和开发者令牌">开发者令牌</a>。</p>
<ol>
<li><p>调用刷新令牌脚本,这里我用<a href="https://github.com/googleads/googleads-python-lib/blob/master/examples/adwords/authentication/generate_refresh_token.py" target="_blank" rel="noopener">Python版</a>的。 修改 generate_refresh_token.py 文件,把其中的 DEFAULT_CLIENT_ID,DEFAULT_CLIENT_SECRET 修改为<a href="#生成-OAuth2-凭据(Credentials)">上面</a>刚刚创建好的 Client ID 和 Client Secret:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">...</span><br><span class="line"># Your OAuth2 Client ID and Secret. If you do not have an ID and Secret yet,</span><br><span class="line"># please go to https://console.developers.google.com and create a set.</span><br><span class="line">DEFAULT_CLIENT_ID = 'Your client id here'</span><br><span class="line">DEFAULT_CLIENT_SECRET = 'Your client secret here'</span><br><span class="line">...</span><br></pre></td></tr></table></figure>
</li>
<li><p>执行:<code>python generate_refresh_token.py</code></p>
</li>
<li>按照提示复制生成的 url 到浏览器,在到达的页面中用<a href="#测试经理帐号(test-manager-account)">测试经理帐号</a>对应的账号登录, 下一步点击“允许”,会出现下图:<br><img src="https://raw.githubusercontent.com/ayonliu/exercise/master/images/access_code.png" alt="access code"></li>
<li>复制下图中的 code 粘贴到步骤2执行的命令行<br><img src="https://raw.githubusercontent.com/ayonliu/exercise/master/images/refresh_token.png" alt="refresh token"></li>
<li>记录下上步中的 Refresh Token。</li>
</ol>
<p>生产环境中,从测试经理帐号切换到生产经理帐号,需要用生产经理帐号相关的 Client ID 和 Client Secret 来请求生产经理帐号的刷新令牌。</p>
<h2 id="测试-ads-API-功能"><a href="#测试-ads-API-功能" class="headerlink" title="测试 ads API 功能"></a>测试 ads API 功能</h2><p>上面的步骤里我们已经准备好了调用 API 需要的必要配置:Developer Token, Client Customer ID, Client ID, Client Secret, Refresh Token。下面测试一个 API 调用:</p>
<ol>
<li>选择自己熟悉语言的<a href="https://developers.google.com/adwords/api/docs/clientlibraries" target="_blank" rel="noopener">客户端库</a>,这里用Python。</li>
<li><p>配置文件(googleads.yaml)中填写正确的配置信息:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"># AdWordsClient configurations</span><br><span class="line">adwords:</span><br><span class="line"> developer_token: Developer Token</span><br><span class="line"> client_customer_id: Client Customer ID</span><br><span class="line"> client_id: Client ID</span><br><span class="line"> client_secret: Client Secret</span><br><span class="line"> refresh_token: Refresh Token</span><br></pre></td></tr></table></figure>
</li>
<li><p>测试 <a href="https://github.com/googleads/googleads-python-lib/blob/master/examples/adwords/v201806/basic_operations/add_ad_groups.py" target="_blank" rel="noopener">ad groups</a> 功能:</p>
<ul>
<li><p>修改 add_ad_groups.py :</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">...</span><br><span class="line">CAMPAIGN_ID = 1557850521 # 上面创建测试客户帐号后添加的 campaign</span><br><span class="line">...</span><br><span class="line">if __name__ == '__main__':</span><br><span class="line"> # Initialize client object.</span><br><span class="line"> adwords_client = adwords.AdWordsClient.LoadFromStorage('你的 googleads.yaml 存放位置')</span><br><span class="line"></span><br><span class="line"> main(adwords_client, CAMPAIGN_ID)</span><br><span class="line"></span><br><span class="line">...</span><br></pre></td></tr></table></figure>
</li>
<li><p>命令行执行:<code>python add_ad_groups.py</code></p>
</li>
</ul>
</li>
<li>执行后到测试客户账号下查看对应的 campaign 下的 ad groups 如下所示:<br><img src="https://raw.githubusercontent.com/ayonliu/exercise/master/images/test-ad-groups.png" alt="test-ad-groups"></li>
</ol>
<h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><ul>
<li><a href="https://developers.google.com/adwords/api/docs/guides/accounts-overview#test_accounts" target="_blank" rel="noopener">管理帐号</a></li>
<li><a href="https://developers.google.com/adwords/api/docs/guides/authentication#generate_oauth2_credentials" target="_blank" rel="noopener">OAuth2 身份验证</a></li>
<li><a href="https://developers.google.com/adwords/api/docs/guides/first-api-call" target="_blank" rel="noopener">进行首次 API 调用</a></li>
<li><a href="https://developers.google.com/adwords/api/docs/guides/call-structure" target="_blank" rel="noopener">API 典型使用案例</a></li>
</ul>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</div>
</article>
<article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
<div class="post-block">
<link itemprop="mainEntityOfPage" href="http://ayonliu.github.io/some-approaches-to-crawl/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="name" content="William Liu">
<meta itemprop="description" content="记录一些编程点滴">
<meta itemprop="image" content="https://s.gravatar.com/avatar/95673ef5d3710a6664b1ac1e28c2620b?s=80">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="刘勇的平凡之路">
</span>
<header class="post-header">
<h1 class="post-title" itemprop="name headline">
<a class="post-title-link" href="/some-approaches-to-crawl/" itemprop="url">
抓取网页内容(爬虫)一些方法介绍
</a>
</h1>
<div class="post-meta">
<span class="post-time">
<span class="post-meta-item-icon">
<i class="fa fa-calendar-o"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="创建时间:2018-07-19 21:09:46" itemprop="dateCreated datePublished" datetime="2018-07-19T21:09:46+08:00">2018-07-19</time>
<span class="post-meta-divider">|</span>
<span class="post-meta-item-icon">
<i class="fa fa-calendar-check-o"></i>
</span>
<span class="post-meta-item-text">更新于</span>
<time title="修改时间:2018-09-07 20:58:41" itemprop="dateModified" datetime="2018-09-07T20:58:41+08:00">2018-09-07</time>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h2 id="抓取网页内容的一般流程"><a href="#抓取网页内容的一般流程" class="headerlink" title="抓取网页内容的一般流程"></a>抓取网页内容的一般流程</h2><ol>
<li>发HTTP请求</li>
<li>解析请求返回的结果</li>
<li>得到的结果持久化</li>
</ol>
<h2 id="常用的抓取网页内容的方法和工具"><a href="#常用的抓取网页内容的方法和工具" class="headerlink" title="常用的抓取网页内容的方法和工具"></a>常用的抓取网页内容的方法和工具</h2><h3 id="命令行"><a href="#命令行" class="headerlink" title="命令行"></a>命令行</h3><ul>
<li>cURL</li>
</ul>
<h3 id="PHP"><a href="#PHP" class="headerlink" title="PHP:"></a>PHP:</h3><ul>
<li>原生Client URL 库(cURL)</li>
<li>类库,比如:<a href="http://requests.ryanmccue.info/" target="_blank" rel="noopener">Requests</a>, <a href="http://guzzlephp.org/" target="_blank" rel="noopener">Guzzle</a></li>
<li>爬虫开发框架:<a href="https://doc.phpspider.org/" target="_blank" rel="noopener">phpspider</a></li>
</ul>
<h3 id="Python"><a href="#Python" class="headerlink" title="Python"></a>Python</h3><ul>
<li>类库,比如:<a href="http://docs.python-requests.org/" target="_blank" rel="noopener">Requests</a></li>
<li>爬虫开发框架:<a href="https://scrapy.org/" target="_blank" rel="noopener">Scrapy</a></li>
</ul>
<h3 id="NodeJS"><a href="#NodeJS" class="headerlink" title="NodeJS"></a>NodeJS</h3><ul>
<li><a href="https://www.npmjs.com/package/curl-request" target="_blank" rel="noopener">curl-request</a></li>
<li>爬虫开发框架:<a href="http://nodecrawler.org/" target="_blank" rel="noopener">node-crawler</a></li>
</ul>
<h2 id="可能遇到的问题和困难"><a href="#可能遇到的问题和困难" class="headerlink" title="可能遇到的问题和困难"></a>可能遇到的问题和困难</h2><ul>
<li>登录:保存Cookie, 认证</li>
<li>被屏蔽</li>
<li>验证码</li>
<li>执行JS</li>
<li>其他</li>
</ul>
<h2 id="另外一种思路"><a href="#另外一种思路" class="headerlink" title="另外一种思路"></a>另外一种思路</h2><p>利用界面自动化测试工具进行抓取,简单点讲就是:程序唤起浏览器后模拟用户行为进行操作<br>
<!--noindex-->
<div class="post-button text-center">
<a class="btn" href="/some-approaches-to-crawl/#more" rel="contents">
阅读全文 »
</a>
</div>
<!--/noindex-->
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</div>
</article>
<article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
<div class="post-block">
<link itemprop="mainEntityOfPage" href="http://ayonliu.github.io/myisam-partition-too-many-open-files/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="name" content="William Liu">
<meta itemprop="description" content="记录一些编程点滴">
<meta itemprop="image" content="https://s.gravatar.com/avatar/95673ef5d3710a6664b1ac1e28c2620b?s=80">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="刘勇的平凡之路">
</span>
<header class="post-header">
<h1 class="post-title" itemprop="name headline">
<a class="post-title-link" href="/myisam-partition-too-many-open-files/" itemprop="url">
MySQL MyISAM 分区(partition)导致打开文件过多
</a>
</h1>
<div class="post-meta">
<span class="post-time">
<span class="post-meta-item-icon">
<i class="fa fa-calendar-o"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="创建时间:2018-07-19 21:09:46" itemprop="dateCreated datePublished" datetime="2018-07-19T21:09:46+08:00">2018-07-19</time>
<span class="post-meta-divider">|</span>
<span class="post-meta-item-icon">
<i class="fa fa-calendar-check-o"></i>
</span>
<span class="post-meta-item-text">更新于</span>
<time title="修改时间:2018-09-11 19:21:01" itemprop="dateModified" datetime="2018-09-11T19:21:01+08:00">2018-09-11</time>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h2 id="问题表现"><a href="#问题表现" class="headerlink" title="问题表现"></a>问题表现</h2><p>最近公司一个业务环境的数据库,出现无法连接的情况,重启后过几个小时问题又出现。查看报错信息,如下所示:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Out of resources when opening file './xxx.MYD' (Errcode: 24 - Too many open files)</span><br></pre></td></tr></table></figure></p>
<p>问题很明显:打开文件过多,超过了配置的限制。</p>
<h2 id="问题分析"><a href="#问题分析" class="headerlink" title="问题分析"></a>问题分析</h2><p>查看 table_open_cache, open_files_limit 当前配置的值:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">mysql> show variables like <span class="string">'%open_%'</span>;</span><br><span class="line">+----------------------------+-------+</span><br><span class="line">| Variable_name | Value |</span><br><span class="line">+----------------------------+-------+</span><br><span class="line">| have_openssl | YES |</span><br><span class="line">| innodb_open_files | 2000 |</span><br><span class="line">| open_files_limit | 5000 |</span><br><span class="line">| table_open_cache | 2000 |</span><br><span class="line">| table_open_cache_instances | 16 |</span><br><span class="line">+----------------------------+-------+</span><br><span class="line">5 rows <span class="keyword">in</span> <span class="built_in">set</span> (0.01 sec)</span><br></pre></td></tr></table></figure></p>
<!--noindex-->
<div class="post-button text-center">
<a class="btn" href="/myisam-partition-too-many-open-files/#more" rel="contents">
阅读全文 »
</a>
</div>
<!--/noindex-->
</div>