Cross Subnet Communication
Two instances in the same VPC but in different subnets can communicate by default, thanks to the VPC routes created along with each subnet (see Using Routing Rules), as long as the Security Group rules allow this traffic.
However, due to a current limitation of the VPC product, this requires a small configuration inside the operating system of your instances: packets destined for the VPC must leave through a VPC interface, not through the public interface.
For example if you have instance-A in the subnet 10.1.0.0/16 and instance-B in the subnet
10.2.0.0/16, you need to run the following commands:
ubuntu@instance-A:~$ sudo ip route add 10.2.0.0/16 via 10.1.0.1 dev eth1
ubuntu@instance-B:~$ sudo ip route add 10.1.0.0/16 via 10.2.0.1 dev eth1
To simplify the configuration on the instance as much as possible, you could set a route for any CIDR that contains the subnet, potentially using a CIDR that contains all your subnets so a single route is enough rather than one per subnet.
Moreover, if you have different VPC interfaces in your instance, you can use any as the target of this routing rule.
Note
Add the following route to all instances that need cross-subnet communication
ubuntu@instance-X:~$ GW=$(ip route show dev eth1 scope link | awk '{print $1; exit}')
ubuntu@instance-X:~$ sudo ip route add <CIDR_THAT_CONTAINS_ALL_SUBNETS> via $GW dev eth1