0%

锁的说明

java中锁有SynchronizedReentrantLock,但是这两种锁一次只能允许一个线程访问资源,而信号量semaphore可以控制多个线程同时获取资源,实现更高级别的限流.

semaphore使用

// 创建信号量,permits表示许可证数量
Semaphore semaphore = new Semaphore(permits);
// 获取一个许可证
semaphore.acquire();
// 获取多个许可证
semaphore.acquire(2);

// 归还一个许可证
semaphore.release();
// 归还多个许可证
semaphore.release(2);

使用场景

如一个停车场有10个停车位,小型车辆进入需要获取一个许可证,大型车辆进入需要获取多个许可证,车辆驶出时归还许可证.

配置application.yml

spring:
  datasource:
#   第一个数据源
    first:
      driver-class-name: com.mysql.jdbc.Driver
      url: jdbc:mysql://192.168.41.128:3306/first?useUnicode=true&characterEncoding=utf8&useSSL=false
      username: root
      password: 123456
    #   第二个数据源
    second:
      driver-class-name: com.mysql.jdbc.Driver
      url: jdbc:mysql://172.16.0.9:3306/second?useUnicode=true&characterEncoding=utf8&useSSL=false
      username: root
      password: 123456

获取DB配置

@Data
@Component
@ConfigurationProperties(prefix = "spring.datasource.first")
public class FirstDataBaseProperties {
    private String url;
    private String username;
    private String password;
    private String driverClassName;
}
@Data
@Component
@ConfigurationProperties(prefix = "spring.datasource.second")
public class SecondDataBaseProperties {
    private String url;
    private String username;
    private String password;
    private String driverClassName;
}

配置数据源

@Configuration
// 第一个数据源与Mapper接口绑定
@MapperScan(basePackages = "com.deri.task.dao.first",sqlSessionTemplateRef ="firstSqlSessionTemplate")
public class FirstDataSourceConfig {
    @Autowired
    FirstDataBaseProperties firstDataBaseProperties;

    @Bean(name = "firstDS")
    // 多数据源情况下需要指定主数据源
    @Primary
    public DataSource getFirstDataSource() {
        DataSource build =  DataSourceBuilder.create()
                .driverClassName(firstDataBaseProperties.getDriverClassName())
                .url(firstDataBaseProperties.getUrl())
                .username(firstDataBaseProperties.getUsername())
                .password(firstDataBaseProperties.getPassword())
                .build();
        return build;
    }

    @Bean(name = "firstSqlSessionFactory")
    @Primary
    public SqlSessionFactory firstSqlSessionFactory(@Qualifier("firstDS") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        return bean.getObject();
    }

    @Bean("firstTransactionManger")
    @Primary
    public DataSourceTransactionManager firstTransactionManger(@Qualifier("firstDS") DataSource dataSource){
        return new DataSourceTransactionManager(dataSource);
    }

    // 创建SqlSessionTemplate

    @Bean(name = "firstSqlSessionTemplate")
    @Primary
    public SqlSessionTemplate firstSqlSessionTemplate(@Qualifier("firstSqlSessionFactory") SqlSessionFactory sqlSessionFactory){
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}
@Configuration
// 第二个数据源与Mapper接口绑定
@MapperScan(basePackages = "com.deri.task.dao.second",sqlSessionTemplateRef ="secondSqlSessionTemplate")
public class FirstDataSourceConfig {
    @Autowired
    SecondDataBaseProperties secondDataBaseProperties;

    @Bean(name = "secondDS")
    public DataSource getFirstDataSource() {
        DataSource build =  DataSourceBuilder.create()
                .driverClassName(secondDataBaseProperties.getDriverClassName())
                .url(secondDataBaseProperties.getUrl())
                .username(secondDataBaseProperties.getUsername())
                .password(secondDataBaseProperties.getPassword())
                .build();
        return build;
    }

    @Bean(name = "secondSqlSessionFactory")
    public SqlSessionFactory firstSqlSessionFactory(@Qualifier("secondDS") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        return bean.getObject();
    }

    @Bean("secondTransactionManger")
    public DataSourceTransactionManager firstTransactionManger(@Qualifier("secondDS") DataSource dataSource){
        return new DataSourceTransactionManager(dataSource);
    }

    // 创建SqlSessionTemplate

    @Bean(name = "secondSqlSessionTemplate")
    public SqlSessionTemplate firstSqlSessionTemplate(@Qualifier("secondSqlSessionFactory") SqlSessionFactory sqlSessionFactory){
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

参考链接

已知问题

  • mybatis驼峰命名转换失效问题
# 默认在application.yml中配置,但是在多数据源场景下该配置失效,需要在代码中显式指定.
mybatis:
  configuration:
    map-underscore-to-camel-case: true
@Bean(name = "secondSqlSessionFactory")
public SqlSessionFactory firstSqlSessionFactory(@Qualifier("secondDS") DataSource dataSource) throws Exception {
    SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
    bean.setDataSource(dataSource);
    // 指定驼峰转换
    bean.getObject().getConfiguration().setMapUnderscoreToCamelCase(true);
    return bean.getObject();
}

另一种配置方法

不用创建FirstDataBasePropertiesSecondDataBaseProperties.其余保持一样.

    @Primary
    @Bean(name = "publicDataSourceProperties")
    @ConfigurationProperties(prefix = "spring.datasource.public")
    public DataSourceProperties publicDataSourceProperties() {
        return new DataSourceProperties();
    }
    @Bean(name = "publicDS")
    @Primary
    public DataSource getFirstDataSource(@Qualifier("publicDataSourceProperties") DataSourceProperties dataSourceProperties) {
        return dataSourceProperties.initializeDataSourceBuilder().build();
    }

命令

# 指定格式
ls -lSh `find /var/lib/docker -type f -name "*.log"` | head -n 5
# 所有文件格式按大小排序
find /var/lib/docker -type f -printf '%s %p\n' | sort -rn | head -10
# 查找大文件
find . -type f -size +800M  -print0 | xargs -0 du -h | sort -nr | head -10

find命令

  • type: b:块设备文档d:目录c:字符设备文档P:管道文档l:符号链接文档f:普通文档 .
  • name: 按文件名查找。支持*模糊匹配.
  • size: 文件大小。+表示大于,-表示小于。支持k,M,G单位.

xargs命令

给命令传递参数的一个过滤器

somecommand |xargs -item  command
  • xargs -0\0 作为定界符.
  • 删除指定格式文件
find . -type f -name "*.log" -print0 | xargs -0 rm -f
  • 统计文件行数
find . -type f -name "*.php" -print0 | xargs -0 wc -l
  • 下载文件中所有url链接
cat url-list.txt | xargs wget -c

问题

容器日志一般存放在/var/lib/docker/containers/container_id/下面,以json.log结尾的文件(业务日志)很大.

处理

  • 临时清空日志
# 注意不能用rm命令
cat /dev/null > /var/lib/docker/containers/容器id/容器id-json.log
  • 如果是docker-compose
    通过配置容器docker-compose.ymlmax-size选项来实现:
nginx: 
  image: nginx:1.12.1 
  restart: always 
  logging: 
    driver: "json-file"
    options: 
      max-size: "5g"
  • 限制docker容器日志大小
// vim /etc/docker/daemon.json
{
  "log-driver":"json-file",
  "log-opts": {"max-size":"500m", "max-file":"3"}
}

重启docker生效

systemctl daemon-reload
systemctl restart docker

参考链接

背景

有时候我们一台主机上部署了多个容器,而且对部分数据做了持久化,时间长了,数据会越来越多,相应的可能会造成磁盘空间不足?那么我们如何,找出占用磁盘空间最大的容器,并删除容器的部分不需要的日志或数据文件呢?

overlay2简介

OverlayFS是一种现代的联合文件系统,与AUFS类似,但速度更快且实现更简单。Docker为OverlayFS提供了两个存储驱动程序:原始的overlay,更新的和更稳定的overlay2。

容器存储目录

[root@docker overlay2]# df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/vda1        40G  4.1G   34G  11% /
devtmpfs        911M     0  911M   0% /dev
tmpfs           920M     0  920M   0% /dev/shm
tmpfs           920M  1.3M  919M   1% /run
tmpfs           920M     0  920M   0% /sys/fs/cgroup
overlay          40G  4.1G   34G  11% /var/lib/docker/overlay2/6c21d550b2e37e23b777490d3f3b26c54ed5b98ad615ac833ff4248a288b9530/merged
overlay          40G  4.1G   34G  11% /var/lib/docker/overlay2/aa7a46d5a35c404e956fa35c88c5ecb8f117d03299f3818d5c66c33caf4ee6f4/merged
overlay          40G  4.1G   34G  11% /var/lib/docker/overlay2/507f4480d6ed67738d618080b0fcbf60ca22623ba9a87eade44fa403e421cf55/merged
overlay          40G  4.1G   34G  11% /var/lib/docker/overlay2/5cc8105791fd74756b0f7cc36ec93685f3ca90bcb72ac025edb7389e5156228b/merged
overlay          40G  4.1G   34G  11% 

在当前版本中,容器存储目录为/var/lib/docker/overlay2。且当前占用宿主机磁盘空间的目录也为容器存储目录。

查找占用磁盘空间大小的容器目录

[root@docker overlay2]# du -s * | sort -nr | head -5
334636	f6acb9573429712fe4d8b8b786e24d790fae8727f403693874b62a168b174870
159348	86444fb8a5127b41323bef731c14eb764135a7066bb5f904427f53816ff4fe2f
146556	6c21d550b2e37e23b777490d3f3b26c54ed5b98ad615ac833ff4248a288b9530
102080	1eb50142766d18f3927615f63f599d9de1885b2954397736b882bb89ab8ae265
88504	ef4e0ff8bf2cd2f8d2f147e30e89e2c7b6f6e02795ebbcd45a3bba1d77b3b132

注意:这里只列出了排名前五的容器目录。那么现在知道了容器目录,那么如何找出对应的容器呢?现在我们要找出f6acb9573429开头的目录对应时哪个容器?

查找容器目录对应的容器名

  • 通过 docker ps -a 查看容器列表
  • 通过 docker inspect 容器ID 查看容器配置信息
[root@docker overlay2]# for i in $(docker ps -q );do echo echo $i ; docker inspect $i|grep f6acb9573429  ; done
echo 4332fe39163b
                "LowerDir": "/var/lib/docker/overlay2/**f6acb9573429**712fe4d8b8b786e24d790fae8727f403693874b62a168b174870-init/diff:/var/lib/docker/overlay2/b76d30a66c8fef0123a2310bd861a0aa626b5a6e7bf83f9982a6344c8e466187/diff:/var/lib/docker/overlay2/c5b396df751ea053d81765d77f85a8dd44c1c847b6fbe95b38230509f372dfd2/diff:/var/lib/docker/overlay2/1efa8716d1f55fde7716deaacabe0e582aff78f7e460f18b9d5dc84db387533e/diff:/var/lib/docker/overlay2/3f78cbaa248e4f8b1e25599e5e1e2496a463b75e39adfaad2026f134a8ebf89f/diff:/var/lib/docker/overlay2/18ca1077ac90dff82d1085d19162d7b56c42effce18b416632c0e1627602fb17/diff:/var/lib/docker/overlay2/bcee6e758f7ac5769da672274262d61b38acc2cc6ade4b9b56cd0475ca886528/diff:/var/lib/docker/overlay2/e23e02b967bdf1aaaef8e002f0a9f1d778d7a7de7adb12cd925e84ef770b62c7/diff:/var/lib/docker/overlay2/916a116fc26d356a61a9e028c52a3a402349e87e1e9eea6f4d2039cf31391155/diff",
                "MergedDir": "/var/lib/docker/overlay2/f6acb9573429712fe4d8b8b786e24d790fae8727f403693874b62a168b174870/merged",
                "UpperDir": "/var/lib/docker/overlay2/f6acb9573429712fe4d8b8b786e24d790fae8727f403693874b62a168b174870/diff",
                "WorkDir": "/var/lib/docker/overlay2/f6acb9573429712fe4d8b8b786e24d790fae8727f403693874b62a168b174870/work"
echo 4172f0cf7985
echo a622665b0a81
echo 20fde2e0a903

注意:这里就已经找出了最占用磁盘空间大小的容器了。4332fe39163b为容器ID.

查看镜像占用磁盘

docker system df 

查看docker日志.json.log

docker日志默认不作限制,可能产生非常大的日志文件,需要清理或者作出限制.

  • 限制docker容器日志大小
// vim /etc/docker/daemon.json
{
  "log-driver":"json-file",
  "log-opts": {"max-size":"500m", "max-file":"3"}
}

参考链接

问题

通过 kubeadm部署k8s,默认生成的证书有效期是一年.需要每年更新证书.

查看证书有效期

kubeadm alpha certs check-expiration

更新证书

kubeadm alpha certs renew all

通过crontab定时更新证书

0 0 15 10 * kubeadm alpha certs renew all

证书过期kubectl命令无法使用

# 更新客户端配置
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

修改源码增加证书有效期

  • 省略…