Jokers's Blog

高尚是高尚者的墓志铭 卑鄙是卑鄙者的通行证


  • 首页

  • 分类

  • 归档

  • 标签

Elasticsearch6测试和开发环境配置

发表于 2018-04-23 | 分类于 BigData |

开发模式和生产模式

es节点加入集群,必须绑定transport到non-loopback地址,es通过http.host,transport.host和single-node discovery的配置判断是否为生产模式。

引导启动检查

使用引导启动检查检查es和系统设置。在开发模式下,不安全的配置会以warnings记录日志。在生产模式下,会拒绝启动。

强制引导启动检查

单节点的生产模式可以绕过引导启动检查,通过设置es.enforce.bootstrap.checks(JVM options)为True,可以强制检查。

堆大小检查

JVM配置初始堆大小和最大堆值相同,否则会导致系统运行停顿。es默认使用1GB的堆。规则如下:

  • 堆越大,缓存越大,但是太大的话会导致长时间的垃圾回收而造成系统停顿。
  • 不要超过物理内存的50%
  • 26GB对大多数系统比较安全,对一些系统可达到30G

jvm.options配置文件

-Xms26g
-Xmx26g

文件描述符检查

es需要大量的文件描述符。必须保证文件描述符的数量限制大与等于65535。通过RPM和Debian包默认设置为65536。可以通过以下命令检查max_file_descriptors的大小。

curl -X GET "localhost:9200/_nodes/stats/process?filter_path=**.max_file_descriptors"

内存锁定检查

JVM进行垃圾回收时,如果有page被换出到硬盘,再换入内存回收,影响效率。有多种办法可以禁止交换。

  • 系统级别的禁止交换

    sudo swapoff -a

  • 配置swappiness

  • 阻止es内存换出,添加以下配置到config/elasticsearch.yml文件

    bootstrap.memory_lock: true

  • 检查mlockall的配置

    GET _nodes?filter_path=**.mlockall

  • 如果mlockall的值是false, 意味着mlockall请求失败,最有可能的原因是运行es的用户没有lock Memory的权限,授权方式

    添加一个文件
    /etc/systemd/system/elasticsearch.service.d/override.conf
    or
    sudo systemctl edit elasticsearch
    编辑
    [Service]
    LimitMEMLOCK=infinity
    加载
    sudo systemctl daemon-reload

  • 如果依然失败可能是临时路径/tmp使用noexec选项挂载,可以使用ES_JAVA_OPTS环境变量指定一个新的temp路径

    export ES_JAVA_OPTS=”$ES_JAVA_OPTS -Djava.io.tmpdir=/path/to/temp/dir”
    ./bin/elasticsearch

最大线程数检查

es需要有创建至少4096个线程的能力并且只会在Linux系统上检查。通过设置/etc/security/limits.conf的nproc值(同时要增大root用户的限制)

最大虚拟内存检查

es需要有无限制的地址空间并且只会在Linux系统上检查。通过设置/etc/security/limits.conf的as值为unlimited(同时要改变root用户的限制)

最大文件大小检查

es需要有无限制大小的写文件能力。通过设置/etc/security/limits.conf的fsize值为unlimited(同时要改变root用户的限制)

最大地图数量检查

es需要至少262144内存映射空间并且只会在Linux系统上检查。通过设置vm.max_map_count(sysctl)

sysctl -w vm.max_map_count=262144
sysctl -a|grep vm.max_map_count

客户端JVM检查

确保es没有运行在客户端JVM而是服务端JVM,现代操作系统,服务端JVM是默认的。

serial collector检查

确保es运行时使用的垃圾收器不是serial collector,除非指定-XX:+UseSerialGC使用,JVM默认使用es的默认配置也就是CMS collector。

系统调用过滤器检查

修复所有可能阻止es安装系统调用过滤器(Linux上的seccomp)的配置(检查日志)

OnError和OnOutOfMemoryError检查

防止es启动时JVM的这两个选项被启用并且系统调用也被启用,它们相互之间不兼容。可以禁止OnError和OnOutOfMemoryError或则升级到Java 8u92并且使用JVM flag ExitOnOutOfMemoryError

常用的Linux命令

发表于 2018-03-13 | 分类于 Linux |

ls统计文件数目

1
2
3
4
5
 # grep "^-" 仅统计普通文件
# grep "^d" 仅统计目录文件
# grep .txt 仅统计制定后缀的文件
# R recusive统计子目录的文件
$ ls -lR|grep "^-"|wc -l

find

统计文件数目

1
2
3
 # -maxdepth 1 仅统计当前目录的文件
# 比ls方法快很多
$ find ./ -maxdepth 1 -type f|wc -l

查找文件

$ find / -name filename

centos7防火墙

基本管理

1
2
3
4
5
6
7
8
9
10
 <!-- 开启防火墙 -->
$ sudo systemctl start firewalld.service
<!-- 关闭防火墙 -->
$ sudo systemctl stop firewalld.service
<!-- 启用开机启动防火墙 -->
$ sudo systemctl enable firewalld.service
<!-- 禁止开机启动防火墙 -->
$ sudo systemctl disable firewalld.service
<!-- 查看防火墙状态 -->
$ sudo systemctl status firewalld.service

端口管理

1
2
3
4
5
6
7
8
 <!-- 查询80端口是否开去 -->
$ firewall-cmd --query-port=80/tcp
<!-- 开启80端口 -->
$ firewall-cmd --add-port=80/tcp --permanent
<!-- 去除80端口 -->
$ firewall-cmd --remove-port=80/tcp --permanent
<!-- 生效 -->
firewall-cmd --reload

Rich Rules

  • ADD

    firewall-cmd --permanent --add-rich-rule="rule family="ipv4" source address="192.168.1.1/24" port protocol="tcp" port="3306" accept"
    
  • DEL

    firewall-cmd --permanent --remove-rich-rule="rule family="ipv4" source address="192.168.1.1/24" port protocol="tcp" port="3306" accept"
    

查看所有规则

firewall-cmd --zone=public --list-all

yum

列出已安装的包

$ yum list installed

netstat

查看端口是否占用

netstat -anp|grep 80

telnet

检测远程端口是否打开

telnet 111.111.111.111 6379

查看进程占用的端口号

netstat -anp|grep pid

RPM

安装

rpm -ivh xxx.rpm

查找

rpm -q xxx

卸载

rpm -e xxx.rpm

Linux 版本号

cat /etc/redhat-release

arping

查看ip的MAC地址及IP占用问题
多块网卡,需要-I指定网卡设备名称

arping -I wlp10s0 192.168.1.204

磁盘使用情况

  • linux服务器的文件系统的磁盘空间占用情况

    df -h
    
  • 统计目录(或文件)所占磁盘空间的大小 (du [选项] [文件])

    <!-- 1级目录 -->
    du -h  --max-depth=1
    

磁盘挂载

  • 挂载
    [-o gid=jokers,uid=jokers]用于指定用户

    sudo mount -o gid=jokers,uid=jokers /dev/sdb1 /mnt/
    
  • 卸载

    umount /dev/sdb1
    

tab

Rencently was troubled by the tab and space in python script in Vim editor, so need to config the editor properly to avoid this.

Below is the reference from others.

Vim里面显示TAB键

  1. 文件中有 TAB 键的时候,你是看不见的。要把它显示出来:

    :set list
    
    取消:set nolist
    

现在 TAB 键显示为 ^I ,而 $显示在每行的结尾,以便你能找到可能会被你忽略的空白 字符在哪里。

  1. 方法1中这样做的一个缺点是在有很多 TAB 的时候看起来很丑。如果你使用一个有颜色的终端,或者使用 GUI 模式,Vim 可以用高亮显示空格和TAB。 使用 ‘listchars’ 选项:

    :set listchars=tab:>-,trail:-
    

现在,TAB会被显示成 “>—“ 而行尾多余的空白字符显示成 “-“。

设定tab的形式

:set tabstop=4
  1. 输入tab时自动将其转化为空格

    :set expandtab
    

如果此时需要输入真正的tab,则输入Ctrl+V, tab,在windows下是Ctrl+Q, tab

  1. 将已存在的tab都转化为空格

    :retab (在设定set expandtab的情况下才可以使用)
    

在没有设定 expandtab 选项时,使用“:retab!”可把空白字符转换成制表符(可能误转换,慎用)

  1. 设定编辑模式下tab的视在宽度

    :set softtabstop
    

这不改变tabstop,但让编辑的时候tab看起来是指定的宽度,输入tab时会插入的tab和空格 的混合,比如tabstop=4, softtabstop=10,那么插入tab时会将光标移动10个字符,可能会是两个tab加两个空格,这对backspace也有效。

  1. 解决shiftwidth和tabstop不等时的麻烦

    :set smarttab
    

在行首输入tab时插入宽度为shiftwidth的空白,在其他地方按tabstop和softtabstop处理

Fedora27安装Mariadb10.2

发表于 2018-02-05 | 分类于 DataBase |

下载

下载编译好的linux版本

  • 截至今天,Mariadb还未发布Fedora27的yum版本,Fedora26版本实测会产生系统崩溃。
  • Centos7的yum版本,修改配置文件改变数据存储位置后,不能正常启动,试了很多方法都没能成功。

配置文件

需要手动建立配置文件

  • 安装好的Mariadb会自动识别/etc/my.cnf
  • 修改socket路径
1
2
3
4
5
# The MariaDB server
[mysqld]
port = 3306
#socket = /var/lib/mysql/mysql.sock
socket = /home/data/mysql/mysql.sock

安装

1
2
3
4
5
6
7
8
9
groupadd mysql
useradd -g mysql mysql
cd /usr/local
tar -zxvpf /path-to/mariadb-VERSION-OS.tar.gz
ln -s mariadb-VERSION-OS mysql
cd mysql
./scripts/mysql_install_db --user=mysql
chown -R root .
chown -R mysql data

启动

1
2
3
./bin/mysqld_safe --user=mysql &
or
./bin/mysqld_safe --defaults-file=~/.my.cnf --user=mysql &

自启动(推荐)

1
cp support-files/mysql.server /etc/init.d/mysql.server
  • 修改mysql.server,改变数据存储位置
1
datadir=/home/data/mysql
  • 复制data
1
2
$ sudo cp -R /usr/local/mysql/data/* /home/data/mysql
$ sudo chown -R mysql:mysql /home/data/mysql
  • 启动方式
1
/etc/init.d/mysql.server start

初始化

1
2
$ /usr/local/mysql/bin/mysqladmin -u root password 'password'
$ /usr/local/mysql/bin/mysql -uroot -p
1
MariaDB [(none)]> GRANT ALL PRIVILEGES ON *.* TO 'ai'@'%' IDENTIFIED BY 'mypassword'

Fedora使用dnf(yum)简易安装Elasticsearch6

发表于 2018-02-05 | 分类于 BigData |

安装JDK8

http://www.oracle.com/technetwork/java/javase/downloads/index.html

下载安装 public signing key

rpm --import https://artifacts.elastic.co/GPG-KEY-elasticsearch

添加仓库

1
2
3
4
5
6
7
8
9
10
11
$ sudo vi /etc/yum.repos.d/elasticsearch.repo

# 添加如下
[elasticsearch-6.x]
name=Elasticsearch repository for 6.x packages
baseurl=https://artifacts.elastic.co/packages/6.x/yum
gpgcheck=1
gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch
enabled=1
autorefresh=1
type=rpm-md

安装

1
$ sudo dnf install Elasticsearch

配置(需要更改存数据储位置或日志存储位置)

1
2
3
4
5
6
7
$ sudo vi /etc/elasticsearch/elasticsearch.yml

# 更改如下
#path.data: /var/lib/elasticsearch
path.data: /home/lib/elasticsearch
#path.logs: /var/log/elasticsearch
path.logs: /home/log/elasticsearch

手动建立/home/lib/elasticsearch和/home/log/elasticsearch路径

更改权限

1
2
$ sudo chown -R elasticsearch:elasticsearch /home/lib/elasticsearch
$ sudo chown -R elasticsearch:elasticsearch /home/log/elasticsearch

运行

1
$ sudo systemctl start elasticsearch

Hello World

发表于 2018-02-05 |

Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

Quick Start

Create a new post

1
$ hexo new "My New Post"

More info: Writing

Run server

1
$ hexo server

More info: Server

Generate static files

1
$ hexo generate

More info: Generating

Deploy to remote sites

1
$ hexo deploy

More info: Deployment

中英文金额转阿拉伯数字

发表于 2017-08-14 | 分类于 Tools |
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
#!/usr/local/python
# -*- coding: utf-8 -*-
'''
Created on 2018-04-14
处理各种中英文金额,转化为阿拉伯数字
author: wangweitao@ipforest.cn
'''
from lib import pub_mysql_product
import re
# 用于处理中文转数字的库
import unicodedata
# debug = True
debug = False

# !!!注意,目前做了个美元的处理,正常逻辑应该是保存美元数字,做货币字段,而不应该转换成人民币

# 中文 以及 混合数字,转为阿拉伯数字
# 思路: 以万和亿进行分段, 字符串压栈,从后向前进行处理
# 记录当前的分段值: 1, 10000, 10000000
# max_mul: 记录当前分段值
# total_num: 总值,当遇到比当前值更大的分段值或者字符串未空,则计算当前总值
# cur_num: 分段数值
# cur_n: 当前字符转成的数字
# last_n: 上一个字符转成的数字
# 示例: 100万, 则max_mul = 10000 , cur_num = 100
# ['1','0','0','万']
# 默认值 max_mul = 1 , cur_num = 0 , total_num = 0
# step 1 : 处理字符 '万'
# 当前数组 ['1','0','0']
# cur_n = 10000
# last_n = 10000
# max_mul = 10000
# cur_num = 0
# total_num = 0
#
# step 2 : 处理字符 '0'
# 当前数组 ['1','0']
# cur_n = 0
# last_n = 0
# max_mul = 10000
# cur_num = 0
# total_num = 0
# step 3 : 处理字符 '0'
# 当前数组 ['1']
# cur_n = 0
# last_n = 0
# max_mul = 10000
# cur_num = 0
# total_num = 0
# step 4 : 处理字符 '1'
# 当前数组 []
# cur_n = 1
# last_n = 0
# max_mul = 10000
# cur_num = 100
# total_num = total_num + cur_num * max_mul = 0 + 100 * 10000


# 当前分段所在的值(total_num = total_num + cur_num * max_mul)
def chinese2digits(num_str):
if debug == True:
print "开始处理字符串:",num_str
# print num_str
str_stack = []
for i in range(0,len(num_str)):
# print unicodedata.numeric(num_str[len(num_str) - 1 - i])
str_stack.append(num_str[i])
# print num_str[len(num_str) - 1 - i]

step = 0
total_num = 0
cur_num = 0
mul = 1
max_mul = 1
last_n = None

# 计算货币
foreign_mul = 1

while len(str_stack) > 0:
cur_str = str_stack.pop()
step = step + 1
try:

if debug == True:
print "----------------",cur_str,str_stack
cur_n = int(unicodedata.numeric(cur_str))
# 万 or 亿 分段
if (cur_n >=10000 and cur_n > max_mul) :
total_num = float(total_num) + cur_num * max_mul
if debug == True:
print "分段计算: ",cur_n,max_mul,cur_num,total_num,str_stack
cur_num = 0
# 最大乘法因子
max_mul = cur_n
# 重置当前乘法因子
mul = 1
else:
if cur_n >= 10:
# 处理万(当分段是已的时候,可能会出现万)千百十
if last_n >= 10 :
# 处理 "3千万亿" 的情况
mul = mul * cur_n
else:
mul = cur_n

pass
elif cur_n < 10 :
if last_n < 10 and last_n is not None and cur_n == 0 :
# 处理数字0,增加乘积,比如 800 , 每遇到
mul = 10 ** len(str(mul))

elif last_n < 10 and last_n is not None and cur_n != 0 :
# 处理 812之类的数据
cur_num = cur_num + 10 ** len(str(mul)) * cur_n
mul = 10 ** len(str(mul))

else:
# 处理 3千
cur_num = cur_num + cur_n * mul

# 记录当前数字
last_n = cur_n
except:
# print "无法识别的字符:", cur_str
if cur_str == u"." or cur_str == u"点":
# 处理小数点
cur_num = float(cur_num) / (10 ** len(str(int(cur_num))))
mul = 1
last_n = None
elif cur_str == u"美":
# 处理美元,不建议转化成中文,需要增加不同语种, 而且需要计算当时的汇率
foreign_mul = 6.3

# 栈空,计算总数,遇到十,则压栈1,继续处理
if len(str_stack) == 0:
if cur_n is not None and cur_n == 10:
# 处理'十'开头的字符串
str_stack.append(u"1")
continue
# 计算结果
total_num = float(total_num + cur_num * max_mul) * foreign_mul
# if debug == True:
# print cur_n,"\ttotal---->",total_num,cur_num,max_mul
# 打印调试信息
if debug == True and cur_n is not None:
print u"Step %d:\
\n\t当前字符 %s,\
\n\t当前数组 %s,\
\n\tcur_n = %s,\
\n\tlast_n = %s,\
\n\tmax_mul = %d,\
\n\tcur_num = %d,\
\n\tmul = %d,\
\n\ttotal_num =%s \n" % (step,cur_str,str_stack,cur_n,last_n,max_mul,cur_num,mul,total_num)


print "=***",num_str,"---->",total_num
return total_num


# 测试函数
def test():
test_str_arr = [u"一",u"一.一",u"一十",u"一十一",u"一百一十",u"1233",u"1233.10",u"3万零1",u"1233",u"3万零1千零1百",u"3.31万",u"3万5千零1",u"3万零1百",u"3亿零3千万",u"1万零3千",u"1万零3百",u"5千万",u"5千1百万",u"5千零30万",u"五千壹百万",u"3.3亿",u"3.3亿美",u"3.3万美",u"叁拾肆",u"一亿三千万",u"十万",u"3",u"⒈",u"①",u"十",u"十三",u"十万零一十",u"1千兆",u"333.333",u"3千万",u"3万零1十",u"十点1万",u"1点1",u"1十点1万",u"1亿零1百点1",u"3千万亿"]

# test_str_arr = [u"3千万亿"]
for str_num in test_str_arr:
chinese2digits(str_num)

# 主程序
if __name__ == '__main__':
test()

GIT

发表于 2017-05-03 | 分类于 Tools |

常用命令

  • 查看已建立的连接

    git remote -v
    
  • 取消对文件的修改。还原到最近的版本,废弃本地做的修改。

    git checkout -- <file>
    
  • 取消已经暂存的文件。即,撤销先前”git add”的操作

    git reset HEAD <file>...
    
  • 回退到上一个版本,即commit后的撤销操作,保留工作区的改变

    git reset HEAD^ <file>...
    
  • 回退到上一个版本

    git reset --hard HEAD^ <file>...
    

Stashing

当我在一个分支fa中修改了文件,但是还没有完全改好,此时我并不想add/commit,但是这个时候有一个更急迫的事情在另外一个分支fb上需要我去做,我必须要切换分支。

  • 将当前分支文件储藏起来

    git stash
    
  • 恢复刚刚储藏的数据

    git stash apply
    
  • 查看储藏

    git stash List
    
  • 恢复到之前的某一次储藏

    git stash apply stash@{1}
    
  • 恢复储藏并出栈, 将栈顶的储藏移除

    git stash pop
    
  • 删除某一个储藏

    git stash drop stash@{4}
    

分支管理

  • 新建分支

    git branch experimental
    
  • 获取分支列表

    git branch
    
  • 切换分支

    git checkout experimental
    
  • To merge the changes made in experimental into master

    git merge experimental
    
  • 删除分支

    git branch -d experimental
    

Configuring a remote for a fork

  • List the current configured remote repository for your fork.

    $ git remote -v
    > origin  https://github.com/YOUR_USERNAME/YOUR_FORK.git (fetch)
    > origin  https://github.com/YOUR_USERNAME/YOUR_FORK.git (push)
    
  • Specify a new remote upstream repository that will be synced with the fork.

    $ git remote add upstream https://github.com/ORIGINAL_OWNER/ORIGINAL_REPOSITORY.git
    
  • Verify the new upstream repository you’ve specified for your fork.

    $ git remote -v
    > origin    https://github.com/YOUR_USERNAME/YOUR_FORK.git (fetch)
    > origin    https://github.com/YOUR_USERNAME/YOUR_FORK.git (push)
    > upstream  https://github.com/ORIGINAL_OWNER/ORIGINAL_REPOSITORY.git (fetch)
    > upstream  https://github.com/ORIGINAL_OWNER/ORIGINAL_REPOSITORY.git (push)
    

Sync a fork of a repository to keep it up-to-date with the upstream repository.

  • Fetch the branches and their respective commits from the upstream repository. Commits to master will be stored in a local branch, upstream/master

    $ git fetch upstream
    
  • Check out your fork’s local master branch.

    $ git checkout master
    > Switched to branch 'master'
    
  • Merge the changes from upstream/master into your local master branch. This brings your fork’s master branch into sync with the upstream repository, without losing your local changes.

    $ git merge upstream/master
    

MySQL开发规范

发表于 2017-04-12 | 分类于 DataBase |

简介

持续借鉴、收集并整理一些开发规范和技巧,期望能更充分利用MySQL的特性,得到更好的性能。
规范是死的,人是活的。
现在定义的规范,是为以后推翻准备的。

目的

提供给开发人员参考,方便写成更有效率的开发。

范围

文档涉及的范围:需要基于MySQL做应用开发的人员。

定义、首字母缩写词和缩略语

暂无

数据库设计

  • 目标三个:功能实现,可伸缩性,可用性。
  • 关键点:平衡业务技术各个方面,做好取舍。
  • 80%的性能优化来自架构设计的优化。

引擎及版本选择

  • 引擎建议使用InnoDB
  • 根据目前我们业务的特点,建议使用MySQL5.1社区版和InnoDB plugin或MySQL5.5,后续MySQL5.6比较稳定后再行考量和评估。

架构浅谈

  • 开发大牛都擅长,这里不多提,仅标注一下。
  • 非功能性需求
  • 读写分离
  • 分库分表
  • 热点数据
  • 多级缓存
  • 雪崩效应与过载保护
  • 读优化
  • 写优化
  • schema设计
  • 尽量不在数据库做运算
  • 复杂运算移到程序端CPU
  • 尽可能简单应用MySQL
    如:md5() 或Order by Rand()或计算字段等操作不在数据库表上进行。

适当的范式设计

  • 库和表预估
  • 常见的有100库100表,1000库10表等。
  • 建议单库不超过300-400个表。
  • 总空间容量不超过100G。

单表控制

  • IO高效;全表遍历;表修复快;提高并发;alter table快。

字段数量

  • 建议上限20~50个。

一年内的单表数据量预估

  • 建议纯INT不超1000W,含CHAR不超500W。

举例

  • 单表1G体积 500W行评估:
  • 顺序读1G文件需N秒
  • 单行不超过200Byte
  • 单表不超50个纯INT字段
  • 单表不超20个CHAR(10)字段

拒绝3B

  • 大SQL (BIG SQL)
  • 大事务 (BIG Transaction)
  • 大批量 (BIG Batch)

反范式设计

  • 无外键,少多表join查询。
  • 便于分布式设计,允许适度冗余,为了容量扩展允许适度开销。
  • 基于业务自由优化,基于i/o 或查询设计,无须遵循范式结构设计。

典型场景

  • 原有展现程序涉及多个表的查询,希望精简查询程序。
  • 数据表拆分往往基于主键,而原有数据表往往存在非基于主键的关键查询,无法在分表结构中完成。
  • 存在较多数据统计需求(count, sum等),效率低下。
  • 解决思路

    基于展现的冗余设计
    如:
    消息表message,存在字段 from_uid,to_uid,msg,send_time 四个字段,而展示程序需要显示发送者姓名和性别。
    通常在message表中增加冗余字段from_username和from_user_sex即可。

基于查询的冗余设计

如:
用户分表,将用户库分成若干数据表。基于用户名的查询和基于uid的查询都是高并发请求。用户分表基于uid分成数据表,同时基于用户名做对应冗余表。
如果允许多方式登陆,可以有如下设计方法:
uid,passwd,用户信息等等,主数据表,基于uid分表
ukey,ukeytype,uid基于ukey分表,便于用户登陆的查询。分解成如下两个SQL:
select uid from ulist_key_13 where ukey=’$username’ and ukeytype=’$login’;
select * from ulist_uid_23 where uid=$uid and passwd=’$passwd’;
ukeytype定义用户的登陆依据,比如用户名,手机号,邮件地址,网站昵称等。 Ukey+ukeytype必须唯一。
此种方式需要登陆密码统一,对于第三方接入模式,可以通过引申额外字段完成。

基于统计的冗余设计

如:
count(*)操作。
需要不精准结果,可以直接show table status like …获得。
需要精准结果,可以在缓存层增加key-value对,实时更新该key-value。同时异步更新到数据库中冗余字段,或冗余表中。

历史数据表

  • 历史数据表对应于热点数据表。
  • 将需求较少又不能丢弃的数据,仅在少数情况下被访问存入历史数据表。

全文检索设计

  • 最差的设计,直接使用sql语句where条件中使用like %fulltext%
  • 直接全表扫描或全索引扫描,性能最差,无任何扩展,基本不可接受。

MySQL相关引擎支持

  • MyISAM全文索引,使用match()函数搜索。InnoDB从MySQL5.6.4开始支持全文索引,对中文支持不好,使用MATCH()…AGAINST。
  • 并发不高,数据量不大,业务逻辑简单,可以考虑。

使用外部开源全文检索引擎

  • 目前常用的有sphinx和lucene等。
  • 适合并发高,数据量大,业务逻辑复杂的场景。
  • 主要关注预热、增量更新及分片功能的实现。

分页设计

  • 传统分页

    Select * from table limit 10000,10;

  • LIMIT原理

    Limit 10000,10
    偏移量越大则越慢

  • LIMIT方式推荐分页

    Select from table WHERE id>=23423 limit 11; #10+1 (每页10条)
    select
    from table WHERE id>=23434 limit 11;

  • LIMIT的高效分页

    可能需按场景分析并重组索引。

    分页方式二
    Select * from table WHERE id >= ( select id from table limit 10000,1 ) limit 10;

    分页方式三
    ?SELECT * FROM table INNER JOIN (SELECT id FROM table LIMIT 10000,10) USING (id) ;

    分页方式四
    程序取ID:select id from table limit 10000,10;
    Select * from table WHERE id in (123,456…) ;

    LIMIT分页举例
    MySQL> select sql_no_cache from post limit 10,10;
    10 row in set (0.01 sec)
    MySQL> select sql_no_cache
    from post limit 20000,10;
    10 row in set (0.13 sec)
    MySQL> select sql_no_cache from post limit 80000,10;
    10 rows in set (0.58 sec)
    MySQL> select sql_no_cache id from post limit 80000,10;
    10 rows in set (0.02 sec)
    MySQL> select sql_no_cache
    from post WHERE id>=323423 limit 10;
    10 rows in set (0.01 sec)
    MySQL> select * from post WHERE id >= ( select sql_no_cache id from post limit 80000,1 ) limit 10 ;
    10 rows in set (0.02 sec)

  • LIMIT分页与缓存结合

    类似sina微博的首页,总共保留最新的500条微博,分10页。

表字段设计

  • 主键

    如果使用的是InnoDB并且不需要特殊的聚簇。定义一个代理键(surrogate key)是个好的主意。意思就是这个主键并不是来自于你的应用程序的数据(与业务逻辑无关,而应用程序的数据如果有唯一的候选列可以做成唯一键),最简单的方法就是使用AUTO_INCREMENT列。这能保证数据插入保持着连续的顺序并且对于使用主键连接会获得更好的性能。最好避免使用随机的聚簇键。 对每张表,最重要的就是一定要有主键。

  • 主键设计之UUID

    从性能的角度来说,使用UUID是个最不好的方法:它使聚簇索引的插入是随机的。这是最不好的场景了。并且对于数据的聚集也没有什么帮助。
    UUID_SHORT()
    UUID_SHORT()所占用的存储空间比UUID要小。(UUID_SHORT()可能要使用bigint占用8个字节,而UUID可能要使用字符串用char(32))。另外uuid_short()是顺序的,这个也解决了随机导致的问题,但是uuid_short()也有一些限制和bug。

  • 主键设计之自增列

    没什么好说的,自增列简单实用。
    仅注意一下锁(gap lock)问题即可。

  • 主键设计之程序控制

    避免自增列引起的一些锁问题,统一管理,并发性更高。

  • 主键设计之使用中间件

    更高的并发性,可以考虑从数据库中剥离,使用自己开发或第三方中间件,如:
    https://github.com/twitter/snowflake

  • 类型溢出

    原因
    int占用4个字节,而int又分为无符号型和有符号性。对于无符号型的范围是0 到 4294967295;有符号型的范围是-2147483648 到 2147483647。

    举一反三,其他类型都可能有类似问题,均需要考量。

    控制方法
    可以通过sql_mode参数控制,但一般建议程序控制,比如:对表单项的值进行校验。

  • 类型转换

    溢出和隐含转换导致的运行缓慢。
    discuz论坛, uid是pk, mediumint类型, MyISAM表,总行数255万 #现象:更新比较慢,快7秒

    MySQL> UPDATE cdb_members SET email=’qin@zol.com.cn’ WHERE uid=’486851368’;Query OK, 0 rows affected (6.94 sec)Rows matched: 0 Changed: 0 Warnings: 0

    #通过观察语句发现有类型转换,因为uid为mediumint,而传过来的值是字符串’2982891440’

    这里的uid是mediumint, 这个条件的uid大小明显超过了范围。(参考 字段定义)

    去掉uid=后面值的’’,速度就正常了。但是对于uid没有溢出的,加不加引号速度都一样。

    原因:
    在non-strict mode下,MySQL会自动帮你把字符串转换成整形,但是如果数值超出了范围,转换就会失败,所以MySQL就按照字符串来处理,因此不能使用索引。而从explain的结果上,并没有表现出这样的差别。

    控制方法:
    可以通过sql_mode参数控制,一般建议程序控制,比如:对表单项的值进行校验。

字段选择

  1. 字段定义为NOT NULL。
  2. 表字符集选择UTF8,对恶魔字符集emoji用utf8mb4,如果MySQL版本不支持时,应用收到这种字符集的时候先转码成定义的串再传入数据库,例如传来\x0F,应用先替换成[i_smile]这样的特定字符串再存入数据库。
  3. 存储年使用YEAR类型。存储日期使用DATE类型。 存储时间(精确到秒)使用TIMESTAMP类型或INT。使用时间字段作为查询条件,尤其是以时间段查询时,应使用INT保存。
  4. 整形定义中不添加长度,比如使用INT,而不是INT[4]。
  5. 使用VARBINARY存储变长字符串。
  6. 自增序列类型的字段只能使用INT或者BIGINT,且明确标识出为无符号型(UNSIGNED),除非确实会出现负数,仅当该字段数字取值会超过42亿,才使用BIGINT类型;
  7. int(10)和int(1)没有什么区别,10和1仅是宽度而已,在zerofill等扩展属性的时候有用或者特殊的命令行交互工具
  8. 少量枚举或状态定义类需求不建议使用ENUM、SET、VARCHAR类型,使用TINYINT来代替。需在COMMENT信息中标明被枚举的含义。例如:
    is_disable tinyint(1) DEFAULT ‘0’ COMMENT ‘0:启用 1:禁用 2:异常’;
  9. 存储精确浮点数使用DECIMAL替代FLOAT和DOUBLE。
  10. 使用UNSIGNED存储非负数值。
  11. 使用INT UNSIGNED存储IPV4。
  12. 使用短数据类型,比如取值范围为0-80时,使用TINYINT UNSIGNED。
  13. 尽可能不使用TEXT、BLOB类型,如果确实需要将过大字段拆分到其他表中。
  14. VARCHAR(N),N表示的是字符数不是字节数,比如VARCHAR(255),可以最大可存储255个汉字,需要根据实际的宽度来选择N,VARCHAR(N),N>5000时,使用BLOB类型。如果N<256时会使用一个字节来存储长度,如果n>=256则使用两个字节来存储长度。
  15. 不在数据库中使用VARBINARY、BLOB存储图片、文件等。
  16. 禁止在数据库中存储明文密码
  17. 数据库中存放IP时,按功能确定字段类型。仅作展示功能的使用CHAR,作为查询功能的应使用INT类型存放。参见”将字符转化为数字”
  18. 严格禁止在库名、表名中使用大写字母。

技巧

  • 将字符转化为数字更高效,查询更快,占用空间更小

    举例:用无符号INT存储IP,而非CHAR(15)

    INT UNSIGNED

    INET_ATON()

    INET_NTOA()

  • 将日期转化为数字

    更高效,查询更快,占用空间更小

    举例:用无符号INT存储日期和时间

    INT UNSIGNED

    FROM_UNIXTIME()

    UNIX_TIMESTAMP()

  • 避免使用NULL字段

    原因:
    很难进行查询优化;

    NULL列加索引,需要额外空间;

    含NULL复合索引无效。

    举例:

    不使用:`a` char(32) DEFAULT NULL

    不使用:`b` int(10) NOT NULL

    使用:`c` int(10) NOT NULL DEFAULT 0

sql语句

  • 多使用等值操作,少使用非等值操作

    WHERE条件中的非等值条件(IN、BETWEEN、<、<=、>、>=)会导致后面的条件使用不了索引,因为不能同时用到两个范围条件。

  • 常数表优先,字典表或小表其次,大表最后

    常数表指:空表或只有1行的表。与在一个PRIMARY KEY或UNIQUE索引的WHERE子句一起使用的表。如:
    SELECT FROM t WHERE primary_key=1;
    SELECT
    FROM t1,t2 WHERE t1.primary_key=1 AND t2.primary_key=t1.id;

    字典表指:小数量的行。如:自定义的自增字段表,而不使用MySQL的AUTO_INCREMENT。

  • 减少或避免临时表

    如果有一个ORDER BY子句和不同的GROUP BY子句,或如果ORDER BY或GROUP BY包含联接队列中的第一个表之外的其它表的列,则创建一个临时表。

  • where子句中的数据扫描别跨越表的30%

  • where子句中同一个表的不同的字段组合建议小于等于5组,否则考虑业务逻辑或分表

  • 不使用is null或is not null,字段设计时建议not null,若麻烦可折中考虑给一默认值,原因参见”避免使用NULL字段”。

  • 使用like时,%不要放在首字符位置。

    如果%必须放在首字符位置,参见”全文检索设计”

  • 值域比较多的表字段放在前面

    比如:id,date字段放在前面,而status这样的字段放在后面,具体的可以通过执行计划来把握。

  • 表字段组合中出现比较多的表字段放在前面

    方便综合评估索引,缓解因为索引过多导致的增删改的一些性能问题。

  • 表字段不能有表达式或是函数

    如:where abs(列)>3或where 列*10>100

  • 注意表字段的类型,避免表字段的隐示转换

    参见”表字段设计”

    比如:列为int,如果where 列=’1’,则会出现转换。

  • 考虑使用union all,少使用union,注意考虑去重

    union all不去重,而少了排序操作,速度相对比union要快,如果没有去重的需求,优先使用union all。

  • 不同字段的值or或in大于等于3次,考虑用union all替换;同一字段的值or用in替换

    Select * from opp WHERE phone=’12347856’ or phone=’42242233’;

    考虑用

    Select * from opp WHERE phone in (‘12347856’ , ‘42242233’);

    Select * from opp WHERE phone=’010-88886666’ or cellPhone=’13800138000’;

    考虑用
    Select from opp WHERE phone=’010-88886666’
    union all
    Select
    from opp WHERE cellPhone=’13800138000’;

  • 用Where子句替换HAVING子句

    select id,count(star) from table group by id having age>=30 order by null;

    考虑用

    select id,count(star) from table where age>=30 group by id order by null;

  • 对同一表的order by和group by操作分别小于3组,否则考虑业务逻辑或分表
    尽量使用主键进行update和delete

    小心text/blobs等大字段,如果确实不需要这样的大字段,则不用放入sql语句中

    Text/blob大字段的用法参见”字段选择”

  • 使用INSERT … ON DUPLICATE KEY update (INSERT IGNORE)来避免不必要的查询

  • 考虑使用limit N,少用limit M,N,特别是大表,或M比较大的时候

    参考”分页设计”

  • 减少或避免排序,如:group by语句中如果不需要排序,可以增加order by null

  • 增删改语句中不使用不确定值函数和随机函数,如:RAND()和NOW()等。
    INSERT语句使用batch提交(INSERT INTO table VALUES(),(),()„„),values的个数不超过500。

  • 避免使用存储过程、触发器、函数、UDF、events等,容易将业务逻辑和DB耦合在一起,并且MySQL的存储过程、触发器、函数、UDF、events中存在一定的bug。

  • 避免使用JOIN。

  • 使用合理的SQL语句减少与数据库的交互次数。

    INSERT … ON DUPLICATE KEY UPDATE
    REPLACE INTO、INSERT IGNORE 、INSERT INTO VALUES(),(),()
    UPDATE … WHERE ID IN(10,20,50,…)

  • 减少使用视图,避免复杂的语句。

  • SQL语句中IN包含的值不超过500。

  • UPDATE、DELETE语句不使用LIMIT。有主键id的表WHERE条件应结合主键。

  • 使用prepared statement,可以提供性能并且避免SQL注入。

  • InnoDB表避免使用COUNT(*)操作,计数统计实时要求较强可以使用memcache或者redis,非实时统计可以使用单独统计表,定时更新。

  • 禁止在Update语句,将”,”写成”and”,非常危险。

    正确示例:update Table set uid=uid+1000,gid=gid+1000 where id <=2 ;

    错误示例:update Table set uid=uid+1000 and gid=gid+1000 where id <=2 ;

    此时”uid=uid+1000 and gid=gid+1000”将作为值赋给uid,并且无Warning!!!

索引

  • 索引名称使用小写。

  • 索引中的字段数不超过5个。

    唯一键由3个以下字段组成,并且字段都是整形时,使用唯一键作为主键。

    没有唯一键或者唯一键不符合5中的条件时,使用自增(或者通过发号器获取)id作为主键。

  • 唯一键不和主键重复。

  • 索引字段的顺序需要考虑字段值去重之后的个数,个数多的放在前面。

  • ORDER BY,GROUP BY,DISTINCT的字段需要添加在索引的后面。

  • 单张表的索引数量控制在5个以内,若单张表多个字段在查询需求上都要单独用到索引,需要经过DBA评估。查询性能问题无法解决的,应从产品设计上进行重构。

  • 使用EXPLAIN判断SQL语句是否合理使用索引,尽量避免extra列出现:Using File Sort,Using Temporary。

  • UPDATE、DELETE语句需要根据WHERE条件添加索引。

  • 对长度大于50的VARCHAR字段建立索引时,按需求恰当的使用前缀索引,或使用其他方法。

  • 合理创建联合索引(避免冗余),(a,b,c) 相当于 (a) 、(a,b) 、(a,b,c)。

  • 合理利用覆盖索引。

大表

  • 表预计行数(比如:100万条以上),表预计大小(比如:100M以上),历史数据维护策略(分表策略,迁移策略,清理策略等);

  • 频繁增删改的表

    方便考虑定期optimize优化减少碎片,减少相关索引提供更好的写性能。

  • 频繁查的表

    方便适当优化语句,合理评估索引。

  • 特殊字段的表

    大字段(text,blob),值域小的字段(比如字段status字段0表示失败,值分布少,并且用该字段查询时以该值居多,1表示成功)。

  • 按表或按功能页面来分类的常用sql语句

    方便dba整体评估索引,为SQL审核用(生成SQL审核报告)。

  • 缓存机制与规划及预热、降级限流方案

    防雪崩、防刷

配置需求

如主从关系,用户权限等等(可以提供在运维部署说明文档中)

Supervisor

发表于 2014-04-23 | 分类于 Tools |

简介

Linux系统上管理控制进程的工具。

supervisorctl Actions

  • restart all
    Restart all processes Note: restart does not reread config files. For that, see reread and update.
1…45
Jokers

Jokers

hlxstc680@gmail.com

49 日志
13 分类
6 标签
© 2019 Jokers
由 Hexo 强力驱动
主题 - NexT.Muse