0%

问题

[root@master busybox]# kubectl get pod -nkube-system -owide
NAME                             READY   STATUS    RESTARTS   AGE     IP               NODE     NOMINATED NODE   READINESS GATES
coredns-5c98db65d4-8zjps         1/1     Running   1          2d23h   10.244.0.13      master   <none>           <none>
coredns-5c98db65d4-d2kth         1/1     Running   1          2d23h   10.244.0.14      master   <none>           <none>
[root@master busybox]# kubectl get pod -owide
NAME                      READY   STATUS    RESTARTS   AGE    IP            NODE     NOMINATED NODE   READINESS GATES
curl-6bf6db5c4f-pjld9     1/1     Running   1          3d     10.244.1.2    node2    <none>           <none>
gateway-99b655cc6-np685   1/1     Running   0          44s    10.244.0.54   master   <none>           <none>
test-post-start1          1/1     Running   0          115s   10.244.1.6    node2    <none>           <none>
test-post-start2          1/1     Running   0          115s   10.244.0.52   master   <none>           <none>
test-post-start3          1/1     Running   0          115s   10.244.0.53   master   <none>           <none>

如上所示,出现部署在master节点上的pod,无法解析gateway.default.svc.cluster.local域名,但是部署在node2,确可以解析,如上curl-6bf6db5c4f-pjld9,test-post-start1通过nslookup都可以解析.

# 报错
/ # nslookup gateway
nslookup: can't resolve '(null)': Name does not resolve

nslookup: can't resolve 'gateway': Try again

/ # nslookup gateway.default.svc.cluster.local
Server:    10.244.0.10
Address 1: 10.244.0.10

nslookup: can't resolve 'gateway.default.svc.cluster.local'

分析

进入master节点pod,直接通过coredns pod ip解析测试

kubectl exec -it test-post-start2 sh
/ # nslookup gateway.default.svc.cluster.local 10.244.0.13
Server:    10.244.0.13
Address 1: 10.244.0.13 10-244-0-13.kube-dns.kube-system.svc.cluster.local

Name:      gateway.default.svc.cluster.local
Address 1: 10.244.106.29 gateway.default.svc.cluster.local

发现直接通过coredns pod ip解析可以成功,证明coredns服务本身没有问题.

查看dns clusterIP.

[root@master ~]# kubectl get svc -nkube-system
NAME            TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)                  AGE
kube-dns        ClusterIP   10.244.0.10    <none>        53/UDP,53/TCP,9153/TCP   21m
# 通过clusterIP解析域名失败
nslookup gateway.default.svc.cluster.local 10.244.0.10

通过以上测试证明问题出现在coredns service上.

解决

导出现有kube-dns service配置

kubectl get svc -nkube-system kube-dns -oyaml > kube-dns-svc.yaml

修改kube-dns-svc.yaml.

apiVersion: v1
kind: Service
metadata:
  annotations:
    prometheus.io/port: "9153"
    prometheus.io/scrape: "true"
  labels:
    k8s-app: kube-dns
    kubernetes.io/cluster-service: "true"
    kubernetes.io/name: KubeDNS
  name: kube-dns
  namespace: kube-system
spec:
  ports:
  - name: dns
    port: 53
    protocol: UDP
    targetPort: 53
  - name: dns-tcp
    port: 53
    protocol: TCP
    targetPort: 53
  - name: metrics
    port: 9153
    protocol: TCP
    targetPort: 9153
  selector:
    k8s-app: kube-dns
  sessionAffinity: None
  type: ClusterIP
kubectl apply -f kube-dns-svc.yaml

查看最新的coredns clusterIP,当前为10.244.47.231.

[root@master ~]# kubectl get svc -nkube-system
NAME            TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)                  AGE
kube-dns        ClusterIP   10.244.47.231    <none>        53/UDP,53/TCP,9153/TCP   21m

进去之前无法解析的pod中测试,证明新的clusterIP没有问题.

nslookup gateway.default.svc.cluster.local 10.244.47.231

修改kubelet --clusterDNS,这样新创建的pod /etc/resolv.confnameserver为新的coredns clusterIP.

# 修改kubelet配置
vim  /var/lib/kubelet/config.yaml

# 找到clusterDNS
clusterDNS:
- 10.244.47.231

# 重启kubelet生效,注意k8s中所有节点都需要修改重启
systemctl restart kubelet.service

最后测试,新的pod/etc/resolv.conf.解析没有问题.

/ # cat /etc/resolv.conf 
nameserver 10.244.47.231
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5

查询series cardinality命令

InfluxDB maintains an in-memory index of every series in the system. As the number of unique series grows, so does the RAM usage. High series cardinality can lead to the operating system killing the InfluxDB process with an out of memory (OOM) exception. See SHOW CARDINALITY to learn about the InfluxSQL commands for series cardinality.

// 翻译
InfluxDB会在系统上为每个series维护一个内存索引,而随着这些series的增加,RAM内存使用率也会增加。如果series cardinality如果太高,就会导致操作系统触发OOMKiller机制,将Influxdb进程KILL掉. 使用 SHOW CARDINALITY 命令可以查看到 series cardinality。
-- show estimated cardinality of the series on current database
SHOW SERIES CARDINALITY
-- show estimated cardinality of the series on specified database
SHOW SERIES CARDINALITY ON mydb
-- show exact series cardinality
SHOW SERIES EXACT CARDINALITY
-- show series cardinality of the series on specified database
SHOW SERIES EXACT CARDINALITY ON mydb
To reduce series cardinality, series must be dropped from the index. DROP DATABASE, DROP MEASUREMENT, and DROP SERIES will all remove series from the index and reduce the overall series cardinality.

//大意
要减少或者删除series cardinality, 需要删除库//series

将series由保存到内存改为保存到TSI文件

修改配置

这里我们需要修改的配置是index-version项,可以在influxdb.conf[data]下修改,也可以通过环境变量INFLUXDB_DATA_INDEX_VERSION修改.

[data]
  # The type of shard index to use for new shards.  The default is an in-memory index that is
  # recreated at startup.  A value of "tsi1" will use a disk based index that supports higher
  # cardinality datasets.
  # 这个配置项默认值inmem,可以取消注释修改为tsi1,那么后续的index将会保存在TSI文件中了.重启生效.
  # index-version = "inmem"

重构TSI索引

  1. 停止InfluxDB服务
  2. 删除所有_series文件夹
    默认情况下,_series保存在/data/<dbName>/_series,检查并删除/data目录下所有_series
  3. 删除所有index文件夹
    默认情况下,index文件夹在/data/<dbName/<rpName>/<shardID>/index
  4. 使用influx_inspect重构TSI index
# 格式
influx_inspect buildtsi -datadir <data_dir> -waldir <wal_dir>
# 示例
influx_inspect buildtsi -datadir /data -waldir /wal
  1. 启动influxDB服务

问题

k8singress使用的是ingress-nginx.

项目中用到了spring cloud gatewayAPI网关,部署环境有dockerk8s等. 测试出现一个问题:
请求的URL路径中如果出现了中文参数,如http://localhost:8080/test?param=你好,如果部署在docker或者裸机上,后台服务接收到的参数param你好,但是如果部署在k8s上,后台接收到的参数可能是UrlEncode之后的%E4%BD%A0%E5%A5%BD,这不是后台需要的. 虽然可以在后台通过URLDecoder.decode(name, "UTF-8")强制解码,不过比较麻烦.

分析

测试中发现,

  • 如果直接将后台服务部署到k8s上,通过service -> ingress暴露出来,不管是通过k8sClusterIP,如http://10.96.240.18:8080/test?param=你好, 还是通过ingress域名http://local.com/test?param=你好请求后台服务,后台能够正确接收到参数为你好,证明问题可能不是因为部署在k8s上造成的,只可能是spring cloud gatewayAPI网关原因;
  • 但是部署在docker或者裸机上,通过spring cloud gateway网关请求后台服务,后台能够正确接收到参数为你好,证明网关也是没有问题的,问题只可能是部署环境k8s的原因;
  • 如果将网关服务部署到k8s上,又有两种情况:
    • 通过ingress域名请求网关 -> 后台,后台接收到的参数是%E4%BD%A0%E5%A5%BD,看似是网关的问题;
    • 通过ClusterIP请求网关 -> 后台,后台接收到的参数是你好,这又证明网关没问题,看似是ingress的问题,但前面也证明了ingress可以正确传递中文字符,非常的奇怪!
  • spring cloud gateway中所有的Filter全部注释掉,发现通过ingress域名请求网关 -> 后台,后台也能正确的接收到中文参数,证明还是网关的问题,而且这个问题只有部署在k8s中搭配ingress-nginx使用时才会暴露.

解决

依次将注释掉的Filter加回去,证明问题出现在class XXXX extends ForwardedHeaderFilter这个类上.这个类用于设置网关跨域访问和网关本身接口权限验证.

测试发现,即使只注释成下面这样,还是会有问题,但是注释掉@Component,就没有问题.应该是super.filter(exchange, chain)父类这个方法有问题.

@Component
@Slf4j
public class AuthTokenFilter extends ForwardedHeaderFilter {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        //跨域问题 接口权限验证 TODO
        return super.filter(exchange, chain);
    }
}

改成下面这样测试可以解决问题.

@Component
@Slf4j
public class AuthTokenFilter extends ForwardedHeaderFilter {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        //跨域问题 接口权限验证 TODO
        return chain.filter(exchange);
    }
}

问题

spring cloud gateway集成了redis后,一直出现重连的日志,如下:

gateway        | 2020-06-28 10:56:11.133  INFO 1 --- [xecutorLoop-2-2] i.l.core.protocol.ConnectionWatchdog     : Reconnecting, last destination was 192.171.0.9/192.171.0.9:6379
gateway        | 2020-06-28 10:56:11.148  INFO 1 --- [llEventLoop-4-6] i.l.core.protocol.ReconnectionHandler    : Reconnected to 192.171.0.9:6379
gateway        | 2020-06-28 11:01:12.431  INFO 1 --- [xecutorLoop-2-3] i.l.core.protocol.ConnectionWatchdog     : Reconnecting, last destination was 192.171.0.9/192.171.0.9:6379
gateway        | 2020-06-28 11:01:12.441  INFO 1 --- [llEventLoop-4-8] i.l.core.protocol.ReconnectionHandler    : Reconnected to 192.171.0.9:6379
gateway        | 2020-06-28 11:06:13.231  INFO 1 --- [xecutorLoop-2-4] i.l.core.protocol.ConnectionWatchdog     : Reconnecting, last destination was 192.171.0.9/192.171.0.9:6379
gateway        | 2020-06-28 11:06:13.237  INFO 1 --- [llEventLoop-4-2] i.l.core.protocol.ReconnectionHandler    : Reconnected to 192.171.0.9:6379

分析

spring boot 2.0之后spring-boot-starter-data-redis默认不再使用jedis连接redis,而是lettuce.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    <!-- 排除lettuce包,使用jedis代替-->
    <!--<exclusions>-->
        <!--<exclusion>-->
            <!--<groupId>io.lettuce</groupId>-->
            <!--<artifactId>lettuce-core</artifactId>-->
        <!--</exclusion>-->
    <!--</exclusions>-->
</dependency>
<!-- jedis -->
<!--<dependency>-->
    <!--<groupId>redis.clients</groupId>-->
    <!--<artifactId>jedis</artifactId>-->
    <!--<version>2.9.0</version>-->
<!--</dependency>-->

考虑是不是程序长时间没有使用redis,而导致连接断开.修改连接池最小空闲连接数:

spring.redis.host=localhost
spring.redis.password=
# 连接超时时间(毫秒)
spring.redis.timeout=10000
# Redis默认情况下有16个分片,这里配置具体使用的分片,默认是0
spring.redis.database=0
# 连接池最大连接数(使用负值表示没有限制) 默认 8
spring.redis.lettuce.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有限制) 默认 -1
spring.redis.lettuce.pool.max-wait=-1
# 连接池中的最大空闲连接 默认 8
spring.redis.lettuce.pool.max-idle=8
# 连接池中的最小空闲连接 默认 0, 修改为1
spring.redis.lettuce.pool.min-idle=1

注意修改完之后需要增加新的依赖包,不然会报错

<!--配置lettuce.pool.min-idle需要增加的依赖-->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
    <version>2.4.2</version>
</dependency>

重启完程序之后,发现每5分钟打印重连日志依然存在.

解决

  • 这个不是错误,只是一个INFO级别的日志,可以日志级别调高,例如:
<logger name="io.lettuce.core.protocol" level="ERROR">
    <appender-ref ref="ERROR_FILE" />
</logger>
  • 原因:这是lettuce-core的实现里,有类似心跳机制的保持长连接方式,不过心跳机制是不停的来回发心跳包直到连接不可用再去被动重新连接,而lettuce的方案是将连接池里处于空闲(idle)状态的client每隔一段时间就主动断开,然后再重新连接。

参考链接

每日算法题【只出现一次的数字】

只出现一次的数字

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

题解:

  • 使用集合存储数字。遍历数组中的每个数字,如果集合中没有该数字,则将该数字加入集合,如果集合中已经有该数字,则将该数字从集合中删除,最后剩下的数字就是只出现一次的数字。
  • 使用哈希表存储每个数字和该数字出现的次数。遍历数组即可得到每个数字出现的次数,并更新哈希表,最后遍历哈希表,得到只出现一次的数字。
  • 使用集合存储数组中出现的所有数字,并计算数组中的元素之和。由于集合保证元素无重复,因此计算集合中的所有元素之和的两倍,即为每个元素出现两次的情况下的元素之和。由于数组中只有一个元素出现一次,其余元素都出现两次,因此用集合中的元素之和的两倍减去数组中的元素之和,剩下的数就是数组中只出现一次的数字。
  • 最优解:位运算,数组中所有数依次做异或运算,最后得到的数就是只出现一次的数。
  1. 任何数和 0 做异或运算,结果仍然是原来的数
  2. 任何数和其自身做异或运算,结果是 0
  3. 异或运算满足交换律和结合律
0^0 = 0
1^0 = 1
0^1 = 1
1^1 = 0