This file is indexed.

/usr/share/doc/pgpool2/pgpool-zh_cn.html is in pgpool2 3.3.4-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

   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
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568
3569
3570
3571
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
3678
3679
3680
3681
3682
3683
3684
3685
3686
3687
3688
3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710
3711
3712
3713
3714
3715
3716
3717
3718
3719
3720
3721
3722
3723
3724
3725
3726
3727
3728
3729
3730
3731
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
3753
3754
3755
3756
3757
3758
3759
3760
3761
3762
3763
3764
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
3776
3777
3778
3779
3780
3781
3782
3783
3784
3785
3786
3787
3788
3789
3790
3791
3792
3793
3794
3795
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
3817
3818
3819
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829
3830
3831
3832
3833
3834
3835
3836
3837
3838
3839
3840
3841
3842
3843
3844
3845
3846
3847
3848
3849
3850
3851
3852
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
3916
3917
3918
3919
3920
3921
3922
3923
3924
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
3943
3944
3945
3946
3947
3948
3949
3950
3951
3952
3953
3954
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979
3980
3981
3982
3983
3984
3985
3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
4000
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016
4017
4018
4019
4020
4021
4022
4023
4024
4025
4026
4027
4028
4029
4030
4031
4032
4033
4034
4035
4036
4037
4038
4039
4040
4041
4042
4043
4044
4045
4046
4047
4048
4049
4050
4051
4052
4053
4054
4055
4056
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066
4067
4068
4069
4070
4071
4072
4073
4074
4075
4076
4077
4078
4079
4080
4081
4082
4083
4084
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095
4096
4097
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
4108
4109
4110
4111
4112
4113
4114
4115
4116
4117
4118
4119
4120
4121
4122
4123
4124
4125
4126
4127
4128
4129
4130
4131
4132
4133
4134
4135
4136
4137
4138
4139
4140
4141
4142
4143
4144
4145
4146
4147
4148
4149
4150
4151
4152
4153
4154
4155
4156
4157
4158
4159
4160
4161
4162
4163
4164
4165
4166
4167
4168
4169
4170
4171
4172
4173
4174
4175
4176
4177
4178
4179
4180
4181
4182
4183
4184
4185
4186
4187
4188
4189
4190
4191
4192
4193
4194
4195
4196
4197
4198
4199
4200
4201
4202
4203
4204
4205
4206
4207
4208
4209
4210
4211
4212
4213
4214
4215
4216
4217
4218
4219
4220
4221
4222
4223
4224
4225
4226
4227
4228
4229
4230
4231
4232
4233
4234
4235
4236
4237
4238
4239
4240
4241
4242
4243
4244
4245
4246
4247
4248
4249
4250
4251
4252
4253
4254
4255
4256
4257
4258
4259
4260
4261
4262
4263
4264
4265
4266
4267
4268
4269
4270
4271
4272
4273
4274
4275
4276
4277
4278
4279
4280
4281
4282
4283
4284
4285
4286
4287
4288
4289
4290
4291
4292
4293
4294
4295
4296
4297
4298
4299
4300
4301
4302
4303
4304
4305
4306
4307
4308
4309
4310
4311
4312
4313
4314
4315
4316
4317
4318
4319
4320
4321
4322
4323
4324
4325
4326
4327
4328
4329
4330
4331
4332
4333
4334
4335
4336
4337
4338
4339
4340
4341
4342
4343
4344
4345
4346
4347
4348
4349
4350
4351
4352
4353
4354
4355
4356
4357
4358
4359
4360
4361
4362
4363
4364
4365
4366
4367
4368
4369
4370
4371
4372
4373
4374
4375
4376
4377
4378
4379
4380
4381
4382
4383
4384
4385
4386
4387
4388
4389
4390
4391
4392
4393
4394
4395
4396
4397
4398
4399
4400
4401
4402
4403
4404
4405
4406
4407
4408
4409
4410
4411
4412
4413
4414
4415
4416
4417
4418
4419
4420
4421
4422
4423
4424
4425
4426
4427
4428
4429
4430
4431
4432
4433
4434
4435
4436
4437
4438
4439
4440
4441
4442
4443
4444
4445
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<link rel="stylesheet" href="./pgpool.css" type="text/css">
<title>pgpool-II 用户手册</title>
</head>

<!-- hhmts start -->
Last modified: Wed Jun 29 09:50:01 JST 2011
<!-- hhmts end -->

<body bgcolor="#ffffff">
<div id="top" class="header_text">欢迎使用 pgpool-II 手册</div>

<div id="menu">
	 <div id="navcontainer">
      <ul id="navlist">
        <li id="active"><a href="#Whatis" id="current">什么是 pgpool</a></li>
        <li><a href="#license">许可协议</a></li>
        <li><a href="#platform">支持的平台</a></li>
        <li><a href="#install">pgpool-II 的安装</a></li>
        <li><a href="#config">配置 pgpool-II</a></li>
        <li><a href="#common">配置通用部分</a></li>
        <li><a href="#connection_pool_mode">连接池模式</a></li>
        <li><a href="#replication_mode">复制模式</a></li>
        <li><a href="#master_slave_mode">主备模式</a></li>
        <li><a href="#stream">流复制</a></li>
        <li><a href="#parallel">并行模式</a></li>
        <li><a href="#hba">客户端认证</a></li>
        <li><a href="#query_cache">设置查询缓存方法</a></li>
        <li><a href="#memqcache">基于内存的查询缓存</a></li>
        <li><a href="#start">启动/停止 pgpool-II</a></li>
        <li><a href="#reload">重新加载 pgpool-II 配置文件</a></li>
        <li><a href="#show-commands">显示命令</a></li>
        <li><a href="#online-recovery">在线恢复</a></li>
        <li><a href="#backup">备份</a></li>
        <li><a href="#deploy">部署 pgpool-II</a></li>
        <li><a href="#watchdog">看门狗</a></li>
        <li><a href="#troubleshooting">故障排除</a></li>
        <li><a href="#restriction">限制</a></li>
        <li><a href="#reference">参考信息</a></li>
        <li><a href="#internal">内部信息</a></li>
      </ul>
    </div>
	 <br />

    <div class="header_small" align="center">
    [<a href="pgpool-en.html">英文页面</a>]
    </div>
</div>


<div id="manual">

<!-- ================================================================================ -->

<h1 style="margin-top: 20px">什么是 pgpool-II?<a name="whatis"></a></h1>

<p> pgpool-II 是一个位于 PostgreSQL 服务器和 PostgreSQL
数据库客户端之间的中间件,它提供以下功能:</p>

<p>
<ul>

<li>连接池</li>
    <p>pgpool-II 保持已经连接到 PostgreSQL 服务器的连接,
    	并在使用相同参数(例如:用户名,数据库,协议版本)
    	连接进来时重用它们。
    	它减少了连接开销,并增加了系统的总体吞吐量。</p>

<li>复制</li>
    <p>pgpool-II 可以管理多个 PostgreSQL 服务器。
    	激活复制功能并使在2台或者更多 PostgreSQL
    	节点中建立一个实时备份成为可能,
    	这样,如果其中一台节点失效,服务可以不被中断继续运行。</p>

<li>负载均衡</li>
    <p>如果数据库进行了复制(可能运行在复制模式或者主备模式下),
    	则在任何一台服务器中执行一个 SELECT 查询将返回相同的结果。
    	pgpool-II 利用了复制的功能以降低每台 PostgreSQL 服务器的负载。
    	它通过分发 SELECT 查询到所有可用的服务器中,增强了系统的整体吞吐量。
    	在理想的情况下,读性能应该和 PostgreSQL 服务器的数量成正比。
    	负载均很功能在有大量用户同时执行很多只读查询的场景中工作的效果最好。</p>

<li>限制超过限度的连接</li>
    <p>PostgreSQL 会限制当前的最大连接数,当到达这个数量时,新的连接将被拒绝。
    	增加这个最大连接数会增加资源消耗并且对系统的全局性能有一定的负面影响。
    	pgpoo-II 也支持限制最大连接数,但它的做法是将连接放入队列,而不是立即返回一个错误。</p>

<li>并行查询</li>
    <p>使用并行查询时,数据可以被分割到多台服务器上,
    	所以一个查询可以在多台服务器上同时执行,以减少总体执行时间。
    	并行查询在查询大规模数据的时候非常有效。</p>

</ul>
</p>

<p>pgpool-II 使用 PostgreSQL 的前后台程序之间的协议,并且在前后台之间传递消息。
	因此,一个(前端的)数据库应用程序认为 pgpool-II 就是实际的 PostgreSQL 数据库,
	而后端的服务进程则认为 pgpool-II 是它的一个客户端。
	因为 pgpool-II 对于服务器和客户端来说是透明的,
	现有的数据库应用程序基本上可以不需要修改就可以使用 pgpool-II 了。</p>

<p>
<strong>通过 pgpool-II 使用 SQL 有一些限制条件。参考 <a href="#restriction">限制</a> 获得详细信息。</strong>
</p>

<p class="top_link"><a href="#Top">返回顶部</a></p>

<!-- ================================================================================ -->

<h1>许可协议<a name="license"></a></h1>

<p>
版权所有 (c) 2003-2013 PgPool 全球开发小组

授权出于任何目的任意使用、拷贝、修改和分发本软件以及文档,
但必须在所有软件拷贝的支持文档中提供以上的版权信息,包括版权通知和许可,
并且在没有事先明确的书面授权前,作者的名字不能用于发布软件的广告和宣传。
作者不对本软件的任何用途负责。
本软件以“现状”来提供,不提供任何明文或暗示的保证。
</p>

<p class="top_link"><a href="#Top">back to top</a></p>

<!-- ================================================================================ -->

<h1>支持的平台<a name="platform"></a></h1>

<p>pgpool-II 可以运行在 Linux,Solaris,FreeBSD 以及基本上所有的类 UNIX 架构的平台上。
	不支持 Windows。支持 6.4 以上版本的 PostgreSQL 服务器。
	然而,如果要使用并行查询功能,需要 7.4 或更高版本。</p>

<p>如果你在使用 7.3 或者更老版本的 PostgreSQL,一些 pgpool-II 的功能将无法使用。
	但无论如何你不应该还在用这么老的版本了。</p>

<p>你还要确保你所有的 PostgreSQL 服务器运行相同主版本号的 PostgreSQL 程序。另外,如果你想要使用在线恢复,硬件架构和操作系统必须一致。
	另外,我们不推荐在使用不同编译参数编译的 PostgreSQL:包括是否支持 SSL,是否使用了 --disable-integer-datetimes 参数或者不同的块大小。
	这些可能对 pgpool-II 的部分功能有影响。
	通常情况下,小版本号不同没有什么影响。但是我们没有针对小版本的区别做全面测试,因此我们建议还是使用相同的版本的 PostgreSQL。</p>

<p class="top_link"><a href="#Top">返回顶部</a></p>

<!-- ================================================================================ -->

<h1>pgpool-II 的安装<a name="install"></a></h1>

<p>
pgpool-II 可以在 <a href="http://pgpool.net/">pgpool 开发页面</a>下载到。
而且也提供包括 CentOS,RedHat Enterprise Linux,Fedora 和 Debian 在内的大量平台的二进制包。
请检查相关的软件库。
</p>

<p>
可以在以下位置下载 pgpool-II 的源码:
<a href="http://pgpool.net/mediawiki/index.php/Downloads">pgpool 开发页面</a></p>

<p>从源码安装 pgpool-II 需要 2.9 甚至或更高版本的 gcc,以及 GNU make。
	而且,pgpool-II 需要链接到 libpq 库,所以在构建 pgpool-II 的机器上必须安装 libpq 库和它的开发头文件。
	另外,还需要 OpenSSL 库和它的头文件以便在 pgpool-II 中提供 OpenSSL 支持。</p>

<dl>
<dt>configure</dt>
    <dd>
    <p>在解压源码包后,执行以下配置脚本。</p>
<pre>
./configure
</pre>

    <p>如果你需要非默认的值,有以下选项可以设置:</p>
    <table border>
      <tr><th class="nodec"><code>--prefix=path</code></th>
      <td>pgpool-II 的二进制程序和文档将被安装到这个目录。默认值为 <code>/usr/local</code></td></tr>
      <tr><th class="nodec"><code>--with-pgsql=path</code></th>
      <td>PostgreSQL 的客户端库安装的顶层目录。默认值由 <code>pg_config</code> 提供</td></tr>
      <tr><th class="nodec"><code>--with-openssl</code></th>
      <td>pgpool-II 程序将提供 OpenSSL 支持。默认是禁用 OpenSSL 支持的。<span class="version">V2.3 -</span></td></tr>
      <tr><th class="nodec"><code>--enable-sequence-lock</code></th>
      <td>在 pgpool-II 3.0 系列中使用 insert_lock 兼容。pgpool-II 针对序列表中的一行进行加锁。PostgreSQL 8.2 或2011年六月以后发布的版本无法使用这种加锁方法。
          <span class="version">V3.1 -</span></td></tr>
      <tr><th class="nodec"><code>--enable-table-lock</code></th>
      <td>在 pgpool-II 2.2 和 2.3 系列中使用 insert_lock 兼容。pgpool-II 针对被插入的表进行加锁。这种锁因为和 VACUUM 冲突,已被废弃。<span class="version">V3.1 -</span></td></tr>
      <tr><th class="nodec"><code>--with-memcached=path</code></th>
      <td>pgpool-II 的二进制程序将使用 <a href="#memcached_params">memcached</a> 作为 <a href="#memqcache">基于内存的查询缓存</a>。你必须先安装 <a href="http://libmemcached.org/libMemcached.html">libmemcached</a><span class="version">V3.2 -</span></td>
      </tr>
      </table>
    </dd>

<dt>make</dt>
    <dd>
<pre>
make
make install
</pre>
    <p>
    这将安装 install pgpool-II. (如果你使用的是 Solaris 或 FreeBSD,需要用 gmake 替换 make )
    </p>
    </dd>

<dt>安装 pgpool_regclass <span class="version">V3.0 -</span></dt>
    <dd>
    <p>
    如果你在使用 PostgreSQL 8.0 或之后的版本,强烈推荐在需要访问的 PostgreSQL
    中安装 pgpool_regclass 函数,因为它被 pgpool-II 内部使用。
    如果不这样做,在不同的 schema 中处理相同的表名会出现问题(临时表不会出问题)。
    </p>
<pre>
cd pgpool-II-x.x.x/sql/pgpool-regclass
make
make install
</pre>
		</p>
		<p>
在这之后:
		<p>
<pre>
psql -f pgpool-regclass.sql template1
</pre>
		</p>
		<p>
或者
		<p>
<pre>
psql template1
CREATE EXTENSION pgpool_regclass;
</pre>
</p>
    <p>
    应在每台通过 pgpool-II 访问的数据库中执行 pgpool-regclass.sql 或者 CREATE EXTENSION。
    你不需要在你执行“psql -f pgpool-regclass.sql template1” 或者 CREATE EXTENSION 后建立的数据库中这么做,
    因为这个模板数据库将被克隆成新建的数据库。
    </p>
    </dd>
<dt>建立 insert_lock 表<span class="version">V3.0 -</span></dt>
    <dd>
    <p>
    如果你在复制模式中使用了 insert_lock ,强烈推荐建立 pgpool_catalog.insert_lock 表,用于互斥。
    到现在为止,insert_lock 还能够工作。但是,在这种情况下,pgpool-II 需要锁定插入的目标表。
    这种行为和 pgpool-II 2.2 和 2.3 系列类似。由于表锁与 VACUUM 冲突,所以 INSERT 操作可能因而等待很长时间。
    </p>
    
<pre>
cd pgpool-II-x.x.x/sql
psql -f insert_lock.sql template1
</pre>
    <p>
    应在在每台通过 pgpool-II 访问的数据库中执行 insert_lock.sql。
    你不需要在你执行“psql -f insert_lock.sql template1”后建立的数据库中这么做,
    因为这个模板数据库将被克隆成新建的数据库。
    </p>
    </dd>
</dl>

<p>
安装过程至此完成。如果你是使用 Solaris 或者 FreeBSD,
你需要在以上的描述中用 “gmake” 代替 “make”,因为这些操作系统需要 GNU make。
</p>

<p class="top_link"><a href="#Top">返回顶部</a></p>

<!-- ================================================================================ -->

<h1>配置 pgpool-II<a name="config"></a></h1>

<p>pgpool-II 的默认配置文件为 <code>/usr/local/etc/pgpool.conf</code><code>/usr/local/etc/pcp.conf</code>。pgpool-II 中有很多操作模式。
每种模式都有相关的可被开启或者禁用的功能,而且有相关的配置项用于控制它们的行为。</p>

<table border>

  <tr class="header">
    <th>功能/模式</th>
    <th>原始模式 (*3)</th>
    <th>复制模式</th>
    <th>主/备模式</th>
    <th>并行查询模式</th>
  </tr>

  <tr>
    <th>连接池</th>
    <td align="center">X</td>
    <td align="center">O</td>
    <td align="center">O</td>
    <td align="center">O</td>
  </tr>

  <tr>
    <th>复制</th>
    <td align="center">X</td>
    <td align="center">O</td>
    <td align="center">X</td>
    <td align="center">(*1)</td>
  </tr>

  <tr>
    <th>负载均衡</th>
    <td align="center">X</td>
    <td align="center">O</td>
    <td align="center">O</td>
    <td align="center">(*1)</td>
  </tr>

  <tr>
    <th>故障恢复</th>
    <td align="center">O</td>
    <td align="center">O</td>
    <td align="center">O</td>
    <td align="center">X</td>
  </tr>

  <tr>
    <th>在线恢复</th>
    <td align="center">X</td>
    <td align="center">O</td>
    <td align="center">(*2)</td>
    <td align="center">X</td>
  </tr>

  <tr>
    <th>并行查询</th>
    <td align="center">X</td>
    <td align="center">X</td>
    <td align="center">X</td>
    <td align="center">O</td>
  </tr>

  <tr>
    <th>需要的服务器数</th>
    <td align="center">1 或更多</td>
    <td align="center">2 或更多</td>
    <td align="center">2 或更多</td>
    <td align="center">2 或更多</td>
  </tr>

  <tr>
    <th>是否需要系统数据库</th>
    <td align="center"></td>
    <td align="center"></td>
    <td align="center"></td>
    <td align="center"></td>
  </tr>

</table>

<ul>
 <li> O 意味着“可用”, X 意味着“不可用
 <li>(*1) 并行查询模式需要同时打开复制和负载均衡,但是复制和负载均衡无法用于并行查询模式中的分布式表。
 <li>(*2) 在线恢复可以和流复制同时使用。
 <li>(*3) 客户端仅仅是通过 pgpool-II 连接到 PostgreSQL 服务器。这种模式仅仅用于限制到服务器的连接数,或者在多台机器上启用故障恢复。
</ul>

<h2 id="pcp_conf">配置 <code>pcp.conf</code></h2>

<p>pgpool-II 有一个控制接口,管理员可以通过它远程收集 pgpool-II 的状态信息或者终止 pgpool-II 进程。
<code>pcp.conf</code> 是用于这个接口认证的用户/密码文件。
所有的模式都需要先设置 <code>pcp.conf</code> 文件。
一个 <code>$prefix/etc/pcp.conf.sample</code> 文件在 pgpool-II 安装时已经被创建。
重命名这个文件为 <code>pcp.conf</code> 并添加你要的用户名和密码到其中。
</p>

<pre>
cp $prefix/etc/pcp.conf.sample $prefix/etc/pcp.conf
</pre>
<p>空行或者以“<code>#</code>”开始的行将被认为是注释,会被忽略掉。一个用户名和对应的密码必须以以下的方式写成一行。</p>
<pre>
username:[password encrypted in md5]
</pre>
<p>
<code>[password encrypted in md5]</code> 可以通过 <code>$prefix/bin/pg_md5</code> 命令生成。
</p>

<pre>
pg_md5 -p
password: &lt;your password&gt;
</pre>
<p>
或者
</p>
<pre>
./pg_md5 foo
acbd18db4cc2f85cedef654fccc4a4d8
</pre>
<p>
<code>pcp.conf</code> 对于运行 pgpool-II 的用户必须可读。</p>

<h2>配置 <code>pgpool.conf</code></h2>

<p>就像之前说的,每种操作模式在 <code>pgpool.conf</code> 文件中有它对应的配置项。一个 <code>$prefix/etc/pgpool.conf.sample</code> 文件在 pgpool-II 安装时已经被创建。重命名这个文件为 <code>pgpool.conf</code> 并修改它的内容。
</p>

<pre>
cp $prefix/etc/pgpool.conf.sample $prefix/etc/pgpool.conf
</pre>

<p>
针对每种不同的模式,提供了附加的示例 pgpool.conf。<span class="version">V2.3 -</span>
</p>
<p>
<table border>
<tr class="header">
<th>模式</th>
<th>示例文件</th>
</tr>

<tr>
<td>复制模式</td>
<td>pgpool.conf.sample-replication</td>
</tr>

<tr>
<td>主/备模式(Slony-I)</td>
<td>pgpool.conf.sample-master-slave</td>
</tr>

<tr>
<td>主/备模式(流复制)</td>
<td>pgpool.conf.sample-stream</td>
</tr>
</table>

<p>
空行或者以“<code>#</code>”开始的行将被认为是注释,会被忽略掉。</p>
</p>

<h3>连接</h3>

<dl>
  <dt><a name="LISTEN_ADDRESS"></a>listen_addresses</dt>
  <dd>
      <p>指定 pgpool-II 将接受 TCP/IP 连接的主机名或者IP地址。<code>'*'</code> 将接受所有的连接。<code>''</code> 将禁用 TCP/IP 连接。默认为 <code>'localhost'</code>。总是支持接受通过 UNIX 域套接字发起的连接。需要重启 pgpool-II 以使改动生效。</p>
  </dd>
      
  <dt><a name="PORT"></a>port</dt>
  <dd>
      <p>pgpool-II 监听 TCP/IP 连接的端口号。默认为 9999。需要重启 pgpool-II 以使改动生效。</p>
  </dd>

  <dt><a name="SOCKET_DIR"></a>socket_dir</dt>
  <dd>
      <p>pgpool-II 建立用于建立接受 UNIX 域套接字连接的目录。默认为 <code>'/tmp'</code>。注意,这个套接字可能被 cron 任务删除。我们建议设置这个值为 <code>'/var/run'</code> 或类似目录。需要重启 pgpool-II 以使改动生效。</p>
  </dd>

  <dt><a name="PCP_PORT"></a>pcp_port</dt>
  <dd>
      <p>PCP 进程接受连接的端口号。默认为 9898。本参数必须在服务器启动前设置。</p>
  </dd>

  <dt><a name="PCP_SOCKET_DIR"></a>pcp_socket_dir</dt>
  <dd>
      <p>PCP 进程用于建立接受 UNIX 域套接字连接的目录。默认为 <code>'/tmp'</code>。注意,这个套接字可能被 cron 任务删除。我们建议设置这个值为 <code>'/var/run'</code> 或类似目录。需要重启 pgpool-II 以使改动生效。</p>
  </dd>
      
  <dt><a name="BACKEND_SOCKET_DIR"></a>backend_socket_dir<span class="version">- V3.0</span></dt>
    <dd>
    <p class="version_notice">
    <em class="caution">不推荐使用</em> :
    为了保持和 libpq 策略的一致性,反对使用本参数。参考 backend_hostname 参数来定义你对应的配置。
    </p>
    <p>本参数定义了 PostgreSQL 服务器的 UNIX 域套接字目录。
      默认为 <code>'/tmp'</code>.
    </p>
    <p>
    本参数必须在服务器启动前设置。</p>
    </dd>
</dl>

<h3></h3>

<dl>
  <dt><a name="NUM_INIT_CHILDREN"></a>num_init_children</dt>
  <dd>
      <p>预先生成的 pgpool-II 服务进程数。默认为 32。num_init_children 也是 pgpool-II 支持的从客户端发起的最大并发连接数。如果超过 num_init_children 数的客户端尝试连接到 pgpool-II,它们将被阻塞(而不是拒绝连接),直到到任何一个 pgpool-II 进程的连接被关闭为止。最多有 2*num_init_children 可以被放入等待队列。</p>
      
	  <p>对于以上内容的一些提示:</p>
	   <p>
	   <ul>
		<li>取消一个执行中的查询将导致建立另一个到后端的连接;因此,如果所有的连接都在使用,则查询无法被取消。如果你想确保查询可以被取消,设置本值为预期最大连接数的两倍。</li>
		<li>PostgreSQL 允许最多 max_connections - superuser_reserved_connections 个非超级用户的并发连接。</li>
	   </ul>
	   </p>
	   <p>归纳起来,max_pool,num_init_children,max_connections 和 superuser_reserved_connections 必须符合以下规则:
	   </p>
	   <p>
	   <pre>
max_pool*num_init_children <= (max_connections - superuser_reserved_connections) (不需要取消查询)
max_pool*num_init_children*2 <= (max_connections - superuser_reserved_connections) (需要取消查询)</pre>
	   <p>
	   	本参数必须在服务器启动前设置。
       </p>
	   </dd>

  <dt><a name="CHILD_LIFE_TIME"></a>child_life_time</dt>
  <dd>
      <p>pgpool-II 子进程的生命周期,单位为秒。如果子进程空闲了这么多秒,它将被终止,一个新的子进程将被创建。这个参数是用于应对内存泄露和其他不可预料错误的一个措施。默认值为 300 (5分钟)。0 将禁用本功能。注意它不影响尚未接受任何连接的进程。如果改变了这个值,你需要重新加载 pgpool.conf 以使变动生效。
      </p>
  </dd>

<dt><a name="CHILD_MAX_CONNECTIONS"></a>child_max_connections</dt>
  <dd>
      <p>当 pgpool-II 子进程处理这么多个客户端连接后,它将被终止。这个参数在繁忙到 child_life_time 和 connection_life_time 永远不会触发的服务器上有效。如果你改变了这个值,需要重新加载 pgpool.conf 以使变动生效。
      </p>
  </dd>

<dt><a name="CLIENT_IDLE_LIMIT"></a>client_idle_limit</dt>
  <dd>
  <p>当一个客户端在执行最后一条查询后如果空闲到了 client_idle_limit 秒数,到这个客户端的连接将被断开。这在避免 pgpool 子进程被懒客户端占用或者探测断开的客户端和 pgpool 之间的 TCP/IP 连接非常有用。如果你改变了这个值,需要重新加载 pgpool.conf 以使变动生效。
	</p>

<dt><a name="ENABLE_POOL_HBA"></a>enable_pool_hba</dt>
    <dd>
    <p>
    如果为 true,则使用 pgpool_hba.conf 来进行客户端认证。
    参考<a href="#hba">设置用于客户端认证的 pool_hba.conf</a></p>
    <p>
    如果你改变了这个值,需要重新加载 pgpool.conf 以使变动生效。
    </p>
    </dd>

<dt><a name="POOL_PASSWD"></a>pool_passwd</dt>
    <dd>
    <p>
    指定用于 md5 认证的文件名。默认值为"pool_passwd"。"" 表示禁用。
    参考 <a href="#md5">认证 / 访问控制</a> 获得更多信息。
    </p>
    <p>
    如果你改变了这个值,需要重启 pgpool-II 以生效。
    </p>
    </dd>

<dt><a name="AUTHENTICATION_TIMEOUT"></a>authentication_timeout</dt>
  <dd>
  <p>指定 pgpool 认证超时的时长。0 指禁用超时,默认值为 60 。如果你改变了这个值,需要重新加载 pgpool.conf 以使变动生效。
  </p>
</dl>

<h3>日志</h3>

<dl>
  <dt><a name="LOG_DESTINATION"></a>log_destination <span class="version">V3.1 -</span></dt>
  <dd>
      <p>pgpool-II 支持多种记录服务器消息的方式,包括 stderr 和 syslog。默认为记录到 stderr。
      </p>
      <p>注:要使用syslog 作为 log_destination 的选项,你将需要更改你系统的 syslog 守护进程的配置。pgpool-II 可以记录到 syslog 设备 LOCAL0 到 LOCAL7 (参考 syslog_facility),
      	但是大部分平台的默认的 syslog 配置将忽略这些消息。你需要添加如下一些内容
	</p>
	<pre>
	local0.*    /var/log/pgpool.log	</pre>
      <p>到 syslog 守护进程的配置文件以使它生效。
	</p>
  </dd>

  <dt><a name="PRINT_TIMESTAMP"></a>print_timestamp</dt>
  <dd>
      <p>如果本值被设置为 true ,则将在日志中添加时间戳。默认值为 true。如果你改变了这个值,需要重新加载 pgpool.conf 以使变动生效。
      </p>
  </dd>

  <dt><a name="LOG_CONNECTIONS"></a>log_connections</dt>
  <dd>
    <p>如果为 true,进入的连接将被打印到日志中。如果你改变了这个值,需要重新加载 pgpool.conf 以使变动生效。
    </p>
  </dd>

  <dt><a name="LOG_HOSTNAME"></a>log_hostname</dt>
  <dd>
    <p>如果为 true,ps 命令将显示客户端的主机名而不是 IP 地址。而且,如果 log_connections 被开启,也会将主机名写入日志。如果你改变了这个值,需要重新加载 pgpool.conf 以使变动生效。
    </p>
  </dd>

  <dt><a name="LOG_STATEMENT"></a>log_statement</dt>
  <dd>
      <p>当设置为 true 时生成 SQL 日志消息。这类似于 PostgreSQL 中的 log_statement 参数。即使调试选项没有在启动的时候传递到 pgpool-II,它也会产生日志。</p>
  </dd>

  <dt><a name="LOG_PER_NODE_STATEMENT"></a>log_per_node_statement <span class="version">V2.3 -</span></dt>
  <dd>
      <p>类似于 log_statement,除了它是针对每个 DB 节点产生日志外。例如它对于确定复制是否正常运行非常有用。如果你改变了这个值,需要重新加载 pgpool.conf 以使变动生效。
       </p>
  </dd>
  
  <dt><a name="SYSLOG_FACILITY"></a>syslog_facility <span class="version">V3.1 -</span></dt>
  <dd>
      <p>当记录日志到 syslog 被启用,本参数确定被使用的 syslog “设备”。你可以使用 LOCAL0, LOCAL1, LOCAL2, LOCAL3, LOCAL4, LOCAL5, LOCAL6, LOCAL7;默认为 LOCAL0。还请参考你系统的 syslog 守护进程的文档。
	</p>
  </dd>

  <dt><a name="SYSLOG_IDENT"></a>syslog_ident <span class="version">V3.1 -</span></dt>
  <dd>
      <p>当记录日志到 syslog 被启用,本参数确定用于标记 syslog 中 pgpool-II 消息的程序名。默认为“pgpool”。
	</p>
  </dd>

  <dt><a name="DEBUG_LEVEL"></a>debug_level <span class="version">V3.0 -</span></dt>
  <dd>
      <p>调试消息详细程度级别。0 表示没有消息。大于 1 表示更详细的消息。默认值为 0。
      </p>
  </dd>
</dl>

<h3>文件位置</h3>

<dl>
  <dt><a name="PID_FILE_NAME"></a>pid_file_name</dt>
  <dd>
      <p>到包含 pgpool-II 进程 ID 的文件的完整路径名。默认为 <code>'/var/run/pgpool/pgpool.pid'</code>。需要重启 pgpool-II 以使改动生效。
       </p>
  </dd>
  <dt><a name="LOGDIR"></a>logdir</dt>
  <dd>
      <p>保存日志文件的目录。 pgpool_status 将被写入这个目录。
       </p>
  </dd>
</dl>

<h3>连接池</h3>

<dl>
  <dt><a name="CONNECTION_CACHE"></a>connection_cache</dt>
  <dd>
      <p>如果本值被设置为 true,则缓存到 PostgreSQL 的连接。默认为 true。需要重启 pgpool-II 以使改动生效。</p>
  </dd>
</dl>

<h3>健康检查</h3>

<dl>
  <dt><a name="HEALTH_CHECK_TIMEOUT"></a>health_check_timeout</dt>
  <dd>
      <p>pgpool-II 定期尝试连接到后台以检测服务器是否在服务器或网络上有问题。这种错误检测过程被称为“健康检查”。如果检测到错误,则 pgpool-II 会尝试进行故障恢复或者退化操作。<br>
      本参数用于避免健康检查在例如网线断开等情况下等待很长时间。超时值的单位为秒。默认值为 20 。0 禁用超时(一直等待到 TCP/IP 超时)。<br>
      健康检查需要额外的到后端程序的连接,所以 <code>postgresql.conf</code> 中的 <code>max_connections</code> 需要加一。<br>
      如果你改变了这个值,需要重新加载 pgpool.conf 以使变动生效。
     </p>
  </dd>

  <dt><a name="HEALTH_CHECK_PERIOD"></a>health_check_period</dt>
  <dd>
      <p>本参数指出健康检查的间隔,单位为秒。默认值为 0 ,代表禁用健康检查。<br>
      如果你改变了这个值,需要重新加载 pgpool.conf 以使变动生效。
       </p>
  </dd>
      
<dt><a name="HEALTH_CHECK_USER"></a>health_check_user</dt>
  <dd>
      <p>用于执行健康检查的用户。用户必须存在于 PostgreSQL 后台中。<br>
      如果你改变了这个值,需要重新加载 pgpool.conf 以使变动生效。
       </p>
  </dd>

<dt><a name="HEALTH_CHECK_PASSWORD"></a>health_check_password <span class="version">V3.1 -</span></dt>
  <dd>
      <p>用于执行健康检查的用户的密码。<br>
      如果你改变了这个值,需要重新加载 pgpool.conf 以使变动生效。
       </p>
  </dd>
<dt><a name="HEALTH_CHECK_MAX_RETRIES"></a>health_check_max_retries <span class="version">V3.2 -</span></dt>
  <dd>
      <p>在执行失效故障切换前尝试的最大失效健康检查次数。这个参数对于网络不稳定的时,健康检查失败但主节点依旧正常的情况下非常有效。默认值为 0,也就是不重试。如果你想启用 health_check_max_retries,建议你禁用 <a href="#FAIL_OVER_ON_BACKEND_ERROR">fail_over_on_backend_error</a><br>
      	如果你改变了 health_check_max_retries,需要重新加载 pgpool.conf。
      </p>
  </dd>

<dt><a name="HEALTH_CHECK_RETRY_DELAY"></a>health_check_retry_delay <span class="version">V3.2 -</span></dt>
  <dd> 
      <p>失效健康检查重试的间隔时间(单位为秒)( health_check_max_retries > 0 时有效 )。如果为 0 则立即重试(不延迟)。<br>
      如果你改变了 health_check_retry_delay,需要重新加载 pgpool.conf。
      </p>
  </dd>

<dt><a name="SEARCH_PRIMARY_NODE_TIMEOUT"></a>search_primary_node_timeout <span class="version">V3.3 -</span></dt>
    <dd>
    <p>本参数指定在发生故障切换的时候查找一个主节点的最长时间,单位为秒。默认值为 10。pgpool-II 将在发生故障切换的时候在设置的时间内尝试搜索主节点,如果到达这么长时间未搜索到则放弃搜索。0 表示一直尝试。本参数在流复制模式之外的情况下被忽略。<br>
    </p>
    <p>
    如果你改变了 search_primary_node_timeout,需要重新加载 pgpool.conf。
    </p>
    </dd>
</dl>

<h3>故障切换和恢复</h3>

<dl>
<dt><a name="FAILOVER_COMMAND"></a>failover_command</dt>
<dd>
<p>本参数指定当一个节点断开连接时执行的命令。pgpool-II 使用后台对应的信息代替以下的特别字符。
</p>


<table border>
    <tr><td>特殊字符</td><td>描述</td></tr>
    <tr><td>%d</td><td>断开连接的节点的后台 ID。</td></tr>
    <tr><td>%h</td><td>断开连接的节点的主机名。</td></tr>
    <tr><td>%p</td><td>断开连接的节点的端口号。</td></tr>
    <tr><td>%D</td><td>断开连接的节点的数据库实例所在目录。</td></tr>
    <tr><td>%M</td><td>旧的主节点 ID。</td></tr>
    <tr><td>%m</td><td>新的主节点 ID。</td></tr>
    <tr><td>%H</td><td>新的主节点主机名。</td></tr>
    <tr><td>%P</td><td>旧的第一节点 ID。</td></tr>
    <tr><td>%r</td><td>新的主节点的端口号。</td></tr>
    <tr><td>%R</td><td>新的主节点的数据库实例所在目录。</td></tr>
    <tr><td>%%</td><td>'%' 字符</td></tr>
</table>

<p>
如果你改变了这个值,需要重新加载 pgpool.conf 以使变动生效。
</p>

<p>
当进行故障切换时,pgpool 杀掉它的所有子进程,这将顺序终止所有的到 pgpool 的会话。然后,pgpool 调用 failover_command 并等待它完成。然后,pgpool 启动新的子进程并再次开始从客户端接受连接。
</p>

<dt><a name="FAILBACK_COMMAND"></a>failback_command</dt>
<dd>
<p>
	本参数指定当一个节点连接时执行的命令。pgpool-II 使用后台对应的信息代替以下的特别字符。

</p>

<table border>
    <tr><td>特殊字符</td><td>描述</td></tr>
    <tr><td>%d</td><td>新连接上的节点的后台 ID。</td></tr>
    <tr><td>%h</td><td>新连接上的节点的主机名。</td></tr>
    <tr><td>%p</td><td>新连接上的节点的端口号。</td></tr>
    <tr><td>%D</td><td>新连接上的节点的数据库实例所在目录。</td></tr>
    <tr><td>%M</td><td>旧的主节点 ID。</td></tr>
    <tr><td>%m</td><td>新的主节点 ID。</td></tr>
    <tr><td>%H</td><td>新的主节点主机名。</td></tr>
    <tr><td>%P</td><td>旧的第一节点 ID。</td></tr>
    <tr><td>%r</td><td>新的主节点的端口号。</td></tr>
    <tr><td>%R</td><td>新的主节点的数据库实例所在目录。</td></tr>
    <tr><td>%%</td><td>'%' 字符</td></tr>
</table>

<p>
如果你改变了这个值,需要重新加载 pgpool.conf 以使变动生效。
</p>

<dt><a name="FOLLOW_MASTER_COMMAND"></a>follow_master_command <span class="version">V3.1 -</span></dt>
<dd>
<p>
本参数指定一个在主备流复制模式中发生主节点故障恢复后执行的命令。pgpool-II 使用后台对应的信息代替以下的特别字符。
</p>

<table border>
    <tr><td>特殊字符</td><td>描述</td></tr>
    <tr><td>%d</td><td>断开连接的节点的后台 ID。</td></tr>
    <tr><td>%h</td><td>断开连接的节点的主机名。</td></tr>
    <tr><td>%p</td><td>断开连接的节点的端口号。</td></tr>
    <tr><td>%D</td><td>断开连接的节点的数据库实例所在目录。</td></tr>
    <tr><td>%M</td><td>旧的主节点 ID。</td></tr>
    <tr><td>%m</td><td>新的主节点 ID。</td></tr>
    <tr><td>%H</td><td>新的主节点主机名。</td></tr>
    <tr><td>%P</td><td>旧的第一节点 ID。</td></tr>
    <tr><td>%r</td><td>新的主节点的端口号。</td></tr>
    <tr><td>%R</td><td>新的主节点的数据库实例所在目录。</td></tr>
    <tr><td>%%</td><td>'%' 字符</td></tr>
</table>

<p>
如果你改变了这个值,需要重新加载 pgpool.conf 以使变动生效。
</p>

<p>
如果 follow_master_commnd 不为空,当一个主备流复制中的主节点的故障切换完成,pgpool 退化所有的除新的主节点外的所有节点并启动一个新的子进程,再次准备好接受客户端的连接。在这之后,pgpool 针对每个退化的节点运行 ‘follow_master_command’ 指定的命令。通常,这个命令应该用于调用例如 pcp_recovery_node 命令来从新的主节点恢复备节点。
</p>

  <dt><a name="FAIL_OVER_ON_BACKEND_ERROR"></a>fail_over_on_backend_error <span class="version">V2.3 -</span></dt>
  <dd>
      <p>
      	如果为 true,当往后台进程的通信中写入数据时发生错误,pgpool-II 将触发故障处理过程。这和 pgpool-II 2.2.x 甚至以前版本的行为一样。如果设置为 false,则 pgpool 将报告错误并断开该连接。请注意如果设置为 true,当连接到一个后台进程失败或者 pgpool 探测到 postmaster 由于管理原因关闭,pgpool 也会执行故障恢复过程。如果你改变了这个值,需要重新加载 pgpool.conf 以使变动生效。
</p>
</dd>
</dl>

<h3>负载均衡模式</h3>

<dl>
  <dt><a name="IGNORE_LEADING_WHITE_SPACE"></a>ignore_leading_white_space</dt>
  <dd>
      <p>在负载均衡模式中 pgpool-II 忽略 SQL 查询语句前面的空白字符。如果使用类似于 DBI/DBD:Pg 一类的在用户的查询前增加空白的 API 中非常有用。如果你改变了这个值,需要重新加载 pgpool.conf 以使变动生效。</p>
  </dd>
</dl>

<h3>后端(PostgreSQL服务器)</h3>

<dl>
  <dt><a name="BACKEND_HOSTNAME"></a>backend_hostname</dt>
  <dd>
      <p>指出连接到 PostgreSQL 后台程序的地址。它用于 pgpool-II 与服务器通信。如果你改变了这个值,需要重新加载 pgpool.conf 以使变动生效。
      </p>
      <p>
      	对于 TCP/IP 通信,本参数可以是一个主机名或者IP地址。如果它是从斜线开始的,它指出是通过 UNIX 域套接字通信,而不是 TCP/IP 协议;它的值为存储套接字文件所在的目录。如果 backend_host 为空,则它的默认行为是通过 <code>/tmp</code> 中的 UNIX 域套接字连接。
      </p>
      <p>
      	可以通过在本参数名的末尾添加一个数字来指定多个后台程序(例如<code>backend_hostname0</code>)。这个数字对应为“数据库节点 ID”,是从 0 开始的正整数。被设置数据库节点ID为 0 的后台程序后台程序将被叫做“主数据库”。当定义了多个后台程序时,即使主数据库当机后依然能继续(某些模式下不行)。在这种情况下,存活的最小的数据库节点编号的数据库将被变成新的主数据库。
      <p> 请注意有编号为 0 的节点在流复制中没有其他意义。但是,你需要注意数据库节点是不是“主节点”。请参考 <a href="#stream">流复制</a> 获得更多细节。</p>
    </p>
      <p>如果你只计划使用一台 PostgreSQL 服务器,可以通过 <code>backend_hostname0</code> 指定。</p>
      <p>
      	可以通过配置本参数后重新加载配置文件添加新的节点。但是,对已有的值无法更新,所以这种情况下你必须重启 pgpool-II。
      </p>
  </dd>

  <dt><a name="BACKEND_PORT"></a>backend_port</dt>
  <dd>
      <p>
      	指定后台程序的端口号。可以通过在本参数名的末尾添加一个数字来指定多个后台程序(例如<code>backend_port0</code>)。如果你只计划使用一台 PostgreSQL 服务器,可以通过 <code>backend_port0</code> 指定。</p>
      <p>
      	可以通过配置本参数后重新加载配置文件添加新的后台端口。但是,对已有的值无法更新,所以这种情况下你必须重启 pgpool-II。
      </p>
  </dd>

  <dt><a name="BACKEND_WEIGHT"></a>backend_weight</dt>
  <dd>
      <p>指定后台程序的负载均衡权重。可以通过在本参数名的末尾添加一个数字来指定多个后台程序(例如<code>backend_weight0</code>)。如果你只计划使用一台 PostgreSQL 服务器,可以通过 <code>backend_weight0</code> 指定。</p><p>在原始模式中,请将本值设置为 1。</p>
      <p>
      	可以通过配置本参数后重新加载配置文件添加新的负载均衡权重。但是,对已有的值无法更新,所以这种情况下你必须重启 pgpool-II。
      </p>
      <p>
      	在 pgpool-II 2.2.6/2.3 或者更新的版本中,你可以通过重新加载配置文件来改变本值。但这只对新连接的客户会话生效。这在主备模式中可以避免任何执行一些管理工作的查询被发送到备用节点上。
      </p>
  </dd>

  <dt><a name="BACKEND_DATA_DIRECTORY"></a>backend_data_directory</dt>
  <dd>
      <p>指定后台的数据库实例的目录。可以通过在本参数名的末尾添加一个数字来指定多个后台程序(例如<code>backend_data_directory0</code>)。如果你不打算使用在线恢复,你可以不设置本参数。</p>

      <p>
      	可以通过配置本参数后重新加载配置文件添加新的后台的数据库实例目录。但是,对已有的值无法更新,所以这种情况下你必须重启 pgpool-II。
      </p>
  </dd>

  <dt><a name="BACKEND_FLAG"></a>backend_flag <span class="version">V3.1 -</span></dt>
   <dd>
    <p>控制大量的后台程序的行为。可以通过在本参数名的末尾添加一个数字来指定多个后台程序(例如<code>backend_flag0</code></p>
    <p>
    当前支持以下的内容。多个标志可以通过“|”来分隔。
    </p>

    <table border>
    <tr><th class="nodec">ALLOW_TO_FAILOVER</th>
        <td>允许故障切换或者从后台程序断开。本值为默认值。指定本值后,不能同时指定 DISALLOW_TO_FAILOVER 。
        </td></tr>
    <tr><th class="nodec">DISALLOW_TO_FAILOVER</th>
    <td>不允许故障切换或者从后台程序断开。本值在你使用 HA(高可用性)软件例如 Heartbeat 或者 Packmaker 来保护后台程序时非常有用。
    	本值为默认值。指定本值后,不能同时指定 DISALLOW_TO_FAILOVER 。
    </td></tr>
    </table>
  </dt>
</dl>

<h3>SSL</h3>

<dl>
  <dt><a name="SSL"></a>ssl <span class="version">V2.3 -</span></dt>
  <dd>
      <p>如果设置为 ture,则启用了到前端程序和后端程序的连接的 ssl 支持。注意为了能与前端程序进行 SSL 连接,必须设置 <code>ssl_key</code><code>ssl_cert</code></p>
      <p>SSL 默认被关闭。就像在 <a href="#install">pgpool-II 的安装</a> 小节所说的,注意必须在编译时配置 OpenSSL 支持才能打开 SSL 支持。</p>
      <p>如果修改了 SSL 相关的设置, pgpool-II 守护进程必须重启。</p>
  </dd>

  <dt><a name="SSL_KEY"></a>ssl_key <span class="version">V2.3 -</span></dt>
  <dd>
      <p>对于进入的连接使用的私钥文件所在路径。
      </p>
      <p>本选项没有默认值,如果本值不设置,则对于进入的连接将禁用 SSL。
      </p>
  </dd>

  <dt><a name="SSL_CERT"></a>ssl_cert <span class="version">V2.3 -</span></dt>
  <dd>
      <p>
      	对于进入的连接使用的公共 x509 证书文件所在的路径。
      </p>
      <p>本选项没有默认值,如果本值不设置,则对于进入的连接将禁用 SSL。
      </p>
  </dd>
</dl>

<h3>其他</h3>

<dl>
  <dt><a name="RELCACHE_EXPIRE"></a>relcache_expire <span class="version">V3.1 -</span></dt>
    <dd>
    <p>
     关系缓存的生命周期。0(默认值)表示没有缓冲区过期。
     关系缓存用于缓存用来获取包含表结构信息或一个表是不是一个临时表等大量信息的相关的
     PostgreSQL 系统 catalog 的查询结果。缓存位于 pgpool 子进程的本地,并被保存到它的生命结束。
     如果某些人使用了 ALTER TABLE 修改了表结构或其他类似内容,关系缓存不再一致。
     为了这个目的,relcache_expire 控制缓存的生命周期。
    </p>
    </dd>

 <dt><a name="RELCACHE_SIZE"></a>relcache_size <span class="version">V3.2 -</span></dt>
    <dd>
    <p>
    	relcache 的条目数。默认为 256。
    	如果你频繁看到以下信息,请增加此数量。
    </p>
<pre>
"pool_search_relcache: cache replacement happened"
</pre>
    </dd>

<dt><a name="CHECK_TEMP_TABLE"></a>check_temp_table <span class="version">V3.2 -</span></dt>
    <dd>
    <p>
    	如果为 on,在 SELECT 语句中启用临时表检查。这会在启动查询前查询主节点上的系统对象,
    	因此增加了主节点上的负载。如果你确定你的系统不会使用临时表,并且你想降低对主节点的访问,
    	弄可以将它设置为 off。默认为 on。
    </p>
    </dd>

</dl>

<h2>生成 SSL 证书</h2>
<p>证书处理不在本文档讨论范围。postgresql.org 的 <a href="http://developer.postgresql.org/pgdocs/postgres/ssl-tcp.html">
Secure TCP/IP Connections with SSL</a> 页面指出了一些用来生成自签名证书的示例命令。
</p>

<h2 id="failover_in_raw_mode">在原始模式中的故障切换</h2>

<p>如果定义了多个服务器,可以在原始模式中进行故障切换。
pgpool-II 在普通操作中通常访问 <code>backend_hostname0</code> 指定的后台程序。
如果 backend_hostname0 因为某些原因不能正常工作,pgpool-II 尝试访问 backend_hostname1 指定的后台程序。
如果它也不能正常工作,pgpool-II 尝试访问 backend_hostname2,3 等等。</p>

<p class="top_link"><a href="#Top">back to top</a></p>

<!-- ================================================================================ -->

<h1><a name="connection_pool_mode"></a>连接池模式</h1>

<p>在连接池模式中,所有在原始模式中的功能以及连接池功能都可以使用。要启用本模式,你需要设置 "<a href="#CONNECTION_CACHE">connection_cache</a>" 为 on。
以下参数会对连接池产生影响。</p>

<dl>
  <dt><a name="MAX_POOL"></a>max_pool</dt>
  <dd>
    <p>在 pgpool-II 子进程中缓存的最大连接数。当有新的连接使用相同的用户名连接到相同的数据库,pgpool-II 将重用缓存的连接。如果不是,则 pgpool-II 建立一个新的连接到 PostgreSQL。如果缓存的连接数达到了 max_pool,则最老的连接将被抛弃,并使用这个槽位来保存新的连接。默认值为 4。请小心通过 pgpool-II 进程到后台的连接数可能达到
    	<code><a href="#NUM_INIT_CHILDREN">num_init_children</a></code> *
      <code><a href="#MAX_POOL">max_pool</a></code> 个。需要重启 pgpool-II 以使改动生效。
	</p>
  </dd>
  <dt><a name="CONNECTION_LIFE_TIME"></a>connection_life_time</dt>
  <dd>
      <p>缓存的连接的过期时长,单位为秒。过期的缓存连接将被关闭。默认值为 0,表示缓存的连接将不被关闭。</p>
  </dd>
  <dt><a name="RESET_QUERY_LIST"></a>reset_query_list</dt>
  <dd>
      <p>指定在推出一个会话时发送到后台程序的SQL命令。多个命令可以通过“;”隔开。默认为以下的设置但你可以根据你的需求改变。
      <pre>
      reset_query_list = 'ABORT; DISCARD ALL'</pre>
<p>
      不同版本的 PostgreSQL 需要使用不同的命令。以下为推荐的设置。
</p>
<p>
<table border>
<tr class="header"><th>PostgreSQL 版本</th><th>reset_query_list 的值</th></tr>
<tr><td>7.1 或更老的版本</td><td>ABORT</td></tr>
<tr><td>7.2 到 8.2</td><td>ABORT; RESET ALL; SET SESSION AUTHORIZATION DEFAULT</td></tr>
<tr><td>8.3 或更新的版本</td><td>ABORT; DISCARD ALL</td></tr>
</table>
</p>
<ul>
<li>在 7.4 或更新的版本中,当不是在一个事务块中的时候,“ABORT”将不会被发出。
</ul>

<p>
修改本参数后需要重新加载 pgpool.conf 以使改变生效。
</p>
</dd>
</dl>

<h2><p>连接池模式中的故障切换</p></h2>

<p>连接池模式中的故障切换和原始模式的相同。</p>

<p class="top_link"><a href="#Top">返回顶部</a></p>

<!-- ================================================================================ -->

<h1><a name="replication_mode"></a>复制模式</h1>

<p>本模式在后台程序间启用了数据复制。以下配置参数必须在设置以上参数之外另外设置。</p>

<dl>
  <dt><a name="REPLICATION_MODE"></a>replication_mode</dt>
  <dd>
      <p>设置为 true 以启用复制模式。默认值为 false。</p>
  </dd>

  <dt><a name="LOAD_BALANCE_MODE"></a>load_balance_mode</dt>
  <dd>
      <p>当设置为 true 时,SELECT 查询将被分发到每个后台程序上用于负载均衡。默认值为 false。本参数必须在服务器启动前设置。</p>
  </dd>

  <dt><a name="REPLICATION_STOP_ON_MISMATCH"></a>replication_stop_on_mismatch</dt>
  <dd>
	  <p>当设置为 true 时,当不同的后台程序返回不同的包类型时,则和其他后台程序差别最大的后台程序将被退化。</p>
	  <p>一个典型的用例为一个事务中的 SELECT 语句,在 <a href="#REPLICATE_SELECT">replicate_select</a> 设置为 true 的情况下,一个 SELECT 语句从不同的后台程序中返回不同的行数。非 SELECT 语句也可能触发这种情况。
	  	例如,一个后台程序执行 UPDATE 成功但其他的失败。注意 pgpool 不会检查 SELECT 返回的记录的内容。如果设置为 false,则会话被终止但后台程序不被退化。默认值为 false。</p>
  </dd>

  <dt><a name="FAILOVER_IF_AFFECTED_TUPLES_MISMATCH"></a>failover_if_affected_tuples_mismatch <span class="version">V3.0 -</span></dt>
  <dd>
	  <p>当设置为 true 时,在执行 INSERT/UPDATE/DELETE 后不同的后台程序返回不同的生效记录数,则和其他后台程序差别最大的后台程序将被退化。如果设置为 false,则会话被终止但后台程序不被退化。默认值为 false。</p>
  </dd>
  
<dt><a name="WHITE_FUNCTION_LIST"></a>white_function_list <span class="version">V3.0 -</span></dt>
<dd>
<p>指定一系列用逗号隔开的<strong>不会</strong>更新数据库的函数名。在复制模式中,不在本列表中指定的函数将即不会被负载均衡,也不会被复制。在主备模式中,这些 SELECT 语句只被发送到主节点。</p>
<p>你可以使用正则表达式来匹配函数名,例如你通过前缀“get_”或“select_”来作为你只读函数的开头:
</p>
<pre>
white_function_list = 'get_.*,select_.*'
</pre>
</dd>

<dt><a name="BLACK_FUNCTION_LIST"></a>black_function_list <span class="version">V3.0 -</span></dt>
<dd>
<p>指定一系列用逗号隔开的<strong></strong>更新数据库的函数名。在复制模式中,在本列表中指定的函数将即不会被负载均衡,也不会被复制。在主备模式中,这些 SELECT 语句只被发送到主节点。</p>
<p>你可以使用正则表达式来匹配函数名,例如你通过前缀“set_”、“update_”、“delete_”或“insert_”来作为你只读函数的开头:</p>
<pre>
black_function_list = 'nextval,setval,set_.*,update_.*,delete_.*,insert_.*'
</pre>
<p>
以上两项不能同时配置。
</p>
<p>在 pgpool-II 3.0 之前,nextval() 和 setval() 是已知的会写入数据库的函数。你可以通使用 white_function_list 好 balck_function_list 来做到:
</p>
<p>
<pre>
white_function_list = ''
black_function_list = 'nextval,setval,lastval,currval'
</pre>
</p>
<p>注意我们在 nextval 和 setval 后面追加了 lastval 和 currval。虽然 lastval() 和 currval() 不是会写入的函数,但添加 lastval() 和 currval() 可以避免这些函数被无意地被负载均衡到其他的数据库节点而导致错误。添加到 black_function_list 将避免它们被负载均衡。
</p>
</dd>

<dt><a name="replicate_select"></a>replicate_select</dt>
<dd>
<p>当设置为 true,pgpool-II 在复制模式中将复制 SELECT 语句。如果为 false,则 pgpool-II 只发送它们到主数据库。默认为 false。
</p>
<p>
	如果 SELECT 查询是在一个显式的事务块中,<a href="#REPLICATE_SELECT">replicate_select</a><a href="#LOAD_BALANCE_MODE">load_balance_mode</a> 将影响复制的工作模式。以下为具体的细节。
</p>

<p>
<table border>

<tr>
<th class="nodec">SELECT 在一个事务块中</th>
<td>Y</td>
<td>Y</td>
<td>Y</td>
<td>N</td>
<td>N</td>
<td>N</td>
<td>Y</td>
<td>N</td>
</tr>

<tr>
<th class="nodec">replicate_select 为 true</th>
<td>Y</td>
<td>Y</td>
<td>N</td>
<td>N</td>
<td>Y</td>
<td>Y</td>
<td>N</td>
<td>N</td>
</tr>

<tr>
<th class="nodec">load_balance_mode 为 true</th>
<td>Y</td>
<td>N</td>
<td>N</td>
<td>N</td>
<td>Y</td>
<td>N</td>
<td>Y</td>
<td>Y</td>
</tr>

<tr>
<th class="nodec">结果(R: 负载均衡, M: 只发送到主节点, L: 负载均衡)</th>
<td>R</td>
<td>R</td>
<td>M</td>
<td>M</td>
<td>R</td>
<td>R</td>
<td>M</td>
<td>L</td>
</tr>
</table>
</p>
  </dd>

  <dt><a name="INSERT_LOCK"></a>insert_lock</dt>
  <dd>
      <p>如果在包含 SERIAL 类型的表中做复制, SERIAL 列的值在不同后台间可能不同。这个问题可以通过显式的锁表解决(当然,事务的并发性将被严重退化)。为了达到这个目的,必须做以下的改变:</p>

<pre>
INSERT INTO ...
</pre>

    <p>
    改变为
    </p>

<pre>
BEGIN;
LOCK TABLE ...
INSERT INTO ...
COMMIT;
</pre>

      <p><code>insert_lock</code> 为 true 时,pgpool-II 自动在每次执行 INSERT 时添加以上的查询(如果已经在事务中,它只是简单地添加 LOCK TABLE ... )。
	</p>
      <p>pgpool-II 2.2 或更高的版本中,可以自动探测是否表拥有 SERIAL 类型的列,所以如果没有 SERIAL 类型的列,则将不会锁表。
	</p>
	   <p>
       pgpool-II 3.0 系列直到 3.0.4 为止针对串行的关系使用一个行锁,而不是表锁。这使在 VACUUM(包括 autovacuum)时的锁冲突最小。但这会导致另一个问题。如果发生了嵌套事务,对串行的关系使用行所会导致 PostgreSQL 的内部错误(确切地说,保存事务状态的 pg_clog 会发生访问错误)。为了避免这个问题,PostgreSQL 核心开发者决定禁止对串行的关系加锁,当然这也会让 pgpool-II 无法工作(&quot;修复&quot;后的 PostgreSQL 版本为 9.0.5, 8.4.9, 8.3.16 和 8.2.22)。
	   </p>
       <p>
       由于新版的 PostgreSQL 不允许对串行的关系加锁,pgpool-II 3.0.5 或更新的版本针对 pgpool_catalog.insert_lock 使用行锁。所以需要预先在通过 pgpool-II 访问的数据库中建立 insert_lock 表。详细内容请参考<a href="#install">建立 insert_lock 表</a>。如果不存在 insert_lock 表,pgpool-II 将锁定插入的目标表。这种行为和 pgpool-II 2.2 和 2.3 系列相同。如果你希望使用与旧版本兼容的 insert_lock,你可以在配置脚本中指定锁定模式。详细内容请参考 <a href="#install">configure</a></p>
	   <p>
      你也许需要更好(针对每个事务)的控制手段:
      </p>

      <ol>
	<li>设置 <code>insert_lock</code> 为 true,并添加 <code>/*NO INSERT LOCK*/</code> 代码到你不想要表锁的 INSERT 语句的开始位置。</li>

	<li>设置 <code>insert_lock</code> 为 false,并添加 <code>/*INSERT LOCK*/</code> 到你需要表锁的 INSERT 语句的开始位置。</li>
      </ol>

      <p>
      默认值为 false。如果 <code>insert_lock</code> 被启用,则(通过 pgpool-II 运行的) PostgreSQL 8.0 的事务、权限、规则和 alter_table 的回归测试会失败。原因是 pgpool-II 会尝试 LOCK 这些规则测试的 VIEW ,并产生以下的错误消息:
      </p>

      <pre>
      ! ERROR: current transaction is aborted, commands ignored until
      end of transaction block
      </pre>

      <p>例如,事务测试尝试 INSERT 到一个不存在的表,而 pgpool-II 导致 PostgreSQL 在这之前请求锁。事务将被终止,而之后的 INSERT 语句会产生以上的错误消息。
      </p>


<dt><a name="RECOVERY_USER"></a>recovery_user</dt>
<dd>
<p>
本参数指定一个用于在线恢复的 PostgreSQL 用户名。改变本参数不需要重启。
</p>

<dt><a name="RECOVERY_PASSWORD"></a>recovery_password</dt>
<dd>
<p>
本参数指定一个用于在线恢复的 PostgreSQL 密码。改变本参数不需要重启。
</p>

<dt><a name="RECOVERY_1ST_STAGE_COMMAND"></a>recovery_1st_stage_command</dt>
<dd>
<p>
本参数指定一个在在线恢复第一阶段在主(Primary)PostgreSQL 服务器上运行的命令。处于安全原因,本命令必须被放置在数据库实例目录中。例如,如果 recovery_1st_stage_command = 'sync-command',那么 pgpool-II 将执行 $PGDATA/sync-command。
</p>
<p>
recovery_1st_stage_command 将接受以下 3 个参数:
</p>
<ol>
<li>到主(Primary)数据库实例的路径</li>
<li>需要恢复的 PostgreSQL 主机名</li>
<li>需要恢复的数据库实例路径</li>
</ol>
</p>
<p>
注意 pgpool-II 在执行 recovery_1st_stage_command 时<b>接收</b>连接和查询。在本阶段中,你可以查询和更新数据。
</p>
<p>
改变本参数不需要重启。
</p>

<dt><a name="RECOVERY_2ND_STAGE_COMMAND"></a>recovery_2nd_stage_command</dt>
<dd>
<p>
本参数指定一个在在线恢复第二阶段在主(Primary)PostgreSQL 服务器上运行的命令。处于安全原因,本命令必须被放置在数据库实例目录中。例如,如果 recovery_2st_stage_command = 'sync-command',那么 pgpool-II 将执行 $PGDATA/sync-command。
</p>
<p>
recovery_2nd_stage_command 将接受以下 3 个参数:
</p>
<ol>
<li>到主(Primary)数据库实例的路径</li>
<li>需要恢复的 PostgreSQL 主机名</li>
<li>需要恢复的数据库实例路径</li>
</ol>
</p>
<p>
注意 pgpool-II 在运行 recovery_2nd_stage_command 时<b>不接收</b>连接和查询。因此如果一个客户端长时间持有一个连接,则恢复命令不会被执行。pgpool-II 等待所有的客户端关闭它们的连接。这个命令只在没有任何客户端连接到 pgpool-II 时才执行。
</p>
<p>
改变本参数不需要重启。
</p>

<dt><a name="RECOVERY_TIMEOUT"></a>recovery_timeout</dt>
<dd>
<p>
pgpool 在第二阶段不接受新的连接。如果一个客户端在恢复过程中连接到 pgpool,它必须等待到恢复结束。
</p>
<p>
本参数指定恢复超时的时间,单位为秒。如果到达了本超时值,则 pgpool 取消在线恢复并接受连接。0 表示不等待。
</p>
<p>
改变本参数不需要重启。
</p>

  <dt><a name="CLIENT_IDLE_LIMIT_IN_RECOVERY"></a>client_idle_limit_in_recovery <span class="version">V2.2 -</span></dt>
  <dd>
  <p> 类似于 client_idle_limit 但是只在恢复的第二阶段生效。从执行最后一个查询后空闲到 client_idle_limit_in_recovery 秒的客户端将被断开连接。
  	这对避免 pgpool 的恢复被懒客户端扰乱或者客户机和 pgpool 之间的 TCP/IP 连接被意外断开(例如网线断开)非常有用。如果设置为 -1 ,则立即断开客户端连接。
  	client_idle_limit_in_recovery 的默认值为 0,表示本功能不启用。
  </p>
  <p> 如果你的客户端非常繁忙,则无论你将 client_idle_limit_in_recovery 设置为多少 pgpool-II 都无法进入恢复的第二阶段。在这种情况下,
  	你可以设置 client_idle_limit_in_recovery 为 -1 因而 pgpool-II 在进入第二阶段前立即断开这些繁忙的客户端的连接。
  </p>
  <p>
   如果你改变了 client_idle_limit_in_recovery 你需要重新加载 pgpool.conf 。</p>

<dt><a name="LOBJ_LOCK_TABLE"></a>lobj_lock_table <span class="version">V2.2 -</span></dt>
<dd>
<p>
本参数指定一个表名用于大对象的复制控制。如果它被指定,pgpool 将锁定由 lobj_lock_table 指定的表并通过查找 pg_largeobject 系统 catalog 生产一个大对象 id,并调用 lo_create 来建立这个大对象。这个过程保证 pgpool 在复制模式中在所有的数据库节点中获得相同的大对象 id。注意 PostgreSQL 8.0 或者更老的版本没有 lo_create,因此本功能将无法工作。
</p>
<p>
对 libpq 的 lo_creat() 函数的调用将触发本功能。通过 Java API(JDBC 驱动),PHP API(pg_lo_create,或者 PHP 库中类似的 API 例如 PDO)进行的大对象创建,以及其他各种编程语言中相同的 API 使用相同的协议,因此也应该能够运行。
</p>
<p>
以下的大对象建立操作将无法运行:
<p>
<ul>
<li>libpq 中的 lo_create
<li>任何语言中使用 lo_create 的任何 API
<li>后台程序的 lo_import 函数
<li>SELECT lo_creat
</ul>
</p>
<p>
lobj_lock_table 存储在哪个 schema 并不重要,但是这个表必须对任何用户都可以写入。以下为如何建立这样一个表的示例:
</p>
<p>
<pre>
CREATE TABLE public.my_lock_table ();
GRANT ALL ON public.my_lock_table TO PUBLIC;
</pre>
</p>
<p>
lobj_lock_table 指定的表必须被预先建立。如果你在 template1 中建立这个表,之后建立的任何数据库都将有这个表。
</p>
<p>
如果 lobj_lock_table 为空字符串(''),这个功能被禁用(大对象的复制将无法工作)。lobj_lock_table is 的默认值为''。
</p>

</dl>

<h2 id="condition_for_load_balance">负载均衡的条件</h2>
<p>
需要对一个查询使用负载均衡,需要满足以下的所有条件:
</p>

<ul>
    <li>PostgreSQL 7.4 或更高版本</li>
	  <li>即可以在复制模式中,也可以在主备模式中</li>
    <li>在复制模式中,查询必须不是在一个显式的事务中(例如,不在 BEGIN ~ END 块中)</li>
    <li>不能是 SELECT INTO</li>
    <li>不能是 SELECT FOR UPDATE 或者 FOR SHARE</li>
    <li>以 "SELECT" 开始或者为 COPY TO STDOUT, EXPLAIN, EXPLAIN ANALYZE SELECT... 其中一个,ignore_leading_white_space = true 将忽略开头的空格。
    	(除非是在 <a href="#BLACK_FUNCTION_LIST">black_list</a> 或者 <a href="#WHITE_FUNCTION_LIST">white_list</a> 指明的有写动作的函数)
	<li><span class="version">V3.0 -</span>在主备模式中,除了以上条件,还包含以下条件:
		<ul>
		  <li>不能使用临时表</li>
		  <li>不能使用不写日志的表</li>
		  <li>不能使用系统表</li>
		  <li>不过,如果碰到以下条件,即使是显式事务,依然有可能进行负载均衡</li>
			  <ul>
				<li>事务隔离级别不是SERIALIZABLE</li>
				<li>事务一直没有进行写查询(直到发生写入查询前,都可能进行负载均衡)</li>
			  </ul>
		</ul>
	</li>
</ul>

<p>
注意你可以通过在 SELECT 语句之前插入任意的注释来禁止负载均衡:
<pre>
/*REPLICATION*/ SELECT ...
</pre>
</p>

<p>
请参考<a href="#replicate_select">replicate_select</a>。也可以参考<a href="where_to_send_queries.pdf">flow chart</a></p>

<p>
<font color="red">
注:JDBC 驱动有自动提交的选项。如果自动提交为 false,则 JDBC 驱动将自己发送 "BEGIN" 和 "COMMIT"。因此 pgpool-II 无法做任何负载均衡。你需要调用 setAutoCommit(true) 来启用自动提交。
</font>
</p>

<h2 id="failover_in_replication_mode">复制模式中的故障切换</h2>

<p> pgpool-II 退化一个死掉的后台并继续提供服务。只要最少还有一个后台还或者,服务就可以继续。</p>

<h2 id="errors_in_replication_mode">复制模式中的特有错误</h2>
<p>
在复制模式中,如果 pgpool 发现 INSERT,UPDATE 和 DELETE 生效的行数不同,如果 failover_if_affected_tuples_mismatch 被设置为 false,则 pgpool 将发送错误的 SQL 语句到所有的数据库节点来取消当前当前事务(如果为 false 则发生退化)。
在这种情况下,你将在客户端终端中看到以下错误信息:
<p>
<pre>
=# UPDATE t SET a = a + 1;
ERROR: pgpool detected difference of the number of update tuples Possible last query was: "update t1 set i = 1;"
HINT: check data consistency between master and other db node
</pre>

<p>
你将在 PostgreSQL 的日志中看到更新的行数(在本例中,数据库节点 0 更新了 0 行而数据库节点 1 更新了 1 行)。
</p>
<pre>
2010-07-22 13:23:25 LOG:   pid 5490: SimpleForwardToFrontend: Number of affected tuples are: 0 1
2010-07-22 13:23:25 LOG:   pid 5490: ReadyForQuery: Degenerate backends: 1
2010-07-22 13:23:25 LOG:   pid 5490: ReadyForQuery: Number of affected tuples are: 0 1
</pre>

<p class="top_link"><a href="#Top">返回顶部</a></p>

<!-- ================================================================================ -->

<h1><a name="master_slave_mode"></a>主/备模式</h1>

<p>
本模式用于使用其他负责完成实际的数据复制的主/备复制软件(类似于 Slong-I 和 基于流复制)来连接 pgpool-II。
必须设置数据库节点的信息(如果你需要在线恢复功能,<a href="#BACKEND_HOSTNAME">backend_hostname</a><a href="#BACKEND_PORT">backend_port</a><a href="#BACKEND_WEIGHT">backend_weight</a><a href="#BACKEND_FLAG">backend_flag</a><a href="#BACKEND_DATA_DIRECTORY">backend_data_directory</a>),
这和复制模式中的方法相同。另外,还需要设置 <code><a href="#MASTER_SLAVE_MODE">master_slave_mode</a></code><code><a href="#LOAD_BALANCE_MODE">load_balance_mode</a></code> 为 true。
</p>
<p>
pgpool-II 将发送需要复制的查询到主数据库,并在必要时将其他的查询将被负载均衡。不能被负载均衡而发送到主数据库的查询当然也是受负载均衡逻辑控制的。
</p>


<p>在主/备模式中,对于临时表的 DDL 和 DML 操作只能在主节点上被执行。SELECT 也可以被强制在主节点上执行,但这需要你在 SELECT 语句前添加一个 /*NO LOAD BALANCE*/ 注释。
</p>

<p>在主/备模式中, <code><a href="#REPLICATION_MODE">replication_mode</a></code> 必须被设置为 false ,并且 <code><a href="#MASTER_SLAVE_MODE">master_slave_mode</a></code> 为 true。</p>

<p>主/备模式有一个“master_slave_sub mode”。默认值为 'slony',用于 Slony-I。你也可以设置它为 'stream',它在你想使用 PostgreSQL 内置的复制系统(基于流复制)时被设置。用于 Slony-I 子模式的示例配置文件为 pgpool.conf.sample-master-slave,用于基于流复制的子模式的示例文件为 sub-module is pgpool.conf.sample-stream。
</p>
<p>
修改以上任何参数都需要重新启动 pgpool-II。
</p>
<p>
在主/备模式中,你可以通过设置 <a href="#WHITE_FUNCTION_LIST">white_function_list</a><a href="#BLACK_FUNCTION_LIST">black_function_list</a> 来控制负载均衡。参考 <a href="#WHITE_FUNCTION_LIST">white_function_list</a> 获得详细信息。
</p>

<p class="top_link"><a href="#Top">返回顶部</a></p>

<!-- ================================================================================ -->

<h1><a name="stream"></a>流复制 <span class="version">V3.1 -</span></h1>
<p>
就像以上规定的,pgpool-II 可以与 PostgreSQL 9.0 带来的基于流复制协同工作。要使用它,启用“<a href="#MASTER_SLAVE_MODE">master_slave_mode</a>”并设置“<a href="#MASTER_SLAVE_SUB_MODE">master_slave_sub_mode</a>”为“stream”。
pgpool-II 认为基于流复制启用了热备,也就是说备库是以只读方式打开的。以下参数可以用于本模式:
</p>

<dl>
<dt id="DELAY_THRESHOLD">delay_threshold <span class="version">V3.0 -</span></dt>
    <dd>
    <p>
    指定能够容忍的备机上相对于主服务器上的 WAL 的复制延迟,单位为字节。
    如果延迟到达了 delay_threshold,pgpool-II 不再发送 SELECT 查询到备机。
    所有的东西都被发送到主服务器,即使启用了负载均衡模式,直到备机追赶上来。
    如果 delay_threshold 为 0 或者流复制检查被禁用,则延迟检查不被执行。
    这个检查在每“<a href=#SR_CHECK_PERIOD">sr_check_period</a>”周期执行一次。
    delay_threshold 的默认值为 0。
    </p>
    <p>
    要使对本参数的改动生效,你需要重新加载 pgpool.conf。
    </p>
    </dd>

<dt id="SR_CHECK_PERIOD">sr_check_period <span class="version">V3.1 -</span></dt>
    <dd>
    <p>
    本参数指出基于流复制的延迟检查的间隔,单位为秒。
    默认为 0,表示禁用这个检查。
    </p>
    <p>
    如果你修改了 sr_check_period,需要重新加载 pgpool.conf 以使变动生效。
    </p>
    </dd>

<dt id="SR_CHECK_USER">sr_check_user <span class="version">V3.1 -</span></dt>
    <dd>
    <p>
    执行基于流复制检查的用户名。用户必须存在于所有的 PostgreSQL 后端上,否则,检查将出错。
    注意即使 sr_check_period 为 0, sr_check_user 和 sr_check_password 也会被使用。
    要识别主服务器,pgpool-II 发送函数调用请求到每个后端。
    sr_check_user 和 sr_check_password 用于这个会话。
    </p>
    <p>
    如果你修改了 sr_check_user,需要重新加载 pgpool.conf 以使变动生效。
    </p>
    </dd>

<dt id="SR_CHECK_PASSWORD">sr_check_password <span class="version">V3.1 -</span></dt>
    <dd>
    <p>
    指出如何记录复制延迟。如果指定 'none',则不写入日志。
    如果为 'always',在每次执行健康检查时记录延迟。如果 'if_over_threshold' 被指定,
    只有当延迟到达 delay_threshold 时记录日志。log_standby_delay 的默认值为 'none'。
    </p>
    <p>
    要使对本参数的改动生效,你需要重新加载 pgpool.conf。
    </p>
    </dd>

<dt id="LOG_STANDBY_DELAY">log_standby_delay <span class="version">V3.1 -</span></dt>
    <dd>
    <p>
    	指出如何记录复制延迟。如果指定 'none',则不写入日志。
    	如果为 'always',在每次执行健康检查时记录延迟。
    	如果 'if_over_threshold' 被指定,只有当延迟到达 <a href="#DELAY_THRESHOLD">delay_threshold</a> 时记录日志。
    	log_standby_delay 的默认值为 'none'。
    	要使对本参数的改动生效,你需要重新加载 pgpool.conf。
    </p>
    <p>
    	你也可以使用“<a href="#pool_status">show pool_status</a>”命令监控复制延迟。
    	列名为“standby_delay#”(其中 '#' 需要用数据库节点编号代替)。
    </p>
    </dd>
</dl>

<h2>流复制下的故障切换</h2>
<p>
在使用流复制的主/备模式中,如果主节点或者备节点失效,pgpool-II 可以被设置为触发一个故障切换。节点可以被自动断开而不需要进行更多设置。
当进行流复制的时候,备节点检查一个“触发文件”的存在,一旦发现它,则备节点停止持续的恢复并进入读写模式。通过使用这种功能,我们可以使备数据库在主节点失效的时候进行替换。
</p>
<p>
<strong>警告:如果你计划使用多个备节点,我们建议设置一个 delay_threshold 值来避免任何查询由于查询被发送到其他备节点而导致获取旧数据。
</p>
<p>
如果第二个备节点在第一个备节点已经发生替换的时候替换主节点,你会从第二备节点获取错误的数据。我们不推荐计划使用这种配置。
</strong>
</p>
<p>
以下例举了如何设置一个故障切换的配置。
</p>
<p>
<ol>
 <li>将一个故障切换脚本放置到某个地方(例如 /usr/local/pgsql/bin )并给它执行权限。
<pre>
$ cd /usr/loca/pgsql/bin
$ cat failover_stream.sh
#! /bin/sh
# Failover command for streaming replication.
# This script assumes that DB node 0 is primary, and 1 is standby.
# 
# If standby goes down, do nothing. If primary goes down, create a
# trigger file so that standby takes over primary node.
#
# Arguments: $1: failed node id. $2: new master hostname. $3: path to
# trigger file.

failed_node=$1
new_master=$2
trigger_file=$3

# Do nothing if standby goes down.
if [ $failed_node = 1 ]; then
	exit 0;
fi

# Create the trigger file.
/usr/bin/ssh -T $new_master /bin/touch $trigger_file

exit 0;

chmod 755 failover_stream.sh
</pre>
<li>在 pgpool.conf 中设置 failover_commmand。
<pre>
failover_command = '/usr/local/src/pgsql/9.0-beta/bin/failover_stream.sh %d %H /tmp/trigger_file0'
</pre>

<li>在备节点中设置 recovery.conf。
<a href="recovery.conf.sample">一个 recovery.conf 示例</a> 可以在 PostgreSQL 安装目录中找到。它的名字为 "share/recovery.conf.sample"。拷贝 recovery.conf.sample 为 recovery.conf 到数据库节点目录并编辑它。
<pre>
standby_mode = 'on'
primary_conninfo = 'host=name of primary_host user=postgres'
trigger_file = '/tmp/trigger_file0'
</pre>

<li>设置主节点上的 postgresql.conf 。以下仅仅是一个示例。你需要根据你自己的环境做调整。
<pre>
wal_level = hot_standby
max_wal_senders = 1
</pre>

<li>设置主节点上的 pg_hba.conf 。以下仅仅是一个示例。你需要根据你自己的环境做调整。
<pre>
host	replication	postgres		192.168.0.10/32		trust
</pre>

</ol>

<p>
启动首要 PostgreSQL 节点和第二 PostgreSQL 节点来初始化基于流复制。如果主节点失效,备节点将自动启动为普通 PostgreSQL 并准备好接受写查询。
</p>

<h2>流复制</h2>
<p>
当使用流复制和热备的时候,确定哪个查询可以被发送到主节点或备节点或者不能被发送到备节点非常重要。pgpool-II 的流复制模式可以很好的处理这种情况。在本章,我们将解释 pgpool-II 如何做到这一点的。
</p>
<p>
我们通过检查查询来辨别哪个查询应该被发送到哪个节点。
</p>
<p>
<ul>
 <li>这些查询只允许被发送到主节点
	  <ul>
	   <li>INSERT, UPDATE, DELETE, COPY FROM, TRUNCATE, CREATE, DROP, ALTER, COMMENT
	   <li>SELECT ... FOR SHARE | UPDATE
	   <li>在事务隔离级别为 SERIALIZABLE 的 SELECT
	   <li>比 ROW EXCLUSIVE MODE 更严厉的 LOCK 命令
	   <li>一些事务相关命令:
			<ul>
			 <li>BEGIN READ WRITE, START TRANSACTION READ WRITE
			 <li>SET TRANSACTION READ WRITE, SET SESSION CHARACTERISTICS AS TRANSACTION READ WRITE
			 <li>SET transaction_read_only = off
			</ul>
	   <li>两步提交命令:PREPARE TRANSACTION, COMMIT PREPARED, ROLLBACK PREPARED
	   <li>LISTEN, UNLISTEN, NOTIFY
	   <li>VACUUM
	   <li>一些序列生成器操作函数(nextval 和 setval)
	   <li>大对象建立命令
	  </ul>
 <li>这些查询可以被发送到主节点和备节点。如果启用了负载均衡,这些查询可以被发送到备节点。但是,如果设置了 delay_threshold 且复制延迟大于这个值,则查询被发送到主节点。
	  <ul>
	   <li>SELECT not listed above
	   <li>COPY TO
	   <li>DECLARE, FETCH, CLOSE
	   <li>SHOW
	  </ul>
 <li>以下查询被同时发送到主节点和备节点
	  <ul>
	   <li>SET
	   <li>DISCARD
	   <li>DEALLOCATE ALL
	  </ul>
</ul>
</p>

<p>
在一个显式的事务中:
<ul>
 <li>启动事务的命令例如 BEGIN 只被发送到主节点。
 <li>接下来的 SELECT 和一些可以被发送到主节点或备节点的其他查询会在事务中执行或者在备节点中执行。
 <li>无法在备节点中执行的命令例如 INSERT 被发送到主节点。在这些命令之后的命令,即使是 SELECT 也被发送到主节点。这是因为这些 SELECT 语句可能需要立即查看 INSERT 的结果。这种行为一直持续到事务关闭或者终止。
</ul>
</p>

<p>
在扩展协议中,在负载均衡模式中在分析查询时,有可能探测是否查询可以被发送到备节点。规则和非扩展协议下相同。例如,INSERT 被发送到主节点。接下来的 bind,describe 和 execute 也将被发送到主节点。
</p>

<p>
[注:如果对 SELECT 语句的分析由于负载均衡被发送到备节点,然后一个 DML 语句,例如一个 INSERT ,被发送到 pgpool-II,那么,被分析的 SELECT 必须在主节点上执行。因此,我们会在主节点上重新分析这个 SELECT 语句。]
</p>
<p>
最后,pgpool-II 的分析认为有错误的查询将被发送到主节点。
</p>

<h2>流复制中的在线恢复</h2>
<p>
在流复制的主/备模式中,可以执行在线恢复。在在线恢复过程中,首要务器扮演了主服务器的角色并恢复到指定的备服务器。因此恢复过程需要首要服务器启动并运行。
如果第一服务器失效且没有备用服务器被提升,你需要停止 pgpool-II 和所有的 PostgreSQL 服务器并手动恢复它们。
</p>
<p>
<ol>
 <li>设置 recovery_user。通常为 "postgres"。
<pre>
recovery_user = 'postgres'
</pre>
<li>设置登录到数据库的 recover_user 的 recovery_password。
<pre>
recovery_password = 't-ishii'
</pre>

<li>设置 recovery_1st_stage_command。这个阶段的这个脚本用来执行一个首要数据库的备份并还原它到备用节点。将此脚本放置在首要数据库示例的目录中并给它可执行权限。这里有一个用于配置了一个主节点和一个备节点的示例脚本 <a href="basebackup.sh">(basebackup.sh)</a> 。你需要设置 ssh 让 recovery_user 可以从首要节点登录到备用节点而不需要提供密码。

<pre>
recovery_1st_stage_command = 'basebackup.sh'
</pre>
<li>让 recovery_2nd_stage_command 保留为空。
<pre>
recovery_2nd_stage_command = ''
</pre>

<li>在每个数据库节点中安装必须的执行在线恢复的 C 和 SQL 函数。
</p>

<pre>
# cd pgpool-II-x.x.x/sql/pgpool-recovery
# make
# make install
# psql -f pgpool-recovery.sql template1
</pre>

<li>在完成在线恢复后,pgpool-II 将在备节点启动 PostgreSQL。在每个数据库节点中安装用于本用途的脚本。
<a href="pgpool_remote_start">示例脚本</a> 包含在源码的“sample”目录中。这个脚本使用了 ssh。你需要允许 recover_user 从首要节点登录到备用节点而不需要输入密码。
</ol>
</p>

<p>
以上未全部内容。现在你可以使用 pcp_recovery_node (作为备用节点的步骤)或者点击 pgpoolAdmin 的“恢复”按钮来执行在线恢复了。如果出现问题,请检查 pgpool-II 的日子,首要服务器的日志和备用服务器的日志。
</p>
<p>
作为参考,以下为恢复过程的步骤。
<ol>
<li>Pgpool-II 使用 user = recovery_user, password = recovery_password 连接到首要服务器的 template1 数据库。
<li>首要服务器执行 pgpool_recovery 函数。
<li>pgpool_recovery 函数执行 recovery_1st_stage_command。注意 PostgreSQL 在数据库实例的当前目录中执行函数。因此,recovery_1st_stage_command 在数据库实例的目录中执行。
<li>首要服务器执行 pgpool_remote_start 函数。本函数执行一个在数据库实例路径中名为“pgpool_remote_start”的脚本,它通过 ssh 在备用服务器上执行 pg_ctl 命令来进行恢复。pg_ctl 将在后台启动 postmaster。所以我们需要确保备用节点上的 postmaster 真正启动了。
<li>pgpool-II 尝试使用 user = recovery_user 和 password = recovery_password 连接到备用 PostgreSQL。如果可能,连接到的数据库为“postgres”。否则,使用“template1”。pgpool-II 尝试 <a href="#RECOVERY_TIMEOUT">recovery_timeout</a> 秒。如果成功,进行下一步。
<li>如果 <a href="#FAILBACK_COMMAND">failback_command</a> 不为空,pgpool-II 父进程执行这个脚本。
<li>在 failback_command 完成后,pgpool-II 重新启动所有的子进程。
</ol>
</p>

<p class="top_link"><a href="#Top">返回顶部</a></p>

<!-- ================================================================================ -->


<h1 id="parallel">并行模式</h3>

<p>本模式实现了查询的并行执行。表可以被分割,数据分布在每个节点中。而且,复制和负载均衡功能也可以同时使用。在并行模式中,pgpool.conf 中的 <a href="#REPLICATION_MODE">replication_mode</a><a href="#LOAD_BALANCE_MODE">load_balance_mode</a> 被设置为 ture,<a href="#MASTER_SLAVE_MODE">master_slave</a> 被设置为 false,<a href="#PARALLEL_MODE">parallel_mode</a> 被设置为 false。当你改变这些参数后,需要重启 pgpool-II。
</p>

<h2 id="system_db">配置 System DB</h2>

<p>如果想使用并行模式,System DB 需要被正确配置。System DB 包含存储在一个表中的,用于选择被分区的数据将被发送到的恰当后端程序的规则。
	System DB 不一定要和 pgpool-II 在同一台主机上。System DB 的配置由 <code>pgpool.conf</code> 完成。</p>

<dl>
  <dt><a name="SYSTEM_DB_HOSTNAME"></a>system_db_hostname</dt>
  <dd>
      <p>System DB 所在的主机名。给出空字符串('')表示 SystemDB 和 pgpool-II 在同一台主机,且将通过 UNIX 域套接字访问。</p>
  </dd>

  <dt><a name="SYSTEM_DB_PORT"></a>system_db_port</dt>
  <dd>
      <p>System DB 使用的端口号</p>
  </dd>

  <dt><a name="SYSTEM_DBNAME"></a>system_dbname</dt>
  <dd>
      <p>分区规则和其他的信息将被定义到这里指定的数据库中。默认值为:<code>'pgpool'</code></p>
  </dd>

  <dt><a name="SYSTEM_DB_SCHEMA"></a>system_db_schema</dt>
  <dd>
      <p>分区规则和其他的信息将被定义到这里指定的模式中。默认值为:<code>'pgpool_catalog'</code></p>
  </dd>

  <dt><a name="SYSTEM_DB_USER"></a>system_db_user</dt>
  <dd>
      <p>连接到 System DB 的用户名。</p>
  </dd>

  <dt><a name="SYSTEM_DB_PASSWORD"></a>system_db_password</dt>
  <dd>
      <p>连接到 System DB 的密码,如果不需要密码,则设置为空字符串('')。</p>
  </dd>

  <dt><a name="SSL_CA_CERT"></a>ssl_ca_cert</dt>
  <dd>
      <p>
      	到达用于校验后台服务器的 PEM 格式的包含一个或者多个 CA 根证书的文件的路径。这类似于 OpenSSL 的 <code>verify(1)</code> 命令的 <code>-CAfile</code> 选项。
      </p>
      <p>
      	默认值为未设置,也就是不进行认证。如果本选项未设置但是 <code>ssl_ca_cert_dir</code>被设置了,则认证过程依旧会发生。
      </p>
  </dd>

  <dt><a name="SSL_CA_CERT_DIR"></a>ssl_ca_cert_dir</dt>
  <dd>
      <p>
      	到达包含用于校验后台服务器的 PEM 格式的 CA 证书的目录的路径。这类似于 OpenSSL 的 <code>verify(1)</code> 命令的 <code>-CApath</code> 选项。
      </p>
      <p>
      	默认值为未设置,也就是不进行认证。如果本选项未设置但是 <code>ssl_ca_cert</code> 被设置了,则认证过程依旧会发生。
      </p>
  </dd>

</dl>

<h2 id="system_db_sql">初始化 System DB 的配置</h2>

<p>首先,需要建立 <code>pgpool.conf</code> 文件中指定的数据库和模式。可以在 <code>$prefix/share/system_db.sql</code> 找到一个示例脚本。如果你指定了不同的数据库名和模式,在脚本中相应地修改它们。
</p>
<pre>
psql -f $prefix/share/system_db.sql pgpool
</pre>

</p>

<h3 id="distdef">注册一条分区规则</h3>

<p>用于数据分区的规则必须被注册到 <code>pgpool_catalog.dist_def</code> 表中。</p>

<pre>
CREATE TABLE pgpool_catalog.dist_def(
dbname TEXT,                                              -- database name
schema_name TEXT,                                         -- schema name
table_name TEXT,                                          -- table name
col_name TEXT NOT NULL CHECK (col_name = ANY (col_list)), -- partitioning key column name
col_list TEXT[] NOT NULL,                                 -- names of table attributes
type_list TEXT[] NOT NULL,                                -- types of table attributes
dist_def_func TEXT NOT NULL,                              -- name of the partitioning rule function
PRIMARY KEY (dbname,schema_name,table_name)
);
</pre>

<h3 id="replicate_def">注册一条复制规则</h3>
<p>
未被分发的表必须被复制. 当一个查询对一个分发表和另外一个表进行连接时,pgpool-II 从 pgpool_catalog.replicate_def 表获取复制信息。一个表只能被复制或被分发。
</p>

<pre>
CREATE TABLE pgpool_catalog.replicate_def(
	dbname TEXT,	    --database name
	schema_name TEXT,	--schema name 
	table_name TEXT,	--table name
	col_list TEXT[] NOT NULL,	-- names of table attributes
	type_list TEXT[] NOT NULL,	-- types of table attributes
	PRIMARY KEY (dbname,schema_name,table_name)
);
</pre>

<h2 id="example_partitioning">对 pgbench 表的分区示例</h2>

<p>
在这个示例中,accounts 表被分区,branches 和 tellers 表被复制。accounts 表和 branches 表通过 bid 进行连接。branches 表注册到复制表中,若这三个表(accounts, branches 和 tellers)将被连接的话,有必要也为 tellers 表注册一条复制规则。
</p>
<pre>
INSERT INTO pgpool_catalog.dist_def VALUES (
	'pgpool',
	'public',
	'accounts',
	'aid',
	ARRAY['aid','bid','abalance','filler'],
	ARRAY['integer','integer','integer','character(84)'],
	'pgpool_catalog.dist_def_accounts'
);

INSERT INTO pgpool_catalog.replicate_def VALUES (
	'pgpool',
	'public',
	'branches',
	ARRAY['bid','bbalance','filler'],
	ARRAY['integer','integer','character(84)']
);
</pre>

<p>分区规则函数(此处是 pgpool_catalog.dist_def_accounts )需要一个值作为分区的关键字列,并返回相应的DB节点ID。注意节点ID必须从0开始,
下面是为pgbench写的函数示例。
</p>
<pre>
CREATE OR REPLACE FUNCTION pgpool_catalog.dist_def_accounts (val ANYELEMENT) RETURNS INTEGER AS '
SELECT CASE WHEN $1 >= 1 and $1 <= 30000 THEN 0
WHEN $1 > 30000 and $1 <= 60000 THEN 1
ELSE 2
</pre>

<p class="top_link"><a href="#Top">返回顶部</a></p>

<!-- ================================================================================ -->

<h1><a name="hba"></a>设置用于客户端认证(HBA)的 pool_hba.conf</h1>

<p>
和 PostgreSQL 中使用的 pg_hba.conf 文件类似,pgpool-II 使用一个称之为 "pool_hba.conf" 的配置文件来支持类似的客户端认证功能。
</p>
<p>
当安装 pgpool 的时候,pool_hba.conf.sample 文件将被安装在"/usr/local/etc"目录下,该位置也是配置文件的默认目录。拷贝 pool_hba.conf.sample 为 pool_hba.conf,如果必要的话并修改它。默认的情况下,<a href="#ENABLE_POOL_HBA">enable_pool_hba</a> 认证被开启。 
</p>
<p>
	pool_hba.conf 文件的格式和 PostgreSQL 的 pg_hba.conf 的格式遵循的非常相近。
</p>
<pre>
    local      DATABASE  USER  METHOD  [OPTION]
    host       DATABASE  USER  CIDR-ADDRESS  METHOD  [OPTION]
</pre>
<p>
  查看 "pool_hba.conf.sample" 文件获取每个字段详细的解释。
</p>
<p>
  下面是 pool_hba 的一些限制。
<ul>
<li>"hostssl" 连接类型不被支持</li>
<p>
    尽管"hostssl"不能被使用,pgpool-II 2.3或更高版本支持SSL,详见<a href="#ssl">SSL</a></p>
<li>DATABASE 字段使用的"samegroup" 不被支持</li>
<p>
    尽管 pgpool 并不知道后端服务器的用户的任何信息,但是将通过 pool_hba.conf 中的 DATABASE 字段项对数据库名进行简单的检查。   
</p>
<li>USER 字段使用的 group 名字后面跟个"+"不被支持 </li>
<p>
    这与上面介绍的 "samegroup" 原因相同,将通过 pool_hba.conf 中 USER 字段项对用户名进行简单的检查。
</p>
<li>为 IP address/mask 使用的 IPv6 不被支持</li>
<p>
    pgpool 当前不支持 IPv6.
</p>
<li>METHOD 字段仅仅支持 "trust", "reject", "md5" 和 "pam" </li>
<p>
    再次,这与上面介绍的 "samegroup" 原因相同, pgpool 不能够访问 user/password 信息。
</p>
<p>
要使用md5认证,你需要在 "pool_passwd" 中注册你的名字和密码。详见<a href="#md5">认证/访问控制</a></ul>
<p>
	注意本节描述的所有认证发生在客户端和 pgpool-II 之间;客户端仍然需要继续通过 PostgreSQL 的认证过程。
	pool_hba 并不关心客户端提供的用户名/数据库名(例如 psql -U testuser testdb)是否真实存在于后端服务器中。pool_hba 仅仅关心是否在 pool_hba.conf 中存在匹配。
</p>

<p>
	PAM 认证使用 pgpool 运行的主机上的用户信息来获得支持。若让 pgpool 支持PAM,需要在 configure 时指定"--with-pam"选项。
</p>
<pre>
    configure --with-pam
</pre>
<p>
  若启用 PAM 认证,你需要为 pgpool 在系统的 PAM 配置目录(通常是在"/etc/pam.d")中创建一个 service-configuration 文件。
  一个 service-configuration 的示例文件被安装为安装目录下的"share/pgpool.pam"。
</p>

<h1 id="query_cache">设置 Query cache 方法 <span class="version">- V3.1 (已废弃)</span></h1>

<strong>注意:这个(基于磁盘的)查询缓存功能将在不久后被移除。
清使用<a href="#memqcache">基于内存的查询缓存</a>代替。
</strong>

<p> Query cache 可以在 pgpool-II 的所有模式中使用。在 pgpool.conf 中启用它如下:</p>
<pre>
enable_query_cache = true
</pre>

<p>
你还需要在 System DB 中创建下面的表:
</p>
<pre>
CREATE TABLE pgpool_catalog.query_cache (
  hash TEXT,
  query TEXT,
  value bytea,
  dbname TEXT,
  create_time TIMESTAMP WITH TIME ZONE,
  PRIMARY KEY(hash, dbname)
);
</pre>
<p>
	然而,如果你不使用"pgpool_catalog"的话,你可能需要修改该语句中的 schema。
</p>
<p>
<strong>注意:当前的查询缓存的实现方法为在数据库中建立缓存数据。因此启用查询缓存可能会导致达不到最高的性能。即使相关的表被更新了,查询缓存的内容不会更新。你需要从缓存的表中删除缓存的数据或者通过 -c(删除缓存) 参数重启 pgpool-II。
</strong>
</p>

<h1><a name="memqcache"></a> 基于内存的查询缓存 <span class="version">V3.2 -</span></h1>

<p>你可以在任何模式中使用基于内存的查询缓存。它不同于以上的查询缓存,因为基于内存的查询缓存会快很多,因为缓存存储于内存中。
	另外,如果缓存事小了,你不需要重启 pgpool-II 因为相关的表已经得到更新了。
</p>

<p>基于内存的缓存保存 SELECT 语句(以及它绑定的参数,如果 SELECT 是一个扩展的查询)以及对应的数据。
如果是相同的 SELECT 语句,则直接返回缓存的值。因为不再有 SQL 分析或者到 PostgreSQL 的调用,实际上它会非常快。
</p>

<p>
其他方面,它会比较慢,因为它增加了一些负载用于缓存。另外,当一个表被更新,pgpool 自动删除相关的表的缓存。
因此,在有很多更新的系统中,性能会降低。如果 cache_hit_ratio 低于 70%,建议你关闭基于内存的缓存。
</p>

<h2 id="MEMORY_CACHE_RESTRICTIONS">限制</h2>
<ul>
    <li>
    基于内存的查询缓存通过监视 UPDATE,INSERT,ALTER TABLE一类的查询语句来自动删除缓存的数据。
    但 pgpool-II 无法发现通过触发器、外键和 DROP TABLE CASCADE 产生的非显式的更新。
    你可以通过配置 <a href="#MEMQCACHE_EXPIRE">memqcache_expire</a> 让 pgpool 在固定时间周期内自动删除缓存来避免这个问题,
    你也可以通过配置 <a href="#BLACK_MEMQCACHE_TABLE_LIST">black_memqcache_table_list</a> 来让 pgpool 的基于内存的缓存忽略指定的表。
    </li>

    <li>
    如果你使用 pgpool-II 的多个实例来使用共享内存进行缓存,可能出现一个 pgpool 发现表被更新了因而删除了缓存,但另一个依旧使用旧的缓存。
    对于这种情况,使用 memcached 是一个更好的策略。
    </li>
</ul>

<h2 id="MEMORY_CACHE_ENABLED">启用基于内存的查询缓存</h2>
<p>
要启用基于内存的查询缓存,设置以下选项为 on(默认为 off)。
</p>

<pre>
memory_cache_enabled = on
</pre>

<h2 id="MEMQCACHE_METHOD">选择缓存存储</h2>
<p>
你可以选择一个缓存策略:共享内存或者 <a href="http://memcached.org">memcached</a>(不能同时使用)。
使用共享内存的查询缓存很快且简单,因为你不需要安装和配置 memcached,但缓存的最大数量限制于共享内存。
使用 memcached 的查询缓存需要更多的负载用于访问网络,但你可以任意设置你需要的大小。
</p>
<p>
可以通过 memqcache_method 指定内存缓存的行为。可以是 “shmem”(共享内存) 或者 “memcached”。默认为 shmem。
</p>
<pre>
memqcache_method = 'shmem'
</pre>


<h2 id="memqcache_cases">基于内存缓存被禁用的情况</h2>
<p>
并非所有的 SELECT 和 WITH 语句可以被缓存。在包括以下列表的一些情况,为了保证数据库和缓存的一致性,缓存被避免了。
</p>
<ul>
    <li>SELECT 语句以 "/*NO QUERY CACHE*/" 注释开始</li>
    <li>SELECT 包含以下表的 <a href="#BLACK_MEMQCACHE_TABLE_LIST">black_memqcache_table_list</a></li>
    <li>SELECT FOR SHARE / UPDATE</li>
    <li>SELECT 包含 un-immutable 函数</li>
    <li>SELECT 包含 TEMP TABLE</li>
    <li>SELECT 包含 系统对象</li>
	  <li>SELECT 包含 VIEW 和 不记录日志的表。但如果表在 <a href="#WHITE_MEMQCACHE_TABLE_LIST">white_memqcache_table_list</a> 中,结果还是会被缓存的。</li>

    <li>SELECT 包含 VIEW </li>
    <li>SELECT 在一个被终止的显示事务中</li>
    <li>SELECT 结果超出 <a href="#MEMQCACHE_MAXCACHE">memqcache_maxcache</a></li>
</ul>

<h2 id="non_memqcache_case">缓存不被使用的情况</h2>
<p>
存在一些情况,及时匹配的查询缓存存在,pgpool 也不返回结果。
</p>
<ul>
    <li>如果一个更新擦做在一个显式的事务中执行,在事务中,pgpool 不使用查询缓存。</li>
    <li>匹配的查询是由其他用户(因为安全原因)生成的。</li>
    <li>匹配的查询由于 <a href="#MEMQCACHE_EXPIRE">memqcache_expire</a> 设置而需要被删除。</li>
</ul>

<h2 id="memqcache_params">配置</h2>

<p>
以下参数可以同时用于 shmem 和 memcached。
</p>

<dl>
<dt id="MEMQCACHE_EXPIRE">memqcache_expire <span class="version">V3.2 -</span></dt>
    <dd>
    <p>
    查询缓存的生命周期,默认为 0。0 表示没有缓存超时,而且缓存被启用直到表被更新。
    本参数和 <a href="#MEMQCACHE_AUTO_CACHE_INVALIDATION">memqcache_auto_cache_invalidation</a> 是相交的。
    </p>
    </dd>

<dt id="MEMQCACHE_AUTO_CACHE_INVALIDATION">memqcache_auto_cache_invalidation
<span class="version">V3.2 -</span></dt>
    <dd>
    <p>
    如果为 on,则在表被更新的时候自动删除相关的缓存。
    如果为 off,则不删除缓存。默认为 on。
    本参数和 <a href="#MEMQCACHE_EXPIRE">memqcache_expire</a> 相交。
    </p>
    </dd>

<dt id="MEMQCACHE_MAXCACHE">memqcache_maxcache <span class="version">V3.2 -</span></dt>
    <dd>
        <p>
        如果 SELECT 结果集的大小超出了 memqcache_maxcache 字节,则不缓存且显示以下消息:
        </p>
<pre>
2012-05-02 15:08:17 LOG:   pid 13756: pool_add_temp_query_cache: data size exceeds memqcache_maxcache. current:4095 requested:111 memq_maxcache:4096
</pre>
        <p>
        要避免这个问题,你需要将 memqcache_maxcache 设置得大一些。
        但如果你使用共享内存作为缓存策略,它必须小于 <a href="#MEMQCACHE_CACHE_BLOCK_SIZE">memqcache_cache_block_size</a>。
        如果是 memchached,她必须小于 slab 的大小(默认为 1 MB)。
        </p>
    </dd>

<dt id="WHITE_MEMQCACHE_TABLE_LIST">white_memqcache_table_list <span class="version">V3.2 -</span></dt>
    <dd>
    <p>
    指定一个以逗号分隔的表名的列表,用于使 SELECT 的结果被缓存,也可以是视图或者不写日志的表。可以使用正则表达式。
    </p>
    <p>
    同时存在于 white_memqcache_table_list 和 <a href="#BLACK_MEMQCACHE_TABLE_LIST">black_memqcache_table_list</a> 的表和视图将被缓存。
    </p>
    </dd>

<dt id="BLACK_MEMQCACHE_TABLE_LIST">black_memqcache_table_list <span class="version">V3.2 -</span></dt>
    <dd>
    <p>
    	指定一个以逗号分隔的表名的列表,用于使 SELECT 的结果不被缓存,也可以是视图或者不写日志的表。可以使用正则表达式。
    </p>
    </dd>

<dt id="MEMQCACHE_OIDDIR">memqcache_oiddir <span class="version">V3.2 -</span></dt>
    <dd>
    <p>
    用于 SELECT 的存储表的 OID 的目录的完整路径。在 memqcache_oiddir 下有使用数据库 oid 命名的目录,
    每个目录之下是在 SELECT 中使用的以表的 oid 命名的文件。在文件中,存储了查询缓存。它们是用于删除缓存的关键。
    </p>
    <p>
    在 memqcache_oiddir 下的目录和文件不会被删除,即使 pgpool-II 重启。
    如果你使用 "<a href="#start">pgpool -C</a>" 启动 pgpool,则 pgpool 使用旧的 oid 映射。
    </p>
    </dd>
</dl>

<h2 id="monitoring_memqcache">监控缓存</h2>
<p>
这里讲述如何监控查询缓存。要知道一个 SELECT 的结果是不是从查询缓存获得,需要启用 <a href="#LOG_PER_NODE_STATEMENT">log_per_node_statement</a></p>
<pre>
2012-05-01 15:42:09 LOG:   pid 20181: query result fetched from cache. statement: select * from t1;
</pre>

<p>
<a href="#pool_status">pool_status</a> 命令显示缓存的命中率。
</p>
<pre>
memqcache_stats_start_time           | Tue May  1 15:41:59 2012 | Start time of query cache stats
memqcache_no_cache_hits              | 80471                    | Number of SELECTs not hitting query cache
memqcache_cache_hits                 | 36717                    | Number of SELECTs hitting query cache
</pre>


<p>
在本例中,你可以通过以下方法计算:
</p>
<p>
<pre>
(memqcache_cache_hits) / (memqcache_no_cache_hits+memqcache_cache_hits) = 36717 / (36717 + 80471) = 31.3%
</pre>

<p>
<a href="#pool_cache">show pool_cache</a> 也显示相同的结果。
</p>

<h2 id="shmem_params">配置使用共享内存</h2>
<p>
以下为用于共享内存缓存策略的参数。
</p>

<dl>
<dt id="MEMQCACHE_TOTAL_SIZE">memqcache_total_size <span class="version">V3.2 -</span></dt>
    <dd>
    <p>
    指定用于缓存的共享内存的大小,单位为字节。
    </p>
    </dd>

<dt id="MEMQCACHE_MAX_NUM_CACHE">memqcache_max_num_cache <span class="version">V3.2 -</span></dt>
    <dd>
    <p>
    制定缓存的项目数。这用于定义缓存管理空间的大小。(你需要它来协助 <a href="#MEMQCACHE_TOTAL_SIZE">memqcache_total_size</a> 参数)。
    可以使用以下方法计算缓存管理空间的大小:<a href="#MEMQCACHE_MAX_NUM_CACHE">memqcache_max_num_cache</a> * 48 字节。
    如果数量太小,则注册缓存的时候会报错。但如果太大则浪费空间。
    </p>
    </dd>

<dt id="MEMQCACHE_CACHE_BLOCK_SIZE">memqcache_cache_block_size <span class="version">V3.2 -</span></dt>
    <dd>
    <p>
    如果缓存存储是共享内存,pgpool 使用内存除以 memqcache_cache_block_size。SELECT 的结果被放入块中。
    但是因为 SELECT 的结果不能被放入多个块中,它无法缓存大于 memqcache_cache_block_size 的结果。
    memqcache_cache_block_size 必须大于或等于 512。
    </p>
    </dd>
</dl>

<h2 id="memcached_params">配置使用 memcached</h2>

<p>
以下为用于 memcached 缓存策略的参数。
</p>

<dl>
<dt id="MEMQCACHE_MEMCACHED_HOST">memqcache_memcached_host <span class="version">V3.2 -</span></dt>
    <dd>
    <p>
    指定 memcached 工作的主机的主机名或 IP 地址。如果和 pgpool-II 在同一台机器,设置为 'localhost'。
    </p>
    </dd>

<dt id="MEMQCACHE_MEMCACHED_PORT">memqcache_memcached_port <span class="version">V3.2 -</span></dt>
    <dd>
    <p>
    指定 memcached 的端口。默认为 11211。
    </p>
    </dd>
</dl>


<h3 id="install_memcached">memcached 安装</h3>

<p>
要使用 memcached 作为缓存策略,pgpool-II 需要配合 memcached 和其客户端 libmemcached 使用。
通过 rpm 安装很简单。这里讲解如何使用源码安装。
</p>

<p>
可以在以下位置获得 memcached 的源码:
<a href="http://memcached.org/">memcached development page</a>
</p>

<dl>
<dt>configure</dt>
    <dd>
    <p>
    在解压源码包后,执行配置脚本。
    </p>
<pre>
./configure
</pre>
    </dd>

<dt>make</dt>
    <dd>
<pre>
make
make install
</pre>
    </dd>
</dl>

<h3 id="install_libmemcached">libmemcached 安装</h3>

<p>
Libmemcached 是 memcached 的客户端库。你需要在安装 memcached 后安装 libmemcached。
</p>

<p>
可以在以下位置获得 libmemcached 的源码:
<a href="http://libmemcached.org/libMemcached.html">libmemcached development page</a>
</p>

<dl>
<dt>configure</dt>
    <dd>
    <p>
    在解压源码包后,执行配置脚本。
    </p>
<pre>
./configure
</pre>

    <p>
    如果你不想使用默认值,一些可选项为:
    </p>

    <ul>
        <li><code>--with-memcached=path</code><br/>
        安装 Memcached 的顶层目录。</li>
    </ul>
    </dd>

<dt>make</dt>
    <dd>
<pre>
make
make install
</pre>
    </dd>
</dl>

<p class="top_link"><a href="#Top">回到顶部</a></p>

<!-- ================================================================================ -->

<h1>启动/停止 pgpool-II<a name="start"></a></h1>

<h2 id="start_pgpool">启动 pgpool-II</h2>

<p>所有后端服务器和System DB(若需要)都必须在启动 pgpool-II 之前启动。
</p>

<pre>
pgpool [-c][-f config_file][-a hba_file][-F pcp_config_file][-n][-D][-d]
</pre>

<table border>
  <tr><td>-c</td><td>--clear-cache</td>
      <td>删除 query cache</td></tr>
  <tr><td>-f config_file</td><td>--config-file config-file</td>
      <td>指定 pgpool.conf</td></tr>
  <tr><td>-a hba_file</td><td>--hba-file hba_file</td>
       <td>指定 pool_hba.conf</tr>
  <tr><td>-F pcp_config_file</td><td>--pcp-password-file</td>
      <td>指定 pcp.conf</td></tr>
  <tr><td>-n</td><td>--no-daemon</td>
      <td>非守护进程模式(不脱离终端运行)</td></tr>
  <tr><td>-D</td><td>--discard-status</td>
      <td>忽略 pgpool_status 文件且不恢复到先前的状态
      <span class="version">V3.0 -</span></td></tr>
  <tr><td>-C</td><td>--clear-oidmaps</td>
      <td>忽略用于基于内存的查询缓存的 <a href="#MEMQCACHE_OIDDIR">memqcache_oiddir</a> 中的 oid 映射文件
      (仅当 <a href="#MEMQCACHE_METHOD">memqcache_method</a> 为 'memcached'时有效),
      如果是 shm,则总是忽略。
      <span class="version">V3.2 -</span></td></tr>
  <tr><td>-d</td><td>--debug</td><td>调试模式</tr>
</table>

<h2 id="stop_pgpool">Stop pgpool-II</h2>
<p>
有两种方式来关闭 pgpool-II。一种是使用 PCP 命令(后面介绍),另外一种是使用 pgpool-II 命令。下面是使用 pgpool-II 命令的示例。
</p>

<pre>
pgpool [-f config_file][-F pcp_config_file] [-m {s[mart]|f[ast]|i[mmediate]}] stop
</pre>

<table border>
  <tr><td><code>-m s[mart]</code></td><td><code>--mode s[mart]</code></td>
      <td>等待客户端断开连接,然后关闭(默认)</td></tr>
  <tr><td><code>-m f[ast]</code></td><td><code>--mode f[ast]</code></td>
      <td>并不等待客户端; 立即关闭</td></tr>
  <tr><td><code>-m i[mmediate]</code></td><td><code>--mode i[mmediate]</code></td>
      <td>等同于 <code>'-m f'</code></td></tr>
</table>

<p>
	pgpool 记录后端服务器的状态到 [logdir]/pgpool_status 文件中,当 pgpool 重启时,它读该文件并恢复后端服务器的状态。
	这将避免可能由于下述原因造成的DB节点间的具有不同的数据:
<ol>
<li>一个后端服务器突然停止,然后pgpool执行恢复程序
<li>一个update通过pgpool出现在一个活动的DBs上
<li>管理员决定停止pgpool
<li>其它人决定重启已停止的DB但并没通知管理员
<li>管理员重启pgpool
</ol>
</p>
<p>
	如果由于某些原因,例如,停止的DB已经通过其它另外的方式已经获得了同步,则 pgpool_status 可在启动 pgpool 之前被安全的移除。
</p>

<p class="top_link"><a href="#Top">回到顶部</a></p>

<!-- ================================================================================ -->

<h1>重新加载 pgpool-II 配置文件<a name="reload"></a></h1>
<p>pgpool-II 能够不需要重启而重新加载配置文件。
</p>

<pre>
pgpool [-c][-f config_file][-a hba_file][-F pcp_config_file] reload
</pre>
<p>

<table border>
  <tr><td>-f config_file</td><td>--config-file config-file</td><td>指定 pgpool.conf</tr>
  <tr><td>-a hba_file</td><td>--hba-file hba_file</td><td>指定 pool_hba.conf</tr>
  <tr><td>-F pcp_config_file</td><td>--pcp-password-file</td><td>指定 pcp.conf</tr>
</table>

<p>
	需要指出的是,一些配置项并不能通过重新加载来改变。新的修改后的配置将在新会话上生效。
</p>

<p class="top_link"><a href="#Top">回到顶部</a></p>

<!-- ================================================================================ -->

<h1><a name="show-commands"></a>SHOW 命令</h1>
<h2>概述</h2>
<p>
pgpool-II 通过 SHOW 命令提供一些信息。SHOW 是一个真实的 SQL 语句, 但是如果该命令查询 pgpool-II 信息的话,pgpool-II 解释了该命令。可用选项如下:
<ul>
  <li>pool_status, 获取配置</li>
  <li>pool_nodes, 获取节点信息 <span class="version">V3.0 -</span></li>
  <li>pool_processes, 获取pgPool-II 进程信息 <span class="version">V3.0 -</span></li>
  <li>pool_pools, 获取pgPool-II 所有的连接池信息 <span class="version">V3.0 -</span></li>
  <li>pool_version, 获取pgPool_II 版本信息 <span class="version">V3.0 -</span></li>
</ul>
<p>除 "pool_status" 之外的选项都是从 pgpool-II 3.0 开始添加的。
<p>
<u>注意</u>:术语 'pool' 指的是一个 pgpool 进程所拥有的 PostgreSQL 会话池,并非指所有的 pgpool 所拥有的会话。
</p> 
</p>
<p>SQL语句中的 "pool_status" 在以前的版本中已经存在,但是其它可选项在 3.0 中才出现。
</p>
<h2>pool_status</h2>
<p>"SHOW pool_status" 返回配置参数列表,包含参数的 name, value, 和 description。下面是返回结果的一个摘录:
<pre>
benchs2=# show pool_status;
                 item                 |             value              |                           description
--------------------------------------+--------------------------------+------------------------------------------------------------------
 listen_addresses                     | localhost                      | host name(s) or IP address(es) to listen to
 port                                 | 9999                           | pgpool accepting port number
 socket_dir                           | /tmp                           | pgpool socket directory
 pcp_port                             | 9898                           | PCP port # to bind
 pcp_socket_dir                       | /tmp                           | PCP socket directory
</pre>
</p>
<h2>pool_nodes <span class="version">V3.0 -</span></h2>
<p>"SHOW pool_nodes" 返回所有配置节点的列表.它显示了节点的 id, hostname, port, status, 以及权重 weight (仅在使用负载均衡模式时有意义)。status 列可能的值可在 <a href="#pcp_node_info">pcp_node_info reference</a> 里获得解释。
<pre>
benchs2=# show pool_nodes;
  id  |  hostname   | port | status | lb_weight |  role
------+-------------+------+--------+-----------+---------
   0  | 127.0.0.1   | 5432 | 2      | 0.5       | primary
   1  | 192.168.1.7 | 5432 | 3      | 0.5       | standby
(2 lignes)
</pre>
</p>
<h2>pool_processes <span class="version">V3.0 -</span></h2>
<p>"SHOW pool_processes" 返回 pgpool-II 所有进程的信息,这些进程正等待连接或在处理一个连接。
</p>
<p>
结果有 6 列:
<ul>
<li>pool_pid 是显示的pgPool-II进程的PID</li>
<li>start_time 是该进程启动时的时间戳</li>
<li>database 是该进程当前连接的活跃的后台数据库名</li>
<li>username 是该进程当前连接的活跃的后台用户名</li>
<li>create_time 是连接的的创建时间和日期</li>
<li>pool_counter 计数客户端使用该连接池(进程)的次数</li>
</ul>
</p>
<p>结果将一直返回 num_init_children 行。</p>
<pre>
benchs2=# show pool_processes;
 pool_pid |     start_time      | database | username  |     create_time     | pool_counter 
----------+---------------------+----------+-----------+---------------------+--------------
 8465     | 2010-08-14 08:35:40 |          |           |                     | 
 8466     | 2010-08-14 08:35:40 | benchs   | guillaume | 2010-08-14 08:35:43 | 1
 8467     | 2010-08-14 08:35:40 |          |           |                     | 
 8468     | 2010-08-14 08:35:40 |          |           |                     | 
 8469     | 2010-08-14 08:35:40 |          |           |                     | 
(5 lines)
</pre>
<h2>pool_pools <span class="version">V3.0 -</span></h2>
<p>"SHOW pool_pools" 返回 pgpool-II 所处理的连接池列表,包含它们的 name, value, 和 description,下面是结果的一个摘录:
</p>
<p>
共 11 列:
<ul>
<li>pool_pid 是 pgpool-II 进程的PID</li>
<li>start_time 是该进程启动时的时间和日期</li>
<li>pool_id is 是连接池的标识符 (应该在 0 到 max_pool-1之间)</li>
<li>backend_id 是后端服务器的标识符(应该在0到最大配置的后端服务器数-1之间)</li>
<li>database 是该进程的连接池所连接的数据库名</li>
<li>username 是该进程的连接池所连接的用户名</li>
<li>create_time 是该连接的创建时间和日期</li>
<li>majorversion and minorversion 是该连接使用的协议版本</li>
<li>pool_counter 计数客户端使用该连接的次数</li>
<li>pool_backendpid 是PostgreSQL 进程的PID </li>
<li>pool_connected 如果前端正使用该后端服务器时是true (1).</li>
</ul>
</p>
<p>结果将一直返回 <a href="#NUM_INIT_CHILDREN">num_init_children</a> * <a href="#MAX_POOL">max_pool</a> 行.</p>
<pre>
 pool_pid |     start_time      | pool_id | backend_id | database | username  |     create_time     | majorversion | minorversion | pool_counter | pool_backendpid | pool_connected 
----------+---------------------+---------+------------+----------+-----------+---------------------+--------------+--------------+--------------+-----------------+----------------
 8465     | 2010-08-14 08:35:40 | 0       | 0          |          |           |                     |              |              |              |                 | 
 8465     | 2010-08-14 08:35:40 | 1       | 0          |          |           |                     |              |              |              |                 | 
 8465     | 2010-08-14 08:35:40 | 2       | 0          |          |           |                     |              |              |              |                 | 
 8465     | 2010-08-14 08:35:40 | 3       | 0          |          |           |                     |              |              |              |                 | 
 8466     | 2010-08-14 08:35:40 | 0       | 0          | benchs   | guillaume | 2010-08-14 08:35:43 | 3            | 0            | 1            | 8473            | 1
 8466     | 2010-08-14 08:35:40 | 1       | 0          |          |           |                     |              |              |              |                 | 
 8466     | 2010-08-14 08:35:40 | 2       | 0          |          |           |                     |              |              |              |                 | 
 8466     | 2010-08-14 08:35:40 | 3       | 0          |          |           |                     |              |              |              |                 | 
 8467     | 2010-08-14 08:35:40 | 0       | 0          |          |           |                     |              |              |              |                 | 
 8467     | 2010-08-14 08:35:40 | 1       | 0          |          |           |                     |              |              |              |                 | 
 8467     | 2010-08-14 08:35:40 | 2       | 0          |          |           |                     |              |              |              |                 | 
 8467     | 2010-08-14 08:35:40 | 3       | 0          |          |           |                     |              |              |              |                 | 
 8468     | 2010-08-14 08:35:40 | 0       | 0          |          |           |                     |              |              |              |                 | 
 8468     | 2010-08-14 08:35:40 | 1       | 0          |          |           |                     |              |              |              |                 | 
 8468     | 2010-08-14 08:35:40 | 2       | 0          |          |           |                     |              |              |              |                 | 
 8468     | 2010-08-14 08:35:40 | 3       | 0          |          |           |                     |              |              |              |                 | 
 8469     | 2010-08-14 08:35:40 | 0       | 0          |          |           |                     |              |              |              |                 | 
 8469     | 2010-08-14 08:35:40 | 1       | 0          |          |           |                     |              |              |              |                 | 
 8469     | 2010-08-14 08:35:40 | 2       | 0          |          |           |                     |              |              |              |                 | 
 8469     | 2010-08-14 08:35:40 | 3       | 0          |          |           |                     |              |              |              |                 | 
(20 lines)
</pre>

<h2 id="pool_version">pool_version <span class="version">V3.0 -</span></h2>
<p>"SHOW pool_version" 将显示包含 pgpool-II 版本号的一个字符串。下面是一个示例:</p>
<pre>
benchs2=# show pool_version;
      pool_version
------------------------
 3.0-dev (umiyameboshi)
(1 line)
</pre>

<h2 id="pool_cache">pool_cache <span class="version">V3.0 -</span></h2>
<p>"SHOW pool_cache" 显示启用 <a href="#memqcache">on memory query cache</a> 时缓存的存储统计。以下为一个示例:
</p>

<pre>
test=# \x
\x
Expanded display is on.
test=# show pool_cache;
show pool_cache;
-[ RECORD 1 ]---------------+---------
num_cache_hits              | 891703
num_selects                 | 99995
cache_hit_ratio             | 0.90
num_hash_entries            | 131072
used_hash_entries           | 99992
num_cache_entries           | 99992
used_cache_enrties_size     | 12482600
free_cache_entries_size     | 54626264
fragment_cache_entries_size | 0
</pre>

<ul>
<li>num_cache_hits  表示命中缓存的 SELECT 语句数量。</li>
<li>num_selects  表示未命中缓存的 SELECT 语句数量。</li>
<li>
cache_hit_ratio  表示缓存的命中率,算法为 num_cache_hits/(num_cache_hits+num_selects)。
<br>num_hash_entries 之下的任何项目仅仅在缓存为共享内存的情况下有效。
</li>
<li>
num_hash_entries  表示哈希表中的项目数,它用于索引缓存存储,其应该和 pgpool.conf 中的
<a href="#MEMQCACHE_MAX_NUM_CACHE">memqcache_max_num_cache</a> 相同。这是缓存条目的上限。
</li>
<li>used_hash_entries  表示 num_hash_entries 中已经使用的项目。</li>
<li>num_cache_entries  表示缓存存储中有效的缓存项目数,应该等于 used_hash_entries。</li>
<li>used_cache_entries_size  表示已经使用的总共缓存存储字节数。</li>
<li>free_cache_entries_size  表示未使用或者说可用的总共缓存存储字节数。</li>
<li>fragment_cache_entries_size  表示由于是碎片而无法使用的总共缓存存储字节数。</li>
<li>如果 free_cache_entries_size 变成 0(或者没有足够的空间存储 SELECT 的结果),则碎片区域可以被重用。</li>
</ul>

<p class="top_link"><a href="#Top">返回顶部</a></p>

<!-- ================================================================================ -->

<h1><a name="online-recovery"></a>在线恢复</h1>
<h2>概述</h2>
<p>
pgpool-II,在复制模式下在给客户端提供服务的同时,能够同步一个数据库并关联(attach)一个节点,我们称这项特性为"在线恢复"。
</p>

<p>
在执行在线恢复之前,一个恢复的目标节点必须处于 detached 状态。如果你想动态的增加一个 PostgreSQL server,则在pgpool.conf中增加'backend_hostname'及其相关的参数并重新加载该配置文件。 pgpool-II 把该新的节点注册为 detached 节点。
</p>

<p>
<font color="red">
注意:停止 master 节点(第一个启动和运行的节点)上的autovacuum。如果Autovacuum运行的话,它可能会改变数据的内容并可能造成在线恢复后的不一致性。这仅适用于使用简单的复制机制的恢复,例如下文将会讨论的 rsync 方式,而对使用 PostgreSQL 的PITR机制进行在线恢复的并不适用。
</font>
</p>

<p>
  若目标 PostgreSQL 服务器已经启动开,你需要关闭它。
</p>

<p>
pgpool-II 以两个阶段来执行在线恢复。当一个恢复节点同步数据库时,客户端可能需要等待几秒到几分钟不等的时间来连接 pgpool-II。下面是这些步骤:
  <ol>
    <li> CHECKPOINT
    <li> 在线恢复的第一阶段
    <li> 等待所有的客户端连接断开
    <li> CHECKPOINT
    <li> 在线恢复的第二阶段
    <li> 启动 postmaster (执行 <a href="#pool_remote_start">pgpool_remote_start</a><li> 节点连接上来
  </ol>
</p>

<p>
   数据同步的第一个步称之为"第一阶段"。 数据在第一阶段中被同步,在第一阶段中,数据<b>能够</b>被并行的从任意表更新或获取。
</p>

<p>
	你可以指定第一阶段中执行的脚本。pgpool-II传递三个参数到该脚本中。
  <ol>
    <li>主节点的数据库实例路径。
    <li>被恢复的目标节点的主机名
    <li>被恢复的目标节点的数据库实例路径
  </ol>
</p>

<p>
	数据同步在称之为"第二阶段"中完成。在进入第二阶段前,pgpool-II 等待所有的客户端断开连接。它阻塞所有新来的连接直到第二阶段完成。当所有的连接被中断后,pgpool-II合并在第一和第二阶段中更新的数据。这是同步的最终数据。  
</p>

<p>
 <font color="red">
 	注意:关于在线恢复有一个限制。如果 pgpool-II 本身安装在多个主机上,在线恢复则不能正确的工作,这是因为 pgpool-II需要在在线恢复的第二阶段中断所有客户端连接。如果存在多个 pgpool-II 主机,只有一个主机能收到在线恢复命令,然后阻塞连接。
</font>
</p>

<h2 id="online_recovery_params">配置在线恢复</h2>
<p>
	为在线恢复在pgpool.conf中设置如下参数:
</p>

<ul>
    <li><a href="#BACKEND_DATA_DIRECTORY">backend_data_directory</a></li>
    <li><a href="#RECOVERY_USER">recovery_user</a></li>
    <li><a href="#RECOVERY_PASSWORD">recovery_password</a></li>
    <li><a href="#RECOVERY_1ST_STAGE_COMMAND">recovery_1st_stage_command</a></li>
    <li><a href="#RECOVERY_2ND_STAGE_COMMAND">recovery_2nd_stage_command</a></li>
</ul>


<h2><a name="installing-c-functions"></a>安装c语言函数</h2>
<p>
	你需要为在线恢复在所有的后端节点中的"template1"数据库中安装c语言函数。源代码在pgpool-II的压缩包中。
</p>

<pre>
  pgpool-II-x.x.x/sql/pgpool-recovery/
</pre>

<p>
改变相应的目录,并执行"make install"。
</p>

<pre>
  % cd pgpool-II-x.x.x/sql/pgpool-recovery/
  % make install
</pre>

<p>
然后安装 SQL 函数。
</p>

<pre>
  % cd pgpool-II-x.x.x/sql/pgpool-recovery/
  % psql -f pgpool-recovery.sql template1
</pre>


<h2 id="recovery_script"> 恢复脚本部署 </h2>
<p>
	我们必须在数据库实例目录($PGDATA)中部署一些数据同步脚本和一个远程启动脚本。在pgpool-II-x.x.x/sample 目录中可找到一些示例脚本文件。
</p>

<h3 id="recovery_pitr">通过PITR在线恢复</h3>
<p>
本节说明如何通过基于时间点的恢复(Point In Time Recovery,PITR)执行在线恢复。PITR 在 PostgreSQL 8.2 以及后续版本可用。注意所有的涉及的 PostgreSQL 服务器都需要支持 PITR。
</p>
<h4>第一阶段</h4>
<p>
	需要一个脚本从主节点获取一个备份库,然后把它拷贝到恢复目标节点中去。该脚本可命名为如"copy-base-backup"。下面是个示例:
</p>

<pre>
#! /bin/sh
DATA=$1
RECOVERY_TARGET=$2
RECOVERY_DATA=$3

psql -c "select pg_start_backup('pgpool-recovery')" postgres
echo "restore_command = 'scp $HOSTNAME:/data/archive_log/%f %p'" &gt; /data/recovery.conf
tar -C /data -zcf pgsql.tar.gz pgsql
psql -c 'select pg_stop_backup()' postgres
scp pgsql.tar.gz $RECOVERY_TARGET:$RECOVERY_DATA
</pre>

<p>
	该脚本把主数据库设成backup模式,生成如下的 recovery.conf:
</p>
<pre>
restore_command = 'scp master:/data/archive_log/%f %p'
</pre>
<p>
执行备份,接着把主数据库不再设成备份模式,然后拷贝备份库到选择的目标节点。
</p>
<h4>第二阶段</h4>
<p>
该过程的第二阶段是一个脚本进行强制 XLOG 文件转换。该脚本此处命名为"pgpool_recovery_pitr"。它强制执行事务日志的一个转换。为此,pg_switch_xlog可能会被用到。</p>
<p><span class="version">V3.1 -</span>然而它可能在转换执行完<b></b>返回,这样可能会导致在线恢复过程的失败。Pgpool-II提供了一个更加安全的称之为"pgpool_switch_xlog"的函数,该函数等待一直到事务日志转换实际被完成后。pgpool_switch_xlog 在<a href="#installing-c-functions">安装 C 函数</a>小节过程执行时被安装。
</p>
<p>
下面是示例脚本。
</p>
<p>
<pre>
#! /bin/sh
# Online recovery 2nd stage script
#
datadir=$1		# master dabatase cluster
DEST=$2			# hostname of the DB node to be recovered
DESTDIR=$3		# database cluster of the DB node to be recovered
port=5432		# PostgreSQL port number
archdir=/data/archive_log	# archive log directory

# Force to flush current value of sequences to xlog 
psql -p $port -t -c 'SELECT datname FROM pg_database WHERE NOT datistemplate AND datallowconn' template1|
while read i
do
  if [ "$i" != "" ];then
    psql -p $port -c "SELECT setval(oid, nextval(oid)) FROM pg_class WHERE relkind = 'S'" $i
  fi
done

psql -p $port -c "SELECT pgpool_switch_xlog('$archdir')" template1
</pre>
</p>

<p>
	该序列注入(flushing of sequences)仅在复制模式下有效:在该情况下,序列不得不在所有节点上具有同一个起点。在主/备模式下并不可用。脚本中的循环强制 PostgreSQL 发出所有数据库中序列生成器的当前值到事务日志中,这样它就传播到恢复的目标节点中去。
</p>

<p>
我们部署这些脚本到 $PGDATA 目录中去。
</p>
<p>
最后,我们修改pgpool.conf。

<pre>
recovery_1st_stage_command = 'copy-base-backup'
recovery_2nd_stage_command = 'pgpool_recovery_pitr'
</pre>

</p>

<p>
	我们已完成通过PITR进行在线恢复的准备工作。
</p>

<h4 id="pool_remote_start">pgpool_remote_start</h4>
<p>
	该脚本启动远程主机的 postmaster 进程。pgpool-II 以如下方式执行。
</p>

<pre>
% pgpool_remote_start remote_host remote_datadir
remote_host:    Hostname of a recovery target.
remote_datadir: Database cluster path of a recovery target.
</pre>

<p>
	在该示例脚本中,我们通过 ssh 启动 postmaster 进程。所以如果你想要它能够运行,你需要提供不需要密码输入的 ssh 连接。
</p>

<p>
	如果你使用PITR进行恢复,你需要部署一个库备份。PostgreSQL 将自动启动一个 PITR 恢复,然后它开始接受连接。
</p>

<pre>
#! /bin/sh
DEST=$1
DESTDIR=$2
PGCTL=/usr/local/pgsql/bin/pg_ctl

# Deploy a base backup
ssh -T $DEST 'cd /data/; tar zxf pgsql.tar.gz' 2>/dev/null 1>/dev/null < /dev/null
# Startup PostgreSQL server
ssh -T $DEST $PGCTL -w -D $DESTDIR start 2>/dev/null 1>/dev/null < /dev/null &
</pre>

<h3>通过rsync在线恢复</h3>
<p>
	PostgreSQL 7.4 没有PITR ,rsync 可被用来进行在线恢复。在 pgpool-II 的压缩包中的"sample"目录中,有一个"pgpool_recovery"交恢复脚本。该脚本使用rsync命令,pgpool-II使用三个参数调用该脚本。
</p>

<pre>
% pgpool_recovery datadir remote_host remote_datadir
datadir:        Database cluster path of a master node.
remote_host:    Hostname of a recovery target node.
remote_datadir: Database cluster path of a recovery target node.
</pre>

<p>
	该脚本通过 ssh 使用 rsync 拷贝物理文件。所以你需要提供不需要密码输入的 ssh 连接。
</p>

<p>
关于rsync的一些笔记:
<ul>
 <li>-c (or --checksum) 当可靠文件传输时需要设置该可选项
 <li>-z (or --compress) 该可选项用于传输数据时数据压缩。这可能对低速连接非常棒,但是对于一个 100Mbit 或更快的连接可能会增加太多的 CPU 负担,在这种情况下你可能不愿意使用该可选项。
 <li>rsync 3.0.5 有着巨大的速度性能提升(根据 pgpool-general 邮件列表里的一份报告,会快50%)
</ul>

</p>

<p>
	如果你使用 pgpool_recovery,在 pgpool.conf 里增加如下几行。
<pre>
recovery_1st_stage_command = 'pgpool_recovery'
recovery_2nd_stage_command = 'pgpool_recovery'
</pre>
</p>

<h2>如何执行在线恢复</h2>
<p>
	为了执行在线恢复,使用 <a href="#PCP_RECOVERY_NODE">pcp_recovery_node</a> 命令或 pgpoolAdmin。
</p>

<p>
	注意你需要给 <a href="#pcp_recovery_node">pcp_recovery_node</a> 第一个参数传递一个大数。该数是一个以秒为单位的定时参数。如果你使用 pgpoolAdmin,在pgmgt.conf.php中设置 "_PGPOOL2_PCP_TIMEOUT "参数为一个大数。
</p>

<h2 id="minorup_w_online_recovery">使用在线恢复实现 PostgreSQL 版本升级</h2>
<h3>复制模式的情况下</h3>
<p>
如果 pgpool-II 运行在复制模式,你可以不停止 pgpool-II 实现对每个 PostgreSQL节点的升级。
注意在断开和重连数据库节点时,从客户端到 pgpool-II 的激活的会话会被关闭。
还请注意这种情况下你不能用以下描述的方法做大版本升级
(例如,需要 dump/restore 的版本升级)。
</p>

<p>
<ol>
    <li><p>
    准备在线恢复</p>
    </li>

    <li><p>版本升级应该先从不是主节点的节点开始。
    	  在非主节点上停止 PostgreSQL。
    	  Pgpool-II 将探测到 PostgreSQL 停止并生成以下日志。
    	  这种情况下,到 pgpool-II 的会话都将被关闭。
        </p>
<pre>
2010-07-27 16:32:29 LOG:   pid 10215: set 1 th backend down status
2010-07-27 16:32:29 LOG:   pid 10215: starting degeneration. shutdown host localhost(5433)
2010-07-27 16:32:29 LOG:   pid 10215: failover_handler: set new master node: 0
2010-07-27 16:32:29 LOG:   pid 10215: failover done. shutdown host localhost(5433)
</pre>
    </li>

    <li><p>
    	在停止的节点上执行 PostgreSQL 的版本升级。
    	你可以覆盖旧的 PostgreSQL,我们建议你将旧版本的 PostgreSQL 移动到某处
    	以便在必要情况下恢复它。
    </p>
    </li>

    <li><p>
    	如果你安装新的 PostgreSQL 在和旧版本不同的位置且你不想更新你的恢复脚本,
    	你需要使用软连接一类的工具来修正路径。
    	如果你选择覆盖,你可以跳过以下步骤,直到安装 C 函数的步骤。
    	你可以立即执行在线恢复。
    </p>
    </li>

    <li><p>
    	改变旧的 PostgreSQL 的安装目录。
    	在以下示例中,PostgreSQL 的安装目录被假设为 /user/local/pgsql。
    </p>
<pre>
$ mv /usr/local/pgsql /usr/local/pgsql-old
</pre>
    </li>

    <li><p>
    	建立一个到新版本 PostgreSQL 安装位置的软连接。
    	这允许你使用你当前的命令搜索路径。
    	在以下示例中,新的 PostgreSQL 的安装路径被假设为 /usr/local/pgsql-new。
    </p>
<pre>
$ ln -s /usr/local/pgsql-new /usr/local/pgsql
</pre>
    </li>

    <li><p>
    	如果数据库目录位于旧的 PostgreSQL 安装目录中,
    	你应该建立或者拷贝一份因而新的 PostgreSQL 可以访问它。
    	在以下示例中我们使用软连接。
    </p>
<pre>
$ ln -s /usr/local/pgsql-old/data /usr/local/pgsql/data
</pre>
    </li>

    <li><p>
      安装 C 函数到 PostgreSQL 中。参考“安装 C 函数”小节。
      因为在线恢复复制了数据库集群,最后一步使用 psql 安装函数不是必要的。
      只需要 make install。
    </p>
    </li>

    <li><p>
    	执行在线恢复。这样,你完成了一个节点的版本升级。
    	要只需在线恢复,你需要使用 <a href="#pcp_recovery_node">pcp_recovery_node</a> 或 pgpoolAdmin。
    </p>
    </li>

    <li><p>
    	针对每个节点重复以上步骤。到最后一步才是升级主节点。然后你就完成了。
    </p>
    </li>
</ol>

<h3>如果你使用流复制</h3>
<p>
可以升级备节点而不停止 pgpool-II。
</p>

<p>
升级 PostgreSQL 备节点的步骤和以上复制模式的步骤一样。
请参考“流复制模式中的在线恢复”设置 recovery_1st_stage_command 和 recovery_2nd_stage_command。
</p>

<p>
无法实现不停止 pgpool-II 升级主节点。
你需要在升级主节点时停止 pgpool-II。
升级主 PostgreSQL 服务器的过程和和备节点相同。
升级主 PostgreSQL 服务器的过程如下:
</p>
<ol>
    <li>停止 pgpool-II</li>
    <li>停止主 PostgreSQL</li>
    <li>升级主 PostgreSQL</li>
    <li>启动主 PostgreSQL</li>
    <li>启动 pgpool-II</li>
</ol>

<p class="top_link"><a href="#Top">返回顶部</a></p>

<!-- ================================================================================ -->

<h1><a name="backup"></a>备份</h1>
<p>
要备份后端的 PostgreSQL 服务器和系统数据库,和备份 PostgreSQL一样,
你可以使用物理备份,逻辑备份(pg_dump,pg_dumpall)和 PITR。
注意使用逻辑备份和 PITR 应该直接在 PostgreSQL 上执行,
而不是通过 pgpool-II,这样才能避免由于 <a href="#LOAD_BALANCE_MODE">load_balance_mode</a><a href="#REPLICATE_SELECT">replicate_select</a> 引起的错误。
</p>

<h2 id="backup_rep_or_ms_mode">复制模式和主/备模式</h2>
<p>
如果 pgpool-II 运行在复制模式或主/备模式,只要备份集群中的一个数据库节点。
</p>

<p>
如果你使用的是主/备模式并且使用了异步复制系统(Slony-I和流复制)且想要最新的备份,
你应该在主节点做备份。
</p>

<p>
pg_dump 在数据库中使用共享锁(ACCESS SHARE lock)。使用排他锁(ACCESS EXECUTE lock)
的命令例如 ALTER TABLE, DROP TABLE, TRUNCATE, REINDEX,CLUSTER 和
VACUUM FULL 将等待 pg_dump 的完成,因为存在锁冲突。这甚至会影响主节点,
即使你在备节点执行 pg_dump。
</p>

<h2 id="backup_parallel">并行模式</h2>
<p>
如果你在使用并行模式且希望得到连续的备份,你需要停止 pgpool-II。
</p>

<p>
要使用逻辑备份,停止应用程序和 pgpool-II,然后在所有节点上执行 pg_dump 或 pg_dumpall。
在完成备份后,启动 pgpool-II,然后启动应用程序。
</p>

<p>
如果使用 PITR,请确保所有节点的系统时间一致。
准备归档日志并执行基础备份。
完成备份后,停止和重启应用程序和 pgpool-II。
记录停止和启动的时间点。
这种临时停止将使各集群之间保持一致的状态。
如果你需要从基础备份和归档日志中恢复,
在启停之间设置 recovery.conf 的 recovery_target_time。
</p>

<h2 id="backup_system_db">备份系统数据库</h2>
<p>
如果 pgpool-II 运行在并行查询模式或者你在使用查询缓存,你需要备份 pgpool-II 的系统数据库。
只需要备份 pgpool.conf 中 system_db_dbname 指定的数据库。
</p>

<p class="top_link"><a href="#Top">返回顶部</a></p>

<!-- ================================================================================ -->

<h1><a name="deploy"></a>部署 pgpool-II</a></h1>
<p>
pgpool-II 可以运行在专用的服务器上,应用服务运行的服务器上或者其他服务器上。
本章我们将讲述如何实现这些部署以及相应的利弊。
</p>

<p>
<dl>
<dt>专用服务器</dt>
    <dd>
    <p>
    pgpool-II 运行在专用服务器上。结构简单且 pgpool-II 不受其他服务软件的影响。
    很明显,缺点是你需要买更多硬件。
    而且这种配置下,pgpool-II 可能发生单点故障
    (你可以使用以下提到的 pgpool-HA 避免这个问题)。
    </p>
    </dd>

<dt>部署在网站服务器或应用服务器上</dt>
    <dd>
    <p>
    将 pgpool-II 部署到一台运行 Apache, JBoss, Tomcat 或其他网站服务器和应用服务器上。
    由于 pgpool-II 和网站服务器或者应用服务器之间的通信是本地的,网络通信速度比服务器间的通信更快。
    而且如果你使用多个网站服务器或者应用服务器,你可以避免单点故障
    (这种情况下,你必须为每个 pgpool-II 实例配置相同的 pgpool.conf)。
    这种配置情况下,你必须注意几项事项:
    </p>
    <ul>
        <li>如果 pgpool-II 和数据库服务器之间的通信部稳定,
        	有可能数据库节点 #1 到一个 pgpool-II 实例的连接断开
        	但到另一个 pgpool-II 实例的连接是正常的。
        	要避免这种问题,你可以使用双网络链路。
        </li>
        <li>当在复制模式中执行在线恢复时,你需要停止除进行在线恢复外所有的 pgpool-II 实例。
        	否则,数据库会运行到不一致的状态。
        	在主备模式和流复制模式中,你不需要停止其他的 pgpool-II 实例。
        	然而,你不允许在多个 pgpool-II 实例运行的时候执行在线恢复。
        </li>
    </ul>
    </dd>

<dt>在数据库服务器上运行 pgpool-II</dt>
    <dd>
    <p>
    在运行 PostgreSQL 的服务器上运行 pgpool-II。
    这种配置下避免 pgpool-II 的单点故障的问题。
    很明显你不需要另外购买专用服务器。
    这种配置下的问题是,应用程序需要选择连接到哪台数据库服务器。
    要解决这个问题你可以通过 pgpool-HA 使用虚拟 IP。
    </p>
    </dd>
</dl>

<h2 id="pgpool_ha">关于 pgpool-HA</h2>
<p>
Pgpool-HA 是一个高可用性软件来让 pgpool-II 配合 hearbeat使用。
Pgpool-HA 是一个 pgpool 以及 pgpool-II 项目的子项目。
Pgpool-HA 可以在 pgpool 开发网站找到,它是一个开源软件。</p>

<p class="top_link"><a href="#Top">返回顶部</a></p>

<!-- ================================================================================ -->

<h1 id="watchdog">看门狗<span class="version">V3.2 -</span></h1>

<p>
“看门狗”是一个 pgpool-II 的子进程,用于添加高可用性功能。
这通过多个 pgpool-II 的合作解决了单点故障的问题。
看门狗为 pgpool-II 添加了以下功能:
</p>
<h3>pgpool-II 服务的生命检测</h3>
    <p>
    看门狗通过两种方式监控 pgpool-II,“心跳”模式或者“查询”模式。
    </p>
    <ul>
    <li>
    在心跳模式中,看门狗使用心跳信号监控其他 pgpool-II 进程。看门狗接收其他 pgpool-II 定期发送的心跳信号。
    如果时间周期到了还没收到信号,则看门狗认为 pgpool-II 已经失效。
    为了冗余,你可以使用多个网络接口设备来在 pgpool-II 之间实现心跳交换。这是默认的模式,且推荐使用。
    </li>
    <li>
    在查询模式中,看门狗监控 pgpool-II 提供的服务,而不是进程。看门狗向其他 pgpool-II 发送查询并检查反馈。
    注意这种模式需要连接到其他 pgpool-II,所以如果 <a href="#NUM_INIT_CHILDREN">num_init_children</a> 不够大则可能监控失败。
    本模式不赞成使用,保留的原因是为了向下兼容。
    </li>
    </ul>
    <p>
    	看门狗还监控到从 pgpool-II 到前端服务器的连接(例如应用服务器),并检查 pgpool-II 能否为这些服务提供服务。如果监控到失败,则认为 pgpool-II 宕机了。
    </p>

<h3>协调多个 pgpool-II 共同工作</h3>
    <p>
    看门狗通过互相交换信息来协调多个 pgpool-II 共同工作。
    </p>
    <ul>
    <li>
    在后端节点例如由于故障切换而发生状态变化后,看门狗通知其他 pgpool-II 节点并同步信息。
    在发生在线恢复时,看门狗限制客户端连接到其他 pgpool-II 节点,以避免后端节点的不一致。
    </li>
    <li>
    故障切换或者故障恢复的命令 (<a href="#FAILOVER_COMMAND">failover_command</a>,
    <a href="#FAILBACK_COMMAND">failback_command</a>, <a href="#FOLLOW_MASTER_COMMAND">follow_master_command</a>)
    通过内部锁机制只被一个 pgpool-II 节点执行。
    </li>
    </ul>

<h3>在检测到某些故障时交换活跃/备用状态</h3>
    <p>
    	当一个 pgpool-II 的故障被检测到,看门狗通知其他的看门狗这个消息。
    	如果是活跃的 pgpool-II 发生故障,看门狗通过投票确定新的活跃 pgpool-II 并更新活跃/备用状态。
    </p>

<h3>在服务器切换的时候实现自动虚拟 IP 地址分配</h3>
    <p>
    	当一个备用 pgpool 服务器提升为活跃的,新的活跃服务器启动虚拟 IP 接口。
    	也就是,之前的活跃服务器停用虚拟 IP 接口。
    	这确保活动的 pgpool 使用相同的 IP 地址,即使在发生服务器切换的时候。
    </p>

<h3>在恢复的时候自动注册服务器为备用服务器</h3>
    <p>
    	当失效的服务器恢复或者新的服务器连接上来,看门狗进程通知其他的看门狗进程关于新服务器的信息,
    	看门狗进程在活跃服务器和其他服务器上接收这些信息。
    	然后,新连接上的服务器注册为备用节点。
    </p>

<h2 id="deploy_watchdog">服务器组件</h2>

<p>
下图描述 pgpool-II 和看门狗进程是如何配置的。
</p>
<p><img src="wd-en.jpg" alt="看门狗服务组件" hight=70% width=70%></p>

<h2 id="start_watchdog">启动/停止看门狗</h2>
<p>
看门狗进程由 pgpool-II 自动启动/停止,也就是说,没有单独的命令来启动/停止它。
</p>
<p>
看门狗功能启动时必须拥有<font color="red">管理员权限(root)</font> 来控制虚拟 IP 接口。
方法之一是使用 root 权限启动 pgpool-II。
不过,考虑安全原因,推荐通过设置设置自定义命令 <a href="#IF_UP_CMD">if_up_cmd</a><a href="#IF_DOWN_CMD">if_up_cmd</a><a href="#ARPING_CMD">if_up_cmd</a> 为使用 sudo 或者 setuid 的方法。
</p>
<p>
在等待到所有的 pgpool 启动后,生命监测将启动。
</p>

<h2>配置看门狗 (pgpool.conf)</h2>
<p>
看门狗的配置参数在 pgpool.conf 中配置。
在 pgpool.conf.sample 文件中的 WATCHDOG 小节是配置看门狗的示例。
</p>

<p>
以下所有的选项都是使用看门狗进程时必须指定的。
</p>
<h3>启用</h3>
<dl>
<dt><a name="USE_WATCHDOG"></a>use_watchdog <span class="version">V3.2 -</span></dt>
    <dd>
    <p>
    如果为 on,则激活看门狗。默认为 off 。
    </p>
    <p>
    修改本值后,你需要重启 pgpool-II 以使改动生效。
    </p>
    </dd>
</dl>

<h3>Watchdog communication</h3>
<dl>
<dt><a name="WD_HOSTNAME"></a>wd_hostname <span class="version">V3.2 -</span></dt>
    <dd>
    <p>
    指定 pgpool-II 的主机名或者 IP 地址。这用于发送/接收查询和通讯包,也用于标记看门狗。
    </p>
    <p>
    修改本值后,你需要重启 pgpool-II 以使改动生效。
    </p>
    </dd>

<dt><a name="WD_PORT"></a>wd_port <span class="version">V3.2 -</span></dt>
    <dd>
    <p>
    指定看门狗的通信端口。
    </p>
    <p>
    修改本值后,你需要重启 pgpool-II 以使改动生效。
    </p>
    </dd>

<dt><a name="WD_AUTHKEY"></a>wd_authkey <span class="version">V3.3 -</span></dt>
    <dd>
    <p>
    本选项指定用于看门狗通信的认证密钥。所有的 pgpool-II 必须有相同的密钥。
    从使用不同密钥的看门狗发送过来的包将被拒绝。
    本密钥也被用于生命检测被设置为心跳模式时的心跳信号。如果本值为空(默认)则看门狗不使用认证。
    </p>
    <p>
    修改本值后,你需要重启 pgpool-II 以使改动生效。
    </p>
    </dd>
</dl>

<h3>连接到上游服务器</h3>

<dl>
<dt><a name="TRUSTED_SERVERS"></a>trusted_servers <span class="version">V3.2 -</span></dt>
    <dd>
    <p>
    用于检测上游连接的可信服务器列表。每台服务器都应能响应 ping。
    指定一个用逗号分隔的服务器列表例如 "hostA,hostB,hostC"。
    如果没有任何服务器可以 ping 通,则看门狗认为 pgpool-II 出故障了。
    </p>
    <p>
    如果本选项为空,则看门狗不检查上游连接。
    </p>
    <p>
    修改本值后,你需要重启 pgpool-II 以使改动生效。
    </p>
    </dd>

<dt><a name="PING_PATH"></a>ping_path <span class="version">V3.2 -</span></dt>
    <dd>
    <p>
    本参数指定用于监控上游服务器的 ping 命令的路径。只需要设置路径例如 "/bin" 。
    </p>
    <p>
    修改本值后,你需要重启 pgpool-II 以使改动生效。
    </p>
    </dd>
</dl>

<h3>虚拟 IP 控制</h3>

<p>
配置虚拟 IP 接口相关控制
</p>

<dl>
<dt><a name="DELEGATE_IP"></a>delegate_IP <span class="version">V3.2 -</span></dt>
    <dd>
    <p>
    指定客户端的服务(例如应用服务等)连接到的 pgpool-II 的虚拟 IP (VIP) 地址。
    当一个 pgpool-II 从备节点切换为激活节点时,pgpool-II 接管这个 VIP。
    </p>
    <p>
    修改本值后,你需要重启 pgpool-II 以使改动生效。
    </p>
    </dd>

<dt><a name="IFCONFIG_PATH"></a>ifconfig_path <span class="version">V3.2 -</span></dt>
    <dd>
    <p>
    本参数指定用于切换 IP 地址的命令的所在路径。
    只设置路径,例如 "/sbin"。
    </p>
    <p>
    修改本值后,你需要重启 pgpool-II 以使改动生效。
    </p>
    </dd>

<dt><a name="IF_UP_CMD"></a>if_up_cmd <span class="version">V3.2 -</span></dt>
    <dd>
    <p>
    本参数指定一个命令用以启用虚拟 IP。设置命令和参数,例如 "ifconfig eth0:0 inet $_IP_$ netmask 255.255.255.0"。
    参数 $_IP_$  会被 <a href="#DELEGATE_IP">delegate_IP</a> 设置的值替换。
    </p>
    <p>
    修改本值后,你需要重启 pgpool-II 以使改动生效。
    </p>
    </dd>

<dt><a name="IF_DOWN_CMD"></a>if_down_cmd <span class="version">V3.2 -</span></dt>
    <dd>
    <p>
    本参数指定一个命令用以停用虚拟 IP。设置命令和参数,例如 "ifconfig eth0:0 down"。
    </p>
    <p>
    修改本值后,你需要重启 pgpool-II 以使改动生效。
    </p>
    </dd>

<dt><a name="ARPING_PATH"></a>arping_path <span class="version">V3.2 -</span></dt>
    <dd>
    <p>
    本参数指定在发生虚拟 IP 切换后用于发送一个 ARP 请求的命令的所在路径。只设置路径,例如 "/sbin"。
    </p>
    <p>
    修改本值后,你需要重启 pgpool-II 以使改动生效。
    </p>
    </dd>

<dt><a name="ARPING_CMD"></a>arping_cmd <span class="version">V3.2 -</span></dt>
    <dd>
    <p>
    本参数指定一个命令用以在发生虚拟 IP 切换后用于发送一个 ARP 请求的命令。
    设置命令和参数,例如 "arping -U $_IP_$ -w 1"。
    参数 $_IP_$  会被 <a href="#DELEGATE_IP">delegate_IP</a> 设置的值替换。
    </p>
    <p>
    修改本值后,你需要重启 pgpool-II 以使改动生效。
    </p>
    </dd>
</dl>

<h3>角色升级时的行为</h3>

<p>配置当 pgpool-II 角色升级为活跃(持有虚拟 IP )时的行为

<dl>
<dt><a name="CLEAR_MEMQCACHE_ON_ESCALATION"></a>clear_memqcache_on_escalation <span class="version">V3.3 -</span></dt>
    <dd>
    <p>
    如果本值为 on,pgpool-II 在升级为活跃状态时清空所有的共享内存中的查询缓存。
    这会避免新激活的 pgpool-II 使用旧的 pgpool-II 而导致的不一致情况。默认值为 on。
    </p>
    <p>
    本选项只有在 <a href="#MEMQCACHE_METHOD">memqcache_method</a> 为 'shmem' 时生效。
    </p>
    </dd>

<dt><a name="WD_ESCALATION_COMMAND"></a>wd_escalation_command <span class="version">V3.3 -</span></dt>
    <dd>
    <p>
    在 pgpool-II 在升级为活跃状态时看门狗执行本命令。执行时间在虚拟 IP 启用之前。
    </p>
    </dd>
</dl>

<h3>pgpool-II 存活情况查询</h3>

<p>看门狗定期检查 pgpool-II 的状态。这被称为“存活检查”。

<h4>通用</h4>

<dl>
<dt><a name="WD_LIFECHECK_METHOD"></a>wd_lifecheck_method <span class="version">V3.3 -</span></dt>
    <dd>
    <p>
    本参数指定存活检查的模式。可以是 'heartbeat' (默认) 或者 'query'。
    </p>
    <p>
    在 'heartbeat' 模式中,看门狗定期发送心跳信号(UDP 包)到其他的 pgpool-II。看门狗也从其他 pgpool-II 获取信号。
    如果在一段时间内没有收到信号,看门狗则认为那个 pgpool-II 发生了故障。
    考虑冗余,你可以使用多个网络接口设备进行 pgpool-II 之间的心跳交换。
    本模式是默认和推荐使用的。
    </p>
    <p>
    在 'query' 模式中,看门狗发送监控查询到其他的 pgpool-II 并检查反馈情况。
    </p>
    <p>
    <font color="red">警告:如果你打算以查询模式使用看门狗,你需要设置 <a href="#NUM_INIT_CHILDREN">num_init_children</a>
    到足够大的值。这是因为看门狗进程是以 pgpool-II 客户端的方式连接。</font>
    </p>
    <p>
    修改本值后,你需要重启 pgpool-II 以使改动生效。
    </p>
    </dd>

<dt><a name="WD_INTERVAL"></a>wd_interval <span class="version">V3.2 -</span></dt>
    <dd>
    <p>
    本参数指定 pgpool-II 进行存活检查的间隔,单位为秒(大于或等于 1)。默认为 10.
    </p>
    <p>
    修改本值后,你需要重启 pgpool-II 以使改动生效。
    </p>
    </dd>
</dl>

<h4>心跳模式的配置</h4>

<dl>
<dt><a name="WD_HEARTBEAT_PORT"></a>wd_heartbeat_port <span class="version">V3.3 -</span></dt>
    <dd>
    <p>
    本选项指定接收心跳信号的端口号。本选项仅用于心跳模式。
    </p>
    <p>
    修改本值后,你需要重启 pgpool-II 以使改动生效。
    </p>
    </dd>

<dt><a name="WD_HEARTBEAT_KEEPALIVE"></a>wd_heartbeat_keepalive <span class="version">V3.3 -</span></dt>
    <dd>
    <p>
    本选项指定发送心跳信号的间隔(秒)。默认值为 2。本选项仅用于心跳模式。
    </p>
    <p>
    修改本值后,你需要重启 pgpool-II 以使改动生效。
    </p>
    </dd>

<dt><a name="WD_HEARTBEAT_DEADTIME"></a>wd_heartbeat_deadtime <span class="version">V3.3 -</span></dt>
    <dd>
    <p>
    如果本选项指定的时间周期内没有收到心跳信号,则看门狗认为远端的 pgpool-II 发生故障。本选项仅用于心跳模式。
    </p>
    <p>
    修改本值后,你需要重启 pgpool-II 以使改动生效。
    </p>
    </dd>
<dt><a name="HEARTBEAT_DESTINATION"></a>heartbeat_destination<font color="red">0</font> <span class="version">V3.3 -</span></dt>
    <dd>
    <p>
	  本选项指定心跳信号发送的目标,可以是 IP 地址或主机名。你可以指定多个目标。
    本参数名后面的数字表示“目标序号”,从 0 开始。本参数仅用于心跳模式。
    </p>
    <p>
    修改本值后,你需要重启 pgpool-II 以使改动生效。
    </p>
    </dd>
<dt><a name="HEARTBEAT_DESTINATION_PORT"></a>heartbeat_destination_port<font color="red">0</font> <span class="version">V3.3 -</span></dt>
    <dd>
    <p>
    本选项指定由 <a href="HEARTBEAT_DESTINATION">heartbeat_destinationX</a> 指定的心跳信号目标的端口号。
    这个值通常等于 <a href="WD_HEARTBEAT_PORT">wd_heartbeat_port</a>。
    但如果这个端口号在某些主机上不能使用或者一个主机上有多个 pgpool-II 的时候你必须指定另一个值。
    本参数名后面的数字表示“目标序号”,从 0 开始。本参数仅用于心跳模式。
    </p>
    <p>
    修改本值后,你需要重启 pgpool-II 以使改动生效。
    </p>
    </dd>
<dt><a name="HEARTBEAT_DEVICE"></a>heartbeat_device<font color="red">0</font> <span class="version">V3.3 -</span></dt>
    <dd>
    <p>
    本选项指定用于发送心跳信号到由 <a href="HEARTBEAT_DESTINATION">heartbeat_destinationX</a>指定的目标的设备名。
    你可以向不同的目标使用相同的设备。
    本参数名后面的数字表示“设备序号”,从 0 开始。
    本选项仅用于心跳模式。另外,这只有在运行在 Linux 下的 root 权限中的 pgpool-II 才能生效,因为这使用了 SO_BINDTODEVICE 套接字选项。
    </p>
    <p>
    修改本值后,你需要重启 pgpool-II 以使改动生效。
    </p>
    </dd>
</dl>

<h4>查询模式的配置</h4>

<dl>
<dt><a name="WD_LIFE_POINT"></a>wd_life_point <span class="version">V3.2 -</span></dt>
    <dd>
    <p>
    在确认 pgpool-II 失效时的重试次数(一个大于或等于 1 的数字)。默认为 3。本选项仅用于查询模式。
    </p>
    <p>
    修改本值后,你需要重启 pgpool-II 以使改动生效。
    </p>
    </dd>

<dt><a name="WD_LIFECHECK_QUERY"></a>wd_lifecheck_query <span class="version">V3.2 -</span></dt>
    <dd>
    <p>
    用于检查 pgpool-II 的查询。默认为 "SELECT 1"。本选项仅用于查询模式。
    </p>
    <p>
    修改本值后,你需要重启 pgpool-II 以使改动生效。
    </p>
    </dd>

<dt><a name="WD_LIFECHECK_DBNAME"></a>wd_lifecheck_dbname <span class="version">V3.3 -</span></dt>
    <dd>
    <p>
    用于检查 pgpool-II 时连接到的数据库名。默认为  "template1"。本选项仅用于查询模式。
    </p>
    </dd>

<dt><a name="WD_LIFECHECK_USER"></a>wd_lifecheck_user <span class="version">V3.3 -</span></dt>
    <dd>
    <p>
    用于检查 pgpool-II 的用户名。用户名必须存在于后端的 PostgreSQL 中。默认为 "nobody"。
    本选项仅用于查询模式。
    </p>
    </dd>

<dt><a name="WD_LIFECHECK_PASSWORD"></a>wd_lifecheck_password <span class="version">V3.3 -</span></dt>
    <dd>
    <p>
    用于检查 pgpool-II 的密码。默认为 ""。
    本选项仅用于查询模式。
    </p>
    </dd>
</dl>

<h3>服务监控</h3>
<dl>
<dt><a name="OTHER_PGPOOL_HOSTNAME"></a>other_pgpool_hostname<font color="red">0</font>
    <span class="version">V3.2 -</span></dt>
    <dd>
    <p>
    指定需要监控的 pgpool-II 服务器主机。这用于发送/接收查询和数据包,同时也是看门狗的标识。
    本参数名后面的数字表示“服务序号”,从 0 开始。
    </p>
    <p>
    修改本值后,你需要重启 pgpool-II 以使改动生效。
    </p>
    </dd>

<dt><a name="OTHER_PGPOOL_PORT"></a>other_pgpool_port<font color="red">0</font>
    <span class="version">V3.2 -</span></dt>
    <dd>
    <p>
    指定需要监控的 pgpool-II 服务器的 pgpool 服务的端口。
    对于查询模式,<a href="#WD_LIFECHECK_QUERY">wd_lifecheck_query</a> 指定的查询语句将被发送到这个端口。
    本参数名后面的数字表示“服务序号”,从 0 开始。
    </p>
    <p>
    修改本值后,你需要重启 pgpool-II 以使改动生效。
    </p>
    </dd>

<dt><a name="OTHER_WD_PORT"></a>other_wd_port<font color="red">0</font> <span class="version">V3.2 -</span></dt>
    <dd>
    <p>
    指定需要监控的 pgpool-II 服务器的看门狗的端口。
    本参数名后面的数字表示“服务序号”,从 0 开始。
    </p>
    <p>
    修改本值后,你需要重启 pgpool-II 以使改动生效。
    </p>
    </dd>
</dl>

<h2 id="watchdog_restrictions">看门狗的限制</h2>
<ul>
<li>
在查询模式中,如果所有的数据库节点由于 PostgreSQL 服务出现故障或者由于调用了 pcp_detach_node,
看门狗会认为 pgpool-II 服务为故障状态并会剥夺虚拟 IP。这样,pgpool-II 的客户端就再也无法通过
虚拟 IP 连接。这对于避免<i>脑裂</i>很重要,也就是说,这种情况下可能出先多个激活的 pgpool-II。
</li>
<li>
不要通过真实 IP 连接到状态为下线的 pgpool-II。因为状态为下线的 pgpool-II 无法从看门狗获取信息,
因此它的后端(数据库)信息可能与其他 pgpool-II 不同。
</li>
<li>
为下线状态的 pgpool-I 不能变为激活或者备用的 pgpool-II。从下线状态恢复需要重启 pgpool-II。
</li>
<li>
注意激活状态的 pgpool-II 停机,需要好几秒钟才能等到备用 pgpool-II 提升为激活状态,以确保之前的
虚拟 IP 下线前的下线通知包被送到其他的 pgpool-II 节点。
</li>
</ul>
<p class="top_link"><a href="#Top">返回顶部</a></p>

<!-- ================================================================================ -->

<h1><a name="troubleshooting"></a>故障解决</h1>
<p>
	本节描述你使用pgpool-II时碰到的问题及其解决办法。
</p>
<p>
<dl>

<dt id="health_check_failed">健康检查失败</dt>
<dd>
<p>
	pgpool-II 的健康检查特性检测到DB节点失效。
</p>

<pre>
2010-07-23 16:42:57 ERROR: pid 20031: health check failed. 1 th host foo at port 5432 is down
2010-07-23 16:42:57 LOG:   pid 20031: set 1 th backend down status
2010-07-23 16:42:57 LOG:   pid 20031: starting degeneration. shutdown host foo(5432)
2010-07-23 16:42:58 LOG:   pid 20031: failover_handler: set new master node: 0
2010-07-23 16:42:58 LOG:   pid 20031: failover done. shutdown host foo(5432)
</pre>

<p>
	该日志表明DB节点1 (主机foo) 与pgpool中断并失去连接(关闭),于是DB节点0成为新的master。检查DB节点1,处理掉产生故障的原因,之后如果可能则会在DB节点1上执行一个在线恢复。
</p>
</dd>

<dt>Failed to read kind from frontend
<dd>
<p>
<pre>
2010-07-26 18:43:24 LOG:   pid 24161: ProcessFrontendResponse: failed to read kind from frontend. frontend abnormally exited
</pre>
<p>
	该日志表明前端程序未能与 pgpool-II 正确的断开。可能的原因是:客户端应的 bug,客户端应用的强制结束(kill)或者是临时的网络故障。该类型的事件不会导致一个DB的破坏或者数据一致性问题。其仅仅是一个关于违反协议的的警告。如果该消息一直出现,建议你检查应用和网络。
</p>

<dt>Kind mismatch errors
<dd>
<p>
	pgpool-II操作在复制模式时你可能得到该消息。
</p>
<pre>
2010-07-22 14:18:32 ERROR: pid 9966: kind mismatch among backends. Possible last query was: "FETCH ALL FROM c;" kind details are: 0[T] 1[E: cursor "c" does not exist]
</pre>
<p>
	pgpool-II把 SQL 命令发送给数据库节点后便会等待响应。该错误消息指示并非所有的数据库节点返回同样的响应。你可能会在"Possible last query
was:"之后看到引起错误的 SQL 语句,接着是响应类型。如果响应指示是一个错误,则从 PostgreSQL 返回的错误消息将被显示出来。这里你看到"0[T]" 显示DB节点响应:0[T]"(开始发送行描述),以及"1[E"
表示DB节点1返回一个错误,消息是"cursor "c" does not exist",然而数据库节点 0 发送了一个行记录。
<p>
	注意:在主/备模式时你同样会看到这类错误。例如即使在主/备模式下,SET 命令将会被发送给所有的数据库节点以保持所有的节点处于同一个状态。
</p>
<p>
	如果你发现数据库不再同步,检查数据库并使用在线复制异步它们。
</p>

<p>
<dt>pgpool-II 检查插入、更新或者删除的不同的行数
<dd>
<p>
	在复制模式下,pgpool-II 检测到 INSERT/UPDATE/DELETE 在影响的节点上产生不同的行数。
</p>
<p>
<pre>
2010-07-22 11:49:28 ERROR: pid 30710: pgpool detected difference of the number of inserted, updated or deleted tuples. Possible last query was: "update t1 set i = 1;"
2010-07-22 11:49:28 LOG:   pid 30710: ReadyForQuery: Degenerate backends: 1
2010-07-22 11:49:28 LOG:   pid 30710: ReadyForQuery: Affected tuples are: 0 1
</pre>
<p>
	在上面的示例中,在不同的数据库节点上执行"update t1 set i = 1"返回更新的行数不同。下一行表明 DB 1 接着出现退化 (断开,disconnected),
	然后是DB节点0受影响的行数是0,然而节点1受影响的行数是1.
</p>
<p>
	停止怀疑有错误数据的数据库节点并执行在线恢复。
</p>
</dl>

<p class="top_link"><a href="#Top">返回顶部</a></p>


<!-- ================================================================================ -->

<h1>限制<a name="restriction"></a></h1>

<p>
<h2>PostgreSQL的函数</h2>
<p>
<ul>
<li>
	如果你使用 pg_terminate_backend() 终止后台数据库,这会触发一个故障。原因是 PostgreSQL 使用完全相同的消息来关闭 postmaster 以终止一个后台数据库,目前还没有办法解决它,请不要使用该函数。
</ul>

<p>
<h2><a name="md5"></a>认证/访问控制</h2>

<p>
<ul>
  <li>在复制模式或主/备模式中,trust, clear text password, 以及 pam 方法被支持,md5 从 pgpool-II 3.0 之后开始被支持。
  	
  	通过使用"pool_passwd"来支持 md5。下面是启用 md5 的步骤:

	   <ol>
		<li>以数据库的操作系统用户(database's operating system user)登入,并键入 "pg_md5 --md5auth --username=<your_username> <your_passwd>",
			用户名和md5加密的密码被注册进 pool_passwd。如果 pool_passwd 还不存在,pg_md5 将会自动的为你创建。
    </li>
		<li> pool_passwd 格式是 "username:encrypted_passwd".</li>
		<li>你还需要在 pool_hba.conf 中增加一个相应的 md5 项。详见<a href="#hba">为客户端认证设置 pool_hba.conf (HBA)</a></li>
		<li>请注意的是用户名和密码必须和 PostgreSQL 中注册的一样</li>
	   </ol>

	   </li>
  <li>在所有的其它模式中,trust, clear text password, crypt, md5, 以及 pam都被支持。</li>
  <li>pgpool-II 并不支持类似 pg_hba.conf 的访问控制。如果 TCP/IP 连接启用的话,pgpool-II 接受来自任何主机的所有连接。若必要,使用iptable来控制其它主机的访问。
  	(当然PostgreSQL服务器能够使用 pg_hba.conf 来接受 pgpool-II 的连接)
</li>
	   </ul>
</p>

<h2>大对象 (Large objects)</h2>
<p>
	pgpool-II 2.3.2 或以上版本支持大对象复制,如果后台服务器是 PostgreSQL 8.1 或以上版本。有鉴于此,你需要启用 pgpool.conf 中的<a href="#lobj_lock_table">lobj_lock_table</a>。然而,使用后台函数 lo_import 的大对象复制不被支持。
</p>

<h2>主/备模式中的临时表</h2>
<p>
	Creating/inserting/updating/deleting 临时表将会永远在主(首要)节点上执行。pgpool-II 3.0 或以上版本中,也可以在这些主节点的表上执行 SELECT。然而,如果在 SELECT 中临时表名被用作一个符号,就没有办法来检测到它,这样 SELECT 将被负载均衡。这会产生一个 "not found the table" 错误或者会找到另外一个同名的表。为避免该问题,使用/*NO LOAD BALANCE*/ SQL 注释。
</p>
<p>
<pre>
将会产生问题的示例 SELECT:
SELECT 't1'::regclass::oid;
</pre>
</p>
<p>
	psql 的 \d命令使用符号表名。pgpool-II 3.0 或更高版本检查是否 SELECT 包含任何对系统表(system catalogs)的访问,并永远把这些查询发送到主节点,这样我们避免了该问题。
</p>

<h2>复制模式中的函数等</h2>

<p>不保证使用依赖上下文的机制所产生的数据(如 random number, transaction ID, OID, SERIAL, sequence),都会被在多个后台服务器上被正确的复制。
</p>
<p>对于SERIAL,启用insert_lock在数据复制中很有用。insert_lock 还有助于 SELECT setval() 和 SELECT nextval()。
</p>

<p>在 pgpool-II 2.3 或更高版本中,使用 CURRENT_TIMESTAMP,CURRENT_DATE, now()的 INSERT/UPDATE 将会被正确的复制。INSERT/UPDATE 使用 CURRENT_TIMESTAMP, CURRENT_DATE, now() 作为表的默认值时,也将会正确的复制。这通过执行时把这些函数替换成从master节点上获取的常量值来完成。然而仍有一些限制:

<ul>
<li>在 pgpool-II 3.0 或更低的以前的版本中,计算表中默认值的临时数据在一些情况下并不准确,例如,下面的表定义:	
<pre>
CREATE TABLE rel1(
  d1 date DEFAULT CURRENT_DATE + 1
)
</pre>
被看成如下的表:
<pre>
CREATE TABLE rel1(
  d1 date DEFAULT CURRENT_DATE
)
</pre>
<p> pgpool-II 3.1 后更高版本能够正确的处理这些情况。这样"d1"将会把明天(CURRENT_DATE + 1)作为默认值。然而当扩展的协议(例如在JDBC, PHP PDO中使用的)或者 PREPARE 被使用时,这个改进并不适用。
</p>
<p>
	请注意如果列类型不是临时的,重写并不会被执行,这儿有个例子:
<pre>
foo bigint default (date_part('epoch'::text,('now'::text)::timestamp(3) with time zone) * (1000)::double precision)
</pre>
</p>
<li>假定我们有如下表:
<pre>
CREATE TABLE rel1(
  c1 int,
  c2 timestamp default now()
)
</pre>
我们可以复制:
<pre>
INSERT INTO rel1(c1) VALUES(1) 
</pre>
因为这将变为:
<pre>
INSERT INTO rel1(c1, c2) VALUES(1, '2009-01-01 23:59:59.123456+09')
</pre>
然而,
<pre>
INSERT INTO rel1(c1) SELECT 1
</pre>
不能够被转换,这样在当前的实现中不能被正确的复制,值将仍然会被插入,但是没有进行任何的转换。
</ul>
</p>
<p>如果你在使用 8.3 或更高的版本 PostgreSQL ,并且在 reset_query_list 中指定 DISCARD ALL,那么将在会话的末尾处删除 <code>CREATE TEMP TABLE</code> 创建的表。

</p>
<p>
	对于8.2.x或更早的版本,退出会话时并不会删除 <code>CREATE TEMP TABLE</code> 创建的表。这是由于连接池的原因,从 PostgreSQL 后台的视角来看,要保持 session 处于活动状态。为避免这一点,你必须通过发出 <code>DROP TABLE</code> 命令显式的删除该临时表,或在事务块中使用 <code>CREATE TEMP TABLE ... ON COMMIT DROP</code> 语句。
</p>

<h2>Queries</h2>

<p>下面是不能被 pgpool-II 处理的查询。</p>

<h3>INSERT (for parallel mode)</h3>

<p>你不能使用 <code>DEFAULT</code> 作为分区关键字列(partitioning key column)。例如如果表t中的列x是分区关键字列,
<pre>
INSERT INTO t(x) VALUES (DEFAULT);
</pre>
<p>
这将是无效的。而且该值也不能使用函数。
</p>

<pre>
INSERT INTO t(x) VALUES (func());
</pre>
<p>
	INSERT的分区值只能是常量值。<code>SELECT INTO</code><code>INSERT INTO ... SELECT</code> 也不被支持。
</p>

<h3>UPDATE (for parallel mode)</h3>

<p>如果分区关键字列值被更新,后台数据库的数据一致性可能会丢失。pgpool-II 并不重新分区更新的数据。
</p>

<p>如果约束被违反时一个查询在后台数据库中引起的了一个错误,一个事务有可能不能够被回滚。
</p>

<p>如果在 <code>WHERE</code> 从句中一个函数被调用,该查询可能不能够被正确的执行。例如:
<pre>
UPDATE branches set bid = 100 where bid = (select max(bid) from beances);
</pre>
</p>

<h3>SELECT ... FOR UPDATE (for parallel mode)</h3>

<p>如果在 <code>WHERE</code> 从句中一个函数被调用,该查询可能不能够被正确的执行。例如:	
<pre>
SELECT * FROM  branches where bid = (select max(bid) from beances) FOR UPDATE;
</pre>
</p>

<h3>COPY (for parallel mode)</h3>

<p><code>COPY BINARY</code> 不被支持。从文件中拷贝也不被支持。只有 <code>COPY FROM STDIN</code><code>COPY TO STDOUT</code> 被支持。
	</p>

<h3>ALTER/CREATE TABLE (for parallel mode)</h3>

<p>为更新分区规则,pgpool-II 必须重启以从 System DB 读取它们。</p>

<h3>Transaction (for parallel mode)</h3>

<p>一个事务块里面执行的 <code>SELECT</code> 语句将被在一个单独的事务中执行,这有个示例:

<pre>
BEGIN;
INSERT INTO t(a) VALUES (1);
SELECT * FROM t ORDER BY a; <-- INSERT above is not visible from this SELECT statement
END;
</pre>

<h3>Views / Rules (for parallel mode)</h3>

<p>
	将会在所有的后台数据库中为 views 和 rules 创建同样的定义。
</p>

<pre>
SELECT * FROM a, b where a.i = b.i
</pre>
<p>像上面的 <code>JOIN</code> 将在后台数据库中执行,然后由每个后台数据库返回的结果进行合并。跨节点的 Views 和 Rules 不能够被创建。然而若连接的表的数据都在同一个节点中,一个 VIEW 能够被创建。该VIEW需要在 pgpool_catalog.dist_def 中注册。一个 col_name 和 一个 dist_def_func 也必须进行注册,它们当在视图上执行插入操作时被使用。
</p>

<h3>Functions / Triggers (for parallel mode)</h3>

<p>同样的函数定义将在所有的后台数据库中被创建。函数内不能执行跨节点连接(Join),不能访问其它节点的数据。
</p>

<h3>Extended Query Protocol (for parallel mode)</h3>

<p>JDBC驱动等等所使用的扩展的查询协议不被支持。必须使用简单的查询协议。这意味着你不能使用prepared statement。
</p>

<h3>Natural Join (for parallel mode)</h3>

<p>自然连接(Natural Join)不被支持。必须使用"ON join condition" 或 "USING (join_column)"。
</p>

<h3>USING CLAUSE (for parallel mode)</h3>

<p>USING CLAUSE 通过查询重写过程被转换为 ON CLAUSE。这样,当在目标列表中含有"*"时,连接的列会出现两次。
</p>
<p>
这儿有个示例:
</p>
<p><pre>
  =# SELECT * FROM t1 JOIN t2 USING(id);
   id |  t  |   t
  ----+-----+-------
    1 | 1st | first
  (1 row)
</pre></p>
<p>
	在query rewrite过程中"USING"被转换成"ON"。这样下面是生效的重写结果:
</p><p><pre>
  =# SELECT * FROM t1 JOIN t2 ON t1.id = t2.id;
   id |  t  | id |   t
  ----+-----+----+-------
    1 | 1st |  1 | first
  (1 row)
</pre>
</p>
<p>
注意列"t"被重复。
</p>

<h3>多字节字符 (for all modes)</h3>

<p>pgpool-II 不会在不同的多字节字符间进行转换。client, backend 以及 System DB 之间的编码必须相同。
	</p>

<h3>Multi-statement Query (for all modes)</h3>
<p>
pgpool-II 不处理 multi-statement queries。
</p>

<h3>Deadlocks (for parallel mode)</h3>

<p>跨越多个后台数据库的死锁不能够被检测。例如:
</p>
<pre>
(tellers table is partitioned using the following rule)
  tid <= 10  --> node 0
  tid >= 10  --> node 1

A) BEGIN;
B) BEGIN;
A) SELECT * FROM tellers WHERE tid = 11 FOR UPDATE;
B) SELECT * FROM tellers WHERE tid = 1 FOR UPDATE;
A) SELECT * FROM tellers WHERE tid = 1 FOR UPDATE;
B) SELECT * FROM tellers WHERE tid = 11 FOR UPDATE;
</pre>
<p>
	在上述情况下,单个的节点不能探测到死锁,这样pgpool-II将会无限期的等待响应。该现象可出现在任何获取行级别锁(row level lock)的query中。
</p>
<p>而且,如果一个节点上出现了一个死锁,每个节点的事务状态将不再具有一致性。这样如果死锁被探测到 pgpool-II 将终止该进程。
</p>
<pre>
pool_read_kind: kind does not match between master(84) slot[1] (69)
</pre>

<h3>Schemas (for parallel mode)</h3>

<p>schema 中非 public 下的对象必须使用完整名字,如:
</p>
<pre>
schema.object
</pre>
<p>
	当路径设置如下时,pgpool-II 不能找到正确的 schema:
</p>
<pre>
set search_path = xxx
</pre>
<p>
	且 schema 名在 query 中被省略。
</p>
<h3>table name - column name(for parallel mode)</h3>
<p>
Limitation object:Parallel mode
</p>
<p>
	一个表或列名不能是以 pool_ 起头。当重写查询时,这些名字被保留为内部处理。
</p>

</p>
<h2>System DB</h2>

<h3>分区规则 (Partitioning Rules)</h3>

<p>仅可在一个分区规则中定义一个分区关键字列。如同'x or y'的条件式不被支持。</p>

<h2>环境要求 (Environment Requirements)</h2>

<h3>libpq</h3>

<p>
	在编译构建pgpool-II时<code>libpq</code>被链接。libpq版本必须是3.0。使用2.0版本的libpq编译pgpool-II将会失败。而且System DB 必须是 PostgreSQL 7.4 或更高版本。
</p>

<h2 id="caution_query_cache">查询缓存</h2>

<p>当前,<a href="#query_cache">查询缓存</a>必须被手动删除。
但这不影响 <a href="#memqcache">基于内存的查询缓存</a>。基于内存的查询缓存会自动清除无效的缓存。</p>

<h2>与pgpool的兼容性 (Compatibility with pgpool)</h2>


<p class="top_link"><a href="#Top">back to top</a></p>

<!-- ================================================================================ -->

<h1>参考<a name="reference"></a></h1>

<h2>PCP 命令参考</h2>

<h3>PCP 命令列表</h3>

<p>PCP 命令是UNIX命令,通过网络操作pgpool-II。</p>

<table border>
<tr><th><a href="#pcp_node_count">pcp_node_count</a></th>
    <td>获取节点数量</td></tr>
<tr><th><a href="#pcp_node_info">pcp_node_info</a></th>
    <td>获取节点信息</td></tr>
<tr><th><a href="#pcp_proc_count">pcp_proc_count</a></th>
    <td>获取进程列表</td></tr>
<tr><th><a href="#pcp_proc_info">pcp_proc_info</a></th>
    <td>获取进程信息</td></tr>
<tr><th><a href="#pcp_pool_status ">pcp_pool_status</a> <span class="version">V3.1 -</span></th>
    <td>获取 pgpool.conf 中的参数</td></tr>
<tr><th><a href="#pcp_systemdb_info">pcp_systemdb_info</a></th>
    <td>获取 System DB 信息</td></tr>
<tr><th><a href="#pcp_detach_node">pcp_detach_node</a></th>
    <td>从 pgpool-II 脱离一个节点</td></tr>
<tr><th><a href="#pcp_attach_node">pcp_attach_node</a></th>
    <td>给 pgpool-II 关联一个节点</td></tr>
<tr><th><a href="#pcp_promote_node">pcp_promote_node</a> <span class="version">V3.1 -</span></th>
    <td>给 pgpool-II 提升一个新的master节点</td></tr>
<tr><th><a href="#pcp_stop_pgpool">pcp_stop_pgpool</a></th>
    <td>停止 pgpool-II</td></tr>
</table>

<h2 id="pcp_comand_args">常用的命令行参数</h2>

<p>对于所有的PCP命令有5个常用的参数。它们给出了pgpool-II的信息和认证。对于有些命令必须需要多余的参数。

<pre>
例如)  $ pcp_node_count 10 localhost 9898 postgres hogehoge

第1个 argument   - 以秒为单位的等待时间. 如果pgpool-II在这个数量的秒内没有响应,PCP将断开连接。
第2个 argument   - pgpool-II的主机名
第3个 argument   - PCP 端口号
第4个 argument   - PCP 用户名
第5个 argument   - PCP 密码
</pre>

<p>PCP的用户名和密码必须在<code>$prefix/etc</code>目录中的<code>pcp.conf</code>中声明。
	启动pgpool-II时<code>-F</code>选项可被用来指定<code>pcp.conf</code>所处的别的位置。当传递给PCP命令时,并不需要以md5格式的密码。
	</p>


<h2>PCP 命令</h2>

<p>所有的PCP命令把结果显示在标准输出中。</p>


<h3>pcp_node_count</h3>

<pre>
Format:
pcp_node_count  _timeout_  _host_  _port_  _userid_  _passwd_
</pre>

<p>
	显示<code>pgpool.conf</code>中定义的所有的节点总数。它并不区别节点状态,例如attached/detached。所有节点都被算进去。
</p>


<h3><a name="pcp_node_info"/>pcp_node_info</a></h3>

<pre>
Format:
pcp_node_info  _timeout_  _host_  _port_  _userid_  _passwd_  _nodeid_
</pre>

<p>
	显示给定节点 ID 的信息,这里是一个输出示例:
</p>

<pre>
$ pcp_node_info 10 localhost 9898 postgres hogehoge 0
host1 5432 1 1073741823.500000

结果以如下顺序被显示:
1. hostname
2. port number
3. status
4. load balance weight

Status 由数字 [0 - 3]来表示。
0 - 该状态仅仅用于初始化,PCP从不显示它。
1 - 节点已启动,还没有连接。
2 - 节点已启动,连接被缓冲。
3 - 节点已关闭。
</pre>
<p>
	负载均衡权重以标准格式来显示。
</p>

<p>
 --verbose 选项帮助理解输出. 例如:
</p>

<pre>
$ pcp_node_info --verbose 10 localhost 9898 postgres hogehoge 0
Hostname: host1
Port    : 5432
Status  : 1
Weight  : 0.5
</pre>

<p>指定一个无效的节点 ID 将会导致一个退出状态为 12 的错误,而且 BackendError 将被显示。</p>

<h3>pcp_proc_count</h3>
<p>
<pre>
Format:
pcp_proc_count  _timeout_  _host_  _port_  _userid_  _passwd_
</pre>
<p>
	显示 pgpool-II 子进程 ID 列表。如果有多于一个的进程,ID 间将用空格来隔开。
</p>
<h3>pcp_proc_info</h3>
<p>
<pre>
Format:
pcp_proc_info  _timeout_  _host_  _port_  _userid_  _passwd_  _processid_
</pre>
<p>
	显示给定 pgpool-II 孩子进程 ID 的信息。输出结果示例如下:
</p>
<pre>
$ pcp_proc_info 10 localhost 9898 postgres hogehoge 3815
postgres_db postgres 1150769932 1150767351 3 0 1 1467 1
postgres_db postgres 1150769932 1150767351 3 0 1 1468 1

结果以如下顺序被显示:
1. 连接的数据库名
2. 连接的用户名
3. 进程启动时间戳
4. 连接创建时间戳
5. 协议major版本
6. 协议minor版本
7. 连接重用计数
8. PostgreSQL backend 进程 ID
9. 前端连接时为1,否则为0
</pre>
<p>
	如果没有与后台的连接,不显示任何内容。如果有多个连接,将显示多行,每行显示一个连接的信息,时间戳显示格式是 EPOCH。
</p>

<p>
--verbose 可选项帮助理解输出. 示例如下:
</p>

<pre>
$ pcp_proc_info --verbose 10 localhost 9898 postgres hogehoge 3815
Database     : postgres_db
Username     : postgres
Start time   : 1150769932
Creation time: 1150767351
Major        : 3
Minor        : 0
Counter      : 1
PID          : 1467
Connected    : 1
Database     : postgres_db
Username     : postgres
Start time   : 1150769932
Creation time: 1150767351
Major        : 3
Minor        : 0
Counter      : 1
PID          : 1468
Connected    : 1
</pre>

<p>指定一个无效的节点 ID 将会导致一个退出状态为 12 的错误,而且 BackendError 将被显示。</p>

<h3 id="pcp_pool_status">pcp_pool_status <span class="version">V3.1 -</span></h3>
<pre>
格式:
pcp_pool_status _timeout_  _host_  _port_  _userid_  _passwd_
</pre>
<p>
显示 pgpool.conf 中的参数。以下是一个输出的示例:
</p>
<pre>
$ pcp_pool_status 10 localhost 9898 postgres hogehoge
name : listen_addresses
value: localhost
desc : host name(s) or IP address(es) to listen to

name : port
value: 9999
desc : pgpool accepting port number

name : socket_dir
value: /tmp
desc : pgpool socket directory

name : pcp_port
value: 9898
desc : PCP port # to bind
</pre>

<h3>pcp_systemdb_info</h3>
<p>
<pre>
Format:
pcp_systemdb_info  _timeout_  _host_  _port_  _userid_  _passwd_
</pre>
<p>
	显示 System DB 信息。输出示例如下:
</p>
<pre>
$ pcp_systemdb_info 10 localhost 9898 postgres hogehoge
localhost 5432 yamaguti '' pgpool_catalog pgpool 3
yamaguti public accounts aid 4 aid bid abalance filler integer integer integer character(84) dist_def_accounts
yamaguti public branches bid 3 bid bbalance filler integer integer character(84) dist_def_branches
yamaguti public tellers bid 4 tid bid tbalance filler integer integer integer character(84) dist_def_tellers

首先,System DB 信息将被显示在第一行。结果以如下顺序被显示:
1. 主机名
2. 端口号
3. 用户名
4. 密码,若无显示为 ''
5. schema 名
6. 数据库名
7. 定义的分区规则数量
</pre>
<p>
	然后,定义的分区规则将被在后续行显示。如果有多个定义,将显示多行,每行显示一个定义。结果以如下顺序被显示:
</p>
<pre>
1. 目标分区数据库名
2. 目标分区schema名
3. 目标分区表名
4. 分区关键字列名
5. 目标表中的列树
6. 列名 (最多显示5个)
7. 列类型 (最多显示5个)
8. 分区规则函数名
</pre>
<p>
	如果 System DB 没有被定义(例如没有在 pgpool-II 模式,且 query cache 没有被启用),将会导致一个退出状态为12的错误,而且 BackendError 将被显示。
</p>


<h3>pcp_detach_node</h3>
<pre>
Format:
pcp_detach_node  [-g] _timeout_  _host_  _port_  _userid_  _passwd_  _nodeid_
</pre>
<p>
	把指定的节点从 pgpool-II 分离。如果设定-g,将等待所有的客户端断开(除非client_idle_limit_in_recovery为-1,或者 recovery_timeout 过期)。
</p>


<h3>pcp_attach_node</h3>
<p>
<pre>
Format:
pcp_attach_node  _timeout_  _host_  _port_  _userid_  _passwd_  _nodeid_

把给定的节点加入到 pgpool-II。
</pre>
</p>

<h3 id="pcp_promote_node">pcp_promote_node <span class="version">V3.1 -</span></h3>
<p>
<pre>
Format:
pcp_promote_node  [-g] _timeout_  _host_  _port_  _userid_  _passwd_  _nodeid_

为 pgpool-II 提升指定的节点为 master 。只适用于 master/slave 流复制。如果设定-g,将等待所有的客户端断开(除非 client_idle_limit_in_recovery 为-1,或者 recovery_timeout 过期)。
</pre>
</p>

<h3>pcp_stop_pgpool</h3>
<pre>
Format:
pcp_stop_pgpool  _timeout_  _host_  _port_  _userid_  _passwd_  _mode_
</pre>

<p>
	使用指定的模式关闭 pgpool-II 进程。可用的模式如下:
</p>

<pre>
s	- 智能模式 (smart mode)
f	- 快速模式 (fast mode)
i	- 立即模式 (immediate mode)
</pre>
<p>
	如果 pgpool-II 进程不存在,将会导致一个退出状态为 8 的错误,而且 BackendError 将被显示。
</p>
<p>* 当前,快速和立即模式没有区别。pgpool-II 终止所有的进程无论是否还有客户端连接到后端服务器。
</p>


<h2>退出状态 (Exit Status)</h2>

<p>PCP 命令正确退出时状态为0.若由错误出现,将会具有如下的错误状态。

<table border>
<tr><th>UNKNOWNERR</th>
    <td>1</td><td>Unknown Error (should not occur)</td></tr>
<tr><th>EOFERR</th>
    <td>2</td><td>EOF Error</td></tr>
<tr><th>NOMEMERR</th>
    <td>3</td><td>Memory shortage</td></tr>
<tr><th>READERR</th>
    <td>4</td><td>Error while reading from the server</td></tr>
<tr><th>WRITEERR</th>
    <td>5</td><td>Error while writing to the server</td></tr>
<tr><th>TIMEOUTERR</th>
    <td>6</td><td>Timeout</td></tr>
<tr><th>INVALERR</th>
    <td>7</td><td>Argument(s) to the PCP command was invalid</td></tr>
<tr><th>CONNERR</th>
    <td>8</td><td>Server connection error</td></tr>
<tr><th>NOCONNERR</th>
    <td>9</td><td>No connection exists</td></tr>
<tr><th>SOCKERR</th>
    <td>10</td><td>Socket error</td></tr>
<tr><th>HOSTERR</th>
    <td>11</td><td>Hostname resolution error</td></tr>
<tr><th>BACKENDERR</th>
    <td>12</td><td>PCP process error on the server (specifying an invalid ID, etc.)</td></tr>
<tr><th>AUTHERR</th>
    <td>13</td><td>Authorization failure</td></tr>
</table>

</p>

<h1>内部信息 (Internal information)<a name="internal"></a></h1>
<p>
	相比于1.x版本,pgpool-II 2.0.x 带来大量的修改。请注意下面的内容不适用1.x版本。
</p>

<h2>并行执行引擎 (Parallel execution engine)</h2>
<p>
	并行执行引擎内置于pgpool-II。殷勤在每一个节点上执行相同的查询(Query),根据节点的响应,传送结果到前端。
</p>

<h2>查询重写 (Query Rewriting)</h2>
<p>
	本节解释了 pgpool-II 并行模式下的查询重写。
</p>
<p>
	在并行模式下,由客户端发出的查询会经历两个阶段的处理:
</p>
<ul>
<li>查询分析 (Analysis of Query)
<li>查询重写 (Rewriting of Query)
</ul>
<p>
下面解释了这两个阶段:
</p>
<h3>查询分析 (Analysis of Query)</h3>
<h4>概述</h4>
<p>
	客户端提交的获取查询(retrieval Query)将会通过 SQL 分析器。然后将会使用存储在system DB中的信息对其进行分析。将会使用该信息更新该查询的每一部分的执行状态。该执行状态存储了哪个节点可以处理。例如,如果一个表的数据分布在多个节点上(正如 catalog 里的 pgpool_catalog.dist_def 中所声明的那样),就需要从所有的节点上获取数据。另外一方面,注册在 pgpool_catalog.replicate_def 中的表的数据若已复制,则可从任意一个节点获取。当数据需要从所有节点上处理时,状态是'P',当需要从一个节点上处理时,状态是'L','S'状态是一个特殊的情况:意味着从所有节点获取后还需要执行另外一个步骤。例如需要对注册在 pgpool_catalog.dist_def 中表的数据进行排序。
</p>

<p>
	获取查询(retrieval Query)将被以如下顺序进行分析,且在此处理过程中会改变执行状态。查询最终将在哪儿处理取决于主选择的最终状态(main select)。
</p>

<ol>
  <li>是否使用了UNION, EXTRACT, INTERSECT?
  <li>FROM语句的执行状态是什么?
  <li>通过TARGETLIST改变执行状态
  <li>根据WHERE语句对执行状态的改变
  <li>根据GROUP BY语句对执行状态的改变
  <li>根据HAVING语句对执行状态的改变
  <li>根据ORDER BY语句对执行状态的改变
  <li>执行状态中LIMIT OFFSET断言的改变
  <li>获取SELECT的最终执行状态
</ol>

<p>
	SELECT最终执行状态(Execution status)和处理位置(Processed place)的关系如下:
</p>

<p>
<table border>
		<tr><td>Execution status</td><td>Processed place</td></tr>
		<tr><td align=center>L</td><td>查询可发送到任意一个节点上 </td></tr>
		<tr><td align=center>P</td><td>在所有节点上运行同样的查询,并返回数据到客户端,使用并行执行引擎</td></tr>
		<tr><td align=center>S</td><td>使用system DB处理完之后,返回数据到客户端</td></tr>
</table>
</p>

<p>
	上面提到的规则也适用于子查询(Sub-Query)。在下面简单的查询中,如果 p1-table 注册在 system DB 的 pgpool_catalog.dist_def 表中(p1-table 是分布式的),最终的子查询的执行状态变为P,这样子查询的父查询,执行状态也变为了P。
</p>

<pre>
SELECT * FROM (SELECT * FROM P1-table) as P2-table;
</pre>

<p>
	接下来,让我们解释一下执行状态是如何具体改变的。让我们从一个例子开始,来解释 FROM 的状态。
</p>

<h4><p>FROM 语句的执行状态</p></h4>
<p>
	这是一个获取查询(SELECT)。数据集和它的状态(P,L 和 S)根据FROM 语句进行定义。表的执行状态如下:当 FROM 语句中只有一个表时,整个数据集的执行状态和该表的执行状态一致。当 FROM 语句中有两个或多个或者有子查询时,根据JOIN的方法以及执行状态来执行查询,如下表所示。
</p>

<p>
<table border>
<tr><td>JOIN type</td><td align = center colspan = 3> LEFT OUTER JOIN </td><td align = center colspan = 3> RIGHT OUTER JOIN </td><td align = center colspan = 3>FULL OUTER JOIN</td><td align = center colspan = 3>Other</td></tr>
		<tr><td align = center>left/right</td><td> P </td><td> L </td><td> S </td><td> P </td><td> L </td><td> S </td><td> P </td><td> L </td><td> S </td><td> P </td><td> L </td><td> S </td></tr>

<tr><td align = center> P </td><td> S </td><td> P </td><td> S </td><td> S </td><td> S </td><td> S </td><td> S </td><td> S </td><td> S </td><td> S </td><td> P </td><td> S </td></tr>

<tr><td align = center> L </td><td> S </td><td> L </td><td> S </td><td> P </td><td> L </td><td> S </td><td> S </td><td> L </td><td> S </td><td> P </td><td> L </td><td> S </td></tr>

<tr><td align = center> S </td><td> S </td><td> S </td><td> S </td><td> S </td><td> S </td><td> S </td><td> S </td><td> S </td><td> S </td><td> S </td><td> S </td><td> S </td></tr>

</td></tr>
</table>
</p>

<p>
	在下面的示例中,P1-table是P状态,L1-table和L2-table是L状态。
<pre>
SELECT * FROM P1-table,L1-table,L2-table;
</pre>
P1-table (左) and L1-table (右)被连接,根据上表它们获得了P状态。根据P状态,它们与L状态的L2-table进行连接,连接之后现在也是P状态。
</p>


<h4><p>由于 TARGETLIST 和 WHERE 从句导致执行状态的改变</p></h4>
<p>
	在一个基本的查询中,执行状态来自于 FROM 语句。然而,如果存在一个T ARGETLIST,WHERE 语句的执行状态能够以如下情况进行改变:
</p>
<ol>
	<li>当有一个子查询
	<li>当有一个聚集函数或者标记为'P'的 TARGETLIST 含 DISTINCT
	<li>当使用的一个列不存在于 FROM 语句中一个表(数据集)中时
</ol>
<p>
	在这些情况下,如果初始状态是P 或 S,最终的子查询、TARGETLIST 和 WHERE 语句的执行状态是S。
<p>
	在下面的例子中,当子查询使用的表的状态是P,那么最终的子查询的执行状态是P。这样 WHERE 从句获得了S状态,无论L1的状态是什么,该查询将被运行在 system DB 中。
<pre>
	SELECT * FROM L1-table where L1-table.column IN (SELECT * FROM P1-table);
</pre>
<p>
	当一个状态为'P'的 TARGETLIST 含有一个聚集函数时,为了在数据获取之后执行聚集函数,FROM语句的状态改为S。在特定的条件下将对聚集函数做一些优化。 
</p>
<p>若一个列不存在于一个表中时,也可以在一个查询中使用。例如在下面的子查询中:
</p>
<pre>
	SELECT * FROM L1-table WHERE L1-table.col1 IN (SELECT * FROM P1-table WHERE P1-table.col = L1-table.col1);
</pre>
<p>
	该子查询从L1-table表中引用了L1-table.col1,含子查询的 WHERE 语句的执行状态为S。
</p>
<h4><p>由于 GROUP BY, HAVING, ORDER BY 和 LIMIT/OFFSET 导致执行状态的改变</p></h4>

<p>
	执行状态是'P'的 WHERE 语句,若还存在GROUP BY, HAVING, ORDER BY 语句, 或 LIMIT/OFFSET 断言时,状态改为'S'。没有 GROUP BY 的查询从 WHERE 语句获取状态。类似的方法,若没有 HAVING 语句,将使用 GROUP BY 语句的执行状态。ORDER BY 语句和 LIMIT/OFFSET 断言具有类似的行为。
</p>

<h4><p>当使用 UNION, EXTRACT, 及 INTERSECT 时</p></h4>
<p>
UNION, EXTRACT, 及 INTERSECT 查询的状态依赖于最终左侧和右侧 SELECT 语句的状态。若左右侧的状态都是L,组合的状态是L。若二者都是P,且查询是 UNION ALL,那么组合的状态是P。其它情况最终结果都是S。

</p>
<h4><p>获取 SELECT 的最终执行状态</p></h4>
<p>
	如果 SELECT 中所有语句都具有状态L,那么最终的执行状态是L。同样规则使用P。对于任何其它的组合最终状态是S。如果状态是L,若 loadbalance_mode 为 true 时负载被分布在不同的节点中,否则只被发送到 MASTER 节点上。对于状态P,将使用并行执行引擎进行并行处理。对于S,将会进入下面讲述的查询重写。
</p>

<h3>查询重写 (Query rewriting)</h3>
<p>
	通过使用查询分析获取的执行状态来重写查询。下面是一个例子,P1-table具有P状态,L1-table具有L状态。
</p>
<pre>
SELECT P1-table.col, L1-table.col 
FROM P1-table,L1-table 
where P1-table.col = L1-table.col 
order by P1-table.col;
</pre>

<p>
	在该查询中,由于有一个 ORDER BY 语句,状态是S。FROM 语句, WHERE 语句, 和 TARGETLIST 都为P状态,查询被重写成:
</p>

<pre>
SELECT P1-table.col, L1-table.col FROM
	dblink(select pool_parallel(SELECT P1-table.col, L1-table.col FROM P1-table,L1-table where P1-table.col = L1-table.col)) 
  	order by P1-table.col;
</pre>
<p>
	此处dblink传送该查询到 pgpool-II。pool_parallel 函数负责发送该查询到并行执行引擎。
</p>
<p>在该示例中 FROM 和 WHERE 语句以及 TARGETLIST 被以并行模式执行。这不是一个真正的重写查询,只是因为想提供一个示例。
</p>
<p>
这儿有另一个例子:
</p>

<pre>
SELECT L1-table.col FROM L1-table WHERE L1-table.col % 2 = 0 AND L1-table.col IN (SELECT P1-table FROM P1-table) ;
</pre>

<p>
	在该示例中,FROM 和 WHERE 语句以及 TARGETLIST 都具有状态L。因为子查询是P状态,查询本身也为S状态。这样重写为如下:
</p>
<pre>
	SELECT L1-table.col 
	  FROM dblink(SELECT loadbalance(SELECT L1-table.col 
	              FROM L1-table 
	              WHERE L1-table.col % 2 = 0 
	                AND TRUE))
		WHERE
			L1-table.col %2 = 0 AND 
		  L1-table.col IN 
		  (
		  	SELECT P1-Table FROM 
		  	dblink(select pool_parallel(SELECT P1-table FROM P1-table))
		  ) ;
</pre>
<p>pool_loadbalance 是一个函数,负责分发查询到任一个节点。
</p>

<h3>为聚集函数的查询重写</h3>
<p>
	对于分组查询(聚集函数和 GROUP BY),重写为了减少system DB上的负载将试图在每一个节点上执行第一次聚集。
</p>
<p>首先,我们看看 pgpool-II 为重写都做了那些事情。
</p>
<p>该查询的 FROM 语句具有P状态且 TARGETLIST 含有count(*),于是重写如下:
</p>
<pre>
  select count(*) from P1-table;

	-> rewrite

    SELECT
        sum(pool_c$1) as count
    FROM
        dblink(select pool_parallel('select count(*) from  P1-table'))
					AS pool_$1g (pool_c$1 bigint);
</pre>
<p>在如下的条件下查询就会重写为上面类似的形式。
</p>
<ol>
		<li> FROM 语句具有P状态。
		<li>聚集函数(仅 count, sum, min, max, 和 avg)以及 GROUP BY 中的列存在于 target list 中。
		<li>WHERE 语句具有P状态。
		<li>仅仅使用聚集函数中定义的、HAVING 语句和 FROM 语句中的、以及 GROUP BY 中的列
</ol>
<h3 id="caution_in_parallel_mode">并行模式一些说明</h3>
<p>
	并行模式下查询分析时需要列名和类型。这样当子查询的 TARGETLIST 中含有一个表达式或函数时,就需要别名和类型(通过映射 through a cast)。
	请注意如果没有为表达式或函数提供映射,默认将选择文本类型。对于count(),假定为bigint类型,对于sum()为numeric类型,对于min()/max(),如果参数是date类型,返回类型为date,
	其它的假定为numeric类型。avg() 被处理为 sum()/count() (总和除以数量)。</p>

<h3 id="performance_parallel_mode">关于并行模式的性能</h3>
<p>下面是一个相对于执行状态的查询性能的粗略估计:
</p>

<table border>
		<tr><td>执行状态</td><td>性能</td></tr>
<tr><td align = center>L</td><td>一个节点时除去pgpool-II的开销,没有性能损失,因为根本就没有并行查询</td></tr>
<tr><td align = center>P</td><td>并行处理是很快的,特别针对顺序扫描。由于扫描大表变成在几个节点上分布式存在的小表上进行并行扫描,故很容易获得加速比。
<tr><td align = center>S</td><td>当聚集函数可在并行方式被重写时,它们很快。</td></tr>
</td></tr>
</table>

<p class="top_link"><a href="#Top">返回顶部</a></p>

<!-- ================================================================================ -->

<h1>入门教程</h1>
<p>
<a href="tutorial-zh_cn.html">pgpool-II入门教程</a> 已发布。
</p>

<p class="top_link"><a href="#Top">返回顶部</a></p>

</div>

<div class="copyright" style="clear: both">
<hr>
<copyright>
Copyright &copy; 2003 &ndash; 2012 pgpool Global Development Group
</copyright>
</div>
</body>
</html>