关于Redis的被动和主动的数据清理问题

我们数据平台中有使用Redis来给线上提供低延时(20毫秒以内)的高并发读写请求,其中最大的Redis使用了阿里云的Redis集群(256G),存储的记录超过10亿,Key的有效期设置为15天,每天写入的记录大概5000万左右,QPS大概在6万左右。由于过期Key的产生速度大于Redis自动清理的速度,因此在Redis中会有大量过期Key未被及时清理。

为什么有过期的Key未被清理呢?这个得先熟悉一下Redis的删除策略。

Redis常用的删除策略有以下三种:

  • 被动删除(惰性删除):当读/写一个已经过期的Key时,会触发惰性删除策略,直接删除掉这个Key;
  • 主动删除(定期删除):Redis会定期巡检,来清理过期Key;
  • 当内存达到maxmemory配置时候,会触发Key的删除操作;

另外,还有一种基于触发器的删除策略,因为对Redis压力太大,一般没人使用。

这里先介绍后两种删除策略(网上有很多说明)。

参考:http://www.cnblogs.com/chenpingzhao/p/5022467.html

主动删除(定期删除)

在 Redis 中,常规操作由 redis.c/serverCron 实现,它主要执行以下操作:

  • 更新服务器的各类统计信息,比如时间、内存占用、数据库占用情况等。
  • 清理数据库中的过期键值对。
  • 对不合理的数据库进行大小调整。
  • 关闭和清理连接失效的客户端。
  • 尝试进行 AOF 或 RDB 持久化操作。
  • 如果服务器是主节点的话,对附属节点进行定期同步。
  • 如果处于集群模式的话,对集群进行定期同步和连接测试。

Redis 将 serverCron 作为时间事件来运行,从而确保它每隔一段时间就会自动运行一次, 又因为 serverCron 需要在 Redis 服务器运行期间一直定期运行, 所以它是一个循环时间事件:serverCron 会一直定期执行,直到服务器关闭为止。

在 Redis 2.6 版本中, 程序规定 serverCron 每秒运行 10 次, 平均每 100 毫秒运行一次。 从 Redis 2.8 开始, 用户可以通过修改 hz选项来调整 serverCron 的每秒执行次数, 具体信息请参考 redis.conf 文件中关于 hz 选项的说明。

也叫定时删除,这里的“定期”指的是Redis定期触发的清理策略,由位于src/redis.c的activeExpireCycle(void)函数来完成。

serverCron是由redis的事件框架驱动的定位任务,这个定时任务中会调用activeExpireCycle函数,针对每个db在限制的时间REDIS_EXPIRELOOKUPS_TIME_LIMIT内迟可能多的删除过期key,之所以要限制时间是为了防止过长时间 的阻塞影响redis的正常运行。这种主动删除策略弥补了被动删除策略在内存上的不友好。

因此,Redis会周期性的随机测试一批设置了过期时间的key并进行处理。测试到的已过期的key将被删除。典型的方式为,Redis每秒做10次如下的步骤:

  • 随机测试100个设置了过期时间的key
  • 删除所有发现的已过期的key
  • 若删除的key超过25个则重复步骤1

这是一个基于概率的简单算法,基本的假设是抽出的样本能够代表整个key空间,redis持续清理过期的数据直至将要过期的key的百分比降到了25%以下。这也意味着在任何给定的时刻已经过期但仍占据着内存空间的key的量最多为每秒的写操作量除以4.

Redis-3.0.0中的默认值是10,代表每秒钟调用10次后台任务。

除了主动淘汰的频率外,Redis对每次淘汰任务执行的最大时长也有一个限定,这样保证了每次主动淘汰不会过多阻塞应用请求,以下是这个限定计算公式:

#define ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC 25 /* CPU max % for keys collection */

…

timelimit = 1000000*ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC/server.hz/100;

hz调大将会提高Redis主动淘汰的频率,如果你的Redis存储中包含很多冷数据占用内存过大的话,可以考虑将这个值调大,但Redis作者建议这个值不要超过100。我们实际线上将这个值调大到100,观察到CPU会增加2%左右,但对冷数据的内存释放速度确实有明显的提高(通过观察keyspace个数和used_memory大小)。

可以看出timelimit和server.hz是一个倒数的关系,也就是说hz配置越大,timelimit就越小。换句话说是每秒钟期望的主动淘汰频率越高,则每次淘汰最长占用时间就越短。这里每秒钟的最长淘汰占用时间是固定的250ms(1000000*ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC/100),而淘汰频率和每次淘汰的最长时间是通过hz参数控制的。

从以上的分析看,当redis中的过期key比率没有超过25%之前,提高hz可以明显提高扫描key的最小个数。假设hz为10,则一秒内最少扫描200个key(一秒调用10次*每次最少随机取出20个key),如果hz改为100,则一秒内最少扫描2000个key;另一方面,如果过期key比率超过25%,则扫描key的个数无上限,但是cpu时间每秒钟最多占用250ms。

当REDIS运行在主从模式时,只有主结点才会执行上述这两种过期删除策略,然后把删除操作”del key”同步到从结点。

maxmemory

当前已用内存超过maxmemory限定时,触发主动清理策略,这些策略可以配置(参数maxmemory-policy),包括以下几个:

  • volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰

  • volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰

  • volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰

  • allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰

  • allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰

  • no-enviction(驱逐):禁止驱逐数据

当mem_used内存已经超过maxmemory的设定,对于所有的读写请求,都会触发redis.c/freeMemoryIfNeeded(void)函数以清理超出的内存。注意这个清理过程是阻塞的,直到清理出足够的内存空间。所以如果在达到maxmemory并且调用方还在不断写入的情况下,可能会反复触发主动清理策略,导致请求会有一定的延迟。

清理时会根据用户配置的maxmemory-policy来做适当的清理(一般是LRU或TTL),这里的LRU或TTL策略并不是针对redis的所有key,而是以配置文件中的maxmemory-samples个key作为样本池进行抽样清理。

总结与备忘

如果Redis中每天过期大量Key(比如几千万),那么必须得考虑过期Key的清理:

  • 增加Redis主动清理的频率(通过调大hz参数);

  • 手动清理过期Key,最简单的方法是进行scan操作,scan操作会触发第一种被动删除,scan操作时候别忘了加count;

  • dbsize命令返回的Key数量,包含了过期Key;

  • randomkey命令返回的Key,不包含过期Key;

  • scan命令返回的Key,包含过期Key;

  • info命令返回的# Keyspace:

  • db6:keys=1034937352,expires=994731489,avg_ttl=507838502

  • keys对应的Key数量等同于dbsize;

  • expires指的是设置了过期时间的Key数量;

  • avg_ttl指设置了过期时间的Key的平均过期时间(单位:毫秒);

Redis缓存数据提高访问性能并同步到mysql永久保存

Redis 是一个高性能的key-value数据库。 redis的出现,很大程度上补偿了memcached这类key-value存储的不足,在部分场合可以对关系数据库起到很好的补充作用。它提供了Python,Ruby,Erlang,PHP客户端,使用很方便。由于游戏服务器数据更新频繁,如果每次读写数据会造成读写数据库的压力大,效率低。

redis的使用场景:

首先,程序先去redis中判断数据是否存在:如果存在,则直接返回缓存好的数据。如果不存在的话,就会去数据库中,读取数据,并把数据缓存到Redis中。

适用场合:如果数据量比较大,但不是经常更新的情况(比如用户排行)。
redis的流程图如下:

未分类

首先先去redis中判断数据是否存在:

  • 如果存在,则直接更新对应的数据,并把更新后的数据返回给页面。
  • 如果不存在的话,就会去先更新数据库中内容,然后把数据保存一份到Redis中。

后台会有Linux的contrab定时任务机制把Redis中的save_update_keys存储的key,分别读取出来,找到对应的数据,更新到DB中。

优点:这个流程的主要目的是把Redis当作数据库使用,更新获取数据比DB快。非常适合大数据量的频繁变动(比如用户游戏数据)。

缺点:对Redis的依赖很大,要做好宕机时的数据保存。(不过可以使用redis的快照AOF,快速恢复的话,应该不会有多大影响,因为就算Redis不工作了,也不会影响后续数据的处理。)

难点:在前期规划key的格式,存储类型很重要,因为这会影响能否把数据同步到DB。

其中第二种方式是游戏服务器中经常使用的方式,例如将用户的游戏数据以hashset的形式存储到redis中,实时更新效率比访问数据库的效率高。根据定时任务将更新的数据存入数据库中,做到永久保存。

解决从phpmyadmin导入sql文件大小被限制的问题

昨天部署了一套考试系统,打算将原来考试系统的数据库直接导入新系统,省去录入数据的苦恼。无奈发现phpmyadmin导入数据限制大小为2M。网上搜索了很多解决办法,将其综合最终导入成功。具体步骤:

1、打开PHP配置文件php.ini。查找upload_max_filesize 和post_max_size 把他们的值修改的大一点(100M)。如果上传的文件很大,还需进行以下修改:

  • max_execution_time(php页面执行最大时间)

  • max_input_time(php页面接受数据最大时间)

  • memory_limit(php页面占用的最大内存)

这是因为phpmyadmin上传大文件时,php页面的执行时间、内存占用也势必变得更长更大,其需要php运行环境的配合,光修改上传文件大小限制是不够的。

2、打开 phpmyadmin 目录下的config.inc.php 文件,查找$cfg[‘ExecTimeLimit’]配置选项,默认值是300,需要修改为0,即没有时间限制。

实际上,在我的环境中$cfg[‘ExecTimeLimit’]的配置项在文件config.default.php中(612行)。

3、打开 phpmyadmin 目录下的import.php 文件 修改$memory_limit 的值

if(empty($memory_limit)){

$memory_limit=2*1024*1024;

}

if(($memory_limit)==-1){

$memory_limit=10*1024*1024;

}

都改成10010241024(根据自己实际情况)。

说明:首选读取php.ini配置文件中的内存配置选项memory_limit,如果为空则默认内存大小限制为2M,如果没有限制则内存大小限制为10M,你可以结合你php.ini配置文件中的相关信息修改这段代码。

注意此时重启服务,会发现文件限制的大小已经变成了100M。但是当我欣喜的导入的时候碰到了另一个问题:

Error: mysql server has gone away。

解决的方法就是找到mysql安装目录,找到my.ini文件,在文件的最后添加:max_allowed_packet = 100M(也可以设置自己需要的大小)。 max_allowed_packet 参数的作用是,用来控制其通信缓冲区的最大长度。

不得不说的是,我在配置这个参数之前,在my.ini中还添加了两个参数:

在my.cnf文件中添加或者修改以下两个变量:

wait_timeout=2880000

interactive_timeout = 2880000

关于两个变量的具体说明可以google或者看官方手册。

(虽然这里说的是my.cnf,但是我是在my.ini中添加的)

最后,成功导入了一个30多M的数据库备份。

centos系统安装配置phpMyAdmin数据库管理工具

centos下安装配置phpmyadmin,我花了二个晚上,郁闷的我不行,配置phpmyadmin简单吧,很简单,我刚工作的时候,就配置过,很顺利,5年后,竟然花了我二个晚上,感觉在centos下有好多陷井,貌似可以走的通,但是进去后,是死胡同。所以做个笔记

一、在phpMyAdmin官方网站http://www.phpmyadmin.net/downloads/下载源码包

cd /usr/local/src

wget https://files.phpmyadmin.net/phpMyAdmin/4.6.0/phpMyAdmin-4.6.0-all-languages.tar.gz

tar zxvf phpMyAdmin-4.6.0-all-languages.tar.gz

二、将phpMyAdmin-4.6.0-all-languages放到web目录下

mv phpMyAdmin-4.6.0-all-languages /usr/local/nginx/html
//重命名
mv phpMyAdmin-4.6.0-all-languages phpMyAdmin

三、配置

cd /usr/local/nginx/html/phpMyAdmin/libraries

vim config.default.php

//修改以下地方
// localhost => 127.0.0.1
$cfg['Servers'][$i]['host'] = '127.0.0.1';
$cfg['Servers'][$i]['user'] = 'root';
$cfg['Servers'][$i]['password'] = '123456';

四、访问

  • 本项目在放在nginx测试目录html下

  • 在浏览器中输入http://localhost/phpMyAdmin

  • 然后输入用户名、密码即可

五、错误信息

1、the local server’s socket is not correctly configured

解决方案如下,在配置文件中修改host

// localhost => 127.0.0.1 
$cfg[‘Servers'][$i][‘host'] = ‘127.0.0.1';

以上就是本文的全部内容,希望对大家的学习有所帮助。

centos7使用systemd配置svn开机启动

1、在/usr/lib/systemd/system/添加svnserve.service文件,文件内容如下:

[Unit] 
Description=Subversion protocol daemon 
After=syslog.target network.target 
[Service] 
Type=forking 
EnvironmentFile=/etc/sysconfig/svnserve
ExecStart=/usr/bin/svnserve --daemon --pid-file=/run/svnserve/svnserve.pid -d -r /home/svn #一定要写svnserve命令的绝对路径 [Install] 
WantedBy=multi-user.target

2、执行

systemctl enable svnserve.service

3、其它、

  • [Unit]:服务的说明
  • Description:描述服务After:描述服务类别
  • [Service]服务运行参数的设置
  • Type=forking是后台运行的形式ExecStart为服务的具体运行命令- ExecReload为重启命令ExecStop为停止命令PrivateTmp=True表示给服务分配独立的临时空间注意:[Service]的启动、重启、停止命令全部要求使用绝对路径

启动svnserve服务

systemctl start svnserve.service

设置开机自启动

systemctl enable svnserve.service

停止开机自启动

systemctl disable svnserve.service

查看服务当前状态

systemctl status svnserve.service

重新启动服务

systemctl restart svnserve.service

查看所有已启动的服务

systemctl list-units --type=service

Linux svn命令行批量操作

详解Linux上svn命令行批量操作

虽然说git很好,大多数时候我也是使用git,但是有时候因为一些原因,不得不使用svn,而在linux上使用svn是没有像windows上的tortoisesvn的软件的(网上有说有类似的,但是折腾了很久仍然没有成功),所以直接来命令行吧。

我们直接安装svn就好,然后文件修改之后使用命令

svn status

查看文件的跟踪信息,这里会使用一些代号,对应的大概是

“ ” 无修改
“A” 新增
“C” 冲突
“D” 删除
“G” 合并
“I” 忽略
“M” 改变
“R” 替换
“X” 未纳入版本控制,但被外部定义所用
“?” 未纳入版本控制
“!” 该项目已遗失 (被非 svn 命令所删除) 或是不完整
“~” 版本控制下的项目与其它类型的项目重名

这里我们需要考虑的是“缺失”和“未纳入版本控制“,也就是”!“和”?“,直接使用下面的命令即可

svn add `svn status |grep ? |awk '{print $2}'`
svn delete `svn status |grep ! |awk '{print $2}'`

注意命令中的反引号,是”esc“键下面,”1“旁边的那个,表示一个命令。

使用上面的命令之后,对应的文件的状态就会变成对应的“D”和“A”,然后就可以使用命令

svn commit -m "xxxx"

进行提交了!

SVN分支 主干Merge操作总结

一、前言

说来惭愧,鄙人从事开发多年,使用svn已经好几个年头了,但是却仅限于update、commit、compare之类的操作,最近想到github上学习别人写的NIO源码,顺便去熟悉git的使用,但是一想到svn,我心里虚了:用了那么多年却对其一知半解,就连最基本的权限分配都没有做过,更别说进行分支拉取和合并了,何谈去get其他技能?做技术的还是要踏实一点,近一年来,我都在对之前未深入的领域进行扫盲,所以,注定svn是绕不过的坎,于是乎开始各种查资料,安装svn服务端(Virtual SVN)和客户端(TortoiseSVN),比对网上的博文进行各种尝试,不能说过程痛苦,但是当你在云里雾里摸索的时候挺难受的吧(顺便说下,在学习的时候精力一定要集中!对我而言,顺便塞上耳塞听音乐工作效率是事半功倍,哈哈哈~)~不废话了,今天这篇博文就讲讲SVN里面比较高级的操作:创建分支(branch)、将主干(trunk)中的代码合并到分支(branch)、将分支(branch)中的代码合并到主干(trunk)中~

二、正文

说到分支和主干,我想不少coder也是比较少接触吧,毕竟很多时候,我们想着的还是如何赶进度~之所以出现分支和主干,就是希望主干和分支两份代码可以各自进行独立的管理互不影响,在需要的时候再进行合并。试想这样一种场景:公司项目已经完成一个阶段的开发计划,这时候拉取一个branch专门用来测试以及BUG修复,而原先trunk上面的代码还可以继续往下开发,互不影响,等测试的branch问题修复之后,将这个branch“合并”回trunk。这样trunk和branch可以在互不干扰的情况下各自做自己的事儿,最后再进行整合,合并过程中有可能会有冲突,这个并不麻烦,等出现冲突的时候自行百度,我相信你们可以解决的,如果还是晕乎乎,欢迎加群交流~

接下来我就来说说如何创建分支(branch)、将主干(trunk)中的代码合并到分支(branch)、将分支(branch)中的代码合并到主干(trunk),首先说明一下笔者当前测试环境:

  • Virtual SVN 1.9.5(传送门:https://www.visualsvn.com/server/download/)
  • TortoiseSVN 1.9.5(传送门:https://sourceforge.net/projects/tortoisesvn/files/1.9.5/Application/)

准备工作(以上客户端服务端自行安装,除了安装路径看自己喜好之外,其他都按照默认设置,点击“下一步”吧):

1、创建repository

打开Virtual SVN,在左侧列表中,右键Repositories,新建一个repository,名字随意,格式笔者是选择FSFS,Repository Structure笔者选择Single-project repository******,这样方便后面的描述,为了测试的方便,在选择“Repository Access Permissions”的时候,选择所有人SVN的user都有访问这个repository的权限(user可以在Virtual SVN的左侧列表Users节点右键,进行新增)

未分类

未分类

未分类  

未分类

未分类 

2、Check out trunk目录到本地

首先复制刚刚新建的repository下trunk的SVN URL

未分类

在本机随意一个目录新建一个空目录,比如笔者在d盘新建了一个svntrunk的目录,然后右键=>SVN Check out,将trunk的svn地址复制到“URL of repository”那一栏,然后点击“OK”

未分类   

3、在D:svntrunk目录下新建一个目录(名称设为project),然后在新建的目录下新增两个text文件:1.txt(文件内容:111111),2.txt(文件内容:222222),然后右键这个project目录,先Add,然后进行commit:

未分类

未分类

未分类

未分类

4、创建分支(branch)(唠叨一下,分支是创建在SVN服务器的repository中,而merge是合并在开发者本地)

右键D:svntrunkproject文件夹,选择TortoiseSVN->Branch/tag,在弹出的对话框中,To path输入分支存放在repository的相对目录,这边注意:project01不能先创建,不然会报project01已经存在,不能创建分支!在log message中输入创建分支的日志,这对后续了解这个分支创建的目的有一定意义。在log message输入栏下面,还有一个Create copy in the repository from的选项,这个选项的目的是为了让开发者选择用哪份源码作为创建的版本 ,第一个是trunk中最新的版本,第二个用户可以选择trunk中指定的版本(通过序号标识),第三个是将工作拷贝作为创建分支的版本

未分类 

上步点击OK之后,创建分支完成,就是这么简单,现在请先记住,我们是以trunk中版本序号是2的工程作为创建分支的版本,这个对后续的合并有意义~(这边顺便说下,在一个repository,版本号是一个全局资源,不管是trunk、branch还是tag,他们使用的版本号不会重复,比如现在trunk已经用掉2这个版本号,那么分支就只能往下一个,用3)

未分类  

5、分支(branch)中的代码合并到主干(trunk)

首先,就像之前将主干(trunk)Check out到本地一样,将svn服务器上面的分支(branches)Check out到D盘svnbranches目录:

未分类  

现在假设主干(trunk)和分支(branche)并行开发,主干(trunk)project下1.txt的文件内容改为121212,分支(branch)中project1下面增加一个3.txt文件,文件内容为:333333

右键主干中project文件夹,选择TortoiseSVN->Merge,这时会弹出一个Merge type让你选(TortoiseSVN1.9.5这个版本只有两个选项,网上有些博文有三个选项),Merge type的选择还是很有讲究,并且也是很容易搞错的,下面会具体来说说:

未分类  

我们先来说说“Merge a range of revisions”这个选项:

我们选中这个选项,然后点击“Next”,会看到如下界面,因为我们是要将分支(branch)合并到主干(trunk),所以这边URL to merge from选项要选择服务器上面需要合并到主干(trunk)的分支(branch)地址(注:前面有提过,合并是合并到本地的working copy,所以一般合并之前,最好将本地working copy代码先更新一遍,有冲突的解决冲突,并且将未提交的代码提交,以防在合并之后,未提交的代码丢失),这边有个Revision range to merge选项,当选择all revisions进行merge的时候,TortoiseSVN做了怎么样的操作呢?其实就是:diff and apply。diff是比较URL to merge from指定的工程最新一个版本和最初的一个版本的差异,假设最新版本是r-last,最初的版本r-first,r-last相对r-first而言,增加了文件a,修改了文件b,那么在合并的时候,就将“增加文件a,修改文件b”的操作应用在本地的working copy上面去,这就完成了合并;假设选择的是specific range,那么用户可以选择一个版本范围,也可以单独指定一个版本或者不填写任何值(此时相当于选all revisions),假设用户指定了版本r1-r3,其中r1新增了文件a,r2新增了文件b,r3删除了文件c,那么在合并的时候TortoiseSVN就会将“新增文件a,新增文件b,删除文件c”应用于本地的 working copy,这样就完成了合并~

(ps:这边还有一个Reverse merge复选框,恢复之前的合并。假设我们刚刚做的merge有问题,需要将本地的working copy恢复成merge之前的,那么就需要将之前应用于本地working copy的操作全部回退,操作和merge基本一样,只是最后,需要复选这个Reverse merge复选框)

未分类 

上步选择了Revision range to merge之后,点击“Next”,进入如下界面,这时我们就可以看到如下界面:

未分类  

全部使用默认的选项,然后在点击Merge之前,可以先点击Test merge按钮,测试一下merge之后的效果:

未分类

如上图所示,分支(branch)版本新增的3.txt文件最终会合并到本次working copy中,最后将本地working copy中的3.txt提交到svn中,这样就完成了分支到trunk的合并了~

我们再来说说这个“Merge two different trees”,从它自己选项的解释来看,是将两个不同的分支(branch)合并到本地working copy中,当然,我们也可以用这个选项将分支(branch)修改的内容合并回主干(trunk)。选择Merge two different trees,点击Next

未分类  

上步之后,会出现如下对话框,注意,我们现在是将分支(branch)合并回主干(trunk),这个时候,我相信很多人想当然的认为Fom处填写的应该是分支(branch)的URL,而To,应该是主干(trunk)的URL,因为是从分支(branch)到主干(trunk)啊,然后事实并非如此!之前在创建分支(branch)这一节,有让读者记住拉取分支(branch)时,主干(trunk)的版本号,当时主干(trunk)的版本号是2,所以From处的URL应该写主干(trunk)的URL,Revision应该选2(其实trunk revision为2的版本,其实也就是branch的第一个版本,所以这边From可以选择主干拉取分支的版本,也可以选取分支最开始的版本),而To处的URL应该选分支的URL,Revision选HEAD Revision,也就是选最新的分支版本。现在就来说说为什么要这样填写:此处进行merge的时候,进行的操作也是diff and apply,将To处URL和revision指定的某个版本,与From处URL和Revision指定的某个版本进行对比,对比是有顺序的,这个怎么理解呢?比如现在To处的为工程project1,From处的为工程project,如果project1相对于project而言,有文件a,没有文件b,换句话说project1相对于project而言,“新增了a,删除了b”,那么此处merge的结果就是会将“新增a,删除b”的操作应用于本地working copy的工程,那为什么From处的project不能指定为最新的Revision呢,既HEAD Revision?试想一下,假如主干(trunk)在拉取了分支(branch)之后,主干(trunk)和分支(branch)都有在并行开发,那么必然主干(trunk)上会有新增的功能,这样就会有新增的代码,这些代码在分支(trunk)上并不存在,在To和From比较过程中,就会出现“删除xxx”的操作,这在merge过程中会应用在本地working copy中,本来这个“xxx”是主干新功能的代码,在将分支合并过来的时候,不应该删除,所以不能用主干最新的版本和分支最新的版本做对比,应该是将当时拉取分支的时候的主干版本和当前最新的分支版本进行对比,应用到本地working copy中才对,所以这边的From必须选取当时拉取当前分支的主干版本,不然主干上面新增的代码会丢失,之前我对From和To的顺序,以及revision的选取也是迷糊了大半天,我希望对读者而言,我这边已经说清楚了~如果还有什么不清楚的欢迎加群交流~

未分类

上步之后,点击Next,进入下面这个页面,同样,在最终merge之时,点击Test merge

未分类
  
点击Test merge之后,可以看到最终合并之后的效果

未分类 

6、主干(trunk)中的代码合并到分支(branch)

这边的操作和分支(branch)合并到主干(类似),需要注意的是,Merge type如果选择“Merge a range of revisions”,那么范围的起始版本应该为拉取分支时的主干版本,结束版本应该为trunk最新的版本;如果选择“Merge two different trees”,那么From必须是选取拉取分支时的主干的版本,或者分支的第一个版本,To必须是主干最新的版本。

svn 版本过低的问题(This client is too old to work with working copy)

在公司使用ubuntu时,出现‘svn版本过低的问题’。从晚上获取了一些信息,已经解决,现做下记录。

如果使用的linux的话,都自带有python.下面是它的下载地址:

1、下载地址

https://subversion.apache.org/source-code

保存下文件。

2、直接使用命令

user@user-desktop:~$ python change-svn-wc-format.py /home/user/workspace 1.5
  • python : 是系统自带的一种语言。

  • change-svn-wc-format.py : 是所保存的文本文件的名称。

  • /home/user/workspace : 工作目录。

  • 1.5 把系统装的svn的版本该为1.5

3、如果出现以下的信息说明成功:

Converted WC at '/home/user/workspace' into format 9 for Subversion 1.5

centos7系统下SVN服务器搭建

1. 安装

sudo yum install subversion

查看安装位置

sudo rpm -ql subversion

2. 创建版本库 svnadmin create 创建一个新的空的版本库

sudo mkdir -p /var/svn
sudo svnadmin create /var/svn/项目名

3. 配置

进入conf目录(该svn版本库配置文件)

  • authz文件是权限控制文件
  • passwd是帐号密码文件
  • svnserve.conf SVN服务配置文件

3.1 设置帐号密码

sudo vim passwd

在[users]块中添加用户和密码,格式:帐号=密码,如junwei = junwei

完整内容参考下面

[users]
june = june
junwei = junwei

3.2 设置权限

用户组格式:

[groups]
groupname=user1,user2,user3

其中,1个用户组可以包含1个或多个用户,用户间以逗号分隔。

例子:

java=xxx,xxx1,xxx2
php=xxx,xxx1,xxx2

版本库目录格式:

  • [<版本库>:/项目/目录]
  • @<用户组名> = <权限>
  • <用户名> = <权限>

其中,方框号内部分可以有多种写法:

  • [/],表示根目录及以下,根目录是svnserve启动时指定的,我们指定为/home/svn/test,[/]就是表示对全部版本库设置权限。
  • [repos:/] 表示对版本库repos设置权限;
  • [repos:/abc] 表示对版本库repos中的abc项目设置权限;
  • [repos:/abc/aaa] 表示对版本库repos中的abc项目的aaa目录设置权限;
  • 权限主体可以是用户组、用户或,用户组在前面加@,表示全部用户。
  • 权限可以是w、r、wr和空,空表示没有任何权限。

例子:

[/tdocs]
@java=rw
@php=rw
@mobile=r
*=

3.3 修改svnserve.conf文件

sudo vim svnserve.conf

打开下面的几个注释:

  • anon-access = read #匿名用户可读
  • auth-access = write #授权用户可写
  • password-db = passwd #使用哪个文件作为账号文件
  • authz-db = authz #使用哪个文件作为权限文件
  • realm = /var/svn/svnrepos # 认证空间名,版本库所在目录

注意:要配置好所处位置,完整参考下面

[general]
anon-access = read
auth-access = write
password-db = passwd
authz-db = authz
realm = /var/svn/project_1
# force-username-case = none
[sasl]
# use-sasl = true
# min-encryption = 0
# max-encryption = 256

4. 启动svn版本库 

sudo svnserve -d -r /var/svn

CentOS系统安装配置svn服务器

今天看大神的博客部署了一下svn,期间遇到各种问题,特写此博客重新将svn在centos下的部署和各种问题的解决方案重新旅顺一下。

一、下载svn

yum install -y subversion

二、验证是否安装成功

svnserve --version

出现版本号说明安装成功了~

三、创建svn版本库

mkdir /var/svn #我这里把版本库放在了var目录下的svn文件夹,方便管理  
svnadmin create /var/svn/repo0 #我这里将svn作为所有版本库的目录,并创建了一个名为repo0的版本库

四、配置当前版本库

创建版本库后,在当前版本库目录中会生成下面的文件,其中我们关心的是配置文件。

[root@localhost svn]# ls  
repo0  
[root@localhost svn]# cd repo0  
[root@localhost repo0]# ls  
conf  db  format  hooks  locks  README.txt  
[root@localhost repo0]# pwd  
/var/svn/repo0  
[root@localhost repo0]# cd conf  
[root@localhost conf]# ls -a  
.  ..  authz  passwd  svnserve.conf

修改passwd文件

passwd文件管理svn用户密码

### This file is an example password file for svnserve.
### Its format is similar to that of svnserve.conf. As shown in the
### example below it contains one section labelled [users].
### The name and password for each user follow, one account per line.

[users]
# harry = harryssecret
# sally = sallyssecret
user0 = user0passwd

修改authz文件

authz文件管理用户组及权限认证,读写控制认证等

### This file is an example authorization file for svnserve.
### Its format is identical to that of mod_authz_svn authorization
### files.
### As shown below each section defines authorizations for the path and
### (optional) repository specified by the section name.
### The authorizations follow. An authorization line can refer to:
###  - a single user,
###  - a group of users defined in a special [groups] section,
###  - an alias defined in a special [aliases] section,
###  - all authenticated users, using the '$authenticated' token,
###  - only anonymous users, using the '$anonymous' token,
###  - anyone, using the '*' wildcard.
###
### A match can be inverted by prefixing the rule with '~'. Rules can
### grant read ('r') access, read-write ('rw') access, or no access
### ('').

[aliases]
# joe = /C=XZ/ST=Dessert/L=Snake City/O=Snake Oil, Ltd./OU=Research Institute/CN=Joe Average
[groups]
team0=user0 #这里代表将user0分在了team0这个小组中
# harry_and_sally = harry,sally
# harry_sally_and_joe = harry,sally,&joe
[/]
@team0=rw  #服务team0用户组读写权限
# [/foo/bar]
# harry = rw
# &joe = r
# * =

# [repository:/baz/fuz]
# @harry_and_sally = rw
# * = r

修改svnserve.conf文件

[general]  
### These options control access to the repository for unauthenticated  
### and authenticated users.  Valid values are "write", "read",  
### and "none".  The sample settings below are the defaults.  
anon-access = none #没有登录的用户不能访问  
auth-access = write #登录的用户可以写入  
### The password-db option controls the location of the password  
### database file.  Unless you specify a path starting with a /,  
### the file's location is relative to the directory containing  
### this configuration file.  
### If SASL is enabled (see below), this file will NOT be used.  
### Uncomment the line below to use the default password file.  
password-db = passwd #密码文件为当前目录下的passwd  
### The authz-db option controls the location of the authorization  
### rules for path-based access control.  Unless you specify a path  
### starting with a /, the file's location is relative to the the  
### directory containing this file.  If you don't specify an  
### authz-db, no path-based access control is done.  
### Uncomment the line below to use the default authorization file.  
authz-db = authz #验证文件为当前目录下的authz

五、停止和启动svn

启动svn

svnserve -d -r /var/svn/

关闭svn

ps -aux |grep svn  
kill -9 进程id

六、导入导出工程

导入工程

$ mkdir MyProject    
$ mkdir MyProject/trunk    
$ mkdir MyProject/branches    
$ mkdir MyProject/tags    
svn import MyProject svn://**svn服务器外网ip**/repo0/MyProject -m "first import project"

导出工程

svn co svn://**svn服务器外网ip**/repo0/MyProject

七、常见错误异常

注:可以使用systemctl status svnserve.service来查看svn当前状态

Authorization failed

svn://192.168.20.242/MyProject1,然后要求输入用户名和密码。如果用户名和密码输入出错了,强行确定后。问题来了!会出现,以下错误信息:

org.tigris.subversion.javahl.ClientException
Authorization failed

这时要清理一下svn用户登录缓存

rm ~/.subversion/auth

svn导入文件时的编码问题

遇到

svn: Valid UTF-8 data 
(hex: 47 64 20 53 63) 
followed by invalid UTF-8 sequence 
(hex: e9 6e 69 63)

或者

svn Error normalizing log message to internal format

这样的错误的原因是所提交的文件中包含非utf8的编码,进入configrm

vim ~/.subversion/config

修改log-encoding值为你文件的编码

[miscellany]
### Set global-ignores to a set of whitespace-delimited globs
### which Subversion will ignore in its 'status' output, and
### while importing or adding files and directories.
### '*' matches leading dots, e.g. '*.rej' matches '.foo.rej'.
# global-ignores = *.o *.lo *.la *.al .libs *.so *.so.[0-9]* *.a *.pyc *.pyo
#   *.rej *~ #*# .#* .*.swp .DS_Store
### Set log-encoding to the default encoding for log messages
log-encoding = binary
### Set use-commit-times to make checkout/update/switch/revert
### put last-committed timestamps on every file touched.
# use-commit-times = yes
### Set no-unlock to prevent 'svn commit' from automatically
### releasing locks on files.
# no-unlock = yes
### Set mime-types-file to a MIME type registry file, used to
### provide hints to Subversion's MIME type auto-detection
### algorithm.
# mime-types-file = /path/to/mime.types
### Set preserved-conflict-file-exts to a whitespace-delimited

当然你也可以给文件转编码

总结:svn配置过程中由于系统环境和版本问题会遇到各种突发问题,多百度谷歌stackoverflow就好了。